From a6163888f3c56123b1db313743c6147ba498732c Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Fri, 8 Aug 2014 14:42:07 +0300 Subject: Add third_party libs --- third_party/windows/fltk-1.1.10/src/CMakeLists.txt | 208 ++ third_party/windows/fltk-1.1.10/src/Fl.cxx | 1311 ++++++++ .../windows/fltk-1.1.10/src/Fl_Adjuster.cxx | 171 + .../windows/fltk-1.1.10/src/Fl_BMP_Image.cxx | 493 +++ third_party/windows/fltk-1.1.10/src/Fl_Bitmap.cxx | 518 +++ third_party/windows/fltk-1.1.10/src/Fl_Box.cxx | 44 + third_party/windows/fltk-1.1.10/src/Fl_Browser.cxx | 551 +++ .../windows/fltk-1.1.10/src/Fl_Browser_.cxx | 842 +++++ .../windows/fltk-1.1.10/src/Fl_Browser_load.cxx | 57 + third_party/windows/fltk-1.1.10/src/Fl_Button.cxx | 175 + third_party/windows/fltk-1.1.10/src/Fl_Chart.cxx | 390 +++ .../windows/fltk-1.1.10/src/Fl_Check_Browser.cxx | 309 ++ .../windows/fltk-1.1.10/src/Fl_Check_Button.cxx | 40 + third_party/windows/fltk-1.1.10/src/Fl_Choice.cxx | 191 ++ third_party/windows/fltk-1.1.10/src/Fl_Clock.cxx | 177 + .../windows/fltk-1.1.10/src/Fl_Color_Chooser.cxx | 529 +++ third_party/windows/fltk-1.1.10/src/Fl_Counter.cxx | 197 ++ third_party/windows/fltk-1.1.10/src/Fl_Dial.cxx | 147 + .../windows/fltk-1.1.10/src/Fl_Double_Window.cxx | 452 +++ .../windows/fltk-1.1.10/src/Fl_File_Browser.cxx | 639 ++++ .../windows/fltk-1.1.10/src/Fl_File_Chooser.cxx | 444 +++ .../windows/fltk-1.1.10/src/Fl_File_Chooser.fl | 426 +++ .../windows/fltk-1.1.10/src/Fl_File_Chooser2.cxx | 1308 ++++++++ .../windows/fltk-1.1.10/src/Fl_File_Icon.cxx | 485 +++ .../windows/fltk-1.1.10/src/Fl_File_Icon2.cxx | 1015 ++++++ .../windows/fltk-1.1.10/src/Fl_File_Input.cxx | 288 ++ third_party/windows/fltk-1.1.10/src/Fl_Font.H | 111 + .../windows/fltk-1.1.10/src/Fl_GIF_Image.cxx | 384 +++ third_party/windows/fltk-1.1.10/src/Fl_Gl_Choice.H | 132 + .../windows/fltk-1.1.10/src/Fl_Gl_Choice.cxx | 453 +++ .../windows/fltk-1.1.10/src/Fl_Gl_Overlay.cxx | 248 ++ .../windows/fltk-1.1.10/src/Fl_Gl_Window.cxx | 440 +++ third_party/windows/fltk-1.1.10/src/Fl_Group.cxx | 623 ++++ .../windows/fltk-1.1.10/src/Fl_Help_Dialog.cxx | 301 ++ .../windows/fltk-1.1.10/src/Fl_Help_Dialog.fl | 265 ++ .../windows/fltk-1.1.10/src/Fl_Help_View.cxx | 3507 ++++++++++++++++++++ third_party/windows/fltk-1.1.10/src/Fl_Image.cxx | 525 +++ third_party/windows/fltk-1.1.10/src/Fl_Input.cxx | 477 +++ third_party/windows/fltk-1.1.10/src/Fl_Input_.cxx | 907 +++++ .../windows/fltk-1.1.10/src/Fl_JPEG_Image.cxx | 193 ++ .../windows/fltk-1.1.10/src/Fl_Light_Button.cxx | 169 + third_party/windows/fltk-1.1.10/src/Fl_Menu.cxx | 949 ++++++ third_party/windows/fltk-1.1.10/src/Fl_Menu_.cxx | 232 ++ .../windows/fltk-1.1.10/src/Fl_Menu_Bar.cxx | 78 + .../windows/fltk-1.1.10/src/Fl_Menu_Button.cxx | 111 + .../windows/fltk-1.1.10/src/Fl_Menu_Window.cxx | 103 + .../windows/fltk-1.1.10/src/Fl_Menu_add.cxx | 268 ++ .../windows/fltk-1.1.10/src/Fl_Menu_global.cxx | 50 + .../windows/fltk-1.1.10/src/Fl_Multi_Label.cxx | 80 + .../windows/fltk-1.1.10/src/Fl_Overlay_Window.cxx | 155 + .../windows/fltk-1.1.10/src/Fl_PNG_Image.cxx | 155 + .../windows/fltk-1.1.10/src/Fl_PNM_Image.cxx | 190 ++ third_party/windows/fltk-1.1.10/src/Fl_Pack.cxx | 147 + third_party/windows/fltk-1.1.10/src/Fl_Pixmap.cxx | 495 +++ .../windows/fltk-1.1.10/src/Fl_Positioner.cxx | 151 + .../windows/fltk-1.1.10/src/Fl_Preferences.cxx | 1182 +++++++ .../windows/fltk-1.1.10/src/Fl_Progress.cxx | 117 + .../windows/fltk-1.1.10/src/Fl_Repeat_Button.cxx | 70 + .../windows/fltk-1.1.10/src/Fl_Return_Button.cxx | 72 + third_party/windows/fltk-1.1.10/src/Fl_Roller.cxx | 180 + .../windows/fltk-1.1.10/src/Fl_Round_Button.cxx | 44 + third_party/windows/fltk-1.1.10/src/Fl_Scroll.cxx | 298 ++ .../windows/fltk-1.1.10/src/Fl_Scrollbar.cxx | 277 ++ .../windows/fltk-1.1.10/src/Fl_Shared_Image.cxx | 467 +++ .../windows/fltk-1.1.10/src/Fl_Single_Window.cxx | 41 + third_party/windows/fltk-1.1.10/src/Fl_Slider.cxx | 339 ++ .../windows/fltk-1.1.10/src/Fl_Sys_Menu_Bar.cxx | 334 ++ third_party/windows/fltk-1.1.10/src/Fl_Tabs.cxx | 403 +++ .../windows/fltk-1.1.10/src/Fl_Text_Buffer.cxx | 2534 ++++++++++++++ .../windows/fltk-1.1.10/src/Fl_Text_Display.cxx | 3272 ++++++++++++++++++ .../windows/fltk-1.1.10/src/Fl_Text_Editor.cxx | 492 +++ third_party/windows/fltk-1.1.10/src/Fl_Tile.cxx | 207 ++ .../windows/fltk-1.1.10/src/Fl_Tiled_Image.cxx | 139 + third_party/windows/fltk-1.1.10/src/Fl_Tooltip.cxx | 263 ++ .../windows/fltk-1.1.10/src/Fl_Valuator.cxx | 149 + .../windows/fltk-1.1.10/src/Fl_Value_Input.cxx | 133 + .../windows/fltk-1.1.10/src/Fl_Value_Output.cxx | 103 + .../windows/fltk-1.1.10/src/Fl_Value_Slider.cxx | 82 + third_party/windows/fltk-1.1.10/src/Fl_Widget.cxx | 318 ++ third_party/windows/fltk-1.1.10/src/Fl_Window.cxx | 179 + .../fltk-1.1.10/src/Fl_Window_fullscreen.cxx | 97 + .../windows/fltk-1.1.10/src/Fl_Window_hotspot.cxx | 100 + .../windows/fltk-1.1.10/src/Fl_Window_iconize.cxx | 49 + third_party/windows/fltk-1.1.10/src/Fl_Wizard.cxx | 210 ++ .../windows/fltk-1.1.10/src/Fl_XBM_Image.cxx | 106 + third_party/windows/fltk-1.1.10/src/Fl_XColor.H | 46 + .../windows/fltk-1.1.10/src/Fl_XPM_Image.cxx | 131 + third_party/windows/fltk-1.1.10/src/Fl_abort.cxx | 102 + .../windows/fltk-1.1.10/src/Fl_add_idle.cxx | 100 + third_party/windows/fltk-1.1.10/src/Fl_arg.cxx | 424 +++ third_party/windows/fltk-1.1.10/src/Fl_compose.cxx | 223 ++ third_party/windows/fltk-1.1.10/src/Fl_display.cxx | 54 + third_party/windows/fltk-1.1.10/src/Fl_get_key.cxx | 69 + .../windows/fltk-1.1.10/src/Fl_get_key_mac.cxx | 110 + .../windows/fltk-1.1.10/src/Fl_get_key_win32.cxx | 138 + .../fltk-1.1.10/src/Fl_get_system_colors.cxx | 386 +++ third_party/windows/fltk-1.1.10/src/Fl_grab.cxx | 106 + third_party/windows/fltk-1.1.10/src/Fl_lock.cxx | 358 ++ third_party/windows/fltk-1.1.10/src/Fl_mac.cxx | 2475 ++++++++++++++ .../windows/fltk-1.1.10/src/Fl_own_colormap.cxx | 83 + third_party/windows/fltk-1.1.10/src/Fl_visual.cxx | 121 + third_party/windows/fltk-1.1.10/src/Fl_win32.cxx | 1728 ++++++++++ third_party/windows/fltk-1.1.10/src/Fl_x.cxx | 1413 ++++++++ third_party/windows/fltk-1.1.10/src/Makefile | 726 ++++ third_party/windows/fltk-1.1.10/src/allfiles.xbm | 6 + third_party/windows/fltk-1.1.10/src/cgdebug.h | 215 ++ third_party/windows/fltk-1.1.10/src/cmap.cxx | 179 + third_party/windows/fltk-1.1.10/src/d1.xbm | 6 + third_party/windows/fltk-1.1.10/src/d1_mask.xbm | 6 + third_party/windows/fltk-1.1.10/src/dump_compose.c | 26 + third_party/windows/fltk-1.1.10/src/ew.xbm | 8 + third_party/windows/fltk-1.1.10/src/ew_mask.xbm | 8 + third_party/windows/fltk-1.1.10/src/fastarrow.h | 6 + .../windows/fltk-1.1.10/src/filename_absolute.cxx | 212 ++ .../windows/fltk-1.1.10/src/filename_expand.cxx | 110 + .../windows/fltk-1.1.10/src/filename_ext.cxx | 47 + .../windows/fltk-1.1.10/src/filename_isdir.cxx | 91 + .../windows/fltk-1.1.10/src/filename_list.cxx | 107 + .../windows/fltk-1.1.10/src/filename_match.cxx | 106 + .../windows/fltk-1.1.10/src/filename_setext.cxx | 46 + third_party/windows/fltk-1.1.10/src/fl_arc.cxx | 87 + third_party/windows/fltk-1.1.10/src/fl_arci.cxx | 126 + third_party/windows/fltk-1.1.10/src/fl_ask.cxx | 396 +++ third_party/windows/fltk-1.1.10/src/fl_boxtype.cxx | 322 ++ third_party/windows/fltk-1.1.10/src/fl_call_main.c | 107 + third_party/windows/fltk-1.1.10/src/fl_cmap.h | 256 ++ third_party/windows/fltk-1.1.10/src/fl_color.cxx | 389 +++ .../windows/fltk-1.1.10/src/fl_color_mac.cxx | 114 + .../windows/fltk-1.1.10/src/fl_color_win32.cxx | 254 ++ third_party/windows/fltk-1.1.10/src/fl_cursor.cxx | 335 ++ third_party/windows/fltk-1.1.10/src/fl_curve.cxx | 106 + .../windows/fltk-1.1.10/src/fl_diamond_box.cxx | 80 + third_party/windows/fltk-1.1.10/src/fl_dnd.cxx | 38 + third_party/windows/fltk-1.1.10/src/fl_dnd_mac.cxx | 90 + .../windows/fltk-1.1.10/src/fl_dnd_win32.cxx | 404 +++ third_party/windows/fltk-1.1.10/src/fl_dnd_x.cxx | 201 ++ third_party/windows/fltk-1.1.10/src/fl_draw.cxx | 336 ++ .../windows/fltk-1.1.10/src/fl_draw_image.cxx | 576 ++++ .../windows/fltk-1.1.10/src/fl_draw_image_mac.cxx | 274 ++ .../fltk-1.1.10/src/fl_draw_image_win32.cxx | 325 ++ .../windows/fltk-1.1.10/src/fl_draw_pixmap.cxx | 340 ++ .../windows/fltk-1.1.10/src/fl_encoding_latin1.cxx | 137 + .../fltk-1.1.10/src/fl_encoding_mac_roman.cxx | 134 + .../windows/fltk-1.1.10/src/fl_engraved_label.cxx | 93 + .../windows/fltk-1.1.10/src/fl_file_dir.cxx | 178 + third_party/windows/fltk-1.1.10/src/fl_font.cxx | 60 + .../windows/fltk-1.1.10/src/fl_font_mac.cxx | 379 +++ .../windows/fltk-1.1.10/src/fl_font_win32.cxx | 173 + third_party/windows/fltk-1.1.10/src/fl_font_x.cxx | 269 ++ .../windows/fltk-1.1.10/src/fl_font_xft.cxx | 445 +++ third_party/windows/fltk-1.1.10/src/fl_gtk.cxx | 304 ++ .../windows/fltk-1.1.10/src/fl_images_core.cxx | 103 + .../windows/fltk-1.1.10/src/fl_labeltype.cxx | 133 + .../windows/fltk-1.1.10/src/fl_line_style.cxx | 165 + .../windows/fltk-1.1.10/src/fl_open_uri.cxx | 370 +++ .../windows/fltk-1.1.10/src/fl_oval_box.cxx | 66 + third_party/windows/fltk-1.1.10/src/fl_overlay.cxx | 125 + .../windows/fltk-1.1.10/src/fl_overlay_visual.cxx | 105 + third_party/windows/fltk-1.1.10/src/fl_plastic.cxx | 381 +++ .../windows/fltk-1.1.10/src/fl_read_image.cxx | 503 +++ .../windows/fltk-1.1.10/src/fl_read_image_mac.cxx | 137 + .../fltk-1.1.10/src/fl_read_image_win32.cxx | 72 + third_party/windows/fltk-1.1.10/src/fl_rect.cxx | 685 ++++ .../windows/fltk-1.1.10/src/fl_round_box.cxx | 122 + .../windows/fltk-1.1.10/src/fl_rounded_box.cxx | 99 + .../windows/fltk-1.1.10/src/fl_scroll_area.cxx | 166 + .../windows/fltk-1.1.10/src/fl_set_font.cxx | 90 + .../windows/fltk-1.1.10/src/fl_set_fonts.cxx | 46 + .../windows/fltk-1.1.10/src/fl_set_fonts_mac.cxx | 213 ++ .../windows/fltk-1.1.10/src/fl_set_fonts_win32.cxx | 149 + .../windows/fltk-1.1.10/src/fl_set_fonts_x.cxx | 350 ++ .../windows/fltk-1.1.10/src/fl_set_fonts_xft.cxx | 366 ++ .../windows/fltk-1.1.10/src/fl_shadow_box.cxx | 56 + .../windows/fltk-1.1.10/src/fl_shortcut.cxx | 243 ++ .../windows/fltk-1.1.10/src/fl_show_colormap.cxx | 162 + third_party/windows/fltk-1.1.10/src/fl_symbols.cxx | 700 ++++ third_party/windows/fltk-1.1.10/src/fl_vertex.cxx | 325 ++ third_party/windows/fltk-1.1.10/src/flstring.c | 105 + third_party/windows/fltk-1.1.10/src/flstring.h | 115 + .../windows/fltk-1.1.10/src/forms_bitmap.cxx | 52 + .../fltk-1.1.10/src/forms_compatability.cxx | 211 ++ third_party/windows/fltk-1.1.10/src/forms_free.cxx | 81 + .../windows/fltk-1.1.10/src/forms_fselect.cxx | 67 + .../windows/fltk-1.1.10/src/forms_pixmap.cxx | 52 + .../windows/fltk-1.1.10/src/forms_timer.cxx | 170 + .../windows/fltk-1.1.10/src/freeglut_geometry.cxx | 1110 +++++++ .../fltk-1.1.10/src/freeglut_stroke_mono_roman.cxx | 2848 ++++++++++++++++ .../fltk-1.1.10/src/freeglut_stroke_roman.cxx | 2848 ++++++++++++++++ .../windows/fltk-1.1.10/src/freeglut_teapot.cxx | 164 + .../windows/fltk-1.1.10/src/freeglut_teapot_data.h | 145 + third_party/windows/fltk-1.1.10/src/gl_draw.cxx | 223 ++ third_party/windows/fltk-1.1.10/src/gl_start.cxx | 134 + .../windows/fltk-1.1.10/src/glut_compatability.cxx | 504 +++ third_party/windows/fltk-1.1.10/src/glut_font.cxx | 199 ++ third_party/windows/fltk-1.1.10/src/makedepend | 601 ++++ third_party/windows/fltk-1.1.10/src/makefile.wat | 235 ++ third_party/windows/fltk-1.1.10/src/mediumarrow.h | 6 + third_party/windows/fltk-1.1.10/src/new.xbm | 6 + third_party/windows/fltk-1.1.10/src/ns.xbm | 8 + third_party/windows/fltk-1.1.10/src/ns_mask.xbm | 8 + third_party/windows/fltk-1.1.10/src/numericsort.c | 111 + third_party/windows/fltk-1.1.10/src/scandir.c | 124 + .../windows/fltk-1.1.10/src/scandir_win32.c | 115 + .../windows/fltk-1.1.10/src/screen_xywh.cxx | 256 ++ third_party/windows/fltk-1.1.10/src/slowarrow.h | 6 + third_party/windows/fltk-1.1.10/src/tile.xpm | 91 + third_party/windows/fltk-1.1.10/src/up.xbm | 6 + third_party/windows/fltk-1.1.10/src/vsnprintf.c | 281 ++ 208 files changed, 69677 insertions(+) create mode 100644 third_party/windows/fltk-1.1.10/src/CMakeLists.txt create mode 100644 third_party/windows/fltk-1.1.10/src/Fl.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Adjuster.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_BMP_Image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Bitmap.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Box.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Browser.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Browser_.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Browser_load.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Button.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Chart.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Check_Browser.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Check_Button.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Choice.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Clock.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Color_Chooser.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Counter.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Dial.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Double_Window.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_File_Browser.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_File_Chooser.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_File_Chooser.fl create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_File_Chooser2.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_File_Icon.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_File_Icon2.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_File_Input.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Font.H create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_GIF_Image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Gl_Choice.H create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Gl_Choice.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Gl_Overlay.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Gl_Window.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Group.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Help_Dialog.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Help_Dialog.fl create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Help_View.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Input.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Input_.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_JPEG_Image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Light_Button.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Menu.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Menu_.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Menu_Bar.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Menu_Button.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Menu_Window.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Menu_add.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Menu_global.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Multi_Label.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Overlay_Window.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_PNG_Image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_PNM_Image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Pack.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Pixmap.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Positioner.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Preferences.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Progress.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Repeat_Button.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Return_Button.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Roller.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Round_Button.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Scroll.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Scrollbar.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Shared_Image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Single_Window.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Slider.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Sys_Menu_Bar.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Tabs.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Text_Buffer.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Text_Display.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Text_Editor.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Tile.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Tiled_Image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Tooltip.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Valuator.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Value_Input.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Value_Output.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Value_Slider.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Widget.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Window.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Window_fullscreen.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Window_hotspot.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Window_iconize.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_Wizard.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_XBM_Image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_XColor.H create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_XPM_Image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_abort.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_add_idle.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_arg.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_compose.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_display.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_get_key.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_get_key_mac.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_get_key_win32.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_get_system_colors.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_grab.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_lock.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_mac.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_own_colormap.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_visual.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_win32.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Fl_x.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/Makefile create mode 100644 third_party/windows/fltk-1.1.10/src/allfiles.xbm create mode 100644 third_party/windows/fltk-1.1.10/src/cgdebug.h create mode 100644 third_party/windows/fltk-1.1.10/src/cmap.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/d1.xbm create mode 100644 third_party/windows/fltk-1.1.10/src/d1_mask.xbm create mode 100644 third_party/windows/fltk-1.1.10/src/dump_compose.c create mode 100644 third_party/windows/fltk-1.1.10/src/ew.xbm create mode 100644 third_party/windows/fltk-1.1.10/src/ew_mask.xbm create mode 100644 third_party/windows/fltk-1.1.10/src/fastarrow.h create mode 100644 third_party/windows/fltk-1.1.10/src/filename_absolute.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/filename_expand.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/filename_ext.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/filename_isdir.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/filename_list.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/filename_match.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/filename_setext.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_arc.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_arci.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_ask.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_boxtype.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_call_main.c create mode 100644 third_party/windows/fltk-1.1.10/src/fl_cmap.h create mode 100644 third_party/windows/fltk-1.1.10/src/fl_color.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_color_mac.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_color_win32.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_cursor.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_curve.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_diamond_box.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_dnd.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_dnd_mac.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_dnd_win32.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_dnd_x.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_draw.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_draw_image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_draw_image_mac.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_draw_image_win32.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_draw_pixmap.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_encoding_latin1.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_encoding_mac_roman.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_engraved_label.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_file_dir.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_font.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_font_mac.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_font_win32.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_font_x.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_font_xft.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_gtk.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_images_core.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_labeltype.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_line_style.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_open_uri.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_oval_box.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_overlay.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_overlay_visual.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_plastic.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_read_image.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_read_image_mac.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_read_image_win32.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_rect.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_round_box.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_rounded_box.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_scroll_area.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_set_font.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_set_fonts.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_set_fonts_mac.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_set_fonts_win32.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_set_fonts_x.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_set_fonts_xft.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_shadow_box.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_shortcut.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_show_colormap.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_symbols.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/fl_vertex.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/flstring.c create mode 100644 third_party/windows/fltk-1.1.10/src/flstring.h create mode 100644 third_party/windows/fltk-1.1.10/src/forms_bitmap.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/forms_compatability.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/forms_free.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/forms_fselect.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/forms_pixmap.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/forms_timer.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/freeglut_geometry.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/freeglut_stroke_mono_roman.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/freeglut_stroke_roman.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/freeglut_teapot.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/freeglut_teapot_data.h create mode 100644 third_party/windows/fltk-1.1.10/src/gl_draw.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/gl_start.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/glut_compatability.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/glut_font.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/makedepend create mode 100644 third_party/windows/fltk-1.1.10/src/makefile.wat create mode 100644 third_party/windows/fltk-1.1.10/src/mediumarrow.h create mode 100644 third_party/windows/fltk-1.1.10/src/new.xbm create mode 100644 third_party/windows/fltk-1.1.10/src/ns.xbm create mode 100644 third_party/windows/fltk-1.1.10/src/ns_mask.xbm create mode 100644 third_party/windows/fltk-1.1.10/src/numericsort.c create mode 100644 third_party/windows/fltk-1.1.10/src/scandir.c create mode 100644 third_party/windows/fltk-1.1.10/src/scandir_win32.c create mode 100644 third_party/windows/fltk-1.1.10/src/screen_xywh.cxx create mode 100644 third_party/windows/fltk-1.1.10/src/slowarrow.h create mode 100644 third_party/windows/fltk-1.1.10/src/tile.xpm create mode 100644 third_party/windows/fltk-1.1.10/src/up.xbm create mode 100644 third_party/windows/fltk-1.1.10/src/vsnprintf.c (limited to 'third_party/windows/fltk-1.1.10/src') diff --git a/third_party/windows/fltk-1.1.10/src/CMakeLists.txt b/third_party/windows/fltk-1.1.10/src/CMakeLists.txt new file mode 100644 index 0000000..95cae3b --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/CMakeLists.txt @@ -0,0 +1,208 @@ +SET(CPPFILES + Fl.cxx + Fl_Adjuster.cxx + Fl_Bitmap.cxx + Fl_Browser.cxx + Fl_Browser_.cxx + Fl_Browser_load.cxx + Fl_Box.cxx + Fl_Button.cxx + Fl_Chart.cxx + Fl_Check_Browser.cxx + Fl_Check_Button.cxx + Fl_Choice.cxx + Fl_Clock.cxx + Fl_Color_Chooser.cxx + Fl_Counter.cxx + Fl_Dial.cxx + Fl_Double_Window.cxx + Fl_File_Browser.cxx + Fl_File_Chooser.cxx + Fl_File_Chooser2.cxx + Fl_File_Icon.cxx + Fl_File_Input.cxx + Fl_Group.cxx + Fl_Help_View.cxx + Fl_Image.cxx + Fl_Input.cxx + Fl_Input_.cxx + Fl_Light_Button.cxx + Fl_Menu.cxx + Fl_Menu_.cxx + Fl_Menu_Bar.cxx + Fl_Sys_Menu_Bar.cxx + Fl_Menu_Button.cxx + Fl_Menu_Window.cxx + Fl_Menu_add.cxx + Fl_Menu_global.cxx + Fl_Multi_Label.cxx + Fl_Overlay_Window.cxx + Fl_Pack.cxx + Fl_Pixmap.cxx + Fl_Positioner.cxx + Fl_Preferences.cxx + Fl_Progress.cxx + Fl_Repeat_Button.cxx + Fl_Return_Button.cxx + Fl_Roller.cxx + Fl_Round_Button.cxx + Fl_Scroll.cxx + Fl_Scrollbar.cxx + Fl_Shared_Image.cxx + Fl_Single_Window.cxx + Fl_Slider.cxx + Fl_Tabs.cxx + Fl_Text_Buffer.cxx + Fl_Text_Display.cxx + Fl_Text_Editor.cxx + Fl_Tile.cxx + Fl_Tiled_Image.cxx + Fl_Tooltip.cxx + Fl_Valuator.cxx + Fl_Value_Input.cxx + Fl_Value_Output.cxx + Fl_Value_Slider.cxx + Fl_Widget.cxx + Fl_Window.cxx + Fl_Window_fullscreen.cxx + Fl_Window_hotspot.cxx + Fl_Window_iconize.cxx + Fl_Wizard.cxx + Fl_XBM_Image.cxx + Fl_XPM_Image.cxx + Fl_abort.cxx + Fl_add_idle.cxx + Fl_arg.cxx + Fl_compose.cxx + Fl_display.cxx + Fl_get_key.cxx + Fl_get_system_colors.cxx + Fl_grab.cxx + Fl_lock.cxx + Fl_own_colormap.cxx + Fl_visual.cxx + Fl_x.cxx + filename_absolute.cxx + filename_expand.cxx + filename_ext.cxx + filename_isdir.cxx + filename_list.cxx + filename_match.cxx + filename_setext.cxx + fl_arc.cxx + fl_arci.cxx + fl_ask.cxx + fl_boxtype.cxx + fl_color.cxx + fl_cursor.cxx + fl_curve.cxx + fl_diamond_box.cxx + fl_dnd.cxx + fl_draw.cxx + fl_draw_image.cxx + fl_draw_pixmap.cxx + fl_engraved_label.cxx + fl_file_dir.cxx + fl_font.cxx + fl_gtk.cxx + fl_labeltype.cxx + fl_line_style.cxx + fl_open_uri.cxx + fl_oval_box.cxx + fl_overlay.cxx + fl_overlay_visual.cxx + fl_plastic.cxx + fl_read_image.cxx + fl_rect.cxx + fl_round_box.cxx + fl_rounded_box.cxx + fl_set_font.cxx + fl_set_fonts.cxx + fl_scroll_area.cxx + fl_shadow_box.cxx + fl_shortcut.cxx + fl_show_colormap.cxx + fl_symbols.cxx + fl_vertex.cxx + screen_xywh.cxx + ) +SET(FLCPPFILES + forms_compatability.cxx + forms_bitmap.cxx + forms_free.cxx + forms_fselect.cxx + forms_pixmap.cxx + forms_timer.cxx + ) +SET(GLCPPFILES + Fl_Gl_Choice.cxx + Fl_Gl_Overlay.cxx + Fl_Gl_Window.cxx + freeglut_geometry.cxx + freeglut_stroke_mono_roman.cxx + freeglut_stroke_roman.cxx + freeglut_teapot.cxx + gl_draw.cxx + gl_start.cxx + glut_compatability.cxx + glut_font.cxx + ) +SET(IMGCPPFILES + fl_images_core.cxx + Fl_BMP_Image.cxx + Fl_File_Icon2.cxx + Fl_GIF_Image.cxx + Fl_Help_Dialog.cxx + Fl_JPEG_Image.cxx + Fl_PNG_Image.cxx + Fl_PNM_Image.cxx + ) + +SET(CFILES + fl_call_main.c + flstring.c + scandir.c + numericsort.c + vsnprintf.c + ) + +ADD_LIBRARY(fltk ${CPPFILES} ${CFILES}) +INSTALL_TARGETS(/lib fltk) +SET_TARGET_PROPERTIES(fltk + PROPERTIES + VERSION ${FLTK_VERSION_MAJOR}.${FLTK_VERSION_MINOR} + SOVERSION ${FLTK_VERSION_PATCH}) + +TARGET_LINK_LIBRARIES(fltk ${FLTK_PLATFORM_DEPENDENT_LIBS} ${CMAKE_THREAD_LIBS_INIT}) + +IF(X11_FOUND) + TARGET_LINK_LIBRARIES(fltk ${X11_LIBRARIES}) +ENDIF(X11_FOUND) + +IF(OPENGL_FOUND) + ADD_LIBRARY(fltk_gl ${GLCPPFILES}) + INSTALL_TARGETS(/lib fltk_gl) + TARGET_LINK_LIBRARIES(fltk_gl fltk ${OPENGL_LIBRARIES}) + SET_TARGET_PROPERTIES(fltk_gl + PROPERTIES + VERSION ${FLTK_VERSION_MAJOR}.${FLTK_VERSION_MINOR} + SOVERSION ${FLTK_VERSION_PATCH}) +ENDIF(OPENGL_FOUND) + +ADD_LIBRARY(fltk_forms ${FLCPPFILES}) +INSTALL_TARGETS(/lib fltk_forms) +TARGET_LINK_LIBRARIES(fltk_forms fltk) +SET_TARGET_PROPERTIES(fltk_forms + PROPERTIES + VERSION ${FLTK_VERSION_MAJOR}.${FLTK_VERSION_MINOR} + SOVERSION ${FLTK_VERSION_PATCH}) + +ADD_LIBRARY(fltk_images ${IMGCPPFILES}) +INSTALL_TARGETS(/lib fltk_images) +TARGET_LINK_LIBRARIES(fltk_images fltk ${FLTK_PNG_LIBRARIES} + ${FLTK_JPEG_LIBRARIES} ${FLTK_ZLIB_LIBRARIES}) +SET_TARGET_PROPERTIES(fltk_images + PROPERTIES + VERSION ${FLTK_VERSION_MAJOR}.${FLTK_VERSION_MINOR} + SOVERSION ${FLTK_VERSION_PATCH}) + diff --git a/third_party/windows/fltk-1.1.10/src/Fl.cxx b/third_party/windows/fltk-1.1.10/src/Fl.cxx new file mode 100644 index 0000000..63a9d8c --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl.cxx @@ -0,0 +1,1311 @@ +// +// "$Id: Fl.cxx 6474 2008-10-19 20:15:48Z matt $" +// +// Main event handling code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// warning: the Apple Quartz version still uses some Quickdraw calls, +// mostly to get around the single active context in QD and +// to implement clipping. This should be changed into pure +// Quartz calls in the near future. + +#include +#include +#include +#include +#include +#include +#include +#include "flstring.h" + +#ifdef DEBUG +# include +#endif // DEBUG + +#ifdef WIN32 +# include +void fl_free_fonts(void); +HBRUSH fl_brush_action(int action); +void fl_cleanup_pens(void); +void fl_release_dc(HWND,HDC); +void fl_cleanup_dc_list(void); +#endif // WIN32 + +// +// Globals... +// + +Fl_Widget *Fl::belowmouse_, + *Fl::pushed_, + *Fl::focus_, + *Fl::selection_owner_; +int Fl::damage_, + Fl::e_number, + Fl::e_x, + Fl::e_y, + Fl::e_x_root, + Fl::e_y_root, + Fl::e_dx, + Fl::e_dy, + Fl::e_state, + Fl::e_clicks, + Fl::e_is_click, + Fl::e_keysym, + Fl::e_original_keysym; +char *Fl::e_text = (char *)""; +int Fl::e_length; +int Fl::visible_focus_ = 1, + Fl::dnd_text_ops_ = 1; + + +Fl_Window *fl_xfocus; // which window X thinks has focus +Fl_Window *fl_xmousewin;// which window X thinks has FL_ENTER +Fl_Window *Fl::grab_; // most recent Fl::grab() +Fl_Window *Fl::modal_; // topmost modal() window + +// +// 'Fl::version()' - Return the API version number... +// + +double +Fl::version() { + return FL_VERSION; +} + + +// +// 'Fl:event_inside()' - Return whether or not the mouse event is inside +// the given rectangle. +// + +int Fl::event_inside(int xx,int yy,int ww,int hh) /*const*/ { + int mx = e_x - xx; + int my = e_y - yy; + return (mx >= 0 && mx < ww && my >= 0 && my < hh); +} + +int Fl::event_inside(const Fl_Widget *o) /*const*/ { + int mx = e_x - o->x(); + int my = e_y - o->y(); + return (mx >= 0 && mx < o->w() && my >= 0 && my < o->h()); +} + +// +// +// timer support +// + +#ifdef WIN32 + +/// implementation in Fl_win32.cxx + +#elif defined(__APPLE__) + +/// implementation in Fl_mac.cxx + +#else + +// +// X11 timers +// + + +//////////////////////////////////////////////////////////////// +// Timeouts are stored in a sorted list, so only the first one needs +// to be checked to see if any should be called. + +struct Timeout { + double time; + void (*cb)(void*); + void* arg; + Timeout* next; +}; +static Timeout* first_timeout, *free_timeout; +static int first_timeout_count, free_timeout_count; + +#include + +// I avoid the overhead of getting the current time when we have no +// timeouts by setting this flag instead of getting the time. +// In this case calling elapse_timeouts() does nothing, but records +// the current time, and the next call will actualy elapse time. +static char reset_clock = 1; + +static void elapse_timeouts() { + static struct timeval prevclock; + struct timeval newclock; + gettimeofday(&newclock, NULL); + double elapsed = newclock.tv_sec - prevclock.tv_sec + + (newclock.tv_usec - prevclock.tv_usec)/1000000.0; + prevclock.tv_sec = newclock.tv_sec; + prevclock.tv_usec = newclock.tv_usec; + if (reset_clock) { + reset_clock = 0; + } else if (elapsed > 0) { + for (Timeout* t = first_timeout; t; t = t->next) t->time -= elapsed; + } +} + +// Continuously-adjusted error value, this is a number <= 0 for how late +// we were at calling the last timeout. This appears to make repeat_timeout +// very accurate even when processing takes a significant portion of the +// time interval: +static double missed_timeout_by; + +void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *argp) { + elapse_timeouts(); + repeat_timeout(time, cb, argp); +} + +void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *argp) { + time += missed_timeout_by; if (time < -.05) time = 0; + Timeout* t = free_timeout; + if (t) { + free_timeout = t->next; + --free_timeout_count; + } else { + t = new Timeout; + } + t->time = time; + t->cb = cb; + t->arg = argp; + // insert-sort the new timeout: + Timeout** p = &first_timeout; + while (*p && (*p)->time <= time) p = &((*p)->next); + t->next = *p; + *p = t; +} + +int Fl::has_timeout(Fl_Timeout_Handler cb, void *argp) { + for (Timeout* t = first_timeout; t; t = t->next) + if (t->cb == cb && t->arg == argp) return 1; + return 0; +} + +void Fl::remove_timeout(Fl_Timeout_Handler cb, void *argp) { + // This version removes all matching timeouts, not just the first one. + // This may change in the future. + for (Timeout** p = &first_timeout; *p;) { + Timeout* t = *p; + if (t->cb == cb && (t->arg == argp || !argp)) { + *p = t->next; + t->next = free_timeout; + free_timeout = t; + } else { + p = &(t->next); + } + } +} + +#endif + +//////////////////////////////////////////////////////////////// +// Checks are just stored in a list. They are called in the reverse +// order that they were added (this may change in the future). +// This is a bit messy because I want to allow checks to be added, +// removed, and have wait() called from inside them, to do this +// next_check points at the next unprocessed one for the outermost +// call to Fl::wait(). + +struct Check { + void (*cb)(void*); + void* arg; + Check* next; +}; +static Check *first_check, *next_check, *free_check; + +void Fl::add_check(Fl_Timeout_Handler cb, void *argp) { + Check* t = free_check; + if (t) free_check = t->next; + else t = new Check; + t->cb = cb; + t->arg = argp; + t->next = first_check; + if (next_check == first_check) next_check = t; + first_check = t; +} + +void Fl::remove_check(Fl_Timeout_Handler cb, void *argp) { + for (Check** p = &first_check; *p;) { + Check* t = *p; + if (t->cb == cb && t->arg == argp) { + if (next_check == t) next_check = t->next; + *p = t->next; + t->next = free_check; + free_check = t; + } else { + p = &(t->next); + } + } +} + +/** + * Return 1, if a check with the same handler and data pointer + * is pending, 0 otherwise. + */ +int Fl::has_check(Fl_Timeout_Handler cb, void *argp) { + for (Check** p = &first_check; *p;) { + Check* t = *p; + if (t->cb == cb && t->arg == argp) { + return 1; + } else { + p = &(t->next); + } + } + return 0; +} + +static void run_checks() +{ + // checks are a bit messy so that add/remove and wait may be called + // from inside them without causing an infinite loop: + if (next_check == first_check) { + while (next_check) { + Check* checkp = next_check; + next_check = checkp->next; + (checkp->cb)(checkp->arg); + } + next_check = first_check; + } +} + +#ifndef WIN32 +static char in_idle; +#endif + +//////////////////////////////////////////////////////////////// +// wait/run/check/ready: + +void (*Fl::idle)(); // see Fl_add_idle.cxx for the add/remove functions + +extern int fl_ready(); // in Fl_.cxx +extern int fl_wait(double time); // in Fl_.cxx + +double Fl::wait(double time_to_wait) { + // delete all widgets that were listed during callbacks + do_widget_deletion(); + +#ifdef WIN32 + + return fl_wait(time_to_wait); + +#elif defined(__APPLE__) + + run_checks(); + if (idle) { + if (!in_idle) { + in_idle = 1; + idle(); + in_idle = 0; + } + // the idle function may turn off idle, we can then wait: + if (idle) time_to_wait = 0.0; + } + flush(); + if (idle && !in_idle) // 'idle' may have been set within flush() + time_to_wait = 0.0; + return fl_wait(time_to_wait); + +#else + + if (first_timeout) { + elapse_timeouts(); + Timeout *t; + while ((t = first_timeout)) { + if (t->time > 0) break; + // The first timeout in the array has expired. + missed_timeout_by = t->time; + // We must remove timeout from array before doing the callback: + void (*cb)(void*) = t->cb; + void *argp = t->arg; + first_timeout = t->next; + t->next = free_timeout; + free_timeout = t; + ++free_timeout_count; + --first_timeout_count; + // Now it is safe for the callback to do add_timeout: + cb(argp); + } + } else { + reset_clock = 1; // we are not going to check the clock + } + run_checks(); +// if (idle && !fl_ready()) { + if (idle) { + if (!in_idle) { + in_idle = 1; + idle(); + in_idle = 0; + } + // the idle function may turn off idle, we can then wait: + if (idle) time_to_wait = 0.0; + } + if (first_timeout && first_timeout->time < time_to_wait) + time_to_wait = first_timeout->time; + if (time_to_wait <= 0.0) { + // do flush second so that the results of events are visible: + int ret = fl_wait(0.0); + flush(); + return ret; + } else { + // do flush first so that user sees the display: + flush(); + if (idle && !in_idle) // 'idle' may have been set within flush() + time_to_wait = 0.0; + return fl_wait(time_to_wait); + } +#endif +} + +#define FOREVER 1e20 + +int Fl::run() { + while (Fl_X::first) wait(FOREVER); + return 0; +} + +#ifdef WIN32 +class Fl_Win32_At_Exit { +public: + Fl_Win32_At_Exit() { } + ~Fl_Win32_At_Exit() { + fl_free_fonts(); // do some WIN32 cleanup + fl_cleanup_pens(); + OleUninitialize(); + fl_brush_action(1); + fl_cleanup_dc_list(); + } +}; +static Fl_Win32_At_Exit win32_at_exit; +#endif + + + +int Fl::wait() { + if (!Fl_X::first) return 0; + wait(FOREVER); + return Fl_X::first != 0; // return true if there is a window +} + +int Fl::check() { + wait(0.0); + return Fl_X::first != 0; // return true if there is a window +} + +int Fl::ready() { +#if ! defined( WIN32 ) && ! defined(__APPLE__) + if (first_timeout) { + elapse_timeouts(); + if (first_timeout->time <= 0) return 1; + } else { + reset_clock = 1; + } +#endif + return fl_ready(); +} + +//////////////////////////////////////////////////////////////// +// Window list management: + +Fl_X* Fl_X::first; + +Fl_Window* fl_find(Window xid) { + Fl_X *window; + for (Fl_X **pp = &Fl_X::first; (window = *pp); pp = &window->next) +#ifdef __APPLE_QD__ + if (window->xid == xid && !window->w->window()) { +#elif defined(__APPLE_QUARTZ__) + if (window->xid == xid && !window->w->window()) { +#else + if (window->xid == xid) { +#endif // __APPLE__ + if (window != Fl_X::first && !Fl::modal()) { + // make this window be first to speed up searches + // this is not done if modal is true to avoid messing up modal stack + *pp = window->next; + window->next = Fl_X::first; + Fl_X::first = window; + } + return window->w; + } + return 0; +} + +Fl_Window* Fl::first_window() { + Fl_X* i = Fl_X::first; + return i ? i->w : 0; +} + +Fl_Window* Fl::next_window(const Fl_Window* window) { + Fl_X* i = Fl_X::i(window)->next; + return i ? i->w : 0; +} + +void Fl::first_window(Fl_Window* window) { + if (!window || !window->shown()) return; + fl_find(fl_xid(window)); +} + +void Fl::redraw() { + for (Fl_X* i = Fl_X::first; i; i = i->next) i->w->redraw(); +} + +void Fl::flush() { + if (damage()) { + damage_ = 0; + for (Fl_X* i = Fl_X::first; i; i = i->next) { + if (i->wait_for_expose) {damage_ = 1; continue;} + Fl_Window* wi = i->w; + if (!wi->visible_r()) continue; + if (wi->damage()) {i->flush(); wi->clear_damage();} + // destroy damage regions for windows that don't use them: + if (i->region) {XDestroyRegion(i->region); i->region = 0;} + } + } + +#ifdef WIN32 + GdiFlush(); +#elif defined(__APPLE_QD__) + GrafPtr port; + GetPort( &port ); + if ( port ) + QDFlushPortBuffer( port, 0 ); +#elif defined (__APPLE_QUARTZ__) + if (fl_gc) + CGContextFlush(fl_gc); +#else + if (fl_display) XFlush(fl_display); +#endif +} + +//////////////////////////////////////////////////////////////// +// Event handlers: + +struct handler_link { + int (*handle)(int); + handler_link *next; +}; + +static handler_link *handlers = 0; + +void Fl::add_handler(int (*ha)(int)) { + handler_link *l = new handler_link; + l->handle = ha; + l->next = handlers; + handlers = l; +} + +void Fl::remove_handler(int (*ha)(int)) { + handler_link *l, *p; + + // Search for the handler in the list... + for (l = handlers, p = 0; l && l->handle != ha; p = l, l = l->next); + + if (l) { + // Found it, so remove it from the list... + if (p) p->next = l->next; + else handlers = l->next; + + // And free the record... + delete l; + } +} + +int (*fl_local_grab)(int); // used by fl_dnd.cxx + +static int send_handlers(int e) { + for (const handler_link *hl = handlers; hl; hl = hl->next) + if (hl->handle(e)) return 1; + return 0; +} + +//////////////////////////////////////////////////////////////// + +Fl_Widget* fl_oldfocus; // kludge for Fl_Group... + +void Fl::focus(Fl_Widget *o) { + if (o && !o->visible_focus()) return; + if (grab()) return; // don't do anything while grab is on + Fl_Widget *p = focus_; + if (o != p) { + Fl::compose_reset(); + focus_ = o; + // make sure that fl_xfocus is set to the top level window + // of this widget, or fl_fix_focus will clear our focus again + if (o) { + Fl_Window *win = 0, *w1 = o->window(); + while (w1) { win=w1; w1=win->window(); } + if (win) fl_xfocus = win; + } + // take focus from the old focused window + fl_oldfocus = 0; + int old_event = e_number; + e_number = FL_UNFOCUS; + for (; p; p = p->parent()) { + p->handle(FL_UNFOCUS); + fl_oldfocus = p; + } + e_number = old_event; + } +} + +static char dnd_flag = 0; // make 'belowmouse' send DND_LEAVE instead of LEAVE + +void Fl::belowmouse(Fl_Widget *o) { + if (grab()) return; // don't do anything while grab is on + Fl_Widget *p = belowmouse_; + if (o != p) { + belowmouse_ = o; + int old_event = e_number; + e_number = dnd_flag ? FL_DND_LEAVE : FL_LEAVE; + for (; p && !p->contains(o); p = p->parent()) { + p->handle(e_number); + } + e_number = old_event; + } +} + +void Fl::pushed(Fl_Widget *o) { + pushed_ = o; +} + +static void nothing(Fl_Widget *) {} +void (*Fl_Tooltip::enter)(Fl_Widget *) = nothing; +void (*Fl_Tooltip::exit)(Fl_Widget *) = nothing; + +// Update modal(), focus() and other state according to system state, +// and send FL_ENTER, FL_LEAVE, FL_FOCUS, and/or FL_UNFOCUS events. +// This is the only function that produces these events in response +// to system activity. +// This is called whenever a window is added or hidden, and whenever +// X says the focus or mouse window have changed. + +void fl_fix_focus() { +#ifdef DEBUG + puts("fl_fix_focus();"); +#endif // DEBUG + + if (Fl::grab()) return; // don't do anything while grab is on. + + // set focus based on Fl::modal() and fl_xfocus + Fl_Widget* w = fl_xfocus; + if (w) { + int saved = Fl::e_keysym; + if (Fl::e_keysym < (FL_Button + FL_LEFT_MOUSE) || + Fl::e_keysym > (FL_Button + FL_RIGHT_MOUSE)) + Fl::e_keysym = 0; // make sure widgets don't think a keystroke moved focus + while (w->parent()) w = w->parent(); + if (Fl::modal()) w = Fl::modal(); + if (!w->contains(Fl::focus())) + if (!w->take_focus()) Fl::focus(w); + Fl::e_keysym = saved; + } else + Fl::focus(0); + +// MRS: Originally we checked the button state, but a user reported that it +// broke click-to-focus in FLWM?!? +// if (!(Fl::event_state() & 0x7f00000 /*FL_BUTTONS*/)) { + if (!Fl::pushed()) { + // set belowmouse based on Fl::modal() and fl_xmousewin: + w = fl_xmousewin; + if (w) { + if (Fl::modal()) w = Fl::modal(); + if (!w->contains(Fl::belowmouse())) { + int old_event = Fl::e_number; + w->handle(Fl::e_number = FL_ENTER); + Fl::e_number = old_event; + if (!w->contains(Fl::belowmouse())) Fl::belowmouse(w); + } else { + // send a FL_MOVE event so the enter/leave state is up to date + Fl::e_x = Fl::e_x_root-fl_xmousewin->x(); + Fl::e_y = Fl::e_y_root-fl_xmousewin->y(); + int old_event = Fl::e_number; + w->handle(Fl::e_number = FL_MOVE); + Fl::e_number = old_event; + } + } else { + Fl::belowmouse(0); + Fl_Tooltip::enter(0); + } + } +} + +#ifndef WIN32 +extern Fl_Widget *fl_selection_requestor; // from Fl_x.cxx +#endif + +// This function is called by ~Fl_Widget() and by Fl_Widget::deactivate +// and by Fl_Widget::hide(). It indicates that the widget does not want +// to receive any more events, and also removes all global variables that +// point at the widget. +// I changed this from the 1.0.1 behavior, the older version could send +// FL_LEAVE or FL_UNFOCUS events to the widget. This appears to not be +// desirable behavior and caused flwm to crash. + +void fl_throw_focus(Fl_Widget *o) { +#ifdef DEBUG + printf("fl_throw_focus(o=%p)\n", o); +#endif // DEBUG + + if (o->contains(Fl::pushed())) Fl::pushed_ = 0; +#ifndef WIN32 + if (o->contains(fl_selection_requestor)) fl_selection_requestor = 0; +#endif + if (o->contains(Fl::belowmouse())) Fl::belowmouse_ = 0; + if (o->contains(Fl::focus())) Fl::focus_ = 0; + if (o == fl_xfocus) fl_xfocus = 0; + if (o == Fl_Tooltip::current()) Fl_Tooltip::current(0); + if (o == fl_xmousewin) fl_xmousewin = 0; + Fl_Tooltip::exit(o); + fl_fix_focus(); +} + +//////////////////////////////////////////////////////////////// + +// Call to->handle but first replace the mouse x/y with the correct +// values to account for nested X windows. 'window' is the outermost +// window the event was posted to by X: +static int send(int event, Fl_Widget* to, Fl_Window* window) { + int dx, dy; + int old_event = Fl::e_number; + if (window) { + dx = window->x(); + dy = window->y(); + } else { + dx = dy = 0; + } + for (const Fl_Widget* w = to; w; w = w->parent()) + if (w->type()>=FL_WINDOW) {dx -= w->x(); dy -= w->y();} + int save_x = Fl::e_x; Fl::e_x += dx; + int save_y = Fl::e_y; Fl::e_y += dy; + int ret = to->handle(Fl::e_number = event); + Fl::e_number = old_event; + Fl::e_y = save_y; + Fl::e_x = save_x; + return ret; +} + +int Fl::handle(int e, Fl_Window* window) +{ + e_number = e; + if (fl_local_grab) return fl_local_grab(e); + + Fl_Widget* wi = window; + + switch (e) { + + case FL_CLOSE: + if (grab() || modal() && window != modal()) return 0; + wi->do_callback(); + return 1; + + case FL_SHOW: + wi->show(); // this calls Fl_Widget::show(), not Fl_Window::show() + return 1; + + case FL_HIDE: + wi->hide(); // this calls Fl_Widget::hide(), not Fl_Window::hide() + return 1; + + case FL_PUSH: +#ifdef DEBUG + printf("Fl::handle(e=%d, window=%p);\n", e, window); +#endif // DEBUG + + if (grab()) wi = grab(); + else if (modal() && wi != modal()) return 0; + pushed_ = wi; + Fl_Tooltip::current(wi); + if (send(e, wi, window)) return 1; + // raise windows that are clicked on: + window->show(); + return 1; + + case FL_DND_ENTER: + case FL_DND_DRAG: + dnd_flag = 1; + break; + + case FL_DND_LEAVE: + dnd_flag = 1; + belowmouse(0); + dnd_flag = 0; + return 1; + + case FL_DND_RELEASE: + wi = belowmouse(); + break; + + case FL_MOVE: + case FL_DRAG: + fl_xmousewin = window; // this should already be set, but just in case. + if (pushed()) { + wi = pushed(); + if (grab()) wi = grab(); + e_number = e = FL_DRAG; + break; + } + if (modal() && wi != modal()) wi = 0; + if (grab()) wi = grab(); + {Fl_Widget* pbm = belowmouse(); + int ret = (wi && send(e, wi, window)); + if (pbm != belowmouse()) { +#ifdef DEBUG + printf("Fl::handle(e=%d, window=%p);\n", e, window); +#endif // DEBUG + Fl_Tooltip::enter(belowmouse()); + } + return ret;} + + case FL_RELEASE: { +// printf("FL_RELEASE: window=%p, pushed() = %p, grab() = %p, modal() = %p\n", +// window, pushed(), grab(), modal()); + + if (grab()) { + wi = grab(); + pushed_ = 0; // must be zero before callback is done! + } else if (pushed()) { + wi = pushed(); + pushed_ = 0; // must be zero before callback is done! + } else if (modal() && wi != modal()) return 0; + int r = send(e, wi, window); + fl_fix_focus(); + return r;} + + case FL_UNFOCUS: + window = 0; + case FL_FOCUS: + fl_xfocus = window; + fl_fix_focus(); + return 1; + + case FL_KEYUP: + // Send the key-up to the current focus. This is not + // always the same widget that received the corresponding + // FL_KEYBOARD event because focus may have changed. + // Sending the KEYUP to the right KEYDOWN is possible, but + // would require that we track the KEYDOWN for every possible + // key stroke (users may hold down multiple keys!) and then + // make sure that the widget still exists before sending + // a KEYUP there. I believe that the current solution is + // "close enough". + for (wi = grab() ? grab() : focus(); wi; wi = wi->parent()) + if (send(FL_KEYUP, wi, window)) return 1; + return 0; + + case FL_KEYBOARD: +#ifdef DEBUG + printf("Fl::handle(e=%d, window=%p);\n", e, window); +#endif // DEBUG + + Fl_Tooltip::enter((Fl_Widget*)0); + + fl_xfocus = window; // this should not happen! But maybe it does: + + // Try it as keystroke, sending it to focus and all parents: + for (wi = grab() ? grab() : focus(); wi; wi = wi->parent()) + if (send(FL_KEYBOARD, wi, window)) return 1; + + // recursive call to try shortcut: + if (handle(FL_SHORTCUT, window)) return 1; + + // and then try a shortcut with the case of the text swapped, by + // changing the text and falling through to FL_SHORTCUT case: + {unsigned char* c = (unsigned char*)event_text(); // cast away const + if (!isalpha(*c)) return 0; + *c = isupper(*c) ? tolower(*c) : toupper(*c);} + e_number = e = FL_SHORTCUT; + + case FL_SHORTCUT: + if (grab()) {wi = grab(); break;} // send it to grab window + + // Try it as shortcut, sending to mouse widget and all parents: + wi = belowmouse(); + if (!wi) { + wi = modal(); + if (!wi) wi = window; + } else if (wi->window() != first_window()) { + if (send(FL_SHORTCUT, first_window(), first_window())) return 1; + } + + for (; wi; wi = wi->parent()) { + if (send(FL_SHORTCUT, wi, wi->window())) return 1; + } + + // try using add_handle() functions: + if (send_handlers(FL_SHORTCUT)) return 1; + + // make Escape key close windows: + if (event_key()==FL_Escape) { + wi = modal(); if (!wi) wi = window; + wi->do_callback(); + return 1; + } + + return 0; + + case FL_ENTER: +#ifdef DEBUG + printf("Fl::handle(e=%d, window=%p);\n", e, window); +#endif // DEBUG + + fl_xmousewin = window; + fl_fix_focus(); + Fl_Tooltip::enter(belowmouse()); + return 1; + + case FL_LEAVE: +#ifdef DEBUG + printf("Fl::handle(e=%d, window=%p);\n", e, window); +#endif // DEBUG + + if (!pushed_) { + belowmouse(0); + Fl_Tooltip::enter(0); + } + if (window == fl_xmousewin) {fl_xmousewin = 0; fl_fix_focus();} + return 1; + + case FL_MOUSEWHEEL: + fl_xfocus = window; // this should not happen! But maybe it does: + + // Try sending it to the "grab" first + if (grab() && grab()!=modal() && grab()!=window) { + if (send(FL_MOUSEWHEEL, grab(), window)) return 1; + } + // Now try sending it to the "modal" window + if (modal()) { + send(FL_MOUSEWHEEL, modal(), window); + return 1; + } + // Finally try sending it to the window, the event occured in + if (send(FL_MOUSEWHEEL, window, window)) return 1; + default: + break; + } + if (wi && send(e, wi, window)) { + dnd_flag = 0; + return 1; + } + dnd_flag = 0; + return send_handlers(e); +} + +//////////////////////////////////////////////////////////////// +// hide() destroys the X window, it does not do unmap! + +#if !defined(WIN32) && USE_XFT +extern void fl_destroy_xft_draw(Window); +#endif + +void Fl_Window::hide() { + clear_visible(); + + if (!shown()) return; + + // remove from the list of windows: + Fl_X* ip = i; + Fl_X** pp = &Fl_X::first; + for (; *pp != ip; pp = &(*pp)->next) if (!*pp) return; + *pp = ip->next; +#ifdef __APPLE__ + MacUnlinkWindow(ip); + // MacOS X manages a single pointer per application. Make sure that hiding + // a toplevel window will not leave us with some random pointer shape, or + // worst case, an invisible pointer + if (!parent()) cursor(FL_CURSOR_DEFAULT); +#endif + i = 0; + + // recursively remove any subwindows: + for (Fl_X *wi = Fl_X::first; wi;) { + Fl_Window* W = wi->w; + if (W->window() == this) { + W->hide(); + W->set_visible(); + wi = Fl_X::first; + } else wi = wi->next; + } + + if (this == Fl::modal_) { // we are closing the modal window, find next one: + Fl_Window* W; + for (W = Fl::first_window(); W; W = Fl::next_window(W)) + if (W->modal()) break; + Fl::modal_ = W; + } + + // Make sure no events are sent to this window: + fl_throw_focus(this); + handle(FL_HIDE); + +#ifdef WIN32 + // this little trick keeps the current clipboard alive, even if we are about + // to destroy the window that owns the selection. + if (GetClipboardOwner()==ip->xid) { + Fl_Window *w1 = Fl::first_window(); + if (w1 && OpenClipboard(fl_xid(w1))) { + EmptyClipboard(); + SetClipboardData(CF_TEXT, NULL); + CloseClipboard(); + } + } + // Send a message to myself so that I'll get out of the event loop... + PostMessage(ip->xid, WM_APP, 0, 0); + if (ip->private_dc) fl_release_dc(ip->xid, ip->private_dc); + if (ip->xid == fl_window && fl_gc) { + fl_release_dc(fl_window, fl_gc); + fl_window = (HWND)-1; + fl_gc = 0; + } +#elif defined(__APPLE_QD__) + if ( ip->xid == fl_window && !parent() ) + fl_window = 0; +#elif defined(__APPLE_QUARTZ__) + Fl_X::q_release_context(ip); + if ( ip->xid == fl_window && !parent() ) + fl_window = 0; +#endif + + if (ip->region) XDestroyRegion(ip->region); + +#ifdef WIN32 + // this little trickery seems to avoid the popup window stacking problem + HWND p = GetForegroundWindow(); + if (p==GetParent(ip->xid)) { + ShowWindow(ip->xid, SW_HIDE); + ShowWindow(p, SW_SHOWNA); + } + XDestroyWindow(fl_display, ip->xid); +#elif defined(__APPLE_QD__) + MacDestroyWindow(this, ip->xid); +#elif defined(__APPLE_QUARTZ__) + MacDestroyWindow(this, ip->xid); +#else +# if USE_XFT + fl_destroy_xft_draw(ip->xid); +# endif + XDestroyWindow(fl_display, ip->xid); +#endif + +#ifdef WIN32 + // Try to stop the annoying "raise another program" behavior + if (non_modal() && Fl::first_window() && Fl::first_window()->shown()) + Fl::first_window()->show(); +#endif + delete ip; +} + +Fl_Window::~Fl_Window() { + hide(); +} + +// FL_SHOW and FL_HIDE are called whenever the visibility of this widget +// or any parent changes. We must correctly map/unmap the system's window. + +// For top-level windows it is assummed the window has already been +// mapped or unmapped!!! This is because this should only happen when +// Fl_Window::show() or Fl_Window::hide() is called, or in response to +// iconize/deiconize events from the system. + +int Fl_Window::handle(int ev) +{ + if (parent()) { + switch (ev) { + case FL_SHOW: + if (!shown()) show(); + else { +#ifdef __APPLE_QD__ + MacMapWindow(this, fl_xid(this)); +#elif defined(__APPLE_QUARTZ__) + MacMapWindow(this, fl_xid(this)); +#else + XMapWindow(fl_display, fl_xid(this)); // extra map calls are harmless +#endif // __APPLE__ + } + break; + case FL_HIDE: + if (shown()) { + // Find what really turned invisible, if is was a parent window + // we do nothing. We need to avoid unnecessary unmap calls + // because they cause the display to blink when the parent is + // remapped. However if this or any intermediate non-window + // widget has really had hide() called directly on it, we must + // unmap because when the parent window is remapped we don't + // want to reappear. + if (visible()) { + Fl_Widget* p = parent(); for (;p->visible();p = p->parent()) {} + if (p->type() >= FL_WINDOW) break; // don't do the unmap + } +#ifdef __APPLE_QD__ + MacUnmapWindow(this, fl_xid(this)); +#elif defined(__APPLE_QUARTZ__) + MacUnmapWindow(this, fl_xid(this)); +#else + XUnmapWindow(fl_display, fl_xid(this)); +#endif // __APPLE__ + } + break; + } +// } else if (ev == FL_FOCUS || ev == FL_UNFOCUS) { +// Fl_Tooltip::exit(Fl_Tooltip::current()); + } + + return Fl_Group::handle(ev); +} + +//////////////////////////////////////////////////////////////// +// Back compatability cut & paste functions for fltk 1.1 only: + +void Fl::selection_owner(Fl_Widget *owner) {selection_owner_ = owner;} + +void Fl::selection(Fl_Widget &owner, const char* text, int len) { + selection_owner_ = &owner; + Fl::copy(text, len, 0); +} + +void Fl::paste(Fl_Widget &receiver) { + Fl::paste(receiver, 0); +} + +//////////////////////////////////////////////////////////////// + +#include + +void Fl_Widget::redraw() { + damage(FL_DAMAGE_ALL); +} + +void Fl_Widget::redraw_label() { + if (window()) { + if (box() == FL_NO_BOX) { + // Widgets with the FL_NO_BOX boxtype need a parent to + // redraw, since it is responsible for redrawing the + // background... + int X = x() > 0 ? x() - 1 : 0; + int Y = y() > 0 ? y() - 1 : 0; + window()->damage(FL_DAMAGE_ALL, X, Y, w() + 2, h() + 2); + } + + if (align() && !(align() & FL_ALIGN_INSIDE) && window()->shown()) { + // If the label is not inside the widget, compute the location of + // the label and redraw the window within that bounding box... + int W = 0, H = 0; + label_.measure(W, H); + W += 5; // Add a little to the size of the label to cover overflow + H += 5; + + if (align() & FL_ALIGN_BOTTOM) { + window()->damage(FL_DAMAGE_EXPOSE, x(), y() + h(), w(), H); + } else if (align() & FL_ALIGN_TOP) { + window()->damage(FL_DAMAGE_EXPOSE, x(), y() - H, w(), H); + } else if (align() & FL_ALIGN_LEFT) { + window()->damage(FL_DAMAGE_EXPOSE, x() - W, y(), W, h()); + } else if (align() & FL_ALIGN_RIGHT) { + window()->damage(FL_DAMAGE_EXPOSE, x() + w(), y(), W, h()); + } else { + window()->damage(FL_DAMAGE_ALL); + } + } else { + // The label is inside the widget, so just redraw the widget itself... + damage(FL_DAMAGE_ALL); + } + } +} + +void Fl_Widget::damage(uchar fl) { + if (type() < FL_WINDOW) { + // damage only the rectangle covered by a child widget: + damage(fl, x(), y(), w(), h()); + } else { + // damage entire window by deleting the region: + Fl_X* i = Fl_X::i((Fl_Window*)this); + if (!i) return; // window not mapped, so ignore it + if (i->region) {XDestroyRegion(i->region); i->region = 0;} + damage_ |= fl; + Fl::damage(FL_DAMAGE_CHILD); + } +} + +void Fl_Widget::damage(uchar fl, int X, int Y, int W, int H) { + Fl_Widget* wi = this; + // mark all parent widgets between this and window with FL_DAMAGE_CHILD: + while (wi->type() < FL_WINDOW) { + wi->damage_ |= fl; + wi = wi->parent(); + if (!wi) return; + fl = FL_DAMAGE_CHILD; + } + Fl_X* i = Fl_X::i((Fl_Window*)wi); + if (!i) return; // window not mapped, so ignore it + + // clip the damage to the window and quit if none: + if (X < 0) {W += X; X = 0;} + if (Y < 0) {H += Y; Y = 0;} + if (W > wi->w()-X) W = wi->w()-X; + if (H > wi->h()-Y) H = wi->h()-Y; + if (W <= 0 || H <= 0) return; + + if (!X && !Y && W==wi->w() && H==wi->h()) { + // if damage covers entire window delete region: + wi->damage(fl); + return; + } + + if (wi->damage()) { + // if we already have damage we must merge with existing region: + if (i->region) { +#ifdef WIN32 + Fl_Region R = XRectangleRegion(X, Y, W, H); + CombineRgn(i->region, i->region, R, RGN_OR); + XDestroyRegion(R); +#elif defined(__APPLE_QD__) + Fl_Region R = NewRgn(); + SetRectRgn(R, X, Y, X+W, Y+H); + UnionRgn(R, i->region, i->region); + DisposeRgn(R); +#elif defined(__APPLE_QUARTZ__) + Fl_Region R = NewRgn(); + SetRectRgn(R, X, Y, X+W, Y+H); + UnionRgn(R, i->region, i->region); + DisposeRgn(R); +#else + XRectangle R; + R.x = X; R.y = Y; R.width = W; R.height = H; + XUnionRectWithRegion(&R, i->region, i->region); +#endif + } + wi->damage_ |= fl; + } else { + // create a new region: + if (i->region) XDestroyRegion(i->region); + i->region = XRectangleRegion(X,Y,W,H); + wi->damage_ = fl; + } + Fl::damage(FL_DAMAGE_CHILD); +} + +void Fl_Window::flush() { + make_current(); +//if (damage() == FL_DAMAGE_EXPOSE && can_boxcheat(box())) fl_boxcheat = this; + fl_clip_region(i->region); i->region = 0; + draw(); +} + +#ifdef WIN32 +# include "Fl_win32.cxx" +#elif defined(__APPLE__) +# include "Fl_mac.cxx" +#endif + +// +// The following methods allow callbacks to schedule the deletion of +// widgets at "safe" times. +// + +static int num_dwidgets = 0, alloc_dwidgets = 0; +static Fl_Widget **dwidgets = 0; + +void +Fl::delete_widget(Fl_Widget *wi) { + if (!wi) return; + + if (num_dwidgets >= alloc_dwidgets) { + Fl_Widget **temp; + + temp = new Fl_Widget *[alloc_dwidgets + 10]; + if (alloc_dwidgets) { + memcpy(temp, dwidgets, alloc_dwidgets * sizeof(Fl_Widget *)); + delete[] dwidgets; + } + + dwidgets = temp; + alloc_dwidgets += 10; + } + + dwidgets[num_dwidgets] = wi; + num_dwidgets ++; +} + + +void +Fl::do_widget_deletion() { + if (!num_dwidgets) return; + + for (int i = 0; i < num_dwidgets; i ++) + delete dwidgets[i]; + + num_dwidgets = 0; +} + +static Fl_Widget ***widget_watch = 0; +static int num_widget_watch = 0; +static int max_widget_watch = 0; + +void Fl::watch_widget_pointer(Fl_Widget *&w) +{ + Fl_Widget **wp = &w; + int i; + for (i=0; i +#include +#include +#include + +#include "fastarrow.h" +static Fl_Bitmap fastarrow(fastarrow_bits, fastarrow_width, fastarrow_height); +#include "mediumarrow.h" +static Fl_Bitmap mediumarrow(mediumarrow_bits, mediumarrow_width, mediumarrow_height); +#include "slowarrow.h" +static Fl_Bitmap slowarrow(slowarrow_bits, slowarrow_width, slowarrow_height); + +// changing the value does not change the appearance: +void Fl_Adjuster::value_damage() {} + +void Fl_Adjuster::draw() { + int dx, dy, W, H; + if (w()>=h()) { + dx = W = w()/3; + dy = 0; H = h(); + } else { + dx = 0; W = w(); + dy = H = h()/3; + } + draw_box(drag==1?FL_DOWN_BOX:box(), x(), y()+2*dy, W, H, color()); + draw_box(drag==2?FL_DOWN_BOX:box(), x()+dx, y()+dy, W, H, color()); + draw_box(drag==3?FL_DOWN_BOX:box(), x()+2*dx, y(), W, H, color()); + if (active_r()) + fl_color(selection_color()); + else + fl_color(fl_inactive(selection_color())); + fastarrow.draw(x()+(W-fastarrow_width)/2, + y()+2*dy+(H-fastarrow_height)/2, W, H); + mediumarrow.draw(x()+dx+(W-mediumarrow_width)/2, + y()+dy+(H-mediumarrow_height)/2, W, H); + slowarrow.draw(x()+2*dx+(W-slowarrow_width)/2, + y()+(H-slowarrow_width)/2, W, H); + if (Fl::focus() == this) draw_focus(); +} + +int Fl_Adjuster::handle(int event) { + double v; + int delta; + int mx = Fl::event_x(); + switch (event) { + case FL_PUSH: + if (Fl::visible_focus()) Fl::focus(this); + ix = mx; + if (w()>=h()) + drag = 3*(mx-x())/w() + 1; + else + drag = 3-3*(Fl::event_y()-y()-1)/h(); + handle_push(); + redraw(); + return 1; + case FL_DRAG: + if (w() >= h()) { + delta = x()+(drag-1)*w()/3; // left edge of button + if (mx < delta) + delta = mx-delta; + else if (mx > (delta+w()/3)) // right edge of button + delta = mx-delta-w()/3; + else + delta = 0; + } else { + if (mx < x()) + delta = mx-x(); + else if (mx > (x()+w())) + delta = mx-x()-w(); + else + delta = 0; + } + switch (drag) { + case 3: v = increment(previous_value(), delta); break; + case 2: v = increment(previous_value(), delta*10); break; + default:v = increment(previous_value(), delta*100); break; + } + handle_drag(soft() ? softclamp(v) : clamp(v)); + return 1; + case FL_RELEASE: + if (Fl::event_is_click()) { // detect click but no drag + if (Fl::event_state()&0xF0000) delta = -10; + else delta = 10; + switch (drag) { + case 3: v = increment(previous_value(), delta); break; + case 2: v = increment(previous_value(), delta*10); break; + default:v = increment(previous_value(), delta*100); break; + } + handle_drag(soft() ? softclamp(v) : clamp(v)); + } + drag = 0; + redraw(); + handle_release(); + return 1; + case FL_KEYBOARD : + switch (Fl::event_key()) { + case FL_Up: + if (w() > h()) return 0; + handle_drag(clamp(increment(value(),-1))); + return 1; + case FL_Down: + if (w() > h()) return 0; + handle_drag(clamp(increment(value(),1))); + return 1; + case FL_Left: + if (w() < h()) return 0; + handle_drag(clamp(increment(value(),-1))); + return 1; + case FL_Right: + if (w() < h()) return 0; + handle_drag(clamp(increment(value(),1))); + return 1; + default: + return 0; + } + // break not required because of switch... + + case FL_FOCUS: + case FL_UNFOCUS: + if (Fl::visible_focus()) { + redraw(); + return 1; + } else return 0; + + case FL_ENTER : + case FL_LEAVE : + return 1; + } + return 0; +} + +Fl_Adjuster::Fl_Adjuster(int X, int Y, int W, int H, const char* l) + : Fl_Valuator(X, Y, W, H, l) { + box(FL_UP_BOX); + step(1, 10000); + selection_color(FL_SELECTION_COLOR); + drag = 0; + soft_ = 1; +} + +// +// End of "$Id: Fl_Adjuster.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_BMP_Image.cxx b/third_party/windows/fltk-1.1.10/src/Fl_BMP_Image.cxx new file mode 100644 index 0000000..13537d3 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_BMP_Image.cxx @@ -0,0 +1,493 @@ +// +// "$Id: Fl_BMP_Image.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Fl_BMP_Image routines. +// +// Copyright 1997-2005 by Easy Software Products. +// Image support donated by Matthias Melcher, Copyright 2000. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_BMP_Image::Fl_BMP_Image() - Load a BMP image file. +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include + + +// +// BMP definitions... +// + +#ifndef BI_RGB +# define BI_RGB 0 // No compression - straight BGR data +# define BI_RLE8 1 // 8-bit run-length compression +# define BI_RLE4 2 // 4-bit run-length compression +# define BI_BITFIELDS 3 // RGB bitmap with RGB masks +#endif // !BI_RGB + + +// +// Local functions... +// + +static int read_long(FILE *fp); +static unsigned short read_word(FILE *fp); +static unsigned int read_dword(FILE *fp); + + +// +// 'Fl_BMP_Image::Fl_BMP_Image()' - Load a BMP image file. +// + +Fl_BMP_Image::Fl_BMP_Image(const char *bmp) // I - File to read + : Fl_RGB_Image(0,0,0) { + FILE *fp; // File pointer + int info_size, // Size of info header + depth, // Depth of image (bits) + bDepth = 3, // Depth of image (bytes) + compression, // Type of compression + colors_used, // Number of colors used + x, y, // Looping vars + color, // Color of RLE pixel + repcount, // Number of times to repeat + temp, // Temporary color + align, // Alignment bytes + dataSize, // number of bytes in image data set + row_order, // 1 = normal; -1 = flipped row order + start_y, // Beginning Y + end_y; // Ending Y + long offbits; // Offset to image data + uchar bit, // Bit in image + byte; // Byte in image + uchar *ptr; // Pointer into pixels + uchar colormap[256][3];// Colormap + uchar havemask; // Single bit mask follows image data + int use_5_6_5; // Use 5:6:5 for R:G:B channels in 16 bit images + + + // Open the file... + if ((fp = fopen(bmp, "rb")) == NULL) return; + + // Get the header... + byte = (uchar)getc(fp); // Check "BM" sync chars + bit = (uchar)getc(fp); + if (byte != 'B' || bit != 'M') { + fclose(fp); + return; + } + + read_dword(fp); // Skip size + read_word(fp); // Skip reserved stuff + read_word(fp); + offbits = (long)read_dword(fp);// Read offset to image data + + // Then the bitmap information... + info_size = read_dword(fp); + +// printf("offbits = %ld, info_size = %d\n", offbits, info_size); + + havemask = 0; + row_order = -1; + use_5_6_5 = 0; + + if (info_size < 40) { + // Old Windows/OS2 BMP header... + w(read_word(fp)); + h(read_word(fp)); + read_word(fp); + depth = read_word(fp); + compression = BI_RGB; + colors_used = 0; + + repcount = info_size - 12; + } else { + // New BMP header... + w(read_long(fp)); + // If the height is negative, the row order is flipped + temp = read_long(fp); + if (temp < 0) row_order = 1; + h(abs(temp)); + read_word(fp); + depth = read_word(fp); + compression = read_dword(fp); + dataSize = read_dword(fp); + read_long(fp); + read_long(fp); + colors_used = read_dword(fp); + read_dword(fp); + + repcount = info_size - 40; + + if (!compression && depth>=8 && w()>32/depth) { + int Bpp = depth/8; + int maskSize = (((w()*Bpp+3)&~3)*h()) + (((((w()+7)/8)+3)&~3)*h()); + if (maskSize==2*dataSize) { + havemask = 1; + h(h()/2); + bDepth = 4; + } + } + } + +// printf("w() = %d, h() = %d, depth = %d, compression = %d, colors_used = %d, repcount = %d\n", +// w(), h(), depth, compression, colors_used, repcount); + + // Skip remaining header bytes... + while (repcount > 0) { + getc(fp); + repcount --; + } + + // Check header data... + if (!w() || !h() || !depth) { + fclose(fp); + return; + } + + // Get colormap... + if (colors_used == 0 && depth <= 8) + colors_used = 1 << depth; + + for (repcount = 0; repcount < colors_used; repcount ++) { + // Read BGR color... + fread(colormap[repcount], 1, 3, fp); + + // Skip pad byte for new BMP files... + if (info_size > 12) getc(fp); + } + + // Read first dword of colormap. It tells us if 5:5:5 or 5:6:5 for 16 bit + if (depth == 16) + use_5_6_5 = (read_dword(fp) == 0xf800); + + // Set byte depth for RGBA images + if (depth == 32) + bDepth=4; + + // Setup image and buffers... + d(bDepth); + if (offbits) fseek(fp, offbits, SEEK_SET); + + array = new uchar[w() * h() * d()]; + alloc_array = 1; + + // Read the image data... + color = 0; + repcount = 0; + align = 0; + byte = 0; + temp = 0; + + if (row_order < 0) { + start_y = h() - 1; + end_y = -1; + } else { + start_y = 0; + end_y = h(); + } + + for (y = start_y; y != end_y; y += row_order) { + ptr = (uchar *)array + y * w() * d(); + + switch (depth) + { + case 1 : // Bitmap + for (x = w(), bit = 128; x > 0; x --) { + if (bit == 128) byte = (uchar)getc(fp); + + if (byte & bit) { + *ptr++ = colormap[1][2]; + *ptr++ = colormap[1][1]; + *ptr++ = colormap[1][0]; + } else { + *ptr++ = colormap[0][2]; + *ptr++ = colormap[0][1]; + *ptr++ = colormap[0][0]; + } + + if (bit > 1) + bit >>= 1; + else + bit = 128; + } + + // Read remaining bytes to align to 32 bits... + for (temp = (w() + 7) / 8; temp & 3; temp ++) { + getc(fp); + } + break; + + case 4 : // 16-color + for (x = w(), bit = 0xf0; x > 0; x --) { + // Get a new repcount as needed... + if (repcount == 0) { + if (compression != BI_RLE4) { + repcount = 2; + color = -1; + } else { + while (align > 0) { + align --; + getc(fp); + } + + if ((repcount = getc(fp)) == 0) { + if ((repcount = getc(fp)) == 0) { + // End of line... + x ++; + continue; + } else if (repcount == 1) { + // End of image... + break; + } else if (repcount == 2) { + // Delta... + repcount = getc(fp) * getc(fp) * w(); + color = 0; + } else { + // Absolute... + color = -1; + align = ((4 - (repcount & 3)) / 2) & 1; + } + } else { + color = getc(fp); + } + } + } + + // Get a new color as needed... + repcount --; + + // Extract the next pixel... + if (bit == 0xf0) { + // Get the next color byte as needed... + if (color < 0) temp = getc(fp); + else temp = color; + + // Copy the color value... + *ptr++ = colormap[(temp >> 4) & 15][2]; + *ptr++ = colormap[(temp >> 4) & 15][1]; + *ptr++ = colormap[(temp >> 4) & 15][0]; + + bit = 0x0f; + } else { + bit = 0xf0; + + // Copy the color value... + *ptr++ = colormap[temp & 15][2]; + *ptr++ = colormap[temp & 15][1]; + *ptr++ = colormap[temp & 15][0]; + } + + } + + if (!compression) { + // Read remaining bytes to align to 32 bits... + for (temp = (w() + 1) / 2; temp & 3; temp ++) { + getc(fp); + } + } + break; + + case 8 : // 256-color + for (x = w(); x > 0; x --) { + // Get a new repcount as needed... + if (compression != BI_RLE8) { + repcount = 1; + color = -1; + } + + if (repcount == 0) { + while (align > 0) { + align --; + getc(fp); + } + + if ((repcount = getc(fp)) == 0) { + if ((repcount = getc(fp)) == 0) { + // End of line... + x ++; + continue; + } else if (repcount == 1) { + // End of image... + break; + } else if (repcount == 2) { + // Delta... + repcount = getc(fp) * getc(fp) * w(); + color = 0; + } else { + // Absolute... + color = -1; + align = (2 - (repcount & 1)) & 1; + } + } else { + color = getc(fp); + } + } + + // Get a new color as needed... + if (color < 0) temp = getc(fp); + else temp = color; + + repcount --; + + // Copy the color value... + *ptr++ = colormap[temp][2]; + *ptr++ = colormap[temp][1]; + *ptr++ = colormap[temp][0]; + if (havemask) ptr++; + } + + if (!compression) { + // Read remaining bytes to align to 32 bits... + for (temp = w(); temp & 3; temp ++) { + getc(fp); + } + } + break; + + case 16 : // 16-bit 5:5:5 or 5:6:5 RGB + for (x = w(); x > 0; x --, ptr += bDepth) { + uchar b = getc(fp), a = getc(fp) ; + if (use_5_6_5) { + ptr[2] = (uchar)(( b << 3 ) & 0xf8); + ptr[1] = (uchar)(((a << 5) & 0xe0) | ((b >> 3) & 0x1c)); + ptr[0] = (uchar)(a & 0xf8); + } else { + ptr[2] = (uchar)((b << 3) & 0xf8); + ptr[1] = (uchar)(((a << 6) & 0xc0) | ((b >> 2) & 0x38)); + ptr[0] = (uchar)((a<<1) & 0xf8); + } + } + + // Read remaining bytes to align to 32 bits... + for (temp = w() * 2; temp & 3; temp ++) { + getc(fp); + } + break; + + case 24 : // 24-bit RGB + for (x = w(); x > 0; x --, ptr += bDepth) { + ptr[2] = (uchar)getc(fp); + ptr[1] = (uchar)getc(fp); + ptr[0] = (uchar)getc(fp); + } + + // Read remaining bytes to align to 32 bits... + for (temp = w() * 3; temp & 3; temp ++) { + getc(fp); + } + break; + + case 32 : // 32-bit RGBA + for (x = w(); x > 0; x --, ptr += bDepth) { + ptr[2] = (uchar)getc(fp); + ptr[1] = (uchar)getc(fp); + ptr[0] = (uchar)getc(fp); + ptr[3] = (uchar)getc(fp); + } + break; + } + } + + if (havemask) { + for (y = h() - 1; y >= 0; y --) { + ptr = (uchar *)array + y * w() * d() + 3; + for (x = w(), bit = 128; x > 0; x --, ptr+=bDepth) { + if (bit == 128) byte = (uchar)getc(fp); + if (byte & bit) + *ptr = 0; + else + *ptr = 255; + if (bit > 1) + bit >>= 1; + else + bit = 128; + } + // Read remaining bytes to align to 32 bits... + for (temp = (w() + 7) / 8; temp & 3; temp ++) + getc(fp); + } + } + + // Close the file and return... + fclose(fp); +} + + +// +// 'read_word()' - Read a 16-bit unsigned integer. +// + +static unsigned short // O - 16-bit unsigned integer +read_word(FILE *fp) { // I - File to read from + unsigned char b0, b1; // Bytes from file + + b0 = (uchar)getc(fp); + b1 = (uchar)getc(fp); + + return ((b1 << 8) | b0); +} + + +// +// 'read_dword()' - Read a 32-bit unsigned integer. +// + +static unsigned int // O - 32-bit unsigned integer +read_dword(FILE *fp) { // I - File to read from + unsigned char b0, b1, b2, b3; // Bytes from file + + b0 = (uchar)getc(fp); + b1 = (uchar)getc(fp); + b2 = (uchar)getc(fp); + b3 = (uchar)getc(fp); + + return ((((((b3 << 8) | b2) << 8) | b1) << 8) | b0); +} + + +// +// 'read_long()' - Read a 32-bit signed integer. +// + +static int // O - 32-bit signed integer +read_long(FILE *fp) { // I - File to read from + unsigned char b0, b1, b2, b3; // Bytes from file + + b0 = (uchar)getc(fp); + b1 = (uchar)getc(fp); + b2 = (uchar)getc(fp); + b3 = (uchar)getc(fp); + + return ((int)(((((b3 << 8) | b2) << 8) | b1) << 8) | b0); +} + + +// +// End of "$Id: Fl_BMP_Image.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Bitmap.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Bitmap.cxx new file mode 100644 index 0000000..09a67cb --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Bitmap.cxx @@ -0,0 +1,518 @@ +// +// "$Id: Fl_Bitmap.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Bitmap drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include +#include +#include "flstring.h" + +#ifdef __APPLE_QD__ // MacOS bitmask functions +Fl_Bitmask fl_create_bitmask(int w, int h, const uchar *array) { + Rect srcRect; + srcRect.left = 0; srcRect.right = w; + srcRect.top = 0; srcRect.bottom = h; + GrafPtr savePort; + + GetPort(&savePort); // remember the current port + + Fl_Bitmask gw; + NewGWorld( &gw, 1, &srcRect, 0L, 0L, 0 ); + PixMapHandle pm = GetGWorldPixMap( gw ); + if ( pm ) + { + LockPixels( pm ); + if ( *pm ) + { + uchar *base = (uchar*)GetPixBaseAddr( pm ); + if ( base ) + { + PixMapPtr pmp = *pm; + // verify the parameters for direct memory write + if ( pmp->pixelType == 0 || pmp->pixelSize == 1 || pmp->cmpCount == 1 || pmp->cmpSize == 1 ) + { + static uchar reverse[16] = /* Bit reversal lookup table */ + { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee, 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff }; + uchar *dst = base; + const uchar *src = array; + int rowBytesSrc = (w+7)>>3 ; + int rowPatch = (pmp->rowBytes&0x3fff) - rowBytesSrc; + for ( int j=0; j> 4) & 0x0f] & 0x0f); + } + } + UnlockPixels( pm ); + } + } + + SetPort(savePort); + return gw; /* tell caller we succeeded! */ +} + +void fl_delete_bitmask(Fl_Bitmask id) { + if (id) DisposeGWorld(id); +} +#elif defined(__APPLE_QUARTZ__) +Fl_Bitmask fl_create_bitmask(int w, int h, const uchar *array) { + static uchar reverse[16] = /* Bit reversal lookup table */ + { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee, + 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff }; + int rowBytes = (w+7)>>3 ; + uchar *bmask = (uchar*)malloc(rowBytes*h), *dst = bmask; + const uchar *src = array; + for ( int i=rowBytes*h; i>0; i--,src++ ) { + *dst++ = ((reverse[*src & 0x0f] & 0xf0) | (reverse[(*src >> 4) & 0x0f] & 0x0f))^0xff; + } + CGDataProviderRef srcp = CGDataProviderCreateWithData( 0L, bmask, rowBytes*h, 0L); + CGImageRef id = CGImageMaskCreate( w, h, 1, 1, rowBytes, srcp, 0L, false); + CGDataProviderRelease(srcp); + return (Fl_Bitmask)id; +} +void fl_delete_bitmask(Fl_Bitmask id) { + if (id) CGImageRelease((CGImageRef)id); +} +#elif defined(WIN32) // Windows bitmask functions... +// 'fl_create_bitmap()' - Create a 1-bit bitmap for drawing... +static Fl_Bitmask fl_create_bitmap(int w, int h, const uchar *data) { + // we need to pad the lines out to words & swap the bits + // in each byte. + int w1 = (w+7)/8; + int w2 = ((w+15)/16)*2; + uchar* newarray = new uchar[w2*h]; + const uchar* src = data; + uchar* dest = newarray; + Fl_Bitmask id; + static uchar reverse[16] = /* Bit reversal lookup table */ + { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee, + 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff }; + + for (int y=0; y < h; y++) { + for (int n = 0; n < w1; n++, src++) + *dest++ = (uchar)((reverse[*src & 0x0f] & 0xf0) | + (reverse[(*src >> 4) & 0x0f] & 0x0f)); + dest += w2-w1; + } + + id = CreateBitmap(w, h, 1, 1, newarray); + + delete[] newarray; + + return id; +} + +// 'fl_create_bitmask()' - Create an N-bit bitmap for masking... +Fl_Bitmask fl_create_bitmask(int w, int h, const uchar *data) { + // this won't work when the user changes display mode during run or + // has two screens with differnet depths + Fl_Bitmask id; + static uchar hiNibble[16] = + { 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, + 0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0 }; + static uchar loNibble[16] = + { 0x00, 0x08, 0x04, 0x0c, 0x02, 0x0a, 0x06, 0x0e, + 0x01, 0x09, 0x05, 0x0d, 0x03, 0x0b, 0x07, 0x0f }; + int np = GetDeviceCaps(fl_gc, PLANES); //: was always one on sample machines + int bpp = GetDeviceCaps(fl_gc, BITSPIXEL);//: 1,4,8,16,24,32 and more odd stuff? + int Bpr = (bpp*w+7)/8; //: bytes per row + int pad = Bpr&1, w1 = (w+7)/8, shr = ((w-1)&7)+1; + if (bpp==4) shr = (shr+1)/2; + uchar *newarray = new uchar[(Bpr+pad)*h]; + uchar *dst = newarray; + const uchar *src = data; + + for (int i=0; i0; j--) { + uchar b = *src++; + if (bpp==1) { + *dst++ = (uchar)( hiNibble[b&15] ) | ( loNibble[(b>>4)&15] ); + } else if (bpp==4) { + for (int k=(j==1)?shr:4; k>0; k--) { + *dst++ = (uchar)("\377\360\017\000"[b&3]); + b = b >> 2; + } + } else { + for (int k=(j==1)?shr:8; k>0; k--) { + if (b&1) { + *dst++=0; + if (bpp>8) *dst++=0; + if (bpp>16) *dst++=0; + if (bpp>24) *dst++=0; + } else { + *dst++=0xff; + if (bpp>8) *dst++=0xff; + if (bpp>16) *dst++=0xff; + if (bpp>24) *dst++=0xff; + } + + b = b >> 1; + } + } + } + + dst += pad; + } + + id = CreateBitmap(w, h, np, bpp, newarray); + delete[] newarray; + + return id; +} + +#if 0 // This doesn't appear to be used anywhere... +Fl_Bitmask fl_create_bitmask(int w, int h, const uchar *data, int for_mask) { + // we need to pad the lines out to words & swap the bits + // in each byte. + int w1 = (w+7)/8; + int w2 = ((w+15)/16)*2; + uchar* newarray = new uchar[w2*h]; + const uchar* src = data; + uchar* dest = newarray; + Fl_Bitmask id; + static uchar reverse[16] = /* Bit reversal lookup table */ + { 0x00, 0x88, 0x44, 0xcc, 0x22, 0xaa, 0x66, 0xee, + 0x11, 0x99, 0x55, 0xdd, 0x33, 0xbb, 0x77, 0xff }; + + for (int y=0; y < h; y++) { + for (int n = 0; n < w1; n++, src++) + *dest++ = (reverse[*src & 0x0f] & 0xf0) | + (reverse[(*src >> 4) & 0x0f] & 0x0f); + dest += w2-w1; + } + + id = CreateBitmap(w, h, 1, 1, newarray); + + delete[] newarray; + + return (id); +} +# endif // 0 + +void fl_delete_bitmask(Fl_Bitmask bm) { + DeleteObject((HGDIOBJ)bm); +} +#else // X11 bitmask functions +Fl_Bitmask fl_create_bitmask(int w, int h, const uchar *data) { + return XCreateBitmapFromData(fl_display, fl_window, (const char *)data, + (w+7)&-8, h); +} + +void fl_delete_bitmask(Fl_Bitmask bm) { + fl_delete_offscreen((Fl_Offscreen)bm); +} +#endif // __APPLE__ + + +// MRS: Currently it appears that CopyDeepMask() does not work with an 8-bit alpha mask. +// If you want to test/fix this, uncomment the "#ifdef __APPLE__" and comment out +// the "#if 0" here. Also see Fl_Image.cxx for a similar check... + +//#ifdef __APPLE_QD__ +#if 0 +// Create an 8-bit mask used for alpha blending +Fl_Bitmask fl_create_alphamask(int w, int h, int d, int ld, const uchar *array) { + Rect srcRect; + srcRect.left = 0; srcRect.right = w; + srcRect.top = 0; srcRect.bottom = h; + GrafPtr savePort; + + GetPort(&savePort); // remember the current port + + Fl_Bitmask gw; + NewGWorld( &gw, 8, &srcRect, 0L, 0L, 0 ); + PixMapHandle pm = GetGWorldPixMap( gw ); + if ( pm ) + { + LockPixels( pm ); + if ( *pm ) + { + uchar *base = (uchar*)GetPixBaseAddr( pm ); + if ( base ) + { + PixMapPtr pmp = *pm; + // verify the parameters for direct memory write + if ( pmp->pixelType == 0 || pmp->pixelSize == 8 || pmp->cmpCount == 1 || pmp->cmpSize == 8 ) + { + // Copy alpha values from the source array to the pixmap... + array += d - 1; + int rowoffset = (pmp->rowBytes & 0x3fff) - w; + for (int y = h; y > 0; y --, array += ld, base += rowoffset) { + for (int x = w; x > 0; x --, array += d) { + *base++ = 255 /*255 - *array*/; + } + } + } + } + UnlockPixels( pm ); + } + } + + SetPort(savePort); + return gw; /* tell caller we succeeded! */ +} +#else +// Create a 1-bit mask used for alpha blending +Fl_Bitmask fl_create_alphamask(int w, int h, int d, int ld, const uchar *array) { + Fl_Bitmask mask; + int bmw = (w + 7) / 8; + uchar *bitmap = new uchar[bmw * h]; + uchar *bitptr, bit; + const uchar *dataptr; + int x, y; + static uchar dither[16][16] = { // Simple 16x16 Floyd dither + { 0, 128, 32, 160, 8, 136, 40, 168, + 2, 130, 34, 162, 10, 138, 42, 170 }, + { 192, 64, 224, 96, 200, 72, 232, 104, + 194, 66, 226, 98, 202, 74, 234, 106 }, + { 48, 176, 16, 144, 56, 184, 24, 152, + 50, 178, 18, 146, 58, 186, 26, 154 }, + { 240, 112, 208, 80, 248, 120, 216, 88, + 242, 114, 210, 82, 250, 122, 218, 90 }, + { 12, 140, 44, 172, 4, 132, 36, 164, + 14, 142, 46, 174, 6, 134, 38, 166 }, + { 204, 76, 236, 108, 196, 68, 228, 100, + 206, 78, 238, 110, 198, 70, 230, 102 }, + { 60, 188, 28, 156, 52, 180, 20, 148, + 62, 190, 30, 158, 54, 182, 22, 150 }, + { 252, 124, 220, 92, 244, 116, 212, 84, + 254, 126, 222, 94, 246, 118, 214, 86 }, + { 3, 131, 35, 163, 11, 139, 43, 171, + 1, 129, 33, 161, 9, 137, 41, 169 }, + { 195, 67, 227, 99, 203, 75, 235, 107, + 193, 65, 225, 97, 201, 73, 233, 105 }, + { 51, 179, 19, 147, 59, 187, 27, 155, + 49, 177, 17, 145, 57, 185, 25, 153 }, + { 243, 115, 211, 83, 251, 123, 219, 91, + 241, 113, 209, 81, 249, 121, 217, 89 }, + { 15, 143, 47, 175, 7, 135, 39, 167, + 13, 141, 45, 173, 5, 133, 37, 165 }, + { 207, 79, 239, 111, 199, 71, 231, 103, + 205, 77, 237, 109, 197, 69, 229, 101 }, + { 63, 191, 31, 159, 55, 183, 23, 151, + 61, 189, 29, 157, 53, 181, 21, 149 }, + { 254, 127, 223, 95, 247, 119, 215, 87, + 253, 125, 221, 93, 245, 117, 213, 85 } + }; + + // Generate a 1-bit "screen door" alpha mask; not always pretty, but + // definitely fast... In the future we may be able to support things + // like the RENDER extension in XFree86, when available, to provide + // true RGBA-blended rendering. See: + // + // http://www.xfree86.org/~keithp/render/protocol.html + // + // for more info on XRender... + // + // MacOS already provides alpha blending support and has its own + // fl_create_alphamask() function... + memset(bitmap, 0, bmw * h); + + for (dataptr = array + d - 1, y = 0; y < h; y ++, dataptr += ld) + for (bitptr = bitmap + y * bmw, bit = 1, x = 0; x < w; x ++, dataptr += d) { + if (*dataptr > dither[x & 15][y & 15]) + *bitptr |= bit; + if (bit < 128) bit <<= 1; + else { + bit = 1; + bitptr ++; + } + } + + mask = fl_create_bitmask(w, h, bitmap); + delete[] bitmap; + + return (mask); +} +#endif // __APPLE__ + +void Fl_Bitmap::draw(int XP, int YP, int WP, int HP, int cx, int cy) { + if (!array) { + draw_empty(XP, YP); + return; + } + + // account for current clip region (faster on Irix): + int X,Y,W,H; fl_clip_box(XP,YP,WP,HP,X,Y,W,H); + cx += X-XP; cy += Y-YP; + // clip the box down to the size of image, quit if empty: + if (cx < 0) {W += cx; X -= cx; cx = 0;} + if ((cx+W) > w()) W = w()-cx; + if (W <= 0) return; + if (cy < 0) {H += cy; Y -= cy; cy = 0;} + if ((cy+H) > h()) H = h()-cy; + if (H <= 0) return; +#ifdef WIN32 + if (!id) id = fl_create_bitmap(w(), h(), array); + + HDC tempdc = CreateCompatibleDC(fl_gc); + int save = SaveDC(tempdc); + SelectObject(tempdc, (HGDIOBJ)id); + SelectObject(fl_gc, fl_brush()); + // secret bitblt code found in old MSWindows reference manual: + BitBlt(fl_gc, X, Y, W, H, tempdc, cx, cy, 0xE20746L); + RestoreDC(tempdc, save); + DeleteDC(tempdc); +#elif defined(__APPLE_QD__) + if (!id) id = fl_create_bitmask(w(), h(), array); + GrafPtr dstPort; + GetPort( &dstPort ); + Rect src, dst; + GetPortBounds( (Fl_Offscreen)id, &src ); + SetRect( &src, cx, cy, cx+W, cy+H ); + SetRect( &dst, X, Y, X+W, Y+H ); + CopyBits(GetPortBitMapForCopyBits((Fl_Offscreen)id), // srcBits + GetPortBitMapForCopyBits(dstPort), // dstBits + &src, // src bounds + &dst, // dst bounds + srcOr, // mode + 0L); // mask region +#elif defined(__APPLE_QUARTZ__) + if (!id) id = fl_create_bitmask(w(), h(), array); + if (id && fl_gc) { + CGRect rect = { { X, Y }, { W, H } }; + Fl_X::q_begin_image(rect, cx, cy, w(), h()); + CGContextDrawImage(fl_gc, rect, (CGImageRef)id); + Fl_X::q_end_image(); + } +#else + if (!id) id = fl_create_bitmask(w(), h(), array); + + XSetStipple(fl_display, fl_gc, id); + int ox = X-cx; if (ox < 0) ox += w(); + int oy = Y-cy; if (oy < 0) oy += h(); + XSetTSOrigin(fl_display, fl_gc, ox, oy); + XSetFillStyle(fl_display, fl_gc, FillStippled); + XFillRectangle(fl_display, fl_window, fl_gc, X, Y, W, H); + XSetFillStyle(fl_display, fl_gc, FillSolid); +#endif +} + +Fl_Bitmap::~Fl_Bitmap() { + uncache(); + if (alloc_array) delete[] (uchar *)array; +} + +void Fl_Bitmap::uncache() { + if (id) { + fl_delete_bitmask((Fl_Offscreen)id); + id = 0; + } +} + +void Fl_Bitmap::label(Fl_Widget* widget) { + widget->image(this); +} + +void Fl_Bitmap::label(Fl_Menu_Item* m) { + Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, measure); + m->label(_FL_IMAGE_LABEL, (const char*)this); +} + +Fl_Image *Fl_Bitmap::copy(int W, int H) { + Fl_Bitmap *new_image; // New RGB image + uchar *new_array; // New array for image data + + // Optimize the simple copy where the width and height are the same... + if (W == w() && H == h()) { + new_array = new uchar [H * ((W + 7) / 8)]; + memcpy(new_array, array, H * ((W + 7) / 8)); + + new_image = new Fl_Bitmap(new_array, W, H); + new_image->alloc_array = 1; + + return new_image; + } + if (W <= 0 || H <= 0) return 0; + + // OK, need to resize the image data; allocate memory and + uchar *new_ptr, // Pointer into new array + new_bit, // Bit for new array + old_bit; // Bit for old array + const uchar *old_ptr; // Pointer into old array + int sx, sy, // Source coordinates + dx, dy, // Destination coordinates + xerr, yerr, // X & Y errors + xmod, ymod, // X & Y moduli + xstep, ystep; // X & Y step increments + + + // Figure out Bresenheim step/modulus values... + xmod = w() % W; + xstep = w() / W; + ymod = h() % H; + ystep = h() / H; + + // Allocate memory for the new image... + new_array = new uchar [H * ((W + 7) / 8)]; + new_image = new Fl_Bitmap(new_array, W, H); + new_image->alloc_array = 1; + + memset(new_array, 0, H * ((W + 7) / 8)); + + // Scale the image using a nearest-neighbor algorithm... + for (dy = H, sy = 0, yerr = H, new_ptr = new_array; dy > 0; dy --) { + for (dx = W, xerr = W, old_ptr = array + sy * ((w() + 7) / 8), sx = 0, new_bit = 1; + dx > 0; + dx --) { + old_bit = (uchar)(1 << (sx & 7)); + if (old_ptr[sx / 8] & old_bit) *new_ptr |= new_bit; + + if (new_bit < 128) new_bit <<= 1; + else { + new_bit = 1; + new_ptr ++; + } + + sx += xstep; + xerr -= xmod; + + if (xerr <= 0) { + xerr += W; + sx ++; + } + } + + if (new_bit > 1) new_ptr ++; + + sy += ystep; + yerr -= ymod; + if (yerr <= 0) { + yerr += H; + sy ++; + } + } + + return new_image; +} + + +// +// End of "$Id: Fl_Bitmap.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Box.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Box.cxx new file mode 100644 index 0000000..bc44d08 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Box.cxx @@ -0,0 +1,44 @@ +// +// "$Id: Fl_Box.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Box widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include + +void Fl_Box::draw() { + draw_box(); + draw_label(); +} + +int Fl_Box::handle(int event) { + if (event == FL_ENTER || event == FL_LEAVE) return 1; + else return 0; +} + + +// +// End of "$Id: Fl_Box.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Browser.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Browser.cxx new file mode 100644 index 0000000..e31c6e0 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Browser.cxx @@ -0,0 +1,551 @@ +// +// "$Id: Fl_Browser.cxx 5987 2007-11-20 21:57:17Z mike $" +// +// Browser widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2007 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include "flstring.h" +#include +#include + +// I modified this from the original Forms data to use a linked list +// so that the number of items in the browser and size of those items +// is unlimited. The only problem is that the old browser used an +// index number to identify a line, and it is slow to convert from/to +// a pointer. I use a cache of the last match to try to speed this +// up. + +// Also added the ability to "hide" a line. This set's it's height to +// zero, so the Fl_Browser_ cannot pick it. + +#define SELECTED 1 +#define NOTDISPLAYED 2 + +struct FL_BLINE { // data is in a linked list of these + FL_BLINE* prev; + FL_BLINE* next; + void* data; + short length; // sizeof(txt)-1, may be longer than string + char flags; // selected, displayed + char txt[1]; // start of allocated array +}; + +void* Fl_Browser::item_first() const {return first;} + +void* Fl_Browser::item_next(void* l) const {return ((FL_BLINE*)l)->next;} + +void* Fl_Browser::item_prev(void* l) const {return ((FL_BLINE*)l)->prev;} + +int Fl_Browser::item_selected(void* l) const { + return ((FL_BLINE*)l)->flags&SELECTED;} + +void Fl_Browser::item_select(void* l, int v) { + if (v) ((FL_BLINE*)l)->flags |= SELECTED; + else ((FL_BLINE*)l)->flags &= ~SELECTED; +} + +FL_BLINE* Fl_Browser::find_line(int line) const { + int n; FL_BLINE* l; + if (line == cacheline) return cache; + if (cacheline && line > (cacheline/2) && line < ((cacheline+lines)/2)) { + n = cacheline; l = cache; + } else if (line <= (lines/2)) { + n = 1; l = first; + } else { + n = lines; l = last; + } + for (; n < line && l; n++) l = l->next; + for (; n > line && l; n--) l = l->prev; + ((Fl_Browser*)this)->cacheline = line; + ((Fl_Browser*)this)->cache = l; + return l; +} + +int Fl_Browser::lineno(void* v) const { + FL_BLINE* l = (FL_BLINE*)v; + if (!l) return 0; + if (l == cache) return cacheline; + if (l == first) return 1; + if (l == last) return lines; + if (!cache) { + ((Fl_Browser*)this)->cache = first; + ((Fl_Browser*)this)->cacheline = 1; + } + // assumme it is near cache, search both directions: + FL_BLINE* b = cache->prev; + int bnum = cacheline-1; + FL_BLINE* f = cache->next; + int fnum = cacheline+1; + int n = 0; + for (;;) { + if (b == l) {n = bnum; break;} + if (f == l) {n = fnum; break;} + if (b) {b = b->prev; bnum--;} + if (f) {f = f->next; fnum++;} + } + ((Fl_Browser*)this)->cache = l; + ((Fl_Browser*)this)->cacheline = n; + return n; +} + +FL_BLINE* Fl_Browser::_remove(int line) { + FL_BLINE* ttt = find_line(line); + deleting(ttt); + + cacheline = line-1; + cache = ttt->prev; + lines--; + full_height_ -= item_height(ttt); + if (ttt->prev) ttt->prev->next = ttt->next; + else first = ttt->next; + if (ttt->next) ttt->next->prev = ttt->prev; + else last = ttt->prev; + + return(ttt); +} + +void Fl_Browser::remove(int line) { + if (line < 1 || line > lines) return; + free(_remove(line)); +} + +void Fl_Browser::insert(int line, FL_BLINE* t) { + if (!first) { + t->prev = t->next = 0; + first = last = t; + } else if (line <= 1) { + inserting(first, t); + t->prev = 0; + t->next = first; + t->next->prev = t; + first = t; + } else if (line > lines) { + t->prev = last; + t->prev->next = t; + t->next = 0; + last = t; + } else { + FL_BLINE* n = find_line(line); + inserting(n, t); + t->next = n; + t->prev = n->prev; + t->prev->next = t; + n->prev = t; + } + cacheline = line; + cache = t; + lines++; + full_height_ += item_height(t); + redraw_line(t); +} + +void Fl_Browser::insert(int line, const char* newtext, void* d) { + int l = strlen(newtext); + FL_BLINE* t = (FL_BLINE*)malloc(sizeof(FL_BLINE)+l); + t->length = (short)l; + t->flags = 0; + strcpy(t->txt, newtext); + t->data = d; + insert(line, t); +} + +void Fl_Browser::move(int to, int from) { + if (from < 1 || from > lines) return; + insert(to, _remove(from)); +} + +void Fl_Browser::text(int line, const char* newtext) { + if (line < 1 || line > lines) return; + FL_BLINE* t = find_line(line); + int l = strlen(newtext); + if (l > t->length) { + FL_BLINE* n = (FL_BLINE*)malloc(sizeof(FL_BLINE)+l); + replacing(t, n); + cache = n; + n->data = t->data; + n->length = (short)l; + n->flags = t->flags; + n->prev = t->prev; + if (n->prev) n->prev->next = n; else first = n; + n->next = t->next; + if (n->next) n->next->prev = n; else last = n; + free(t); + t = n; + } + strcpy(t->txt, newtext); + redraw_line(t); +} + +void Fl_Browser::data(int line, void* d) { + if (line < 1 || line > lines) return; + find_line(line)->data = d; +} + +int Fl_Browser::item_height(void* lv) const { + FL_BLINE* l = (FL_BLINE*)lv; + if (l->flags & NOTDISPLAYED) return 0; + + int hmax = 2; // use 2 to insure we don't return a zero! + + if (!l->txt[0]) { + // For blank lines set the height to exactly 1 line! + fl_font(textfont(), textsize()); + int hh = fl_height(); + if (hh > hmax) hmax = hh; + } + else { + const int* i = column_widths(); + // do each column separately as they may all set different fonts: + for (char* str = l->txt; str && *str; str++) { + Fl_Font font = textfont(); // default font + int tsize = textsize(); // default size + while (*str==format_char()) { + str++; + switch (*str++) { + case 'l': case 'L': tsize = 24; break; + case 'm': case 'M': tsize = 18; break; + case 's': tsize = 11; break; + case 'b': font = (Fl_Font)(font|FL_BOLD); break; + case 'i': font = (Fl_Font)(font|FL_ITALIC); break; + case 'f': case 't': font = FL_COURIER; break; + case 'B': + case 'C': strtol(str, &str, 10); break;// skip a color number + case 'F': font = (Fl_Font)strtol(str,&str,10); break; + case 'S': tsize = strtol(str,&str,10); break; + case 0: case '@': str--; + case '.': goto END_FORMAT; + } + } + END_FORMAT: + char* ptr = str; + if (ptr && *i++) str = strchr(str, column_char()); + else str = NULL; + if((!str && *ptr) || (str && ptr < str)) { + fl_font(font, tsize); int hh = fl_height(); + if (hh > hmax) hmax = hh; + } + if (!str || !*str) break; + } + } + + return hmax; // previous version returned hmax+2! +} + +int Fl_Browser::item_width(void* v) const { + char* str = ((FL_BLINE*)v)->txt; + const int* i = column_widths(); + int ww = 0; + + while (*i) { // add up all tab-seperated fields + char* e; + e = strchr(str, column_char()); + if (!e) break; // last one occupied by text + str = e+1; + ww += *i++; + } + + // OK, we gotta parse the string and find the string width... + int tsize = textsize(); + Fl_Font font = textfont(); + int done = 0; + + while (*str == format_char_ && str[1] && str[1] != format_char_) { + str ++; + switch (*str++) { + case 'l': case 'L': tsize = 24; break; + case 'm': case 'M': tsize = 18; break; + case 's': tsize = 11; break; + case 'b': font = (Fl_Font)(font|FL_BOLD); break; + case 'i': font = (Fl_Font)(font|FL_ITALIC); break; + case 'f': case 't': font = FL_COURIER; break; + case 'B': + case 'C': strtol(str, &str, 10); break;// skip a color number + case 'F': font = (Fl_Font)strtol(str, &str, 10); break; + case 'S': tsize = strtol(str, &str, 10); break; + case '.': + done = 1; + break; + case '@': + str--; + done = 1; + } + + if (done) + break; + } + + if (*str == format_char_ && str[1]) + str ++; + + fl_font(font, tsize); + return ww + int(fl_width(str)) + 6; +} + +int Fl_Browser::full_height() const { + return full_height_; +} + +int Fl_Browser::incr_height() const { + return textsize()+2; +} + +void Fl_Browser::item_draw(void* v, int X, int Y, int W, int H) const { + char* str = ((FL_BLINE*)v)->txt; + const int* i = column_widths(); + + while (W > 6) { // do each tab-seperated field + int w1 = W; // width for this field + char* e = 0; // pointer to end of field or null if none + if (*i) { // find end of field and temporarily replace with 0 + e = strchr(str, column_char()); + if (e) {*e = 0; w1 = *i++;} + } + int tsize = textsize(); + Fl_Font font = textfont(); + Fl_Color lcol = textcolor(); + Fl_Align talign = FL_ALIGN_LEFT; + // check for all the @-lines recognized by XForms: + while (*str == format_char() && *++str && *str != format_char()) { + switch (*str++) { + case 'l': case 'L': tsize = 24; break; + case 'm': case 'M': tsize = 18; break; + case 's': tsize = 11; break; + case 'b': font = (Fl_Font)(font|FL_BOLD); break; + case 'i': font = (Fl_Font)(font|FL_ITALIC); break; + case 'f': case 't': font = FL_COURIER; break; + case 'c': talign = FL_ALIGN_CENTER; break; + case 'r': talign = FL_ALIGN_RIGHT; break; + case 'B': + if (!(((FL_BLINE*)v)->flags & SELECTED)) { + fl_color((Fl_Color)strtol(str, &str, 10)); + fl_rectf(X, Y, w1, H); + } else strtol(str, &str, 10); + break; + case 'C': + lcol = (Fl_Color)strtol(str, &str, 10); + break; + case 'F': + font = (Fl_Font)strtol(str, &str, 10); + break; + case 'N': + lcol = FL_INACTIVE_COLOR; + break; + case 'S': + tsize = strtol(str, &str, 10); + break; + case '-': + fl_color(FL_DARK3); + fl_line(X+3, Y+H/2, X+w1-3, Y+H/2); + fl_color(FL_LIGHT3); + fl_line(X+3, Y+H/2+1, X+w1-3, Y+H/2+1); + break; + case 'u': + case '_': + fl_color(lcol); + fl_line(X+3, Y+H-1, X+w1-3, Y+H-1); + break; + case '.': + goto BREAK; + case '@': + str--; goto BREAK; + } + } + BREAK: + fl_font(font, tsize); + if (((FL_BLINE*)v)->flags & SELECTED) + lcol = fl_contrast(lcol, selection_color()); + if (!active_r()) lcol = fl_inactive(lcol); + fl_color(lcol); + fl_draw(str, X+3, Y, w1-6, H, e ? Fl_Align(talign|FL_ALIGN_CLIP) : talign, 0, 0); + if (!e) break; // no more fields... + *e = column_char(); // put the seperator back + X += w1; + W -= w1; + str = e+1; + } +} + +static const int no_columns[1] = {0}; + +Fl_Browser::Fl_Browser(int X, int Y, int W, int H, const char*l) + : Fl_Browser_(X, Y, W, H, l) { + column_widths_ = no_columns; + lines = 0; + full_height_ = 0; + cacheline = 0; + format_char_ = '@'; + column_char_ = '\t'; + first = last = cache = 0; +} + +void Fl_Browser::lineposition(int line, Fl_Line_Position pos) { + if (line<1) line = 1; + if (line>lines) line = lines; + int p = 0; + + FL_BLINE* l; + for (l=first; l && line>1; l = l->next) { + line--; p += item_height(l); + } + if (l && (pos == BOTTOM)) p += item_height (l); + + int final = p, X, Y, W, H; + bbox(X, Y, W, H); + + switch(pos) { + case TOP: break; + case BOTTOM: final -= H; break; + case MIDDLE: final -= H/2; break; + } + + if (final > (full_height() - H)) final = full_height() -H; + position(final); +} + +int Fl_Browser::topline() const { + return lineno(top()); +} + +void Fl_Browser::clear() { + for (FL_BLINE* l = first; l;) { + FL_BLINE* n = l->next; + free(l); + l = n; + } + full_height_ = 0; + first = 0; + lines = 0; + new_list(); +} + +void Fl_Browser::add(const char* newtext, void* d) { + insert(lines+1, newtext, d); + //Fl_Browser_::display(last); +} + +const char* Fl_Browser::text(int line) const { + if (line < 1 || line > lines) return 0; + return find_line(line)->txt; +} + +void* Fl_Browser::data(int line) const { + if (line < 1 || line > lines) return 0; + return find_line(line)->data; +} + +int Fl_Browser::select(int line, int v) { + if (line < 1 || line > lines) return 0; + return Fl_Browser_::select(find_line(line), v); +} + +int Fl_Browser::selected(int line) const { + if (line < 1 || line > lines) return 0; + return find_line(line)->flags & SELECTED; +} + +void Fl_Browser::show(int line) { + FL_BLINE* t = find_line(line); + if (t->flags & NOTDISPLAYED) { + t->flags &= ~NOTDISPLAYED; + full_height_ += item_height(t); + if (Fl_Browser_::displayed(t)) redraw(); + } +} + +void Fl_Browser::hide(int line) { + FL_BLINE* t = find_line(line); + if (!(t->flags & NOTDISPLAYED)) { + full_height_ -= item_height(t); + t->flags |= NOTDISPLAYED; + if (Fl_Browser_::displayed(t)) redraw(); + } +} + +void Fl_Browser::display(int line, int v) { + if (line < 1 || line > lines) return; + if (v) show(line); else hide(line); +} + +int Fl_Browser::visible(int line) const { + if (line < 1 || line > lines) return 0; + return !(find_line(line)->flags&NOTDISPLAYED); +} + +int Fl_Browser::value() const { + return lineno(selection()); +} + +// SWAP TWO LINES +void Fl_Browser::swap(FL_BLINE *a, FL_BLINE *b) { + + if ( a == b || !a || !b) return; // nothing to do + swapping(a, b); + FL_BLINE *aprev = a->prev; + FL_BLINE *anext = a->next; + FL_BLINE *bprev = b->prev; + FL_BLINE *bnext = b->next; + if ( b->prev == a ) { // A ADJACENT TO B + if ( aprev ) aprev->next = b; else first = b; + b->next = a; + a->next = bnext; + b->prev = aprev; + a->prev = b; + if ( bnext ) bnext->prev = a; else last = a; + } else if ( a->prev == b ) { // B ADJACENT TO A + if ( bprev ) bprev->next = a; else first = a; + a->next = b; + b->next = anext; + a->prev = bprev; + b->prev = a; + if ( anext ) anext->prev = b; else last = b; + } else { // A AND B NOT ADJACENT + // handle prev's + b->prev = aprev; + if ( anext ) anext->prev = b; else last = b; + a->prev = bprev; + if ( bnext ) bnext->prev = a; else last = a; + // handle next's + if ( aprev ) aprev->next = b; else first = b; + b->next = anext; + if ( bprev ) bprev->next = a; else first = a; + a->next = bnext; + } + // Disable cache -- we played around with positions + cacheline = 0; + cache = 0; +} + +void Fl_Browser::swap(int ai, int bi) { + if (ai < 1 || ai > lines || bi < 1 || bi > lines) return; + FL_BLINE* a = find_line(ai); + FL_BLINE* b = find_line(bi); + swap(a,b); +} + +// +// End of "$Id: Fl_Browser.cxx 5987 2007-11-20 21:57:17Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Browser_.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Browser_.cxx new file mode 100644 index 0000000..ae97f2d --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Browser_.cxx @@ -0,0 +1,842 @@ +// +// "$Id: Fl_Browser_.cxx 5992 2007-12-15 16:20:16Z mike $" +// +// Base Browser widget class for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#define DISPLAY_SEARCH_BOTH_WAYS_AT_ONCE + +#include +#include +#include +#include +#include + + +// This is the base class for browsers. To be useful it must be +// subclassed and several virtual functions defined. The +// Forms-compatable browser and the file chooser's browser are +// subclassed off of this. + +// Yes, I know this should be a template... + +// This has been designed so that the subclass has complete control +// over the storage of the data, although because next() and prev() +// functions are used to index, it works best as a linked list or as a +// large block of characters in which the line breaks must be searched +// for. + +// A great deal of work has been done so that the "height" of a data +// object does not need to be determined until it is drawn. This was +// done for the file chooser, because the height requires doing stat() +// to see if the file is a directory, which can be annoyingly slow +// over the network. + +/* redraw bits: + 1 = redraw children (the scrollbar) + 2 = redraw one or two items + 4 = redraw all items +*/ + +static void scrollbar_callback(Fl_Widget* s, void*) { + ((Fl_Browser_*)(s->parent()))->position(int(((Fl_Scrollbar*)s)->value())); +} + +static void hscrollbar_callback(Fl_Widget* s, void*) { + ((Fl_Browser_*)(s->parent()))->hposition(int(((Fl_Scrollbar*)s)->value())); +} + +// Scrollbar size should be part of the Fl class, but is left here for +// binary compatibility in 1.1.x - M. Sweet +int Fl_Browser_::scrollbar_width_ = 16; + +// Get the standard scrollbar size +int Fl::scrollbar_size() { + return Fl_Browser_::scrollbar_width(); +} + +// Set the standard scrollbar size +void Fl::scrollbar_size(int W) { + Fl_Browser_::scrollbar_width(W); +} + +// return where to draw the actual box: +void Fl_Browser_::bbox(int& X, int& Y, int& W, int& H) const { + Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; + X = x()+Fl::box_dx(b); + Y = y()+Fl::box_dy(b); + W = w()-Fl::box_dw(b); + H = h()-Fl::box_dh(b); + if (scrollbar.visible()) { + W -= scrollbar_width_; + if (scrollbar.align() & FL_ALIGN_LEFT) X += scrollbar_width_; + } + if (W < 0) W = 0; + if (hscrollbar.visible()) { + H -= scrollbar_width_; + if (scrollbar.align() & FL_ALIGN_TOP) Y += scrollbar_width_; + } + if (H < 0) H = 0; +} + +int Fl_Browser_::leftedge() const { + int X, Y, W, H; bbox(X, Y, W, H); + return X; +} + +// The scrollbars may be moved again by draw(), since each one's size +// depends on whether the other is visible or not. This skips over +// Fl_Group::resize since it moves the scrollbars uselessly. +void Fl_Browser_::resize(int X, int Y, int W, int H) { + Fl_Widget::resize(X, Y, W, H); + // move the scrollbars so they can respond to events: + bbox(X,Y,W,H); + scrollbar.resize( + scrollbar.align()&FL_ALIGN_LEFT ? X-scrollbar_width_ : X+W, + Y, scrollbar_width_, H); + hscrollbar.resize( + X, scrollbar.align()&FL_ALIGN_TOP ? Y-scrollbar_width_ : Y+H, + W, scrollbar_width_); +} + +// Cause minimal update to redraw the given item: +void Fl_Browser_::redraw_line(void* l) { + if (!redraw1 || redraw1 == l) {redraw1 = l; damage(FL_DAMAGE_EXPOSE);} + else if (!redraw2 || redraw2 == l) {redraw2 = l; damage(FL_DAMAGE_EXPOSE);} + else damage(FL_DAMAGE_SCROLL); +} + +// Figure out top() based on position(): +void Fl_Browser_::update_top() { + if (!top_) top_ = item_first(); + if (position_ != real_position_) { + void* l; + int ly; + int yy = position_; + // start from either head or current position, whichever is closer: + if (!top_ || yy <= (real_position_/2)) { + l = item_first(); + ly = 0; + } else { + l = top_; + ly = real_position_-offset_; + } + if (!l) { + top_ = 0; + offset_ = 0; + real_position_ = 0; + } else { + int hh = item_quick_height(l); + // step through list until we find line containing this point: + while (ly > yy) { + void* l1 = item_prev(l); + if (!l1) {ly = 0; break;} // hit the top + l = l1; + hh = item_quick_height(l); + ly -= hh; + } + while ((ly+hh) <= yy) { + void* l1 = item_next(l); + if (!l1) {yy = ly+hh-1; break;} + l = l1; + ly += hh; + hh = item_quick_height(l); + } + // top item must *really* be visible, use slow height: + for (;;) { + hh = item_height(l); + if ((ly+hh) > yy) break; // it is big enough to see + // go up to top of previous item: + void* l1 = item_prev(l); + if (!l1) {ly = yy = 0; break;} // hit the top + l = l1; yy = position_ = ly = ly-item_quick_height(l); + } + // use it: + top_ = l; + offset_ = yy-ly; + real_position_ = yy; + } + damage(FL_DAMAGE_SCROLL); + } +} + +// Change position(), top() will update when update_top() is called +// (probably by draw() or handle()): +void Fl_Browser_::position(int yy) { + if (yy < 0) yy = 0; + if (yy == position_) return; + position_ = yy; + if (yy != real_position_) redraw_lines(); +} + +void Fl_Browser_::hposition(int xx) { + if (xx < 0) xx = 0; + if (xx == hposition_) return; + hposition_ = xx; + if (xx != real_hposition_) redraw_lines(); +} + +// Tell whether item is currently displayed: +int Fl_Browser_::displayed(void* p) const { + int X, Y, W, H; bbox(X, Y, W, H); + int yy = H+offset_; + for (void* l = top_; l && yy > 0; l = item_next(l)) { + if (l == p) return 1; + yy -= item_height(l); + } + return 0; +} + +// Ensure this item is displayed: +// Messy because we have no idea if it is before top or after bottom: +void Fl_Browser_::display(void* p) { + + // First special case - want to display first item in the list? + update_top(); + if (p == item_first()) {position(0); return;} + + int X, Y, W, H, Yp; bbox(X, Y, W, H); + void* l = top_; + Y = Yp = -offset_; + int h1; + + // 2nd special case - want to display item already displayed at top of browser? + if (l == p) {position(real_position_+Y); return;} // scroll up a bit + + // 3rd special case - want to display item just above top of browser? + void* lp = item_prev(l); + if (lp == p) {position(real_position_+Y-item_quick_height(lp)); return;} + +#ifdef DISPLAY_SEARCH_BOTH_WAYS_AT_ONCE + // search for item. We search both up and down the list at the same time, + // this evens up the execution time for the two cases - the old way was + // much slower for going up than for going down. + while (l || lp) { + if (l) { + h1 = item_quick_height(l); + if (l == p) { + if (Y <= H) { // it is visible or right at bottom + Y = Y+h1-H; // find where bottom edge is + if (Y > 0) position(real_position_+Y); // scroll down a bit + } else { + position(real_position_+Y-(H-h1)/2); // center it + } + return; + } + Y += h1; + l = item_next(l); + } + if (lp) { + h1 = item_quick_height(lp); + Yp -= h1; + if (lp == p) { + if ((Yp + h1) >= 0) position(real_position_+Yp); + else position(real_position_+Yp-(H-h1)/2); + return; + } + lp = item_prev(lp); + } + } +#else + // Old version went forwards and then backwards: + // search forward for it: + l = top_; + for (; l; l = item_next(l)) { + h1 = item_quick_height(l); + if (l == p) { + if (Y <= H) { // it is visible or right at bottom + Y = Y+h1-H; // find where bottom edge is + if (Y > 0) position(real_position_+Y); // scroll down a bit + } else { + position(real_position_+Y-(H-h1)/2); // center it + } + return; + } + Y += h1; + } + // search backward for it, if found center it: + l = lp; + Y = -offset_; + for (; l; l = item_prev(l)) { + h1 = item_quick_height(l); + Y -= h1; + if (l == p) { + if ((Y + h1) >= 0) position(real_position_+Y); + else position(real_position_+Y-(H-h1)/2); + return; + } + } +#endif +} + +// redraw, has side effect of updating top and setting scrollbar: + +void Fl_Browser_::draw() { + int drawsquare = 0; + update_top(); + int full_width_ = full_width(); + int full_height_ = full_height(); + int X, Y, W, H; bbox(X, Y, W, H); + int dont_repeat = 0; +J1: + if (damage() & FL_DAMAGE_ALL) { // redraw the box if full redraw + Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; + draw_box(b, x(), y(), w(), h(), color()); + drawsquare = 1; + } + // see if scrollbar needs to be switched on/off: + if ((has_scrollbar_ & VERTICAL) && ( + (has_scrollbar_ & ALWAYS_ON) || position_ || full_height_ > H)) { + if (!scrollbar.visible()) { + scrollbar.set_visible(); + drawsquare = 1; + bbox(X, Y, W, H); + } + } else { + top_ = item_first(); real_position_ = offset_ = 0; + if (scrollbar.visible()) { + scrollbar.clear_visible(); + clear_damage((uchar)(damage()|FL_DAMAGE_SCROLL)); + } + } + + if ((has_scrollbar_ & HORIZONTAL) && ( + (has_scrollbar_ & ALWAYS_ON) || hposition_ || full_width_ > W)) { + if (!hscrollbar.visible()) { + hscrollbar.set_visible(); + drawsquare = 1; + bbox(X, Y, W, H); + } + } else { + real_hposition_ = 0; + if (hscrollbar.visible()) { + hscrollbar.clear_visible(); + clear_damage((uchar)(damage()|FL_DAMAGE_SCROLL)); + } + } + + // Check the vertical scrollbar again, just in case it needs to be drawn + // because the horizontal one is drawn. There should be a cleaner way + // to do this besides copying the same code... + if ((has_scrollbar_ & VERTICAL) && ( + (has_scrollbar_ & ALWAYS_ON) || position_ || full_height_ > H)) { + if (!scrollbar.visible()) { + scrollbar.set_visible(); + drawsquare = 1; + bbox(X, Y, W, H); + } + } else { + top_ = item_first(); real_position_ = offset_ = 0; + if (scrollbar.visible()) { + scrollbar.clear_visible(); + clear_damage((uchar)(damage()|FL_DAMAGE_SCROLL)); + } + } + + bbox(X, Y, W, H); + + fl_clip(X, Y, W, H); + // for each line, draw it if full redraw or scrolled. Erase background + // if not a full redraw or if it is selected: + void* l = top(); + int yy = -offset_; + for (; l && yy < H; l = item_next(l)) { + int hh = item_height(l); + if (hh <= 0) continue; + if ((damage()&(FL_DAMAGE_SCROLL|FL_DAMAGE_ALL)) || l == redraw1 || l == redraw2) { + if (item_selected(l)) { + fl_color(active_r() ? selection_color() : fl_inactive(selection_color())); + fl_rectf(X, yy+Y, W, hh); + } else if (!(damage()&FL_DAMAGE_ALL)) { + fl_push_clip(X, yy+Y, W, hh); + draw_box(box() ? box() : FL_DOWN_BOX, x(), y(), w(), h(), color()); + fl_pop_clip(); + } + item_draw(l, X-hposition_, yy+Y, W+hposition_, hh); + if (l == selection_ && Fl::focus() == this) { + draw_box(FL_BORDER_FRAME, X, yy+Y, W, hh, color()); + draw_focus(FL_NO_BOX, X, yy+Y, W+1, hh+1); + } + int ww = item_width(l); + if (ww > max_width) {max_width = ww; max_width_item = l;} + } + yy += hh; + } + // erase the area below last line: + if (!(damage()&FL_DAMAGE_ALL) && yy < H) { + fl_push_clip(X, yy+Y, W, H-yy); + draw_box(box() ? box() : FL_DOWN_BOX, x(), y(), w(), h(), color()); + fl_pop_clip(); + } + fl_pop_clip(); + redraw1 = redraw2 = 0; + + if (!dont_repeat) { + dont_repeat = 1; + // see if changes to full_height caused by calls to slow_height + // caused scrollbar state to change, in which case we have to redraw: + full_height_ = full_height(); + full_width_ = full_width(); + if ((has_scrollbar_ & VERTICAL) && + ((has_scrollbar_ & ALWAYS_ON) || position_ || full_height_>H)) { + if (!scrollbar.visible()) { damage(FL_DAMAGE_ALL); goto J1; } + } else { + if (scrollbar.visible()) { damage(FL_DAMAGE_ALL); goto J1; } + } + if ((has_scrollbar_ & HORIZONTAL) && + ((has_scrollbar_ & ALWAYS_ON) || hposition_ || full_width_>W)) { + if (!hscrollbar.visible()) { damage(FL_DAMAGE_ALL); goto J1; } + } else { + if (hscrollbar.visible()) { damage(FL_DAMAGE_ALL); goto J1; } + } + } + + // update the scrollbars and redraw them: + int dy = top_ ? item_quick_height(top_) : 0; if (dy < 10) dy = 10; + if (scrollbar.visible()) { + scrollbar.damage_resize( + scrollbar.align()&FL_ALIGN_LEFT ? X-scrollbar_width_ : X+W, + Y, scrollbar_width_, H); + scrollbar.value(position_, H, 0, full_height_); + scrollbar.linesize(dy); + if (drawsquare) draw_child(scrollbar); + else update_child(scrollbar); + } + if (hscrollbar.visible()) { + hscrollbar.damage_resize( + X, scrollbar.align()&FL_ALIGN_TOP ? Y-scrollbar_width_ : Y+H, + W, scrollbar_width_); + hscrollbar.value(hposition_, W, 0, full_width_); + hscrollbar.linesize(dy); + if (drawsquare) draw_child(hscrollbar); + else update_child(hscrollbar); + } + + // draw that little square between the scrollbars: + if (drawsquare && scrollbar.visible() && hscrollbar.visible()) { + fl_color(parent()->color()); + fl_rectf(scrollbar.x(), hscrollbar.y(), scrollbar_width_,scrollbar_width_); + } + + real_hposition_ = hposition_; +} + +// Quick way to delete and reset everything: +void Fl_Browser_::new_list() { + top_ = 0; + position_ = real_position_ = 0; + hposition_ = real_hposition_ = 0; + selection_ = 0; + offset_ = 0; + max_width = 0; + max_width_item = 0; + redraw_lines(); +} + +// Tell it that this item is going away, and that this must remove +// all pointers to it: +void Fl_Browser_::deleting(void* l) { + if (displayed(l)) { + redraw_lines(); + if (l == top_) { + real_position_ -= offset_; + offset_ = 0; + top_ = item_next(l); + if (!top_) top_ = item_prev(l); + } + } else { + // we don't know where this item is, recalculate top... + real_position_ = 0; + offset_ = 0; + top_ = 0; + } + if (l == selection_) selection_ = 0; + if (l == max_width_item) {max_width_item = 0; max_width = 0;} +} + +void Fl_Browser_::replacing(void* a, void* b) { + redraw_line(a); + if (a == selection_) selection_ = b; + if (a == top_) top_ = b; + if (a == max_width_item) {max_width_item = 0; max_width = 0;} +} + +void Fl_Browser_::swapping(void* a, void* b) { + redraw_line(a); + redraw_line(b); + if (a == selection_) selection_ = b; + else if (b == selection_) selection_ = a; + if (a == top_) top_ = b; + else if (b == top_) top_ = a; +} + +void Fl_Browser_::inserting(void* a, void* b) { + if (displayed(a)) redraw_lines(); + if (a == top_) top_ = b; +} + +void* Fl_Browser_::find_item(int my) { + update_top(); + int X, Y, W, H; bbox(X, Y, W, H); + void* l; + int yy = Y-offset_; + for (l = top_; l; l = item_next(l)) { + int hh = item_height(l); if (hh <= 0) continue; + yy += hh; + if (my <= yy || yy>=(Y+H)) return l; + } + return 0; +} + +int Fl_Browser_::select(void* l, int i, int docallbacks) { + if (type() == FL_MULTI_BROWSER) { + if (selection_ != l) { + if (selection_) redraw_line(selection_); + selection_ = l; + redraw_line(l); + } + if ((!i)==(!item_selected(l))) return 0; + item_select(l, i); + redraw_line(l); + } else { + if (i && selection_ == l) return 0; + if (!i && selection_ != l) return 0; + if (selection_) { + item_select(selection_, 0); + redraw_line(selection_); + selection_ = 0; + } + if (i) { + item_select(l, 1); + selection_ = l; + redraw_line(l); + display(l); + } + } + if (docallbacks) { + set_changed(); + do_callback(); + } + return 1; +} + +int Fl_Browser_::deselect(int docallbacks) { + if (type() == FL_MULTI_BROWSER) { + int change = 0; + for (void* p = item_first(); p; p = item_next(p)) + change |= select(p, 0, docallbacks); + return change; + } else { + if (!selection_) return 0; + item_select(selection_, 0); + redraw_line(selection_); + selection_ = 0; + return 1; + } +} + +int Fl_Browser_::select_only(void* l, int docallbacks) { + if (!l) return deselect(docallbacks); + int change = 0; + if (type() == FL_MULTI_BROWSER) { + for (void* p = item_first(); p; p = item_next(p)) + if (p != l) change |= select(p, 0, docallbacks); + } + change |= select(l, 1, docallbacks); + display(l); + return change; +} + +int Fl_Browser_::handle(int event) { + // must do shortcuts first or the scrollbar will get them... + if (event == FL_ENTER || event == FL_LEAVE) return 1; + if (event == FL_KEYBOARD && type() >= FL_HOLD_BROWSER) { + void* l1 = selection_; + void* l = l1; if (!l) l = top_; if (!l) l = item_first(); + if (l) { + if (type()==FL_HOLD_BROWSER) { + switch (Fl::event_key()) { + case FL_Down: + while ((l = item_next(l))) + if (item_height(l)>0) {select_only(l, when()); break;} + return 1; + case FL_Up: + while ((l = item_prev(l))) if (item_height(l)>0) { + select_only(l, when()); break;} + return 1; + } + } else { + switch (Fl::event_key()) { + case FL_Enter: + case FL_KP_Enter: + select_only(l, when() & ~FL_WHEN_ENTER_KEY); + if (when() & FL_WHEN_ENTER_KEY) { + set_changed(); + do_callback(); + } + return 1; + case ' ': + selection_ = l; + select(l, !item_selected(l), when() & ~FL_WHEN_ENTER_KEY); + return 1; + case FL_Down: + while ((l = item_next(l))) { + if (Fl::event_state(FL_SHIFT|FL_CTRL)) + select(l, l1 ? item_selected(l1) : 1, when()); + if (item_height(l)>0) goto J1; + } + return 1; + case FL_Up: + while ((l = item_prev(l))) { + if (Fl::event_state(FL_SHIFT|FL_CTRL)) + select(l, l1 ? item_selected(l1) : 1, when()); + if (item_height(l)>0) goto J1; + } + return 1; +J1: + if (selection_) redraw_line(selection_); + selection_ = l; redraw_line(l); + display(l); + return 1; + } + } + } + } + + if (Fl_Group::handle(event)) return 1; + int X, Y, W, H; bbox(X, Y, W, H); + int my; +// NOTE: +// instead of: +// change = select_only(find_item(my), when() & FL_WHEN_CHANGED) +// we use the construct: +// change = select_only(find_item(my), 0); +// if (change && (when() & FL_WHEN_CHANGED)) { +// set_changed(); +// do_callback(); +// } +// See str #834 +// The first form calls the callback *before* setting change. +// The callback may execute an Fl::wait(), resulting in another +// call of Fl_Browser_::handle() for the same widget. The sequence +// of events can be an FL_PUSH followed by an FL_RELEASE. +// This second call of Fl_Browser_::handle() may result in a - +// somewhat unexpected - second concurrent invocation of the callback. + + static char change; + static char whichway; + static int py; + switch (event) { + case FL_PUSH: + if (!Fl::event_inside(X, Y, W, H)) return 0; + if (Fl::visible_focus()) { + Fl::focus(this); + redraw(); + } + my = py = Fl::event_y(); + change = 0; + if (type() == FL_NORMAL_BROWSER || !top_) + ; + else if (type() != FL_MULTI_BROWSER) { + change = select_only(find_item(my), 0); + if (change && (when() & FL_WHEN_CHANGED)) { + set_changed(); + do_callback(); + } + } else { + void* l = find_item(my); + whichway = 1; + if (Fl::event_state(FL_CTRL)) { // toggle selection: + TOGGLE: + if (l) { + whichway = !item_selected(l); + change = select(l, whichway, 0); + if (change && (when() & FL_WHEN_CHANGED)) { + set_changed(); + do_callback(); + } + } + } else if (Fl::event_state(FL_SHIFT)) { // extend selection: + if (l == selection_) goto TOGGLE; + // state of previous selection determines new value: + whichway = l ? !item_selected(l) : 1; + // see which of the new item or previous selection is earlier, + // by searching from the previous forward for this one: + int down; + if (!l) down = 1; + else {for (void* m = selection_; ; m = item_next(m)) { + if (m == l) {down = 1; break;} + if (!m) {down = 0; break;} + }} + if (down) { + for (void* m = selection_; m != l; m = item_next(m)) + select(m, whichway, when() & FL_WHEN_CHANGED); + } else { + void* e = selection_; + for (void* m = item_next(l); m; m = item_next(m)) { + select(m, whichway, when() & FL_WHEN_CHANGED); + if (m == e) break; + } + } + // do the clicked item last so the select box is around it: + change = 1; + if (l) select(l, whichway, when() & FL_WHEN_CHANGED); + } else { // select only this item + change = select_only(l, 0); + if (change && (when() & FL_WHEN_CHANGED)) { + set_changed(); + do_callback(); + } + } + } + return 1; + case FL_DRAG: + // do the scrolling first: + my = Fl::event_y(); + if (my < Y && my < py) { + int p = real_position_+my-Y; + if (p<0) p = 0; + position(p); + } else if (my > (Y+H) && my > py) { + int p = real_position_+my-(Y+H); + int hh = full_height()-H; if (p > hh) p = hh; + if (p<0) p = 0; + position(p); + } + if (type() == FL_NORMAL_BROWSER || !top_) + ; + else if (type() == FL_MULTI_BROWSER) { + void* l = find_item(my); + void* t; void* b; // this will be the range to change + if (my > py) { // go down + t = selection_ ? item_next(selection_) : 0; + b = l ? item_next(l) : 0; + } else { // go up + t = l; + b = selection_; + } + for (; t && t != b; t = item_next(t)) { + char change_t; + change_t = select(t, whichway, 0); + change |= change_t; + if (change_t && (when() & FL_WHEN_CHANGED)) { + set_changed(); + do_callback(); + } + } + if (l) selection_ = l; + } else { + void* l1 = selection_; + void* l = + (Fl::event_x()x()+w()) ? selection_ : + find_item(my); + change = (l != l1); + select_only(l, when() & FL_WHEN_CHANGED); + } + py = my; + return 1; + case FL_RELEASE: + if (type() == FL_SELECT_BROWSER) { + void* t = selection_; deselect(); selection_ = t; + } + if (change) { + set_changed(); + if (when() & FL_WHEN_RELEASE) do_callback(); + } else { + if (when() & FL_WHEN_NOT_CHANGED) do_callback(); + } + + // double click calls the callback: (like Enter Key) + if (Fl::event_clicks() && (when() & FL_WHEN_ENTER_KEY)) { + set_changed(); + do_callback(); + } + return 1; + case FL_FOCUS: + case FL_UNFOCUS: + if (type() >= FL_HOLD_BROWSER && Fl::visible_focus()) { + redraw(); + return 1; + } else return 0; + } + + return 0; +} + +Fl_Browser_::Fl_Browser_(int X, int Y, int W, int H, const char* l) + : Fl_Group(X, Y, W, H, l), + scrollbar(0, 0, 0, 0, 0), // they will be resized by draw() + hscrollbar(0, 0, 0, 0, 0) +{ + box(FL_NO_BOX); + align(FL_ALIGN_BOTTOM); + position_ = real_position_ = 0; + hposition_ = real_hposition_ = 0; + offset_ = 0; + top_ = 0; + when(FL_WHEN_RELEASE_ALWAYS); + selection_ = 0; + color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR); + scrollbar.callback(scrollbar_callback); +//scrollbar.align(FL_ALIGN_LEFT|FL_ALIGN_BOTTOM); // back compatability? + hscrollbar.callback(hscrollbar_callback); + hscrollbar.type(FL_HORIZONTAL); + textfont_ = FL_HELVETICA; + textsize_ = (uchar)FL_NORMAL_SIZE; + textcolor_ = FL_FOREGROUND_COLOR; + has_scrollbar_ = BOTH; + max_width = 0; + max_width_item = 0; + redraw1 = redraw2 = 0; + end(); +} + +// Default versions of some of the virtual functions: + +int Fl_Browser_::item_quick_height(void* l) const { + return item_height(l); +} + +int Fl_Browser_::incr_height() const { + return item_quick_height(item_first()); +} + +int Fl_Browser_::full_height() const { + int t = 0; + for (void* p = item_first(); p; p = item_next(p)) + t += item_quick_height(p); + return t; +} + +int Fl_Browser_::full_width() const { + return max_width; +} + +void Fl_Browser_::item_select(void*, int) {} + +int Fl_Browser_::item_selected(void* l) const {return l==selection_;} + +// +// End of "$Id: Fl_Browser_.cxx 5992 2007-12-15 16:20:16Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Browser_load.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Browser_load.cxx new file mode 100644 index 0000000..f0ee771 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Browser_load.cxx @@ -0,0 +1,57 @@ +// +// "$Id: Fl_Browser_load.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// File loading routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include + +int Fl_Browser::load(const char *filename) { +#define MAXFL_BLINE 1024 + char newtext[MAXFL_BLINE]; + int c; + int i; + clear(); + if (!filename || !(filename[0])) return 1; + FILE *fl = fopen(filename,"r"); + if (!fl) return 0; + i = 0; + do { + c = getc(fl); + if (c == '\n' || c <= 0 || i>=(MAXFL_BLINE-1)) { + newtext[i] = 0; + add(newtext); + i = 0; + } else + newtext[i++] = c; + } while (c >= 0); + fclose(fl); + return 1; +} + +// +// End of "$Id: Fl_Browser_load.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Button.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Button.cxx new file mode 100644 index 0000000..3f480d1 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Button.cxx @@ -0,0 +1,175 @@ +// +// "$Id: Fl_Button.cxx 6589 2008-12-17 10:47:09Z fabien $" +// +// Button widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include + +// There are a lot of subclasses, named Fl_*_Button. Some of +// them are implemented by setting the type() value and testing it +// here. This includes Fl_Radio_Button and Fl_Toggle_Button + +int Fl_Button::value(int v) { + v = v ? 1 : 0; + oldval = v; + clear_changed(); + if (value_ != v) { + value_ = v; + if (box()) redraw(); + else redraw_label(); + return 1; + } else { + return 0; + } +} + +void Fl_Button::setonly() { // set this radio button on, turn others off + value(1); + Fl_Group* g = (Fl_Group*)parent(); + Fl_Widget*const* a = g->array(); + for (int i = g->children(); i--;) { + Fl_Widget* o = *a++; + if (o != this && o->type()==FL_RADIO_BUTTON) ((Fl_Button*)o)->value(0); + } +} + +void Fl_Button::draw() { + if (type() == FL_HIDDEN_BUTTON) return; + Fl_Color col = value() ? selection_color() : color(); + draw_box(value() ? (down_box()?down_box():fl_down(box())) : box(), col); + if (labeltype() == FL_NORMAL_LABEL && value()) { + Fl_Color c = labelcolor(); + labelcolor(fl_contrast(c, col)); + draw_label(); + labelcolor(c); + } else draw_label(); + if (Fl::focus() == this) draw_focus(); +} + +int Fl_Button::handle(int event) { + int newval; + switch (event) { + case FL_ENTER: + case FL_LEAVE: +// if ((value_?selection_color():color())==FL_GRAY) redraw(); + return 1; + case FL_PUSH: + if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this); + case FL_DRAG: + if (Fl::event_inside(this)) { + if (type() == FL_RADIO_BUTTON) newval = 1; + else newval = !oldval; + } else + { + clear_changed(); + newval = oldval; + } + if (newval != value_) { + value_ = newval; + set_changed(); + redraw(); + if (when() & FL_WHEN_CHANGED) do_callback(); + } + return 1; + case FL_RELEASE: + if (value_ == oldval) { + if (when() & FL_WHEN_NOT_CHANGED) do_callback(); + return 1; + } + set_changed(); + if (type() == FL_RADIO_BUTTON) setonly(); + else if (type() == FL_TOGGLE_BUTTON) oldval = value_; + else { + value(oldval); + set_changed(); + if (when() & FL_WHEN_CHANGED) do_callback(); + } + if (when() & FL_WHEN_RELEASE) do_callback(); + return 1; + case FL_SHORTCUT: + if (!(shortcut() ? + Fl::test_shortcut(shortcut()) : test_shortcut())) return 0; + + if (Fl::visible_focus() && handle(FL_FOCUS)) Fl::focus(this); + + if (type() == FL_RADIO_BUTTON && !value_) { + setonly(); + set_changed(); + if (when() & (FL_WHEN_CHANGED|FL_WHEN_RELEASE)) + do_callback(); + } else if (type() == FL_TOGGLE_BUTTON) { + value(!value()); + set_changed(); + if (when() & (FL_WHEN_CHANGED|FL_WHEN_RELEASE)) + do_callback(); + } else if (when() & FL_WHEN_RELEASE) do_callback(); + return 1; + case FL_FOCUS : + case FL_UNFOCUS : + if (Fl::visible_focus()) { + if (box() == FL_NO_BOX) { + // Widgets with the FL_NO_BOX boxtype need a parent to + // redraw, since it is responsible for redrawing the + // background... + int X = x() > 0 ? x() - 1 : 0; + int Y = y() > 0 ? y() - 1 : 0; + if (window()) window()->damage(FL_DAMAGE_ALL, X, Y, w() + 2, h() + 2); + } else redraw(); + return 1; + } else return 0; + case FL_KEYBOARD : + if (Fl::focus() == this && Fl::event_key() == ' ' && + !(Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT | FL_META))) { + set_changed(); + if (type() == FL_RADIO_BUTTON && !value_) { + setonly(); + if (when() & FL_WHEN_CHANGED) do_callback(); + } else if (type() == FL_TOGGLE_BUTTON) { + value(!value()); + if (when() & FL_WHEN_CHANGED) do_callback(); + } + if (when() & FL_WHEN_RELEASE) do_callback(); + return 1; + } + default: + return 0; + } +} + +Fl_Button::Fl_Button(int X, int Y, int W, int H, const char *l) +: Fl_Widget(X,Y,W,H,l) { + box(FL_UP_BOX); + down_box(FL_NO_BOX); + value_ = oldval = 0; + shortcut_ = 0; + set_flag(SHORTCUT_LABEL); +} + +// +// End of "$Id: Fl_Button.cxx 6589 2008-12-17 10:47:09Z fabien $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Chart.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Chart.cxx new file mode 100644 index 0000000..003a892 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Chart.cxx @@ -0,0 +1,390 @@ +// +// "$Id: Fl_Chart.cxx 5942 2007-10-06 17:33:17Z matt $" +// +// Forms-compatible chart widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include "flstring.h" +#include + +#define ARCINC (2.0*M_PI/360.0) + +// this function is in fl_boxtype.cxx: +void fl_rectbound(int x,int y,int w,int h, Fl_Color color); + +/* Widget specific information */ + +static void draw_barchart(int x,int y,int w,int h, + int numb, FL_CHART_ENTRY entries[], + double min, double max, int autosize, int maxnumb, + Fl_Color textcolor) +/* Draws a bar chart. x,y,w,h is the bounding box, entries the array of + numb entries and min and max the boundaries. */ +{ + double incr; + int zeroh; + double lh = fl_height(); + if (max == min) incr = h; + else incr = h/(max-min); + if ( (-min*incr) < lh) { + incr = (h - lh + min*incr)/(max-min); + zeroh = int(y+h-lh); + } else { + zeroh = (int)rint(y+h+min * incr); + } + int bwidth = (int)rint(w/double(autosize?numb:maxnumb)); + /* Draw base line */ + fl_color(textcolor); + fl_line(x, zeroh, x+w, zeroh); + if (min == 0.0 && max == 0.0) return; /* Nothing else to draw */ + int i; + /* Draw the bars */ + for (i=0; i 0) + fl_rectbound(x+i*bwidth,zeroh-hh,bwidth+1,hh+1,(Fl_Color)entries[i].col); + } + /* Draw the labels */ + fl_color(textcolor); + for (i=0; i lw) lw = w1; + } + if (lw > 0.0) lw += 4.0; + double incr; + int zeroh; + if (max == min) incr = w; + else incr = w/(max-min); + if ( (-min*incr) < lw) { + incr = (w - lw + min*incr)/(max-min); + zeroh = x+(int)rint(lw); + } else { + zeroh = (int)rint(x-min * incr); + } + int bwidth = (int)rint(h/double(autosize?numb:maxnumb)); + /* Draw base line */ + fl_color(textcolor); + fl_line(zeroh, y, zeroh, y+h); + if (min == 0.0 && max == 0.0) return; /* Nothing else to draw */ + /* Draw the bars */ + for (i=0; i 0) + fl_rectbound(zeroh,y+i*bwidth,ww+1,bwidth+1, (Fl_Color)entries[i].col); + else if (ww < 0) + fl_rectbound(zeroh+ww,y+i*bwidth,-ww+1,bwidth+1,(Fl_Color)entries[i].col); + } + /* Draw the labels */ + fl_color(textcolor); + for (i=0; i0.0)!=(entries[i].val>0.0)) { + double ttt = entries[i-1].val/(entries[i-1].val-entries[i].val); + int xt = x + (int)rint((i-.5+ttt)*bwidth); + fl_polygon(x0,zeroh, x0,yy0, xt,zeroh); + fl_polygon(xt,zeroh, x1,yy1, x1,zeroh); + } else { + fl_polygon(x0,zeroh, x0,yy0, x1,yy1, x1,zeroh); + } + fl_color(textcolor); + fl_line(x0,yy0,x1,yy1); + } + } + /* Draw base line */ + fl_color(textcolor); + fl_line(x,zeroh,x+w,zeroh); + /* Draw the labels */ + for (i=0; i=0 ? FL_ALIGN_BOTTOM : FL_ALIGN_TOP); +} + +static void draw_piechart(int x,int y,int w,int h, + int numb, FL_CHART_ENTRY entries[], int special, + Fl_Color textcolor) +/* Draws a pie chart. x,y,w,h is the bounding box, entries the array of + numb entries */ +{ + int i; + double xc,yc,rad; /* center and radius */ + double tot; /* sum of values */ + double incr; /* increment in angle */ + double curang; /* current angle we are drawing */ + double txc,tyc; /* temporary center */ + double lh = fl_height(); + /* compute center and radius */ + double h_denom = (special ? 2.3 : 2.0); + rad = (h - 2*lh)/h_denom/1.1; + xc = x+w/2.0; yc = y+h-1.1*rad-lh; + /* compute sum of values */ + tot = 0.0; + for (i=0; i 0.0) tot += entries[i].val; + if (tot == 0.0) return; + incr = 360.0/tot; + /* Draw the pie */ + curang = 0.0; + for (i=0; i 0.0) + { + txc = xc; tyc = yc; + /* Correct for special pies */ + if (special && i==0) + { + txc += 0.3*rad*cos(ARCINC*(curang+0.5*incr*entries[i].val)); + tyc -= 0.3*rad*sin(ARCINC*(curang+0.5*incr*entries[i].val)); + } + fl_color((Fl_Color)entries[i].col); + fl_begin_polygon(); fl_vertex(txc,tyc); + fl_arc(txc,tyc,rad,curang, curang+incr*entries[i].val); + fl_end_polygon(); + fl_color(textcolor); + fl_begin_loop(); fl_vertex(txc,tyc); + fl_arc(txc,tyc,rad,curang, curang+incr*entries[i].val); + fl_end_loop(); + curang += 0.5 * incr * entries[i].val; + /* draw the label */ + double xl = txc + 1.1*rad*cos(ARCINC*curang); + fl_draw(entries[i].str, + (int)rint(xl), + (int)rint(tyc - 1.1*rad*sin(ARCINC*curang)), + 0, 0, + xl= max) { + min = max = 0.0; + for (int i=0; i max) max = entries[i].val; + } + } + + fl_font(textfont(),textsize()); + + switch (type()) { + case FL_BAR_CHART: + ww++; // makes the bars fill box correctly + draw_barchart(xx,yy,ww,hh, numb, entries, min, max, + autosize(), maxnumb, textcolor()); + break; + case FL_HORBAR_CHART: + hh++; // makes the bars fill box correctly + draw_horbarchart(xx,yy,ww,hh, numb, entries, min, max, + autosize(), maxnumb, textcolor()); + break; + case FL_PIE_CHART: + draw_piechart(xx,yy,ww,hh,numb,entries,0, textcolor()); + break; + case FL_SPECIALPIE_CHART: + draw_piechart(xx,yy,ww,hh,numb,entries,1,textcolor()); + break; + default: + draw_linechart(type(),xx,yy,ww,hh, numb, entries, min, max, + autosize(), maxnumb, textcolor()); + break; + } + draw_label(); + fl_pop_clip(); +} + +/*------------------------------*/ + +#define FL_CHART_BOXTYPE FL_BORDER_BOX +#define FL_CHART_COL1 FL_COL1 +#define FL_CHART_LCOL FL_LCOL +#define FL_CHART_ALIGN FL_ALIGN_BOTTOM + +Fl_Chart::Fl_Chart(int X, int Y, int W, int H,const char *l) : +Fl_Widget(X,Y,W,H,l) { + box(FL_BORDER_BOX); + align(FL_ALIGN_BOTTOM); + numb = 0; + maxnumb = 0; + sizenumb = FL_CHART_MAX; + autosize_ = 1; + min = max = 0; + textfont_ = FL_HELVETICA; + textsize_ = 10; + textcolor_ = FL_FOREGROUND_COLOR; + entries = (FL_CHART_ENTRY *)calloc(sizeof(FL_CHART_ENTRY), FL_CHART_MAX + 1); +} + +Fl_Chart::~Fl_Chart() { + free(entries); +} + +void Fl_Chart::clear() { + numb = 0; + redraw(); +} + +void Fl_Chart::add(double val, const char *str, unsigned col) { + /* Allocate more entries if required */ + if (numb >= sizenumb) { + sizenumb += FL_CHART_MAX; + entries = (FL_CHART_ENTRY *)realloc(entries, sizeof(FL_CHART_ENTRY) * (sizenumb + 1)); + } + // Shift entries as needed + if (numb >= maxnumb && maxnumb > 0) { + memmove(entries, entries + 1, sizeof(FL_CHART_ENTRY) * (numb - 1)); + numb --; + } + entries[numb].val = float(val); + entries[numb].col = col; + if (str) { + strlcpy(entries[numb].str,str,FL_CHART_LABEL_MAX + 1); + } else { + entries[numb].str[0] = 0; + } + numb++; + redraw(); +} + +void Fl_Chart::insert(int ind, double val, const char *str, unsigned col) { + int i; + if (ind < 1 || ind > numb+1) return; + /* Allocate more entries if required */ + if (numb >= sizenumb) { + sizenumb += FL_CHART_MAX; + entries = (FL_CHART_ENTRY *)realloc(entries, sizeof(FL_CHART_ENTRY) * (sizenumb + 1)); + } + // Shift entries as needed + for (i=numb; i >= ind; i--) entries[i] = entries[i-1]; + if (numb < maxnumb || maxnumb == 0) numb++; + /* Fill in the new entry */ + entries[ind-1].val = float(val); + entries[ind-1].col = col; + if (str) { + strlcpy(entries[ind-1].str,str,FL_CHART_LABEL_MAX+1); + } else { + entries[ind-1].str[0] = 0; + } + redraw(); +} + +void Fl_Chart::replace(int ind,double val, const char *str, unsigned col) { + if (ind < 1 || ind > numb) return; + entries[ind-1].val = float(val); + entries[ind-1].col = col; + if (str) { + strlcpy(entries[ind-1].str,str,FL_CHART_LABEL_MAX+1); + } else { + entries[ind-1].str[0] = 0; + } + redraw(); +} + +void Fl_Chart::bounds(double mymin, double mymax) { + this->min = mymin; + this->max = mymax; + redraw(); +} + +void Fl_Chart::maxsize(int m) { + int i; + /* Fill in the new number */ + if (m < 0) return; + maxnumb = m; + /* Shift entries if required */ + if (numb > maxnumb) { + for (i = 0; i +#include +#include "flstring.h" +#include +#include + +/* This uses a cache for faster access when you're scanning the list +either forwards or backwards. */ + +Fl_Check_Browser::cb_item *Fl_Check_Browser::find_item(int n) const { + int i = n; + cb_item *p = first; + + if (n <= 0 || n > nitems_ || p == 0) { + return 0; + } + + if (n == cached_item) { + p = cache; + n = 1; + } else if (n == cached_item + 1) { + p = cache->next; + n = 1; + } else if (n == cached_item - 1) { + p = cache->prev; + n = 1; + } + + while (--n) { + p = p->next; + } + + /* Cast to not const and cache it. */ + + ((Fl_Check_Browser *)this)->cache = p; + ((Fl_Check_Browser *)this)->cached_item = i; + + return p; +} + +int Fl_Check_Browser::lineno(cb_item *p0) const { + cb_item *p = first; + + if (p == 0) { + return 0; + } + + int i = 1; + while (p) { + if (p == p0) { + return i; + } + i++; + p = p->next; + } + + return 0; +} + +Fl_Check_Browser::Fl_Check_Browser(int X, int Y, int W, int H, const char *l) + : Fl_Browser_(X, Y, W, H, l) { + type(FL_SELECT_BROWSER); + when(FL_WHEN_NEVER); + first = last = 0; + nitems_ = nchecked_ = 0; + cached_item = -1; +} + +void *Fl_Check_Browser::item_first() const { + return first; +} + +void *Fl_Check_Browser::item_next(void *l) const { + return ((cb_item *)l)->next; +} + +void *Fl_Check_Browser::item_prev(void *l) const { + return ((cb_item *)l)->prev; +} + +int Fl_Check_Browser::item_height(void *) const { + return textsize() + 2; +} + +#define CHECK_SIZE (textsize()-2) + +int Fl_Check_Browser::item_width(void *v) const { + fl_font(textfont(), textsize()); + return int(fl_width(((cb_item *)v)->text)) + CHECK_SIZE + 8; +} + +void Fl_Check_Browser::item_draw(void *v, int X, int Y, int, int) const { + cb_item *i = (cb_item *)v; + char *s = i->text; + int tsize = textsize(); + Fl_Color col = active_r() ? textcolor() : fl_inactive(textcolor()); + int cy = Y + (tsize + 1 - CHECK_SIZE) / 2; + X += 2; + + fl_color(active_r() ? FL_FOREGROUND_COLOR : fl_inactive(FL_FOREGROUND_COLOR)); + fl_loop(X, cy, X, cy + CHECK_SIZE, + X + CHECK_SIZE, cy + CHECK_SIZE, X + CHECK_SIZE, cy); + if (i->checked) { + int tx = X + 3; + int tw = CHECK_SIZE - 4; + int d1 = tw/3; + int d2 = tw-d1; + int ty = cy + (CHECK_SIZE+d2)/2-d1-2; + for (int n = 0; n < 3; n++, ty++) { + fl_line(tx, ty, tx+d1, ty+d1); + fl_line(tx+d1, ty+d1, tx+tw-1, ty+d1-d2+1); + } + } + fl_font(textfont(), tsize); + if (i->selected) { + col = fl_contrast(col, selection_color()); + } + fl_color(col); + fl_draw(s, X + CHECK_SIZE + 8, Y + tsize - 1); +} + +void Fl_Check_Browser::item_select(void *v, int state) { + cb_item *i = (cb_item *)v; + + if (state) { + if (i->checked) { + i->checked = 0; + nchecked_--; + } else { + i->checked = 1; + nchecked_++; + } + } +} + +int Fl_Check_Browser::item_selected(void *v) const { + cb_item *i = (cb_item *)v; + return i->selected; +} + +int Fl_Check_Browser::add(char *s) { + return (add(s, 0)); +} + +int Fl_Check_Browser::add(char *s, int b) { + cb_item *p = (cb_item *)malloc(sizeof(cb_item)); + p->next = 0; + p->prev = 0; + p->checked = b; + p->selected = 0; + p->text = strdup(s); + + if (b) { + nchecked_++; + } + + if (last == 0) { + first = last = p; + } else { + last->next = p; + p->prev = last; + last = p; + } + nitems_++; + + return (nitems_); +} + +int Fl_Check_Browser::remove(int item) { + cb_item *p = find_item(item); + + // line at item exists + if(p) { + // tell the Browser_ what we will do + deleting(p); + + // fix checked count + if(p->checked) + --nchecked_; + + // remove the node + if (p->prev) + p->prev->next = p->next; + else + first = p->next; + if (p->next) + p->next->prev = p->prev; + else + last = p->prev; + + free(p->text); + free(p); + + --nitems_; + cached_item = -1; + } + + return (nitems_); +} + +void Fl_Check_Browser::clear() { + cb_item *p = first; + cb_item *next; + + if (p == 0) { + return; + } + + new_list(); + do { + next = p->next; + free(p->text); + free(p); + p = next; + } while (p); + + first = last = 0; + nitems_ = nchecked_ = 0; + cached_item = -1; +} + +int Fl_Check_Browser::checked(int i) const { + cb_item *p = find_item(i); + + if (p) return p->checked; + return 0; +} + +void Fl_Check_Browser::checked(int i, int b) { + cb_item *p = find_item(i); + + if (p && (p->checked ^ b)) { + p->checked = b; + if (b) { + nchecked_++; + } else { + nchecked_--; + } + redraw(); + } +} + +int Fl_Check_Browser::value() const { + return lineno((cb_item *)selection()); +} + +char *Fl_Check_Browser::text(int i) const { + cb_item *p = find_item(i); + + if (p) return p->text; + return 0; +} + +void Fl_Check_Browser::check_all() { + cb_item *p; + + nchecked_ = nitems_; + for (p = first; p; p = p->next) { + p->checked = 1; + } + redraw(); +} + +void Fl_Check_Browser::check_none() { + cb_item *p; + + nchecked_ = 0; + for (p = first; p; p = p->next) { + p->checked = 0; + } + redraw(); +} + +int Fl_Check_Browser::handle(int event) { + if (event==FL_PUSH) + deselect(); + return Fl_Browser_::handle(event); +} + +// +// End of "$Id: Fl_Check_Browser.cxx 5985 2007-11-20 21:15:08Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Check_Button.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Check_Button.cxx new file mode 100644 index 0000000..3c2643d --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Check_Button.cxx @@ -0,0 +1,40 @@ +// +// "$Id: Fl_Check_Button.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Check button widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include + +// A subclass of Fl_Button that always draws as a diamond box. This +// diamond is smaller than the widget size and can be surchecked by +// another box type, for compatability with Forms. + +Fl_Check_Button::Fl_Check_Button(int X, int Y, int W, int H, const char *l) +: Fl_Light_Button(X, Y, W, H, l) { + box(FL_NO_BOX); + down_box(FL_DOWN_BOX); + selection_color(FL_FOREGROUND_COLOR); +} diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Choice.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Choice.cxx new file mode 100644 index 0000000..e742a10 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Choice.cxx @@ -0,0 +1,191 @@ +// +// "$Id: Fl_Choice.cxx 6872 2009-09-16 07:04:37Z AlbrechtS $" +// +// Choice widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include "flstring.h" + +// Emulates the Forms choice widget. This is almost exactly the same +// as an Fl_Menu_Button. The only difference is the appearance of the +// button: it draws the text of the current pick and a down-arrow. + +void Fl_Choice::draw() { + int dx = Fl::box_dx(FL_DOWN_BOX); + int dy = Fl::box_dy(FL_DOWN_BOX); + int H = h() - 2 * dy; + int W = (H > 20) ? 20 : H; + int X = x() + w() - W - dx; + int Y = y() + dy; + int w1 = (W - 4) / 3; if (w1 < 1) w1 = 1; + int x1 = X + (W - 2 * w1 - 1) / 2; + int y1 = Y + (H - w1 - 1) / 2; + + if (Fl::scheme()) { + draw_box(FL_UP_BOX, color()); + + fl_color(active_r() ? labelcolor() : fl_inactive(labelcolor())); + if (!strcmp(Fl::scheme(), "plastic")) { + // Show larger up/down arrows... + fl_polygon(x1, y1 + 3, x1 + w1, y1 + w1 + 3, x1 + 2 * w1, y1 + 3); + fl_polygon(x1, y1 + 1, x1 + w1, y1 - w1 + 1, x1 + 2 * w1, y1 + 1); + } else { + // Show smaller up/down arrows with a divider... + x1 = x() + w() - 13 - dx; + y1 = y() + h() / 2; + fl_polygon(x1, y1 - 2, x1 + 3, y1 - 5, x1 + 6, y1 - 2); + fl_polygon(x1, y1 + 2, x1 + 3, y1 + 5, x1 + 6, y1 + 2); + + fl_color(fl_darker(color())); + fl_yxline(x1 - 7, y1 - 8, y1 + 8); + + fl_color(fl_lighter(color())); + fl_yxline(x1 - 6, y1 - 8, y1 + 8); + } + } else { + if (fl_contrast(textcolor(), FL_BACKGROUND2_COLOR) == textcolor()) { + draw_box(FL_DOWN_BOX, FL_BACKGROUND2_COLOR); + } else { + draw_box(FL_DOWN_BOX, fl_lighter(color())); + } + draw_box(FL_UP_BOX,X,Y,W,H,color()); + + fl_color(active_r() ? labelcolor() : fl_inactive(labelcolor())); + fl_polygon(x1, y1, x1 + w1, y1 + w1, x1 + 2 * w1, y1); + } + + W += 2 * dx; + + if (mvalue()) { + Fl_Menu_Item m = *mvalue(); + if (active_r()) m.activate(); else m.deactivate(); + + // ERCO + int xx = x() + dx, yy = y() + dy + 1, ww = w() - W, hh = H - 2; + + fl_clip(xx, yy, ww, hh); + + if ( Fl::scheme()) { + Fl_Label l; + l.value = m.text; + l.image = 0; + l.deimage = 0; + l.type = m.labeltype_; + l.font = m.labelsize_ || m.labelfont_ ? m.labelfont_ : uchar(textfont()); + l.size = m.labelsize_ ? m.labelsize_ : textsize(); + l.color= m.labelcolor_ ? m.labelcolor_ : textcolor(); + if (!m.active()) l.color = fl_inactive((Fl_Color)l.color); + fl_draw_shortcut = 2; // hack value to make '&' disappear + l.draw(xx+3, yy, ww>6 ? ww-6 : 0, hh, FL_ALIGN_LEFT); + fl_draw_shortcut = 0; + if ( Fl::focus() == this ) draw_focus(box(), xx, yy, ww, hh); + } + else { + fl_draw_shortcut = 2; // hack value to make '&' disappear + m.draw(xx, yy, ww, hh, this, Fl::focus() == this); + fl_draw_shortcut = 0; + } + + fl_pop_clip(); + } + + draw_label(); +} + +Fl_Choice::Fl_Choice(int X, int Y, int W, int H, const char *l) +: Fl_Menu_(X,Y,W,H,l) { + align(FL_ALIGN_LEFT); + when(FL_WHEN_RELEASE); + textfont(FL_HELVETICA); + box(FL_FLAT_BOX); + down_box(FL_BORDER_BOX); +} + +int Fl_Choice::value(const Fl_Menu_Item *v) { + if (!Fl_Menu_::value(v)) return 0; + redraw(); + return 1; +} + +int Fl_Choice::value(int v) { + if (v == -1) return value((const Fl_Menu_Item *)0); + if (v < 0 || v >= (size() - 1)) return 0; + if (!Fl_Menu_::value(v)) return 0; + redraw(); + return 1; +} + +int Fl_Choice::handle(int e) { + if (!menu() || !menu()->text) return 0; + const Fl_Menu_Item* v; + switch (e) { + case FL_ENTER: + case FL_LEAVE: + return 1; + + case FL_KEYBOARD: + if (Fl::event_key() != ' ' || + (Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT | FL_META))) return 0; + case FL_PUSH: + if (Fl::visible_focus()) Fl::focus(this); + J1: + if (Fl::scheme() + || fl_contrast(textcolor(), FL_BACKGROUND2_COLOR) != textcolor()) { + v = menu()->pulldown(x(), y(), w(), h(), mvalue(), this); + } else { + // In order to preserve the old look-n-feel of "white" menus, + // temporarily override the color() of this widget... + Fl_Color c = color(); + color(FL_BACKGROUND2_COLOR); + v = menu()->pulldown(x(), y(), w(), h(), mvalue(), this); + color(c); + } + if (!v || v->submenu()) return 1; + if (v != mvalue()) redraw(); + picked(v); + return 1; + case FL_SHORTCUT: + if (Fl_Widget::test_shortcut()) goto J1; + v = menu()->test_shortcut(); + if (!v) return 0; + if (v != mvalue()) redraw(); + picked(v); + return 1; + case FL_FOCUS: + case FL_UNFOCUS: + if (Fl::visible_focus()) { + redraw(); + return 1; + } else return 0; + default: + return 0; + } +} + +// +// End of "$Id: Fl_Choice.cxx 6872 2009-09-16 07:04:37Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Clock.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Clock.cxx new file mode 100644 index 0000000..fb46384 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Clock.cxx @@ -0,0 +1,177 @@ +// +// "$Id: Fl_Clock.cxx 5472 2006-09-20 03:03:14Z mike $" +// +// Clock widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include +#ifndef WIN32 +# include +#endif /* !WIN32 */ + +// Original clock display written by Paul Haeberli at SGI. +// Modifications by Mark Overmars for Forms +// Further changes by Bill Spitzak for fltk + +const float hourhand[4][2] = {{-0.5f, 0}, {0, 1.5f}, {0.5f, 0}, {0, -7.0f}}; +const float minhand[4][2] = {{-0.5f, 0}, {0, 1.5f}, {0.5f, 0}, {0, -11.5f}}; +const float sechand[4][2] = {{-0.1f, 0}, {0, 2.0f}, {0.1f, 0}, {0, -11.5f}}; + +static void drawhand(double ang,const float v[][2],Fl_Color fill,Fl_Color line) +{ + fl_push_matrix(); + fl_rotate(ang); + fl_color(fill); fl_begin_polygon(); + int i; for (i=0; i<4; i++) fl_vertex(v[i][0],v[i][1]); fl_end_polygon(); + fl_color(line); fl_begin_loop(); + for (i=0; i<4; i++) fl_vertex(v[i][0],v[i][1]); fl_end_loop(); + fl_pop_matrix(); +} + +void Fl_Clock_Output::drawhands(Fl_Color fill, Fl_Color line) { + if (!active_r()) { + fill = fl_inactive(fill); + line = fl_inactive(line); + } + drawhand(-360*(hour()+minute()/60.0)/12, hourhand, fill, line); + drawhand(-360*(minute()+second()/60.0)/60, minhand, fill, line); + drawhand(-360*(second()/60.0), sechand, fill, line); +} + +static void rect(double x, double y, double w, double h) { + double r = x+w; + double t = y+h; + fl_begin_polygon(); + fl_vertex(x, y); + fl_vertex(r, y); + fl_vertex(r, t); + fl_vertex(x, t); + fl_end_polygon(); +} + +void Fl_Clock_Output::draw(int X, int Y, int W, int H) { + Fl_Color box_color = type()==FL_ROUND_CLOCK ? FL_GRAY : color(); + Fl_Color shadow_color = fl_color_average(box_color, FL_BLACK, 0.5); + draw_box(box(), X, Y, W, H, box_color); + fl_push_matrix(); + fl_translate(X+W/2.0-.5, Y+H/2.0-.5); + fl_scale((W-1)/28.0, (H-1)/28.0); + if (type() == FL_ROUND_CLOCK) { + fl_color(active_r() ? color() : fl_inactive(color())); + fl_begin_polygon(); fl_circle(0,0,14); fl_end_polygon(); + fl_color(active_r() ? FL_FOREGROUND_COLOR : fl_inactive(FL_FOREGROUND_COLOR)); + fl_begin_loop(); fl_circle(0,0,14); fl_end_loop(); + } + // draw the shadows: + fl_push_matrix(); + fl_translate(0.60, 0.60); + drawhands(shadow_color, shadow_color); + fl_pop_matrix(); + // draw the tick marks: + fl_push_matrix(); + fl_color(active_r() ? FL_FOREGROUND_COLOR : fl_inactive(FL_FOREGROUND_COLOR)); + for (int i=0; i<12; i++) { + if (i==6) rect(-0.5, 9, 1, 2); + else if (i==3 || i==0 || i== 9) rect(-0.5, 9.5, 1, 1); + else rect(-0.25, 9.5, .5, 1); + fl_rotate(-30); + } + fl_pop_matrix(); + // draw the hands: + drawhands(selection_color(), FL_FOREGROUND_COLOR); // color was 54 + fl_pop_matrix(); +} + +void Fl_Clock_Output::draw() { + draw(x(), y(), w(), h()); + draw_label(); +} + +void Fl_Clock_Output::value(int H, int m, int s) { + if (H!=hour_ || m!=minute_ || s!=second_) { + hour_ = H; minute_ = m; second_ = s; + value_ = (H * 60 + m) * 60 + s; + damage(FL_DAMAGE_CHILD); + } +} + +void Fl_Clock_Output::value(ulong v) { + value_ = v; + struct tm *timeofday; + // Some platforms, notably Windows, now use a 64-bit time_t value... + time_t vv = (time_t)v; + timeofday = localtime(&vv); + value(timeofday->tm_hour, timeofday->tm_min, timeofday->tm_sec); +} + +Fl_Clock_Output::Fl_Clock_Output(int X, int Y, int W, int H, const char *l) +: Fl_Widget(X, Y, W, H, l) { + box(FL_UP_BOX); + selection_color(fl_gray_ramp(5)); + align(FL_ALIGN_BOTTOM); + hour_ = 0; + minute_ = 0; + second_ = 0; + value_ = 0; +} + +//////////////////////////////////////////////////////////////// + +Fl_Clock::Fl_Clock(int X, int Y, int W, int H, const char *l) + : Fl_Clock_Output(X, Y, W, H, l) {} + +Fl_Clock::Fl_Clock(uchar t, int X, int Y, int W, int H, const char *l) + : Fl_Clock_Output(X, Y, W, H, l) { + type(t); + box(t==FL_ROUND_CLOCK ? FL_NO_BOX : FL_UP_BOX); +} + +static void tick(void *v) { + ((Fl_Clock*)v)->value(time(0)); + Fl::add_timeout(1.0, tick, v); +} + +int Fl_Clock::handle(int event) { + switch (event) { + case FL_SHOW: + tick(this); + break; + case FL_HIDE: + Fl::remove_timeout(tick, this); + break; + } + return Fl_Clock_Output::handle(event); +} + +Fl_Clock::~Fl_Clock() { + Fl::remove_timeout(tick, this); +} + +// +// End of "$Id: Fl_Clock.cxx 5472 2006-09-20 03:03:14Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Color_Chooser.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Color_Chooser.cxx new file mode 100644 index 0000000..212a8bd --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Color_Chooser.cxx @@ -0,0 +1,529 @@ +// +// "$Id: Fl_Color_Chooser.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Color chooser for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include + +// Besides being a useful object on it's own, the Fl_Color_Chooser was +// an attempt to make a complex composite object that could be easily +// imbedded into a user interface. If you wish to make complex objects +// of your own, be sure to read this code. + +// The function fl_color_chooser() creates a window containing a color +// chooser and a few buttons and current-color indicators. It is an +// easier interface for simple programs that just need a color. + +// The "hue box" can be a circle or rectilinear. +// You get a circle by defining this: +#define CIRCLE 1 +// And the "hue box" can auto-update when the value changes +// you get this by defining this: +#define UPDATE_HUE_BOX 1 + +void Fl_Color_Chooser::hsv2rgb( + double H, double S, double V, double& R, double& G, double& B) { + if (S < 5.0e-6) { + R = G = B = V; + } else { + int i = (int)H; + double f = H - (float)i; + double p1 = V*(1.0-S); + double p2 = V*(1.0-S*f); + double p3 = V*(1.0-S*(1.0-f)); + switch (i) { + case 0: R = V; G = p3; B = p1; break; + case 1: R = p2; G = V; B = p1; break; + case 2: R = p1; G = V; B = p3; break; + case 3: R = p1; G = p2; B = V; break; + case 4: R = p3; G = p1; B = V; break; + case 5: R = V; G = p1; B = p2; break; + } + } +} + +void Fl_Color_Chooser::rgb2hsv( + double R, double G, double B, double& H, double& S, double& V) { + double maxv = R > G ? R : G; if (B > maxv) maxv = B; + V = maxv; + if (maxv>0) { + double minv = R < G ? R : G; if (B < minv) minv = B; + S = 1.0 - double(minv)/maxv; + if (maxv > minv) { + if (maxv == R) {H = (G-B)/double(maxv-minv); if (H<0) H += 6.0;} + else if (maxv == G) H = 2.0+(B-R)/double(maxv-minv); + else H = 4.0+(R-G)/double(maxv-minv); + } + } +} + +enum {M_RGB, M_BYTE, M_HEX, M_HSV}; // modes +static Fl_Menu_Item mode_menu[] = { + {"rgb"}, + {"byte"}, + {"hex"}, + {"hsv"}, + {0} +}; + +int Flcc_Value_Input::format(char* buf) { + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); + if (c->mode() == M_HEX) return sprintf(buf,"0x%02X", int(value())); + else return Fl_Valuator::format(buf); +} + +void Fl_Color_Chooser::set_valuators() { + switch (mode()) { + case M_RGB: + rvalue.range(0,1); rvalue.step(1,1000); rvalue.value(r_); + gvalue.range(0,1); gvalue.step(1,1000); gvalue.value(g_); + bvalue.range(0,1); bvalue.step(1,1000); bvalue.value(b_); + break; + case M_BYTE: + case M_HEX: + rvalue.range(0,255); rvalue.step(1); rvalue.value(int(255*r_+.5)); + gvalue.range(0,255); gvalue.step(1); gvalue.value(int(255*g_+.5)); + bvalue.range(0,255); bvalue.step(1); bvalue.value(int(255*b_+.5)); + break; + case M_HSV: + rvalue.range(0,6); rvalue.step(1,1000); rvalue.value(hue_); + gvalue.range(0,1); gvalue.step(1,1000); gvalue.value(saturation_); + bvalue.range(0,1); bvalue.step(1,1000); bvalue.value(value_); + break; + } +} + +int Fl_Color_Chooser::rgb(double R, double G, double B) { + if (R == r_ && G == g_ && B == b_) return 0; + r_ = R; g_ = G; b_ = B; + double ph = hue_; + double ps = saturation_; + double pv = value_; + rgb2hsv(R,G,B,hue_,saturation_,value_); + set_valuators(); + set_changed(); + if (value_ != pv) { +#ifdef UPDATE_HUE_BOX + huebox.damage(FL_DAMAGE_SCROLL); +#endif + valuebox.damage(FL_DAMAGE_EXPOSE);} + if (hue_ != ph || saturation_ != ps) { + huebox.damage(FL_DAMAGE_EXPOSE); + valuebox.damage(FL_DAMAGE_SCROLL); + } + return 1; +} + +int Fl_Color_Chooser::hsv(double H, double S, double V) { + H = fmod(H,6.0); if (H < 0.0) H += 6.0; + if (S < 0.0) S = 0.0; else if (S > 1.0) S = 1.0; + if (V < 0.0) V = 0.0; else if (V > 1.0) V = 1.0; + if (H == hue_ && S == saturation_ && V == value_) return 0; + double ph = hue_; + double ps = saturation_; + double pv = value_; + hue_ = H; saturation_ = S; value_ = V; + if (value_ != pv) { +#ifdef UPDATE_HUE_BOX + huebox.damage(FL_DAMAGE_SCROLL); +#endif + valuebox.damage(FL_DAMAGE_EXPOSE);} + if (hue_ != ph || saturation_ != ps) { + huebox.damage(FL_DAMAGE_EXPOSE); + valuebox.damage(FL_DAMAGE_SCROLL); + } + hsv2rgb(H,S,V,r_,g_,b_); + set_valuators(); + set_changed(); + return 1; +} + +//////////////////////////////////////////////////////////////// + +static void tohs(double x, double y, double& h, double& s) { +#ifdef CIRCLE + x = 2*x-1; + y = 1-2*y; + s = sqrt(x*x+y*y); if (s > 1.0) s = 1.0; + h = (3.0/M_PI)*atan2(y,x); + if (h<0) h += 6.0; +#else + h = fmod(6.0*x,6.0); if (h < 0.0) h += 6.0; + s = 1.0-y; if (s < 0.0) s = 0.0; else if (s > 1.0) s = 1.0; +#endif +} + +int Flcc_HueBox::handle(int e) { + static double ih, is; + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); + switch (e) { + case FL_PUSH: + if (Fl::visible_focus()) { + Fl::focus(this); + redraw(); + } + ih = c->hue(); + is = c->saturation(); + case FL_DRAG: { + double Xf, Yf, H, S; + Xf = (Fl::event_x()-x()-Fl::box_dx(box()))/double(w()-Fl::box_dw(box())); + Yf = (Fl::event_y()-y()-Fl::box_dy(box()))/double(h()-Fl::box_dh(box())); + tohs(Xf, Yf, H, S); + if (fabs(H-ih) < 3*6.0/w()) H = ih; + if (fabs(S-is) < 3*1.0/h()) S = is; + if (Fl::event_state(FL_CTRL)) H = ih; + if (c->hsv(H, S, c->value())) c->do_callback(); + } return 1; + case FL_FOCUS : + case FL_UNFOCUS : + if (Fl::visible_focus()) { + redraw(); + return 1; + } + else return 1; + case FL_KEYBOARD : + return handle_key(Fl::event_key()); + default: + return 0; + } +} + +static void generate_image(void* vv, int X, int Y, int W, uchar* buf) { + Flcc_HueBox* v = (Flcc_HueBox*)vv; + int iw = v->w()-Fl::box_dw(v->box()); + double Yf = double(Y)/(v->h()-Fl::box_dh(v->box())); +#ifdef UPDATE_HUE_BOX + const double V = ((Fl_Color_Chooser*)(v->parent()))->value(); +#else + const double V = 1.0; +#endif + for (int x = X; x < X+W; x++) { + double Xf = double(x)/iw; + double H,S; tohs(Xf,Yf,H,S); + double r,g,b; + Fl_Color_Chooser::hsv2rgb(H,S,V,r,g,b); + *buf++ = uchar(255*r+.5); + *buf++ = uchar(255*g+.5); + *buf++ = uchar(255*b+.5); + } +} + +int Flcc_HueBox::handle_key(int key) { + int w1 = w()-Fl::box_dw(box())-6; + int h1 = h()-Fl::box_dh(box())-6; + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); + +#ifdef CIRCLE + int X = int(.5*(cos(c->hue()*(M_PI/3.0))*c->saturation()+1) * w1); + int Y = int(.5*(1-sin(c->hue()*(M_PI/3.0))*c->saturation()) * h1); +#else + int X = int(c->hue()/6.0*w1); + int Y = int((1-c->saturation())*h1); +#endif + + switch (key) { + case FL_Up : + Y -= 3; + break; + case FL_Down : + Y += 3; + break; + case FL_Left : + X -= 3; + break; + case FL_Right : + X += 3; + break; + default : + return 0; + } + + double Xf, Yf, H, S; + Xf = (double)X/(double)w1; + Yf = (double)Y/(double)h1; + tohs(Xf, Yf, H, S); + if (c->hsv(H, S, c->value())) c->do_callback(); + + return 1; +} + +void Flcc_HueBox::draw() { + if (damage()&FL_DAMAGE_ALL) draw_box(); + int x1 = x()+Fl::box_dx(box()); + int yy1 = y()+Fl::box_dy(box()); + int w1 = w()-Fl::box_dw(box()); + int h1 = h()-Fl::box_dh(box()); + if (damage() == FL_DAMAGE_EXPOSE) fl_clip(x1+px,yy1+py,6,6); + fl_draw_image(generate_image, this, x1, yy1, w1, h1); + if (damage() == FL_DAMAGE_EXPOSE) fl_pop_clip(); + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); +#ifdef CIRCLE + int X = int(.5*(cos(c->hue()*(M_PI/3.0))*c->saturation()+1) * (w1-6)); + int Y = int(.5*(1-sin(c->hue()*(M_PI/3.0))*c->saturation()) * (h1-6)); +#else + int X = int(c->hue()/6.0*(w1-6)); + int Y = int((1-c->saturation())*(h1-6)); +#endif + if (X < 0) X = 0; else if (X > w1-6) X = w1-6; + if (Y < 0) Y = 0; else if (Y > h1-6) Y = h1-6; + // fl_color(c->value()>.75 ? FL_BLACK : FL_WHITE); + draw_box(FL_UP_BOX,x1+X,yy1+Y,6,6,Fl::focus() == this ? FL_FOREGROUND_COLOR : FL_GRAY); + px = X; py = Y; +} + +//////////////////////////////////////////////////////////////// + +int Flcc_ValueBox::handle(int e) { + static double iv; + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); + switch (e) { + case FL_PUSH: + if (Fl::visible_focus()) { + Fl::focus(this); + redraw(); + } + iv = c->value(); + case FL_DRAG: { + double Yf; + Yf = 1-(Fl::event_y()-y()-Fl::box_dy(box()))/double(h()-Fl::box_dh(box())); + if (fabs(Yf-iv)<(3*1.0/h())) Yf = iv; + if (c->hsv(c->hue(),c->saturation(),Yf)) c->do_callback(); + } return 1; + case FL_FOCUS : + case FL_UNFOCUS : + if (Fl::visible_focus()) { + redraw(); + return 1; + } + else return 1; + case FL_KEYBOARD : + return handle_key(Fl::event_key()); + default: + return 0; + } +} + +static double tr, tg, tb; +static void generate_vimage(void* vv, int X, int Y, int W, uchar* buf) { + Flcc_ValueBox* v = (Flcc_ValueBox*)vv; + double Yf = 255*(1.0-double(Y)/(v->h()-Fl::box_dh(v->box()))); + uchar r = uchar(tr*Yf+.5); + uchar g = uchar(tg*Yf+.5); + uchar b = uchar(tb*Yf+.5); + for (int x = X; x < X+W; x++) { + *buf++ = r; *buf++ = g; *buf++ = b; + } +} + +void Flcc_ValueBox::draw() { + if (damage()&FL_DAMAGE_ALL) draw_box(); + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); + c->hsv2rgb(c->hue(),c->saturation(),1.0,tr,tg,tb); + int x1 = x()+Fl::box_dx(box()); + int yy1 = y()+Fl::box_dy(box()); + int w1 = w()-Fl::box_dw(box()); + int h1 = h()-Fl::box_dh(box()); + if (damage() == FL_DAMAGE_EXPOSE) fl_clip(x1,yy1+py,w1,6); + fl_draw_image(generate_vimage, this, x1, yy1, w1, h1); + if (damage() == FL_DAMAGE_EXPOSE) fl_pop_clip(); + int Y = int((1-c->value()) * (h1-6)); + if (Y < 0) Y = 0; else if (Y > h1-6) Y = h1-6; + draw_box(FL_UP_BOX,x1,yy1+Y,w1,6,Fl::focus() == this ? FL_FOREGROUND_COLOR : FL_GRAY); + py = Y; +} + +int Flcc_ValueBox::handle_key(int key) { + int h1 = h()-Fl::box_dh(box())-6; + Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent(); + + int Y = int((1-c->value()) * h1); + if (Y < 0) Y = 0; else if (Y > h1) Y = h1; + + switch (key) { + case FL_Up : + Y -= 3; + break; + case FL_Down : + Y += 3; + break; + default : + return 0; + } + + double Yf; + Yf = 1-((double)Y/(double)h1); + if (c->hsv(c->hue(),c->saturation(),Yf)) c->do_callback(); + + return 1; +} + +//////////////////////////////////////////////////////////////// + +void Fl_Color_Chooser::rgb_cb(Fl_Widget* o, void*) { + Fl_Color_Chooser* c = (Fl_Color_Chooser*)(o->parent()); + double R = c->rvalue.value(); + double G = c->gvalue.value(); + double B = c->bvalue.value(); + if (c->mode() == M_HSV) { + if (c->hsv(R,G,B)) c->do_callback(); + return; + } + if (c->mode() != M_RGB) { + R = R/255; + G = G/255; + B = B/255; + } + if (c->rgb(R,G,B)) c->do_callback(); +} + +void Fl_Color_Chooser::mode_cb(Fl_Widget* o, void*) { + Fl_Color_Chooser* c = (Fl_Color_Chooser*)(o->parent()); + // force them to redraw even if value is the same: + c->rvalue.value(-1); + c->gvalue.value(-1); + c->bvalue.value(-1); + c->set_valuators(); +} + +//////////////////////////////////////////////////////////////// + +Fl_Color_Chooser::Fl_Color_Chooser(int X, int Y, int W, int H, const char* L) + : Fl_Group(0,0,195,115,L), + huebox(0,0,115,115), + valuebox(115,0,20,115), + choice(140,0,55,25), + rvalue(140,30,55,25), + gvalue(140,60,55,25), + bvalue(140,90,55,25), + resize_box(0,0,115,115) +{ + end(); + resizable(resize_box); + resize(X,Y,W,H); + r_ = g_ = b_ = 0; + hue_ = 0.0; + saturation_ = 0.0; + value_ = 0.0; + huebox.box(FL_DOWN_FRAME); + valuebox.box(FL_DOWN_FRAME); + choice.menu(mode_menu); + set_valuators(); + rvalue.callback(rgb_cb); + gvalue.callback(rgb_cb); + bvalue.callback(rgb_cb); + choice.callback(mode_cb); + choice.box(FL_THIN_UP_BOX); + choice.textfont(FL_HELVETICA_BOLD_ITALIC); +} + +//////////////////////////////////////////////////////////////// +// fl_color_chooser(): + +#include +#include +#include + +class ColorChip : public Fl_Widget { + void draw(); +public: + uchar r,g,b; + ColorChip(int X, int Y, int W, int H) : Fl_Widget(X,Y,W,H) { + box(FL_ENGRAVED_FRAME);} +}; + +void ColorChip::draw() { + if (damage()&FL_DAMAGE_ALL) draw_box(); + fl_rectf(x()+Fl::box_dx(box()), + y()+Fl::box_dy(box()), + w()-Fl::box_dw(box()), + h()-Fl::box_dh(box()),r,g,b); +} + +static void chooser_cb(Fl_Object* o, void* vv) { + Fl_Color_Chooser* c = (Fl_Color_Chooser*)o; + ColorChip* v = (ColorChip*)vv; + v->r = uchar(255*c->r()+.5); + v->g = uchar(255*c->g()+.5); + v->b = uchar(255*c->b()+.5); + v->damage(FL_DAMAGE_EXPOSE); +} + +extern const char* fl_ok; +extern const char* fl_cancel; + +int fl_color_chooser(const char* name, double& r, double& g, double& b) { + Fl_Window window(215,200,name); + Fl_Color_Chooser chooser(10, 10, 195, 115); + ColorChip ok_color(10, 130, 95, 25); + Fl_Return_Button ok_button(10, 165, 95, 25, fl_ok); + ColorChip cancel_color(110, 130, 95, 25); + cancel_color.r = uchar(255*r+.5); ok_color.r = cancel_color.r; + ok_color.g = cancel_color.g = uchar(255*g+.5); + ok_color.b = cancel_color.b = uchar(255*b+.5); + Fl_Button cancel_button(110, 165, 95, 25, fl_cancel); + window.resizable(chooser); + chooser.rgb(r,g,b); + chooser.callback(chooser_cb, &ok_color); + window.end(); + window.set_modal(); + window.hotspot(window); + window.show(); + while (window.shown()) { + Fl::wait(); + for (;;) { + Fl_Widget* o = Fl::readqueue(); + if (!o) break; + if (o == &ok_button) { + r = chooser.r(); + g = chooser.g(); + b = chooser.b(); + return 1; + } + if (o == &window || o == &cancel_button) return 0; + } + } + return 0; +} + +int fl_color_chooser(const char* name, uchar& r, uchar& g, uchar& b) { + double dr = r/255.0; + double dg = g/255.0; + double db = b/255.0; + if (fl_color_chooser(name,dr,dg,db)) { + r = uchar(255*dr+.5); + g = uchar(255*dg+.5); + b = uchar(255*db+.5); + return 1; + } + return 0; +} + +// +// End of "$Id: Fl_Color_Chooser.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Counter.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Counter.cxx new file mode 100644 index 0000000..3bc6363 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Counter.cxx @@ -0,0 +1,197 @@ +// +// "$Id: Fl_Counter.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Counter widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include + +void Fl_Counter::draw() { + int i; Fl_Boxtype boxtype[5]; + Fl_Color selcolor; + + boxtype[0] = box(); + if (boxtype[0] == FL_UP_BOX) boxtype[0] = FL_DOWN_BOX; + if (boxtype[0] == FL_THIN_UP_BOX) boxtype[0] = FL_THIN_DOWN_BOX; + for (i=1; i<5; i++) + if (mouseobj == i) + boxtype[i] = fl_down(box()); + else + boxtype[i] = box(); + + int xx[5], ww[5]; + if (type() == FL_NORMAL_COUNTER) { + int W = w()*15/100; + xx[1] = x(); ww[1] = W; + xx[2] = x()+1*W; ww[2] = W; + xx[0] = x()+2*W; ww[0] = w()-4*W; + xx[3] = x()+w()-2*W; ww[3] = W; + xx[4] = x()+w()-1*W; ww[4] = W; + } else { + int W = w()*20/100; + xx[1] = 0; ww[1] = 0; + xx[2] = x(); ww[2] = W; + xx[0] = x()+W; ww[0] = w()-2*W; + xx[3] = x()+w()-1*W; ww[3] = W; + xx[4] = 0; ww[4] = 0; + } + + draw_box(boxtype[0], xx[0], y(), ww[0], h(), FL_BACKGROUND2_COLOR); + fl_font(textfont(), textsize()); + fl_color(active_r() ? textcolor() : fl_inactive(textcolor())); + char str[128]; format(str); + fl_draw(str, xx[0], y(), ww[0], h(), FL_ALIGN_CENTER); + if (Fl::focus() == this) draw_focus(boxtype[0], xx[0], y(), ww[0], h()); + if (!(damage()&FL_DAMAGE_ALL)) return; // only need to redraw text + + if (active_r()) + selcolor = labelcolor(); + else + selcolor = fl_inactive(labelcolor()); + + if (type() == FL_NORMAL_COUNTER) { + draw_box(boxtype[1], xx[1], y(), ww[1], h(), color()); + fl_draw_symbol("@-4<<", xx[1], y(), ww[1], h(), selcolor); + } + draw_box(boxtype[2], xx[2], y(), ww[2], h(), color()); + fl_draw_symbol("@-4<", xx[2], y(), ww[2], h(), selcolor); + draw_box(boxtype[3], xx[3], y(), ww[3], h(), color()); + fl_draw_symbol("@-4>", xx[3], y(), ww[3], h(), selcolor); + if (type() == FL_NORMAL_COUNTER) { + draw_box(boxtype[4], xx[4], y(), ww[4], h(), color()); + fl_draw_symbol("@-4>>", xx[4], y(), ww[4], h(), selcolor); + } +} + +void Fl_Counter::increment_cb() { + if (!mouseobj) return; + double v = value(); + switch (mouseobj) { + case 1: v -= lstep_; break; + case 2: v = increment(v, -1); break; + case 3: v = increment(v, 1); break; + case 4: v += lstep_; break; + } + handle_drag(clamp(round(v))); +} + +#define INITIALREPEAT .5 +#define REPEAT .1 + +void Fl_Counter::repeat_callback(void* v) { + Fl_Counter* b = (Fl_Counter*)v; + if (b->mouseobj) { + Fl::add_timeout(REPEAT, repeat_callback, b); + b->increment_cb(); + } +} + +int Fl_Counter::calc_mouseobj() { + if (type() == FL_NORMAL_COUNTER) { + int W = w()*15/100; + if (Fl::event_inside(x(), y(), W, h())) return 1; + if (Fl::event_inside(x()+W, y(), W, h())) return 2; + if (Fl::event_inside(x()+w()-2*W, y(), W, h())) return 3; + if (Fl::event_inside(x()+w()-W, y(), W, h())) return 4; + } else { + int W = w()*20/100; + if (Fl::event_inside(x(), y(), W, h())) return 2; + if (Fl::event_inside(x()+w()-W, y(), W, h())) return 3; + } + return -1; +} + +int Fl_Counter::handle(int event) { + int i; + switch (event) { + case FL_RELEASE: + if (mouseobj) { + Fl::remove_timeout(repeat_callback, this); + mouseobj = 0; + redraw(); + } + handle_release(); + return 1; + case FL_PUSH: + if (Fl::visible_focus()) Fl::focus(this); + handle_push(); + case FL_DRAG: + i = calc_mouseobj(); + if (i != mouseobj) { + Fl::remove_timeout(repeat_callback, this); + mouseobj = (uchar)i; + if (i) Fl::add_timeout(INITIALREPEAT, repeat_callback, this); + increment_cb(); + redraw(); + } + return 1; + case FL_KEYBOARD : + switch (Fl::event_key()) { + case FL_Left: + handle_drag(clamp(increment(value(),-1))); + return 1; + case FL_Right: + handle_drag(clamp(increment(value(),1))); + return 1; + default: + return 0; + } + // break not required because of switch... + case FL_FOCUS : + case FL_UNFOCUS : + if (Fl::visible_focus()) { + redraw(); + return 1; + } else return 0; + case FL_ENTER : + case FL_LEAVE : + return 1; + default: + return 0; + } +} + +Fl_Counter::~Fl_Counter() { + Fl::remove_timeout(repeat_callback, this); +} + +Fl_Counter::Fl_Counter(int X, int Y, int W, int H, const char* l) + : Fl_Valuator(X, Y, W, H, l) { + box(FL_UP_BOX); + selection_color(FL_INACTIVE_COLOR); // was FL_BLUE + align(FL_ALIGN_BOTTOM); + bounds(-1000000.0, 1000000.0); + Fl_Valuator::step(1, 10); + lstep_ = 1.0; + mouseobj = 0; + textfont_ = FL_HELVETICA; + textsize_ = (uchar)FL_NORMAL_SIZE; + textcolor_ = FL_FOREGROUND_COLOR; +} + +// +// End of "$Id: Fl_Counter.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Dial.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Dial.cxx new file mode 100644 index 0000000..3f8a32d --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Dial.cxx @@ -0,0 +1,147 @@ +// +// "$Id: Fl_Dial.cxx 5472 2006-09-20 03:03:14Z mike $" +// +// Circular dial widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include + +// All angles are measured with 0 to the right and counter-clockwise + +void Fl_Dial::draw(int X, int Y, int W, int H) { + if (damage()&FL_DAMAGE_ALL) draw_box(box(), X, Y, W, H, color()); + X += Fl::box_dx(box()); + Y += Fl::box_dy(box()); + W -= Fl::box_dw(box()); + H -= Fl::box_dh(box()); + double angle = (a2-a1)*(value()-minimum())/(maximum()-minimum()) + a1; + if (type() == FL_FILL_DIAL) { + // foo: draw this nicely in certain round box types + int foo = (box() > _FL_ROUND_UP_BOX && Fl::box_dx(box())); + if (foo) {X--; Y--; W+=2; H+=2;} + if (active_r()) fl_color(color()); + else fl_color(fl_inactive(color())); + fl_pie(X, Y, W, H, 270-a1, angle > a1 ? 360+270-angle : 270-360-angle); + if (active_r()) fl_color(selection_color()); + else fl_color(fl_inactive(selection_color())); + fl_pie(X, Y, W, H, 270-angle, 270-a1); + if (foo) { + if (active_r()) fl_color(FL_FOREGROUND_COLOR); + else fl_color(fl_inactive(FL_FOREGROUND_COLOR)); + fl_arc(X, Y, W, H, 0, 360); + } + return; + } + if (!(damage()&FL_DAMAGE_ALL)) { + if (active_r()) fl_color(color()); + else fl_color(fl_inactive(color())); + fl_pie(X+1, Y+1, W-2, H-2, 0, 360); + } + fl_push_matrix(); + fl_translate(X+W/2-.5, Y+H/2-.5); + fl_scale(W-1, H-1); + fl_rotate(45-angle); + if (active_r()) fl_color(selection_color()); + else fl_color(fl_inactive(selection_color())); + if (type()) { // FL_LINE_DIAL + fl_begin_polygon(); + fl_vertex(0.0, 0.0); + fl_vertex(-0.04, 0.0); + fl_vertex(-0.25, 0.25); + fl_vertex(0.0, 0.04); + fl_end_polygon(); + if (active_r()) fl_color(FL_FOREGROUND_COLOR); + else fl_color(fl_inactive(FL_FOREGROUND_COLOR)); + fl_begin_loop(); + fl_vertex(0.0, 0.0); + fl_vertex(-0.04, 0.0); + fl_vertex(-0.25, 0.25); + fl_vertex(0.0, 0.04); + fl_end_loop(); + } else { + fl_begin_polygon(); fl_circle(-0.20, 0.20, 0.07); fl_end_polygon(); + if (active_r()) fl_color(FL_FOREGROUND_COLOR); + else fl_color(fl_inactive(FL_FOREGROUND_COLOR)); + fl_begin_loop(); fl_circle(-0.20, 0.20, 0.07); fl_end_loop(); + } + fl_pop_matrix(); +} + +void Fl_Dial::draw() { + draw(x(), y(), w(), h()); + draw_label(); +} + +int Fl_Dial::handle(int event, int X, int Y, int W, int H) { + switch (event) { + case FL_PUSH: + handle_push(); + case FL_DRAG: { + int mx = (Fl::event_x()-X-W/2)*H; + int my = (Fl::event_y()-Y-H/2)*W; + if (!mx && !my) return 1; + double angle = 270-atan2((float)-my, (float)mx)*180/M_PI; + double oldangle = (a2-a1)*(value()-minimum())/(maximum()-minimum()) + a1; + while (angle < oldangle-180) angle += 360; + while (angle > oldangle+180) angle -= 360; + double val; + if ((a1= a1)) { + val = minimum(); + } else if ((a1= a2) : (angle <= a2)) { + val = maximum(); + } else { + val = minimum() + (maximum()-minimum())*(angle-a1)/(a2-a1); + } + handle_drag(clamp(round(val))); + } return 1; + case FL_RELEASE: + handle_release(); + return 1; + case FL_ENTER : + case FL_LEAVE : + return 1; + default: + return 0; + } +} + +int Fl_Dial::handle(int e) { + return handle(e, x(), y(), w(), h()); +} + +Fl_Dial::Fl_Dial(int X, int Y, int W, int H, const char* l) + : Fl_Valuator(X, Y, W, H, l) { + box(FL_OVAL_BOX); + selection_color(FL_INACTIVE_COLOR); // was 37 + a1 = 45; + a2 = 315; +} + +// +// End of "$Id: Fl_Dial.cxx 5472 2006-09-20 03:03:14Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Double_Window.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Double_Window.cxx new file mode 100644 index 0000000..eaaacfb --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Double_Window.cxx @@ -0,0 +1,452 @@ +// +// "$Id: Fl_Double_Window.cxx 5829 2007-05-14 15:51:00Z matt $" +// +// Double-buffered window code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2007 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include + +// On systems that support double buffering "naturally" the base +// Fl_Window class will probably do double-buffer and this subclass +// does nothing. + +#if USE_XDBE + +#include + +static int use_xdbe; + +static int can_xdbe() { + static int tried; + if (!tried) { + tried = 1; + int event_base, error_base; + if (!XdbeQueryExtension(fl_display, &event_base, &error_base)) return 0; + Drawable root = RootWindow(fl_display,fl_screen); + int numscreens = 1; + XdbeScreenVisualInfo *a = XdbeGetVisualInfo(fl_display,&root,&numscreens); + if (!a) return 0; + for (int j = 0; j < a->count; j++) + if (a->visinfo[j].visual == fl_visual->visualid + /*&& a->visinfo[j].perflevel > 0*/) {use_xdbe = 1; break;} + XdbeFreeVisualInfo(a); + } + return use_xdbe; +} +#endif + +void Fl_Double_Window::show() { + Fl_Window::show(); +} + +#ifdef WIN32 + +// Code used to switch output to an off-screen window. See macros in +// win32.H which save the old state in local variables. + +typedef struct { BYTE a; BYTE b; BYTE c; BYTE d; } FL_BLENDFUNCTION; +typedef BOOL (WINAPI* fl_alpha_blend_func) + (HDC,int,int,int,int,HDC,int,int,int,int,FL_BLENDFUNCTION); +static fl_alpha_blend_func fl_alpha_blend = NULL; +static FL_BLENDFUNCTION blendfunc = { 0, 0, 255, 1}; + +/* + * This function checks if the version of MSWindows that we + * curently run on supports alpha blending for bitmap transfers + * and finds the required function if so. + */ +char fl_can_do_alpha_blending() { + static char been_here = 0; + static char can_do = 0; + // do this test only once + if (been_here) return can_do; + been_here = 1; + // load the library that implements alpha blending + HMODULE hMod = LoadLibrary("MSIMG32.DLL"); + // give up if that doesn't exist (Win95?) + if (!hMod) return 0; + // now find the blending function inside that dll + fl_alpha_blend = (fl_alpha_blend_func)GetProcAddress(hMod, "AlphaBlend"); + // give up if we can't find it (Win95) + if (!fl_alpha_blend) return 0; + // we have the call, but does our display support alpha blending? + HDC dc = 0L;//fl_gc; + // get the current or the desktop's device context + if (!dc) dc = GetDC(0L); + if (!dc) return 0; + // check the device capabilities flags. However GetDeviceCaps + // does not return anything useful, so we have to do it manually: + + HBITMAP bm = CreateCompatibleBitmap(dc, 1, 1); + HDC new_gc = CreateCompatibleDC(dc); + int save = SaveDC(new_gc); + SelectObject(new_gc, bm); + /*COLORREF set = */ SetPixel(new_gc, 0, 0, 0x01010101); + BOOL alpha_ok = fl_alpha_blend(dc, 0, 0, 1, 1, new_gc, 0, 0, 1, 1, blendfunc); + RestoreDC(new_gc, save); + DeleteDC(new_gc); + DeleteObject(bm); + + if (!fl_gc) ReleaseDC(0L, dc); + if (alpha_ok) can_do = 1; + return can_do; +} + +HDC fl_makeDC(HBITMAP bitmap) { + HDC new_gc = CreateCompatibleDC(fl_gc); + SetTextAlign(new_gc, TA_BASELINE|TA_LEFT); + SetBkMode(new_gc, TRANSPARENT); +#if USE_COLORMAP + if (fl_palette) SelectPalette(new_gc, fl_palette, FALSE); +#endif + SelectObject(new_gc, bitmap); + return new_gc; +} + +void fl_copy_offscreen(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) { + HDC new_gc = CreateCompatibleDC(fl_gc); + int save = SaveDC(new_gc); + SelectObject(new_gc, bitmap); + BitBlt(fl_gc, x, y, w, h, new_gc, srcx, srcy, SRCCOPY); + RestoreDC(new_gc, save); + DeleteDC(new_gc); +} + +void fl_copy_offscreen_with_alpha(int x,int y,int w,int h,HBITMAP bitmap,int srcx,int srcy) { + HDC new_gc = CreateCompatibleDC(fl_gc); + int save = SaveDC(new_gc); + SelectObject(new_gc, bitmap); + BOOL alpha_ok = 0; + // first try to alpha blend + if (fl_can_do_alpha_blending()) + alpha_ok = fl_alpha_blend(fl_gc, x, y, w, h, new_gc, srcx, srcy, w, h, blendfunc); + // if that failed (it shouldn,t), still copy the bitmap over, but now alpha is 1 + if (!alpha_ok) + BitBlt(fl_gc, x, y, w, h, new_gc, srcx, srcy, SRCCOPY); + RestoreDC(new_gc, save); + DeleteDC(new_gc); +} + +extern void fl_restore_clip(); + +#elif defined(__APPLE_QD__) + +char fl_can_do_alpha_blending() { + return 0; +} + +GWorldPtr fl_create_offscreen(int w, int h) { + GWorldPtr gw; + Rect bounds; + bounds.left=0; bounds.right=w; bounds.top=0; bounds.bottom=h; + QDErr err = NewGWorld(&gw, 0, &bounds, 0L, 0L, 0); // 'useTempMem' should not be used (says the Carbon port manual) + if ( err == -108 ) + { } +// fl_message( "The application memory is low. Please increase the initial memory assignment.\n" ); + if (err!=noErr || gw==0L) return 0L; + return gw; +} + +void fl_copy_offscreen(int x,int y,int w,int h,GWorldPtr gWorld,int srcx,int srcy) { + Rect src; + if ( !gWorld ) return; + src.top = srcy; src.left = srcx; src.bottom = srcy+h; src.right = srcx+w; + Rect dst; + GrafPtr dstPort; GetPort(&dstPort); + dst.top = y; dst.left = x; dst.bottom = y+h; dst.right = x+w; + RGBColor rgb, oldbg, oldfg; + GetForeColor(&oldfg); + GetBackColor(&oldbg); + rgb.red = 0xffff; rgb.green = 0xffff; rgb.blue = 0xffff; + RGBBackColor( &rgb ); + rgb.red = 0x0000; rgb.green = 0x0000; rgb.blue = 0x0000; + RGBForeColor( &rgb ); + CopyBits(GetPortBitMapForCopyBits(gWorld), GetPortBitMapForCopyBits(dstPort), &src, &dst, srcCopy, 0L); + RGBBackColor(&oldbg); + RGBForeColor(&oldfg); +} + +void fl_delete_offscreen(GWorldPtr gWorld) { + DisposeGWorld(gWorld); +} + +static GrafPtr prevPort; +static GDHandle prevGD; + +void fl_begin_offscreen(GWorldPtr gWorld) { + GetGWorld( &prevPort, &prevGD ); + if ( gWorld ) + { + SetGWorld( gWorld, 0 ); // sets the correct port + PixMapHandle pm = GetGWorldPixMap(gWorld); + Boolean ret = LockPixels(pm); + if ( ret == false ) + { + Rect rect; + GetPortBounds( gWorld, &rect ); + UpdateGWorld( &gWorld, 0, &rect, 0, 0, 0 ); + pm = GetGWorldPixMap( gWorld ); + LockPixels( pm ); + } + fl_window = 0; + } + fl_push_no_clip(); +} + +void fl_end_offscreen() { + GWorldPtr currPort; + GDHandle currGD; + GetGWorld( &currPort, &currGD ); + fl_pop_clip(); + PixMapHandle pm = GetGWorldPixMap(currPort); + UnlockPixels(pm); + SetGWorld( prevPort, prevGD ); + fl_window = GetWindowFromPort( prevPort ); +} + +extern void fl_restore_clip(); + +#elif defined(__APPLE_QUARTZ__) + +char fl_can_do_alpha_blending() { + return 1; +} + +Fl_Offscreen fl_create_offscreen(int w, int h) { + void *data = calloc(w*h,4); + CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); + CGContextRef ctx = CGBitmapContextCreate( + data, w, h, 8, w*4, lut, kCGImageAlphaNoneSkipLast); + CGColorSpaceRelease(lut); + return (Fl_Offscreen)ctx; +} + +Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h) { + void *data = calloc(w*h,4); + CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); + CGContextRef ctx = CGBitmapContextCreate( + data, w, h, 8, w*4, lut, kCGImageAlphaPremultipliedLast); + CGColorSpaceRelease(lut); + return (Fl_Offscreen)ctx; +} + +void fl_copy_offscreen(int x,int y,int w,int h,Fl_Offscreen osrc,int srcx,int srcy) { + CGContextRef src = (CGContextRef)osrc; + void *data = CGBitmapContextGetData(src); + int sw = CGBitmapContextGetWidth(src); + int sh = CGBitmapContextGetHeight(src); + CGImageAlphaInfo alpha = CGBitmapContextGetAlphaInfo(src); + CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); + CGDataProviderRef src_bytes = CGDataProviderCreateWithData( 0L, data, sw*sh*4, 0L); + CGImageRef img = CGImageCreate( sw, sh, 8, 4*8, 4*sw, lut, alpha, + src_bytes, 0L, false, kCGRenderingIntentDefault); + // fl_push_clip(); + CGRect rect = { { x, y }, { w, h } }; + Fl_X::q_begin_image(rect, srcx, srcy, sw, sh); + CGContextDrawImage(fl_gc, rect, img); + Fl_X::q_end_image(); + CGImageRelease(img); + CGColorSpaceRelease(lut); + CGDataProviderRelease(src_bytes); +} + +void fl_delete_offscreen(Fl_Offscreen ctx) { + if (!ctx) return; + void *data = CGBitmapContextGetData((CGContextRef)ctx); + CGContextRelease((CGContextRef)ctx); + if (!data) return; + free(data); +} + +const int stack_max = 16; +static int stack_ix = 0; +static CGContextRef stack_gc[stack_max]; +static Window stack_window[stack_max]; + +void fl_begin_offscreen(Fl_Offscreen ctx) { + if (stack_ix0) + stack_ix--; + else + fprintf(stderr, "FLTK CGContext Stack underflow error\n"); + if (stack_ixother_xid) { +#if USE_XDBE + if (can_xdbe()) { + myi->other_xid = + XdbeAllocateBackBufferName(fl_display, fl_xid(this), XdbeCopied); + myi->backbuffer_bad = 1; + } else +#endif +#ifdef __APPLE_QD__ + if ( ( !QDIsPortBuffered( GetWindowPort(myi->xid) ) ) + || force_doublebuffering_ ) { + myi->other_xid = fl_create_offscreen(w(), h()); + clear_damage(FL_DAMAGE_ALL); + } +#elif defined(__APPLE_QUARTZ__) + if (force_doublebuffering_) { + myi->other_xid = fl_create_offscreen(w(), h()); + clear_damage(FL_DAMAGE_ALL); + } +#else + myi->other_xid = fl_create_offscreen(w(), h()); + clear_damage(FL_DAMAGE_ALL); +#endif + } +#if USE_XDBE + if (use_xdbe) { + if (myi->backbuffer_bad) { + // Make sure we do a complete redraw... + if (myi->region) {XDestroyRegion(myi->region); myi->region = 0;} + clear_damage(FL_DAMAGE_ALL); + myi->backbuffer_bad = 0; + } + + // Redraw as needed... + if (damage()) { + fl_clip_region(myi->region); myi->region = 0; + fl_window = myi->other_xid; + draw(); + fl_window = myi->xid; + } + + // Copy contents of back buffer to window... + XdbeSwapInfo s; + s.swap_window = fl_xid(this); + s.swap_action = XdbeCopied; + XdbeSwapBuffers(fl_display, &s, 1); + return; + } else +#endif + if (damage() & ~FL_DAMAGE_EXPOSE) { + fl_clip_region(myi->region); myi->region = 0; +#ifdef WIN32 + HDC _sgc = fl_gc; + fl_gc = fl_makeDC(myi->other_xid); + int save = SaveDC(fl_gc); + fl_restore_clip(); // duplicate region into new gc + draw(); + RestoreDC(fl_gc, save); + DeleteDC(fl_gc); + fl_gc = _sgc; +#elif defined(__APPLE__) + if ( myi->other_xid ) { + fl_begin_offscreen( myi->other_xid ); + fl_clip_region( 0 ); + draw(); + fl_end_offscreen(); + } else { + draw(); + } +#else // X: + fl_window = myi->other_xid; + draw(); + fl_window = myi->xid; +#endif + } + if (eraseoverlay) fl_clip_region(0); + // on Irix (at least) it is faster to reduce the area copied to + // the current clip region: + int X,Y,W,H; fl_clip_box(0,0,w(),h(),X,Y,W,H); + if (myi->other_xid) fl_copy_offscreen(X, Y, W, H, myi->other_xid, X, Y); +} + +void Fl_Double_Window::resize(int X,int Y,int W,int H) { + int ow = w(); + int oh = h(); + Fl_Window::resize(X,Y,W,H); +#if USE_XDBE + if (use_xdbe) return; +#endif + Fl_X* myi = Fl_X::i(this); + if (myi && myi->other_xid && (ow != w() || oh != h())) { + fl_delete_offscreen(myi->other_xid); + myi->other_xid = 0; + } +} + +void Fl_Double_Window::hide() { + Fl_X* myi = Fl_X::i(this); + if (myi && myi->other_xid) { +#if USE_XDBE + if (!use_xdbe) +#endif + fl_delete_offscreen(myi->other_xid); + } + Fl_Window::hide(); +} + +Fl_Double_Window::~Fl_Double_Window() { + hide(); +} + +// +// End of "$Id: Fl_Double_Window.cxx 5829 2007-05-14 15:51:00Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_File_Browser.cxx b/third_party/windows/fltk-1.1.10/src/Fl_File_Browser.cxx new file mode 100644 index 0000000..aa37a76 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_File_Browser.cxx @@ -0,0 +1,639 @@ +// +// "$Id: Fl_File_Browser.cxx 5635 2007-01-23 15:02:00Z mike $" +// +// Fl_File_Browser routines. +// +// Copyright 1999-2006 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_File_Browser::full_height() - Return the height of the list. +// Fl_File_Browser::item_height() - Return the height of a list item. +// Fl_File_Browser::item_width() - Return the width of a list item. +// Fl_File_Browser::item_draw() - Draw a list item. +// Fl_File_Browser::Fl_File_Browser() - Create a Fl_File_Browser widget. +// Fl_File_Browser::load() - Load a directory into the browser. +// Fl_File_Browser::filter() - Set the filename filter. +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include +#include +#include "flstring.h" + +#ifdef __CYGWIN__ +# include +#elif defined(WIN32) +# include +# include +// Apparently Borland C++ defines DIRECTORY in , which +// interfers with the Fl_File_Icon enumeration of the same name. +# ifdef DIRECTORY +# undef DIRECTORY +# endif // DIRECTORY +#endif // __CYGWIN__ + +#ifdef __EMX__ +# define INCL_DOS +# define INCL_DOSMISC +# include +#endif // __EMX__ + +// CodeWarrior (__MWERKS__) gets its include paths confused, so we +// temporarily disable this... +#if defined(__APPLE__) && !defined(__MWERKS__) +# include +# include +# include +#endif // __APPLE__ && !__MWERKS__ + + +// +// FL_BLINE definition from "Fl_Browser.cxx"... +// + +#define SELECTED 1 +#define NOTDISPLAYED 2 + +struct FL_BLINE // data is in a linked list of these +{ + FL_BLINE *prev; // Previous item in list + FL_BLINE *next; // Next item in list + void *data; // Pointer to data (function) + short length; // sizeof(txt)-1, may be longer than string + char flags; // selected, displayed + char txt[1]; // start of allocated array +}; + + +// +// 'Fl_File_Browser::full_height()' - Return the height of the list. +// + +int // O - Height in pixels +Fl_File_Browser::full_height() const +{ + int i, // Looping var + th; // Total height of list. + + + for (i = 0, th = 0; i < size(); i ++) + th += item_height(find_line(i)); + + return (th); +} + + +// +// 'Fl_File_Browser::item_height()' - Return the height of a list item. +// + +int // O - Height in pixels +Fl_File_Browser::item_height(void *p) const // I - List item data +{ + FL_BLINE *line; // Pointer to line + char *t; // Pointer into text + int height; // Width of line + int textheight; // Height of text + + + // Figure out the standard text height... + fl_font(textfont(), textsize()); + textheight = fl_height(); + + // We always have at least 1 line... + height = textheight; + + // Scan for newlines... + line = (FL_BLINE *)p; + + if (line != NULL) + for (t = line->txt; *t != '\0'; t ++) + if (*t == '\n') + height += textheight; + + // If we have enabled icons then add space for them... + if (Fl_File_Icon::first() != NULL && height < iconsize_) + height = iconsize_; + + // Add space for the selection border.. + height += 2; + + // Return the height + return (height); +} + + +// +// 'Fl_File_Browser::item_width()' - Return the width of a list item. +// + +int // O - Width in pixels +Fl_File_Browser::item_width(void *p) const // I - List item data +{ + int i; // Looping var + FL_BLINE *line; // Pointer to line + char *t, // Pointer into text + *ptr, // Pointer into fragment + fragment[10240]; // Fragment of text + int width, // Width of line + tempwidth; // Width of fragment + int column; // Current column + const int *columns; // Columns + + + // Scan for newlines... + line = (FL_BLINE *)p; + columns = column_widths(); + + // Set the font and size... + if (line->txt[strlen(line->txt) - 1] == '/') + fl_font(textfont() | FL_BOLD, textsize()); + else + fl_font(textfont(), textsize()); + + if (strchr(line->txt, '\n') == NULL && + strchr(line->txt, column_char()) == NULL) + { + // Do a fast width calculation... + width = (int)fl_width(line->txt); + } + else + { + // More than 1 line or have columns; find the maximum width... + width = 0; + tempwidth = 0; + column = 0; + + for (t = line->txt, ptr = fragment; *t != '\0'; t ++) + if (*t == '\n') + { + // Newline - nul terminate this fragment and get the width... + *ptr = '\0'; + + tempwidth += (int)fl_width(fragment); + + // Update the max width as needed... + if (tempwidth > width) + width = tempwidth; + + // Point back to the start of the fragment... + ptr = fragment; + tempwidth = 0; + column = 0; + } + else if (*t == column_char()) + { + // Advance to the next column... + column ++; + if (columns) + { + for (i = 0, tempwidth = 0; i < column && columns[i]; i ++) + tempwidth += columns[i]; + } + else + tempwidth = column * (int)(fl_height() * 0.6 * 8.0); + + if (tempwidth > width) + width = tempwidth; + + ptr = fragment; + } + else + *ptr++ = *t; + + if (ptr > fragment) + { + // Nul terminate this fragment and get the width... + *ptr = '\0'; + + tempwidth += (int)fl_width(fragment); + + // Update the max width as needed... + if (tempwidth > width) + width = tempwidth; + } + } + + // If we have enabled icons then add space for them... + if (Fl_File_Icon::first() != NULL) + width += iconsize_ + 8; + + // Add space for the selection border.. + width += 2; + + // Return the width + return (width); +} + + +// +// 'Fl_File_Browser::item_draw()' - Draw a list item. +// + +void +Fl_File_Browser::item_draw(void *p, // I - List item data + int X, // I - Upper-lefthand X coordinate + int Y, // I - Upper-lefthand Y coordinate + int W, // I - Width of item + int) const // I - Height of item +{ + int i; // Looping var + FL_BLINE *line; // Pointer to line + Fl_Color c; // Text color + char *t, // Pointer into text + *ptr, // Pointer into fragment + fragment[10240]; // Fragment of text + int width, // Width of line + height; // Height of line + int column; // Current column + const int *columns; // Columns + + + // Draw the list item text... + line = (FL_BLINE *)p; + + if (line->txt[strlen(line->txt) - 1] == '/') + fl_font(textfont() | FL_BOLD, textsize()); + else + fl_font(textfont(), textsize()); + + if (line->flags & SELECTED) + c = fl_contrast(textcolor(), selection_color()); + else + c = textcolor(); + + if (Fl_File_Icon::first() == NULL) + { + // No icons, just draw the text... + X ++; + W -= 2; + } + else + { + // Draw the icon if it is set... + if (line->data) + ((Fl_File_Icon *)line->data)->draw(X, Y, iconsize_, iconsize_, + (line->flags & SELECTED) ? FL_YELLOW : + FL_LIGHT2, + active_r()); + + // Draw the text offset to the right... + X += iconsize_ + 9; + W -= iconsize_ - 10; + + // Center the text vertically... + height = fl_height(); + + for (t = line->txt; *t != '\0'; t ++) + if (*t == '\n') + height += fl_height(); + + if (height < iconsize_) + Y += (iconsize_ - height) / 2; + } + + // Draw the text... + line = (FL_BLINE *)p; + columns = column_widths(); + width = 0; + column = 0; + + if (active_r()) + fl_color(c); + else + fl_color(fl_inactive(c)); + + for (t = line->txt, ptr = fragment; *t != '\0'; t ++) + if (*t == '\n') + { + // Newline - nul terminate this fragment and draw it... + *ptr = '\0'; + + fl_draw(fragment, X + width, Y, W - width, fl_height(), + (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP), 0, 0); + + // Point back to the start of the fragment... + ptr = fragment; + width = 0; + Y += fl_height(); + column = 0; + } + else if (*t == column_char()) + { + // Tab - nul terminate this fragment and draw it... + *ptr = '\0'; + + int cW = W - width; // Clip width... + + if (columns) + { + // Try clipping inside this column... + for (i = 0; i < column && columns[i]; i ++); + + if (columns[i]) + cW = columns[i]; + } + + fl_draw(fragment, X + width, Y, cW, fl_height(), + (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP), 0, 0); + + // Advance to the next column... + column ++; + if (columns) + { + for (i = 0, width = 0; i < column && columns[i]; i ++) + width += columns[i]; + } + else + width = column * (int)(fl_height() * 0.6 * 8.0); + + ptr = fragment; + } + else + *ptr++ = *t; + + if (ptr > fragment) + { + // Nul terminate this fragment and draw it... + *ptr = '\0'; + + fl_draw(fragment, X + width, Y, W - width, fl_height(), + (Fl_Align)(FL_ALIGN_LEFT | FL_ALIGN_CLIP), 0, 0); + } +} + + +// +// 'Fl_File_Browser::Fl_File_Browser()' - Create a Fl_File_Browser widget. +// + +Fl_File_Browser::Fl_File_Browser(int X, // I - Upper-lefthand X coordinate + int Y, // I - Upper-lefthand Y coordinate + int W, // I - Width in pixels + int H, // I - Height in pixels + const char *l) // I - Label text + : Fl_Browser(X, Y, W, H, l) +{ + // Initialize the filter pattern, current directory, and icon size... + pattern_ = "*"; + directory_ = ""; + iconsize_ = (uchar)(3 * textsize() / 2); + filetype_ = FILES; +} + + +// +// 'Fl_File_Browser::load()' - Load a directory into the browser. +// + +int // O - Number of files loaded +Fl_File_Browser::load(const char *directory,// I - Directory to load + Fl_File_Sort_F *sort) // I - Sort function to use +{ + int i; // Looping var + int num_files; // Number of files in directory + int num_dirs; // Number of directories in list + char filename[4096]; // Current file + Fl_File_Icon *icon; // Icon to use + + +// printf("Fl_File_Browser::load(\"%s\")\n", directory); + + clear(); + + directory_ = directory; + + if (!directory) + return (0); + + if (directory_[0] == '\0') + { + // + // No directory specified; for UNIX list all mount points. For DOS + // list all valid drive letters... + // + + num_files = 0; + if ((icon = Fl_File_Icon::find("any", Fl_File_Icon::DEVICE)) == NULL) + icon = Fl_File_Icon::find("any", Fl_File_Icon::DIRECTORY); + +#ifdef WIN32 +# ifdef __CYGWIN__ + // + // Cygwin provides an implementation of setmntent() to get the list + // of available drives... + // + FILE *m = setmntent("/-not-used-", "r"); + struct mntent *p; + + while ((p = getmntent (m)) != NULL) { + add(p->mnt_dir, icon); + num_files ++; + } + + endmntent(m); +# else + // + // Normal WIN32 code uses drive bits... + // + DWORD drives; // Drive available bits + + drives = GetLogicalDrives(); + for (i = 'A'; i <= 'Z'; i ++, drives >>= 1) + if (drives & 1) + { + sprintf(filename, "%c:/", i); + + if (i < 'C') // see also: GetDriveType and GetVolumeInformation in WIN32 + add(filename, icon); + else + add(filename, icon); + + num_files ++; + } +# endif // __CYGWIN__ +#elif defined(__EMX__) + // + // OS/2 code uses drive bits... + // + ULONG curdrive; // Current drive + ULONG drives; // Drive available bits + int start = 3; // 'C' (MRS - dunno if this is correct!) + + + DosQueryCurrentDisk(&curdrive, &drives); + drives >>= start - 1; + for (i = 'A'; i <= 'Z'; i ++, drives >>= 1) + if (drives & 1) + { + sprintf(filename, "%c:/", i); + add(filename, icon); + + num_files ++; + } +#elif defined(__APPLE__) && !defined(__MWERKS__) + // MacOS X and Darwin use getfsstat() system call... + int numfs; // Number of file systems + struct statfs *fs; // Buffer for file system info + + + // We always have the root filesystem. + add("/", icon); + + // Get the mounted filesystems... + numfs = getfsstat(NULL, 0, MNT_NOWAIT); + if (numfs > 0) { + // We have file systems, get them... + fs = new struct statfs[numfs]; + getfsstat(fs, sizeof(struct statfs) * numfs, MNT_NOWAIT); + + // Add filesystems to the list... + for (i = 0; i < numfs; i ++) { + // Ignore "/", "/dev", and "/.vol"... + if (fs[i].f_mntonname[1] && strcmp(fs[i].f_mntonname, "/dev") && + strcmp(fs[i].f_mntonname, "/.vol")) { + snprintf(filename, sizeof(filename), "%s/", fs[i].f_mntonname); + add(filename, icon); + } + num_files ++; + } + + // Free the memory used for the file system info array... + delete[] fs; + } +#else + // + // UNIX code uses /etc/fstab or similar... + // + FILE *mtab; // /etc/mtab or /etc/mnttab file + char line[1024]; // Input line + + // + // Open the file that contains a list of mounted filesystems... + // + + mtab = fopen("/etc/mnttab", "r"); // Fairly standard + if (mtab == NULL) + mtab = fopen("/etc/mtab", "r"); // More standard + if (mtab == NULL) + mtab = fopen("/etc/fstab", "r"); // Otherwise fallback to full list + if (mtab == NULL) + mtab = fopen("/etc/vfstab", "r"); // Alternate full list file + + if (mtab != NULL) + { + while (fgets(line, sizeof(line), mtab) != NULL) + { + if (line[0] == '#' || line[0] == '\n') + continue; + if (sscanf(line, "%*s%4095s", filename) != 1) + continue; + + strlcat(filename, "/", sizeof(filename)); + +// printf("Fl_File_Browser::load() - adding \"%s\" to list...\n", filename); + add(filename, icon); + num_files ++; + } + + fclose(mtab); + } +#endif // WIN32 || __EMX__ + } + else + { + dirent **files; // Files in in directory + + + // + // Build the file list... + // + +#if (defined(WIN32) && !defined(__CYGWIN__)) || defined(__EMX__) + strlcpy(filename, directory_, sizeof(filename)); + i = strlen(filename) - 1; + + if (i == 2 && filename[1] == ':' && + (filename[2] == '/' || filename[2] == '\\')) + filename[2] = '/'; + else if (filename[i] != '/' && filename[i] != '\\') + strlcat(filename, "/", sizeof(filename)); + + num_files = fl_filename_list(filename, &files, sort); +#else + num_files = fl_filename_list(directory_, &files, sort); +#endif /* WIN32 || __EMX__ */ + + if (num_files <= 0) + return (0); + + for (i = 0, num_dirs = 0; i < num_files; i ++) { + if (strcmp(files[i]->d_name, "./")) { + snprintf(filename, sizeof(filename), "%s/%s", directory_, + files[i]->d_name); + + icon = Fl_File_Icon::find(filename); + if ((icon && icon->type() == Fl_File_Icon::DIRECTORY) || + _fl_filename_isdir_quick(filename)) { + num_dirs ++; + insert(num_dirs, files[i]->d_name, icon); + } else if (filetype_ == FILES && + fl_filename_match(files[i]->d_name, pattern_)) { + add(files[i]->d_name, icon); + } + } + + free(files[i]); + } + + free(files); + } + + return (num_files); +} + + +// +// 'Fl_File_Browser::filter()' - Set the filename filter. +// + +void +Fl_File_Browser::filter(const char *pattern) // I - Pattern string +{ + // If pattern is NULL set the pattern to "*"... + if (pattern) + pattern_ = pattern; + else + pattern_ = "*"; +} + + +// +// End of "$Id: Fl_File_Browser.cxx 5635 2007-01-23 15:02:00Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_File_Chooser.cxx b/third_party/windows/fltk-1.1.10/src/Fl_File_Chooser.cxx new file mode 100644 index 0000000..ca1a7cb --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_File_Chooser.cxx @@ -0,0 +1,444 @@ +// +// "$Id: Fl_File_Chooser.cxx 6092 2008-04-11 12:57:37Z matt $" +// +// Fl_File_Chooser dialog for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// generated by Fast Light User Interface Designer (fluid) version 1.0108 + +#include "../FL/Fl_File_Chooser.H" +#include + +void Fl_File_Chooser::cb_window_i(Fl_Double_Window*, void*) { + fileName->value(""); +fileList->deselect(); +Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this); +window->hide(); +} +void Fl_File_Chooser::cb_window(Fl_Double_Window* o, void* v) { + ((Fl_File_Chooser*)(o->user_data()))->cb_window_i(o,v); +} + +void Fl_File_Chooser::cb_showChoice_i(Fl_Choice*, void*) { + showChoiceCB(); +} +void Fl_File_Chooser::cb_showChoice(Fl_Choice* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->user_data()))->cb_showChoice_i(o,v); +} + +void Fl_File_Chooser::cb_favoritesButton_i(Fl_Menu_Button*, void*) { + favoritesButtonCB(); +} +void Fl_File_Chooser::cb_favoritesButton(Fl_Menu_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->user_data()))->cb_favoritesButton_i(o,v); +} + +void Fl_File_Chooser::cb_newButton_i(Fl_Button*, void*) { + newdir(); +} +void Fl_File_Chooser::cb_newButton(Fl_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->user_data()))->cb_newButton_i(o,v); +} + +#include +static unsigned char idata_new[] = +{0,0,120,0,132,0,2,1,1,254,1,128,49,128,49,128,253,128,253,128,49,128,49, +128,1,128,1,128,255,255,0,0}; +static Fl_Bitmap image_new(idata_new, 16, 16); + +void Fl_File_Chooser::cb__i(Fl_Tile*, void*) { + update_preview(); +} +void Fl_File_Chooser::cb_(Fl_Tile* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->user_data()))->cb__i(o,v); +} + +void Fl_File_Chooser::cb_fileList_i(Fl_File_Browser*, void*) { + fileListCB(); +} +void Fl_File_Chooser::cb_fileList(Fl_File_Browser* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->user_data()))->cb_fileList_i(o,v); +} + +void Fl_File_Chooser::cb_previewButton_i(Fl_Check_Button*, void*) { + preview(previewButton->value()); +} +void Fl_File_Chooser::cb_previewButton(Fl_Check_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->parent()->user_data()))->cb_previewButton_i(o,v); +} + +void Fl_File_Chooser::cb_fileName_i(Fl_File_Input*, void*) { + fileNameCB(); +} +void Fl_File_Chooser::cb_fileName(Fl_File_Input* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->user_data()))->cb_fileName_i(o,v); +} + +void Fl_File_Chooser::cb_okButton_i(Fl_Return_Button*, void*) { + window->hide(); + +// Do any callback that is registered... +if (callback_) + (*callback_)(this, data_); +} +void Fl_File_Chooser::cb_okButton(Fl_Return_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->parent()->user_data()))->cb_okButton_i(o,v); +} + +void Fl_File_Chooser::cb_cancelButton_i(Fl_Button*, void*) { + fileName->value(""); +fileList->deselect(); +Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this); +window->hide(); +} +void Fl_File_Chooser::cb_cancelButton(Fl_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->parent()->user_data()))->cb_cancelButton_i(o,v); +} + +void Fl_File_Chooser::cb_favList_i(Fl_File_Browser*, void*) { + favoritesCB(favList); +} +void Fl_File_Chooser::cb_favList(Fl_File_Browser* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->user_data()))->cb_favList_i(o,v); +} + +void Fl_File_Chooser::cb_favUpButton_i(Fl_Button*, void*) { + favoritesCB(favUpButton); +} +void Fl_File_Chooser::cb_favUpButton(Fl_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->user_data()))->cb_favUpButton_i(o,v); +} + +void Fl_File_Chooser::cb_favDeleteButton_i(Fl_Button*, void*) { + favoritesCB(favDeleteButton); +} +void Fl_File_Chooser::cb_favDeleteButton(Fl_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->user_data()))->cb_favDeleteButton_i(o,v); +} + +void Fl_File_Chooser::cb_favDownButton_i(Fl_Button*, void*) { + favoritesCB(favDownButton); +} +void Fl_File_Chooser::cb_favDownButton(Fl_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->user_data()))->cb_favDownButton_i(o,v); +} + +void Fl_File_Chooser::cb_favCancelButton_i(Fl_Button*, void*) { + favWindow->hide(); +} +void Fl_File_Chooser::cb_favCancelButton(Fl_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->user_data()))->cb_favCancelButton_i(o,v); +} + +void Fl_File_Chooser::cb_favOkButton_i(Fl_Return_Button*, void*) { + favoritesCB(favOkButton); +} +void Fl_File_Chooser::cb_favOkButton(Fl_Return_Button* o, void* v) { + ((Fl_File_Chooser*)(o->parent()->parent()->user_data()))->cb_favOkButton_i(o,v); +} + +Fl_File_Chooser::Fl_File_Chooser(const char *d, const char *p, int t, const char *title) { + Fl_Group *prev_current = Fl_Group::current(); + { window = new Fl_Double_Window(490, 380, "Choose File"); + window->callback((Fl_Callback*)cb_window, (void*)(this)); + { Fl_Group* o = new Fl_Group(10, 10, 470, 25); + { showChoice = new Fl_Choice(65, 10, 215, 25, "Show:"); + showChoice->down_box(FL_BORDER_BOX); + showChoice->labelfont(1); + showChoice->callback((Fl_Callback*)cb_showChoice); + Fl_Group::current()->resizable(showChoice); + showChoice->label(show_label); + } // Fl_Choice* showChoice + { favoritesButton = new Fl_Menu_Button(290, 10, 155, 25, "Favorites"); + favoritesButton->down_box(FL_BORDER_BOX); + favoritesButton->callback((Fl_Callback*)cb_favoritesButton); + favoritesButton->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE); + favoritesButton->label(favorites_label); + } // Fl_Menu_Button* favoritesButton + { Fl_Button* o = newButton = new Fl_Button(455, 10, 25, 25); + newButton->image(image_new); + newButton->labelsize(8); + newButton->callback((Fl_Callback*)cb_newButton); + o->tooltip(new_directory_tooltip); + } // Fl_Button* newButton + o->end(); + } // Fl_Group* o + { Fl_Tile* o = new Fl_Tile(10, 45, 470, 225); + o->callback((Fl_Callback*)cb_); + { fileList = new Fl_File_Browser(10, 45, 295, 225); + fileList->type(2); + fileList->callback((Fl_Callback*)cb_fileList); + fileList->window()->hotspot(fileList); + } // Fl_File_Browser* fileList + { previewBox = new Fl_Box(305, 45, 175, 225, "?"); + previewBox->box(FL_DOWN_BOX); + previewBox->labelsize(100); + previewBox->align(FL_ALIGN_CLIP|FL_ALIGN_INSIDE); + } // Fl_Box* previewBox + o->end(); + Fl_Group::current()->resizable(o); + } // Fl_Tile* o + { Fl_Group* o = new Fl_Group(10, 275, 470, 95); + { Fl_Group* o = new Fl_Group(10, 275, 470, 20); + { previewButton = new Fl_Check_Button(10, 275, 73, 20, "Preview"); + previewButton->down_box(FL_DOWN_BOX); + previewButton->value(1); + previewButton->shortcut(0x80070); + previewButton->callback((Fl_Callback*)cb_previewButton); + previewButton->label(preview_label); + } // Fl_Check_Button* previewButton + { Fl_Box* o = new Fl_Box(115, 275, 365, 20); + Fl_Group::current()->resizable(o); + } // Fl_Box* o + o->end(); + } // Fl_Group* o + { fileName = new Fl_File_Input(115, 300, 365, 35); + fileName->labelfont(1); + fileName->callback((Fl_Callback*)cb_fileName); + fileName->when(FL_WHEN_ENTER_KEY); + Fl_Group::current()->resizable(fileName); + fileName->when(FL_WHEN_CHANGED | FL_WHEN_ENTER_KEY); + } // Fl_File_Input* fileName + { Fl_Box* o = new Fl_Box(10, 310, 105, 25, "Filename:"); + o->labelfont(1); + o->align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE); + o->label(filename_label); + } // Fl_Box* o + { Fl_Group* o = new Fl_Group(10, 345, 470, 25); + { okButton = new Fl_Return_Button(313, 345, 85, 25, "OK"); + okButton->callback((Fl_Callback*)cb_okButton); + okButton->label(fl_ok); + } // Fl_Return_Button* okButton + { Fl_Button* o = cancelButton = new Fl_Button(408, 345, 72, 25, "Cancel"); + cancelButton->callback((Fl_Callback*)cb_cancelButton); + o->label(fl_cancel); + } // Fl_Button* cancelButton + { Fl_Box* o = new Fl_Box(10, 345, 30, 25); + Fl_Group::current()->resizable(o); + } // Fl_Box* o + o->end(); + } // Fl_Group* o + o->end(); + } // Fl_Group* o + if (title) window->label(title); + window->set_modal(); + window->end(); + } // Fl_Double_Window* window + { favWindow = new Fl_Double_Window(355, 150, "Manage Favorites"); + favWindow->user_data((void*)(this)); + { favList = new Fl_File_Browser(10, 10, 300, 95); + favList->type(2); + favList->callback((Fl_Callback*)cb_favList); + Fl_Group::current()->resizable(favList); + } // Fl_File_Browser* favList + { Fl_Group* o = new Fl_Group(320, 10, 25, 95); + { favUpButton = new Fl_Button(320, 10, 25, 25, "@8>"); + favUpButton->callback((Fl_Callback*)cb_favUpButton); + } // Fl_Button* favUpButton + { favDeleteButton = new Fl_Button(320, 45, 25, 25, "X"); + favDeleteButton->labelfont(1); + favDeleteButton->callback((Fl_Callback*)cb_favDeleteButton); + Fl_Group::current()->resizable(favDeleteButton); + } // Fl_Button* favDeleteButton + { favDownButton = new Fl_Button(320, 80, 25, 25, "@2>"); + favDownButton->callback((Fl_Callback*)cb_favDownButton); + } // Fl_Button* favDownButton + o->end(); + } // Fl_Group* o + { Fl_Group* o = new Fl_Group(10, 113, 335, 29); + { favCancelButton = new Fl_Button(273, 115, 72, 25, "Cancel"); + favCancelButton->callback((Fl_Callback*)cb_favCancelButton); + favCancelButton->label(fl_cancel); + } // Fl_Button* favCancelButton + { favOkButton = new Fl_Return_Button(181, 115, 79, 25, "Save"); + favOkButton->callback((Fl_Callback*)cb_favOkButton); + favOkButton->label(save_label); + } // Fl_Return_Button* favOkButton + { Fl_Box* o = new Fl_Box(10, 115, 161, 25); + Fl_Group::current()->resizable(o); + } // Fl_Box* o + o->end(); + } // Fl_Group* o + favWindow->label(manage_favorites_label); + favWindow->set_modal(); + favWindow->size_range(181, 150); + favWindow->end(); + } // Fl_Double_Window* favWindow + callback_ = 0; +data_ = 0; +directory_[0] = 0; +window->size_range(window->w(), window->h(), Fl::w(), Fl::h()); +type(t); +filter(p); +update_favorites(); +value(d); +type(t); +int e; +prefs_.get("preview", e, 1); +preview(e); +Fl_Group::current(prev_current); +} + +Fl_File_Chooser::~Fl_File_Chooser() { + Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this); +delete window; +delete favWindow; +} + +void Fl_File_Chooser::callback(void (*cb)(Fl_File_Chooser *, void *), void *d ) { + callback_ = cb; +data_ = d; +} + +void Fl_File_Chooser::color(Fl_Color c) { + fileList->color(c); +} + +Fl_Color Fl_File_Chooser::color() { + return (fileList->color()); +} + +char * Fl_File_Chooser::directory() { + return directory_; +} + +const char * Fl_File_Chooser::filter() { + return (fileList->filter()); +} + +int Fl_File_Chooser::filter_value() { + return showChoice->value(); +} + +void Fl_File_Chooser::filter_value(int f) { + showChoice->value(f); +showChoiceCB(); +} + +void Fl_File_Chooser::hide() { + window->hide(); +} + +void Fl_File_Chooser::iconsize(uchar s) { + fileList->iconsize(s); +} + +uchar Fl_File_Chooser::iconsize() { + return (fileList->iconsize()); +} + +void Fl_File_Chooser::label(const char *l) { + window->label(l); +} + +const char * Fl_File_Chooser::label() { + return (window->label()); +} + +void Fl_File_Chooser::ok_label(const char *l) { + okButton->label(l); +int w=0, h=0; +okButton->measure_label(w, h); +okButton->resize(cancelButton->x() - 50 - w, cancelButton->y(), + w + 40, 25); +okButton->parent()->init_sizes(); +} + +const char * Fl_File_Chooser::ok_label() { + return (okButton->label()); +} + +void Fl_File_Chooser::show() { + window->hotspot(fileList); +window->show(); +Fl::flush(); +fl_cursor(FL_CURSOR_WAIT); +rescan_keep_filename(); +fl_cursor(FL_CURSOR_DEFAULT); +fileName->take_focus(); +} + +int Fl_File_Chooser::shown() { + return window->shown(); +} + +void Fl_File_Chooser::textcolor(Fl_Color c) { + fileList->textcolor(c); +} + +Fl_Color Fl_File_Chooser::textcolor() { + return (fileList->textcolor()); +} + +void Fl_File_Chooser::textfont(uchar f) { + fileList->textfont(f); +} + +uchar Fl_File_Chooser::textfont() { + return (fileList->textfont()); +} + +void Fl_File_Chooser::textsize(uchar s) { + fileList->textsize(s); +} + +uchar Fl_File_Chooser::textsize() { + return (fileList->textsize()); +} + +void Fl_File_Chooser::type(int t) { + type_ = t; +if (t & MULTI) + fileList->type(FL_MULTI_BROWSER); +else + fileList->type(FL_HOLD_BROWSER); +if (t & CREATE) + newButton->activate(); +else + newButton->deactivate(); +if (t & DIRECTORY) + fileList->filetype(Fl_File_Browser::DIRECTORIES); +else + fileList->filetype(Fl_File_Browser::FILES); +} + +int Fl_File_Chooser::type() { + return (type_); +} + +void * Fl_File_Chooser::user_data() const { + return (data_); +} + +void Fl_File_Chooser::user_data(void *d) { + data_ = d; +} + +int Fl_File_Chooser::visible() { + return window->visible(); +} + +// +// End of "$Id: Fl_File_Chooser.cxx 6092 2008-04-11 12:57:37Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_File_Chooser.fl b/third_party/windows/fltk-1.1.10/src/Fl_File_Chooser.fl new file mode 100644 index 0000000..934e4d4 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_File_Chooser.fl @@ -0,0 +1,426 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0108 +header_name {../FL/Fl_File_Chooser.H} +code_name {.cxx} +comment {// +// "$Id: Fl_File_Chooser.fl 6092 2008-04-11 12:57:37Z matt $" +// +// Fl_File_Chooser dialog for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +} {in_source in_header +} + +decl {\#include } {} + +class FL_EXPORT Fl_File_Chooser {open +} { + decl {enum { SINGLE = 0, MULTI = 1, CREATE = 2, DIRECTORY = 4 };} {public + } + decl {static Fl_Preferences prefs_;} {} + decl {void (*callback_)(Fl_File_Chooser*, void *);} {} + decl {void *data_;} {} + decl {char directory_[1024];} {} + decl {char pattern_[1024];} {} + decl {char preview_text_[2048];} {} + decl {int type_;} {} + decl {void favoritesButtonCB();} {} + decl {void favoritesCB(Fl_Widget *w);} {} + decl {void fileListCB();} {} + decl {void fileNameCB();} {} + decl {void newdir();} {} + decl {static void previewCB(Fl_File_Chooser *fc);} {} + decl {void showChoiceCB();} {} + decl {void update_favorites();} {} + decl {void update_preview();} {} + Function {Fl_File_Chooser(const char *d, const char *p, int t, const char *title)} {open + } { + code {Fl_Group *prev_current = Fl_Group::current();} {} + Fl_Window window { + label {Choose File} + callback {fileName->value(""); +fileList->deselect(); +Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this); +window->hide();} open + private xywh {388 284 490 380} type Double resizable + code0 {if (title) window->label(title);} + code1 {\#include } + code2 {\#include } + code3 {\#include } modal visible + } { + Fl_Group {} { + private xywh {10 10 470 25} + } { + Fl_Choice showChoice { + label {Show:} + callback {showChoiceCB();} open + private xywh {65 10 215 25} down_box BORDER_BOX labelfont 1 resizable + code0 {showChoice->label(show_label);} + } {} + Fl_Menu_Button favoritesButton { + label Favorites + callback {favoritesButtonCB();} open + private xywh {290 10 155 25} down_box BORDER_BOX align 20 + code0 {favoritesButton->label(favorites_label);} + } {} + Fl_Button newButton { + callback {newdir();} + image {new.xbm} xywh {455 10 25 25} labelsize 8 + code0 {\#include } + code1 {o->tooltip(new_directory_tooltip);} + } + } + Fl_Tile {} { + callback {update_preview();} + private xywh {10 45 470 225} resizable + } { + Fl_File_Browser fileList { + callback {fileListCB();} + private xywh {10 45 295 225} type Hold hotspot + code0 {\#include } + } + Fl_Box previewBox { + label {?} selected + private xywh {305 45 175 225} box DOWN_BOX labelsize 100 align 80 + } + } + Fl_Group {} {open + private xywh {10 275 470 95} + } { + Fl_Group {} {open + private xywh {10 275 470 20} + } { + Fl_Check_Button previewButton { + label Preview + callback {preview(previewButton->value());} + xywh {10 275 73 20} down_box DOWN_BOX shortcut 0x80070 value 1 + code0 {previewButton->label(preview_label);} + } + Fl_Box {} { + private xywh {115 275 365 20} resizable + } + } + Fl_File_Input fileName { + callback {fileNameCB();} + private xywh {115 300 365 35} labelfont 1 when 8 resizable + code0 {fileName->when(FL_WHEN_CHANGED | FL_WHEN_ENTER_KEY);} + } + Fl_Box {} { + label {Filename:} + private xywh {10 310 105 25} labelfont 1 align 24 + code0 {o->label(filename_label);} + } + Fl_Group {} {open + private xywh {10 345 470 25} + } { + Fl_Return_Button okButton { + label OK + callback {window->hide(); + +// Do any callback that is registered... +if (callback_) + (*callback_)(this, data_);} + private xywh {313 345 85 25} + code0 {\#include } + code1 {okButton->label(fl_ok);} + } + Fl_Button cancelButton { + label Cancel + callback {fileName->value(""); +fileList->deselect(); +Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this); +window->hide();} + private xywh {408 345 72 25} + code0 {o->label(fl_cancel);} + } + Fl_Box {} { + private xywh {10 345 30 25} resizable + } + } + } + } + Fl_Window favWindow { + label {Manage Favorites} + private xywh {413 100 355 150} type Double resizable + code0 {favWindow->label(manage_favorites_label);} modal size_range {181 150 0 0} visible + } { + Fl_File_Browser favList { + callback {favoritesCB(favList);} + private xywh {10 10 300 95} type Hold resizable + } + Fl_Group {} {open + xywh {320 10 25 95} + } { + Fl_Button favUpButton { + label {@8>} + callback {favoritesCB(favUpButton);} + private xywh {320 10 25 25} + } + Fl_Button favDeleteButton { + label X + callback {favoritesCB(favDeleteButton);} + private xywh {320 45 25 25} labelfont 1 resizable + } + Fl_Button favDownButton { + label {@2>} + callback {favoritesCB(favDownButton);} + private xywh {320 80 25 25} + } + } + Fl_Group {} {open + xywh {10 113 335 29} + } { + Fl_Button favCancelButton { + label Cancel + callback {favWindow->hide();} + private xywh {273 115 72 25} + code0 {favCancelButton->label(fl_cancel);} + } + Fl_Return_Button favOkButton { + label Save + callback {favoritesCB(favOkButton);} + private xywh {181 115 79 25} + code0 {\#include } + code1 {favOkButton->label(save_label);} + } + Fl_Box {} { + xywh {10 115 161 25} resizable + } + } + } + code {callback_ = 0; +data_ = 0; +directory_[0] = 0; +window->size_range(window->w(), window->h(), Fl::w(), Fl::h()); +type(t); +filter(p); +update_favorites(); +value(d); +type(t); +int e; +prefs_.get("preview", e, 1); +preview(e); +Fl_Group::current(prev_current);} {} + } + Function {~Fl_File_Chooser()} {} { + code {Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this); +delete window; +delete favWindow;} {} + } + Function {callback(void (*cb)(Fl_File_Chooser *, void *), void *d = 0)} {return_type void + } { + code {callback_ = cb; +data_ = d;} {} + } + Function {color(Fl_Color c)} {} { + code {fileList->color(c);} {} + } + Function {color()} {return_type Fl_Color + } { + code {return (fileList->color());} {} + } + decl {int count();} {public + } + decl {void directory(const char *d);} {public + } + Function {directory()} {return_type {char *} + } { + code {return directory_;} {} + } + decl {void filter(const char *p);} {public + } + Function {filter()} {return_type {const char *} + } { + code {return (fileList->filter());} {} + } + Function {filter_value()} {return_type int + } { + code {return showChoice->value();} {} + } + Function {filter_value(int f)} {return_type void + } { + code {showChoice->value(f); +showChoiceCB();} {} + } + Function {hide()} {return_type void + } { + code {window->hide();} {} + } + Function {iconsize(uchar s)} {return_type void + } { + code {fileList->iconsize(s);} {} + } + Function {iconsize()} {return_type uchar + } { + code {return (fileList->iconsize());} {} + } + Function {label(const char *l)} {return_type void + } { + code {window->label(l);} {} + } + Function {label()} {return_type {const char *} + } { + code {return (window->label());} {} + } + Function {ok_label(const char *l)} {return_type void + } { + code {okButton->label(l); +int w=0, h=0; +okButton->measure_label(w, h); +okButton->resize(cancelButton->x() - 50 - w, cancelButton->y(), + w + 40, 25); +okButton->parent()->init_sizes();} {} + } + Function {ok_label()} {return_type {const char *} + } { + code {return (okButton->label());} {} + } + decl {void preview(int e);} {public + } + decl {int preview() const { return previewButton->value(); }} {public + } + decl {void rescan();} {public + } + decl {void rescan_keep_filename();} {public + } + Function {show()} {open return_type void + } { + code {window->hotspot(fileList); +window->show(); +Fl::flush(); +fl_cursor(FL_CURSOR_WAIT); +rescan_keep_filename(); +fl_cursor(FL_CURSOR_DEFAULT); +fileName->take_focus();} {} + } + Function {shown()} {return_type int + } { + code {return window->shown();} {} + } + Function {textcolor(Fl_Color c)} {return_type void + } { + code {fileList->textcolor(c);} {} + } + Function {textcolor()} {return_type Fl_Color + } { + code {return (fileList->textcolor());} {} + } + Function {textfont(uchar f)} {return_type void + } { + code {fileList->textfont(f);} {} + } + Function {textfont()} {return_type uchar + } { + code {return (fileList->textfont());} {} + } + Function {textsize(uchar s)} {return_type void + } { + code {fileList->textsize(s);} {} + } + Function {textsize()} {return_type uchar + } { + code {return (fileList->textsize());} {} + } + Function {type(int t)} {return_type void + } { + code {type_ = t; +if (t & MULTI) + fileList->type(FL_MULTI_BROWSER); +else + fileList->type(FL_HOLD_BROWSER); +if (t & CREATE) + newButton->activate(); +else + newButton->deactivate(); +if (t & DIRECTORY) + fileList->filetype(Fl_File_Browser::DIRECTORIES); +else + fileList->filetype(Fl_File_Browser::FILES);} {} + } + Function {type()} {return_type int + } { + code {return (type_);} {} + } + Function {user_data() const} {return_type {void *} + } { + code {return (data_);} {} + } + Function {user_data(void *d)} {return_type void + } { + code {data_ = d;} {} + } + decl {const char *value(int f = 1);} {public + } + decl {void value(const char *filename);} {public + } + Function {visible()} {return_type int + } { + code {return window->visible();} {} + } + decl {static const char *add_favorites_label;} {public + } + decl {static const char *all_files_label;} {public + } + decl {static const char *custom_filter_label;} {public + } + decl {static const char *existing_file_label;} {public + } + decl {static const char *favorites_label;} {public + } + decl {static const char *filename_label;} {public + } + decl {static const char *filesystems_label;} {public + } + decl {static const char *manage_favorites_label;} {public + } + decl {static const char *new_directory_label;} {public + } + decl {static const char *new_directory_tooltip;} {public + } + decl {static const char *preview_label;} {public + } + decl {static const char *save_label;} {public + } + decl {static const char *show_label;} {public + } + decl {static Fl_File_Sort_F *sort;} {public + } +} + +decl {FL_EXPORT char *fl_dir_chooser(const char *message,const char *fname,int relative=0);} {public +} + +decl {FL_EXPORT char *fl_file_chooser(const char *message,const char *pat,const char *fname,int relative=0);} {public +} + +decl {FL_EXPORT void fl_file_chooser_callback(void (*cb)(const char*));} {public +} + +decl {FL_EXPORT void fl_file_chooser_ok_label(const char*l);} {public +} + +comment { +// +// End of "$Id: Fl_File_Chooser.fl 6092 2008-04-11 12:57:37Z matt $". +//} {in_source in_header +} diff --git a/third_party/windows/fltk-1.1.10/src/Fl_File_Chooser2.cxx b/third_party/windows/fltk-1.1.10/src/Fl_File_Chooser2.cxx new file mode 100644 index 0000000..b147546 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_File_Chooser2.cxx @@ -0,0 +1,1308 @@ +// +// "$Id: Fl_File_Chooser2.cxx 6092 2008-04-11 12:57:37Z matt $" +// +// More Fl_File_Chooser routines. +// +// Copyright 1999-2005 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_File_Chooser::count() - Return the number of selected files. +// Fl_File_Chooser::directory() - Set the directory in the file chooser. +// Fl_File_Chooser::filter() - Set the filter(s) for the chooser. +// Fl_File_Chooser::newdir() - Make a new directory. +// Fl_File_Chooser::value() - Return a selected filename. +// Fl_File_Chooser::rescan() - Rescan the current directory. +// Fl_File_Chooser::favoritesButtonCB() - Handle favorites selections. +// Fl_File_Chooser::fileListCB() - Handle clicks (and double-clicks) +// in the Fl_File_Browser. +// Fl_File_Chooser::fileNameCB() - Handle text entry in the FileBrowser. +// Fl_File_Chooser::showChoiceCB() - Handle show selections. +// compare_dirnames() - Compare two directory names. +// quote_pathname() - Quote a pathname for a menu. +// unquote_pathname() - Unquote a pathname from a menu. +// + +// +// Include necessary headers. +// + +#include +#include +#include +#include +#include + +#include +#include +#include "flstring.h" +#include +#include +#include + +#if defined(WIN32) && ! defined (__CYGWIN__) +# include +# include +// Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs +// on Windows, which is supposed to be POSIX compliant... +# define access _access +# define mkdir _mkdir +// Apparently Borland C++ defines DIRECTORY in , which +// interfers with the Fl_File_Icon enumeration of the same name. +# ifdef DIRECTORY +# undef DIRECTORY +# endif // DIRECTORY +#else +# include +# include +#endif /* WIN32 */ + + +// +// File chooser label strings and sort function... +// + +Fl_Preferences Fl_File_Chooser::prefs_(Fl_Preferences::USER, "fltk.org", "filechooser"); + +const char *Fl_File_Chooser::add_favorites_label = "Add to Favorites"; +const char *Fl_File_Chooser::all_files_label = "All Files (*)"; +const char *Fl_File_Chooser::custom_filter_label = "Custom Filter"; +const char *Fl_File_Chooser::existing_file_label = "Please choose an existing file!"; +const char *Fl_File_Chooser::favorites_label = "Favorites"; +const char *Fl_File_Chooser::filename_label = "Filename:"; +#ifdef WIN32 +const char *Fl_File_Chooser::filesystems_label = "My Computer"; +#else +const char *Fl_File_Chooser::filesystems_label = "File Systems"; +#endif // WIN32 +const char *Fl_File_Chooser::manage_favorites_label = "Manage Favorites"; +const char *Fl_File_Chooser::new_directory_label = "New Directory?"; +const char *Fl_File_Chooser::new_directory_tooltip = "Create a new directory."; +const char *Fl_File_Chooser::preview_label = "Preview"; +const char *Fl_File_Chooser::save_label = "Save"; +const char *Fl_File_Chooser::show_label = "Show:"; +Fl_File_Sort_F *Fl_File_Chooser::sort = fl_numericsort; + + +// +// Local functions... +// + +static int compare_dirnames(const char *a, const char *b); +static void quote_pathname(char *, const char *, int); +static void unquote_pathname(char *, const char *, int); + + +// +// 'Fl_File_Chooser::count()' - Return the number of selected files. +// + +int // O - Number of selected files +Fl_File_Chooser::count() { + int i; // Looping var + int fcount; // Number of selected files + const char *filename; // Filename in input field or list + + + filename = fileName->value(); + + if (!(type_ & MULTI)) { + // Check to see if the file name input field is blank... + if (!filename || !filename[0]) return 0; + else return 1; + } + + for (i = 1, fcount = 0; i <= fileList->size(); i ++) + if (fileList->selected(i)) { + // See if this file is a directory... + // matt: why would we do that? It is perfectly legal to select multiple + // directories in a DIR chooser. They are visually selected and value(i) + // returns all of them as expected + //filename = (char *)fileList->text(i); + + //if (filename[strlen(filename) - 1] != '/') + fcount ++; + } + + if (fcount) return fcount; + else if (!filename || !filename[0]) return 0; + else return 1; +} + + +// +// 'Fl_File_Chooser::directory()' - Set the directory in the file chooser. +// + +void +Fl_File_Chooser::directory(const char *d)// I - Directory to change to +{ + char *dirptr; // Pointer into directory + + +// printf("Fl_File_Chooser::directory(\"%s\")\n", d == NULL ? "(null)" : d); + + // NULL == current directory + if (d == NULL) + d = "."; + +#ifdef WIN32 + // See if the filename contains backslashes... + char *slash; // Pointer to slashes + char fixpath[1024]; // Path with slashes converted + if (strchr(d, '\\')) { + // Convert backslashes to slashes... + strlcpy(fixpath, d, sizeof(fixpath)); + + for (slash = strchr(fixpath, '\\'); slash; slash = strchr(slash + 1, '\\')) + *slash = '/'; + + d = fixpath; + } +#endif // WIN32 + + if (d[0] != '\0') + { + // Make the directory absolute... +#if (defined(WIN32) && ! defined(__CYGWIN__))|| defined(__EMX__) + if (d[0] != '/' && d[0] != '\\' && d[1] != ':') +#else + if (d[0] != '/' && d[0] != '\\') +#endif /* WIN32 || __EMX__ */ + fl_filename_absolute(directory_, d); + else + strlcpy(directory_, d, sizeof(directory_)); + + // Strip any trailing slash... + dirptr = directory_ + strlen(directory_) - 1; + if ((*dirptr == '/' || *dirptr == '\\') && dirptr > directory_) + *dirptr = '\0'; + + // See if we have a trailing .. or . in the filename... + dirptr = directory_ + strlen(directory_) - 3; + if (dirptr >= directory_ && strcmp(dirptr, "/..") == 0) { + // Yes, we have "..", so strip the trailing path... + *dirptr = '\0'; + while (dirptr > directory_) { + if (*dirptr == '/') break; + dirptr --; + } + + if (dirptr >= directory_ && *dirptr == '/') + *dirptr = '\0'; + } else if ((dirptr + 1) >= directory_ && strcmp(dirptr + 1, "/.") == 0) { + // Strip trailing "."... + dirptr[1] = '\0'; + } + } + else + directory_[0] = '\0'; + + if (shown()) { + // Rescan the directory... + rescan(); + } +} + + +// +// 'Fl_File_Chooser::favoritesButtonCB()' - Handle favorites selections. +// + +void +Fl_File_Chooser::favoritesButtonCB() +{ + int v; // Current selection + char pathname[1024], // Pathname + menuname[2048]; // Menu name + + + v = favoritesButton->value(); + + if (!v) { + // Add current directory to favorites... + if (getenv("HOME")) v = favoritesButton->size() - 5; + else v = favoritesButton->size() - 4; + + sprintf(menuname, "favorite%02d", v); + + prefs_.set(menuname, directory_); + prefs_.flush(); + + quote_pathname(menuname, directory_, sizeof(menuname)); + favoritesButton->add(menuname); + + if (favoritesButton->size() > 104) { + ((Fl_Menu_Item *)favoritesButton->menu())[0].deactivate(); + } + } else if (v == 1) { + // Manage favorites... + favoritesCB(0); + } else if (v == 2) { + // Filesystems/My Computer + directory(""); + } else { + unquote_pathname(pathname, favoritesButton->text(v), sizeof(pathname)); + directory(pathname); + } +} + + +// +// 'Fl_File_Chooser::favoritesCB()' - Handle favorites dialog. +// + +void +Fl_File_Chooser::favoritesCB(Fl_Widget *w) + // I - Widget +{ + int i; // Looping var + char name[32], // Preference name + pathname[1024]; // Directory in list + + + if (!w) { + // Load the favorites list... + favList->clear(); + favList->deselect(); + + for (i = 0; i < 100; i ++) { + // Get favorite directory 0 to 99... + sprintf(name, "favorite%02d", i); + + prefs_.get(name, pathname, "", sizeof(pathname)); + + // Stop on the first empty favorite... + if (!pathname[0]) break; + + // Add the favorite to the list... + favList->add(pathname, + Fl_File_Icon::find(pathname, Fl_File_Icon::DIRECTORY)); + } + + favUpButton->deactivate(); + favDeleteButton->deactivate(); + favDownButton->deactivate(); + favOkButton->deactivate(); + + favWindow->hotspot(favList); + favWindow->show(); + } else if (w == favList) { + i = favList->value(); + if (i) { + if (i > 1) favUpButton->activate(); + else favUpButton->deactivate(); + + favDeleteButton->activate(); + + if (i < favList->size()) favDownButton->activate(); + else favDownButton->deactivate(); + } else { + favUpButton->deactivate(); + favDeleteButton->deactivate(); + favDownButton->deactivate(); + } + } else if (w == favUpButton) { + i = favList->value(); + + favList->insert(i - 1, favList->text(i), favList->data(i)); + favList->remove(i + 1); + favList->select(i - 1); + + if (i == 2) favUpButton->deactivate(); + + favDownButton->activate(); + + favOkButton->activate(); + } else if (w == favDeleteButton) { + i = favList->value(); + + favList->remove(i); + + if (i > favList->size()) i --; + favList->select(i); + + if (i < favList->size()) favDownButton->activate(); + else favDownButton->deactivate(); + + if (i > 1) favUpButton->activate(); + else favUpButton->deactivate(); + + if (!i) favDeleteButton->deactivate(); + + favOkButton->activate(); + } else if (w == favDownButton) { + i = favList->value(); + + favList->insert(i + 2, favList->text(i), favList->data(i)); + favList->remove(i); + favList->select(i + 1); + + if ((i + 1) == favList->size()) favDownButton->deactivate(); + + favUpButton->activate(); + + favOkButton->activate(); + } else if (w == favOkButton) { + // Copy the new list over... + for (i = 0; i < favList->size(); i ++) { + // Set favorite directory 0 to 99... + sprintf(name, "favorite%02d", i); + + prefs_.set(name, favList->text(i + 1)); + } + + // Clear old entries as necessary... + for (; i < 100; i ++) { + // Clear favorite directory 0 to 99... + sprintf(name, "favorite%02d", i); + + prefs_.get(name, pathname, "", sizeof(pathname)); + + if (pathname[0]) prefs_.set(name, ""); + else break; + } + + update_favorites(); + prefs_.flush(); + + favWindow->hide(); + } +} + + +// +// 'Fl_File_Chooser::fileListCB()' - Handle clicks (and double-clicks) in the +// Fl_File_Browser. +// + +void +Fl_File_Chooser::fileListCB() +{ + char *filename, // New filename + pathname[1024]; // Full pathname to file + + + filename = (char *)fileList->text(fileList->value()); + if (!filename) + return; + + if (!directory_[0]) { + strlcpy(pathname, filename, sizeof(pathname)); + } else if (strcmp(directory_, "/") == 0) { + snprintf(pathname, sizeof(pathname), "/%s", filename); + } else { + snprintf(pathname, sizeof(pathname), "%s/%s", directory_, filename); + } + + if (Fl::event_clicks()) { +#if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__) + if ((strlen(pathname) == 2 && pathname[1] == ':') || + _fl_filename_isdir_quick(pathname)) +#else + if (_fl_filename_isdir_quick(pathname)) +#endif /* WIN32 || __EMX__ */ + { + // Change directories... + directory(pathname); + + // Reset the click count so that a click in the same spot won't + // be treated as a triple-click. We use a value of -1 because + // the next click will increment click count to 0, which is what + // we really want... + Fl::event_clicks(-1); + } + else + { + // Hide the window - picked the file... + window->hide(); + } + } + else + { + // Check if the user clicks on a directory when picking files; + // if so, make sure only that item is selected... + filename = pathname + strlen(pathname) - 1; + + if ((type_ & MULTI) && !(type_ & DIRECTORY)) { + if (*filename == '/') { + // Clicked on a directory, deselect everything else... + int i = fileList->value(); + fileList->deselect(); + fileList->select(i); + } else { + // Clicked on a file - see if there are other directories selected... + int i; + const char *temp; + for (i = 1; i <= fileList->size(); i ++) { + if (i != fileList->value() && fileList->selected(i)) { + temp = fileList->text(i); + temp += strlen(temp) - 1; + if (*temp == '/') break; // Yes, selected directory + } + } + + if (i <= fileList->size()) { + i = fileList->value(); + fileList->deselect(); + fileList->select(i); + } + } + } + // Strip any trailing slash from the directory name... + if (*filename == '/') *filename = '\0'; + +// puts("Setting fileName from fileListCB..."); + fileName->value(pathname); + + // Update the preview box... + Fl::remove_timeout((Fl_Timeout_Handler)previewCB, this); + Fl::add_timeout(1.0, (Fl_Timeout_Handler)previewCB, this); + + // Do any callback that is registered... + if (callback_) (*callback_)(this, data_); + + // Activate the OK button as needed... + if (!_fl_filename_isdir_quick(pathname) || (type_ & DIRECTORY)) + okButton->activate(); + else + okButton->deactivate(); + } +} + + +// +// 'Fl_File_Chooser::fileNameCB()' - Handle text entry in the FileBrowser. +// + +void +Fl_File_Chooser::fileNameCB() +{ + char *filename, // New filename + *slash, // Pointer to trailing slash + pathname[1024], // Full pathname to file + matchname[256]; // Matching filename + int i, // Looping var + min_match, // Minimum number of matching chars + max_match, // Maximum number of matching chars + num_files, // Number of files in directory + first_line; // First matching line + const char *file; // File from directory + +// puts("fileNameCB()"); +// printf("Event: %s\n", fl_eventnames[Fl::event()]); + + // Get the filename from the text field... + filename = (char *)fileName->value(); + + if (!filename || !filename[0]) { + okButton->deactivate(); + return; + } + + // Expand ~ and $ variables as needed... + if (strchr(filename, '~') || strchr(filename, '$')) { + fl_filename_expand(pathname, sizeof(pathname), filename); + filename = pathname; + value(pathname); + } + + // Make sure we have an absolute path... +#if (defined(WIN32) && !defined(__CYGWIN__)) || defined(__EMX__) + if (directory_[0] != '\0' && filename[0] != '/' && + filename[0] != '\\' && + !(isalpha(filename[0] & 255) && (!filename[1] || filename[1] == ':'))) { +#else + if (directory_[0] != '\0' && filename[0] != '/') { +#endif /* WIN32 || __EMX__ */ + fl_filename_absolute(pathname, sizeof(pathname), filename); + value(pathname); + fileName->mark(fileName->position()); // no selection after expansion + } else if (filename != pathname) { + // Finally, make sure that we have a writable copy... + strlcpy(pathname, filename, sizeof(pathname)); + } + + filename = pathname; + + // Now process things according to the key pressed... + if (Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter) { + // Enter pressed - select or change directory... +#if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__) + if ((isalpha(pathname[0] & 255) && pathname[1] == ':' && !pathname[2]) || + _fl_filename_isdir_quick(pathname) && + compare_dirnames(pathname, directory_)) { +#else + if (_fl_filename_isdir_quick(pathname) && + compare_dirnames(pathname, directory_)) { +#endif /* WIN32 || __EMX__ */ + directory(pathname); + } else if ((type_ & CREATE) || access(pathname, 0) == 0) { + if (!_fl_filename_isdir_quick(pathname) || (type_ & DIRECTORY)) { + // Update the preview box... + update_preview(); + + // Do any callback that is registered... + if (callback_) (*callback_)(this, data_); + + // Hide the window to signal things are done... + window->hide(); + } + } else { + // File doesn't exist, so beep at and alert the user... + fl_alert(existing_file_label); + } + } + else if (Fl::event_key() != FL_Delete && + Fl::event_key() != FL_BackSpace) { + // Check to see if the user has entered a directory... + if ((slash = strrchr(pathname, '/')) == NULL) + slash = strrchr(pathname, '\\'); + + if (!slash) return; + + // Yes, change directories if necessary... + *slash++ = '\0'; + filename = slash; + +#if defined(WIN32) || defined(__EMX__) + if (strcasecmp(pathname, directory_) && + (pathname[0] || strcasecmp("/", directory_))) { +#else + if (strcmp(pathname, directory_) && + (pathname[0] || strcasecmp("/", directory_))) { +#endif // WIN32 || __EMX__ + int p = fileName->position(); + int m = fileName->mark(); + + directory(pathname); + + if (filename[0]) { + char tempname[1024]; + + snprintf(tempname, sizeof(tempname), "%s/%s", directory_, filename); + fileName->value(tempname); + strlcpy(pathname, tempname, sizeof(pathname)); + } + + fileName->position(p, m); + } + + // Other key pressed - do filename completion as possible... + num_files = fileList->size(); + min_match = strlen(filename); + max_match = min_match + 1; + first_line = 0; + + for (i = 1; i <= num_files && max_match > min_match; i ++) { + file = fileList->text(i); + +#if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__) + if (strncasecmp(filename, file, min_match) == 0) { +#else + if (strncmp(filename, file, min_match) == 0) { +#endif // WIN32 || __EMX__ + // OK, this one matches; check against the previous match + if (!first_line) { + // First match; copy stuff over... + strlcpy(matchname, file, sizeof(matchname)); + max_match = strlen(matchname); + + // Strip trailing /, if any... + if (matchname[max_match - 1] == '/') { + max_match --; + matchname[max_match] = '\0'; + } + + // And then make sure that the item is visible + fileList->topline(i); + first_line = i; + } else { + // Succeeding match; compare to find maximum string match... + while (max_match > min_match) +#if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__) + if (strncasecmp(file, matchname, max_match) == 0) +#else + if (strncmp(file, matchname, max_match) == 0) +#endif // WIN32 || __EMX__ + break; + else + max_match --; + + // Truncate the string as needed... + matchname[max_match] = '\0'; + } + } + } + + // If we have any matches, add them to the input field... + if (first_line > 0 && min_match == max_match && + max_match == (int)strlen(fileList->text(first_line))) { + // This is the only possible match... + fileList->deselect(0); + fileList->select(first_line); + fileList->redraw(); + } else if (max_match > min_match && first_line) { + // Add the matching portion... + fileName->replace(filename - pathname, filename - pathname + min_match, + matchname); + + // Highlight it with the cursor at the end of the selection so + // s/he can press the right arrow to accept the selection + // (Tab and End also do this for both cases.) + fileName->position(filename - pathname + max_match, + filename - pathname + min_match); + } else if (max_match == 0) { + fileList->deselect(0); + fileList->redraw(); + } + + // See if we need to enable the OK button... + if (((type_ & CREATE) || !access(fileName->value(), 0)) && + (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) { + okButton->activate(); + } else { + okButton->deactivate(); + } + } else { + // FL_Delete or FL_BackSpace + fileList->deselect(0); + fileList->redraw(); + if (((type_ & CREATE) || !access(fileName->value(), 0)) && + (!fl_filename_isdir(fileName->value()) || (type_ & DIRECTORY))) { + okButton->activate(); + } else { + okButton->deactivate(); + } + } +} + + +// +// 'Fl_File_Chooser::filter()' - Set the filter(s) for the chooser. +// + +void +Fl_File_Chooser::filter(const char *p) // I - Pattern(s) +{ + char *copyp, // Copy of pattern + *start, // Start of pattern + *end; // End of pattern + int allfiles; // Do we have a "*" pattern? + char temp[1024]; // Temporary pattern string + + + // Make sure we have a pattern... + if (!p || !*p) p = "*"; + + // Copy the pattern string... + copyp = strdup(p); + + // Separate the pattern string as necessary... + showChoice->clear(); + + for (start = copyp, allfiles = 0; start && *start; start = end) { + end = strchr(start, '\t'); + if (end) *end++ = '\0'; + + if (strcmp(start, "*") == 0) { + showChoice->add(all_files_label); + allfiles = 1; + } else { + quote_pathname(temp, start, sizeof(temp)); + showChoice->add(temp); + if (strstr(start, "(*)") != NULL) allfiles = 1; + } + } + + free(copyp); + + if (!allfiles) showChoice->add(all_files_label); + + showChoice->add(custom_filter_label); + + showChoice->value(0); + showChoiceCB(); +} + + +// +// 'Fl_File_Chooser::newdir()' - Make a new directory. +// + +void +Fl_File_Chooser::newdir() +{ + const char *dir; // New directory name + char pathname[1024]; // Full path of directory + + + // Get a directory name from the user + if ((dir = fl_input(new_directory_label, NULL)) == NULL) + return; + + // Make it relative to the current directory as needed... +#if (defined(WIN32) && ! defined (__CYGWIN__)) || defined(__EMX__) + if (dir[0] != '/' && dir[0] != '\\' && dir[1] != ':') +#else + if (dir[0] != '/' && dir[0] != '\\') +#endif /* WIN32 || __EMX__ */ + snprintf(pathname, sizeof(pathname), "%s/%s", directory_, dir); + else + strlcpy(pathname, dir, sizeof(pathname)); + + // Create the directory; ignore EEXIST errors... +#if defined(WIN32) && ! defined (__CYGWIN__) + if (mkdir(pathname)) +#else + if (mkdir(pathname, 0777)) +#endif /* WIN32 */ + if (errno != EEXIST) + { + fl_alert("%s", strerror(errno)); + return; + } + + // Show the new directory... + directory(pathname); +} + + +// +// 'Fl_File_Chooser::preview()' - Enable or disable the preview tile. +// + +void +Fl_File_Chooser::preview(int e)// I - 1 = enable preview, 0 = disable preview +{ + previewButton->value(e); + prefs_.set("preview", e); + prefs_.flush(); + + Fl_Group *p = previewBox->parent(); + if (e) { + int w = p->w() * 2 / 3; + fileList->resize(fileList->x(), fileList->y(), + w, fileList->h()); + previewBox->resize(fileList->x()+w, previewBox->y(), + p->w()-w, previewBox->h()); + previewBox->show(); + update_preview(); + } else { + fileList->resize(fileList->x(), fileList->y(), + p->w(), fileList->h()); + previewBox->resize(p->x()+p->w(), previewBox->y(), + 0, previewBox->h()); + previewBox->hide(); + } + p->init_sizes(); + + fileList->parent()->redraw(); +} + + +// +// 'Fl_File_Chooser::previewCB()' - Timeout handler for the preview box. +// + +void +Fl_File_Chooser::previewCB(Fl_File_Chooser *fc) { // I - File chooser + fc->update_preview(); +} + + +// +// 'Fl_File_Chooser::rescan()' - Rescan the current directory. +// + +void +Fl_File_Chooser::rescan() +{ + char pathname[1024]; // New pathname for filename field + + + // Clear the current filename + strlcpy(pathname, directory_, sizeof(pathname)); + if (pathname[0] && pathname[strlen(pathname) - 1] != '/') { + strlcat(pathname, "/", sizeof(pathname)); + } +// puts("Setting fileName in rescan()"); + fileName->value(pathname); + + if (type_ & DIRECTORY) + okButton->activate(); + else + okButton->deactivate(); + + // Build the file list... + fileList->load(directory_, sort); + + // Update the preview box... + update_preview(); +} + +// +// 'Fl_File_Chooser::rescan_keep_filename()' - Rescan the current directory +// without clearing the filename, then select the file if it is in the list +// + +void +Fl_File_Chooser::rescan_keep_filename() +{ + // if no filename was set, this is likely a diretory browser + const char *fn = fileName->value(); + if (!fn || !*fn || fn[strlen(fn) - 1]=='/') { + rescan(); + return; + } + + int i; + char pathname[1024]; // New pathname for filename field + strlcpy(pathname, fn, sizeof(pathname)); + + // Build the file list... + fileList->load(directory_, sort); + + // Update the preview box... + update_preview(); + + // and select the chosen file + char found = 0; + char *slash = strrchr(pathname, '/'); + if (slash) + slash++; + else + slash = pathname; + for (i = 1; i <= fileList->size(); i ++) +#if defined(WIN32) || defined(__EMX__) + if (strcasecmp(fileList->text(i), slash) == 0) { +#else + if (strcmp(fileList->text(i), slash) == 0) { +#endif // WIN32 || __EMX__ + fileList->topline(i); + fileList->select(i); + found = 1; + break; + } + + // update OK button activity + if (found || type_ & CREATE) + okButton->activate(); + else + okButton->deactivate(); +} + + +// +// 'Fl_File_Chooser::showChoiceCB()' - Handle show selections. +// + +void +Fl_File_Chooser::showChoiceCB() +{ + const char *item, // Selected item + *patstart; // Start of pattern + char *patend; // End of pattern + char temp[1024]; // Temporary string for pattern + + + item = showChoice->text(showChoice->value()); + + if (strcmp(item, custom_filter_label) == 0) { + if ((item = fl_input(custom_filter_label, pattern_)) != NULL) { + strlcpy(pattern_, item, sizeof(pattern_)); + + quote_pathname(temp, item, sizeof(temp)); + showChoice->add(temp); + showChoice->value(showChoice->size() - 2); + } + } else if ((patstart = strchr(item, '(')) == NULL) { + strlcpy(pattern_, item, sizeof(pattern_)); + } else { + strlcpy(pattern_, patstart + 1, sizeof(pattern_)); + if ((patend = strrchr(pattern_, ')')) != NULL) *patend = '\0'; + } + + fileList->filter(pattern_); + + if (shown()) { + // Rescan the directory... + rescan_keep_filename(); + } +} + + +// +// 'Fl_File_Chooser::update_favorites()' - Update the favorites menu. +// + +void +Fl_File_Chooser::update_favorites() +{ + int i; // Looping var + char pathname[1024], // Pathname + menuname[2048]; // Menu name + const char *home; // Home directory + + + favoritesButton->clear(); + favoritesButton->add("bla"); + favoritesButton->clear(); + favoritesButton->add(add_favorites_label, FL_ALT + 'a', 0); + favoritesButton->add(manage_favorites_label, FL_ALT + 'm', 0, 0, FL_MENU_DIVIDER); + favoritesButton->add(filesystems_label, FL_ALT + 'f', 0); + + if ((home = getenv("HOME")) != NULL) { + quote_pathname(menuname, home, sizeof(menuname)); + favoritesButton->add(menuname, FL_ALT + 'h', 0); + } + + for (i = 0; i < 100; i ++) { + sprintf(menuname, "favorite%02d", i); + prefs_.get(menuname, pathname, "", sizeof(pathname)); + if (!pathname[0]) break; + + quote_pathname(menuname, pathname, sizeof(menuname)); + + if (i < 10) favoritesButton->add(menuname, FL_ALT + '0' + i, 0); + else favoritesButton->add(menuname); + } + + if (i == 100) ((Fl_Menu_Item *)favoritesButton->menu())[0].deactivate(); +} + + +// +// 'Fl_File_Chooser::update_preview()' - Update the preview box... +// + +void +Fl_File_Chooser::update_preview() +{ + const char *filename; // Current filename + Fl_Shared_Image *image, // New image + *oldimage; // Old image + int pbw, pbh; // Width and height of preview box + int w, h; // Width and height of preview image + + + if (!previewButton->value()) return; + + if ((filename = value()) == NULL || fl_filename_isdir(filename)) image = NULL; + else { + window->cursor(FL_CURSOR_WAIT); + Fl::check(); + + image = Fl_Shared_Image::get(filename); + + if (image) { + window->cursor(FL_CURSOR_DEFAULT); + Fl::check(); + } + } + + oldimage = (Fl_Shared_Image *)previewBox->image(); + + if (oldimage) oldimage->release(); + + previewBox->image(0); + + if (!image) { + FILE *fp; + int bytes; + char *ptr; + + if (filename) fp = fopen(filename, "rb"); + else fp = NULL; + + if (fp != NULL) { + // Try reading the first 1k of data for a label... + bytes = fread(preview_text_, 1, sizeof(preview_text_) - 1, fp); + preview_text_[bytes] = '\0'; + fclose(fp); + } else { + // Assume we can't read any data... + preview_text_[0] = '\0'; + } + + window->cursor(FL_CURSOR_DEFAULT); + Fl::check(); + + // Scan the buffer for printable chars... + for (ptr = preview_text_; + *ptr && (isprint(*ptr & 255) || isspace(*ptr & 255)); + ptr ++); + + if (*ptr || ptr == preview_text_) { + // Non-printable file, just show a big ?... + previewBox->label(filename ? "?" : 0); + previewBox->align(FL_ALIGN_CLIP); + previewBox->labelsize(100); + previewBox->labelfont(FL_HELVETICA); + } else { + // Show the first 1k of text... + int size = previewBox->h() / 20; + if (size < 6) size = 6; + else if (size > 14) size = 14; + + previewBox->label(preview_text_); + previewBox->align((Fl_Align)(FL_ALIGN_CLIP | FL_ALIGN_INSIDE | + FL_ALIGN_LEFT | FL_ALIGN_TOP)); + previewBox->labelsize((uchar)size); + previewBox->labelfont(FL_COURIER); + } + } else { + pbw = previewBox->w() - 20; + pbh = previewBox->h() - 20; + + if (image->w() > pbw || image->h() > pbh) { + w = pbw; + h = w * image->h() / image->w(); + + if (h > pbh) { + h = pbh; + w = h * image->w() / image->h(); + } + + oldimage = (Fl_Shared_Image *)image->copy(w, h); + previewBox->image((Fl_Image *)oldimage); + + image->release(); + } else { + previewBox->image((Fl_Image *)image); + } + + previewBox->align(FL_ALIGN_CLIP); + previewBox->label(0); + } + + previewBox->redraw(); +} + + +// +// 'Fl_File_Chooser::value()' - Return a selected filename. +// + +const char * // O - Filename or NULL +Fl_File_Chooser::value(int f) // I - File number +{ + int i; // Looping var + int fcount; // Number of selected files + const char *name; // Current filename + static char pathname[1024]; // Filename + directory + + + name = fileName->value(); + + if (!(type_ & MULTI)) { + // Return the filename in the filename field... + if (!name || !name[0]) return NULL; + else return name; + } + + // Return a filename from the list... + for (i = 1, fcount = 0; i <= fileList->size(); i ++) + if (fileList->selected(i)) { + // See if this file is a selected file/directory... + name = fileList->text(i); + + fcount ++; + + if (fcount == f) { + if (directory_[0]) { + snprintf(pathname, sizeof(pathname), "%s/%s", directory_, name); + } else { + strlcpy(pathname, name, sizeof(pathname)); + } + + return pathname; + } + } + + // If nothing is selected, use the filename field... + if (!name || !name[0]) return NULL; + else return name; +} + + +// +// 'Fl_File_Chooser::value()' - Set the current filename. +// + +void +Fl_File_Chooser::value(const char *filename) + // I - Filename + directory +{ + int i, // Looping var + fcount; // Number of items in list + char *slash; // Directory separator + char pathname[1024]; // Local copy of filename + + +// printf("Fl_File_Chooser::value(\"%s\")\n", filename == NULL ? "(null)" : filename); + + // See if the filename is the "My System" directory... + if (filename == NULL || !filename[0]) { + // Yes, just change the current directory... + directory(filename); + fileName->value(""); + okButton->deactivate(); + return; + } + +#ifdef WIN32 + // See if the filename contains backslashes... + char fixpath[1024]; // Path with slashes converted + if (strchr(filename, '\\')) { + // Convert backslashes to slashes... + strlcpy(fixpath, filename, sizeof(fixpath)); + + for (slash = strchr(fixpath, '\\'); slash; slash = strchr(slash + 1, '\\')) + *slash = '/'; + + filename = fixpath; + } +#endif // WIN32 + + // See if there is a directory in there... + fl_filename_absolute(pathname, sizeof(pathname), filename); + + if ((slash = strrchr(pathname, '/')) != NULL) { + // Yes, change the display to the directory... + if (!fl_filename_isdir(pathname)) *slash++ = '\0'; + + directory(pathname); + if (*slash == '/') slash = pathname; + } else { + directory("."); + slash = pathname; + } + + // Set the input field to the absolute path... + if (slash > pathname) slash[-1] = '/'; + + fileName->value(pathname); + fileName->position(0, strlen(pathname)); + okButton->activate(); + + // Then find the file in the file list and select it... + fcount = fileList->size(); + + fileList->deselect(0); + fileList->redraw(); + + for (i = 1; i <= fcount; i ++) +#if defined(WIN32) || defined(__EMX__) + if (strcasecmp(fileList->text(i), slash) == 0) { +#else + if (strcmp(fileList->text(i), slash) == 0) { +#endif // WIN32 || __EMX__ +// printf("Selecting line %d...\n", i); + fileList->topline(i); + fileList->select(i); + break; + } +} + + +// +// 'compare_dirnames()' - Compare two directory names. +// + +static int +compare_dirnames(const char *a, const char *b) { + int alen, blen; + + // Get length of each string... + alen = strlen(a) - 1; + blen = strlen(b) - 1; + + if (alen < 0 || blen < 0) return alen - blen; + + // Check for trailing slashes... + if (a[alen] != '/') alen ++; + if (b[blen] != '/') blen ++; + + // If the lengths aren't the same, then return the difference... + if (alen != blen) return alen - blen; + + // Do a comparison of the first N chars (alen == blen at this point)... +#ifdef WIN32 + return strncasecmp(a, b, alen); +#else + return strncmp(a, b, alen); +#endif // WIN32 +} + + +// +// 'quote_pathname()' - Quote a pathname for a menu. +// + +static void +quote_pathname(char *dst, // O - Destination string + const char *src, // I - Source string + int dstsize) // I - Size of destination string +{ + dstsize --; + + while (*src && dstsize > 1) { + if (*src == '\\') { + // Convert backslash to forward slash... + *dst++ = '\\'; + *dst++ = '/'; + src ++; + } else { + if (*src == '/') *dst++ = '\\'; + + *dst++ = *src++; + } + } + + *dst = '\0'; +} + + +// +// 'unquote_pathname()' - Unquote a pathname from a menu. +// + +static void +unquote_pathname(char *dst, // O - Destination string + const char *src, // I - Source string + int dstsize) // I - Size of destination string +{ + dstsize --; + + while (*src && dstsize > 1) { + if (*src == '\\') src ++; + *dst++ = *src++; + } + + *dst = '\0'; +} + + +// +// End of "$Id: Fl_File_Chooser2.cxx 6092 2008-04-11 12:57:37Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_File_Icon.cxx b/third_party/windows/fltk-1.1.10/src/Fl_File_Icon.cxx new file mode 100644 index 0000000..853b22e --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_File_Icon.cxx @@ -0,0 +1,485 @@ +// +// "$Id: Fl_File_Icon.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Fl_File_Icon routines. +// +// KDE icon code donated by Maarten De Boer. +// +// Copyright 1999-2005 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_File_Icon::Fl_File_Icon() - Create a new file icon. +// Fl_File_Icon::~Fl_File_Icon() - Remove a file icon. +// Fl_File_Icon::add() - Add data to an icon. +// Fl_File_Icon::find() - Find an icon based upon a given file. +// Fl_File_Icon::draw() - Draw an icon. +// Fl_File_Icon::label() - Set the widgets label to an icon. +// Fl_File_Icon::labeltype() - Draw the icon label. +// + +// +// Include necessary header files... +// + +#include +#include +#include "flstring.h" +#include +#include +#include +#if (defined(WIN32) && ! defined(__CYGWIN__)) || defined(__EMX__) +# include +# define F_OK 0 +#else +# include +#endif /* WIN32 || __EMX__ */ + +#include +#include +#include +#include + + +// +// Define missing POSIX/XPG4 macros as needed... +// + +#ifndef S_ISDIR +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif /* !S_ISDIR */ + + +// +// Icon cache... +// + +Fl_File_Icon *Fl_File_Icon::first_ = (Fl_File_Icon *)0; + + +// +// 'Fl_File_Icon::Fl_File_Icon()' - Create a new file icon. +// + +Fl_File_Icon::Fl_File_Icon(const char *p, /* I - Filename pattern */ + int t, /* I - File type */ + int nd, /* I - Number of data values */ + short *d) /* I - Data values */ +{ + // Initialize the pattern and type... + pattern_ = p; + type_ = t; + + // Copy icon data as needed... + if (nd) + { + num_data_ = nd; + alloc_data_ = nd + 1; + data_ = (short *)calloc(sizeof(short), nd + 1); + memcpy(data_, d, nd * sizeof(short)); + } + else + { + num_data_ = 0; + alloc_data_ = 0; + } + + // And add the icon to the list of icons... + next_ = first_; + first_ = this; +} + + +// +// 'Fl_File_Icon::~Fl_File_Icon()' - Remove a file icon. +// + +Fl_File_Icon::~Fl_File_Icon() +{ + Fl_File_Icon *current, // Current icon in list + *prev; // Previous icon in list + + + // Find the icon in the list... + for (current = first_, prev = (Fl_File_Icon *)0; + current != this && current != (Fl_File_Icon *)0; + prev = current, current = current->next_); + + // Remove the icon from the list as needed... + if (current) + { + if (prev) + prev->next_ = current->next_; + else + first_ = current->next_; + } + + // Free any memory used... + if (alloc_data_) + free(data_); +} + + +// +// 'Fl_File_Icon::add()' - Add data to an icon. +// + +short * // O - Pointer to new data value +Fl_File_Icon::add(short d) // I - Data to add +{ + short *dptr; // Pointer to new data value + + + // Allocate/reallocate memory as needed + if ((num_data_ + 1) >= alloc_data_) + { + alloc_data_ += 128; + + if (alloc_data_ == 128) + dptr = (short *)malloc(sizeof(short) * alloc_data_); + else + dptr = (short *)realloc(data_, sizeof(short) * alloc_data_); + + if (dptr == NULL) + return (NULL); + + data_ = dptr; + } + + // Store the new data value and return + data_[num_data_++] = d; + data_[num_data_] = END; + + return (data_ + num_data_ - 1); +} + + +// +// 'Fl_File_Icon::find()' - Find an icon based upon a given file. +// + +Fl_File_Icon * // O - Matching file icon or NULL +Fl_File_Icon::find(const char *filename,// I - Name of file */ + int filetype) // I - Enumerated file type +{ + Fl_File_Icon *current; // Current file in list +#ifndef WIN32 + struct stat fileinfo; // Information on file +#endif // !WIN32 + const char *name; // Base name of filename + + + // Get file information if needed... + if (filetype == ANY) + { +#ifdef WIN32 + if (filename[strlen(filename) - 1] == '/') + filetype = DIRECTORY; + else if (fl_filename_isdir(filename)) + filetype = DIRECTORY; + else + filetype = PLAIN; +#else + if (!stat(filename, &fileinfo)) + { + if (S_ISDIR(fileinfo.st_mode)) + filetype = DIRECTORY; +# ifdef S_IFIFO + else if (S_ISFIFO(fileinfo.st_mode)) + filetype = FIFO; +# endif // S_IFIFO +# if defined(S_ICHR) && defined(S_IBLK) + else if (S_ISCHR(fileinfo.st_mode) || S_ISBLK(fileinfo.st_mode)) + filetype = DEVICE; +# endif // S_ICHR && S_IBLK +# ifdef S_ILNK + else if (S_ISLNK(fileinfo.st_mode)) + filetype = LINK; +# endif // S_ILNK + else + filetype = PLAIN; + } + else + filetype = PLAIN; +#endif // WIN32 + } + + // Look at the base name in the filename + name = fl_filename_name(filename); + + // Loop through the available file types and return any match that + // is found... + for (current = first_; current != (Fl_File_Icon *)0; current = current->next_) + if ((current->type_ == filetype || current->type_ == ANY) && + (fl_filename_match(filename, current->pattern_) || + fl_filename_match(name, current->pattern_))) + break; + + // Return the match (if any)... + return (current); +} + + +// +// 'Fl_File_Icon::draw()' - Draw an icon. +// + +void +Fl_File_Icon::draw(int x, // I - Upper-lefthand X + int y, // I - Upper-lefthand Y + int w, // I - Width of bounding box + int h, // I - Height of bounding box + Fl_Color ic, // I - Icon color... + int active) // I - Active or inactive? +{ + Fl_Color c, // Current color + oc; // Outline color + short *d, // Pointer to data + *dend; // End of data... + short *prim; // Pointer to start of primitive... + double scale; // Scale of icon + + + // Don't try to draw a NULL array! + if (num_data_ == 0) + return; + + // Setup the transform matrix as needed... + scale = w < h ? w : h; + + fl_push_matrix(); + fl_translate((float)x + 0.5 * ((float)w - scale), + (float)y + 0.5 * ((float)h + scale)); + fl_scale(scale, -scale); + + // Loop through the array until we see an unmatched END... + d = data_; + dend = data_ + num_data_; + prim = NULL; + c = ic; + + if (active) + fl_color(c); + else + fl_color(fl_inactive(c)); + + while (d < dend) + switch (*d) + { + case END : + if (prim) + switch (*prim) + { + case LINE : + fl_end_line(); + break; + + case CLOSEDLINE : + fl_end_loop(); + break; + + case POLYGON : + fl_end_complex_polygon(); + break; + + case OUTLINEPOLYGON : + fl_end_complex_polygon(); + + oc = (Fl_Color)((((unsigned short *)prim)[1] << 16) | + ((unsigned short *)prim)[2]); + if (active) + { + if (oc == FL_ICON_COLOR) + fl_color(ic); + else + fl_color(oc); + } + else + { + if (oc == FL_ICON_COLOR) + fl_color(fl_inactive(ic)); + else + fl_color(fl_inactive(oc)); + } + + fl_begin_loop(); + + prim += 3; + while (*prim == VERTEX) + { + fl_vertex(prim[1] * 0.0001, prim[2] * 0.0001); + prim += 3; + } + + fl_end_loop(); + fl_color(c); + break; + } + + prim = NULL; + d ++; + break; + + case COLOR : + c = (Fl_Color)((((unsigned short *)d)[1] << 16) | + ((unsigned short *)d)[2]); + + if (c == FL_ICON_COLOR) + c = ic; + + if (!active) + c = fl_inactive(c); + + fl_color(c); + d += 3; + break; + + case LINE : + prim = d; + d ++; + fl_begin_line(); + break; + + case CLOSEDLINE : + prim = d; + d ++; + fl_begin_loop(); + break; + + case POLYGON : + prim = d; + d ++; + fl_begin_complex_polygon(); + break; + + case OUTLINEPOLYGON : + prim = d; + d += 3; + fl_begin_complex_polygon(); + break; + + case VERTEX : + if (prim) + fl_vertex(d[1] * 0.0001, d[2] * 0.0001); + d += 3; + break; + + default : // Ignore invalid data... + d ++; + } + + // If we still have an open primitive, close it... + if (prim) + switch (*prim) + { + case LINE : + fl_end_line(); + break; + + case CLOSEDLINE : + fl_end_loop(); + break; + + case POLYGON : + fl_end_polygon(); + break; + + case OUTLINEPOLYGON : + fl_end_polygon(); + + oc = (Fl_Color)((((unsigned short *)prim)[1] << 16) | + ((unsigned short *)prim)[2]); + if (active) + { + if (oc == FL_ICON_COLOR) + fl_color(ic); + else + fl_color(oc); + } + else + { + if (oc == FL_ICON_COLOR) + fl_color(fl_inactive(ic)); + else + fl_color(fl_inactive(oc)); + } + + fl_begin_loop(); + + prim += 3; + while (*prim == VERTEX) + { + fl_vertex(prim[1] * 0.0001, prim[2] * 0.0001); + prim += 3; + } + + fl_end_loop(); + fl_color(c); + break; + } + + // Restore the transform matrix + fl_pop_matrix(); +} + + +// +// 'Fl_File_Icon::label()' - Set the widget's label to an icon. +// + +void +Fl_File_Icon::label(Fl_Widget *w) // I - Widget to label +{ + Fl::set_labeltype(_FL_ICON_LABEL, labeltype, 0); + w->label(_FL_ICON_LABEL, (const char*)this); +} + + +// +// 'Fl_File_Icon::labeltype()' - Draw the icon label. +// + +void +Fl_File_Icon::labeltype(const Fl_Label *o, // I - Label data + int x, // I - X position of label + int y, // I - Y position of label + int w, // I - Width of label + int h, // I - Height of label + Fl_Align a) // I - Label alignment (not used) +{ + Fl_File_Icon *icon; // Pointer to icon data + + + (void)a; + + icon = (Fl_File_Icon *)(o->value); + if (icon) icon->draw(x, y, w, h, (Fl_Color)(o->color)); +} + + +// +// End of "$Id: Fl_File_Icon.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_File_Icon2.cxx b/third_party/windows/fltk-1.1.10/src/Fl_File_Icon2.cxx new file mode 100644 index 0000000..d7b6eaf --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_File_Icon2.cxx @@ -0,0 +1,1015 @@ +// +// "$Id: Fl_File_Icon2.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Fl_File_Icon system icon routines. +// +// KDE icon code donated by Maarten De Boer. +// +// Copyright 1999-2005 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_File_Icon::load() - Load an icon file... +// Fl_File_Icon::load_fti() - Load an SGI-format FTI file... +// Fl_File_Icon::load_image() - Load an image icon file... +// Fl_File_Icon::load_system_icons() - Load the standard system icons/filetypes. +// load_kde_icons() - Load KDE icon files. +// load_kde_mimelnk() - Load a KDE "mimelnk" file. +// kde_to_fltk_pattern() - Convert a KDE pattern to a FLTK pattern. +// get_kde_val() - Get a KDE value. +// + +// +// Include necessary header files... +// + +#include +#include +#include "flstring.h" +#include +#include +#include +#include +#include +#if defined(WIN32) && !defined(__CYGWIN__) +# include +# define F_OK 0 +// Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs +// on Windows, which is supposed to be POSIX compliant... +# define access _access +#else +# include +#endif // WIN32 + +#include +#include +#include +#include +#include + + +// +// Define missing POSIX/XPG4 macros as needed... +// + +#ifndef S_ISDIR +# define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +# define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +# define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +# define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +# define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#endif /* !S_ISDIR */ + + +// +// Local functions... +// + +static void load_kde_icons(const char *directory, const char *icondir); +static void load_kde_mimelnk(const char *filename, const char *icondir); +static char *kde_to_fltk_pattern(const char *kdepattern); +static char *get_kde_val(char *str, const char *key); + + +// +// Local globals... +// + +static const char *kdedir = NULL; + + +// +// 'Fl_File_Icon::load()' - Load an icon file... +// + +void +Fl_File_Icon::load(const char *f) // I - File to read from +{ + int i; // Load status... + const char *ext; // File extension + + + ext = fl_filename_ext(f); + + if (ext && strcmp(ext, ".fti") == 0) + i = load_fti(f); + else + i = load_image(f); + + if (i) + { + Fl::warning("Fl_File_Icon::load(): Unable to load icon file \"%s\".", f); + return; + } +} + + +// +// 'Fl_File_Icon::load_fti()' - Load an SGI-format FTI file... +// + +int // O - 0 on success, non-zero on error +Fl_File_Icon::load_fti(const char *fti) // I - File to read from +{ + FILE *fp; // File pointer + int ch; // Current character + char command[255], // Command string ("vertex", etc.) + params[255], // Parameter string ("10.0,20.0", etc.) + *ptr; // Pointer into strings + int outline; // Outline polygon + + + // Try to open the file... + if ((fp = fopen(fti, "rb")) == NULL) + { + Fl::error("Fl_File_Icon::load_fti(): Unable to open \"%s\" - %s", + fti, strerror(errno)); + return -1; + } + + // Read the entire file, adding data as needed... + outline = 0; + + while ((ch = getc(fp)) != EOF) + { + // Skip whitespace + if (isspace(ch)) + continue; + + // Skip comments starting with "#"... + if (ch == '#') + { + while ((ch = getc(fp)) != EOF) + if (ch == '\n') + break; + + if (ch == EOF) + break; + else + continue; + } + + // OK, this character better be a letter... + if (!isalpha(ch)) + { + Fl::error("Fl_File_Icon::load_fti(): Expected a letter at file position %ld (saw '%c')", + ftell(fp) - 1, ch); + break; + } + + // Scan the command name... + ptr = command; + *ptr++ = ch; + + while ((ch = getc(fp)) != EOF) + { + if (ch == '(') + break; + else if (ptr < (command + sizeof(command) - 1)) + *ptr++ = ch; + } + + *ptr++ = '\0'; + + // Make sure we stopped on a parenthesis... + if (ch != '(') + { + Fl::error("Fl_File_Icon::load_fti(): Expected a ( at file position %ld (saw '%c')", + ftell(fp) - 1, ch); + break; + } + + // Scan the parameters... + ptr = params; + + while ((ch = getc(fp)) != EOF) + { + if (ch == ')') + break; + else if (ptr < (params + sizeof(params) - 1)) + *ptr++ = ch; + } + + *ptr++ = '\0'; + + // Make sure we stopped on a parenthesis... + if (ch != ')') + { + Fl::error("Fl_File_Icon::load_fti(): Expected a ) at file position %ld (saw '%c')", + ftell(fp) - 1, ch); + break; + } + + // Make sure the next character is a semicolon... + if ((ch = getc(fp)) != ';') + { + Fl::error("Fl_File_Icon::load_fti(): Expected a ; at file position %ld (saw '%c')", + ftell(fp) - 1, ch); + break; + } + + // Now process the command... + if (strcmp(command, "color") == 0) + { + // Set the color; for negative colors blend the two primaries to + // produce a composite color. Also, the following symbolic color + // names are understood: + // + // name FLTK color + // ------------- ---------- + // iconcolor FL_ICON_COLOR; mapped to the icon color in + // Fl_File_Icon::draw() + // shadowcolor FL_DARK3 + // outlinecolor FL_BLACK + if (strcmp(params, "iconcolor") == 0) + add_color(FL_ICON_COLOR); + else if (strcmp(params, "shadowcolor") == 0) + add_color(FL_DARK3); + else if (strcmp(params, "outlinecolor") == 0) + add_color(FL_BLACK); + else + { + int c = atoi(params); // Color value + + + if (c < 0) + { + // Composite color; compute average... + c = -c; + add_color(fl_color_average((Fl_Color)(c >> 4), + (Fl_Color)(c & 15), 0.5f)); + } + else + add_color((Fl_Color)c); + } + } + else if (strcmp(command, "bgnline") == 0) + add(LINE); + else if (strcmp(command, "bgnclosedline") == 0) + add(CLOSEDLINE); + else if (strcmp(command, "bgnpolygon") == 0) + add(POLYGON); + else if (strcmp(command, "bgnoutlinepolygon") == 0) + { + add(OUTLINEPOLYGON); + outline = add(0) - data_; + add(0); + } + else if (strcmp(command, "endoutlinepolygon") == 0 && outline) + { + unsigned cval; // Color value + + // Set the outline color; see above for valid values... + if (strcmp(params, "iconcolor") == 0) + cval = FL_ICON_COLOR; + else if (strcmp(params, "shadowcolor") == 0) + cval = FL_DARK3; + else if (strcmp(params, "outlinecolor") == 0) + cval = FL_BLACK; + else + { + int c = atoi(params); // Color value + + + if (c < 0) + { + // Composite color; compute average... + c = -c; + cval = fl_color_average((Fl_Color)(c >> 4), (Fl_Color)(c & 15), 0.5f); + } + else + cval = c; + } + + // Store outline color... + data_[outline] = cval >> 16; + data_[outline + 1] = cval; + + outline = 0; + add(END); + } + else if (strncmp(command, "end", 3) == 0) + add(END); + else if (strcmp(command, "vertex") == 0) + { + float x, y; // Coordinates of vertex + + + if (sscanf(params, "%f,%f", &x, &y) != 2) + break; + + add_vertex((short)(int)rint(x * 100.0), (short)(int)rint(y * 100.0)); + } + else + { + Fl::error("Fl_File_Icon::load_fti(): Unknown command \"%s\" at file position %ld.", + command, ftell(fp) - 1); + break; + } + } + + // Close the file and return... + fclose(fp); + +#ifdef DEBUG + printf("Icon File \"%s\":\n", fti); + for (int i = 0; i < num_data_; i ++) + printf(" %d,\n", data_[i]); +#endif /* DEBUG */ + + return 0; +} + + +// +// 'Fl_File_Icon::load_image()' - Load an image icon file... +// + +int // O - 0 on success, non-0 on error +Fl_File_Icon::load_image(const char *ifile) // I - File to read from +{ + Fl_Shared_Image *img; // Image file + + + img = Fl_Shared_Image::get(ifile); + if (!img || !img->count() || !img->w() || !img->h()) return -1; + + if (img->count() == 1) { + int x, y; // X & Y in image + int startx; // Starting X coord + Fl_Color c, // Current color + temp; // Temporary color + const uchar *row; // Pointer into image + + + // Loop through grayscale or RGB image... + for (y = 0, row = (const uchar *)(*(img->data())); y < img->h(); y ++, row += img->ld()) + { + for (x = 0, startx = 0, c = (Fl_Color)-1; + x < img->w(); + x ++, row += img->d()) + { + switch (img->d()) + { + case 1 : + temp = fl_rgb_color(row[0], row[0], row[0]); + break; + case 2 : + if (row[1] > 127) + temp = fl_rgb_color(row[0], row[0], row[0]); + else + temp = (Fl_Color)-1; + break; + case 3 : + temp = fl_rgb_color(row[0], row[1], row[2]); + break; + default : + if (row[3] > 127) + temp = fl_rgb_color(row[0], row[1], row[2]); + else + temp = (Fl_Color)-1; + break; + } + + if (temp != c) + { + if (x > startx && c != (Fl_Color)-1) + { + add_color(c); + add(POLYGON); + add_vertex(startx * 9000 / img->w() + 1000, 9500 - y * 9000 / img->h()); + add_vertex(x * 9000 / img->w() + 1000, 9500 - y * 9000 / img->h()); + add_vertex(x * 9000 / img->w() + 1000, 9500 - (y + 1) * 9000 / img->h()); + add_vertex(startx * 9000 / img->w() + 1000, 9500 - (y + 1) * 9000 / img->h()); + add(END); + } + + c = temp; + startx = x; + } + } + + if (x > startx && c != (Fl_Color)-1) + { + add_color(c); + add(POLYGON); + add_vertex(startx * 9000 / img->w() + 1000, 9500 - y * 9000 / img->h()); + add_vertex(x * 9000 / img->w() + 1000, 9500 - y * 9000 / img->h()); + add_vertex(x * 9000 / img->w() + 1000, 9500 - (y + 1) * 9000 / img->h()); + add_vertex(startx * 9000 / img->w() + 1000, 9500 - (y + 1) * 9000 / img->h()); + add(END); + } + } + } else { + int i, j; // Looping vars + int ch; // Current character + int newch; // New character + int bg; // Background color + char val[16]; // Color value + const char *lineptr, // Pointer into line + *const*ptr; // Pointer into data array + int ncolors, // Number of colors + chars_per_color; // Characters per color + Fl_Color *colors; // Colors + int red, green, blue; // Red, green, and blue values + int x, y; // X & Y in image + int startx; // Starting X coord + + + // Get the pixmap data... + ptr = img->data(); + sscanf(*ptr, "%*d%*d%d%d", &ncolors, &chars_per_color); + + colors = new Fl_Color[1 << (chars_per_color * 8)]; + + // Read the colormap... + memset(colors, 0, sizeof(Fl_Color) << (chars_per_color * 8)); + bg = ' '; + + ptr ++; + + if (ncolors < 0) { + // Read compressed colormap... + const uchar *cmapptr; + + ncolors = -ncolors; + + for (i = 0, cmapptr = (const uchar *)*ptr; i < ncolors; i ++, cmapptr += 4) + colors[cmapptr[0]] = fl_rgb_color(cmapptr[1], cmapptr[2], cmapptr[3]); + + ptr ++; + } else { + for (i = 0; i < ncolors; i ++, ptr ++) { + // Get the color's character + lineptr = *ptr; + ch = *lineptr++; + + if (chars_per_color > 1) ch = (ch << 8) | *lineptr++; + + // Get the color value... + if ((lineptr = strstr(lineptr, "c ")) == NULL) { + // No color; make this black... + colors[ch] = FL_BLACK; + } else if (lineptr[2] == '#') { + // Read the RGB triplet... + lineptr += 3; + for (j = 0; j < 12; j ++) + if (!isxdigit(lineptr[j])) + break; + + switch (j) { + case 0 : + bg = ch; + default : + red = green = blue = 0; + break; + + case 3 : + val[0] = lineptr[0]; + val[1] = '\0'; + red = 255 * strtol(val, NULL, 16) / 15; + + val[0] = lineptr[1]; + val[1] = '\0'; + green = 255 * strtol(val, NULL, 16) / 15; + + val[0] = lineptr[2]; + val[1] = '\0'; + blue = 255 * strtol(val, NULL, 16) / 15; + break; + + case 6 : + case 9 : + case 12 : + j /= 3; + + val[0] = lineptr[0]; + val[1] = lineptr[1]; + val[2] = '\0'; + red = strtol(val, NULL, 16); + + val[0] = lineptr[j + 0]; + val[1] = lineptr[j + 1]; + val[2] = '\0'; + green = strtol(val, NULL, 16); + + val[0] = lineptr[2 * j + 0]; + val[1] = lineptr[2 * j + 1]; + val[2] = '\0'; + blue = strtol(val, NULL, 16); + break; + } + + colors[ch] = fl_rgb_color((uchar)red, (uchar)green, (uchar)blue); + } else { + // Read a color name... + if (strncasecmp(lineptr + 2, "white", 5) == 0) colors[ch] = FL_WHITE; + else if (strncasecmp(lineptr + 2, "black", 5) == 0) colors[ch] = FL_BLACK; + else if (strncasecmp(lineptr + 2, "none", 4) == 0) { + colors[ch] = FL_BLACK; + bg = ch; + } else colors[ch] = FL_GRAY; + } + } + } + + // Read the image data... + for (y = 0; y < img->h(); y ++, ptr ++) { + lineptr = *ptr; + startx = 0; + ch = bg; + + for (x = 0; x < img->w(); x ++) { + newch = *lineptr++; + + if (chars_per_color > 1) newch = (newch << 8) | *lineptr++; + + if (newch != ch) { + if (ch != bg) { + add_color(colors[ch]); + add(POLYGON); + add_vertex(startx * 9000 / img->w() + 1000, 9500 - y * 9000 / img->h()); + add_vertex(x * 9000 / img->w() + 1000, 9500 - y * 9000 / img->h()); + add_vertex(x * 9000 / img->w() + 1000, 9500 - (y + 1) * 9000 / img->h()); + add_vertex(startx * 9000 / img->w() + 1000, 9500 - (y + 1) * 9000 / img->h()); + add(END); + } + + ch = newch; + startx = x; + } + } + + if (ch != bg) { + add_color(colors[ch]); + add(POLYGON); + add_vertex(startx * 9000 / img->w() + 1000, 9500 - y * 9000 / img->h()); + add_vertex(x * 9000 / img->w() + 1000, 9500 - y * 9000 / img->h()); + add_vertex(x * 9000 / img->w() + 1000, 9500 - (y + 1) * 9000 / img->h()); + add_vertex(startx * 9000 / img->w() + 1000, 9500 - (y + 1) * 9000 / img->h()); + add(END); + } + } + + // Free the colormap... + delete[] colors; + } + + img->release(); + +#ifdef DEBUG + printf("Icon File \"%s\":\n", xpm); + for (i = 0; i < num_data_; i ++) + printf(" %d,\n", data_[i]); +#endif // DEBUG + + return 0; +} + + +// +// 'Fl_File_Icon::load_system_icons()' - Load the standard system icons/filetypes. + +void +Fl_File_Icon::load_system_icons(void) { + int i; // Looping var + Fl_File_Icon *icon; // New icons + char filename[1024]; // Filename + char icondir[1024]; // Icon directory + static int init = 0; // Have the icons been initialized? + const char * const icondirs[] = { + "Bluecurve", // Icon directories to look for, in order + "crystalsvg", + "default.kde", + "hicolor", + NULL + }; + static short plain[] = { // Plain file icon + COLOR, -1, -1, OUTLINEPOLYGON, 0, FL_GRAY, + VERTEX, 2000, 1000, VERTEX, 2000, 9000, + VERTEX, 6000, 9000, VERTEX, 8000, 7000, + VERTEX, 8000, 1000, END, OUTLINEPOLYGON, 0, FL_GRAY, + VERTEX, 6000, 9000, VERTEX, 6000, 7000, + VERTEX, 8000, 7000, END, + COLOR, 0, FL_BLACK, LINE, VERTEX, 6000, 7000, + VERTEX, 8000, 7000, VERTEX, 8000, 1000, + VERTEX, 2000, 1000, END, LINE, VERTEX, 3000, 7000, + VERTEX, 5000, 7000, END, LINE, VERTEX, 3000, 6000, + VERTEX, 5000, 6000, END, LINE, VERTEX, 3000, 5000, + VERTEX, 7000, 5000, END, LINE, VERTEX, 3000, 4000, + VERTEX, 7000, 4000, END, LINE, VERTEX, 3000, 3000, + VERTEX, 7000, 3000, END, LINE, VERTEX, 3000, 2000, + VERTEX, 7000, 2000, END, + END + }; + static short image[] = { // Image file icon + COLOR, -1, -1, OUTLINEPOLYGON, 0, FL_GRAY, + VERTEX, 2000, 1000, VERTEX, 2000, 9000, + VERTEX, 6000, 9000, VERTEX, 8000, 7000, + VERTEX, 8000, 1000, END, OUTLINEPOLYGON, 0, FL_GRAY, + VERTEX, 6000, 9000, VERTEX, 6000, 7000, + VERTEX, 8000, 7000, END, + COLOR, 0, FL_BLACK, LINE, VERTEX, 6000, 7000, + VERTEX, 8000, 7000, VERTEX, 8000, 1000, + VERTEX, 2000, 1000, END, + COLOR, 0, FL_RED, POLYGON, VERTEX, 3500, 2500, + VERTEX, 3000, 3000, VERTEX, 3000, 4000, + VERTEX, 3500, 4500, VERTEX, 4500, 4500, + VERTEX, 5000, 4000, VERTEX, 5000, 3000, + VERTEX, 4500, 2500, END, + COLOR, 0, FL_GREEN, POLYGON, VERTEX, 5500, 2500, + VERTEX, 5000, 3000, VERTEX, 5000, 4000, + VERTEX, 5500, 4500, VERTEX, 6500, 4500, + VERTEX, 7000, 4000, VERTEX, 7000, 3000, + VERTEX, 6500, 2500, END, + COLOR, 0, FL_BLUE, POLYGON, VERTEX, 4500, 3500, + VERTEX, 4000, 4000, VERTEX, 4000, 5000, + VERTEX, 4500, 5500, VERTEX, 5500, 5500, + VERTEX, 6000, 5000, VERTEX, 6000, 4000, + VERTEX, 5500, 3500, END, + END + }; + static short dir[] = { // Directory icon + COLOR, -1, -1, POLYGON, VERTEX, 1000, 1000, + VERTEX, 1000, 7500, VERTEX, 9000, 7500, + VERTEX, 9000, 1000, END, + POLYGON, VERTEX, 1000, 7500, VERTEX, 2500, 9000, + VERTEX, 5000, 9000, VERTEX, 6500, 7500, END, + COLOR, 0, FL_WHITE, LINE, VERTEX, 1500, 1500, + VERTEX, 1500, 7000, VERTEX, 9000, 7000, END, + COLOR, 0, FL_BLACK, LINE, VERTEX, 9000, 7500, + VERTEX, 9000, 1000, VERTEX, 1000, 1000, END, + COLOR, 0, FL_GRAY, LINE, VERTEX, 1000, 1000, + VERTEX, 1000, 7500, VERTEX, 2500, 9000, + VERTEX, 5000, 9000, VERTEX, 6500, 7500, + VERTEX, 9000, 7500, END, + END + }; + + + // Add symbols if they haven't been added already... + if (!init) { + // This method requires the images library... + fl_register_images(); + + if (!kdedir) { + // Figure out where KDE is installed... + if ((kdedir = getenv("KDEDIR")) == NULL) { + if (!access("/opt/kde", F_OK)) kdedir = "/opt/kde"; + else if (!access("/usr/local/share/mimelnk", F_OK)) kdedir = "/usr/local"; + else kdedir = "/usr"; + } + } + + snprintf(filename, sizeof(filename), "%s/share/mimelnk", kdedir); + + if (!access(filename, F_OK)) { + // Load KDE icons... + icon = new Fl_File_Icon("*", Fl_File_Icon::PLAIN); + + for (i = 0; icondirs[i]; i ++) { + snprintf(icondir, sizeof(icondir), "%s/share/icons/%s", kdedir, + icondirs[i]); + + if (!access(icondir, F_OK)) break; + } + + if (icondirs[i]) { + snprintf(filename, sizeof(filename), "%s/16x16/mimetypes/unknown.png", + icondir); + } else { + snprintf(filename, sizeof(filename), "%s/share/icons/unknown.xpm", + kdedir); + } + + if (!access(filename, F_OK)) icon->load_image(filename); + + icon = new Fl_File_Icon("*", Fl_File_Icon::LINK); + + snprintf(filename, sizeof(filename), "%s/16x16/filesystems/link.png", + icondir); + + if (!access(filename, F_OK)) icon->load_image(filename); + + snprintf(filename, sizeof(filename), "%s/share/mimelnk", kdedir); + load_kde_icons(filename, icondir); + } else if (!access("/usr/share/icons/folder.xpm", F_OK)) { + // Load GNOME icons... + icon = new Fl_File_Icon("*", Fl_File_Icon::PLAIN); + icon->load_image("/usr/share/icons/page.xpm"); + + icon = new Fl_File_Icon("*", Fl_File_Icon::DIRECTORY); + icon->load_image("/usr/share/icons/folder.xpm"); + } else if (!access("/usr/dt/appconfig/icons", F_OK)) { + // Load CDE icons... + icon = new Fl_File_Icon("*", Fl_File_Icon::PLAIN); + icon->load_image("/usr/dt/appconfig/icons/C/Dtdata.m.pm"); + + icon = new Fl_File_Icon("*", Fl_File_Icon::DIRECTORY); + icon->load_image("/usr/dt/appconfig/icons/C/DtdirB.m.pm"); + + icon = new Fl_File_Icon("core", Fl_File_Icon::PLAIN); + icon->load_image("/usr/dt/appconfig/icons/C/Dtcore.m.pm"); + + icon = new Fl_File_Icon("*.{bmp|bw|gif|jpg|pbm|pcd|pgm|ppm|png|ras|rgb|tif|xbm|xpm}", Fl_File_Icon::PLAIN); + icon->load_image("/usr/dt/appconfig/icons/C/Dtimage.m.pm"); + + icon = new Fl_File_Icon("*.{eps|pdf|ps}", Fl_File_Icon::PLAIN); + icon->load_image("/usr/dt/appconfig/icons/C/Dtps.m.pm"); + + icon = new Fl_File_Icon("*.ppd", Fl_File_Icon::PLAIN); + icon->load_image("/usr/dt/appconfig/icons/C/DtPrtpr.m.pm"); + } else if (!access("/usr/lib/filetype", F_OK)) { + // Load SGI icons... + icon = new Fl_File_Icon("*", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/iconlib/generic.doc.fti"); + + icon = new Fl_File_Icon("*", Fl_File_Icon::DIRECTORY); + icon->load_fti("/usr/lib/filetype/iconlib/generic.folder.closed.fti"); + + icon = new Fl_File_Icon("core", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/default/iconlib/CoreFile.fti"); + + icon = new Fl_File_Icon("*.{bmp|bw|gif|jpg|pbm|pcd|pgm|ppm|png|ras|rgb|tif|xbm|xpm}", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/system/iconlib/ImageFile.fti"); + + if (!access("/usr/lib/filetype/install/iconlib/acroread.doc.fti", F_OK)) { + icon = new Fl_File_Icon("*.{eps|ps}", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/system/iconlib/PostScriptFile.closed.fti"); + + icon = new Fl_File_Icon("*.pdf", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/install/iconlib/acroread.doc.fti"); + } else { + icon = new Fl_File_Icon("*.{eps|pdf|ps}", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/system/iconlib/PostScriptFile.closed.fti"); + } + + if (!access("/usr/lib/filetype/install/iconlib/html.fti", F_OK)) { + icon = new Fl_File_Icon("*.{htm|html|shtml}", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/iconlib/generic.doc.fti"); + icon->load_fti("/usr/lib/filetype/install/iconlib/html.fti"); + } + + if (!access("/usr/lib/filetype/install/iconlib/color.ps.idle.fti", F_OK)) { + icon = new Fl_File_Icon("*.ppd", Fl_File_Icon::PLAIN); + icon->load_fti("/usr/lib/filetype/install/iconlib/color.ps.idle.fti"); + } + } else { + // Create the default icons... + new Fl_File_Icon("*", Fl_File_Icon::PLAIN, sizeof(plain) / sizeof(plain[0]), plain); + new Fl_File_Icon("*.{bm|bmp|bw|gif|jpg|pbm|pcd|pgm|ppm|png|ras|rgb|tif|xbm|xpm}", Fl_File_Icon::PLAIN, + sizeof(image) / sizeof(image[0]), image); + new Fl_File_Icon("*", Fl_File_Icon::DIRECTORY, sizeof(dir) / sizeof(dir[0]), dir); + } + + // Mark things as initialized... + init = 1; + +#ifdef DEBUG + int count; + Fl_File_Icon *temp; + for (count = 0, temp = first_; temp; temp = temp->next_, count ++); + printf("count of Fl_File_Icon's is %d...\n", count); +#endif // DEBUG + } +} + + +// +// 'load_kde_icons()' - Load KDE icon files. +// + +static void +load_kde_icons(const char *directory, // I - Directory to load + const char *icondir) { // I - Location of icons + int i; // Looping var + int n; // Number of entries in directory + dirent **entries; // Entries in directory + char full[1024]; // Full name of file + + + entries = (dirent **)0; + n = fl_filename_list(directory, &entries); + + for (i = 0; i < n; i ++) { + if (entries[i]->d_name[0] != '.') { + snprintf(full, sizeof(full), "%s/%s", directory, entries[i]->d_name); + + if (fl_filename_isdir(full)) load_kde_icons(full, icondir); + else load_kde_mimelnk(full, icondir); + } + + free((void *)entries[i]); + } + + free((void*)entries); +} + + +// +// 'load_kde_mimelnk()' - Load a KDE "mimelnk" file. +// + +static void +load_kde_mimelnk(const char *filename, // I - mimelnk filename + const char *icondir) { // I - Location of icons + FILE *fp; + char tmp[1024]; + char iconfilename[1024]; + char pattern[1024]; + char mimetype[1024]; + char *val; + char full_iconfilename[1024]; + Fl_File_Icon *icon; + + + mimetype[0] = '\0'; + pattern[0] = '\0'; + iconfilename[0] = '\0'; + + if ((fp = fopen(filename, "rb")) != NULL) { + while (fgets(tmp, sizeof(tmp), fp)) { + if ((val = get_kde_val(tmp, "Icon")) != NULL) + strlcpy(iconfilename, val, sizeof(iconfilename)); + else if ((val = get_kde_val(tmp, "MimeType")) != NULL) + strlcpy(mimetype, val, sizeof(mimetype)); + else if ((val = get_kde_val(tmp, "Patterns")) != NULL) + strlcpy(pattern, val, sizeof(pattern)); + } + + fclose(fp); + +#ifdef DEBUG + printf("%s: Icon=\"%s\", MimeType=\"%s\", Patterns=\"%s\"\n", filename, + iconfilename, mimetype, pattern); +#endif // DEBUG + + if (!pattern[0] && strncmp(mimetype, "inode/", 6)) return; + + if (iconfilename[0]) { + if (iconfilename[0] == '/') { + strlcpy(full_iconfilename, iconfilename, sizeof(full_iconfilename)); + } else if (!access(icondir, F_OK)) { + // KDE 3.x and 2.x icons + int i; // Looping var + static const char *paths[] = { // Subdirs to look in... + "16x16/actions", + "16x16/apps", + "16x16/devices", + "16x16/filesystems", + "16x16/mimetypes", +/* + "20x20/actions", + "20x20/apps", + "20x20/devices", + "20x20/filesystems", + "20x20/mimetypes", + + "22x22/actions", + "22x22/apps", + "22x22/devices", + "22x22/filesystems", + "22x22/mimetypes", + + "24x24/actions", + "24x24/apps", + "24x24/devices", + "24x24/filesystems", + "24x24/mimetypes", +*/ + "32x32/actions", + "32x32/apps", + "32x32/devices", + "32x32/filesystems", + "32x32/mimetypes", +/* + "36x36/actions", + "36x36/apps", + "36x36/devices", + "36x36/filesystems", + "36x36/mimetypes", + + "48x48/actions", + "48x48/apps", + "48x48/devices", + "48x48/filesystems", + "48x48/mimetypes", + + "64x64/actions", + "64x64/apps", + "64x64/devices", + "64x64/filesystems", + "64x64/mimetypes", + + "96x96/actions", + "96x96/apps", + "96x96/devices", + "96x96/filesystems", + "96x96/mimetypes" +*/ }; + + for (i = 0; i < (int)(sizeof(paths) / sizeof(paths[0])); i ++) { + snprintf(full_iconfilename, sizeof(full_iconfilename), + "%s/%s/%s.png", icondir, paths[i], iconfilename); + + if (!access(full_iconfilename, F_OK)) break; + } + + if (i >= (int)(sizeof(paths) / sizeof(paths[0]))) return; + } else { + // KDE 1.x icons + snprintf(full_iconfilename, sizeof(full_iconfilename), + "%s/%s", tmp, iconfilename); + + if (access(full_iconfilename, F_OK)) return; + } + + if (strncmp(mimetype, "inode/", 6) == 0) { + if (!strcmp(mimetype + 6, "directory")) + icon = new Fl_File_Icon("*", Fl_File_Icon::DIRECTORY); + else if (!strcmp(mimetype + 6, "blockdevice")) + icon = new Fl_File_Icon("*", Fl_File_Icon::DEVICE); + else if (!strcmp(mimetype + 6, "fifo")) + icon = new Fl_File_Icon("*", Fl_File_Icon::FIFO); + else return; + } else { + icon = new Fl_File_Icon(kde_to_fltk_pattern(pattern), + Fl_File_Icon::PLAIN); + } + + icon->load(full_iconfilename); + } + } +} + + +// +// 'kde_to_fltk_pattern()' - Convert a KDE pattern to a FLTK pattern. +// + +static char * +kde_to_fltk_pattern(const char *kdepattern) { + char *pattern, + *patptr; + + + pattern = (char *)malloc(strlen(kdepattern) + 3); + strcpy(pattern, "{"); + strcpy(pattern + 1, kdepattern); + + if (pattern[strlen(pattern) - 1] == ';') pattern[strlen(pattern) - 1] = '\0'; + + strcat(pattern, "}"); + + for (patptr = pattern; *patptr; patptr ++) { + if (*patptr == ';') *patptr = '|'; + } + + return (pattern); +} + + +// +// 'get_kde_val()' - Get a KDE value. +// + +static char * +get_kde_val(char *str, + const char *key) { + while (*str == *key) { + str ++; + key ++; + } + + if (*key == '\0' && *str == '=') { + if (str[strlen(str) - 1] == '\n') str[strlen(str) - 1] = '\0'; + + return (str + 1); + } + + return ((char *)0); +} + + +// +// End of "$Id: Fl_File_Icon2.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_File_Input.cxx b/third_party/windows/fltk-1.1.10/src/Fl_File_Input.cxx new file mode 100644 index 0000000..bfcc794 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_File_Input.cxx @@ -0,0 +1,288 @@ +// +// "$Id: Fl_File_Input.cxx 6759 2009-04-13 07:32:03Z matt $" +// +// File_Input header file for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// Original version Copyright 1998 by Curtis Edwards. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include +#include "flstring.h" + + +// +// Height of directory buttons... +// + +#define DIR_HEIGHT 10 + + +// +// Redraw bit for directory bar... +// + +#define FL_DAMAGE_BAR 0x10 + + +// +// 'Fl_File_Input::Fl_File_Input()' - Create a Fl_File_Input widget. +// + +Fl_File_Input::Fl_File_Input(int X, int Y, int W, int H, const char *l) + : Fl_Input(X, Y, W, H, l) { + buttons_[0] = 0; + errorcolor_ = FL_RED; + ok_entry_ = 1; + pressed_ = -1; + + down_box(FL_UP_BOX); +} + +// +// 'Fl_File_Input::draw_buttons()' - Draw directory buttons. +// + +void +Fl_File_Input::draw_buttons() { + int i, // Looping var + X; // Current X position + + + if (damage() & (FL_DAMAGE_BAR | FL_DAMAGE_ALL)) { + update_buttons(); + } + + for (X = 0, i = 0; buttons_[i]; i ++) + { + if ((X + buttons_[i]) > xscroll()) { + if (X < xscroll()) { + draw_box(pressed_ == i ? fl_down(down_box()) : down_box(), + x(), y(), X + buttons_[i] - xscroll(), DIR_HEIGHT, FL_GRAY); + } else if ((X + buttons_[i] - xscroll()) > w()) { + draw_box(pressed_ == i ? fl_down(down_box()) : down_box(), + x() + X - xscroll(), y(), w() - X + xscroll(), DIR_HEIGHT, + FL_GRAY); + } else { + draw_box(pressed_ == i ? fl_down(down_box()) : down_box(), + x() + X - xscroll(), y(), buttons_[i], DIR_HEIGHT, FL_GRAY); + } + } + + X += buttons_[i]; + } + + if (X < w()) { + draw_box(pressed_ == i ? fl_down(down_box()) : down_box(), + x() + X - xscroll(), y(), w() - X + xscroll(), DIR_HEIGHT, FL_GRAY); + } +} + +// +// 'Fl_File_Input::update_buttons()' - Update the sizes of the directory buttons. +// + +void +Fl_File_Input::update_buttons() { + int i; // Looping var + const char *start, // Start of path component + *end; // End of path component + + +// puts("update_buttons()"); + + // Set the current font & size... + fl_font(textfont(), textsize()); + + // Loop through the value string, setting widths... + for (i = 0, start = value(); + start && i < (int)(sizeof(buttons_) / sizeof(buttons_[0]) - 1); + start = end, i ++) { +// printf(" start = \"%s\"\n", start); + if ((end = strchr(start, '/')) == NULL) +#if defined(WIN32) || defined(__EMX__) + if ((end = strchr(start, '\\')) == NULL) +#endif // WIN32 || __EMX__ + break; + + end ++; + + buttons_[i] = (short)fl_width(start, end - start); + if (!i) buttons_[i] += Fl::box_dx(box()) + 6; + } + +// printf(" found %d components/buttons...\n", i); + + buttons_[i] = 0; +} + + +// +// 'Fl_File_Input::value()' - Set the value of the widget... +// + +int // O - TRUE on success +Fl_File_Input::value(const char *str, // I - New string value + int len) { // I - Length of value + damage(FL_DAMAGE_BAR); + return Fl_Input::value(str,len); +} + + +int // O - TRUE on success +Fl_File_Input::value(const char *str) { // I - New string value + damage(FL_DAMAGE_BAR); + return Fl_Input::value(str); +} + + +// +// 'Fl_File_Input::draw()' - Draw the file input widget... +// + +void +Fl_File_Input::draw() { + Fl_Boxtype b = box(); + if (damage() & (FL_DAMAGE_BAR | FL_DAMAGE_ALL)) draw_buttons(); + // this flag keeps Fl_Input_::drawtext from drawing a bogus box! + char must_trick_fl_input_ = + Fl::focus()!=this && !size() && !(damage()&FL_DAMAGE_ALL); + if ((damage() & FL_DAMAGE_ALL) || must_trick_fl_input_) + draw_box(b,x(),y()+DIR_HEIGHT,w(),h()-DIR_HEIGHT,color()); + if (!must_trick_fl_input_) + Fl_Input_::drawtext(x()+Fl::box_dx(b)+3, y()+Fl::box_dy(b)+DIR_HEIGHT, + w()-Fl::box_dw(b)-6, h()-Fl::box_dh(b)-DIR_HEIGHT); +} + + +// +// 'Fl_File_Input::handle()' - Handle events in the widget... +// + +int // O - TRUE if we handled event +Fl_File_Input::handle(int event) // I - Event +{ +// printf("handle(event = %d)\n", event); + static char inButtonBar = 0; + + switch (event) { + case FL_MOVE : + case FL_ENTER : + if (active_r()) { + if (Fl::event_y() < (y() + DIR_HEIGHT)) + window()->cursor(FL_CURSOR_DEFAULT); + else + window()->cursor(FL_CURSOR_INSERT); + } + + return 1; + + case FL_PUSH : + inButtonBar = (Fl::event_y() < (y() + DIR_HEIGHT)); + case FL_RELEASE : + case FL_DRAG : + if (inButtonBar) + return handle_button(event); + else + return Fl_Input::handle(event); + + default : + if (Fl_Input::handle(event)) { + damage(FL_DAMAGE_BAR); + return 1; + } + + return 0; + } +} + + +// +// 'Fl_File_Input::handle_button()' - Handle button events in the widget... +// + +int // O - TRUE if we handled event +Fl_File_Input::handle_button(int event) // I - Event +{ + int i, // Looping var + X; // Current X position + char *start, // Start of path component + *end; // End of path component + char newvalue[1024]; // New value + + + // Figure out which button is being pressed... + for (X = 0, i = 0; buttons_[i]; i ++) + { + X += buttons_[i]; + + if (X > xscroll() && Fl::event_x() < (x() + X - xscroll())) break; + } + +// printf("handle_button(event = %d), button = %d\n", event, i); + + // Redraw the directory bar... + if (event == FL_RELEASE) pressed_ = -1; + else pressed_ = (short)i; + + window()->make_current(); + draw_buttons(); + + // Return immediately if the user is clicking on the last button or + // has not released the mouse button... + if (!buttons_[i] || event != FL_RELEASE) return 1; + + // Figure out where to truncate the path... + strlcpy(newvalue, value(), sizeof(newvalue)); + + for (start = newvalue, end = start; start && i >= 0; start = end, i --) { +// printf(" start = \"%s\"\n", start); + if ((end = strchr(start, '/')) == NULL) +#if defined(WIN32) || defined(__EMX__) + if ((end = strchr(start, '\\')) == NULL) +#endif // WIN32 || __EMX__ + break; + + end ++; + } + + if (i < 0) { + // Found the end; truncate the value and update the buttons... + *start = '\0'; + value(newvalue, start - newvalue); + + // Then do the callbacks, if necessary... + set_changed(); + if (when() & FL_WHEN_CHANGED) do_callback(); + } + + return 1; +} + + +// +// End of "$Id: Fl_File_Input.cxx 6759 2009-04-13 07:32:03Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Font.H b/third_party/windows/fltk-1.1.10/src/Fl_Font.H new file mode 100644 index 0000000..f28e0a6 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Font.H @@ -0,0 +1,111 @@ +// +// "$Id: Fl_Font.H 5334 2006-08-19 15:24:55Z matt $" +// +// Font definitions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Two internal fltk data structures: +// +// Fl_Fontdesc: an entry into the fl_font() table. There is one of these +// for each fltk font number. +// +// Fl_FontSize: a structure for an actual system font, with junk to +// help choose it and info on character sizes. Each Fl_Fontdesc has a +// linked list of these. These are created the first time each system +// font/size combination is used. + +#ifndef FL_FONT_ +#define FL_FONT_ + +#include + +# if USE_XFT +typedef struct _XftFont XftFont; +# endif // USE_XFT + +class Fl_FontSize { +public: + Fl_FontSize *next; // linked list for this Fl_Fontdesc +# ifdef WIN32 + HFONT fid; + int width[256]; + TEXTMETRIC metr; + FL_EXPORT Fl_FontSize(const char* fontname, int size); +# elif defined(__APPLE_QD__) + FL_EXPORT Fl_FontSize(const char* fontname, int size); + short font, face, size; + short ascent, descent; + short width[256]; + bool knowMetrics; +# elif defined(__APPLE_QUARTZ__) + FL_EXPORT Fl_FontSize(const char* fontname, int size); + ATSUTextLayout layout; + ATSUStyle style; + short ascent, descent, q_width; + short width[256]; + bool knowWidths; + char *q_name; + int size; +# elif USE_XFT + XftFont* font; + const char* encoding; + int size; + FL_EXPORT Fl_FontSize(const char* xfontname); +# else + XFontStruct* font; // X font information + FL_EXPORT Fl_FontSize(const char* xfontname); +# endif + int minsize; // smallest point size that should use this + int maxsize; // largest point size that should use this +# if HAVE_GL + unsigned int listbase;// base of display list, 0 = none +# endif + FL_EXPORT ~Fl_FontSize(); +}; + +extern FL_EXPORT Fl_FontSize *fl_fontsize; // the currently selected one + +struct Fl_Fontdesc { + const char *name; + char fontname[128]; // "Pretty" font name + Fl_FontSize *first; // linked list of sizes of this style +# ifndef WIN32 + char **xlist; // matched X font names + int n; // size of xlist, negative = don't free xlist! +# endif +}; + +extern FL_EXPORT Fl_Fontdesc *fl_fonts; // the table + +# ifndef WIN32 +// functions for parsing X font names: +FL_EXPORT const char* fl_font_word(const char *p, int n); +FL_EXPORT char *fl_find_fontsize(char *name); +# endif + +#endif + +// +// End of "$Id: Fl_Font.H 5334 2006-08-19 15:24:55Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_GIF_Image.cxx b/third_party/windows/fltk-1.1.10/src/Fl_GIF_Image.cxx new file mode 100644 index 0000000..21ea9fd --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_GIF_Image.cxx @@ -0,0 +1,384 @@ +// +// "$Id: Fl_GIF_Image.cxx 5845 2007-05-20 00:01:06Z mike $" +// +// Fl_GIF_Image routines. +// +// Copyright 1997-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include +#include "flstring.h" + +// Read a .gif file and convert it to a "xpm" format (actually my +// modified one with compressed colormaps). + +// Extensively modified from original code for gif2ras by +// Patrick J. Naughton of Sun Microsystems. The original +// copyright notice follows: + +/* gif2ras.c - Converts from a Compuserve GIF (tm) image to a Sun Raster image. + * + * Copyright (c) 1988 by Patrick J. Naughton + * + * Author: Patrick J. Naughton + * naughton@wind.sun.com + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation. + * + * This file is provided AS IS with no warranties of any kind. The author + * shall have no liability with respect to the infringement of copyrights, + * trade secrets or any patents by this file or any part thereof. In no + * event will the author be liable for any lost revenue or profits or + * other special, indirect and consequential damages. + * + * Comments and additions should be sent to the author: + * + * Patrick J. Naughton + * Sun Microsystems, Inc. + * 2550 Garcia Ave, MS 14-40 + * Mountain View, CA 94043 + * (415) 336-1080 + */ + +typedef unsigned char uchar; + +#define NEXTBYTE (uchar)getc(GifFile) +#define GETSHORT(var) var = NEXTBYTE; var += NEXTBYTE << 8 + +Fl_GIF_Image::Fl_GIF_Image(const char *infname) : Fl_Pixmap((char *const*)0) { + FILE *GifFile; // File to read + char **new_data; // Data array + + if ((GifFile = fopen(infname, "rb")) == NULL) { + Fl::error("Fl_GIF_Image: Unable to open %s!", infname); + return; + } + + {char b[6]; + if (fread(b,1,6,GifFile)<6) { + fclose(GifFile); + return; /* quit on eof */ + } + if (b[0]!='G' || b[1]!='I' || b[2] != 'F') { + fclose(GifFile); + Fl::error("Fl_GIF_Image: %s is not a GIF file.\n", infname); + return; + } + if (b[3]!='8' || b[4]>'9' || b[5]!= 'a') + Fl::warning("%s is version %c%c%c.",infname,b[3],b[4],b[5]); + } + + int Width; GETSHORT(Width); + int Height; GETSHORT(Height); + + uchar ch = NEXTBYTE; + char HasColormap = ((ch & 0x80) != 0); + int BitsPerPixel = (ch & 7) + 1; + int ColorMapSize = 1 << BitsPerPixel; + // int OriginalResolution = ((ch>>4)&7)+1; + // int SortedTable = (ch&8)!=0; + ch = NEXTBYTE; // Background Color index + ch = NEXTBYTE; // Aspect ratio is N/64 + + // Read in global colormap: + uchar transparent_pixel = 0; + char has_transparent = 0; + uchar Red[256], Green[256], Blue[256]; /* color map */ + if (HasColormap) { + for (int i=0; i < ColorMapSize; i++) { + Red[i] = NEXTBYTE; + Green[i] = NEXTBYTE; + Blue[i] = NEXTBYTE; + } + } else { + Fl::warning("%s does not have a colormap.", infname); + for (int i = 0; i < ColorMapSize; i++) + Red[i] = Green[i] = Blue[i] = (uchar)(255 * i / (ColorMapSize-1)); + } + + int CodeSize; /* Code size, init from GIF header, increases... */ + char Interlace; + + for (;;) { + + int i = NEXTBYTE; + if (i<0) { + fclose(GifFile); + Fl::error("Fl_GIF_Image: %s - unexpected EOF",infname); + return; + } + int blocklen; + + // if (i == 0x3B) return 0; eof code + + if (i == 0x21) { // a "gif extension" + + ch = NEXTBYTE; + blocklen = NEXTBYTE; + + if (ch==0xF9 && blocklen==4) { // Netscape animation extension + + char bits; + bits = NEXTBYTE; + getc(GifFile); getc(GifFile); // GETSHORT(delay); + transparent_pixel = NEXTBYTE; + if (bits & 1) has_transparent = 1; + blocklen = NEXTBYTE; + + } else if (ch == 0xFF) { // Netscape repeat count + ; + + } else if (ch != 0xFE) { //Gif Comment + Fl::warning("%s: unknown gif extension 0x%02x.", infname, ch); + } + } else if (i == 0x2c) { // an image + + ch = NEXTBYTE; ch = NEXTBYTE; // GETSHORT(x_position); + ch = NEXTBYTE; ch = NEXTBYTE; // GETSHORT(y_position); + GETSHORT(Width); + GETSHORT(Height); + ch = NEXTBYTE; + Interlace = ((ch & 0x40) != 0); + if (ch&0x80) { + // read local color map + int n = 2<<(ch&7); + for (i=0; i < n; i++) { + Red[i] = NEXTBYTE; + Green[i] = NEXTBYTE; + Blue[i] = NEXTBYTE; + } + } + CodeSize = NEXTBYTE+1; + break; // okay, this is the image we want + } else { + Fl::warning("%s: unknown gif code 0x%02x", infname, i); + blocklen = 0; + } + + // skip the data: + while (blocklen>0) {while (blocklen--) {ch = NEXTBYTE;} blocklen=NEXTBYTE;} + } + + if (BitsPerPixel >= CodeSize) + { + // Workaround for broken GIF files... + BitsPerPixel = CodeSize - 1; + ColorMapSize = 1 << BitsPerPixel; + } + + uchar *Image = new uchar[Width*Height]; + + int YC = 0, Pass = 0; /* Used to de-interlace the picture */ + uchar *p = Image; + uchar *eol = p+Width; + + int InitCodeSize = CodeSize; + int ClearCode = (1 << (CodeSize-1)); + int EOFCode = ClearCode + 1; + int FirstFree = ClearCode + 2; + int FinChar = 0; + int ReadMask = (1< 7) { + if (blocklen <= 0) { + blocklen = NEXTBYTE; + if (blocklen <= 0) break; + } + thisbyte = NEXTBYTE; blocklen--; + CurCode |= thisbyte<<8; + } + if (frombit+CodeSize > 15) { + if (blocklen <= 0) { + blocklen = NEXTBYTE; + if (blocklen <= 0) break; + } + thisbyte = NEXTBYTE; blocklen--; + CurCode |= thisbyte<<16; + } + CurCode = (CurCode>>frombit)&ReadMask; + frombit = (frombit+CodeSize)%8; + + if (CurCode == ClearCode) { + CodeSize = InitCodeSize; + ReadMask = (1<= ColorMapSize) {*tp++ = Suffix[i]; i = Prefix[i];} + *tp++ = FinChar = i; + do { + *p++ = *--tp; + if (p >= eol) { + if (!Interlace) YC++; + else switch (Pass) { + case 0: YC += 8; if (YC >= Height) {Pass++; YC = 4;} break; + case 1: YC += 8; if (YC >= Height) {Pass++; YC = 2;} break; + case 2: YC += 4; if (YC >= Height) {Pass++; YC = 1;} break; + case 3: YC += 2; break; + } + if (YC>=Height) YC=0; /* cheap bug fix when excess data */ + p = Image + YC*Width; + eol = p+Width; + } + } while (tp > OutCode); + + if (OldCode != ClearCode) { + Prefix[FreeCode] = (short)OldCode; + Suffix[FreeCode] = FinChar; + FreeCode++; + if (FreeCode > ReadMask) { + if (CodeSize < 12) { + CodeSize++; + ReadMask = (1 << CodeSize) - 1; + } + else FreeCode--; + } + } + OldCode = CurCode; + } + + // We are done reading the file, now convert to xpm: + + // allocate line pointer arrays: + w(Width); + h(Height); + d(1); + new_data = new char*[Height+2]; + + // transparent pixel must be zero, swap if it isn't: + if (has_transparent && transparent_pixel != 0) { + // swap transparent pixel with zero + p = Image+Width*Height; + while (p-- > Image) { + if (*p==transparent_pixel) *p = 0; + else if (!*p) *p = transparent_pixel; + } + uchar t; + t = Red[0]; + Red[0] = Red[transparent_pixel]; + Red[transparent_pixel] = t; + + t = Green[0]; + Green[0] = Green[transparent_pixel]; + Green[transparent_pixel] = t; + + t = Blue[0]; + Blue[0] = Blue[transparent_pixel]; + Blue[transparent_pixel] = t; + } + + // find out what colors are actually used: + uchar used[256]; uchar remap[256]; + int i; + for (i = 0; i < ColorMapSize; i++) used[i] = 0; + p = Image+Width*Height; + while (p-- > Image) used[*p] = 1; + + // remap them to start with printing characters: + int base = has_transparent && used[0] ? ' ' : ' '+1; + int numcolors = 0; + for (i = 0; i < ColorMapSize; i++) if (used[i]) { + remap[i] = (uchar)(base++); + numcolors++; + } + + // write the first line of xpm data (use suffix as temp array): + int length = sprintf((char*)(Suffix), + "%d %d %d %d",Width,Height,-numcolors,1); + new_data[0] = new char[length+1]; + strcpy(new_data[0], (char*)Suffix); + + // write the colormap + new_data[1] = (char*)(p = new uchar[4*numcolors]); + for (i = 0; i < ColorMapSize; i++) if (used[i]) { + *p++ = remap[i]; + *p++ = Red[i]; + *p++ = Green[i]; + *p++ = Blue[i]; + } + + // remap the image data: + p = Image+Width*Height; + while (p-- > Image) *p = remap[*p]; + + // split the image data into lines: + for (i=0; i +# define GLContext HGLRC +#elif defined(__APPLE_QD__) +# include +# include +# define GLContext AGLContext +#elif defined(__APPLE_QUARTZ__) +// warning: the Quartz version should probably use Core GL (CGL) instead of AGL +# include +# include +# define GLContext AGLContext +#else +# include +# define GLContext GLXContext +#endif + +// Describes crap needed to create a GLContext. +class Fl_Gl_Choice { + int mode; + const int *alist; + Fl_Gl_Choice *next; +public: +#ifdef WIN32 + int pixelformat; // the visual to use + PIXELFORMATDESCRIPTOR pfd; // some wgl calls need this thing +#elif defined(__APPLE_QD__) + AGLPixelFormat pixelformat; +#elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + AGLPixelFormat pixelformat; +#else + XVisualInfo *vis; // the visual to use + Colormap colormap; // a colormap for that visual +#endif + // Return one of these structures for a given gl mode. + // The second argument is a glX attribute list, and is used if mode is + // zero. This is not supported on Win32: + static Fl_Gl_Choice *find(int mode, const int *); +}; + +class Fl_Window; + +#ifdef WIN32 + +GLContext fl_create_gl_context(Fl_Window*, const Fl_Gl_Choice*, int layer=0); + +#elif defined(__APPLE_QD__) + +GLContext fl_create_gl_context(Fl_Window*, const Fl_Gl_Choice*, int layer=0); + +#elif defined(__APPLE_QUARTZ__) +// warning: the Quartz version should probably use Core GL (CGL) instead of AGL + +GLContext fl_create_gl_context(Fl_Window*, const Fl_Gl_Choice*, int layer=0); + +#else + +GLContext fl_create_gl_context(XVisualInfo* vis); + +static inline +GLContext fl_create_gl_context(Fl_Window*, const Fl_Gl_Choice* g) { + return fl_create_gl_context(g->vis); +} + +#endif + +void fl_set_gl_context(Fl_Window*, GLContext); +void fl_no_gl_context(); +void fl_delete_gl_context(GLContext); + +#endif + +// +// End of "$Id: Fl_Gl_Choice.H 4052 2005-02-24 21:55:12Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Gl_Choice.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Gl_Choice.cxx new file mode 100644 index 0000000..124f1a0 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Gl_Choice.cxx @@ -0,0 +1,453 @@ +// +// "$Id: Fl_Gl_Choice.cxx 6811 2009-06-30 19:05:09Z matt $" +// +// OpenGL visual selection code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#if HAVE_GL + +# include +# include +# include +# include "Fl_Gl_Choice.H" +# include +# include "flstring.h" + +# ifdef __APPLE__ +# include +# endif + +# ifdef WIN32 +void fl_save_dc(HWND, HDC); +# endif + +static Fl_Gl_Choice *first; + +// this assummes one of the two arguments is zero: +// We keep the list system in Win32 to stay compatible and interpret +// the list later... +Fl_Gl_Choice *Fl_Gl_Choice::find(int m, const int *alistp) { + Fl_Gl_Choice *g; + + for (g = first; g; g = g->next) + if (g->mode == m && g->alist == alistp) + return g; + +# ifdef __APPLE_QD__ + const int *blist; + int list[32]; + + if (alistp) + blist = alistp; + else { + int n = 0; + if (m & FL_INDEX) { + list[n++] = AGL_BUFFER_SIZE; + list[n++] = 8; // glut tries many sizes, but this should work... + } else { + list[n++] = AGL_RGBA; + list[n++] = AGL_GREEN_SIZE; + list[n++] = (m & FL_RGB8) ? 8 : 1; + if (m & FL_ALPHA) { + list[n++] = AGL_ALPHA_SIZE; + list[n++] = (m & FL_RGB8) ? 8 : 1; + } + if (m & FL_ACCUM) { + list[n++] = AGL_ACCUM_GREEN_SIZE; + list[n++] = 1; + if (m & FL_ALPHA) { + list[n++] = AGL_ACCUM_ALPHA_SIZE; + list[n++] = 1; + } + } + } + if (m & FL_DOUBLE) { + list[n++] = AGL_DOUBLEBUFFER; + } + if (m & FL_DEPTH) { + list[n++] = AGL_DEPTH_SIZE; list[n++] = 24; + } + if (m & FL_STENCIL) { + list[n++] = AGL_STENCIL_SIZE; list[n++] = 1; + } +# ifdef AGL_STEREO + if (m & FL_STEREO) { + list[n++] = AGL_STEREO; + } +# endif + list[n] = AGL_NONE; + blist = list; + } + fl_open_display(); + AGLPixelFormat fmt = aglChoosePixelFormat(NULL, 0, (GLint*)blist); + if (!fmt) return 0; + +#elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + const int *blist; + int list[32]; + + if (alistp) + blist = alistp; + else { + int n = 0; + if (m & FL_INDEX) { + list[n++] = AGL_BUFFER_SIZE; + list[n++] = 8; // glut tries many sizes, but this should work... + } else { + list[n++] = AGL_RGBA; + list[n++] = AGL_GREEN_SIZE; + list[n++] = (m & FL_RGB8) ? 8 : 1; + if (m & FL_ALPHA) { + list[n++] = AGL_ALPHA_SIZE; + list[n++] = (m & FL_RGB8) ? 8 : 1; + } + if (m & FL_ACCUM) { + list[n++] = AGL_ACCUM_GREEN_SIZE; + list[n++] = 1; + if (m & FL_ALPHA) { + list[n++] = AGL_ACCUM_ALPHA_SIZE; + list[n++] = 1; + } + } + } + if (m & FL_DOUBLE) { + list[n++] = AGL_DOUBLEBUFFER; + } + if (m & FL_DEPTH) { + list[n++] = AGL_DEPTH_SIZE; list[n++] = 24; + } + if (m & FL_STENCIL) { + list[n++] = AGL_STENCIL_SIZE; list[n++] = 1; + } +# ifdef AGL_STEREO + if (m & FL_STEREO) { + list[n++] = AGL_STEREO; + } +# endif + list[n] = AGL_NONE; + blist = list; + } + fl_open_display(); + AGLPixelFormat fmt = aglChoosePixelFormat(NULL, 0, (GLint*)blist); + if (!fmt) return 0; + +# elif !defined(WIN32) + + const int *blist; + int list[32]; + + if (alistp) + blist = alistp; + else { + int n = 0; + if (m & FL_INDEX) { + list[n++] = GLX_BUFFER_SIZE; + list[n++] = 8; // glut tries many sizes, but this should work... + } else { + list[n++] = GLX_RGBA; + list[n++] = GLX_GREEN_SIZE; + list[n++] = (m & FL_RGB8) ? 8 : 1; + if (m & FL_ALPHA) { + list[n++] = GLX_ALPHA_SIZE; + list[n++] = (m & FL_RGB8) ? 8 : 1; + } + if (m & FL_ACCUM) { + list[n++] = GLX_ACCUM_GREEN_SIZE; + list[n++] = 1; + if (m & FL_ALPHA) { + list[n++] = GLX_ACCUM_ALPHA_SIZE; + list[n++] = 1; + } + } + } + if (m & FL_DOUBLE) { + list[n++] = GLX_DOUBLEBUFFER; + } + if (m & FL_DEPTH) { + list[n++] = GLX_DEPTH_SIZE; list[n++] = 1; + } + if (m & FL_STENCIL) { + list[n++] = GLX_STENCIL_SIZE; list[n++] = 1; + } + if (m & FL_STEREO) { + list[n++] = GLX_STEREO; + } +# if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) + if (m & FL_MULTISAMPLE) { + list[n++] = GLX_SAMPLES_SGIS; + list[n++] = 4; // value Glut uses + } +# endif + list[n] = 0; + blist = list; + } + + fl_open_display(); + XVisualInfo *visp = glXChooseVisual(fl_display, fl_screen, (int *)blist); + if (!visp) { +# if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) + if (m&FL_MULTISAMPLE) return find(m&~FL_MULTISAMPLE,0); +# endif + return 0; + } + +# else + + // Replacement for ChoosePixelFormat() that finds one with an overlay + // if possible: + if (!fl_gc) fl_GetDC(0); + int pixelformat = 0; + PIXELFORMATDESCRIPTOR chosen_pfd; + for (int i = 1; ; i++) { + PIXELFORMATDESCRIPTOR pfd; + if (!DescribePixelFormat(fl_gc, i, sizeof(pfd), &pfd)) break; + // continue if it does not satisfy our requirements: + if (~pfd.dwFlags & (PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL)) continue; + if (pfd.iPixelType != ((m&FL_INDEX)?PFD_TYPE_COLORINDEX:PFD_TYPE_RGBA)) continue; + if ((m & FL_ALPHA) && !pfd.cAlphaBits) continue; + if ((m & FL_ACCUM) && !pfd.cAccumBits) continue; + if ((!(m & FL_DOUBLE)) != (!(pfd.dwFlags & PFD_DOUBLEBUFFER))) continue; + if ((!(m & FL_STEREO)) != (!(pfd.dwFlags & PFD_STEREO))) continue; + if ((m & FL_DEPTH) && !pfd.cDepthBits) continue; + if ((m & FL_STENCIL) && !pfd.cStencilBits) continue; + // see if better than the one we have already: + if (pixelformat) { + // offering non-generic rendering is better (read: hardware accelleration) + if (!(chosen_pfd.dwFlags & PFD_GENERIC_FORMAT) && + (pfd.dwFlags & PFD_GENERIC_FORMAT)) continue; + // offering overlay is better: + else if (!(chosen_pfd.bReserved & 15) && (pfd.bReserved & 15)) {} + // otherwise more bit planes is better: + else if (chosen_pfd.cColorBits > pfd.cColorBits) continue; + else if (chosen_pfd.cDepthBits > pfd.cDepthBits) continue; + } + pixelformat = i; + chosen_pfd = pfd; + } + //printf("Chosen pixel format is %d\n", pixelformat); + if (!pixelformat) return 0; + +# endif + + g = new Fl_Gl_Choice; + g->mode = m; + g->alist = alistp; + g->next = first; + first = g; + +# ifdef WIN32 + g->pixelformat = pixelformat; + g->pfd = chosen_pfd; +# elif defined(__APPLE_QD__) + g->pixelformat = fmt; +# elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + g->pixelformat = fmt; +# else + g->vis = visp; + + if (/*MaxCmapsOfScreen(ScreenOfDisplay(fl_display,fl_screen))==1 && */ + visp->visualid == fl_visual->visualid && + !getenv("MESA_PRIVATE_CMAP")) + g->colormap = fl_colormap; + else + g->colormap = XCreateColormap(fl_display, RootWindow(fl_display,fl_screen), + visp->visual, AllocNone); +# endif + + return g; +} + +static GLContext *context_list = 0; +static int nContext = 0, NContext = 0; + +static void add_context(GLContext ctx) { + if (!ctx) return; + if (nContext==NContext) { + if (!NContext) NContext = 8; + NContext *= 2; + context_list = (GLContext*)realloc( + context_list, NContext*sizeof(GLContext)); + } + context_list[nContext++] = ctx; +} + +static void del_context(GLContext ctx) { + int i; + for (i=0; iprivate_dc; + if (!hdc) { + hdc = i->private_dc = GetDCEx(i->xid, 0, DCX_CACHE); + fl_save_dc(i->xid, hdc); + SetPixelFormat(hdc, g->pixelformat, (PIXELFORMATDESCRIPTOR*)(&g->pfd)); +# if USE_COLORMAP + if (fl_palette) SelectPalette(hdc, fl_palette, FALSE); +# endif + } + GLContext context = + layer ? wglCreateLayerContext(hdc, layer) : wglCreateContext(hdc); + if (context) { + if (context_list && nContext) + wglShareLists(context_list[0], context); + add_context(context); + } + return context; +} + +# elif defined(__APPLE_QD__) +GLContext fl_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) { + GLContext context, shared_ctx = 0; + if (context_list && nContext) shared_ctx = context_list[0]; + context = aglCreateContext( g->pixelformat, shared_ctx); + if (!context) return 0; + add_context((GLContext)context); + if ( window->parent() ) { + Rect wrect; GetWindowPortBounds( fl_xid(window), &wrect ); + GLint rect[] = { window->x(), wrect.bottom-window->h()-window->y(), window->w(), window->h() }; + aglSetInteger( (GLContext)context, AGL_BUFFER_RECT, rect ); + aglEnable( (GLContext)context, AGL_BUFFER_RECT ); + } + aglSetDrawable( context, GetWindowPort( fl_xid(window) ) ); + return (context); +} +# elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + GLContext fl_create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) { + GLContext context, shared_ctx = 0; + if (context_list && nContext) shared_ctx = context_list[0]; + context = aglCreateContext( g->pixelformat, shared_ctx); + if (!context) return 0; + add_context((GLContext)context); + if ( window->parent() ) { + Rect wrect; GetWindowPortBounds( fl_xid(window), &wrect ); + GLint rect[] = { window->x(), wrect.bottom-window->h()-window->y(), window->w(), window->h() }; + aglSetInteger( (GLContext)context, AGL_BUFFER_RECT, rect ); + aglEnable( (GLContext)context, AGL_BUFFER_RECT ); + } + aglSetDrawable( context, GetWindowPort( fl_xid(window) ) ); + return (context); +} +# else + +GLContext fl_create_gl_context(XVisualInfo* vis) { + GLContext shared_ctx = 0; + if (context_list && nContext) shared_ctx = context_list[0]; + GLContext context = glXCreateContext(fl_display, vis, shared_ctx, 1); + if (context) + add_context(context); + return context; +} + +# endif + +static GLContext cached_context; +static Fl_Window* cached_window; + +void fl_set_gl_context(Fl_Window* w, GLContext context) { + if (context != cached_context || w != cached_window) { + cached_context = context; + cached_window = w; +# ifdef WIN32 + wglMakeCurrent(Fl_X::i(w)->private_dc, context); +# elif defined(__APPLE_QD__) + if ( w->parent() ) { //: resize our GL buffer rectangle + Rect wrect; GetWindowPortBounds( fl_xid(w), &wrect ); + GLint rect[] = { w->x(), wrect.bottom-w->h()-w->y(), w->w(), w->h() }; + aglSetInteger( context, AGL_BUFFER_RECT, rect ); + aglEnable( context, AGL_BUFFER_RECT ); + } + aglSetDrawable(context, GetWindowPort( fl_xid(w) ) ); + aglSetCurrentContext(context); +# elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + if ( w->parent() ) { //: resize our GL buffer rectangle + Rect wrect; GetWindowPortBounds( fl_xid(w), &wrect ); + GLint rect[] = { w->x(), wrect.bottom-w->h()-w->y(), w->w(), w->h() }; + aglSetInteger( context, AGL_BUFFER_RECT, rect ); + aglEnable( context, AGL_BUFFER_RECT ); + } + aglSetDrawable(context, GetWindowPort( fl_xid(w) ) ); + aglSetCurrentContext(context); +# else + glXMakeCurrent(fl_display, fl_xid(w), context); +# endif + } +} + +void fl_no_gl_context() { + cached_context = 0; + cached_window = 0; +# ifdef WIN32 + wglMakeCurrent(0, 0); +# elif defined(__APPLE_QD__) + AGLContext ctx = aglGetCurrentContext(); + if (ctx) aglSetDrawable(ctx, NULL); + aglSetCurrentContext(0); +# elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + AGLContext ctx = aglGetCurrentContext(); + if (ctx) aglSetDrawable(ctx, NULL); + aglSetCurrentContext(0); +# else + glXMakeCurrent(fl_display, 0, 0); +# endif +} + +void fl_delete_gl_context(GLContext context) { + if (cached_context == context) fl_no_gl_context(); +# ifdef WIN32 + wglDeleteContext(context); +# elif defined(__APPLE_QD__) + aglDestroyContext( context ); +# elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + aglDestroyContext( context ); +# else + glXDestroyContext(fl_display, context); +# endif + del_context(context); +} + +#endif // HAVE_GL + + +// +// End of "$Id: Fl_Gl_Choice.cxx 6811 2009-06-30 19:05:09Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Gl_Overlay.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Gl_Overlay.cxx new file mode 100644 index 0000000..db95ab9 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Gl_Overlay.cxx @@ -0,0 +1,248 @@ +// +// "$Id: Fl_Gl_Overlay.cxx 5350 2006-08-23 17:40:54Z mike $" +// +// OpenGL overlay code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#if HAVE_GL + +#include +#include +#include "Fl_Gl_Choice.H" +#include +#include + +#if !HAVE_GL_OVERLAY + +int Fl_Gl_Window::can_do_overlay() {return 0;} + +void Fl_Gl_Window::make_overlay() {overlay = this;} + +#else + +// Methods on Fl_Gl_Window that create an overlay window. Because +// many programs don't need the overlay, this is seperated into this +// source file so it is not linked in if not used. + +// Under X this is done by creating another window, of class _Fl_Gl_Overlay +// which is a subclass of Fl_Gl_Window except it uses the overlay planes. +// A pointer to this is stored in the "overlay" pointer of the Fl_Gl_Window. + +// Under win32 another GLX context is created to draw into the overlay +// and it is stored in into the "overlay" pointer. + +// In both cases if overlay hardware is unavailable, the overlay is +// "faked" by drawing into the main layers. This is indicated by +// setting overlay == this. + +#ifndef WIN32 +//////////////////////////////////////////////////////////////// +// X version + +extern XVisualInfo *fl_find_overlay_visual(); +extern XVisualInfo *fl_overlay_visual; +extern Colormap fl_overlay_colormap; +extern unsigned long fl_transparent_pixel; +extern uchar fl_overlay; + +class _Fl_Gl_Overlay : public Fl_Gl_Window { + void flush(); + void draw(); +public: + void show(); + _Fl_Gl_Overlay(int x, int y, int w, int h) : + Fl_Gl_Window(x,y,w,h) { + set_flag(INACTIVE); + } +}; + +void _Fl_Gl_Overlay::flush() { + make_current(); +#ifdef BOXX_BUGS + // The BoXX overlay is broken and you must not call swap-buffers. This + // code will make it work, but we lose because machines that do support + // double-buffered overlays will blink when they don't have to + glDrawBuffer(GL_FRONT); + draw(); +#else + draw(); + swap_buffers(); +#endif + glFlush(); + valid(1); +} + +void _Fl_Gl_Overlay::draw() { + if (!valid()) glClearIndex((GLfloat)fl_transparent_pixel); + if (damage() != FL_DAMAGE_EXPOSE) glClear(GL_COLOR_BUFFER_BIT); + Fl_Gl_Window *w = (Fl_Gl_Window *)parent(); + uchar save_valid = w->valid(); + w->valid(valid()); + fl_overlay = 1; + w->draw_overlay(); + fl_overlay = 0; + valid(w->valid()); + w->valid(save_valid); +} + +void _Fl_Gl_Overlay::show() { + if (!shown()) { + fl_background_pixel = int(fl_transparent_pixel); + Fl_X::make_xid(this, fl_overlay_visual, fl_overlay_colormap); + fl_background_pixel = -1; + // find the outermost window to tell wm about the colormap: + Fl_Window *w = window(); + for (;;) {Fl_Window *w1 = w->window(); if (!w1) break; w = w1;} + XSetWMColormapWindows(fl_display, fl_xid(w), &(Fl_X::i(this)->xid), 1); + context(fl_create_gl_context(fl_overlay_visual), 1); + valid(0); + } + Fl_Gl_Window::show(); +} + +int Fl_Gl_Window::can_do_overlay() { + return fl_find_overlay_visual() != 0; +} + +void Fl_Gl_Window::make_overlay() { + if (overlay) return; + if (can_do_overlay()) { + _Fl_Gl_Overlay* o = new _Fl_Gl_Overlay(0,0,w(),h()); + overlay = o; + add(*o); + o->show(); + } else { + overlay = this; // fake the overlay + } +} + +#else +//////////////////////////////////////////////////////////////// +// WIN32 version: + +//static COLORREF *palette; +extern int fl_overlay_depth; + +void Fl_Gl_Window::make_overlay() { + if (overlay) return; + + GLContext context = fl_create_gl_context(this, g, 1); + if (!context) {overlay = this; return;} // fake the overlay + + HDC hdc = Fl_X::i(this)->private_dc; + overlay = context; + LAYERPLANEDESCRIPTOR pfd; + wglDescribeLayerPlane(hdc, g->pixelformat, 1, sizeof(pfd), &pfd); + if (!pfd.iPixelType) { + ; // full-color overlay + } else { + fl_overlay_depth = pfd.cColorBits; // used by gl_color() + if (fl_overlay_depth > 8) fl_overlay_depth = 8; + COLORREF palette[256]; + int n = (1<pfd.bReserved & 15) != 0; +} + +//////////////////////////////////////////////////////////////// +#endif + +#endif + +void Fl_Gl_Window::redraw_overlay() { + if (!shown()) return; + make_overlay(); +#ifdef __APPLE__ + redraw(); +#else +#ifndef WIN32 + if (overlay != this) + ((Fl_Gl_Window*)overlay)->redraw(); + else +#endif + damage(FL_DAMAGE_OVERLAY); +#endif +} + +void Fl_Gl_Window::make_overlay_current() { + make_overlay(); +#ifdef __APPLE__ + // this is not very useful, but unfortunatly, Apple decided + // that front buffer drawing can no longer (OS X 10.4) be + // supported on their platforms. + make_current(); +#else +#if HAVE_GL_OVERLAY + if (overlay != this) { +#ifdef WIN32 + fl_set_gl_context(this, (GLContext)overlay); +// if (fl_overlay_depth) +// wglRealizeLayerPalette(Fl_X::i(this)->private_dc, 1, TRUE); +#else + ((Fl_Gl_Window*)overlay)->make_current(); +#endif + } else +#endif + glDrawBuffer(GL_FRONT); +#endif +} + +void Fl_Gl_Window::hide_overlay() { +#if HAVE_GL_OVERLAY +#ifdef WIN32 + // nothing needs to be done? Or should it be erased? +#else + if (overlay && overlay!=this) ((Fl_Gl_Window*)overlay)->hide(); +#endif +#endif +} + +#endif + +// +// End of "$Id: Fl_Gl_Overlay.cxx 5350 2006-08-23 17:40:54Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Gl_Window.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Gl_Window.cxx new file mode 100644 index 0000000..0deecca --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Gl_Window.cxx @@ -0,0 +1,440 @@ +// +// "$Id: Fl_Gl_Window.cxx 6807 2009-06-30 13:38:52Z matt $" +// +// OpenGL window code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include "flstring.h" +#if HAVE_GL + +#include +#include +#include "Fl_Gl_Choice.H" +#include +#include + +//////////////////////////////////////////////////////////////// + +// The symbol SWAP_TYPE defines what is in the back buffer after doing +// a glXSwapBuffers(). + +// The OpenGl documentation says that the contents of the backbuffer +// are "undefined" after glXSwapBuffers(). However, if we know what +// is in the backbuffers then we can save a good deal of time. For +// this reason you can define some symbols to describe what is left in +// the back buffer. + +// Having not found any way to determine this from glx (or wgl) I have +// resorted to letting the user specify it with an environment variable, +// GL_SWAP_TYPE, it should be equal to one of these symbols: + +// contents of back buffer after glXSwapBuffers(): +#define UNDEFINED 1 // anything +#define SWAP 2 // former front buffer (same as unknown) +#define COPY 3 // unchanged +#define NODAMAGE 4 // unchanged even by X expose() events + +static char SWAP_TYPE = 0 ; // 0 = determine it from environment variable + +//////////////////////////////////////////////////////////////// + +int Fl_Gl_Window::can_do(int a, const int *b) { + return Fl_Gl_Choice::find(a,b) != 0; +} + +void Fl_Gl_Window::show() { + if (!shown()) { + if (!g) { + g = Fl_Gl_Choice::find(mode_,alist); + + if (!g && (mode_ & FL_DOUBLE) == FL_SINGLE) { + g = Fl_Gl_Choice::find(mode_ | FL_DOUBLE,alist); + if (g) mode_ |= FL_FAKE_SINGLE; + } + + if (!g) { + Fl::error("Insufficient GL support"); + return; + } + } +#if !defined(WIN32) && !defined(__APPLE__) + Fl_X::make_xid(this, g->vis, g->colormap); + if (overlay && overlay != this) ((Fl_Gl_Window*)overlay)->show(); +#endif + } + Fl_Window::show(); + +#ifdef __APPLE__ + set_visible(); +#endif /* __APPLE__ */ +} + +void Fl_Gl_Window::invalidate() { + valid(0); + context_valid(0); +#ifndef WIN32 + if (overlay) { + ((Fl_Gl_Window*)overlay)->valid(0); + ((Fl_Gl_Window*)overlay)->context_valid(0); + } +#endif +} + +int Fl_Gl_Window::mode(int m, const int *a) { + if (m == mode_ && a == alist) return 0; +#ifndef __APPLE__ + int oldmode = mode_; +#endif // !__APPLE__ +#if !defined(WIN32) && !defined(__APPLE__) + Fl_Gl_Choice* oldg = g; +#endif // !WIN32 && !__APPLE__ + context(0); + mode_ = m; alist = a; + if (shown()) { + g = Fl_Gl_Choice::find(m, a); +#if defined(WIN32) + if (!g || (oldmode^m)&(FL_DOUBLE|FL_STEREO)) { + hide(); + show(); + } +#elif defined(__APPLE_QD__) + redraw(); +#elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + redraw(); +#else + // under X, if the visual changes we must make a new X window (yuck!): + if (!g || g->vis->visualid!=oldg->vis->visualid || (oldmode^m)&FL_DOUBLE) { + hide(); + show(); + } +#endif + } else { + g = 0; + } + return 1; +} + +#define NON_LOCAL_CONTEXT 0x80000000 + +void Fl_Gl_Window::make_current() { +// puts("Fl_Gl_Window::make_current()"); +// printf("make_current: context_=%p\n", context_); + if (!context_) { + mode_ &= ~NON_LOCAL_CONTEXT; + context_ = fl_create_gl_context(this, g); + valid(0); + context_valid(0); + } + fl_set_gl_context(this, context_); + +#ifdef __APPLE__ + // Set the buffer rectangle here, since in resize() we won't have the + // correct parent window size to work with... + GLint xywh[4]; + + if (window()) { + xywh[0] = x(); + xywh[1] = window()->h() - y() - h(); + } else { + xywh[0] = 0; + xywh[1] = 0; + } + + xywh[2] = w(); + xywh[3] = h(); + + aglSetInteger(context_, AGL_BUFFER_RECT, xywh); + aglEnable(context_, AGL_BUFFER_RECT); +// printf("make_current: xywh=[%d %d %d %d]\n", xywh[0], xywh[1], xywh[2], xywh[3]); +#endif // __APPLE__ + +#if defined(WIN32) && USE_COLORMAP + if (fl_palette) { + fl_GetDC(fl_xid(this)); + SelectPalette(fl_gc, fl_palette, FALSE); + RealizePalette(fl_gc); + } +#endif // USE_COLORMAP + if (mode_ & FL_FAKE_SINGLE) { + glDrawBuffer(GL_FRONT); + glReadBuffer(GL_FRONT); + } + current_ = this; +} + +void Fl_Gl_Window::ortho() { +// Alpha NT seems to have a broken OpenGL that does not like negative coords: +#ifdef _M_ALPHA + glLoadIdentity(); + glViewport(0, 0, w(), h()); + glOrtho(0, w(), 0, h(), -1, 1); +#else + GLint v[2]; + glGetIntegerv(GL_MAX_VIEWPORT_DIMS, v); + glLoadIdentity(); + glViewport(w()-v[0], h()-v[1], v[0], v[1]); + glOrtho(w()-v[0], w(), h()-v[1], h(), -1, 1); +#endif +} + +void Fl_Gl_Window::swap_buffers() { +#ifdef WIN32 +# if HAVE_GL_OVERLAY + // Do not swap the overlay, to match GLX: + BOOL ret = wglSwapLayerBuffers(Fl_X::i(this)->private_dc, WGL_SWAP_MAIN_PLANE); + DWORD err = GetLastError();; +# else + SwapBuffers(Fl_X::i(this)->private_dc); +# endif +#elif defined(__APPLE_QD__) + aglSwapBuffers((AGLContext)context_); +#elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + aglSwapBuffers((AGLContext)context_); +#else + glXSwapBuffers(fl_display, fl_xid(this)); +#endif +} + +#if HAVE_GL_OVERLAY && defined(WIN32) +uchar fl_overlay; // changes how fl_color() works +int fl_overlay_depth = 0; +#endif + +void Fl_Gl_Window::flush() { + uchar save_valid = valid_f_ & 1; +#if HAVE_GL_OVERLAY && defined(WIN32) + uchar save_valid_f = valid_f_; +#endif + +#ifdef __APPLE_QD__ + //: clear previous clipping in this shared port + GrafPtr port = GetWindowPort( fl_xid(this) ); + Rect rect; SetRect( &rect, 0, 0, 0x7fff, 0x7fff ); + GrafPtr old; GetPort( &old ); + SetPort( port ); + ClipRect( &rect ); + SetPort( old ); +#elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + //: clear previous clipping in this shared port + GrafPtr port = GetWindowPort( fl_xid(this) ); + Rect rect; SetRect( &rect, 0, 0, 0x7fff, 0x7fff ); + GrafPtr old; GetPort( &old ); + SetPort( port ); + ClipRect( &rect ); + SetPort( old ); +#endif + +#if HAVE_GL_OVERLAY && defined(WIN32) + + bool fixcursor = false; // for fixing the SGI 320 bug + + // Draw into hardware overlay planes if they are damaged: + if (overlay && overlay != this + && (damage()&(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE) || !save_valid)) { + // SGI 320 messes up overlay with user-defined cursors: + if (Fl_X::i(this)->cursor && Fl_X::i(this)->cursor != fl_default_cursor) { + fixcursor = true; // make it restore cursor later + SetCursor(0); + } + fl_set_gl_context(this, (GLContext)overlay); + if (fl_overlay_depth) + wglRealizeLayerPalette(Fl_X::i(this)->private_dc, 1, TRUE); + glDisable(GL_SCISSOR_TEST); + glClear(GL_COLOR_BUFFER_BIT); + fl_overlay = 1; + draw_overlay(); + fl_overlay = 0; + valid_f_ = save_valid_f; + wglSwapLayerBuffers(Fl_X::i(this)->private_dc, WGL_SWAP_OVERLAY1); + // if only the overlay was damaged we are done, leave main layer alone: + if (damage() == FL_DAMAGE_OVERLAY) { + if (fixcursor) SetCursor(Fl_X::i(this)->cursor); + return; + } + } +#endif + + make_current(); + + if (mode_ & FL_DOUBLE) { + + glDrawBuffer(GL_BACK); + + if (!SWAP_TYPE) { +#ifdef __APPLE_QD__ + SWAP_TYPE = COPY; +#elif defined __APPLE_QUARTZ__ + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + SWAP_TYPE = COPY; +#else + SWAP_TYPE = UNDEFINED; +#endif + const char* c = getenv("GL_SWAP_TYPE"); + if (c) { + if (!strcmp(c,"COPY")) SWAP_TYPE = COPY; + else if (!strcmp(c, "NODAMAGE")) SWAP_TYPE = NODAMAGE; + else if (!strcmp(c, "SWAP")) SWAP_TYPE = SWAP; + } + } + + if (SWAP_TYPE == NODAMAGE) { + + // don't draw if only overlay damage or expose events: + if ((damage()&~(FL_DAMAGE_OVERLAY|FL_DAMAGE_EXPOSE)) || !save_valid) + draw(); + swap_buffers(); + + } else if (SWAP_TYPE == COPY) { + + // don't draw if only the overlay is damaged: + if (damage() != FL_DAMAGE_OVERLAY || !save_valid) draw(); + swap_buffers(); + + } else { // SWAP_TYPE == UNDEFINED + + // If we are faking the overlay, use CopyPixels to act like + // SWAP_TYPE == COPY. Otherwise overlay redraw is way too slow. + if (overlay == this) { + // don't draw if only the overlay is damaged: + if (damage1_ || damage() != FL_DAMAGE_OVERLAY || !save_valid) draw(); + // we use a seperate context for the copy because rasterpos must be 0 + // and depth test needs to be off: + static GLContext ortho_context = 0; + static Fl_Gl_Window* ortho_window = 0; + int orthoinit = !ortho_context; + if (orthoinit) ortho_context = fl_create_gl_context(this, g); + fl_set_gl_context(this, ortho_context); + if (orthoinit || !save_valid || ortho_window != this) { + glDisable(GL_DEPTH_TEST); + glReadBuffer(GL_BACK); + glDrawBuffer(GL_FRONT); + glLoadIdentity(); + glViewport(0, 0, w(), h()); + glOrtho(0, w(), 0, h(), -1, 1); + glRasterPos2i(0,0); + ortho_window = this; + } + glCopyPixels(0,0,w(),h(),GL_COLOR); + make_current(); // set current context back to draw overlay + damage1_ = 0; + + } else { + damage1_ = damage(); + clear_damage(0xff); draw(); + swap_buffers(); + } + + } + + if (overlay==this) { // fake overlay in front buffer + glDrawBuffer(GL_FRONT); + draw_overlay(); + glDrawBuffer(GL_BACK); + glFlush(); + } + + } else { // single-buffered context is simpler: + + draw(); + if (overlay == this) draw_overlay(); + glFlush(); + + } + +#if HAVE_GL_OVERLAY && defined(WIN32) + if (fixcursor) SetCursor(Fl_X::i(this)->cursor); +#endif + valid(1); + context_valid(1); +} + +void Fl_Gl_Window::resize(int X,int Y,int W,int H) { +// printf("Fl_Gl_Window::resize(X=%d, Y=%d, W=%d, H=%d)\n", X, Y, W, H); +// printf("current: x()=%d, y()=%d, w()=%d, h()=%d\n", x(), y(), w(), h()); + + if (W != w() || H != h()) valid(0); + +#ifdef __APPLE__ + if (X != x() || Y != y() || W != w() || H != h()) aglUpdateContext(context_); +#elif !defined(WIN32) + if ((W != w() || H != h()) && !resizable() && overlay && overlay != this) { + ((Fl_Gl_Window*)overlay)->resize(0,0,W,H); + } +#endif + + Fl_Window::resize(X,Y,W,H); +} + +void Fl_Gl_Window::context(void* v, int destroy_flag) { + if (context_ && !(mode_&NON_LOCAL_CONTEXT)) fl_delete_gl_context(context_); + context_ = (GLContext)v; + if (destroy_flag) mode_ &= ~NON_LOCAL_CONTEXT; + else mode_ |= NON_LOCAL_CONTEXT; +} + +void Fl_Gl_Window::hide() { + context(0); +#if HAVE_GL_OVERLAY && defined(WIN32) + if (overlay && overlay != this) { + fl_delete_gl_context((GLContext)overlay); + overlay = 0; + } +#endif + Fl_Window::hide(); +} + +Fl_Gl_Window::~Fl_Gl_Window() { + hide(); +// delete overlay; this is done by ~Fl_Group +} + +void Fl_Gl_Window::init() { + end(); // we probably don't want any children + box(FL_NO_BOX); + + mode_ = FL_RGB | FL_DEPTH | FL_DOUBLE; + alist = 0; + context_ = 0; + g = 0; + overlay = 0; + valid_f_ = 0; + damage1_ = 0; + +#if 0 // This breaks resizing on Linux/X11 + int H = h(); + h(1); // Make sure we actually do something in resize()... + resize(x(), y(), w(), H); +#endif // 0 +} + +void Fl_Gl_Window::draw_overlay() {} + +#endif + +// +// End of "$Id: Fl_Gl_Window.cxx 6807 2009-06-30 13:38:52Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Group.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Group.cxx new file mode 100644 index 0000000..b3ab928 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Group.cxx @@ -0,0 +1,623 @@ +// +// "$Id: Fl_Group.cxx 6463 2008-10-19 06:40:02Z AlbrechtS $" +// +// Group widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// The Fl_Group is the only defined container type in FLTK. + +// Fl_Window itself is a subclass of this, and most of the event +// handling is designed so windows themselves work correctly. + +#include +#include +#include +#include +#include +#include + +Fl_Group* Fl_Group::current_; + +// Hack: A single child is stored in the pointer to the array, while +// multiple children are stored in an allocated array: +Fl_Widget*const* Fl_Group::array() const { + return children_ <= 1 ? (Fl_Widget**)(&array_) : array_; +} + +int Fl_Group::find(const Fl_Widget* o) const { + Fl_Widget*const* a = array(); + int i; for (i=0; i < children_; i++) if (*a++ == o) break; + return i; +} + +// Metrowerks CodeWarrior and others can't export the static +// class member: current_, so these methods can't be inlined... +void Fl_Group::begin() {current_ = this;} +void Fl_Group::end() {current_ = (Fl_Group*)parent();} +Fl_Group *Fl_Group::current() {return current_;} +void Fl_Group::current(Fl_Group *g) {current_ = g;} + +extern Fl_Widget* fl_oldfocus; // set by Fl::focus + +// For back-compatability, we must adjust all events sent to child +// windows so they are relative to that window. + +static int send(Fl_Widget* o, int event) { + if (o->type() < FL_WINDOW) return o->handle(event); + switch ( event ) + { + case FL_DND_ENTER: + case FL_DND_DRAG: + // figure out correct type of event: + event = (o->contains(Fl::belowmouse())) ? FL_DND_DRAG : FL_DND_ENTER; + } + int save_x = Fl::e_x; Fl::e_x -= o->x(); + int save_y = Fl::e_y; Fl::e_y -= o->y(); + int ret = o->handle(event); + Fl::e_y = save_y; + Fl::e_x = save_x; + switch ( event ) + { + case FL_ENTER: + case FL_DND_ENTER: + // Successful completion of FL_ENTER means the widget is now the + // belowmouse widget, but only call Fl::belowmouse if the child + // widget did not do so: + if (!o->contains(Fl::belowmouse())) Fl::belowmouse(o); + break; + } + return ret; +} + +// translate the current keystroke into up/down/left/right for navigation: +#define ctrl(x) (x^0x40) +static int navkey() { + switch (Fl::event_key()) { + case 0: // not an FL_KEYBOARD/FL_SHORTCUT event + break; + case FL_Tab: + if (!Fl::event_state(FL_SHIFT)) return FL_Right; + case 0xfe20: // XK_ISO_Left_Tab + return FL_Left; + case FL_Right: + return FL_Right; + case FL_Left: + return FL_Left; + case FL_Up: + return FL_Up; + case FL_Down: + return FL_Down; + } + return 0; +} + +int Fl_Group::handle(int event) { + + Fl_Widget*const* a = array(); + int i; + Fl_Widget* o; + + switch (event) { + + case FL_FOCUS: + switch (navkey()) { + default: + if (savedfocus_ && savedfocus_->take_focus()) return 1; + case FL_Right: + case FL_Down: + for (i = children(); i--;) if ((*a++)->take_focus()) return 1; + break; + case FL_Left: + case FL_Up: + for (i = children(); i--;) if (a[i]->take_focus()) return 1; + break; + } + return 0; + + case FL_UNFOCUS: + savedfocus_ = fl_oldfocus; + return 0; + + case FL_KEYBOARD: + return navigation(navkey()); + + case FL_SHORTCUT: + for (i = children(); i--;) { + o = a[i]; + if (o->takesevents() && Fl::event_inside(o) && send(o,FL_SHORTCUT)) + return 1; + } + for (i = children(); i--;) { + o = a[i]; + if (o->takesevents() && !Fl::event_inside(o) && send(o,FL_SHORTCUT)) + return 1; + } + if ((Fl::event_key() == FL_Enter || Fl::event_key() == FL_KP_Enter)) return navigation(FL_Down); + return 0; + + case FL_ENTER: + case FL_MOVE: + for (i = children(); i--;) { + o = a[i]; + if (o->visible() && Fl::event_inside(o)) { + if (o->contains(Fl::belowmouse())) { + return send(o,FL_MOVE); + } else { + Fl::belowmouse(o); + if (send(o,FL_ENTER)) return 1; + } + } + } + Fl::belowmouse(this); + return 1; + + case FL_DND_ENTER: + case FL_DND_DRAG: + for (i = children(); i--;) { + o = a[i]; + if (o->takesevents() && Fl::event_inside(o)) { + if (o->contains(Fl::belowmouse())) { + return send(o,FL_DND_DRAG); + } else if (send(o,FL_DND_ENTER)) { + if (!o->contains(Fl::belowmouse())) Fl::belowmouse(o); + return 1; + } + } + } + Fl::belowmouse(this); + return 0; + + case FL_PUSH: + for (i = children(); i--;) { + o = a[i]; + if (o->takesevents() && Fl::event_inside(o)) { + if (send(o,FL_PUSH)) { + if (Fl::pushed() && !o->contains(Fl::pushed())) Fl::pushed(o); + return 1; + } + } + } + return 0; + + case FL_RELEASE: + case FL_DRAG: + o = Fl::pushed(); + if (o == this) return 0; + else if (o) send(o,event); + else { + for (i = children(); i--;) { + o = a[i]; + if (o->takesevents() && Fl::event_inside(o)) { + if (send(o,event)) return 1; + } + } + } + return 0; + + case FL_MOUSEWHEEL: + for (i = children(); i--;) { + o = a[i]; + if (o->takesevents() && Fl::event_inside(o) && send(o,FL_MOUSEWHEEL)) + return 1; + } + for (i = children(); i--;) { + o = a[i]; + if (o->takesevents() && !Fl::event_inside(o) && send(o,FL_MOUSEWHEEL)) + return 1; + } + return 0; + + case FL_DEACTIVATE: + case FL_ACTIVATE: + for (i = children(); i--;) { + o = *a++; + if (o->active()) o->handle(event); + } + return 1; + + case FL_SHOW: + case FL_HIDE: + for (i = children(); i--;) { + o = *a++; + if (event == FL_HIDE && o == Fl::focus()) { + // Give up input focus... + int old_event = Fl::e_number; + o->handle(Fl::e_number = FL_UNFOCUS); + Fl::e_number = old_event; + Fl::focus(0); + } + if (o->visible()) o->handle(event); + } + return 1; + + default: + // For all other events, try to give to each child, starting at focus: + for (i = 0; i < children(); i ++) + if (Fl::focus_ == a[i]) break; + + if (i >= children()) i = 0; + + if (children()) { + for (int j = i;;) { + if (a[j]->takesevents()) if (send(a[j], event)) return 1; + j++; + if (j >= children()) j = 0; + if (j == i) break; + } + } + + return 0; + } +} + +//void Fl_Group::focus(Fl_Widget *o) {Fl::focus(o); o->handle(FL_FOCUS);} + +#if 0 +const char *nameof(Fl_Widget *o) { + if (!o) return "NULL"; + if (!o->label()) return ""; + return o->label(); +} +#endif + +// try to move the focus in response to a keystroke: +int Fl_Group::navigation(int key) { + if (children() <= 1) return 0; + int i; + for (i = 0; ; i++) { + if (i >= children_) return 0; + if (array_[i]->contains(Fl::focus())) break; + } + Fl_Widget *previous = array_[i]; + + for (;;) { + switch (key) { + case FL_Right: + case FL_Down: + i++; + if (i >= children_) { + if (parent()) return 0; + i = 0; + } + break; + case FL_Left: + case FL_Up: + if (i) i--; + else { + if (parent()) return 0; + i = children_-1; + } + break; + default: + return 0; + } + Fl_Widget* o = array_[i]; + if (o == previous) return 0; + switch (key) { + case FL_Down: + case FL_Up: + // for up/down, the widgets have to overlap horizontally: + if (o->x() >= previous->x()+previous->w() || + o->x()+o->w() <= previous->x()) continue; + } + if (o->take_focus()) return 1; + } +} + +//////////////////////////////////////////////////////////////// + +Fl_Group::Fl_Group(int X,int Y,int W,int H,const char *l) +: Fl_Widget(X,Y,W,H,l) { + align(FL_ALIGN_TOP); + children_ = 0; + array_ = 0; + savedfocus_ = 0; + resizable_ = this; + sizes_ = 0; // this is allocated when first resize() is done + // Subclasses may want to construct child objects as part of their + // constructor, so make sure they are add()'d to this object. + // But you must end() the object! + begin(); +} + +void Fl_Group::clear() { + Fl_Widget*const* old_array = array(); + int old_children = children(); + // clear everything now, in case fl_fix_focus recursively calls us: + children_ = 0; + //array_ = 0; //dont do this, it will clobber old_array if only one child + savedfocus_ = 0; + resizable_ = this; + init_sizes(); + // okay, now it is safe to destroy the children: + Fl_Widget*const* a = old_array; + for (int i=old_children; i--;) { + Fl_Widget* o = *a++; + if (o->parent() == this) delete o; + } + if (old_children > 1) free((void*)old_array); +} + +Fl_Group::~Fl_Group() { + clear(); +} + +void Fl_Group::insert(Fl_Widget &o, int index) { + if (o.parent()) { + Fl_Group* g = (Fl_Group*)(o.parent()); + int n = g->find(o); + if (g == this) { + if (index > n) index--; + if (index == n) return; + } + g->remove(o); + } + o.parent_ = this; + if (children_ == 0) { // use array pointer to point at single child + array_ = (Fl_Widget**)&o; + } else if (children_ == 1) { // go from 1 to 2 children + Fl_Widget* t = (Fl_Widget*)array_; + array_ = (Fl_Widget**)malloc(2*sizeof(Fl_Widget*)); + if (index) {array_[0] = t; array_[1] = &o;} + else {array_[0] = &o; array_[1] = t;} + } else { + if (!(children_ & (children_-1))) // double number of children + array_ = (Fl_Widget**)realloc((void*)array_, + 2*children_*sizeof(Fl_Widget*)); + int j; for (j = children_; j > index; j--) array_[j] = array_[j-1]; + array_[j] = &o; + } + children_++; + init_sizes(); +} + +void Fl_Group::add(Fl_Widget &o) {insert(o, children_);} + +void Fl_Group::remove(Fl_Widget &o) { + if (!children_) return; + int i = find(o); + if (i >= children_) return; + if (&o == savedfocus_) savedfocus_ = 0; + o.parent_ = 0; + children_--; + if (children_ == 1) { // go from 2 to 1 child + Fl_Widget *t = array_[!i]; + free((void*)array_); + array_ = (Fl_Widget**)t; + } else if (children_ > 1) { // delete from array + for (; i < children_; i++) array_[i] = array_[i+1]; + } + init_sizes(); +} + +//////////////////////////////////////////////////////////////// + +// Rather lame kludge here, I need to detect windows and ignore the +// changes to X,Y, since all children are relative to X,Y. That +// is why I check type(): + +// sizes array stores the initial positions of widgets as +// left,right,top,bottom quads. The first quad is the group, the +// second is the resizable (clipped to the group), and the +// rest are the children. This is a convienent order for the +// algorithim. If you change this be sure to fix Fl_Tile which +// also uses this array! + +void Fl_Group::init_sizes() { + delete[] sizes_; sizes_ = 0; +} + +short* Fl_Group::sizes() { + if (!sizes_) { + short* p = sizes_ = new short[4*(children_+2)]; + // first thing in sizes array is the group's size: + if (type() < FL_WINDOW) {p[0] = x(); p[2] = y();} else {p[0] = p[2] = 0;} + p[1] = p[0]+w(); p[3] = p[2]+h(); + // next is the resizable's size: + p[4] = p[0]; // init to the group's size + p[5] = p[1]; + p[6] = p[2]; + p[7] = p[3]; + Fl_Widget* r = resizable(); + if (r && r != this) { // then clip the resizable to it + int t; + t = r->x(); if (t > p[0]) p[4] = t; + t +=r->w(); if (t < p[1]) p[5] = t; + t = r->y(); if (t > p[2]) p[6] = t; + t +=r->h(); if (t < p[3]) p[7] = t; + } + // next is all the children's sizes: + p += 8; + Fl_Widget*const* a = array(); + for (int i=children_; i--;) { + Fl_Widget* o = *a++; + *p++ = o->x(); + *p++ = o->x()+o->w(); + *p++ = o->y(); + *p++ = o->y()+o->h(); + } + } + return sizes_; +} + +void Fl_Group::resize(int X, int Y, int W, int H) { + + int dx = X-x(); + int dy = Y-y(); + int dw = W-w(); + int dh = H-h(); + + short *p = sizes(); // save initial sizes and positions + + Fl_Widget::resize(X,Y,W,H); // make new xywh values visible for children + + if (!resizable() || dw==0 && dh==0 ) { + + if (type() < FL_WINDOW) { + Fl_Widget*const* a = array(); + for (int i=children_; i--;) { + Fl_Widget* o = *a++; + o->resize(o->x()+dx, o->y()+dy, o->w(), o->h()); + } + } + + } else if (children_) { + + // get changes in size/position from the initial size: + dx = X - p[0]; + dw = W - (p[1]-p[0]); + dy = Y - p[2]; + dh = H - (p[3]-p[2]); + if (type() >= FL_WINDOW) dx = dy = 0; + p += 4; + + // get initial size of resizable(): + int IX = *p++; + int IR = *p++; + int IY = *p++; + int IB = *p++; + + Fl_Widget*const* a = array(); + for (int i=children_; i--;) { + Fl_Widget* o = *a++; +#if 1 + int XX = *p++; + if (XX >= IR) XX += dw; + else if (XX > IX) XX = IX+((XX-IX)*(IR+dw-IX)+(IR-IX)/2)/(IR-IX); + int R = *p++; + if (R >= IR) R += dw; + else if (R > IX) R = IX+((R-IX)*(IR+dw-IX)+(IR-IX)/2)/(IR-IX); + + int YY = *p++; + if (YY >= IB) YY += dh; + else if (YY > IY) YY = IY+((YY-IY)*(IB+dh-IY)+(IB-IY)/2)/(IB-IY); + int B = *p++; + if (B >= IB) B += dh; + else if (B > IY) B = IY+((B-IY)*(IB+dh-IY)+(IB-IY)/2)/(IB-IY); +#else // much simpler code from Francois Ostiguy: + int XX = *p++; + if (XX >= IR) XX += dw; + else if (XX > IX) XX += dw * (XX-IX)/(IR-IX); + int R = *p++; + if (R >= IR) R += dw; + else if (R > IX) R = R + dw * (R-IX)/(IR-IX); + + int YY = *p++; + if (YY >= IB) YY += dh; + else if (YY > IY) YY = YY + dh*(YY-IY)/(IB-IY); + int B = *p++; + if (B >= IB) B += dh; + else if (B > IY) B = B + dh*(B-IY)/(IB-IY); +#endif + o->resize(XX+dx, YY+dy, R-XX, B-YY); + } + } +} + +void Fl_Group::draw_children() { + Fl_Widget*const* a = array(); + + if (clip_children()) { + fl_push_clip(x() + Fl::box_dx(box()), + y() + Fl::box_dy(box()), + w() - Fl::box_dw(box()), + h() - Fl::box_dh(box())); + } + + if (damage() & ~FL_DAMAGE_CHILD) { // redraw the entire thing: + for (int i=children_; i--;) { + Fl_Widget& o = **a++; + draw_child(o); + draw_outside_label(o); + } + } else { // only redraw the children that need it: + for (int i=children_; i--;) update_child(**a++); + } + + if (clip_children()) fl_pop_clip(); +} + +void Fl_Group::draw() { + if (damage() & ~FL_DAMAGE_CHILD) { // redraw the entire thing: + draw_box(); + draw_label(); + } + draw_children(); +} + +// Draw a child only if it needs it: +void Fl_Group::update_child(Fl_Widget& widget) const { + if (widget.damage() && widget.visible() && widget.type() < FL_WINDOW && + fl_not_clipped(widget.x(), widget.y(), widget.w(), widget.h())) { + widget.draw(); + widget.clear_damage(); + } +} + +// Force a child to redraw: +void Fl_Group::draw_child(Fl_Widget& widget) const { + if (widget.visible() && widget.type() < FL_WINDOW && + fl_not_clipped(widget.x(), widget.y(), widget.w(), widget.h())) { + widget.clear_damage(FL_DAMAGE_ALL); + widget.draw(); + widget.clear_damage(); + } +} + +extern char fl_draw_shortcut; + +// Parents normally call this to draw outside labels: +void Fl_Group::draw_outside_label(const Fl_Widget& widget) const { + if (!widget.visible()) return; + // skip any labels that are inside the widget: + if (!(widget.align()&15) || (widget.align() & FL_ALIGN_INSIDE)) return; + // invent a box that is outside the widget: + int a = widget.align(); + int X = widget.x(); + int Y = widget.y(); + int W = widget.w(); + int H = widget.h(); + if (a & FL_ALIGN_TOP) { + a ^= (FL_ALIGN_BOTTOM|FL_ALIGN_TOP); + Y = y(); + H = widget.y()-Y; + } else if (a & FL_ALIGN_BOTTOM) { + a ^= (FL_ALIGN_BOTTOM|FL_ALIGN_TOP); + Y = Y+H; + H = y()+h()-Y; + } else if (a & FL_ALIGN_LEFT) { + a ^= (FL_ALIGN_LEFT|FL_ALIGN_RIGHT); + X = x(); + W = widget.x()-X-3; + } else if (a & FL_ALIGN_RIGHT) { + a ^= (FL_ALIGN_LEFT|FL_ALIGN_RIGHT); + X = X+W+3; + W = x()+this->w()-X; + } + widget.draw_label(X,Y,W,H,(Fl_Align)a); +} + +// +// End of "$Id: Fl_Group.cxx 6463 2008-10-19 06:40:02Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Help_Dialog.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Help_Dialog.cxx new file mode 100644 index 0000000..0488f91 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Help_Dialog.cxx @@ -0,0 +1,301 @@ +// +// "$Id: Fl_Help_Dialog.cxx 5643 2007-01-28 19:36:51Z mike $" +// +// Fl_Help_Dialog dialog for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// generated by Fast Light User Interface Designer (fluid) version 1.0108 + +#include "../FL/Fl_Help_Dialog.H" +#include "flstring.h" +#include + +void Fl_Help_Dialog::cb_back__i(Fl_Button*, void*) { + if (index_ > 0) + index_ --; + +if (index_ == 0) + back_->deactivate(); + +forward_->activate(); + +int l = line_[index_]; + +if (strcmp(view_->filename(), file_[index_]) != 0) + view_->load(file_[index_]); + +view_->topline(l); +} +void Fl_Help_Dialog::cb_back_(Fl_Button* o, void* v) { + ((Fl_Help_Dialog*)(o->parent()->parent()->user_data()))->cb_back__i(o,v); +} + +void Fl_Help_Dialog::cb_forward__i(Fl_Button*, void*) { + if (index_ < max_) + index_ ++; + +if (index_ >= max_) + forward_->deactivate(); + +back_->activate(); + +int l = view_->topline(); + +if (strcmp(view_->filename(), file_[index_]) != 0) + view_->load(file_[index_]); + +view_->topline(l); +} +void Fl_Help_Dialog::cb_forward_(Fl_Button* o, void* v) { + ((Fl_Help_Dialog*)(o->parent()->parent()->user_data()))->cb_forward__i(o,v); +} + +void Fl_Help_Dialog::cb_smaller__i(Fl_Button*, void*) { + if (view_->textsize() > 8) + view_->textsize(view_->textsize() - 2); + +if (view_->textsize() <= 8) + smaller_->deactivate(); +larger_->activate(); +} +void Fl_Help_Dialog::cb_smaller_(Fl_Button* o, void* v) { + ((Fl_Help_Dialog*)(o->parent()->parent()->user_data()))->cb_smaller__i(o,v); +} + +void Fl_Help_Dialog::cb_larger__i(Fl_Button*, void*) { + if (view_->textsize() < 18) + view_->textsize(view_->textsize() + 2); + +if (view_->textsize() >= 18) + larger_->deactivate(); +smaller_->activate(); +} +void Fl_Help_Dialog::cb_larger_(Fl_Button* o, void* v) { + ((Fl_Help_Dialog*)(o->parent()->parent()->user_data()))->cb_larger__i(o,v); +} + +void Fl_Help_Dialog::cb_find__i(Fl_Input*, void*) { + find_pos_ = view_->find(find_->value(), find_pos_); +} +void Fl_Help_Dialog::cb_find_(Fl_Input* o, void* v) { + ((Fl_Help_Dialog*)(o->parent()->parent()->parent()->user_data()))->cb_find__i(o,v); +} + +void Fl_Help_Dialog::cb_view__i(Fl_Help_View*, void*) { + if (view_->filename()) +{ + if (view_->changed()) + { + index_ ++; + + if (index_ >= 100) + { + memmove(line_, line_ + 10, sizeof(line_[0]) * 90); + memmove(file_, file_ + 10, sizeof(file_[0]) * 90); + index_ -= 10; + } + + max_ = index_; + + strlcpy(file_[index_], view_->filename(),sizeof(file_[0])); + line_[index_] = view_->topline(); + + if (index_ > 0) + back_->activate(); + else + back_->deactivate(); + + forward_->deactivate(); + window_->label(view_->title()); + } + else // if ! view_->changed() + { + strlcpy(file_[index_], view_->filename(), sizeof(file_[0])); + line_[index_] = view_->topline(); + } +} else { // if ! view_->filename() + index_ = 0; // hitting an internal page will disable the back/fwd buffer + file_[index_][0] = 0; // unnamed internal page + line_[index_] = view_->topline(); + back_->deactivate(); + forward_->deactivate(); +}; +} +void Fl_Help_Dialog::cb_view_(Fl_Help_View* o, void* v) { + ((Fl_Help_Dialog*)(o->parent()->user_data()))->cb_view__i(o,v); +} + +Fl_Help_Dialog::Fl_Help_Dialog() { + { window_ = new Fl_Double_Window(530, 385, "Help Dialog"); + window_->user_data((void*)(this)); + { Fl_Group* o = new Fl_Group(10, 10, 511, 25); + { back_ = new Fl_Button(10, 10, 25, 25, "@<-"); + back_->tooltip("Show the previous help page."); + back_->shortcut(0xff51); + back_->labelcolor((Fl_Color)2); + back_->callback((Fl_Callback*)cb_back_); + } // Fl_Button* back_ + { forward_ = new Fl_Button(45, 10, 25, 25, "@->"); + forward_->tooltip("Show the next help page."); + forward_->shortcut(0xff53); + forward_->labelcolor((Fl_Color)2); + forward_->callback((Fl_Callback*)cb_forward_); + } // Fl_Button* forward_ + { smaller_ = new Fl_Button(80, 10, 25, 25, "F"); + smaller_->tooltip("Make the help text smaller."); + smaller_->labelfont(1); + smaller_->labelsize(10); + smaller_->callback((Fl_Callback*)cb_smaller_); + } // Fl_Button* smaller_ + { larger_ = new Fl_Button(115, 10, 25, 25, "F"); + larger_->tooltip("Make the help text larger."); + larger_->labelfont(1); + larger_->labelsize(16); + larger_->callback((Fl_Callback*)cb_larger_); + } // Fl_Button* larger_ + { Fl_Group* o = new Fl_Group(350, 10, 171, 25); + o->box(FL_DOWN_BOX); + o->color(FL_BACKGROUND2_COLOR); + { find_ = new Fl_Input(375, 12, 143, 21, "@search"); + find_->tooltip("find text in document"); + find_->box(FL_FLAT_BOX); + find_->labelsize(13); + find_->textfont(4); + find_->callback((Fl_Callback*)cb_find_); + find_->when(FL_WHEN_ENTER_KEY_ALWAYS); + } // Fl_Input* find_ + o->end(); + } // Fl_Group* o + { Fl_Box* o = new Fl_Box(150, 10, 190, 25); + Fl_Group::current()->resizable(o); + } // Fl_Box* o + o->end(); + } // Fl_Group* o + { view_ = new Fl_Help_View(10, 45, 510, 330); + view_->box(FL_DOWN_BOX); + view_->callback((Fl_Callback*)cb_view_); + Fl_Group::current()->resizable(view_); + } // Fl_Help_View* view_ + window_->size_range(260, 150); + window_->end(); + } // Fl_Double_Window* window_ + back_->deactivate(); +forward_->deactivate(); + +index_ = -1; +max_ = 0; +find_pos_ = 0; + +fl_register_images(); +} + +Fl_Help_Dialog::~Fl_Help_Dialog() { + delete window_; +} + +int Fl_Help_Dialog::h() { + return (window_->h()); +} + +void Fl_Help_Dialog::hide() { + window_->hide(); +} + +void Fl_Help_Dialog::load(const char *f) { + view_->set_changed(); +view_->load(f); +window_->label(view_->title()); +} + +void Fl_Help_Dialog::position(int xx, int yy) { + window_->position(xx, yy); +} + +void Fl_Help_Dialog::resize(int xx, int yy, int ww, int hh) { + window_->resize(xx, yy, ww, hh); +} + +void Fl_Help_Dialog::show() { + window_->show(); +} + +void Fl_Help_Dialog::show(int argc, char **argv) { + window_->show(argc, argv); +} + +void Fl_Help_Dialog::textsize(uchar s) { + view_->textsize(s); + +if (s <= 8) + smaller_->deactivate(); +else + smaller_->activate(); + +if (s >= 18) + larger_->deactivate(); +else + larger_->activate(); +} + +uchar Fl_Help_Dialog::textsize() { + return (view_->textsize()); +} + +void Fl_Help_Dialog::topline(const char *n) { + view_->topline(n); +} + +void Fl_Help_Dialog::topline(int n) { + view_->topline(n); +} + +void Fl_Help_Dialog::value(const char *f) { + view_->set_changed(); +view_->value(f); +window_->label(view_->title()); +} + +const char * Fl_Help_Dialog::value() const { + return view_->value(); +} + +int Fl_Help_Dialog::visible() { + return (window_->visible()); +} + +int Fl_Help_Dialog::w() { + return (window_->w()); +} + +int Fl_Help_Dialog::x() { + return (window_->x()); +} + +int Fl_Help_Dialog::y() { + return (window_->y()); +} + +// +// End of "$Id: Fl_Help_Dialog.cxx 5643 2007-01-28 19:36:51Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Help_Dialog.fl b/third_party/windows/fltk-1.1.10/src/Fl_Help_Dialog.fl new file mode 100644 index 0000000..78f23a5 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Help_Dialog.fl @@ -0,0 +1,265 @@ +# data file for the Fltk User Interface Designer (fluid) +version 1.0108 +header_name {../FL/Fl_Help_Dialog.H} +code_name {.cxx} +comment {// +// "$Id: Fl_Help_Dialog.fl 5643 2007-01-28 19:36:51Z mike $" +// +// Fl_Help_Dialog dialog for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +} {in_source in_header +} + +decl {\#include "flstring.h"} {} + +decl {\#include } {} + +class FL_EXPORT Fl_Help_Dialog {open +} { + decl {int index_;} {} + decl {int max_;} {} + decl {int line_[100];} {} + decl {char file_[100][256];} {} + decl {int find_pos_;} {} + Function {Fl_Help_Dialog()} {open + } { + Fl_Window window_ { + label {Help Dialog} open + private xywh {398 64 530 385} type Double resizable size_range {260 150 0 0} visible + } { + Fl_Group {} {open selected + xywh {10 10 511 25} + } { + Fl_Button back_ { + label {@<-} + callback {if (index_ > 0) + index_ --; + +if (index_ == 0) + back_->deactivate(); + +forward_->activate(); + +int l = line_[index_]; + +if (strcmp(view_->filename(), file_[index_]) != 0) + view_->load(file_[index_]); + +view_->topline(l);} + private tooltip {Show the previous help page.} xywh {10 10 25 25} shortcut 0xff51 labelcolor 2 + } + Fl_Button forward_ { + label {@->} + callback {if (index_ < max_) + index_ ++; + +if (index_ >= max_) + forward_->deactivate(); + +back_->activate(); + +int l = view_->topline(); + +if (strcmp(view_->filename(), file_[index_]) != 0) + view_->load(file_[index_]); + +view_->topline(l);} + private tooltip {Show the next help page.} xywh {45 10 25 25} shortcut 0xff53 labelcolor 2 + } + Fl_Button smaller_ { + label F + callback {if (view_->textsize() > 8) + view_->textsize(view_->textsize() - 2); + +if (view_->textsize() <= 8) + smaller_->deactivate(); +larger_->activate();} + private tooltip {Make the help text smaller.} xywh {80 10 25 25} labelfont 1 labelsize 10 + } + Fl_Button larger_ { + label F + callback {if (view_->textsize() < 18) + view_->textsize(view_->textsize() + 2); + +if (view_->textsize() >= 18) + larger_->deactivate(); +smaller_->activate();} + private tooltip {Make the help text larger.} xywh {115 10 25 25} labelfont 1 labelsize 16 + } + Fl_Group {} {open + xywh {350 10 171 25} box DOWN_BOX color 7 + } { + Fl_Input find_ { + label {@search} + callback {find_pos_ = view_->find(find_->value(), find_pos_);} + private tooltip {find text in document} xywh {375 12 143 21} box FLAT_BOX labelsize 13 when 10 textfont 4 + } + } + Fl_Box {} { + xywh {150 10 190 25} resizable + } + } + Fl_Help_View view_ { + callback {if (view_->filename()) +{ + if (view_->changed()) + { + index_ ++; + + if (index_ >= 100) + { + memmove(line_, line_ + 10, sizeof(line_[0]) * 90); + memmove(file_, file_ + 10, sizeof(file_[0]) * 90); + index_ -= 10; + } + + max_ = index_; + + strlcpy(file_[index_], view_->filename(),sizeof(file_[0])); + line_[index_] = view_->topline(); + + if (index_ > 0) + back_->activate(); + else + back_->deactivate(); + + forward_->deactivate(); + window_->label(view_->title()); + } + else // if ! view_->changed() + { + strlcpy(file_[index_], view_->filename(), sizeof(file_[0])); + line_[index_] = view_->topline(); + } +} else { // if ! view_->filename() + index_ = 0; // hitting an internal page will disable the back/fwd buffer + file_[index_][0] = 0; // unnamed internal page + line_[index_] = view_->topline(); + back_->deactivate(); + forward_->deactivate(); +}} + private xywh {10 45 510 330} box DOWN_BOX resizable + } + } + code {back_->deactivate(); +forward_->deactivate(); + +index_ = -1; +max_ = 0; +find_pos_ = 0; + +fl_register_images();} {} + } + Function {~Fl_Help_Dialog()} {} { + code {delete window_;} {} + } + Function {h()} {return_type int + } { + code {return (window_->h());} {} + } + Function {hide()} {return_type void + } { + code {window_->hide();} {} + } + Function {load(const char *f)} {return_type void + } { + code {view_->set_changed(); +view_->load(f); +window_->label(view_->title());} {} + } + Function {position(int xx, int yy)} {return_type void + } { + code {window_->position(xx, yy);} {} + } + Function {resize(int xx, int yy, int ww, int hh)} {return_type void + } { + code {window_->resize(xx, yy, ww, hh);} {} + } + Function {show()} {return_type void + } { + code {window_->show();} {} + } + Function {show(int argc, char **argv)} {return_type void + } { + code {window_->show(argc, argv);} {} + } + Function {textsize(uchar s)} {return_type void + } { + code {view_->textsize(s); + +if (s <= 8) + smaller_->deactivate(); +else + smaller_->activate(); + +if (s >= 18) + larger_->deactivate(); +else + larger_->activate();} {} + } + Function {textsize()} {return_type uchar + } { + code {return (view_->textsize());} {} + } + Function {topline(const char *n)} {return_type void + } { + code {view_->topline(n);} {} + } + Function {topline(int n)} {return_type void + } { + code {view_->topline(n);} {} + } + Function {value(const char *f)} {return_type void + } { + code {view_->set_changed(); +view_->value(f); +window_->label(view_->title());} {} + } + Function {value() const} {return_type {const char *} + } { + code {return view_->value();} {} + } + Function {visible()} {return_type int + } { + code {return (window_->visible());} {} + } + Function {w()} {return_type int + } { + code {return (window_->w());} {} + } + Function {x()} {return_type int + } { + code {return (window_->x());} {} + } + Function {y()} {return_type int + } { + code {return (window_->y());} {} + } +} + +comment { +// +// End of "$Id: Fl_Help_Dialog.fl 5643 2007-01-28 19:36:51Z mike $". +//} {in_source in_header +} diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Help_View.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Help_View.cxx new file mode 100644 index 0000000..c7bd073 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Help_View.cxx @@ -0,0 +1,3507 @@ +// +// "$Id: Fl_Help_View.cxx 6745 2009-04-07 18:37:25Z AlbrechtS $" +// +// Fl_Help_View widget routines. +// +// Copyright 1997-2007 by Easy Software Products. +// Image support donated by Matthias Melcher, Copyright 2000. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_Help_View::add_block() - Add a text block to the list. +// Fl_Help_View::add_link() - Add a new link to the list. +// Fl_Help_View::add_target() - Add a new target to the list. +// Fl_Help_View::compare_targets() - Compare two targets. +// Fl_Help_View::do_align() - Compute the alignment for a line in +// a block. +// Fl_Help_View::draw() - Draw the Fl_Help_View widget. +// Fl_Help_View::format() - Format the help text. +// Fl_Help_View::format_table() - Format a table... +// Fl_Help_View::free_data() - Free memory used for the document. +// Fl_Help_View::get_align() - Get an alignment attribute. +// Fl_Help_View::get_attr() - Get an attribute value from the string. +// Fl_Help_View::get_color() - Get an alignment attribute. +// Fl_Help_View::handle() - Handle events in the widget. +// Fl_Help_View::Fl_Help_View() - Build a Fl_Help_View widget. +// Fl_Help_View::~Fl_Help_View() - Destroy a Fl_Help_View widget. +// Fl_Help_View::load() - Load the specified file. +// Fl_Help_View::resize() - Resize the help widget. +// Fl_Help_View::topline() - Set the top line to the named target. +// Fl_Help_View::topline() - Set the top line by number. +// Fl_Help_View::value() - Set the help text directly. +// scrollbar_callback() - A callback for the scrollbar. +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include +#include +#include +#include "flstring.h" +#include +#include +#include + +#if defined(WIN32) && ! defined(__CYGWIN__) +# include +# include +// Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs +// on Windows, which is supposed to be POSIX compliant... +# define getcwd _getcwd +#else +# include +#endif // WIN32 + +#define MAX_COLUMNS 200 + + +// +// Typedef the C API sort function type the only way I know how... +// + +extern "C" +{ + typedef int (*compare_func_t)(const void *, const void *); +} + + +// +// Local functions... +// + +static int quote_char(const char *); +static void scrollbar_callback(Fl_Widget *s, void *); +static void hscrollbar_callback(Fl_Widget *s, void *); + +// +// global flag for image loading (see get_image). +// + +static char initial_load = 0; + +// +// Broken image... +// + +static const char *broken_xpm[] = + { + "16 24 4 1", + "@ c #000000", + " c #ffffff", + "+ c none", + "x c #ff0000", + // pixels + "@@@@@@@+++++++++", + "@ @++++++++++", + "@ @+++++++++++", + "@ @++@++++++++", + "@ @@+++++++++", + "@ @+++@+++++", + "@ @++@@++++@", + "@ xxx @@ @++@@", + "@ xxx xx@@ @", + "@ xxx xxx @", + "@ xxxxxx @", + "@ xxxx @", + "@ xxxxxx @", + "@ xxx xxx @", + "@ xxx xxx @", + "@ xxx xxx @", + "@ @", + "@ @", + "@ @", + "@ @", + "@ @", + "@ @", + "@ @", + "@@@@@@@@@@@@@@@@", + NULL + }; + +static Fl_Pixmap broken_image(broken_xpm); + +// +// Simple margin stack for Fl_Help_View::format()... +// + +struct fl_margins { + int depth_; + int margins_[100]; + + fl_margins() { clear(); } + + int clear() { +// puts("fl_margins::clear()"); + + depth_ = 0; + return margins_[0] = 4; + } + + int current() { return margins_[depth_]; } + + int pop() { +// printf("fl_margins::pop(): depth_=%d, xx=%d\n", depth_, +// depth_ > 0 ? margins_[depth_ - 1] : 4); + + if (depth_ > 0) { + depth_ --; + return margins_[depth_]; + } else return 4; + } + + int push(int indent) { + int xx; + + xx = margins_[depth_] + indent; + +// printf("fl_margins::push(indent=%d): depth_=%d, xx=%d\n", indent, +// depth_ + 1, xx); + + if (depth_ < 99) { + depth_ ++; + margins_[depth_] = xx; + } + + return xx; + } +}; + +// +// All the stuff needed to implement text selection in Fl_Help_View +// + +/* matt: + * We are trying to keep binary compatibility with previous versions + * of FLTK. This means that we are limited to adding static variables + * only to not enlarge the Fl_Help_View class. Lucky for us, only one + * text can be selected system wide, so we can remember the selection + * in a single set of variables. + * + * Still to do: + * - &word; style characters mess up our count inside a word boundary + * - we can only select words, no individual characters + * - no dragging of the selection into another widget + * - selection must be cleared if another widget get focus! + * - write a comment for every new function + */ + +/* +The following functions are also used to draw stuff and should be replaced with +local copies that are much faster when merely counting: + +fl_color(Fl_Color); +fl_rectf(int, int, int, int); +fl_push_clip(int, int, int, int); +fl_xyline(int, int, int); +fl_rect() +fl_line() +img->draw() +*/ + +// We don't put the offscreen buffer in the help view class because +// we'd need to include x.H in the header... +static Fl_Offscreen fl_help_view_buffer; +int Fl_Help_View::selection_first = 0; +int Fl_Help_View::selection_last = 0; +int Fl_Help_View::selection_push_first = 0; +int Fl_Help_View::selection_push_last = 0; +int Fl_Help_View::selection_drag_first = 0; +int Fl_Help_View::selection_drag_last = 0; +int Fl_Help_View::selected = 0; +int Fl_Help_View::draw_mode = 0; +int Fl_Help_View::mouse_x = 0; +int Fl_Help_View::mouse_y = 0; +int Fl_Help_View::current_pos = 0; +Fl_Help_View *Fl_Help_View::current_view = 0L; +Fl_Color Fl_Help_View::hv_selection_color; +Fl_Color Fl_Help_View::hv_selection_text_color; + +/* + * Limitation: if a word contains &code; notations, we will calculate a wrong length. + * + * This function must be optimized for speed! + */ +void Fl_Help_View::hv_draw(const char *t, int x, int y) +{ + if (selected && current_view==this && current_pos=selection_first) { + Fl_Color c = fl_color(); + fl_color(hv_selection_color); + int w = (int)fl_width(t); + if (current_pos+(int)strlen(t)=x && mouse_x=y-fl_height()+fl_descent()&&mouse_y<=y+fl_descent()) { + int f = current_pos; + int l = f+strlen(t); // use 'quote_char' to calculate the true length of the HTML string + if (draw_mode==1) { + selection_push_first = f; + selection_push_last = l; + } else { + selection_drag_first = f; + selection_drag_last = l; + } + } + } + } +} + + +// +// 'Fl_Help_View::add_block()' - Add a text block to the list. +// + +Fl_Help_Block * // O - Pointer to new block +Fl_Help_View::add_block(const char *s, // I - Pointer to start of block text + int xx, // I - X position of block + int yy, // I - Y position of block + int ww, // I - Right margin of block + int hh, // I - Height of block + unsigned char border) // I - Draw border? +{ + Fl_Help_Block *temp; // New block + + +// printf("add_block(s = %p, xx = %d, yy = %d, ww = %d, hh = %d, border = %d)\n", +// s, xx, yy, ww, hh, border); + + if (nblocks_ >= ablocks_) + { + ablocks_ += 16; + + if (ablocks_ == 16) + blocks_ = (Fl_Help_Block *)malloc(sizeof(Fl_Help_Block) * ablocks_); + else + blocks_ = (Fl_Help_Block *)realloc(blocks_, sizeof(Fl_Help_Block) * ablocks_); + } + + temp = blocks_ + nblocks_; + memset(temp, 0, sizeof(Fl_Help_Block)); + temp->start = s; + temp->end = s; + temp->x = xx; + temp->y = yy; + temp->w = ww; + temp->h = hh; + temp->border = border; + temp->bgcolor = bgcolor_; + nblocks_ ++; + + return (temp); +} + + +// +// 'Fl_Help_View::add_link()' - Add a new link to the list. +// + +void +Fl_Help_View::add_link(const char *n, // I - Name of link + int xx, // I - X position of link + int yy, // I - Y position of link + int ww, // I - Width of link text + int hh) // I - Height of link text +{ + Fl_Help_Link *temp; // New link + char *target; // Pointer to target name + + + if (nlinks_ >= alinks_) + { + alinks_ += 16; + + if (alinks_ == 16) + links_ = (Fl_Help_Link *)malloc(sizeof(Fl_Help_Link) * alinks_); + else + links_ = (Fl_Help_Link *)realloc(links_, sizeof(Fl_Help_Link) * alinks_); + } + + temp = links_ + nlinks_; + + temp->x = xx; + temp->y = yy; + temp->w = xx + ww; + temp->h = yy + hh; + + strlcpy(temp->filename, n, sizeof(temp->filename)); + + if ((target = strrchr(temp->filename, '#')) != NULL) + { + *target++ = '\0'; + strlcpy(temp->name, target, sizeof(temp->name)); + } + else + temp->name[0] = '\0'; + + nlinks_ ++; +} + + +// +// 'Fl_Help_View::add_target()' - Add a new target to the list. +// + +void +Fl_Help_View::add_target(const char *n, // I - Name of target + int yy) // I - Y position of target +{ + Fl_Help_Target *temp; // New target + + + if (ntargets_ >= atargets_) + { + atargets_ += 16; + + if (atargets_ == 16) + targets_ = (Fl_Help_Target *)malloc(sizeof(Fl_Help_Target) * atargets_); + else + targets_ = (Fl_Help_Target *)realloc(targets_, sizeof(Fl_Help_Target) * atargets_); + } + + temp = targets_ + ntargets_; + + temp->y = yy; + strlcpy(temp->name, n, sizeof(temp->name)); + + ntargets_ ++; +} + + +// +// 'Fl_Help_View::compare_targets()' - Compare two targets. +// + +int // O - Result of comparison +Fl_Help_View::compare_targets(const Fl_Help_Target *t0, // I - First target + const Fl_Help_Target *t1) // I - Second target +{ + return (strcasecmp(t0->name, t1->name)); +} + + +// +// 'Fl_Help_View::do_align()' - Compute the alignment for a line in a block. +// + +int // O - New line +Fl_Help_View::do_align(Fl_Help_Block *block, // I - Block to add to + int line, // I - Current line + int xx, // I - Current X position + int a, // I - Current alignment + int &l) // IO - Starting link +{ + int offset; // Alignment offset + + + switch (a) + { + case RIGHT : // Right align + offset = block->w - xx; + break; + case CENTER : // Center + offset = (block->w - xx) / 2; + break; + default : // Left align + offset = 0; + break; + } + + block->line[line] = block->x + offset; + + if (line < 31) + line ++; + + while (l < nlinks_) + { + links_[l].x += offset; + links_[l].w += offset; + l ++; + } + + return (line); +} + + +// +// 'Fl_Help_View::draw()' - Draw the Fl_Help_View widget. +// + +void +Fl_Help_View::draw() +{ + int i; // Looping var + const Fl_Help_Block *block; // Pointer to current block + const char *ptr, // Pointer to text in block + *attrs; // Pointer to start of element attributes + char *s, // Pointer into buffer + buf[1024], // Text buffer + attr[1024]; // Attribute buffer + int xx, yy, ww, hh; // Current positions and sizes + int line; // Current line + unsigned char font, fsize; // Current font and size + int head, pre, // Flags for text + needspace; // Do we need whitespace? + Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; + // Box to draw... + int underline, // Underline text? + xtra_ww; // Extra width for underlined space between words + + + // Draw the scrollbar(s) and box first... + ww = w() ; + hh = h(); + i = 0; + + draw_box(b, x(), y(), ww, hh, bgcolor_); + + int ss = Fl::scrollbar_size(); + if (hscrollbar_.visible()) { + draw_child(hscrollbar_); + hh -= ss; + i ++; + } + if (scrollbar_.visible()) { + draw_child(scrollbar_); + ww -= ss; + i ++; + } + if (i == 2) { + fl_color(FL_GRAY); + fl_rectf(x() + ww - Fl::box_dw(b) + Fl::box_dx(b), + y() + hh - Fl::box_dh(b) + Fl::box_dy(b), ss, ss); + } + + if (!value_) + return; + + if (current_view == this && selected) { + hv_selection_color = FL_SELECTION_COLOR; + hv_selection_text_color = fl_contrast(textcolor_, FL_SELECTION_COLOR); + } + current_pos = 0; + + // Clip the drawing to the inside of the box... + fl_push_clip(x() + Fl::box_dx(b), y() + Fl::box_dy(b), + ww - Fl::box_dw(b), hh - Fl::box_dh(b)); + fl_color(textcolor_); + + // Draw all visible blocks... + for (i = 0, block = blocks_; i < nblocks_; i ++, block ++) + if ((block->y + block->h) >= topline_ && block->y < (topline_ + h())) + { + line = 0; + xx = block->line[line]; + yy = block->y - topline_; + hh = 0; + pre = 0; + head = 0; + needspace = 0; + underline = 0; + + initfont(font, fsize); + + for (ptr = block->start, s = buf; ptr < block->end;) + { + if ((*ptr == '<' || isspace((*ptr)&255)) && s > buf) + { + if (!head && !pre) + { + // Check width... + *s = '\0'; + s = buf; + ww = (int)fl_width(buf); + + if (needspace && xx > block->x) + xx += (int)fl_width(' '); + + if ((xx + ww) > block->w) + { + if (line < 31) + line ++; + xx = block->line[line]; + yy += hh; + hh = 0; + } + + hv_draw(buf, xx + x() - leftline_, yy + y()); + if (underline) { + xtra_ww = isspace((*ptr)&255)?(int)fl_width(' '):0; + fl_xyline(xx + x() - leftline_, yy + y() + 1, + xx + x() - leftline_ + ww + xtra_ww); + } + current_pos = ptr-value_; + + xx += ww; + if ((fsize + 2) > hh) + hh = fsize + 2; + + needspace = 0; + } + else if (pre) + { + while (isspace((*ptr)&255)) + { + if (*ptr == '\n') + { + *s = '\0'; + s = buf; + + hv_draw(buf, xx + x() - leftline_, yy + y()); + if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, + xx + x() - leftline_ + + (int)fl_width(buf)); + + current_pos = ptr-value_; + if (line < 31) + line ++; + xx = block->line[line]; + yy += hh; + hh = fsize + 2; + } + else if (*ptr == '\t') + { + // Do tabs every 8 columns... + while (((s - buf) & 7)) + *s++ = ' '; + } + else + *s++ = ' '; + + if ((fsize + 2) > hh) + hh = fsize + 2; + + ptr ++; + } + + if (s > buf) + { + *s = '\0'; + s = buf; + + hv_draw(buf, xx + x() - leftline_, yy + y()); + ww = (int)fl_width(buf); + if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, + xx + x() - leftline_ + ww); + xx += ww; + current_pos = ptr-value_; + } + + needspace = 0; + } + else + { + s = buf; + + while (isspace((*ptr)&255)) + ptr ++; + current_pos = ptr-value_; + } + } + + if (*ptr == '<') + { + ptr ++; + + if (strncmp(ptr, "!--", 3) == 0) + { + // Comment... + ptr += 3; + if ((ptr = strstr(ptr, "-->")) != NULL) + { + ptr += 3; + continue; + } + else + break; + } + + while (*ptr && *ptr != '>' && !isspace((*ptr)&255)) + if (s < (buf + sizeof(buf) - 1)) + *s++ = *ptr++; + else + ptr ++; + + *s = '\0'; + s = buf; + + attrs = ptr; + while (*ptr && *ptr != '>') + ptr ++; + + if (*ptr == '>') + ptr ++; + + // end of command reached, set the supposed start of printed eord here + current_pos = ptr-value_; + if (strcasecmp(buf, "HEAD") == 0) + head = 1; + else if (strcasecmp(buf, "BR") == 0) + { + if (line < 31) + line ++; + xx = block->line[line]; + yy += hh; + hh = 0; + } + else if (strcasecmp(buf, "HR") == 0) + { + fl_line(block->x + x(), yy + y(), block->w + x(), + yy + y()); + + if (line < 31) + line ++; + xx = block->line[line]; + yy += 2 * hh; + hh = 0; + } + else if (strcasecmp(buf, "CENTER") == 0 || + strcasecmp(buf, "P") == 0 || + strcasecmp(buf, "H1") == 0 || + strcasecmp(buf, "H2") == 0 || + strcasecmp(buf, "H3") == 0 || + strcasecmp(buf, "H4") == 0 || + strcasecmp(buf, "H5") == 0 || + strcasecmp(buf, "H6") == 0 || + strcasecmp(buf, "UL") == 0 || + strcasecmp(buf, "OL") == 0 || + strcasecmp(buf, "DL") == 0 || + strcasecmp(buf, "LI") == 0 || + strcasecmp(buf, "DD") == 0 || + strcasecmp(buf, "DT") == 0 || + strcasecmp(buf, "PRE") == 0) + { + if (tolower(buf[0]) == 'h') + { + font = FL_HELVETICA_BOLD; + fsize = (uchar)(textsize_ + '7' - buf[1]); + } + else if (strcasecmp(buf, "DT") == 0) + { + font = (uchar)(textfont_ | FL_ITALIC); + fsize = textsize_; + } + else if (strcasecmp(buf, "PRE") == 0) + { + font = FL_COURIER; + fsize = textsize_; + pre = 1; + } + + if (strcasecmp(buf, "LI") == 0) + { +#ifdef __APPLE_QUARTZ__ + fl_font(FL_SYMBOL, fsize); + hv_draw("\245", xx - fsize + x() - leftline_, yy + y()); +#else + fl_font(FL_SYMBOL, fsize); + hv_draw("\267", xx - fsize + x() - leftline_, yy + y()); +#endif + } + + pushfont(font, fsize); + } + else if (strcasecmp(buf, "A") == 0 && + get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL) + { + fl_color(linkcolor_); + underline = 1; + } + else if (strcasecmp(buf, "/A") == 0) + { + fl_color(textcolor_); + underline = 0; + } + else if (strcasecmp(buf, "FONT") == 0) + { + if (get_attr(attrs, "COLOR", attr, sizeof(attr)) != NULL) { + fl_color(get_color(attr, textcolor_)); + } + + if (get_attr(attrs, "FACE", attr, sizeof(attr)) != NULL) { + if (!strncasecmp(attr, "helvetica", 9) || + !strncasecmp(attr, "arial", 5) || + !strncasecmp(attr, "sans", 4)) font = FL_HELVETICA; + else if (!strncasecmp(attr, "times", 5) || + !strncasecmp(attr, "serif", 5)) font = FL_TIMES; + else if (!strncasecmp(attr, "symbol", 6)) font = FL_SYMBOL; + else font = FL_COURIER; + } + + if (get_attr(attrs, "SIZE", attr, sizeof(attr)) != NULL) { + if (isdigit(attr[0] & 255)) { + // Absolute size + fsize = (int)(textsize_ * pow(1.2, atof(attr) - 3.0)); + } else { + // Relative size + fsize = (int)(fsize * pow(1.2, atof(attr) - 3.0)); + } + } + + pushfont(font, fsize); + } + else if (strcasecmp(buf, "/FONT") == 0) + { + fl_color(textcolor_); + popfont(font, fsize); + } + else if (strcasecmp(buf, "U") == 0) + underline = 1; + else if (strcasecmp(buf, "/U") == 0) + underline = 0; + else if (strcasecmp(buf, "B") == 0 || + strcasecmp(buf, "STRONG") == 0) + pushfont(font |= FL_BOLD, fsize); + else if (strcasecmp(buf, "TD") == 0 || + strcasecmp(buf, "TH") == 0) + { + int tx, ty, tw, th; + + if (tolower(buf[1]) == 'h') + pushfont(font |= FL_BOLD, fsize); + else + pushfont(font = textfont_, fsize); + + tx = block->x - 4 - leftline_; + ty = block->y - topline_ - fsize - 3; + tw = block->w - block->x + 7; + th = block->h + fsize - 5; + + if (tx < 0) + { + tw += tx; + tx = 0; + } + + if (ty < 0) + { + th += ty; + ty = 0; + } + + tx += x(); + ty += y(); + + if (block->bgcolor != bgcolor_) + { + fl_color(block->bgcolor); + fl_rectf(tx, ty, tw, th); + fl_color(textcolor_); + } + + if (block->border) + fl_rect(tx, ty, tw, th); + } + else if (strcasecmp(buf, "I") == 0 || + strcasecmp(buf, "EM") == 0) + pushfont(font |= FL_ITALIC, fsize); + else if (strcasecmp(buf, "CODE") == 0 || + strcasecmp(buf, "TT") == 0) + pushfont(font = FL_COURIER, fsize); + else if (strcasecmp(buf, "KBD") == 0) + pushfont(font = FL_COURIER_BOLD, fsize); + else if (strcasecmp(buf, "VAR") == 0) + pushfont(font = FL_COURIER_ITALIC, fsize); + else if (strcasecmp(buf, "/HEAD") == 0) + head = 0; + else if (strcasecmp(buf, "/H1") == 0 || + strcasecmp(buf, "/H2") == 0 || + strcasecmp(buf, "/H3") == 0 || + strcasecmp(buf, "/H4") == 0 || + strcasecmp(buf, "/H5") == 0 || + strcasecmp(buf, "/H6") == 0 || + strcasecmp(buf, "/B") == 0 || + strcasecmp(buf, "/STRONG") == 0 || + strcasecmp(buf, "/I") == 0 || + strcasecmp(buf, "/EM") == 0 || + strcasecmp(buf, "/CODE") == 0 || + strcasecmp(buf, "/TT") == 0 || + strcasecmp(buf, "/KBD") == 0 || + strcasecmp(buf, "/VAR") == 0) + popfont(font, fsize); + else if (strcasecmp(buf, "/PRE") == 0) + { + popfont(font, fsize); + pre = 0; + } + else if (strcasecmp(buf, "IMG") == 0) + { + Fl_Shared_Image *img = 0; + int width, height; + char wattr[8], hattr[8]; + + + get_attr(attrs, "WIDTH", wattr, sizeof(wattr)); + get_attr(attrs, "HEIGHT", hattr, sizeof(hattr)); + width = get_length(wattr); + height = get_length(hattr); + + if (get_attr(attrs, "SRC", attr, sizeof(attr))) { + img = get_image(attr, width, height); + if (!width) width = img->w(); + if (!height) height = img->h(); + } + + if (!width || !height) { + if (get_attr(attrs, "ALT", attr, sizeof(attr)) == NULL) { + strcpy(attr, "IMG"); + } + } + + ww = width; + + if (needspace && xx > block->x) + xx += (int)fl_width(' '); + + if ((xx + ww) > block->w) + { + if (line < 31) + line ++; + + xx = block->line[line]; + yy += hh; + hh = 0; + } + + if (img) { + img->draw(xx + x() - leftline_, + yy + y() - fl_height() + fl_descent() + 2); + } + + xx += ww; + if ((height + 2) > hh) + hh = height + 2; + + needspace = 0; + } + } + else if (*ptr == '\n' && pre) + { + *s = '\0'; + s = buf; + + hv_draw(buf, xx + x() - leftline_, yy + y()); + + if (line < 31) + line ++; + xx = block->line[line]; + yy += hh; + hh = fsize + 2; + needspace = 0; + + ptr ++; + current_pos = ptr-value_; + } + else if (isspace((*ptr)&255)) + { + if (pre) + { + if (*ptr == ' ') + *s++ = ' '; + else + { + // Do tabs every 8 columns... + while (((s - buf) & 7)) + *s++ = ' '; + } + } + + ptr ++; + if (!pre) current_pos = ptr-value_; + needspace = 1; + } + else if (*ptr == '&') + { + ptr ++; + + int qch = quote_char(ptr); + + if (qch < 0) + *s++ = '&'; + else { + *s++ = qch; + ptr = strchr(ptr, ';') + 1; + } + + if ((fsize + 2) > hh) + hh = fsize + 2; + } + else + { + *s++ = *ptr++; + + if ((fsize + 2) > hh) + hh = fsize + 2; + } + } + + *s = '\0'; + + if (s > buf && !pre && !head) + { + ww = (int)fl_width(buf); + + if (needspace && xx > block->x) + xx += (int)fl_width(' '); + + if ((xx + ww) > block->w) + { + if (line < 31) + line ++; + xx = block->line[line]; + yy += hh; + hh = 0; + } + } + + if (s > buf && !head) + { + hv_draw(buf, xx + x() - leftline_, yy + y()); + if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, + xx + x() - leftline_ + ww); + current_pos = ptr-value_; + } + } + + fl_pop_clip(); +} + + +// +// 'Fl_Help_View::find()' - Find the specified string... +// + +int // O - Matching position or -1 if not found +Fl_Help_View::find(const char *s, // I - String to find + int p) // I - Starting position +{ + int i, // Looping var + c; // Current character + Fl_Help_Block *b; // Current block + const char *bp, // Block matching pointer + *bs, // Start of current comparison + *sp; // Search string pointer + + + // Range check input and value... + if (!s || !value_) return -1; + + if (p < 0 || p >= (int)strlen(value_)) p = 0; + else if (p > 0) p ++; + + // Look for the string... + for (i = nblocks_, b = blocks_; i > 0; i --, b ++) { + if (b->end < (value_ + p)) + continue; + + if (b->start < (value_ + p)) bp = value_ + p; + else bp = b->start; + + for (sp = s, bs = bp; *sp && *bp && bp < b->end; bp ++) { + if (*bp == '<') { + // skip to end of element... + while (*bp && bp < b->end && *bp != '>') bp ++; + continue; + } else if (*bp == '&') { + // decode HTML entity... + if ((c = quote_char(bp + 1)) < 0) c = '&'; + else bp = strchr(bp + 1, ';') + 1; + } else c = *bp; + + if (tolower(*sp) == tolower(c)) sp ++; + else { + // No match, so reset to start of search... + sp = s; + bs ++; + bp = bs; + } + } + + if (!*sp) { + // Found a match! + topline(b->y - b->h); + return (b->end - value_); + } + } + + // No match! + return (-1); +} + + +// +// 'Fl_Help_View::format()' - Format the help text. +// + +void +Fl_Help_View::format() +{ + int i; // Looping var + int done; // Are we done yet? + Fl_Help_Block *block, // Current block + *cell; // Current table cell + int cells[MAX_COLUMNS], + // Cells in the current row... + row; // Current table row (block number) + const char *ptr, // Pointer into block + *start, // Pointer to start of element + *attrs; // Pointer to start of element attributes + char *s, // Pointer into buffer + buf[1024], // Text buffer + attr[1024], // Attribute buffer + wattr[1024], // Width attribute buffer + hattr[1024], // Height attribute buffer + linkdest[1024]; // Link destination + int xx, yy, ww, hh; // Size of current text fragment + int line; // Current line in block + int links; // Links for current line + unsigned char font, fsize; // Current font and size + unsigned char border; // Draw border? + int talign, // Current alignment + newalign, // New alignment + head, // In the section? + pre, //
 text?
+		needspace;	// Do we need whitespace?
+  int		table_width,	// Width of table
+		table_offset;	// Offset of table
+  int		column,		// Current table column number
+		columns[MAX_COLUMNS];
+				// Column widths
+  Fl_Color	tc, rc;		// Table/row background color
+  Fl_Boxtype	b = box() ? box() : FL_DOWN_BOX;
+				// Box to draw...
+  fl_margins	margins;	// Left margin stack...
+
+
+  // Reset document width...
+  hsize_ = w() - Fl::scrollbar_size() - Fl::box_dw(b);
+
+  done = 0;
+  while (!done)
+  {
+    // Reset state variables...
+    done       = 1;
+    nblocks_   = 0;
+    nlinks_    = 0;
+    ntargets_  = 0;
+    size_      = 0;
+    bgcolor_   = color();
+    textcolor_ = textcolor();
+    linkcolor_ = fl_contrast(FL_BLUE, color());
+
+    tc = rc = bgcolor_;
+
+    strcpy(title_, "Untitled");
+
+    if (!value_)
+      return;
+
+    // Setup for formatting...
+    initfont(font, fsize);
+
+    line         = 0;
+    links        = 0;
+    xx           = margins.clear();
+    yy           = fsize + 2;
+    ww           = 0;
+    column       = 0;
+    border       = 0;
+    hh           = 0;
+    block        = add_block(value_, xx, yy, hsize_, 0);
+    row          = 0;
+    head         = 0;
+    pre          = 0;
+    talign       = LEFT;
+    newalign     = LEFT;
+    needspace    = 0;
+    linkdest[0]  = '\0';
+    table_offset = 0;
+
+    for (ptr = value_, s = buf; *ptr;)
+    {
+      if ((*ptr == '<' || isspace((*ptr)&255)) && s > buf)
+      {
+        // Get width...
+        *s = '\0';
+        ww = (int)fl_width(buf);
+
+	if (!head && !pre)
+	{
+          // Check width...
+          if (ww > hsize_) {
+	    hsize_ = ww;
+	    done   = 0;
+	    break;
+	  }
+
+          if (needspace && xx > block->x)
+	    ww += (int)fl_width(' ');
+
+  //        printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n",
+  //	       line, xx, ww, block->x, block->w);
+
+          if ((xx + ww) > block->w)
+	  {
+            line     = do_align(block, line, xx, newalign, links);
+	    xx       = block->x;
+	    yy       += hh;
+	    block->h += hh;
+	    hh       = 0;
+	  }
+
+          if (linkdest[0])
+	    add_link(linkdest, xx, yy - fsize, ww, fsize);
+
+	  xx += ww;
+	  if ((fsize + 2) > hh)
+	    hh = fsize + 2;
+
+	  needspace = 0;
+	}
+	else if (pre)
+	{
+          // Add a link as needed...
+          if (linkdest[0])
+	    add_link(linkdest, xx, yy - hh, ww, hh);
+
+	  xx += ww;
+	  if ((fsize + 2) > hh)
+	    hh = fsize + 2;
+
+          // Handle preformatted text...
+	  while (isspace((*ptr)&255))
+	  {
+	    if (*ptr == '\n')
+	    {
+              if (xx > hsize_) break;
+
+              line     = do_align(block, line, xx, newalign, links);
+              xx       = block->x;
+	      yy       += hh;
+	      block->h += hh;
+	      hh       = fsize + 2;
+	    }
+	    else
+              xx += (int)fl_width(' ');
+
+            if ((fsize + 2) > hh)
+	      hh = fsize + 2;
+
+            ptr ++;
+	  }
+
+          if (xx > hsize_) {
+	    hsize_ = xx;
+	    done   = 0;
+	    break;
+	  }
+
+	  needspace = 0;
+	}
+	else
+	{
+          // Handle normal text or stuff in the  section...
+	  while (isspace((*ptr)&255))
+            ptr ++;
+	}
+
+	s = buf;
+      }
+
+      if (*ptr == '<')
+      {
+	start = ptr;
+	ptr ++;
+
+        if (strncmp(ptr, "!--", 3) == 0)
+	{
+	  // Comment...
+	  ptr += 3;
+	  if ((ptr = strstr(ptr, "-->")) != NULL)
+	  {
+	    ptr += 3;
+	    continue;
+	  }
+	  else
+	    break;
+	}
+
+	while (*ptr && *ptr != '>' && !isspace((*ptr)&255))
+          if (s < (buf + sizeof(buf) - 1))
+            *s++ = *ptr++;
+	  else
+	    ptr ++;
+
+	*s = '\0';
+	s = buf;
+
+//        puts(buf);
+
+	attrs = ptr;
+	while (*ptr && *ptr != '>')
+          ptr ++;
+
+	if (*ptr == '>')
+          ptr ++;
+
+	if (strcasecmp(buf, "HEAD") == 0)
+          head = 1;
+	else if (strcasecmp(buf, "/HEAD") == 0)
+          head = 0;
+	else if (strcasecmp(buf, "TITLE") == 0)
+	{
+          // Copy the title in the document...
+          for (s = title_;
+	       *ptr != '<' && *ptr && s < (title_ + sizeof(title_) - 1);
+	       *s++ = *ptr++);
+
+	  *s = '\0';
+	  s = buf;
+	}
+	else if (strcasecmp(buf, "A") == 0)
+	{
+          if (get_attr(attrs, "NAME", attr, sizeof(attr)) != NULL)
+	    add_target(attr, yy - fsize - 2);
+
+	  if (get_attr(attrs, "HREF", attr, sizeof(attr)) != NULL)
+	    strlcpy(linkdest, attr, sizeof(linkdest));
+	}
+	else if (strcasecmp(buf, "/A") == 0)
+          linkdest[0] = '\0';
+	else if (strcasecmp(buf, "BODY") == 0)
+	{
+          bgcolor_   = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)),
+	                	 color());
+          textcolor_ = get_color(get_attr(attrs, "TEXT", attr, sizeof(attr)),
+	                	 textcolor());
+          linkcolor_ = get_color(get_attr(attrs, "LINK", attr, sizeof(attr)),
+	                	 fl_contrast(FL_BLUE, color()));
+	}
+	else if (strcasecmp(buf, "BR") == 0)
+	{
+          line     = do_align(block, line, xx, newalign, links);
+          xx       = block->x;
+	  block->h += hh;
+          yy       += hh;
+	  hh       = 0;
+	}
+	else if (strcasecmp(buf, "CENTER") == 0 ||
+        	 strcasecmp(buf, "P") == 0 ||
+        	 strcasecmp(buf, "H1") == 0 ||
+		 strcasecmp(buf, "H2") == 0 ||
+		 strcasecmp(buf, "H3") == 0 ||
+		 strcasecmp(buf, "H4") == 0 ||
+		 strcasecmp(buf, "H5") == 0 ||
+		 strcasecmp(buf, "H6") == 0 ||
+		 strcasecmp(buf, "UL") == 0 ||
+		 strcasecmp(buf, "OL") == 0 ||
+		 strcasecmp(buf, "DL") == 0 ||
+		 strcasecmp(buf, "LI") == 0 ||
+		 strcasecmp(buf, "DD") == 0 ||
+		 strcasecmp(buf, "DT") == 0 ||
+		 strcasecmp(buf, "HR") == 0 ||
+		 strcasecmp(buf, "PRE") == 0 ||
+		 strcasecmp(buf, "TABLE") == 0)
+	{
+          block->end = start;
+          line       = do_align(block, line, xx, newalign, links);
+	  newalign   = strcasecmp(buf, "CENTER") ? LEFT : CENTER;
+          xx         = block->x;
+          block->h   += hh;
+
+          if (strcasecmp(buf, "UL") == 0 ||
+	      strcasecmp(buf, "OL") == 0 ||
+	      strcasecmp(buf, "DL") == 0)
+          {
+	    block->h += fsize + 2;
+	    xx       = margins.push(4 * fsize);
+	  }
+          else if (strcasecmp(buf, "TABLE") == 0)
+	  {
+	    if (get_attr(attrs, "BORDER", attr, sizeof(attr)))
+	      border = (uchar)atoi(attr);
+	    else
+	      border = 0;
+
+            tc = rc = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), bgcolor_);
+
+	    block->h += fsize + 2;
+
+            format_table(&table_width, columns, start);
+
+            if ((xx + table_width) > hsize_) {
+#ifdef DEBUG
+              printf("xx=%d, table_width=%d, hsize_=%d\n", xx, table_width,
+	             hsize_);
+#endif // DEBUG
+	      hsize_ = xx + table_width;
+	      done   = 0;
+	      break;
+	    }
+
+            switch (get_align(attrs, talign))
+	    {
+	      default :
+	          table_offset = 0;
+	          break;
+
+	      case CENTER :
+	          table_offset = (hsize_ - table_width) / 2 - textsize_;
+	          break;
+
+	      case RIGHT :
+	          table_offset = hsize_ - table_width - textsize_;
+	          break;
+	    }
+
+	    column = 0;
+	  }
+
+          if (tolower(buf[0]) == 'h' && isdigit(buf[1]))
+	  {
+	    font  = FL_HELVETICA_BOLD;
+	    fsize = (uchar)(textsize_ + '7' - buf[1]);
+	  }
+	  else if (strcasecmp(buf, "DT") == 0)
+	  {
+	    font  = (uchar)(textfont_ | FL_ITALIC);
+	    fsize = textsize_;
+	  }
+	  else if (strcasecmp(buf, "PRE") == 0)
+	  {
+	    font  = FL_COURIER;
+	    fsize = textsize_;
+	    pre   = 1;
+	  }
+	  else
+	  {
+	    font  = textfont_;
+	    fsize = textsize_;
+	  }
+
+	  pushfont(font, fsize);
+
+          yy = block->y + block->h;
+          hh = 0;
+
+          if ((tolower(buf[0]) == 'h' && isdigit(buf[1])) ||
+	      strcasecmp(buf, "DD") == 0 ||
+	      strcasecmp(buf, "DT") == 0 ||
+	      strcasecmp(buf, "P") == 0)
+            yy += fsize + 2;
+	  else if (strcasecmp(buf, "HR") == 0)
+	  {
+	    hh += 2 * fsize;
+	    yy += fsize;
+	  }
+
+          if (row)
+	    block = add_block(start, xx, yy, block->w, 0);
+	  else
+	    block = add_block(start, xx, yy, hsize_, 0);
+
+	  needspace = 0;
+	  line      = 0;
+
+	  if (strcasecmp(buf, "CENTER") == 0)
+	    newalign = talign = CENTER;
+	  else
+	    newalign = get_align(attrs, talign);
+	}
+	else if (strcasecmp(buf, "/CENTER") == 0 ||
+		 strcasecmp(buf, "/P") == 0 ||
+		 strcasecmp(buf, "/H1") == 0 ||
+		 strcasecmp(buf, "/H2") == 0 ||
+		 strcasecmp(buf, "/H3") == 0 ||
+		 strcasecmp(buf, "/H4") == 0 ||
+		 strcasecmp(buf, "/H5") == 0 ||
+		 strcasecmp(buf, "/H6") == 0 ||
+		 strcasecmp(buf, "/PRE") == 0 ||
+		 strcasecmp(buf, "/UL") == 0 ||
+		 strcasecmp(buf, "/OL") == 0 ||
+		 strcasecmp(buf, "/DL") == 0 ||
+		 strcasecmp(buf, "/TABLE") == 0)
+	{
+          line       = do_align(block, line, xx, newalign, links);
+          xx         = block->x;
+          block->end = ptr;
+
+          if (strcasecmp(buf, "/UL") == 0 ||
+	      strcasecmp(buf, "/OL") == 0 ||
+	      strcasecmp(buf, "/DL") == 0)
+	  {
+	    xx       = margins.pop();
+	    block->h += fsize + 2;
+	  }
+          else if (strcasecmp(buf, "/TABLE") == 0) 
+          {
+	    block->h += fsize + 2;
+            xx       = margins.current();
+          }
+	  else if (strcasecmp(buf, "/PRE") == 0)
+	  {
+	    pre = 0;
+	    hh  = 0;
+	  }
+	  else if (strcasecmp(buf, "/CENTER") == 0)
+	    talign = LEFT;
+
+          popfont(font, fsize);
+
+          while (isspace((*ptr)&255))
+	    ptr ++;
+
+          block->h += hh;
+          yy       += hh;
+
+          if (tolower(buf[2]) == 'l')
+            yy += fsize + 2;
+
+          if (row)
+	    block = add_block(ptr, xx, yy, block->w, 0);
+	  else
+	    block = add_block(ptr, xx, yy, hsize_, 0);
+
+	  needspace = 0;
+	  hh        = 0;
+	  line      = 0;
+	  newalign  = talign;
+	}
+	else if (strcasecmp(buf, "TR") == 0)
+	{
+          block->end = start;
+          line       = do_align(block, line, xx, newalign, links);
+          xx         = block->x;
+          block->h   += hh;
+
+          if (row)
+	  {
+            yy = blocks_[row].y + blocks_[row].h;
+
+	    for (cell = blocks_ + row + 1; cell <= block; cell ++)
+	      if ((cell->y + cell->h) > yy)
+		yy = cell->y + cell->h;
+
+            block = blocks_ + row;
+
+            block->h = yy - block->y + 2;
+
+	    for (i = 0; i < column; i ++)
+	      if (cells[i])
+	      {
+		cell = blocks_ + cells[i];
+		cell->h = block->h;
+	      }
+	  }
+
+          memset(cells, 0, sizeof(cells));
+
+	  yy        = block->y + block->h - 4;
+	  hh        = 0;
+          block     = add_block(start, xx, yy, hsize_, 0);
+	  row       = block - blocks_;
+	  needspace = 0;
+	  column    = 0;
+	  line      = 0;
+
+          rc = get_color(get_attr(attrs, "BGCOLOR", attr, sizeof(attr)), tc);
+	}
+	else if (strcasecmp(buf, "/TR") == 0 && row)
+	{
+          line       = do_align(block, line, xx, newalign, links);
+          block->end = start;
+	  block->h   += hh;
+	  talign     = LEFT;
+
+          xx = blocks_[row].x;
+          yy = blocks_[row].y + blocks_[row].h;
+
+	  for (cell = blocks_ + row + 1; cell <= block; cell ++)
+	    if ((cell->y + cell->h) > yy)
+	      yy = cell->y + cell->h;
+
+          block = blocks_ + row;
+
+          block->h = yy - block->y + 2;
+
+	  for (i = 0; i < column; i ++)
+	    if (cells[i])
+	    {
+	      cell = blocks_ + cells[i];
+	      cell->h = block->h;
+	    }
+
+	  yy        = block->y + block->h /*- 4*/;
+          block     = add_block(start, xx, yy, hsize_, 0);
+	  needspace = 0;
+	  row       = 0;
+	  line      = 0;
+	}
+	else if ((strcasecmp(buf, "TD") == 0 ||
+                  strcasecmp(buf, "TH") == 0) && row)
+	{
+          int	colspan;		// COLSPAN attribute
+
+
+          line       = do_align(block, line, xx, newalign, links);
+          block->end = start;
+	  block->h   += hh;
+
+          if (strcasecmp(buf, "TH") == 0)
+	    font = (uchar)(textfont_ | FL_BOLD);
+	  else
+	    font = textfont_;
+
+          fsize = textsize_;
+
+          xx = blocks_[row].x + fsize + 3 + table_offset;
+	  for (i = 0; i < column; i ++)
+	    xx += columns[i] + 6;
+
+          margins.push(xx - margins.current());
+
+          if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL)
+	    colspan = atoi(attr);
+	  else
+	    colspan = 1;
+
+          for (i = 0, ww = -6; i < colspan; i ++)
+	    ww += columns[column + i] + 6;
+
+          if (block->end == block->start && nblocks_ > 1)
+	  {
+	    nblocks_ --;
+	    block --;
+	  }
+
+	  pushfont(font, fsize);
+
+	  yy        = blocks_[row].y;
+	  hh        = 0;
+          block     = add_block(start, xx, yy, xx + ww, 0, border);
+	  needspace = 0;
+	  line      = 0;
+	  newalign  = get_align(attrs, tolower(buf[1]) == 'h' ? CENTER : LEFT);
+	  talign    = newalign;
+
+          cells[column] = block - blocks_;
+
+	  column += colspan;
+
+          block->bgcolor = get_color(get_attr(attrs, "BGCOLOR", attr,
+	                                      sizeof(attr)), rc);
+	}
+	else if ((strcasecmp(buf, "/TD") == 0 ||
+                  strcasecmp(buf, "/TH") == 0) && row)
+	{
+          line = do_align(block, line, xx, newalign, links);
+          popfont(font, fsize);
+	  xx = margins.pop();
+	  talign = LEFT;
+	}
+	else if (strcasecmp(buf, "FONT") == 0)
+	{
+          if (get_attr(attrs, "FACE", attr, sizeof(attr)) != NULL) {
+	    if (!strncasecmp(attr, "helvetica", 9) ||
+	        !strncasecmp(attr, "arial", 5) ||
+		!strncasecmp(attr, "sans", 4)) font = FL_HELVETICA;
+            else if (!strncasecmp(attr, "times", 5) ||
+	             !strncasecmp(attr, "serif", 5)) font = FL_TIMES;
+            else if (!strncasecmp(attr, "symbol", 6)) font = FL_SYMBOL;
+	    else font = FL_COURIER;
+          }
+
+          if (get_attr(attrs, "SIZE", attr, sizeof(attr)) != NULL) {
+            if (isdigit(attr[0] & 255)) {
+	      // Absolute size
+	      fsize = (int)(textsize_ * pow(1.2, atoi(attr) - 3.0));
+	    } else {
+	      // Relative size
+	      fsize = (int)(fsize * pow(1.2, atoi(attr)));
+	    }
+	  }
+
+          pushfont(font, fsize);
+	}
+	else if (strcasecmp(buf, "/FONT") == 0)
+	  popfont(font, fsize);
+	else if (strcasecmp(buf, "B") == 0 ||
+        	 strcasecmp(buf, "STRONG") == 0)
+	  pushfont(font |= FL_BOLD, fsize);
+	else if (strcasecmp(buf, "I") == 0 ||
+        	 strcasecmp(buf, "EM") == 0)
+	  pushfont(font |= FL_ITALIC, fsize);
+	else if (strcasecmp(buf, "CODE") == 0 ||
+	         strcasecmp(buf, "TT") == 0)
+	  pushfont(font = FL_COURIER, fsize);
+	else if (strcasecmp(buf, "KBD") == 0)
+	  pushfont(font = FL_COURIER_BOLD, fsize);
+	else if (strcasecmp(buf, "VAR") == 0)
+	  pushfont(font = FL_COURIER_ITALIC, fsize);
+	else if (strcasecmp(buf, "/B") == 0 ||
+		 strcasecmp(buf, "/STRONG") == 0 ||
+		 strcasecmp(buf, "/I") == 0 ||
+		 strcasecmp(buf, "/EM") == 0 ||
+		 strcasecmp(buf, "/CODE") == 0 ||
+		 strcasecmp(buf, "/TT") == 0 ||
+		 strcasecmp(buf, "/KBD") == 0 ||
+		 strcasecmp(buf, "/VAR") == 0)
+	  popfont(font, fsize);
+	else if (strcasecmp(buf, "IMG") == 0)
+	{
+	  Fl_Shared_Image	*img = 0;
+	  int		width;
+	  int		height;
+
+
+          get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
+          get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
+	  width  = get_length(wattr);
+	  height = get_length(hattr);
+
+	  if (get_attr(attrs, "SRC", attr, sizeof(attr))) {
+	    img    = get_image(attr, width, height);
+	    width  = img->w();
+	    height = img->h();
+	  }
+
+	  ww = width;
+
+          if (ww > hsize_) {
+	    hsize_ = ww;
+	    done   = 0;
+	    break;
+	  }
+
+	  if (needspace && xx > block->x)
+	    ww += (int)fl_width(' ');
+
+	  if ((xx + ww) > block->w)
+	  {
+	    line     = do_align(block, line, xx, newalign, links);
+	    xx       = block->x;
+	    yy       += hh;
+	    block->h += hh;
+	    hh       = 0;
+	  }
+
+	  if (linkdest[0])
+	    add_link(linkdest, xx, yy - height, ww, height);
+
+	  xx += ww;
+	  if ((height + 2) > hh)
+	    hh = height + 2;
+
+	  needspace = 0;
+	}
+      }
+      else if (*ptr == '\n' && pre)
+      {
+	if (linkdest[0])
+	  add_link(linkdest, xx, yy - hh, ww, hh);
+
+        if (xx > hsize_) {
+	  hsize_ = xx;
+          done   = 0;
+	  break;
+	}
+
+	line      = do_align(block, line, xx, newalign, links);
+	xx        = block->x;
+	yy        += hh;
+	block->h  += hh;
+	needspace = 0;
+	ptr ++;
+      }
+      else if (isspace((*ptr)&255))
+      {
+	needspace = 1;
+
+	ptr ++;
+      }
+      else if (*ptr == '&' && s < (buf + sizeof(buf) - 1))
+      {
+	ptr ++;
+
+        int qch = quote_char(ptr);
+
+	if (qch < 0)
+	  *s++ = '&';
+	else {
+	  *s++ = qch;
+	  ptr = strchr(ptr, ';') + 1;
+	}
+
+	if ((fsize + 2) > hh)
+          hh = fsize + 2;
+      }
+      else
+      {
+	if (s < (buf + sizeof(buf) - 1))
+          *s++ = *ptr++;
+	else
+          ptr ++;
+
+	if ((fsize + 2) > hh)
+          hh = fsize + 2;
+      }
+    }
+
+    if (s > buf && !head)
+    {
+      *s = '\0';
+      ww = (int)fl_width(buf);
+
+  //    printf("line = %d, xx = %d, ww = %d, block->x = %d, block->w = %d\n",
+  //	   line, xx, ww, block->x, block->w);
+
+      if (ww > hsize_) {
+	hsize_ = ww;
+	done   = 0;
+	break;
+      }
+
+      if (needspace && xx > block->x)
+	ww += (int)fl_width(' ');
+
+      if ((xx + ww) > block->w)
+      {
+	line     = do_align(block, line, xx, newalign, links);
+	xx       = block->x;
+	yy       += hh;
+	block->h += hh;
+	hh       = 0;
+      }
+
+      if (linkdest[0])
+	add_link(linkdest, xx, yy - fsize, ww, fsize);
+
+      xx += ww;
+    }
+
+    do_align(block, line, xx, newalign, links);
+
+    block->end = ptr;
+    size_      = yy + hh;
+  }
+
+//  printf("margins.depth_=%d\n", margins.depth_);
+
+  if (ntargets_ > 1)
+    qsort(targets_, ntargets_, sizeof(Fl_Help_Target),
+          (compare_func_t)compare_targets);
+
+  int dx = Fl::box_dw(b) - Fl::box_dx(b);
+  int dy = Fl::box_dh(b) - Fl::box_dy(b);
+  int ss = Fl::scrollbar_size();
+  int dw = Fl::box_dw(b) + ss;
+  int dh = Fl::box_dh(b);
+
+  if (hsize_ > (w() - dw)) {
+    hscrollbar_.show();
+
+    dh += ss;
+
+    if (size_ < (h() - dh)) {
+      scrollbar_.hide();
+      hscrollbar_.resize(x() + Fl::box_dx(b), y() + h() - ss - dy,
+                         w() - Fl::box_dw(b), ss);
+    } else {
+      scrollbar_.show();
+      scrollbar_.resize(x() + w() - ss - dx, y() + Fl::box_dy(b),
+                        ss, h() - ss - Fl::box_dh(b));
+      hscrollbar_.resize(x() + Fl::box_dx(b), y() + h() - ss - dy,
+                         w() - ss - Fl::box_dw(b), ss);
+    }
+  } else {
+    hscrollbar_.hide();
+
+    if (size_ < (h() - dh)) scrollbar_.hide();
+    else {
+      scrollbar_.resize(x() + w() - ss - dx, y() + Fl::box_dy(b),
+                        ss, h() - Fl::box_dh(b));
+      scrollbar_.show();
+    }
+  }
+
+  // Reset scrolling if it needs to be...
+  if (scrollbar_.visible()) {
+    int temph = h() - Fl::box_dh(b);
+    if (hscrollbar_.visible()) temph -= ss;
+    if ((topline_ + temph) > size_) topline(size_ - temph);
+    else topline(topline_);
+  } else topline(0);
+
+  if (hscrollbar_.visible()) {
+    int tempw = w() - ss - Fl::box_dw(b);
+    if ((leftline_ + tempw) > hsize_) leftline(hsize_ - tempw);
+    else leftline(leftline_);
+  } else leftline(0);
+}
+
+
+//
+// 'Fl_Help_View::format_table()' - Format a table...
+//
+
+void
+Fl_Help_View::format_table(int        *table_width,	// O - Total table width
+                           int        *columns,		// O - Column widths
+	                   const char *table)		// I - Pointer to start of table
+{
+  int		column,					// Current column
+		num_columns,				// Number of columns
+		colspan,				// COLSPAN attribute
+		width,					// Current width
+		temp_width,				// Temporary width
+		max_width,				// Maximum width
+		incell,					// In a table cell?
+		pre,					// 
 text?
+		needspace;				// Need whitespace?
+  char		*s,					// Pointer into buffer
+		buf[1024],				// Text buffer
+		attr[1024],				// Other attribute
+		wattr[1024],				// WIDTH attribute
+		hattr[1024];				// HEIGHT attribute
+  const char	*ptr,					// Pointer into table
+		*attrs,					// Pointer to attributes
+		*start;					// Start of element
+  int		minwidths[MAX_COLUMNS];			// Minimum widths for each column
+  unsigned char	font, fsize;				// Current font and size
+
+
+  // Clear widths...
+  *table_width = 0;
+  for (column = 0; column < MAX_COLUMNS; column ++)
+  {
+    columns[column]   = 0;
+    minwidths[column] = 0;
+  }
+
+  num_columns = 0;
+  colspan     = 0;
+  max_width   = 0;
+  pre         = 0;
+  needspace   = 0;
+  font        = fonts_[nfonts_][0];
+  fsize       = fonts_[nfonts_][1];
+
+  // Scan the table...
+  for (ptr = table, column = -1, width = 0, s = buf, incell = 0; *ptr;)
+  {
+    if ((*ptr == '<' || isspace((*ptr)&255)) && s > buf && incell)
+    {
+      // Check width...
+      if (needspace)
+      {
+        *s++      = ' ';
+	needspace = 0;
+      }
+
+      *s         = '\0';
+      temp_width = (int)fl_width(buf);
+      s          = buf;
+
+      if (temp_width > minwidths[column])
+        minwidths[column] = temp_width;
+
+      width += temp_width;
+
+      if (width > max_width)
+        max_width = width;
+    }
+
+    if (*ptr == '<')
+    {
+      start = ptr;
+
+      for (s = buf, ptr ++; *ptr && *ptr != '>' && !isspace((*ptr)&255);)
+        if (s < (buf + sizeof(buf) - 1))
+          *s++ = *ptr++;
+	else
+	  ptr ++;
+
+      *s = '\0';
+      s = buf;
+
+      attrs = ptr;
+      while (*ptr && *ptr != '>')
+        ptr ++;
+
+      if (*ptr == '>')
+        ptr ++;
+
+      if (strcasecmp(buf, "BR") == 0 ||
+	  strcasecmp(buf, "HR") == 0)
+      {
+        width     = 0;
+	needspace = 0;
+      }
+      else if (strcasecmp(buf, "TABLE") == 0 && start > table)
+        break;
+      else if (strcasecmp(buf, "CENTER") == 0 ||
+               strcasecmp(buf, "P") == 0 ||
+               strcasecmp(buf, "H1") == 0 ||
+	       strcasecmp(buf, "H2") == 0 ||
+	       strcasecmp(buf, "H3") == 0 ||
+	       strcasecmp(buf, "H4") == 0 ||
+	       strcasecmp(buf, "H5") == 0 ||
+	       strcasecmp(buf, "H6") == 0 ||
+	       strcasecmp(buf, "UL") == 0 ||
+	       strcasecmp(buf, "OL") == 0 ||
+	       strcasecmp(buf, "DL") == 0 ||
+	       strcasecmp(buf, "LI") == 0 ||
+	       strcasecmp(buf, "DD") == 0 ||
+	       strcasecmp(buf, "DT") == 0 ||
+	       strcasecmp(buf, "PRE") == 0)
+      {
+        width     = 0;
+	needspace = 0;
+
+        if (tolower(buf[0]) == 'h' && isdigit(buf[1]))
+	{
+	  font  = FL_HELVETICA_BOLD;
+	  fsize = (uchar)(textsize_ + '7' - buf[1]);
+	}
+	else if (strcasecmp(buf, "DT") == 0)
+	{
+	  font  = (uchar)(textfont_ | FL_ITALIC);
+	  fsize = textsize_;
+	}
+	else if (strcasecmp(buf, "PRE") == 0)
+	{
+	  font  = FL_COURIER;
+	  fsize = textsize_;
+	  pre   = 1;
+	}
+	else if (strcasecmp(buf, "LI") == 0)
+	{
+	  width  += 4 * fsize;
+	  font   = textfont_;
+	  fsize  = textsize_;
+	}
+	else
+	{
+	  font  = textfont_;
+	  fsize = textsize_;
+	}
+
+	pushfont(font, fsize);
+      }
+      else if (strcasecmp(buf, "/CENTER") == 0 ||
+	       strcasecmp(buf, "/P") == 0 ||
+	       strcasecmp(buf, "/H1") == 0 ||
+	       strcasecmp(buf, "/H2") == 0 ||
+	       strcasecmp(buf, "/H3") == 0 ||
+	       strcasecmp(buf, "/H4") == 0 ||
+	       strcasecmp(buf, "/H5") == 0 ||
+	       strcasecmp(buf, "/H6") == 0 ||
+	       strcasecmp(buf, "/PRE") == 0 ||
+	       strcasecmp(buf, "/UL") == 0 ||
+	       strcasecmp(buf, "/OL") == 0 ||
+	       strcasecmp(buf, "/DL") == 0)
+      {
+        width     = 0;
+	needspace = 0;
+
+        popfont(font, fsize);
+      }
+      else if (strcasecmp(buf, "TR") == 0 || strcasecmp(buf, "/TR") == 0 ||
+               strcasecmp(buf, "/TABLE") == 0)
+      {
+//        printf("%s column = %d, colspan = %d, num_columns = %d\n",
+//	       buf, column, colspan, num_columns);
+
+        if (column >= 0)
+	{
+	  // This is a hack to support COLSPAN...
+	  max_width /= colspan;
+
+	  while (colspan > 0)
+	  {
+	    if (max_width > columns[column])
+	      columns[column] = max_width;
+
+	    column ++;
+	    colspan --;
+	  }
+	}
+
+	if (strcasecmp(buf, "/TABLE") == 0)
+	  break;
+
+	needspace = 0;
+	column    = -1;
+	width     = 0;
+	max_width = 0;
+	incell    = 0;
+      }
+      else if (strcasecmp(buf, "TD") == 0 ||
+               strcasecmp(buf, "TH") == 0)
+      {
+//        printf("BEFORE column = %d, colspan = %d, num_columns = %d\n",
+//	       column, colspan, num_columns);
+
+        if (column >= 0)
+	{
+	  // This is a hack to support COLSPAN...
+	  max_width /= colspan;
+
+	  while (colspan > 0)
+	  {
+	    if (max_width > columns[column])
+	      columns[column] = max_width;
+
+	    column ++;
+	    colspan --;
+	  }
+	}
+	else
+	  column ++;
+
+        if (get_attr(attrs, "COLSPAN", attr, sizeof(attr)) != NULL)
+	  colspan = atoi(attr);
+	else
+	  colspan = 1;
+
+//        printf("AFTER column = %d, colspan = %d, num_columns = %d\n",
+//	       column, colspan, num_columns);
+
+        if ((column + colspan) >= num_columns)
+	  num_columns = column + colspan;
+
+	needspace = 0;
+	width     = 0;
+	incell    = 1;
+
+        if (strcasecmp(buf, "TH") == 0)
+	  font = (uchar)(textfont_ | FL_BOLD);
+	else
+	  font = textfont_;
+
+        fsize = textsize_;
+
+	pushfont(font, fsize);
+
+        if (get_attr(attrs, "WIDTH", attr, sizeof(attr)) != NULL)
+	  max_width = get_length(attr);
+	else
+	  max_width = 0;
+
+//        printf("max_width = %d\n", max_width);
+      }
+      else if (strcasecmp(buf, "/TD") == 0 ||
+               strcasecmp(buf, "/TH") == 0)
+      {
+	incell = 0;
+        popfont(font, fsize);
+      }
+      else if (strcasecmp(buf, "B") == 0 ||
+               strcasecmp(buf, "STRONG") == 0)
+	pushfont(font |= FL_BOLD, fsize);
+      else if (strcasecmp(buf, "I") == 0 ||
+               strcasecmp(buf, "EM") == 0)
+	pushfont(font |= FL_ITALIC, fsize);
+      else if (strcasecmp(buf, "CODE") == 0 ||
+               strcasecmp(buf, "TT") == 0)
+	pushfont(font = FL_COURIER, fsize);
+      else if (strcasecmp(buf, "KBD") == 0)
+	pushfont(font = FL_COURIER_BOLD, fsize);
+      else if (strcasecmp(buf, "VAR") == 0)
+	pushfont(font = FL_COURIER_ITALIC, fsize);
+      else if (strcasecmp(buf, "/B") == 0 ||
+	       strcasecmp(buf, "/STRONG") == 0 ||
+	       strcasecmp(buf, "/I") == 0 ||
+	       strcasecmp(buf, "/EM") == 0 ||
+	       strcasecmp(buf, "/CODE") == 0 ||
+	       strcasecmp(buf, "/TT") == 0 ||
+	       strcasecmp(buf, "/KBD") == 0 ||
+	       strcasecmp(buf, "/VAR") == 0)
+	popfont(font, fsize);
+      else if (strcasecmp(buf, "IMG") == 0 && incell)
+      {
+	Fl_Shared_Image	*img = 0;
+	int		iwidth, iheight;
+
+
+        get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
+        get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
+	iwidth  = get_length(wattr);
+	iheight = get_length(hattr);
+
+        if (get_attr(attrs, "SRC", attr, sizeof(attr))) {
+	  img     = get_image(attr, iwidth, iheight);
+	  iwidth  = img->w();
+	  iheight = img->h();
+	}
+
+	if (iwidth > minwidths[column])
+          minwidths[column] = iwidth;
+
+        width += iwidth;
+	if (needspace)
+	  width += (int)fl_width(' ');
+
+	if (width > max_width)
+          max_width = width;
+
+	needspace = 0;
+      }
+    }
+    else if (*ptr == '\n' && pre)
+    {
+      width     = 0;
+      needspace = 0;
+      ptr ++;
+    }
+    else if (isspace((*ptr)&255))
+    {
+      needspace = 1;
+
+      ptr ++;
+    }
+    else if (*ptr == '&' && s < (buf + sizeof(buf) - 1))
+    {
+      ptr ++;
+
+      int qch = quote_char(ptr);
+
+      if (qch < 0)
+	*s++ = '&';
+      else {
+	*s++ = qch;
+	ptr = strchr(ptr, ';') + 1;
+      }
+    }
+    else
+    {
+      if (s < (buf + sizeof(buf) - 1))
+        *s++ = *ptr++;
+      else
+        ptr ++;
+    }
+  }
+
+  // Now that we have scanned the entire table, adjust the table and
+  // cell widths to fit on the screen...
+  if (get_attr(table + 6, "WIDTH", attr, sizeof(attr)))
+    *table_width = get_length(attr);
+  else
+    *table_width = 0;
+
+#ifdef DEBUG
+  printf("num_columns = %d, table_width = %d\n", num_columns, *table_width);
+#endif // DEBUG
+
+  if (num_columns == 0)
+    return;
+
+  // Add up the widths...
+  for (column = 0, width = 0; column < num_columns; column ++)
+    width += columns[column];
+
+#ifdef DEBUG
+  printf("width = %d, w() = %d\n", width, w());
+  for (column = 0; column < num_columns; column ++)
+    printf("    columns[%d] = %d, minwidths[%d] = %d\n", column, columns[column],
+           column, minwidths[column]);
+#endif // DEBUG
+
+  // Adjust the width if needed...
+  int scale_width = *table_width;
+
+  if (scale_width == 0) {
+    if (width > (hsize_ - Fl::scrollbar_size())) scale_width = hsize_ - Fl::scrollbar_size();
+    else scale_width = width;
+  }
+
+  if (width < scale_width) {
+#ifdef DEBUG
+    printf("Scaling table up to %d from %d...\n", scale_width, width);
+#endif // DEBUG
+
+    *table_width = 0;
+
+    scale_width = (scale_width - width) / num_columns;
+
+#ifdef DEBUG
+    printf("adjusted scale_width = %d\n", scale_width);
+#endif // DEBUG
+
+    for (column = 0; column < num_columns; column ++) {
+      columns[column] += scale_width;
+
+      (*table_width) += columns[column];
+    }
+  }
+  else if (width > scale_width) {
+#ifdef DEBUG
+    printf("Scaling table down to %d from %d...\n", scale_width, width);
+#endif // DEBUG
+
+    for (column = 0; column < num_columns; column ++) {
+      width       -= minwidths[column];
+      scale_width -= minwidths[column];
+    }
+
+#ifdef DEBUG
+    printf("adjusted width = %d, scale_width = %d\n", width, scale_width);
+#endif // DEBUG
+
+    if (width > 0) {
+      for (column = 0; column < num_columns; column ++) {
+	columns[column] -= minwidths[column];
+	columns[column] = scale_width * columns[column] / width;
+	columns[column] += minwidths[column];
+      }
+    }
+
+    *table_width = 0;
+    for (column = 0; column < num_columns; column ++) {
+      (*table_width) += columns[column];
+    }
+  }
+  else if (*table_width == 0)
+    *table_width = width;
+
+#ifdef DEBUG
+  printf("FINAL table_width = %d\n", *table_width);
+  for (column = 0; column < num_columns; column ++)
+    printf("    columns[%d] = %d\n", column, columns[column]);
+#endif // DEBUG
+}
+
+
+//
+// 'Fl_Help_View::free_data()' - Free memory used for the document.
+//
+
+void
+Fl_Help_View::free_data() {
+  // Release all images...
+  if (value_) {
+    const char	*ptr,		// Pointer into block
+		*attrs;		// Pointer to start of element attributes
+    char	*s,		// Pointer into buffer
+		buf[1024],	// Text buffer
+		attr[1024],	// Attribute buffer
+		wattr[1024],	// Width attribute buffer
+		hattr[1024];	// Height attribute buffer
+
+    for (ptr = value_; *ptr;)
+    {
+      if (*ptr == '<')
+      {
+	ptr ++;
+
+        if (strncmp(ptr, "!--", 3) == 0)
+	{
+	  // Comment...
+	  ptr += 3;
+	  if ((ptr = strstr(ptr, "-->")) != NULL)
+	  {
+	    ptr += 3;
+	    continue;
+	  }
+	  else
+	    break;
+	}
+
+        s = buf;
+
+	while (*ptr && *ptr != '>' && !isspace((*ptr)&255))
+          if (s < (buf + sizeof(buf) - 1))
+            *s++ = *ptr++;
+	  else
+	    ptr ++;
+
+	*s = '\0';
+
+	attrs = ptr;
+	while (*ptr && *ptr != '>')
+          ptr ++;
+
+	if (*ptr == '>')
+          ptr ++;
+
+	if (strcasecmp(buf, "IMG") == 0)
+	{
+	  Fl_Shared_Image	*img;
+	  int		width;
+	  int		height;
+
+          get_attr(attrs, "WIDTH", wattr, sizeof(wattr));
+          get_attr(attrs, "HEIGHT", hattr, sizeof(hattr));
+	  width  = get_length(wattr);
+	  height = get_length(hattr);
+
+	  if (get_attr(attrs, "SRC", attr, sizeof(attr))) {
+	    // Get and release the image to free it from memory...
+	    img = get_image(attr, width, height);
+	    if ((void*)img != &broken_image) {
+	      img->release();
+	    }
+	  }
+	}
+      }
+      else
+        ptr ++;
+    }
+
+    free((void *)value_);
+    value_ = 0;
+  }
+
+  // Free all of the arrays...
+  if (nblocks_) {
+    free(blocks_);
+
+    ablocks_ = 0;
+    nblocks_ = 0;
+    blocks_  = 0;
+  }
+
+  if (nlinks_) {
+    free(links_);
+
+    alinks_ = 0;
+    nlinks_ = 0;
+    links_  = 0;
+  }
+
+  if (ntargets_) {
+    free(targets_);
+
+    atargets_ = 0;
+    ntargets_ = 0;
+    targets_  = 0;
+  }
+}
+
+//
+// 'Fl_Help_View::get_align()' - Get an alignment attribute.
+//
+
+int					// O - Alignment
+Fl_Help_View::get_align(const char *p,	// I - Pointer to start of attrs
+                        int        a)	// I - Default alignment
+{
+  char	buf[255];			// Alignment value
+
+
+  if (get_attr(p, "ALIGN", buf, sizeof(buf)) == NULL)
+    return (a);
+
+  if (strcasecmp(buf, "CENTER") == 0)
+    return (CENTER);
+  else if (strcasecmp(buf, "RIGHT") == 0)
+    return (RIGHT);
+  else
+    return (LEFT);
+}
+
+
+//
+// 'Fl_Help_View::get_attr()' - Get an attribute value from the string.
+//
+
+const char *					// O - Pointer to buf or NULL
+Fl_Help_View::get_attr(const char *p,		// I - Pointer to start of attributes
+                      const char *n,		// I - Name of attribute
+		      char       *buf,		// O - Buffer for attribute value
+		      int        bufsize)	// I - Size of buffer
+{
+  char	name[255],				// Name from string
+	*ptr,					// Pointer into name or value
+	quote;					// Quote
+
+
+  buf[0] = '\0';
+
+  while (*p && *p != '>')
+  {
+    while (isspace((*p)&255))
+      p ++;
+
+    if (*p == '>' || !*p)
+      return (NULL);
+
+    for (ptr = name; *p && !isspace((*p)&255) && *p != '=' && *p != '>';)
+      if (ptr < (name + sizeof(name) - 1))
+        *ptr++ = *p++;
+      else
+        p ++;
+
+    *ptr = '\0';
+
+    if (isspace((*p)&255) || !*p || *p == '>')
+      buf[0] = '\0';
+    else
+    {
+      if (*p == '=')
+        p ++;
+
+      for (ptr = buf; *p && !isspace((*p)&255) && *p != '>';)
+        if (*p == '\'' || *p == '\"')
+	{
+	  quote = *p++;
+
+	  while (*p && *p != quote)
+	    if ((ptr - buf + 1) < bufsize)
+	      *ptr++ = *p++;
+	    else
+	      p ++;
+
+          if (*p == quote)
+	    p ++;
+	}
+	else if ((ptr - buf + 1) < bufsize)
+	  *ptr++ = *p++;
+	else
+	  p ++;
+
+      *ptr = '\0';
+    }
+
+    if (strcasecmp(n, name) == 0)
+      return (buf);
+    else
+      buf[0] = '\0';
+
+    if (*p == '>')
+      return (NULL);
+  }
+
+  return (NULL);
+}
+
+
+//
+// 'Fl_Help_View::get_color()' - Get a color attribute.
+//
+
+Fl_Color				// O - Color value
+Fl_Help_View::get_color(const char *n,	// I - Color name
+                        Fl_Color   c)	// I - Default color value
+{
+  int	i;				// Looping var
+  int	rgb, r, g, b;			// RGB values
+  static const struct {			// Color name table
+    const char *name;
+    int r, g, b;
+  }	colors[] = {
+    { "black",		0x00, 0x00, 0x00 },
+    { "red",		0xff, 0x00, 0x00 },
+    { "green",		0x00, 0x80, 0x00 },
+    { "yellow",		0xff, 0xff, 0x00 },
+    { "blue",		0x00, 0x00, 0xff },
+    { "magenta",	0xff, 0x00, 0xff },
+    { "fuchsia",	0xff, 0x00, 0xff },
+    { "cyan",		0x00, 0xff, 0xff },
+    { "aqua",		0x00, 0xff, 0xff },
+    { "white",		0xff, 0xff, 0xff },
+    { "gray",		0x80, 0x80, 0x80 },
+    { "grey",		0x80, 0x80, 0x80 },
+    { "lime",		0x00, 0xff, 0x00 },
+    { "maroon",		0x80, 0x00, 0x00 },
+    { "navy",		0x00, 0x00, 0x80 },
+    { "olive",		0x80, 0x80, 0x00 },
+    { "purple",		0x80, 0x00, 0x80 },
+    { "silver",		0xc0, 0xc0, 0xc0 },
+    { "teal",		0x00, 0x80, 0x80 }
+  };
+
+
+  if (!n || !n[0]) return c;
+
+  if (n[0] == '#') {
+    // Do hex color lookup
+    rgb = strtol(n + 1, NULL, 16);
+
+    if (strlen(n) > 4) {
+      r = rgb >> 16;
+      g = (rgb >> 8) & 255;
+      b = rgb & 255;
+    } else {
+      r = (rgb >> 8) * 17;
+      g = ((rgb >> 4) & 15) * 17;
+      b = (rgb & 15) * 17;
+    }
+    return (fl_rgb_color((uchar)r, (uchar)g, (uchar)b));
+  } else {
+    for (i = 0; i < (int)(sizeof(colors) / sizeof(colors[0])); i ++)
+      if (!strcasecmp(n, colors[i].name)) {
+        return fl_rgb_color(colors[i].r, colors[i].g, colors[i].b);
+      }
+    return c;
+  }
+}
+
+
+//
+// 'Fl_Help_View::get_image()' - Get an inline image.
+//
+
+/** Gets an inline image.
+
+  The image reference count is maintained accordingly, such that
+  the image can be released exactly once when the document is closed.
+
+  \return a pointer to a cached Fl_Shared_Image, if the image can be loaded,
+  	  otherwise a pointer to an internal Fl_Pixmap (broken_image).
+
+  \todo Fl_Help_View::get_image() returns a pointer to the internal
+  Fl_Pixmap broken_image, but this is _not_ compatible with the
+  return type Fl_Shared_Image (release() must not be called).
+*/
+
+/* Implementation note: (A.S. Apr 05, 2009)
+
+  Fl_Help_View::get_image() uses a static global flag (initial_load)
+  to determine, if it is called from the initial loading of a document
+  (load() or value()), or from resize() or draw().
+
+  A better solution would be to manage all loaded images in an own
+  structure like Fl_Help_Target (Fl_Help_Image ?) to avoid using this
+  global flag, but this would break the ABI !
+
+  This should be fixed in FLTK 1.3 !
+
+
+  If initial_load is true, then Fl_Shared_Image::get() is called to
+  load the image, and the reference count of the shared image is
+  increased by one.
+
+  If initial_load is false, then Fl_Shared_Image::find() is called to
+  load the image, and the image is released immediately. This avoids
+  increasing the reference count when calling get_image() from draw()
+  or resize().
+
+  Calling Fl_Shared_Image::find() instead of Fl_Shared_Image::get() avoids
+  doing unnecessary i/o for "broken images" within each resize/redraw.
+
+  Each image must be released exactly once in the destructor or before
+  a new document is loaded: see free_data().
+*/
+
+Fl_Shared_Image *
+Fl_Help_View::get_image(const char *name, int W, int H) {
+  const char	*localname;		// Local filename
+  char		dir[1024];		// Current directory
+  char		temp[1024],		// Temporary filename
+		*tempptr;		// Pointer into temporary name
+  Fl_Shared_Image *ip;			// Image pointer...
+
+  // See if the image can be found...
+  if (strchr(directory_, ':') != NULL && strchr(name, ':') == NULL) {
+    if (name[0] == '/') {
+      strlcpy(temp, directory_, sizeof(temp));
+
+      if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL) {
+        strlcpy(tempptr, name, sizeof(temp) - (tempptr - temp));
+      } else {
+        strlcat(temp, name, sizeof(temp));
+      }
+    } else {
+      snprintf(temp, sizeof(temp), "%s/%s", directory_, name);
+    }
+
+    if (link_) localname = (*link_)(this, temp);
+    else localname = temp;
+  } else if (name[0] != '/' && strchr(name, ':') == NULL) {
+    if (directory_[0]) snprintf(temp, sizeof(temp), "%s/%s", directory_, name);
+    else {
+      getcwd(dir, sizeof(dir));
+      snprintf(temp, sizeof(temp), "file:%s/%s", dir, name);
+    }
+
+    if (link_) localname = (*link_)(this, temp);
+    else localname = temp;
+  } else if (link_) localname = (*link_)(this, name);
+  else localname = name;
+
+  if (!localname) return 0;
+
+  if (strncmp(localname, "file:", 5) == 0) localname += 5;
+
+  if (initial_load) {
+    if ((ip = Fl_Shared_Image::get(localname, W, H)) == NULL) {
+      ip = (Fl_Shared_Image *)&broken_image;
+    }
+  } else { // draw or resize
+    if ((ip = Fl_Shared_Image::find(localname, W, H)) == NULL) {
+      ip = (Fl_Shared_Image *)&broken_image;
+    } else {
+      ip->release();
+    }
+  }
+
+  return ip;
+}
+
+
+//
+// 'Fl_Help_View::get_length()' - Get a length value, either absolute or %.
+//
+
+int
+Fl_Help_View::get_length(const char *l) {	// I - Value
+  int	val;					// Integer value
+
+  if (!l[0]) return 0;
+
+  val = atoi(l);
+  if (l[strlen(l) - 1] == '%') {
+    if (val > 100) val = 100;
+    else if (val < 0) val = 0;
+
+    val = val * (hsize_ - Fl::scrollbar_size()) / 100;
+  }
+
+  return val;
+}
+
+
+Fl_Help_Link *Fl_Help_View::find_link(int xx, int yy)
+{
+  int		i;
+  Fl_Help_Link	*linkp;
+  for (i = nlinks_, linkp = links_; i > 0; i --, linkp ++) {
+    if (xx >= linkp->x && xx < linkp->w &&
+        yy >= linkp->y && yy < linkp->h)
+      break;
+  }
+  return i ? linkp : 0L;
+}
+
+void Fl_Help_View::follow_link(Fl_Help_Link *linkp)
+{
+  char		target[32];	// Current target
+
+  clear_selection();
+
+  strlcpy(target, linkp->name, sizeof(target));
+
+  set_changed();
+
+  if (strcmp(linkp->filename, filename_) != 0 && linkp->filename[0])
+  {
+    char	dir[1024];	// Current directory
+    char	temp[1024],	// Temporary filename
+	      *tempptr;	// Pointer into temporary filename
+
+
+    if (strchr(directory_, ':') != NULL &&
+        strchr(linkp->filename, ':') == NULL)
+    {
+      if (linkp->filename[0] == '/')
+      {
+        strlcpy(temp, directory_, sizeof(temp));
+        if ((tempptr = strrchr(strchr(directory_, ':') + 3, '/')) != NULL)
+	  strlcpy(tempptr, linkp->filename, sizeof(temp));
+	else
+	  strlcat(temp, linkp->filename, sizeof(temp));
+      }
+      else
+	snprintf(temp, sizeof(temp), "%s/%s", directory_, linkp->filename);
+    }
+    else if (linkp->filename[0] != '/' && strchr(linkp->filename, ':') == NULL)
+    {
+      if (directory_[0])
+	snprintf(temp, sizeof(temp), "%s/%s", directory_, linkp->filename);
+      else
+      {
+	getcwd(dir, sizeof(dir));
+	snprintf(temp, sizeof(temp), "file:%s/%s", dir, linkp->filename);
+      }
+    }
+    else
+      strlcpy(temp, linkp->filename, sizeof(temp));
+
+    if (linkp->name[0])
+      snprintf(temp + strlen(temp), sizeof(temp) - strlen(temp), "#%s",
+	       linkp->name);
+
+    load(temp);
+  }
+  else if (target[0])
+    topline(target);
+  else
+    topline(0);
+
+  leftline(0);
+}
+
+void Fl_Help_View::clear_selection()
+{
+  if (current_view==this)
+    clear_global_selection();
+}
+
+void Fl_Help_View::select_all()
+{
+  clear_global_selection();
+  if (!value_) return;
+  current_view = this;
+  selection_drag_last = selection_last = strlen(value_);
+  selected = 1;
+}
+
+void Fl_Help_View::clear_global_selection()
+{
+  if (selected) redraw();
+  selection_push_first = selection_push_last = 0;
+  selection_drag_first = selection_drag_last = 0;
+  selection_first = selection_last = 0;
+  selected = 0;
+}
+
+char Fl_Help_View::begin_selection()
+{
+  clear_global_selection();
+
+  if (!fl_help_view_buffer) fl_help_view_buffer = fl_create_offscreen(1, 1);
+
+  mouse_x = Fl::event_x();
+  mouse_y = Fl::event_y();
+  draw_mode = 1;
+
+    current_view = this;
+    fl_begin_offscreen(fl_help_view_buffer);
+    draw();
+    fl_end_offscreen();
+
+  draw_mode = 0;
+
+  if (selection_push_last) return 1;
+  else return 0;
+}
+
+char Fl_Help_View::extend_selection()
+{
+  if (Fl::event_is_click())
+    return 0;
+
+//  printf("old selection_first=%d, selection_last=%d\n",
+//         selection_first, selection_last);
+
+  int sf = selection_first, sl = selection_last;
+
+  selected = 1;
+  mouse_x = Fl::event_x();
+  mouse_y = Fl::event_y();
+  draw_mode = 2;
+
+    fl_begin_offscreen(fl_help_view_buffer);
+    draw();
+    fl_end_offscreen();
+
+  draw_mode = 0;
+
+  if (selection_push_first < selection_drag_first) {
+    selection_first = selection_push_first;
+  } else {
+    selection_first = selection_drag_first;
+  }
+
+  if (selection_push_last > selection_drag_last) {
+    selection_last = selection_push_last;
+  } else {
+    selection_last = selection_drag_last;
+  }
+
+//  printf("new selection_first=%d, selection_last=%d\n",
+//         selection_first, selection_last);
+
+  if (sf!=selection_first || sl!=selection_last) {
+//    puts("REDRAW!!!\n");
+    return 1;
+  } else {
+//    puts("");
+    return 0;
+  }
+}
+
+// convert a command with up to four letters into an unsigned int
+static unsigned int command(const char *cmd)
+{
+  unsigned int ret = (tolower(cmd[0])<<24);
+  char c = cmd[1];
+  if (c=='>' || c==' ' || c==0) return ret;
+  ret |= (tolower(c)<<16);
+  c = cmd[2];
+  if (c=='>' || c==' ' || c==0) return ret;
+  ret |= (tolower(c)<<8);
+  c = cmd[3];
+  if (c=='>' || c==' ' || c==0) return ret;
+  ret |= tolower(c);
+  c = cmd[4];
+  if (c=='>' || c==' ' || c==0) return ret;
+  return 0;
+}
+
+#define CMD(a, b, c, d) ((a<<24)|(b<<16)|(c<<8)|d)
+
+void Fl_Help_View::end_selection(int clipboard) 
+{
+  if (!selected || current_view!=this) 
+    return;
+  // convert the select part of our html text into some kind of somewhat readable ASCII
+  // and store it in the selection buffer
+  char p = 0, pre = 0;;
+  int len = strlen(value_);
+  char *txt = (char*)malloc(len+1), *d = txt;
+  const char *s = value_, *cmd, *src;
+  for (;;) {
+    char c = *s++;
+    if (c==0) break;
+    if (c=='<') { // begin of some html command. Skip until we find a '>'
+      cmd = s;
+      for (;;) {
+        c = *s++;
+        if (c==0 || c=='>') break;
+      }
+      if (c==0) break;
+      // do something with this command... .
+      // the replacement string must not be longer that the command itself plus '<' and '>'
+      src = 0;
+      switch (command(cmd)) {
+        case CMD('p','r','e', 0 ): pre = 1; break;
+        case CMD('/','p','r','e'): pre = 0; break;
+        case CMD('t','d', 0 , 0 ):
+        case CMD('p', 0 , 0 , 0 ):
+        case CMD('/','p', 0 , 0 ):
+        case CMD('b','r', 0 , 0 ): src = "\n"; break;
+        case CMD('l','i', 0 , 0 ): src = "\n * "; break;
+        case CMD('/','h','1', 0 ):
+        case CMD('/','h','2', 0 ):
+        case CMD('/','h','3', 0 ):
+        case CMD('/','h','4', 0 ):
+        case CMD('/','h','5', 0 ):
+        case CMD('/','h','6', 0 ): src = "\n\n"; break;
+        case CMD('t','r', 0 , 0 ):
+        case CMD('h','1', 0 , 0 ):
+        case CMD('h','2', 0 , 0 ):
+        case CMD('h','3', 0 , 0 ):
+        case CMD('h','4', 0 , 0 ):
+        case CMD('h','5', 0 , 0 ):
+        case CMD('h','6', 0 , 0 ): src = "\n\n"; break;
+        case CMD('d','t', 0 , 0 ): src = "\n "; break;
+        case CMD('d','d', 0 , 0 ): src = "\n - "; break;
+      }
+      int n = s-value_;
+      if (src && n>selection_first && n<=selection_last) {
+        while (*src) {
+          *d++ = *src++;
+        }
+        c = src[-1];
+        p = isspace(c&255) ? ' ' : c;
+      }
+      continue;
+    }
+    if (c=='&') { // special characters
+      int xx = quote_char(s);
+      if (xx>=0) {
+        c = (char)xx;
+        for (;;) {
+          char cc = *s++;
+          if (!cc || cc==';') break;
+        }
+      }
+    }
+    int n = s-value_;
+    if (n>selection_first && n<=selection_last) {
+      if (!pre && isspace(c&255)) c = ' ';
+      if (p!=' '||c!=' ')
+        *d++ = c;
+      p = c;
+    }
+  }
+  *d = 0;
+  Fl::copy(txt, strlen(txt), clipboard);
+  free(txt);
+}
+
+#define ctrl(x) ((x)&0x1f)
+
+//
+// 'Fl_Help_View::handle()' - Handle events in the widget.
+//
+
+int				// O - 1 if we handled it, 0 otherwise
+Fl_Help_View::handle(int event)	// I - Event to handle
+{
+  static Fl_Help_Link *linkp;   // currently clicked link
+
+  int xx = Fl::event_x() - x() + leftline_;
+  int yy = Fl::event_y() - y() + topline_;
+
+  switch (event)
+  {
+    case FL_FOCUS:
+      redraw();
+      return 1;
+    case FL_UNFOCUS:
+      clear_selection();
+      redraw();
+      return 1;
+    case FL_ENTER :
+      Fl_Group::handle(event);
+      return 1;
+    case FL_LEAVE :
+      fl_cursor(FL_CURSOR_DEFAULT);
+      break;
+    case FL_MOVE:
+      if (find_link(xx, yy)) fl_cursor(FL_CURSOR_HAND);
+      else fl_cursor(FL_CURSOR_DEFAULT);
+      return 1;
+    case FL_PUSH:
+      if (Fl_Group::handle(event)) return 1;
+      linkp = find_link(xx, yy);
+      if (linkp) {
+        fl_cursor(FL_CURSOR_HAND);
+        return 1;
+      }
+      if (begin_selection()) {
+        fl_cursor(FL_CURSOR_INSERT);
+        return 1;
+      }
+      fl_cursor(FL_CURSOR_DEFAULT);
+      return 1;
+    case FL_DRAG:
+      if (linkp) {
+        if (Fl::event_is_click()) {
+          fl_cursor(FL_CURSOR_HAND);
+        } else {
+          fl_cursor(FL_CURSOR_DEFAULT); // should be "FL_CURSOR_CANCEL" if we had it
+        }
+        return 1;
+      }
+      if (current_view==this && selection_push_last) {
+        if (extend_selection()) redraw();
+        fl_cursor(FL_CURSOR_INSERT);
+        return 1;
+      }
+      fl_cursor(FL_CURSOR_DEFAULT);
+      return 1;
+    case FL_RELEASE:
+      if (linkp) {
+        if (Fl::event_is_click()) {
+          follow_link(linkp);
+        }
+        fl_cursor(FL_CURSOR_DEFAULT);
+        linkp = 0;
+        return 1;
+      }
+      if (current_view==this && selection_push_last) {
+        end_selection();
+        return 1;
+      }
+      return 1;
+    case FL_SHORTCUT: {
+      char ascii = Fl::event_text()[0];
+      switch (ascii) {
+        case ctrl('A'): select_all(); redraw(); return 1;
+        case ctrl('C'):
+        case ctrl('X'): end_selection(1); return 1;
+      }
+      break; }
+  }
+  return (Fl_Group::handle(event));
+}
+
+//
+// 'Fl_Help_View::Fl_Help_View()' - Build a Fl_Help_View widget.
+//
+
+Fl_Help_View::Fl_Help_View(int        xx,	// I - Left position
+                	   int        yy,	// I - Top position
+			   int        ww,	// I - Width in pixels
+			   int        hh,	// I - Height in pixels
+			   const char *l)
+    : Fl_Group(xx, yy, ww, hh, l),
+      scrollbar_(xx + ww - Fl::scrollbar_size(), yy,
+                 Fl::scrollbar_size(), hh - Fl::scrollbar_size()),
+      hscrollbar_(xx, yy + hh - Fl::scrollbar_size(),
+                  ww - Fl::scrollbar_size(), Fl::scrollbar_size())
+{
+  color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR);
+
+  title_[0]     = '\0';
+  defcolor_     = FL_FOREGROUND_COLOR;
+  bgcolor_      = FL_BACKGROUND_COLOR;
+  textcolor_    = FL_FOREGROUND_COLOR;
+  linkcolor_    = FL_SELECTION_COLOR;
+  textfont_     = FL_TIMES;
+  textsize_     = 12;
+  value_        = NULL;
+
+  ablocks_      = 0;
+  nblocks_      = 0;
+  blocks_       = (Fl_Help_Block *)0;
+
+  nfonts_       = 0;
+
+  link_         = (Fl_Help_Func *)0;
+
+  alinks_       = 0;
+  nlinks_       = 0;
+  links_        = (Fl_Help_Link *)0;
+
+  atargets_     = 0;
+  ntargets_     = 0;
+  targets_      = (Fl_Help_Target *)0;
+
+  directory_[0] = '\0';
+  filename_[0]  = '\0';
+
+  topline_      = 0;
+  leftline_     = 0;
+  size_         = 0;
+  hsize_        = 0;
+
+  scrollbar_.value(0, hh, 0, 1);
+  scrollbar_.step(8.0);
+  scrollbar_.show();
+  scrollbar_.callback(scrollbar_callback);
+
+  hscrollbar_.value(0, ww, 0, 1);
+  hscrollbar_.step(8.0);
+  hscrollbar_.show();
+  hscrollbar_.callback(hscrollbar_callback);
+  hscrollbar_.type(FL_HORIZONTAL);
+  end();
+
+  resize(xx, yy, ww, hh);
+}
+
+
+//
+// 'Fl_Help_View::~Fl_Help_View()' - Destroy a Fl_Help_View widget.
+//
+
+Fl_Help_View::~Fl_Help_View()
+{
+  clear_selection();
+  free_data();
+}
+
+
+//
+// 'Fl_Help_View::load()' - Load the specified file.
+//
+
+int				// O - 0 on success, -1 on error
+Fl_Help_View::load(const char *f)// I - Filename to load (may also have target)
+{
+  FILE		*fp;		// File to read from
+  long		len;		// Length of file
+  char		*target;	// Target in file
+  char		*slash;		// Directory separator
+  const char	*localname;	// Local filename
+  char		error[1024];	// Error buffer
+  char		newname[1024];	// New filename buffer
+
+  clear_selection();
+
+  strlcpy(newname, f, sizeof(newname));
+  if ((target = strrchr(newname, '#')) != NULL)
+    *target++ = '\0';
+
+  if (link_)
+    localname = (*link_)(this, newname);
+  else
+    localname = filename_;
+
+  if (!localname)
+    return (0);
+
+  free_data();
+
+  strlcpy(filename_, newname, sizeof(filename_));
+  strlcpy(directory_, newname, sizeof(directory_));
+
+  // Note: We do not support Windows backslashes, since they are illegal
+  //       in URLs...
+  if ((slash = strrchr(directory_, '/')) == NULL)
+    directory_[0] = '\0';
+  else if (slash > directory_ && slash[-1] != '/')
+    *slash = '\0';
+
+  if (strncmp(localname, "ftp:", 4) == 0 ||
+      strncmp(localname, "http:", 5) == 0 ||
+      strncmp(localname, "https:", 6) == 0 ||
+      strncmp(localname, "ipp:", 4) == 0 ||
+      strncmp(localname, "mailto:", 7) == 0 ||
+      strncmp(localname, "news:", 5) == 0)
+  {
+    // Remote link wasn't resolved...
+    snprintf(error, sizeof(error),
+             "Error"
+             "

Error

" + "

Unable to follow the link \"%s\" - " + "no handler exists for this URI scheme.

", + localname); + value_ = strdup(error); + } + else + { + if (strncmp(localname, "file:", 5) == 0) + localname += 5; // Adjust for local filename... + + if ((fp = fopen(localname, "rb")) != NULL) + { + fseek(fp, 0, SEEK_END); + len = ftell(fp); + rewind(fp); + + value_ = (const char *)calloc(len + 1, 1); + fread((void *)value_, 1, len, fp); + fclose(fp); + } + else + { + snprintf(error, sizeof(error), + "Error" + "

Error

" + "

Unable to follow the link \"%s\" - " + "%s.

", + localname, strerror(errno)); + value_ = strdup(error); + } + } + + initial_load = 1; + format(); + initial_load = 0; + + if (target) + topline(target); + else + topline(0); + + return (0); +} + + +// +// 'Fl_Help_View::resize()' - Resize the help widget. +// + +void +Fl_Help_View::resize(int xx, // I - New left position + int yy, // I - New top position + int ww, // I - New width + int hh) // I - New height +{ + Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; + // Box to draw... + + + Fl_Widget::resize(xx, yy, ww, hh); + + int ss = Fl::scrollbar_size(); + scrollbar_.resize(x() + w() - ss - Fl::box_dw(b) + Fl::box_dx(b), + y() + Fl::box_dy(b), ss, h() - ss - Fl::box_dh(b)); + hscrollbar_.resize(x() + Fl::box_dx(b), + y() + h() - ss - Fl::box_dh(b) + Fl::box_dy(b), + w() - ss - Fl::box_dw(b), ss); + + format(); +} + + +// +// 'Fl_Help_View::topline()' - Set the top line to the named target. +// + +void +Fl_Help_View::topline(const char *n) // I - Target name +{ + Fl_Help_Target key, // Target name key + *target; // Pointer to matching target + + + if (ntargets_ == 0) + return; + + strlcpy(key.name, n, sizeof(key.name)); + + target = (Fl_Help_Target *)bsearch(&key, targets_, ntargets_, sizeof(Fl_Help_Target), + (compare_func_t)compare_targets); + + if (target != NULL) + topline(target->y); +} + + +// +// 'Fl_Help_View::topline()' - Set the top line by number. +// + +void +Fl_Help_View::topline(int t) // I - Top line number +{ + if (!value_) + return; + + if (size_ < (h() - Fl::scrollbar_size()) || t < 0) + t = 0; + else if (t > size_) + t = size_; + + topline_ = t; + + scrollbar_.value(topline_, h() - Fl::scrollbar_size(), 0, size_); + + do_callback(); + + redraw(); +} + + +// +// 'Fl_Help_View::leftline()' - Set the left position. +// + +void +Fl_Help_View::leftline(int l) // I - Left position +{ + if (!value_) + return; + + if (hsize_ < (w() - Fl::scrollbar_size()) || l < 0) + l = 0; + else if (l > hsize_) + l = hsize_; + + leftline_ = l; + + hscrollbar_.value(leftline_, w() - Fl::scrollbar_size(), 0, hsize_); + + redraw(); +} + + +// +// 'Fl_Help_View::value()' - Set the help text directly. +// + +void +Fl_Help_View::value(const char *v) // I - Text to view +{ + clear_selection(); + free_data(); + set_changed(); + + if (!v) + return; + + value_ = strdup(v); + + initial_load = 1; + format(); + initial_load = 0; + + topline(0); + leftline(0); +} + +#ifdef ENC +# undef ENC +#endif +#ifdef __APPLE__ +# define ENC(a, b) b +#else +# define ENC(a, b) a +#endif + +// +// 'quote_char()' - Return the character code associated with a quoted char. +// + +static int // O - Code or -1 on error +quote_char(const char *p) { // I - Quoted string + int i; // Looping var + static struct { + const char *name; + int namelen; + int code; + } *nameptr, // Pointer into name array + names[] = { // Quoting names + { "Aacute;", 7, ENC(193,231) }, + { "aacute;", 7, ENC(225,135) }, + { "Acirc;", 6, ENC(194,229) }, + { "acirc;", 6, ENC(226,137) }, + { "acute;", 6, ENC(180,171) }, + { "AElig;", 6, ENC(198,174) }, + { "aelig;", 6, ENC(230,190) }, + { "Agrave;", 7, ENC(192,203) }, + { "agrave;", 7, ENC(224,136) }, + { "amp;", 4, ENC('&','&') }, + { "Aring;", 6, ENC(197,129) }, + { "aring;", 6, ENC(229,140) }, + { "Atilde;", 7, ENC(195,204) }, + { "atilde;", 7, ENC(227,139) }, + { "Auml;", 5, ENC(196,128) }, + { "auml;", 5, ENC(228,138) }, + { "brvbar;", 7, ENC(166, -1) }, + { "bull;", 5, ENC(149,165) }, + { "Ccedil;", 7, ENC(199,199) }, + { "ccedil;", 7, ENC(231,141) }, + { "cedil;", 6, ENC(184,252) }, + { "cent;", 5, ENC(162,162) }, + { "copy;", 5, ENC(169,169) }, + { "curren;", 7, ENC(164, -1) }, + { "deg;", 4, ENC(176,161) }, + { "divide;", 7, ENC(247,214) }, + { "Eacute;", 7, ENC(201,131) }, + { "eacute;", 7, ENC(233,142) }, + { "Ecirc;", 6, ENC(202,230) }, + { "ecirc;", 6, ENC(234,144) }, + { "Egrave;", 7, ENC(200,233) }, + { "egrave;", 7, ENC(232,143) }, + { "ETH;", 4, ENC(208, -1) }, + { "eth;", 4, ENC(240, -1) }, + { "Euml;", 5, ENC(203,232) }, + { "euml;", 5, ENC(235,145) }, + { "euro;", 5, ENC(128,219) }, + { "frac12;", 7, ENC(189, -1) }, + { "frac14;", 7, ENC(188, -1) }, + { "frac34;", 7, ENC(190, -1) }, + { "gt;", 3, ENC('>','>') }, + { "Iacute;", 7, ENC(205,234) }, + { "iacute;", 7, ENC(237,146) }, + { "Icirc;", 6, ENC(206,235) }, + { "icirc;", 6, ENC(238,148) }, + { "iexcl;", 6, ENC(161,193) }, + { "Igrave;", 7, ENC(204,237) }, + { "igrave;", 7, ENC(236,147) }, + { "iquest;", 7, ENC(191,192) }, + { "Iuml;", 5, ENC(207,236) }, + { "iuml;", 5, ENC(239,149) }, + { "laquo;", 6, ENC(171,199) }, + { "lt;", 3, ENC('<','<') }, + { "macr;", 5, ENC(175,248) }, + { "micro;", 6, ENC(181,181) }, + { "middot;", 7, ENC(183,225) }, + { "nbsp;", 5, ENC(' ',' ') }, + { "not;", 4, ENC(172,194) }, + { "Ntilde;", 7, ENC(209,132) }, + { "ntilde;", 7, ENC(241,150) }, + { "Oacute;", 7, ENC(211,238) }, + { "oacute;", 7, ENC(243,151) }, + { "Ocirc;", 6, ENC(212,239) }, + { "ocirc;", 6, ENC(244,153) }, + { "Ograve;", 7, ENC(210,241) }, + { "ograve;", 7, ENC(242,152) }, + { "ordf;", 5, ENC(170,187) }, + { "ordm;", 5, ENC(186,188) }, + { "Oslash;", 7, ENC(216,175) }, + { "oslash;", 7, ENC(248,191) }, + { "Otilde;", 7, ENC(213,205) }, + { "otilde;", 7, ENC(245,155) }, + { "Ouml;", 5, ENC(214,133) }, + { "ouml;", 5, ENC(246,154) }, + { "para;", 5, ENC(182,166) }, + { "premil;", 7, ENC(137,228) }, + { "plusmn;", 7, ENC(177,177) }, + { "pound;", 6, ENC(163,163) }, + { "quot;", 5, ENC('\"','\"') }, + { "raquo;", 6, ENC(187,200) }, + { "reg;", 4, ENC(174,168) }, + { "sect;", 5, ENC(167,164) }, + { "shy;", 4, ENC(173,'-') }, + { "sup1;", 5, ENC(185, -1) }, + { "sup2;", 5, ENC(178, -1) }, + { "sup3;", 5, ENC(179, -1) }, + { "szlig;", 6, ENC(223,167) }, + { "THORN;", 6, ENC(222, -1) }, + { "thorn;", 6, ENC(254, -1) }, + { "times;", 6, ENC(215,'x') }, + { "trade;", 6, ENC(153,170) }, + { "Uacute;", 7, ENC(218,242) }, + { "uacute;", 7, ENC(250,156) }, + { "Ucirc;", 6, ENC(219,243) }, + { "ucirc;", 6, ENC(251,158) }, + { "Ugrave;", 7, ENC(217,244) }, + { "ugrave;", 7, ENC(249,157) }, + { "uml;", 4, ENC(168,172) }, + { "Uuml;", 5, ENC(220,134) }, + { "uuml;", 5, ENC(252,159) }, + { "Yacute;", 7, ENC(221, -1) }, + { "yacute;", 7, ENC(253, -1) }, + { "yen;", 4, ENC(165,180) }, + { "Yuml;", 5, ENC(159,217) }, + { "yuml;", 5, ENC(255,216) } + }; + + if (!strchr(p, ';')) return -1; + if (*p == '#') { + if (*(p+1) == 'x' || *(p+1) == 'X') return strtol(p+2, NULL, 16); + else return atoi(p+1); + } + for (i = (int)(sizeof(names) / sizeof(names[0])), nameptr = names; i > 0; i --, nameptr ++) + if (strncmp(p, nameptr->name, nameptr->namelen) == 0) + return nameptr->code; + + return -1; +} + + +// +// 'scrollbar_callback()' - A callback for the scrollbar. +// + +static void +scrollbar_callback(Fl_Widget *s, void *) +{ + ((Fl_Help_View *)(s->parent()))->topline(int(((Fl_Scrollbar*)s)->value())); +} + + +// +// 'hscrollbar_callback()' - A callback for the horizontal scrollbar. +// + +static void +hscrollbar_callback(Fl_Widget *s, void *) +{ + ((Fl_Help_View *)(s->parent()))->leftline(int(((Fl_Scrollbar*)s)->value())); +} + + +// +// End of "$Id: Fl_Help_View.cxx 6745 2009-04-07 18:37:25Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Image.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Image.cxx new file mode 100644 index 0000000..56cf83d --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Image.cxx @@ -0,0 +1,525 @@ +// +// "$Id: Fl_Image.cxx 6805 2009-06-29 07:45:48Z AlbrechtS $" +// +// Image drawing code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include +#include +#include "flstring.h" + +#ifdef WIN32 +void fl_release_dc(HWND, HDC); // from Fl_win32.cxx +#endif + +void fl_restore_clip(); // from fl_rect.cxx + +// +// Base image class... +// + +Fl_Image::~Fl_Image() { +} + +void Fl_Image::uncache() { +} + +void Fl_Image::draw(int XP, int YP, int, int, int, int) { + draw_empty(XP, YP); +} + +void Fl_Image::draw_empty(int X, int Y) { + if (w() > 0 && h() > 0) { + fl_color(FL_FOREGROUND_COLOR); + fl_rect(X, Y, w(), h()); + fl_line(X, Y, X + w() - 1, Y + h() - 1); + fl_line(X, Y + h() - 1, X + w() - 1, Y); + } +} + +Fl_Image *Fl_Image::copy(int W, int H) { + return new Fl_Image(W, H, d()); +} + +void Fl_Image::color_average(Fl_Color, float) { +} + +void Fl_Image::desaturate() { +} + +void Fl_Image::label(Fl_Widget* widget) { + widget->image(this); +} + +void Fl_Image::label(Fl_Menu_Item* m) { + Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, measure); + m->label(_FL_IMAGE_LABEL, (const char*)this); +} + +void +Fl_Image::labeltype(const Fl_Label *lo, // I - Label + int lx, // I - X position + int ly, // I - Y position + int lw, // I - Width of label + int lh, // I - Height of label + Fl_Align la) { // I - Alignment + Fl_Image *img; // Image pointer + int cx, cy; // Image position + + img = (Fl_Image *)(lo->value); + + if (la & FL_ALIGN_LEFT) cx = 0; + else if (la & FL_ALIGN_RIGHT) cx = img->w() - lw; + else cx = (img->w() - lw) / 2; + + if (la & FL_ALIGN_TOP) cy = 0; + else if (la & FL_ALIGN_BOTTOM) cy = img->h() - lh; + else cy = (img->h() - lh) / 2; + + fl_color((Fl_Color)lo->color); + + img->draw(lx, ly, lw, lh, cx, cy); +} + +void +Fl_Image::measure(const Fl_Label *lo, // I - Label + int &lw, // O - Width of image + int &lh) { // O - Height of image + Fl_Image *img; // Image pointer + + img = (Fl_Image *)(lo->value); + + lw = img->w(); + lh = img->h(); +} + + +// +// RGB image class... +// + +Fl_RGB_Image::~Fl_RGB_Image() { + uncache(); + if (alloc_array) delete[] (uchar *)array; +} + +void Fl_RGB_Image::uncache() { +#ifdef __APPLE_QUARTZ__ + if (id) { + CGImageRelease((CGImageRef)id); + id = 0; + } +#else + if (id) { + fl_delete_offscreen((Fl_Offscreen)id); + id = 0; + } + + if (mask) { + fl_delete_bitmask((Fl_Bitmask)mask); + mask = 0; + } +#endif +} + +Fl_Image *Fl_RGB_Image::copy(int W, int H) { + Fl_RGB_Image *new_image; // New RGB image + uchar *new_array; // New array for image data + + // Optimize the simple copy where the width and height are the same, + // or when we are copying an empty image... + if ((W == w() && H == h()) || + !w() || !h() || !d() || !array) { + if (array) { + // Make a copy of the image data and return a new Fl_RGB_Image... + new_array = new uchar[w() * h() * d()]; + if (ld() && ld()!=w()*d()) { + const uchar *src = array; + uchar *dst = new_array; + int dy, dh = h(), wd = w()*d(), wld = ld(); + for (dy=0; dyalloc_array = 1; + + return new_image; + } else return new Fl_RGB_Image(array, w(), h(), d(), ld()); + } + if (W <= 0 || H <= 0) return 0; + + // OK, need to resize the image data; allocate memory and + uchar *new_ptr; // Pointer into new array + const uchar *old_ptr; // Pointer into old array + int c, // Channel number + sy, // Source coordinate + dx, dy, // Destination coordinates + xerr, yerr, // X & Y errors + xmod, ymod, // X & Y moduli + xstep, ystep, // X & Y step increments + line_d; // stride from line to line + + + // Figure out Bresenheim step/modulus values... + xmod = w() % W; + xstep = (w() / W) * d(); + ymod = h() % H; + ystep = h() / H; + line_d = ld() ? ld() : w() * d(); + + // Allocate memory for the new image... + new_array = new uchar [W * H * d()]; + new_image = new Fl_RGB_Image(new_array, W, H, d()); + new_image->alloc_array = 1; + + // Scale the image using a nearest-neighbor algorithm... + for (dy = H, sy = 0, yerr = H, new_ptr = new_array; dy > 0; dy --) { + for (dx = W, xerr = W, old_ptr = array + sy * line_d; dx > 0; dx --) { + for (c = 0; c < d(); c ++) *new_ptr++ = old_ptr[c]; + + old_ptr += xstep; + xerr -= xmod; + + if (xerr <= 0) { + xerr += W; + old_ptr += d(); + } + } + + sy += ystep; + yerr -= ymod; + if (yerr <= 0) { + yerr += H; + sy ++; + } + } + + return new_image; +} + +void Fl_RGB_Image::color_average(Fl_Color c, float i) { + // Don't average an empty image... + if (!w() || !h() || !d() || !array) return; + + // Delete any existing pixmap/mask objects... + uncache(); + + // Allocate memory as needed... + uchar *new_array, + *new_ptr; + + if (!alloc_array) new_array = new uchar[h() * w() * d()]; + else new_array = (uchar *)array; + + // Get the color to blend with... + uchar r, g, b; + unsigned ia, ir, ig, ib; + + Fl::get_color(c, r, g, b); + if (i < 0.0f) i = 0.0f; + else if (i > 1.0f) i = 1.0f; + + ia = (unsigned)(256 * i); + ir = r * (256 - ia); + ig = g * (256 - ia); + ib = b * (256 - ia); + + // Update the image data to do the blend... + const uchar *old_ptr; + int x, y; + int line_i = ld() ? ld() - (w()*d()) : 0; // increment from line end to beginning of next line + + if (d() < 3) { + ig = (r * 31 + g * 61 + b * 8) / 100 * (256 - ia); + + for (new_ptr = new_array, old_ptr = array, y = 0; y < h(); y ++, old_ptr += line_i) + for (x = 0; x < w(); x ++) { + *new_ptr++ = (*old_ptr++ * ia + ig) >> 8; + if (d() > 1) *new_ptr++ = *old_ptr++; + } + } else { + for (new_ptr = new_array, old_ptr = array, y = 0; y < h(); y ++, old_ptr += line_i) + for (x = 0; x < w(); x ++) { + *new_ptr++ = (*old_ptr++ * ia + ir) >> 8; + *new_ptr++ = (*old_ptr++ * ia + ig) >> 8; + *new_ptr++ = (*old_ptr++ * ia + ib) >> 8; + if (d() > 3) *new_ptr++ = *old_ptr++; + } + } + + // Set the new pointers/values as needed... + if (!alloc_array) { + array = new_array; + alloc_array = 1; + + ld(0); + } +} + +void Fl_RGB_Image::desaturate() { + // Don't desaturate an empty image... + if (!w() || !h() || !d() || !array) return; + + // Can only desaturate color images... + if (d() < 3) return; + + // Delete any existing pixmap/mask objects... + uncache(); + + // Allocate memory for a grayscale image... + uchar *new_array, + *new_ptr; + int new_d; + + new_d = d() - 2; + new_array = new uchar[h() * w() * new_d]; + + // Copy the image data, converting to grayscale... + const uchar *old_ptr; + int x, y; + int line_i = ld() ? ld() - (w()*d()) : 0; // increment from line end to beginning of next line + + for (new_ptr = new_array, old_ptr = array, y = 0; y < h(); y ++, old_ptr += line_i) + for (x = 0; x < w(); x ++, old_ptr += d()) { + *new_ptr++ = (uchar)((31 * old_ptr[0] + 61 * old_ptr[1] + 8 * old_ptr[2]) / 100); + if (d() > 3) *new_ptr++ = old_ptr[3]; + } + + // Free the old array as needed, and then set the new pointers/values... + if (alloc_array) delete[] (uchar *)array; + + array = new_array; + alloc_array = 1; + + ld(0); + d(new_d); +} + +#if !defined(WIN32) && !USE_QUARTZ +// Composite an image with alpha on systems that don't have accelerated +// alpha compositing... +static void alpha_blend(Fl_RGB_Image *img, int X, int Y, int W, int H, int cx, int cy) { + uchar *srcptr = (uchar*)img->array + img->d() * (img->w() * cy + cx); + int srcskip = img->d() * (img->w() - W); + + uchar *dst = new uchar[W * H * 3]; + uchar *dstptr = dst; + + fl_read_image(dst, X, Y, W, H, 0); + + uchar srcr, srcg, srcb, srca; + uchar dstr, dstg, dstb, dsta; + + if (img->d() == 2) { + // Composite grayscale + alpha over RGB... + // Composite RGBA over RGB... + for (int y = H; y > 0; y--, srcptr+=srcskip) + for (int x = W; x > 0; x--) { + srcg = *srcptr++; + srca = *srcptr++; + + dstr = dstptr[0]; + dstg = dstptr[1]; + dstb = dstptr[2]; + dsta = 255 - srca; + + *dstptr++ = (srcg * srca + dstr * dsta) >> 8; + *dstptr++ = (srcg * srca + dstg * dsta) >> 8; + *dstptr++ = (srcg * srca + dstb * dsta) >> 8; + } + } else { + // Composite RGBA over RGB... + for (int y = H; y > 0; y--, srcptr+=srcskip) + for (int x = W; x > 0; x--) { + srcr = *srcptr++; + srcg = *srcptr++; + srcb = *srcptr++; + srca = *srcptr++; + + dstr = dstptr[0]; + dstg = dstptr[1]; + dstb = dstptr[2]; + dsta = 255 - srca; + + *dstptr++ = (srcr * srca + dstr * dsta) >> 8; + *dstptr++ = (srcg * srca + dstg * dsta) >> 8; + *dstptr++ = (srcb * srca + dstb * dsta) >> 8; + } + } + + fl_draw_image(dst, X, Y, W, H, 3, 0); + + delete[] dst; +} +#endif // !WIN32 && !USE_QUARTZ + +void Fl_RGB_Image::draw(int XP, int YP, int WP, int HP, int cx, int cy) { + // Don't draw an empty image... + if (!d() || !array) { + draw_empty(XP, YP); + return; + } + + // account for current clip region (faster on Irix): + int X,Y,W,H; fl_clip_box(XP,YP,WP,HP,X,Y,W,H); + cx += X-XP; cy += Y-YP; + // clip the box down to the size of image, quit if empty: + if (cx < 0) {W += cx; X -= cx; cx = 0;} + if (cx+W > w()) W = w()-cx; + if (W <= 0) return; + if (cy < 0) {H += cy; Y -= cy; cy = 0;} + if (cy+H > h()) H = h()-cy; + if (H <= 0) return; + if (!id) { +#ifdef __APPLE_QUARTZ__ + CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); + CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, w()*h()*d(), 0L); + id = CGImageCreate( w(), h(), 8, d()*8, ld()?ld():w()*d(), + lut, (d()&1)?kCGImageAlphaNone:kCGImageAlphaLast, + src, 0L, false, kCGRenderingIntentDefault); + CGColorSpaceRelease(lut); + CGDataProviderRelease(src); +#elif defined(WIN32) + id = fl_create_offscreen(w(), h()); + if ((d() == 2 || d() == 4) && fl_can_do_alpha_blending()) { + fl_begin_offscreen((Fl_Offscreen)id); + fl_draw_image(array, 0, 0, w(), h(), d()|FL_IMAGE_WITH_ALPHA, ld()); + fl_end_offscreen(); + } else { + fl_begin_offscreen((Fl_Offscreen)id); + fl_draw_image(array, 0, 0, w(), h(), d(), ld()); + fl_end_offscreen(); + if (d() == 2 || d() == 4) { + mask = fl_create_alphamask(w(), h(), d(), ld(), array); + } + } +#else + if (d() == 1 || d() == 3) { + id = fl_create_offscreen(w(), h()); + fl_begin_offscreen((Fl_Offscreen)id); + fl_draw_image(array, 0, 0, w(), h(), d(), ld()); + fl_end_offscreen(); + } +#endif + } +#ifdef WIN32 + if (mask) { + HDC new_gc = CreateCompatibleDC(fl_gc); + int save = SaveDC(new_gc); + SelectObject(new_gc, (void*)mask); + BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND); + SelectObject(new_gc, (void*)id); + BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT); + RestoreDC(new_gc,save); + DeleteDC(new_gc); + } else if (d()==2 || d()==4) { + fl_copy_offscreen_with_alpha(X, Y, W, H, (Fl_Offscreen)id, cx, cy); + } else { + fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)id, cx, cy); + } +#elif defined(__APPLE_QD__) + if (mask) { + Rect src, dst; + // MRS: STR #114 says we should be using cx, cy, W, and H... +// src.left = 0; src.right = w(); +// src.top = 0; src.bottom = h(); +// dst.left = X; dst.right = X+w(); +// dst.top = Y; dst.bottom = Y+h(); + src.left = cx; src.right = cx+W; + src.top = cy; src.bottom = cy+H; + dst.left = X; dst.right = X+W; + dst.top = Y; dst.bottom = Y+H; + RGBColor rgb; + rgb.red = 0xffff; rgb.green = 0xffff; rgb.blue = 0xffff; + RGBBackColor(&rgb); + rgb.red = 0x0000; rgb.green = 0x0000; rgb.blue = 0x0000; + RGBForeColor(&rgb); + + CopyMask(GetPortBitMapForCopyBits((GrafPtr)id), + GetPortBitMapForCopyBits((GrafPtr)mask), + GetPortBitMapForCopyBits(GetWindowPort(fl_window)), + &src, &src, &dst); + } else if (id) fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)id, cx, cy); + else { + // Composite image with alpha manually each time... + alpha_blend(this, X, Y, W, H, cx, cy); + } +#elif defined(__APPLE_QUARTZ__) + if (id && fl_gc) { + CGRect rect = { { X, Y }, { W, H } }; + Fl_X::q_begin_image(rect, cx, cy, w(), h()); + CGContextDrawImage(fl_gc, rect, (CGImageRef)id); + Fl_X::q_end_image(); + } +#else + if (id) { + if (mask) { + // I can't figure out how to combine a mask with existing region, + // so cut the image down to a clipped rectangle: + int nx, ny; fl_clip_box(X,Y,W,H,nx,ny,W,H); + cx += nx-X; X = nx; + cy += ny-Y; Y = ny; + // make X use the bitmap as a mask: + XSetClipMask(fl_display, fl_gc, mask); + int ox = X-cx; if (ox < 0) ox += w(); + int oy = Y-cy; if (oy < 0) oy += h(); + XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy); + } + + fl_copy_offscreen(X, Y, W, H, id, cx, cy); + + if (mask) { + // put the old clip region back + XSetClipOrigin(fl_display, fl_gc, 0, 0); + fl_restore_clip(); + } + } else { + // Composite image with alpha manually each time... + alpha_blend(this, X, Y, W, H, cx, cy); + } +#endif +} + +void Fl_RGB_Image::label(Fl_Widget* widget) { + widget->image(this); +} + +void Fl_RGB_Image::label(Fl_Menu_Item* m) { + Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, measure); + m->label(_FL_IMAGE_LABEL, (const char*)this); +} + + +// +// End of "$Id: Fl_Image.cxx 6805 2009-06-29 07:45:48Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Input.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Input.cxx new file mode 100644 index 0000000..c32da2c --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Input.cxx @@ -0,0 +1,477 @@ +// +// "$Id: Fl_Input.cxx 6940 2009-11-17 19:39:01Z matt $" +// +// Input widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This is the "user interface", it decodes user actions into what to +// do to the text. See also Fl_Input_.cxx, where the text is actually +// manipulated (and some ui, in particular the mouse, is done...). +// In theory you can replace this code with another subclass to change +// the keybindings. + +#include +#include +#include +#include +#include +#include +#include +#include "flstring.h" + +#ifdef HAVE_LOCALE_H +# include +#endif + + +void Fl_Input::draw() { + if (input_type() == FL_HIDDEN_INPUT) return; + Fl_Boxtype b = box(); + if (damage() & FL_DAMAGE_ALL) draw_box(b, color()); + Fl_Input_::drawtext(x()+Fl::box_dx(b), y()+Fl::box_dy(b), + w()-Fl::box_dw(b), h()-Fl::box_dh(b)); +} + +// kludge so shift causes selection to extend: +int Fl_Input::shift_position(int p) { + return position(p, Fl::event_state(FL_SHIFT) ? mark() : p); +} +int Fl_Input::shift_up_down_position(int p) { + return up_down_position(p, Fl::event_state(FL_SHIFT)); +} + +// If you define this symbol as zero you will get the peculiar fltk +// behavior where moving off the end of an input field will move the +// cursor into the next field: +// define it as 1 to prevent cursor movement from going to next field: +#define NORMAL_INPUT_MOVE 0 + +#define ctrl(x) ((x)^0x40) + +// List of characters that are legal in a floating point input field. +// This text string is created at run-time to take the current locale +// into account (for example, continental Europe uses a comma instead +// of a decimal point). For back compatibility reasons, we always +// allow the decimal point. +#ifdef HAVE_LOCALECONV +static const char *standard_fp_chars = ".eE+-"; +static const char *legal_fp_chars = 0L; +#else +static const char *legal_fp_chars = ".eE+-"; +#endif + +int Fl_Input::handle_key() { + + char ascii = Fl::event_text()[0]; + + int repeat_num=1; + + int del; + if (Fl::compose(del)) { + + // Insert characters into numeric fields after checking for legality: + if (input_type() == FL_FLOAT_INPUT || input_type() == FL_INT_INPUT) { + Fl::compose_reset(); // ignore any foreign letters... + + // initialize the list of legal characters inside a floating point number +#ifdef HAVE_LOCALECONV + if (!legal_fp_chars) { + int len = strlen(standard_fp_chars); + struct lconv *lc = localeconv(); + if (lc) { + if (lc->decimal_point) len += strlen(lc->decimal_point); + if (lc->mon_decimal_point) len += strlen(lc->mon_decimal_point); + if (lc->positive_sign) len += strlen(lc->positive_sign); + if (lc->negative_sign) len += strlen(lc->negative_sign); + } + // the following line is not a true memory leak because the array is only + // allocated once if required, and automatically freed when the program quits + char *chars = (char*)malloc(len+1); + legal_fp_chars = chars; + strcpy(chars, standard_fp_chars); + if (lc) { + if (lc->decimal_point) strcat(chars, lc->decimal_point); + if (lc->mon_decimal_point) strcat(chars, lc->mon_decimal_point); + if (lc->positive_sign) strcat(chars, lc->positive_sign); + if (lc->negative_sign) strcat(chars, lc->negative_sign); + } + } +#endif // HAVE_LOCALECONV + + // find the insert position + int ip = position()= '0' && ascii <= '9') + || (ip==1 && index(0)=='0' && (ascii=='x' || ascii == 'X')) + || (ip>1 && index(0)=='0' && (index(1)=='x'||index(1)=='X') + && (ascii>='A'&& ascii<='F' || ascii>='a'&& ascii<='f')) + || input_type()==FL_FLOAT_INPUT && ascii && strchr(legal_fp_chars, ascii)) + { + if (readonly()) fl_beep(); + else replace(position(), mark(), &ascii, 1); + } + return 1; + } + + if (del || Fl::event_length()) { + if (readonly()) fl_beep(); + else replace(position(), del ? position()-del : mark(), + Fl::event_text(), Fl::event_length()); + } + return 1; + } + + switch (Fl::event_key()) { + case FL_Insert: + if (Fl::event_state() & FL_CTRL) ascii = ctrl('C'); + else if (Fl::event_state() & FL_SHIFT) ascii = ctrl('V'); + break; + case FL_Delete: + if (Fl::event_state() & FL_SHIFT) ascii = ctrl('X'); + else ascii = ctrl('D'); + break; + case FL_Left: + ascii = ctrl('B'); break; + case FL_Right: + ascii = ctrl('F'); break; + case FL_Page_Up: + fl_font(textfont(),textsize()); //ensure current font is set to ours + repeat_num=h()/fl_height(); // number of lines to scroll + if (!repeat_num) repeat_num=1; + case FL_Up: + ascii = ctrl('P'); break; + case FL_Page_Down: + fl_font(textfont(),textsize()); + repeat_num=h()/fl_height(); + if (!repeat_num) repeat_num=1; + case FL_Down: + ascii = ctrl('N'); break; + case FL_Home: + if (Fl::event_state() & FL_CTRL) { + shift_position(0); + return 1; + } + ascii = ctrl('A'); + break; + case FL_End: + if (Fl::event_state() & FL_CTRL) { + shift_position(size()); + return 1; + } + ascii = ctrl('E'); break; + + case FL_BackSpace: + ascii = ctrl('H'); break; + case FL_Enter: + case FL_KP_Enter: + if (when() & FL_WHEN_ENTER_KEY) { + position(size(), 0); + maybe_do_callback(); + return 1; + } else if (input_type() == FL_MULTILINE_INPUT && !readonly()) + return replace(position(), mark(), "\n", 1); + else + return 0; // reserved for shortcuts + case FL_Tab: + if (Fl::event_state(FL_CTRL|FL_SHIFT) || input_type()!=FL_MULTILINE_INPUT || readonly()) return 0; + return replace(position(), mark(), &ascii, 1); +#ifdef __APPLE__ + case 'c' : + case 'v' : + case 'x' : + case 'z' : +// printf("'%c' (0x%02x) pressed with%s%s%s%s\n", ascii, ascii, +// Fl::event_state(FL_SHIFT) ? " FL_SHIFT" : "", +// Fl::event_state(FL_CTRL) ? " FL_CTRL" : "", +// Fl::event_state(FL_ALT) ? " FL_ALT" : "", +// Fl::event_state(FL_META) ? " FL_META" : ""); + if (Fl::event_state(FL_META)) ascii -= 0x60; +// printf("using '%c' (0x%02x)...\n", ascii, ascii); + break; +#endif // __APPLE__ + } + + int i; + switch (ascii) { + case ctrl('A'): + return shift_position(line_start(position())) + NORMAL_INPUT_MOVE; + case ctrl('B'): + return shift_position(position()-1) + NORMAL_INPUT_MOVE; + case ctrl('C'): // copy + return copy(1); + case ctrl('D'): + case ctrl('?'): + if (readonly()) { + fl_beep(); + return 1; + } + if (mark() != position()) return cut(); + else return cut(1); + case ctrl('E'): + return shift_position(line_end(position())) + NORMAL_INPUT_MOVE; + case ctrl('F'): + return shift_position(position()+1) + NORMAL_INPUT_MOVE; + case ctrl('H'): + if (readonly()) { + fl_beep(); + return 1; + } + if (mark() != position()) cut(); + else cut(-1); + return 1; + case ctrl('K'): + if (readonly()) { + fl_beep(); + return 1; + } + if (position()>=size()) return 0; + i = line_end(position()); + if (i == position() && i < size()) i++; + cut(position(), i); + return copy_cuts(); + case ctrl('N'): + i = position(); + if (line_end(i) >= size()) return NORMAL_INPUT_MOVE; + while (repeat_num--) { + i = line_end(i); + if (i >= size()) break; + i++; + } + shift_up_down_position(i); + return 1; + case ctrl('P'): + i = position(); + if (!line_start(i)) return NORMAL_INPUT_MOVE; + while(repeat_num--) { + i = line_start(i); + if (!i) break; + i--; + } + shift_up_down_position(line_start(i)); + return 1; + case ctrl('U'): + if (readonly()) { + fl_beep(); + return 1; + } + return cut(0, size()); + case ctrl('V'): + case ctrl('Y'): + if (readonly()) { + fl_beep(); + return 1; + } + Fl::paste(*this, 1); + return 1; + case ctrl('X'): + case ctrl('W'): + if (readonly()) { + fl_beep(); + return 1; + } + copy(1); + return cut(); + case ctrl('Z'): + case ctrl('_'): + if (readonly()) { + fl_beep(); + return 1; + } + return undo(); + case ctrl('I'): + case ctrl('J'): + case ctrl('L'): + case ctrl('M'): + if (readonly()) { + fl_beep(); + return 1; + } + // insert a few selected control characters literally: + if (input_type() != FL_FLOAT_INPUT && input_type() != FL_INT_INPUT) + return replace(position(), mark(), &ascii, 1); + } + + return 0; +} + +int Fl_Input::handle(int event) { + static int dnd_save_position, dnd_save_mark, drag_start = -1, newpos; + static Fl_Widget *dnd_save_focus; + switch (event) { + case FL_FOCUS: + switch (Fl::event_key()) { + case FL_Right: + position(0); + break; + case FL_Left: + position(size()); + break; + case FL_Down: + up_down_position(0); + break; + case FL_Up: + up_down_position(line_start(size())); + break; + case FL_Tab: + case 0xfe20: // XK_ISO_Left_Tab + position(size(),0); + break; + default: + position(position(),mark());// turns off the saved up/down arrow position + break; + } + break; + + case FL_KEYBOARD: + if (Fl::event_key() == FL_Tab && mark() != position()) { + // Set the current cursor position to the end of the selection... + if (mark() > position()) + position(mark()); + else + position(position()); + return (1); + } else { + if (active_r() && window() && this == Fl::belowmouse()) + window()->cursor(FL_CURSOR_NONE); + return handle_key(); + } + + case FL_PUSH: + if (Fl::dnd_text_ops()) { + int oldpos = position(), oldmark = mark(); + Fl_Boxtype b = box(); + Fl_Input_::handle_mouse( + x()+Fl::box_dx(b), y()+Fl::box_dy(b), + w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0); + newpos = position(); + position( oldpos, oldmark ); + if (Fl::focus()==this && !Fl::event_state(FL_SHIFT) && input_type()!=FL_SECRET_INPUT && + (newpos >= mark() && newpos < position() || + newpos >= position() && newpos < mark())) { + // user clicked in the selection, may be trying to drag + drag_start = newpos; + return 1; + } + drag_start = -1; + } + + if (Fl::focus() != this) { + Fl::focus(this); + handle(FL_FOCUS); + } + break; + + case FL_DRAG: + if (Fl::dnd_text_ops()) { + if (drag_start >= 0) { + if (Fl::event_is_click()) return 1; // debounce the mouse + // save the position because sometimes we don't get DND_ENTER: + dnd_save_position = position(); + dnd_save_mark = mark(); + // drag the data: + copy(0); Fl::dnd(); + return 1; + } + } + break; + + case FL_RELEASE: + if (Fl::event_button() == 2) { + Fl::event_is_click(0); // stop double click from picking a word + Fl::paste(*this, 0); + } else if (!Fl::event_is_click()) { + // copy drag-selected text to the clipboard. + copy(0); + } else if (Fl::event_is_click() && drag_start >= 0) { + // user clicked in the field and wants to reset the cursor position... + position(drag_start, drag_start); + drag_start = -1; + } else if (Fl::event_clicks()) { + // user double or triple clicked to select word or whole text + copy(0); + } + + // For output widgets, do the callback so the app knows the user + // did something with the mouse... + if (readonly()) do_callback(); + + return 1; + + case FL_DND_ENTER: + Fl::belowmouse(this); // send the leave events first + dnd_save_position = position(); + dnd_save_mark = mark(); + dnd_save_focus = Fl::focus(); + if (dnd_save_focus != this) { + Fl::focus(this); + handle(FL_FOCUS); + } + // fall through: + case FL_DND_DRAG: + //int p = mouse_position(X, Y, W, H); +#if DND_OUT_XXXX + if (Fl::focus()==this && (p>=dnd_save_position && p<=dnd_save_mark || + p>=dnd_save_mark && p<=dnd_save_position)) { + position(dnd_save_position, dnd_save_mark); + return 0; + } +#endif + { + Fl_Boxtype b = box(); + Fl_Input_::handle_mouse( + x()+Fl::box_dx(b), y()+Fl::box_dy(b), + w()-Fl::box_dw(b), h()-Fl::box_dh(b), 0); + } + return 1; + + case FL_DND_LEAVE: + position(dnd_save_position, dnd_save_mark); +#if DND_OUT_XXXX + if (!focused()) +#endif + if (dnd_save_focus != this) { + Fl::focus(dnd_save_focus); + handle(FL_UNFOCUS); + } + return 1; + + case FL_DND_RELEASE: + take_focus(); + return 1; + + } + Fl_Boxtype b = box(); + return Fl_Input_::handletext(event, + x()+Fl::box_dx(b), y()+Fl::box_dy(b), + w()-Fl::box_dw(b), h()-Fl::box_dh(b)); +} + +Fl_Input::Fl_Input(int X, int Y, int W, int H, const char *l) +: Fl_Input_(X, Y, W, H, l) { +} + +// +// End of "$Id: Fl_Input.cxx 6940 2009-11-17 19:39:01Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Input_.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Input_.cxx new file mode 100644 index 0000000..7642653 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Input_.cxx @@ -0,0 +1,907 @@ +// +// "$Id: Fl_Input_.cxx 6104 2008-04-21 20:54:37Z matt $" +// +// Common input widget routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This is the base class for Fl_Input. You can use it directly +// if you are one of those people who like to define their own +// set of editing keys. It may also be useful for adding scrollbars +// to the input field. + +#include +#include +#include +#include +#include +#include +#include "flstring.h" +#include +#include + +#define MAXBUF 1024 + +extern void fl_draw(const char*, int, float, float); + +//////////////////////////////////////////////////////////////// + +// Copy string p..e to the buffer, replacing characters with ^X and \nnn +// as necessary. Truncate if necessary so the resulting string and +// null terminator fits in a buffer of size n. Return new end pointer. +const char* Fl_Input_::expand(const char* p, char* buf) const { + char* o = buf; + char* e = buf+(MAXBUF-4); + const char* lastspace = p; + char* lastspace_out = o; + int width_to_lastspace = 0; + int word_count = 0; + int word_wrap; + + if (input_type()==FL_SECRET_INPUT) { + while (o= value_+size_ || isspace(*p & 255))) { + word_wrap = w() - Fl::box_dw(box()) - 2; + width_to_lastspace += (int)fl_width(lastspace_out, o-lastspace_out); + if (p > lastspace+1) { + if (word_count && width_to_lastspace > word_wrap) { + p = lastspace; o = lastspace_out; break; + } + word_count++; + } + lastspace = p; + lastspace_out = o; + } + + if (p >= value_+size_) break; + int c = *p++ & 255; + if (c < ' ' || c == 127) { + if (c=='\n' && input_type()==FL_MULTILINE_INPUT) {p--; break;} + if (c == '\t' && input_type()==FL_MULTILINE_INPUT) { + for (c = (o-buf)%8; c<8 && o= 128 && c < 0xA0) { + // these codes are not defined in ISO code, so we output the octal code instead + // *o++ = '\\'; + // *o++ = ((c>>6)&0x03) + '0'; + // *o++ = ((c>>3)&0x07) + '0'; + // *o++ = (c&0x07) + '0'; + } else if (c == 0xA0) { // nbsp + *o++ = ' '; +#endif + } else { + *o++ = c; + } + } + *o = 0; + return p; +} + +// After filling in such a buffer, find the width to e +double Fl_Input_::expandpos( + const char* p, // real string + const char* e, // pointer into real string + const char* buf, // conversion of real string by expand() + int* returnn // return offset into buf here +) const { + int n = 0; + if (input_type()==FL_SECRET_INPUT) n = e-p; + else while (p= 128 && c < 0xA0) { + // these codes are not defined in ISO code, so we output the octal code instead + // n += 4; +#endif + } else { + n++; + } + } + if (returnn) *returnn = n; + return fl_width(buf, n); +} + +//////////////////////////////////////////////////////////////// + +// minimal update: +// Characters from mu_p to end of widget are redrawn. +// If erase_cursor_only, small part at mu_p is redrawn. +// Right now minimal update just keeps unchanged characters from +// being erased, so they don't blink. + +void Fl_Input_::minimal_update(int p) { + if (damage() & FL_DAMAGE_ALL) return; // don't waste time if it won't be done + if (damage() & FL_DAMAGE_EXPOSE) { + if (p < mu_p) mu_p = p; + } else { + mu_p = p; + } + + damage(FL_DAMAGE_EXPOSE); + erase_cursor_only = 0; +} + +void Fl_Input_::minimal_update(int p, int q) { + if (q < p) p = q; + minimal_update(p); +} + +//////////////////////////////////////////////////////////////// + +static double up_down_pos; +static int was_up_down; + +void Fl_Input_::setfont() const { + fl_font(textfont(), textsize()); +} + +void Fl_Input_::drawtext(int X, int Y, int W, int H) { + int do_mu = !(damage()&FL_DAMAGE_ALL); + + if (Fl::focus()!=this && !size()) { + if (do_mu) { // we have to erase it if cursor was there + draw_box(box(), X-Fl::box_dx(box()), Y-Fl::box_dy(box()), + W+Fl::box_dw(box()), H+Fl::box_dh(box()), color()); + } + return; + } + + int selstart, selend; + if (Fl::focus()!=this && /*Fl::selection_owner()!=this &&*/ Fl::pushed()!=this) + selstart = selend = 0; + else if (position() <= mark()) { + selstart = position(); selend = mark(); + } else { + selend = position(); selstart = mark(); + } + + setfont(); + const char *p, *e; + char buf[MAXBUF]; + + // count how many lines and put the last one into the buffer: + // And figure out where the cursor is: + int height = fl_height(); + int lines; + int curx, cury; + for (p=value(), curx=cury=lines=0; ;) { + e = expand(p, buf); + if (position() >= p-value() && position() <= e-value()) { + curx = int(expandpos(p, value()+position(), buf, 0)+.5); + if (Fl::focus()==this && !was_up_down) up_down_pos = curx; + cury = lines*height; + int newscroll = xscroll_; + if (curx > newscroll+W-20) { + // figure out scrolling so there is space after the cursor: + newscroll = curx+20-W; + // figure out the furthest left we ever want to scroll: + int ex = int(expandpos(p, e, buf, 0))+2-W; + // use minimum of both amounts: + if (ex < newscroll) newscroll = ex; + } else if (curx < newscroll+20) { + newscroll = curx-20; + } + if (newscroll < 0) newscroll = 0; + if (newscroll != xscroll_) { + xscroll_ = newscroll; + mu_p = 0; erase_cursor_only = 0; + } + } + lines++; + if (e >= value_+size_) break; + p = e+1; + } + + // adjust the scrolling: + if (input_type()==FL_MULTILINE_INPUT) { + int newy = yscroll_; + if (cury < newy) newy = cury; + if (cury > newy+H-height) newy = cury-H+height; + if (newy < -1) newy = -1; + if (newy != yscroll_) {yscroll_ = newy; mu_p = 0; erase_cursor_only = 0;} + } else { + yscroll_ = -(H-height)/2; + } + + fl_clip(X, Y, W, H); + Fl_Color tc = active_r() ? textcolor() : fl_inactive(textcolor()); + + p = value(); + // visit each line and draw it: + int desc = height-fl_descent(); + float xpos = (float)(X - xscroll_ + 1); + int ypos = -yscroll_; + for (; ypos < H;) { + + // re-expand line unless it is the last one calculated above: + if (lines>1) e = expand(p, buf); + + if (ypos <= -height) goto CONTINUE; // clipped off top + + if (do_mu) { // for minimal update: + const char* pp = value()+mu_p; // pointer to where minimal update starts + if (e < pp) goto CONTINUE2; // this line is before the changes + if (readonly()) erase_cursor_only = 0; // this isn't the most efficient way + if (erase_cursor_only && p > pp) goto CONTINUE2; // this line is after + // calculate area to erase: + float r = (float)(X+W); + float xx; + if (p >= pp) { + xx = (float)X; + if (erase_cursor_only) r = xpos+2; + else if (readonly()) xx -= 3; + } else { + xx = xpos + (float)expandpos(p, pp, buf, 0); + if (erase_cursor_only) r = xx+2; + else if (readonly()) xx -= 3; + } + // clip to and erase it: + fl_push_clip((int)xx-1-height/8, Y+ypos, (int)(r-xx+2+height/4), height); + draw_box(box(), X-Fl::box_dx(box()), Y-Fl::box_dy(box()), + W+Fl::box_dw(box()), H+Fl::box_dh(box()), color()); + // it now draws entire line over it + // this should not draw letters to left of erased area, but + // that is nyi. + } + + // Draw selection area if required: + if (selstart < selend && selstart <= e-value() && selend > p-value()) { + const char* pp = value()+selstart; + float x1 = xpos; + int offset1 = 0; + if (pp > p) { + fl_color(tc); + x1 += (float)expandpos(p, pp, buf, &offset1); + fl_draw(buf, offset1, xpos, (float)(Y+ypos+desc)); + } + pp = value()+selend; + float x2 = (float)(X+W); + int offset2; + if (pp <= e) x2 = xpos + (float)expandpos(p, pp, buf, &offset2); + else offset2 = strlen(buf); + fl_color(selection_color()); + fl_rectf((int)(x1+0.5), Y+ypos, (int)(x2-x1+0.5), height); + fl_color(fl_contrast(textcolor(), selection_color())); + fl_draw(buf+offset1, offset2-offset1, x1, (float)(Y+ypos+desc)); + if (pp < e) { + fl_color(tc); + fl_draw(buf+offset2, strlen(buf+offset2), x2, (float)(Y+ypos+desc)); + } + } else { + // draw unselected text + fl_color(tc); + fl_draw(buf, strlen(buf), xpos, (float)(Y+ypos+desc)); + } + + if (do_mu) fl_pop_clip(); + + CONTINUE2: + // draw the cursor: + if (Fl::focus() == this && selstart == selend && + position() >= p-value() && position() <= e-value()) { + fl_color(cursor_color()); + if (readonly()) { + fl_line((int)(xpos+curx-2.5f), Y+ypos+height-1, + (int)(xpos+curx+0.5f), Y+ypos+height-4, + (int)(xpos+curx+3.5f), Y+ypos+height-1); + } else { + fl_rectf((int)(xpos+curx+0.5), Y+ypos, 2, height); + } + } + + CONTINUE: + ypos += height; + if (e >= value_+size_) break; + if (*e == '\n' || *e == ' ') e++; + p = e; + } + + // for minimal update, erase all lines below last one if necessary: + if (input_type()==FL_MULTILINE_INPUT && do_mu && ypos= size() || !isword(index(i))) +// while (i > 0 && !isword(index(i-1))) i--; + while (i > 0 && isword(index(i-1))) i--; + return i; +} + +int Fl_Input_::line_end(int i) const { + if (input_type() != FL_MULTILINE_INPUT) return size(); + + if (wrap()) { + // go to the start of the paragraph: + int j = i; + while (j > 0 && index(j-1) != '\n') j--; + // now measure lines until we get past i, end of that line is real eol: + setfont(); + for (const char* p=value()+j; ;) { + char buf[MAXBUF]; + p = expand(p, buf); + if (p-value() >= i) return p-value(); + p++; + } + } else { + while (i < size() && index(i) != '\n') i++; + return i; + } +} + +int Fl_Input_::line_start(int i) const { + if (input_type() != FL_MULTILINE_INPUT) return 0; + int j = i; + while (j > 0 && index(j-1) != '\n') j--; + if (wrap()) { + // now measure lines until we get past i, start of that line is real eol: + setfont(); + for (const char* p=value()+j; ;) { + char buf[MAXBUF]; + const char* e = expand(p, buf); + if (e-value() >= i) return p-value(); + p = e+1; + } + } else return j; +} + +void Fl_Input_::handle_mouse(int X, int Y, int /*W*/, int /*H*/, int drag) { + was_up_down = 0; + if (!size()) return; + setfont(); + + const char *p, *e; + char buf[MAXBUF]; + + int theline = (input_type()==FL_MULTILINE_INPUT) ? + (Fl::event_y()-Y+yscroll_)/fl_height() : 0; + + int newpos = 0; + for (p=value();; ) { + e = expand(p, buf); + theline--; if (theline < 0) break; + if (e >= value_+size_) break; + p = e+1; + } + const char *l, *r, *t; double f0 = Fl::event_x()-X+xscroll_; + for (l = p, r = e; l= newmark) { + if (newpos == newmark) { + if (newpos < size()) newpos++; + else newmark--; + } + if (Fl::event_clicks() > 1) { + newpos = line_end(newpos); + newmark = line_start(newmark); + } else { + newpos = word_end(newpos); + newmark = word_start(newmark); + } + } else { + if (Fl::event_clicks() > 1) { + newpos = line_start(newpos); + newmark = line_end(newmark); + } else { + newpos = word_start(newpos); + newmark = word_end(newmark); + } + } + // if the multiple click does not increase the selection, revert + // to single-click behavior: + if (!drag && (mark() > position() ? + (newmark >= position() && newpos <= mark()) : + (newmark >= mark() && newpos <= position()))) { + Fl::event_clicks(0); + newmark = newpos = l-value(); + } + } + position(newpos, newmark); +} + +int Fl_Input_::position(int p, int m) { + was_up_down = 0; + if (p<0) p = 0; + if (p>size()) p = size(); + if (m<0) m = 0; + if (m>size()) m = size(); + if (p == position_ && m == mark_) return 0; + //if (Fl::selection_owner() == this) Fl::selection_owner(0); + if (p != m) { + if (p != position_) minimal_update(position_, p); + if (m != mark_) minimal_update(mark_, m); + } else { + // new position is a cursor + if (position_ == mark_) { + // old position was just a cursor + if (Fl::focus() == this && !(damage()&FL_DAMAGE_EXPOSE)) { + minimal_update(position_); erase_cursor_only = 1; + } + } else { // old position was a selection + minimal_update(position_, mark_); + } + } + position_ = p; + mark_ = m; + return 1; +} + +int Fl_Input_::up_down_position(int i, int keepmark) { + // unlike before, i must be at the start of the line already! + + setfont(); + char buf[MAXBUF]; + const char* p = value()+i; + const char* e = expand(p, buf); + const char *l, *r, *t; + for (l = p, r = e; l e) {b = mark(); e = position();} + if (input_type() == FL_SECRET_INPUT) e = b; + Fl::copy(value()+b, e-b, clipboard); + return 1; + } + return 0; +} + +#define MAXFLOATSIZE 40 + +static char* undobuffer; +static int undobufferlength; +static Fl_Input_* undowidget; +static int undoat; // points after insertion +static int undocut; // number of characters deleted there +static int undoinsert; // number of characters inserted +static int yankcut; // length of valid contents of buffer, even if undocut=0 + +static void undobuffersize(int n) { + if (n > undobufferlength) { + if (undobuffer) { + do {undobufferlength *= 2;} while (undobufferlength < n); + undobuffer = (char*)realloc(undobuffer, undobufferlength); + } else { + undobufferlength = n+9; + undobuffer = (char*)malloc(undobufferlength); + } + } +} + +// all changes go through here, delete characters b-e and insert text: +int Fl_Input_::replace(int b, int e, const char* text, int ilen) { + + was_up_down = 0; + + if (b<0) b = 0; + if (e<0) e = 0; + if (b>size_) b = size_; + if (e>size_) e = size_; + if (e maximum_size_) { + ilen = maximum_size_-size_+(e-b); + if (ilen < 0) ilen = 0; + } + + put_in_buffer(size_+ilen); + + if (e>b) { + if (undowidget == this && b == undoat) { + undobuffersize(undocut+(e-b)); + memcpy(undobuffer+undocut, value_+b, e-b); + undocut += e-b; + } else if (undowidget == this && e == undoat && !undoinsert) { + undobuffersize(undocut+(e-b)); + memmove(undobuffer+(e-b), undobuffer, undocut); + memcpy(undobuffer, value_+b, e-b); + undocut += e-b; + } else if (undowidget == this && e == undoat && (e-b) 0 && !isspace(index(b) & 255) && index(b)!='\n') b--; + else + while (b > 0 && index(b)!='\n') b--; + } + + // make sure we redraw the old selection or cursor: + if (mark_ < b) b = mark_; + if (position_ < b) b = position_; + + minimal_update(b); + + mark_ = position_ = undoat; + + set_changed(); + if (when()&FL_WHEN_CHANGED) do_callback(); + return 1; +} + +int Fl_Input_::undo() { + was_up_down = 0; + if (undowidget != this || !undocut && !undoinsert) return 0; + + int ilen = undocut; + int xlen = undoinsert; + int b = undoat-xlen; + int b1 = b; + + put_in_buffer(size_+ilen); + + if (ilen) { + memmove(buffer+b+ilen, buffer+b, size_-b+1); + memcpy(buffer+b, undobuffer, ilen); + size_ += ilen; + b += ilen; + } + + if (xlen) { + undobuffersize(xlen); + memcpy(undobuffer, buffer+b, xlen); + memmove(buffer+b, buffer+b+xlen, size_-xlen-b+1); + size_ -= xlen; + } + + undocut = xlen; + if (xlen) yankcut = xlen; + undoinsert = ilen; + undoat = b; + mark_ = b /* -ilen */; + position_ = b; + + if (wrap()) + while (b1 > 0 && index(b1)!='\n') b1--; + minimal_update(b1); + set_changed(); + if (when()&FL_WHEN_CHANGED) do_callback(); + return 1; +} + +int Fl_Input_::copy_cuts() { + // put the yank buffer into the X clipboard + if (!yankcut || input_type()==FL_SECRET_INPUT) return 0; + Fl::copy(undobuffer, yankcut, 1); + return 1; +} + +void Fl_Input_::maybe_do_callback() { + if (changed() || (when()&FL_WHEN_NOT_CHANGED)) { + do_callback(); + } +} + +int Fl_Input_::handletext(int event, int X, int Y, int W, int H) { + switch (event) { + + case FL_ENTER: + case FL_MOVE: + if (active_r() && window()) window()->cursor(FL_CURSOR_INSERT); + return 1; + + case FL_LEAVE: + if (active_r() && window()) window()->cursor(FL_CURSOR_DEFAULT); + return 1; + + case FL_FOCUS: + if (mark_ == position_) { + minimal_update(size()+1); + } else //if (Fl::selection_owner() != this) + minimal_update(mark_, position_); + return 1; + + case FL_UNFOCUS: + if (active_r() && window()) window()->cursor(FL_CURSOR_DEFAULT); + if (mark_ == position_) { + if (!(damage()&FL_DAMAGE_EXPOSE)) {minimal_update(position_); erase_cursor_only = 1;} + } else //if (Fl::selection_owner() != this) + minimal_update(mark_, position_); + case FL_HIDE: + if (!readonly() && (when() & FL_WHEN_RELEASE)) + maybe_do_callback(); + return 1; + + case FL_PUSH: + if (active_r() && window()) window()->cursor(FL_CURSOR_INSERT); + + handle_mouse(X, Y, W, H, Fl::event_state(FL_SHIFT)); + + if (Fl::focus() != this) { + Fl::focus(this); + handle(FL_FOCUS); + } + return 1; + + case FL_DRAG: + handle_mouse(X, Y, W, H, 1); + return 1; + + case FL_RELEASE: + copy(0); + return 1; + + case FL_PASTE: { + // Don't allow pastes into readonly widgets... + if (readonly()) { + fl_beep(FL_BEEP_ERROR); + return 1; + } + + // See if we have anything to paste... + if (!Fl::event_text() || !Fl::event_length()) return 1; + + // strip trailing control characters and spaces before pasting: + const char* t = Fl::event_text(); + const char* e = t+Fl::event_length(); + if (input_type() != FL_MULTILINE_INPUT) while (e > t && isspace(*(e-1) & 255)) e--; + if (!t || e <= t) return 1; // Int/float stuff will crash without this test + if (input_type() == FL_INT_INPUT) { + while (isspace(*t & 255) && t < e) t ++; + const char *p = t; + if (*p == '+' || *p == '-') p ++; + if (strncmp(p, "0x", 2) == 0) { + p += 2; + while (isxdigit(*p & 255) && p < e) p ++; + } else { + while (isdigit(*p & 255) && p < e) p ++; + } + if (p < e) { + fl_beep(FL_BEEP_ERROR); + return 1; + } else return replace(0, size(), t, e - t); + } else if (input_type() == FL_FLOAT_INPUT) { + while (isspace(*t & 255) && t < e) t ++; + const char *p = t; + if (*p == '+' || *p == '-') p ++; + while (isdigit(*p & 255) && p < e) p ++; + if (*p == '.') { + p ++; + while (isdigit(*p & 255) && p < e) p ++; + if (*p == 'e' || *p == 'E') { + p ++; + if (*p == '+' || *p == '-') p ++; + while (isdigit(*p & 255) && p < e) p ++; + } + } + if (p < e) { + fl_beep(FL_BEEP_ERROR); + return 1; + } else return replace(0, size(), t, e - t); + } + return replace(position(), mark(), t, e-t);} + + default: + return 0; + } +} + +/*------------------------------*/ + +Fl_Input_::Fl_Input_(int X, int Y, int W, int H, const char* l) +: Fl_Widget(X, Y, W, H, l) { + box(FL_DOWN_BOX); + color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR); + align(FL_ALIGN_LEFT); + textsize_ = (uchar)FL_NORMAL_SIZE; + textfont_ = FL_HELVETICA; + textcolor_ = FL_FOREGROUND_COLOR; + cursor_color_ = FL_FOREGROUND_COLOR; // was FL_BLUE + mark_ = position_ = size_ = 0; + bufsize = 0; + buffer = 0; + value_ = ""; + xscroll_ = yscroll_ = 0; + maximum_size_ = 32767; +} + +void Fl_Input_::put_in_buffer(int len) { + if (value_ == buffer && bufsize > len) { + buffer[size_] = 0; + return; + } + if (!bufsize) { + if (len > size_) len += 9; // let a few characters insert before realloc + bufsize = len+1; + buffer = (char*)malloc(bufsize); + } else if (bufsize <= len) { + // we may need to move old value in case it points into buffer: + int moveit = (value_ >= buffer && value_ < buffer+bufsize); + // enlarge current buffer + if (len > size_) { + do {bufsize *= 2;} while (bufsize <= len); + } else { + bufsize = len+1; + } + // Note: the following code is equivalent to: + // + // if (moveit) value_ = value_ - buffer; + // char* nbuffer = (char*)realloc(buffer, bufsize); + // if (moveit) value_ = value_ + nbuffer; + // buffer = nbuffer; + // + // We just optimized the pointer arithmetic for value_... + // + char* nbuffer = (char*)realloc(buffer, bufsize); + if (moveit) value_ += (nbuffer-buffer); + buffer = nbuffer; + } + memmove(buffer, value_, size_); buffer[size_] = 0; + value_ = buffer; +} + +int Fl_Input_::static_value(const char* str, int len) { + clear_changed(); + if (undowidget == this) undowidget = 0; + if (str == value_ && len == size_) return 0; + if (len) { // non-empty new value: + if (xscroll_ || yscroll_) { + xscroll_ = yscroll_ = 0; + minimal_update(0); + } else { + int i = 0; + // find first different character: + if (value_) { + for (; i +#include +#include +#include +#include + + +// Some releases of the Cygwin JPEG libraries don't have a correctly +// updated header file for the INT32 data type; the following define +// from Shane Hill seems to be a usable workaround... + +#if defined(WIN32) && defined(__CYGWIN__) +# define XMD_H +#endif // WIN32 && __CYGWIN__ + + +extern "C" +{ +#ifdef HAVE_LIBJPEG +# include +#endif // HAVE_LIBJPEG +} + + +// +// Custom JPEG error handling structure... +// + +#ifdef HAVE_LIBJPEG +struct fl_jpeg_error_mgr { + jpeg_error_mgr pub_; // Destination manager... + jmp_buf errhand_; // Error handler +}; +#endif // HAVE_LIBJPEG + + +// +// Error handler for JPEG files... +// + +#ifdef HAVE_LIBJPEG +extern "C" { + static void + fl_jpeg_error_handler(j_common_ptr dinfo) { // I - Decompressor info + longjmp(((fl_jpeg_error_mgr *)(dinfo->err))->errhand_, 1); + } + + static void + fl_jpeg_output_handler(j_common_ptr) { // I - Decompressor info (not used) + } +} +#endif // HAVE_LIBJPEG + + +// +// 'Fl_JPEG_Image::Fl_JPEG_Image()' - Load a JPEG image file. +// + +Fl_JPEG_Image::Fl_JPEG_Image(const char *jpeg) // I - File to load + : Fl_RGB_Image(0,0,0) { +#ifdef HAVE_LIBJPEG + FILE *fp; // File pointer + jpeg_decompress_struct dinfo; // Decompressor info + fl_jpeg_error_mgr jerr; // Error handler info + JSAMPROW row; // Sample row pointer + + // the following variables are pointers allocating some private space that + // is not reset by 'setjmp()' + char* max_finish_decompress_err; // count errors and give up afer a while + char* max_destroy_decompress_err; // to avoid recusion and deadlock + + // Clear data... + alloc_array = 0; + array = (uchar *)0; + + // Open the image file... + if ((fp = fopen(jpeg, "rb")) == NULL) return; + + // Setup the decompressor info and read the header... + dinfo.err = jpeg_std_error((jpeg_error_mgr *)&jerr); + jerr.pub_.error_exit = fl_jpeg_error_handler; + jerr.pub_.output_message = fl_jpeg_output_handler; + + // Setup error loop variables + max_finish_decompress_err = (char*)malloc(1); // allocate space on the frame for error counters + max_destroy_decompress_err = (char*)malloc(1); // otherwise, the variables are reset on the longjmp + *max_finish_decompress_err=10; + *max_destroy_decompress_err=10; + + if (setjmp(jerr.errhand_)) + { + // JPEG error handling... + // if any of the cleanup routines hits another error, we would end up + // in a loop. So instead, we decrement max_err for some upper cleanup limit. + if ( ((*max_finish_decompress_err)-- > 0) && array) + jpeg_finish_decompress(&dinfo); + if ( (*max_destroy_decompress_err)-- > 0) + jpeg_destroy_decompress(&dinfo); + + fclose(fp); + + w(0); + h(0); + d(0); + + if (array) { + delete[] (uchar *)array; + array = 0; + alloc_array = 0; + } + + free(max_destroy_decompress_err); + free(max_finish_decompress_err); + + return; + } + + jpeg_create_decompress(&dinfo); + jpeg_stdio_src(&dinfo, fp); + jpeg_read_header(&dinfo, 1); + + dinfo.quantize_colors = (boolean)FALSE; + dinfo.out_color_space = JCS_RGB; + dinfo.out_color_components = 3; + dinfo.output_components = 3; + + jpeg_calc_output_dimensions(&dinfo); + + w(dinfo.output_width); + h(dinfo.output_height); + d(dinfo.output_components); + + array = new uchar[w() * h() * d()]; + alloc_array = 1; + + jpeg_start_decompress(&dinfo); + + while (dinfo.output_scanline < dinfo.output_height) { + row = (JSAMPROW)(array + + dinfo.output_scanline * dinfo.output_width * + dinfo.output_components); + jpeg_read_scanlines(&dinfo, &row, (JDIMENSION)1); + } + + jpeg_finish_decompress(&dinfo); + jpeg_destroy_decompress(&dinfo); + + free(max_destroy_decompress_err); + free(max_finish_decompress_err); + + fclose(fp); +#endif // HAVE_LIBJPEG +} + +// +// End of "$Id: Fl_JPEG_Image.cxx 5845 2007-05-20 00:01:06Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Light_Button.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Light_Button.cxx new file mode 100644 index 0000000..76d865a --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Light_Button.cxx @@ -0,0 +1,169 @@ +// +// "$Id: Fl_Light_Button.cxx 5721 2007-02-27 19:23:24Z matt $" +// +// Lighted button widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Subclass of Fl_Button where the "box" indicates whether it is +// pushed or not, and the "down box" is drawn small and square on +// the left to indicate the current state. + +// The default down_box of zero draws a rectangle designed to look +// just like Flame's buttons. + +#include +#include +#include +#include "flstring.h" + +void Fl_Light_Button::draw() { + if (box()) draw_box(this==Fl::pushed() ? fl_down(box()) : box(), color()); + Fl_Color col = value() ? (active_r() ? selection_color() : + fl_inactive(selection_color())) : color(); + int W; + int dx, dy; + + W = labelsize(); + dx = Fl::box_dx(box()) + 2; + dy = (h() - W) / 2; + // if (dy < 0) dy = 0; // neg. offset o.k. for vertical centering + + if (down_box()) { + // draw other down_box() styles: + switch (down_box()) { + case FL_DOWN_BOX : + case FL_UP_BOX : + case _FL_PLASTIC_DOWN_BOX : + case _FL_PLASTIC_UP_BOX : + // Check box... + draw_box(down_box(), x()+dx, y()+dy, W, W, FL_BACKGROUND2_COLOR); + if (value()) { + if (Fl::scheme() && !strcmp(Fl::scheme(), "gtk+")) { + fl_color(FL_SELECTION_COLOR); + } else { + fl_color(col); + } + int tx = x() + dx + 3; + int tw = W - 6; + int d1 = tw/3; + int d2 = tw-d1; + int ty = y() + dy + (W+d2)/2-d1-2; + for (int n = 0; n < 3; n++, ty++) { + fl_line(tx, ty, tx+d1, ty+d1); + fl_line(tx+d1, ty+d1, tx+tw-1, ty+d1-d2+1); + } + } + break; + case _FL_ROUND_DOWN_BOX : + case _FL_ROUND_UP_BOX : + // Radio button... + draw_box(down_box(), x()+dx, y()+dy, W, W, FL_BACKGROUND2_COLOR); + if (value()) { + int tW = (W - Fl::box_dw(down_box())) / 2 + 1; + if ((W - tW) & 1) tW++; // Make sure difference is even to center + int tdx = dx + (W - tW) / 2; + int tdy = dy + (W - tW) / 2; + + if (Fl::scheme() && !strcmp(Fl::scheme(), "gtk+")) { + fl_color(FL_SELECTION_COLOR); + tW --; + fl_pie(x() + tdx - 1, y() + tdy - 1, tW + 3, tW + 3, 0.0, 360.0); + fl_arc(x() + tdx - 1, y() + tdy - 1, tW + 3, tW + 3, 0.0, 360.0); + fl_color(fl_color_average(FL_WHITE, FL_SELECTION_COLOR, 0.2f)); + } else fl_color(col); + + switch (tW) { + // Larger circles draw fine... + default : + fl_pie(x() + tdx, y() + tdy, tW, tW, 0.0, 360.0); + break; + + // Small circles don't draw well on many systems... + case 6 : + fl_rectf(x() + tdx + 2, y() + tdy, tW - 4, tW); + fl_rectf(x() + tdx + 1, y() + tdy + 1, tW - 2, tW - 2); + fl_rectf(x() + tdx, y() + tdy + 2, tW, tW - 4); + break; + + case 5 : + case 4 : + case 3 : + fl_rectf(x() + tdx + 1, y() + tdy, tW - 2, tW); + fl_rectf(x() + tdx, y() + tdy + 1, tW, tW - 2); + break; + + case 2 : + case 1 : + fl_rectf(x() + tdx, y() + tdy, tW, tW); + break; + } + + if (Fl::scheme() && !strcmp(Fl::scheme(), "gtk+")) { + fl_color(fl_color_average(FL_WHITE, FL_SELECTION_COLOR, 0.5)); + fl_arc(x() + tdx, y() + tdy, tW + 1, tW + 1, 60.0, 180.0); + } + } + break; + default : + draw_box(down_box(), x()+dx, y()+dy, W, W, col); + break; + } + } else { + // if down_box() is zero, draw light button style: + int hh = h()-2*dy - 2; + int ww = W/2+1; + int xx = dx; + if (w() +#include +#include +#include +#include +#include "flstring.h" + +#ifdef __APPLE__ +# include +#endif + +int Fl_Menu_Item::size() const { + const Fl_Menu_Item* m = this; + int nest = 0; + for (;;) { + if (!m->text) { + if (!nest) return (m-this+1); + nest--; + } else if (m->flags & FL_SUBMENU) { + nest++; + } + m++; + } +} + +const Fl_Menu_Item* Fl_Menu_Item::next(int n) const { + if (n < 0) return 0; // this is so selected==-1 returns NULL + const Fl_Menu_Item* m = this; + int nest = 0; + if (!m->visible()) n++; + while (n>0) { + if (!m->text) { + if (!nest) return m; + nest--; + } else if (m->flags&FL_SUBMENU) { + nest++; + } + m++; + if (!nest && m->visible()) n--; + } + return m; +} + +// appearance of current menus are pulled from this parent widget: +static const Fl_Menu_* button; + +//////////////////////////////////////////////////////////////// + +// tiny window for title of menu: +class menutitle : public Fl_Menu_Window { + void draw(); +public: + const Fl_Menu_Item* menu; + menutitle(int X, int Y, int W, int H, const Fl_Menu_Item*); +}; + +// each vertical menu has one of these: +class menuwindow : public Fl_Menu_Window { + void draw(); + void drawentry(const Fl_Menu_Item*, int i, int erase); +public: + menutitle* title; + int handle(int); +#ifdef __APPLE__ + int early_hide_handle(int); +#endif + int itemheight; // zero == menubar + int numitems; + int selected; + int drawn_selected; // last redraw has this selected + const Fl_Menu_Item* menu; + menuwindow(const Fl_Menu_Item* m, int X, int Y, int W, int H, + const Fl_Menu_Item* picked, const Fl_Menu_Item* title, + int menubar = 0, int menubar_title = 0, int right_edge = 0); + ~menuwindow(); + void set_selected(int); + int find_selected(int mx, int my); + int titlex(int); + void autoscroll(int); + void position(int x, int y); + int is_inside(int x, int y); +}; + +#define LEADING 4 // extra vertical leading + +extern char fl_draw_shortcut; + +// width of label, including effect of & characters: +int Fl_Menu_Item::measure(int* hp, const Fl_Menu_* m) const { + Fl_Label l; + l.value = text; + l.image = 0; + l.deimage = 0; + l.type = labeltype_; + l.font = labelsize_ || labelfont_ ? labelfont_ : uchar(m ? m->textfont() : FL_HELVETICA); + l.size = labelsize_ ? labelsize_ : m ? m->textsize() : (uchar)FL_NORMAL_SIZE; + l.color = FL_FOREGROUND_COLOR; // this makes no difference? + fl_draw_shortcut = 1; + int w = 0; int h = 0; + l.measure(w, hp ? *hp : h); + fl_draw_shortcut = 0; + if (flags & (FL_MENU_TOGGLE|FL_MENU_RADIO)) w += 14; + return w; +} + +void Fl_Menu_Item::draw(int x, int y, int w, int h, const Fl_Menu_* m, + int selected) const { + Fl_Label l; + l.value = text; + l.image = 0; + l.deimage = 0; + l.type = labeltype_; + l.font = labelsize_ || labelfont_ ? labelfont_ : uchar(m ? m->textfont() : FL_HELVETICA); + l.size = labelsize_ ? labelsize_ : m ? m->textsize() : (uchar)FL_NORMAL_SIZE; + l.color = labelcolor_ ? labelcolor_ : m ? m->textcolor() : int(FL_FOREGROUND_COLOR); + if (!active()) l.color = fl_inactive((Fl_Color)l.color); + Fl_Color color = m ? m->color() : FL_GRAY; + if (selected) { + Fl_Color r = m ? m->selection_color() : FL_SELECTION_COLOR; + Fl_Boxtype b = m && m->down_box() ? m->down_box() : FL_FLAT_BOX; + if (fl_contrast(r,color)!=r) { // back compatability boxtypes + if (selected == 2) { // menu title + r = color; + b = m ? m->box() : FL_UP_BOX; + } else { + r = (Fl_Color)(FL_COLOR_CUBE-1); // white + l.color = fl_contrast((Fl_Color)labelcolor_, r); + } + } else { + l.color = fl_contrast((Fl_Color)labelcolor_, r); + } + if (selected == 2) { // menu title + fl_draw_box(b, x, y, w, h, r); + x += 3; + w -= 8; + } else { + fl_draw_box(b, x+1, y-(LEADING-2)/2, w-2, h+(LEADING-2), r); + } + } + + if (flags & (FL_MENU_TOGGLE|FL_MENU_RADIO)) { + int d = (h - FL_NORMAL_SIZE + 1) / 2; + int W = h - 2 * d; + + if (flags & FL_MENU_RADIO) { + fl_draw_box(FL_ROUND_DOWN_BOX, x+2, y+d, W, W, FL_BACKGROUND2_COLOR); + if (value()) { + int tW = (W - Fl::box_dw(FL_ROUND_DOWN_BOX)) / 2 + 1; + if ((W - tW) & 1) tW++; // Make sure difference is even to center + int td = Fl::box_dx(FL_ROUND_DOWN_BOX) + 1; + if (Fl::scheme()) { + // Offset the radio circle... + td ++; + + if (!strcmp(Fl::scheme(), "gtk+")) { + fl_color(FL_SELECTION_COLOR); + tW --; + fl_pie(x + td + 1, y + d + td - 1, tW + 3, tW + 3, 0.0, 360.0); + fl_arc(x + td + 1, y + d + td - 1, tW + 3, tW + 3, 0.0, 360.0); + fl_color(fl_color_average(FL_WHITE, FL_SELECTION_COLOR, 0.2f)); + } else fl_color(labelcolor_); + } else fl_color(labelcolor_); + + switch (tW) { + // Larger circles draw fine... + default : + fl_pie(x + td + 2, y + d + td, tW, tW, 0.0, 360.0); + break; + + // Small circles don't draw well on many systems... + case 6 : + fl_rectf(x + td + 4, y + d + td, tW - 4, tW); + fl_rectf(x + td + 3, y + d + td + 1, tW - 2, tW - 2); + fl_rectf(x + td + 2, y + d + td + 2, tW, tW - 4); + break; + + case 5 : + case 4 : + case 3 : + fl_rectf(x + td + 3, y + d + td, tW - 2, tW); + fl_rectf(x + td + 2, y + d + td + 1, tW, tW - 2); + break; + + case 2 : + case 1 : + fl_rectf(x + td + 2, y + d + td, tW, tW); + break; + } + + if (Fl::scheme() && !strcmp(Fl::scheme(), "gtk+")) { + fl_color(fl_color_average(FL_WHITE, FL_SELECTION_COLOR, 0.5)); + fl_arc(x + td + 2, y + d + td, tW + 1, tW + 1, 60.0, 180.0); + } + } + } else { + fl_draw_box(FL_DOWN_BOX, x+2, y+d, W, W, FL_BACKGROUND2_COLOR); + if (value()) { + if (Fl::scheme() && !strcmp(Fl::scheme(), "gtk+")) { + fl_color(FL_SELECTION_COLOR); + } else { + fl_color(labelcolor_); + } + int tx = x + 5; + int tw = W - 6; + int d1 = tw/3; + int d2 = tw-d1; + int ty = y + d + (W+d2)/2-d1-2; + for (int n = 0; n < 3; n++, ty++) { + fl_line(tx, ty, tx+d1, ty+d1); + fl_line(tx+d1, ty+d1, tx+tw-1, ty+d1-d2+1); + } + } + } + x += W + 3; + w -= W + 3; + } + + if (!fl_draw_shortcut) fl_draw_shortcut = 1; + l.draw(x+3, y, w>6 ? w-6 : 0, h, FL_ALIGN_LEFT); + fl_draw_shortcut = 0; +} + +menutitle::menutitle(int X, int Y, int W, int H, const Fl_Menu_Item* L) : + Fl_Menu_Window(X, Y, W, H, 0) { + end(); + set_modal(); + clear_border(); + menu = L; + if (L->labelcolor_ || Fl::scheme() || L->labeltype_ > FL_NO_LABEL) clear_overlay(); +} + +menuwindow::menuwindow(const Fl_Menu_Item* m, int X, int Y, int Wp, int Hp, + const Fl_Menu_Item* picked, const Fl_Menu_Item* t, + int menubar, int menubar_title, int right_edge) + : Fl_Menu_Window(X, Y, Wp, Hp, 0) +{ + int scr_x, scr_y, scr_w, scr_h; + int tx = X, ty = Y; + + Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h); + if (!right_edge || right_edge > scr_x+scr_w) right_edge = scr_x+scr_w; + + end(); + set_modal(); + clear_border(); + menu = m; + if (m) m = m->first(); // find the first item that needs to be rendered + drawn_selected = -1; + if (button) { + box(button->box()); + if (box() == FL_NO_BOX || box() == FL_FLAT_BOX) box(FL_UP_BOX); + } else { + box(FL_UP_BOX); + } + color(button && !Fl::scheme() ? button->color() : FL_GRAY); + selected = -1; + {int j = 0; + if (m) for (const Fl_Menu_Item* m1=m; ; m1 = m1->next(), j++) { + if (picked) { + if (m1 == picked) {selected = j; picked = 0;} + else if (m1 > picked) {selected = j-1; picked = 0; Wp = Hp = 0;} + } + if (!m1->text) break; + } + numitems = j;} + + if (menubar) { + itemheight = 0; + title = 0; + return; + } + + itemheight = 1; + + int hotKeysw = 0; + int Wtitle = 0; + int Htitle = 0; + if (t) Wtitle = t->measure(&Htitle, button) + 12; + int W = 0; + if (m) for (; m->text; m = m->next()) { + int hh; int w1 = m->measure(&hh, button); + if (hh+LEADING>itemheight) itemheight = hh+LEADING; + if (m->flags&(FL_SUBMENU|FL_SUBMENU_POINTER)) w1 += 14; + if (w1 > W) W = w1; + if (m->shortcut_) { + w1 = int(fl_width(fl_shortcut_label(m->shortcut_))) + 8; + if (w1 > hotKeysw) hotKeysw = w1; + } + if (m->labelcolor_ || Fl::scheme() || m->labeltype_ > FL_NO_LABEL) clear_overlay(); + } + if (selected >= 0 && !Wp) X -= W/2; + int BW = Fl::box_dx(box()); + W += hotKeysw+2*BW+7; + if (Wp > W) W = Wp; + if (Wtitle > W) W = Wtitle; + + if (X < scr_x) X = scr_x; if (X > scr_x+scr_w-W) X = right_edge-W; // X= scr_x+scr_w-W; + x(X); w(W); + h((numitems ? itemheight*numitems-LEADING : 0)+2*BW+3); + if (selected >= 0) + Y = Y+(Hp-itemheight)/2-selected*itemheight-BW; + else { + Y = Y+Hp; + // if the menu hits the bottom of the screen, we try to draw + // it above the menubar instead. We will not adjust any menu + // that has a selected item. + if (Y+h()>scr_y+scr_h && Y-h()>=scr_y) { + if (Hp>1) + // if we know the height of the Fl_Menu_, use it + Y = Y-Hp-h(); + else if (t) + // assume that the menubar item height relates to the first + // menuitem as well + Y = Y-itemheight-h()-Fl::box_dh(box()); + else + // draw the menu to the right + Y = Y-h()+itemheight+Fl::box_dy(box()); + } + } + if (m) y(Y); else {y(Y-2); w(1); h(1);} + + if (t) { + if (menubar_title) { + int dy = Fl::box_dy(button->box())+1; + int ht = button->h()-dy*2; + title = new menutitle(tx, ty-ht-dy, Wtitle, ht, t); + } else { + int dy = 2; + int ht = Htitle+2*BW+3; + title = new menutitle(X, Y-ht-dy, Wtitle, ht, t); + } + } else + title = 0; +} + +menuwindow::~menuwindow() { + hide(); + delete title; +} + +void menuwindow::position(int X, int Y) { + if (title) {title->position(X, title->y()+Y-y());} + Fl_Menu_Window::position(X, Y); + // x(X); y(Y); // don't wait for response from X +} + +// scroll so item i is visible on screen +void menuwindow::autoscroll(int n) { + int scr_x, scr_y, scr_w, scr_h; + int Y = y()+Fl::box_dx(box())+2+n*itemheight; + + Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h); + if (Y <= scr_y) Y = scr_y-Y+10; + else { + Y = Y+itemheight-scr_h-scr_y; + if (Y < 0) return; + Y = -Y-10; + } + Fl_Menu_Window::position(x(), y()+Y); + // y(y()+Y); // don't wait for response from X +} + +//////////////////////////////////////////////////////////////// + +void menuwindow::drawentry(const Fl_Menu_Item* m, int n, int eraseit) { + if (!m) return; // this happens if -1 is selected item and redrawn + + int BW = Fl::box_dx(box()); + int xx = BW; + int W = w(); + int ww = W-2*BW-1; + int yy = BW+1+n*itemheight; + int hh = itemheight - LEADING; + + if (eraseit && n != selected) { + fl_push_clip(xx+1, yy-(LEADING-2)/2, ww-2, hh+(LEADING-2)); + draw_box(box(), 0, 0, w(), h(), button ? button->color() : color()); + fl_pop_clip(); + } + + m->draw(xx, yy, ww, hh, button, n==selected); + + // the shortcuts and arrows assumme fl_color() was left set by draw(): + if (m->submenu()) { + int sz = (hh-7)&-2; + int y1 = yy+(hh-sz)/2; + int x1 = xx+ww-sz-3; + fl_polygon(x1+2, y1, x1+2, y1+sz, x1+sz/2+2, y1+sz/2); + } else if (m->shortcut_) { + Fl_Font f = m->labelsize_ || m->labelfont_ ? (Fl_Font)m->labelfont_ : + button ? button->textfont() : FL_HELVETICA; + fl_font(f, m->labelsize_ ? m->labelsize_ : + button ? button->textsize() : FL_NORMAL_SIZE); + fl_draw(fl_shortcut_label(m->shortcut_), xx, yy, ww-3, hh, FL_ALIGN_RIGHT); + } + + if (m->flags & FL_MENU_DIVIDER) { + fl_color(FL_DARK3); + fl_xyline(BW-1, yy+hh+(LEADING-2)/2, W-2*BW+2); + fl_color(FL_LIGHT3); + fl_xyline(BW-1, yy+hh+((LEADING-2)/2+1), W-2*BW+2); + } +} + +void menutitle::draw() { + menu->draw(0, 0, w(), h(), button, 2); +} + +void menuwindow::draw() { + if (damage() != FL_DAMAGE_CHILD) { // complete redraw + fl_draw_box(box(), 0, 0, w(), h(), button ? button->color() : color()); + if (menu) { + const Fl_Menu_Item* m; int j; + for (m=menu->first(), j=0; m->text; j++, m = m->next()) drawentry(m, j, 0); + } + } else { + if (damage() & FL_DAMAGE_CHILD && selected!=drawn_selected) { // change selection + drawentry(menu->next(drawn_selected), drawn_selected, 1); + drawentry(menu->next(selected), selected, 1); + } + } + drawn_selected = selected; +} + +void menuwindow::set_selected(int n) { + if (n != selected) {selected = n; damage(FL_DAMAGE_CHILD);} +} + +//////////////////////////////////////////////////////////////// + +int menuwindow::find_selected(int mx, int my) { + if (!menu || !menu->text) return -1; + mx -= x(); + my -= y(); + if (my < 0 || my >= h()) return -1; + if (!itemheight) { // menubar + int xx = 3; int n = 0; + const Fl_Menu_Item* m = menu ? menu->first() : 0; + for (; ; m = m->next(), n++) { + if (!m->text) return -1; + xx += m->measure(0, button) + 16; + if (xx > mx) break; + } + return n; + } + if (mx < Fl::box_dx(box()) || mx >= w()) return -1; + int n = (my-Fl::box_dx(box())-1)/itemheight; + if (n < 0 || n>=numitems) return -1; + return n; +} + +// return horizontal position for item n in a menubar: +int menuwindow::titlex(int n) { + const Fl_Menu_Item* m; + int xx = 3; + for (m=menu->first(); n--; m = m->next()) xx += m->measure(0, button) + 16; + return xx; +} + +// return 1, if the given root coordinates are inside the window +int menuwindow::is_inside(int mx, int my) { + if ( mx < x_root() || mx >= x_root() + w() || + my < y_root() || my >= y_root() + h()) { + return 0; + } + return 1; +} + +//////////////////////////////////////////////////////////////// +// Fl_Menu_Item::popup(...) + +// Because Fl::grab() is done, all events go to one of the menu windows. +// But the handle method needs to look at all of them to find out +// what item the user is pointing at. And it needs a whole lot +// of other state variables to determine what is going on with +// the currently displayed menus. +// So the main loop (handlemenu()) puts all the state in a structure +// and puts a pointer to it in a static location, so the handle() +// on menus can refer to it and alter it. The handle() method +// changes variables in this state to indicate what item is +// picked, but does not actually alter the display, instead the +// main loop does that. This is because the X mapping and unmapping +// of windows is slow, and we don't want to fall behind the events. + +// values for menustate.state: +#define INITIAL_STATE 0 // no mouse up or down since popup() called +#define PUSH_STATE 1 // mouse has been pushed on a normal item +#define DONE_STATE 2 // exit the popup, the current item was picked +#define MENU_PUSH_STATE 3 // mouse has been pushed on a menu title + +struct menustate { + const Fl_Menu_Item* current_item; // what mouse is pointing at + int menu_number; // which menu it is in + int item_number; // which item in that menu, -1 if none + menuwindow* p[20]; // pointers to menus + int nummenus; + int menubar; // if true p[0] is a menubar + int state; + menuwindow* fakemenu; // kludge for buttons in menubar + int is_inside(int mx, int my); +}; +static menustate* p; + +// return 1 if the coordinates are inside any of the menuwindows +int menustate::is_inside(int mx, int my) { + int i; + for (i=nummenus-1; i>=0; i--) { + if (p[i]->is_inside(mx, my)) + return 1; + } + return 0; +} + +static inline void setitem(const Fl_Menu_Item* i, int m, int n) { + p->current_item = i; + p->menu_number = m; + p->item_number = n; +} + +static void setitem(int m, int n) { + menustate &pp = *p; + pp.current_item = (n >= 0) ? pp.p[m]->menu->next(n) : 0; + pp.menu_number = m; + pp.item_number = n; +} + +static int forward(int menu) { // go to next item in menu menu if possible + menustate &pp = *p; + // Fl_Menu_Button can geberate menu=-1. This line fixes it and selectes the first item. + if (menu==-1) + menu = 0; + menuwindow &m = *(pp.p[menu]); + int item = (menu == pp.menu_number) ? pp.item_number : m.selected; + while (++item < m.numitems) { + const Fl_Menu_Item* m1 = m.menu->next(item); + if (m1->activevisible()) {setitem(m1, menu, item); return 1;} + } + return 0; +} + +static int backward(int menu) { // previous item in menu menu if possible + menustate &pp = *p; + menuwindow &m = *(pp.p[menu]); + int item = (menu == pp.menu_number) ? pp.item_number : m.selected; + if (item < 0) item = m.numitems; + while (--item >= 0) { + const Fl_Menu_Item* m1 = m.menu->next(item); + if (m1->activevisible()) {setitem(m1, menu, item); return 1;} + } + return 0; +} + +int menuwindow::handle(int e) { +#ifdef __APPLE__ + // This off-route takes care of the "detached menu" bug on OS X. + // Apple event handler requires that we hide all menu windows right + // now, so that Carbon can continue undisturbed with handling window + // manager events, like dragging the application window. + int ret = early_hide_handle(e); + menustate &pp = *p; + if (pp.state == DONE_STATE) { + hide(); + if (pp.fakemenu) { + pp.fakemenu->hide(); + if (pp.fakemenu->title) + pp.fakemenu->title->hide(); + } + int i = pp.nummenus; + while (i>0) { + menuwindow *mw = pp.p[--i]; + if (mw) { + mw->hide(); + if (mw->title) + mw->title->hide(); + } + } + } + return ret; +} + +int menuwindow::early_hide_handle(int e) { +#endif + menustate &pp = *p; + switch (e) { + case FL_KEYBOARD: + switch (Fl::event_key()) { + case FL_BackSpace: + case 0xFE20: // backtab + BACKTAB: + if (!backward(pp.menu_number)) {pp.item_number = -1;backward(pp.menu_number);} + return 1; + case FL_Up: + if (pp.menubar && pp.menu_number == 0) { + // Do nothing... + } else if (backward(pp.menu_number)) { + // Do nothing... + } else if (pp.menubar && pp.menu_number==1) { + setitem(0, pp.p[0]->selected); + } + return 1; + case FL_Tab: + if (Fl::event_shift()) goto BACKTAB; + case FL_Down: + if (pp.menu_number || !pp.menubar) { + if (!forward(pp.menu_number) && Fl::event_key()==FL_Tab) { + pp.item_number = -1; + forward(pp.menu_number); + } + } else if (pp.menu_number < pp.nummenus-1) { + forward(pp.menu_number+1); + } + return 1; + case FL_Right: + if (pp.menubar && (pp.menu_number<=0 || pp.menu_number==1 && pp.nummenus==2)) + forward(0); + else if (pp.menu_number < pp.nummenus-1) forward(pp.menu_number+1); + return 1; + case FL_Left: + if (pp.menubar && pp.menu_number<=1) backward(0); + else if (pp.menu_number>0) + setitem(pp.menu_number-1, pp.p[pp.menu_number-1]->selected); + return 1; + case FL_Enter: + case FL_KP_Enter: + case ' ': + pp.state = DONE_STATE; + return 1; + case FL_Escape: + setitem(0, -1, 0); + pp.state = DONE_STATE; + return 1; + } + break; + case FL_SHORTCUT: { + for (int mymenu = pp.nummenus; mymenu--;) { + menuwindow &mw = *(pp.p[mymenu]); + int item; const Fl_Menu_Item* m = mw.menu->find_shortcut(&item); + if (m) { + setitem(m, mymenu, item); + if (!m->submenu()) pp.state = DONE_STATE; + return 1; + } + }} break; + case FL_ENTER: + case FL_MOVE: + case FL_PUSH: + case FL_DRAG: { +#ifdef __QNX__ + // STR 704: workaround QNX X11 bug - in QNX a FL_MOVE event is sent + // right after FL_RELEASE... + if (pp.state == DONE_STATE) return 1; +#endif // __QNX__ + int mx = Fl::event_x_root(); + int my = Fl::event_y_root(); + int item=0; int mymenu = pp.nummenus-1; + // Clicking or dragging outside menu cancels it... + if ((!pp.menubar || mymenu) && !pp.is_inside(mx, my)) { + setitem(0, -1, 0); + if (e==FL_PUSH) + pp.state = DONE_STATE; + return 1; + } + for (mymenu = pp.nummenus-1; ; mymenu--) { + item = pp.p[mymenu]->find_selected(mx, my); + if (item >= 0) + break; + if (mymenu <= 0) { + // buttons in menubars must be deselected if we move outside of them! + if (pp.menu_number==-1 && e==FL_PUSH) { + pp.state = DONE_STATE; + return 1; + } + if (pp.current_item && pp.menu_number==0 && !pp.current_item->submenu()) { + if (e==FL_PUSH) + pp.state = DONE_STATE; + setitem(0, -1, 0); + return 1; + } + // all others can stay selected + return 0; + } + } + if (my == 0 && item > 0) setitem(mymenu, item - 1); + else setitem(mymenu, item); + if (e == FL_PUSH) { + if (pp.current_item && pp.current_item->submenu() // this is a menu title + && item != pp.p[mymenu]->selected // and it is not already on + && !pp.current_item->callback_) // and it does not have a callback + pp.state = MENU_PUSH_STATE; + else + pp.state = PUSH_STATE; + }} return 1; + case FL_RELEASE: + // Mouse must either be held down/dragged some, or this must be + // the second click (not the one that popped up the menu): + if (!Fl::event_is_click() || pp.state == PUSH_STATE || + pp.menubar && pp.current_item && !pp.current_item->submenu() // button + ) { +#if 0 // makes the check/radio items leave the menu up + const Fl_Menu_Item* m = pp.current_item; + if (m && button && (m->flags & (FL_MENU_TOGGLE|FL_MENU_RADIO))) { + ((Fl_Menu_*)button)->picked(m); + pp.p[pp.menu_number]->redraw(); + } else +#endif + // do nothing if they try to pick inactive items + if (!pp.current_item || pp.current_item->activevisible()) + pp.state = DONE_STATE; + } + return 1; + } + return Fl_Window::handle(e); +} + +const Fl_Menu_Item* Fl_Menu_Item::pulldown( + int X, int Y, int W, int H, + const Fl_Menu_Item* initial_item, + const Fl_Menu_* pbutton, + const Fl_Menu_Item* t, + int menubar) const +{ + Fl_Group::current(0); // fix possible user error... + + button = pbutton; + if (pbutton) { + for (Fl_Window* w = pbutton->window(); w; w = w->window()) { + X += w->x(); + Y += w->y(); + } + } else { + X += Fl::event_x_root()-Fl::event_x(); + Y += Fl::event_y_root()-Fl::event_y(); + } + menuwindow mw(this, X, Y, W, H, initial_item, t, menubar); + Fl::grab(mw); + menustate pp; p = &pp; + pp.p[0] = &mw; + pp.nummenus = 1; + pp.menubar = menubar; + pp.state = INITIAL_STATE; + pp.fakemenu = 0; // kludge for buttons in menubar + + // preselected item, pop up submenus if necessary: + if (initial_item && mw.selected >= 0) { + setitem(0, mw.selected); + goto STARTUP; + } + + pp.current_item = 0; pp.menu_number = 0; pp.item_number = -1; + if (menubar) { + // find the initial menu + if (!mw.handle(FL_DRAG)) { + Fl::release(); + return 0; + } + } + initial_item = pp.current_item; + if (initial_item) goto STARTUP; + + // the main loop, runs until p.state goes to DONE_STATE: + for (;;) { + + // make sure all the menus are shown: + {for (int k = menubar; k < pp.nummenus; k++) + if (!pp.p[k]->shown()) { + if (pp.p[k]->title) pp.p[k]->title->show(); + pp.p[k]->show(); + } + } + + // get events: + {const Fl_Menu_Item* oldi = pp.current_item; + Fl::wait(); + if (pp.state == DONE_STATE) break; // done. + if (pp.current_item == oldi) continue;} + // only do rest if item changes: + + delete pp.fakemenu; pp.fakemenu = 0; // turn off "menubar button" + + if (!pp.current_item) { // pointing at nothing + // turn off selection in deepest menu, but don't erase other menus: + pp.p[pp.nummenus-1]->set_selected(-1); + continue; + } + + delete pp.fakemenu; pp.fakemenu = 0; + initial_item = 0; // stop the startup code + pp.p[pp.menu_number]->autoscroll(pp.item_number); + + STARTUP: + menuwindow& cw = *pp.p[pp.menu_number]; + const Fl_Menu_Item* m = pp.current_item; + if (!m->activevisible()) { // pointing at inactive item + cw.set_selected(-1); + initial_item = 0; // turn off startup code + continue; + } + cw.set_selected(pp.item_number); + + if (m==initial_item) initial_item=0; // stop the startup code if item found + if (m->submenu()) { + const Fl_Menu_Item* title = m; + const Fl_Menu_Item* menutable; + if (m->flags&FL_SUBMENU) menutable = m+1; + else menutable = (Fl_Menu_Item*)(m)->user_data_; + // figure out where new menu goes: + int nX, nY; + if (!pp.menu_number && pp.menubar) { // menu off a menubar: + nX = cw.x() + cw.titlex(pp.item_number); + nY = cw.y() + cw.h(); + initial_item = 0; + } else { + nX = cw.x() + cw.w(); + nY = cw.y() + pp.item_number * cw.itemheight; + title = 0; + } + if (initial_item) { // bring up submenu containing initial item: + menuwindow* n = new menuwindow(menutable,X,Y,W,H,initial_item,title,0,0,cw.x()); + pp.p[pp.nummenus++] = n; + // move all earlier menus to line up with this new one: + if (n->selected>=0) { + int dy = n->y()-nY; + int dx = n->x()-nX; + for (int menu = 0; menu <= pp.menu_number; menu++) { + menuwindow* tt = pp.p[menu]; + int nx = tt->x()+dx; if (nx < 0) {nx = 0; dx = -tt->x();} + int ny = tt->y()+dy; if (ny < 0) {ny = 0; dy = -tt->y();} + tt->position(nx, ny); + } + setitem(pp.nummenus-1, n->selected); + goto STARTUP; + } + } else if (pp.nummenus > pp.menu_number+1 && + pp.p[pp.menu_number+1]->menu == menutable) { + // the menu is already up: + while (pp.nummenus > pp.menu_number+2) delete pp.p[--pp.nummenus]; + pp.p[pp.nummenus-1]->set_selected(-1); + } else { + // delete all the old menus and create new one: + while (pp.nummenus > pp.menu_number+1) delete pp.p[--pp.nummenus]; + pp.p[pp.nummenus++]= new menuwindow(menutable, nX, nY, + title?1:0, 0, 0, title, 0, menubar, cw.x()); + } + } else { // !m->submenu(): + while (pp.nummenus > pp.menu_number+1) delete pp.p[--pp.nummenus]; + if (!pp.menu_number && pp.menubar) { + // kludge so "menubar buttons" turn "on" by using menu title: + pp.fakemenu = new menuwindow(0, + cw.x()+cw.titlex(pp.item_number), + cw.y()+cw.h(), 0, 0, + 0, m, 0, 1); + pp.fakemenu->title->show(); + } + } + } + const Fl_Menu_Item* m = pp.current_item; + Fl::release(); + delete pp.fakemenu; + while (pp.nummenus>1) delete pp.p[--pp.nummenus]; + mw.hide(); + return m; +} + +const Fl_Menu_Item* +Fl_Menu_Item::popup( + int X, int Y, + const char* title, + const Fl_Menu_Item* picked, + const Fl_Menu_* but + ) const +{ + static Fl_Menu_Item dummy; // static so it is all zeros + dummy.text = title; + return pulldown(X, Y, 0, 0, picked, but, title ? &dummy : 0); +} + +// Search only the top level menu for a shortcut. Either &x in the +// label or the shortcut fields are used: +const Fl_Menu_Item* Fl_Menu_Item::find_shortcut(int* ip) const { + const Fl_Menu_Item* m = first(); + if (m) for (int ii = 0; m->text; m = m->next(), ii++) { + if (m->activevisible()) { + if (Fl::test_shortcut(m->shortcut_) + || Fl_Widget::test_shortcut(m->text)) { + if (ip) *ip=ii; + return m; + } + } + } + return 0; +} + +// Recursive search of all submenus for anything with this key as a +// shortcut. Only uses the shortcut field, ignores &x in the labels: +const Fl_Menu_Item* Fl_Menu_Item::test_shortcut() const { + const Fl_Menu_Item* m = first(); + const Fl_Menu_Item* ret = 0; + if (m) for (; m->text; m = m->next()) { + if (m->activevisible()) { + // return immediately any match of an item in top level menu: + if (Fl::test_shortcut(m->shortcut_)) return m; + // if (Fl_Widget::test_shortcut(m->text)) return m; + // only return matches from lower menu if nothing found in top menu: + if (!ret && m->submenu()) { + const Fl_Menu_Item* s = + (m->flags&FL_SUBMENU) ? m+1:(const Fl_Menu_Item*)m->user_data_; + ret = s->test_shortcut(); + } + } + } + return ret; +} + +// +// End of "$Id: Fl_Menu.cxx 6478 2008-10-19 21:28:06Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Menu_.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Menu_.cxx new file mode 100644 index 0000000..f8a8f59 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Menu_.cxx @@ -0,0 +1,232 @@ +// +// "$Id: Fl_Menu_.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Common menu code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This is a base class for all items that have a menu: +// Fl_Menu_Bar, Fl_Menu_Button, Fl_Choice +// This provides storage for a menu item, functions to add/modify/delete +// items, and a call for when the user picks a menu item. + +// More code in Fl_Menu_add.cxx + +#include +#include +#include "flstring.h" +#include +#include + +// Set 'pathname' of specified menuitem +// If finditem==NULL, mvalue() is used (the most recently picked menuitem) +// Returns: +// 0 : OK +// -1 : item not found (name="") +// -2 : 'name' not large enough (name="") +// +#define SAFE_STRCAT(s) \ + { len += strlen(s); if ( len >= namelen ) { *name='\0'; return(-2); } else strcat(name,(s)); } +int Fl_Menu_::item_pathname(char *name, int namelen, const Fl_Menu_Item *finditem) const { + int len = 0; + finditem = finditem ? finditem : mvalue(); + name[0] = '\0'; + for ( int t=0; tsubmenu() ) { // submenu? descend + if (*name) SAFE_STRCAT("/"); + if (m->label()) SAFE_STRCAT(m->label()); + } else { + if (m->label()) { // menu item? + if ( m == finditem ) { // found? tack on itemname, done. + SAFE_STRCAT("/"); + SAFE_STRCAT(m->label()); + return(0); + } + } else { // end of submenu? pop + char *ss = strrchr(name, '/'); + if ( ss ) { *ss = 0; len = strlen(name); } // "File/Edit" -> "File" + else { name[0] = '\0'; len = 0; } // "File" -> "" + continue; + } + } + } + *name = '\0'; + return(-1); // item not found +} + +// FIND MENU ITEM INDEX, GIVEN MENU PATHNAME +// eg. "Edit/Copy" +// Will also return submenus, eg. "Edit" +// Returns NULL if not found. +// +const Fl_Menu_Item * +Fl_Menu_::find_item(const char *name) +{ + char menupath[1024] = ""; // File/Export + + for ( int t=0; t < size(); t++ ) { + Fl_Menu_Item *m = menu_ + t; + + if (m->flags&FL_SUBMENU) { + // IT'S A SUBMENU + // we do not support searches through FL_SUBMENU_POINTER links + if (menupath[0]) strlcat(menupath, "/", sizeof(menupath)); + strlcat(menupath, m->label(), sizeof(menupath)); + if (!strcmp(menupath, name)) return m; + } else { + if (!m->label()) { + // END OF SUBMENU? Pop back one level. + char *ss = strrchr(menupath, '/'); + if ( ss ) *ss = 0; + else menupath[0] = '\0'; + continue; + } + + // IT'S A MENU ITEM + char itempath[1024]; // eg. Edit/Copy + strcpy(itempath, menupath); + if (itempath[0]) strlcat(itempath, "/", sizeof(itempath)); + strlcat(itempath, m->label(), sizeof(itempath)); + if (!strcmp(itempath, name)) return m; + } + } + + return (const Fl_Menu_Item *)0; +} + +int Fl_Menu_::value(const Fl_Menu_Item* m) { + clear_changed(); + if (value_ != m) {value_ = m; return 1;} + return 0; +} + +// When user picks a menu item, call this. It will do the callback. +// Unfortunatly this also casts away const for the checkboxes, but this +// was necessary so non-checkbox menus can really be declared const... +const Fl_Menu_Item* Fl_Menu_::picked(const Fl_Menu_Item* v) { + if (v) { + if (v->radio()) { + if (!v->value()) { // they are turning on a radio item + set_changed(); + ((Fl_Menu_Item*)v)->setonly(); + } + redraw(); + } else if (v->flags & FL_MENU_TOGGLE) { + set_changed(); + ((Fl_Menu_Item*)v)->flags ^= FL_MENU_VALUE; + redraw(); + } else if (v != value_) { // normal item + set_changed(); + } + value_ = v; + if (when()&(FL_WHEN_CHANGED|FL_WHEN_RELEASE)) { + if (changed() || when()&FL_WHEN_NOT_CHANGED) { + if (value_ && value_->callback_) value_->do_callback((Fl_Widget*)this); + else do_callback(); + } + } + } + return v; +} + +// turn on one of a set of radio buttons +void Fl_Menu_Item::setonly() { + flags |= FL_MENU_RADIO | FL_MENU_VALUE; + Fl_Menu_Item* j; + for (j = this; ; ) { // go down + if (j->flags & FL_MENU_DIVIDER) break; // stop on divider lines + j++; + if (!j->text || !j->radio()) break; // stop after group + j->clear(); + } + for (j = this-1; ; j--) { // go up + if (!j->text || (j->flags&FL_MENU_DIVIDER) || !j->radio()) break; + j->clear(); + } +} + +Fl_Menu_::Fl_Menu_(int X,int Y,int W,int H,const char* l) +: Fl_Widget(X,Y,W,H,l) { + set_flag(SHORTCUT_LABEL); + box(FL_UP_BOX); + when(FL_WHEN_RELEASE_ALWAYS); + value_ = menu_ = 0; + alloc = 0; + selection_color(FL_SELECTION_COLOR); + textfont(FL_HELVETICA); + textsize((uchar)FL_NORMAL_SIZE); + textcolor(FL_FOREGROUND_COLOR); + down_box(FL_NO_BOX); +} + +int Fl_Menu_::size() const { + if (!menu_) return 0; + return menu_->size(); +} + +void Fl_Menu_::menu(const Fl_Menu_Item* m) { + clear(); + value_ = menu_ = (Fl_Menu_Item*)m; +} + +// this version is ok with new Fl_Menu_add code with fl_menu_array_owner: + +void Fl_Menu_::copy(const Fl_Menu_Item* m, void* ud) { + int n = m->size(); + Fl_Menu_Item* newMenu = new Fl_Menu_Item[n]; + memcpy(newMenu, m, n*sizeof(Fl_Menu_Item)); + menu(newMenu); + alloc = 1; // make destructor free array, but not strings + // for convienence, provide way to change all the user data pointers: + if (ud) for (; n--;) { + if (newMenu->callback_) newMenu->user_data_ = ud; + newMenu++; + } +} + +Fl_Menu_::~Fl_Menu_() { + clear(); +} + +// Fl_Menu::add() uses this to indicate the owner of the dynamically- +// expanding array. We must not free this array: +Fl_Menu_* fl_menu_array_owner = 0; + +void Fl_Menu_::clear() { + if (alloc) { + if (alloc>1) for (int i = size(); i--;) + if (menu_[i].text) free((void*)menu_[i].text); + if (this == fl_menu_array_owner) + fl_menu_array_owner = 0; + else + delete[] menu_; + menu_ = 0; + value_ = 0; + alloc = 0; + } +} + +// +// End of "$Id: Fl_Menu_.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Menu_Bar.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Menu_Bar.cxx new file mode 100644 index 0000000..d8bba77 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Menu_Bar.cxx @@ -0,0 +1,78 @@ +// +// "$Id: Fl_Menu_Bar.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Menu bar widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include + +void Fl_Menu_Bar::draw() { + draw_box(); + if (!menu() || !menu()->text) return; + const Fl_Menu_Item* m; + int X = x()+6; + for (m=menu()->first(); m->text; m = m->next()) { + int W = m->measure(0,this) + 16; + m->draw(X, y(), W, h(), this); + X += W; + if (m->flags & FL_MENU_DIVIDER) { + int y1 = y() + Fl::box_dy(box()); + int y2 = y1 + h() - Fl::box_dh(box()) - 1; + + // Draw a vertical divider between menus... + fl_color(FL_DARK3); + fl_yxline(X - 6, y1, y2); + fl_color(FL_LIGHT3); + fl_yxline(X - 5, y1, y2); + } + } +} + +int Fl_Menu_Bar::handle(int event) { + const Fl_Menu_Item* v; + if (menu() && menu()->text) switch (event) { + case FL_ENTER: + case FL_LEAVE: + return 1; + case FL_PUSH: + v = 0; + J1: + v = menu()->pulldown(x(), y(), w(), h(), v, this, 0, 1); + picked(v); + return 1; + case FL_SHORTCUT: + if (visible_r()) { + v = menu()->find_shortcut(); + if (v && v->submenu()) goto J1; + } + return test_shortcut() != 0; + } + return 0; +} + +// +// End of "$Id: Fl_Menu_Bar.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Menu_Button.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Menu_Button.cxx new file mode 100644 index 0000000..3097434 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Menu_Button.cxx @@ -0,0 +1,111 @@ +// +// "$Id: Fl_Menu_Button.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Menu button widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include + + +static Fl_Menu_Button *pressed_menu_button_ = 0; + +void Fl_Menu_Button::draw() { + if (!box() || type()) return; + draw_box(pressed_menu_button_ == this ? fl_down(box()) : box(), color()); + draw_label(); + if (Fl::focus() == this) draw_focus(); + if (box() == FL_FLAT_BOX) return; // for XForms compatability + int H = (labelsize()-3)&-2; + int X = x()+w()-H*2; + int Y = y()+(h()-H)/2; + fl_color(active_r() ? FL_DARK3 : fl_inactive(FL_DARK3)); + fl_line(X+H/2, Y+H, X, Y, X+H, Y); + fl_color(active_r() ? FL_LIGHT3 : fl_inactive(FL_LIGHT3)); + fl_line(X+H, Y, X+H/2, Y+H); +} + +const Fl_Menu_Item* Fl_Menu_Button::popup() { + const Fl_Menu_Item* m; + pressed_menu_button_ = this; + redraw(); + Fl_Widget *mb = this; + Fl::watch_widget_pointer(mb); + if (!box() || type()) { + m = menu()->popup(Fl::event_x(), Fl::event_y(), label(), mvalue(), this); + } else { + m = menu()->pulldown(x(), y(), w(), h(), 0, this); + } + picked(m); + pressed_menu_button_ = 0; + if (mb) mb->redraw(); + Fl::release_widget_pointer(mb); + return m; +} + +int Fl_Menu_Button::handle(int e) { + if (!menu() || !menu()->text) return 0; + switch (e) { + case FL_ENTER: + case FL_LEAVE: + return (box() && !type()) ? 1 : 0; + case FL_PUSH: + if (!box()) { + if (Fl::event_button() != 3) return 0; + } else if (type()) { + if (!(type() & (1 << (Fl::event_button()-1)))) return 0; + } + if (Fl::visible_focus()) Fl::focus(this); + popup(); + return 1; + case FL_KEYBOARD: + if (!box()) return 0; + if (Fl::event_key() == ' ' && + !(Fl::event_state() & (FL_SHIFT | FL_CTRL | FL_ALT | FL_META))) { + popup(); + return 1; + } else return 0; + case FL_SHORTCUT: + if (Fl_Widget::test_shortcut()) {popup(); return 1;} + return test_shortcut() != 0; + case FL_FOCUS: + case FL_UNFOCUS: + if (box() && Fl::visible_focus()) { + redraw(); + return 1; + } + default: + return 0; + } +} + +Fl_Menu_Button::Fl_Menu_Button(int X,int Y,int W,int H,const char *l) +: Fl_Menu_(X,Y,W,H,l) { + down_box(FL_NO_BOX); +} + +// +// End of "$Id: Fl_Menu_Button.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Menu_Window.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Menu_Window.cxx new file mode 100644 index 0000000..e89ae28 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Menu_Window.cxx @@ -0,0 +1,103 @@ +// +// "$Id: Fl_Menu_Window.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Menu window code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This is the window type used by Fl_Menu to make the pop-ups. +// It draws in the overlay planes if possible. + +// Also here is the implementation of the mouse & keyboard grab, +// which are used so that clicks outside the program's windows +// can be used to dismiss the menus. + +#include +#include +#include +#include +#include + +// WIN32 note: HAVE_OVERLAY is false +#if HAVE_OVERLAY +extern XVisualInfo *fl_find_overlay_visual(); +extern XVisualInfo *fl_overlay_visual; +extern Colormap fl_overlay_colormap; +extern unsigned long fl_transparent_pixel; +static GC gc; // the GC used by all X windows +extern uchar fl_overlay; // changes how fl_color(x) works +#endif + +#include + +void Fl_Menu_Window::show() { +#if HAVE_OVERLAY + if (!shown() && overlay() && fl_find_overlay_visual()) { + XInstallColormap(fl_display, fl_overlay_colormap); + fl_background_pixel = int(fl_transparent_pixel); + Fl_X::make_xid(this, fl_overlay_visual, fl_overlay_colormap); + fl_background_pixel = -1; + } else +#endif + Fl_Single_Window::show(); +} + +void Fl_Menu_Window::flush() { +#if HAVE_OVERLAY + if (!fl_overlay_visual || !overlay()) {Fl_Single_Window::flush(); return;} + Fl_X *myi = Fl_X::i(this); + fl_window = myi->xid; + if (!gc) gc = XCreateGC(fl_display, myi->xid, 0, 0); + fl_gc = gc; + fl_overlay = 1; + fl_clip_region(myi->region); myi->region = 0; current_ = this; + draw(); + fl_overlay = 0; +#else + Fl_Single_Window::flush(); +#endif +} + +void Fl_Menu_Window::erase() { +#if HAVE_OVERLAY + if (!gc || !shown()) return; +//XSetForeground(fl_display, gc, 0); +//XFillRectangle(fl_display, fl_xid(this), gc, 0, 0, w(), h()); + XClearWindow(fl_display, fl_xid(this)); +#endif +} + +// Fix the colormap flashing on Maximum Impact Graphics by erasing the +// menu before unmapping it: +void Fl_Menu_Window::hide() { + erase(); + Fl_Single_Window::hide(); +} + +Fl_Menu_Window::~Fl_Menu_Window() { + hide(); +} + +// +// End of "$Id: Fl_Menu_Window.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Menu_add.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Menu_add.cxx new file mode 100644 index 0000000..2b046e6 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Menu_add.cxx @@ -0,0 +1,268 @@ +// +// "$Id: Fl_Menu_add.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Menu utilities for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Methods to alter the menu in an Fl_Menu_ widget. + +// These are for Forms emulation and for dynamically changing the +// menus. They are in this source file so they are not linked in if +// not used, which is what will happen if the the program only uses +// constant menu tables. + +// Not at all guaranteed to be Forms compatable, especially with any +// string with a % sign in it! + +#include +#include "flstring.h" +#include +#include + +// If the array is this, we will double-reallocate as necessary: +static Fl_Menu_Item* local_array = 0; +static int local_array_alloc = 0; // number allocated +static int local_array_size = 0; // == size(local_array) +extern Fl_Menu_* fl_menu_array_owner; // in Fl_Menu_.cxx + +// For historical reasons there are matching methods that work on a +// user-allocated array of Fl_Menu_Item. These methods are quite +// depreciated and should not be used. These old methods use the +// above pointers to detect if the array belongs to an Fl_Menu_ +// widget, and if so it reallocates as necessary. + +// Insert a single Fl_Menu_Item into an array of size at offset n, +// if this is local_array it will be reallocated if needed. +static Fl_Menu_Item* insert( + Fl_Menu_Item* array, int size, + int n, + const char *text, + int flags +) { + if (array == local_array && size >= local_array_alloc) { + local_array_alloc = 2*size; + Fl_Menu_Item* newarray = new Fl_Menu_Item[local_array_alloc]; + memmove(newarray, array, size*sizeof(Fl_Menu_Item)); + delete[] local_array; + local_array = array = newarray; + } + // move all the later items: + memmove(array+n+1, array+n, sizeof(Fl_Menu_Item)*(size-n)); + // create the new item: + Fl_Menu_Item* m = array+n; + m->text = text ? strdup(text) : 0; + m->shortcut_ = 0; + m->callback_ = 0; + m->user_data_ = 0; + m->flags = flags; + m->labeltype_ = m->labelfont_ = m->labelsize_ = m->labelcolor_ = 0; + return array; +} + +// Comparison that does not care about deleted '&' signs: +static int compare(const char* a, const char* b) { + for (;;) { + int n = *a-*b; + if (n) { + if (*a == '&') a++; + else if (*b == '&') b++; + else return n; + } else if (*a) { + a++; b++; + } else { + return 0; + } + } +} + +// Add an item. The text is split at '/' characters to automatically +// produce submenus (actually a totally unnecessary feature as you can +// now add submenu titles directly by setting SUBMENU in the flags): +int Fl_Menu_Item::add( + const char *mytext, + int sc, + Fl_Callback *cb, + void *data, + int myflags +) { + Fl_Menu_Item *array = this; + Fl_Menu_Item *m = this; + const char *p; + char *q; + char buf[1024]; + + int msize = array==local_array ? local_array_size : array->size(); + int flags1 = 0; + const char* item; + + // split at slashes to make submenus: + for (;;) { + + // leading slash makes us assumme it is a filename: + if (*mytext == '/') {item = mytext; break;} + + // leading underscore causes divider line: + if (*mytext == '_') {mytext++; flags1 = FL_MENU_DIVIDER;} + + // copy to buf, changing \x to x: + q = buf; + for (p=mytext; *p && *p != '/'; *q++ = *p++) if (*p=='\\' && p[1]) p++; + *q = 0; + + item = buf; + if (*p != '/') break; /* not a menu title */ + mytext = p+1; /* point at item title */ + + /* find a matching menu title: */ + for (; m->text; m = m->next()) + if (m->flags&FL_SUBMENU && !compare(item, m->text)) break; + + if (!m->text) { /* create a new menu */ + int n = m-array; + array = insert(array, msize, n, item, FL_SUBMENU|flags1); + msize++; + array = insert(array, msize, n+1, 0, 0); + msize++; + m = array+n; + } + m++; /* go into the submenu */ + flags1 = 0; + } + + /* find a matching menu item: */ + for (; m->text; m = m->next()) + if (!(m->flags&FL_SUBMENU) && !compare(m->text,item)) break; + + if (!m->text) { /* add a new menu item */ + int n = m-array; + array = insert(array, msize, n, item, myflags|flags1); + msize++; + if (myflags & FL_SUBMENU) { // add submenu delimiter + array = insert(array, msize, n+1, 0, 0); + msize++; + } + m = array+n; + } + + /* fill it in */ + m->shortcut_ = sc; + m->callback_ = cb; + m->user_data_ = data; + m->flags = myflags|flags1; + + if (array == local_array) local_array_size = msize; + return m-array; +} + +int Fl_Menu_::add(const char *t, int s, Fl_Callback *c,void *v,int f) { + // make this widget own the local array: + if (this != fl_menu_array_owner) { + if (fl_menu_array_owner) { + Fl_Menu_* o = fl_menu_array_owner; + // the previous owner get's its own correctly-sized array: + int value_offset = o->value_-local_array; + int n = local_array_size; + Fl_Menu_Item* newMenu = o->menu_ = new Fl_Menu_Item[n]; + memcpy(newMenu, local_array, n*sizeof(Fl_Menu_Item)); + if (o->value_) o->value_ = newMenu+value_offset; + } + if (menu_) { + // this already has a menu array, use it as the local one: + delete[] local_array; + if (!alloc) copy(menu_); // duplicate a user-provided static array + // add to the menu's current array: + local_array_alloc = local_array_size = size(); + local_array = menu_; + } else { + // start with a blank array: + alloc = 2; // indicates that the strings can be freed + if (local_array) { + menu_ = local_array; + } else { + local_array_alloc = 15; + local_array = menu_ = new Fl_Menu_Item[local_array_alloc]; + memset(local_array, 0, sizeof(Fl_Menu_Item) * local_array_alloc); + } + memset(menu_, 0, sizeof(Fl_Menu_Item)); + local_array_size = 1; + } + fl_menu_array_owner = this; + } + int r = menu_->add(t,s,c,v,f); + // if it rellocated array we must fix the pointer: + int value_offset = value_-menu_; + menu_ = local_array; // in case it reallocated it + if (value_) value_ = menu_+value_offset; + return r; +} + +// This is a Forms (and SGI GL library) compatable add function, it +// adds many menu items, with '|' seperating the menu items, and tab +// seperating the menu item names from an optional shortcut string. +int Fl_Menu_::add(const char *str) { + char buf[1024]; + int r = 0; + while (*str) { + int sc = 0; + char *c; + for (c = buf; c < (buf + sizeof(buf) - 2) && *str && *str != '|'; str++) { + if (*str == '\t') {*c++ = 0; sc = fl_old_shortcut(str);} + else *c++ = *str; + } + *c = 0; + r = add(buf, sc, 0, 0, 0); + if (*str) str++; + } + return r; +} + +void Fl_Menu_::replace(int i, const char *str) { + if (i<0 || i>=size()) return; + if (!alloc) copy(menu_); + if (alloc > 1) { + free((void *)menu_[i].text); + str = strdup(str); + } + menu_[i].text = str; +} + +void Fl_Menu_::remove(int i) { + int n = size(); + if (i<0 || i>=n) return; + if (!alloc) copy(menu_); + // find the next item, skipping submenus: + Fl_Menu_Item* item = menu_+i; + const Fl_Menu_Item* next_item = item->next(); + // delete the text only if all items were created with add(): + if (alloc > 1) { + for (Fl_Menu_Item* m = item; m < next_item; m++) + if (m->text) free((void*)(m->text)); + } + // MRS: "n" is the menu size(), which includes the trailing NULL entry... + memmove(item, next_item, (menu_+n-next_item)*sizeof(Fl_Menu_Item)); +} + +// +// End of "$Id: Fl_Menu_add.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Menu_global.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Menu_global.cxx new file mode 100644 index 0000000..3238fad --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Menu_global.cxx @@ -0,0 +1,50 @@ +// +// "$Id: Fl_Menu_global.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Global menu shortcut code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Make all the shortcuts in this menu global. +// Currently only one menu at a time and you cannot destruct the menu, +// is this sufficient? + +#include +#include + +static Fl_Menu_* the_widget; + +static int handler(int e) { + if (e != FL_SHORTCUT || Fl::modal()) return 0; + Fl::first_window(the_widget->window()); + return the_widget->handle(e); +} + +void Fl_Menu_::global() { + if (!the_widget) Fl::add_handler(handler); + the_widget = this; +} + +// +// End of "$Id: Fl_Menu_global.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Multi_Label.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Multi_Label.cxx new file mode 100644 index 0000000..eafe3c8 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Multi_Label.cxx @@ -0,0 +1,80 @@ +// +// "$Id: Fl_Multi_Label.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Multi-label widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Allows two labels to be used on a widget (by having one of them +// be one of these it allows an infinte number!) + +#include +#include +#include +#include + +static void multi_labeltype( + const Fl_Label* o, int x, int y, int w, int h, Fl_Align a) +{ + Fl_Multi_Label* b = (Fl_Multi_Label*)(o->value); + Fl_Label local = *o; + local.value = b->labela; + local.type = b->typea; + int W = w; int H = h; local.measure(W, H); + local.draw(x,y,w,h,a); + if (a & FL_ALIGN_BOTTOM) h -= H; + else if (a & FL_ALIGN_TOP) {y += H; h -= H;} + else if (a & FL_ALIGN_RIGHT) w -= W; + else if (a & FL_ALIGN_LEFT) {x += W; w -= W;} + else {int d = (h+H)/2; y += d; h -= d;} + local.value = b->labelb; + local.type = b->typeb; + local.draw(x,y,w,h,a); +} + +// measurement is only correct for left-to-right appending... +static void multi_measure(const Fl_Label* o, int& w, int& h) { + Fl_Multi_Label* b = (Fl_Multi_Label*)(o->value); + Fl_Label local = *o; + local.value = b->labela; + local.type = b->typea; + local.measure(w,h); + local.value = b->labelb; + local.type = b->typeb; + int W = 0; int H = 0; local.measure(W,H); + w += W; if (H>h) h = H; +} + +void Fl_Multi_Label::label(Fl_Widget* o) { + Fl::set_labeltype(_FL_MULTI_LABEL, multi_labeltype, multi_measure); + o->label(_FL_MULTI_LABEL, (const char*)this); +} + +void Fl_Multi_Label::label(Fl_Menu_Item* o) { + Fl::set_labeltype(_FL_MULTI_LABEL, multi_labeltype, multi_measure); + o->label(_FL_MULTI_LABEL, (const char*)this); +} + +// +// End of "$Id: Fl_Multi_Label.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Overlay_Window.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Overlay_Window.cxx new file mode 100644 index 0000000..8d31a5d --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Overlay_Window.cxx @@ -0,0 +1,155 @@ +// +// "$Id: Fl_Overlay_Window.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Overlay window code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// A window using double-buffering and able to draw an overlay +// on top of that. Uses the hardware to draw the overlay if +// possible, otherwise it just draws in the front buffer. + +#include +#include +#include +#include +#include + +void Fl_Overlay_Window::show() { + Fl_Double_Window::show(); + if (overlay_ && overlay_ != this) overlay_->show(); +} + +void Fl_Overlay_Window::hide() { + Fl_Double_Window::hide(); +} + +void Fl_Overlay_Window::flush() { +#ifdef BOXX_BUGS + if (overlay_ && overlay_ != this && overlay_->shown()) { + // all drawing to windows hidden by overlay windows is ignored, fix this + XUnmapWindow(fl_display, fl_xid(overlay_)); + Fl_Double_Window::flush(0); + XMapWindow(fl_display, fl_xid(overlay_)); + return; + } +#endif + int erase_overlay = (damage()&FL_DAMAGE_OVERLAY); + clear_damage((uchar)(damage()&~FL_DAMAGE_OVERLAY)); + Fl_Double_Window::flush(erase_overlay); + if (overlay_ == this) draw_overlay(); +} + +void Fl_Overlay_Window::resize(int X, int Y, int W, int H) { + Fl_Double_Window::resize(X,Y,W,H); + if (overlay_ && overlay_!=this) overlay_->resize(0,0,w(),h()); +} + +Fl_Overlay_Window::~Fl_Overlay_Window() { + hide(); +// delete overlay; this is done by ~Fl_Group +} + +#if !HAVE_OVERLAY + +int Fl_Overlay_Window::can_do_overlay() {return 0;} + +void Fl_Overlay_Window::redraw_overlay() { + overlay_ = this; + clear_damage((uchar)(damage()|FL_DAMAGE_OVERLAY)); + Fl::damage(FL_DAMAGE_CHILD); +} + +#else + +extern XVisualInfo *fl_find_overlay_visual(); +extern XVisualInfo *fl_overlay_visual; +extern Colormap fl_overlay_colormap; +extern unsigned long fl_transparent_pixel; +static GC gc; // the GC used by all X windows +extern uchar fl_overlay; // changes how fl_color(x) works + +class _Fl_Overlay : public Fl_Window { + friend class Fl_Overlay_Window; + void flush(); + void show(); +public: + _Fl_Overlay(int x, int y, int w, int h) : + Fl_Window(x,y,w,h) {set_flag(INACTIVE);} +}; + +int Fl_Overlay_Window::can_do_overlay() { + return fl_find_overlay_visual() != 0; +} + +void _Fl_Overlay::show() { + if (shown()) {Fl_Window::show(); return;} + fl_background_pixel = int(fl_transparent_pixel); + Fl_X::make_xid(this, fl_overlay_visual, fl_overlay_colormap); + fl_background_pixel = -1; + // find the outermost window to tell wm about the colormap: + Fl_Window *w = window(); + for (;;) {Fl_Window *w1 = w->window(); if (!w1) break; w = w1;} + XSetWMColormapWindows(fl_display, fl_xid(w), &(Fl_X::i(this)->xid), 1); +} + +void _Fl_Overlay::flush() { + fl_window = fl_xid(this); + if (!gc) gc = XCreateGC(fl_display, fl_xid(this), 0, 0); + fl_gc = gc; + fl_overlay = 1; + Fl_Overlay_Window *w = (Fl_Overlay_Window *)parent(); + Fl_X *myi = Fl_X::i(this); + if (damage() != FL_DAMAGE_EXPOSE) XClearWindow(fl_display, fl_xid(this)); + fl_clip_region(myi->region); myi->region = 0; + w->draw_overlay(); + fl_overlay = 0; +} + +void Fl_Overlay_Window::redraw_overlay() { + if (!fl_display) return; // this prevents fluid -c from opening display + if (!overlay_) { + if (can_do_overlay()) { + Fl_Group::current(this); + overlay_ = new _Fl_Overlay(0,0,w(),h()); + Fl_Group::current(0); + } else { + overlay_ = this; // fake the overlay + } + } + if (shown()) { + if (overlay_ == this) { + clear_damage(damage()|FL_DAMAGE_OVERLAY); + Fl::damage(FL_DAMAGE_CHILD); + } else if (!overlay_->shown()) + overlay_->show(); + else + overlay_->redraw(); + } +} + +#endif + +// +// End of "$Id: Fl_Overlay_Window.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_PNG_Image.cxx b/third_party/windows/fltk-1.1.10/src/Fl_PNG_Image.cxx new file mode 100644 index 0000000..fa1deb4 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_PNG_Image.cxx @@ -0,0 +1,155 @@ +// +// "$Id: Fl_PNG_Image.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Fl_PNG_Image routines. +// +// Copyright 1997-2005 by Easy Software Products. +// Image support donated by Matthias Melcher, Copyright 2000. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_PNG_Image::Fl_PNG_Image() - Load a PNG image file. +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include +#include + +extern "C" +{ +#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ) +# include +# ifdef HAVE_PNG_H +# include +# else +# include +# endif // HAVE_PNG_H +#endif // HAVE_LIBPNG && HAVE_LIBZ +} + + +// +// 'Fl_PNG_Image::Fl_PNG_Image()' - Load a PNG image file. +// + +Fl_PNG_Image::Fl_PNG_Image(const char *png) // I - File to read + : Fl_RGB_Image(0,0,0) { +#if defined(HAVE_LIBPNG) && defined(HAVE_LIBZ) + int i; // Looping var + FILE *fp; // File pointer + int channels; // Number of color channels + png_structp pp; // PNG read pointer + png_infop info; // PNG info pointers + png_bytep *rows; // PNG row pointers + + + // Open the PNG file... + if ((fp = fopen(png, "rb")) == NULL) return; + + // Setup the PNG data structures... + pp = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + info = png_create_info_struct(pp); + + if (setjmp(pp->jmpbuf)) + { + Fl::warning("PNG file \"%s\" contains errors!\n", png); + return; + } + + // Initialize the PNG read "engine"... + png_init_io(pp, fp); + + // Get the image dimensions and convert to grayscale or RGB... + png_read_info(pp, info); + + if (info->color_type == PNG_COLOR_TYPE_PALETTE) + png_set_expand(pp); + + if (info->color_type & PNG_COLOR_MASK_COLOR) + channels = 3; + else + channels = 1; + + if ((info->color_type & PNG_COLOR_MASK_ALPHA) || info->num_trans) + channels ++; + + w((int)(info->width)); + h((int)(info->height)); + d(channels); + + if (info->bit_depth < 8) + { + png_set_packing(pp); + png_set_expand(pp); + } + else if (info->bit_depth == 16) + png_set_strip_16(pp); + +# if defined(HAVE_PNG_GET_VALID) && defined(HAVE_PNG_SET_TRNS_TO_ALPHA) + // Handle transparency... + if (png_get_valid(pp, info, PNG_INFO_tRNS)) + png_set_tRNS_to_alpha(pp); +# endif // HAVE_PNG_GET_VALID && HAVE_PNG_SET_TRNS_TO_ALPHA + + array = new uchar[w() * h() * d()]; + alloc_array = 1; + + // Allocate pointers... + rows = new png_bytep[h()]; + + for (i = 0; i < h(); i ++) + rows[i] = (png_bytep)(array + i * w() * d()); + + // Read the image, handling interlacing as needed... + for (i = png_set_interlace_handling(pp); i > 0; i --) + png_read_rows(pp, rows, NULL, h()); + +#ifdef WIN32 + // Some Windows graphics drivers don't honor transparency when RGB == white + if (channels == 4) { + // Convert RGB to 0 when alpha == 0... + uchar *ptr = (uchar *)array; + for (i = w() * h(); i > 0; i --, ptr += 4) + if (!ptr[3]) ptr[0] = ptr[1] = ptr[2] = 0; + } +#endif // WIN32 + + // Free memory and return... + delete[] rows; + + png_read_end(pp, info); + png_destroy_read_struct(&pp, &info, NULL); + + fclose(fp); +#endif // HAVE_LIBPNG && HAVE_LIBZ +} + + +// +// End of "$Id: Fl_PNG_Image.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_PNM_Image.cxx b/third_party/windows/fltk-1.1.10/src/Fl_PNM_Image.cxx new file mode 100644 index 0000000..59bf866 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_PNM_Image.cxx @@ -0,0 +1,190 @@ +// +// "$Id: Fl_PNM_Image.cxx 6006 2007-12-20 16:32:56Z matt $" +// +// Fl_PNM_Image routines. +// +// Copyright 1997-2005 by Easy Software Products. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_PNM_Image::Fl_PNM_Image() - Load a PNM image... +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include +#include "flstring.h" + + +// +// 'Fl_PNM_Image::Fl_PNM_Image()' - Load a PNM image... +// + +Fl_PNM_Image::Fl_PNM_Image(const char *name) // I - File to read + : Fl_RGB_Image(0,0,0) { + FILE *fp; // File pointer + int x, y; // Looping vars + char line[1024], // Input line + *lineptr; // Pointer in line + uchar *ptr, // Pointer to pixel values + byte, // Byte from file + bit; // Bit in pixel + int format, // Format of PNM file + val, // Pixel value + maxval; // Maximum pixel value + + + if ((fp = fopen(name, "rb")) == NULL) return; + + // + // Read the file header in the format: + // + // Pformat + // # comment1 + // # comment2 + // ... + // # commentN + // width + // height + // max sample + // + + lineptr = fgets(line, sizeof(line), fp); + if (!lineptr) { + fclose(fp); + Fl::error("Early end-of-file in PNM file \"%s\"!", name); + return; + } + + lineptr ++; + + format = atoi(lineptr); + while (isdigit(*lineptr)) lineptr ++; + + if (format == 7) lineptr = (char *)""; + + while (lineptr != NULL && w() == 0) { + if (*lineptr == '\0' || *lineptr == '#') { + lineptr = fgets(line, sizeof(line), fp); + } else if (isdigit(*lineptr)) { + w(strtol(lineptr, &lineptr, 10)); + } else lineptr ++; + } + + while (lineptr != NULL && h() == 0) { + if (*lineptr == '\0' || *lineptr == '#') { + lineptr = fgets(line, sizeof(line), fp); + } else if (isdigit(*lineptr)) { + h(strtol(lineptr, &lineptr, 10)); + } else lineptr ++; + } + + if (format != 1 && format != 4) { + maxval = 0; + + while (lineptr != NULL && maxval == 0) { + if (*lineptr == '\0' || *lineptr == '#') { + lineptr = fgets(line, sizeof(line), fp); + } else if (isdigit(*lineptr)) { + maxval = strtol(lineptr, &lineptr, 10); + } else lineptr ++; + } + } else maxval = 1; + + // Allocate memory... + if (format == 1 || format == 2 || format == 4 || format == 5) d(1); + else d(3); + +// printf("%s = %dx%dx%d\n", name, w(), h(), d()); + + array = new uchar[w() * h() * d()]; + alloc_array = 1; + + // Read the image file... + for (y = 0; y < h(); y ++) { + ptr = (uchar *)array + y * w() * d(); + + switch (format) { + case 1 : + case 2 : + for (x = w(); x > 0; x --) + if (fscanf(fp, "%d", &val) == 1) *ptr++ = (uchar)(255 * val / maxval); + break; + + case 3 : + for (x = w(); x > 0; x --) { + if (fscanf(fp, "%d", &val) == 1) *ptr++ = (uchar)(255 * val / maxval); + if (fscanf(fp, "%d", &val) == 1) *ptr++ = (uchar)(255 * val / maxval); + if (fscanf(fp, "%d", &val) == 1) *ptr++ = (uchar)(255 * val / maxval); + } + break; + + case 4 : + for (x = w(), byte = (uchar)getc(fp), bit = 128; x > 0; x --) { + if (byte & bit) *ptr++ = 255; + else *ptr++ = 0; + + if (bit > 1) bit >>= 1; + else { + bit = 128; + byte = (uchar)getc(fp); + } + } + break; + + case 5 : + case 6 : + if (maxval < 256) { + fread(ptr, w(), d(), fp); + } else { + for (x = d() * w(); x > 0; x --) { + val = (uchar)getc(fp); + val = (val<<8)|(uchar)getc(fp); + *ptr++ = (255*val)/maxval; + } + } + break; + + case 7 : /* XV 3:3:2 thumbnail format */ + for (x = w(); x > 0; x --) { + byte = (uchar)getc(fp); + + *ptr++ = (uchar)(255 * ((byte >> 5) & 7) / 7); + *ptr++ = (uchar)(255 * ((byte >> 2) & 7) / 7); + *ptr++ = (uchar)(255 * (byte & 3) / 3); + } + break; + } + } + + fclose(fp); +} + + +// +// End of "$Id: Fl_PNM_Image.cxx 6006 2007-12-20 16:32:56Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Pack.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Pack.cxx new file mode 100644 index 0000000..7738172 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Pack.cxx @@ -0,0 +1,147 @@ +// +// "$Id: Fl_Pack.cxx 6868 2009-09-13 12:10:56Z AlbrechtS $" +// +// Packing widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Based on code by Curtis Edwards +// Group that compresses all it's children together and resizes to surround +// them on each redraw (only if box() is zero) +// Bugs: ? + +#include +#include +#include + +Fl_Pack::Fl_Pack(int X, int Y, int W, int H,const char *l) +: Fl_Group(X, Y, W, H, l) { + resizable(0); + spacing_ = 0; + // type(VERTICAL); // already set like this +} + +void Fl_Pack::draw() { + int tx = x()+Fl::box_dx(box()); + int ty = y()+Fl::box_dy(box()); + int tw = w()-Fl::box_dw(box()); + int th = h()-Fl::box_dh(box()); + int rw, rh; + int current_position = horizontal() ? tx : ty; + int maximum_position = current_position; + uchar d = damage(); + Fl_Widget*const* a = array(); + if (horizontal()) { + rw = -spacing_; + rh = th; + + for (int i = children(); i--;) + if (child(i)->visible()) { + if (child(i) != this->resizable()) rw += child(i)->w(); + rw += spacing_; + } + } else { + rw = tw; + rh = -spacing_; + + for (int i = children(); i--;) + if (child(i)->visible()) { + if (child(i) != this->resizable()) rh += child(i)->h(); + rh += spacing_; + } + } + for (int i = children(); i--;) { + Fl_Widget* o = *a++; + if (o->visible()) { + int X,Y,W,H; + if (horizontal()) { + X = current_position; + W = o->w(); + Y = ty; + H = th; + } else { + X = tx; + W = tw; + Y = current_position; + H = o->h(); + } + // Last child, if resizable, takes all remaining room + if(i == 0 && o == this->resizable()) { + if(horizontal()) + W = tw - rw; + else + H = th - rh; + } + if (spacing_ && current_position>maximum_position && box() && + (X != o->x() || Y != o->y() || d&FL_DAMAGE_ALL)) { + fl_color(color()); + if (horizontal()) + fl_rectf(maximum_position, ty, spacing_, th); + else + fl_rectf(tx, maximum_position, tw, spacing_); + } + if (X != o->x() || Y != o->y() || W != o->w() || H != o->h()) { + o->resize(X,Y,W,H); + o->clear_damage(FL_DAMAGE_ALL); + } + if (d&FL_DAMAGE_ALL) { + draw_child(*o); + draw_outside_label(*o); + } else update_child(*o); + // child's draw() can change it's size, so use new size: + current_position += (horizontal() ? o->w() : o->h()); + if (current_position > maximum_position) + maximum_position = current_position; + current_position += spacing_; + } + } + + if (horizontal()) { + if (maximum_position < tx+tw && box()) { + fl_color(color()); + fl_rectf(maximum_position, ty, tx+tw-maximum_position, th); + } + tw = maximum_position-tx; + } else { + if (maximum_position < ty+th && box()) { + fl_color(color()); + fl_rectf(tx, maximum_position, tw, ty+th-maximum_position); + } + th = maximum_position-ty; + } + + tw += Fl::box_dw(box()); if (tw <= 0) tw = 1; + th += Fl::box_dh(box()); if (th <= 0) th = 1; + if (tw != w() || th != h()) { + Fl_Widget::resize(x(),y(),tw,th); + d = FL_DAMAGE_ALL; + } + if (d&FL_DAMAGE_ALL) { + draw_box(); + draw_label(); + } +} + +// +// End of "$Id: Fl_Pack.cxx 6868 2009-09-13 12:10:56Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Pixmap.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Pixmap.cxx new file mode 100644 index 0000000..86e86fa --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Pixmap.cxx @@ -0,0 +1,495 @@ +// +// "$Id: Fl_Pixmap.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Pixmap drawing code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Draws X pixmap data, keeping it stashed in a server pixmap so it +// redraws fast. + +// See fl_draw_pixmap.cxx for code used to get the actual data into pixmap. +// Implemented without using the xpm library (which I can't use because +// it interferes with the color cube used by fl_draw_image). + +#include +#include +#include +#include +#include +#include + +#include +#include "flstring.h" +#include + +#ifdef WIN32 +extern void fl_release_dc(HWND, HDC); // located in Fl_win32.cxx +#endif + +#ifdef __APPLE_QUARTZ__ +extern Fl_Offscreen fl_create_offscreen_with_alpha(int w, int h); +#endif + +extern uchar **fl_mask_bitmap; // used by fl_draw_pixmap.cxx to store mask +void fl_restore_clip(); // in fl_rect.cxx + +void Fl_Pixmap::measure() { + int W, H; + + // ignore empty or bad pixmap data: + if (w()<0 && data()) { + fl_measure_pixmap(data(), W, H); + w(W); h(H); + } +} + +void Fl_Pixmap::draw(int XP, int YP, int WP, int HP, int cx, int cy) { + // ignore empty or bad pixmap data: + if (!data()) { + draw_empty(XP, YP); + return; + } + if (w()<0) measure(); + if (WP==-1) { + WP = w(); + HP = h(); + } + if (!w()) { + draw_empty(XP, YP); + return; + } + // account for current clip region (faster on Irix): + int X,Y,W,H; fl_clip_box(XP,YP,WP,HP,X,Y,W,H); + cx += X-XP; cy += Y-YP; + // clip the box down to the size of image, quit if empty: + if (cx < 0) {W += cx; X -= cx; cx = 0;} + if (cx+W > w()) W = w()-cx; + if (W <= 0) return; + if (cy < 0) {H += cy; Y -= cy; cy = 0;} + if (cy+H > h()) H = h()-cy; + if (H <= 0) return; + if (!id) { +#ifdef __APPLE_QUARTZ__ + id = fl_create_offscreen_with_alpha(w(), h()); + fl_begin_offscreen((Fl_Offscreen)id); + fl_draw_pixmap(data(), 0, 0, FL_GREEN); + fl_end_offscreen(); +#else + id = fl_create_offscreen(w(), h()); + fl_begin_offscreen((Fl_Offscreen)id); + uchar *bitmap = 0; + fl_mask_bitmap = &bitmap; + fl_draw_pixmap(data(), 0, 0, FL_BLACK); + fl_mask_bitmap = 0; + if (bitmap) { + mask = fl_create_bitmask(w(), h(), bitmap); + delete[] bitmap; + } + fl_end_offscreen(); +#endif + } +#ifdef WIN32 + if (mask) { + HDC new_gc = CreateCompatibleDC(fl_gc); + int save = SaveDC(new_gc); + SelectObject(new_gc, (void*)mask); + BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCAND); + SelectObject(new_gc, (void*)id); + BitBlt(fl_gc, X, Y, W, H, new_gc, cx, cy, SRCPAINT); + RestoreDC(new_gc,save); + DeleteDC(new_gc); + } else { + fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)id, cx, cy); + } +#elif defined(__APPLE_QD__) + if (mask) { + Rect src, dst; + src.left = cx; src.right = cx+W; + src.top = cy; src.bottom = cy+H; + dst.left = X; dst.right = X+W; + dst.top = Y; dst.bottom = Y+H; + RGBColor rgb, oldfg, oldbg; + GetForeColor(&oldfg); + GetBackColor(&oldbg); + rgb.red = 0xffff; rgb.green = 0xffff; rgb.blue = 0xffff; + RGBBackColor(&rgb); + rgb.red = 0x0000; rgb.green = 0x0000; rgb.blue = 0x0000; + RGBForeColor(&rgb); + CopyMask(GetPortBitMapForCopyBits((GrafPtr)id), + GetPortBitMapForCopyBits((GrafPtr)mask), + GetPortBitMapForCopyBits(GetWindowPort(fl_window)), + &src, &src, &dst); + RGBBackColor(&oldbg); + RGBForeColor(&oldfg); + } else { + fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)id, cx, cy); + } +#elif defined(__APPLE_QUARTZ__) + fl_copy_offscreen(X, Y, W, H, (Fl_Offscreen)id, cx, cy); +#else + if (mask) { + // I can't figure out how to combine a mask with existing region, + // so cut the image down to a clipped rectangle: + int nx, ny; fl_clip_box(X,Y,W,H,nx,ny,W,H); + cx += nx-X; X = nx; + cy += ny-Y; Y = ny; + // make X use the bitmap as a mask: + XSetClipMask(fl_display, fl_gc, mask); + int ox = X-cx; if (ox < 0) ox += w(); + int oy = Y-cy; if (oy < 0) oy += h(); + XSetClipOrigin(fl_display, fl_gc, X-cx, Y-cy); + } + fl_copy_offscreen(X, Y, W, H, id, cx, cy); + if (mask) { + // put the old clip region back + XSetClipOrigin(fl_display, fl_gc, 0, 0); + fl_restore_clip(); + } +#endif +} + +Fl_Pixmap::~Fl_Pixmap() { + uncache(); + delete_data(); +} + +void Fl_Pixmap::uncache() { + if (id) { + fl_delete_offscreen((Fl_Offscreen)id); + id = 0; + } + + if (mask) { + fl_delete_bitmask((Fl_Bitmask)mask); + mask = 0; + } +} + +void Fl_Pixmap::label(Fl_Widget* widget) { + widget->image(this); +} + +void Fl_Pixmap::label(Fl_Menu_Item* m) { + Fl::set_labeltype(_FL_IMAGE_LABEL, labeltype, Fl_Image::measure); + m->label(_FL_IMAGE_LABEL, (const char*)this); +} + +void Fl_Pixmap::copy_data() { + if (alloc_data) return; + + char **new_data, // New data array + **new_row; // Current row in image + int i, // Looping var + ncolors, // Number of colors in image + chars_per_pixel,// Characters per color + chars_per_line; // Characters per line + + // Figure out how many colors there are, and how big they are... + sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel); + chars_per_line = chars_per_pixel * w() + 1; + + // Allocate memory for the new array... + if (ncolors < 0) new_data = new char *[h() + 2]; + else new_data = new char *[h() + ncolors + 1]; + + new_data[0] = new char[strlen(data()[0]) + 1]; + strcpy(new_data[0], data()[0]); + + // Copy colors... + if (ncolors < 0) { + // Copy FLTK colormap values... + ncolors = -ncolors; + new_row = new_data + 1; + *new_row = new char[ncolors * 4]; + memcpy(*new_row, data()[1], ncolors * 4); + ncolors = 1; + new_row ++; + } else { + // Copy standard XPM colormap values... + for (i = 0, new_row = new_data + 1; i < ncolors; i ++, new_row ++) { + *new_row = new char[strlen(data()[i + 1]) + 1]; + strcpy(*new_row, data()[i + 1]); + } + } + + // Copy image data... + for (i = 0; i < h(); i ++, new_row ++) { + *new_row = new char[chars_per_line]; + memcpy(*new_row, data()[i + ncolors + 1], chars_per_line); + } + + // Update pointers... + data((const char **)new_data, h() + ncolors + 1); + alloc_data = 1; +} + +Fl_Image *Fl_Pixmap::copy(int W, int H) { + Fl_Pixmap *new_image; // New pixmap + + // Optimize the simple copy where the width and height are the same... + if (W == w() && H == h()) { + // Make an exact copy of the image and return it... + new_image = new Fl_Pixmap(data()); + new_image->copy_data(); + return new_image; + } + if (W <= 0 || H <= 0) return 0; + + // OK, need to resize the image data; allocate memory and + char **new_data, // New array for image data + **new_row, // Pointer to row in image data + *new_ptr, // Pointer into new array + new_info[255]; // New information line + const char *old_ptr; // Pointer into old array + int i, // Looping var + c, // Channel number + sy, // Source coordinate + dx, dy, // Destination coordinates + xerr, yerr, // X & Y errors + xmod, ymod, // X & Y moduli + xstep, ystep; // X & Y step increments + int ncolors, // Number of colors in image + chars_per_pixel,// Characters per color + chars_per_line; // Characters per line + + // Figure out how many colors there are, and how big they are... + sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel); + chars_per_line = chars_per_pixel * W + 1; + + sprintf(new_info, "%d %d %d %d", W, H, ncolors, chars_per_pixel); + + // Figure out Bresenheim step/modulus values... + xmod = w() % W; + xstep = (w() / W) * chars_per_pixel; + ymod = h() % H; + ystep = h() / H; + + // Allocate memory for the new array... + if (ncolors < 0) new_data = new char *[H + 2]; + else new_data = new char *[H + ncolors + 1]; + new_data[0] = new char[strlen(new_info) + 1]; + strcpy(new_data[0], new_info); + + // Copy colors... + if (ncolors < 0) { + // Copy FLTK colormap values... + ncolors = -ncolors; + new_row = new_data + 1; + *new_row = new char[ncolors * 4]; + memcpy(*new_row, data()[1], ncolors * 4); + ncolors = 1; + new_row ++; + } else { + // Copy standard XPM colormap values... + for (i = 0, new_row = new_data + 1; i < ncolors; i ++, new_row ++) { + *new_row = new char[strlen(data()[i + 1]) + 1]; + strcpy(*new_row, data()[i + 1]); + } + } + + // Scale the image using a nearest-neighbor algorithm... + for (dy = H, sy = 0, yerr = H; dy > 0; dy --, new_row ++) { + *new_row = new char[chars_per_line]; + new_ptr = *new_row; + + for (dx = W, xerr = W, old_ptr = data()[sy + ncolors + 1]; + dx > 0; + dx --) { + for (c = 0; c < chars_per_pixel; c ++) *new_ptr++ = old_ptr[c]; + + old_ptr += xstep; + xerr -= xmod; + + if (xerr <= 0) { + xerr += W; + old_ptr += chars_per_pixel; + } + } + + *new_ptr = '\0'; + sy += ystep; + yerr -= ymod; + if (yerr <= 0) { + yerr += H; + sy ++; + } + } + + new_image = new Fl_Pixmap((char*const*)new_data); + new_image->alloc_data = 1; + + return new_image; +} + +void Fl_Pixmap::color_average(Fl_Color c, float i) { + // Delete any existing pixmap/mask objects... + uncache(); + + // Allocate memory as needed... + copy_data(); + + // Get the color to blend with... + uchar r, g, b; + unsigned ia, ir, ig, ib; + + Fl::get_color(c, r, g, b); + if (i < 0.0f) i = 0.0f; + else if (i > 1.0f) i = 1.0f; + + ia = (unsigned)(256 * i); + ir = r * (256 - ia); + ig = g * (256 - ia); + ib = b * (256 - ia); + + // Update the colormap to do the blend... + char line[255]; // New colormap line + int color, // Looping var + ncolors, // Number of colors in image + chars_per_pixel;// Characters per color + + + sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel); + + if (ncolors < 0) { + // Update FLTK colormap... + ncolors = -ncolors; + uchar *cmap = (uchar *)(data()[1]); + for (color = 0; color < ncolors; color ++, cmap += 4) { + cmap[1] = (ia * cmap[1] + ir) >> 8; + cmap[2] = (ia * cmap[2] + ig) >> 8; + cmap[3] = (ia * cmap[3] + ib) >> 8; + } + } else { + // Update standard XPM colormap... + for (color = 0; color < ncolors; color ++) { + // look for "c word", or last word if none: + const char *p = data()[color + 1] + chars_per_pixel + 1; + const char *previous_word = p; + for (;;) { + while (*p && isspace(*p)) p++; + char what = *p++; + while (*p && !isspace(*p)) p++; + while (*p && isspace(*p)) p++; + if (!*p) {p = previous_word; break;} + if (what == 'c') break; + previous_word = p; + while (*p && !isspace(*p)) p++; + } + + if (fl_parse_color(p, r, g, b)) { + r = (ia * r + ir) >> 8; + g = (ia * g + ig) >> 8; + b = (ia * b + ib) >> 8; + + if (chars_per_pixel > 1) sprintf(line, "%c%c c #%02X%02X%02X", + data()[color + 1][0], + data()[color + 1][1], r, g, b); + else sprintf(line, "%c c #%02X%02X%02X", data()[color + 1][0], r, g, b); + + delete[] (char *)data()[color + 1]; + ((char **)data())[color + 1] = new char[strlen(line) + 1]; + strcpy((char *)data()[color + 1], line); + } + } + } +} + +void Fl_Pixmap::delete_data() { + if (alloc_data) { + for (int i = 0; i < count(); i ++) delete[] (char *)data()[i]; + delete[] (char **)data(); + } +} + +void Fl_Pixmap::set_data(const char * const * p) { + int height, // Number of lines in image + ncolors; // Number of colors in image + + if (p) { + sscanf(p[0],"%*d%d%d", &height, &ncolors); + if (ncolors < 0) data(p, height + 2); + else data(p, height + ncolors + 1); + } +} + + +void Fl_Pixmap::desaturate() { + // Delete any existing pixmap/mask objects... + uncache(); + + // Allocate memory as needed... + copy_data(); + + // Update the colormap to grayscale... + char line[255]; // New colormap line + int i, // Looping var + ncolors, // Number of colors in image + chars_per_pixel;// Characters per color + uchar r, g, b; + + sscanf(data()[0],"%*d%*d%d%d", &ncolors, &chars_per_pixel); + + if (ncolors < 0) { + // Update FLTK colormap... + ncolors = -ncolors; + uchar *cmap = (uchar *)(data()[1]); + for (i = 0; i < ncolors; i ++, cmap += 4) { + g = (uchar)((cmap[1] * 31 + cmap[2] * 61 + cmap[3] * 8) / 100); + cmap[1] = cmap[2] = cmap[3] = g; + } + } else { + // Update standard XPM colormap... + for (i = 0; i < ncolors; i ++) { + // look for "c word", or last word if none: + const char *p = data()[i + 1] + chars_per_pixel + 1; + const char *previous_word = p; + for (;;) { + while (*p && isspace(*p)) p++; + char what = *p++; + while (*p && !isspace(*p)) p++; + while (*p && isspace(*p)) p++; + if (!*p) {p = previous_word; break;} + if (what == 'c') break; + previous_word = p; + while (*p && !isspace(*p)) p++; + } + + if (fl_parse_color(p, r, g, b)) { + g = (uchar)((r * 31 + g * 61 + b * 8) / 100); + + if (chars_per_pixel > 1) sprintf(line, "%c%c c #%02X%02X%02X", data()[i + 1][0], + data()[i + 1][1], g, g, g); + else sprintf(line, "%c c #%02X%02X%02X", data()[i + 1][0], g, g, g); + + delete[] (char *)data()[i + 1]; + ((char **)data())[i + 1] = new char[strlen(line) + 1]; + strcpy((char *)data()[i + 1], line); + } + } + } +} + +// +// End of "$Id: Fl_Pixmap.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Positioner.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Positioner.cxx new file mode 100644 index 0000000..f0c6bd8 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Positioner.cxx @@ -0,0 +1,151 @@ +// +// "$Id: Fl_Positioner.cxx 5347 2006-08-23 12:57:42Z matt $" +// +// Positioner widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// The positioner widget from Forms, gives 2D input +// Written by: Mark Overmars + +#include +#include +#include + +static double flinear(double val, double smin, double smax, double gmin, double gmax) +{ + if (smin == smax) return gmax; + else return gmin + (gmax - gmin) * (val - smin) / (smax - smin); +} + +void Fl_Positioner::draw(int X, int Y, int W, int H) { + int x1 = X + 4; + int y1 = Y + 4; + int w1 = W - 2 * 4; + int h1 = H - 2 * 4; + int xx = int(flinear(xvalue(), xmin, xmax, x1, x1+w1-1)+.5); + int yy = int(flinear(yvalue(), ymin, ymax, y1, y1+h1-1)+.5); + draw_box(box(), X, Y, W, H, color()); + fl_color(selection_color()); + fl_xyline(x1, yy, x1+w1); + fl_yxline(xx, y1, y1+h1); +} + +void Fl_Positioner::draw() { + draw(x(), y(), w(), h()); + draw_label(); +} + +int Fl_Positioner::value(double X, double Y) { + clear_changed(); + if (X == xvalue_ && Y == yvalue_) return 0; + xvalue_ = X; yvalue_ = Y; + redraw(); + return 1; +} + +int Fl_Positioner::xvalue(double X) { + return(value(X, yvalue_)); +} + +int Fl_Positioner::yvalue(double Y) { + return(value(xvalue_, Y)); +} + +int Fl_Positioner::handle(int event, int X, int Y, int W, int H) { + switch (event) { + case FL_PUSH: + case FL_DRAG: + case FL_RELEASE: { + double x1 = X + 4; + double y1 = Y + 4; + double w1 = W - 2 * 4; + double h1 = H - 2 * 4; + double xx = flinear(Fl::event_x(), x1, x1+w1-1.0, xmin, xmax); + if (xstep_) xx = int(xx/xstep_+0.5) * xstep_; + if (xmin < xmax) { + if (xx < xmin) xx = xmin; + if (xx > xmax) xx = xmax; + } else { + if (xx > xmin) xx = xmin; + if (xx < xmax) xx = xmax; + } + double yy = flinear(Fl::event_y(), y1, y1+h1-1.0, ymin, ymax); + if (ystep_) yy = int(yy/ystep_+0.5) * ystep_; + if (ymin < ymax) { + if (yy < ymin) yy = ymin; + if (yy > ymax) yy = ymax; + } else { + if (yy > ymin) yy = ymin; + if (yy < ymax) yy = ymax; + } + if (xx != xvalue_ || yy != yvalue_) { + xvalue_ = xx; yvalue_ = yy; + set_changed(); + redraw(); + } } + if (!(when() & FL_WHEN_CHANGED || + (when() & FL_WHEN_RELEASE && event == FL_RELEASE))) return 1; + if (changed() || when()&FL_WHEN_NOT_CHANGED) { + if (event == FL_RELEASE) clear_changed(); + do_callback(); + } + return 1; + default: + return 0; + } +} + +int Fl_Positioner::handle(int e) { + return handle(e, x(), y(), w(), h()); +} + +Fl_Positioner::Fl_Positioner(int X, int Y, int W, int H, const char* l) +: Fl_Widget(X, Y, W, H, l) { + box(FL_DOWN_BOX); + selection_color(FL_RED); + align(FL_ALIGN_BOTTOM); + when(FL_WHEN_CHANGED); + xmin = ymin = 0; + xmax = ymax = 1; + xvalue_ = yvalue_ = .5; + xstep_ = ystep_ = 0; +} + +void Fl_Positioner::xbounds(double a, double b) { + if (a != xmin || b != xmax) { + xmin = a; xmax = b; + redraw(); + } +} + +void Fl_Positioner::ybounds(double a, double b) { + if (a != ymin || b != ymax) { + ymin = a; ymax = b; + redraw(); + } +} + +// +// End of "$Id: Fl_Positioner.cxx 5347 2006-08-23 12:57:42Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Preferences.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Preferences.cxx new file mode 100644 index 0000000..9693720 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Preferences.cxx @@ -0,0 +1,1182 @@ +// +// "$Id: Fl_Preferences.cxx 6015 2008-01-09 21:23:51Z matt $" +// +// Preferences methods for the Fast Light Tool Kit (FLTK). +// +// Copyright 2002-2005 by Matthias Melcher. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + + +#include +#include +#include + +#include +#include +#include +#include "flstring.h" +#include + +#if defined(WIN32) && !defined(__CYGWIN__) +# include +# include +// Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs +// on Windows, which is supposed to be POSIX compliant... +# define access _access +# define mkdir _mkdir +#elif defined (__APPLE__) +# include +# include +#else +# include +#endif + + +char Fl_Preferences::nameBuffer[128]; + + +/** + * create the initial preferences base + * - root: machine or user preferences + * - vendor: unique identification of author or vendor of application + * Must be a valid directory name. + * - application: vendor unique application name, i.e. "PreferencesTest" + * multiple preferences files can be created per application. + * Must be a valid file name. + * example: Fl_Preferences base( Fl_Preferences::USER, "fltk.org", "test01"); + */ +Fl_Preferences::Fl_Preferences( Root root, const char *vendor, const char *application ) +{ + node = new Node( "." ); + rootNode = new RootNode( this, root, vendor, application ); +} + + +/** + * create the initial preferences base + * - path: an application-supplied path + * example: Fl_Preferences base( "/usr/foo" ); + */ +Fl_Preferences::Fl_Preferences( const char *path, const char *vendor, const char *application ) +{ + node = new Node( "." ); + rootNode = new RootNode( this, path, vendor, application ); +} + + +/** + * create a Preferences node in relation to a parent node for reading and writing + * - parent: base name for group + * - group: group name (can contain '/' seperated group names) + * example: Fl_Preferences colors( base, "setup/colors" ); + */ +Fl_Preferences::Fl_Preferences( Fl_Preferences &parent, const char *key ) +{ + rootNode = parent.rootNode; + node = parent.node->addChild( key ); +} + + +/** + * create a Preferences node in relation to a parent node for reading and writing + * - parent: base name for group + * - group: group name (can contain '/' seperated group names) + * example: Fl_Preferences colors( base, "setup/colors" ); + */ +Fl_Preferences::Fl_Preferences( Fl_Preferences *parent, const char *key ) +{ + rootNode = parent->rootNode; + node = parent->node->addChild( key ); +} + + +/** + * destroy individual keys + * - destroying the base preferences will flush changes to the prefs file + * - after destroying the base, none of the depending preferences must be read or written + */ +Fl_Preferences::~Fl_Preferences() +{ + if (node && !node->parent()) delete rootNode; + // DO NOT delete nodes! The root node will do that after writing the preferences + // zero all pointer to avoid memory errors, event though + // Valgrind does not complain (Cygwind does though) + node = 0L; + rootNode = 0L; +} + + +/** + * return the number of groups that are contained within a group + * example: int n = base.groups(); + */ +int Fl_Preferences::groups() +{ + return node->nChildren(); +} + + +/** + * return the group name of the n'th group + * - there is no guaranteed order of group names + * - the index must be within the range given by groups() + * example: printf( "Group(%d)='%s'\n", ix, base.group(ix) ); + */ +const char *Fl_Preferences::group( int ix ) +{ + return node->child( ix ); +} + + +/** + * return 1, if a group with this name exists + * example: if ( base.groupExists( "setup/colors" ) ) ... + */ +char Fl_Preferences::groupExists( const char *key ) +{ + return node->search( key ) ? 1 : 0 ; +} + + +/** + * delete a group + * example: setup.deleteGroup( "colors/buttons" ); + */ +char Fl_Preferences::deleteGroup( const char *key ) +{ + Node *nd = node->search( key ); + if ( nd ) return nd->remove(); + return 0; +} + + +/** + * return the number of entries (name/value) pairs for a group + * example: int n = buttonColor.entries(); + */ +int Fl_Preferences::entries() +{ + return node->nEntry; +} + + +/** + * return the name of an entry + * - there is no guaranteed order of entry names + * - the index must be within the range given by entries() + * example: printf( "Entry(%d)='%s'\n", ix, buttonColor.entry(ix) ); + */ +const char *Fl_Preferences::entry( int ix ) +{ + return node->entry[ix].name; +} + + +/** + * return 1, if an entry with this name exists + * example: if ( buttonColor.entryExists( "red" ) ) ... + */ +char Fl_Preferences::entryExists( const char *key ) +{ + return node->getEntry( key )>=0 ? 1 : 0 ; +} + + +/** + * remove a single entry (name/value pair) + * example: buttonColor.deleteEntry( "red" ); + */ +char Fl_Preferences::deleteEntry( const char *key ) +{ + return node->deleteEntry( key ); +} + + +/** + * read an entry from the group + */ +char Fl_Preferences::get( const char *key, int &value, int defaultValue ) +{ + const char *v = node->get( key ); + value = v ? atoi( v ) : defaultValue; + return ( v != 0 ); +} + + +/** + * set an entry (name/value pair) + */ +char Fl_Preferences::set( const char *key, int value ) +{ + sprintf( nameBuffer, "%d", value ); + node->set( key, nameBuffer ); + return 1; +} + + +/** + * read an entry from the group + */ +char Fl_Preferences::get( const char *key, float &value, float defaultValue ) +{ + const char *v = node->get( key ); + value = v ? (float)atof( v ) : defaultValue; + return ( v != 0 ); +} + + +/** + * set an entry (name/value pair) + */ +char Fl_Preferences::set( const char *key, float value ) +{ + sprintf( nameBuffer, "%g", value ); + node->set( key, nameBuffer ); + return 1; +} + + +/** + * set an entry (name/value pair) + */ +char Fl_Preferences::set( const char *key, float value, int precision ) +{ + sprintf( nameBuffer, "%.*g", precision, value ); + node->set( key, nameBuffer ); + return 1; +} + + +/** + * read an entry from the group + */ +char Fl_Preferences::get( const char *key, double &value, double defaultValue ) +{ + const char *v = node->get( key ); + value = v ? atof( v ) : defaultValue; + return ( v != 0 ); +} + + +/** + * set an entry (name/value pair) + */ +char Fl_Preferences::set( const char *key, double value ) +{ + sprintf( nameBuffer, "%g", value ); + node->set( key, nameBuffer ); + return 1; +} + + +/** + * set an entry (name/value pair) + */ +char Fl_Preferences::set( const char *key, double value, int precision ) +{ + sprintf( nameBuffer, "%.*g", precision, value ); + node->set( key, nameBuffer ); + return 1; +} + + +// remove control sequences from a string +static char *decodeText( const char *src ) +{ + int len = 0; + const char *s = src; + for ( ; *s; s++, len++ ) + { + if ( *s == '\\' ) + if ( isdigit( s[1] ) ) s+=3; else s+=1; + } + char *dst = (char*)malloc( len+1 ), *d = dst; + for ( s = src; *s; s++ ) + { + char c = *s; + if ( c == '\\' ) + { + if ( s[1] == '\\' ) { *d++ = c; s++; } + else if ( s[1] == 'n' ) { *d++ = '\n'; s++; } + else if ( s[1] == 'r' ) { *d++ = '\r'; s++; } + else if ( isdigit( s[1] ) ) { *d++ = ((s[1]-'0')<<6) + ((s[2]-'0')<<3) + (s[3]-'0'); s+=3; } + else s++; // error + } + else + *d++ = c; + } + *d = 0; + return dst; +} + + +/** + * read a text entry from the group + * the text will be moved into the given text buffer + * text will be clipped to the buffer size + */ +char Fl_Preferences::get( const char *key, char *text, const char *defaultValue, int maxSize ) +{ + const char *v = node->get( key ); + if ( v && strchr( v, '\\' ) ) { + char *w = decodeText( v ); + strlcpy(text, w, maxSize); + free( w ); + return 1; + } + if ( !v ) v = defaultValue; + if ( v ) strlcpy(text, v, maxSize); + else text = 0; + return ( v != defaultValue ); +} + + +/** + * read a text entry from the group + * 'text' will be changed to point to a new text buffer + * the text buffer must be deleted with 'free(text)' by the user. + */ +char Fl_Preferences::get( const char *key, char *&text, const char *defaultValue ) +{ + const char *v = node->get( key ); + if ( v && strchr( v, '\\' ) ) + { + text = decodeText( v ); + return 1; + } + if ( !v ) v = defaultValue; + if ( v ) + text = strdup( v ); + else + text = 0; + return ( v != defaultValue ); +} + + +/** + * set an entry (name/value pair) + */ +char Fl_Preferences::set( const char *key, const char *text ) +{ + const char *s = text ? text : ""; + int n=0, ns=0; + for ( ; *s; s++ ) { n++; if ( *s<32 || *s=='\\' || *s==0x7f ) ns+=4; } + if ( ns ) + { + char *buffer = (char*)malloc( n+ns+1 ), *d = buffer; + for ( s=text; *s; ) + { + char c = *s; + if ( c=='\\' ) { *d++ = '\\'; *d++ = '\\'; s++; } + else if ( c=='\n' ) { *d++ = '\\'; *d++ = 'n'; s++; } + else if ( c=='\r' ) { *d++ = '\\'; *d++ = 'r'; s++; } + else if ( c<32 || c==0x7f ) + { *d++ = '\\'; *d++ = '0'+((c>>6)&3); *d++ = '0'+((c>>3)&7); *d++ = '0'+(c&7); s++; } + else *d++ = *s++; + } + *d = 0; + node->set( key, buffer ); + free( buffer ); + } + else + node->set( key, text ); + return 1; +} + + +// convert a hex string to binary data +static void *decodeHex( const char *src, int &size ) +{ + size = strlen( src )/2; + unsigned char *data = (unsigned char*)malloc( size ), *d = data; + const char *s = src; + int i; + + for ( i=size; i>0; i-- ) + { + int v; + char x = tolower(*s++); + if ( x >= 'a' ) v = x-'a'+10; else v = x-'0'; + v = v<<4; + x = tolower(*s++); + if ( x >= 'a' ) v += x-'a'+10; else v += x-'0'; + *d++ = (uchar)v; + } + + return (void*)data; +} + + +/** + * read a binary entry from the group + * the data will be moved into the given destination buffer + * data will be clipped to the buffer size + */ +char Fl_Preferences::get( const char *key, void *data, const void *defaultValue, int defaultSize, int maxSize ) +{ + const char *v = node->get( key ); + if ( v ) + { + int dsize; + void *w = decodeHex( v, dsize ); + memmove( data, w, dsize>maxSize?maxSize:dsize ); + free( w ); + return 1; + } + if ( defaultValue ) + memmove( data, defaultValue, defaultSize>maxSize?maxSize:defaultSize ); + return 0; +} + + +/** + * read a binary entry from the group + * 'data' will be changed to point to a new data buffer + * the data buffer must be deleted with 'free(data)' by the user. + */ +char Fl_Preferences::get( const char *key, void *&data, const void *defaultValue, int defaultSize ) +{ + const char *v = node->get( key ); + if ( v ) + { + int dsize; + data = decodeHex( v, dsize ); + return 1; + } + if ( defaultValue ) + { + data = (void*)malloc( defaultSize ); + memmove( data, defaultValue, defaultSize ); + } + else + data = 0; + return 0; +} + + +/** + * set an entry (name/value pair) + */ +char Fl_Preferences::set( const char *key, const void *data, int dsize ) +{ + char *buffer = (char*)malloc( dsize*2+1 ), *d = buffer;; + unsigned char *s = (unsigned char*)data; + for ( ; dsize>0; dsize-- ) + { + static char lu[] = "0123456789abcdef"; + unsigned char v = *s++; + *d++ = lu[v>>4]; + *d++ = lu[v&0xf]; + } + *d = 0; + node->set( key, buffer ); + free( buffer ); + return 1; +} + + +/** + * return the size of the value part of an entry + */ +int Fl_Preferences::size( const char *key ) +{ + const char *v = node->get( key ); + return v ? strlen( v ) : 0 ; +} + +/** + * creates a path that is related to the preferences file + * and that is usable for application data beyond what is covered + * by Fl_Preferences. + * - 'getUserdataPath' actually creates the directory + * - 'path' must be large enough to receive a complete file path + * example: + * Fl_Preferences prefs( USER, "matthiasm.com", "test" ); + * char path[FL_PATH_MAX]; + * prefs.getUserdataPath( path ); + * sample returns: + * Win32: c:/Documents and Settings/matt/Application Data/matthiasm.com/test/ + * prefs: c:/Documents and Settings/matt/Application Data/matthiasm.com/test.prefs + */ +char Fl_Preferences::getUserdataPath( char *path, int pathlen ) +{ + if ( rootNode ) + return rootNode->getPath( path, pathlen ); + return 0; +} + +/** + * write all preferences to disk + * - this function works only with the base preference group + * - this function is rarely used as deleting the base preferences flushes automatically + */ +void Fl_Preferences::flush() +{ + if ( rootNode && node->dirty() ) + rootNode->write(); +} + +//----------------------------------------------------------------------------- +// helper class to create dynamic group and entry names on the fly +// + +/** + * create a group name or entry name on the fly + * - this version creates a simple unsigned integer as an entry name + * example: + * int n, i; + * Fl_Preferences prev( appPrefs, "PreviousFiles" ); + * prev.get( "n", 0 ); + * for ( i=0; inode->dirty() ) + write(); + if ( filename_ ) { + free( filename_ ); + filename_ = 0L; + } + if ( vendor_ ) { + free( vendor_ ); + vendor_ = 0L; + } + if ( application_ ) { + free( application_ ); + application_ = 0L; + } + delete prefs_->node; + prefs_->node = 0L; +} + +// read a preferences file and construct the group tree and with all entry leafs +int Fl_Preferences::RootNode::read() +{ + char buf[1024]; + FILE *f = fopen( filename_, "rb" ); + if ( !f ) return 0; + fgets( buf, 1024, f ); + fgets( buf, 1024, f ); + fgets( buf, 1024, f ); + Node *nd = prefs_->node; + for (;;) + { + if ( !fgets( buf, 1024, f ) ) break; // EOF or Error + if ( buf[0]=='[' ) // read a new group + { + int end = strcspn( buf+1, "]\n\r" ); + buf[ end+1 ] = 0; + nd = prefs_->node->find( buf+1 ); + } + else if ( buf[0]=='+' ) // + { // value of previous name/value pair spans multiple lines + int end = strcspn( buf+1, "\n\r" ); + if ( end != 0 ) // if entry is not empty + { + buf[ end+1 ] = 0; + nd->add( buf+1 ); + } + } + else // read a name/value pair + { + int end = strcspn( buf, "\n\r" ); + if ( end != 0 ) // if entry is not empty + { + buf[ end ] = 0; + nd->set( buf ); + } + } + } + fclose( f ); + return 0; +} + +// write the group tree and all entry leafs +int Fl_Preferences::RootNode::write() +{ + makePathForFile(filename_); + FILE *f = fopen( filename_, "wb" ); + if ( !f ) return 1; + fprintf( f, "; FLTK preferences file format 1.0\n" ); + fprintf( f, "; vendor: %s\n", vendor_ ); + fprintf( f, "; application: %s\n", application_ ); + prefs_->node->write( f ); + fclose( f ); + return 0; +} + +// get the path to the preferences directory +char Fl_Preferences::RootNode::getPath( char *path, int pathlen ) +{ + strlcpy( path, filename_, pathlen); + + char *s; + for ( s = path; *s; s++ ) if ( *s == '\\' ) *s = '/'; + s = strrchr( path, '.' ); + if ( !s ) return 0; + *s = 0; + char ret = makePath( path ); + strcpy( s, "/" ); + return ret; +} + +// create a node that represents a group +// - path must be a single word, prferable alnum(), dot and underscore only. Space is ok. +Fl_Preferences::Node::Node( const char *path ) +{ + if ( path ) path_ = strdup( path ); else path_ = 0; + child_ = 0; next_ = 0; parent_ = 0; + entry = 0; + nEntry = NEntry = 0; + dirty_ = 0; +} + +// delete this and all depending nodes +Fl_Preferences::Node::~Node() +{ + Node *nx; + for ( Node *nd = child_; nd; nd = nx ) + { + nx = nd->next_; + delete nd; + } + child_ = 0L; + if ( entry ) + { + for ( int i = 0; i < nEntry; i++ ) + { + if ( entry[i].name ) { + free( entry[i].name ); + entry[i].name = 0L; + } + if ( entry[i].value ) { + free( entry[i].value ); + entry[i].value = 0L; + } + } + free( entry ); + entry = 0L; + nEntry = 0; + } + if ( path_ ) { + free( path_ ); + path_ = 0L; + } + next_ = 0L; + parent_ = 0L; +} + +// recursively check if any entry is dirty (was changed after loading a fresh prefs file) +char Fl_Preferences::Node::dirty() +{ + if ( dirty_ ) return 1; + if ( next_ && next_->dirty() ) return 1; + if ( child_ && child_->dirty() ) return 1; + return 0; +} + +// write this node (recursively from the last neighbor back to this) +// write all entries +// write all children +int Fl_Preferences::Node::write( FILE *f ) +{ + if ( next_ ) next_->write( f ); + fprintf( f, "\n[%s]\n\n", path_ ); + for ( int i = 0; i < nEntry; i++ ) + { + char *src = entry[i].value; + if ( src ) + { // hack it into smaller pieces if needed + fprintf( f, "%s:", entry[i].name ); + int cnt; + for ( cnt = 0; cnt < 60; cnt++ ) + if ( src[cnt]==0 ) break; + fwrite( src, cnt, 1, f ); + fprintf( f, "\n" ); + src += cnt; + for (;*src;) + { + for ( cnt = 0; cnt < 80; cnt++ ) + if ( src[cnt]==0 ) break; + fputc( '+', f ); + fwrite( src, cnt, 1, f ); + fputc( '\n', f ); + src += cnt; + } + } + else + fprintf( f, "%s\n", entry[i].name ); + } + if ( child_ ) child_->write( f ); + dirty_ = 0; + return 0; +} + +// set the parent node and create the full path +void Fl_Preferences::Node::setParent( Node *pn ) +{ + parent_ = pn; + next_ = pn->child_; + pn->child_ = this; + sprintf( nameBuffer, "%s/%s", pn->path_, path_ ); + free( path_ ); + path_ = strdup( nameBuffer ); +} + +// add a child to this node and set its path (try to find it first...) +Fl_Preferences::Node *Fl_Preferences::Node::addChild( const char *path ) +{ + sprintf( nameBuffer, "%s/%s", path_, path ); + char *name = strdup( nameBuffer ); + Node *nd = find( name ); + free( name ); + dirty_ = 1; + return nd; +} + +// create and set, or change an entry within this node +void Fl_Preferences::Node::set( const char *name, const char *value ) +{ + for ( int i=0; i= sizeof( nameBuffer ) ) + len = sizeof( nameBuffer ); + strlcpy( nameBuffer, line, len ); + set( nameBuffer, c+1 ); + } + else + set( line, "" ); + } + dirty_ = dirt; +} + +// add more data to an existing entry +void Fl_Preferences::Node::add( const char *line ) +{ + if ( lastEntrySet<0 || lastEntrySet>=nEntry ) return; + char *&dst = entry[ lastEntrySet ].value; + int a = strlen( dst ); + int b = strlen( line ); + dst = (char*)realloc( dst, a+b+1 ); + memcpy( dst+a, line, b+1 ); + dirty_ = 1; +} + +// get the value for a name, returns 0 if no such name +const char *Fl_Preferences::Node::get( const char *name ) +{ + int i = getEntry( name ); + return i>=0 ? entry[i].value : 0 ; +} + +// find the index of an entry, returns -1 if no such entry +int Fl_Preferences::Node::getEntry( const char *name ) +{ + for ( int i=0; inext_ ) + { + Node *nn = nd->find( path ); + if ( nn ) return nn; + } + const char *s = path+len+1; + const char *e = strchr( s, '/' ); + if (e) strlcpy( nameBuffer, s, e-s+1 ); + else strlcpy( nameBuffer, s, sizeof(nameBuffer)); + nd = new Node( nameBuffer ); + nd->setParent( this ); + return nd->find( path ); + } + } + return 0; +} + +// find a group somewhere in the tree starting here +// caller must not set 'offset' argument +// - if the node does not exist, 'search' returns NULL +// - if the pathname is "." (current node) return this node +// - if the pathname is "./" (root node) return the topmost node +// - if the pathname starts with "./", start the search at the root node instead +Fl_Preferences::Node *Fl_Preferences::Node::search( const char *path, int offset ) +{ + + if ( offset == 0 ) + { + if ( path[0] == '.' ) + { + if ( path[1] == 0 ) + { + return this; // user was searching for current node + } + else if ( path[1] == '/' ) + { + Node *nn = this; + while ( nn->parent_ ) nn = nn->parent_; + if ( path[2]==0 ) + { // user is searching for root ( "./" ) + return nn; + } + return nn->search( path+2, 2 ); // do a relative search on the root node + } + } + offset = strlen( path_ ) + 1; + } + + int len = strlen( path_ ); + if ( len < offset-1 ) return 0; + len -= offset; + if ( ( len <= 0 ) || ( strncmp( path, path_+offset, len ) == 0 ) ) + { + if ( len > 0 && path[ len ] == 0 ) + return this; + if ( len <= 0 || path[ len ] == '/' ) + { + for ( Node *nd = child_; nd; nd = nd->next_ ) + { + Node *nn = nd->search( path, offset ); + if ( nn ) return nn; + } + return 0; + } + } + return 0; +} + +// return the number of child nodes (groups) +int Fl_Preferences::Node::nChildren() +{ + int cnt = 0; + for ( Node *nd = child_; nd; nd = nd->next_ ) + cnt++; + return cnt; +} + +// return the n'th child node +const char *Fl_Preferences::Node::child( int ix ) +{ + Node *nd; + for ( nd = child_; nd; nd = nd->next_ ) + { + if ( !ix-- ) break; + } + if ( nd && nd->path_ ) + { + char *r = strrchr( nd->path_, '/' ); + return r ? r+1 : nd->path_ ; + } + return 0L ; +} + +// remove myself from the list and delete me (and all children) +char Fl_Preferences::Node::remove() +{ + Node *nd = 0, *np; + if ( parent_ ) + { + nd = parent_->child_; np = 0L; + for ( ; nd; np = nd, nd = nd->next_ ) + { + if ( nd == this ) + { + if ( np ) + np->next_ = nd->next_; + else + parent_->child_ = nd->next_; + break; + } + } + parent_->dirty_ = 1; + } + delete this; + return ( nd != 0 ); +} + + +// +// End of "$Id: Fl_Preferences.cxx 6015 2008-01-09 21:23:51Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Progress.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Progress.cxx new file mode 100644 index 0000000..5613449 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Progress.cxx @@ -0,0 +1,117 @@ +// +// "$Id: Fl_Progress.cxx 5540 2006-11-12 20:44:12Z matt $" +// +// Progress bar widget routines. +// +// Copyright 2000-2005 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_Progress::draw() - Draw the check button. +// Fl_Progress::Fl_Progress() - Construct a Fl_Progress widget. +// + +// +// Include necessary header files... +// + +#include +#include +#include + + +// +// Fl_Progress is a progress bar widget based off Fl_Widget that shows a +// standard progress bar... +// + + +// +// 'Fl_Progress::draw()' - Draw the check button. +// + +void Fl_Progress::draw() +{ + int progress; // Size of progress bar... + int bx, by, bw, bh; // Box areas... + int tx, tw; // Temporary X + width + + + // Get the box borders... + bx = Fl::box_dx(box()); + by = Fl::box_dy(box()); + bw = Fl::box_dw(box()); + bh = Fl::box_dh(box()); + + tx = x() + bx; + tw = w() - bw; + + // Draw the progress bar... + if (maximum_ > minimum_) + progress = (int)(w() * (value_ - minimum_) / (maximum_ - minimum_) + 0.5f); + else + progress = 0; + + // Draw the box and label... + if (progress > 0) { + Fl_Color c = labelcolor(); + labelcolor(fl_contrast(labelcolor(), color2())); + + fl_clip(x(), y(), progress + bx, h()); + draw_box(box(), x(), y(), w(), h(), active_r() ? color2() : fl_inactive(color2())); + draw_label(tx, y() + by, tw, h() - bh); + fl_pop_clip(); + + labelcolor(c); + + if (progress +#include + +#define INITIALREPEAT .5 +#define REPEAT .1 + +void Fl_Repeat_Button::repeat_callback(void *v) { + Fl_Button *b = (Fl_Button*)v; + Fl::add_timeout(REPEAT,repeat_callback,b); + b->do_callback(); +} + +int Fl_Repeat_Button::handle(int event) { + int newval; + switch (event) { + case FL_HIDE: + case FL_DEACTIVATE: + case FL_RELEASE: + newval = 0; goto J1; + case FL_PUSH: + case FL_DRAG: + if (Fl::visible_focus()) Fl::focus(this); + newval = Fl::event_inside(this); + J1: + if (!active()) + newval = 0; + if (value(newval)) { + if (newval) { + Fl::add_timeout(INITIALREPEAT,repeat_callback,this); + do_callback(); + } else { + Fl::remove_timeout(repeat_callback,this); + } + } + return 1; + default: + return Fl_Button::handle(event); + } +} + +// +// End of "$Id: Fl_Repeat_Button.cxx 5219 2006-06-21 06:52:10Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Return_Button.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Return_Button.cxx new file mode 100644 index 0000000..57e1979 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Return_Button.cxx @@ -0,0 +1,72 @@ +// +// "$Id: Fl_Return_Button.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Return button widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include + +int fl_return_arrow(int x, int y, int w, int h) { + int size = w; if (h +#include +#include +#include + +int Fl_Roller::handle(int event) { + static int ipos; + int newpos = horizontal() ? Fl::event_x() : Fl::event_y(); + switch (event) { + case FL_PUSH: + if (Fl::visible_focus()) { + Fl::focus(this); + redraw(); + } + handle_push(); + ipos = newpos; + return 1; + case FL_DRAG: + handle_drag(clamp(round(increment(previous_value(),newpos-ipos)))); + return 1; + case FL_RELEASE: + handle_release(); + return 1; + case FL_KEYBOARD : + switch (Fl::event_key()) { + case FL_Up: + if (horizontal()) return 0; + handle_drag(clamp(increment(value(),-1))); + return 1; + case FL_Down: + if (horizontal()) return 0; + handle_drag(clamp(increment(value(),1))); + return 1; + case FL_Left: + if (!horizontal()) return 0; + handle_drag(clamp(increment(value(),-1))); + return 1; + case FL_Right: + if (!horizontal()) return 0; + handle_drag(clamp(increment(value(),1))); + return 1; + default: + return 0; + } + // break not required because of switch... + case FL_FOCUS : + case FL_UNFOCUS : + if (Fl::visible_focus()) { + redraw(); + return 1; + } else return 0; + case FL_ENTER : + case FL_LEAVE : + return 1; + default: + return 0; + } +} + +void Fl_Roller::draw() { + if (damage()&FL_DAMAGE_ALL) draw_box(); + int X = x()+Fl::box_dx(box()); + int Y = y()+Fl::box_dy(box()); + int W = w()-Fl::box_dw(box())-1; + int H = h()-Fl::box_dh(box())-1; + if (W<=0 || H <=0) return; + int offset = step() ? int(value()/step()) : 0; + const double ARC = 1.5; // 1/2 the number of radians visible + const double delta = .2; // radians per knurl + if (horizontal()) { // horizontal one + // draw shaded ends of wheel: + int h1 = W/4+1; // distance from end that shading starts + fl_color(color()); fl_rectf(X+h1,Y,W-2*h1,H); + for (int i=0; h1; i++) { + fl_color((Fl_Color)(FL_GRAY-i-1)); + int h2 = FL_GRAY-i-1 > FL_DARK3 ? 2*h1/3+1 : 0; + fl_rectf(X+h2,Y,h1-h2,H); + fl_rectf(X+W-h1,Y,h1-h2,H); + h1 = h2; + } + if (active_r()) { + // draw ridges: + double junk; + for (double yy = -ARC+modf(offset*sin(ARC)/(W/2)/delta,&junk)*delta;; + yy += delta) { + int yy1 = int((sin(yy)/sin(ARC)+1)*W/2); + if (yy1 <= 0) continue; else if (yy1 >= W-1) break; + fl_color(FL_DARK3); fl_yxline(X+yy1,Y+1,Y+H-1); + if (yy < 0) yy1--; else yy1++; + fl_color(FL_LIGHT1);fl_yxline(X+yy1,Y+1,Y+H-1); + } + // draw edges: + h1 = W/8+1; // distance from end the color inverts + fl_color(FL_DARK2); + fl_xyline(X+h1,Y+H-1,X+W-h1); + fl_color(FL_DARK3); + fl_yxline(X,Y+H,Y,X+h1); + fl_xyline(X+W-h1,Y,X+W); + fl_color(FL_LIGHT2); + fl_xyline(X+h1,Y-1,X+W-h1); + fl_yxline(X+W,Y,Y+H,X+W-h1); + fl_xyline(X+h1,Y+H,X); + } + } else { // vertical one + // draw shaded ends of wheel: + int h1 = H/4+1; // distance from end that shading starts + fl_color(color()); fl_rectf(X,Y+h1,W,H-2*h1); + for (int i=0; h1; i++) { + fl_color((Fl_Color)(FL_GRAY-i-1)); + int h2 = FL_GRAY-i-1 > FL_DARK3 ? 2*h1/3+1 : 0; + fl_rectf(X,Y+h2,W,h1-h2); + fl_rectf(X,Y+H-h1,W,h1-h2); + h1 = h2; + } + if (active_r()) { + // draw ridges: + double junk; + for (double yy = -ARC+modf(offset*sin(ARC)/(H/2)/delta,&junk)*delta; + ; yy += delta) { + int yy1 = int((sin(yy)/sin(ARC)+1)*H/2); + if (yy1 <= 0) continue; else if (yy1 >= H-1) break; + fl_color(FL_DARK3); fl_xyline(X+1,Y+yy1,X+W-1); + if (yy < 0) yy1--; else yy1++; + fl_color(FL_LIGHT1);fl_xyline(X+1,Y+yy1,X+W-1); + } + // draw edges: + h1 = H/8+1; // distance from end the color inverts + fl_color(FL_DARK2); + fl_yxline(X+W-1,Y+h1,Y+H-h1); + fl_color(FL_DARK3); + fl_xyline(X+W,Y,X,Y+h1); + fl_yxline(X,Y+H-h1,Y+H); + fl_color(FL_LIGHT2); + fl_yxline(X,Y+h1,Y+H-h1); + fl_xyline(X,Y+H,X+W,Y+H-h1); + fl_yxline(X+W,Y+h1,Y); + } + } + + if (Fl::focus() == this) draw_focus(FL_THIN_UP_FRAME, x(), y(), w(), h()); +} + +Fl_Roller::Fl_Roller(int X,int Y,int W,int H,const char* L) + : Fl_Valuator(X,Y,W,H,L) { + box(FL_UP_BOX); + step(1,1000); +} + +// +// End of "$Id: Fl_Roller.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Round_Button.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Round_Button.cxx new file mode 100644 index 0000000..2a91862 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Round_Button.cxx @@ -0,0 +1,44 @@ +// +// "$Id: Fl_Round_Button.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Round button for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// A subclass of Fl_Button that always draws as a round circle. This +// circle is smaller than the widget size and can be surrounded by +// another box type, for compatability with Forms. + +#include +#include + +Fl_Round_Button::Fl_Round_Button(int X,int Y,int W,int H, const char *l) +: Fl_Light_Button(X,Y,W,H,l) { + box(FL_NO_BOX); + down_box(FL_ROUND_DOWN_BOX); + selection_color(FL_FOREGROUND_COLOR); +} + +// +// End of "$Id: Fl_Round_Button.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Scroll.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Scroll.cxx new file mode 100644 index 0000000..5b07ad3 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Scroll.cxx @@ -0,0 +1,298 @@ +// +// "$Id: Fl_Scroll.cxx 6927 2009-11-07 21:02:52Z matt $" +// +// Scroll widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include + +// Clear all but the scrollbars... +void Fl_Scroll::clear() { + for (int i=children() - 1; i >= 0; i --) { + Fl_Widget* o = child(i); + if (o != &hscrollbar && o != &scrollbar) { + remove(o); + delete o; + } + } +} + +// Insure the scrollbars are the last children: +void Fl_Scroll::fix_scrollbar_order() { + Fl_Widget** a = (Fl_Widget**)array(); + if (a[children()-1] != &scrollbar) { + int i,j; for (i = j = 0; j < children(); j++) + if (a[j] != &hscrollbar && a[j] != &scrollbar) a[i++] = a[j]; + a[i++] = &hscrollbar; + a[i++] = &scrollbar; + } +} + +void Fl_Scroll::draw_clip(void* v,int X, int Y, int W, int H) { + fl_clip(X,Y,W,H); + Fl_Scroll* s = (Fl_Scroll*)v; + // erase background as needed... + switch (s->box()) { + case FL_NO_BOX : + case FL_UP_FRAME : + case FL_DOWN_FRAME : + case FL_THIN_UP_FRAME : + case FL_THIN_DOWN_FRAME : + case FL_ENGRAVED_FRAME : + case FL_EMBOSSED_FRAME : + case FL_BORDER_FRAME : + case _FL_SHADOW_FRAME : + case _FL_ROUNDED_FRAME : + case _FL_OVAL_FRAME : + case _FL_PLASTIC_UP_FRAME : + case _FL_PLASTIC_DOWN_FRAME : + if (s->parent() == (Fl_Group *)s->window() && Fl::scheme_bg_) { + Fl::scheme_bg_->draw(X-(X%((Fl_Tiled_Image *)Fl::scheme_bg_)->image()->w()), + Y-(Y%((Fl_Tiled_Image *)Fl::scheme_bg_)->image()->h()), + W+((Fl_Tiled_Image *)Fl::scheme_bg_)->image()->w(), + H+((Fl_Tiled_Image *)Fl::scheme_bg_)->image()->h()); + break; + } + + default : + fl_color(s->color()); + fl_rectf(X,Y,W,H); + break; + } + Fl_Widget*const* a = s->array(); + for (int i=s->children()-2; i--;) { + Fl_Widget& o = **a++; + s->draw_child(o); + s->draw_outside_label(o); + } + fl_pop_clip(); +} + +void Fl_Scroll::bbox(int& X, int& Y, int& W, int& H) { + X = x()+Fl::box_dx(box()); + Y = y()+Fl::box_dy(box()); + W = w()-Fl::box_dw(box()); + H = h()-Fl::box_dh(box()); + if (scrollbar.visible()) { + W -= scrollbar.w(); + if (scrollbar.align() & FL_ALIGN_LEFT) X += scrollbar.w(); + } + if (hscrollbar.visible()) { + H -= hscrollbar.h(); + if (scrollbar.align() & FL_ALIGN_TOP) Y += hscrollbar.h(); + } +} + +void Fl_Scroll::draw() { + fix_scrollbar_order(); + int X,Y,W,H; bbox(X,Y,W,H); + + uchar d = damage(); + + if (d & FL_DAMAGE_ALL) { // full redraw + draw_box(box(),x(),y(),w(),h(),color()); + draw_clip(this, X, Y, W, H); + } else { + if (d & FL_DAMAGE_SCROLL) { + // scroll the contents: + fl_scroll(X, Y, W, H, oldx-xposition_, oldy-yposition_, draw_clip, this); + + // Erase the background as needed... + Fl_Widget*const* a = array(); + int L, R, T, B; + L = 999999; + R = 0; + T = 999999; + B = 0; + for (int i=children()-2; i--; a++) { + if ((*a)->x() < L) L = (*a)->x(); + if (((*a)->x() + (*a)->w()) > R) R = (*a)->x() + (*a)->w(); + if ((*a)->y() < T) T = (*a)->y(); + if (((*a)->y() + (*a)->h()) > B) B = (*a)->y() + (*a)->h(); + } + if (L > X) draw_clip(this, X, Y, L - X, H); + if (R < (X + W)) draw_clip(this, R, Y, X + W - R, H); + if (T > Y) draw_clip(this, X, Y, W, T - Y); + if (B < (Y + H)) draw_clip(this, X, B, W, Y + H - B); + } + if (d & FL_DAMAGE_CHILD) { // draw damaged children + fl_clip(X, Y, W, H); + Fl_Widget*const* a = array(); + for (int i=children()-2; i--;) update_child(**a++); + fl_pop_clip(); + } + } + + // accumulate bounding box of children: + int l = X; int r = X; int t = Y; int b = Y; + Fl_Widget*const* a = array(); + for (int i=children()-2; i--;) { + Fl_Object* o = *a++; + if (o->x() < l) l = o->x(); + if (o->y() < t) t = o->y(); + if (o->x()+o->w() > r) r = o->x()+o->w(); + if (o->y()+o->h() > b) b = o->y()+o->h(); + } + + // turn the scrollbars on and off as necessary: + // See if children would fit if we had no scrollbars... + X = x()+Fl::box_dx(box()); + Y = y()+Fl::box_dy(box()); + W = w()-Fl::box_dw(box()); + H = h()-Fl::box_dh(box()); + int vneeded = 0; + int hneeded = 0; + if (type() & VERTICAL) { + if ((type() & ALWAYS_ON) || t < Y || b > Y+H) { + vneeded = 1; + W -= scrollbar.w(); + if (scrollbar.align() & FL_ALIGN_LEFT) X += scrollbar.w(); + } + } + if (type() & HORIZONTAL) { + if ((type() & ALWAYS_ON) || l < X || r > X+W) { + hneeded = 1; + H -= hscrollbar.h(); + if (scrollbar.align() & FL_ALIGN_TOP) Y += hscrollbar.h(); + // recheck vertical since we added a horizontal scrollbar + if (!vneeded && (type() & VERTICAL)) { + if ((type() & ALWAYS_ON) || t < Y || b > Y+H) { + vneeded = 1; + W -= scrollbar.w(); + if (scrollbar.align() & FL_ALIGN_LEFT) X += scrollbar.w(); + } + } + } + } + // Now that we know what's needed, make it so. + if (vneeded && !scrollbar.visible()) { + scrollbar.set_visible(); + d = FL_DAMAGE_ALL; + } + else if (!vneeded && scrollbar.visible()) { + scrollbar.clear_visible(); + draw_clip(this, + scrollbar.align()&FL_ALIGN_LEFT ? X : X+W-scrollbar.w(), + Y, scrollbar.w(), H); + d = FL_DAMAGE_ALL; + } + if (hneeded && !hscrollbar.visible()) { + hscrollbar.set_visible(); + d = FL_DAMAGE_ALL; + } + else if (!hneeded && hscrollbar.visible()) { + hscrollbar.clear_visible(); + draw_clip(this, + X, scrollbar.align()&FL_ALIGN_TOP ? Y : Y+H-hscrollbar.h(), + W, hscrollbar.h()); + d = FL_DAMAGE_ALL; + } + + scrollbar.resize(scrollbar.align()&FL_ALIGN_LEFT ? X-scrollbar.w() : X+W, + Y, scrollbar.w(), H); + scrollbar.value(oldy = yposition_ = (Y-t), H, 0, b-t); + + hscrollbar.resize(X, + scrollbar.align()&FL_ALIGN_TOP ? Y-hscrollbar.h() : Y+H, + W, hscrollbar.h()); + hscrollbar.value(oldx = xposition_ = (X-l), W, 0, r-l); + + // draw the scrollbars: + if (d & FL_DAMAGE_ALL) { + draw_child(scrollbar); + draw_child(hscrollbar); + if (scrollbar.visible() && hscrollbar.visible()) { + // fill in the little box in the corner + fl_color(color()); + fl_rectf(scrollbar.x(), hscrollbar.y(), scrollbar.w(), hscrollbar.h()); + } + } else { + update_child(scrollbar); + update_child(hscrollbar); + } +} + +void Fl_Scroll::resize(int X, int Y, int W, int H) { + int dx = X-x(), dy = Y-y(); + Fl_Widget::resize(X,Y,W,H); // resize _before_ moving children around + fix_scrollbar_order(); + // move all the children: + Fl_Widget*const* a = array(); + for (int i=children()-2; i--;) { + Fl_Object* o = *a++; + o->position(o->x()+dx, o->y()+dy); + } +} + +void Fl_Scroll::position(int X, int Y) { + int dx = xposition_-X; + int dy = yposition_-Y; + if (!dx && !dy) return; + xposition_ = X; + yposition_ = Y; + Fl_Widget*const* a = array(); + for (int i=children(); i--;) { + Fl_Widget* o = *a++; + if (o == &hscrollbar || o == &scrollbar) continue; + o->position(o->x()+dx, o->y()+dy); + } + if (parent() == (Fl_Group *)window() && Fl::scheme_bg_) damage(FL_DAMAGE_ALL); + else damage(FL_DAMAGE_SCROLL); +} + +void Fl_Scroll::hscrollbar_cb(Fl_Widget* o, void*) { + Fl_Scroll* s = (Fl_Scroll*)(o->parent()); + s->position(int(((Fl_Scrollbar*)o)->value()), s->yposition()); +} + +void Fl_Scroll::scrollbar_cb(Fl_Widget* o, void*) { + Fl_Scroll* s = (Fl_Scroll*)(o->parent()); + s->position(s->xposition(), int(((Fl_Scrollbar*)o)->value())); +} + +Fl_Scroll::Fl_Scroll(int X,int Y,int W,int H,const char* L) + : Fl_Group(X,Y,W,H,L), + scrollbar(X+W-Fl::scrollbar_size(),Y, + Fl::scrollbar_size(),H-Fl::scrollbar_size()), + hscrollbar(X,Y+H-Fl::scrollbar_size(), + W-Fl::scrollbar_size(),Fl::scrollbar_size()) { + type(BOTH); + xposition_ = oldx = 0; + yposition_ = oldy = 0; + hscrollbar.type(FL_HORIZONTAL); + hscrollbar.callback(hscrollbar_cb); + scrollbar.callback(scrollbar_cb); +} + +int Fl_Scroll::handle(int event) { + fix_scrollbar_order(); + return Fl_Group::handle(event); +} + +// +// End of "$Id: Fl_Scroll.cxx 6927 2009-11-07 21:02:52Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Scrollbar.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Scrollbar.cxx new file mode 100644 index 0000000..f3a43c7 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Scrollbar.cxx @@ -0,0 +1,277 @@ +// +// "$Id: Fl_Scrollbar.cxx 6042 2008-02-25 13:00:53Z matt $" +// +// Scroll bar widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include "flstring.h" + +#define INITIALREPEAT .5 +#define REPEAT .05 + +void Fl_Scrollbar::increment_cb() { + int ls = maximum()>=minimum() ? linesize_ : -linesize_; + int i; + switch (pushed_) { + case 1: + i = -ls; + break; + default: + i = ls; + break; + case 5: + i = -int((maximum()-minimum())*slider_size()/(1.0-slider_size())) + ls; + if (i > -ls) i = -ls; + break; + case 6: + i = int((maximum()-minimum())*slider_size()/(1.0-slider_size())) - ls; + if (i < ls) i = ls; + break; + } + handle_drag(clamp(value() + i)); +} + +void Fl_Scrollbar::timeout_cb(void* v) { + Fl_Scrollbar* s = (Fl_Scrollbar*)v; + s->increment_cb(); + Fl::add_timeout(REPEAT, timeout_cb, s); +} + +int Fl_Scrollbar::handle(int event) { + // area of scrollbar: + int area; + int X=x(); int Y=y(); int W=w(); int H=h(); + + // adjust slider area to be inside the arrow buttons: + if (horizontal()) { + if (W >= 3*H) {X += H; W -= 2*H;} + } else { + if (H >= 3*W) {Y += W; H -= 2*W;} + } + + // which widget part is highlighted? + int relx; + int ww; + if (horizontal()) { + relx = Fl::event_x()-X; + ww = W; + } else { + relx = Fl::event_y()-Y; + ww = H; + } + if (relx < 0) area = 1; + else if (relx >= ww) area = 2; + else { + int S = int(slider_size()*ww+.5); + int T = (horizontal() ? H : W)/2+1; + if (type()==FL_VERT_NICE_SLIDER || type()==FL_HOR_NICE_SLIDER) T += 4; + if (S < T) S = T; + double val = + (maximum()-minimum()) ? (value()-minimum())/(maximum()-minimum()) : 0.5; + int sliderx; + if (val >= 1.0) sliderx = ww-S; + else if (val <= 0.0) sliderx = 0; + else sliderx = int(val*(ww-S)+.5); + if (Fl::event_button() == FL_MIDDLE_MOUSE) area = 8; + else if (relx < sliderx) area = 5; + else if (relx >= sliderx+S) area = 6; + else area = 8; + } + + switch (event) { + case FL_ENTER: + case FL_LEAVE: + return 1; + case FL_RELEASE: + damage(FL_DAMAGE_ALL); + if (pushed_) { + Fl::remove_timeout(timeout_cb, this); + pushed_ = 0; + } + handle_release(); + return 1; + case FL_PUSH: + if (pushed_) return 1; + if (area != 8) pushed_ = area; + if (pushed_) { + handle_push(); + Fl::add_timeout(INITIALREPEAT, timeout_cb, this); + increment_cb(); + damage(FL_DAMAGE_ALL); + return 1; + } + return Fl_Slider::handle(event, X,Y,W,H); + case FL_DRAG: + if (pushed_) return 1; + return Fl_Slider::handle(event, X,Y,W,H); + case FL_MOUSEWHEEL : + if (horizontal()) { + if (Fl::e_dx==0) return 0; + handle_drag(clamp(value() + linesize_ * Fl::e_dx)); + return 1; + } else { + if (Fl::e_dy==0) return 0; + handle_drag(clamp(value() + linesize_ * Fl::e_dy)); + return 1; + } + case FL_SHORTCUT: + case FL_KEYBOARD: { + int v = value(); + int ls = maximum()>=minimum() ? linesize_ : -linesize_; + if (horizontal()) { + switch (Fl::event_key()) { + case FL_Left: + v -= ls; + break; + case FL_Right: + v += ls; + break; + default: + return 0; + } + } else { // vertical + switch (Fl::event_key()) { + case FL_Up: + v -= ls; + break; + case FL_Down: + v += ls; + break; + case FL_Page_Up: + if (slider_size() >= 1.0) return 0; + v -= int((maximum()-minimum())*slider_size()/(1.0-slider_size())); + v += ls; + break; + case FL_Page_Down: + if (slider_size() >= 1.0) return 0; + v += int((maximum()-minimum())*slider_size()/(1.0-slider_size())); + v -= ls; + break; + case FL_Home: + v = int(minimum()); + break; + case FL_End: + v = int(maximum()); + break; + default: + return 0; + } + } + v = int(clamp(v)); + if (v != value()) { + Fl_Slider::value(v); + value_damage(); + set_changed(); + do_callback(); + } + return 1;} + } + return 0; +} + +void Fl_Scrollbar::draw() { + if (damage()&FL_DAMAGE_ALL) draw_box(); + int X = x()+Fl::box_dx(box()); + int Y = y()+Fl::box_dy(box()); + int W = w()-Fl::box_dw(box()); + int H = h()-Fl::box_dh(box()); + if (horizontal()) { + if (W < 3*H) {Fl_Slider::draw(X,Y,W,H); return;} + Fl_Slider::draw(X+H,Y,W-2*H,H); + if (damage()&FL_DAMAGE_ALL) { + draw_box((pushed_==1) ? fl_down(slider()) : slider(), + X, Y, H, H, selection_color()); + draw_box((pushed_==2) ? fl_down(slider()) : slider(), + X+W-H, Y, H, H, selection_color()); + if (active_r()) + fl_color(labelcolor()); + else + fl_color(fl_inactive(labelcolor())); + int w1 = (H-4)/3; if (w1 < 1) w1 = 1; + int x1 = X+(H-w1-1)/2; + int yy1 = Y+(H-2*w1-1)/2; + if (Fl::scheme_ && !strcmp(Fl::scheme_, "gtk+")) { + fl_polygon(x1, yy1+w1, x1+w1, yy1+2*w1, x1+w1-1, yy1+w1, x1+w1, yy1); + x1 += (W-H); + fl_polygon(x1, yy1, x1+1, yy1+w1, x1, yy1+2*w1, x1+w1, yy1+w1); + } else { + fl_polygon(x1, yy1+w1, x1+w1, yy1+2*w1, x1+w1, yy1); + x1 += (W-H); + fl_polygon(x1, yy1, x1, yy1+2*w1, x1+w1, yy1+w1); + } + } + } else { // vertical + if (H < 3*W) {Fl_Slider::draw(X,Y,W,H); return;} + Fl_Slider::draw(X,Y+W,W,H-2*W); + if (damage()&FL_DAMAGE_ALL) { + draw_box((pushed_==1) ? fl_down(slider()) : slider(), + X, Y, W, W, selection_color()); + draw_box((pushed_==2) ? fl_down(slider()) : slider(), + X, Y+H-W, W, W, selection_color()); + if (active_r()) + fl_color(labelcolor()); + else + fl_color(fl_inactive(labelcolor())); + int w1 = (W-4)/3; if (w1 < 1) w1 = 1; + int x1 = X+(W-2*w1-1)/2; + int yy1 = Y+(W-w1-1)/2; + if (Fl::scheme_ && !strcmp(Fl::scheme_, "gtk+")) { + fl_polygon(x1, yy1+w1, x1+w1, yy1+w1-1, x1+2*w1, yy1+w1, x1+w1, yy1); + yy1 += H-W; + fl_polygon(x1, yy1, x1+w1, yy1+1, x1+w1, yy1+w1); + fl_polygon(x1+w1, yy1+1, x1+2*w1, yy1, x1+w1, yy1+w1); + } else { + fl_polygon(x1, yy1+w1, x1+2*w1, yy1+w1, x1+w1, yy1); + yy1 += H-W; + fl_polygon(x1, yy1, x1+w1, yy1+w1, x1+2*w1, yy1); + } + } + } +} + +Fl_Scrollbar::Fl_Scrollbar(int X, int Y, int W, int H, const char* L) + : Fl_Slider(X, Y, W, H, L) +{ + box(FL_FLAT_BOX); + color(FL_DARK2); + slider(FL_UP_BOX); + linesize_ = 16; + pushed_ = 0; + step(1); +} + +Fl_Scrollbar::~Fl_Scrollbar() +{ + if (pushed_) + Fl::remove_timeout(timeout_cb, this); +} + + +// +// End of "$Id: Fl_Scrollbar.cxx 6042 2008-02-25 13:00:53Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Shared_Image.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Shared_Image.cxx new file mode 100644 index 0000000..365e904 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Shared_Image.cxx @@ -0,0 +1,467 @@ +// +// "$Id: Fl_Shared_Image.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Shared image code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include "flstring.h" + +#include +#include +#include +#include + + +// +// Global class vars... +// + +Fl_Shared_Image **Fl_Shared_Image::images_ = 0; // Shared images +int Fl_Shared_Image::num_images_ = 0; // Number of shared images +int Fl_Shared_Image::alloc_images_ = 0; // Allocated shared images + +Fl_Shared_Handler *Fl_Shared_Image::handlers_ = 0;// Additional format handlers +int Fl_Shared_Image::num_handlers_ = 0; // Number of format handlers +int Fl_Shared_Image::alloc_handlers_ = 0; // Allocated format handlers + + +// +// Typedef the C API sort function type the only way I know how... +// + +extern "C" { + typedef int (*compare_func_t)(const void *, const void *); +} + + +// Static methods that really should be inline, but some WIN32 compilers +// can't handle it... +Fl_Shared_Image **Fl_Shared_Image::images() { + return images_; +} + +int Fl_Shared_Image::num_images() { + return num_images_; +} + + +// +// 'Fl_Shared_Image::compare()' - Compare two shared images... +// + +int +Fl_Shared_Image::compare(Fl_Shared_Image **i0, // I - First image + Fl_Shared_Image **i1) { // I - Second image + int i = strcmp((*i0)->name(), (*i1)->name()); + + if (i) return i; + else if (((*i0)->w() == 0 && (*i1)->original_) || + ((*i1)->w() == 0 && (*i0)->original_)) return 0; + else if ((*i0)->w() != (*i1)->w()) return (*i0)->w() - (*i1)->w(); + else return (*i0)->h() - (*i1)->h(); +} + + +// +// 'Fl_Shared_Image::Fl_Shared_Image()' - Basic constructor. +// + +Fl_Shared_Image::Fl_Shared_Image() : Fl_Image(0,0,0) { + name_ = 0; + refcount_ = 1; + original_ = 0; + image_ = 0; + alloc_image_ = 0; +} + + +// +// 'Fl_Shared_Image::Fl_Shared_Image()' - Add an image to the image cache. +// + +Fl_Shared_Image::Fl_Shared_Image(const char *n, // I - Filename + Fl_Image *img) // I - Image + : Fl_Image(0,0,0) { + name_ = new char[strlen(n) + 1]; + strcpy((char *)name_, n); + + refcount_ = 1; + image_ = img; + alloc_image_ = !img; + original_ = 1; + + if (!img) reload(); + else update(); +} + + +// +// 'Fl_Shared_Image::add()' - Add a shared image to the array. +// + +void +Fl_Shared_Image::add() { + Fl_Shared_Image **temp; // New image pointer array... + + if (num_images_ >= alloc_images_) { + // Allocate more memory... + temp = new Fl_Shared_Image *[alloc_images_ + 32]; + + if (alloc_images_) { + memcpy(temp, images_, alloc_images_ * sizeof(Fl_Shared_Image *)); + + delete[] images_; + } + + images_ = temp; + alloc_images_ += 32; + } + + images_[num_images_] = this; + num_images_ ++; + + if (num_images_ > 1) { + qsort(images_, num_images_, sizeof(Fl_Shared_Image *), + (compare_func_t)compare); + } +} + + +// +// 'Fl_Shared_Image::update()' - Update the dimensions of the shared images. +// + +void +Fl_Shared_Image::update() { + if (image_) { + w(image_->w()); + h(image_->h()); + d(image_->d()); + data(image_->data(), image_->count()); + } +} + + +// +// 'Fl_Shared_Image::~Fl_Shared_Image()' - Destroy a shared image... +// + +Fl_Shared_Image::~Fl_Shared_Image() { + if (name_) delete[] (char *)name_; + if (alloc_image_) delete image_; +} + + +// +// 'Fl_Shared_Image::release()' - Release and possibly destroy a shared image. +// + +void +Fl_Shared_Image::release() { + int i; // Looping var... + + refcount_ --; + if (refcount_ > 0) return; + + for (i = 0; i < num_images_; i ++) + if (images_[i] == this) { + num_images_ --; + + if (i < num_images_) { + memmove(images_ + i, images_ + i + 1, + (num_images_ - i) * sizeof(Fl_Shared_Image *)); + } + + break; + } + + delete this; + + if (num_images_ == 0 && images_) { + delete[] images_; + + images_ = 0; + alloc_images_ = 0; + } +} + + +// +// 'Fl_Shared_Image::reload()' - Reload the shared image... +// + +void +Fl_Shared_Image::reload() { + // Load image from disk... + int i; // Looping var + FILE *fp; // File pointer + uchar header[64]; // Buffer for auto-detecting files + Fl_Image *img; // New image + + if (!name_) return; + + if ((fp = fopen(name_, "rb")) != NULL) { + fread(header, 1, sizeof(header), fp); + fclose(fp); + } else { + return; + } + + // Load the image as appropriate... + if (memcmp(header, "#define", 7) == 0) // XBM file + img = new Fl_XBM_Image(name_); + else if (memcmp(header, "/* XPM */", 9) == 0) // XPM file + img = new Fl_XPM_Image(name_); + else { + // Not a standard format; try an image handler... + for (i = 0, img = 0; i < num_handlers_; i ++) { + img = (handlers_[i])(name_, header, sizeof(header)); + + if (img) break; + } + } + + if (img) { + if (alloc_image_) delete image_; + + alloc_image_ = 1; + + if ((img->w() != w() && w()) || (img->h() != h() && h())) { + // Make sure the reloaded image is the same size as the existing one. + Fl_Image *temp = img->copy(w(), h()); + delete img; + image_ = temp; + } else { + image_ = img; + } + + update(); + } +} + + +// +// 'Fl_Shared_Image::copy()' - Copy and resize a shared image... +// + +Fl_Image * +Fl_Shared_Image::copy(int W, int H) { + Fl_Image *temp_image; // New image file + Fl_Shared_Image *temp_shared; // New shared image + + // Make a copy of the image we're sharing... + if (!image_) temp_image = 0; + else temp_image = image_->copy(W, H); + + // Then make a new shared image... + temp_shared = new Fl_Shared_Image(); + + temp_shared->name_ = new char[strlen(name_) + 1]; + strcpy((char *)temp_shared->name_, name_); + + temp_shared->refcount_ = 1; + temp_shared->image_ = temp_image; + temp_shared->alloc_image_ = 1; + + temp_shared->update(); + + return temp_shared; +} + + +// +// 'Fl_Shared_Image::color_average()' - Blend colors... +// + +void +Fl_Shared_Image::color_average(Fl_Color c, // I - Color to blend with + float i) { // I - Blend fraction + if (!image_) return; + + image_->color_average(c, i); + update(); +} + + +// +// 'Fl_Shared_Image::desaturate()' - Convert the image to grayscale... +// + +void +Fl_Shared_Image::desaturate() { + if (!image_) return; + + image_->desaturate(); + update(); +} + + +// +// 'Fl_Shared_Image::draw()' - Draw a shared image... +// + +void +Fl_Shared_Image::draw(int X, int Y, int W, int H, int cx, int cy) { + if (image_) image_->draw(X, Y, W, H, cx, cy); + else Fl_Image::draw(X, Y, W, H, cx, cy); +} + + +// +// 'Fl_Shared_Image::uncache()' - Uncache the shared image... +// + +void +Fl_Shared_Image::uncache() +{ + if (image_) image_->uncache(); +} + + +// +// 'Fl_Shared_Image::find()' - Find a shared image... +// + +Fl_Shared_Image * +Fl_Shared_Image::find(const char *n, int W, int H) { + Fl_Shared_Image *key, // Image key + **match; // Matching image + + if (num_images_) { + key = new Fl_Shared_Image(); + key->name_ = new char[strlen(n) + 1]; + strcpy((char *)key->name_, n); + key->w(W); + key->h(H); + + match = (Fl_Shared_Image **)bsearch(&key, images_, num_images_, + sizeof(Fl_Shared_Image *), + (compare_func_t)compare); + + delete key; + + if (match) { + (*match)->refcount_ ++; + return *match; + } + } + + return 0; +} + + +// +// 'Fl_Shared_Image::get()' - Get a shared image... +// + +Fl_Shared_Image * +Fl_Shared_Image::get(const char *n, int W, int H) { + Fl_Shared_Image *temp; // Image + + if ((temp = find(n, W, H)) != NULL) return temp; + + if ((temp = find(n)) == NULL) { + temp = new Fl_Shared_Image(n); + + if (!temp->image_) { + delete temp; + return NULL; + } + + temp->add(); + } + + if ((temp->w() != W || temp->h() != H) && W && H) { + temp = (Fl_Shared_Image *)temp->copy(W, H); + temp->add(); + } + + return temp; +} + + +// +// 'Fl_Shared_Image::add_handler()' - Add a shared image handler. +// + +void +Fl_Shared_Image::add_handler(Fl_Shared_Handler f) { + int i; // Looping var... + Fl_Shared_Handler *temp; // New image handler array... + + // First see if we have already added the handler... + for (i = 0; i < num_handlers_; i ++) { + if (handlers_[i] == f) return; + } + + if (num_handlers_ >= alloc_handlers_) { + // Allocate more memory... + temp = new Fl_Shared_Handler [alloc_handlers_ + 32]; + + if (alloc_handlers_) { + memcpy(temp, handlers_, alloc_handlers_ * sizeof(Fl_Shared_Handler)); + + delete[] handlers_; + } + + handlers_ = temp; + alloc_handlers_ += 32; + } + + handlers_[num_handlers_] = f; + num_handlers_ ++; +} + + +// +// 'Fl_Shared_Image::remove_handler()' - Remove a shared image handler. +// + +void +Fl_Shared_Image::remove_handler(Fl_Shared_Handler f) { + int i; // Looping var... + + // First see if the handler has been added... + for (i = 0; i < num_handlers_; i ++) { + if (handlers_[i] == f) break; + } + + if (i >= num_handlers_) return; + + // OK, remove the handler from the array... + num_handlers_ --; + + if (i < num_handlers_) { + // Shift later handlers down 1... + memmove(handlers_ + i, handlers_ + i + 1, + (num_handlers_ - i) * sizeof(Fl_Shared_Handler )); + } +} + + +// +// End of "$Id: Fl_Shared_Image.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Single_Window.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Single_Window.cxx new file mode 100644 index 0000000..380ae94 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Single_Window.cxx @@ -0,0 +1,41 @@ +// +// "$Id: Fl_Single_Window.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Single-buffered window for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// A window with a single-buffered context +// +// This is provided for systems where the base class is double +// buffered. You can turn it off using this subclass in case +// your display looks better without it. + +#include + +void Fl_Single_Window::show() {Fl_Window::show();} +void Fl_Single_Window::flush() {Fl_Window::flush();} + +// +// End of "$Id: Fl_Single_Window.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Slider.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Slider.cxx new file mode 100644 index 0000000..5776ef6 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Slider.cxx @@ -0,0 +1,339 @@ +// +// "$Id: Fl_Slider.cxx 5438 2006-09-17 14:58:25Z mike $" +// +// Slider widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include "flstring.h" + +void Fl_Slider::_Fl_Slider() { + slider_size_ = 0; + slider_ = 0; // FL_UP_BOX; +} + +Fl_Slider::Fl_Slider(int X, int Y, int W, int H, const char* l) +: Fl_Valuator(X, Y, W, H, l) { + box(FL_DOWN_BOX); + _Fl_Slider(); +} + +Fl_Slider::Fl_Slider(uchar t, int X, int Y, int W, int H, const char* l) + : Fl_Valuator(X, Y, W, H, l) { + type(t); + box(t==FL_HOR_NICE_SLIDER || t==FL_VERT_NICE_SLIDER ? + FL_FLAT_BOX : FL_DOWN_BOX); + _Fl_Slider(); +} + +void Fl_Slider::slider_size(double v) { + if (v < 0) v = 0; + if (v > 1) v = 1; + if (slider_size_ != float(v)) { + slider_size_ = float(v); + damage(FL_DAMAGE_EXPOSE); + } +} + +void Fl_Slider::bounds(double a, double b) { + if (minimum() != a || maximum() != b) { + Fl_Valuator::bounds(a, b); + damage(FL_DAMAGE_EXPOSE); + } +} + +int Fl_Slider::scrollvalue(int p, int W, int t, int l) { +// p = position, first line displayed +// w = window, number of lines displayed +// t = top, number of first line +// l = length, total number of lines + step(1, 1); + if (p+W > t+l) l = p+W-t; + slider_size(W >= l ? 1.0 : double(W)/double(l)); + bounds(t, l-W+t); + return value(p); +} + +// All slider interaction is done as though the slider ranges from +// zero to one, and the left (bottom) edge of the slider is at the +// given position. Since when the slider is all the way to the +// right (top) the left (bottom) edge is not all the way over, a +// position on the widget itself covers a wider range than 0-1, +// actually it ranges from 0 to 1/(1-size). + +void Fl_Slider::draw_bg(int X, int Y, int W, int H) { + fl_push_clip(X, Y, W, H); + draw_box(); + fl_pop_clip(); + + Fl_Color black = active_r() ? FL_FOREGROUND_COLOR : FL_INACTIVE_COLOR; + if (type() == FL_VERT_NICE_SLIDER) { + draw_box(FL_THIN_DOWN_BOX, X+W/2-2, Y, 4, H, black); + } else if (type() == FL_HOR_NICE_SLIDER) { + draw_box(FL_THIN_DOWN_BOX, X, Y+H/2-2, W, 4, black); + } +} + +void Fl_Slider::draw(int X, int Y, int W, int H) { + + double val; + if (minimum() == maximum()) + val = 0.5; + else { + val = (value()-minimum())/(maximum()-minimum()); + if (val > 1.0) val = 1.0; + else if (val < 0.0) val = 0.0; + } + + int ww = (horizontal() ? W : H); + int xx, S; + if (type()==FL_HOR_FILL_SLIDER || type() == FL_VERT_FILL_SLIDER) { + S = int(val*ww+.5); + if (minimum()>maximum()) {S = ww-S; xx = ww-S;} + else xx = 0; + } else { + S = int(slider_size_*ww+.5); + int T = (horizontal() ? H : W)/2+1; + if (type()==FL_VERT_NICE_SLIDER || type()==FL_HOR_NICE_SLIDER) T += 4; + if (S < T) S = T; + xx = int(val*(ww-S)+.5); + } + int xsl, ysl, wsl, hsl; + if (horizontal()) { + xsl = X+xx; + wsl = S; + ysl = Y; + hsl = H; + } else { + ysl = Y+xx; + hsl = S; + xsl = X; + wsl = W; + } + + draw_bg(X, Y, W, H); + + Fl_Boxtype box1 = slider(); + if (!box1) {box1 = (Fl_Boxtype)(box()&-2); if (!box1) box1 = FL_UP_BOX;} + if (type() == FL_VERT_NICE_SLIDER) { + draw_box(box1, xsl, ysl, wsl, hsl, FL_GRAY); + int d = (hsl-4)/2; + draw_box(FL_THIN_DOWN_BOX, xsl+2, ysl+d, wsl-4, hsl-2*d,selection_color()); + } else if (type() == FL_HOR_NICE_SLIDER) { + draw_box(box1, xsl, ysl, wsl, hsl, FL_GRAY); + int d = (wsl-4)/2; + draw_box(FL_THIN_DOWN_BOX, xsl+d, ysl+2, wsl-2*d, hsl-4,selection_color()); + } else { + if (wsl>0 && hsl>0) draw_box(box1, xsl, ysl, wsl, hsl, selection_color()); + + if (type()!=FL_HOR_FILL_SLIDER && type() != FL_VERT_FILL_SLIDER && + Fl::scheme_ && !strcmp(Fl::scheme_, "gtk+")) { + if (W>H && wsl>(hsl+8)) { + // Draw horizontal grippers + int yy, hh; + hh = hsl-8; + xx = xsl+(wsl-hsl-4)/2; + yy = ysl+3; + + fl_color(fl_darker(selection_color())); + fl_line(xx, yy+hh, xx+hh, yy); + fl_line(xx+6, yy+hh, xx+hh+6, yy); + fl_line(xx+12, yy+hh, xx+hh+12, yy); + + xx++; + fl_color(fl_lighter(selection_color())); + fl_line(xx, yy+hh, xx+hh, yy); + fl_line(xx+6, yy+hh, xx+hh+6, yy); + fl_line(xx+12, yy+hh, xx+hh+12, yy); + } else if (H>W && hsl>(wsl+8)) { + // Draw vertical grippers + int yy; + xx = xsl+4; + ww = wsl-8; + yy = ysl+(hsl-wsl-4)/2; + + fl_color(fl_darker(selection_color())); + fl_line(xx, yy+ww, xx+ww, yy); + fl_line(xx, yy+ww+6, xx+ww, yy+6); + fl_line(xx, yy+ww+12, xx+ww, yy+12); + + yy++; + fl_color(fl_lighter(selection_color())); + fl_line(xx, yy+ww, xx+ww, yy); + fl_line(xx, yy+ww+6, xx+ww, yy+6); + fl_line(xx, yy+ww+12, xx+ww, yy+12); + } + } + } + + draw_label(xsl, ysl, wsl, hsl); + if (Fl::focus() == this) { + if (type() == FL_HOR_FILL_SLIDER || type() == FL_VERT_FILL_SLIDER) draw_focus(); + else draw_focus(box1, xsl, ysl, wsl, hsl); + } +} + +void Fl_Slider::draw() { + if (damage()&FL_DAMAGE_ALL) draw_box(); + draw(x()+Fl::box_dx(box()), + y()+Fl::box_dy(box()), + w()-Fl::box_dw(box()), + h()-Fl::box_dh(box())); +} + +int Fl_Slider::handle(int event, int X, int Y, int W, int H) { + switch (event) { + case FL_PUSH: + if (!Fl::event_inside(X, Y, W, H)) return 0; + handle_push(); + case FL_DRAG: { + + double val; + if (minimum() == maximum()) + val = 0.5; + else { + val = (value()-minimum())/(maximum()-minimum()); + if (val > 1.0) val = 1.0; + else if (val < 0.0) val = 0.0; + } + + int ww = (horizontal() ? W : H); + int mx = (horizontal() ? Fl::event_x()-X : Fl::event_y()-Y); + int S; + static int offcenter; + + if (type() == FL_HOR_FILL_SLIDER || type() == FL_VERT_FILL_SLIDER) { + + S = 0; + if (event == FL_PUSH) { + int xx = int(val*ww+.5); + offcenter = mx-xx; + if (offcenter < -10 || offcenter > 10) offcenter = 0; + else return 1; + } + + } else { + + S = int(slider_size_*ww+.5); if (S >= ww) return 0; + int T = (horizontal() ? H : W)/2+1; + if (type()==FL_VERT_NICE_SLIDER || type()==FL_HOR_NICE_SLIDER) T += 4; + if (S < T) S = T; + if (event == FL_PUSH) { + int xx = int(val*(ww-S)+.5); + offcenter = mx-xx; + if (offcenter < 0) offcenter = 0; + else if (offcenter > S) offcenter = S; + else return 1; + } + } + + int xx = mx-offcenter; + double v; + char tryAgain = 1; + while (tryAgain) + { + tryAgain = 0; + if (xx < 0) { + xx = 0; + offcenter = mx; if (offcenter < 0) offcenter = 0; + } else if (xx > (ww-S)) { + xx = ww-S; + offcenter = mx-xx; if (offcenter > S) offcenter = S; + } + v = round(xx*(maximum()-minimum())/(ww-S) + minimum()); + // make sure a click outside the sliderbar moves it: + if (event == FL_PUSH && v == value()) { + offcenter = S/2; + event = FL_DRAG; + tryAgain = 1; + } + } + handle_drag(clamp(v)); + } return 1; + case FL_RELEASE: + handle_release(); + return 1; + case FL_KEYBOARD : + switch (Fl::event_key()) { + case FL_Up: + if (horizontal()) return 0; + handle_push(); + handle_drag(clamp(increment(value(),-1))); + handle_release(); + return 1; + case FL_Down: + if (horizontal()) return 0; + handle_push(); + handle_drag(clamp(increment(value(),1))); + handle_release(); + return 1; + case FL_Left: + if (!horizontal()) return 0; + handle_push(); + handle_drag(clamp(increment(value(),-1))); + handle_release(); + return 1; + case FL_Right: + if (!horizontal()) return 0; + handle_push(); + handle_drag(clamp(increment(value(),1))); + handle_release(); + return 1; + default: + return 0; + } + // break not required because of switch... + case FL_FOCUS : + case FL_UNFOCUS : + if (Fl::visible_focus()) { + redraw(); + return 1; + } else return 0; + case FL_ENTER : + case FL_LEAVE : + return 1; + default: + return 0; + } +} + +int Fl_Slider::handle(int event) { + if (event == FL_PUSH && Fl::visible_focus()) { + Fl::focus(this); + redraw(); + } + + return handle(event, + x()+Fl::box_dx(box()), + y()+Fl::box_dy(box()), + w()-Fl::box_dw(box()), + h()-Fl::box_dh(box())); +} + +// +// End of "$Id: Fl_Slider.cxx 5438 2006-09-17 14:58:25Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Sys_Menu_Bar.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Sys_Menu_Bar.cxx new file mode 100644 index 0000000..a8800ea --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Sys_Menu_Bar.cxx @@ -0,0 +1,334 @@ +// +// "$Id: Fl_Sys_Menu_Bar.cxx 6016 2008-01-09 21:32:40Z matt $" +// +// MacOS system menu bar widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +/** + * This code is a quick hack! It was written as a proof of concept. + * It has been tested on the "menubar" sample program and provides + * basic functionality. + * + * To use the System Menu Bar, simply replace the main Fl_Menu_Bar + * in an application with Fl_Sys_Menu_Bar. + * + * FLTK features not supported by the Mac System menu + * + * - no invisible menu items + * - no sybolic labels + * - embossed labels will be underlined instead + * - no font sizes + * - Shortcut Characters should be English alphanumeric only, no modifiers yet + * - no disable main menus + * - changes to menubar in run-time don't update! + * (disable, etc. - toggle and readio button do!) + * + * No care was taken to clean up the menu bar after destruction! + * ::menu(bar) should only be called once! + * Many other calls of the parent class don't work. + * Changing the menu items has no effect on the menu bar. + * Starting with OS X 10.5, FLTK applications must be created as + * a bundle for the System Menu Bar (and maybe other features) to work! + */ + +#if defined(__APPLE__) + +#include +#include +#include + +#include "flstring.h" +#include +#include + +typedef const Fl_Menu_Item *pFl_Menu_Item; + +/** + * copy the text of a menuitem into a buffer. + * Skip all '&' which would mark the shortcut in FLTK + * Skip all Mac control characters ('(', '<', ';', '^', '!' ) + */ +static void catMenuText( const char *src, char *dst ) +{ + char c; + while ( *dst ) + dst++; + if ( *src == '-' ) + src++; + while ( ( c = *src++ ) ) + { + if ( !strchr( "&(<;^!", c ) ) + *dst++ = c; + } + *dst = 0; +} + +/** + * append a marker to identify the menu font style + * labeltype_ && !m->labelfont_ ) + return; + while ( *dst ) + dst++; + + if ( m->labelfont_ & FL_BOLD ) + strcat( dst, "labelfont_ & FL_ITALIC ) + strcat( dst, "labelfont_ & FL_UNDERLINE ) + // strcat( dst, "labeltype_ == FL_EMBOSSED_LABEL ) + strcat( dst, "labeltype_ == FL_ENGRAVED_LABEL ) + strcat( dst, "labeltype_ == FL_SHADOW_LABEL ) + strcat( dst, "labeltype_ == FL_SYMBOL_LABEL ) + ; // not supported +} + +/** + * append a marker to identify the menu shortcut + * shortcut_ ) + return; + if ( m->flags & FL_SUBMENU ) + return; + if ( m->flags & FL_SUBMENU_POINTER ) + return; + char key = m->shortcut_ & 0xff; + if ( !isalnum( key ) ) + return; + + long macMod = kMenuNoCommandModifier; + if ( m->shortcut_ & FL_META ) macMod = kMenuNoModifiers; + if ( m->shortcut_ & FL_SHIFT || isupper(key) ) macMod |= kMenuShiftModifier; + if ( m->shortcut_ & FL_ALT ) macMod |= kMenuOptionModifier; + if ( m->shortcut_ & FL_CTRL ) macMod |= kMenuControlModifier; + + //SetMenuItemKeyGlyph( mh, miCnt, key ); + SetItemCmd( mh, miCnt, toupper(key) ); + SetMenuItemModifiers( mh, miCnt, macMod ); +} + +#if 0 +// this function needs to be verified before we compile it back in. +static void catMenuShortcut( const Fl_Menu_Item *m, char *dst ) +{ + if ( !m->shortcut_ ) + return; + char c = m->shortcut_ & 0xff; + if ( !isalnum( c & 0xff ) ) + return; + while ( *dst ) + dst++; + if ( m->shortcut_ & FL_CTRL ) + { + sprintf( dst, "/%c", toupper( c ) ); + } + //if ( isalnum( mm->shortcut_ ) && !( mm->flags & FL_SUBMENU ) ) + //sprintf( buf+strlen(buf), "/%c", mm->shortcut_ ); +} +#endif + +static void setMenuFlags( MenuHandle mh, int miCnt, const Fl_Menu_Item *m ) +{ + if ( m->flags & FL_MENU_TOGGLE ) + { + SetItemMark( mh, miCnt, ( m->flags & FL_MENU_VALUE ) ? 0x12 : 0 ); + } + else if ( m->flags & FL_MENU_RADIO ) + SetItemMark( mh, miCnt, ( m->flags & FL_MENU_VALUE ) ? 0x13 : 0 ); +} + +static void catMenuFlags( const Fl_Menu_Item *m, char *dst ) +{ + if ( !m->flags ) + return; + if ( m->flags & FL_MENU_INACTIVE ) + strcat( dst, "(" ); +} + +/** + * create a sub menu for a specific menu handle + */ +static void createSubMenu( MenuHandle mh, int &cnt, pFl_Menu_Item &mm ) +{ + char buf[255]; + int miCnt = 1; + while ( mm->text ) + { + MenuHandle smh = 0; + buf[1] = 0; + catMenuFont( mm, buf+1 ); + //catMenuShortcut( mm, buf+1 ); + catMenuText( mm->text, buf+1 ); + catMenuFlags( mm, buf+1 ); + if ( mm->flags & (FL_SUBMENU | FL_SUBMENU_POINTER) ) + { + cnt++; + smh = NewMenu( cnt, (unsigned char*)"\001 " ); + sprintf( buf+1+strlen(buf+1), "/\033!%c", cnt ); + } + if ( mm->flags & FL_MENU_DIVIDER ) + strcat( buf+1, ";-" ); + buf[0] = strlen( buf+1 ); + AppendMenu( mh, (unsigned char*)buf ); + // insert Appearanc manager functions here! + setMenuFlags( mh, miCnt, mm ); + setMenuShortcut( mh, miCnt, mm ); + SetMenuItemRefCon( mh, miCnt, (UInt32)mm ); + miCnt++; + if ( mm->flags & FL_MENU_DIVIDER ) + miCnt++; + if ( mm->flags & FL_SUBMENU ) + { + createSubMenu( smh, cnt, ++mm ); + } + else if ( mm->flags & FL_SUBMENU_POINTER ) + { + const Fl_Menu_Item *smm = (Fl_Menu_Item*)mm->user_data_; + createSubMenu( mh, cnt, smm ); + } + mm++; + } + InsertMenu( mh, -1 ); +} + + +/** + * create a system menu bar using the given list of menu structs + * + * \author Matthias Melcher + * + * @param m list of Fl_Menu_Item + */ +void Fl_Sys_Menu_Bar::menu(const Fl_Menu_Item *m) +{ + fl_open_display(); + Fl_Menu_Bar::menu( m ); + fl_sys_menu_bar = this; + + char buf[255]; + + int cnt = 1; // first menu is no 2. no 1 is the Apple Menu + const Fl_Menu_Item *mm = m; + for (;;) + { + if ( !mm || !mm->text ) + break; + char visible = mm->visible() ? 1 : 0; + buf[1] = 0; + catMenuText( mm->text, buf+1 ); + buf[0] = strlen( buf+1 ); + MenuHandle mh = NewMenu( ++cnt, (unsigned char*)buf ); + if ( mm->flags & FL_MENU_INACTIVE ) { + ChangeMenuAttributes(mh, kMenuAttrAutoDisable, 0); + DisableAllMenuItems(mh); + DisableMenuItem(mh, 0); + } + if ( mm->flags & FL_SUBMENU ) + createSubMenu( mh, cnt, ++mm ); + else if ( mm->flags & FL_SUBMENU_POINTER ) { + const Fl_Menu_Item *smm = (Fl_Menu_Item*)mm->user_data_; + createSubMenu( mh, cnt, smm ); + } + if ( visible ) { + InsertMenu( mh, 0 ); + } + mm++; + } + DrawMenuBar(); +} + +/* +const Fl_Menu_Item* Fl_Sys_Menu_Bar::picked(const Fl_Menu_Item* v) { + Fl_menu_Item *ret = Fl_Menu_Bar::picked( v ); + + if ( m->flags & FL_MENU_TOGGLE ) + { + SetItemMark( mh, miCnt, ( m->flags & FL_MENU_VALUE ) ? 0x12 : 0 ); + } + + return ret; +} +*/ + +void Fl_Sys_Menu_Bar::draw() { +/* -- nothing to do, system should take care of this + draw_box(); + if (!menu() || !menu()->text) return; + const Fl_Menu_Item* m; + int X = x()+6; + for (m=menu(); m->text; m = m->next()) { + int W = m->measure(0,this) + 16; + m->draw(X, y(), W, h(), this); + X += W; + } + */ +} + +/* +int Fl_Menu_Bar::handle(int event) { + const Fl_Menu_Item* v; + if (menu() && menu()->text) switch (event) { + case FL_ENTER: + case FL_LEAVE: + return 1; + case FL_PUSH: + v = 0; + J1: + v = menu()->pulldown(x(), y(), w(), h(), v, this, 0, 1); + picked(v); + return 1; + case FL_SHORTCUT: + if (visible_r()) { + v = menu()->find_shortcut(); + if (v && v->submenu()) goto J1; + } + return test_shortcut() != 0; + } + return 0; +} +*/ + +#endif /* __APPLE__ */ + +// +// End of "$Id: Fl_Sys_Menu_Bar.cxx 6016 2008-01-09 21:32:40Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Tabs.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Tabs.cxx new file mode 100644 index 0000000..fd83a58 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Tabs.cxx @@ -0,0 +1,403 @@ +// +// "$Id: Fl_Tabs.cxx 5791 2007-05-01 20:20:21Z matt $" +// +// Tab widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This is the "file card tabs" interface to allow you to put lots and lots +// of buttons and switches in a panel, as popularized by many toolkits. + +// Each child widget is a card, and it's label() is printed on the card tab. +// Clicking the tab makes that card visible. + +#include +#include +#include +#include +#include + +#define BORDER 2 +#define EXTRASPACE 10 + +// return the left edges of each tab (plus a fake left edge for a tab +// past the right-hand one). These position are actually of the left +// edge of the slope. They are either seperated by the correct distance +// or by EXTRASPACE or by zero. +// Return value is the index of the selected item. + +int Fl_Tabs::tab_positions(int* p, int* wp) { + int selected = 0; + Fl_Widget*const* a = array(); + int i; + char prev_draw_shortcut = fl_draw_shortcut; + fl_draw_shortcut = 1; + + p[0] = Fl::box_dx(box()); + for (i=0; ivisible()) selected = i; + + int wt = 0; int ht = 0; + o->measure_label(wt,ht); + + wp[i] = wt+EXTRASPACE; + p[i+1] = p[i]+wp[i]+BORDER; + } + fl_draw_shortcut = prev_draw_shortcut; + + int r = w(); + if (p[i] <= r) return selected; + // uh oh, they are too big: + // pack them against right edge: + p[i] = r; + for (i = children(); i--;) { + int l = r-wp[i]; + if (p[i+1] < l) l = p[i+1]; + if (p[i] <= l) break; + p[i] = l; + r -= EXTRASPACE; + } + // pack them against left edge and truncate width if they still don't fit: + for (i = 0; i= i*EXTRASPACE) break; + p[i] = i*EXTRASPACE; + int W = w()-1-EXTRASPACE*(children()-i) - p[i]; + if (wp[i] > W) wp[i] = W; + } + // adjust edges according to visiblity: + for (i = children(); i > selected; i--) { + p[i] = p[i-1]+wp[i-1]; + } + return selected; +} + +// return space needed for tabs. Negative to put them on the bottom: +int Fl_Tabs::tab_height() { + int H = h(); + int H2 = y(); + Fl_Widget*const* a = array(); + for (int i=children(); i--;) { + Fl_Widget* o = *a++; + if (o->y() < y()+H) H = o->y()-y(); + if (o->y()+o->h() > H2) H2 = o->y()+o->h(); + } + H2 = y()+h()-H2; + if (H2 > H) return (H2 <= 0) ? 0 : -H2; + else return (H <= 0) ? 0 : H; +} + +// this is used by fluid to pick tabs: +Fl_Widget *Fl_Tabs::which(int event_x, int event_y) { + int H = tab_height(); + if (H < 0) { + if (event_y > y()+h() || event_y < y()+h()+H) return 0; + } else { + if (event_y > y()+H || event_y < y()) return 0; + } + if (event_x < x()) return 0; + int p[128], wp[128]; + tab_positions(p, wp); + for (int i=0; i= 0) { + H += Fl::box_dy(box()); + damage(FL_DAMAGE_SCROLL, x(), y(), w(), H); + } else { + H = Fl::box_dy(box()) - H; + damage(FL_DAMAGE_SCROLL, x(), y() + h() - H, w(), H); + } +} + +int Fl_Tabs::handle(int event) { + + Fl_Widget *o; + int i; + + switch (event) { + + case FL_PUSH: { + int H = tab_height(); + if (H >= 0) { + if (Fl::event_y() > y()+H) return Fl_Group::handle(event); + } else { + if (Fl::event_y() < y()+h()+H) return Fl_Group::handle(event); + }} + case FL_DRAG: + case FL_RELEASE: + o = which(Fl::event_x(), Fl::event_y()); + if (event == FL_RELEASE) { + push(0); + if (o && Fl::visible_focus() && Fl::focus()!=this) { + Fl::focus(this); + redraw_tabs(); + } + if (o && value(o)) { + set_changed(); + do_callback(); + } + Fl_Tooltip::current(o); + } else { + push(o); + } + return 1; + case FL_MOVE: { + int ret = Fl_Group::handle(event); + Fl_Widget *o = Fl_Tooltip::current(), *n = o; + int H = tab_height(); + if ( (H>=0) && (Fl::event_y()>y()+H) ) + return ret; + else if ( (H<0) && (Fl::event_y() < y()+h()+H) ) + return ret; + else { + n = which(Fl::event_x(), Fl::event_y()); + if (!n) n = this; + } + if (n!=o) + Fl_Tooltip::enter(n); + return ret; } + case FL_FOCUS: + case FL_UNFOCUS: + if (!Fl::visible_focus()) return Fl_Group::handle(event); + if (Fl::event() == FL_RELEASE || + Fl::event() == FL_SHORTCUT || + Fl::event() == FL_KEYBOARD || + Fl::event() == FL_FOCUS || + Fl::event() == FL_UNFOCUS) { + redraw_tabs(); + if (Fl::event() == FL_FOCUS || Fl::event() == FL_UNFOCUS) return 0; + else return 1; + } else return Fl_Group::handle(event); + case FL_KEYBOARD: + switch (Fl::event_key()) { + case FL_Left: + if (child(0)->visible()) return 0; + for (i = 1; i < children(); i ++) + if (child(i)->visible()) break; + value(child(i - 1)); + set_changed(); + do_callback(); + return 1; + case FL_Right: + if (child(children() - 1)->visible()) return 0; + for (i = 0; i < children(); i ++) + if (child(i)->visible()) break; + value(child(i + 1)); + set_changed(); + do_callback(); + return 1; + case FL_Down: + redraw(); + return Fl_Group::handle(FL_FOCUS); + default: + break; + } + return Fl_Group::handle(event); + case FL_SHORTCUT: + for (i = 0; i < children(); ++i) { + Fl_Widget *c = child(i); + if (c->test_shortcut(c->label())) { + char sc = !c->visible(); + value(c); + if (sc) set_changed(); + do_callback(); + return 1; + } + } + return Fl_Group::handle(event); + case FL_SHOW: + value(); // update visibilities and fall through + default: + return Fl_Group::handle(event); + + } +} + +int Fl_Tabs::push(Fl_Widget *o) { + if (push_ == o) return 0; + if (push_ && !push_->visible() || o && !o->visible()) + redraw_tabs(); + push_ = o; + return 1; +} + +// The value() is the first visible child (or the last child if none +// are visible) and this also hides any other children. +// This allows the tabs to be deleted, moved to other groups, and +// show()/hide() called without it screwing up. +Fl_Widget* Fl_Tabs::value() { + Fl_Widget* v = 0; + Fl_Widget*const* a = array(); + for (int i=children(); i--;) { + Fl_Widget* o = *a++; + if (v) o->hide(); + else if (o->visible()) v = o; + else if (!i) {o->show(); v = o;} + } + return v; +} + +// Setting the value hides all other children, and makes this one +// visible, iff it is really a child: +int Fl_Tabs::value(Fl_Widget *newvalue) { + Fl_Widget*const* a = array(); + int ret = 0; + for (int i=children(); i--;) { + Fl_Widget* o = *a++; + if (o == newvalue) { + if (!o->visible()) ret = 1; + o->show(); + } else { + o->hide(); + } + } + return ret; +} + +enum {LEFT, RIGHT, SELECTED}; + +void Fl_Tabs::draw() { + Fl_Widget *v = value(); + int H = tab_height(); + + if (damage() & FL_DAMAGE_ALL) { // redraw the entire thing: + Fl_Color c = v ? v->color() : color(); + + draw_box(box(), x(), y()+(H>=0?H:0), w(), h()-(H>=0?H:-H), c); + + if (selection_color() != c) { + // Draw the top 5 lines of the tab pane in the selection color so + // that the user knows which tab is selected... + if (H >= 0) fl_push_clip(x(), y() + H, w(), 5); + else fl_push_clip(x(), y() + h() - H - 4, w(), 5); + + draw_box(box(), x(), y()+(H>=0?H:0), w(), h()-(H>=0?H:-H), + selection_color()); + + fl_pop_clip(); + } + if (v) draw_child(*v); + } else { // redraw the child + if (v) update_child(*v); + } + if (damage() & (FL_DAMAGE_SCROLL|FL_DAMAGE_ALL)) { + int p[128]; int wp[128]; + int selected = tab_positions(p,wp); + int i; + Fl_Widget*const* a = array(); + for (i=0; i selected; i--) + draw_tab(x()+p[i], x()+p[i+1], wp[i], H, a[i], RIGHT); + if (v) { + i = selected; + draw_tab(x()+p[i], x()+p[i+1], wp[i], H, a[i], SELECTED); + } + } +} + +void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int what) { + int sel = (what == SELECTED); + int dh = Fl::box_dh(box()); + int dy = Fl::box_dy(box()); + char prev_draw_shortcut = fl_draw_shortcut; + fl_draw_shortcut = 1; + + Fl_Boxtype bt = (o==push_ &&!sel) ? fl_down(box()) : box(); + + // compute offsets to make selected tab look bigger + int yofs = sel ? 0 : BORDER; + + if ((x2 < x1+W) && what == RIGHT) x1 = x2 - W; + + if (H >= 0) { + if (sel) fl_clip(x1, y(), x2 - x1, H + dh - dy); + else fl_clip(x1, y(), x2 - x1, H); + + H += dh; + + Fl_Color c = sel ? selection_color() : o->selection_color(); + + draw_box(bt, x1, y() + yofs, W, H + 10 - yofs, c); + + // Save the previous label color + Fl_Color oc = o->labelcolor(); + + // Draw the label using the current color... + o->labelcolor(sel ? labelcolor() : o->labelcolor()); + o->draw_label(x1, y() + yofs, W, H - yofs, FL_ALIGN_CENTER); + + // Restore the original label color... + o->labelcolor(oc); + + if (Fl::focus() == this && o->visible()) + draw_focus(box(), x1, y(), W, H); + + fl_pop_clip(); + } else { + H = -H; + + if (sel) fl_clip(x1, y() + h() - H - dy, x2 - x1, H + dy); + else fl_clip(x1, y() + h() - H, x2 - x1, H); + + H += dh; + + Fl_Color c = sel ? selection_color() : o->selection_color(); + + draw_box(bt, x1, y() + h() - H - 10, W, H + 10 - yofs, c); + + // Save the previous label color + Fl_Color oc = o->labelcolor(); + + // Draw the label using the current color... + o->labelcolor(sel ? labelcolor() : o->labelcolor()); + o->draw_label(x1, y() + h() - H, W, H - yofs, FL_ALIGN_CENTER); + + // Restore the original label color... + o->labelcolor(oc); + + if (Fl::focus() == this && o->visible()) + draw_focus(box(), x1, y() + h() - H, W, H); + + fl_pop_clip(); + } + fl_draw_shortcut = prev_draw_shortcut; +} + +Fl_Tabs::Fl_Tabs(int X,int Y,int W, int H, const char *l) : + Fl_Group(X,Y,W,H,l) +{ + box(FL_THIN_UP_BOX); + push_ = 0; +} + +// +// End of "$Id: Fl_Tabs.cxx 5791 2007-05-01 20:20:21Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Text_Buffer.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Text_Buffer.cxx new file mode 100644 index 0000000..64ee22f --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Text_Buffer.cxx @@ -0,0 +1,2534 @@ +// +// "$Id: Fl_Text_Buffer.cxx 6011 2008-01-04 20:32:37Z matt $" +// +// Copyright 2001-2005 by Bill Spitzak and others. +// Original code Copyright Mark Edel. Permission to distribute under +// the LGPL for the FLTK library granted by Mark Edel. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include "flstring.h" +#include +#include +#include + + +#define PREFERRED_GAP_SIZE 1024 +/* Initial size for the buffer gap (empty space +in the buffer where text might be inserted +if the user is typing sequential chars ) */ + +static void histogramCharacters( const char *string, int length, char hist[ 256 ], + int init ); +static void subsChars( char *string, int length, char fromChar, char toChar ); +static char chooseNullSubsChar( char hist[ 256 ] ); +static void insertColInLine( const char *line, char *insLine, int column, int insWidth, + int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, + int *endOffset ); +static void deleteRectFromLine( const char *line, int rectStart, int rectEnd, + int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, + int *endOffset ); +static void overlayRectInLine( const char *line, char *insLine, int rectStart, + int rectEnd, int tabDist, int useTabs, char nullSubsChar, char *outStr, + int *outLen, int *endOffset ); + +static void addPadding( char *string, int startIndent, int toIndent, + int tabDist, int useTabs, char nullSubsChar, int *charsAdded ); +static char *copyLine( const char* text, int *lineLen ); +static int countLines( const char *string ); +static int textWidth( const char *text, int tabDist, char nullSubsChar ); +static char *realignTabs( const char *text, int origIndent, int newIndent, + int tabDist, int useTabs, char nullSubsChar, int *newLength ); +static char *expandTabs( const char *text, int startIndent, int tabDist, + char nullSubsChar, int *newLen ); +static char *unexpandTabs( char *text, int startIndent, int tabDist, + char nullSubsChar, int *newLen ); +static int max( int i1, int i2 ); +static int min( int i1, int i2 ); + +static const char *ControlCodeTable[ 32 ] = { + "nul", "soh", "stx", "etx", "eot", "enq", "ack", "bel", + "bs", "ht", "nl", "vt", "np", "cr", "so", "si", + "dle", "dc1", "dc2", "dc3", "dc4", "nak", "syn", "etb", + "can", "em", "sub", "esc", "fs", "gs", "rs", "us"}; + +static char* undobuffer; +static int undobufferlength; +static Fl_Text_Buffer* undowidget; +static int undoat; // points after insertion +static int undocut; // number of characters deleted there +static int undoinsert; // number of characters inserted +static int undoyankcut; // length of valid contents of buffer, even if undocut=0 + +static void undobuffersize(int n) { + if (n > undobufferlength) { + if (undobuffer) { + do {undobufferlength *= 2;} while (undobufferlength < n); + undobuffer = (char*)realloc(undobuffer, undobufferlength); + } else { + undobufferlength = n+9; + undobuffer = (char*)malloc(undobufferlength); + } + } +} + +/* +** Create an empty text buffer of a pre-determined size (use this to +** avoid unnecessary re-allocation if you know exactly how much the buffer +** will need to hold +*/ +Fl_Text_Buffer::Fl_Text_Buffer( int requestedSize ) { + mLength = 0; + mBuf = (char *)malloc( requestedSize + PREFERRED_GAP_SIZE ); + mGapStart = 0; + mGapEnd = PREFERRED_GAP_SIZE; + mTabDist = 8; + mUseTabs = 1; + mPrimary.mSelected = 0; + mPrimary.mRectangular = 0; + mPrimary.mStart = mPrimary.mEnd = 0; + mSecondary.mSelected = 0; + mSecondary.mStart = mSecondary.mEnd = 0; + mSecondary.mRectangular = 0; + mHighlight.mSelected = 0; + mHighlight.mStart = mHighlight.mEnd = 0; + mHighlight.mRectangular = 0; + mNodifyProcs = NULL; + mCbArgs = NULL; + mNModifyProcs = 0; + mNPredeleteProcs = 0; + mPredeleteProcs = NULL; + mPredeleteCbArgs = NULL; + mCursorPosHint = 0; + mNullSubsChar = '\0'; + mCanUndo = 1; +#ifdef PURIFY +{ int i; for (i = mGapStart; i < mGapEnd; i++) mBuf[ i ] = '.'; } +#endif +} + +/* +** Free a text buffer +*/ +Fl_Text_Buffer::~Fl_Text_Buffer() { + free( mBuf ); + if ( mNModifyProcs != 0 ) { + delete[] mNodifyProcs; + delete[] mCbArgs; + } + if ( mNPredeleteProcs != 0 ) { + delete[] mPredeleteProcs; + delete[] mPredeleteCbArgs; + } +} + +/* +** Get the entire contents of a text buffer. Memory is allocated to contain +** the returned string, which the caller must free. +*/ +char * Fl_Text_Buffer::text() { + char *t; + + t = (char *)malloc( mLength + 1 ); + memcpy( t, mBuf, mGapStart ); + memcpy( &t[ mGapStart ], &mBuf[ mGapEnd ], + mLength - mGapStart ); + t[ mLength ] = '\0'; + return t; +} + +/* +** Replace the entire contents of the text buffer +*/ +void Fl_Text_Buffer::text( const char *t ) { + int insertedLength, deletedLength; + const char *deletedText; + + call_predelete_callbacks(0, length()); + + /* Save information for redisplay, and get rid of the old buffer */ + deletedText = text(); + deletedLength = mLength; + free( (void *)mBuf ); + + /* Start a new buffer with a gap of PREFERRED_GAP_SIZE in the center */ + insertedLength = strlen( t ); + mBuf = (char *)malloc( insertedLength + PREFERRED_GAP_SIZE ); + mLength = insertedLength; + mGapStart = insertedLength / 2; + mGapEnd = mGapStart + PREFERRED_GAP_SIZE; + memcpy( mBuf, t, mGapStart ); + memcpy( &mBuf[ mGapEnd ], &t[ mGapStart ], insertedLength - mGapStart ); +#ifdef PURIFY +{ int i; for ( i = mGapStart; i < mGapEnd; i++ ) mBuf[ i ] = '.'; } +#endif + + /* Zero all of the existing selections */ + update_selections( 0, deletedLength, 0 ); + + /* Call the saved display routine(s) to update the screen */ + call_modify_callbacks( 0, deletedLength, insertedLength, 0, deletedText ); + free( (void *)deletedText ); +} + +/* +** Return a copy of the text between "start" and "end" character positions +** from text buffer "buf". Positions start at 0, and the range does not +** include the character pointed to by "end" +*/ +char * Fl_Text_Buffer::text_range( int start, int end ) { + char * s; + int copiedLength, part1Length; + + /* Make sure start and end are ok, and allocate memory for returned string. + If start is bad, return "", if end is bad, adjust it. */ + if ( start < 0 || start > mLength ) { + s = (char *)malloc( 1 ); + s[ 0 ] = '\0'; + return s; + } + if ( end < start ) { + int temp = start; + start = end; + end = temp; + } + if ( end > mLength ) + end = mLength; + copiedLength = end - start; + s = (char *)malloc( copiedLength + 1 ); + + /* Copy the text from the buffer to the returned string */ + if ( end <= mGapStart ) { + memcpy( s, &mBuf[ start ], copiedLength ); + } else if ( start >= mGapStart ) { + memcpy( s, &mBuf[ start + ( mGapEnd - mGapStart ) ], copiedLength ); + } else { + part1Length = mGapStart - start; + memcpy( s, &mBuf[ start ], part1Length ); + memcpy( &s[ part1Length ], &mBuf[ mGapEnd ], copiedLength - part1Length ); + } + s[ copiedLength ] = '\0'; + return s; +} + +/* +** Return the character at buffer position "pos". Positions start at 0. +*/ +char Fl_Text_Buffer::character( int pos ) { + if ( pos < 0 || pos >= mLength ) + return '\0'; + if ( pos < mGapStart ) + return mBuf[ pos ]; + else + return mBuf[ pos + mGapEnd - mGapStart ]; +} + +/* +** Insert null-terminated string "text" at position "pos" in "buf" +*/ +void Fl_Text_Buffer::insert( int pos, const char *s ) { + int nInserted; + + /* if pos is not contiguous to existing text, make it */ + if ( pos > mLength ) pos = mLength; + if ( pos < 0 ) pos = 0; + + /* Even if nothing is deleted, we must call these callbacks */ + call_predelete_callbacks( pos, 0 ); + + /* insert and redisplay */ + nInserted = insert_( pos, s ); + mCursorPosHint = pos + nInserted; + call_modify_callbacks( pos, 0, nInserted, 0, NULL ); +} + +/* +** Delete the characters between "start" and "end", and insert the +** null-terminated string "text" in their place in in "buf" +*/ +void Fl_Text_Buffer::replace( int start, int end, const char *s ) { + const char * deletedText; + int nInserted; + + // Range check... + if (!s) return; + if (start < 0) start = 0; + if (end > mLength) end = mLength; + + call_predelete_callbacks( start, end-start ); + deletedText = text_range( start, end ); + remove_( start, end ); + //undoyankcut = undocut; + nInserted = insert_( start, s ); + mCursorPosHint = start + nInserted; + call_modify_callbacks( start, end - start, nInserted, 0, deletedText ); + free( (void *)deletedText ); +} + +void Fl_Text_Buffer::remove( int start, int end ) { + const char * deletedText; + + /* Make sure the arguments make sense */ + if ( start > end ) { + int temp = start; + start = end; + end = temp; + } + if ( start > mLength ) start = mLength; + if ( start < 0 ) start = 0; + if ( end > mLength ) end = mLength; + if ( end < 0 ) end = 0; + + if (start == end) return; + + call_predelete_callbacks( start, end-start ); + /* Remove and redisplay */ + deletedText = text_range( start, end ); + remove_( start, end ); + mCursorPosHint = start; + call_modify_callbacks( start, end - start, 0, 0, deletedText ); + free( (void *)deletedText ); +} + +void Fl_Text_Buffer::copy( Fl_Text_Buffer *fromBuf, int fromStart, + int fromEnd, int toPos ) { + int copiedLength = fromEnd - fromStart; + int part1Length; + + /* Prepare the buffer to receive the new text. If the new text fits in + the current buffer, just move the gap (if necessary) to where + the text should be inserted. If the new text is too large, reallocate + the buffer with a gap large enough to accomodate the new text and a + gap of PREFERRED_GAP_SIZE */ + if ( copiedLength > mGapEnd - mGapStart ) + reallocate_with_gap( toPos, copiedLength + PREFERRED_GAP_SIZE ); + else if ( toPos != mGapStart ) + move_gap( toPos ); + + /* Insert the new text (toPos now corresponds to the start of the gap) */ + if ( fromEnd <= fromBuf->mGapStart ) { + memcpy( &mBuf[ toPos ], &fromBuf->mBuf[ fromStart ], copiedLength ); + } else if ( fromStart >= fromBuf->mGapStart ) { + memcpy( &mBuf[ toPos ], + &fromBuf->mBuf[ fromStart + ( fromBuf->mGapEnd - fromBuf->mGapStart ) ], + copiedLength ); + } else { + part1Length = fromBuf->mGapStart - fromStart; + memcpy( &mBuf[ toPos ], &fromBuf->mBuf[ fromStart ], part1Length ); + memcpy( &mBuf[ toPos + part1Length ], &fromBuf->mBuf[ fromBuf->mGapEnd ], + copiedLength - part1Length ); + } + mGapStart += copiedLength; + mLength += copiedLength; + update_selections( toPos, 0, copiedLength ); +} + +/* +** remove text according to the undo variables or insert text +** from the undo buffer +*/ +int Fl_Text_Buffer::undo(int *cursorPos) { + if (undowidget != this || !undocut && !undoinsert &&!mCanUndo) return 0; + + int ilen = undocut; + int xlen = undoinsert; + int b = undoat-xlen; + + if (xlen && undoyankcut && !ilen) { + ilen = undoyankcut; + } + + if (xlen && ilen) { + undobuffersize(ilen+1); + undobuffer[ilen] = 0; + char *tmp = strdup(undobuffer); + replace(b, undoat, tmp); + if (cursorPos) *cursorPos = mCursorPosHint; + free(tmp); + } + else if (xlen) { + remove(b, undoat); + if (cursorPos) *cursorPos = mCursorPosHint; + } + else if (ilen) { + undobuffersize(ilen+1); + undobuffer[ilen] = 0; + insert(undoat, undobuffer); + if (cursorPos) *cursorPos = mCursorPosHint; + undoyankcut = 0; + } + + return 1; +} + +/* +** let the undo system know if we can undo changes +*/ +void Fl_Text_Buffer::canUndo(char flag) { + mCanUndo = flag; +} + +/* +** Insert "text" columnwise into buffer starting at displayed character +** position "column" on the line beginning at "startPos". Opens a rectangular +** space the width and height of "text", by moving all text to the right of +** "column" right. If charsInserted and charsDeleted are not NULL, the +** number of characters inserted and deleted in the operation (beginning +** at startPos) are returned in these arguments +*/ +void Fl_Text_Buffer::insert_column( int column, int startPos, const char *s, + int *charsInserted, int *charsDeleted ) { + int nLines, lineStartPos, nDeleted, insertDeleted, nInserted; + const char *deletedText; + + nLines = countLines( s ); + lineStartPos = line_start( startPos ); + nDeleted = line_end( skip_lines( startPos, nLines ) ) - + lineStartPos; + call_predelete_callbacks( lineStartPos, nDeleted ); + deletedText = text_range( lineStartPos, lineStartPos + nDeleted ); + insert_column_( column, lineStartPos, s, &insertDeleted, &nInserted, + &mCursorPosHint ); + if ( nDeleted != insertDeleted ) + Fl::error("Fl_Text_Buffer::insert_column(): internal consistency check ins1 failed"); + call_modify_callbacks( lineStartPos, nDeleted, nInserted, 0, deletedText ); + free( (void *) deletedText ); + if ( charsInserted != NULL ) + * charsInserted = nInserted; + if ( charsDeleted != NULL ) + * charsDeleted = nDeleted; +} + +/* +** Overlay "text" between displayed character positions "rectStart" and +** "rectEnd" on the line beginning at "startPos". If charsInserted and +** charsDeleted are not NULL, the number of characters inserted and deleted +** in the operation (beginning at startPos) are returned in these arguments. +*/ +void Fl_Text_Buffer::overlay_rectangular( int startPos, int rectStart, + int rectEnd, const char *s, int *charsInserted, int *charsDeleted ) { + int nLines, lineStartPos, nDeleted, insertDeleted, nInserted; + const char *deletedText; + + nLines = countLines( s ); + lineStartPos = line_start( startPos ); + nDeleted = line_end( skip_lines( startPos, nLines ) ) - + lineStartPos; + call_predelete_callbacks( lineStartPos, nDeleted ); + deletedText = text_range( lineStartPos, lineStartPos + nDeleted ); + overlay_rectangular_( lineStartPos, rectStart, rectEnd, s, &insertDeleted, + &nInserted, &mCursorPosHint ); + if ( nDeleted != insertDeleted ) + Fl::error("Fl_Text_Buffer::overlay_rectangle(): internal consistency check ovly1 failed"); + call_modify_callbacks( lineStartPos, nDeleted, nInserted, 0, deletedText ); + free( (void *) deletedText ); + if ( charsInserted != NULL ) + * charsInserted = nInserted; + if ( charsDeleted != NULL ) + * charsDeleted = nDeleted; +} + +/* +** Replace a rectangular area in buf, given by "start", "end", "rectStart", +** and "rectEnd", with "text". If "text" is vertically longer than the +** rectangle, add extra lines to make room for it. +*/ +void Fl_Text_Buffer::replace_rectangular( int start, int end, int rectStart, + int rectEnd, const char *s ) { + char *insPtr; + const char *deletedText; + char *insText = (char *)""; + int i, nInsertedLines, nDeletedLines, insLen, hint; + int insertDeleted, insertInserted, deleteInserted; + int linesPadded = 0; + + /* Make sure start and end refer to complete lines, since the + columnar delete and insert operations will replace whole lines */ + start = line_start( start ); + end = line_end( end ); + + call_predelete_callbacks( start, end-start ); + + /* If more lines will be deleted than inserted, pad the inserted text + with newlines to make it as long as the number of deleted lines. This + will indent all of the text to the right of the rectangle to the same + column. If more lines will be inserted than deleted, insert extra + lines in the buffer at the end of the rectangle to make room for the + additional lines in "text" */ + nInsertedLines = countLines( s ); + nDeletedLines = count_lines( start, end ); + if ( nInsertedLines < nDeletedLines ) { + insLen = strlen( s ); + insText = (char *)malloc( insLen + nDeletedLines - nInsertedLines + 1 ); + strcpy( insText, s ); + insPtr = insText + insLen; + for ( i = 0; i < nDeletedLines - nInsertedLines; i++ ) + *insPtr++ = '\n'; + *insPtr = '\0'; + } else if ( nDeletedLines < nInsertedLines ) { + linesPadded = nInsertedLines - nDeletedLines; + for ( i = 0; i < linesPadded; i++ ) + insert_( end, "\n" ); + } /* else nDeletedLines == nInsertedLines; */ + + /* Save a copy of the text which will be modified for the modify CBs */ + deletedText = text_range( start, end ); + + /* Delete then insert */ + remove_rectangular_( start, end, rectStart, rectEnd, &deleteInserted, &hint ); + insert_column_( rectStart, start, insText, &insertDeleted, &insertInserted, + &mCursorPosHint ); + + /* Figure out how many chars were inserted and call modify callbacks */ + if ( insertDeleted != deleteInserted + linesPadded ) + Fl::error("Fl_Text_Buffer::replace_rectangular(): internal consistency check repl1 failed"); + call_modify_callbacks( start, end - start, insertInserted, 0, deletedText ); + free( (void *) deletedText ); + if ( nInsertedLines < nDeletedLines ) + free( (void *) insText ); +} + +/* +** Remove a rectangular swath of characters between character positions start +** and end and horizontal displayed-character offsets rectStart and rectEnd. +*/ +void Fl_Text_Buffer::remove_rectangular( int start, int end, int rectStart, + int rectEnd ) { + const char * deletedText; + int nInserted; + + start = line_start( start ); + end = line_end( end ); + call_predelete_callbacks( start, end-start ); + deletedText = text_range( start, end ); + remove_rectangular_( start, end, rectStart, rectEnd, &nInserted, + &mCursorPosHint ); + call_modify_callbacks( start, end - start, nInserted, 0, deletedText ); + free( (void *) deletedText ); +} + +/* +** Clear a rectangular "hole" out of the buffer between character positions +** start and end and horizontal displayed-character offsets rectStart and +** rectEnd. +*/ +void Fl_Text_Buffer::clear_rectangular( int start, int end, int rectStart, + int rectEnd ) { + int i, nLines; + char *newlineString; + + nLines = count_lines( start, end ); + newlineString = (char *)malloc( nLines + 1 ); + for ( i = 0; i < nLines; i++ ) + newlineString[ i ] = '\n'; + newlineString[ i ] = '\0'; + overlay_rectangular( start, rectStart, rectEnd, newlineString, + NULL, NULL ); + free( (void *) newlineString ); +} + +char * Fl_Text_Buffer::text_in_rectangle( int start, int end, + int rectStart, int rectEnd ) { + int lineStart, selLeft, selRight, len; + char *textOut, *outPtr, *retabbedStr; + const char *textIn; + + start = line_start( start ); + end = line_end( end ); + textOut = (char *)malloc( ( end - start ) + 1 ); + lineStart = start; + outPtr = textOut; + while ( lineStart <= end ) { + rectangular_selection_boundaries( lineStart, rectStart, rectEnd, + &selLeft, &selRight ); + textIn = text_range( selLeft, selRight ); + len = selRight - selLeft; + memcpy( outPtr, textIn, len ); + free( (void *) textIn ); + outPtr += len; + lineStart = line_end( selRight ) + 1; + *outPtr++ = '\n'; + } + if ( outPtr != textOut ) + outPtr--; /* don't leave trailing newline */ + *outPtr = '\0'; + + /* If necessary, realign the tabs in the selection as if the text were + positioned at the left margin */ + retabbedStr = realignTabs( textOut, rectStart, 0, mTabDist, + mUseTabs, mNullSubsChar, &len ); + free( (void *) textOut ); + return retabbedStr; +} + +/* +** Set the hardware tab distance used by all displays for this buffer, +** and used in computing offsets for rectangular selection operations. +*/ +void Fl_Text_Buffer::tab_distance( int tabDist ) { + const char * deletedText; + + /* First call the pre-delete callbacks with the previous tab setting + still active. */ + call_predelete_callbacks( 0, mLength ); + + /* Change the tab setting */ + mTabDist = tabDist; + + /* Force any display routines to redisplay everything (unfortunately, + this means copying the whole buffer contents to provide "deletedText" */ + deletedText = text(); + call_modify_callbacks( 0, mLength, mLength, 0, deletedText ); + free( (void *) deletedText ); +} + +void Fl_Text_Buffer::select( int start, int end ) { + Fl_Text_Selection oldSelection = mPrimary; + + mPrimary.set( start, end ); + redisplay_selection( &oldSelection, &mPrimary ); +} + +void Fl_Text_Buffer::unselect() { + Fl_Text_Selection oldSelection = mPrimary; + + mPrimary.mSelected = 0; + redisplay_selection( &oldSelection, &mPrimary ); +} + +void Fl_Text_Buffer::select_rectangular( int start, int end, int rectStart, + int rectEnd ) { + Fl_Text_Selection oldSelection = mPrimary; + + mPrimary.set_rectangular( start, end, rectStart, rectEnd ); + redisplay_selection( &oldSelection, &mPrimary ); +} + +int Fl_Text_Buffer::selection_position( int *start, int *end + ) { + return mPrimary.position( start, end ); +} + +int Fl_Text_Buffer::selection_position( int *start, int *end, + int *isRect, int *rectStart, int *rectEnd ) { + return mPrimary.position( start, end, isRect, rectStart, + rectEnd ); +} + +char * Fl_Text_Buffer::selection_text() { + return selection_text_( &mPrimary ); +} + +void Fl_Text_Buffer::remove_selection() { + remove_selection_( &mPrimary ); +} + +void Fl_Text_Buffer::replace_selection( const char *s ) { + replace_selection_( &mPrimary, s ); +} + +void Fl_Text_Buffer::secondary_select( int start, int end ) { + Fl_Text_Selection oldSelection = mSecondary; + + mSecondary.set( start, end ); + redisplay_selection( &oldSelection, &mSecondary ); +} + +void Fl_Text_Buffer::secondary_unselect() { + Fl_Text_Selection oldSelection = mSecondary; + + mSecondary.mSelected = 0; + redisplay_selection( &oldSelection, &mSecondary ); +} + +void Fl_Text_Buffer::secondary_select_rectangular( int start, int end, + int rectStart, int rectEnd ) { + Fl_Text_Selection oldSelection = mSecondary; + + mSecondary.set_rectangular( start, end, rectStart, rectEnd ); + redisplay_selection( &oldSelection, &mSecondary ); +} + +int Fl_Text_Buffer::secondary_selection_position( int *start, int *end + ) { + return mSecondary.position( start, end ); +} + +int Fl_Text_Buffer::secondary_selection_position( int *start, int *end, + int *isRect, int *rectStart, int *rectEnd ) { + return mSecondary.position( start, end, isRect, rectStart, + rectEnd ); +} + +char * Fl_Text_Buffer::secondary_selection_text() { + return selection_text_( &mSecondary ); +} + +void Fl_Text_Buffer::remove_secondary_selection() { + remove_selection_( &mSecondary ); +} + +void Fl_Text_Buffer::replace_secondary_selection( const char *s ) { + replace_selection_( &mSecondary, s ); +} + +void Fl_Text_Buffer::highlight( int start, int end ) { + Fl_Text_Selection oldSelection = mHighlight; + + mHighlight.set( start, end ); + redisplay_selection( &oldSelection, &mHighlight ); +} + +void Fl_Text_Buffer::unhighlight() { + Fl_Text_Selection oldSelection = mHighlight; + + mHighlight.mSelected = 0; + redisplay_selection( &oldSelection, &mHighlight ); +} + +void Fl_Text_Buffer::highlight_rectangular( int start, int end, + int rectStart, int rectEnd ) { + Fl_Text_Selection oldSelection = mHighlight; + + mHighlight.set_rectangular( start, end, rectStart, rectEnd ); + redisplay_selection( &oldSelection, &mHighlight ); +} + +int Fl_Text_Buffer::highlight_position( int *start, int *end + ) { + return mHighlight.position( start, end ); +} + +int Fl_Text_Buffer::highlight_position( int *start, int *end, + int *isRect, int *rectStart, int *rectEnd ) { + return mHighlight.position( start, end, isRect, rectStart, + rectEnd ); +} + +char * Fl_Text_Buffer::highlight_text() { + return selection_text_( &mHighlight ); +} + +/* +** Add a callback routine to be called when the buffer is modified +*/ +void Fl_Text_Buffer::add_modify_callback( Fl_Text_Modify_Cb bufModifiedCB, + void *cbArg ) { + Fl_Text_Modify_Cb * newModifyProcs; + void **newCBArgs; + int i; + + newModifyProcs = new Fl_Text_Modify_Cb [ mNModifyProcs + 1 ]; + newCBArgs = new void * [ mNModifyProcs + 1 ]; + for ( i = 0; i < mNModifyProcs; i++ ) { + newModifyProcs[ i + 1 ] = mNodifyProcs[ i ]; + newCBArgs[ i + 1 ] = mCbArgs[ i ]; + } + if ( mNModifyProcs != 0 ) { + delete [] mNodifyProcs; + delete [] mCbArgs; + } + newModifyProcs[ 0 ] = bufModifiedCB; + newCBArgs[ 0 ] = cbArg; + mNModifyProcs++; + mNodifyProcs = newModifyProcs; + mCbArgs = newCBArgs; +} + +void Fl_Text_Buffer::remove_modify_callback( Fl_Text_Modify_Cb bufModifiedCB, + void *cbArg ) { + int i, toRemove = -1; + Fl_Text_Modify_Cb *newModifyProcs; + void **newCBArgs; + + /* find the matching callback to remove */ + for ( i = 0; i < mNModifyProcs; i++ ) { + if ( mNodifyProcs[ i ] == bufModifiedCB && mCbArgs[ i ] == cbArg ) { + toRemove = i; + break; + } + } + if ( toRemove == -1 ) { + Fl::error("Fl_Text_Buffer::remove_modify_callback(): Can't find modify CB to remove"); + return; + } + + /* Allocate new lists for remaining callback procs and args (if + any are left) */ + mNModifyProcs--; + if ( mNModifyProcs == 0 ) { + mNModifyProcs = 0; + delete[] mNodifyProcs; + mNodifyProcs = NULL; + delete[] mCbArgs; + mCbArgs = NULL; + return; + } + newModifyProcs = new Fl_Text_Modify_Cb [ mNModifyProcs ]; + newCBArgs = new void * [ mNModifyProcs ]; + + /* copy out the remaining members and free the old lists */ + for ( i = 0; i < toRemove; i++ ) { + newModifyProcs[ i ] = mNodifyProcs[ i ]; + newCBArgs[ i ] = mCbArgs[ i ]; + } + for ( ; i < mNModifyProcs; i++ ) { + newModifyProcs[ i ] = mNodifyProcs[ i + 1 ]; + newCBArgs[ i ] = mCbArgs[ i + 1 ]; + } + delete[] mNodifyProcs; + delete[] mCbArgs; + mNodifyProcs = newModifyProcs; + mCbArgs = newCBArgs; +} + +/* +** Add a callback routine to be called before text is deleted from the buffer. +*/ +void Fl_Text_Buffer::add_predelete_callback(Fl_Text_Predelete_Cb bufPreDeleteCB, + void *cbArg) { + Fl_Text_Predelete_Cb *newPreDeleteProcs; + void **newCBArgs; + int i; + + newPreDeleteProcs = new Fl_Text_Predelete_Cb[ mNPredeleteProcs + 1 ]; + newCBArgs = new void * [ mNPredeleteProcs + 1 ]; + for ( i = 0; i < mNPredeleteProcs; i++ ) { + newPreDeleteProcs[i + 1] = mPredeleteProcs[i]; + newCBArgs[i + 1] = mPredeleteCbArgs[i]; + } + if (! mNPredeleteProcs != 0) { + delete [] mPredeleteProcs; + delete [] mPredeleteCbArgs; + } + newPreDeleteProcs[0] = bufPreDeleteCB; + newCBArgs[0] = cbArg; + mNPredeleteProcs++; + mPredeleteProcs = newPreDeleteProcs; + mPredeleteCbArgs = newCBArgs; +} + +void Fl_Text_Buffer::remove_predelete_callback( + Fl_Text_Predelete_Cb bufPreDeleteCB, void *cbArg) { + int i, toRemove = -1; + Fl_Text_Predelete_Cb *newPreDeleteProcs; + void **newCBArgs; + + /* find the matching callback to remove */ + for ( i = 0; i < mNPredeleteProcs; i++) { + if (mPredeleteProcs[i] == bufPreDeleteCB && + mPredeleteCbArgs[i] == cbArg) { + toRemove = i; + break; + } + } + if (toRemove == -1) { + Fl::error("Fl_Text_Buffer::remove_predelete_callback(): Can't find pre-delete CB to remove"); + return; + } + + /* Allocate new lists for remaining callback procs and args (if + any are left) */ + mNPredeleteProcs--; + if (mNPredeleteProcs == 0) { + mNPredeleteProcs = 0; + delete[] mPredeleteProcs; + mPredeleteProcs = NULL; + delete[] mPredeleteCbArgs; + mPredeleteCbArgs = NULL; + return; + } + newPreDeleteProcs = new Fl_Text_Predelete_Cb [ mNPredeleteProcs ]; + newCBArgs = new void * [ mNPredeleteProcs ]; + + /* copy out the remaining members and free the old lists */ + for ( i = 0; i < toRemove; i++) { + newPreDeleteProcs[i] = mPredeleteProcs[i]; + newCBArgs[i] = mPredeleteCbArgs[i]; + } + for ( ; i < mNPredeleteProcs; i++) { + newPreDeleteProcs[i] = mPredeleteProcs[i+1]; + newCBArgs[i] = mPredeleteCbArgs[i+1]; + } + delete[] mPredeleteProcs; + delete[] mPredeleteCbArgs; + mPredeleteProcs = newPreDeleteProcs; + mPredeleteCbArgs = newCBArgs; +} + +/* +** Return the text from the entire line containing position "pos" +*/ +char * Fl_Text_Buffer::line_text( int pos ) { + return text_range( line_start( pos ), line_end( pos ) ); +} + +/* +** Find the position of the start of the line containing position "pos" +*/ +int Fl_Text_Buffer::line_start( int pos ) { + if ( !findchar_backward( pos, '\n', &pos ) ) + return 0; + return pos + 1; +} + +/* +** Find the position of the end of the line containing position "pos" +** (which is either a pointer to the newline character ending the line, +** or a pointer to one character beyond the end of the buffer) +*/ +int Fl_Text_Buffer::line_end( int pos ) { + if ( !findchar_forward( pos, '\n', &pos ) ) + pos = mLength; + return pos; +} + +int Fl_Text_Buffer::word_start( int pos ) { + while ( pos && ( isalnum( character( pos ) ) || character( pos ) == '_' ) ) { + pos--; + } + if ( !( isalnum( character( pos ) ) || character( pos ) == '_' ) ) pos++; + return pos; +} + +int Fl_Text_Buffer::word_end( int pos ) { + while (pos < length() && (isalnum(character(pos)) || character(pos) == '_' )) { + pos++; + } + return pos; +} + +/* +** Get a character from the text buffer expanded into it's screen +** representation (which may be several characters for a tab or a +** control code). Returns the number of characters written to "outStr". +** "indent" is the number of characters from the start of the line +** for figuring tabs. Output string is guranteed to be shorter or +** equal in length to FL_TEXT_MAX_EXP_CHAR_LEN +*/ +int Fl_Text_Buffer::expand_character( int pos, int indent, char *outStr ) { + return expand_character( character( pos ), indent, outStr, + mTabDist, mNullSubsChar ); +} + +/* +** Expand a single character from the text buffer into it's screen +** representation (which may be several characters for a tab or a +** control code). Returns the number of characters added to "outStr". +** "indent" is the number of characters from the start of the line +** for figuring tabs. Output string is guranteed to be shorter or +** equal in length to FL_TEXT_MAX_EXP_CHAR_LEN +*/ +int Fl_Text_Buffer::expand_character( char c, int indent, char *outStr, int tabDist, + char nullSubsChar ) { + int i, nSpaces; + + /* Convert tabs to spaces */ + if ( c == '\t' ) { + nSpaces = tabDist - ( indent % tabDist ); + for ( i = 0; i < nSpaces; i++ ) + outStr[ i ] = ' '; + return nSpaces; + } + + /* Convert control codes to readable character sequences */ + /*... is this safe with international character sets? */ + if ( ( ( unsigned char ) c ) <= 31 ) { + sprintf( outStr, "<%s>", ControlCodeTable[ ( unsigned char ) c ] ); + return strlen( outStr ); + } else if ( c == 127 ) { + sprintf( outStr, "" ); + return 5; + } else if ( c == nullSubsChar ) { + sprintf( outStr, "" ); + return 5; + } + + /* Otherwise, just return the character */ + *outStr = c; + return 1; +} + +/* +** Return the length in displayed characters of character "c" expanded +** for display (as discussed above in BufGetExpandedChar). If the +** buffer for which the character width is being measured is doing null +** substitution, nullSubsChar should be passed as that character (or nul +** to ignore). +*/ +int Fl_Text_Buffer::character_width( char c, int indent, int tabDist, char nullSubsChar ) { + /* Note, this code must parallel that in Fl_Text_Buffer::ExpandCharacter */ + if ( c == '\t' ) + return tabDist - ( indent % tabDist ); + else if ( ( ( unsigned char ) c ) <= 31 ) + return strlen( ControlCodeTable[ ( unsigned char ) c ] ) + 2; + else if ( c == 127 ) + return 5; + else if ( c == nullSubsChar ) + return 5; + return 1; +} + +/* +** Count the number of displayed characters between buffer position +** "lineStartPos" and "targetPos". (displayed characters are the characters +** shown on the screen to represent characters in the buffer, where tabs and +** control characters are expanded) +*/ +int Fl_Text_Buffer::count_displayed_characters( int lineStartPos, int targetPos ) { + int pos, charCount = 0; + char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ]; + + pos = lineStartPos; + while ( pos < targetPos ) + charCount += expand_character( pos++, charCount, expandedChar ); + return charCount; +} + +/* +** Count forward from buffer position "startPos" in displayed characters +** (displayed characters are the characters shown on the screen to represent +** characters in the buffer, where tabs and control characters are expanded) +*/ +int Fl_Text_Buffer::skip_displayed_characters( int lineStartPos, int nChars ) { + int pos, charCount = 0; + char c; + + pos = lineStartPos; + while ( charCount < nChars && pos < mLength ) { + c = character( pos ); + if ( c == '\n' ) + return pos; + charCount += character_width( c, charCount, mTabDist, mNullSubsChar ); + pos++; + } + return pos; +} + +/* +** Count the number of newlines between startPos and endPos in buffer "buf". +** The character at position "endPos" is not counted. +*/ +int Fl_Text_Buffer::count_lines( int startPos, int endPos ) { + int pos, gapLen = mGapEnd - mGapStart; + int lineCount = 0; + + pos = startPos; + while ( pos < mGapStart ) { + if ( pos == endPos ) + return lineCount; + if ( mBuf[ pos++ ] == '\n' ) + lineCount++; + } + while ( pos < mLength ) { + if ( pos == endPos ) + return lineCount; + if ( mBuf[ pos++ + gapLen ] == '\n' ) + lineCount++; + } + return lineCount; +} + +/* +** Find the first character of the line "nLines" forward from "startPos" +** in "buf" and return its position +*/ +int Fl_Text_Buffer::skip_lines( int startPos, int nLines ) { + int pos, gapLen = mGapEnd - mGapStart; + int lineCount = 0; + + if ( nLines == 0 ) + return startPos; + + pos = startPos; + while ( pos < mGapStart ) { + if ( mBuf[ pos++ ] == '\n' ) { + lineCount++; + if ( lineCount == nLines ) + return pos; + } + } + while ( pos < mLength ) { + if ( mBuf[ pos++ + gapLen ] == '\n' ) { + lineCount++; + if ( lineCount >= nLines ) + return pos; + } + } + return pos; +} + +/* +** Find the position of the first character of the line "nLines" backwards +** from "startPos" (not counting the character pointed to by "startpos" if +** that is a newline) in "buf". nLines == 0 means find the beginning of +** the line +*/ +int Fl_Text_Buffer::rewind_lines( int startPos, int nLines ) { + int pos, gapLen = mGapEnd - mGapStart; + int lineCount = -1; + + pos = startPos - 1; + if ( pos <= 0 ) + return 0; + + while ( pos >= mGapStart ) { + if ( mBuf[ pos + gapLen ] == '\n' ) { + if ( ++lineCount >= nLines ) + return pos + 1; + } + pos--; + } + while ( pos >= 0 ) { + if ( mBuf[ pos ] == '\n' ) { + if ( ++lineCount >= nLines ) + return pos + 1; + } + pos--; + } + return 0; +} + +/* +** Search forwards in buffer for string "searchString", starting with the +** character "startPos", and returning the result in "foundPos" +** returns 1 if found, 0 if not. +*/ +int Fl_Text_Buffer::search_forward( int startPos, const char *searchString, + int *foundPos, int matchCase ) +{ + if (!searchString) return 0; + int bp; + const char* sp; + while (startPos < length()) { + bp = startPos; + sp = searchString; + do { + if (!*sp) { *foundPos = startPos; return 1; } + } while ((matchCase ? character(bp++) == *sp++ : + toupper(character(bp++)) == toupper(*sp++)) + && bp < length()); + startPos++; + } + return 0; +} + +/* +** Search backwards in buffer for string "searchString", starting with the +** character BEFORE "startPos", returning the result in "foundPos" +** returns 1 if found, 0 if not. +*/ +int Fl_Text_Buffer::search_backward( int startPos, const char *searchString, + int *foundPos, int matchCase ) +{ + if (!searchString) return 0; + int bp; + const char* sp; + while (startPos > 0) { + bp = startPos-1; + sp = searchString+strlen(searchString)-1; + do { + if (sp < searchString) { *foundPos = bp+1; return 1; } + } while ((matchCase ? character(bp--) == *sp-- : + toupper(character(bp--)) == toupper(*sp--)) + && bp >= 0); + startPos--; + } + return 0; +} + +/* +** Search forwards in buffer for characters in "searchChars", starting +** with the character "startPos", and returning the result in "foundPos" +** returns 1 if found, 0 if not. +*/ +int Fl_Text_Buffer::findchars_forward( int startPos, const char *searchChars, + int *foundPos ) { + int pos, gapLen = mGapEnd - mGapStart; + const char *c; + + pos = startPos; + while ( pos < mGapStart ) { + for ( c = searchChars; *c != '\0'; c++ ) { + if ( mBuf[ pos ] == *c ) { + *foundPos = pos; + return 1; + } + } + pos++; + } + while ( pos < mLength ) { + for ( c = searchChars; *c != '\0'; c++ ) { + if ( mBuf[ pos + gapLen ] == *c ) { + *foundPos = pos; + return 1; + } + } + pos++; + } + *foundPos = mLength; + return 0; +} + +/* +** Search backwards in buffer for characters in "searchChars", starting +** with the character BEFORE "startPos", returning the result in "foundPos" +** returns 1 if found, 0 if not. +*/ +int Fl_Text_Buffer::findchars_backward( int startPos, const char *searchChars, + int *foundPos ) { + int pos, gapLen = mGapEnd - mGapStart; + const char *c; + + if ( startPos == 0 ) { + *foundPos = 0; + return 0; + } + pos = startPos == 0 ? 0 : startPos - 1; + while ( pos >= mGapStart ) { + for ( c = searchChars; *c != '\0'; c++ ) { + if ( mBuf[ pos + gapLen ] == *c ) { + *foundPos = pos; + return 1; + } + } + pos--; + } + while ( pos >= 0 ) { + for ( c = searchChars; *c != '\0'; c++ ) { + if ( mBuf[ pos ] == *c ) { + *foundPos = pos; + return 1; + } + } + pos--; + } + *foundPos = 0; + return 0; +} + +/* +** A horrible design flaw in NEdit (from the very start, before we knew that +** NEdit would become so popular), is that it uses C NULL terminated strings +** to hold text. This means editing text containing NUL characters is not +** possible without special consideration. Here is the special consideration. +** The routines below maintain a special substitution-character which stands +** in for a null, and translates strings an buffers back and forth from/to +** the substituted form, figure out what to substitute, and figure out +** when we're in over our heads and no translation is possible. +*/ + +/* +** The primary routine for integrating new text into a text buffer with +** substitution of another character for ascii nuls. This substitutes null +** characters in the string in preparation for being copied or replaced +** into the buffer, and if neccessary, adjusts the buffer as well, in the +** event that the string contains the character it is currently using for +** substitution. Returns 0, if substitution is no longer possible +** because all non-printable characters are already in use. +*/ +int Fl_Text_Buffer::substitute_null_characters( char *string, int len ) { + char histogram[ 256 ]; + + /* Find out what characters the string contains */ + histogramCharacters( string, len, histogram, 1 ); + + /* Does the string contain the null-substitute character? If so, re- + histogram the buffer text to find a character which is ok in both the + string and the buffer, and change the buffer's null-substitution + character. If none can be found, give up and return 0 */ + if ( histogram[ ( unsigned char ) mNullSubsChar ] != 0 ) { + char * bufString; + char newSubsChar; + bufString = (char*)text(); + histogramCharacters( bufString, mLength, histogram, 0 ); + newSubsChar = chooseNullSubsChar( histogram ); + if ( newSubsChar == '\0' ) + return 0; + subsChars( bufString, mLength, mNullSubsChar, newSubsChar ); + remove_( 0, mLength ); + insert_( 0, bufString ); + free( (void *) bufString ); + mNullSubsChar = newSubsChar; + } + + /* If the string contains null characters, substitute them with the + buffer's null substitution character */ + if ( histogram[ 0 ] != 0 ) + subsChars( string, len, '\0', mNullSubsChar ); + return 1; +} + +/* +** Convert strings obtained from buffers which contain null characters, which +** have been substituted for by a special substitution character, back to +** a null-containing string. There is no time penalty for calling this +** routine if no substitution has been done. +*/ +void Fl_Text_Buffer::unsubstitute_null_characters( char *string ) { + register char * c, subsChar = mNullSubsChar; + + if ( subsChar == '\0' ) + return; + for ( c = string; *c != '\0'; c++ ) + if ( *c == subsChar ) + * c = '\0'; +} + +/* +** Create a pseudo-histogram of the characters in a string (don't actually +** count, because we don't want overflow, just mark the character's presence +** with a 1). If init is true, initialize the histogram before acumulating. +** if not, add the new data to an existing histogram. +*/ +static void histogramCharacters( const char *string, int length, char hist[ 256 ], + int init ) { + int i; + const char *c; + + if ( init ) + for ( i = 0; i < 256; i++ ) + hist[ i ] = 0; + for ( c = string; c < &string[ length ]; c++ ) + hist[ *( ( unsigned char * ) c ) ] |= 1; +} + +/* +** Substitute fromChar with toChar in string. +*/ +static void subsChars( char *string, int length, char fromChar, char toChar ) { + char * c; + + for ( c = string; c < &string[ length ]; c++ ) + if ( *c == fromChar ) * c = toChar; +} + +/* +** Search through ascii control characters in histogram in order of least +** likelihood of use, find an unused character to use as a stand-in for a +** null. If the character set is full (no available characters outside of +** the printable set, return the null character. +*/ +static char chooseNullSubsChar( char hist[ 256 ] ) { +#define N_REPLACEMENTS 25 + static char replacements[ N_REPLACEMENTS ] = {1, 2, 3, 4, 5, 6, 14, 15, 16, 17, 18, 19, + 20, 21, 22, 23, 24, 25, 26, 28, 29, 30, 31, 11, 7}; + int i; + for ( i = 0; i < N_REPLACEMENTS; i++ ) + if ( hist[ replacements[ i ] ] == 0 ) + return replacements[ i ]; + return '\0'; +} + +/* +** Internal (non-redisplaying) version of BufInsert. Returns the length of +** text inserted (this is just strlen(text), however this calculation can be +** expensive and the length will be required by any caller who will continue +** on to call redisplay). pos must be contiguous with the existing text in +** the buffer (i.e. not past the end). +*/ +int Fl_Text_Buffer::insert_( int pos, const char *s ) { + int insertedLength = strlen( s ); + + /* Prepare the buffer to receive the new text. If the new text fits in + the current buffer, just move the gap (if necessary) to where + the text should be inserted. If the new text is too large, reallocate + the buffer with a gap large enough to accomodate the new text and a + gap of PREFERRED_GAP_SIZE */ + if ( insertedLength > mGapEnd - mGapStart ) + reallocate_with_gap( pos, insertedLength + PREFERRED_GAP_SIZE ); + else if ( pos != mGapStart ) + move_gap( pos ); + + /* Insert the new text (pos now corresponds to the start of the gap) */ + memcpy( &mBuf[ pos ], s, insertedLength ); + mGapStart += insertedLength; + mLength += insertedLength; + update_selections( pos, 0, insertedLength ); + + if (mCanUndo) { + if ( undowidget==this && undoat==pos && undoinsert ) { + undoinsert += insertedLength; + } + else { + undoinsert = insertedLength; + undoyankcut = (undoat==pos) ? undocut : 0 ; + } + undoat = pos+insertedLength; + undocut = 0; + undowidget = this; + } + + return insertedLength; +} + +/* +** Internal (non-redisplaying) version of BufRemove. Removes the contents +** of the buffer between start and end (and moves the gap to the site of +** the delete). +*/ +void Fl_Text_Buffer::remove_( int start, int end ) { + /* if the gap is not contiguous to the area to remove, move it there */ + + if (mCanUndo) { + if ( undowidget==this && undoat==end && undocut ) { + undobuffersize( undocut+end-start+1 ); + memmove( undobuffer+end-start, undobuffer, undocut ); + undocut += end-start; + } + else { + undocut = end-start; + undobuffersize(undocut); + } + undoat = start; + undoinsert = 0; + undoyankcut = 0; + undowidget = this; + } + + if ( start > mGapStart ) { + if (mCanUndo) + memcpy( undobuffer, mBuf+(mGapEnd-mGapStart)+start, end-start ); + move_gap( start ); + } + else if ( end < mGapStart ) { + if (mCanUndo) + memcpy( undobuffer, mBuf+start, end-start ); + move_gap( end ); + } + else { + int prelen = mGapStart - start; + if (mCanUndo) { + memcpy( undobuffer, mBuf+start, prelen ); + memcpy( undobuffer+prelen, mBuf+mGapEnd, end-start-prelen); + } + } + + /* expand the gap to encompass the deleted characters */ + mGapEnd += end - mGapStart; + mGapStart -= mGapStart - start; + + /* update the length */ + mLength -= end - start; + + /* fix up any selections which might be affected by the change */ + update_selections( start, end - start, 0 ); +} + +/* +** Insert a column of text without calling the modify callbacks. Note that +** in some pathological cases, inserting can actually decrease the size of +** the buffer because of spaces being coalesced into tabs. "nDeleted" and +** "nInserted" return the number of characters deleted and inserted beginning +** at the start of the line containing "startPos". "endPos" returns buffer +** position of the lower left edge of the inserted column (as a hint for +** routines which need to set a cursor position). +*/ +void Fl_Text_Buffer::insert_column_( int column, int startPos, const char *insText, + int *nDeleted, int *nInserted, int *endPos ) { + int nLines, start, end, insWidth, lineStart, lineEnd; + int expReplLen, expInsLen, len, endOffset; + char *c, *outStr, *outPtr, *expText, *insLine; + const char *line; + const char *replText; + const char *insPtr; + + if ( column < 0 ) + column = 0; + + /* Allocate a buffer for the replacement string large enough to hold + possibly expanded tabs in both the inserted text and the replaced + area, as well as per line: 1) an additional 2*FL_TEXT_MAX_EXP_CHAR_LEN + characters for padding where tabs and control characters cross the + column of the selection, 2) up to "column" additional spaces per + line for padding out to the position of "column", 3) padding up + to the width of the inserted text if that must be padded to align + the text beyond the inserted column. (Space for additional + newlines if the inserted text extends beyond the end of the buffer + is counted with the length of insText) */ + start = line_start( startPos ); + nLines = countLines( insText ) + 1; + insWidth = textWidth( insText, mTabDist, mNullSubsChar ); + end = line_end( skip_lines( start, nLines - 1 ) ); + replText = text_range( start, end ); + expText = expandTabs( replText, 0, mTabDist, mNullSubsChar, + &expReplLen ); + free( (void *) replText ); + free( (void *) expText ); + expText = expandTabs( insText, 0, mTabDist, mNullSubsChar, + &expInsLen ); + free( (void *) expText ); + outStr = (char *)malloc( expReplLen + expInsLen + + nLines * ( column + insWidth + FL_TEXT_MAX_EXP_CHAR_LEN ) + 1 ); + + /* Loop over all lines in the buffer between start and end removing the + text between rectStart and rectEnd and padding appropriately. Trim + trailing space from line (whitespace at the ends of lines otherwise + tends to multiply, since additional padding is added to maintain it */ + outPtr = outStr; + lineStart = start; + insPtr = insText; + for (;;) { + lineEnd = line_end( lineStart ); + line = text_range( lineStart, lineEnd ); + insLine = copyLine( insPtr, &len ); + insPtr += len; + insertColInLine( line, insLine, column, insWidth, mTabDist, + mUseTabs, mNullSubsChar, outPtr, &len, &endOffset ); + free( (void *) line ); + free( (void *) insLine ); + for ( c = outPtr + len - 1; c > outPtr && isspace( *c ); c-- ) + len--; + outPtr += len; + *outPtr++ = '\n'; + lineStart = lineEnd < mLength ? lineEnd + 1 : mLength; + if ( *insPtr == '\0' ) + break; + insPtr++; + } + if ( outPtr != outStr ) + outPtr--; /* trim back off extra newline */ + *outPtr = '\0'; + + /* replace the text between start and end with the new stuff */ + remove_( start, end ); + insert_( start, outStr ); + *nInserted = outPtr - outStr; + *nDeleted = end - start; + *endPos = start + ( outPtr - outStr ) - len + endOffset; + free( (void *) outStr ); +} + +/* +** Delete a rectangle of text without calling the modify callbacks. Returns +** the number of characters replacing those between start and end. Note that +** in some pathological cases, deleting can actually increase the size of +** the buffer because of tab expansions. "endPos" returns the buffer position +** of the point in the last line where the text was removed (as a hint for +** routines which need to position the cursor after a delete operation) +*/ +void Fl_Text_Buffer::remove_rectangular_( int start, int end, int rectStart, + int rectEnd, int *replaceLen, int *endPos ) { + int nLines, lineStart, lineEnd, len, endOffset; + char *outStr, *outPtr, *expText; + const char *s, *line; + + /* allocate a buffer for the replacement string large enough to hold + possibly expanded tabs as well as an additional FL_TEXT_MAX_EXP_CHAR_LEN * 2 + characters per line for padding where tabs and control characters cross + the edges of the selection */ + start = line_start( start ); + end = line_end( end ); + nLines = count_lines( start, end ) + 1; + s = text_range( start, end ); + expText = expandTabs( s, 0, mTabDist, mNullSubsChar, &len ); + free( (void *) s ); + free( (void *) expText ); + outStr = (char *)malloc( len + nLines * FL_TEXT_MAX_EXP_CHAR_LEN * 2 + 1 ); + + /* loop over all lines in the buffer between start and end removing + the text between rectStart and rectEnd and padding appropriately */ + lineStart = start; + outPtr = outStr; + endOffset = 0; + while ( lineStart <= mLength && lineStart <= end ) { + lineEnd = line_end( lineStart ); + line = text_range( lineStart, lineEnd ); + deleteRectFromLine( line, rectStart, rectEnd, mTabDist, + mUseTabs, mNullSubsChar, outPtr, &len, &endOffset ); + free( (void *) line ); + outPtr += len; + *outPtr++ = '\n'; + lineStart = lineEnd + 1; + } + if ( outPtr != outStr ) + outPtr--; /* trim back off extra newline */ + *outPtr = '\0'; + + /* replace the text between start and end with the newly created string */ + remove_( start, end ); + insert_( start, outStr ); + *replaceLen = outPtr - outStr; + *endPos = start + ( outPtr - outStr ) - len + endOffset; + free( (void *) outStr ); +} + +/* +** Overlay a rectangular area of text without calling the modify callbacks. +** "nDeleted" and "nInserted" return the number of characters deleted and +** inserted beginning at the start of the line containing "startPos". +** "endPos" returns buffer position of the lower left edge of the inserted +** column (as a hint for routines which need to set a cursor position). +*/ +void Fl_Text_Buffer::overlay_rectangular_(int startPos, int rectStart, + int rectEnd, const char *insText, + int *nDeleted, int *nInserted, + int *endPos ) { + int nLines, start, end, lineStart, lineEnd; + int expInsLen, len, endOffset; + char *c, *outStr, *outPtr, *expText, *insLine; + const char *line; + const char *insPtr; + + /* Allocate a buffer for the replacement string large enough to hold + possibly expanded tabs in the inserted text, as well as per line: 1) + an additional 2*FL_TEXT_MAX_EXP_CHAR_LEN characters for padding where tabs + and control characters cross the column of the selection, 2) up to + "column" additional spaces per line for padding out to the position + of "column", 3) padding up to the width of the inserted text if that + must be padded to align the text beyond the inserted column. (Space + for additional newlines if the inserted text extends beyond the end + of the buffer is counted with the length of insText) */ + start = line_start( startPos ); + nLines = countLines( insText ) + 1; + end = line_end( skip_lines( start, nLines - 1 ) ); + expText = expandTabs( insText, 0, mTabDist, mNullSubsChar, + &expInsLen ); + free( (void *) expText ); + outStr = (char *)malloc( end - start + expInsLen + + nLines * ( rectEnd + FL_TEXT_MAX_EXP_CHAR_LEN ) + 1 ); + + /* Loop over all lines in the buffer between start and end overlaying the + text between rectStart and rectEnd and padding appropriately. Trim + trailing space from line (whitespace at the ends of lines otherwise + tends to multiply, since additional padding is added to maintain it */ + outPtr = outStr; + lineStart = start; + insPtr = insText; + for (;;) { + lineEnd = line_end( lineStart ); + line = text_range( lineStart, lineEnd ); + insLine = copyLine( insPtr, &len ); + insPtr += len; + overlayRectInLine( line, insLine, rectStart, rectEnd, mTabDist, + mUseTabs, mNullSubsChar, outPtr, &len, &endOffset ); + free( (void *) line ); + free( (void *) insLine ); + for ( c = outPtr + len - 1; c > outPtr && isspace( *c ); c-- ) + len--; + outPtr += len; + *outPtr++ = '\n'; + lineStart = lineEnd < mLength ? lineEnd + 1 : mLength; + if ( *insPtr == '\0' ) + break; + insPtr++; + } + if ( outPtr != outStr ) + outPtr--; /* trim back off extra newline */ + *outPtr = '\0'; + + /* replace the text between start and end with the new stuff */ + remove_( start, end ); + insert_( start, outStr ); + *nInserted = outPtr - outStr; + *nDeleted = end - start; + *endPos = start + ( outPtr - outStr ) - len + endOffset; + free( (void *) outStr ); +} + +/* +** Insert characters from single-line string "insLine" in single-line string +** "line" at "column", leaving "insWidth" space before continuing line. +** "outLen" returns the number of characters written to "outStr", "endOffset" +** returns the number of characters from the beginning of the string to +** the right edge of the inserted text (as a hint for routines which need +** to position the cursor). +*/ +static void insertColInLine( const char *line, char *insLine, int column, int insWidth, + int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, + int *endOffset ) { + char * c, *outPtr, *retabbedStr; + const char *linePtr; + int indent, toIndent, len, postColIndent; + + /* copy the line up to "column" */ + outPtr = outStr; + indent = 0; + for ( linePtr = line; *linePtr != '\0'; linePtr++ ) { + len = Fl_Text_Buffer::character_width( *linePtr, indent, tabDist, nullSubsChar ); + if ( indent + len > column ) + break; + indent += len; + *outPtr++ = *linePtr; + } + + /* If "column" falls in the middle of a character, and the character is a + tab, leave it off and leave the indent short and it will get padded + later. If it's a control character, insert it and adjust indent + accordingly. */ + if ( indent < column && *linePtr != '\0' ) { + postColIndent = indent + len; + if ( *linePtr == '\t' ) + linePtr++; + else { + *outPtr++ = *linePtr++; + indent += len; + } + } else + postColIndent = indent; + + /* If there's no text after the column and no text to insert, that's all */ + if ( *insLine == '\0' && *linePtr == '\0' ) { + *outLen = *endOffset = outPtr - outStr; + return; + } + + /* pad out to column if text is too short */ + if ( indent < column ) { + addPadding( outPtr, indent, column, tabDist, useTabs, nullSubsChar, &len ); + outPtr += len; + indent = column; + } + + /* Copy the text from "insLine" (if any), recalculating the tabs as if + the inserted string began at column 0 to its new column destination */ + if ( *insLine != '\0' ) { + retabbedStr = realignTabs( insLine, 0, indent, tabDist, useTabs, + nullSubsChar, &len ); + for ( c = retabbedStr; *c != '\0'; c++ ) { + *outPtr++ = *c; + len = Fl_Text_Buffer::character_width( *c, indent, tabDist, nullSubsChar ); + indent += len; + } + free( (void *) retabbedStr ); + } + + /* If the original line did not extend past "column", that's all */ + if ( *linePtr == '\0' ) { + *outLen = *endOffset = outPtr - outStr; + return; + } + + /* Pad out to column + width of inserted text + (additional original + offset due to non-breaking character at column) */ + toIndent = column + insWidth + postColIndent - column; + addPadding( outPtr, indent, toIndent, tabDist, useTabs, nullSubsChar, &len ); + outPtr += len; + indent = toIndent; + + /* realign tabs for text beyond "column" and write it out */ + retabbedStr = realignTabs( linePtr, postColIndent, indent, tabDist, + useTabs, nullSubsChar, &len ); + strcpy( outPtr, retabbedStr ); + free( (void *) retabbedStr ); + *endOffset = outPtr - outStr; + *outLen = ( outPtr - outStr ) + len; +} + +/* +** Remove characters in single-line string "line" between displayed positions +** "rectStart" and "rectEnd", and write the result to "outStr", which is +** assumed to be large enough to hold the returned string. Note that in +** certain cases, it is possible for the string to get longer due to +** expansion of tabs. "endOffset" returns the number of characters from +** the beginning of the string to the point where the characters were +** deleted (as a hint for routines which need to position the cursor). +*/ +static void deleteRectFromLine( const char *line, int rectStart, int rectEnd, + int tabDist, int useTabs, char nullSubsChar, char *outStr, int *outLen, + int *endOffset ) { + int indent, preRectIndent, postRectIndent, len; + const char *c; + char *retabbedStr, *outPtr; + + /* copy the line up to rectStart */ + outPtr = outStr; + indent = 0; + for ( c = line; *c != '\0'; c++ ) { + if ( indent > rectStart ) + break; + len = Fl_Text_Buffer::character_width( *c, indent, tabDist, nullSubsChar ); + if ( indent + len > rectStart && ( indent == rectStart || *c == '\t' ) ) + break; + indent += len; + *outPtr++ = *c; + } + preRectIndent = indent; + + /* skip the characters between rectStart and rectEnd */ + for ( ; *c != '\0' && indent < rectEnd; c++ ) + indent += Fl_Text_Buffer::character_width( *c, indent, tabDist, nullSubsChar ); + postRectIndent = indent; + + /* If the line ended before rectEnd, there's nothing more to do */ + if ( *c == '\0' ) { + *outPtr = '\0'; + *outLen = *endOffset = outPtr - outStr; + return; + } + + /* fill in any space left by removed tabs or control characters + which straddled the boundaries */ + indent = max( rectStart + postRectIndent - rectEnd, preRectIndent ); + addPadding( outPtr, preRectIndent, indent, tabDist, useTabs, nullSubsChar, + &len ); + outPtr += len; + + /* Copy the rest of the line. If the indentation has changed, preserve + the position of non-whitespace characters by converting tabs to + spaces, then back to tabs with the correct offset */ + retabbedStr = realignTabs( c, postRectIndent, indent, tabDist, useTabs, + nullSubsChar, &len ); + strcpy( outPtr, retabbedStr ); + free( (void *) retabbedStr ); + *endOffset = outPtr - outStr; + *outLen = ( outPtr - outStr ) + len; +} + +/* +** Overlay characters from single-line string "insLine" on single-line string +** "line" between displayed character offsets "rectStart" and "rectEnd". +** "outLen" returns the number of characters written to "outStr", "endOffset" +** returns the number of characters from the beginning of the string to +** the right edge of the inserted text (as a hint for routines which need +** to position the cursor). +*/ +static void overlayRectInLine( const char *line, char *insLine, int rectStart, + int rectEnd, int tabDist, int useTabs, char nullSubsChar, char *outStr, + int *outLen, int *endOffset ) { + char * c, *outPtr, *retabbedStr; + int inIndent, outIndent, len, postRectIndent; + const char *linePtr; + + /* copy the line up to "rectStart" */ + outPtr = outStr; + inIndent = outIndent = 0; + for ( linePtr = line; *linePtr != '\0'; linePtr++ ) { + len = Fl_Text_Buffer::character_width( *linePtr, inIndent, tabDist, nullSubsChar ); + if ( inIndent + len > rectStart ) + break; + inIndent += len; + outIndent += len; + *outPtr++ = *linePtr; + } + + /* If "rectStart" falls in the middle of a character, and the character + is a tab, leave it off and leave the outIndent short and it will get + padded later. If it's a control character, insert it and adjust + outIndent accordingly. */ + if ( inIndent < rectStart && *linePtr != '\0' ) { + if ( *linePtr == '\t' ) { + linePtr++; + inIndent += len; + } else { + *outPtr++ = *linePtr++; + outIndent += len; + inIndent += len; + } + } + + /* skip the characters between rectStart and rectEnd */ + postRectIndent = rectEnd; + for ( ; *linePtr != '\0'; linePtr++ ) { + inIndent += Fl_Text_Buffer::character_width( *linePtr, inIndent, tabDist, nullSubsChar ); + if ( inIndent >= rectEnd ) { + linePtr++; + postRectIndent = inIndent; + break; + } + } + + /* If there's no text after rectStart and no text to insert, that's all */ + if ( *insLine == '\0' && *linePtr == '\0' ) { + *outLen = *endOffset = outPtr - outStr; + return; + } + + /* pad out to rectStart if text is too short */ + if ( outIndent < rectStart ) { + addPadding( outPtr, outIndent, rectStart, tabDist, useTabs, nullSubsChar, + &len ); + outPtr += len; + } + outIndent = rectStart; + + /* Copy the text from "insLine" (if any), recalculating the tabs as if + the inserted string began at column 0 to its new column destination */ + if ( *insLine != '\0' ) { + retabbedStr = realignTabs( insLine, 0, rectStart, tabDist, useTabs, + nullSubsChar, &len ); + for ( c = retabbedStr; *c != '\0'; c++ ) { + *outPtr++ = *c; + len = Fl_Text_Buffer::character_width( *c, outIndent, tabDist, nullSubsChar ); + outIndent += len; + } + free( (void *) retabbedStr ); + } + + /* If the original line did not extend past "rectStart", that's all */ + if ( *linePtr == '\0' ) { + *outLen = *endOffset = outPtr - outStr; + return; + } + + /* Pad out to rectEnd + (additional original offset + due to non-breaking character at right boundary) */ + addPadding( outPtr, outIndent, postRectIndent, tabDist, useTabs, + nullSubsChar, &len ); + outPtr += len; + outIndent = postRectIndent; + + /* copy the text beyond "rectEnd" */ + strcpy( outPtr, linePtr ); + *endOffset = outPtr - outStr; + *outLen = ( outPtr - outStr ) + strlen( linePtr ); +} + +void Fl_Text_Selection::set( int startpos, int endpos ) { + mSelected = startpos != endpos; + mRectangular = 0; + mStart = min( startpos, endpos ); + mEnd = max( startpos, endpos ); +} + +void Fl_Text_Selection::set_rectangular( int startpos, int endpos, + int rectStart, int rectEnd ) { + mSelected = rectStart < rectEnd; + mRectangular = 1; + mStart = startpos; + mEnd = endpos; + mRectStart = rectStart; + mRectEnd = rectEnd; +} + +int Fl_Text_Selection::position( int *startpos, int *endpos ) { + if ( !mSelected ) + return 0; + *startpos = mStart; + *endpos = mEnd; + + return 1; +} + +int Fl_Text_Selection::position( int *startpos, int *endpos, + int *isRect, int *rectStart, int *rectEnd ) { + if ( !mSelected ) + return 0; + *isRect = mRectangular; + *startpos = mStart; + *endpos = mEnd; + if ( mRectangular ) { + *rectStart = mRectStart; + *rectEnd = mRectEnd; + } + return 1; +} + +/* +** Return true if position "pos" with indentation "dispIndex" is in +** the Fl_Text_Selection. +*/ +int Fl_Text_Selection::includes(int pos, int lineStartPos, int dispIndex) { + return selected() && + ( (!rectangular() && pos >= start() && pos < end()) || + (rectangular() && pos >= start() && lineStartPos <= end() && + dispIndex >= rect_start() && dispIndex < rect_end()) + ); +} + + + +char * Fl_Text_Buffer::selection_text_( Fl_Text_Selection *sel ) { + int start, end, isRect, rectStart, rectEnd; + char *s; + + /* If there's no selection, return an allocated empty string */ + if ( !sel->position( &start, &end, &isRect, &rectStart, &rectEnd ) ) { + s = (char *)malloc( 1 ); + *s = '\0'; + return s; + } + + /* If the selection is not rectangular, return the selected range */ + if ( isRect ) + return text_in_rectangle( start, end, rectStart, rectEnd ); + else + return text_range( start, end ); +} + +void Fl_Text_Buffer::remove_selection_( Fl_Text_Selection *sel ) { + int start, end; + int isRect, rectStart, rectEnd; + + if ( !sel->position( &start, &end, &isRect, &rectStart, &rectEnd ) ) + return; + if ( isRect ) + remove_rectangular( start, end, rectStart, rectEnd ); + else { + remove( start, end ); + //undoyankcut = undocut; + } +} + +void Fl_Text_Buffer::replace_selection_( Fl_Text_Selection *sel, const char *s ) { + int start, end, isRect, rectStart, rectEnd; + Fl_Text_Selection oldSelection = *sel; + + /* If there's no selection, return */ + if ( !sel->position( &start, &end, &isRect, &rectStart, &rectEnd ) ) + return; + + /* Do the appropriate type of replace */ + if ( isRect ) + replace_rectangular( start, end, rectStart, rectEnd, s ); + else + replace( start, end, s ); + + /* Unselect (happens automatically in BufReplace, but BufReplaceRect + can't detect when the contents of a selection goes away) */ + sel->mSelected = 0; + redisplay_selection( &oldSelection, sel ); +} + +static void addPadding( char *string, int startIndent, int toIndent, + int tabDist, int useTabs, char nullSubsChar, int *charsAdded ) { + char * outPtr; + int len, indent; + + indent = startIndent; + outPtr = string; + if ( useTabs ) { + while ( indent < toIndent ) { + len = Fl_Text_Buffer::character_width( '\t', indent, tabDist, nullSubsChar ); + if ( len > 1 && indent + len <= toIndent ) { + *outPtr++ = '\t'; + indent += len; + } else { + *outPtr++ = ' '; + indent++; + } + } + } else { + while ( indent < toIndent ) { + *outPtr++ = ' '; + indent++; + } + } + *charsAdded = outPtr - string; +} + +/* +** Call the stored modify callback procedure(s) for this buffer to update the +** changed area(s) on the screen and any other listeners. +*/ +void Fl_Text_Buffer::call_modify_callbacks( int pos, int nDeleted, + int nInserted, int nRestyled, const char *deletedText ) { + int i; + + for ( i = 0; i < mNModifyProcs; i++ ) + ( *mNodifyProcs[ i ] ) ( pos, nInserted, nDeleted, nRestyled, + deletedText, mCbArgs[ i ] ); +} + +/* +** Call the stored pre-delete callback procedure(s) for this buffer to update +** the changed area(s) on the screen and any other listeners. +*/ +void Fl_Text_Buffer::call_predelete_callbacks(int pos, int nDeleted) { + int i; + + for (i=0; imStart; + newStart = newSelection->mStart; + oldEnd = oldSelection->mEnd; + newEnd = newSelection->mEnd; + if ( oldSelection->mRectangular ) + oldEnd++; + if ( newSelection->mRectangular ) + newEnd++; + + /* If the old or new selection is unselected, just redisplay the + single area that is (was) selected and return */ + if ( !oldSelection->mSelected && !newSelection->mSelected ) + return; + if ( !oldSelection->mSelected ) { + call_modify_callbacks( newStart, 0, 0, newEnd - newStart, NULL ); + return; + } + if ( !newSelection->mSelected ) { + call_modify_callbacks( oldStart, 0, 0, oldEnd - oldStart, NULL ); + return; + } + + /* If the selection changed from normal to rectangular or visa versa, or + if a rectangular selection changed boundaries, redisplay everything */ + if ( ( oldSelection->mRectangular && !newSelection->mRectangular ) || + ( !oldSelection->mRectangular && newSelection->mRectangular ) || + ( oldSelection->mRectangular && ( + ( oldSelection->mRectStart != newSelection->mRectStart ) || + ( oldSelection->mRectEnd != newSelection->mRectEnd ) ) ) ) { + call_modify_callbacks( min( oldStart, newStart ), 0, 0, + max( oldEnd, newEnd ) - min( oldStart, newStart ), NULL ); + return; + } + + /* If the selections are non-contiguous, do two separate updates + and return */ + if ( oldEnd < newStart || newEnd < oldStart ) { + call_modify_callbacks( oldStart, 0, 0, oldEnd - oldStart, NULL ); + call_modify_callbacks( newStart, 0, 0, newEnd - newStart, NULL ); + return; + } + + /* Otherwise, separate into 3 separate regions: ch1, and ch2 (the two + changed areas), and the unchanged area of their intersection, + and update only the changed area(s) */ + ch1Start = min( oldStart, newStart ); + ch2End = max( oldEnd, newEnd ); + ch1End = max( oldStart, newStart ); + ch2Start = min( oldEnd, newEnd ); + if ( ch1Start != ch1End ) + call_modify_callbacks( ch1Start, 0, 0, ch1End - ch1Start, NULL ); + if ( ch2Start != ch2End ) + call_modify_callbacks( ch2Start, 0, 0, ch2End - ch2Start, NULL ); +} + +void Fl_Text_Buffer::move_gap( int pos ) { + int gapLen = mGapEnd - mGapStart; + + if ( pos > mGapStart ) + memmove( &mBuf[ mGapStart ], &mBuf[ mGapEnd ], + pos - mGapStart ); + else + memmove( &mBuf[ pos + gapLen ], &mBuf[ pos ], mGapStart - pos ); + mGapEnd += pos - mGapStart; + mGapStart += pos - mGapStart; +} + +/* +** reallocate the text storage in "buf" to have a gap starting at "newGapStart" +** and a gap size of "newGapLen", preserving the buffer's current contents. +*/ +void Fl_Text_Buffer::reallocate_with_gap( int newGapStart, int newGapLen ) { + char * newBuf; + int newGapEnd; + + newBuf = (char *)malloc( mLength + newGapLen ); + newGapEnd = newGapStart + newGapLen; + if ( newGapStart <= mGapStart ) { + memcpy( newBuf, mBuf, newGapStart ); + memcpy( &newBuf[ newGapEnd ], &mBuf[ newGapStart ], + mGapStart - newGapStart ); + memcpy( &newBuf[ newGapEnd + mGapStart - newGapStart ], + &mBuf[ mGapEnd ], mLength - mGapStart ); + } else { /* newGapStart > mGapStart */ + memcpy( newBuf, mBuf, mGapStart ); + memcpy( &newBuf[ mGapStart ], &mBuf[ mGapEnd ], + newGapStart - mGapStart ); + memcpy( &newBuf[ newGapEnd ], + &mBuf[ mGapEnd + newGapStart - mGapStart ], + mLength - newGapStart ); + } + free( (void *) mBuf ); + mBuf = newBuf; + mGapStart = newGapStart; + mGapEnd = newGapEnd; +#ifdef PURIFY +{int i; for ( i = mGapStart; i < mGapEnd; i++ ) mBuf[ i ] = '.'; } +#endif +} + +/* +** Update all of the selections in "buf" for changes in the buffer's text +*/ +void Fl_Text_Buffer::update_selections( int pos, int nDeleted, + int nInserted ) { + mPrimary.update( pos, nDeleted, nInserted ); + mSecondary.update( pos, nDeleted, nInserted ); + mHighlight.update( pos, nDeleted, nInserted ); +} + +/* +** Update an individual selection for changes in the corresponding text +*/ +void Fl_Text_Selection::update( int pos, int nDeleted, + int nInserted ) { + if ( !mSelected || pos > mEnd ) + return; + if ( pos + nDeleted <= mStart ) { + mStart += nInserted - nDeleted; + mEnd += nInserted - nDeleted; + } else if ( pos <= mStart && pos + nDeleted >= mEnd ) { + mStart = pos; + mEnd = pos; + mSelected = 0; + } else if ( pos <= mStart && pos + nDeleted < mEnd ) { + mStart = pos; + mEnd = nInserted + mEnd - nDeleted; + } else if ( pos < mEnd ) { + mEnd += nInserted - nDeleted; + if ( mEnd <= mStart ) + mSelected = 0; + } +} + +/* +** Search forwards in buffer "buf" for character "searchChar", starting +** with the character "startPos", and returning the result in "foundPos" +** returns 1 if found, 0 if not. (The difference between this and +** BufSearchForward is that it's optimized for single characters. The +** overall performance of the text widget is dependent on its ability to +** count lines quickly, hence searching for a single character: newline) +*/ +int Fl_Text_Buffer::findchar_forward( int startPos, char searchChar, + int *foundPos ) { + int pos, gapLen = mGapEnd - mGapStart; + + if (startPos < 0 || startPos >= mLength) { + *foundPos = mLength; + return 0; + } + + pos = startPos; + while ( pos < mGapStart ) { + if ( mBuf[ pos ] == searchChar ) { + *foundPos = pos; + return 1; + } + pos++; + } + while ( pos < mLength ) { + if ( mBuf[ pos + gapLen ] == searchChar ) { + *foundPos = pos; + return 1; + } + pos++; + } + *foundPos = mLength; + return 0; +} + +/* +** Search backwards in buffer "buf" for character "searchChar", starting +** with the character BEFORE "startPos", returning the result in "foundPos" +** returns 1 if found, 0 if not. (The difference between this and +** BufSearchBackward is that it's optimized for single characters. The +** overall performance of the text widget is dependent on its ability to +** count lines quickly, hence searching for a single character: newline) +*/ +int Fl_Text_Buffer::findchar_backward( int startPos, char searchChar, + int *foundPos ) { + int pos, gapLen = mGapEnd - mGapStart; + + if ( startPos <= 0 || startPos > mLength ) { + *foundPos = 0; + return 0; + } + pos = startPos - 1; + while ( pos >= mGapStart ) { + if ( mBuf[ pos + gapLen ] == searchChar ) { + *foundPos = pos; + return 1; + } + pos--; + } + while ( pos >= 0 ) { + if ( mBuf[ pos ] == searchChar ) { + *foundPos = pos; + return 1; + } + pos--; + } + *foundPos = 0; + return 0; +} + +/* +** Copy from "text" to end up to but not including newline (or end of "text") +** and return the copy as the function value, and the length of the line in +** "lineLen" +*/ +static char *copyLine( const char *text, int *lineLen ) { + int len = 0; + const char *c; + char *outStr; + + for ( c = text; *c != '\0' && *c != '\n'; c++ ) + len++; + outStr = (char *)malloc( len + 1 ); + strlcpy( outStr, text, len + 1); + *lineLen = len; + return outStr; +} + +/* +** Count the number of newlines in a null-terminated text string; +*/ +static int countLines( const char *string ) { + const char * c; + int lineCount = 0; + + for ( c = string; *c != '\0'; c++ ) + if ( *c == '\n' ) lineCount++; + return lineCount; +} + +/* +** Measure the width in displayed characters of string "text" +*/ +static int textWidth( const char *text, int tabDist, char nullSubsChar ) { + int width = 0, maxWidth = 0; + const char *c; + + for ( c = text; *c != '\0'; c++ ) { + if ( *c == '\n' ) { + if ( width > maxWidth ) + maxWidth = width; + width = 0; + } else + width += Fl_Text_Buffer::character_width( *c, width, tabDist, nullSubsChar ); + } + if ( width > maxWidth ) + return width; + return maxWidth; +} + +/* +** Find the first and last character position in a line within a rectangular +** selection (for copying). Includes tabs which cross rectStart, but not +** control characters which do so. Leaves off tabs which cross rectEnd. +** +** Technically, the calling routine should convert tab characters which +** cross the right boundary of the selection to spaces which line up with +** the edge of the selection. Unfortunately, the additional memory +** management required in the parent routine to allow for the changes +** in string size is not worth all the extra work just for a couple of +** shifted characters, so if a tab protrudes, just lop it off and hope +** that there are other characters in the selection to establish the right +** margin for subsequent columnar pastes of this data. +*/ +void Fl_Text_Buffer::rectangular_selection_boundaries( int lineStartPos, + int rectStart, int rectEnd, int *selStart, int *selEnd ) { + int pos, width, indent = 0; + char c; + + /* find the start of the selection */ + for ( pos = lineStartPos; pos < mLength; pos++ ) { + c = character( pos ); + if ( c == '\n' ) + break; + width = Fl_Text_Buffer::character_width( c, indent, mTabDist, mNullSubsChar ); + if ( indent + width > rectStart ) { + if ( indent != rectStart && c != '\t' ) { + pos++; + indent += width; + } + break; + } + indent += width; + } + *selStart = pos; + + /* find the end */ + for ( ; pos < mLength; pos++ ) { + c = character( pos ); + if ( c == '\n' ) + break; + width = Fl_Text_Buffer::character_width( c, indent, mTabDist, mNullSubsChar ); + indent += width; + if ( indent > rectEnd ) { + if ( indent - width != rectEnd && c != '\t' ) + pos++; + break; + } + } + *selEnd = pos; +} + +/* +** Adjust the space and tab characters from string "text" so that non-white +** characters remain stationary when the text is shifted from starting at +** "origIndent" to starting at "newIndent". Returns an allocated string +** which must be freed by the caller with XtFree. +*/ +static char *realignTabs( const char *text, int origIndent, int newIndent, + int tabDist, int useTabs, char nullSubsChar, int *newLength ) { + char * expStr, *outStr; + int len; + + /* If the tabs settings are the same, retain original tabs */ + if ( origIndent % tabDist == newIndent % tabDist ) { + len = strlen( text ); + outStr = (char *)malloc( len + 1 ); + strcpy( outStr, text ); + *newLength = len; + return outStr; + } + + /* If the tab settings are not the same, brutally convert tabs to + spaces, then back to tabs in the new position */ + expStr = expandTabs( text, origIndent, tabDist, nullSubsChar, &len ); + if ( !useTabs ) { + *newLength = len; + return expStr; + } + outStr = unexpandTabs( expStr, newIndent, tabDist, nullSubsChar, newLength ); + free( (void *) expStr ); + return outStr; +} + +/* +** Expand tabs to spaces for a block of text. The additional parameter +** "startIndent" if nonzero, indicates that the text is a rectangular selection +** beginning at column "startIndent" +*/ +static char *expandTabs( const char *text, int startIndent, int tabDist, + char nullSubsChar, int *newLen ) { + char * outStr, *outPtr; + const char *c; + int indent, len, outLen = 0; + + /* rehearse the expansion to figure out length for output string */ + indent = startIndent; + for ( c = text; *c != '\0'; c++ ) { + if ( *c == '\t' ) { + len = Fl_Text_Buffer::character_width( *c, indent, tabDist, nullSubsChar ); + outLen += len; + indent += len; + } else if ( *c == '\n' ) { + indent = startIndent; + outLen++; + } else { + indent += Fl_Text_Buffer::character_width( *c, indent, tabDist, nullSubsChar ); + outLen++; + } + } + + /* do the expansion */ + outStr = (char *)malloc( outLen + 1 ); + outPtr = outStr; + indent = startIndent; + for ( c = text; *c != '\0'; c++ ) { + if ( *c == '\t' ) { + len = Fl_Text_Buffer::expand_character( *c, indent, outPtr, tabDist, nullSubsChar ); + outPtr += len; + indent += len; + } else if ( *c == '\n' ) { + indent = startIndent; + *outPtr++ = *c; + } else { + indent += Fl_Text_Buffer::character_width( *c, indent, tabDist, nullSubsChar ); + *outPtr++ = *c; + } + } + outStr[ outLen ] = '\0'; + *newLen = outLen; + return outStr; +} + +/* +** Convert sequences of spaces into tabs. The threshold for conversion is +** when 3 or more spaces can be converted into a single tab, this avoids +** converting double spaces after a period withing a block of text. +*/ +static char *unexpandTabs( char *text, int startIndent, int tabDist, + char nullSubsChar, int *newLen ) { + char * outStr, *outPtr, *c, expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ]; + int indent, len; + + outStr = (char *)malloc( strlen( text ) + 1 ); + outPtr = outStr; + indent = startIndent; + for ( c = text; *c != '\0'; ) { + if ( *c == ' ' ) { + len = Fl_Text_Buffer::expand_character( '\t', indent, expandedChar, tabDist, + nullSubsChar ); + if ( len >= 3 && !strncmp( c, expandedChar, len ) ) { + c += len; + *outPtr++ = '\t'; + indent += len; + } else { + *outPtr++ = *c++; + indent++; + } + } else if ( *c == '\n' ) { + indent = startIndent; + *outPtr++ = *c++; + } else { + *outPtr++ = *c++; + indent++; + } + } + *outPtr = '\0'; + *newLen = outPtr - outStr; + return outStr; +} + +static int max( int i1, int i2 ) { + return i1 >= i2 ? i1 : i2; +} + +static int min( int i1, int i2 ) { + return i1 <= i2 ? i1 : i2; +} + +int +Fl_Text_Buffer::insertfile(const char *file, int pos, int buflen) { + FILE *fp; int r; + if (!(fp = fopen(file, "r"))) return 1; + char *buffer = new char[buflen]; + for (; (r = fread(buffer, 1, buflen - 1, fp)) > 0; pos += r) { + buffer[r] = (char)0; + insert(pos, buffer); + } + + int e = ferror(fp) ? 2 : 0; + fclose(fp); + delete[] buffer; + return e; +} + +int +Fl_Text_Buffer::outputfile(const char *file, int start, int end, int buflen) { + FILE *fp; + if (!(fp = fopen(file, "w"))) return 1; + for (int n; (n = min(end - start, buflen)); start += n) { + const char *p = text_range(start, start + n); + int r = fwrite(p, 1, n, fp); + free((void *)p); + if (r != n) break; + } + + int e = ferror(fp) ? 2 : 0; + fclose(fp); + return e; +} + + +// +// End of "$Id: Fl_Text_Buffer.cxx 6011 2008-01-04 20:32:37Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Text_Display.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Text_Display.cxx new file mode 100644 index 0000000..4f0f1c1 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Text_Display.cxx @@ -0,0 +1,3272 @@ +// +// "$Id: Fl_Text_Display.cxx 6105 2008-04-21 21:03:22Z matt $" +// +// Copyright 2001-2006 by Bill Spitzak and others. +// Original code Copyright Mark Edel. Permission to distribute under +// the LGPL for the FLTK library granted by Mark Edel. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include "flstring.h" +#include +#include +#include +#include +#include +#include + +#undef min +#undef max + +// Text area margins. Left & right margins should be at least 3 so that +// there is some room for the overhanging parts of the cursor! +#define TOP_MARGIN 1 +#define BOTTOM_MARGIN 1 +#define LEFT_MARGIN 3 +#define RIGHT_MARGIN 3 + +#define NO_HINT -1 + +/* Masks for text drawing methods. These are or'd together to form an + integer which describes what drawing calls to use to draw a string */ +#define FILL_MASK 0x0100 +#define SECONDARY_MASK 0x0200 +#define PRIMARY_MASK 0x0400 +#define HIGHLIGHT_MASK 0x0800 +#define BG_ONLY_MASK 0x1000 +#define TEXT_ONLY_MASK 0x2000 +#define STYLE_LOOKUP_MASK 0xff + +/* Maximum displayable line length (how many characters will fit across the + widest window). This amount of memory is temporarily allocated from the + stack in the draw_vline() method for drawing strings */ +#define MAX_DISP_LINE_LEN 1000 + +static int max( int i1, int i2 ); +static int min( int i1, int i2 ); +static int countlines( const char *string ); + +/* The variables below are used in a timer event to allow smooth + scrolling of the text area when the pointer has left the area. */ +static int scroll_direction = 0; +static int scroll_amount = 0; +static int scroll_y = 0; +static int scroll_x = 0; + +// CET - FIXME +#define TMPFONTWIDTH 6 + +Fl_Text_Display::Fl_Text_Display(int X, int Y, int W, int H, const char* l) + : Fl_Group(X, Y, W, H, l) { + int i; + + mMaxsize = 0; + damage_range1_start = damage_range1_end = -1; + damage_range2_start = damage_range2_end = -1; + dragPos = dragType = dragging = 0; + display_insert_position_hint = 0; + + color(FL_BACKGROUND2_COLOR, FL_SELECTION_COLOR); + box(FL_DOWN_FRAME); + textsize((uchar)FL_NORMAL_SIZE); + textcolor(FL_FOREGROUND_COLOR); + textfont(FL_HELVETICA); + + text_area.x = 0; + text_area.y = 0; + text_area.w = 0; + text_area.h = 0; + + mVScrollBar = new Fl_Scrollbar(0,0,1,1); + mVScrollBar->callback((Fl_Callback*)v_scrollbar_cb, this); + mHScrollBar = new Fl_Scrollbar(0,0,1,1); + mHScrollBar->callback((Fl_Callback*)h_scrollbar_cb, this); + mHScrollBar->type(FL_HORIZONTAL); + + end(); + + scrollbar_width(Fl::scrollbar_size()); + scrollbar_align(FL_ALIGN_BOTTOM_RIGHT); + + mCursorOn = 0; + mCursorPos = 0; + mCursorOldY = -100; + mCursorToHint = NO_HINT; + mCursorStyle = NORMAL_CURSOR; + mCursorPreferredCol = -1; + mBuffer = 0; + mFirstChar = 0; + mLastChar = 0; + mNBufferLines = 0; + mTopLineNum = mTopLineNumHint = 1; + mAbsTopLineNum = 1; + mNeedAbsTopLineNum = 0; + mHorizOffset = mHorizOffsetHint = 0; + + mCursor_color = FL_FOREGROUND_COLOR; + + mFixedFontWidth = -1; + mStyleBuffer = 0; + mStyleTable = 0; + mNStyles = 0; + mNVisibleLines = 1; + mLineStarts = new int[mNVisibleLines]; + mLineStarts[0] = 0; + for (i=1; iremove_modify_callback(buffer_modified_cb, this); + mBuffer->remove_predelete_callback(buffer_predelete_cb, this); + } + if (mLineStarts) delete[] mLineStarts; +} + +/* +** Attach a text buffer to display, replacing the current buffer (if any) +*/ +void Fl_Text_Display::buffer( Fl_Text_Buffer *buf ) { + /* If the text display is already displaying a buffer, clear it off + of the display and remove our callback from it */ + if ( buf == mBuffer) return; + if ( mBuffer != 0 ) { + buffer_modified_cb( 0, 0, mBuffer->length(), 0, 0, this ); + mNBufferLines = 0; + mBuffer->remove_modify_callback( buffer_modified_cb, this ); + mBuffer->remove_predelete_callback( buffer_predelete_cb, this ); + } + + /* Add the buffer to the display, and attach a callback to the buffer for + receiving modification information when the buffer contents change */ + mBuffer = buf; + if (mBuffer) { + mBuffer->add_modify_callback( buffer_modified_cb, this ); + mBuffer->add_predelete_callback( buffer_predelete_cb, this ); + + /* Update the display */ + buffer_modified_cb( 0, buf->length(), 0, 0, 0, this ); + } + + /* Resize the widget to update the screen... */ + resize(x(), y(), w(), h()); +} + +/* +** Attach (or remove) highlight information in text display and redisplay. +** Highlighting information consists of a style buffer which parallels the +** normal text buffer, but codes font and color information for the display; +** a style table which translates style buffer codes (indexed by buffer +** character - 'A') into fonts and colors; and a callback mechanism for +** as-needed highlighting, triggered by a style buffer entry of +** "unfinishedStyle". Style buffer can trigger additional redisplay during +** a normal buffer modification if the buffer contains a primary Fl_Text_Selection +** (see extendRangeForStyleMods for more information on this protocol). +** +** Style buffers, tables and their associated memory are managed by the caller. +*/ +void +Fl_Text_Display::highlight_data(Fl_Text_Buffer *styleBuffer, + const Style_Table_Entry *styleTable, + int nStyles, char unfinishedStyle, + Unfinished_Style_Cb unfinishedHighlightCB, + void *cbArg ) { + mStyleBuffer = styleBuffer; + mStyleTable = styleTable; + mNStyles = nStyles; + mUnfinishedStyle = unfinishedStyle; + mUnfinishedHighlightCB = unfinishedHighlightCB; + mHighlightCBArg = cbArg; + + mStyleBuffer->canUndo(0); +#if 0 + // FIXME: this is in nedit code -- is it needed? + /* Call TextDSetFont to combine font information from style table and + primary font, adjust font-related parameters, and then redisplay */ + TextDSetFont(textD, textD->fontStruct); +#endif + damage(FL_DAMAGE_EXPOSE); +} + +#if 0 + // FIXME: this is in nedit code -- is it needed? +/* +** Change the (non highlight) font +*/ +void TextDSetFont(textDisp *textD, XFontStruct *fontStruct) { + Display *display = XtDisplay(textD->w); + int i, maxAscent = fontStruct->ascent, maxDescent = fontStruct->descent; + int width, height, fontWidth; + Pixel bgPixel, fgPixel, selectFGPixel, selectBGPixel; + Pixel highlightFGPixel, highlightBGPixel; + XGCValues values; + XFontStruct *styleFont; + + /* If font size changes, cursor will be redrawn in a new position */ + blankCursorProtrusions(textD); + + /* If there is a (syntax highlighting) style table in use, find the new + maximum font height for this text display */ + for (i=0; inStyles; i++) { + styleFont = textD->styleTable[i].font; + if (styleFont != NULL && styleFont->ascent > maxAscent) + maxAscent = styleFont->ascent; + if (styleFont != NULL && styleFont->descent > maxDescent) + maxDescent = styleFont->descent; + } + textD->ascent = maxAscent; + textD->descent = maxDescent; + + /* If all of the current fonts are fixed and match in width, compute */ + fontWidth = fontStruct->max_bounds.width; + if (fontWidth != fontStruct->min_bounds.width) + fontWidth = -1; + else { + for (i=0; inStyles; i++) { + styleFont = textD->styleTable[i].font; + if (styleFont != NULL && (styleFont->max_bounds.width != fontWidth || + styleFont->max_bounds.width != styleFont->min_bounds.width)) + fontWidth = -1; + } + } + textD->fixedFontWidth = fontWidth; + + /* Don't let the height dip below one line, or bad things can happen */ + if (textD->height < maxAscent + maxDescent) + textD->height = maxAscent + maxDescent; + + /* Change the font. In most cases, this means re-allocating the + affected GCs (they are shared with other widgets, and if the primary + font changes, must be re-allocated to change it). Unfortunately, + this requres recovering all of the colors from the existing GCs */ + textD->fontStruct = fontStruct; + XGetGCValues(display, textD->gc, GCForeground|GCBackground, &values); + fgPixel = values.foreground; + bgPixel = values.background; + XGetGCValues(display, textD->selectGC, GCForeground|GCBackground, &values); + selectFGPixel = values.foreground; + selectBGPixel = values.background; + XGetGCValues(display, textD->highlightGC,GCForeground|GCBackground,&values); + highlightFGPixel = values.foreground; + highlightBGPixel = values.background; + releaseGC(textD->w, textD->gc); + releaseGC(textD->w, textD->selectGC); + releaseGC(textD->w, textD->highlightGC); + releaseGC(textD->w, textD->selectBGGC); + releaseGC(textD->w, textD->highlightBGGC); + if (textD->lineNumGC != NULL) + releaseGC(textD->w, textD->lineNumGC); + textD->lineNumGC = NULL; + allocateFixedFontGCs(textD, fontStruct, bgPixel, fgPixel, selectFGPixel, + selectBGPixel, highlightFGPixel, highlightBGPixel); + XSetFont(display, textD->styleGC, fontStruct->fid); + + /* Do a full resize to force recalculation of font related parameters */ + width = textD->width; + height = textD->height; + textD->width = textD->height = 0; + TextDResize(textD, width, height); + + /* Redisplay */ + TextDRedisplayRect(textD, textD->left, textD->top, textD->width, + textD->height); + + /* Clean up line number area in case spacing has changed */ + draw_line_numbers(textD, True); +} + +int TextDMinFontWidth(textDisp *textD, Boolean considerStyles) { + int fontWidth = textD->fontStruct->max_bounds.width; + int i; + + if (considerStyles) { + for (i = 0; i < textD->nStyles; ++i) { + int thisWidth = (textD->styleTable[i].font)->min_bounds.width; + if (thisWidth < fontWidth) { + fontWidth = thisWidth; + } + } + } + return(fontWidth); +} + +int TextDMaxFontWidth(textDisp *textD, Boolean considerStyles) { + int fontWidth = textD->fontStruct->max_bounds.width; + int i; + + if (considerStyles) { + for (i = 0; i < textD->nStyles; ++i) { + int thisWidth = (textD->styleTable[i].font)->max_bounds.width; + if (thisWidth > fontWidth) { + fontWidth = thisWidth; + } + } + } + return(fontWidth); +} +#endif + +int Fl_Text_Display::longest_vline() { + int longest = 0; + for (int i = 0; i < mNVisibleLines; i++) + longest = max(longest, measure_vline(i)); + return longest; +} + +/* +** Change the size of the displayed text area +*/ +void Fl_Text_Display::resize(int X, int Y, int W, int H) { +#ifdef DEBUG + printf("Fl_Text_Display::resize(X=%d, Y=%d, W=%d, H=%d)\n", X, Y, W, H); +#endif // DEBUG + const int oldWidth = w(); +#ifdef DEBUG + printf(" oldWidth=%d, mContinuousWrap=%d, mWrapMargin=%d\n", oldWidth, + mContinuousWrap, mWrapMargin); +#endif // DEBUG + Fl_Widget::resize(X,Y,W,H); + if (!buffer()) return; + X += Fl::box_dx(box()); + Y += Fl::box_dy(box()); + W -= Fl::box_dw(box()); + H -= Fl::box_dh(box()); + + text_area.x = X+LEFT_MARGIN; + text_area.y = Y+BOTTOM_MARGIN; + text_area.w = W-LEFT_MARGIN-RIGHT_MARGIN; + text_area.h = H-TOP_MARGIN-BOTTOM_MARGIN; + int i; + + /* Find the new maximum font height for this text display */ + for (i = 0, mMaxsize = fl_height(textfont(), textsize()); i < mNStyles; i++) + mMaxsize = max(mMaxsize, fl_height(mStyleTable[i].font, mStyleTable[i].size)); + + // did we have scrollbars initially? + int hscrollbarvisible = mHScrollBar->visible(); + int vscrollbarvisible = mVScrollBar->visible(); + + // try without scrollbars first + mVScrollBar->clear_visible(); + mHScrollBar->clear_visible(); + + for (int again = 1; again;) { + again = 0; + /* In continuous wrap mode, a change in width affects the total number of + lines in the buffer, and can leave the top line number incorrect, and + the top character no longer pointing at a valid line start */ + if (mContinuousWrap && !mWrapMargin && W!=oldWidth) { + int oldFirstChar = mFirstChar; + mNBufferLines = count_lines(0, buffer()->length(), true); + mFirstChar = line_start(mFirstChar); + mTopLineNum = count_lines(0, mFirstChar, true)+1; + absolute_top_line_number(oldFirstChar); + +#ifdef DEBUG + printf(" mNBufferLines=%d\n", mNBufferLines); +#endif // DEBUG + } + + /* reallocate and update the line starts array, which may have changed + size and / or contents. */ + int nvlines = (text_area.h + mMaxsize - 1) / mMaxsize; + if (nvlines < 1) nvlines = 1; + if (mNVisibleLines != nvlines) { + mNVisibleLines = nvlines; + if (mLineStarts) delete[] mLineStarts; + mLineStarts = new int [mNVisibleLines]; + } + + calc_line_starts(0, mNVisibleLines); + calc_last_char(); + + // figure the scrollbars + if (scrollbar_width()) { + /* Decide if the vertical scroll bar needs to be visible */ + if (scrollbar_align() & (FL_ALIGN_LEFT|FL_ALIGN_RIGHT) && + mNBufferLines >= mNVisibleLines - 1) + { + mVScrollBar->set_visible(); + if (scrollbar_align() & FL_ALIGN_LEFT) { + text_area.x = X+scrollbar_width()+LEFT_MARGIN; + text_area.w = W-scrollbar_width()-LEFT_MARGIN-RIGHT_MARGIN; + mVScrollBar->resize(X, text_area.y-TOP_MARGIN, scrollbar_width(), + text_area.h+TOP_MARGIN+BOTTOM_MARGIN); + } else { + text_area.x = X+LEFT_MARGIN; + text_area.w = W-scrollbar_width()-LEFT_MARGIN-RIGHT_MARGIN; + mVScrollBar->resize(X+W-scrollbar_width(), text_area.y-TOP_MARGIN, + scrollbar_width(), text_area.h+TOP_MARGIN+BOTTOM_MARGIN); + } + } + + /* + Decide if the horizontal scroll bar needs to be visible. If there + is a vertical scrollbar, a horizontal is always created too. This + is because the alternatives are unatractive: + * Dynamically creating a horizontal scrollbar based on the currently + visible lines is what the original nedit does, but it always wastes + space for the scrollbar even when it's not used. Since the FLTK + widget dynamically allocates the space for the scrollbar and + rearranges the widget to make room for it, this would create a very + visually displeasing "bounce" effect when the vertical scrollbar is + dragged. Trust me, I tried it and it looks really bad. + * The other alternative would be to keep track of what the longest + line in the entire buffer is and base the scrollbar on that. I + didn't do this because I didn't see any easy way to do that using + the nedit code and this could involve a lengthy calculation for + large buffers. If an efficient and non-costly way of doing this + can be found, this might be a way to go. + */ + /* WAS: Suggestion: Try turning the horizontal scrollbar on when + you first see a line that is too wide in the window, but then + don't turn it off (ie mix both of your solutions). */ + if (scrollbar_align() & (FL_ALIGN_TOP|FL_ALIGN_BOTTOM) && + (mVScrollBar->visible() || longest_vline() > text_area.w)) + { + if (!mHScrollBar->visible()) { + mHScrollBar->set_visible(); + again = 1; // loop again to see if we now need vert. & recalc sizes + } + if (scrollbar_align() & FL_ALIGN_TOP) { + text_area.y = Y + scrollbar_width()+TOP_MARGIN; + text_area.h = H - scrollbar_width()-TOP_MARGIN-BOTTOM_MARGIN; + mHScrollBar->resize(text_area.x-LEFT_MARGIN, Y, + text_area.w+LEFT_MARGIN+RIGHT_MARGIN, scrollbar_width()); + } else { + text_area.y = Y+TOP_MARGIN; + text_area.h = H - scrollbar_width()-TOP_MARGIN-BOTTOM_MARGIN; + mHScrollBar->resize(text_area.x-LEFT_MARGIN, Y+H-scrollbar_width(), + text_area.w+LEFT_MARGIN+RIGHT_MARGIN, scrollbar_width()); + } + } + } + } + + // user request to change viewport + if (mTopLineNumHint != mTopLineNum || mHorizOffsetHint != mHorizOffset) + scroll_(mTopLineNumHint, mHorizOffsetHint); + + // everything will fit in the viewport + if (mNBufferLines < mNVisibleLines || mBuffer == NULL || mBuffer->length() == 0) + scroll_(1, mHorizOffset); + /* if empty lines become visible, there may be an opportunity to + display more text by scrolling down */ + else while (mLineStarts[mNVisibleLines-2] == -1) + scroll_(mTopLineNum-1, mHorizOffset); + + // user request to display insert position + if (display_insert_position_hint) + display_insert(); + + // in case horizontal offset is now greater than longest line + int maxhoffset = max(0, longest_vline()-text_area.w); + if (mHorizOffset > maxhoffset) + scroll_(mTopLineNumHint, maxhoffset); + + mTopLineNumHint = mTopLineNum; + mHorizOffsetHint = mHorizOffset; + display_insert_position_hint = 0; + + if (mContinuousWrap || + hscrollbarvisible != mHScrollBar->visible() || + vscrollbarvisible != mVScrollBar->visible()) + redraw(); + + update_v_scrollbar(); + update_h_scrollbar(); +} + +/* +** Refresh a rectangle of the text display. left and top are in coordinates of +** the text drawing window +*/ +void Fl_Text_Display::draw_text( int left, int top, int width, int height ) { + int fontHeight, firstLine, lastLine, line; + + /* find the line number range of the display */ + fontHeight = mMaxsize ? mMaxsize : textsize_; + firstLine = ( top - text_area.y - fontHeight + 1 ) / fontHeight; + lastLine = ( top + height - text_area.y ) / fontHeight + 1; + + fl_push_clip( left, top, width, height ); + + /* draw the lines */ + for ( line = firstLine; line <= lastLine; line++ ) + draw_vline( line, left, left + width, 0, INT_MAX ); + + /* draw the line numbers if exposed area includes them */ + if (mLineNumWidth != 0 && left <= mLineNumLeft + mLineNumWidth) + draw_line_numbers(false); + + fl_pop_clip(); +} + +void Fl_Text_Display::redisplay_range(int startpos, int endpos) { + if (damage_range1_start == -1 && damage_range1_end == -1) { + damage_range1_start = startpos; + damage_range1_end = endpos; + } else if ((startpos >= damage_range1_start && startpos <= damage_range1_end) || + (endpos >= damage_range1_start && endpos <= damage_range1_end)) { + damage_range1_start = min(damage_range1_start, startpos); + damage_range1_end = max(damage_range1_end, endpos); + } else if (damage_range2_start == -1 && damage_range2_end == -1) { + damage_range2_start = startpos; + damage_range2_end = endpos; + } else { + damage_range2_start = min(damage_range2_start, startpos); + damage_range2_end = max(damage_range2_end, endpos); + } + damage(FL_DAMAGE_SCROLL); +} +/* +** Refresh all of the text between buffer positions "start" and "end" +** not including the character at the position "end". +** If end points beyond the end of the buffer, refresh the whole display +** after pos, including blank lines which are not technically part of +** any range of characters. +*/ +void Fl_Text_Display::draw_range(int startpos, int endpos) { + int i, startLine, lastLine, startIndex, endIndex; + + /* If the range is outside of the displayed text, just return */ + if ( endpos < mFirstChar || ( startpos > mLastChar && + !empty_vlines() ) ) return; + + /* Clean up the starting and ending values */ + if ( startpos < 0 ) startpos = 0; + if ( startpos > mBuffer->length() ) startpos = mBuffer->length(); + if ( endpos < 0 ) endpos = 0; + if ( endpos > mBuffer->length() ) endpos = mBuffer->length(); + + /* Get the starting and ending lines */ + if ( startpos < mFirstChar ) + startpos = mFirstChar; + if ( !position_to_line( startpos, &startLine ) ) + startLine = mNVisibleLines - 1; + if ( endpos >= mLastChar ) { + lastLine = mNVisibleLines - 1; + } else { + if ( !position_to_line( endpos, &lastLine ) ) { + /* shouldn't happen */ + lastLine = mNVisibleLines - 1; + } + } + + /* Get the starting and ending positions within the lines */ + startIndex = mLineStarts[ startLine ] == -1 ? 0 : + startpos - mLineStarts[ startLine ]; + if ( endpos >= mLastChar ) + endIndex = INT_MAX; + else if ( mLineStarts[ lastLine ] == -1 ) + endIndex = 0; + else + endIndex = endpos - mLineStarts[ lastLine ]; + + /* If the starting and ending lines are the same, redisplay the single + line between "start" and "end" */ + if ( startLine == lastLine ) { + draw_vline( startLine, 0, INT_MAX, startIndex, endIndex ); + return; + } + + /* Redisplay the first line from "start" */ + draw_vline( startLine, 0, INT_MAX, startIndex, INT_MAX ); + + /* Redisplay the lines in between at their full width */ + for ( i = startLine + 1; i < lastLine; i++ ) + draw_vline( i, 0, INT_MAX, 0, INT_MAX ); + + /* Redisplay the last line to "end" */ + draw_vline( lastLine, 0, INT_MAX, 0, endIndex ); +} + +/* +** Set the position of the text insertion cursor for text display +*/ +void Fl_Text_Display::insert_position( int newPos ) { + /* make sure new position is ok, do nothing if it hasn't changed */ + if ( newPos == mCursorPos ) + return; + if ( newPos < 0 ) newPos = 0; + if ( newPos > mBuffer->length() ) newPos = mBuffer->length(); + + /* cursor movement cancels vertical cursor motion column */ + mCursorPreferredCol = -1; + + /* erase the cursor at it's previous position */ + redisplay_range(mCursorPos - 1, mCursorPos + 1); + + mCursorPos = newPos; + + /* draw cursor at its new position */ + redisplay_range(mCursorPos - 1, mCursorPos + 1); +} + +void Fl_Text_Display::show_cursor(int b) { + mCursorOn = b; + redisplay_range(mCursorPos - 1, mCursorPos + 1); +} + +void Fl_Text_Display::cursor_style(int style) { + mCursorStyle = style; + if (mCursorOn) show_cursor(); +} + +void Fl_Text_Display::wrap_mode(int wrap, int wrapMargin) { + mWrapMargin = wrapMargin; + mContinuousWrap = wrap; + + if (buffer()) { + /* wrapping can change the total number of lines, re-count */ + mNBufferLines = count_lines(0, buffer()->length(), true); + + /* changing wrap margins or changing from wrapped mode to non-wrapped + can leave the character at the top no longer at a line start, and/or + change the line number */ + mFirstChar = line_start(mFirstChar); + mTopLineNum = count_lines(0, mFirstChar, true) + 1; + + reset_absolute_top_line_number(); + + /* update the line starts array */ + calc_line_starts(0, mNVisibleLines); + calc_last_char(); + } else { + // No buffer, so just clear the state info for later... + mNBufferLines = 0; + mFirstChar = 0; + mTopLineNum = 1; + mAbsTopLineNum = 0; + } + + resize(x(), y(), w(), h()); +} + +/* +** Insert "text" at the current cursor location. This has the same +** effect as inserting the text into the buffer using BufInsert and +** then moving the insert position after the newly inserted text, except +** that it's optimized to do less redrawing. +*/ +void Fl_Text_Display::insert(const char* text) { + int pos = mCursorPos; + + mCursorToHint = pos + strlen( text ); + mBuffer->insert( pos, text ); + mCursorToHint = NO_HINT; +} + +/* +** Insert "text" (which must not contain newlines), overstriking the current +** cursor location. +*/ +void Fl_Text_Display::overstrike(const char* text) { + int startPos = mCursorPos; + Fl_Text_Buffer *buf = mBuffer; + int lineStart = buf->line_start( startPos ); + int textLen = strlen( text ); + int i, p, endPos, indent, startIndent, endIndent; + const char *c; + char ch, *paddedText = NULL; + + /* determine how many displayed character positions are covered */ + startIndent = mBuffer->count_displayed_characters( lineStart, startPos ); + indent = startIndent; + for ( c = text; *c != '\0'; c++ ) + indent += Fl_Text_Buffer::character_width( *c, indent, buf->tab_distance(), buf->null_substitution_character() ); + endIndent = indent; + + /* find which characters to remove, and if necessary generate additional + padding to make up for removed control characters at the end */ + indent = startIndent; + for ( p = startPos; ; p++ ) { + if ( p == buf->length() ) + break; + ch = buf->character( p ); + if ( ch == '\n' ) + break; + indent += Fl_Text_Buffer::character_width( ch, indent, buf->tab_distance(), buf->null_substitution_character() ); + if ( indent == endIndent ) { + p++; + break; + } else if ( indent > endIndent ) { + if ( ch != '\t' ) { + p++; + paddedText = new char [ textLen + FL_TEXT_MAX_EXP_CHAR_LEN + 1 ]; + strcpy( paddedText, text ); + for ( i = 0; i < indent - endIndent; i++ ) + paddedText[ textLen + i ] = ' '; + paddedText[ textLen + i ] = '\0'; + } + break; + } + } + endPos = p; + + mCursorToHint = startPos + textLen; + buf->replace( startPos, endPos, paddedText == NULL ? text : paddedText ); + mCursorToHint = NO_HINT; + if ( paddedText != NULL ) + delete [] paddedText; +} + +/* +** Translate a buffer text position to the XY location where the top left +** of the cursor would be positioned to point to that character. Returns +** 0 if the position is not displayed because it is VERTICALLY out +** of view. If the position is horizontally out of view, returns the +** X coordinate where the position would be if it were visible. +*/ + +int Fl_Text_Display::position_to_xy( int pos, int* X, int* Y ) { + int charIndex, lineStartPos, fontHeight, lineLen; + int visLineNum, charLen, outIndex, xStep, charStyle; + char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ]; + const char *lineStr; + +// printf("position_to_xy(pos=%d, X=%p, Y=%p)\n", pos, X, Y); + + /* If position is not displayed, return false */ + if (pos < mFirstChar || (pos > mLastChar && !empty_vlines())) { +// printf(" returning 0\n" +// " mFirstChar=%d, mLastChar=%d, empty_vlines()=0\n", +// mFirstChar, mLastChar); + return 0; + } + + /* Calculate Y coordinate */ + if (!position_to_line(pos, &visLineNum)) { +// puts(" returning 0\n" +// " position_to_line()=0"); + return 0; + } + + if (visLineNum < 0 || visLineNum > mNBufferLines) { +// printf(" returning 0\n" +// " visLineNum=%d, mNBufferLines=%d\n", +// visLineNum, mNBufferLines); + return 0; + } + + fontHeight = mMaxsize; + *Y = text_area.y + visLineNum * fontHeight; + + /* Get the text, length, and buffer position of the line. If the position + is beyond the end of the buffer and should be at the first position on + the first empty line, don't try to get or scan the text */ + lineStartPos = mLineStarts[visLineNum]; + if ( lineStartPos == -1 ) { + *X = text_area.x - mHorizOffset; + return 1; + } + lineLen = vline_length( visLineNum ); + lineStr = mBuffer->text_range( lineStartPos, lineStartPos + lineLen ); + + /* Step through character positions from the beginning of the line + to "pos" to calculate the X coordinate */ + xStep = text_area.x - mHorizOffset; + outIndex = 0; + for ( charIndex = 0; charIndex < lineLen && charIndex < pos - lineStartPos; charIndex++ ) { + charLen = Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, expandedChar, + mBuffer->tab_distance(), mBuffer->null_substitution_character() ); + charStyle = position_style( lineStartPos, lineLen, charIndex, + outIndex ); + xStep += string_width( expandedChar, charLen, charStyle ); + outIndex += charLen; + } + *X = xStep; + free((char *)lineStr); + return 1; +} + +/* +** Find the line number of position "pos". Note: this only works for +** displayed lines. If the line is not displayed, the function returns +** 0 (without the mLineStarts array it could turn in to very long +** calculation involving scanning large amounts of text in the buffer). +** If continuous wrap mode is on, returns the absolute line number (as opposed +** to the wrapped line number which is used for scrolling). +*/ +int Fl_Text_Display::position_to_linecol( int pos, int* lineNum, int* column ) { + int retVal; + + /* In continuous wrap mode, the absolute (non-wrapped) line count is + maintained separately, as needed. Only return it if we're actually + keeping track of it and pos is in the displayed text */ + if (mContinuousWrap) { + if (!maintaining_absolute_top_line_number() || + pos < mFirstChar || pos > mLastChar) + return 0; + *lineNum = mAbsTopLineNum + buffer()->count_lines(mFirstChar, pos); + *column + = buffer()->count_displayed_characters(buffer()->line_start(pos), pos); + return 1; + } + + retVal = position_to_line( pos, lineNum ); + if ( retVal ) { + *column = mBuffer->count_displayed_characters( + mLineStarts[ *lineNum ], pos ); + *lineNum += mTopLineNum; + } + return retVal; +} + +/* +** Return 1 if position (X, Y) is inside of the primary Fl_Text_Selection +*/ +int Fl_Text_Display::in_selection( int X, int Y ) { + int row, column, pos = xy_to_position( X, Y, CHARACTER_POS ); + Fl_Text_Buffer *buf = mBuffer; + + xy_to_rowcol( X, Y, &row, &column, CHARACTER_POS ); + if (range_touches_selection(buf->primary_selection(), mFirstChar, mLastChar)) + column = wrapped_column(row, column); + return buf->primary_selection()->includes(pos, buf->line_start( pos ), column); +} + +/* +** Correct a column number based on an unconstrained position (as returned by +** TextDXYToUnconstrainedPosition) to be relative to the last actual newline +** in the buffer before the row and column position given, rather than the +** last line start created by line wrapping. This is an adapter +** for rectangular selections and code written before continuous wrap mode, +** which thinks that the unconstrained column is the number of characters +** from the last newline. Obviously this is time consuming, because it +** invloves character re-counting. +*/ +int Fl_Text_Display::wrapped_column(int row, int column) { + int lineStart, dispLineStart; + + if (!mContinuousWrap || row < 0 || row > mNVisibleLines) + return column; + dispLineStart = mLineStarts[row]; + if (dispLineStart == -1) + return column; + lineStart = buffer()->line_start(dispLineStart); + return column + + buffer()->count_displayed_characters(lineStart, dispLineStart); +} + +/* +** Correct a row number from an unconstrained position (as returned by +** TextDXYToUnconstrainedPosition) to a straight number of newlines from the +** top line of the display. Because rectangular selections are based on +** newlines, rather than display wrapping, and anywhere a rectangular selection +** needs a row, it needs it in terms of un-wrapped lines. +*/ +int Fl_Text_Display::wrapped_row(int row) { + if (!mContinuousWrap || row < 0 || row > mNVisibleLines) + return row; + return buffer()->count_lines(mFirstChar, mLineStarts[row]); +} + +/* +** Scroll the display to bring insertion cursor into view. +** +** Note: it would be nice to be able to do this without counting lines twice +** (scroll_() counts them too) and/or to count from the most efficient +** starting point, but the efficiency of this routine is not as important to +** the overall performance of the text display. +*/ +void Fl_Text_Display::display_insert() { + int hOffset, topLine, X, Y; + hOffset = mHorizOffset; + topLine = mTopLineNum; + +// FIXME: I don't understand this well enough to know if it is correct +// it is different than nedit 5.3 + if (insert_position() < mFirstChar) { + topLine -= count_lines(insert_position(), mFirstChar, false); + } else if (mLineStarts[mNVisibleLines-2] != -1) { + int lastChar = line_end(mLineStarts[mNVisibleLines-2],true); + if (insert_position() >= lastChar) + topLine + += count_lines(lastChar - (wrap_uses_character(mLastChar) ? 0 : 1), + insert_position(), false); + } + + /* Find the new setting for horizontal offset (this is a bit ungraceful). + If the line is visible, just use PositionToXY to get the position + to scroll to, otherwise, do the vertical scrolling first, then the + horizontal */ + if (!position_to_xy( mCursorPos, &X, &Y )) { + scroll_(topLine, hOffset); + if (!position_to_xy( mCursorPos, &X, &Y )) { + #ifdef DEBUG + printf ("*** display_insert/position_to_xy # GIVE UP !\n"); fflush(stdout); + #endif // DEBUG + return; /* Give up, it's not worth it (but why does it fail?) */ + } + } + if (X > text_area.x + text_area.w) + hOffset += X-(text_area.x + text_area.w); + else if (X < text_area.x) + hOffset += X-text_area.x; + + /* Do the scroll */ + if (topLine != mTopLineNum || hOffset != mHorizOffset) + scroll_(topLine, hOffset); +} + +void Fl_Text_Display::show_insert_position() { + display_insert_position_hint = 1; + resize(x(), y(), w(), h()); +} + +/* +** Cursor movement functions +*/ +int Fl_Text_Display::move_right() { + if ( mCursorPos >= mBuffer->length() ) + return 0; + insert_position( mCursorPos + 1 ); + return 1; +} + +int Fl_Text_Display::move_left() { + if ( mCursorPos <= 0 ) + return 0; + insert_position( mCursorPos - 1 ); + return 1; +} + +int Fl_Text_Display::move_up() { + int lineStartPos, column, prevLineStartPos, newPos, visLineNum; + + /* Find the position of the start of the line. Use the line starts array + if possible */ + if ( position_to_line( mCursorPos, &visLineNum ) ) + lineStartPos = mLineStarts[ visLineNum ]; + else { + lineStartPos = line_start( mCursorPos ); + visLineNum = -1; + } + if ( lineStartPos == 0 ) + return 0; + + /* Decide what column to move to, if there's a preferred column use that */ + column = mCursorPreferredCol >= 0 ? mCursorPreferredCol : + mBuffer->count_displayed_characters( lineStartPos, mCursorPos ); + + /* count forward from the start of the previous line to reach the column */ + if ( visLineNum != -1 && visLineNum != 0 ) + prevLineStartPos = mLineStarts[ visLineNum - 1 ]; + else + prevLineStartPos = rewind_lines( lineStartPos, 1 ); + newPos = mBuffer->skip_displayed_characters( prevLineStartPos, column ); + if (mContinuousWrap) + newPos = min(newPos, line_end(prevLineStartPos, true)); + + /* move the cursor */ + insert_position( newPos ); + + /* if a preferred column wasn't aleady established, establish it */ + mCursorPreferredCol = column; + return 1; +} + +int Fl_Text_Display::move_down() { + int lineStartPos, column, nextLineStartPos, newPos, visLineNum; + + if ( mCursorPos == mBuffer->length() ) + return 0; + if ( position_to_line( mCursorPos, &visLineNum ) ) + lineStartPos = mLineStarts[ visLineNum ]; + else { + lineStartPos = line_start( mCursorPos ); + visLineNum = -1; + } + column = mCursorPreferredCol >= 0 ? mCursorPreferredCol : + mBuffer->count_displayed_characters( lineStartPos, mCursorPos ); + nextLineStartPos = skip_lines( lineStartPos, 1, true ); + newPos = mBuffer->skip_displayed_characters( nextLineStartPos, column ); + if (mContinuousWrap) + newPos = min(newPos, line_end(nextLineStartPos, true)); + + insert_position( newPos ); + mCursorPreferredCol = column; + return 1; +} + +/* +** Same as BufCountLines, but takes in to account wrapping if wrapping is +** turned on. If the caller knows that startPos is at a line start, it +** can pass "startPosIsLineStart" as True to make the call more efficient +** by avoiding the additional step of scanning back to the last newline. +*/ +int Fl_Text_Display::count_lines(int startPos, int endPos, + bool startPosIsLineStart) { + int retLines, retPos, retLineStart, retLineEnd; + +#ifdef DEBUG + printf("Fl_Text_Display::count_lines(startPos=%d, endPos=%d, startPosIsLineStart=%d\n", + startPos, endPos, startPosIsLineStart); +#endif // DEBUG + + /* If we're not wrapping use simple (and more efficient) BufCountLines */ + if (!mContinuousWrap) + return buffer()->count_lines(startPos, endPos); + + wrapped_line_counter(buffer(), startPos, endPos, INT_MAX, + startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, + &retLineEnd); + +#ifdef DEBUG + printf(" # after WLC: retPos=%d, retLines=%d, retLineStart=%d, retLineEnd=%d\n", + retPos, retLines, retLineStart, retLineEnd); +#endif // DEBUG + + return retLines; +} + +/* +** Same as BufCountForwardNLines, but takes in to account line breaks when +** wrapping is turned on. If the caller knows that startPos is at a line start, +** it can pass "startPosIsLineStart" as True to make the call more efficient +** by avoiding the additional step of scanning back to the last newline. +*/ +int Fl_Text_Display::skip_lines(int startPos, int nLines, + bool startPosIsLineStart) { + int retLines, retPos, retLineStart, retLineEnd; + + /* if we're not wrapping use more efficient BufCountForwardNLines */ + if (!mContinuousWrap) + return buffer()->skip_lines(startPos, nLines); + + /* wrappedLineCounter can't handle the 0 lines case */ + if (nLines == 0) + return startPos; + + /* use the common line counting routine to count forward */ + wrapped_line_counter(buffer(), startPos, buffer()->length(), + nLines, startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, + &retLineEnd); + return retPos; +} + +/* +** Same as BufEndOfLine, but takes in to account line breaks when wrapping +** is turned on. If the caller knows that startPos is at a line start, it +** can pass "startPosIsLineStart" as True to make the call more efficient +** by avoiding the additional step of scanning back to the last newline. +** +** Note that the definition of the end of a line is less clear when continuous +** wrap is on. With continuous wrap off, it's just a pointer to the newline +** that ends the line. When it's on, it's the character beyond the last +** DISPLAYABLE character on the line, where a whitespace character which has +** been "converted" to a newline for wrapping is not considered displayable. +** Also note that, a line can be wrapped at a non-whitespace character if the +** line had no whitespace. In this case, this routine returns a pointer to +** the start of the next line. This is also consistent with the model used by +** visLineLength. +*/ +int Fl_Text_Display::line_end(int pos, bool startPosIsLineStart) { + int retLines, retPos, retLineStart, retLineEnd; + + /* If we're not wrapping use more efficien BufEndOfLine */ + if (!mContinuousWrap) + return buffer()->line_end(pos); + + if (pos == buffer()->length()) + return pos; + wrapped_line_counter(buffer(), pos, buffer()->length(), 1, + startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, + &retLineEnd); + return retLineEnd; +} + +/* +** Same as BufStartOfLine, but returns the character after last wrap point +** rather than the last newline. +*/ +int Fl_Text_Display::line_start(int pos) { + int retLines, retPos, retLineStart, retLineEnd; + + /* If we're not wrapping, use the more efficient BufStartOfLine */ + if (!mContinuousWrap) + return buffer()->line_start(pos); + + wrapped_line_counter(buffer(), buffer()->line_start(pos), pos, INT_MAX, true, 0, + &retPos, &retLines, &retLineStart, &retLineEnd); + return retLineStart; +} + +/* +** Same as BufCountBackwardNLines, but takes in to account line breaks when +** wrapping is turned on. +*/ +int Fl_Text_Display::rewind_lines(int startPos, int nLines) { + Fl_Text_Buffer *buf = buffer(); + int pos, lineStart, retLines, retPos, retLineStart, retLineEnd; + + /* If we're not wrapping, use the more efficient BufCountBackwardNLines */ + if (!mContinuousWrap) + return buf->rewind_lines(startPos, nLines); + + pos = startPos; + for (;;) { + lineStart = buf->line_start(pos); + wrapped_line_counter(buf, lineStart, pos, INT_MAX, + true, 0, &retPos, &retLines, &retLineStart, &retLineEnd, false); + if (retLines > nLines) + return skip_lines(lineStart, retLines-nLines, + true); + nLines -= retLines; + pos = lineStart - 1; + if (pos < 0) + return 0; + nLines -= 1; + } +} + +static inline int fl_isseparator(int c) { + return c != '$' && c != '_' && (isspace(c) || ispunct(c)); +} + +void Fl_Text_Display::next_word() { + int pos = insert_position(); + while (pos < buffer()->length() && !fl_isseparator(buffer()->character(pos))) { + pos++; + } + while (pos < buffer()->length() && fl_isseparator(buffer()->character(pos))) { + pos++; + } + + insert_position( pos ); +} + +void Fl_Text_Display::previous_word() { + int pos = insert_position(); + if (pos==0) return; + pos--; + while (pos && fl_isseparator(buffer()->character(pos))) { + pos--; + } + while (pos && !fl_isseparator(buffer()->character(pos))) { + pos--; + } + if (fl_isseparator(buffer()->character(pos))) pos++; + + insert_position( pos ); +} + +/* +** Callback attached to the text buffer to receive delete information before +** the modifications are actually made. +*/ +void Fl_Text_Display::buffer_predelete_cb(int pos, int nDeleted, void *cbArg) { + Fl_Text_Display *textD = (Fl_Text_Display *)cbArg; + if (textD->mContinuousWrap && + (textD->mFixedFontWidth == -1 || textD->mModifyingTabDistance)) + /* Note: we must perform this measurement, even if there is not a + single character deleted; the number of "deleted" lines is the + number of visual lines spanned by the real line in which the + modification takes place. + Also, a modification of the tab distance requires the same + kind of calculations in advance, even if the font width is "fixed", + because when the width of the tab characters changes, the layout + of the text may be completely different. */ + textD->measure_deleted_lines(pos, nDeleted); + else + textD->mSuppressResync = 0; /* Probably not needed, but just in case */ +} + +/* +** Callback attached to the text buffer to receive modification information +*/ +void Fl_Text_Display::buffer_modified_cb( int pos, int nInserted, int nDeleted, + int nRestyled, const char *deletedText, void *cbArg ) { + int linesInserted, linesDeleted, startDispPos, endDispPos; + Fl_Text_Display *textD = ( Fl_Text_Display * ) cbArg; + Fl_Text_Buffer *buf = textD->mBuffer; + int oldFirstChar = textD->mFirstChar; + int scrolled, origCursorPos = textD->mCursorPos; + int wrapModStart, wrapModEnd; + + /* buffer modification cancels vertical cursor motion column */ + if ( nInserted != 0 || nDeleted != 0 ) + textD->mCursorPreferredCol = -1; + + /* Count the number of lines inserted and deleted, and in the case + of continuous wrap mode, how much has changed */ + if (textD->mContinuousWrap) { + textD->find_wrap_range(deletedText, pos, nInserted, nDeleted, + &wrapModStart, &wrapModEnd, &linesInserted, &linesDeleted); + } else { + linesInserted = nInserted == 0 ? 0 : + buf->count_lines( pos, pos + nInserted ); + linesDeleted = nDeleted == 0 ? 0 : countlines( deletedText ); + } + + /* Update the line starts and mTopLineNum */ + if ( nInserted != 0 || nDeleted != 0 ) { + if (textD->mContinuousWrap) { + textD->update_line_starts( wrapModStart, wrapModEnd-wrapModStart, + nDeleted + pos-wrapModStart + (wrapModEnd-(pos+nInserted)), + linesInserted, linesDeleted, &scrolled ); + } else { + textD->update_line_starts( pos, nInserted, nDeleted, linesInserted, + linesDeleted, &scrolled ); + } + } else + scrolled = 0; + + /* If we're counting non-wrapped lines as well, maintain the absolute + (non-wrapped) line number of the text displayed */ + if (textD->maintaining_absolute_top_line_number() && + (nInserted != 0 || nDeleted != 0)) { + if (pos + nDeleted < oldFirstChar) + textD->mAbsTopLineNum += buf->count_lines(pos, pos + nInserted) - + countlines(deletedText); + else if (pos < oldFirstChar) + textD->reset_absolute_top_line_number(); + } + + /* Update the line count for the whole buffer */ + textD->mNBufferLines += linesInserted - linesDeleted; + + /* Update the cursor position */ + if ( textD->mCursorToHint != NO_HINT ) { + textD->mCursorPos = textD->mCursorToHint; + textD->mCursorToHint = NO_HINT; + } else if ( textD->mCursorPos > pos ) { + if ( textD->mCursorPos < pos + nDeleted ) + textD->mCursorPos = pos; + else + textD->mCursorPos += nInserted - nDeleted; + } + + // refigure scrollbars & stuff + textD->resize(textD->x(), textD->y(), textD->w(), textD->h()); + + // don't need to do anything else if not visible? + if (!textD->visible_r()) return; + + /* If the changes caused scrolling, re-paint everything and we're done. */ + if ( scrolled ) { + textD->damage(FL_DAMAGE_EXPOSE); + if ( textD->mStyleBuffer ) /* See comments in extendRangeForStyleMods */ + textD->mStyleBuffer->primary_selection()->selected(0); + return; + } + + /* If the changes didn't cause scrolling, decide the range of characters + that need to be re-painted. Also if the cursor position moved, be + sure that the redisplay range covers the old cursor position so the + old cursor gets erased, and erase the bits of the cursor which extend + beyond the left and right edges of the text. */ + startDispPos = textD->mContinuousWrap ? wrapModStart : pos; + if ( origCursorPos == startDispPos && textD->mCursorPos != startDispPos ) + startDispPos = min( startDispPos, origCursorPos - 1 ); + if ( linesInserted == linesDeleted ) { + if ( nInserted == 0 && nDeleted == 0 ) + endDispPos = pos + nRestyled; + else { + endDispPos = textD->mContinuousWrap ? wrapModEnd : + buf->line_end( pos + nInserted ) + 1; + // CET - FIXME if ( origCursorPos >= startDispPos && + // ( origCursorPos <= endDispPos || endDispPos == buf->length() ) ) + } + + if (linesInserted > 1) textD->draw_line_numbers(false); + } else { + endDispPos = textD->mLastChar + 1; + // CET - FIXME if ( origCursorPos >= pos ) + /* If more than one line is inserted/deleted, a line break may have + been inserted or removed in between, and the line numbers may + have changed. If only one line is altered, line numbers cannot + be affected (the insertion or removal of a line break always + results in at least two lines being redrawn). */ + textD->draw_line_numbers(false); + } + + /* If there is a style buffer, check if the modification caused additional + changes that need to be redisplayed. (Redisplaying separately would + cause double-redraw on almost every modification involving styled + text). Extend the redraw range to incorporate style changes */ + if ( textD->mStyleBuffer ) + textD->extend_range_for_styles( &startDispPos, &endDispPos ); + + /* Redisplay computed range */ + textD->redisplay_range( startDispPos, endDispPos ); +} + +/* +** In continuous wrap mode, internal line numbers are calculated after +** wrapping. A separate non-wrapped line count is maintained when line +** numbering is turned on. There is some performance cost to maintaining this +** line count, so normally absolute line numbers are not tracked if line +** numbering is off. This routine allows callers to specify that they still +** want this line count maintained (for use via TextDPosToLineAndCol). +** More specifically, this allows the line number reported in the statistics +** line to be calibrated in absolute lines, rather than post-wrapped lines. +*/ +void Fl_Text_Display::maintain_absolute_top_line_number(int state) { + mNeedAbsTopLineNum = state; + reset_absolute_top_line_number(); +} + +/* +** Returns the absolute (non-wrapped) line number of the first line displayed. +** Returns 0 if the absolute top line number is not being maintained. +*/ +int Fl_Text_Display::get_absolute_top_line_number() { + if (!mContinuousWrap) + return mTopLineNum; + if (maintaining_absolute_top_line_number()) + return mAbsTopLineNum; + return 0; +} + +/* +** Re-calculate absolute top line number for a change in scroll position. +*/ +void Fl_Text_Display::absolute_top_line_number(int oldFirstChar) { + if (maintaining_absolute_top_line_number()) { + if (mFirstChar < oldFirstChar) + mAbsTopLineNum -= buffer()->count_lines(mFirstChar, oldFirstChar); + else + mAbsTopLineNum += buffer()->count_lines(oldFirstChar, mFirstChar); + } +} + +/* +** Return true if a separate absolute top line number is being maintained +** (for displaying line numbers or showing in the statistics line). +*/ +int Fl_Text_Display::maintaining_absolute_top_line_number() { + return mContinuousWrap && + (mLineNumWidth != 0 || mNeedAbsTopLineNum); +} + +/* +** Count lines from the beginning of the buffer to reestablish the +** absolute (non-wrapped) top line number. If mode is not continuous wrap, +** or the number is not being maintained, does nothing. +*/ +void Fl_Text_Display::reset_absolute_top_line_number() { + mAbsTopLineNum = 1; + absolute_top_line_number(0); +} + +/* +** Find the line number of position "pos" relative to the first line of +** displayed text. Returns 0 if the line is not displayed. +*/ +int Fl_Text_Display::position_to_line( int pos, int *lineNum ) { + int i; + + *lineNum = 0; + if ( pos < mFirstChar ) return 0; + if ( pos > mLastChar ) { + if ( empty_vlines() ) { + if ( mLastChar < mBuffer->length() ) { + if ( !position_to_line( mLastChar, lineNum ) ) { + Fl::error("Fl_Text_Display::position_to_line(): Consistency check ptvl failed"); + return 0; + } + return ++( *lineNum ) <= mNVisibleLines - 1; + } else { + position_to_line( mLastChar - 1, lineNum ); + return 1; + } + } + return 0; + } + + for ( i = mNVisibleLines - 1; i >= 0; i-- ) { + if ( mLineStarts[ i ] != -1 && pos >= mLineStarts[ i ] ) { + *lineNum = i; + return 1; + } + } + return 0; /* probably never be reached */ +} + +/* +** Draw the text on a single line represented by "visLineNum" (the +** number of lines down from the top of the display), limited by +** "leftClip" and "rightClip" window coordinates and "leftCharIndex" and +** "rightCharIndex" character positions (not including the character at +** position "rightCharIndex"). +*/ +void Fl_Text_Display::draw_vline(int visLineNum, int leftClip, int rightClip, + int leftCharIndex, int rightCharIndex) { + Fl_Text_Buffer * buf = mBuffer; + int i, X, Y, startX, charIndex, lineStartPos, lineLen, fontHeight; + int stdCharWidth, charWidth, startIndex, charStyle, style; + int charLen, outStartIndex, outIndex; + int dispIndexOffset; + char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ], outStr[ MAX_DISP_LINE_LEN ]; + char *outPtr; + const char *lineStr; + +// printf("draw_vline(visLineNum=%d, leftClip=%d, rightClip=%d, leftCharIndex=%d, rightCharIndex=%d)\n", +// visLineNum, leftClip, rightClip, leftCharIndex, rightCharIndex); +// printf("nNVisibleLines=%d\n", mNVisibleLines); + + /* If line is not displayed, skip it */ + if ( visLineNum < 0 || visLineNum >= mNVisibleLines ) + return; + + /* Calculate Y coordinate of the string to draw */ + fontHeight = mMaxsize; + Y = text_area.y + visLineNum * fontHeight; + + /* Get the text, length, and buffer position of the line to display */ + lineStartPos = mLineStarts[ visLineNum ]; +// printf("lineStartPos=%d\n", lineStartPos); + if ( lineStartPos == -1 ) { + lineLen = 0; + lineStr = NULL; + } else { + lineLen = vline_length( visLineNum ); + lineStr = buf->text_range( lineStartPos, lineStartPos + lineLen ); + } + + /* Space beyond the end of the line is still counted in units of characters + of a standardized character width (this is done mostly because style + changes based on character position can still occur in this region due + to rectangular Fl_Text_Selections). stdCharWidth must be non-zero to + prevent a potential infinite loop if X does not advance */ + stdCharWidth = TMPFONTWIDTH; //mFontStruct->max_bounds.width; + if ( stdCharWidth <= 0 ) { + Fl::error("Fl_Text_Display::draw_vline(): bad font measurement"); + free((void *)lineStr); + return; + } + + /* Shrink the clipping range to the active display area */ + leftClip = max( text_area.x, leftClip ); + rightClip = min( rightClip, text_area.x + text_area.w ); + + /* Rectangular Fl_Text_Selections are based on "real" line starts (after + a newline or start of buffer). Calculate the difference between the + last newline position and the line start we're using. Since scanning + back to find a newline is expensive, only do so if there's actually a + rectangular Fl_Text_Selection which needs it */ + if (mContinuousWrap && (range_touches_selection(buf->primary_selection(), + lineStartPos, lineStartPos + lineLen) || range_touches_selection( + buf->secondary_selection(), lineStartPos, lineStartPos + lineLen) || + range_touches_selection(buf->highlight_selection(), lineStartPos, + lineStartPos + lineLen))) { + dispIndexOffset = buf->count_displayed_characters( + buf->line_start(lineStartPos), lineStartPos); + } else + dispIndexOffset = 0; + + /* Step through character positions from the beginning of the line (even if + that's off the left edge of the displayed area) to find the first + character position that's not clipped, and the X coordinate for drawing + that character */ + X = text_area.x - mHorizOffset; + outIndex = 0; + for ( charIndex = 0; ; charIndex++ ) { + charLen = charIndex >= lineLen ? 1 : + Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, + expandedChar, buf->tab_distance(), buf->null_substitution_character() ); + style = position_style( lineStartPos, lineLen, charIndex, + outIndex + dispIndexOffset ); + charWidth = charIndex >= lineLen ? stdCharWidth : + string_width( expandedChar, charLen, style ); + if ( X + charWidth >= leftClip && charIndex >= leftCharIndex ) { + startIndex = charIndex; + outStartIndex = outIndex; + startX = X; + break; + } + X += charWidth; + outIndex += charLen; + } + + /* Scan character positions from the beginning of the clipping range, and + draw parts whenever the style changes (also note if the cursor is on + this line, and where it should be drawn to take advantage of the x + position which we've gone to so much trouble to calculate) */ + /* since characters between style may overlap, we draw the full + background first */ + int sX = startX; + outPtr = outStr; + outIndex = outStartIndex; + X = startX; + for ( charIndex = startIndex; charIndex < rightCharIndex; charIndex++ ) { + charLen = charIndex >= lineLen ? 1 : + Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, expandedChar, + buf->tab_distance(), buf->null_substitution_character() ); + charStyle = position_style( lineStartPos, lineLen, charIndex, + outIndex + dispIndexOffset ); + for ( i = 0; i < charLen; i++ ) { + if ( i != 0 && charIndex < lineLen && lineStr[ charIndex ] == '\t' ) + charStyle = position_style( lineStartPos, lineLen, + charIndex, outIndex + dispIndexOffset ); + if ( charStyle != style ) { + draw_string( style|BG_ONLY_MASK, sX, Y, X, outStr, outPtr - outStr ); + outPtr = outStr; + sX = X; + style = charStyle; + } + if ( charIndex < lineLen ) { + *outPtr = expandedChar[ i ]; + charWidth = string_width( &expandedChar[ i ], 1, charStyle ); + } else + charWidth = stdCharWidth; + outPtr++; + X += charWidth; + outIndex++; + } + if ( outPtr - outStr + FL_TEXT_MAX_EXP_CHAR_LEN >= MAX_DISP_LINE_LEN || X >= rightClip ) + break; + } + draw_string( style|BG_ONLY_MASK, sX, Y, X, outStr, outPtr - outStr ); + + /* now draw the text over the previously erased background */ + outPtr = outStr; + outIndex = outStartIndex; + X = startX; + for ( charIndex = startIndex; charIndex < rightCharIndex; charIndex++ ) { + charLen = charIndex >= lineLen ? 1 : + Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, expandedChar, + buf->tab_distance(), buf->null_substitution_character() ); + charStyle = position_style( lineStartPos, lineLen, charIndex, + outIndex + dispIndexOffset ); + for ( i = 0; i < charLen; i++ ) { + if ( i != 0 && charIndex < lineLen && lineStr[ charIndex ] == '\t' ) + charStyle = position_style( lineStartPos, lineLen, + charIndex, outIndex + dispIndexOffset ); + if ( charStyle != style ) { + draw_string( style|TEXT_ONLY_MASK, startX, Y, X, outStr, outPtr - outStr ); + outPtr = outStr; + startX = X; + style = charStyle; + } + if ( charIndex < lineLen ) { + *outPtr = expandedChar[ i ]; + charWidth = string_width( &expandedChar[ i ], 1, charStyle ); + } else + charWidth = stdCharWidth; + outPtr++; + X += charWidth; + outIndex++; + } + if ( outPtr - outStr + FL_TEXT_MAX_EXP_CHAR_LEN >= MAX_DISP_LINE_LEN || X >= rightClip ) + break; + } + + /* Draw the remaining style segment */ + draw_string( style|TEXT_ONLY_MASK, startX, Y, X, outStr, outPtr - outStr ); + + /* Draw the cursor if part of it appeared on the redisplayed part of + this line. Also check for the cases which are not caught as the + line is scanned above: when the cursor appears at the very end + of the redisplayed section. */ + /* CET - FIXME + if ( mCursorOn ) + { + if ( hasCursor ) + draw_cursor( cursorX, Y ); + else if ( charIndex < lineLen && ( lineStartPos + charIndex + 1 == cursorPos ) + && X == rightClip ) + { + if ( cursorPos >= buf->length() ) + draw_cursor( X - 1, Y ); + else + { + draw_cursor( X - 1, Y ); + } + } + } + */ + if ( lineStr != NULL ) + free((void *)lineStr); +} + +/* +** Draw a string or blank area according to parameter "style", using the +** appropriate colors and drawing method for that style, with top left +** corner at X, y. If style says to draw text, use "string" as source of +** characters, and draw "nChars", if style is FILL, erase +** rectangle where text would have drawn from X to toX and from Y to +** the maximum Y extent of the current font(s). +*/ +void Fl_Text_Display::draw_string( int style, int X, int Y, int toX, + const char *string, int nChars ) { + const Style_Table_Entry * styleRec; + + /* Draw blank area rather than text, if that was the request */ + if ( style & FILL_MASK ) { + if (style & TEXT_ONLY_MASK) return; + clear_rect( style, X, Y, toX - X, mMaxsize ); + return; + } + + /* Set font, color, and gc depending on style. For normal text, GCs + for normal drawing, or drawing within a Fl_Text_Selection or highlight are + pre-allocated and pre-configured. For syntax highlighting, GCs are + configured here, on the fly. */ + + Fl_Font font = textfont(); + int fsize = textsize(); + Fl_Color foreground; + Fl_Color background; + + if ( style & STYLE_LOOKUP_MASK ) { + int si = (style & STYLE_LOOKUP_MASK) - 'A'; + if (si < 0) si = 0; + else if (si >= mNStyles) si = mNStyles - 1; + + styleRec = mStyleTable + si; + font = styleRec->font; + fsize = styleRec->size; + + if (style & PRIMARY_MASK) { + if (Fl::focus() == this) background = selection_color(); + else background = fl_color_average(color(), selection_color(), 0.4f); + } else if (style & HIGHLIGHT_MASK) { + if (Fl::focus() == this) background = fl_color_average(color(), selection_color(), 0.5f); + else background = fl_color_average(color(), selection_color(), 0.6f); + } else background = color(); + foreground = fl_contrast(styleRec->color, background); + } else if (style & PRIMARY_MASK) { + if (Fl::focus() == this) background = selection_color(); + else background = fl_color_average(color(), selection_color(), 0.4f); + foreground = fl_contrast(textcolor(), background); + } else if (style & HIGHLIGHT_MASK) { + if (Fl::focus() == this) background = fl_color_average(color(), selection_color(), 0.5f); + else background = fl_color_average(color(), selection_color(), 0.6f); + foreground = fl_contrast(textcolor(), background); + } else { + foreground = textcolor(); + background = color(); + } + + if (!(style & TEXT_ONLY_MASK)) { + fl_color( background ); + fl_rectf( X, Y, toX - X, mMaxsize ); + } + if (!(style & BG_ONLY_MASK)) { + fl_color( foreground ); + fl_font( font, fsize ); + fl_draw( string, nChars, X, Y + mMaxsize - fl_descent()); + } + + // CET - FIXME + /* If any space around the character remains unfilled (due to use of + different sized fonts for highlighting), fill in above or below + to erase previously drawn characters */ + /* + if (fs->ascent < mAscent) + clear_rect( style, X, Y, toX - X, mAscent - fs->ascent); + if (fs->descent < mDescent) + clear_rect( style, X, Y + mAscent + fs->descent, toX - x, + mDescent - fs->descent); + */ + /* Underline if style is secondary Fl_Text_Selection */ + + /* + if (style & SECONDARY_MASK) + XDrawLine(XtDisplay(mW), XtWindow(mW), gc, x, + y + mAscent, toX - 1, Y + fs->ascent); + */ +} + + +/* +** Clear a rectangle with the appropriate background color for "style" +*/ +void Fl_Text_Display::clear_rect( int style, int X, int Y, + int width, int height ) { + /* A width of zero means "clear to end of window" to XClearArea */ + if ( width == 0 ) + return; + + if (style & PRIMARY_MASK) { + if (Fl::focus()==this) { + fl_color(selection_color()); + } else { + fl_color(fl_color_average(color(), selection_color(), 0.4f)); + } + } else if (style & HIGHLIGHT_MASK) { + if (Fl::focus()==this) { + fl_color(fl_color_average(color(), selection_color(), 0.5f)); + } else { + fl_color(fl_color_average(color(), selection_color(), 0.6f)); + } + } else { + fl_color( color() ); + } + fl_rectf( X, Y, width, height ); +} + + +/* +** Draw a cursor with top center at X, y. +*/ +void Fl_Text_Display::draw_cursor( int X, int Y ) { + typedef struct { + int x1, y1, x2, y2; + } + Segment; + + Segment segs[ 5 ]; + int left, right, cursorWidth, midY; + // int fontWidth = mFontStruct->min_bounds.width, nSegs = 0; + int fontWidth = TMPFONTWIDTH; // CET - FIXME + int nSegs = 0; + int fontHeight = mMaxsize; + int bot = Y + fontHeight - 1; + + if ( X < text_area.x - 1 || X > text_area.x + text_area.w ) + return; + + /* For cursors other than the block, make them around 2/3 of a character + width, rounded to an even number of pixels so that X will draw an + odd number centered on the stem at x. */ + cursorWidth = 4; //(fontWidth/3) * 2; + left = X - cursorWidth / 2; + right = left + cursorWidth; + + /* Create segments and draw cursor */ + if ( mCursorStyle == CARET_CURSOR ) { + midY = bot - fontHeight / 5; + segs[ 0 ].x1 = left; segs[ 0 ].y1 = bot; segs[ 0 ].x2 = X; segs[ 0 ].y2 = midY; + segs[ 1 ].x1 = X; segs[ 1 ].y1 = midY; segs[ 1 ].x2 = right; segs[ 1 ].y2 = bot; + segs[ 2 ].x1 = left; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = X; segs[ 2 ].y2 = midY - 1; + segs[ 3 ].x1 = X; segs[ 3 ].y1 = midY - 1; segs[ 3 ].x2 = right; segs[ 3 ].y2 = bot; + nSegs = 4; + } else if ( mCursorStyle == NORMAL_CURSOR ) { + segs[ 0 ].x1 = left; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = right; segs[ 0 ].y2 = Y; + segs[ 1 ].x1 = X; segs[ 1 ].y1 = Y; segs[ 1 ].x2 = X; segs[ 1 ].y2 = bot; + segs[ 2 ].x1 = left; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = right; segs[ 2 ].y2 = bot; + nSegs = 3; + } else if ( mCursorStyle == HEAVY_CURSOR ) { + segs[ 0 ].x1 = X - 1; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = X - 1; segs[ 0 ].y2 = bot; + segs[ 1 ].x1 = X; segs[ 1 ].y1 = Y; segs[ 1 ].x2 = X; segs[ 1 ].y2 = bot; + segs[ 2 ].x1 = X + 1; segs[ 2 ].y1 = Y; segs[ 2 ].x2 = X + 1; segs[ 2 ].y2 = bot; + segs[ 3 ].x1 = left; segs[ 3 ].y1 = Y; segs[ 3 ].x2 = right; segs[ 3 ].y2 = Y; + segs[ 4 ].x1 = left; segs[ 4 ].y1 = bot; segs[ 4 ].x2 = right; segs[ 4 ].y2 = bot; + nSegs = 5; + } else if ( mCursorStyle == DIM_CURSOR ) { + midY = Y + fontHeight / 2; + segs[ 0 ].x1 = X; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = X; segs[ 0 ].y2 = Y; + segs[ 1 ].x1 = X; segs[ 1 ].y1 = midY; segs[ 1 ].x2 = X; segs[ 1 ].y2 = midY; + segs[ 2 ].x1 = X; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = X; segs[ 2 ].y2 = bot; + nSegs = 3; + } else if ( mCursorStyle == BLOCK_CURSOR ) { + right = X + fontWidth; + segs[ 0 ].x1 = X; segs[ 0 ].y1 = Y; segs[ 0 ].x2 = right; segs[ 0 ].y2 = Y; + segs[ 1 ].x1 = right; segs[ 1 ].y1 = Y; segs[ 1 ].x2 = right; segs[ 1 ].y2 = bot; + segs[ 2 ].x1 = right; segs[ 2 ].y1 = bot; segs[ 2 ].x2 = X; segs[ 2 ].y2 = bot; + segs[ 3 ].x1 = X; segs[ 3 ].y1 = bot; segs[ 3 ].x2 = X; segs[ 3 ].y2 = Y; + nSegs = 4; + } + fl_color( mCursor_color ); + + for ( int k = 0; k < nSegs; k++ ) { + fl_line( segs[ k ].x1, segs[ k ].y1, segs[ k ].x2, segs[ k ].y2 ); + } +} + +/* +** Determine the drawing method to use to draw a specific character from "buf". +** "lineStartPos" gives the character index where the line begins, "lineIndex", +** the number of characters past the beginning of the line, and "dispIndex", +** the number of displayed characters past the beginning of the line. Passing +** lineStartPos of -1 returns the drawing style for "no text". +** +** Why not just: position_style(pos)? Because style applies to blank areas +** of the window beyond the text boundaries, and because this routine must also +** decide whether a position is inside of a rectangular Fl_Text_Selection, and do +** so efficiently, without re-counting character positions from the start of the +** line. +** +** Note that style is a somewhat incorrect name, drawing method would +** be more appropriate. +*/ +int Fl_Text_Display::position_style( int lineStartPos, + int lineLen, int lineIndex, int dispIndex ) { + Fl_Text_Buffer * buf = mBuffer; + Fl_Text_Buffer *styleBuf = mStyleBuffer; + int pos, style = 0; + + if ( lineStartPos == -1 || buf == NULL ) + return FILL_MASK; + + pos = lineStartPos + min( lineIndex, lineLen ); + + if ( lineIndex >= lineLen ) + style = FILL_MASK; + else if ( styleBuf != NULL ) { + style = ( unsigned char ) styleBuf->character( pos ); + if (style == mUnfinishedStyle && mUnfinishedHighlightCB) { + /* encountered "unfinished" style, trigger parsing */ + (mUnfinishedHighlightCB)( pos, mHighlightCBArg); + style = (unsigned char) styleBuf->character( pos); + } + } + if (buf->primary_selection()->includes(pos, lineStartPos, dispIndex)) + style |= PRIMARY_MASK; + if (buf->highlight_selection()->includes(pos, lineStartPos, dispIndex)) + style |= HIGHLIGHT_MASK; + if (buf->secondary_selection()->includes(pos, lineStartPos, dispIndex)) + style |= SECONDARY_MASK; + return style; +} + +/* +** Find the width of a string in the font of a particular style +*/ +int Fl_Text_Display::string_width( const char *string, int length, int style ) { + Fl_Font font; + int fsize; + + if ( style & STYLE_LOOKUP_MASK ) { + int si = (style & STYLE_LOOKUP_MASK) - 'A'; + if (si < 0) si = 0; + else if (si >= mNStyles) si = mNStyles - 1; + + font = mStyleTable[si].font; + fsize = mStyleTable[si].size; + } else { + font = textfont(); + fsize = textsize(); + } + fl_font( font, fsize ); + + return ( int ) ( fl_width( string, length ) ); +} + +/* +** Translate window coordinates to the nearest (insert cursor or character +** cell) text position. The parameter posType specifies how to interpret the +** position: CURSOR_POS means translate the coordinates to the nearest cursor +** position, and CHARACTER_POS means return the position of the character +** closest to (X, Y). +*/ +int Fl_Text_Display::xy_to_position( int X, int Y, int posType ) { + int charIndex, lineStart, lineLen, fontHeight; + int charWidth, charLen, charStyle, visLineNum, xStep, outIndex; + char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ]; + const char *lineStr; + + /* Find the visible line number corresponding to the Y coordinate */ + fontHeight = mMaxsize; + visLineNum = ( Y - text_area.y ) / fontHeight; + if ( visLineNum < 0 ) + return mFirstChar; + if ( visLineNum >= mNVisibleLines ) + visLineNum = mNVisibleLines - 1; + + /* Find the position at the start of the line */ + lineStart = mLineStarts[ visLineNum ]; + + /* If the line start was empty, return the last position in the buffer */ + if ( lineStart == -1 ) + return mBuffer->length(); + + /* Get the line text and its length */ + lineLen = vline_length( visLineNum ); + lineStr = mBuffer->text_range( lineStart, lineStart + lineLen ); + + /* Step through character positions from the beginning of the line + to find the character position corresponding to the X coordinate */ + xStep = text_area.x - mHorizOffset; + outIndex = 0; + for ( charIndex = 0; charIndex < lineLen; charIndex++ ) { + charLen = Fl_Text_Buffer::expand_character( lineStr[ charIndex ], outIndex, expandedChar, + mBuffer->tab_distance(), mBuffer->null_substitution_character() ); + charStyle = position_style( lineStart, lineLen, charIndex, outIndex ); + charWidth = string_width( expandedChar, charLen, charStyle ); + if ( X < xStep + ( posType == CURSOR_POS ? charWidth / 2 : charWidth ) ) { + free((char *)lineStr); + return lineStart + charIndex; + } + xStep += charWidth; + outIndex += charLen; + } + + /* If the X position was beyond the end of the line, return the position + of the newline at the end of the line */ + free((char *)lineStr); + return lineStart + lineLen; +} + +/* +** Translate window coordinates to the nearest row and column number for +** positioning the cursor. This, of course, makes no sense when the font is +** proportional, since there are no absolute columns. The parameter posType +** specifies how to interpret the position: CURSOR_POS means translate the +** coordinates to the nearest position between characters, and CHARACTER_POS +** means translate the position to the nearest character cell. +*/ +void Fl_Text_Display::xy_to_rowcol( int X, int Y, int *row, + int *column, int posType ) { + int fontHeight = mMaxsize; + int fontWidth = TMPFONTWIDTH; //mFontStruct->max_bounds.width; + + /* Find the visible line number corresponding to the Y coordinate */ + *row = ( Y - text_area.y ) / fontHeight; + if ( *row < 0 ) * row = 0; + if ( *row >= mNVisibleLines ) * row = mNVisibleLines - 1; + *column = ( ( X - text_area.x ) + mHorizOffset + + ( posType == CURSOR_POS ? fontWidth / 2 : 0 ) ) / fontWidth; + if ( *column < 0 ) * column = 0; +} + +/* +** Offset the line starts array, mTopLineNum, mFirstChar and lastChar, for a new +** vertical scroll position given by newTopLineNum. If any currently displayed +** lines will still be visible, salvage the line starts values, otherwise, +** count lines from the nearest known line start (start or end of buffer, or +** the closest value in the mLineStarts array) +*/ +void Fl_Text_Display::offset_line_starts( int newTopLineNum ) { + int oldTopLineNum = mTopLineNum; + int oldFirstChar = mFirstChar; + int lineDelta = newTopLineNum - oldTopLineNum; + int nVisLines = mNVisibleLines; + int *lineStarts = mLineStarts; + int i, lastLineNum; + Fl_Text_Buffer *buf = mBuffer; + + /* If there was no offset, nothing needs to be changed */ + if ( lineDelta == 0 ) + return; + + /* Find the new value for mFirstChar by counting lines from the nearest + known line start (start or end of buffer, or the closest value in the + lineStarts array) */ + lastLineNum = oldTopLineNum + nVisLines - 1; + if ( newTopLineNum < oldTopLineNum && newTopLineNum < -lineDelta ) { + mFirstChar = skip_lines( 0, newTopLineNum - 1, true ); + } else if ( newTopLineNum < oldTopLineNum ) { + mFirstChar = rewind_lines( mFirstChar, -lineDelta ); + } else if ( newTopLineNum < lastLineNum ) { + mFirstChar = lineStarts[ newTopLineNum - oldTopLineNum ]; + } else if ( newTopLineNum - lastLineNum < mNBufferLines - newTopLineNum ) { + mFirstChar = skip_lines( lineStarts[ nVisLines - 1 ], + newTopLineNum - lastLineNum, true ); + } else { + mFirstChar = rewind_lines( buf->length(), mNBufferLines - newTopLineNum + 1 ); + } + + /* Fill in the line starts array */ + if ( lineDelta < 0 && -lineDelta < nVisLines ) { + for ( i = nVisLines - 1; i >= -lineDelta; i-- ) + lineStarts[ i ] = lineStarts[ i + lineDelta ]; + calc_line_starts( 0, -lineDelta ); + } else if ( lineDelta > 0 && lineDelta < nVisLines ) { + for ( i = 0; i < nVisLines - lineDelta; i++ ) + lineStarts[ i ] = lineStarts[ i + lineDelta ]; + calc_line_starts( nVisLines - lineDelta, nVisLines - 1 ); + } else + calc_line_starts( 0, nVisLines ); + + /* Set lastChar and mTopLineNum */ + calc_last_char(); + mTopLineNum = newTopLineNum; + + /* If we're numbering lines or being asked to maintain an absolute line + number, re-calculate the absolute line number */ + absolute_top_line_number(oldFirstChar); +} + +/* +** Update the line starts array, mTopLineNum, mFirstChar and lastChar for text +** display "textD" after a modification to the text buffer, given by the +** position where the change began "pos", and the nmubers of characters +** and lines inserted and deleted. +*/ +void Fl_Text_Display::update_line_starts( int pos, int charsInserted, + int charsDeleted, int linesInserted, int linesDeleted, int *scrolled ) { + int * lineStarts = mLineStarts; + int i, lineOfPos, lineOfEnd, nVisLines = mNVisibleLines; + int charDelta = charsInserted - charsDeleted; + int lineDelta = linesInserted - linesDeleted; + + /* If all of the changes were before the displayed text, the display + doesn't change, just update the top line num and offset the line + start entries and first and last characters */ + if ( pos + charsDeleted < mFirstChar ) { + mTopLineNum += lineDelta; + for ( i = 0; i < nVisLines && lineStarts[i] != -1; i++ ) + lineStarts[ i ] += charDelta; + mFirstChar += charDelta; + mLastChar += charDelta; + *scrolled = 0; + return; + } + + /* The change began before the beginning of the displayed text, but + part or all of the displayed text was deleted */ + if ( pos < mFirstChar ) { + /* If some text remains in the window, anchor on that */ + if ( position_to_line( pos + charsDeleted, &lineOfEnd ) && + ++lineOfEnd < nVisLines && lineStarts[ lineOfEnd ] != -1 ) { + mTopLineNum = max( 1, mTopLineNum + lineDelta ); + mFirstChar = rewind_lines( + lineStarts[ lineOfEnd ] + charDelta, lineOfEnd ); + /* Otherwise anchor on original line number and recount everything */ + } else { + if ( mTopLineNum > mNBufferLines + lineDelta ) { + mTopLineNum = 1; + mFirstChar = 0; + } else + mFirstChar = skip_lines( 0, mTopLineNum - 1, true ); + } + calc_line_starts( 0, nVisLines - 1 ); + /* calculate lastChar by finding the end of the last displayed line */ + calc_last_char(); + *scrolled = 1; + return; + } + + /* If the change was in the middle of the displayed text (it usually is), + salvage as much of the line starts array as possible by moving and + offsetting the entries after the changed area, and re-counting the + added lines or the lines beyond the salvaged part of the line starts + array */ + if ( pos <= mLastChar ) { + /* find line on which the change began */ + position_to_line( pos, &lineOfPos ); + /* salvage line starts after the changed area */ + if ( lineDelta == 0 ) { + for ( i = lineOfPos + 1; i < nVisLines && lineStarts[ i ] != -1; i++ ) + lineStarts[ i ] += charDelta; + } else if ( lineDelta > 0 ) { + for ( i = nVisLines - 1; i >= lineOfPos + lineDelta + 1; i-- ) + lineStarts[ i ] = lineStarts[ i - lineDelta ] + + ( lineStarts[ i - lineDelta ] == -1 ? 0 : charDelta ); + } else /* (lineDelta < 0) */ { + for ( i = max( 0, lineOfPos + 1 ); i < nVisLines + lineDelta; i++ ) + lineStarts[ i ] = lineStarts[ i - lineDelta ] + + ( lineStarts[ i - lineDelta ] == -1 ? 0 : charDelta ); + } + /* fill in the missing line starts */ + if ( linesInserted >= 0 ) + calc_line_starts( lineOfPos + 1, lineOfPos + linesInserted ); + if ( lineDelta < 0 ) + calc_line_starts( nVisLines + lineDelta, nVisLines ); + /* calculate lastChar by finding the end of the last displayed line */ + calc_last_char(); + *scrolled = 0; + return; + } + + /* Change was past the end of the displayed text, but displayable by virtue + of being an insert at the end of the buffer into visible blank lines */ + if ( empty_vlines() ) { + position_to_line( pos, &lineOfPos ); + calc_line_starts( lineOfPos, lineOfPos + linesInserted ); + calc_last_char(); + *scrolled = 0; + return; + } + + /* Change was beyond the end of the buffer and not visible, do nothing */ + *scrolled = 0; +} + +/* +** Scan through the text in the "textD"'s buffer and recalculate the line +** starts array values beginning at index "startLine" and continuing through +** (including) "endLine". It assumes that the line starts entry preceding +** "startLine" (or mFirstChar if startLine is 0) is good, and re-counts +** newlines to fill in the requested entries. Out of range values for +** "startLine" and "endLine" are acceptable. +*/ +void Fl_Text_Display::calc_line_starts( int startLine, int endLine ) { + int startPos, bufLen = mBuffer->length(); + int line, lineEnd, nextLineStart, nVis = mNVisibleLines; + int *lineStarts = mLineStarts; + + /* Clean up (possibly) messy input parameters */ + if ( endLine < 0 ) endLine = 0; + if ( endLine >= nVis ) endLine = nVis - 1; + if ( startLine < 0 ) startLine = 0; + if ( startLine >= nVis ) startLine = nVis - 1; + if ( startLine > endLine ) + return; + + /* Find the last known good line number -> position mapping */ + if ( startLine == 0 ) { + lineStarts[ 0 ] = mFirstChar; + startLine = 1; + } + startPos = lineStarts[ startLine - 1 ]; + + /* If the starting position is already past the end of the text, + fill in -1's (means no text on line) and return */ + if ( startPos == -1 ) { + for ( line = startLine; line <= endLine; line++ ) + lineStarts[ line ] = -1; + return; + } + + /* Loop searching for ends of lines and storing the positions of the + start of the next line in lineStarts */ + for ( line = startLine; line <= endLine; line++ ) { + find_line_end(startPos, true, &lineEnd, &nextLineStart); + startPos = nextLineStart; + if ( startPos >= bufLen ) { + /* If the buffer ends with a newline or line break, put + buf->length() in the next line start position (instead of + a -1 which is the normal marker for an empty line) to + indicate that the cursor may safely be displayed there */ + if ( line == 0 || ( lineStarts[ line - 1 ] != bufLen && + lineEnd != nextLineStart ) ) { + lineStarts[ line ] = bufLen; + line++; + } + break; + } + lineStarts[ line ] = startPos; + } + + /* Set any entries beyond the end of the text to -1 */ + for ( ; line <= endLine; line++ ) + lineStarts[ line ] = -1; +} + +/* +** Given a Fl_Text_Display with a complete, up-to-date lineStarts array, update +** the lastChar entry to point to the last buffer position displayed. +*/ +void Fl_Text_Display::calc_last_char() { + int i; + for (i = mNVisibleLines - 1; i >= 0 && mLineStarts[i] == -1; i--) ; + mLastChar = i < 0 ? 0 : line_end(mLineStarts[i], true); +} + +void Fl_Text_Display::scroll(int topLineNum, int horizOffset) { + mTopLineNumHint = topLineNum; + mHorizOffsetHint = horizOffset; + resize(x(), y(), w(), h()); +} + +void Fl_Text_Display::scroll_(int topLineNum, int horizOffset) { + /* Limit the requested scroll position to allowable values */ + if (topLineNum > mNBufferLines + 3 - mNVisibleLines) + topLineNum = mNBufferLines + 3 - mNVisibleLines; + if (topLineNum < 1) topLineNum = 1; + + if (horizOffset > longest_vline() - text_area.w) + horizOffset = longest_vline() - text_area.w; + if (horizOffset < 0) horizOffset = 0; + + /* Do nothing if scroll position hasn't actually changed or there's no + window to draw in yet */ + if (mHorizOffset == horizOffset && mTopLineNum == topLineNum) + return; + + /* If the vertical scroll position has changed, update the line + starts array and related counters in the text display */ + offset_line_starts(topLineNum); + + /* Just setting mHorizOffset is enough information for redisplay */ + mHorizOffset = horizOffset; + + // redraw all text + damage(FL_DAMAGE_EXPOSE); +} + +/* +** Update the minimum, maximum, slider size, page increment, and value +** for vertical scroll bar. +*/ +void Fl_Text_Display::update_v_scrollbar() { + /* The Vert. scroll bar value and slider size directly represent the top + line number, and the number of visible lines respectively. The scroll + bar maximum value is chosen to generally represent the size of the whole + buffer, with minor adjustments to keep the scroll bar widget happy */ +#ifdef DEBUG + printf("Fl_Text_Display::update_v_scrollbar():\n" + " mTopLineNum=%d, mNVisibleLines=%d, mNBufferLines=%d\n", + mTopLineNum, mNVisibleLines, mNBufferLines); +#endif // DEBUG + + mVScrollBar->value(mTopLineNum, mNVisibleLines, 1, mNBufferLines+2); + mVScrollBar->linesize(3); +} + +/* +** Update the minimum, maximum, slider size, page increment, and value +** for the horizontal scroll bar. +*/ +void Fl_Text_Display::update_h_scrollbar() { + int sliderMax = max(longest_vline(), text_area.w + mHorizOffset); + mHScrollBar->value( mHorizOffset, text_area.w, 0, sliderMax ); +} + +/* +** Callbacks for drag or valueChanged on scroll bars +*/ +void Fl_Text_Display::v_scrollbar_cb(Fl_Scrollbar* b, Fl_Text_Display* textD) { + if (b->value() == textD->mTopLineNum) return; + textD->scroll(b->value(), textD->mHorizOffset); +} + +void Fl_Text_Display::h_scrollbar_cb(Fl_Scrollbar* b, Fl_Text_Display* textD) { + if (b->value() == textD->mHorizOffset) return; + textD->scroll(textD->mTopLineNum, b->value()); +} + +/* +** Refresh the line number area. If clearAll is False, writes only over +** the character cell areas. Setting clearAll to True will clear out any +** stray marks outside of the character cell area, which might have been +** left from before a resize or font change. +*/ +void Fl_Text_Display::draw_line_numbers(bool /*clearAll*/) { +#if 0 + // FIXME: don't want this yet, so will leave for another time + + int y, line, visLine, nCols, lineStart; + char lineNumString[12]; + int lineHeight = mMaxsize ? mMaxsize : textsize_; + int charWidth = TMPFONTWIDTH; //mFontStruct->max_bounds.width; + + /* Don't draw if mLineNumWidth == 0 (line numbers are hidden), or widget is + not yet realized */ + if (mLineNumWidth == 0 || visible_r()) + return; + + /* GC is allocated on demand, since not everyone will use line numbering */ + if (textD->lineNumGC == NULL) { + XGCValues values; + values.foreground = textD->lineNumFGPixel; + values.background = textD->bgPixel; + values.font = textD->fontStruct->fid; + textD->lineNumGC = XtGetGC(textD->w, + GCFont| GCForeground | GCBackground, &values); + } + + /* Erase the previous contents of the line number area, if requested */ + if (clearAll) + XClearArea(XtDisplay(textD->w), XtWindow(textD->w), textD->lineNumLeft, + textD->top, textD->lineNumWidth, textD->height, False); + + /* Draw the line numbers, aligned to the text */ + nCols = min(11, textD->lineNumWidth / charWidth); + y = textD->top; + line = getAbsTopLineNum(textD); + for (visLine=0; visLine < textD->nVisibleLines; visLine++) { + lineStart = textD->lineStarts[visLine]; + if (lineStart != -1 && (lineStart==0 || + BufGetCharacter(textD->buffer, lineStart-1)=='\n')) { + sprintf(lineNumString, "%*d", nCols, line); + XDrawImageString(XtDisplay(textD->w), XtWindow(textD->w), + textD->lineNumGC, textD->lineNumLeft, y + textD->ascent, + lineNumString, strlen(lineNumString)); + line++; + } else { + XClearArea(XtDisplay(textD->w), XtWindow(textD->w), + textD->lineNumLeft, y, textD->lineNumWidth, + textD->ascent + textD->descent, False); + if (visLine == 0) + line++; + } + y += lineHeight; + } +#endif +} + +static int max( int i1, int i2 ) { + return i1 >= i2 ? i1 : i2; +} + +static int min( int i1, int i2 ) { + return i1 <= i2 ? i1 : i2; +} + +/* +** Count the number of newlines in a null-terminated text string; +*/ +static int countlines( const char *string ) { + const char * c; + int lineCount = 0; + + if (!string) return 0; + + for ( c = string; *c != '\0'; c++ ) + if ( *c == '\n' ) lineCount++; + return lineCount; +} + +/* +** Return the width in pixels of the displayed line pointed to by "visLineNum" +*/ +int Fl_Text_Display::measure_vline( int visLineNum ) { + int i, width = 0, len, style, lineLen = vline_length( visLineNum ); + int charCount = 0, lineStartPos = mLineStarts[ visLineNum ]; + char expandedChar[ FL_TEXT_MAX_EXP_CHAR_LEN ]; + + if (lineStartPos < 0 || lineLen == 0) return 0; + if ( mStyleBuffer == NULL ) { + for ( i = 0; i < lineLen; i++ ) { + len = mBuffer->expand_character( lineStartPos + i, + charCount, expandedChar ); + + fl_font( textfont(), textsize() ); + + width += ( int ) fl_width( expandedChar, len ); + + charCount += len; + } + } else { + for ( i = 0; i < lineLen; i++ ) { + len = mBuffer->expand_character( lineStartPos + i, + charCount, expandedChar ); + style = ( unsigned char ) mStyleBuffer->character( + lineStartPos + i ) - 'A'; + + if (style < 0) style = 0; + else if (style >= mNStyles) style = mNStyles - 1; + + fl_font( mStyleTable[ style ].font, mStyleTable[ style ].size ); + + width += ( int ) fl_width( expandedChar, len ); + + charCount += len; + } + } + return width; +} + +/* +** Return true if there are lines visible with no corresponding buffer text +*/ +int Fl_Text_Display::empty_vlines() { + return mNVisibleLines > 0 && + mLineStarts[ mNVisibleLines - 1 ] == -1; +} + +/* +** Return the length of a line (number of displayable characters) by examining +** entries in the line starts array rather than by scanning for newlines +*/ +int Fl_Text_Display::vline_length( int visLineNum ) { + int nextLineStart, lineStartPos; + + if (visLineNum < 0 || visLineNum >= mNVisibleLines) + return (0); + + lineStartPos = mLineStarts[ visLineNum ]; + + if ( lineStartPos == -1 ) + return 0; + if ( visLineNum + 1 >= mNVisibleLines ) + return mLastChar - lineStartPos; + nextLineStart = mLineStarts[ visLineNum + 1 ]; + if ( nextLineStart == -1 ) + return mLastChar - lineStartPos; + if (wrap_uses_character(nextLineStart-1)) + return nextLineStart-1 - lineStartPos; + return nextLineStart - lineStartPos; +} + +/* +** When continuous wrap is on, and the user inserts or deletes characters, +** wrapping can happen before and beyond the changed position. This routine +** finds the extent of the changes, and counts the deleted and inserted lines +** over that range. It also attempts to minimize the size of the range to +** what has to be counted and re-displayed, so the results can be useful +** both for delimiting where the line starts need to be recalculated, and +** for deciding what part of the text to redisplay. +*/ +void Fl_Text_Display::find_wrap_range(const char *deletedText, int pos, + int nInserted, int nDeleted, int *modRangeStart, int *modRangeEnd, + int *linesInserted, int *linesDeleted) { + int length, retPos, retLines, retLineStart, retLineEnd; + Fl_Text_Buffer *deletedTextBuf, *buf = buffer(); + int nVisLines = mNVisibleLines; + int *lineStarts = mLineStarts; + int countFrom, countTo, lineStart, adjLineStart, i; + int visLineNum = 0, nLines = 0; + + /* + ** Determine where to begin searching: either the previous newline, or + ** if possible, limit to the start of the (original) previous displayed + ** line, using information from the existing line starts array + */ + if (pos >= mFirstChar && pos <= mLastChar) { + for (i=nVisLines-1; i>0; i--) + if (lineStarts[i] != -1 && pos >= lineStarts[i]) + break; + if (i > 0) { + countFrom = lineStarts[i-1]; + visLineNum = i-1; + } else + countFrom = buf->line_start(pos); + } else + countFrom = buf->line_start(pos); + + + /* + ** Move forward through the (new) text one line at a time, counting + ** displayed lines, and looking for either a real newline, or for the + ** line starts to re-sync with the original line starts array + */ + lineStart = countFrom; + *modRangeStart = countFrom; + for (;;) { + + /* advance to the next line. If the line ended in a real newline + or the end of the buffer, that's far enough */ + wrapped_line_counter(buf, lineStart, buf->length(), 1, true, 0, + &retPos, &retLines, &retLineStart, &retLineEnd); + if (retPos >= buf->length()) { + countTo = buf->length(); + *modRangeEnd = countTo; + if (retPos != retLineEnd) + nLines++; + break; + } else + lineStart = retPos; + nLines++; + if (lineStart > pos + nInserted && + buf->character(lineStart-1) == '\n') { + countTo = lineStart; + *modRangeEnd = lineStart; + break; + } + + /* Don't try to resync in continuous wrap mode with non-fixed font + sizes; it would result in a chicken-and-egg dependency between + the calculations for the inserted and the deleted lines. + If we're in that mode, the number of deleted lines is calculated in + advance, without resynchronization, so we shouldn't resynchronize + for the inserted lines either. */ + if (mSuppressResync) + continue; + + /* check for synchronization with the original line starts array + before pos, if so, the modified range can begin later */ + if (lineStart <= pos) { + while (visLineNum pos + nInserted) { + adjLineStart = lineStart - nInserted + nDeleted; + while (visLineNumcopy(buffer(), countFrom, pos, 0); + if (nDeleted != 0) + deletedTextBuf->insert(pos-countFrom, deletedText); + deletedTextBuf->copy(buffer(), + pos+nInserted, countTo, pos-countFrom+nDeleted); + /* Note that we need to take into account an offset for the style buffer: + the deletedTextBuf can be out of sync with the style buffer. */ + wrapped_line_counter(deletedTextBuf, 0, length, INT_MAX, true, + countFrom, &retPos, &retLines, &retLineStart, &retLineEnd, false); + delete deletedTextBuf; + *linesDeleted = retLines; + mSuppressResync = 0; +} + +/* +** This is a stripped-down version of the findWrapRange() function above, +** intended to be used to calculate the number of "deleted" lines during +** a buffer modification. It is called _before_ the modification takes place. +** +** This function should only be called in continuous wrap mode with a +** non-fixed font width. In that case, it is impossible to calculate +** the number of deleted lines, because the necessary style information +** is no longer available _after_ the modification. In other cases, we +** can still perform the calculation afterwards (possibly even more +** efficiently). +*/ +void Fl_Text_Display::measure_deleted_lines(int pos, int nDeleted) { + int retPos, retLines, retLineStart, retLineEnd; + Fl_Text_Buffer *buf = buffer(); + int nVisLines = mNVisibleLines; + int *lineStarts = mLineStarts; + int countFrom, lineStart; + int nLines = 0, i; + /* + ** Determine where to begin searching: either the previous newline, or + ** if possible, limit to the start of the (original) previous displayed + ** line, using information from the existing line starts array + */ + if (pos >= mFirstChar && pos <= mLastChar) { + for (i=nVisLines-1; i>0; i--) + if (lineStarts[i] != -1 && pos >= lineStarts[i]) + break; + if (i > 0) countFrom = lineStarts[i-1]; + else countFrom = buf->line_start(pos); + } else + countFrom = buf->line_start(pos); + + /* + ** Move forward through the (new) text one line at a time, counting + ** displayed lines, and looking for either a real newline, or for the + ** line starts to re-sync with the original line starts array + */ + lineStart = countFrom; + for (;;) { + /* advance to the next line. If the line ended in a real newline + or the end of the buffer, that's far enough */ + wrapped_line_counter(buf, lineStart, buf->length(), 1, true, 0, + &retPos, &retLines, &retLineStart, &retLineEnd); + if (retPos >= buf->length()) { + if (retPos != retLineEnd) + nLines++; + break; + } else + lineStart = retPos; + nLines++; + if (lineStart > pos + nDeleted && + buf->character(lineStart-1) == '\n') { + break; + } + + /* Unlike in the findWrapRange() function above, we don't try to + resync with the line starts, because we don't know the length + of the inserted text yet, nor the updated style information. + + Because of that, we also shouldn't resync with the line starts + after the modification either, because we must perform the + calculations for the deleted and inserted lines in the same way. + + This can result in some unnecessary recalculation and redrawing + overhead, and therefore we should only use this two-phase mode + of calculation when it's really needed (continuous wrap + variable + font width). */ + } + mNLinesDeleted = nLines; + mSuppressResync = 1; +} + +/* +** Count forward from startPos to either maxPos or maxLines (whichever is +** reached first), and return all relevant positions and line count. +** The provided textBuffer may differ from the actual text buffer of the +** widget. In that case it must be a (partial) copy of the actual text buffer +** and the styleBufOffset argument must indicate the starting position of the +** copy, to take into account the correct style information. +** +** Returned values: +** +** retPos: Position where counting ended. When counting lines, the +** position returned is the start of the line "maxLines" +** lines beyond "startPos". +** retLines: Number of line breaks counted +** retLineStart: Start of the line where counting ended +** retLineEnd: End position of the last line traversed +*/ +void Fl_Text_Display::wrapped_line_counter(Fl_Text_Buffer *buf, int startPos, + int maxPos, int maxLines, bool startPosIsLineStart, int styleBufOffset, + int *retPos, int *retLines, int *retLineStart, int *retLineEnd, + bool countLastLineMissingNewLine) { + int lineStart, newLineStart = 0, b, p, colNum, wrapMargin; + int maxWidth, i, foundBreak, width; + bool countPixels; + int nLines = 0, tabDist = buffer()->tab_distance(); + unsigned char c; + char nullSubsChar = buffer()->null_substitution_character(); + + /* If the font is fixed, or there's a wrap margin set, it's more efficient + to measure in columns, than to count pixels. Determine if we can count + in columns (countPixels == False) or must count pixels (countPixels == + True), and set the wrap target for either pixels or columns */ + if (mFixedFontWidth != -1 || mWrapMargin != 0) { + countPixels = false; + wrapMargin = mWrapMargin ? mWrapMargin : text_area.w / (mFixedFontWidth + 1); + maxWidth = INT_MAX; + } else { + countPixels = true; + wrapMargin = INT_MAX; + maxWidth = text_area.w; + } + + /* Find the start of the line if the start pos is not marked as a + line start. */ + if (startPosIsLineStart) + lineStart = startPos; + else + lineStart = line_start(startPos); + + /* + ** Loop until position exceeds maxPos or line count exceeds maxLines. + ** (actually, contines beyond maxPos to end of line containing maxPos, + ** in case later characters cause a word wrap back before maxPos) + */ + colNum = 0; + width = 0; + for (p=lineStart; plength(); p++) { + c = (unsigned char)buf->character(p); + + /* If the character was a newline, count the line and start over, + otherwise, add it to the width and column counts */ + if (c == '\n') { + if (p >= maxPos) { + *retPos = maxPos; + *retLines = nLines; + *retLineStart = lineStart; + *retLineEnd = maxPos; + return; + } + nLines++; + if (nLines >= maxLines) { + *retPos = p + 1; + *retLines = nLines; + *retLineStart = p + 1; + *retLineEnd = p; + return; + } + lineStart = p + 1; + colNum = 0; + width = 0; + } else { + colNum += Fl_Text_Buffer::character_width(c, colNum, tabDist, nullSubsChar); + if (countPixels) + width += measure_proportional_character(c, colNum, p+styleBufOffset); + } + + /* If character exceeded wrap margin, find the break point + and wrap there */ + if (colNum > wrapMargin || width > maxWidth) { + foundBreak = false; + for (b=p; b>=lineStart; b--) { + c = (unsigned char)buf->character(b); + if (c == '\t' || c == ' ') { + newLineStart = b + 1; + if (countPixels) { + colNum = 0; + width = 0; + for (i=b+1; icharacter(i), colNum, + i+styleBufOffset); + colNum++; + } + } else + colNum = buf->count_displayed_characters(b+1, p+1); + foundBreak = true; + break; + } + } + if (!foundBreak) { /* no whitespace, just break at margin */ + newLineStart = max(p, lineStart+1); + colNum = Fl_Text_Buffer::character_width(c, colNum, tabDist, nullSubsChar); + if (countPixels) + width = measure_proportional_character(c, colNum, p+styleBufOffset); + } + if (p >= maxPos) { + *retPos = maxPos; + *retLines = maxPos < newLineStart ? nLines : nLines + 1; + *retLineStart = maxPos < newLineStart ? lineStart : + newLineStart; + *retLineEnd = maxPos; + return; + } + nLines++; + if (nLines >= maxLines) { + *retPos = foundBreak ? b + 1 : max(p, lineStart+1); + *retLines = nLines; + *retLineStart = lineStart; + *retLineEnd = foundBreak ? b : p; + return; + } + lineStart = newLineStart; + } + } + + /* reached end of buffer before reaching pos or line target */ + *retPos = buf->length(); + *retLines = nLines; + if (countLastLineMissingNewLine && colNum > 0) + ++(*retLines); + *retLineStart = lineStart; + *retLineEnd = buf->length(); +} + +/* +** Measure the width in pixels of a character "c" at a particular column +** "colNum" and buffer position "pos". This is for measuring characters in +** proportional or mixed-width highlighting fonts. +** +** A note about proportional and mixed-width fonts: the mixed width and +** proportional font code in nedit does not get much use in general editing, +** because nedit doesn't allow per-language-mode fonts, and editing programs +** in a proportional font is usually a bad idea, so very few users would +** choose a proportional font as a default. There are still probably mixed- +** width syntax highlighting cases where things don't redraw properly for +** insertion/deletion, though static display and wrapping and resizing +** should now be solid because they are now used for online help display. +*/ +int Fl_Text_Display::measure_proportional_character(char c, int colNum, int pos) { + int charLen, style; + char expChar[ FL_TEXT_MAX_EXP_CHAR_LEN ]; + Fl_Text_Buffer *styleBuf = mStyleBuffer; + + charLen = Fl_Text_Buffer::expand_character(c, colNum, expChar, + buffer()->tab_distance(), buffer()->null_substitution_character()); + if (styleBuf == 0) { + style = 0; + } else { + style = (unsigned char)styleBuf->character(pos); + if (style == mUnfinishedStyle && mUnfinishedHighlightCB) { + /* encountered "unfinished" style, trigger parsing */ + (mUnfinishedHighlightCB)(pos, mHighlightCBArg); + style = (unsigned char)styleBuf->character(pos); + } + } + return string_width(expChar, charLen, style); +} + +/* +** Finds both the end of the current line and the start of the next line. Why? +** In continuous wrap mode, if you need to know both, figuring out one from the +** other can be expensive or error prone. The problem comes when there's a +** trailing space or tab just before the end of the buffer. To translate an +** end of line value to or from the next lines start value, you need to know +** whether the trailing space or tab is being used as a line break or just a +** normal character, and to find that out would otherwise require counting all +** the way back to the beginning of the line. +*/ +void Fl_Text_Display::find_line_end(int startPos, bool startPosIsLineStart, + int *lineEnd, int *nextLineStart) { + int retLines, retLineStart; + + /* if we're not wrapping use more efficient BufEndOfLine */ + if (!mContinuousWrap) { + *lineEnd = buffer()->line_end(startPos); + *nextLineStart = min(buffer()->length(), *lineEnd + 1); + return; + } + + /* use the wrapped line counter routine to count forward one line */ + wrapped_line_counter(buffer(), startPos, buffer()->length(), + 1, startPosIsLineStart, 0, nextLineStart, &retLines, + &retLineStart, lineEnd); + return; +} + +/* +** Line breaks in continuous wrap mode usually happen at newlines or +** whitespace. This line-terminating character is not included in line +** width measurements and has a special status as a non-visible character. +** However, lines with no whitespace are wrapped without the benefit of a +** line terminating character, and this distinction causes endless trouble +** with all of the text display code which was originally written without +** continuous wrap mode and always expects to wrap at a newline character. +** +** Given the position of the end of the line, as returned by TextDEndOfLine +** or BufEndOfLine, this returns true if there is a line terminating +** character, and false if there's not. On the last character in the +** buffer, this function can't tell for certain whether a trailing space was +** used as a wrap point, and just guesses that it wasn't. So if an exact +** accounting is necessary, don't use this function. +*/ +int Fl_Text_Display::wrap_uses_character(int lineEndPos) { + char c; + + if (!mContinuousWrap || lineEndPos == buffer()->length()) + return 1; + + c = buffer()->character(lineEndPos); + return c == '\n' || ((c == '\t' || c == ' ') && + lineEndPos + 1 != buffer()->length()); +} + +/* +** Return true if the selection "sel" is rectangular, and touches a +** buffer position withing "rangeStart" to "rangeEnd" +*/ +int Fl_Text_Display::range_touches_selection(Fl_Text_Selection *sel, + int rangeStart, int rangeEnd) { + return sel->selected() && sel->rectangular() && sel->end() >= rangeStart && + sel->start() <= rangeEnd; +} + +/* +** Extend the range of a redraw request (from *start to *end) with additional +** redraw requests resulting from changes to the attached style buffer (which +** contains auxiliary information for coloring or styling text). +*/ +void Fl_Text_Display::extend_range_for_styles( int *startpos, int *endpos ) { + Fl_Text_Selection * sel = mStyleBuffer->primary_selection(); + int extended = 0; + + /* The peculiar protocol used here is that modifications to the style + buffer are marked by selecting them with the buffer's primary Fl_Text_Selection. + The style buffer is usually modified in response to a modify callback on + the text buffer BEFORE Fl_Text_Display.c's modify callback, so that it can keep + the style buffer in step with the text buffer. The style-update + callback can't just call for a redraw, because Fl_Text_Display hasn't processed + the original text changes yet. Anyhow, to minimize redrawing and to + avoid the complexity of scheduling redraws later, this simple protocol + tells the text display's buffer modify callback to extend it's redraw + range to show the text color/and font changes as well. */ + if ( sel->selected() ) { + if ( sel->start() < *startpos ) { + *startpos = sel->start(); + extended = 1; + } + if ( sel->end() > *endpos ) { + *endpos = sel->end(); + extended = 1; + } + } + + /* If the Fl_Text_Selection was extended due to a style change, and some of the + fonts don't match in spacing, extend redraw area to end of line to + redraw characters exposed by possible font size changes */ + if ( mFixedFontWidth == -1 && extended ) + *endpos = mBuffer->line_end( *endpos ) + 1; +} + +// The draw() method. It tries to minimize what is draw as much as possible. +void Fl_Text_Display::draw(void) { + // don't even try if there is no associated text buffer! + if (!buffer()) { draw_box(); return; } + + fl_push_clip(x(),y(),w(),h()); // prevent drawing outside widget area + + // draw the non-text, non-scrollbar areas. + if (damage() & FL_DAMAGE_ALL) { +// printf("drawing all (box = %d)\n", box()); + // draw the box() + int W = w(), H = h(); + draw_box(box(), x(), y(), W, H, color()); + + if (mHScrollBar->visible()) + W -= scrollbar_width(); + if (mVScrollBar->visible()) + H -= scrollbar_width(); + + // left margin + fl_rectf(text_area.x-LEFT_MARGIN, text_area.y-TOP_MARGIN, + LEFT_MARGIN, text_area.h+TOP_MARGIN+BOTTOM_MARGIN, + color()); + + // right margin + fl_rectf(text_area.x+text_area.w, text_area.y-TOP_MARGIN, + RIGHT_MARGIN, text_area.h+TOP_MARGIN+BOTTOM_MARGIN, + color()); + + // top margin + fl_rectf(text_area.x, text_area.y-TOP_MARGIN, + text_area.w, TOP_MARGIN, color()); + + // bottom margin + fl_rectf(text_area.x, text_area.y+text_area.h, + text_area.w, BOTTOM_MARGIN, color()); + + // draw that little box in the corner of the scrollbars + if (mVScrollBar->visible() && mHScrollBar->visible()) + fl_rectf(mVScrollBar->x(), mHScrollBar->y(), + mVScrollBar->w(), mHScrollBar->h(), + FL_GRAY); + + // blank the previous cursor protrusions + } + else if (damage() & (FL_DAMAGE_SCROLL | FL_DAMAGE_EXPOSE)) { +// printf("blanking previous cursor extrusions at Y: %d\n", mCursorOldY); + // CET - FIXME - save old cursor position instead and just draw side needed? + fl_push_clip(text_area.x-LEFT_MARGIN, + text_area.y, + text_area.w+LEFT_MARGIN+RIGHT_MARGIN, + text_area.h); + fl_rectf(text_area.x-LEFT_MARGIN, mCursorOldY, + LEFT_MARGIN, mMaxsize, color()); + fl_rectf(text_area.x+text_area.w, mCursorOldY, + RIGHT_MARGIN, mMaxsize, color()); + fl_pop_clip(); + } + + // draw the scrollbars + if (damage() & (FL_DAMAGE_ALL | FL_DAMAGE_CHILD)) { + mVScrollBar->damage(FL_DAMAGE_ALL); + mHScrollBar->damage(FL_DAMAGE_ALL); + } + update_child(*mVScrollBar); + update_child(*mHScrollBar); + + // draw all of the text + if (damage() & (FL_DAMAGE_ALL | FL_DAMAGE_EXPOSE)) { + //printf("drawing all text\n"); + int X, Y, W, H; + if (fl_clip_box(text_area.x, text_area.y, text_area.w, text_area.h, + X, Y, W, H)) { + // Draw text using the intersected clipping box... + // (this sets the clipping internally) + draw_text(X, Y, W, H); + } else { + // Draw the whole area... + draw_text(text_area.x, text_area.y, text_area.w, text_area.h); + } + } + else if (damage() & FL_DAMAGE_SCROLL) { + // draw some lines of text + fl_push_clip(text_area.x, text_area.y, + text_area.w, text_area.h); + //printf("drawing text from %d to %d\n", damage_range1_start, damage_range1_end); + draw_range(damage_range1_start, damage_range1_end); + if (damage_range2_end != -1) { + //printf("drawing text from %d to %d\n", damage_range2_start, damage_range2_end); + draw_range(damage_range2_start, damage_range2_end); + } + damage_range1_start = damage_range1_end = -1; + damage_range2_start = damage_range2_end = -1; + fl_pop_clip(); + } + + // draw the text cursor + if (damage() & (FL_DAMAGE_ALL | FL_DAMAGE_SCROLL | FL_DAMAGE_EXPOSE) + && !buffer()->primary_selection()->selected() && + mCursorOn && Fl::focus() == this ) { + fl_push_clip(text_area.x-LEFT_MARGIN, + text_area.y, + text_area.w+LEFT_MARGIN+RIGHT_MARGIN, + text_area.h); + + int X, Y; + if (position_to_xy(mCursorPos, &X, &Y)) draw_cursor(X, Y); +// else puts("position_to_xy() failed - unable to draw cursor!"); + //printf("drew cursor at pos: %d (%d,%d)\n", mCursorPos, X, Y); + mCursorOldY = Y; + fl_pop_clip(); + } + fl_pop_clip(); +} + +// this processes drag events due to mouse for Fl_Text_Display and +// also drags due to cursor movement with shift held down for +// Fl_Text_Editor +void fl_text_drag_me(int pos, Fl_Text_Display* d) { + if (d->dragType == Fl_Text_Display::DRAG_CHAR) { + if (pos >= d->dragPos) { + d->buffer()->select(d->dragPos, pos); + } else { + d->buffer()->select(pos, d->dragPos); + } + d->insert_position(pos); + } else if (d->dragType == Fl_Text_Display::DRAG_WORD) { + if (pos >= d->dragPos) { + d->insert_position(d->word_end(pos)); + d->buffer()->select(d->word_start(d->dragPos), d->word_end(pos)); + } else { + d->insert_position(d->word_start(pos)); + d->buffer()->select(d->word_start(pos), d->word_end(d->dragPos)); + } + } else if (d->dragType == Fl_Text_Display::DRAG_LINE) { + if (pos >= d->dragPos) { + d->insert_position(d->buffer()->line_end(pos)+1); + d->buffer()->select(d->buffer()->line_start(d->dragPos), + d->buffer()->line_end(pos)+1); + } else { + d->insert_position(d->buffer()->line_start(pos)); + d->buffer()->select(d->buffer()->line_start(pos), + d->buffer()->line_end(d->dragPos)+1); + } + } +} + +// This timer event scrolls the text view proportionally to +// how far the mouse pointer has left the text area. This +// allows for smooth scrolling without "wiggeling" the mouse. +void Fl_Text_Display::scroll_timer_cb(void *user_data) { + Fl_Text_Display *w = (Fl_Text_Display*)user_data; + int pos; + switch (scroll_direction) { + case 1: // mouse is to the right, scroll left + w->scroll(w->mTopLineNum, w->mHorizOffset + scroll_amount); + pos = w->xy_to_position(w->text_area.x + w->text_area.w, scroll_y, CURSOR_POS); + break; + case 2: // mouse is to the left, scroll right + w->scroll(w->mTopLineNum, w->mHorizOffset + scroll_amount); + pos = w->xy_to_position(w->text_area.x, scroll_y, CURSOR_POS); + break; + case 3: // mouse is above, scroll down + w->scroll(w->mTopLineNum + scroll_amount, w->mHorizOffset); + pos = w->xy_to_position(scroll_x, w->text_area.y, CURSOR_POS); + break; + case 4: // mouse is below, scroll up + w->scroll(w->mTopLineNum + scroll_amount, w->mHorizOffset); + pos = w->xy_to_position(scroll_x, w->text_area.y + w->text_area.h, CURSOR_POS); + break; + default: + return; + } + fl_text_drag_me(pos, w); + Fl::repeat_timeout(.1, scroll_timer_cb, user_data); +} + + +int Fl_Text_Display::handle(int event) { + if (!buffer()) return 0; + // This isn't very elegant! + if (!Fl::event_inside(text_area.x, text_area.y, text_area.w, text_area.h) && + !dragging && event != FL_LEAVE && event != FL_ENTER && + event != FL_MOVE && event != FL_FOCUS && event != FL_UNFOCUS && + event != FL_KEYBOARD && event != FL_KEYUP) { + return Fl_Group::handle(event); + } + + switch (event) { + case FL_ENTER: + case FL_MOVE: + if (active_r()) { + if (Fl::event_inside(text_area.x, text_area.y, text_area.w, + text_area.h)) window()->cursor(FL_CURSOR_INSERT); + else window()->cursor(FL_CURSOR_DEFAULT); + return 1; + } else { + return 0; + } + + case FL_LEAVE: + case FL_HIDE: + if (active_r() && window()) { + window()->cursor(FL_CURSOR_DEFAULT); + + return 1; + } else { + return 0; + } + + case FL_PUSH: { + if (active_r() && window()) { + if (Fl::event_inside(text_area.x, text_area.y, text_area.w, + text_area.h)) window()->cursor(FL_CURSOR_INSERT); + else window()->cursor(FL_CURSOR_DEFAULT); + } + + if (Fl::focus() != this) { + Fl::focus(this); + handle(FL_FOCUS); + } + if (Fl_Group::handle(event)) return 1; + if (Fl::event_state()&FL_SHIFT) return handle(FL_DRAG); + dragging = 1; + int pos = xy_to_position(Fl::event_x(), Fl::event_y(), CURSOR_POS); + dragType = Fl::event_clicks(); + dragPos = pos; + if (dragType == DRAG_CHAR) + buffer()->unselect(); + else if (dragType == DRAG_WORD) + buffer()->select(word_start(pos), word_end(pos)); + else if (dragType == DRAG_LINE) + buffer()->select(buffer()->line_start(pos), buffer()->line_end(pos)+1); + + if (buffer()->primary_selection()->selected()) + insert_position(buffer()->primary_selection()->end()); + else + insert_position(pos); + show_insert_position(); + return 1; + } + + case FL_DRAG: { + if (dragType < 0) return 1; + int X = Fl::event_x(), Y = Fl::event_y(), pos; + // if we leave the text_area, we start a timer event + // that will take care of scrolling and selecting + if (Y < text_area.y) { + scroll_x = X; + scroll_amount = (Y - text_area.y) / 5 - 1; + if (!scroll_direction) { + Fl::add_timeout(.01, scroll_timer_cb, this); + } + scroll_direction = 3; + } else if (Y >= text_area.y+text_area.h) { + scroll_x = X; + scroll_amount = (Y - text_area.y - text_area.h) / 5 + 1; + if (!scroll_direction) { + Fl::add_timeout(.01, scroll_timer_cb, this); + } + scroll_direction = 4; + } else if (X < text_area.x) { + scroll_y = Y; + scroll_amount = (X - text_area.x) / 2 - 1; + if (!scroll_direction) { + Fl::add_timeout(.01, scroll_timer_cb, this); + } + scroll_direction = 2; + } else if (X >= text_area.x+text_area.w) { + scroll_y = Y; + scroll_amount = (X - text_area.x - text_area.w) / 2 + 1; + if (!scroll_direction) { + Fl::add_timeout(.01, scroll_timer_cb, this); + } + scroll_direction = 1; + } else { + if (scroll_direction) { + Fl::remove_timeout(scroll_timer_cb, this); + scroll_direction = 0; + } + pos = xy_to_position(X, Y, CURSOR_POS); + fl_text_drag_me(pos, this); + } + return 1; + } + + case FL_RELEASE: { + dragging = 0; + if (scroll_direction) { + Fl::remove_timeout(scroll_timer_cb, this); + scroll_direction = 0; + } + + // convert from WORD or LINE selection to CHAR + if (insert_position() >= dragPos) + dragPos = buffer()->primary_selection()->start(); + else + dragPos = buffer()->primary_selection()->end(); + dragType = DRAG_CHAR; + + const char* copy = buffer()->selection_text(); + if (*copy) Fl::copy(copy, strlen(copy), 0); + free((void*)copy); + return 1; + } + + case FL_MOUSEWHEEL: + if (Fl::event_dy()) return mVScrollBar->handle(event); + else return mHScrollBar->handle(event); + + case FL_UNFOCUS: + if (active_r() && window()) window()->cursor(FL_CURSOR_DEFAULT); + case FL_FOCUS: + if (buffer()->selected()) { + int start, end; + if (buffer()->selection_position(&start, &end)) + redisplay_range(start, end); + } + if (buffer()->secondary_selected()) { + int start, end; + if (buffer()->secondary_selection_position(&start, &end)) + redisplay_range(start, end); + } + if (buffer()->highlight()) { + int start, end; + if (buffer()->highlight_position(&start, &end)) + redisplay_range(start, end); + } + return 1; + + case FL_KEYBOARD: + // Copy? + if ((Fl::event_state()&(FL_CTRL|FL_COMMAND)) && Fl::event_key()=='c') { + if (!buffer()->selected()) return 1; + const char *copy = buffer()->selection_text(); + if (*copy) Fl::copy(copy, strlen(copy), 1); + free((void*)copy); + return 1; + } + + // Select all ? + if ((Fl::event_state()&(FL_CTRL|FL_COMMAND)) && Fl::event_key()=='a') { + buffer()->select(0,buffer()->length()); + return 1; + } + + if (mVScrollBar->handle(event)) return 1; + if (mHScrollBar->handle(event)) return 1; + + break; + } + + return 0; +} + + +// +// End of "$Id: Fl_Text_Display.cxx 6105 2008-04-21 21:03:22Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Text_Editor.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Text_Editor.cxx new file mode 100644 index 0000000..4750896 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Text_Editor.cxx @@ -0,0 +1,492 @@ +// +// "$Id: Fl_Text_Editor.cxx 5671 2007-02-08 07:58:47Z matt $" +// +// Copyright 2001-2006 by Bill Spitzak and others. +// Original code Copyright Mark Edel. Permission to distribute under +// the LGPL for the FLTK library granted by Mark Edel. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include "flstring.h" +#include +#include +#include +#include +#include + + +Fl_Text_Editor::Fl_Text_Editor(int X, int Y, int W, int H, const char* l) + : Fl_Text_Display(X, Y, W, H, l) { + mCursorOn = 1; + insert_mode_ = 1; + key_bindings = 0; + + // handle the default key bindings + add_default_key_bindings(&key_bindings); + + // handle everything else + default_key_function(kf_default); +} + +Fl_Text_Editor::Key_Binding* Fl_Text_Editor::global_key_bindings = 0; + +// These are the default key bindings every widget should start with +static struct { + int key; + int state; + Fl_Text_Editor::Key_Func func; +} default_key_bindings[] = { + { FL_Escape, FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_ignore }, + { FL_Enter, FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_enter }, + { FL_KP_Enter, FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_enter }, + { FL_BackSpace, FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_backspace }, + { FL_Insert, FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_insert }, + { FL_Delete, FL_TEXT_EDITOR_ANY_STATE, Fl_Text_Editor::kf_delete }, + { FL_Home, 0, Fl_Text_Editor::kf_move }, + { FL_End, 0, Fl_Text_Editor::kf_move }, + { FL_Left, 0, Fl_Text_Editor::kf_move }, + { FL_Up, 0, Fl_Text_Editor::kf_move }, + { FL_Right, 0, Fl_Text_Editor::kf_move }, + { FL_Down, 0, Fl_Text_Editor::kf_move }, + { FL_Page_Up, 0, Fl_Text_Editor::kf_move }, + { FL_Page_Down, 0, Fl_Text_Editor::kf_move }, + { FL_Home, FL_SHIFT, Fl_Text_Editor::kf_shift_move }, + { FL_End, FL_SHIFT, Fl_Text_Editor::kf_shift_move }, + { FL_Left, FL_SHIFT, Fl_Text_Editor::kf_shift_move }, + { FL_Up, FL_SHIFT, Fl_Text_Editor::kf_shift_move }, + { FL_Right, FL_SHIFT, Fl_Text_Editor::kf_shift_move }, + { FL_Down, FL_SHIFT, Fl_Text_Editor::kf_shift_move }, + { FL_Page_Up, FL_SHIFT, Fl_Text_Editor::kf_shift_move }, + { FL_Page_Down, FL_SHIFT, Fl_Text_Editor::kf_shift_move }, + { FL_Home, FL_CTRL, Fl_Text_Editor::kf_ctrl_move }, + { FL_End, FL_CTRL, Fl_Text_Editor::kf_ctrl_move }, + { FL_Left, FL_CTRL, Fl_Text_Editor::kf_ctrl_move }, + { FL_Up, FL_CTRL, Fl_Text_Editor::kf_ctrl_move }, + { FL_Right, FL_CTRL, Fl_Text_Editor::kf_ctrl_move }, + { FL_Down, FL_CTRL, Fl_Text_Editor::kf_ctrl_move }, + { FL_Page_Up, FL_CTRL, Fl_Text_Editor::kf_ctrl_move }, + { FL_Page_Down, FL_CTRL, Fl_Text_Editor::kf_ctrl_move }, + { FL_Home, FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_c_s_move }, + { FL_End, FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_c_s_move }, + { FL_Left, FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_c_s_move }, + { FL_Up, FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_c_s_move }, + { FL_Right, FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_c_s_move }, + { FL_Down, FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_c_s_move }, + { FL_Page_Up, FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_c_s_move }, + { FL_Page_Down, FL_CTRL|FL_SHIFT, Fl_Text_Editor::kf_c_s_move }, +//{ FL_Clear, 0, Fl_Text_Editor::delete_to_eol }, + { 'z', FL_CTRL, Fl_Text_Editor::kf_undo }, + { '/', FL_CTRL, Fl_Text_Editor::kf_undo }, + { 'x', FL_CTRL, Fl_Text_Editor::kf_cut }, + { FL_Delete, FL_SHIFT, Fl_Text_Editor::kf_cut }, + { 'c', FL_CTRL, Fl_Text_Editor::kf_copy }, + { FL_Insert, FL_CTRL, Fl_Text_Editor::kf_copy }, + { 'v', FL_CTRL, Fl_Text_Editor::kf_paste }, + { FL_Insert, FL_SHIFT, Fl_Text_Editor::kf_paste }, + { 'a', FL_CTRL, Fl_Text_Editor::kf_select_all }, + +#ifdef __APPLE__ + // Define CMD+key accelerators... + { 'z', FL_COMMAND, Fl_Text_Editor::kf_undo }, + { 'x', FL_COMMAND, Fl_Text_Editor::kf_cut }, + { 'c', FL_COMMAND, Fl_Text_Editor::kf_copy }, + { 'v', FL_COMMAND, Fl_Text_Editor::kf_paste }, + { 'a', FL_COMMAND, Fl_Text_Editor::kf_select_all }, +#endif // __APPLE__ + + { 0, 0, 0 } +}; + +void Fl_Text_Editor::add_default_key_bindings(Key_Binding** list) { + for (int i = 0; default_key_bindings[i].key; i++) { + add_key_binding(default_key_bindings[i].key, + default_key_bindings[i].state, + default_key_bindings[i].func, + list); + } +} + +Fl_Text_Editor::Key_Func +Fl_Text_Editor::bound_key_function(int key, int state, Key_Binding* list) { + Key_Binding* cur; + for (cur = list; cur; cur = cur->next) + if (cur->key == key) + if (cur->state == FL_TEXT_EDITOR_ANY_STATE || cur->state == state) + break; + if (!cur) return 0; + return cur->function; +} + +void +Fl_Text_Editor::remove_all_key_bindings(Key_Binding** list) { + Key_Binding *cur, *next; + for (cur = *list; cur; cur = next) { + next = cur->next; + delete cur; + } + *list = 0; +} + +void +Fl_Text_Editor::remove_key_binding(int key, int state, Key_Binding** list) { + Key_Binding *cur, *last = 0; + for (cur = *list; cur; last = cur, cur = cur->next) + if (cur->key == key && cur->state == state) break; + if (!cur) return; + if (last) last->next = cur->next; + else *list = cur->next; + delete cur; +} + +void +Fl_Text_Editor::add_key_binding(int key, int state, Key_Func function, + Key_Binding** list) { + Key_Binding* kb = new Key_Binding; + kb->key = key; + kb->state = state; + kb->function = function; + kb->next = *list; + *list = kb; +} + +//////////////////////////////////////////////////////////////// + +#define NORMAL_INPUT_MOVE 0 + +static void kill_selection(Fl_Text_Editor* e) { + if (e->buffer()->selected()) { + e->insert_position(e->buffer()->primary_selection()->start()); + e->buffer()->remove_selection(); + } +} + +int Fl_Text_Editor::kf_default(int c, Fl_Text_Editor* e) { + if (!c || (!isprint(c) && c != '\t')) return 0; + char s[2] = "\0"; + s[0] = (char)c; + kill_selection(e); + if (e->insert_mode()) e->insert(s); + else e->overstrike(s); + e->show_insert_position(); + e->set_changed(); + if (e->when()&FL_WHEN_CHANGED) e->do_callback(); + return 1; +} + +int Fl_Text_Editor::kf_ignore(int, Fl_Text_Editor*) { + return 0; // don't handle +} + +int Fl_Text_Editor::kf_backspace(int, Fl_Text_Editor* e) { + if (!e->buffer()->selected() && e->move_left()) + e->buffer()->select(e->insert_position(), e->insert_position()+1); + kill_selection(e); + e->show_insert_position(); + e->set_changed(); + if (e->when()&FL_WHEN_CHANGED) e->do_callback(); + return 1; +} + +int Fl_Text_Editor::kf_enter(int, Fl_Text_Editor* e) { + kill_selection(e); + e->insert("\n"); + e->show_insert_position(); + e->set_changed(); + if (e->when()&FL_WHEN_CHANGED) e->do_callback(); + return 1; +} + +extern void fl_text_drag_me(int pos, Fl_Text_Display* d); + +int Fl_Text_Editor::kf_move(int c, Fl_Text_Editor* e) { + int i; + int selected = e->buffer()->selected(); + if (!selected) + e->dragPos = e->insert_position(); + e->buffer()->unselect(); + switch (c) { + case FL_Home: + e->insert_position(e->buffer()->line_start(e->insert_position())); + break; + case FL_End: + e->insert_position(e->buffer()->line_end(e->insert_position())); + break; + case FL_Left: + e->move_left(); + break; + case FL_Right: + e->move_right(); + break; + case FL_Up: + e->move_up(); + break; + case FL_Down: + e->move_down(); + break; + case FL_Page_Up: + for (i = 0; i < e->mNVisibleLines - 1; i++) e->move_up(); + break; + case FL_Page_Down: + for (i = 0; i < e->mNVisibleLines - 1; i++) e->move_down(); + break; + } + e->show_insert_position(); + return 1; +} + +int Fl_Text_Editor::kf_shift_move(int c, Fl_Text_Editor* e) { + kf_move(c, e); + fl_text_drag_me(e->insert_position(), e); + return 1; +} + +int Fl_Text_Editor::kf_ctrl_move(int c, Fl_Text_Editor* e) { + if (!e->buffer()->selected()) + e->dragPos = e->insert_position(); + if (c != FL_Up && c != FL_Down) { + e->buffer()->unselect(); + e->show_insert_position(); + } + switch (c) { + case FL_Home: + e->insert_position(0); + e->scroll(0, 0); + break; + case FL_End: + e->insert_position(e->buffer()->length()); + e->scroll(e->count_lines(0, e->buffer()->length(), 1), 0); + break; + case FL_Left: + e->previous_word(); + break; + case FL_Right: + e->next_word(); + break; + case FL_Up: + e->scroll(e->mTopLineNum-1, e->mHorizOffset); + break; + case FL_Down: + e->scroll(e->mTopLineNum+1, e->mHorizOffset); + break; + case FL_Page_Up: + e->insert_position(e->mLineStarts[0]); + break; + case FL_Page_Down: + e->insert_position(e->mLineStarts[e->mNVisibleLines-2]); + break; + } + return 1; +} + +int Fl_Text_Editor::kf_c_s_move(int c, Fl_Text_Editor* e) { + kf_ctrl_move(c, e); + fl_text_drag_me(e->insert_position(), e); + return 1; +} + +int Fl_Text_Editor::kf_home(int, Fl_Text_Editor* e) { + return kf_move(FL_Home, e); +} + +int Fl_Text_Editor::kf_end(int, Fl_Text_Editor* e) { + return kf_move(FL_End, e); +} + +int Fl_Text_Editor::kf_left(int, Fl_Text_Editor* e) { + return kf_move(FL_Left, e); +} + +int Fl_Text_Editor::kf_up(int, Fl_Text_Editor* e) { + return kf_move(FL_Up, e); +} + +int Fl_Text_Editor::kf_right(int, Fl_Text_Editor* e) { + return kf_move(FL_Right, e); +} + +int Fl_Text_Editor::kf_down(int, Fl_Text_Editor* e) { + return kf_move(FL_Down, e); +} + +int Fl_Text_Editor::kf_page_up(int, Fl_Text_Editor* e) { + return kf_move(FL_Page_Up, e); +} + +int Fl_Text_Editor::kf_page_down(int, Fl_Text_Editor* e) { + return kf_move(FL_Page_Down, e); +} + + +int Fl_Text_Editor::kf_insert(int, Fl_Text_Editor* e) { + e->insert_mode(e->insert_mode() ? 0 : 1); + return 1; +} + +int Fl_Text_Editor::kf_delete(int, Fl_Text_Editor* e) { + if (!e->buffer()->selected()) + e->buffer()->select(e->insert_position(), e->insert_position()+1); + kill_selection(e); + e->show_insert_position(); + e->set_changed(); + if (e->when()&FL_WHEN_CHANGED) e->do_callback(); + return 1; +} + +int Fl_Text_Editor::kf_copy(int, Fl_Text_Editor* e) { + if (!e->buffer()->selected()) return 1; + const char *copy = e->buffer()->selection_text(); + if (*copy) Fl::copy(copy, strlen(copy), 1); + free((void*)copy); + e->show_insert_position(); + return 1; +} + +int Fl_Text_Editor::kf_cut(int c, Fl_Text_Editor* e) { + kf_copy(c, e); + kill_selection(e); + e->set_changed(); + if (e->when()&FL_WHEN_CHANGED) e->do_callback(); + return 1; +} + +int Fl_Text_Editor::kf_paste(int, Fl_Text_Editor* e) { + kill_selection(e); + Fl::paste(*e, 1); + e->show_insert_position(); + e->set_changed(); + if (e->when()&FL_WHEN_CHANGED) e->do_callback(); + return 1; +} + +int Fl_Text_Editor::kf_select_all(int, Fl_Text_Editor* e) { + e->buffer()->select(0, e->buffer()->length()); + return 1; +} + +int Fl_Text_Editor::kf_undo(int , Fl_Text_Editor* e) { + e->buffer()->unselect(); + int crsr; + int ret = e->buffer()->undo(&crsr); + e->insert_position(crsr); + e->show_insert_position(); + e->set_changed(); + if (e->when()&FL_WHEN_CHANGED) e->do_callback(); + return ret; +} + +int Fl_Text_Editor::handle_key() { + // Call FLTK's rules to try to turn this into a printing character. + // This uses the right-hand ctrl key as a "compose prefix" and returns + // the changes that should be made to the text, as a number of + // bytes to delete and a string to insert: + int del; + if (Fl::compose(del)) { + if (del) buffer()->select(insert_position()-del, insert_position()); + kill_selection(this); + if (Fl::event_length()) { + if (insert_mode()) insert(Fl::event_text()); + else overstrike(Fl::event_text()); + } + show_insert_position(); + set_changed(); + if (when()&FL_WHEN_CHANGED) do_callback(); + return 1; + } + + int key = Fl::event_key(), state = Fl::event_state(), c = Fl::event_text()[0]; + state &= FL_SHIFT|FL_CTRL|FL_ALT|FL_META; // only care about these states + Key_Func f; + f = bound_key_function(key, state, global_key_bindings); + if (!f) f = bound_key_function(key, state, key_bindings); + if (f) return f(key, this); + if (default_key_function_ && !state) return default_key_function_(c, this); + return 0; +} + +void Fl_Text_Editor::maybe_do_callback() { +// printf("Fl_Text_Editor::maybe_do_callback()\n"); +// printf("changed()=%d, when()=%x\n", changed(), when()); + if (changed() || (when()&FL_WHEN_NOT_CHANGED)) do_callback(); +} + +int Fl_Text_Editor::handle(int event) { + if (!buffer()) return 0; + + switch (event) { + case FL_FOCUS: + show_cursor(mCursorOn); // redraws the cursor + if (buffer()->selected()) redraw(); // Redraw selections... + Fl::focus(this); + return 1; + + case FL_UNFOCUS: + show_cursor(mCursorOn); // redraws the cursor + if (buffer()->selected()) redraw(); // Redraw selections... + case FL_HIDE: + if (when() & FL_WHEN_RELEASE) maybe_do_callback(); + return 1; + + case FL_KEYBOARD: + if (active_r() && window() && this == Fl::belowmouse()) + window()->cursor(FL_CURSOR_NONE); + return handle_key(); + + case FL_PASTE: + if (!Fl::event_text()) { + fl_beep(); + return 1; + } + buffer()->remove_selection(); + if (insert_mode()) insert(Fl::event_text()); + else overstrike(Fl::event_text()); + show_insert_position(); + set_changed(); + if (when()&FL_WHEN_CHANGED) do_callback(); + return 1; + + case FL_ENTER: +// MRS: WIN32 only? Need to test! +// case FL_MOVE: + show_cursor(mCursorOn); + return 1; + + case FL_PUSH: + if (Fl::event_button() == 2) { + // don't let the text_display see this event + if (Fl_Group::handle(event)) return 1; + dragType = -1; + Fl::paste(*this, 0); + Fl::focus(this); + set_changed(); + if (when()&FL_WHEN_CHANGED) do_callback(); + return 1; + } + break; + } + + return Fl_Text_Display::handle(event); +} + +// +// End of "$Id: Fl_Text_Editor.cxx 5671 2007-02-08 07:58:47Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Tile.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Tile.cxx new file mode 100644 index 0000000..97590f4 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Tile.cxx @@ -0,0 +1,207 @@ +// +// "$Id: Fl_Tile.cxx 5606 2007-01-18 10:01:24Z matt $" +// +// Tile widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Group of 2 or 4 "tiles" that can be resized by dragging border +// The size of the first child determines where the resize border is. +// The resizebox is used to limit where the border can be dragged to. + +#include +#include +#include +#include + +// Drag the edges that were initially at oldx,oldy to newx,newy: +// pass zero as oldx or oldy to disable drag in that direction: + +void Fl_Tile::position(int oix, int oiy, int newx, int newy) { + Fl_Widget*const* a = array(); + short* p = sizes(); + p += 8; // skip group & resizable's saved size + for (int i=children(); i--; p += 4) { + Fl_Widget* o = *a++; + if (o == resizable()) continue; + int X = o->x(); + int R = X+o->w(); + if (oix) { + int t = p[0]; + if (t == oix || t>oix && Xnewx) X = newx; + t = p[1]; + if (t == oix || t>oix && Rnewx) R = newx; + } + int Y = o->y(); + int B = Y+o->h(); + if (oiy) { + int t = p[2]; + if (t == oiy || t>oiy && Ynewy) Y = newy; + t = p[3]; + if (t == oiy || t>oiy && Bnewy) B = newy; + } + o->damage_resize(X,Y,R-X,B-Y); + } +} + +// move the lower-right corner (sort of): +void Fl_Tile::resize(int X,int Y,int W,int H) { + //Fl_Group::resize(X, Y, W, H); + //return; + // remember how much to move the child widgets: + int dx = X-x(); + int dy = Y-y(); + int dw = W-w(); + int dh = H-h(); + short* p = sizes(); + // resize this (skip the Fl_Group resize): + Fl_Widget::resize(X,Y,W,H); + // find bottom-right of resiable: + int OR = p[5]; + int NR = X+W-(p[1]-OR); + int OB = p[7]; + int NB = Y+H-(p[3]-OB); + // move everything to be on correct side of new resizable: + Fl_Widget*const* a = array(); + p += 8; + for (int i=children(); i--;) { + Fl_Widget* o = *a++; + int xx = o->x()+dx; + int R = xx+o->w(); + if (*p++ >= OR) xx += dw; else if (xx > NR) xx = NR; + if (*p++ >= OR) R += dw; else if (R > NR) R = NR; + int yy = o->y()+dy; + int B = yy+o->h(); + if (*p++ >= OB) yy += dh; else if (yy > NB) yy = NB; + if (*p++ >= OB) B += dh; else if (B > NB) B = NB; + o->resize(xx,yy,R-xx,B-yy); + // do *not* call o->redraw() here! If you do, and the tile is inside a + // scroll, it'll set the damage areas wrong for all children! + } +} + +static void set_cursor(Fl_Tile*t, Fl_Cursor c) { + static Fl_Cursor cursor; + if (cursor == c || !t->window()) return; + cursor = c; +#ifdef __sgi + t->window()->cursor(c,FL_RED,FL_WHITE); +#else + t->window()->cursor(c); +#endif +} + +static Fl_Cursor cursors[4] = { + FL_CURSOR_DEFAULT, + FL_CURSOR_WE, + FL_CURSOR_NS, + FL_CURSOR_MOVE}; + +int Fl_Tile::handle(int event) { + static int sdrag; + static int sdx, sdy; + static int sx, sy; +#define DRAGH 1 +#define DRAGV 2 +#define GRABAREA 4 + + int mx = Fl::event_x(); + int my = Fl::event_y(); + + switch (event) { + + case FL_MOVE: + case FL_ENTER: + case FL_PUSH: { + int mindx = 100; + int mindy = 100; + int oldx = 0; + int oldy = 0; + Fl_Widget*const* a = array(); + short* q = sizes(); + short* p = q+8; + for (int i=children(); i--; p += 4) { + Fl_Widget* o = *a++; + if (o == resizable()) continue; + if (p[1]y()<=my+GRABAREA && o->y()+o->h()>=my-GRABAREA) { + int t = mx - (o->x()+o->w()); + if (abs(t) < mindx) { + sdx = t; + mindx = abs(t); + oldx = p[1]; + } + } + if (p[3]x()<=mx+GRABAREA && o->x()+o->w()>=mx-GRABAREA) { + int t = my - (o->y()+o->h()); + if (abs(t) < mindy) { + sdy = t; + mindy = abs(t); + oldy = p[3]; + } + } + } + sdrag = 0; sx = sy = 0; + if (mindx <= GRABAREA) {sdrag = DRAGH; sx = oldx;} + if (mindy <= GRABAREA) {sdrag |= DRAGV; sy = oldy;} + set_cursor(this, cursors[sdrag]); + if (sdrag) return 1; + return Fl_Group::handle(event); + } + + case FL_LEAVE: + set_cursor(this, FL_CURSOR_DEFAULT); + break; + + case FL_DRAG: + // This is necessary if CONSOLIDATE_MOTION in Fl_x.cxx is turned off: + // if (damage()) return 1; // don't fall behind + case FL_RELEASE: { + if (!sdrag) return 0; // should not happen + Fl_Widget* r = resizable(); if (!r) r = this; + int newx; + if (sdrag&DRAGH) { + newx = Fl::event_x()-sdx; + if (newx < r->x()) newx = r->x(); + else if (newx > r->x()+r->w()) newx = r->x()+r->w(); + } else + newx = sx; + int newy; + if (sdrag&DRAGV) { + newy = Fl::event_y()-sdy; + if (newy < r->y()) newy = r->y(); + else if (newy > r->y()+r->h()) newy = r->y()+r->h(); + } else + newy = sy; + position(sx,sy,newx,newy); + if (event == FL_DRAG) set_changed(); + do_callback(); + return 1;} + + } + + return Fl_Group::handle(event); +} + +// +// End of "$Id: Fl_Tile.cxx 5606 2007-01-18 10:01:24Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Tiled_Image.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Tiled_Image.cxx new file mode 100644 index 0000000..289bcab --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Tiled_Image.cxx @@ -0,0 +1,139 @@ +// +// "$Id: Fl_Tiled_Image.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Tiled image code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include + + +// +// 'Fl_Tiled_Image::Fl_Tiled_Image()' - Constructor. +// +// Use a width and height of 0 to tile the whole window/widget. +// + +Fl_Tiled_Image::Fl_Tiled_Image(Fl_Image *i, // I - Image to tile + int W, // I - Width of tiled area + int H) : // I - Height of tiled area + Fl_Image(W,H,0) { + image_ = i; + alloc_image_ = 0; + + if (W == 0) w(Fl::w()); + if (H == 0) h(Fl::h()); +} + + +// +// 'Fl_Tiled_Image::~Fl_Tiled_Image()' - Destructor. +// + +Fl_Tiled_Image::~Fl_Tiled_Image() { + if (alloc_image_) delete image_; +} + + +// +// 'Fl_Tiled_Image::copy()' - Copy and resize a tiled image... +// + +Fl_Image * // O - New image +Fl_Tiled_Image::copy(int W, // I - New width + int H) { // I - New height + if (W == w() && H == h()) return this; + else return new Fl_Tiled_Image(image_, W, H); +} + + +// +// 'Fl_Tiled_Image::color_average()' - Blend colors... +// + +void +Fl_Tiled_Image::color_average(Fl_Color c, // I - Color to blend with + float i) { // I - Blend fraction + if (!alloc_image_) { + image_ = image_->copy(); + alloc_image_ = 1; + } + + image_->color_average(c, i); +} + + +// +// 'Fl_Tiled_Image::desaturate()' - Convert the image to grayscale... +// + +void +Fl_Tiled_Image::desaturate() { + if (!alloc_image_) { + image_ = image_->copy(); + alloc_image_ = 1; + } + + image_->desaturate(); +} + + +// +// 'Fl_Tiled_Image::draw()' - Draw a shared image... +// + +void +Fl_Tiled_Image::draw(int X, // I - Starting X position + int Y, // I - Starting Y position + int W, // I - Width of area to be filled + int H, // I - Height of area to be filled + int cx, // I - "Source" X position + int cy) { // I - "Source" Y position + if (!image_->w() || !image_->h()) return; + if (W == 0) W = Fl::w(); + if (H == 0) H = Fl::h(); + + fl_clip(X, Y, W, H); + + X += cx; + Y += cy; + + X = X - (X % image_->w()); + Y = Y - (Y % image_->h()); + + W += X; + H += Y; + + for (int yy = Y; yy < H; yy += image_->h()) + for (int xx = X; xx < W; xx += image_->w()) + image_->draw(xx, yy); + + fl_pop_clip(); +} + + +// +// End of "$Id: Fl_Tiled_Image.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Tooltip.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Tooltip.cxx new file mode 100644 index 0000000..4eb99b6 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Tooltip.cxx @@ -0,0 +1,263 @@ +// +// "$Id: Fl_Tooltip.cxx 5848 2007-05-20 16:18:31Z mike $" +// +// Tooltip source file for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include + +#include + +float Fl_Tooltip::delay_ = 1.0f; +float Fl_Tooltip::hoverdelay_ = 0.2f; +int Fl_Tooltip::enabled_ = 1; +unsigned Fl_Tooltip::color_ = fl_color_cube(FL_NUM_RED - 1, + FL_NUM_GREEN - 1, + FL_NUM_BLUE - 2); +unsigned Fl_Tooltip::textcolor_ = FL_BLACK; +int Fl_Tooltip::font_ = FL_HELVETICA; +int Fl_Tooltip::size_ = FL_NORMAL_SIZE; + +#define MAX_WIDTH 400 + +static const char* tip; + +class Fl_TooltipBox : public Fl_Menu_Window { +public: + Fl_TooltipBox() : Fl_Menu_Window(0, 0) { + set_override(); + end(); + } + void draw(); + void layout(); + void show() { + if (tip) Fl_Menu_Window::show(); + } +}; + +Fl_Widget* Fl_Tooltip::widget_ = 0; +static Fl_TooltipBox *window = 0; +static int Y,H; + +void Fl_TooltipBox::layout() { + fl_font(Fl_Tooltip::font(), Fl_Tooltip::size()); + int ww, hh; + ww = MAX_WIDTH; + fl_measure(tip, ww, hh, FL_ALIGN_LEFT|FL_ALIGN_WRAP|FL_ALIGN_INSIDE); + ww += 6; hh += 6; + + // find position on the screen of the widget: + int ox = Fl::event_x_root(); + int oy = Y + H+2; + for (Fl_Widget* p = Fl_Tooltip::current(); p; p = p->window()) { + oy += p->y(); + } + int scr_x, scr_y, scr_w, scr_h; + Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h); + if (ox+ww > scr_x+scr_w) ox = scr_x+scr_w - ww; + if (ox < scr_x) ox = scr_x; + if (H > 30) { + oy = Fl::event_y_root()+13; + if (oy+hh > scr_y+scr_h) oy -= 23+hh; + } else { + if (oy+hh > scr_y+scr_h) oy -= (4+hh+H); + } + if (oy < scr_y) oy = scr_y; + + resize(ox, oy, ww, hh); +} + +void Fl_TooltipBox::draw() { + draw_box(FL_BORDER_BOX, 0, 0, w(), h(), Fl_Tooltip::color()); + fl_color(Fl_Tooltip::textcolor()); + fl_font(Fl_Tooltip::font(), Fl_Tooltip::size()); + fl_draw(tip, 3, 3, w()-6, h()-6, Fl_Align(FL_ALIGN_LEFT|FL_ALIGN_WRAP)); +} + +static char recent_tooltip; + +static void recent_timeout(void*) { +#ifdef DEBUG + puts("recent_timeout();"); +#endif // DEBUG + + recent_tooltip = 0; +} + +static char recursion; + +static void tooltip_timeout(void*) { +#ifdef DEBUG + puts("tooltip_timeout();"); +#endif // DEBUG + + if (recursion) return; + recursion = 1; + if (!tip || !*tip) { + if (window) window->hide(); + } else { + //if (Fl::grab()) return; + if (!window) window = new Fl_TooltipBox; + // this cast bypasses the normal Fl_Window label() code: + ((Fl_Widget*)window)->label(tip); + window->layout(); + window->redraw(); +// printf("tooltip_timeout: Showing window %p with tooltip \"%s\"...\n", +// window, tip ? tip : "(null)"); + window->show(); + } + + Fl::remove_timeout(recent_timeout); + recent_tooltip = 1; + recursion = 0; +} + +// If this widget or one of it's parents has a tooltip, enter it. This +// will do nothing if this is the current widget (even if the mouse moved +// out so an exit() was done and then moved back in). If no tooltip can +// be found do Fl_Tooltip::exit_(). If you don't want this behavior (for instance +// if you want the tooltip to reappear when the mouse moves back in) +// call the fancier enter_area() below. +void +Fl_Tooltip::enter_(Fl_Widget* w) { +#ifdef DEBUG + printf("Fl_Tooltip::enter_(w=%p)\n", w); + printf(" window=%p\n", window); +#endif // DEBUG + + // find the enclosing group with a tooltip: + Fl_Widget* tw = w; + for (;;) { + if (!tw) {exit_(0); return;} + if (tw == widget_) return; + if (tw->tooltip()) break; + tw = tw->parent(); + } + enter_area(w, 0, 0, w->w(), w->h(), tw->tooltip()); +} + +// Acts as though enter(widget) was done but does not pop up a +// tooltip. This is useful to prevent a tooltip from reappearing when +// a modal overlapping window is deleted. FLTK does this automatically +// when you click the mouse button. +void Fl_Tooltip::current(Fl_Widget* w) { +#ifdef DEBUG + printf("Fl_Tooltip::current(w=%p)\n", w); +#endif // DEBUG + + exit_(0); + // find the enclosing group with a tooltip: + Fl_Widget* tw = w; + for (;;) { + if (!tw) return; + if (tw->tooltip()) break; + tw = tw->parent(); + } + // act just like Fl_Tooltip::enter_() except we can remember a zero: + widget_ = w; +} + +// Hide any visible tooltip. +void +Fl_Tooltip::exit_(Fl_Widget *w) { +#ifdef DEBUG + printf("Fl_Tooltip::exit_(w=%p)\n", w); + printf(" widget=%p, window=%p\n", widget_, window); +#endif // DEBUG + + if (!widget_ || w == window) return; + widget_ = 0; + Fl::remove_timeout(tooltip_timeout); + Fl::remove_timeout(recent_timeout); + if (window && window->visible()) window->hide(); + if (recent_tooltip) { + if (Fl::event_state() & FL_BUTTONS) recent_tooltip = 0; + else Fl::add_timeout(Fl_Tooltip::hoverdelay(), recent_timeout); + } +} + +// Get ready to display a tooltip. The widget and the xywh box inside +// it define an area the tooltip is for, this along with the current +// mouse position places the tooltip (the mouse is assummed to point +// inside or near the box). +void +Fl_Tooltip::enter_area(Fl_Widget* wid, int x,int y,int w,int h, const char* t) +{ + (void)x; + (void)w; + +#ifdef DEBUG + printf("Fl_Tooltip::enter_area(wid=%p, x=%d, y=%d, w=%d, h=%d, t=\"%s\")\n", + wid, x, y, w, h, t ? t : "(null)"); + printf(" recursion=%d, window=%p\n", recursion, window); +#endif // DEBUG + + if (recursion) return; + if (!t || !*t || !enabled()) { + exit_(0); + return; + } + // do nothing if it is the same: + if (wid==widget_ /*&& x==X && y==Y && w==W && h==H*/ && t==tip) return; + Fl::remove_timeout(tooltip_timeout); + Fl::remove_timeout(recent_timeout); + // remember it: + widget_ = wid; Y = y; H = h; tip = t; + // popup the tooltip immediately if it was recently up: + if (recent_tooltip) { + if (window) window->hide(); + Fl::add_timeout(Fl_Tooltip::hoverdelay(), tooltip_timeout); + } else if (Fl_Tooltip::delay() < .1) { +#ifdef WIN32 + // possible fix for the Windows titlebar, it seems to want the + // window to be destroyed, moving it messes up the parenting: + if (window && window->visible()) window->hide(); +#endif // WIN32 + tooltip_timeout(0); + } else { + if (window && window->visible()) window->hide(); + Fl::add_timeout(Fl_Tooltip::delay(), tooltip_timeout); + } + +#ifdef DEBUG + printf(" tip=\"%s\", window->shown()=%d\n", tip ? tip : "(null)", + window ? window->shown() : 0); +#endif // DEBUG +} + +void Fl_Widget::tooltip(const char *tt) { + static char beenhere = 0; + if (!beenhere) { + beenhere = 1; + Fl_Tooltip::enter = Fl_Tooltip::enter_; + Fl_Tooltip::exit = Fl_Tooltip::exit_; + } + tooltip_ = tt; +} + +// +// End of "$Id: Fl_Tooltip.cxx 5848 2007-05-20 16:18:31Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Valuator.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Valuator.cxx new file mode 100644 index 0000000..bdb829a --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Valuator.cxx @@ -0,0 +1,149 @@ +// +// "$Id: Fl_Valuator.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Valuator widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Base class for sliders and all other one-value "knobs" + +#include +#include +#include +#include +#include "flstring.h" + +Fl_Valuator::Fl_Valuator(int X, int Y, int W, int H, const char* L) + : Fl_Widget(X,Y,W,H,L) { + align(FL_ALIGN_BOTTOM); + when(FL_WHEN_CHANGED); + value_ = 0; + previous_value_ = 1; + min = 0; + max = 1; + A = 0.0; + B = 1; +} + +const double epsilon = 4.66e-10; + +void Fl_Valuator::step(double s) { + if (s < 0) s = -s; + A = rint(s); + B = 1; + while (fabs(s-A/B) > epsilon && B<=(0x7fffffff/10)) {B *= 10; A = rint(s*B);} +} + +void Fl_Valuator::precision(int p) { + A = 1.0; + for (B = 1; p--;) B *= 10; +} + +void Fl_Valuator::value_damage() {damage(FL_DAMAGE_EXPOSE);} // by default do partial-redraw + +int Fl_Valuator::value(double v) { + clear_changed(); + if (v == value_) return 0; + value_ = v; + value_damage(); + return 1; +} + +double Fl_Valuator::softclamp(double v) { + int which = (min<=max); + double p = previous_value_; + if ((vmax)==which && p!=max && (p>max)!=which) return max; + else return v; +} + +// inline void Fl_Valuator::handle_push() {previous_value_ = value_;} + +void Fl_Valuator::handle_drag(double v) { + if (v != value_) { + value_ = v; + value_damage(); + set_changed(); + if (when() & FL_WHEN_CHANGED) do_callback(); + } +} + +void Fl_Valuator::handle_release() { + if (when()&FL_WHEN_RELEASE) { + // insure changed() is off even if no callback is done. It may have + // been turned on by the drag, and then the slider returned to it's + // initial position: + clear_changed(); + // now do the callback only if slider in new position or always is on: + if (value_ != previous_value_ || when() & FL_WHEN_NOT_CHANGED) { + do_callback(); + } + } +} + +double Fl_Valuator::round(double v) { + if (A) return rint(v*B/A)*A/B; + else return v; +} + +double Fl_Valuator::clamp(double v) { + if ((vmax)==(min<=max)) return max; + else return v; +} + +double Fl_Valuator::increment(double v, int n) { + if (!A) return v+n*(max-min)/100; + if (min > max) n = -n; + return (rint(v*B/A)+n)*A/B; +} + +int Fl_Valuator::format(char* buffer) { + double v = value(); + // MRS: THIS IS A HACK - RECOMMEND ADDING BUFFER SIZE ARGUMENT + if (!A || !B) return snprintf(buffer, 128, "%g", v); + + // Figure out how many digits are required to correctly format the + // value. + int i, c = 0; + char temp[32]; + // output a number with many digits after the decimal point. This + // seems to be needed to get high precission + snprintf(temp, sizeof(temp), "%.12f", A/B); + // strip all trailing 0's + for (i=strlen(temp)-1; i>0; i--) { + if (temp[i]!='0') break; + } + // count digits until we find the decimal point (or comma or whatever + // letter is set in the current locale) + for (; i>0; i--, c++) { + if (!isdigit(temp[i])) break; + } + + // MRS: THIS IS A HACK - RECOMMEND ADDING BUFFER SIZE ARGUMENT + return snprintf(buffer, 128, "%.*f", c, v); +} + +// +// End of "$Id: Fl_Valuator.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Value_Input.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Value_Input.cxx new file mode 100644 index 0000000..5d1fae4 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Value_Input.cxx @@ -0,0 +1,133 @@ +// +// "$Id: Fl_Value_Input.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Value input widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// FLTK widget for drag-adjusting a floating point value. +// Warning: this works by making a child Fl_Input object, even +// though this object is *not* an Fl_Group. May be a kludge? + +#include +#include +#include +#include +#include + + +void Fl_Value_Input::input_cb(Fl_Widget*, void* v) { + Fl_Value_Input& t = *(Fl_Value_Input*)v; + double nv; + if ((t.step() - floor(t.step()))>0.0 || t.step() == 0.0) nv = strtod(t.input.value(), 0); + else nv = strtol(t.input.value(), 0, 0); + if (nv != t.value() || t.when() & FL_WHEN_NOT_CHANGED) { + t.set_value(nv); + t.set_changed(); + if (t.when()) t.do_callback(); + } +} + +void Fl_Value_Input::draw() { + if (damage()&~FL_DAMAGE_CHILD) input.clear_damage(FL_DAMAGE_ALL); + input.box(box()); + input.color(color(), selection_color()); + input.draw(); + input.clear_damage(); +} + +void Fl_Value_Input::resize(int X, int Y, int W, int H) { + Fl_Valuator::resize(X, Y, W, H); + input.resize(X, Y, W, H); +} + +void Fl_Value_Input::value_damage() { + char buf[128]; + format(buf); + input.value(buf); + input.mark(input.position()); // turn off selection highlight +} + +int Fl_Value_Input::handle(int event) { + double v; + int delta; + int mx = Fl::event_x_root(); + static int ix, drag; + input.when(when()); + switch (event) { + case FL_PUSH: + if (!step()) goto DEFAULT; + ix = mx; + drag = Fl::event_button(); + handle_push(); + return 1; + case FL_DRAG: + if (!step()) goto DEFAULT; + delta = mx-ix; + if (delta > 5) delta -= 5; + else if (delta < -5) delta += 5; + else delta = 0; + switch (drag) { + case 3: v = increment(previous_value(), delta*100); break; + case 2: v = increment(previous_value(), delta*10); break; + default:v = increment(previous_value(), delta); break; + } + v = round(v); + handle_drag(soft()?softclamp(v):clamp(v));; + return 1; + case FL_RELEASE: + if (!step()) goto DEFAULT; + if (value() != previous_value() || !Fl::event_is_click()) + handle_release(); + else { + input.handle(FL_PUSH); + input.handle(FL_RELEASE); + } + return 1; + case FL_FOCUS: + return input.take_focus(); + default: + DEFAULT: + input.type(((step() - floor(step()))>0.0 || step() == 0.0) ? FL_FLOAT_INPUT : FL_INT_INPUT); + return input.handle(event); + } +} + +Fl_Value_Input::Fl_Value_Input(int X, int Y, int W, int H, const char* l) +: Fl_Valuator(X, Y, W, H, l), input(X, Y, W, H, 0) { + soft_ = 0; + if (input.parent()) // defeat automatic-add + ((Fl_Group*)input.parent())->remove(input); + input.parent((Fl_Group *)this); // kludge! + input.callback(input_cb, this); + input.when(FL_WHEN_CHANGED); + box(input.box()); + color(input.color()); + selection_color(input.selection_color()); + align(FL_ALIGN_LEFT); + value_damage(); +} + +// +// End of "$Id: Fl_Value_Input.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Value_Output.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Value_Output.cxx new file mode 100644 index 0000000..bb9a8f8 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Value_Output.cxx @@ -0,0 +1,103 @@ +// +// "$Id: Fl_Value_Output.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Value output widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Fltk widget for drag-adjusting a floating point value. +// This is much lighter than Fl_Value_Input because it has no text editor +// If step() is zero then it can be used to display a floating-point value + +#include +#include +#include + +void Fl_Value_Output::draw() { + Fl_Boxtype b = box() ? box() : FL_DOWN_BOX; + int X = x()+Fl::box_dx(b); + int Y = y()+Fl::box_dy(b); + int W = w()-Fl::box_dw(b); + int H = h()-Fl::box_dh(b); + if (damage()&~FL_DAMAGE_CHILD) + draw_box(b, color()); + else { + fl_color(color()); + fl_rectf(X, Y, W, H); + } + char buf[128]; + format(buf); + fl_color(active_r() ? textcolor() : fl_inactive(textcolor())); + fl_font(textfont(), textsize()); + fl_draw(buf,X,Y,W,H,FL_ALIGN_LEFT); +} + +int Fl_Value_Output::handle(int event) { + if (!step()) return 0; + double v; + int delta; + int mx = Fl::event_x(); + static int ix, drag; + switch (event) { + case FL_PUSH: + ix = mx; + drag = Fl::event_button(); + handle_push(); + return 1; + case FL_DRAG: + delta = Fl::event_x()-ix; + if (delta > 5) delta -= 5; + else if (delta < -5) delta += 5; + else delta = 0; + switch (drag) { + case 3: v = increment(previous_value(),delta*100); break; + case 2: v = increment(previous_value(),delta*10); break; + default:v = increment(previous_value(),delta); break; + } + v = round(v); + handle_drag(soft()?softclamp(v):clamp(v));; + return 1; + case FL_RELEASE: + handle_release(); + return 1; + case FL_ENTER : + case FL_LEAVE : + return 1; + default: + return 0; + } +} + +Fl_Value_Output::Fl_Value_Output(int X, int Y, int W, int H,const char *l) +: Fl_Valuator(X,Y,W,H,l) { + box(FL_NO_BOX); + align(FL_ALIGN_LEFT); + textfont_ = FL_HELVETICA; + textsize_ = (uchar)FL_NORMAL_SIZE; + textcolor_ = FL_FOREGROUND_COLOR; + soft_ = 0; +} + +// +// End of "$Id: Fl_Value_Output.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Value_Slider.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Value_Slider.cxx new file mode 100644 index 0000000..e26d1ea --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Value_Slider.cxx @@ -0,0 +1,82 @@ +// +// "$Id: Fl_Value_Slider.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Value slider widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include + +Fl_Value_Slider::Fl_Value_Slider(int X, int Y, int W, int H, const char*l) +: Fl_Slider(X,Y,W,H,l) { + step(1,100); + textfont_ = FL_HELVETICA; + textsize_ = 10; + textcolor_ = FL_FOREGROUND_COLOR; +} + +void Fl_Value_Slider::draw() { + int sxx = x(), syy = y(), sww = w(), shh = h(); + int bxx = x(), byy = y(), bww = w(), bhh = h(); + if (horizontal()) { + bww = 35; sxx += 35; sww -= 35; + } else { + syy += 25; bhh = 25; shh -= 25; + } + if (damage()&FL_DAMAGE_ALL) draw_box(box(),sxx,syy,sww,shh,color()); + Fl_Slider::draw(sxx+Fl::box_dx(box()), + syy+Fl::box_dy(box()), + sww-Fl::box_dw(box()), + shh-Fl::box_dh(box())); + draw_box(box(),bxx,byy,bww,bhh,color()); + char buf[128]; + format(buf); + fl_font(textfont(), textsize()); + fl_color(active_r() ? textcolor() : fl_inactive(textcolor())); + fl_draw(buf, bxx, byy, bww, bhh, FL_ALIGN_CLIP); +} + +int Fl_Value_Slider::handle(int event) { + if (event == FL_PUSH && Fl::visible_focus()) { + Fl::focus(this); + redraw(); + } + int sxx = x(), syy = y(), sww = w(), shh = h(); + if (horizontal()) { + sxx += 35; sww -= 35; + } else { + syy += 25; shh -= 25; + } + return Fl_Slider::handle(event, + sxx+Fl::box_dx(box()), + syy+Fl::box_dy(box()), + sww-Fl::box_dw(box()), + shh-Fl::box_dh(box())); +} + +// +// End of "$Id: Fl_Value_Slider.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Widget.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Widget.cxx new file mode 100644 index 0000000..f3713a9 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Widget.cxx @@ -0,0 +1,318 @@ +// +// "$Id: Fl_Widget.cxx 6978 2009-12-23 12:54:41Z AlbrechtS $" +// +// Base widget class for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include +#include +#include "flstring.h" + + +//////////////////////////////////////////////////////////////// +// for compatability with Forms, all widgets without callbacks are +// inserted into a "queue" when they are activated, and the forms +// compatability interaction functions (fl_do_events, etc) will +// read one widget at a time from this queue and return it: + +const int QUEUE_SIZE = 20; + +static Fl_Widget *obj_queue[QUEUE_SIZE]; +static int obj_head, obj_tail; + +void Fl_Widget::default_callback(Fl_Widget *o, void * /*v*/) { +#if 0 + // This is necessary for strict forms compatibility but is confusing. + // Use the parent's callback if this widget does not have one. + for (Fl_Widget *p = o->parent(); p; p = p->parent()) + if (p->callback() != default_callback) { + p->do_callback(o,v); + return; + } +#endif + obj_queue[obj_head++] = o; + if (obj_head >= QUEUE_SIZE) obj_head = 0; + if (obj_head == obj_tail) { + obj_tail++; + if (obj_tail >= QUEUE_SIZE) obj_tail = 0; + } +} +/* + All Fl_Widgets that don't have a callback defined use a + default callback that puts a pointer to the widget in this queue, + and this method reads the oldest widget out of this queue. +*/ +Fl_Widget *Fl::readqueue() { + if (obj_tail==obj_head) return 0; + Fl_Widget *o = obj_queue[obj_tail++]; + if (obj_tail >= QUEUE_SIZE) obj_tail = 0; + return o; +} +/* + This static internal function removes all pending callbacks for a + specific widget from the default callback queue (Fl::readqueue()). + It is only called from Fl_Widget's destructor if the widget + doesn't have an own callback. + Note: There's no need to have this in the Fl:: namespace. +*/ +static void cleanup_readqueue(Fl_Widget *w) { + + if (obj_tail==obj_head) return; + + // Read the entire queue and copy over all valid entries. + // The new head will be determined after the last copied entry. + + int old_head = obj_head; // save newest entry + int entry = obj_tail; // oldest entry + obj_head = obj_tail; // new queue start + for (;;) { + Fl_Widget *o = obj_queue[entry++]; + if (entry >= QUEUE_SIZE) entry = 0; + if (o != w) { // valid entry + obj_queue[obj_head++] = o; + if (obj_head >= QUEUE_SIZE) obj_head = 0; + } // valid entry + if (entry == old_head) break; + } + return; +} + +//////////////////////////////////////////////////////////////// + +int Fl_Widget::handle(int) { + return 0; +} + +int FL_NORMAL_SIZE = 14; + +Fl_Widget::Fl_Widget(int X, int Y, int W, int H, const char* L) { + + x_ = X; y_ = Y; w_ = W; h_ = H; + + label_.value = L; + label_.image = 0; + label_.deimage = 0; + label_.type = FL_NORMAL_LABEL; + label_.font = FL_HELVETICA; + label_.size = (uchar)FL_NORMAL_SIZE; + label_.color = FL_FOREGROUND_COLOR; + tooltip_ = 0; + callback_ = default_callback; + user_data_ = 0; + type_ = 0; + flags_ = VISIBLE_FOCUS; + damage_ = 0; + box_ = FL_NO_BOX; + color_ = FL_GRAY; + color2_ = FL_GRAY; + align_ = FL_ALIGN_CENTER; + when_ = FL_WHEN_RELEASE; + + parent_ = 0; + if (Fl_Group::current()) Fl_Group::current()->add(this); +} + +void Fl_Widget::resize(int X, int Y, int W, int H) { + x_ = X; y_ = Y; w_ = W; h_ = H; +} + +// this is useful for parent widgets to call to resize children: +int Fl_Widget::damage_resize(int X, int Y, int W, int H) { + if (x() == X && y() == Y && w() == W && h() == H) return 0; + resize(X, Y, W, H); + redraw(); + return 1; +} + +int Fl_Widget::take_focus() { + if (!takesevents()) return 0; + if (!visible_focus()) return 0; + if (!handle(FL_FOCUS)) return 0; // see if it wants it + if (contains(Fl::focus())) return 1; // it called Fl::focus for us + Fl::focus(this); + return 1; +} + +extern void fl_throw_focus(Fl_Widget*); // in Fl_x.cxx + +// Destruction does not remove from any parent group! And groups when +// destroyed destroy all their children. This is convienent and fast. +// However, it is only legal to destroy a "root" such as an Fl_Window, +// and automatic destructors may be called. +Fl_Widget::~Fl_Widget() { + Fl::clear_widget_pointer(this); + if (flags() & COPIED_LABEL) free((void *)(label_.value)); + parent_ = 0; // Don't throw focus to a parent widget. + fl_throw_focus(this); + // remove stale entries from default callback queue (Fl::readqueue()) + if (callback_ == default_callback) cleanup_readqueue(this); +} + +// draw a focus box for the widget... +void +Fl_Widget::draw_focus(Fl_Boxtype B, int X, int Y, int W, int H) const { + if (!Fl::visible_focus()) return; + switch (B) { + case FL_DOWN_BOX: + case FL_DOWN_FRAME: + case FL_THIN_DOWN_BOX: + case FL_THIN_DOWN_FRAME: + X ++; + Y ++; + default: + break; + } + + fl_color(fl_contrast(FL_BLACK, color())); + +#if defined(WIN32) || defined(__APPLE_QD__) + // Windows 95/98/ME do not implement the dotted line style, so draw + // every other pixel around the focus area... + // + // Also, QuickDraw (MacOS) does not support line styles specifically, + // and the hack we use in fl_line_style() will not draw horizontal lines + // on odd-numbered rows... + int i, xx, yy; + + X += Fl::box_dx(B); + Y += Fl::box_dy(B); + W -= Fl::box_dw(B) + 2; + H -= Fl::box_dh(B) + 2; + + for (xx = 0, i = 1; xx < W; xx ++, i ++) if (i & 1) fl_point(X + xx, Y); + for (yy = 0; yy < H; yy ++, i ++) if (i & 1) fl_point(X + W, Y + yy); + for (xx = W; xx > 0; xx --, i ++) if (i & 1) fl_point(X + xx, Y + H); + for (yy = H; yy > 0; yy --, i ++) if (i & 1) fl_point(X, Y + yy); +#else + fl_line_style(FL_DOT); + fl_rect(X + Fl::box_dx(B), Y + Fl::box_dy(B), + W - Fl::box_dw(B) - 1, H - Fl::box_dh(B) - 1); + fl_line_style(FL_SOLID); +#endif // WIN32 +} + + +void Fl_Widget::activate() { + if (!active()) { + clear_flag(INACTIVE); + if (active_r()) { + redraw(); + redraw_label(); + handle(FL_ACTIVATE); + if (inside(Fl::focus())) Fl::focus()->take_focus(); + } + } +} + +void Fl_Widget::deactivate() { + if (active_r()) { + set_flag(INACTIVE); + redraw(); + redraw_label(); + handle(FL_DEACTIVATE); + fl_throw_focus(this); + } else { + set_flag(INACTIVE); + } +} + +int Fl_Widget::active_r() const { + for (const Fl_Widget* o = this; o; o = o->parent()) + if (!o->active()) return 0; + return 1; +} + +void Fl_Widget::show() { + if (!visible()) { + clear_flag(INVISIBLE); + if (visible_r()) { + redraw(); + redraw_label(); + handle(FL_SHOW); + if (inside(Fl::focus())) Fl::focus()->take_focus(); + } + } +} + +void Fl_Widget::hide() { + if (visible_r()) { + set_flag(INVISIBLE); + for (Fl_Widget *p = parent(); p; p = p->parent()) + if (p->box() || !p->parent()) {p->redraw(); break;} + handle(FL_HIDE); + fl_throw_focus(this); + } else { + set_flag(INVISIBLE); + } +} + +int Fl_Widget::visible_r() const { + for (const Fl_Widget* o = this; o; o = o->parent()) + if (!o->visible()) return 0; + return 1; +} + +// return true if widget is inside (or equal to) this: +// Returns false for null widgets. +int Fl_Widget::contains(const Fl_Widget *o) const { + for (; o; o = o->parent_) if (o == this) return 1; + return 0; +} + + +void +Fl_Widget::label(const char *a) { + if (flags() & COPIED_LABEL) { + // reassigning a copied label remains the same copied label + if (label_.value == a) + return; + free((void *)(label_.value)); + clear_flag(COPIED_LABEL); + } + label_.value=a; + redraw_label(); +} + + +void +Fl_Widget::copy_label(const char *a) { + if (flags() & COPIED_LABEL) free((void *)(label_.value)); + if (a) { + set_flag(COPIED_LABEL); + label_.value=strdup(a); + } else { + clear_flag(COPIED_LABEL); + label_.value=(char *)0; + } + redraw_label(); +} + + +// +// End of "$Id: Fl_Widget.cxx 6978 2009-12-23 12:54:41Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Window.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Window.cxx new file mode 100644 index 0000000..e224c1f --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Window.cxx @@ -0,0 +1,179 @@ +// +// "$Id: Fl_Window.cxx 5251 2006-06-28 10:23:33Z matt $" +// +// Window widget class for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// The Fl_Window is a window in the fltk library. +// This is the system-independent portions. The huge amount of +// crap you need to do to communicate with X is in Fl_x.cxx, the +// equivalent (but totally different) crap for MSWindows is in Fl_win32.cxx + +#include +#include +#include +#include "flstring.h" + +#ifdef __APPLE_QUARTZ__ +#include +#endif + +void Fl_Window::_Fl_Window() { + type(FL_WINDOW); + box(FL_FLAT_BOX); + if (Fl::scheme_bg_) { + labeltype(FL_NORMAL_LABEL); + align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP); + image(Fl::scheme_bg_); + } else { + labeltype(FL_NO_LABEL); + } + i = 0; + xclass_ = 0; + icon_ = 0; + iconlabel_ = 0; + resizable(0); + size_range_set = 0; + minw = maxw = minh = maxh = 0; + callback((Fl_Callback*)default_callback); +} + +Fl_Window::Fl_Window(int X,int Y,int W, int H, const char *l) +: Fl_Group(X, Y, W, H, l) { + cursor_default = FL_CURSOR_DEFAULT; + cursor_fg = FL_BLACK; + cursor_bg = FL_WHITE; + + _Fl_Window(); + set_flag(FL_FORCE_POSITION); +} + +Fl_Window::Fl_Window(int W, int H, const char *l) +// fix common user error of a missing end() with current(0): + : Fl_Group((Fl_Group::current(0),0), 0, W, H, l) { + cursor_default = FL_CURSOR_DEFAULT; + cursor_fg = FL_BLACK; + cursor_bg = FL_WHITE; + + _Fl_Window(); + clear_visible(); +} + +Fl_Window *Fl_Widget::window() const { + for (Fl_Widget *o = parent(); o; o = o->parent()) + if (o->type() >= FL_WINDOW) return (Fl_Window*)o; + return 0; +} + +int Fl_Window::x_root() const { + Fl_Window *p = window(); + if (p) return p->x_root() + x(); + return x(); +} + +int Fl_Window::y_root() const { + Fl_Window *p = window(); + if (p) return p->y_root() + y(); + return y(); +} + +void Fl_Window::draw() { + const char *savelabel = label(); + int saveflags = flags(); + int savex = x(); x(0); + int savey = y(); y(0); + // Make sure we don't draw the window title in the window background... + clear_flag(COPIED_LABEL); // do not free copied labels! + Fl_Widget::label(0); + Fl_Group::draw(); +#ifdef __APPLE_QUARTZ__ + if (!parent() && resizable() && (!size_range_set || minh!=maxh || minw!=maxw)) { + int dx = Fl::box_dw(box())-Fl::box_dx(box()); + int dy = Fl::box_dh(box())-Fl::box_dy(box()); + if (dx<=0) dx = 1; + if (dy<=0) dy = 1; + int x1 = w()-dx-1, x2 = x1, y1 = h()-dx-1, y2 = y1; + Fl_Color c[4] = { + color(), + fl_color_average(color(), FL_WHITE, 0.7f), + fl_color_average(color(), FL_BLACK, 0.6f), + fl_color_average(color(), FL_BLACK, 0.8f), + }; + int i; + for (i=dx; i<12; i++) { + fl_color(c[i&3]); + fl_line(x1--, y1, x2, y2--); + } + } +#endif + // Restore the label... + Fl_Widget::label(savelabel); + set_flag(saveflags); + y(savey); + x(savex); +} + +void Fl_Window::label(const char *name) { + label(name, iconlabel()); +} + +void Fl_Window::copy_label(const char *a) { + if (flags() & COPIED_LABEL) { + free((void *)label()); + clear_flag(COPIED_LABEL); + } + if (a) a = strdup(a); + label(a, iconlabel()); + set_flag(COPIED_LABEL); +} + + +void Fl_Window::iconlabel(const char *iname) { + uchar saveflags = flags(); + label(label(), iname); + set_flag(saveflags); +} + +// the Fl::atclose pointer is provided for back compatability. You +// can now just change the callback for the window instead. + +void Fl::default_atclose(Fl_Window* window, void* v) { + window->hide(); + Fl_Widget::default_callback(window, v); // put on Fl::read_queue() +} + +void (*Fl::atclose)(Fl_Window*, void*) = default_atclose; + +void Fl_Window::default_callback(Fl_Window* win, void* v) { + Fl::atclose(win, v); +} + +Fl_Window *Fl_Window::current() { + return current_; +} + + +// +// End of "$Id: Fl_Window.cxx 5251 2006-06-28 10:23:33Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Window_fullscreen.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Window_fullscreen.cxx new file mode 100644 index 0000000..fc36dc2 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Window_fullscreen.cxx @@ -0,0 +1,97 @@ +// +// "$Id: Fl_Window_fullscreen.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Fullscreen window support for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Turning the border on/off by changing the motif_wm_hints property +// works on Irix 4DWM. Does not appear to work for any other window +// manager. Fullscreen still works on some window managers (fvwm is one) +// because they allow the border to be placed off-screen. + +// Unfortunatly most X window managers ignore changes to the border +// and refuse to position the border off-screen, so attempting to make +// the window full screen will lose the size of the border off the +// bottom and right. + +#include +#include + +#ifdef __APPLE__ +#include +#endif + +void Fl_Window::border(int b) { + if (b) { + if (border()) return; + clear_flag(FL_NOBORDER); + } else { + if (!border()) return; + set_flag(FL_NOBORDER); + } +#ifdef WIN32 + // not yet implemented, but it's possible + // for full fullscreen we have to make the window topmost as well +#elif defined(__APPLE_QD__) + // warning: not implemented in Quickdraw/Carbon +#elif defined(__APPLE_QUARTZ__) + // warning: not implemented in Quartz/Carbon +#else + if (shown()) Fl_X::i(this)->sendxjunk(); +#endif +} + +void Fl_Window::fullscreen() { +#ifndef WIN32 + //this would clobber the fake wm, since it relies on the border flags to + //determine its thickness + border(0); +#endif +#if defined(__APPLE__) || defined(WIN32) + int sx, sy, sw, sh; + Fl::screen_xywh(sx, sy, sw, sh, x()+w()/2, y()+h()/2); + // if we are on the main screen, we will leave the system menu bar unobstructed + if (Fl::x()>=sx && Fl::y()>=sy && Fl::x()+Fl::w()<=sx+sw && Fl::y()+Fl::h()<=sy+sh) { + sx = Fl::x(); sy = Fl::y(); + sw = Fl::w(); sh = Fl::h(); + } + if (x()==sx) x(sx+1); // make sure that we actually execute the resize + resize(sx, sy, sw, sh); +#else + if (!x()) x(1); // force it to call XResizeWindow() + resize(0,0,Fl::w(),Fl::h()); +#endif +} + +void Fl_Window::fullscreen_off(int X,int Y,int W,int H) { + // this order produces less blinking on IRIX: + resize(X,Y,W,H); +#ifndef WIN32 + border(1); +#endif +} + +// +// End of "$Id: Fl_Window_fullscreen.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Window_hotspot.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Window_hotspot.cxx new file mode 100644 index 0000000..493370d --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Window_hotspot.cxx @@ -0,0 +1,100 @@ +// +// "$Id: Fl_Window_hotspot.cxx 5697 2007-02-13 14:38:43Z matt $" +// +// Common hotspot routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include + +void Fl_Window::hotspot(int X, int Y, int offscreen) { + int mx,my; + + // Update the screen position based on the mouse position. + Fl::get_mouse(mx,my); + X = mx-X; Y = my-Y; + + // If offscreen is 0 (the default), make sure that the window + // stays on the screen, if possible. + if (!offscreen) { + int scr_x, scr_y, scr_w, scr_h; + Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h); + + int top = 0; + int left = 0; + int right = 0; + int bottom = 0; + + if (border()) { +#ifdef WIN32 + if (size_range_set && (maxw != minw || maxh != minh)) { + left = right = GetSystemMetrics(SM_CXSIZEFRAME); + top = bottom = GetSystemMetrics(SM_CYSIZEFRAME); + } else { + left = right = GetSystemMetrics(SM_CXFIXEDFRAME); + top = bottom = GetSystemMetrics(SM_CYFIXEDFRAME); + } + top += GetSystemMetrics(SM_CYCAPTION); +#elif defined(__APPLE__) + top = 24; + left = 2; + right = 2; + bottom = 2; +#else + // Ensure border is on screen; these values are generic enough + // to work with many window managers, and are based on KDE defaults. + top = 20; + left = 4; + right = 4; + bottom = 8; +#endif + } + // now insure contents are on-screen (more important than border): + if (X+w()+right > scr_w-scr_x) X = scr_w-scr_x-right-w(); + if (X-left < scr_x) X = left; + if (Y+h()+bottom > scr_h-scr_y) Y = scr_h-scr_y-bottom-h(); + if (Y-top < scr_y) Y = top; + // make sure that we will force this position + if (X==x()) x(X-1); + } + + position(X,Y); +} + +void Fl_Window::hotspot(const Fl_Widget *o, int offscreen) { + int X = o->w()/2; + int Y = o->h()/2; + while (o != this && o) { + X += o->x(); Y += o->y(); + o = o->window(); + } + hotspot(X,Y,offscreen); +} + + +// +// End of "$Id: Fl_Window_hotspot.cxx 5697 2007-02-13 14:38:43Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Window_iconize.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Window_iconize.cxx new file mode 100644 index 0000000..9996b84 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Window_iconize.cxx @@ -0,0 +1,49 @@ +// +// "$Id: Fl_Window_iconize.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Window minification code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include + +extern char fl_show_iconic; // in Fl_x.cxx + +void Fl_Window::iconize() { + if (!shown()) { + fl_show_iconic = 1; + show(); + } else { +#ifdef WIN32 + ShowWindow(i->xid, SW_SHOWMINNOACTIVE); +#elif defined(__APPLE__) + CollapseWindow( i->xid, true ); +#else + XIconifyWindow(fl_display, i->xid, fl_screen); +#endif + } +} + +// +// End of "$Id: Fl_Window_iconize.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_Wizard.cxx b/third_party/windows/fltk-1.1.10/src/Fl_Wizard.cxx new file mode 100644 index 0000000..f5c2d60 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_Wizard.cxx @@ -0,0 +1,210 @@ +// +// "$Id: Fl_Wizard.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Fl_Wizard widget routines. +// +// Copyright 1997-2005 by Easy Software Products. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_Wizard::Fl_Wizard() - Create an Fl_Wizard widget. +// Fl_Wizard::draw() - Draw the wizard border and visible child. +// Fl_Wizard::next() - Show the next child. +// Fl_Wizard::prev() - Show the previous child. +// Fl_Wizard::value() - Return the current visible child. +// Fl_Wizard::value() - Set the visible child. +// + +// +// Include necessary header files... +// + +#include +#include +#include + + +// +// 'Fl_Wizard::Fl_Wizard()' - Create an Fl_Wizard widget. +// + +Fl_Wizard::Fl_Wizard(int xx, // I - Lefthand position + int yy, // I - Upper position + int ww, // I - Width + int hh, // I - Height + const char *l) : // I - Label + Fl_Group(xx, yy, ww, hh, l) +{ + box(FL_THIN_UP_BOX); + + value_ = (Fl_Widget *)0; +} + + +// +// 'Fl_Wizard::draw()' - Draw the wizard border and visible child. +// + +void +Fl_Wizard::draw() +{ + Fl_Widget *kid; // Visible child + + + kid = value(); + + if (damage() & FL_DAMAGE_ALL) + { + // Redraw everything... + if (kid) + { + draw_box(box(), x(), y(), w(), h(), kid->color()); + draw_child(*kid); + } + else + draw_box(box(), x(), y(), w(), h(), color()); + + } + else if (kid) + update_child(*kid); +} + + +// +// 'Fl_Wizard::next()' - Show the next child. +// + +void +Fl_Wizard::next() +{ + int num_kids; + Fl_Widget * const *kids; + + + if ((num_kids = children()) == 0) + return; + + for (kids = array(); num_kids > 0; kids ++, num_kids --) + if ((*kids)->visible()) + break; + + if (num_kids > 1) + value(kids[1]); +} + + +// +// 'Fl_Wizard::prev()' - Show the previous child. +// + + +void +Fl_Wizard::prev() +{ + int num_kids; + Fl_Widget * const *kids; + + + if ((num_kids = children()) == 0) + return; + + for (kids = array(); num_kids > 0; kids ++, num_kids --) + if ((*kids)->visible()) + break; + + if (num_kids > 0 && num_kids < children()) + value(kids[-1]); +} + + +// +// 'Fl_Wizard::value()' - Return the current visible child. +// + +Fl_Widget * +Fl_Wizard::value() +{ + int num_kids; + Fl_Widget * const *kids; + Fl_Widget *kid; + + + if ((num_kids = children()) == 0) + return ((Fl_Widget *)0); + + for (kids = array(), kid = (Fl_Widget *)0; num_kids > 0; kids ++, num_kids --) + { + if ((*kids)->visible()) + { + if (kid) + (*kids)->hide(); + else + kid = *kids; + } + } + + if (!kid) + { + kids --; + kid = *kids; + kid->show(); + } + + return (kid); +} + + +// +// 'Fl_Wizard::value()' - Set the visible child. +// + +void +Fl_Wizard::value(Fl_Widget *kid) +{ + int num_kids; + Fl_Widget * const *kids; + + + if ((num_kids = children()) == 0) + return; + + for (kids = array(); num_kids > 0; kids ++, num_kids --) + { + if (*kids == kid) + { + if (!kid->visible()) + kid->show(); + } + else + (*kids)->hide(); + } + + // This will restore the mouse pointer to the window's default cursor + // whenever the wizard pane is changed. Otherwise text widgets that + // show the next pane may leave the cursor set to the I beam, etc... + if (window()) window()->cursor(FL_CURSOR_DEFAULT); +} + + +// +// End of "$Id: Fl_Wizard.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_XBM_Image.cxx b/third_party/windows/fltk-1.1.10/src/Fl_XBM_Image.cxx new file mode 100644 index 0000000..0254195 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_XBM_Image.cxx @@ -0,0 +1,106 @@ +// +// "$Id: Fl_XBM_Image.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Fl_XBM_Image routines. +// +// Copyright 1997-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// Fl_XBM_Image::Fl_XBM_Image() - Load an XBM file. +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include +#include "flstring.h" + +// +// 'Fl_XBM_Image::Fl_XBM_Image()' - Load an XBM file. +// + +Fl_XBM_Image::Fl_XBM_Image(const char *name) : Fl_Bitmap((const char *)0,0,0) { + FILE *f; + uchar *ptr; + + if ((f = fopen(name, "rb")) == NULL) return; + + char buffer[1024]; + char junk[1024]; + int wh[2]; // width and height + int i; + for (i = 0; i<2; i++) { + for (;;) { + if (!fgets(buffer,1024,f)) { + fclose(f); + return; + } + int r = sscanf(buffer,"#define %s %d",junk,&wh[i]); + if (r >= 2) break; + } + } + + // skip to data array: + for (;;) { + if (!fgets(buffer,1024,f)) { + fclose(f); + return; + } + if (!strncmp(buffer,"static ",7)) break; + } + + // Allocate memory... + w(wh[0]); + h(wh[1]); + + int n = ((wh[0]+7)/8)*wh[1]; + array = new uchar[n]; + + // read the data: + for (i = 0, ptr = (uchar *)array; i < n;) { + if (!fgets(buffer,1024,f)) { + fclose(f); + return; + } + const char *a = buffer; + while (*a && i0) { + *ptr++ = (uchar)t; + i ++; + } + while (*a && *a++ != ','); + } + } + + fclose(f); +} + + +// +// End of "$Id: Fl_XBM_Image.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_XColor.H b/third_party/windows/fltk-1.1.10/src/Fl_XColor.H new file mode 100644 index 0000000..cd14ef8 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_XColor.H @@ -0,0 +1,46 @@ +// +// "$Id: Fl_XColor.H 4288 2005-04-16 00:13:17Z mike $" +// +// X-specific color definitions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2001 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include + +// one of these for each color in fltk's "colormap": +// if overlays are enabled, another one for the overlay +struct Fl_XColor { + unsigned char r,g,b; // actual color used by X + unsigned char mapped; // true when XAllocColor done + unsigned long pixel; // the X pixel to use +}; +extern Fl_XColor fl_xmap[/*overlay*/][256]; + +// mask & shifts to produce xcolor for truecolor visuals: +extern unsigned char fl_redmask, fl_greenmask, fl_bluemask; +extern int fl_redshift, fl_greenshift, fl_blueshift, fl_extrashift; + +// +// End of "$Id: Fl_XColor.H 4288 2005-04-16 00:13:17Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_XPM_Image.cxx b/third_party/windows/fltk-1.1.10/src/Fl_XPM_Image.cxx new file mode 100644 index 0000000..a09e479 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_XPM_Image.cxx @@ -0,0 +1,131 @@ +// +// "$Id: Fl_XPM_Image.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Fl_XPM_Image routines. +// +// Copyright 1997-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include +#include "flstring.h" + + +// +// 'hexdigit()' - Convert a hex digit to an integer. +// + +static int hexdigit(int x) { // I - Hex digit... + if (isdigit(x)) return x-'0'; + if (isupper(x)) return x-'A'+10; + if (islower(x)) return x-'a'+10; + return 20; +} + +#define MAXSIZE 2048 +#define INITIALLINES 256 + +Fl_XPM_Image::Fl_XPM_Image(const char *name) : Fl_Pixmap((char *const*)0) { + FILE *f; + + if ((f = fopen(name, "rb")) == NULL) return; + + // read all the c-strings out of the file: + char** new_data = new char *[INITIALLINES]; + char** temp_data; + int malloc_size = INITIALLINES; + char buffer[MAXSIZE+20]; + int i = 0; + while (fgets(buffer,MAXSIZE+20,f)) { + if (buffer[0] != '\"') continue; + char *myp = buffer; + char *q = buffer+1; + while (*q != '\"' && myp < buffer+MAXSIZE) { + if (*q == '\\') switch (*++q) { + case '\r': + case '\n': + fgets(q,(buffer+MAXSIZE+20)-q,f); break; + case 0: + break; + case 'x': { + q++; + int n = 0; + for (int x = 0; x < 3; x++) { + int xd = hexdigit(*q); + if (xd > 15) break; + n = (n<<4)+xd; + q++; + } + *myp++ = n; + } break; + default: { + int c = *q++; + if (c>='0' && c<='7') { + c -= '0'; + for (int x=0; x<2; x++) { + int xd = hexdigit(*q); + if (xd>7) break; + c = (c<<3)+xd; + q++; + } + } + *myp++ = c; + } break; + } else { + *myp++ = *q++; + } + } + *myp++ = 0; + if (i >= malloc_size) { + temp_data = new char *[malloc_size + INITIALLINES]; + memcpy(temp_data, new_data, sizeof(char *) * malloc_size); + delete[] new_data; + new_data = temp_data; + malloc_size += INITIALLINES; + } + new_data[i] = new char[myp-buffer+1]; + memcpy(new_data[i], buffer,myp-buffer); + new_data[i][myp-buffer] = 0; + i++; + } + + fclose(f); + + data((const char **)new_data, i); + alloc_data = 1; + + measure(); +} + + +// +// End of "$Id: Fl_XPM_Image.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_abort.cxx b/third_party/windows/fltk-1.1.10/src/Fl_abort.cxx new file mode 100644 index 0000000..db9a7bc --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_abort.cxx @@ -0,0 +1,102 @@ +// +// "$Id: Fl_abort.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Warning/error message code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This method is in it's own source file so that stdlib and stdio +// do not need to be included in Fl.cxx: +// You can also override this by redefining all of these. + +#include +#include +#include +#include +#include "flstring.h" + +#ifdef WIN32 +# include + +static void warning(const char *, ...) { + // Show nothing for warnings under WIN32... +} + +static void error(const char *format, ...) { + va_list args; + char buf[1024]; + va_start(args, format); + vsnprintf(buf, 1024, format, args); + va_end(args); + MessageBox(0,buf,"Error",MB_ICONEXCLAMATION|MB_SYSTEMMODAL); +} + +static void fatal(const char *format, ...) { + va_list args; + char buf[1024]; + va_start(args, format); + vsnprintf(buf, 1024, format, args); + va_end(args); + MessageBox(0,buf,"Error",MB_ICONSTOP|MB_SYSTEMMODAL); + ::exit(1); +} + +#else + +static void warning(const char *format, ...) { + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fputc('\n', stderr); + fflush(stderr); +} + +static void error(const char *format, ...) { + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fputc('\n', stderr); + fflush(stderr); +} + +static void fatal(const char *format, ...) { + va_list args; + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fputc('\n', stderr); + fflush(stderr); + ::exit(1); +} + +#endif + +void (*Fl::warning)(const char* format, ...) = ::warning; +void (*Fl::error)(const char* format, ...) = ::error; +void (*Fl::fatal)(const char* format, ...) = ::fatal; + +// +// End of "$Id: Fl_abort.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_add_idle.cxx b/third_party/windows/fltk-1.1.10/src/Fl_add_idle.cxx new file mode 100644 index 0000000..495bb89 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_add_idle.cxx @@ -0,0 +1,100 @@ +// +// "$Id: Fl_add_idle.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Idle routine support for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Allows you to manage an arbitrary set of idle() callbacks. +// Replaces the older set_idle() call (which is used to implement this) + +#include + +struct idle_cb { + void (*cb)(void*); + void* data; + idle_cb *next; +}; + +// the callbacks are stored linked in a ring. last points at the one +// just called, first at the next to call. last->next == first. + +static idle_cb* first; +static idle_cb* last; +static idle_cb* freelist; + +static void call_idle() { + idle_cb* p = first; + last = p; first = p->next; + p->cb(p->data); // this may call add_idle() or remove_idle()! +} + +void Fl::add_idle(void (*cb)(void*), void* data) { + idle_cb* p = freelist; + if (p) freelist = p->next; + else p = new idle_cb; + p->cb = cb; + p->data = data; + if (first) { + last->next = p; + last = p; + p->next = first; + } else { + first = last = p; + p->next = p; + set_idle(call_idle); + } +} + +int Fl::has_idle(void (*cb)(void*), void* data) { + idle_cb* p = first; + if (!p) return 0; + for (;; p = p->next) { + if (p->cb == cb && p->data == data) return 1; + if (p==last) return 0; + } +} + +void Fl::remove_idle(void (*cb)(void*), void* data) { + idle_cb* p = first; + if (!p) return; + idle_cb* l = last; + for (;; p = p->next) { + if (p->cb == cb && p->data == data) break; + if (p==last) return; // not found + l = p; + } + if (l == p) { // only one + first = last = 0; + set_idle(0); + } else { + last = l; + first = l->next = p->next; + } + p->next = freelist; + freelist = p; +} + +// +// End of "$Id: Fl_add_idle.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_arg.cxx b/third_party/windows/fltk-1.1.10/src/Fl_arg.cxx new file mode 100644 index 0000000..1733c8f --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_arg.cxx @@ -0,0 +1,424 @@ +// +// "$Id: Fl_arg.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Optional argument initialization code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// OPTIONAL initialization code for a program using fltk. +// You do not need to call this! Feel free to make up your own switches. + +#include +#include +#include +#include +#include +#include +#include +#include "flstring.h" + +#if defined(WIN32) || defined(__APPLE__) +int XParseGeometry(const char*, int*, int*, unsigned int*, unsigned int*); +# define NoValue 0x0000 +# define XValue 0x0001 +# define YValue 0x0002 +# define WidthValue 0x0004 +# define HeightValue 0x0008 +# define AllValues 0x000F +# define XNegative 0x0010 +# define YNegative 0x0020 +#endif + +static int fl_match(const char *a, const char *s, int atleast = 1) { + const char *b = s; + while (*a && (*a == *b || tolower(*a) == *b)) {a++; b++;} + return !*a && b >= s+atleast; +} + +// flags set by previously parsed arguments: +extern char fl_show_iconic; // in Fl_x.cxx +static char arg_called; +static char return_i; +static const char *name; +static const char *geometry; +static const char *title; +// these are in Fl_get_system_colors and are set by the switches: +extern const char *fl_fg; +extern const char *fl_bg; +extern const char *fl_bg2; + +// consume a switch from argv. Returns number of words eaten, 0 on error: +int Fl::arg(int argc, char **argv, int &i) { + arg_called = 1; + const char *s = argv[i]; + + if (!s) {i++; return 1;} // something removed by calling program? + + // a word that does not start with '-', or a word after a '--', or + // the word '-' by itself all start the "non-switch arguments" to + // a program. Return 0 to indicate that we don't understand the + // word, but set a flag (return_i) so that args() will return at + // that point: + if (s[0] != '-' || s[1] == '-' || !s[1]) {return_i = 1; return 0;} + s++; // point after the dash + + if (fl_match(s, "iconic")) { + fl_show_iconic = 1; + i++; + return 1; + } else if (fl_match(s, "kbd")) { + Fl::visible_focus(1); + i++; + return 1; + } else if (fl_match(s, "nokbd", 3)) { + Fl::visible_focus(0); + i++; + return 1; + } else if (fl_match(s, "dnd", 2)) { + Fl::dnd_text_ops(1); + i++; + return 1; + } else if (fl_match(s, "nodnd", 3)) { + Fl::dnd_text_ops(0); + i++; + return 1; + } else if (fl_match(s, "tooltips", 2)) { + Fl_Tooltip::enable(); + i++; + return 1; + } else if (fl_match(s, "notooltips", 3)) { + Fl_Tooltip::disable(); + i++; + return 1; + } +#ifdef __APPLE__ + // The Finder application in MacOS X passes the "-psn_N_NNNNN" option + // to all apps... + else if (strncmp(s, "psn_", 4) == 0) { + i++; + return 1; + } +#endif // __APPLE__ + + const char *v = argv[i+1]; + if (i >= argc-1 || !v) + return 0; // all the rest need an argument, so if missing it is an error + + if (fl_match(s, "geometry")) { + + int flags, gx, gy; unsigned int gw, gh; + flags = XParseGeometry(v, &gx, &gy, &gw, &gh); + if (!flags) return 0; + geometry = v; + +#if !defined(WIN32) && !defined(__APPLE__) + } else if (fl_match(s, "display", 2)) { + Fl::display(v); +#endif + + } else if (fl_match(s, "title", 2)) { + title = v; + + } else if (fl_match(s, "name", 2)) { + name = v; + + } else if (fl_match(s, "bg2", 3) || fl_match(s, "background2", 11)) { + fl_bg2 = v; + + } else if (fl_match(s, "bg", 2) || fl_match(s, "background", 10)) { + fl_bg = v; + + } else if (fl_match(s, "fg", 2) || fl_match(s, "foreground", 10)) { + fl_fg = v; + + } else if (fl_match(s, "scheme", 1)) { + Fl::scheme(v); + + } else return 0; // unrecognized + + i += 2; + return 2; +} + +// consume all switches from argv. Returns number of words eaten. +// Returns zero on error. 'i' will either point at first word that +// does not start with '-', at the error word, or after a '--', or at +// argc. If your program does not take any word arguments you can +// report an error if i < argc. + +int Fl::args(int argc, char** argv, int& i, int (*cb)(int,char**,int&)) { + arg_called = 1; + i = 1; // skip argv[0] + while (i < argc) { + if (cb && cb(argc,argv,i)) continue; + if (!arg(argc,argv,i)) return return_i ? i : 0; + } + return i; +} + +// show a main window, use any parsed arguments +void Fl_Window::show(int argc, char **argv) { + if (argc && !arg_called) Fl::args(argc,argv); + + Fl::get_system_colors(); + +#if !defined(WIN32) && !defined(__APPLE__) + // Get defaults for drag-n-drop and focus... + const char *key = 0, *val; + + if (Fl::first_window()) key = Fl::first_window()->xclass(); + if (!key) key = "fltk"; + + val = XGetDefault(fl_display, key, "dndTextOps"); + if (val) Fl::dnd_text_ops(strcasecmp(val, "true") == 0 || + strcasecmp(val, "on") == 0 || + strcasecmp(val, "yes") == 0); + + val = XGetDefault(fl_display, key, "tooltips"); + if (val) Fl_Tooltip::enable(strcasecmp(val, "true") == 0 || + strcasecmp(val, "on") == 0 || + strcasecmp(val, "yes") == 0); + + val = XGetDefault(fl_display, key, "visibleFocus"); + if (val) Fl::visible_focus(strcasecmp(val, "true") == 0 || + strcasecmp(val, "on") == 0 || + strcasecmp(val, "yes") == 0); +#endif // !WIN32 && !__APPLE__ + + // set colors first, so background_pixel is correct: + static char beenhere; + if (!beenhere) { + if (geometry) { + int fl = 0, gx = x(), gy = y(); unsigned int gw = w(), gh = h(); + fl = XParseGeometry(geometry, &gx, &gy, &gw, &gh); + if (fl & XNegative) gx = Fl::w()-w()+gx; + if (fl & YNegative) gy = Fl::h()-h()+gy; + // int mw,mh; minsize(mw,mh); + // if (mw > gw) gw = mw; + // if (mh > gh) gh = mh; + Fl_Widget *r = resizable(); + if (!r) resizable(this); + // for WIN32 we assumme window is not mapped yet: + if (fl & (XValue | YValue)) + x(-1), resize(gx,gy,gw,gh); + else + size(gw,gh); + resizable(r); + } + } + + // set the class, which is used by X version of get_system_colors: + if (name) {xclass(name); name = 0;} + else if (!xclass()) xclass(fl_filename_name(argv[0])); + + if (title) {label(title); title = 0;} + else if (!label()) label(xclass()); + + if (!beenhere) { + beenhere = 1; + Fl::scheme(Fl::scheme()); // opens display! May call Fl::fatal() + } + + // Show the window AFTER we have set the colors and scheme. + show(); + +#if !defined(WIN32) && !defined(__APPLE__) + // set the command string, used by state-saving window managers: + int j; + int n=0; for (j=0; jx{+-}{+-}", where + * width, height, xoffset, and yoffset are unsigned integers. + * Example: "=80x24+300-49" + * The equal sign is optional. + * It returns a bitmask that indicates which of the four values + * were actually found in the string. For each value found, + * the corresponding argument is updated; for each value + * not found, the corresponding argument is left unchanged. + */ + +static int ReadInteger(char* string, char** NextString) +{ + register int Result = 0; + int Sign = 1; + + if (*string == '+') + string++; + else if (*string == '-') { + string++; + Sign = -1; + } + for (; (*string >= '0') && (*string <= '9'); string++) { + Result = (Result * 10) + (*string - '0'); + } + *NextString = string; + if (Sign >= 0) + return (Result); + else + return (-Result); +} + +int XParseGeometry(const char* string, int* x, int* y, + unsigned int* width, unsigned int* height) +{ + int mask = NoValue; + register char *strind; + unsigned int tempWidth = 0, tempHeight = 0; + int tempX = 0, tempY = 0; + char *nextCharacter; + + if ( (string == NULL) || (*string == '\0')) return(mask); + if (*string == '=') + string++; /* ignore possible '=' at beg of geometry spec */ + + strind = (char *)string; + if (*strind != '+' && *strind != '-' && *strind != 'x') { + tempWidth = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return (0); + strind = nextCharacter; + mask |= WidthValue; + } + + if (*strind == 'x' || *strind == 'X') { + strind++; + tempHeight = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return (0); + strind = nextCharacter; + mask |= HeightValue; + } + + if ((*strind == '+') || (*strind == '-')) { + if (*strind == '-') { + strind++; + tempX = -ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return (0); + strind = nextCharacter; + mask |= XNegative; + + } else { + strind++; + tempX = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return(0); + strind = nextCharacter; + } + mask |= XValue; + if ((*strind == '+') || (*strind == '-')) { + if (*strind == '-') { + strind++; + tempY = -ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return(0); + strind = nextCharacter; + mask |= YNegative; + + } else { + strind++; + tempY = ReadInteger(strind, &nextCharacter); + if (strind == nextCharacter) + return(0); + strind = nextCharacter; + } + mask |= YValue; + } + } + + /* If strind isn't at the end of the string the it's an invalid + geometry specification. */ + + if (*strind != '\0') return (0); + + if (mask & XValue) + *x = tempX; + if (mask & YValue) + *y = tempY; + if (mask & WidthValue) + *width = tempWidth; + if (mask & HeightValue) + *height = tempHeight; + return (mask); +} + +#endif // ifdef WIN32 + +// +// End of "$Id: Fl_arg.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_compose.cxx b/third_party/windows/fltk-1.1.10/src/Fl_compose.cxx new file mode 100644 index 0000000..b884b8f --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_compose.cxx @@ -0,0 +1,223 @@ +// +// "$Id: Fl_compose.cxx 5211 2006-06-19 07:43:39Z matt $" +// +// Character compose processing for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include + +// +// MRS: Uncomment the following define to get the original (pre-1.1.2) +// dead key support code. The original code apparently did not +// work on Belgian keyboards. +// + +//#define OLD_DEAD_KEY_CODE + + +#ifdef __APPLE__ + +static const char* const compose_pairs = +":A*A,C'E~N:O:U'a`a^a:a~a*a,c'e`e" +"^e:e'i`i^i:i~n'o`o^o:o~o'u`u^u:u" +"+ o /c# SS* P|ssrOcOTM' : !=AE/O" +"oo+-<=>=Y=mudtSgPipiS a dgOmaeo/" +"? ! !!v-f ~~Dt<<>>.. `A~A~OOEoe" +"- --''``\"'\"`:-^V:y:Y//E=< > fifl" +"++..,,_\"%%^A^E'A:E`E'I^I:I`I'O^O" +"mc`O'U^U`U||^ ~^_ u . * , ~-; v "; + +#else + +static const char* const compose_pairs = +"=E _'f _\"..+ ++^ %%^S< OE ^Z ^''^^\"\"^-*- --~ TM^s> oe ^z:Y" +" ! % # $ y=| & : c a <<~ - r _ * +-2 3 ' u p . , 1 o >>141234? " +"`A'A^A~A:A*AAE,C`E'E^E:E`I'I^I:I-D~N`O'O^O~O:Ox O/`U'U^U:U'YTHss" +"`a'a^a~a:a*aae,c`e'e^e:e`i'i^i:i-d~n`o'o^o~o:o-:o/`u'u^u:u'yth:y"; + +#endif + +#if !defined(WIN32) && defined(OLD_DEAD_KEY_CODE) // X only +// X dead-key lookup table. This turns a dead-key keysym into the +// first of two characters for one of the compose sequences. These +// keysyms start at 0xFE50. +// Win32 handles the dead keys before FLTK can see them. This is +// unfortunate, because you don't get the preview effect. +static char dead_keys[] = { + '`', // XK_dead_grave + '\'', // XK_dead_acute + '^', // XK_dead_circumflex + '~', // XK_dead_tilde + '_', // XK_dead_macron + 0, // XK_dead_breve + '.', // XK_dead_abovedot + ':', // XK_dead_diaeresis + '*', // XK_dead_abovering + 0, // XK_dead_doubleacute + 'v', // XK_dead_caron + ',' // XK_dead_cedilla +// 0, // XK_dead_ogonek +// 0, // XK_dead_iota +// 0, // XK_dead_voiced_sound +// 0, // XK_dead_semivoiced_sound +// 0 // XK_dead_belowdot +}; +#endif // !WIN32 && OLD_DEAD_KEY_CODE + +int Fl::compose_state = 0; + +int Fl::compose(int& del) { + + del = 0; + unsigned char ascii = (unsigned)e_text[0]; + + // Alt+letters are reserved for shortcuts. But alt+foreign letters + // has to be allowed, because some key layouts require alt to be held + // down in order to type them... + // + // OSX users sometimes need to hold down ALT for keys, so we only check + // for META on OSX... +#ifdef __APPLE__ + if ((e_state & FL_META) && !(ascii & 128)) return 0; +#else + if ((e_state & (FL_ALT|FL_META)) && !(ascii & 128)) return 0; +#endif // __APPLE__ + + if (compose_state == 1) { // after the compose key + if ( // do not get distracted by any modifier keys + e_keysym==FL_Shift_L|| + e_keysym==FL_Shift_R || + e_keysym==FL_Alt_L || + e_keysym==FL_Alt_R || + e_keysym==FL_Meta_L || + e_keysym==FL_Meta_R || + e_keysym==FL_Control_R || + e_keysym==FL_Control_L || + e_keysym==FL_Menu + ) return 0; + + if (ascii == ' ') { // space turns into nbsp +#ifdef __APPLE__ + e_text[0] = char(0xCA); +#else + e_text[0] = char(0xA0); +#endif + compose_state = 0; + return 1; + } else if (ascii < ' ' || ascii == 127) { + compose_state = 0; + return 0; + } + + // see if it is either character of any pair: + for (const char *p = compose_pairs; *p; p += 2) + if (p[0] == ascii || p[1] == ascii) { + if (p[1] == ' ') e_text[0] = (p-compose_pairs)/2+0x80; + compose_state = ascii; + return 1; + } + + if (e_length) { // compose key also "quotes" control characters + compose_state = 0; + return 1; + } + + } else if (compose_state) { // second character of compose + + char c1 = char(compose_state); // retrieve first character +#ifdef __APPLE__ + if ( (c1==0x60 && ascii==0xab) || (c1==0x27 && ascii==0x60)) { + del = 1; + compose_state = '^'; + e_text[0] = 0xf6; + return 1; + } + if (ascii==' ') { + del = 0; + compose_state = 0; + return 0; + } +#endif + // now search for the pair in either order: + for (const char *p = compose_pairs; *p; p += 2) { + if (p[0] == ascii && p[1] == c1 || p[1] == ascii && p[0] == c1) { + e_text[0] = (p-compose_pairs)/2+0x80; + del = 1; // delete the old character and insert new one + compose_state = 0; + return 1; + } + } + + } + + int i = e_keysym; + + // See if they type the compose prefix key: + if (i == FL_Control_R || i == 0xff20/* Multi-Key */) { + compose_state = 1; + return 1; + } + +#ifdef WIN32 +#elif (defined __APPLE__) + if (e_state & 0x40000000) { + if (ascii<0x80) + compose_state = ascii; + else + compose_state = compose_pairs[(ascii-0x80)*2]; + return 1; + } +#else + // See if they typed a dead key. This gets it into the same state as + // typing prefix+accent: + if (i >= 0xfe50 && i <= 0xfe5b) { +# ifdef OLD_DEAD_KEY_CODE + ascii = dead_keys[i-0xfe50]; + for (const char *p = compose_pairs; *p; p += 2) + if (p[0] == ascii) { + compose_state = ascii; + return 1; + } +# else + ascii = e_text[0]; + for (const char *p = compose_pairs; *p; p += 2) + if (p[0] == ascii || + (p[1] == ' ' && (p - compose_pairs) / 2 + 0x80 == ascii)) { + compose_state = p[0]; + return 1; + } +# endif // OLD_DEAD_KEY_CODE + compose_state = 0; + return 1; + } +#endif + + // Only insert non-control characters: + if (e_length && (ascii & ~31 && ascii!=127)) {compose_state = 0; return 1;} + + return 0; +} + + + diff --git a/third_party/windows/fltk-1.1.10/src/Fl_display.cxx b/third_party/windows/fltk-1.1.10/src/Fl_display.cxx new file mode 100644 index 0000000..d0db51e --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_display.cxx @@ -0,0 +1,54 @@ +// +// "$Id: Fl_display.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Display function for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Startup method to set what display to use. +// Using setenv makes programs that are exec'd use the same display. + +#include +#include +#include "flstring.h" + +void Fl::display(const char *d) { +#if defined(__APPLE__) || defined(WIN32) + (void)d; +#else + static char e[1024]; + strcpy(e,"DISPLAY="); + strlcat(e,d,sizeof(e)); + for (char *c = e+8; *c!=':'; c++) { + if (!*c) { + strlcat(e,":0.0",sizeof(e)); + break; + } + } + putenv(e); +#endif // __APPLE__ +} + +// +// End of "$Id: Fl_display.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_get_key.cxx b/third_party/windows/fltk-1.1.10/src/Fl_get_key.cxx new file mode 100644 index 0000000..3536ce2 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_get_key.cxx @@ -0,0 +1,69 @@ +// +// "$Id: Fl_get_key.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Keyboard state routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#ifdef WIN32 +# include "Fl_get_key_win32.cxx" +#elif defined(__APPLE__) +# include "Fl_get_key_mac.cxx" +#else + +// Return the current state of a key. This is the X version. I identify +// keys (mostly) by the X keysym. So this turns the keysym into a keycode +// and looks it up in the X key bit vector, which Fl_x.cxx keeps track of. + +# include +# include + +extern char fl_key_vector[32]; // in Fl_x.cxx + +int Fl::event_key(int k) { + if (k > FL_Button && k <= FL_Button+8) + return Fl::event_state(8<<(k-FL_Button)); + int i; +# ifdef __sgi + // get some missing PC keyboard keys: + if (k == FL_Meta_L) i = 147; + else if (k == FL_Meta_R) i = 148; + else if (k == FL_Menu) i = 149; + else +# endif + i = XKeysymToKeycode(fl_display, k); + if (i==0) return 0; + return fl_key_vector[i/8] & (1 << (i%8)); +} + +int Fl::get_key(int k) { + fl_open_display(); + XQueryKeymap(fl_display, fl_key_vector); + return event_key(k); +} + +#endif + +// +// End of "$Id: Fl_get_key.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_get_key_mac.cxx b/third_party/windows/fltk-1.1.10/src/Fl_get_key_mac.cxx new file mode 100644 index 0000000..02dd22b --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_get_key_mac.cxx @@ -0,0 +1,110 @@ +// +// "$Id: Fl_get_key_mac.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// MacOS keyboard state routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Return the current state of a key. Keys are named by fltk symbols, +// which are actually X keysyms. So this has to translate to macOS +// symbols. + +#include +#include +#include + +// convert an FLTK (X) keysym to a MacOS symbol: +// See also the inverse converter in Fl_mac.cxx +// This table is in numeric order by FLTK symbol order for binary search: + +static const struct {unsigned short vk, fltk;} vktab[] = { + { 49, ' ' }, { 39, '\'' }, { 43, ',' }, { 27, '-' }, { 47, '.' }, { 44, '/' }, + { 29, '0' }, { 18, '1' }, { 19, '2' }, { 20, '3' }, + { 21, '4' }, { 23, '5' }, { 22, '6' }, { 26, '7' }, + { 28, '8' }, { 25, '9' }, { 41, ';' }, { 24, '=' }, + { 0, 'A' }, { 11, 'B' }, { 8, 'C' }, { 2, 'D' }, + { 14, 'E' }, { 3, 'F' }, { 5, 'G' }, { 4, 'H' }, + { 34, 'I' }, { 38, 'J' }, { 40, 'K' }, { 37, 'L' }, + { 46, 'M' }, { 45, 'N' }, { 31, 'O' }, { 35, 'P' }, + { 12, 'Q' }, { 15, 'R' }, { 1, 'S' }, { 17, 'T' }, + { 32, 'U' }, { 9, 'V' }, { 13, 'W' }, { 7, 'X' }, + { 16, 'Y' }, { 6, 'Z' }, + { 33, '[' }, { 30, ']' }, { 50, '`' }, { 42, '|' }, + { 51, FL_BackSpace }, { 48, FL_Tab }, { 36, FL_Enter }, { 127, FL_Pause }, + { 107, FL_Scroll_Lock }, { 53, FL_Escape }, { 0x73, FL_Home }, { 123, FL_Left }, + { 126, FL_Up }, { 124, FL_Right }, { 125, FL_Down }, { 0x74, FL_Page_Up }, + { 0x79, FL_Page_Down }, { 119, FL_End }, { 0x71, FL_Print }, { 127, FL_Insert }, + { 0x6e, FL_Menu }, { 114, FL_Help }, { 0x47, FL_Num_Lock }, + { 76, FL_KP_Enter }, { 67, FL_KP+'*' }, { 69, FL_KP+'+'}, { 78, FL_KP+'-' }, { 65, FL_KP+'.' }, { 75, FL_KP+'/' }, + { 82, FL_KP+'0' }, { 83, FL_KP+'1' }, { 84, FL_KP+'2' }, { 85, FL_KP+'3' }, + { 86, FL_KP+'4' }, { 87, FL_KP+'5' }, { 88, FL_KP+'6' }, { 89, FL_KP+'7' }, + { 91, FL_KP+'8' }, { 92, FL_KP+'9' }, { 81, FL_KP+'=' }, + { 0x7a, FL_F+1 }, { 0x78, FL_F+2 }, { 0x63, FL_F+3 }, { 0x76, FL_F+4 }, + { 0x60, FL_F+5 }, { 0x61, FL_F+6 }, { 0x62, FL_F+7 }, { 0x64, FL_F+8 }, + { 0x65, FL_F+9 }, { 0x6D, FL_F+10 }, { 0x67, FL_F+11 }, { 0x6f, FL_F+12 }, + { 56, FL_Shift_L }, { 56, FL_Shift_R }, { 59, FL_Control_L }, { 59, FL_Control_R }, + { 57, FL_Caps_Lock }, { 55, FL_Meta_L }, { 55, FL_Meta_R }, + { 58, FL_Alt_L }, { 58, FL_Alt_R }, { 0x75, FL_Delete }, +}; + +static int fltk2mac(int fltk) { + int a = 0; + int b = sizeof(vktab)/sizeof(*vktab); + while (a < b) { + int c = (a+b)/2; + if (vktab[c].fltk == fltk) return vktab[c].vk; + if (vktab[c].fltk < fltk) a = c+1; else b = c; + } + return 127; +} + +//: returns true, if that key was pressed during the last event +int Fl::event_key(int k) { + return get_key(k); +} + +#include + +//: returns true, if that key is pressed right now +int Fl::get_key(int k) { + KeyMap foo; + GetKeys(foo); +#ifdef MAC_TEST_FOR_KEYCODES + static int cnt = 0; + if (cnt++>1024) { + cnt = 0; + printf("%08x %08x %08x %08x\n", (ulong*)(foo)[3], (ulong*)(foo)[2], (ulong*)(foo)[1], (ulong*)(foo)[0]); + } +#endif + unsigned char *b = (unsigned char*)foo; + // KP_Enter can be at different locations for Powerbooks vs. desktop Macs + if (k==FL_KP_Enter) { + return (((b[0x34>>3]>>(0x34&7))&1)||((b[0x4c>>3]>>(0x4c&7))&1)); + } + int i = fltk2mac(k); + return (b[i>>3]>>(i&7))&1; +} + +// +// End of "$Id: Fl_get_key_mac.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_get_key_win32.cxx b/third_party/windows/fltk-1.1.10/src/Fl_get_key_win32.cxx new file mode 100644 index 0000000..0970848 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_get_key_win32.cxx @@ -0,0 +1,138 @@ +// +// "$Id: Fl_get_key_win32.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// WIN32 keyboard state routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Return the current state of a key. Keys are named by fltk symbols, +// which are actually X keysyms. So this has to translate to MSWindows +// VK_x symbols. + +#include +#include + +// convert an Fltk (X) keysym to a MSWindows VK symbol: +// See also the inverse converter in Fl_win32.cxx +// This table is in numeric order by Fltk symbol order for binary search: + +static const struct {unsigned short vk, fltk;} vktab[] = { + {VK_SPACE, ' '}, + {'1', '!'}, + {0xde, '\"'}, + {'3', '#'}, + {'4', '$'}, + {'5', '%'}, + {'7', '&'}, + {0xde, '\''}, + {'9', '('}, + {'0', ')'}, + {'8', '*'}, + {0xbb, '+'}, + {0xbc, ','}, + {0xbd, '-'}, + {0xbe, '.'}, + {0xbf, '/'}, + {0xba, ':'}, + {0xba, ';'}, + {0xbc, '<'}, + {0xbb, '='}, + {0xbe, '>'}, + {0xbf, '?'}, + {'2', '@'}, + {0xdb, '['}, + {0xdc, '\\'}, + {0xdd, ']'}, + {'6', '^'}, + {0xbd, '_'}, + {0xc0, '`'}, + {0xdb, '{'}, + {0xdc, '|'}, + {0xdd, '}'}, + {0xc0, '~'}, + {VK_BACK, FL_BackSpace}, + {VK_TAB, FL_Tab}, + {VK_CLEAR, 0xff0b/*XK_Clear*/}, + {VK_RETURN, FL_Enter}, + {VK_PAUSE, FL_Pause}, + {VK_SCROLL, FL_Scroll_Lock}, + {VK_ESCAPE, FL_Escape}, + {VK_HOME, FL_Home}, + {VK_LEFT, FL_Left}, + {VK_UP, FL_Up}, + {VK_RIGHT, FL_Right}, + {VK_DOWN, FL_Down}, + {VK_PRIOR, FL_Page_Up}, + {VK_NEXT, FL_Page_Down}, + {VK_END, FL_End}, + {VK_SNAPSHOT, FL_Print}, + {VK_INSERT, FL_Insert}, + {VK_APPS, FL_Menu}, + {VK_NUMLOCK, FL_Num_Lock}, +//{VK_???, FL_KP_Enter}, + {VK_MULTIPLY, FL_KP+'*'}, + {VK_ADD, FL_KP+'+'}, + {VK_SUBTRACT, FL_KP+'-'}, + {VK_DECIMAL, FL_KP+'.'}, + {VK_DIVIDE, FL_KP+'/'}, + {VK_LSHIFT, FL_Shift_L}, + {VK_RSHIFT, FL_Shift_R}, + {VK_LCONTROL, FL_Control_L}, + {VK_RCONTROL, FL_Control_R}, + {VK_CAPITAL, FL_Caps_Lock}, + {VK_LWIN, FL_Meta_L}, + {VK_RWIN, FL_Meta_R}, + {VK_LMENU, FL_Alt_L}, + {VK_RMENU, FL_Alt_R}, + {VK_DELETE, FL_Delete} +}; + +static int fltk2ms(int fltk) { + if (fltk >= '0' && fltk <= '9') return fltk; + if (fltk >= 'A' && fltk <= 'Z') return fltk; + if (fltk >= 'a' && fltk <= 'z') return fltk-('a'-'A'); + if (fltk > FL_F && fltk <= FL_F+16) return fltk-(FL_F-(VK_F1-1)); + if (fltk >= FL_KP+'0' && fltk<=FL_KP+'9') return fltk-(FL_KP+'0'-VK_NUMPAD0); + int a = 0; + int b = sizeof(vktab)/sizeof(*vktab); + while (a < b) { + int c = (a+b)/2; + if (vktab[c].fltk == fltk) return vktab[c].vk; + if (vktab[c].fltk < fltk) a = c+1; else b = c; + } + return 0; +} + +int Fl::event_key(int k) { + return GetKeyState(fltk2ms(k))&~1; +} + +int Fl::get_key(int k) { + uchar foo[256]; + GetKeyboardState(foo); + return foo[fltk2ms(k)]&~1; +} + +// +// End of "$Id: Fl_get_key_win32.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_get_system_colors.cxx b/third_party/windows/fltk-1.1.10/src/Fl_get_system_colors.cxx new file mode 100644 index 0000000..2c8b46e --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_get_system_colors.cxx @@ -0,0 +1,386 @@ +// +// "$Id: Fl_get_system_colors.cxx 5699 2007-02-20 17:02:41Z matt $" +// +// System color support for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include +#include "flstring.h" +#include +#include +#include +#include +#include "tile.xpm" + +#if defined(__APPLE__) && defined(__MWERKS__) +extern "C" int putenv(const char*); +#endif // __APPLE__ && __MWERKS__ + +#if defined(WIN32) && !defined(__CYGWIN__) && !defined(__WATCOMC__) +// Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs +// on Windows, which is supposed to be POSIX compliant... +# define putenv _putenv +#endif // WIN32 && !__CYGWIN__ + +static char fl_bg_set = 0; +static char fl_bg2_set = 0; +static char fl_fg_set = 0; + + +void Fl::background(uchar r, uchar g, uchar b) { + fl_bg_set = 1; + + // replace the gray ramp so that FL_GRAY is this color + if (!r) r = 1; else if (r==255) r = 254; + double powr = log(r/255.0)/log((FL_GRAY-FL_GRAY_RAMP)/(FL_NUM_GRAY-1.0)); + if (!g) g = 1; else if (g==255) g = 254; + double powg = log(g/255.0)/log((FL_GRAY-FL_GRAY_RAMP)/(FL_NUM_GRAY-1.0)); + if (!b) b = 1; else if (b==255) b = 254; + double powb = log(b/255.0)/log((FL_GRAY-FL_GRAY_RAMP)/(FL_NUM_GRAY-1.0)); + for (int i = 0; i < FL_NUM_GRAY; i++) { + double gray = i/(FL_NUM_GRAY-1.0); + Fl::set_color(fl_gray_ramp(i), + uchar(pow(gray,powr)*255+.5), + uchar(pow(gray,powg)*255+.5), + uchar(pow(gray,powb)*255+.5)); + } +} + +void Fl::foreground(uchar r, uchar g, uchar b) { + fl_fg_set = 1; + + Fl::set_color(FL_FOREGROUND_COLOR,r,g,b); +} + +void Fl::background2(uchar r, uchar g, uchar b) { + fl_bg2_set = 1; + + Fl::set_color(FL_BACKGROUND2_COLOR,r,g,b); + Fl::set_color(FL_FOREGROUND_COLOR, + get_color(fl_contrast(FL_FOREGROUND_COLOR,FL_BACKGROUND2_COLOR))); +} + +// these are set by Fl::args() and override any system colors: +const char *fl_fg = NULL; +const char *fl_bg = NULL; +const char *fl_bg2 = NULL; + +static void set_selection_color(uchar r, uchar g, uchar b) { + Fl::set_color(FL_SELECTION_COLOR,r,g,b); +} + +#if defined(WIN32) || defined(__APPLE__) + +# include +// simulation of XParseColor: +int fl_parse_color(const char* p, uchar& r, uchar& g, uchar& b) { + if (*p == '#') p++; + int n = strlen(p); + int m = n/3; + const char *pattern = 0; + switch(m) { + case 1: pattern = "%1x%1x%1x"; break; + case 2: pattern = "%2x%2x%2x"; break; + case 3: pattern = "%3x%3x%3x"; break; + case 4: pattern = "%4x%4x%4x"; break; + default: return 0; + } + int R,G,B; if (sscanf(p,pattern,&R,&G,&B) != 3) return 0; + switch(m) { + case 1: R *= 0x11; G *= 0x11; B *= 0x11; break; + case 3: R >>= 4; G >>= 4; B >>= 4; break; + case 4: R >>= 8; G >>= 8; B >>= 8; break; + } + r = (uchar)R; g = (uchar)G; b = (uchar)B; + return 1; +} +#else +// Wrapper around XParseColor... +int fl_parse_color(const char* p, uchar& r, uchar& g, uchar& b) { + XColor x; + if (!fl_display) fl_open_display(); + if (XParseColor(fl_display, fl_colormap, p, &x)) { + r = (uchar)(x.red>>8); + g = (uchar)(x.green>>8); + b = (uchar)(x.blue>>8); + return 1; + } else return 0; +} +#endif // WIN32 || __APPLE__ + +#if defined(WIN32) +static void +getsyscolor(int what, const char* arg, void (*func)(uchar,uchar,uchar)) +{ + if (arg) { + uchar r,g,b; + if (!fl_parse_color(arg, r,g,b)) + Fl::error("Unknown color: %s", arg); + else + func(r,g,b); + } else { + DWORD x = GetSysColor(what); + func(uchar(x&255), uchar(x>>8), uchar(x>>16)); + } +} + +void Fl::get_system_colors() { + if (!fl_bg2_set) getsyscolor(COLOR_WINDOW, fl_bg2,Fl::background2); + if (!fl_fg_set) getsyscolor(COLOR_WINDOWTEXT, fl_fg, Fl::foreground); + if (!fl_bg_set) getsyscolor(COLOR_BTNFACE, fl_bg, Fl::background); + getsyscolor(COLOR_HIGHLIGHT, 0, set_selection_color); +} + +#elif defined(__APPLE__) +// MacOS X currently supports two color schemes - Blue and Graphite. +// Since we aren't emulating the Aqua interface (even if Apple would +// let us), we use some defaults that are similar to both. The +// Fl::scheme("plastic") color/box scheme provides a usable Aqua-like +// look-n-feel... +void Fl::get_system_colors() +{ + fl_open_display(); + + if (!fl_bg2_set) background2(0xff, 0xff, 0xff); + if (!fl_fg_set) foreground(0, 0, 0); + if (!fl_bg_set) background(0xd8, 0xd8, 0xd8); + +#if 0 + // this would be the correct code, but it does not run on all versions + // of OS X. Also, setting a bright selection color would require + // some updates in Fl_Adjuster and Fl_Help_Browser + OSStatus err; + RGBColor c; + err = GetThemeBrushAsColor(kThemeBrushPrimaryHighlightColor, 24, true, &c); + if (err) + set_selection_color(0x00, 0x00, 0x80); + else + set_selection_color(c.red, c.green, c.blue); +#else + set_selection_color(0x00, 0x00, 0x80); +#endif +} +#else + +// Read colors that KDE writes to the xrdb database. + +// XGetDefault does not do the expected thing: it does not like +// periods in either word. Therefore it cannot match class.Text.background. +// However *.Text.background is matched by pretending the program is "Text". +// But this will also match *.background if there is no *.Text.background +// entry, requiring users to put in both (unless they want the text fields +// the same color as the windows). + +static void +getsyscolor(const char *key1, const char* key2, const char *arg, const char *defarg, void (*func)(uchar,uchar,uchar)) +{ + if (!arg) { + arg = XGetDefault(fl_display, key1, key2); + if (!arg) arg = defarg; + } + XColor x; + if (!XParseColor(fl_display, fl_colormap, arg, &x)) + Fl::error("Unknown color: %s", arg); + else + func(x.red>>8, x.green>>8, x.blue>>8); +} + +void Fl::get_system_colors() +{ + fl_open_display(); + const char* key1 = 0; + if (Fl::first_window()) key1 = Fl::first_window()->xclass(); + if (!key1) key1 = "fltk"; + if (!fl_bg2_set) getsyscolor("Text","background", fl_bg2, "#ffffff", Fl::background2); + if (!fl_fg_set) getsyscolor(key1, "foreground", fl_fg, "#000000", Fl::foreground); + if (!fl_bg_set) getsyscolor(key1, "background", fl_bg, "#c0c0c0", Fl::background); + getsyscolor("Text", "selectBackground", 0, "#000080", set_selection_color); +} + +#endif + + +//// Simple implementation of 2.0 Fl::scheme() interface... +#define D1 BORDER_WIDTH +#define D2 (BORDER_WIDTH+BORDER_WIDTH) + +extern void fl_up_box(int, int, int, int, Fl_Color); +extern void fl_down_box(int, int, int, int, Fl_Color); +extern void fl_thin_up_box(int, int, int, int, Fl_Color); +extern void fl_thin_down_box(int, int, int, int, Fl_Color); +extern void fl_round_up_box(int, int, int, int, Fl_Color); +extern void fl_round_down_box(int, int, int, int, Fl_Color); + +extern void fl_up_frame(int, int, int, int, Fl_Color); +extern void fl_down_frame(int, int, int, int, Fl_Color); +extern void fl_thin_up_frame(int, int, int, int, Fl_Color); +extern void fl_thin_down_frame(int, int, int, int, Fl_Color); + +const char *Fl::scheme_ = (const char *)0; +Fl_Image *Fl::scheme_bg_ = (Fl_Image *)0; + +static Fl_Pixmap tile(tile_xpm); + +int Fl::scheme(const char *s) { + if (!s) { + if ((s = getenv("FLTK_SCHEME")) == NULL) { +#if !defined(WIN32) && !defined(__APPLE__) + const char* key = 0; + if (Fl::first_window()) key = Fl::first_window()->xclass(); + if (!key) key = "fltk"; + fl_open_display(); + s = XGetDefault(fl_display, key, "scheme"); +#endif // !WIN32 && !__APPLE__ + } + } + + if (s) { + if (!strcasecmp(s, "none") || !strcasecmp(s, "base") || !*s) s = 0; + else s = strdup(s); + } + if (scheme_) free((void*)scheme_); + scheme_ = s; + + // Save the new scheme in the FLTK_SCHEME env var so that child processes + // inherit it... + static char e[1024]; + strcpy(e,"FLTK_SCHEME="); + if (s) strlcat(e,s,sizeof(e)); + putenv(e); + + // Load the scheme... + return reload_scheme(); +} + +int Fl::reload_scheme() { + Fl_Window *win; + + if (scheme_ && !strcasecmp(scheme_, "plastic")) { + // Update the tile image to match the background color... + uchar r, g, b; + int nr, ng, nb; + int i; +// static uchar levels[3] = { 0xff, 0xef, 0xe8 }; + // OSX 10.3 and higher use a background with less contrast... + static uchar levels[3] = { 0xff, 0xf8, 0xf4 }; + + get_color(FL_GRAY, r, g, b); + +// printf("FL_GRAY = 0x%02x 0x%02x 0x%02x\n", r, g, b); + + for (i = 0; i < 3; i ++) { + nr = levels[i] * r / 0xe8; + if (nr > 255) nr = 255; + + ng = levels[i] * g / 0xe8; + if (ng > 255) ng = 255; + + nb = levels[i] * b / 0xe8; + if (nb > 255) nb = 255; + + sprintf(tile_cmap[i], "%c c #%02x%02x%02x", "Oo."[i], nr, ng, nb); +// puts(tile_cmap[i]); + } + + tile.uncache(); + + if (!scheme_bg_) scheme_bg_ = new Fl_Tiled_Image(&tile, w(), h()); + + // Load plastic buttons, etc... + set_boxtype(FL_UP_FRAME, FL_PLASTIC_UP_FRAME); + set_boxtype(FL_DOWN_FRAME, FL_PLASTIC_DOWN_FRAME); + set_boxtype(FL_THIN_UP_FRAME, FL_PLASTIC_UP_FRAME); + set_boxtype(FL_THIN_DOWN_FRAME, FL_PLASTIC_DOWN_FRAME); + + set_boxtype(FL_UP_BOX, FL_PLASTIC_UP_BOX); + set_boxtype(FL_DOWN_BOX, FL_PLASTIC_DOWN_BOX); + set_boxtype(FL_THIN_UP_BOX, FL_PLASTIC_THIN_UP_BOX); + set_boxtype(FL_THIN_DOWN_BOX, FL_PLASTIC_THIN_DOWN_BOX); + set_boxtype(_FL_ROUND_UP_BOX, FL_PLASTIC_ROUND_UP_BOX); + set_boxtype(_FL_ROUND_DOWN_BOX, FL_PLASTIC_ROUND_DOWN_BOX); + + // Use standard size scrollbars... + Fl::scrollbar_size(16); + } else if (scheme_ && !strcasecmp(scheme_, "gtk+")) { + // Use a GTK+ inspired look-n-feel... + if (scheme_bg_) { + delete scheme_bg_; + scheme_bg_ = (Fl_Image *)0; + } + + set_boxtype(FL_UP_FRAME, FL_GTK_UP_FRAME); + set_boxtype(FL_DOWN_FRAME, FL_GTK_DOWN_FRAME); + set_boxtype(FL_THIN_UP_FRAME, FL_GTK_THIN_UP_FRAME); + set_boxtype(FL_THIN_DOWN_FRAME, FL_GTK_THIN_DOWN_FRAME); + + set_boxtype(FL_UP_BOX, FL_GTK_UP_BOX); + set_boxtype(FL_DOWN_BOX, FL_GTK_DOWN_BOX); + set_boxtype(FL_THIN_UP_BOX, FL_GTK_THIN_UP_BOX); + set_boxtype(FL_THIN_DOWN_BOX, FL_GTK_THIN_DOWN_BOX); + set_boxtype(_FL_ROUND_UP_BOX, FL_GTK_ROUND_UP_BOX); + set_boxtype(_FL_ROUND_DOWN_BOX, FL_GTK_ROUND_DOWN_BOX); + + // Use slightly thinner scrollbars... + Fl::scrollbar_size(15); + } else { + // Use the standard FLTK look-n-feel... + if (scheme_bg_) { + delete scheme_bg_; + scheme_bg_ = (Fl_Image *)0; + } + + set_boxtype(FL_UP_FRAME, fl_up_frame, D1, D1, D2, D2); + set_boxtype(FL_DOWN_FRAME, fl_down_frame, D1, D1, D2, D2); + set_boxtype(FL_THIN_UP_FRAME, fl_thin_up_frame, 1, 1, 2, 2); + set_boxtype(FL_THIN_DOWN_FRAME, fl_thin_down_frame, 1, 1, 2, 2); + + set_boxtype(FL_UP_BOX, fl_up_box, D1, D1, D2, D2); + set_boxtype(FL_DOWN_BOX, fl_down_box, D1, D1, D2, D2); + set_boxtype(FL_THIN_UP_BOX, fl_thin_up_box, 1, 1, 2, 2); + set_boxtype(FL_THIN_DOWN_BOX, fl_thin_down_box, 1, 1, 2, 2); + set_boxtype(_FL_ROUND_UP_BOX, fl_round_up_box, 3, 3, 6, 6); + set_boxtype(_FL_ROUND_DOWN_BOX, fl_round_down_box, 3, 3, 6, 6); + + // Use standard size scrollbars... + Fl::scrollbar_size(16); + } + + // Set (or clear) the background tile for all windows... + for (win = first_window(); win; win = next_window(win)) { + win->labeltype(scheme_bg_ ? FL_NORMAL_LABEL : FL_NO_LABEL); + win->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP); + win->image(scheme_bg_); + win->redraw(); + } + + return 1; +} + + +// +// End of "$Id: Fl_get_system_colors.cxx 5699 2007-02-20 17:02:41Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_grab.cxx b/third_party/windows/fltk-1.1.10/src/Fl_grab.cxx new file mode 100644 index 0000000..fe7e5e7 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_grab.cxx @@ -0,0 +1,106 @@ +// +// "$Id: Fl_grab.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Grab/release code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include + +//////////////////////////////////////////////////////////////// +// "Grab" is done while menu systems are up. This has several effects: +// Events are all sent to the "grab window", which does not even +// have to be displayed (and in the case of Fl_Menu.cxx it isn't). +// The system is also told to "grab" events and send them to this app. +// This also modifies how Fl_Window::show() works, on X it turns on +// override_redirect, it does similar things on WIN32. + +extern void fl_fix_focus(); // in Fl.cxx + +#ifdef WIN32 +// We have to keep track of whether we have captured the mouse, since +// MSWindows shows little respect for this... Grep for fl_capture to +// see where and how this is used. +extern HWND fl_capture; +#endif + +#ifdef __APPLE__ +// MacOS Carbon does not seem to have a mechanism to grab the mouse pointer +extern WindowRef fl_capture; +#endif + +void Fl::grab(Fl_Window* win) { + if (win) { + if (!grab_) { +#ifdef WIN32 + SetActiveWindow(fl_capture = fl_xid(first_window())); + SetCapture(fl_capture); +#elif defined(__APPLE__) + fl_capture = fl_xid( first_window() ); + SetUserFocusWindow( fl_capture ); +#else + XGrabPointer(fl_display, + fl_xid(first_window()), + 1, + ButtonPressMask|ButtonReleaseMask| + ButtonMotionMask|PointerMotionMask, + GrabModeAsync, + GrabModeAsync, + None, + 0, + fl_event_time); + XGrabKeyboard(fl_display, + fl_xid(first_window()), + 1, + GrabModeAsync, + GrabModeAsync, + fl_event_time); +#endif + } + grab_ = win; + } else { + if (grab_) { +#ifdef WIN32 + fl_capture = 0; + ReleaseCapture(); +#elif defined(__APPLE__) + fl_capture = 0; + SetUserFocusWindow( (WindowRef)kUserFocusAuto ); +#else + XUngrabKeyboard(fl_display, fl_event_time); + XUngrabPointer(fl_display, fl_event_time); + // this flush is done in case the picked menu item goes into + // an infinite loop, so we don't leave the X server locked up: + XFlush(fl_display); +#endif + grab_ = 0; + fl_fix_focus(); + } + } +} + +// +// End of "$Id: Fl_grab.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_lock.cxx b/third_party/windows/fltk-1.1.10/src/Fl_lock.cxx new file mode 100644 index 0000000..ced5259 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_lock.cxx @@ -0,0 +1,358 @@ +// +// "$Id: Fl_lock.cxx 5950 2007-10-07 10:44:28Z matt $" +// +// Multi-threading support code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2007 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + + +#include +#include + +#include + +/* + From Bill: + + I would prefer that FLTK contain the minimal amount of extra + stuff for doing threads. There are other portable thread + wrapper libraries out there and FLTK should not be providing + another. This file is an attempt to make minimal additions + and make them self-contained in this source file. + + From Mike: + + Starting with 1.1.8, we now have a callback so that you can + process awake() messages as they come in. + + + The API: + + Fl::lock() - recursive lock. You must call this before the + first call to Fl::wait()/run() to initialize the thread + system. The lock is locked all the time except when + Fl::wait() is waiting for events. + + Fl::unlock() - release the recursive lock. + + Fl::awake(void*) - Causes Fl::wait() to return (with the lock + locked) even if there are no events ready. + + Fl::awake(void (*cb)(void *), void*) - Call a function + in the main thread from within another thread of execution. + + Fl::thread_message() - returns an argument sent to an + Fl::awake() call, or returns NULL if none. WARNING: the + current implementation only has a one-entry queue and only + returns the most recent value! +*/ + +Fl_Awake_Handler *Fl::awake_ring_; +void **Fl::awake_data_; +int Fl::awake_ring_size_; +int Fl::awake_ring_head_; +int Fl::awake_ring_tail_; +static const int AWAKE_RING_SIZE = 1024; + +static void lock_ring(); +static void unlock_ring(); + + +int Fl::add_awake_handler_(Fl_Awake_Handler func, void *data) +{ + int ret = 0; + lock_ring(); + if (!awake_ring_) { + awake_ring_size_ = AWAKE_RING_SIZE; + awake_ring_ = (Fl_Awake_Handler*)malloc(awake_ring_size_*sizeof(Fl_Awake_Handler)); + awake_data_ = (void**)malloc(awake_ring_size_*sizeof(void*)); + } + if (awake_ring_head_==awake_ring_tail_-1 || awake_ring_head_+1==awake_ring_tail_) { + // ring is full. Return -1 as an error indicator. + ret = -1; + } else { + awake_ring_[awake_ring_head_] = func; + awake_data_[awake_ring_head_] = data; + ++awake_ring_head_; + if (awake_ring_head_ == awake_ring_size_) + awake_ring_head_ = 0; + } + unlock_ring(); + return ret; +} + +int Fl::get_awake_handler_(Fl_Awake_Handler &func, void *&data) +{ + int ret = 0; + lock_ring(); + if (!awake_ring_ || awake_ring_head_ == awake_ring_tail_) { + ret = -1; + } else { + func = awake_ring_[awake_ring_tail_]; + data = awake_data_[awake_ring_tail_]; + ++awake_ring_tail_; + if (awake_ring_tail_ == awake_ring_size_) + awake_ring_tail_ = 0; + } + unlock_ring(); + return ret; +} + +// +// 'Fl::awake()' - Let the main thread know an update is pending +// and have it cal a specific function +// +int Fl::awake(Fl_Awake_Handler func, void *data) { + int ret = add_awake_handler_(func, data); + Fl::awake(); + return ret; +} + +//////////////////////////////////////////////////////////////// +// Windows threading... +#ifdef WIN32 +# include +# include +# include + +// These pointers are in Fl_win32.cxx: +extern void (*fl_lock_function)(); +extern void (*fl_unlock_function)(); + +// The main thread's ID +static DWORD main_thread; + +// Microsoft's version of a MUTEX... +CRITICAL_SECTION cs; +CRITICAL_SECTION *cs_ring; + +void unlock_ring() { + LeaveCriticalSection(cs_ring); +} + +void lock_ring() { + if (!cs_ring) { + cs_ring = (CRITICAL_SECTION*)malloc(sizeof(CRITICAL_SECTION)); + InitializeCriticalSection(cs_ring); + } + EnterCriticalSection(cs_ring); +} + +// +// 'unlock_function()' - Release the lock. +// + +static void unlock_function() { + LeaveCriticalSection(&cs); +} + +// +// 'lock_function()' - Get the lock. +// + +static void lock_function() { + EnterCriticalSection(&cs); +} + +// +// 'Fl::lock()' - Lock access to FLTK data structures... +// + +void Fl::lock() { + if (!main_thread) InitializeCriticalSection(&cs); + + lock_function(); + + if (!main_thread) { + fl_lock_function = lock_function; + fl_unlock_function = unlock_function; + main_thread = GetCurrentThreadId(); + } +} + +// +// 'Fl::unlock()' - Unlock access to FLTK data structures... +// + +void Fl::unlock() { + unlock_function(); +} + + +// +// 'Fl::awake()' - Let the main thread know an update is pending. +// +// When called from a thread, it causes FLTK to awake from Fl::wait()... +// + +void Fl::awake(void* msg) { + PostThreadMessage( main_thread, fl_wake_msg, (WPARAM)msg, 0); +} + +//////////////////////////////////////////////////////////////// +// POSIX threading... +#elif HAVE_PTHREAD +# include +# include +# include + +// Pipe for thread messaging via Fl::awake()... +static int thread_filedes[2]; + +// Mutex and state information for Fl::lock() and Fl::unlock()... +static pthread_mutex_t fltk_mutex; +static pthread_t owner; +static int counter; + +static void lock_function_init_std() { + pthread_mutex_init(&fltk_mutex, NULL); +} + +static void lock_function_std() { + if (!counter || owner != pthread_self()) { + pthread_mutex_lock(&fltk_mutex); + owner = pthread_self(); + } + counter++; +} + +static void unlock_function_std() { + if (!--counter) pthread_mutex_unlock(&fltk_mutex); +} + +# ifdef PTHREAD_MUTEX_RECURSIVE +static bool lock_function_init_rec() { + pthread_mutexattr_t attrib; + pthread_mutexattr_init(&attrib); + if (pthread_mutexattr_settype(&attrib, PTHREAD_MUTEX_RECURSIVE)) { + pthread_mutexattr_destroy(&attrib); + return true; + } + + pthread_mutex_init(&fltk_mutex, &attrib); + return false; +} + +static void lock_function_rec() { + pthread_mutex_lock(&fltk_mutex); +} + +static void unlock_function_rec() { + pthread_mutex_unlock(&fltk_mutex); +} +# endif // PTHREAD_MUTEX_RECURSIVE + +void Fl::awake(void* msg) { + write(thread_filedes[1], &msg, sizeof(void*)); +} + +static void* thread_message_; +void* Fl::thread_message() { + void* r = thread_message_; + thread_message_ = 0; + return r; +} + +static void thread_awake_cb(int fd, void*) { + read(fd, &thread_message_, sizeof(void*)); + Fl_Awake_Handler func; + void *data; + while (Fl::get_awake_handler_(func, data)==0) { + (*func)(data); + } +} + +// These pointers are in Fl_x.cxx: +extern void (*fl_lock_function)(); +extern void (*fl_unlock_function)(); + +void Fl::lock() { + if (!thread_filedes[1]) { + // Initialize thread communication pipe to let threads awake FLTK + // from Fl::wait() + pipe(thread_filedes); + + // Make the write side of the pipe non-blocking to avoid deadlock + // conditions (STR #1537) + fcntl(thread_filedes[1], F_SETFL, + fcntl(thread_filedes[1], F_GETFL) | O_NONBLOCK); + + // Monitor the read side of the pipe so that messages sent via + // Fl::awake() from a thread will "wake up" the main thread in + // Fl::wait(). + Fl::add_fd(thread_filedes[0], FL_READ, thread_awake_cb); + + // Set lock/unlock functions for this system, using a system-supplied + // recursive mutex if supported... +# ifdef PTHREAD_MUTEX_RECURSIVE + if (!lock_function_init_rec()) { + fl_lock_function = lock_function_rec; + fl_unlock_function = unlock_function_rec; + } else { +# endif // PTHREAD_MUTEX_RECURSIVE + lock_function_init_std(); + fl_lock_function = lock_function_std; + fl_unlock_function = unlock_function_std; +# ifdef PTHREAD_MUTEX_RECURSIVE + } +# endif // PTHREAD_MUTEX_RECURSIVE + } + + fl_lock_function(); +} + +void Fl::unlock() { + fl_unlock_function(); +} + +// Mutex code for the awake ring buffer +static pthread_mutex_t *ring_mutex; + +void unlock_ring() { + pthread_mutex_unlock(ring_mutex); +} + +void lock_ring() { + if (!ring_mutex) { + ring_mutex = (pthread_mutex_t*)malloc(sizeof(pthread_mutex_t)); + pthread_mutex_init(ring_mutex, NULL); + } + pthread_mutex_lock(ring_mutex); +} + +#else + +void unlock_ring() { +} + +void lock_ring() { +} + +void Fl::awake(void*) { +} + +#endif // WIN32 + +// +// End of "$Id: Fl_lock.cxx 5950 2007-10-07 10:44:28Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_mac.cxx b/third_party/windows/fltk-1.1.10/src/Fl_mac.cxx new file mode 100644 index 0000000..6a8fbf5 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_mac.cxx @@ -0,0 +1,2475 @@ +// +// "$Id: Fl_mac.cxx 6800 2009-06-28 21:54:59Z matt $" +// +// MacOS specific code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2007 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +//// From the inner edge of a MetroWerks CodeWarrior CD: +// (without permission) +// +// "Three Compiles for 68Ks under the sky, +// Seven Compiles for PPCs in their fragments of code, +// Nine Compiles for Mortal Carbon doomed to die, +// One Compile for Mach-O Cocoa on its Mach-O throne, +// in the Land of MacOS X where the Drop-Shadows lie. +// +// One Compile to link them all, One Compile to merge them, +// One Compile to copy them all and in the bundle bind them, +// in the Land of MacOS X where the Drop-Shadows lie." + +// warning: the Apple Quartz version still uses some Quickdraw calls, +// mostly to get around the single active context in QD and +// to implement clipping. This should be changed into pure +// Quartz calls in the near future. + +// we don't need the following definition because we deliver only +// true mouse moves. On very slow systems however, this flag may +// still be useful. +#define CONSOLIDATE_MOTION 0 +extern "C" { +#include +} + +#include +#include +#include +#include +#include +#include +#include +#include +#include "flstring.h" +#include + +// #define DEBUG_SELECT // UNCOMMENT FOR SELECT()/THREAD DEBUGGING +#ifdef DEBUG_SELECT +#include // testing +#define DEBUGMSG(msg) if ( msg ) fprintf(stderr, msg); +#define DEBUGPERRORMSG(msg) if ( msg ) perror(msg) +#define DEBUGTEXT(txt) txt +#else +#define DEBUGMSG(msg) +#define DEBUGPERRORMSG(msg) +#define DEBUGTEXT(txt) NULL +#endif /*DEBUG_SELECT*/ + +// external functions +extern Fl_Window* fl_find(Window); +extern void fl_fix_focus(); + +// forward definition of functions in this file +static void handleUpdateEvent( WindowPtr xid ); +//+ int fl_handle(const EventRecord &event); +static int FSSpec2UnixPath( FSSpec *fs, char *dst ); + +// public variables +int fl_screen; +CGContextRef fl_gc = 0; +Handle fl_system_menu; +Fl_Sys_Menu_Bar *fl_sys_menu_bar = 0; +CursHandle fl_default_cursor; +WindowRef fl_capture = 0; // we need this to compensate for a missing(?) mouse capture +ulong fl_event_time; // the last timestamp from an x event +char fl_key_vector[32]; // used by Fl::get_key() +bool fl_show_iconic; // true if called from iconize() - shows the next created window in collapsed state +int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR +const Fl_Window* fl_modal_for; // parent of modal() window +Fl_Region fl_window_region = 0; +Window fl_window; +Fl_Window *Fl_Window::current_; +EventRef fl_os_event; // last (mouse) event + +// forward declarations of variables in this file +static int got_events = 0; +static Fl_Window* resize_from_system; +static CursPtr default_cursor_ptr; +static Cursor default_cursor; +static WindowRef fl_os_capture = 0; // the dispatch handler will redirect mose move and drag events to these windows + +#if CONSOLIDATE_MOTION +static Fl_Window* send_motion; +extern Fl_Window* fl_xmousewin; +#endif + +enum { kEventClassFLTK = 'fltk' }; +enum { kEventFLTKBreakLoop = 1, kEventFLTKDataReady }; + +/** +* Mac keyboard lookup table + */ +static unsigned short macKeyLookUp[128] = +{ + 'a', 's', 'd', 'f', 'h', 'g', 'z', 'x', + 'c', 'v', '^', 'b', 'q', 'w', 'e', 'r', + + 'y', 't', '1', '2', '3', '4', '6', '5', + '=', '9', '7', '-', '8', '0', ']', 'o', + + 'u', '[', 'i', 'p', FL_Enter, 'l', 'j', '\'', + 'k', ';', '\\', ',', '/', 'n', 'm', '.', + + FL_Tab, ' ', '`', FL_BackSpace, + FL_KP_Enter, FL_Escape, 0, 0/*FL_Meta_L*/, + 0/*FL_Shift_L*/, 0/*FL_Caps_Lock*/, 0/*FL_Alt_L*/, 0/*FL_Control_L*/, + 0/*FL_Shift_R*/, 0/*FL_Alt_R*/, 0/*FL_Control_R*/, 0, + + 0, FL_KP+'.', FL_Right, FL_KP+'*', 0, FL_KP+'+', FL_Left, FL_Num_Lock, + FL_Down, 0, 0, FL_KP+'/', FL_KP_Enter, FL_Up, FL_KP+'-', 0, + + 0, FL_KP+'=', FL_KP+'0', FL_KP+'1', FL_KP+'2', FL_KP+'3', FL_KP+'4', FL_KP+'5', + FL_KP+'6', FL_KP+'7', 0, FL_KP+'8', FL_KP+'9', 0, 0, 0, + + FL_F+5, FL_F+6, FL_F+7, FL_F+3, FL_F+8, FL_F+9, 0, FL_F+11, + 0, 0/*FL_F+13*/, FL_Print, FL_Scroll_Lock, 0, FL_F+10, FL_Menu, FL_F+12, + + 0, FL_Pause, FL_Help, FL_Home, FL_Page_Up, FL_Delete, FL_F+4, FL_End, + FL_F+2, FL_Page_Down, FL_F+1, FL_Left, FL_Right, FL_Down, FL_Up, 0/*FL_Power*/, +}; + +/** + * convert the current mouse chord into the FLTK modifier state + */ +static unsigned int mods_to_e_state( UInt32 mods ) +{ + long state = 0; + if ( mods & kEventKeyModifierNumLockMask ) state |= FL_NUM_LOCK; + if ( mods & cmdKey ) state |= FL_META; + if ( mods & (optionKey|rightOptionKey) ) state |= FL_ALT; + if ( mods & (controlKey|rightControlKey) ) state |= FL_CTRL; + if ( mods & (shiftKey|rightShiftKey) ) state |= FL_SHIFT; + if ( mods & alphaLock ) state |= FL_CAPS_LOCK; + unsigned int ret = ( Fl::e_state & 0xff000000 ) | state; + Fl::e_state = ret; + //printf( "State 0x%08x (%04x)\n", ret, mods ); + return ret; +} + + +/** + * convert the current mouse chord into the FLTK keysym + */ +static void mods_to_e_keysym( UInt32 mods ) +{ + if ( mods & cmdKey ) Fl::e_keysym = FL_Meta_L; + else if ( mods & kEventKeyModifierNumLockMask ) Fl::e_keysym = FL_Num_Lock; + else if ( mods & optionKey ) Fl::e_keysym = FL_Alt_L; + else if ( mods & rightOptionKey ) Fl::e_keysym = FL_Alt_R; + else if ( mods & controlKey ) Fl::e_keysym = FL_Control_L; + else if ( mods & rightControlKey ) Fl::e_keysym = FL_Control_R; + else if ( mods & shiftKey ) Fl::e_keysym = FL_Shift_L; + else if ( mods & rightShiftKey ) Fl::e_keysym = FL_Shift_R; + else if ( mods & alphaLock ) Fl::e_keysym = FL_Caps_Lock; + else Fl::e_keysym = 0; + //printf( "to sym 0x%08x (%04x)\n", Fl::e_keysym, mods ); +} +// these pointers are set by the Fl::lock() function: +static void nothing() {} +void (*fl_lock_function)() = nothing; +void (*fl_unlock_function)() = nothing; + +// +// Select interface -- how it's implemented: +// When the user app configures one or more file descriptors to monitor +// with Fl::add_fd(), we start a separate thread to select() the data, +// sending a custom OSX 'FLTK data ready event' to the parent thread's +// RunApplicationLoop(), so that it triggers the data ready callbacks +// in the parent thread. -erco 04/04/04 +// +#define POLLIN 1 +#define POLLOUT 4 +#define POLLERR 8 + +// Class to handle select() 'data ready' +class DataReady +{ + struct FD + { + int fd; + short events; + void (*cb)(int, void*); + void* arg; + }; + int nfds, fd_array_size; + FD *fds; + pthread_t tid; // select()'s thread id + + // Data that needs to be locked (all start with '_') + pthread_mutex_t _datalock; // data lock + fd_set _fdsets[3]; // r/w/x sets user wants to monitor + int _maxfd; // max fd count to monitor + int _cancelpipe[2]; // pipe used to help cancel thread + void *_userdata; // thread's userdata + +public: + DataReady() + { + nfds = 0; + fd_array_size = 0; + fds = 0; + tid = 0; + + pthread_mutex_init(&_datalock, NULL); + FD_ZERO(&_fdsets[0]); FD_ZERO(&_fdsets[1]); FD_ZERO(&_fdsets[2]); + _cancelpipe[0] = _cancelpipe[1] = 0; + _userdata = 0; + _maxfd = 0; + } + + ~DataReady() + { + CancelThread(DEBUGTEXT("DESTRUCTOR\n")); + if (fds) { free(fds); fds = 0; } + nfds = 0; + } + + // Locks + // The convention for locks: volatile vars start with '_', + // and must be locked before use. Locked code is prefixed + // with /*LOCK*/ to make painfully obvious esp. in debuggers. -erco + // + void DataLock() { pthread_mutex_lock(&_datalock); } + void DataUnlock() { pthread_mutex_unlock(&_datalock); } + + // Accessors + int IsThreadRunning() { return(tid ? 1 : 0); } + int GetNfds() { return(nfds); } + int GetCancelPipe(int ix) { return(_cancelpipe[ix]); } + fd_set GetFdset(int ix) { return(_fdsets[ix]); } + + // Methods + void AddFD(int n, int events, void (*cb)(int, void*), void *v); + void RemoveFD(int n, int events); + int CheckData(fd_set& r, fd_set& w, fd_set& x); + void HandleData(fd_set& r, fd_set& w, fd_set& x); + static void* DataReadyThread(void *self); + void StartThread(void *userdata); + void CancelThread(const char *reason); +}; + +static DataReady dataready; + +void DataReady::AddFD(int n, int events, void (*cb)(int, void*), void *v) +{ + RemoveFD(n, events); + int i = nfds++; + if (i >= fd_array_size) + { + FD *temp; + fd_array_size = 2*fd_array_size+1; + if (!fds) { temp = (FD*)malloc(fd_array_size*sizeof(FD)); } + else { temp = (FD*)realloc(fds, fd_array_size*sizeof(FD)); } + if (!temp) return; + fds = temp; + } + fds[i].cb = cb; + fds[i].arg = v; + fds[i].fd = n; + fds[i].events = events; + DataLock(); + /*LOCK*/ if (events & POLLIN) FD_SET(n, &_fdsets[0]); + /*LOCK*/ if (events & POLLOUT) FD_SET(n, &_fdsets[1]); + /*LOCK*/ if (events & POLLERR) FD_SET(n, &_fdsets[2]); + /*LOCK*/ if (n > _maxfd) _maxfd = n; + DataUnlock(); +} + +// Remove an FD from the array +void DataReady::RemoveFD(int n, int events) +{ + int i,j; + for (i=j=0; iDataLock(); + /*LOCK*/ int maxfd = self->_maxfd; + /*LOCK*/ fd_set r = self->GetFdset(0); + /*LOCK*/ fd_set w = self->GetFdset(1); + /*LOCK*/ fd_set x = self->GetFdset(2); + /*LOCK*/ void *userdata = self->_userdata; + /*LOCK*/ int cancelpipe = self->GetCancelPipe(0); + /*LOCK*/ if ( cancelpipe > maxfd ) maxfd = cancelpipe; + /*LOCK*/ FD_SET(cancelpipe, &r); // add cancelpipe to fd's to watch + /*LOCK*/ FD_SET(cancelpipe, &x); + self->DataUnlock(); + // timeval t = { 1000, 0 }; // 1000 seconds; + timeval t = { 2, 0 }; // HACK: 2 secs prevents 'hanging' problem + int ret = ::select(maxfd+1, &r, &w, &x, &t); + pthread_testcancel(); // OSX 10.0.4 and older: needed for parent to cancel + switch ( ret ) + { + case 0: // NO DATA + continue; + case -1: // ERROR + { + DEBUGPERRORMSG("CHILD THREAD: select() failed"); + return(NULL); // error? exit thread + } + default: // DATA READY + { + if (FD_ISSET(cancelpipe, &r) || FD_ISSET(cancelpipe, &x)) // cancel? + { return(NULL); } // just exit + DEBUGMSG("CHILD THREAD: DATA IS READY\n"); + EventRef drEvent; + CreateEvent( 0, kEventClassFLTK, kEventFLTKDataReady, + 0, kEventAttributeUserEvent, &drEvent); + EventQueueRef eventqueue = (EventQueueRef)userdata; + PostEventToQueue(eventqueue, drEvent, kEventPriorityStandard ); + ReleaseEvent( drEvent ); + return(NULL); // done with thread + } + } + } +} + +// START 'DATA READY' THREAD RUNNING, CREATE INTER-THREAD PIPE +void DataReady::StartThread(void *new_userdata) +{ + CancelThread(DEBUGTEXT("STARTING NEW THREAD\n")); + DataLock(); + /*LOCK*/ pipe(_cancelpipe); // pipe for sending cancel msg to thread + /*LOCK*/ _userdata = new_userdata; + DataUnlock(); + DEBUGMSG("*** START THREAD\n"); + pthread_create(&tid, NULL, DataReadyThread, (void*)this); +} + +// CANCEL 'DATA READY' THREAD, CLOSE PIPE +void DataReady::CancelThread(const char *reason) +{ + if ( tid ) + { + DEBUGMSG("*** CANCEL THREAD: "); + DEBUGMSG(reason); + if ( pthread_cancel(tid) == 0 ) // cancel first + { + DataLock(); + /*LOCK*/ write(_cancelpipe[1], "x", 1); // wake thread from select + DataUnlock(); + pthread_join(tid, NULL); // wait for thread to finish + } + tid = 0; + DEBUGMSG("(JOINED) OK\n"); + } + // Close pipe if open + DataLock(); + /*LOCK*/ if ( _cancelpipe[0] ) { close(_cancelpipe[0]); _cancelpipe[0] = 0; } + /*LOCK*/ if ( _cancelpipe[1] ) { close(_cancelpipe[1]); _cancelpipe[1] = 0; } + DataUnlock(); +} + +void Fl::add_fd( int n, int events, void (*cb)(int, void*), void *v ) + { dataready.AddFD(n, events, cb, v); } + +void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) + { dataready.AddFD(fd, POLLIN, cb, v); } + +void Fl::remove_fd(int n, int events) + { dataready.RemoveFD(n, events); } + +void Fl::remove_fd(int n) + { dataready.RemoveFD(n, -1); } + +/** + * Check if there is actually a message pending! + */ +int fl_ready() +{ + EventRef event; + return !ReceiveNextEvent(0, NULL, 0.0, false, &event); +} + +/** + * handle Apple Menu items (can be created using the Fl_Sys_Menu_Bar + * returns eventNotHandledErr if the menu item could not be handled + */ +OSStatus HandleMenu( HICommand *cmd ) +{ + OSStatus ret = eventNotHandledErr; + // attributes, commandIDm menu.menuRef, menu.menuItemIndex + UInt32 ref; + OSErr rrc = GetMenuItemRefCon( cmd->menu.menuRef, cmd->menu.menuItemIndex, &ref ); + //printf( "%d, %08x, %08x, %d, %d, %8x\n", rrc, cmd->attributes, cmd->commandID, cmd->menu.menuRef, cmd->menu.menuItemIndex, rrc ); + if ( rrc==noErr && ref ) + { + Fl_Menu_Item *m = (Fl_Menu_Item*)ref; + //printf( "Menu: %s\n", m->label() ); + fl_sys_menu_bar->picked( m ); + if ( m->flags & FL_MENU_TOGGLE ) // update the menu toggle symbol + SetItemMark( cmd->menu.menuRef, cmd->menu.menuItemIndex, (m->flags & FL_MENU_VALUE ) ? 0x12 : 0 ); + if ( m->flags & FL_MENU_RADIO ) // update all radio buttons in this menu + { + Fl_Menu_Item *j = m; + int i = cmd->menu.menuItemIndex; + for (;;) + { + if ( j->flags & FL_MENU_DIVIDER ) + break; + j++; i++; + if ( !j->text || !j->radio() ) + break; + SetItemMark( cmd->menu.menuRef, i, ( j->flags & FL_MENU_VALUE ) ? 0x13 : 0 ); + } + j = m-1; i = cmd->menu.menuItemIndex-1; + for ( ; i>0; j--, i-- ) + { + if ( !j->text || j->flags&FL_MENU_DIVIDER || !j->radio() ) + break; + SetItemMark( cmd->menu.menuRef, i, ( j->flags & FL_MENU_VALUE ) ? 0x13 : 0 ); + } + SetItemMark( cmd->menu.menuRef, cmd->menu.menuItemIndex, ( m->flags & FL_MENU_VALUE ) ? 0x13 : 0 ); + } + ret = noErr; // done handling this event + } + HiliteMenu(0); + return ret; +} + + +/** + * We can make every event pass through this function + * - mouse events need to be manipulated to use a mouse focus window + * - keyboard, mouse and some window events need to quit the Apple Event Loop + * so FLTK can continue its own management + */ +static pascal OSStatus carbonDispatchHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData ) +{ + OSStatus ret = eventNotHandledErr; + HICommand cmd; + + fl_lock_function(); + + got_events = 1; + + switch ( GetEventClass( event ) ) + { + case kEventClassMouse: + switch ( GetEventKind( event ) ) + { + case kEventMouseUp: + case kEventMouseMoved: + case kEventMouseDragged: + if ( fl_capture ) + ret = SendEventToEventTarget( event, GetWindowEventTarget( fl_capture ) ); + else if ( fl_os_capture ){ + ret = SendEventToEventTarget( event, GetWindowEventTarget( fl_os_capture ) ); + fl_os_capture = 0; + } + break; + } + break; + case kEventClassCommand: + switch (GetEventKind( event ) ) + { + case kEventCommandProcess: + ret = GetEventParameter( event, kEventParamDirectObject, typeHICommand, NULL, sizeof(HICommand), NULL, &cmd ); + if (ret == noErr && (cmd.attributes & kHICommandFromMenu) != 0) + ret = HandleMenu( &cmd ); + else + ret = eventNotHandledErr; + break; + } + break; + case kEventClassFLTK: + switch ( GetEventKind( event ) ) + { + case kEventFLTKBreakLoop: + ret = noErr; + break; + case kEventFLTKDataReady: + { + dataready.CancelThread(DEBUGTEXT("DATA READY EVENT\n")); + + // CHILD THREAD TELLS US DATA READY + // Check to see what's ready, and invoke user's cb's + // + fd_set r,w,x; + switch(dataready.CheckData(r,w,x)) + { + case 0: // NO DATA + break; + case -1: // ERROR + break; + default: // DATA READY + dataready.HandleData(r,w,x); + break; + } + } + ret = noErr; + break; + } + } + if ( ret == eventNotHandledErr ) + ret = CallNextEventHandler( nextHandler, event ); // let the OS handle the activation, but continue to get a click-through effect + + fl_unlock_function(); + + return ret; +} + + +/** + * break the current event loop + */ +static void breakMacEventLoop() +{ + EventRef breakEvent; + + fl_lock_function(); + + CreateEvent( 0, kEventClassFLTK, kEventFLTKBreakLoop, 0, kEventAttributeUserEvent, &breakEvent ); + PostEventToQueue( GetCurrentEventQueue(), breakEvent, kEventPriorityStandard ); + ReleaseEvent( breakEvent ); + + fl_unlock_function(); +} + +// +// MacOS X timers +// + +struct MacTimeout { + Fl_Timeout_Handler callback; + void* data; + EventLoopTimerRef timer; + EventLoopTimerUPP upp; + char pending; +}; +static MacTimeout* mac_timers; +static int mac_timer_alloc; +static int mac_timer_used; + + +static void realloc_timers() +{ + if (mac_timer_alloc == 0) { + mac_timer_alloc = 8; + } + mac_timer_alloc *= 2; + MacTimeout* new_timers = new MacTimeout[mac_timer_alloc]; + memset(new_timers, 0, sizeof(MacTimeout)*mac_timer_alloc); + memcpy(new_timers, mac_timers, sizeof(MacTimeout) * mac_timer_used); + MacTimeout* delete_me = mac_timers; + mac_timers = new_timers; + delete [] delete_me; +} + +static void delete_timer(MacTimeout& t) +{ + if (t.timer) { + RemoveEventLoopTimer(t.timer); + DisposeEventLoopTimerUPP(t.upp); + memset(&t, 0, sizeof(MacTimeout)); + } +} + + +static pascal void do_timer(EventLoopTimerRef timer, void* data) +{ + for (int i = 0; i < mac_timer_used; ++i) { + MacTimeout& t = mac_timers[i]; + if (t.timer == timer && t.data == data) { + t.pending = 0; + (*t.callback)(data); + if (t.pending==0) + delete_timer(t); + break; + } + } + breakMacEventLoop(); +} + +/** + * This function is the central event handler. + * It reads events from the event queue using the given maximum time + * Funny enough, it returns the same time that it got as the argument. + */ +static double do_queued_events( double time = 0.0 ) +{ + static bool been_here = 0; + static RgnHandle rgn; + + // initialize events and a region that enables mouse move events + if (!been_here) { + rgn = NewRgn(); + Point mp; + GetMouse(&mp); + SetRectRgn(rgn, mp.h, mp.v, mp.h, mp.v); + SetEventMask(everyEvent); + been_here = 1; + } + OSStatus ret; + static EventTargetRef target = 0; + if ( !target ) + { + target = GetEventDispatcherTarget(); + + EventHandlerUPP dispatchHandler = NewEventHandlerUPP( carbonDispatchHandler ); // will not be disposed by Carbon... + static EventTypeSpec dispatchEvents[] = { + { kEventClassWindow, kEventWindowShown }, + { kEventClassWindow, kEventWindowHidden }, + { kEventClassWindow, kEventWindowActivated }, + { kEventClassWindow, kEventWindowDeactivated }, + { kEventClassWindow, kEventWindowClose }, + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + { kEventClassKeyboard, kEventRawKeyUp }, + { kEventClassKeyboard, kEventRawKeyModifiersChanged }, + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, 11 }, // MightyMouse wheels + { kEventClassMouse, kEventMouseWheelMoved }, + { kEventClassMouse, kEventMouseDragged }, + { kEventClassFLTK, kEventFLTKBreakLoop }, + { kEventClassFLTK, kEventFLTKDataReady } }; + ret = InstallEventHandler( target, dispatchHandler, GetEventTypeCount(dispatchEvents), dispatchEvents, 0, 0L ); + static EventTypeSpec appEvents[] = { + { kEventClassCommand, kEventCommandProcess } }; + ret = InstallApplicationEventHandler( dispatchHandler, GetEventTypeCount(appEvents), appEvents, 0, 0L ); + } + + got_events = 0; + + // Check for re-entrant condition + if ( dataready.IsThreadRunning() ) + { dataready.CancelThread(DEBUGTEXT("AVOID REENTRY\n")); } + + // Start thread to watch for data ready + if ( dataready.GetNfds() ) + { dataready.StartThread((void*)GetCurrentEventQueue()); } + + fl_unlock_function(); + + EventRef event; + EventTimeout timeout = time; + if (!ReceiveNextEvent(0, NULL, timeout, true, &event)) { + got_events = 1; + OSErr ret = SendEventToEventTarget( event, target ); + if (ret!=noErr) { + EventRecord clevent; + ConvertEventRefToEventRecord(event, &clevent); + if (clevent.what==kHighLevelEvent) { + ret = AEProcessAppleEvent(&clevent); + } + } + if ( ret==eventNotHandledErr + && GetEventClass(event)==kEventClassMouse + && GetEventKind(event)==kEventMouseDown ) { + WindowRef win; Point pos; + GetEventParameter(event, kEventParamMouseLocation, typeQDPoint, + NULL, sizeof(pos), NULL, &pos); + if (MacFindWindow(pos, &win)==inMenuBar) { + MenuSelect(pos); + } + } + ReleaseEvent( event ); + } + + fl_lock_function(); + +#if CONSOLIDATE_MOTION + if (send_motion && send_motion == fl_xmousewin) { + send_motion = 0; + Fl::handle(FL_MOVE, fl_xmousewin); + } +#endif + + return time; +} + + +/** + * This public function handles all events. It wait a maximum of + * 'time' secods for an event. This version returns 1 if events + * other than the timeout timer were processed. + * + * \todo there is no socket handling in this code whatsoever + */ +int fl_wait( double time ) +{ + do_queued_events( time ); + return (got_events); +} + + +/** + * event handler for Apple-Q key combination + * this is also called from the Carbon Window handler after all windows were closed + */ +static OSErr QuitAppleEventHandler( const AppleEvent *appleEvt, AppleEvent* reply, UInt32 refcon ) +{ + fl_lock_function(); + + while ( Fl_X::first ) { + Fl_X *x = Fl_X::first; + Fl::handle( FL_CLOSE, x->w ); + if ( Fl_X::first == x ) { + fl_unlock_function(); + return noErr; // FLTK has not close all windows, so we return to the main program now + } + } + + fl_unlock_function(); + + return noErr; +} + + +/** + * Carbon Window handler + * This needs to be linked into all new window event handlers + */ +static pascal OSStatus carbonWindowHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData ) +{ + UInt32 kind = GetEventKind( event ); + OSStatus ret = eventNotHandledErr; + Fl_Window *window = (Fl_Window*)userData; + Fl::first_window(window); + + Rect currentBounds, originalBounds; + WindowClass winClass; + static Fl_Window *activeWindow = 0; + + fl_lock_function(); + + switch ( kind ) + { + case kEventWindowBoundsChanging: + GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, ¤tBounds ); + GetEventParameter( event, kEventParamOriginalBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &originalBounds ); + break; + case kEventWindowDrawContent: + handleUpdateEvent( fl_xid( window ) ); + ret = noErr; + break; + case kEventWindowBoundsChanged: { + GetEventParameter( event, kEventParamCurrentBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, ¤tBounds ); + GetEventParameter( event, kEventParamOriginalBounds, typeQDRectangle, NULL, sizeof(Rect), NULL, &originalBounds ); + int X = currentBounds.left, W = currentBounds.right-X; + int Y = currentBounds.top, H = currentBounds.bottom-Y; + resize_from_system = window; + window->resize( X, Y, W, H ); + if ( ( originalBounds.right - originalBounds.left != W ) + || ( originalBounds.bottom - originalBounds.top != H ) ) + { + if ( window->shown() ) + handleUpdateEvent( fl_xid( window ) ); + } + break; } + case kEventWindowShown: + if ( !window->parent() ) + { + GetWindowClass( fl_xid( window ), &winClass ); + if ( winClass != kHelpWindowClass ) { // help windows can't get the focus! + Fl::handle( FL_FOCUS, window); + activeWindow = window; + } + Fl::handle( FL_SHOW, window); + mods_to_e_state(GetCurrentKeyModifiers()); + } + break; + case kEventWindowHidden: + if ( !window->parent() ) Fl::handle( FL_HIDE, window); + break; + case kEventWindowActivated: + if ( window->shown() && window!=activeWindow ) + { + GetWindowClass( fl_xid( window ), &winClass ); + if ( winClass != kHelpWindowClass ) { // help windows can't get the focus! + Fl::handle( FL_FOCUS, window); + activeWindow = window; + } + } + break; + case kEventWindowDeactivated: + if ( window==activeWindow ) + { + Fl::handle( FL_UNFOCUS, window); + activeWindow = 0; + } + break; + case kEventWindowClose: + Fl::handle( FL_CLOSE, window ); // this might or might not close the window + // if there are no more windows, send a high-level quit event + if (!Fl_X::first) QuitAppleEventHandler( 0, 0, 0 ); + ret = noErr; // returning noErr tells Carbon to stop following up on this event + break; + case kEventWindowCollapsed: + window->clear_visible(); + break; + case kEventWindowExpanded: + window->set_visible(); + break; + } + + fl_unlock_function(); + + return ret; +} + + +/** + * Carbon Mousewheel handler + * This needs to be linked into all new window event handlers + */ +static pascal OSStatus carbonMousewheelHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData ) +{ + // Handle the new "MightyMouse" mouse wheel events. Please, someone explain + // to me why Apple changed the API on this even though the current API + // supports two wheels just fine. Matthias, + fl_lock_function(); + + fl_os_event = event; + Fl_Window *window = (Fl_Window*)userData; + if ( !window->shown() ) + { + fl_unlock_function(); + return noErr; + } + Fl::first_window(window); + + EventMouseWheelAxis axis; + GetEventParameter( event, kEventParamMouseWheelAxis, typeMouseWheelAxis, NULL, sizeof(EventMouseWheelAxis), NULL, &axis ); + long delta; + GetEventParameter( event, kEventParamMouseWheelDelta, typeLongInteger, NULL, sizeof(long), NULL, &delta ); +// fprintf(stderr, "axis=%d, delta=%d\n", axis, delta); + if ( axis == kEventMouseWheelAxisX ) { + Fl::e_dx = -delta; + Fl::e_dy = 0; + if ( Fl::e_dx) Fl::handle( FL_MOUSEWHEEL, window ); + } else if ( axis == kEventMouseWheelAxisY ) { + Fl::e_dx = 0; + Fl::e_dy = -delta; + if ( Fl::e_dy) Fl::handle( FL_MOUSEWHEEL, window ); + } else { + fl_unlock_function(); + + return eventNotHandledErr; + } + + fl_unlock_function(); + + return noErr; +} + + +/** + * convert the current mouse chord into the FLTK modifier state + */ +static void chord_to_e_state( UInt32 chord ) +{ + static ulong state[] = + { + 0, FL_BUTTON1, FL_BUTTON3, FL_BUTTON1|FL_BUTTON3, FL_BUTTON2, + FL_BUTTON2|FL_BUTTON1, FL_BUTTON2|FL_BUTTON3, + FL_BUTTON2|FL_BUTTON1|FL_BUTTON3 + }; + Fl::e_state = ( Fl::e_state & 0xff0000 ) | state[ chord & 0x07 ]; +} + + +/** + * Carbon Mouse Button Handler + */ +static pascal OSStatus carbonMouseHandler( EventHandlerCallRef nextHandler, EventRef event, void *userData ) +{ + static int keysym[] = { 0, FL_Button+1, FL_Button+3, FL_Button+2 }; + static int px, py; + static char suppressed = 0; + + fl_lock_function(); + + fl_os_event = event; + Fl_Window *window = (Fl_Window*)userData; + if ( !window->shown() ) + { + fl_unlock_function(); + return noErr; + } + Fl::first_window(window); + Point pos; + GetEventParameter( event, kEventParamMouseLocation, typeQDPoint, NULL, sizeof(Point), NULL, &pos ); + EventMouseButton btn; + GetEventParameter( event, kEventParamMouseButton, typeMouseButton, NULL, sizeof(EventMouseButton), NULL, &btn ); + UInt32 clickCount; + GetEventParameter( event, kEventParamClickCount, typeUInt32, NULL, sizeof(UInt32), NULL, &clickCount ); + UInt32 chord; + GetEventParameter( event, kEventParamMouseChord, typeUInt32, NULL, sizeof(UInt32), NULL, &chord ); + WindowRef xid = fl_xid(window), tempXid; + int sendEvent = 0, part = 0; + switch ( GetEventKind( event ) ) + { + case kEventMouseDown: + part = FindWindow( pos, &tempXid ); + if (!(Fl::grab() && window!=Fl::grab())) { + if ( part == inGrow ) { + fl_unlock_function(); + suppressed = 1; + Fl_Tooltip::current(0L); + return CallNextEventHandler( nextHandler, event ); // let the OS handle this for us + } + if ( part != inContent ) { + fl_unlock_function(); + suppressed = 1; + Fl_Tooltip::current(0L); + // anything else to here? + return CallNextEventHandler( nextHandler, event ); // let the OS handle this for us + } + } + suppressed = 0; + if (part==inContent && !IsWindowActive( xid ) ) { + CallNextEventHandler( nextHandler, event ); // let the OS handle the activation, but continue to get a click-through effect + } + // normal handling of mouse-down follows + fl_os_capture = xid; + sendEvent = FL_PUSH; + Fl::e_is_click = 1; px = pos.h; py = pos.v; + if (clickCount>1) + Fl::e_clicks++; + else + Fl::e_clicks = 0; + // fall through + case kEventMouseUp: + if (suppressed) { + suppressed = 0; + break; + } + if ( !window ) break; + if ( !sendEvent ) { + sendEvent = FL_RELEASE; + } + Fl::e_keysym = keysym[ btn ]; + // fall through + case kEventMouseMoved: + suppressed = 0; + if ( !sendEvent ) { + sendEvent = FL_MOVE; chord = 0; + } + // fall through + case kEventMouseDragged: + if (suppressed) break; + if ( !sendEvent ) { + sendEvent = FL_MOVE; // Fl::handle will convert into FL_DRAG + if (abs(pos.h-px)>5 || abs(pos.v-py)>5) + Fl::e_is_click = 0; + } + chord_to_e_state( chord ); + GrafPtr oldPort; + GetPort( &oldPort ); + SetPort( GetWindowPort(xid) ); // \todo replace this! There must be some GlobalToLocal call that has a port as an argument + SetOrigin(0, 0); + Fl::e_x_root = pos.h; + Fl::e_y_root = pos.v; + GlobalToLocal( &pos ); + Fl::e_x = pos.h; + Fl::e_y = pos.v; + SetPort( oldPort ); + if (GetEventKind(event)==kEventMouseDown && part!=inContent) { + int used = Fl::handle( sendEvent, window ); + CallNextEventHandler( nextHandler, event ); // let the OS handle this for us + if (!used) + suppressed = 1; + } else { + Fl::handle( sendEvent, window ); + } + break; + } + + fl_unlock_function(); + + return noErr; +} + + +/** + * convert the keyboard return code into the symbol on the keycaps + */ +static unsigned short keycode_to_sym( UInt32 keyCode, UInt32 mods, unsigned short deflt ) +{ + static Ptr map = 0; + UInt32 state = 0; + if (!map) { + map = (Ptr)GetScriptManagerVariable(smKCHRCache); + if (!map) { + long kbID = GetScriptManagerVariable(smKeyScript); + map = *GetResource('KCHR', kbID); + } + } + if (map) + return KeyTranslate(map, keyCode|mods, &state ); + return deflt; +} + +/** + * handle carbon keyboard events + */ +pascal OSStatus carbonKeyboardHandler( + EventHandlerCallRef nextHandler, EventRef event, void *userData ) +{ + static char buffer[5]; + int sendEvent = 0; + Fl_Window *window = (Fl_Window*)userData; + Fl::first_window(window); + UInt32 mods; + static UInt32 prevMods = mods_to_e_state( GetCurrentKeyModifiers() ); + + fl_lock_function(); + + int kind = GetEventKind(event); + + // get the modifiers for any of the events + GetEventParameter( event, kEventParamKeyModifiers, typeUInt32, + NULL, sizeof(UInt32), NULL, &mods ); + + // get the key code only for key events + UInt32 keyCode = 0, maskedKeyCode = 0; + unsigned char key = 0; + unsigned short sym = 0; + if (kind!=kEventRawKeyModifiersChanged) { + GetEventParameter( event, kEventParamKeyCode, typeUInt32, + NULL, sizeof(UInt32), NULL, &keyCode ); + GetEventParameter( event, kEventParamKeyMacCharCodes, typeChar, + NULL, sizeof(char), NULL, &key ); + } + maskedKeyCode = keyCode & 0x7f; + /* output a human readbale event identifier for debugging + const char *ev = ""; + switch (kind) { + case kEventRawKeyDown: ev = "kEventRawKeyDown"; break; + case kEventRawKeyRepeat: ev = "kEventRawKeyRepeat"; break; + case kEventRawKeyUp: ev = "kEventRawKeyUp"; break; + case kEventRawKeyModifiersChanged: ev = "kEventRawKeyModifiersChanged"; break; + default: ev = "unknown"; + } + printf("%08x %08x %08x '%c' %s \n", mods, keyCode, key, key, ev); + */ + switch (kind) + { + case kEventRawKeyDown: + case kEventRawKeyRepeat: + // When the user presses a "dead key", no information is send about + // which dead key symbol was created. So we need to trick Carbon into + // giving us the code by sending a "space" after the "dead key". + if (key==0) { + UInt32 ktState = 0; + KeyboardLayoutRef klr; + KLGetCurrentKeyboardLayout(&klr); + const void *kchar = 0; KLGetKeyboardLayoutProperty(klr, kKLKCHRData, &kchar); + KeyTranslate(kchar, (mods&0xff00) | keyCode, &ktState); // send the dead key + key = KeyTranslate(kchar, 0x31, &ktState); // fake a space key press + Fl::e_state |= 0x40000000; // mark this as a dead key + } else { + Fl::e_state &= 0xbfffffff; // clear the deadkey flag + } + sendEvent = FL_KEYBOARD; + // fall through + case kEventRawKeyUp: + if ( !sendEvent ) { + sendEvent = FL_KEYUP; + Fl::e_state &= 0xbfffffff; // clear the deadkey flag + } + // if the user pressed alt/option, event_key should have the keycap, + // but event_text should generate the international symbol + sym = macKeyLookUp[ maskedKeyCode ]; + if ( isalpha(key) ) + sym = tolower(key); + else if ( Fl::e_state&FL_CTRL && key<32 && sym<0xff00) + sym = key+96; + else if ( Fl::e_state&FL_ALT && sym<0xff00) // find the keycap of this key + sym = keycode_to_sym( maskedKeyCode, 0, macKeyLookUp[ maskedKeyCode ] ); + Fl::e_keysym = Fl::e_original_keysym = sym; + // Handle FL_KP_Enter on regular keyboards and on Powerbooks + if ( maskedKeyCode==0x4c || maskedKeyCode==0x34) key=0x0d; + // Matt: the Mac has no concept of a NumLock key, or at least not visible + // Matt: to Carbon. The kEventKeyModifierNumLockMask is only set when + // Matt: a numeric keypad key is pressed and does not correspond with + // Matt: the NumLock light in PowerBook keyboards. + if ( (sym >= FL_KP && sym <= FL_KP_Last) || !(sym & 0xff00) || + sym == FL_Tab || sym == FL_Enter) { + buffer[0] = key; + Fl::e_length = 1; + } else { + buffer[0] = 0; + Fl::e_length = 0; + } + Fl::e_text = buffer; + // insert UnicodeHandling here! + break; + case kEventRawKeyModifiersChanged: { + UInt32 tMods = prevMods ^ mods; + if ( tMods ) + { + mods_to_e_keysym( tMods ); + if ( Fl::e_keysym ) + sendEvent = ( prevModsparent()) window = window->window(); + if (sendEvent && Fl::handle(sendEvent,window)) { + fl_unlock_function(); + return noErr; // return noErr if FLTK handled the event + } else { + fl_unlock_function(); + //return CallNextEventHandler( nextHandler, event );; + // Matt: I had better results (no duplicate events) always returning + // Matt: 'noErr'. System keyboard events still seem to work just fine. + return noErr; + } +} + + + +/** + * Open callback function to call... + */ + +static void (*open_cb)(const char *) = 0; + + +/** + * Event handler for Apple-O key combination and also for file opens + * via the finder... + */ + +static OSErr OpenAppleEventHandler(const AppleEvent *appleEvt, + AppleEvent *reply, + UInt32 refcon) { + OSErr err; + AEDescList documents; + long i, n; + FSSpec fileSpec; + AEKeyword keyWd; + DescType typeCd; + Size actSz; + char filename[1024]; + + if (!open_cb) return noErr; + + // Initialize the document list... + AECreateDesc(typeNull, NULL, 0, &documents); + + // Get the open parameter(s)... + err = AEGetParamDesc(appleEvt, keyDirectObject, typeAEList, &documents); + if (err != noErr) { + AEDisposeDesc(&documents); + return err; + } + + // Lock access to FLTK in this thread... + fl_lock_function(); + + // Open the documents via the callback... + if (AECountItems(&documents, &n) == noErr) { + for (i = 1; i <= n; i ++) { + // Get the next FSSpec record... + AEGetNthPtr(&documents, i, typeFSS, &keyWd, &typeCd, + (Ptr)&fileSpec, sizeof(fileSpec), + (actSz = sizeof(fileSpec), &actSz)); + + // Convert to a UNIX path... + FSSpec2UnixPath(&fileSpec, filename); + + // Call the callback with the filename... + (*open_cb)(filename); + } + } + + // Unlock access to FLTK for all threads... + fl_unlock_function(); + + // Get rid of the document list... + AEDisposeDesc(&documents); + + return noErr; +} + + +/** + * Install an open documents event handler... + */ + +void fl_open_callback(void (*cb)(const char *)) { + open_cb = cb; + if (cb) { + AEInstallEventHandler(kCoreEventClass, kAEOpenDocuments, + NewAEEventHandlerUPP((AEEventHandlerProcPtr) + OpenAppleEventHandler), 0, false); + } else { + AERemoveEventHandler(kCoreEventClass, kAEOpenDocuments, + NewAEEventHandlerUPP((AEEventHandlerProcPtr) + OpenAppleEventHandler), false); + } +} + + +/** + * initialize the Mac toolboxes, dock status, and set the default menubar + */ + +extern "C" { + extern OSErr CPSEnableForegroundOperation(ProcessSerialNumber *psn, UInt32 _arg2, + UInt32 _arg3, UInt32 _arg4, UInt32 _arg5); +} + +void fl_open_display() { + static char beenHereDoneThat = 0; + if ( !beenHereDoneThat ) { + beenHereDoneThat = 1; + + FlushEvents(everyEvent,0); + + MoreMasters(); // \todo Carbon suggests MoreMasterPointers() + AEInstallEventHandler( kCoreEventClass, kAEQuitApplication, NewAEEventHandlerUPP((AEEventHandlerProcPtr)QuitAppleEventHandler), 0, false ); + + // create the Mac Handle for the default cursor (a pointer to a pointer) + GetQDGlobalsArrow(&default_cursor); + default_cursor_ptr = &default_cursor; + fl_default_cursor = &default_cursor_ptr; + + ClearMenuBar(); + AppendResMenu( GetMenuHandle( 1 ), 'DRVR' ); + DrawMenuBar(); + + // bring the application into foreground without a 'CARB' resource + Boolean same_psn; + ProcessSerialNumber cur_psn, front_psn; + if( !GetCurrentProcess( &cur_psn ) && !GetFrontProcess( &front_psn ) && + !SameProcess( &front_psn, &cur_psn, &same_psn ) && !same_psn ) + { + // only transform the application type for unbundled apps + CFBundleRef bundle = CFBundleGetMainBundle(); + if( bundle ) + { + FSRef execFs; + CFURLRef execUrl = CFBundleCopyExecutableURL( bundle ); + CFURLGetFSRef( execUrl, &execFs ); + + FSRef bundleFs; + GetProcessBundleLocation( &cur_psn, &bundleFs ); + + if( !FSCompareFSRefs( &execFs, &bundleFs ) ) + bundle = NULL; + + CFRelease(execUrl); + } + + if( !bundle ) + { + // Earlier versions of this code tried to use weak linking, however it + // appears that this does not work on 10.2. Since 10.3 and higher provide + // both TransformProcessType and CPSEnableForegroundOperation, the following + // conditional code compiled on 10.2 will still work on newer releases... + OSErr err; + +#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2 + if (TransformProcessType != NULL) { + err = TransformProcessType(&cur_psn, kProcessTransformToForegroundApplication); + } else +#endif // MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_2 + err = CPSEnableForegroundOperation(&cur_psn, 0x03, 0x3C, 0x2C, 0x1103); + + if (err == noErr) { + SetFrontProcess( &cur_psn ); + } + } + } + } +} + + +/** + * get rid of allocated resources + */ +void fl_close_display() { +} + + +/** + * smallest x ccordinate in screen space + */ +int Fl::x() { + BitMap r; + GetQDGlobalsScreenBits(&r); + return r.bounds.left; +} + + +/** + * smallest y ccordinate in screen space + */ +int Fl::y() { + BitMap r; + GetQDGlobalsScreenBits(&r); + return r.bounds.top + 20; // \todo 20 pixel menu bar? +} + + +/** + * screen width (single monitor!?) + */ +int Fl::w() { + BitMap r; + GetQDGlobalsScreenBits(&r); + return r.bounds.right - r.bounds.left; +} + + +/** + * screen height (single monitor!?) + */ +int Fl::h() { + BitMap r; + GetQDGlobalsScreenBits(&r); + return r.bounds.bottom - r.bounds.top - 20; +} + + +/** + * get the current mouse pointer world coordinates + */ +void Fl::get_mouse(int &x, int &y) +{ + fl_open_display(); + Point loc; + GetMouse( &loc ); + LocalToGlobal( &loc ); + x = loc.h; + y = loc.v; +} + + +/** + * convert Mac keystrokes to FLTK + */ +unsigned short mac2fltk(ulong macKey) +{ + unsigned short cc = macKeyLookUp[(macKey>>8)&0x7f]; + if (cc) return cc; + return macKey&0xff; +} + + +/** + * Initialize the given port for redraw and call the windw's flush() to actually draw the content + */ +void Fl_X::flush() +{ + w->flush(); +#ifdef __APPLE_QD__ + GrafPtr port; + GetPort( &port ); + if ( port ) + QDFlushPortBuffer( port, 0 ); +#elif defined (__APPLE_QUARTZ__) + if (fl_gc) + CGContextFlush(fl_gc); +#endif + SetOrigin( 0, 0 ); +} + + +/** + * Handle all clipping and redraw for the given port + * There are two different callers for this event: + * 1: the OS can request a redraw and provides all clipping itself + * 2: Fl::flush() wants all redraws now + */ +void handleUpdateEvent( WindowPtr xid ) +{ + Fl_Window *window = fl_find( xid ); + if ( !window ) return; + GrafPtr oldPort; + GetPort( &oldPort ); + SetPort( GetWindowPort(xid) ); + Fl_X *i = Fl_X::i( window ); + i->wait_for_expose = 0; + if ( window->damage() ) { + if ( i->region ) { + InvalWindowRgn( xid, i->region ); + } + } + if ( i->region ) { // no region, so the sytem will take the update region from the OS + DisposeRgn( i->region ); + i->region = 0; + } + for ( Fl_X *cx = i->xidChildren; cx; cx = cx->xidNext ) + { + cx->w->clear_damage(window->damage()|FL_DAMAGE_EXPOSE); + cx->flush(); + cx->w->clear_damage(); + } + window->clear_damage(window->damage()|FL_DAMAGE_EXPOSE); + i->flush(); + window->clear_damage(); + SetPort( oldPort ); +} + + +/** + * \todo this is a leftover from OS9 times. Please check how much applies to Carbon! + */ +int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by) { + int W, H, xoff, yoff, dx, dy; + int ret = bx = by = bt = 0; + if (w->border() && !w->parent()) { + if (w->maxw != w->minw || w->maxh != w->minh) { + ret = 2; + bx = 6; // \todo Mac : GetSystemMetrics(SM_CXSIZEFRAME); + by = 6; // \todo Mac : get Mac window frame size GetSystemMetrics(SM_CYSIZEFRAME); + } else { + ret = 1; + bx = 6; // \todo Mac : GetSystemMetrics(SM_CXFIXEDFRAME); + by = 6; // \todo Mac : GetSystemMetrics(SM_CYFIXEDFRAME); + } + bt = 22; // \todo Mac : GetSystemMetrics(SM_CYCAPTION); + } + //The coordinates of the whole window, including non-client area + xoff = bx; + yoff = by + bt; + dx = 2*bx; + dy = 2*by + bt; + X = w->x()-xoff; + Y = w->y()-yoff; + W = w->w()+dx; + H = w->h()+dy; + + //Proceed to positioning the window fully inside the screen, if possible + + // let's get a little elaborate here. Mac OS X puts a lot of stuff on the desk + // that we want to avoid when positioning our window, namely the Dock and the + // top menu bar (and even more stuff in 10.4 Tiger). So we will go through the + // list of all available screens and find the one that this window is most + // likely to go to, and then reposition it to fit withing the 'good' area. + Rect r; + // find the screen, that the center of this window will fall into + int R = X+W, B = Y+H; // right and bottom + int cx = (X+R)/2, cy = (Y+B)/2; // center of window; + GDHandle gd = 0L; + for (gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) { + GDPtr gp = *gd; + if ( cx >= gp->gdRect.left && cx <= gp->gdRect.right + && cy >= gp->gdRect.top && cy <= gp->gdRect.bottom) + break; + } + // if the center doesn't fall on a screen, try the top left + if (!gd) { + for (gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) { + GDPtr gp = *gd; + if ( X >= gp->gdRect.left && X <= gp->gdRect.right + && Y >= gp->gdRect.top && Y <= gp->gdRect.bottom) + break; + } + } + // if that doesn't fall on a screen, try the top right + if (!gd) { + for (gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) { + GDPtr gp = *gd; + if ( R >= gp->gdRect.left && R <= gp->gdRect.right + && Y >= gp->gdRect.top && Y <= gp->gdRect.bottom) + break; + } + } + // if that doesn't fall on a screen, try the bottom left + if (!gd) { + for (gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) { + GDPtr gp = *gd; + if ( X >= gp->gdRect.left && X <= gp->gdRect.right + && B >= gp->gdRect.top && B <= gp->gdRect.bottom) + break; + } + } + // last resort, try the bottom right + if (!gd) { + for (gd = GetDeviceList(); gd; gd = GetNextDevice(gd)) { + GDPtr gp = *gd; + if ( R >= gp->gdRect.left && R <= gp->gdRect.right + && B >= gp->gdRect.top && B <= gp->gdRect.bottom) + break; + } + } + // if we still have not found a screen, we will use the main + // screen, the one that has the application menu bar. + if (!gd) gd = GetMainDevice(); + if (gd) { + GetAvailableWindowPositioningBounds(gd, &r); + if ( R > r.right ) X -= R - r.right; + if ( B > r.bottom ) Y -= B - r.bottom; + if ( X < r.left ) X = r.left; + if ( Y < r.top ) Y = r.top; + } + + //Return the client area's top left corner in (X,Y) + X+=xoff; + Y+=yoff; + + return ret; +} + +/** + * convert a Mac FSSpec structure into a Unix filename + */ +static int FSSpec2UnixPath( FSSpec *fs, char *dst ) +{ + FSRef fsRef; + FSpMakeFSRef( fs, &fsRef ); + FSRefMakePath( &fsRef, (UInt8*)dst, 1024 ); + return strlen(dst); +} + +static DragReference currDragRef = 0; +static char *currDragData = 0L; +static int currDragSize = 0; +static OSErr currDragErr = noErr; +Fl_Window *fl_dnd_target_window = 0; +#include + +/** + * Fill the currDrag* variables with the current DnD ASCII text. + */ +static OSErr fillCurrentDragData(DragReference dragRef) +{ + OSErr ret = noErr; + char *dst = 0L; + + // shortcut through this whole procedure if this is still the same drag event + if (dragRef==currDragRef) + return currDragErr; + + // clear currDrag* for a new drag event + currDragRef = dragRef; + if (currDragData) free(currDragData); + currDragData = 0; + currDragSize = 0; + + // fill currDRag* with ASCII data, if available + UInt16 i, nItem; + ItemReference itemRef; + FlavorFlags flags; + Size itemSize, size = 0; + CountDragItems( dragRef, &nItem ); + for ( i = 1; i <= nItem; i++ ) + { + GetDragItemReferenceNumber( dragRef, i, &itemRef ); + ret = GetFlavorFlags( dragRef, itemRef, 'TEXT', &flags ); + if ( ret == noErr ) + { + GetFlavorDataSize( dragRef, itemRef, 'TEXT', &itemSize ); + size += itemSize; + } + ret = GetFlavorFlags( dragRef, itemRef, 'hfs ', &flags ); + if ( ret == noErr ) + { + size += 1024; //++ ouch! We should create the full pathname and figure out its length + } + } + + if ( !size ) + { + currDragErr = userCanceledErr; + return currDragErr; + } + + currDragSize = size + nItem - 1; + currDragData = dst = (char*)malloc( size+nItem );; + + for ( i = 1; i <= nItem; i++ ) + { + GetDragItemReferenceNumber( dragRef, i, &itemRef ); + ret = GetFlavorFlags( dragRef, itemRef, 'TEXT', &flags ); + if ( ret == noErr ) + { + GetFlavorDataSize( dragRef, itemRef, 'TEXT', &itemSize ); + GetFlavorData( dragRef, itemRef, 'TEXT', dst, &itemSize, 0L ); + dst += itemSize; + *dst++ = '\n'; // add our element seperator + } + ret = GetFlavorFlags( dragRef, itemRef, 'hfs ', &flags ); + if ( ret == noErr ) + { + HFSFlavor hfs; itemSize = sizeof( hfs ); + GetFlavorData( dragRef, itemRef, 'hfs ', &hfs, &itemSize, 0L ); + itemSize = FSSpec2UnixPath( &hfs.fileSpec, dst ); + dst += itemSize; + if ( itemSize>1 && ( hfs.fileType=='fold' || hfs.fileType=='disk' ) ) + *dst++ = '/'; + *dst++ = '\n'; // add our element seperator + } + } + + dst[-1] = 0; + currDragSize = dst - currDragData - 1; + currDragErr = ret; + return ret; +} + +/** + * Drag'n'drop tracking handler + */ +static pascal OSErr dndTrackingHandler( DragTrackingMessage msg, WindowPtr w, void *userData, DragReference dragRef ) +{ + Fl_Window *target = (Fl_Window*)userData; + Fl::first_window(target); + Point mp; + static int px, py; + + fillCurrentDragData(dragRef); + Fl::e_length = currDragSize; + Fl::e_text = currDragData; + + switch ( msg ) + { + case kDragTrackingEnterWindow: + // check if 'TEXT' is available + GetDragMouse( dragRef, &mp, 0 ); + Fl::e_x_root = px = mp.h; + Fl::e_y_root = py = mp.v; + Fl::e_x = px - target->x(); + Fl::e_y = py - target->y(); + fl_dnd_target_window = target; + if ( Fl::handle( FL_DND_ENTER, target ) ) + fl_cursor( FL_CURSOR_HAND ); //ShowDragHilite( ); // modify the mouse cursor?! + else + fl_cursor( FL_CURSOR_DEFAULT ); //HideDragHilite( dragRef ); + breakMacEventLoop(); + return noErr; + case kDragTrackingInWindow: + GetDragMouse( dragRef, &mp, 0 ); + if ( mp.h==px && mp.v==py ) + break; //+ return previous condition for dnd hiliting + Fl::e_x_root = px = mp.h; + Fl::e_y_root = py = mp.v; + Fl::e_x = px - target->x(); + Fl::e_y = py - target->y(); + fl_dnd_target_window = target; + if ( Fl::handle( FL_DND_DRAG, target ) ) + fl_cursor( FL_CURSOR_HAND ); //ShowDragHilite( ); // modify the mouse cursor?! + else + fl_cursor( FL_CURSOR_DEFAULT ); //HideDragHilite( dragRef ); + breakMacEventLoop(); + return noErr; + break; + case kDragTrackingLeaveWindow: + // HideDragHilite() + fl_cursor( FL_CURSOR_DEFAULT ); //HideDragHilite( dragRef ); + if ( fl_dnd_target_window ) + { + Fl::handle( FL_DND_LEAVE, fl_dnd_target_window ); + fl_dnd_target_window = 0; + } + breakMacEventLoop(); + return noErr; + } + return noErr; +} + + +/** + * Drag'n'drop receive handler + */ +static pascal OSErr dndReceiveHandler( WindowPtr w, void *userData, DragReference dragRef ) +{ + Point mp; + OSErr ret; + + Fl_Window *target = fl_dnd_target_window = (Fl_Window*)userData; + Fl::first_window(target); + GetDragMouse( dragRef, &mp, 0 ); + Fl::e_x_root = mp.h; + Fl::e_y_root = mp.v; + Fl::e_x = Fl::e_x_root - target->x(); + Fl::e_y = Fl::e_y_root - target->y(); + if ( !Fl::handle( FL_DND_RELEASE, target ) ) + return userCanceledErr; + + ret = fillCurrentDragData(dragRef); + if (ret==userCanceledErr) + return userCanceledErr; + + Fl::e_length = currDragSize; + Fl::e_text = currDragData; +// printf("Sending following text to widget %p:\n%s\n", Fl::belowmouse(), Fl::e_text); + int old_event = Fl::e_number; + Fl::belowmouse()->handle(Fl::e_number = FL_PASTE); + Fl::e_number = old_event; + + if (currDragData) { + free(currDragData); + } + currDragData = 0L; + currDragRef = 0; + Fl::e_text = 0L; + Fl::e_length = 0; + fl_dnd_target_window = 0L; + + breakMacEventLoop(); + return noErr; +} + + +/** + * go ahead, create that (sub)window + * \todo we should make menu windows slightly transparent for the new Mac look + */ +void Fl_X::make(Fl_Window* w) +{ + static int xyPos = 100; + if ( w->parent() ) // create a subwindow + { + Fl_Group::current(0); + Rect wRect; + wRect.top = w->y(); + wRect.left = w->x(); + wRect.bottom = w->y() + w->h(); if (wRect.bottom<=wRect.top) wRect.bottom = wRect.top+1; + wRect.right = w->x() + w->w(); if (wRect.right<=wRect.left) wRect.right = wRect.left+1; + // our subwindow needs this structure to know about its clipping. + Fl_X* x = new Fl_X; + x->other_xid = 0; + x->region = 0; + x->subRegion = 0; + x->cursor = fl_default_cursor; + x->gc = 0; // stay 0 for Quickdraw; fill with CGContext for Quartz + Fl_Window *win = w->window(); + Fl_X *xo = Fl_X::i(win); + if (xo) { + x->xidNext = xo->xidChildren; + x->xidChildren = 0L; + xo->xidChildren = x; + x->xid = fl_xid(win); + x->w = w; w->i = x; + x->wait_for_expose = 0; + x->next = Fl_X::first; // must be in the list for ::flush() + Fl_X::first = x; + int old_event = Fl::e_number; + w->handle(Fl::e_number = FL_SHOW); + Fl::e_number = old_event; + w->redraw(); // force draw to happen + } + fl_show_iconic = 0; + } + else // create a desktop window + { + Fl_Group::current(0); + fl_open_display(); + int winclass = kDocumentWindowClass; + int winattr = kWindowStandardHandlerAttribute | kWindowCloseBoxAttribute | kWindowCollapseBoxAttribute; + int xp = w->x(); + int yp = w->y(); + int wp = w->w(); + int hp = w->h(); + if (w->size_range_set) { + if ( w->minh != w->maxh || w->minw != w->maxw) + winattr |= kWindowFullZoomAttribute | kWindowResizableAttribute | kWindowLiveResizeAttribute; + } else { + if (w->resizable()) { + Fl_Widget *o = w->resizable(); + int minw = o->w(); if (minw > 100) minw = 100; + int minh = o->h(); if (minh > 100) minh = 100; + w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0); + winattr |= kWindowFullZoomAttribute | kWindowResizableAttribute | kWindowLiveResizeAttribute; + } else { + w->size_range(w->w(), w->h(), w->w(), w->h()); + } + } + int xwm = xp, ywm = yp, bt, bx, by; + + if (!fake_X_wm(w, xwm, ywm, bt, bx, by)) { + // menu windows and tooltips + if (w->modal()||w->override()) { + winclass = kHelpWindowClass; + winattr = 0; + } else { + winattr = 512; // kWindowNoTitleBarAttribute; + } + } else if (w->modal()) { + winclass = kMovableModalWindowClass; + } + + if (by+bt) { + wp += 2*bx; + hp += 2*by+bt; + } + if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) { + // use the Carbon functions below for default window positioning + w->x(xyPos+Fl::x()); + w->y(xyPos+Fl::y()); + xyPos += 25; + if (xyPos>200) xyPos = 100; + } else { + if (!Fl::grab()) { + xp = xwm; yp = ywm; + w->x(xp);w->y(yp); + } + xp -= bx; + yp -= by+bt; + } + + if (w->non_modal() && Fl_X::first && !fl_disable_transient_for) { + // find some other window to be "transient for": + Fl_Window* w = Fl_X::first->w; + while (w->parent()) w = w->window(); // todo: this code does not make any sense! (w!=w??) + } + + Rect wRect; + wRect.top = w->y(); + wRect.left = w->x(); + wRect.bottom = w->y() + w->h(); if (wRect.bottom<=wRect.top) wRect.bottom = wRect.top+1; + wRect.right = w->x() + w->w(); if (wRect.right<=wRect.left) wRect.right = wRect.left+1; + + const char *name = w->label(); + Str255 pTitle; + if (name) { + if (strlen(name) > 255) pTitle[0] = 255; + else pTitle[0] = strlen(name); + + memcpy(pTitle+1, name, pTitle[0]); + } else pTitle[0] = 0; + + Fl_X* x = new Fl_X; + x->other_xid = 0; // room for doublebuffering image map. On OS X this is only used by overlay windows + x->region = 0; + x->subRegion = 0; + x->cursor = fl_default_cursor; + x->xidChildren = 0; + x->xidNext = 0; + x->gc = 0; + + winattr &= GetAvailableWindowAttributes( winclass ); // make sure that the window will open + CreateNewWindow( winclass, winattr, &wRect, &(x->xid) ); + SetWTitle(x->xid, pTitle); + MoveWindow(x->xid, wRect.left, wRect.top, 1); // avoid Carbon Bug on old OS + if (w->non_modal() && !w->modal()) { + // Major kludge: this is to have the regular look, but stay above the document windows + SetWindowClass(x->xid, kFloatingWindowClass); + SetWindowActivationScope(x->xid, kWindowActivationScopeAll); + } + if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) + { + WindowRef pw = Fl_X::first ? Fl_X::first->xid : 0 ; + if (w->modal()) { + RepositionWindow(x->xid, pw, kWindowAlertPositionOnParentWindowScreen); + } else if (w->non_modal()) { + RepositionWindow(x->xid, pw, kWindowCenterOnParentWindowScreen); + } else { + RepositionWindow(x->xid, pw, kWindowCascadeOnParentWindowScreen); + } + } + x->w = w; w->i = x; + x->wait_for_expose = 1; + x->next = Fl_X::first; + Fl_X::first = x; + { // Install Carbon Event handlers + OSStatus ret; + EventHandlerUPP mousewheelHandler = NewEventHandlerUPP( carbonMousewheelHandler ); // will not be disposed by Carbon... + static EventTypeSpec mousewheelEvents[] = { + { kEventClassMouse, kEventMouseWheelMoved } }; + ret = InstallWindowEventHandler( x->xid, mousewheelHandler, + (int)(sizeof(mousewheelEvents)/sizeof(mousewheelEvents[0])), + mousewheelEvents, w, 0L ); + EventHandlerUPP mouseHandler = NewEventHandlerUPP( carbonMouseHandler ); // will not be disposed by Carbon... + static EventTypeSpec mouseEvents[] = { + { kEventClassMouse, kEventMouseDown }, + { kEventClassMouse, kEventMouseUp }, + { kEventClassMouse, kEventMouseMoved }, + { kEventClassMouse, kEventMouseDragged } }; + ret = InstallWindowEventHandler( x->xid, mouseHandler, 4, mouseEvents, w, 0L ); + EventHandlerUPP keyboardHandler = NewEventHandlerUPP( carbonKeyboardHandler ); // will not be disposed by Carbon... + static EventTypeSpec keyboardEvents[] = { + { kEventClassKeyboard, kEventRawKeyDown }, + { kEventClassKeyboard, kEventRawKeyRepeat }, + { kEventClassKeyboard, kEventRawKeyUp }, + { kEventClassKeyboard, kEventRawKeyModifiersChanged } }; + ret = InstallWindowEventHandler( x->xid, keyboardHandler, 4, keyboardEvents, w, 0L ); + EventHandlerUPP windowHandler = NewEventHandlerUPP( carbonWindowHandler ); // will not be disposed by Carbon... + static EventTypeSpec windowEvents[] = { + { kEventClassWindow, kEventWindowDrawContent }, + { kEventClassWindow, kEventWindowShown }, + { kEventClassWindow, kEventWindowHidden }, + { kEventClassWindow, kEventWindowActivated }, + { kEventClassWindow, kEventWindowDeactivated }, + { kEventClassWindow, kEventWindowClose }, + { kEventClassWindow, kEventWindowCollapsed }, + { kEventClassWindow, kEventWindowExpanded }, + { kEventClassWindow, kEventWindowBoundsChanging }, + { kEventClassWindow, kEventWindowBoundsChanged } }; + ret = InstallWindowEventHandler( x->xid, windowHandler, 10, windowEvents, w, 0L ); + ret = InstallTrackingHandler( dndTrackingHandler, x->xid, w ); + ret = InstallReceiveHandler( dndReceiveHandler, x->xid, w ); + } + + if ( ! Fl_X::first->next ) // if this is the first window, we need to bring the application to the front + { + ProcessSerialNumber psn; + OSErr err = GetCurrentProcess( &psn ); + if ( err==noErr ) SetFrontProcess( &psn ); + } + + if (w->size_range_set) w->size_range_(); + + if (winclass != kHelpWindowClass) { + Fl_Tooltip::enter(0); + } + if (w->size_range_set) w->size_range_(); + ShowWindow(x->xid); + if (fl_show_iconic) { + fl_show_iconic = 0; + CollapseWindow( x->xid, true ); // \todo Mac ; untested + } else { + w->set_visible(); + } + + Rect rect; + GetWindowBounds(x->xid, kWindowContentRgn, &rect); + w->x(rect.left); w->y(rect.top); + w->w(rect.right-rect.left); w->h(rect.bottom-rect.top); + + int old_event = Fl::e_number; + w->handle(Fl::e_number = FL_SHOW); + Fl::e_number = old_event; + w->redraw(); // force draw to happen + + if (w->modal()) { Fl::modal_ = w; fl_fix_focus(); } + } +} + + +/** + * Tell the OS what window sizes we want to allow + */ +void Fl_Window::size_range_() { + size_range_set = 1; + HISize minSize = { minw, minh }; + HISize maxSize = { maxw?maxw:32000, maxh?maxh:32000 }; + if (i && i->xid) + SetWindowResizeLimits(i->xid, &minSize, &maxSize); +} + + +/** + * returns pointer to the filename, or null if name ends with ':' + */ +const char *fl_filename_name( const char *name ) +{ + const char *p, *q; + if (!name) return (0); + for ( p = q = name ; *p ; ) + { + if ( ( p[0] == ':' ) && ( p[1] == ':' ) ) + { + q = p+2; + p++; + } + else if (p[0] == '/') + q = p + 1; + p++; + } + return q; +} + + +/** + * set the window title bar + * \todo make the titlebar icon work! + */ +void Fl_Window::label(const char *name,const char */*iname*/) { + Fl_Widget::label(name); + Str255 pTitle; + + if (name) { pTitle[0] = strlen(name); memcpy(pTitle+1, name, pTitle[0]); } + else pTitle[0] = 0; + + if (shown() || i) SetWTitle(fl_xid(this), pTitle); +} + + +/** + * make a window visible + */ +void Fl_Window::show() { + image(Fl::scheme_bg_); + if (Fl::scheme_bg_) { + labeltype(FL_NORMAL_LABEL); + align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP); + } else { + labeltype(FL_NO_LABEL); + } + Fl_Tooltip::exit(this); + if (!shown() || !i) { + Fl_X::make(this); + } else { + if ( !parent() ) + { + if ( IsWindowCollapsed( i->xid ) ) CollapseWindow( i->xid, false ); + if (!fl_capture) { + BringToFront(i->xid); + SelectWindow(i->xid); + } + } + } +} + + +/** + * resize a window + */ +void Fl_Window::resize(int X,int Y,int W,int H) { + if (W<=0) W = 1; // OS X does not like zero width windows + if (H<=0) H = 1; + int is_a_resize = (W != w() || H != h()); +// printf("Fl_Winodw::resize(X=%d, Y=%d, W=%d, H=%d), is_a_resize=%d, resize_from_system=%p, this=%p\n", +// X, Y, W, H, is_a_resize, resize_from_system, this); + if (X != x() || Y != y()) set_flag(FL_FORCE_POSITION); + else if (!is_a_resize) return; + if ( (resize_from_system!=this) && (!parent()) && shown()) { + if (is_a_resize) { + if (resizable()) { + if (Wmaxw) maxw = W; // over a previously set size_range + if (Hmaxh) maxh = H; + size_range(minw, minh, maxw, maxh); + } else { + size_range(W, H, W, H); + } + Rect dim; dim.left=X; dim.top=Y; dim.right=X+W; dim.bottom=Y+H; + SetWindowBounds(i->xid, kWindowContentRgn, &dim); + Rect all; all.top=-32000; all.bottom=32000; all.left=-32000; all.right=32000; + InvalWindowRect( i->xid, &all ); + } else { + MoveWindow(i->xid, X, Y, 0); + } + } + resize_from_system = 0; + if (is_a_resize) { + Fl_Group::resize(X,Y,W,H); + if (shown()) { + redraw(); + } + } else { + x(X); y(Y); + } +} + + +/** + * make all drawing go into this window (called by subclass flush() impl.) + */ +void Fl_Window::make_current() +{ +#ifdef __APPLE_QUARTZ__ + OSStatus err; + Fl_X::q_release_context(); +#endif + if ( !fl_window_region ) + fl_window_region = NewRgn(); + fl_window = i->xid; + current_ = this; + + SetPort( GetWindowPort(i->xid) ); // \todo check for the handling of doublebuffered windows + + int xp = 0, yp = 0; + Fl_Window *win = this; + while ( win ) + { + if ( !win->window() ) + break; + xp += win->x(); + yp += win->y(); + win = (Fl_Window*)win->window(); + } + SetOrigin( -xp, -yp ); + + SetRectRgn( fl_window_region, 0, 0, w(), h() ); + + // \todo for performance reasons: we don't have to create this unless the child windows moved + for ( Fl_X *cx = i->xidChildren; cx; cx = cx->xidNext ) + { + Fl_Window *cw = cx->w; + if (!cw->visible_r()) continue; + Fl_Region r = NewRgn(); + SetRectRgn( r, cw->x() - xp, cw->y() - yp, + cw->x() + cw->w() - xp, cw->y() + cw->h() - yp ); + DiffRgn( fl_window_region, r, fl_window_region ); + DisposeRgn( r ); + } + +#ifdef __APPLE_QUARTZ__ + err = QDBeginCGContext(GetWindowPort(i->xid), &i->gc); + if (err!=noErr) + fprintf(stderr, "Error %d in QDBeginCGContext\n", (int)err); + fl_gc = i->gc; + CGContextSaveGState(fl_gc); + Fl_X::q_fill_context(); +#endif + fl_clip_region( 0 ); + SetPortClipRegion( GetWindowPort(i->xid), fl_window_region ); + return; +} + +// helper function to manage the current CGContext fl_gc +#ifdef __APPLE_QUARTZ__ +extern Fl_Color fl_color_; +extern class Fl_FontSize *fl_fontsize; +extern void fl_font(class Fl_FontSize*); +extern void fl_quartz_restore_line_style_(); + +// FLTK has only one global graphics state. This function copies the FLTK state into the +// current Quartz context +void Fl_X::q_fill_context() { + if (!fl_gc) return; + int hgt = 0; + if (fl_window) { + Rect portRect; + GetPortBounds(GetWindowPort( fl_window ), &portRect); + hgt = portRect.bottom-portRect.top; + } else { + hgt = CGBitmapContextGetHeight(fl_gc); + } + CGContextTranslateCTM(fl_gc, 0.5, hgt-0.5f); + CGContextScaleCTM(fl_gc, 1.0f, -1.0f); + fl_font(fl_fontsize); + fl_color(fl_color_); + fl_quartz_restore_line_style_(); +} + +// The only way to reset clipping to its original state is to pop the current graphics +// state and restore the global state. +void Fl_X::q_clear_clipping() { + if (!fl_gc) return; + CGContextRestoreGState(fl_gc); + CGContextSaveGState(fl_gc); +} + +// Give the Quartz context back to the system +void Fl_X::q_release_context(Fl_X *x) { + if (x && x->gc!=fl_gc) return; + if (!fl_gc) return; + CGContextRestoreGState(fl_gc); + if (fl_window) { + OSStatus err = QDEndCGContext(GetWindowPort(fl_window), &fl_gc); + if (err!=noErr) + fprintf(stderr, "Error %d in QDEndCGContext\n", (int)err); + } + fl_gc = 0; +} + +void Fl_X::q_begin_image(CGRect &rect, int cx, int cy, int w, int h) { + CGContextSaveGState(fl_gc); + CGAffineTransform mx = CGContextGetCTM(fl_gc); + CGRect r2 = rect; + r2.origin.x -= 0.5f; + r2.origin.y -= 0.5f; + CGContextClipToRect(fl_gc, r2); + mx.d = -1.0; mx.tx = -mx.tx; + CGContextConcatCTM(fl_gc, mx); + rect.origin.x = -(mx.tx+0.5f) + rect.origin.x - cx; + rect.origin.y = (mx.ty+0.5f) - rect.origin.y - h + cy; + rect.size.width = w; + rect.size.height = h; +} + +void Fl_X::q_end_image() { + CGContextRestoreGState(fl_gc); +} + +#endif + +//////////////////////////////////////////////////////////////// +// Cut & paste. + +Fl_Widget *fl_selection_requestor = 0; +char *fl_selection_buffer[2]; +int fl_selection_length[2]; +int fl_selection_buffer_length[2]; +static ScrapRef myScrap = 0; + +/** + * create a selection + * owner: widget that created the selection + * stuff: pointer to selected data + * size of selected data + */ +void Fl::copy(const char *stuff, int len, int clipboard) { + if (!stuff || len<0) return; + if (len+1 > fl_selection_buffer_length[clipboard]) { + delete[] fl_selection_buffer[clipboard]; + fl_selection_buffer[clipboard] = new char[len+100]; + fl_selection_buffer_length[clipboard] = len+100; + } + memcpy(fl_selection_buffer[clipboard], stuff, len); + fl_selection_buffer[clipboard][len] = 0; // needed for direct paste + fl_selection_length[clipboard] = len; + if (clipboard) { + ClearCurrentScrap(); + OSStatus ret = GetCurrentScrap( &myScrap ); + if ( ret != noErr ) { + myScrap = 0; + return; + } + // Previous version changed \n to \r before sending the text, but I would + // prefer to leave the local buffer alone, so a copied buffer may be + // needed. Check to see if this is necessary on OS/X. + PutScrapFlavor( myScrap, kScrapFlavorTypeText, 0, + len, fl_selection_buffer[1] ); + } +} + +// Call this when a "paste" operation happens: +void Fl::paste(Fl_Widget &receiver, int clipboard) { + if (clipboard) { + // see if we own the selection, if not go get it: + ScrapRef scrap = 0; + Size len = 0; + if (GetCurrentScrap(&scrap) == noErr && scrap != myScrap && + GetScrapFlavorSize(scrap, kScrapFlavorTypeText, &len) == noErr) { + if ( len >= fl_selection_buffer_length[1] ) { + fl_selection_buffer_length[1] = len + 32; + delete[] fl_selection_buffer[1]; + fl_selection_buffer[1] = new char[len + 32]; + } + fl_selection_length[1] = len; len++; + GetScrapFlavorData( scrap, kScrapFlavorTypeText, &len, + fl_selection_buffer[1] ); + fl_selection_buffer[1][fl_selection_length[1]] = 0; + // turn all \r characters into \n: + for (int x = 0; x < len; x++) { + if (fl_selection_buffer[1][x] == '\r') + fl_selection_buffer[1][x] = '\n'; + } + } + } + Fl::e_text = fl_selection_buffer[clipboard]; + Fl::e_length = fl_selection_length[clipboard]; + if (!Fl::e_text) Fl::e_text = (char *)""; + receiver.handle(FL_PASTE); + return; +} + +void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data) +{ + // check, if this timer slot exists already + for (int i = 0; i < mac_timer_used; ++i) { + MacTimeout& t = mac_timers[i]; + // if so, simply change the fire interval + if (t.callback == cb && t.data == data) { + SetEventLoopTimerNextFireTime(t.timer, (EventTimerInterval)time); + t.pending = 1; + return; + } + } + // no existing timer to use. Create a new one: + int timer_id = -1; + // find an empty slot in the timer array + for (int i = 0; i < mac_timer_used; ++i) { + if ( !mac_timers[i].timer ) { + timer_id = i; + break; + } + } + // if there was no empty slot, append a new timer + if (timer_id == -1) { + // make space if needed + if (mac_timer_used == mac_timer_alloc) { + realloc_timers(); + } + timer_id = mac_timer_used++; + } + // now install a brand new timer + MacTimeout& t = mac_timers[timer_id]; + EventTimerInterval fireDelay = (EventTimerInterval)time; + EventLoopTimerUPP timerUPP = NewEventLoopTimerUPP(do_timer); + EventLoopTimerRef timerRef = 0; + OSStatus err = InstallEventLoopTimer(GetMainEventLoop(), fireDelay, 0, timerUPP, data, &timerRef); + if (err == noErr) { + t.callback = cb; + t.data = data; + t.timer = timerRef; + t.upp = timerUPP; + t.pending = 1; + } else { + if (timerRef) + RemoveEventLoopTimer(timerRef); + if (timerUPP) + DisposeEventLoopTimerUPP(timerUPP); + } +} + +void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data) +{ + // currently, repeat_timeout does not subtract the trigger time of the previous timer event as it should. + add_timeout(time, cb, data); +} + +int Fl::has_timeout(Fl_Timeout_Handler cb, void* data) +{ + for (int i = 0; i < mac_timer_used; ++i) { + MacTimeout& t = mac_timers[i]; + if (t.callback == cb && t.data == data && t.pending) { + return 1; + } + } + return 0; +} + +void Fl::remove_timeout(Fl_Timeout_Handler cb, void* data) +{ + for (int i = 0; i < mac_timer_used; ++i) { + MacTimeout& t = mac_timers[i]; + if (t.callback == cb && ( t.data == data || data == NULL)) { + delete_timer(t); + } + } +} + +int MacUnlinkWindow(Fl_X *ip, Fl_X *start) { + if (!ip) return 0; + if (start) { + Fl_X *pc = start; + while (pc) { + if (pc->xidNext == ip) { + pc->xidNext = ip->xidNext; + return 1; + } + if (pc->xidChildren) { + if (pc->xidChildren == ip) { + pc->xidChildren = ip->xidNext; + return 1; + } + if (MacUnlinkWindow(ip, pc->xidChildren)) + return 1; + } + pc = pc->xidNext; + } + } else { + for ( Fl_X *pc = Fl_X::first; pc; pc = pc->next ) { + if (MacUnlinkWindow(ip, pc)) + return 1; + } + } + return 0; +} + +static void MacRelinkWindow(Fl_X *x, Fl_X *p) { + if (!x || !p) return; + // first, check if 'x' is already registered as a child of 'p' + for (Fl_X *i = p->xidChildren; i; i=i->xidNext) { + if (i == x) return; + } + // now add 'x' as the first child of 'p' + x->xidNext = p->xidChildren; + p->xidChildren = x; +} + +void MacDestroyWindow(Fl_Window *w, WindowPtr p) { + MacUnmapWindow(w, p); + if (w && !w->parent() && p) + DisposeWindow(p); +} + +void MacMapWindow(Fl_Window *w, WindowPtr p) { + if (w && p) + ShowWindow(p); + //+ link to window list + if (w && w->parent()) { + MacRelinkWindow(Fl_X::i(w), Fl_X::i(w->window())); + w->redraw(); + } +} + +void MacUnmapWindow(Fl_Window *w, WindowPtr p) { + if (w && !w->parent() && p) + HideWindow(p); + if (w && Fl_X::i(w)) + MacUnlinkWindow(Fl_X::i(w)); +} + +// +// End of "$Id: Fl_mac.cxx 6800 2009-06-28 21:54:59Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_own_colormap.cxx b/third_party/windows/fltk-1.1.10/src/Fl_own_colormap.cxx new file mode 100644 index 0000000..d7fdaec --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_own_colormap.cxx @@ -0,0 +1,83 @@ +// +// "$Id: Fl_own_colormap.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Private colormap support for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Using the default system colormap can be a bad idea on PseudoColor +// visuals, since typically every application uses the default colormap and +// you can run out of colormap entries easily. +// +// The solution is to always create a new colormap on PseudoColor displays +// and copy the first 16 colors from the default colormap so that we won't +// get huge color changes when switching windows. + +#include +#include +#include + +#ifdef WIN32 +// There is probably something relevant to do on MSWindows 8-bit displays +// but I don't know what it is + +void Fl::own_colormap() {} + +#elif defined(__APPLE__) +// MacOS X always provides a TrueColor interface... + +void Fl::own_colormap() {} +#else +// X version + +void Fl::own_colormap() { + fl_open_display(); +#if USE_COLORMAP + switch (fl_visual->c_class) { + case GrayScale : + case PseudoColor : + case DirectColor : + break; + default: + return; // don't do anything for non-colormapped visuals + } + int i; + XColor colors[16]; + // Get the first 16 colors from the default colormap... + for (i = 0; i < 16; i ++) colors[i].pixel = i; + XQueryColors(fl_display, fl_colormap, colors, 16); + // Create a new colormap... + fl_colormap = XCreateColormap(fl_display, + RootWindow(fl_display,fl_screen), + fl_visual->visual, AllocNone); + // Copy those first 16 colors to our own colormap: + for (i = 0; i < 16; i ++) + XAllocColor(fl_display, fl_colormap, colors + i); +#endif +} + +#endif + +// +// End of "$Id: Fl_own_colormap.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_visual.cxx b/third_party/windows/fltk-1.1.10/src/Fl_visual.cxx new file mode 100644 index 0000000..6a9ee85 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_visual.cxx @@ -0,0 +1,121 @@ +// +// "$Id: Fl_visual.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Visual support for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Set the default visual according to passed switches: + +#include +#include +#include + +#ifdef WIN32 +int Fl::visual(int flags) { + fl_GetDC(0); + if (flags & FL_DOUBLE) return 0; + if (!(flags & FL_INDEX) && + GetDeviceCaps(fl_gc,BITSPIXEL) <= 8) return 0; + if ((flags & FL_RGB8) && GetDeviceCaps(fl_gc,BITSPIXEL)<24) return 0; + return 1; +} +#elif defined(__APPLE__) + +// \todo Mac : need to implement Visual flags +int Fl::visual(int flags) { + (void)flags; + return 1; +} + +#else + +#if USE_XDBE +#include +#endif + +static int test_visual(XVisualInfo& v, int flags) { + if (v.screen != fl_screen) return 0; +#if USE_COLORMAP + if (!(flags & FL_INDEX)) { + if (v.c_class != StaticColor && v.c_class != TrueColor) return 0; + if (v.depth <= 8) return 0; // fltk will work better in colormap mode + } + if (flags & FL_RGB8) { + if (v.depth < 24) return 0; + } + // for now, fltk does not like colormaps of more than 8 bits: + if ((v.c_class&1) && v.depth > 8) return 0; +#else + // simpler if we can't use colormapped visuals at all: + if (v.c_class != StaticColor && v.c_class != TrueColor) return 0; +#endif +#if USE_XDBE + if (flags & FL_DOUBLE) { + static XdbeScreenVisualInfo *xdbejunk; + if (!xdbejunk) { + int event_base, error_base; + if (!XdbeQueryExtension(fl_display, &event_base, &error_base)) return 0; + Drawable root = RootWindow(fl_display,fl_screen); + int numscreens = 1; + xdbejunk = XdbeGetVisualInfo(fl_display,&root,&numscreens); + if (!xdbejunk) return 0; + } + for (int j = 0; ; j++) { + if (j >= xdbejunk->count) return 0; + if (xdbejunk->visinfo[j].visual == v.visualid) break; + } + } +#endif + return 1; +} + +int Fl::visual(int flags) { +#if USE_XDBE == 0 + if (flags & FL_DOUBLE) return 0; +#endif + fl_open_display(); + // always use default if possible: + if (test_visual(*fl_visual, flags)) return 1; + // get all the visuals: + XVisualInfo vTemplate; + int num; + XVisualInfo *visualList = XGetVisualInfo(fl_display, 0, &vTemplate, &num); + // find all matches, use the one with greatest depth: + XVisualInfo *found = 0; + for (int i=0; idepth < visualList[i].depth) + found = &visualList[i]; + } + if (!found) {XFree((void*)visualList); return 0;} + fl_visual = found; + fl_colormap = XCreateColormap(fl_display, RootWindow(fl_display,fl_screen), + fl_visual->visual, AllocNone); + return 1; +} + +#endif + +// +// End of "$Id: Fl_visual.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_win32.cxx b/third_party/windows/fltk-1.1.10/src/Fl_win32.cxx new file mode 100644 index 0000000..1df2671 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_win32.cxx @@ -0,0 +1,1728 @@ +// +// "$Id: Fl_win32.cxx 6553 2008-12-07 11:05:41Z AlbrechtS $" +// +// WIN32-specific code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2007 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This file contains win32-specific code for fltk which is always linked +// in. Search other files for "WIN32" or filenames ending in _win32.cxx +// for other system-specific code. + +#include +#include +#include +#include +#include +#include "flstring.h" +#include "Fl_Font.H" +#include +#include +#include +#include +#ifdef __CYGWIN__ +# include +# include +#else +# include +#endif +#include +#include + +// The following include files require GCC 3.x or a non-GNU compiler... +#if !defined(__GNUC__) || __GNUC__ >= 3 +# include +# include +#endif // !__GNUC__ || __GNUC__ >= 3 + + +// +// USE_ASYNC_SELECT - define it if you have WSAAsyncSelect()... +// +// This currently doesn't appear to work; needs to be fixed! +// + +//#define USE_ASYNC_SELECT + +// USE_TRACK_MOUSE - define NO_TRACK_MOUSE if you don't have +// TrackMouseEvent()... +// +// Now (Dec. 2008) we can assume that current Cygwin/MinGW versions +// support the TrackMouseEvent() function, but WinCE obviously doesn't +// support it (STR 2095). Therefore, USE_TRACK_MOUSE is enabled by +// default, but you can disable it by defining NO_TRACK_MOUSE. +// +// TrackMouseEvent is only used to support window leave notifications +// under Windows. It can be used to get FL_LEAVE events, when the +// mouse leaves the _main_ application window (FLTK detects subwindow +// leave events by using normal move events). +// +// Implementation note: If the mouse cursor leaves one subwindow and +// enters another window, then Windows sends a WM_MOUSEMOVE message to +// the new window before it sends a WM_MOUSELEAVE message to the old +// (just left) window. We save the current mouse window in a static variable, +// and if we get a WM_MOUSELEAVE event for the current mouse window, this +// means that the top level window has been left (otherwise we would have +// got another WM_MOUSEMOVE message before). + +// #define NO_TRACK_MOUSE + +#if !defined(NO_TRACK_MOUSE) +# define USE_TRACK_MOUSE +#endif // NO_TRACK_MOUSE + +static Fl_Window *track_mouse_win=0; // current TrackMouseEvent() window + +// USE_CAPTURE_MOUSE_WIN - this must be defined for TrackMouseEvent to work +// correctly with subwindows - otherwise a single mouse click and release +// (without a move) would generate phantom leave events. +// This defines, if the current mouse window (maybe a subwindow) or the +// main window should get mouse events after pushing (and holding) a mouse +// button, i.e. when dragging the mouse. This is done by calling SetCapture +// (see below). + +#ifdef USE_TRACK_MOUSE +#define USE_CAPTURE_MOUSE_WIN +#endif // USE_TRACK_MOUSE + +// +// WM_SYNCPAINT is an "undocumented" message, which is finally defined in +// VC++ 6.0. +// + +#ifndef WM_SYNCPAINT +# define WM_SYNCPAINT 0x0088 +#endif + +#ifndef WM_MOUSELEAVE +# define WM_MOUSELEAVE 0x02a3 +#endif + +#ifndef WM_MOUSEWHEEL +# define WM_MOUSEWHEEL 0x020a +#endif + +#ifndef WHEEL_DELTA +# define WHEEL_DELTA 120 // according to MSDN. +#endif + + +// +// WM_FLSELECT is the user-defined message that we get when one of +// the sockets has pending data, etc. +// + +#define WM_FLSELECT (WM_APP+1) // WM_APP is used for hide-window + + +//////////////////////////////////////////////////////////////// +// interface to poll/select call: + +// fd's are only implemented for sockets. Microsoft Windows does not +// have a unified IO system, so it doesn't support select() on files, +// devices, or pipes... +// +// Microsoft provides the Berkeley select() call and an asynchronous +// select function that sends a WIN32 message when the select condition +// exists... +static int maxfd = 0; +#ifndef USE_ASYNC_SELECT +static fd_set fdsets[3]; +#endif // !USE_ASYNC_SELECT + +#define POLLIN 1 +#define POLLOUT 4 +#define POLLERR 8 + +#if !defined(__GNUC__) || __GNUC__ >= 3 +extern IDropTarget *flIDropTarget; +#endif // !__GNUC__ || __GNUC__ >= 3 + +static int nfds = 0; +static int fd_array_size = 0; +static struct FD { + int fd; + short events; + void (*cb)(int, void*); + void* arg; +} *fd = 0; + +void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) { + remove_fd(n,events); + int i = nfds++; + if (i >= fd_array_size) { + fd_array_size = 2*fd_array_size+1; + fd = (FD*)realloc(fd, fd_array_size*sizeof(FD)); + } + fd[i].fd = n; + fd[i].events = (short)events; + fd[i].cb = cb; + fd[i].arg = v; + +#ifdef USE_ASYNC_SELECT + int mask = 0; + if (events & POLLIN) mask |= FD_READ; + if (events & POLLOUT) mask |= FD_WRITE; + if (events & POLLERR) mask |= FD_CLOSE; + WSAAsyncSelect(n, fl_window, WM_FLSELECT, mask); +#else + if (events & POLLIN) FD_SET((unsigned)n, &fdsets[0]); + if (events & POLLOUT) FD_SET((unsigned)n, &fdsets[1]); + if (events & POLLERR) FD_SET((unsigned)n, &fdsets[2]); + if (n > maxfd) maxfd = n; +#endif // USE_ASYNC_SELECT +} + +void Fl::add_fd(int fd, void (*cb)(int, void*), void* v) { + Fl::add_fd(fd, POLLIN, cb, v); +} + +void Fl::remove_fd(int n, int events) { + int i,j; + for (i=j=0; i0 if any callbacks were done. This version only +// returns zero if nothing happens during a 0.0 timeout, otherwise +// it returns 1. +int fl_wait(double time_to_wait) { + int have_message = 0; + + run_checks(); + + // idle processing + static char in_idle; + if (Fl::idle && !in_idle) { + in_idle = 1; + Fl::idle(); + in_idle = 0; + } + +#ifndef USE_ASYNC_SELECT + if (nfds) { + // For WIN32 we need to poll for socket input FIRST, since + // the event queue is not something we can select() on... + timeval t; + t.tv_sec = 0; + t.tv_usec = 0; + + fd_set fdt[3]; + fdt[0] = fdsets[0]; + fdt[1] = fdsets[1]; + fdt[2] = fdsets[2]; + if (::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t)) { + // We got something - do the callback! + for (int i = 0; i < nfds; i ++) { + int f = fd[i].fd; + short revents = 0; + if (FD_ISSET(f,&fdt[0])) revents |= POLLIN; + if (FD_ISSET(f,&fdt[1])) revents |= POLLOUT; + if (FD_ISSET(f,&fdt[2])) revents |= POLLERR; + if (fd[i].events & revents) fd[i].cb(f, fd[i].arg); + } + time_to_wait = 0.0; // just peek for any messages + } else { + // we need to check them periodically, so set a short timeout: + if (time_to_wait > .001) time_to_wait = .001; + } + } +#endif // USE_ASYNC_SELECT + + if (Fl::idle || Fl::damage()) + time_to_wait = 0.0; + + // if there are no more windows and this timer is set + // to FOREVER, continue through or look up indefinetely + if (!Fl::first_window() && time_to_wait==1e20) + time_to_wait = 0.0; + + fl_unlock_function(); + + time_to_wait = (time_to_wait > 10000 ? 10000 : time_to_wait); + int t_msec = (int) (time_to_wait * 1000.0 + 0.5); + MsgWaitForMultipleObjects(0, NULL, FALSE, t_msec, QS_ALLINPUT); + + fl_lock_function(); + + // Execute the message we got, and all other pending messages: + have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); + if (have_message > 0) { + while (have_message != 0 && have_message != -1) { +#ifdef USE_ASYNC_SELECT + if (fl_msg.message == WM_FLSELECT) { + // Got notification for socket + for (int i = 0; i < nfds; i ++) + if (fd[i].fd == (int)fl_msg.wParam) { + (fd[i].cb)(fd[i].fd, fd[i].arg); + break; + } + // looks like it is best to do the dispatch-message anyway: + } +#endif + + if (fl_msg.message == fl_wake_msg) { + // Used for awaking wait() from another thread + thread_message_ = (void*)fl_msg.wParam; + Fl_Awake_Handler func; + void *data; + while (Fl::get_awake_handler_(func, data)==0) { + func(data); + } + } + + TranslateMessage(&fl_msg); + DispatchMessage(&fl_msg); + have_message = PeekMessage(&fl_msg, NULL, 0, 0, PM_REMOVE); + } + } + Fl::flush(); + + // This should return 0 if only timer events were handled: + return 1; +} + +// fl_ready() is just like fl_wait(0.0) except no callbacks are done: +int fl_ready() { + if (PeekMessage(&fl_msg, NULL, 0, 0, PM_NOREMOVE)) return 1; +#ifdef USE_ASYNC_SELECT + return 0; +#else + timeval t; + t.tv_sec = 0; + t.tv_usec = 0; + fd_set fdt[3]; + fdt[0] = fdsets[0]; + fdt[1] = fdsets[1]; + fdt[2] = fdsets[2]; + return ::select(0,&fdt[0],&fdt[1],&fdt[2],&t); +#endif // USE_ASYNC_SELECT +} + +//////////////////////////////////////////////////////////////// + +int Fl::x() +{ + RECT r; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); + return r.left; +} + +int Fl::y() +{ + RECT r; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); + return r.top; +} + +int Fl::h() +{ + RECT r; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); + return r.bottom - r.top; +} + +int Fl::w() +{ + RECT r; + + SystemParametersInfo(SPI_GETWORKAREA, 0, &r, 0); + return r.right - r.left; +} + +void Fl::get_mouse(int &x, int &y) { + POINT p; + GetCursorPos(&p); + x = p.x; + y = p.y; +} + +//////////////////////////////////////////////////////////////// +// code used for selections: + +char *fl_selection_buffer[2]; +int fl_selection_length[2]; +int fl_selection_buffer_length[2]; +char fl_i_own_selection[2]; + +// Convert \n -> \r\n +class Lf2CrlfConvert { + char *out; + int outlen; +public: + Lf2CrlfConvert(const char *in, int inlen) { + outlen = 0; + const char *i; + char *o; + int lencount; + // Predict size of \r\n conversion buffer + for ( i=in, lencount = inlen; lencount--; ) { + if ( *i == '\r' && *(i+1) == '\n' ) // leave \r\n untranslated + { i+=2; outlen+=2; } + else if ( *i == '\n' ) // \n by itself? leave room to insert \r + { i++; outlen+=2; } + else + { ++i; ++outlen; } + } + // Alloc conversion buffer + NULL + out = new char[outlen+1]; + // Handle \n -> \r\n conversion + for ( i=in, o=out, lencount = inlen; lencount--; ) { + if ( *i == '\r' && *(i+1) == '\n' ) // leave \r\n untranslated + { *o++ = *i++; *o++ = *i++; } + else if ( *i == '\n' ) // \n by itself? insert \r + { *o++ = '\r'; *o++ = *i++; } + else + { *o++ = *i++; } + } + *o++ = 0; + } + ~Lf2CrlfConvert() { + delete[] out; + } + int GetLength() const { return(outlen); } + const char* GetValue() const { return(out); } +}; + +// call this when you create a selection: +void Fl::copy(const char *stuff, int len, int clipboard) { + if (!stuff || len<0) return; + + // Convert \n -> \r\n (for old apps like Notepad, DOS) + Lf2CrlfConvert buf(stuff, len); + len = buf.GetLength(); + stuff = buf.GetValue(); + + if (len+1 > fl_selection_buffer_length[clipboard]) { + delete[] fl_selection_buffer[clipboard]; + fl_selection_buffer[clipboard] = new char[len+100]; + fl_selection_buffer_length[clipboard] = len+100; + } + memcpy(fl_selection_buffer[clipboard], stuff, len); + fl_selection_buffer[clipboard][len] = 0; // needed for direct paste + fl_selection_length[clipboard] = len; + if (clipboard) { + // set up for "delayed rendering": + if (OpenClipboard(fl_xid(Fl::first_window()))) { + // if the system clipboard works, use it + EmptyClipboard(); + SetClipboardData(CF_TEXT, NULL); + CloseClipboard(); + fl_i_own_selection[clipboard] = 0; + } else { + // only if it fails, instruct paste() to use the internal buffers + fl_i_own_selection[clipboard] = 1; + } + } +} + +// Call this when a "paste" operation happens: +void Fl::paste(Fl_Widget &receiver, int clipboard) { + if (!clipboard || fl_i_own_selection[clipboard]) { + // We already have it, do it quickly without window server. + // Notice that the text is clobbered if set_selection is + // called in response to FL_PASTE! + + // Convert \r\n -> \n + char *i = fl_selection_buffer[clipboard]; + if (i==0L) { + Fl::e_text = 0; + return; + } + Fl::e_text = new char[fl_selection_length[clipboard]+1]; + char *o = Fl::e_text; + while (*i) { + if ( *i == '\r' && *(i+1) == '\n') i++; + else *o++ = *i++; + } + *o = 0; + Fl::e_length = o - Fl::e_text; + receiver.handle(FL_PASTE); + delete [] Fl::e_text; + Fl::e_text = 0; + } else { + if (!OpenClipboard(NULL)) return; + HANDLE h = GetClipboardData(CF_TEXT); + if (h) { + Fl::e_text = (LPSTR)GlobalLock(h); + LPSTR a,b; + a = b = Fl::e_text; + while (*a) { // strip the CRLF pairs ($%$#@^) + if (*a == '\r' && a[1] == '\n') a++; + else *b++ = *a++; + } + *b = 0; + Fl::e_length = b - Fl::e_text; + receiver.handle(FL_PASTE); + GlobalUnlock(h); + } + CloseClipboard(); + } +} + +//////////////////////////////////////////////////////////////// + +HWND fl_capture; + +static int mouse_event(Fl_Window *window, int what, int button, + WPARAM wParam, LPARAM lParam) +{ + static int px, py, pmx, pmy; + POINT pt; + Fl::e_x = pt.x = (signed short)LOWORD(lParam); + Fl::e_y = pt.y = (signed short)HIWORD(lParam); + ClientToScreen(fl_xid(window), &pt); + Fl::e_x_root = pt.x; + Fl::e_y_root = pt.y; +#ifdef USE_CAPTURE_MOUSE_WIN + Fl_Window *mouse_window = window; // save "mouse window" +#endif + while (window->parent()) { + Fl::e_x += window->x(); + Fl::e_y += window->y(); + window = window->window(); + } + + ulong state = Fl::e_state & 0xff0000; // keep shift key states +#if 0 + // mouse event reports some shift flags, perhaps save them? + if (wParam & MK_SHIFT) state |= FL_SHIFT; + if (wParam & MK_CONTROL) state |= FL_CTRL; +#endif + if (wParam & MK_LBUTTON) state |= FL_BUTTON1; + if (wParam & MK_MBUTTON) state |= FL_BUTTON2; + if (wParam & MK_RBUTTON) state |= FL_BUTTON3; + Fl::e_state = state; + + switch (what) { + case 1: // double-click + if (Fl::e_is_click) {Fl::e_clicks++; goto J1;} + case 0: // single-click + Fl::e_clicks = 0; + J1: +#ifdef USE_CAPTURE_MOUSE_WIN + if (!fl_capture) SetCapture(fl_xid(mouse_window)); // use mouse window +#else + if (!fl_capture) SetCapture(fl_xid(window)); // use main window +#endif + Fl::e_keysym = FL_Button + button; + Fl::e_is_click = 1; + px = pmx = Fl::e_x_root; py = pmy = Fl::e_y_root; + return Fl::handle(FL_PUSH,window); + + case 2: // release: + if (!fl_capture) ReleaseCapture(); + Fl::e_keysym = FL_Button + button; + return Fl::handle(FL_RELEASE,window); + + case 3: // move: + default: // avoid compiler warning + // MSWindows produces extra events even if mouse does not move, ignore em: + if (Fl::e_x_root == pmx && Fl::e_y_root == pmy) return 1; + pmx = Fl::e_x_root; pmy = Fl::e_y_root; + if (abs(Fl::e_x_root-px)>5 || abs(Fl::e_y_root-py)>5) Fl::e_is_click = 0; + return Fl::handle(FL_MOVE,window); + + } +} + +// convert a MSWindows VK_x to an Fltk (X) Keysym: +// See also the inverse converter in Fl_get_key_win32.cxx +// This table is in numeric order by VK: +static const struct {unsigned short vk, fltk, extended;} vktab[] = { + {VK_BACK, FL_BackSpace}, + {VK_TAB, FL_Tab}, + {VK_CLEAR, FL_KP+'5', 0xff0b/*XK_Clear*/}, + {VK_RETURN, FL_Enter, FL_KP_Enter}, + {VK_SHIFT, FL_Shift_L, FL_Shift_R}, + {VK_CONTROL, FL_Control_L, FL_Control_R}, + {VK_MENU, FL_Alt_L, FL_Alt_R}, + {VK_PAUSE, FL_Pause}, + {VK_CAPITAL, FL_Caps_Lock}, + {VK_ESCAPE, FL_Escape}, + {VK_SPACE, ' '}, + {VK_PRIOR, FL_KP+'9', FL_Page_Up}, + {VK_NEXT, FL_KP+'3', FL_Page_Down}, + {VK_END, FL_KP+'1', FL_End}, + {VK_HOME, FL_KP+'7', FL_Home}, + {VK_LEFT, FL_KP+'4', FL_Left}, + {VK_UP, FL_KP+'8', FL_Up}, + {VK_RIGHT, FL_KP+'6', FL_Right}, + {VK_DOWN, FL_KP+'2', FL_Down}, + {VK_SNAPSHOT, FL_Print}, // does not work on NT + {VK_INSERT, FL_KP+'0', FL_Insert}, + {VK_DELETE, FL_KP+'.', FL_Delete}, + {VK_LWIN, FL_Meta_L}, + {VK_RWIN, FL_Meta_R}, + {VK_APPS, FL_Menu}, + {VK_MULTIPLY, FL_KP+'*'}, + {VK_ADD, FL_KP+'+'}, + {VK_SUBTRACT, FL_KP+'-'}, + {VK_DECIMAL, FL_KP+'.'}, + {VK_DIVIDE, FL_KP+'/'}, + {VK_NUMLOCK, FL_Num_Lock}, + {VK_SCROLL, FL_Scroll_Lock}, + {0xba, ';'}, + {0xbb, '='}, + {0xbc, ','}, + {0xbd, '-'}, + {0xbe, '.'}, + {0xbf, '/'}, + {0xc0, '`'}, + {0xdb, '['}, + {0xdc, '\\'}, + {0xdd, ']'}, + {0xde, '\''} +}; +static int ms2fltk(int vk, int extended) { + static unsigned short vklut[256]; + static unsigned short extendedlut[256]; + if (!vklut[1]) { // init the table + unsigned int i; + for (i = 0; i < 256; i++) vklut[i] = tolower(i); + for (i=VK_F1; i<=VK_F16; i++) vklut[i] = i+(FL_F-(VK_F1-1)); + for (i=VK_NUMPAD0; i<=VK_NUMPAD9; i++) vklut[i] = i+(FL_KP+'0'-VK_NUMPAD0); + for (i = 0; i < sizeof(vktab)/sizeof(*vktab); i++) { + vklut[vktab[i].vk] = vktab[i].fltk; + extendedlut[vktab[i].vk] = vktab[i].extended; + } + for (i = 0; i < 256; i++) if (!extendedlut[i]) extendedlut[i] = vklut[i]; + } + return extended ? extendedlut[vk] : vklut[vk]; +} + +#if USE_COLORMAP +extern HPALETTE fl_select_palette(void); // in fl_color_win32.cxx +#endif + + +///////////////////////////////////////////////////////////////////////////// +/// Win32 timers +/// + +struct Win32Timer +{ + UINT_PTR handle; + Fl_Timeout_Handler callback; + void *data; +}; +static Win32Timer* win32_timers; +static int win32_timer_alloc; +static int win32_timer_used; +static HWND s_TimerWnd; + +static void realloc_timers() +{ + if (win32_timer_alloc == 0) { + win32_timer_alloc = 8; + } + win32_timer_alloc *= 2; + Win32Timer* new_timers = new Win32Timer[win32_timer_alloc]; + memset(new_timers, 0, sizeof(Win32Timer) * win32_timer_used); + memcpy(new_timers, win32_timers, sizeof(Win32Timer) * win32_timer_used); + Win32Timer* delete_me = win32_timers; + win32_timers = new_timers; + delete [] delete_me; +} + +static void delete_timer(Win32Timer& t) +{ + KillTimer(s_TimerWnd, t.handle); + memset(&t, 0, sizeof(Win32Timer)); +} + +/// END TIMERS +///////////////////////////////////////////////////////////////////////////// + +static Fl_Window* resize_bug_fix; + +extern void fl_save_pen(void); +extern void fl_restore_pen(void); + +static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) +{ + // Copy the message to fl_msg so add_handler code can see it, it is + // already there if this is called by DispatchMessage, but not if + // Windows calls this directly. + fl_msg.hwnd = hWnd; + fl_msg.message = uMsg; + fl_msg.wParam = wParam; + fl_msg.lParam = lParam; + //fl_msg.time = ??? + //fl_msg.pt = ??? + //fl_msg.lPrivate = ??? + + Fl_Window *window = fl_find(hWnd); + + if (window) switch (uMsg) { + + case WM_QUIT: // this should not happen? + Fl::fatal("WM_QUIT message"); + + case WM_CLOSE: // user clicked close box + Fl::handle(FL_CLOSE, window); + PostQuitMessage(0); + return 0; + + case WM_SYNCPAINT : + case WM_NCPAINT : + case WM_ERASEBKGND : + // Andreas Weitl - WM_SYNCPAINT needs to be passed to DefWindowProc + // so that Windows can generate the proper paint messages... + // Similarly, WM_NCPAINT and WM_ERASEBKGND need this, too... + break; + + case WM_PAINT: { + Fl_Region R; + Fl_X *i = Fl_X::i(window); + i->wait_for_expose = 0; + char redraw_whole_window = false; + if (!i->region && window->damage()) { + // Redraw the whole window... + i->region = CreateRectRgn(0, 0, window->w(), window->h()); + redraw_whole_window = true; + } + + // We need to merge WIN32's damage into FLTK's damage. + R = CreateRectRgn(0,0,0,0); + int r = GetUpdateRgn(hWnd,R,0); + if (r==NULLREGION && !redraw_whole_window) { + break; + } + + if (i->region) { + // Also tell WIN32 that we are drawing someplace else as well... + CombineRgn(i->region, i->region, R, RGN_OR); + XDestroyRegion(R); + } else { + i->region = R; + } + if (window->type() == FL_DOUBLE_WINDOW) ValidateRgn(hWnd,0); + else ValidateRgn(hWnd,i->region); + + window->clear_damage((uchar)(window->damage()|FL_DAMAGE_EXPOSE)); + // These next two statements should not be here, so that all update + // is deferred until Fl::flush() is called during idle. However WIN32 + // apparently is very unhappy if we don't obey it and draw right now. + // Very annoying! + fl_GetDC(hWnd); // Make sure we have a DC for this window... + fl_save_pen(); + i->flush(); + fl_restore_pen(); + window->clear_damage(); + } return 0; + + case WM_LBUTTONDOWN: mouse_event(window, 0, 1, wParam, lParam); return 0; + case WM_LBUTTONDBLCLK:mouse_event(window, 1, 1, wParam, lParam); return 0; + case WM_LBUTTONUP: mouse_event(window, 2, 1, wParam, lParam); return 0; + case WM_MBUTTONDOWN: mouse_event(window, 0, 2, wParam, lParam); return 0; + case WM_MBUTTONDBLCLK:mouse_event(window, 1, 2, wParam, lParam); return 0; + case WM_MBUTTONUP: mouse_event(window, 2, 2, wParam, lParam); return 0; + case WM_RBUTTONDOWN: mouse_event(window, 0, 3, wParam, lParam); return 0; + case WM_RBUTTONDBLCLK:mouse_event(window, 1, 3, wParam, lParam); return 0; + case WM_RBUTTONUP: mouse_event(window, 2, 3, wParam, lParam); return 0; + + case WM_MOUSEMOVE: +#ifdef USE_TRACK_MOUSE + if (track_mouse_win != window) { + TRACKMOUSEEVENT tme; + tme.cbSize = sizeof(TRACKMOUSEEVENT); + tme.dwFlags = TME_LEAVE; + tme.hwndTrack = hWnd; + _TrackMouseEvent(&tme); + track_mouse_win = window; + } +#endif // USE_TRACK_MOUSE + mouse_event(window, 3, 0, wParam, lParam); + return 0; + + case WM_MOUSELEAVE: + if (track_mouse_win == window) { // we left the top level window ! + Fl_Window *tw = window; + while (tw->parent()) tw = tw->window(); // find top level window + Fl::belowmouse(0); + Fl::handle(FL_LEAVE, tw); + } + track_mouse_win = 0; // force TrackMouseEvent() restart + break; + + case WM_SETFOCUS: + Fl::handle(FL_FOCUS, window); + break; + + case WM_KILLFOCUS: + Fl::handle(FL_UNFOCUS, window); + Fl::flush(); // it never returns to main loop when deactivated... + break; + + case WM_SHOWWINDOW: + if (!window->parent()) { + Fl::handle(wParam ? FL_SHOW : FL_HIDE, window); + } + break; + + case WM_ACTIVATEAPP: + // From eric@vfx.sel.sony.com, we should process WM_ACTIVATEAPP + // messages to restore the correct state of the shift/ctrl/alt/lock + // keys... Added control, shift, alt, and meta keys, and changed + // to use GetAsyncKeyState and do it when wParam is 1 + // (that means we have focus...) + if (wParam) + { + ulong state = 0; + if (GetAsyncKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK; + if (GetAsyncKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK; + if (GetAsyncKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; + if (GetAsyncKeyState(VK_CONTROL)&~1) state |= FL_CTRL; + if (GetAsyncKeyState(VK_SHIFT)&~1) state |= FL_SHIFT; + if (GetAsyncKeyState(VK_MENU)) state |= FL_ALT; + if ((GetAsyncKeyState(VK_LWIN)|GetAsyncKeyState(VK_RWIN))&~1) state |= FL_META; + Fl::e_state = state; + return 0; + } + break; + + case WM_KEYDOWN: + case WM_SYSKEYDOWN: + case WM_KEYUP: + case WM_SYSKEYUP: + // save the keysym until we figure out the characters: + Fl::e_keysym = Fl::e_original_keysym = ms2fltk(wParam,lParam&(1<<24)); + // See if TranslateMessage turned it into a WM_*CHAR message: + if (PeekMessage(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) { + uMsg = fl_msg.message; + wParam = fl_msg.wParam; + lParam = fl_msg.lParam; + } + case WM_DEADCHAR: + case WM_SYSDEADCHAR: + case WM_CHAR: + case WM_SYSCHAR: { + ulong state = Fl::e_state & 0xff000000; // keep the mouse button state + // if GetKeyState is expensive we might want to comment some of these out: + if (GetKeyState(VK_SHIFT)&~1) state |= FL_SHIFT; + if (GetKeyState(VK_CAPITAL)) state |= FL_CAPS_LOCK; + if (GetKeyState(VK_CONTROL)&~1) state |= FL_CTRL; + // Alt gets reported for the Alt-GR switch on foreign keyboards. + // so we need to check the event as well to get it right: + if ((lParam&(1<<29)) //same as GetKeyState(VK_MENU) + && uMsg != WM_CHAR) state |= FL_ALT; + if (GetKeyState(VK_NUMLOCK)) state |= FL_NUM_LOCK; + if ((GetKeyState(VK_LWIN)|GetKeyState(VK_RWIN))&~1) { + // WIN32 bug? GetKeyState returns garbage if the user hit the + // meta key to pop up start menu. Sigh. + if ((GetAsyncKeyState(VK_LWIN)|GetAsyncKeyState(VK_RWIN))&~1) + state |= FL_META; + } + if (GetKeyState(VK_SCROLL)) state |= FL_SCROLL_LOCK; + Fl::e_state = state; + static char buffer[2]; + if (uMsg == WM_CHAR || uMsg == WM_SYSCHAR) { + buffer[0] = char(wParam); + Fl::e_length = 1; + } else if (Fl::e_keysym >= FL_KP && Fl::e_keysym <= FL_KP_Last) { + if (state & FL_NUM_LOCK) { + // Convert to regular keypress... + buffer[0] = Fl::e_keysym-FL_KP; + Fl::e_length = 1; + } else { + // Convert to special keypress... + buffer[0] = 0; + Fl::e_length = 0; + switch (Fl::e_keysym) { + case FL_KP + '0' : + Fl::e_keysym = FL_Insert; + break; + case FL_KP + '1' : + Fl::e_keysym = FL_End; + break; + case FL_KP + '2' : + Fl::e_keysym = FL_Down; + break; + case FL_KP + '3' : + Fl::e_keysym = FL_Page_Down; + break; + case FL_KP + '4' : + Fl::e_keysym = FL_Left; + break; + case FL_KP + '6' : + Fl::e_keysym = FL_Right; + break; + case FL_KP + '7' : + Fl::e_keysym = FL_Home; + break; + case FL_KP + '8' : + Fl::e_keysym = FL_Up; + break; + case FL_KP + '9' : + Fl::e_keysym = FL_Page_Up; + break; + case FL_KP + '.' : + Fl::e_keysym = FL_Delete; + break; + case FL_KP + '/' : + case FL_KP + '*' : + case FL_KP + '-' : + case FL_KP + '+' : + buffer[0] = Fl::e_keysym-FL_KP; + Fl::e_length = 1; + break; + } + } + } else if ((lParam & (1<<31))==0){ + buffer[0] = 0; + Fl::e_length = 0; + } + Fl::e_text = buffer; + if (lParam & (1<<31)) { // key up events. + if (Fl::handle(FL_KEYUP, window)) return 0; + break; + } + // for (int i = lParam&0xff; i--;) + while (window->parent()) window = window->window(); + if (Fl::handle(FL_KEYBOARD,window)) return 0; + break;} + + case WM_MOUSEWHEEL: { + static int delta = 0; // running total of all motion + delta += (SHORT)(HIWORD(wParam)); + Fl::e_dy = -delta / WHEEL_DELTA; + delta += Fl::e_dy * WHEEL_DELTA; + if (Fl::e_dy) Fl::handle(FL_MOUSEWHEEL, window); + return 0; + } + + case WM_GETMINMAXINFO: + Fl_X::i(window)->set_minmax((LPMINMAXINFO)lParam); + break; + + case WM_SIZE: + if (!window->parent()) { + if (wParam == SIZE_MINIMIZED || wParam == SIZE_MAXHIDE) { + Fl::handle(FL_HIDE, window); + } else { + Fl::handle(FL_SHOW, window); + resize_bug_fix = window; + window->size(LOWORD(lParam), HIWORD(lParam)); + } + } + break; + + case WM_MOVE: { + resize_bug_fix = window; + int nx = LOWORD(lParam); + int ny = HIWORD(lParam); + if (nx & 0x8000) nx -= 65536; + if (ny & 0x8000) ny -= 65536; + window->position(nx, ny); } + break; + + case WM_SETCURSOR: + if (LOWORD(lParam) == HTCLIENT) { + while (window->parent()) window = window->window(); + SetCursor(Fl_X::i(window)->cursor); + return 0; + } + break; + +#if USE_COLORMAP + case WM_QUERYNEWPALETTE : + fl_GetDC(hWnd); + if (fl_select_palette()) InvalidateRect(hWnd, NULL, FALSE); + break; + + case WM_PALETTECHANGED: + fl_GetDC(hWnd); + if ((HWND)wParam != hWnd && fl_select_palette()) UpdateColors(fl_gc); + break; + + case WM_CREATE : + fl_GetDC(hWnd); + fl_select_palette(); + break; +#endif + + case WM_DESTROYCLIPBOARD: + fl_i_own_selection[1] = 0; + return 1; + + case WM_RENDERALLFORMATS: + fl_i_own_selection[1] = 0; + // Windoze seems unhappy unless I do these two steps. Documentation + // seems to vary on whether opening the clipboard is necessary or + // is in fact wrong: + CloseClipboard(); + OpenClipboard(NULL); + // fall through... + case WM_RENDERFORMAT: { + HANDLE h = GlobalAlloc(GHND, fl_selection_length[1]+1); + if (h) { + LPSTR p = (LPSTR)GlobalLock(h); + memcpy(p, fl_selection_buffer[1], fl_selection_length[1]); + p[fl_selection_length[1]] = 0; + GlobalUnlock(h); + SetClipboardData(CF_TEXT, h); + } + // Windoze also seems unhappy if I don't do this. Documentation very + // unclear on what is correct: + if (fl_msg.message == WM_RENDERALLFORMATS) CloseClipboard(); + return 1;} + + default: + if (Fl::handle(0,0)) return 0; + break; + } + + return DefWindowProc(hWnd, uMsg, wParam, lParam); +} + +//////////////////////////////////////////////////////////////// +// This function gets the dimensions of the top/left borders and +// the title bar, if there is one, based on the FL_BORDER, FL_MODAL +// and FL_NONMODAL flags, and on the window's size range. +// It returns the following values: +// +// value | border | title bar +// 0 | none | no +// 1 | fix | yes +// 2 | size | yes + +int Fl_X::fake_X_wm(const Fl_Window* w,int &X,int &Y, int &bt,int &bx, int &by) { + int W, H, xoff, yoff, dx, dy; + int ret = bx = by = bt = 0; + + int fallback = 1; + if (!w->parent()) { + HWND hwnd = fl_xid(w); + if (hwnd) { + // The block below calculates the window borders by requesting the + // required decorated window rectangle for a desired client rectangle. + // If any part of the function above fails, we will drop to a + // fallback to get the best guess which is always available. + HWND hwnd = fl_xid(w); + // request the style flags of this window, as WIN32 sees them + LONG style = GetWindowLong(hwnd, GWL_STYLE); + LONG exstyle = GetWindowLong(hwnd, GWL_EXSTYLE); + RECT r; + r.left = w->x(); + r.top = w->y(); + r.right = w->x()+w->w(); + r.bottom = w->y()+w->h(); + // get the decoration rectangle for the desired client rectangle + BOOL ok = AdjustWindowRectEx(&r, style, FALSE, exstyle); + if (ok) { + X = r.left; + Y = r.top; + W = r.right - r.left; + H = r.bottom - r.top; + bx = w->x() - r.left; + by = r.bottom - w->y() - w->h(); // height of the bootm frame + bt = w->y() - r.top - by; // height of top caption bar + xoff = bx; + yoff = by + bt; + dx = W - w->w(); + dy = H - w->h(); + if (w->size_range_set && (w->maxw != w->minw || w->maxh != w->minh)) + ret = 2; + else + ret = 1; + fallback = 0; + } + } + } + // This is the original (pre 1.1.7) routine to calculate window border sizes. + if (fallback) { + if (w->border() && !w->parent()) { + if (w->size_range_set && (w->maxw != w->minw || w->maxh != w->minh)) { + ret = 2; + bx = GetSystemMetrics(SM_CXSIZEFRAME); + by = GetSystemMetrics(SM_CYSIZEFRAME); + } else { + ret = 1; + bx = GetSystemMetrics(SM_CXFIXEDFRAME); + by = GetSystemMetrics(SM_CYFIXEDFRAME); + } + bt = GetSystemMetrics(SM_CYCAPTION); + } + //The coordinates of the whole window, including non-client area + xoff = bx; + yoff = by + bt; + dx = 2*bx; + dy = 2*by + bt; + X = w->x()-xoff; + Y = w->y()-yoff; + W = w->w()+dx; + H = w->h()+dy; + } + + //Proceed to positioning the window fully inside the screen, if possible + //Make border's lower right corner visible + int scr_x, scr_y, scr_w, scr_h; + Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h, X, Y); + if (scr_x+scr_w < X+W) X = scr_x+scr_w - W; + if (scr_y+scr_h < Y+H) Y = scr_y+scr_h - H; + //Make border's upper left corner visible + if (Xw()) X = scr_x+scr_w - w->w() - dx; + if (scr_y+scr_h < Y+dy+ w->h()) Y = scr_y+scr_h - w->h() - dy; + //Make client area's upper left corner visible + if (X+xoff < scr_x) X = scr_x-xoff; + if (Y+yoff < scr_y) Y = scr_y-yoff; + //Return the client area's top left corner in (X,Y) + X+=xoff; + Y+=yoff; + + return ret; +} + +//////////////////////////////////////////////////////////////// + +void Fl_Window::resize(int X,int Y,int W,int H) { + UINT flags = SWP_NOSENDCHANGING | SWP_NOZORDER + | SWP_NOACTIVATE | SWP_NOOWNERZORDER; + int is_a_resize = (W != w() || H != h()); + int resize_from_program = (this != resize_bug_fix); + if (!resize_from_program) resize_bug_fix = 0; + if (X != x() || Y != y()) { + set_flag(FL_FORCE_POSITION); + } else { + if (!is_a_resize) return; + flags |= SWP_NOMOVE; + } + if (is_a_resize) { + Fl_Group::resize(X,Y,W,H); + if (visible_r()) { + redraw(); + // only wait for exposure if this window has a size - a window + // with no width or height will never get an exposure event + if (i && W>0 && H>0) + i->wait_for_expose = 1; + } + } else { + x(X); y(Y); + flags |= SWP_NOSIZE; + } + if (!border()) flags |= SWP_NOACTIVATE; + if (resize_from_program && shown()) { + if (!resizable()) size_range(w(),h(),w(),h()); + int dummy_x, dummy_y, bt, bx, by; + //Ignore window managing when resizing, so that windows (and more + //specifically menus) can be moved offscreen. + if (Fl_X::fake_X_wm(this, dummy_x, dummy_y, bt, bx, by)) { + X -= bx; + Y -= by+bt; + W += 2*bx; + H += 2*by+bt; + } + // avoid zero size windows. A zero sized window on Win32 + // will cause continouly new redraw events. + if (W<=0) W = 1; + if (H<=0) H = 1; + SetWindowPos(i->xid, 0, X, Y, W, H, flags); + } +} + +//////////////////////////////////////////////////////////////// + +/* + * This silly little class remembers the name of all window classes + * we register to avoid double registration. It has the added bonus + * of freeing everything on application colse as well. + */ +class NameList { +public: + NameList() { name = (char**)malloc(sizeof(char**)); NName = 1; nName = 0; } + ~NameList() { + int i; + for (i=0; iparent() && !Fl_X::i(w->window())) { + w->set_visible(); + return 0L; + } + + static NameList class_name_list; + static const char *first_class_name = 0L; + const char *class_name = w->xclass(); + if (!class_name) class_name = first_class_name; // reuse first class name used + if (!class_name) class_name = "FLTK"; // default to create a "FLTK" WNDCLASS + if (!first_class_name) { + first_class_name = class_name; + } + + if (!class_name_list.has_name(class_name)) { + WNDCLASSEX wc; + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof(WNDCLASSEX); + // Documentation states a device context consumes about 800 bytes + // of memory... so who cares? If 800 bytes per window is what it + // takes to speed things up, I'm game. + //wc.style = CS_HREDRAW | CS_VREDRAW | CS_CLASSDC | CS_DBLCLKS; + wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC | CS_DBLCLKS; + wc.lpfnWndProc = (WNDPROC)WndProc; + wc.hInstance = fl_display; + if (!w->icon()) + w->icon((void *)LoadIcon(NULL, IDI_APPLICATION)); + wc.hIcon = wc.hIconSm = (HICON)w->icon(); + wc.hCursor = fl_default_cursor = LoadCursor(NULL, IDC_ARROW); + //uchar r,g,b; Fl::get_color(FL_GRAY,r,g,b); + //wc.hbrBackground = (HBRUSH)CreateSolidBrush(RGB(r,g,b)); + wc.lpszClassName = class_name; + RegisterClassEx(&wc); + class_name_list.add_name(class_name); + } + + const char* message_name = "FLTK::ThreadWakeup"; + if (!fl_wake_msg) fl_wake_msg = RegisterWindowMessage(message_name); + + HWND parent; + DWORD style = WS_CLIPCHILDREN | WS_CLIPSIBLINGS; + DWORD styleEx = WS_EX_LEFT; + + int xp = w->x(); + int yp = w->y(); + int wp = w->w(); + int hp = w->h(); + + int showit = 1; + + if (w->parent()) { + style |= WS_CHILD; + styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; + parent = fl_xid(w->window()); + } else { + if (!w->size_range_set) { + if (w->resizable()) { + Fl_Widget *o = w->resizable(); + int minw = o->w(); if (minw > 100) minw = 100; + int minh = o->h(); if (minh > 100) minh = 100; + w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0); + } else { + w->size_range(w->w(), w->h(), w->w(), w->h()); + } + } + styleEx |= WS_EX_WINDOWEDGE | WS_EX_CONTROLPARENT; + int xwm = xp , ywm = yp , bt, bx, by; + switch (fake_X_wm(w, xwm, ywm, bt, bx, by)) { + // No border (used for menus) + case 0: style |= WS_POPUP; + styleEx |= WS_EX_TOOLWINDOW; + break; + + // Thin border and title bar + case 1: style |= WS_DLGFRAME | WS_CAPTION; break; + + // Thick, resizable border and title bar, with maximize button + case 2: style |= WS_THICKFRAME | WS_MAXIMIZEBOX | WS_CAPTION ; break; + } + if (by+bt) { + if (!w->modal()) style |= WS_SYSMENU | WS_MINIMIZEBOX; + wp += 2*bx; + hp += 2*by+bt; + } + if (!(w->flags() & Fl_Window::FL_FORCE_POSITION)) { + xp = yp = CW_USEDEFAULT; + } else { + if (!Fl::grab()) { + xp = xwm; yp = ywm; + w->x(xp);w->y(yp); + } + xp -= bx; + yp -= by+bt; + } + + parent = 0; + if (w->non_modal() && Fl_X::first && !fl_disable_transient_for) { + // find some other window to be "transient for": + Fl_Window* w = Fl_X::first->w; + while (w->parent()) w = w->window(); + parent = fl_xid(w); + if (!w->visible()) showit = 0; + } else if (Fl::grab()) parent = fl_xid(Fl::grab()); + } + + Fl_X* x = new Fl_X; + x->other_xid = 0; + x->setwindow(w); + x->region = 0; + x->private_dc = 0; + x->cursor = fl_default_cursor; + x->xid = CreateWindowEx( + styleEx, + class_name, w->label(), style, + xp, yp, wp, hp, + parent, + NULL, // menu + fl_display, + NULL // creation parameters + ); + x->next = Fl_X::first; + Fl_X::first = x; + + x->wait_for_expose = 1; + if (fl_show_iconic) {showit = 0; fl_show_iconic = 0;} + if (showit) { + w->set_visible(); + int old_event = Fl::e_number; + w->handle(Fl::e_number = FL_SHOW); // get child windows to appear + Fl::e_number = old_event; + w->redraw(); // force draw to happen + } + // If we've captured the mouse, we dont want to activate any + // other windows from the code, or we loose the capture. + ShowWindow(x->xid, !showit ? SW_SHOWMINNOACTIVE : + (Fl::grab() || (style & WS_POPUP)) ? SW_SHOWNOACTIVATE : SW_SHOWNORMAL); + + // Drag-n-drop requires GCC 3.x or a non-GNU compiler... +#if !defined(__GNUC__) || __GNUC__ >= 3 + // Register all windows for potential drag'n'drop operations + static char oleInitialized = 0; + if (!oleInitialized) { OleInitialize(0L); oleInitialized=1; } + + RegisterDragDrop(x->xid, flIDropTarget); +#endif // !__GNUC__ || __GNUC__ >= 3 + + if (w->modal()) {Fl::modal_ = w; fl_fix_focus();} + return x; +} + + + + +///////////////////////////////////////////////////////////////////////////// +/// Win32 timers +/// + + +static LRESULT CALLBACK s_TimerProc(HWND hwnd, UINT msg, + WPARAM wParam, LPARAM lParam) +{ + switch (msg) { + case WM_TIMER: + { + unsigned int id = wParam - 1; + if (id < (unsigned int)win32_timer_used && win32_timers[id].handle) { + Fl_Timeout_Handler cb = win32_timers[id].callback; + void* data = win32_timers[id].data; + delete_timer(win32_timers[id]); + if (cb) { + (*cb)(data); + } + } + } + return 0; + + default: + break; + } + + return DefWindowProc(hwnd, msg, wParam, lParam); +} + +void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void* data) +{ + repeat_timeout(time, cb, data); +} + +void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void* data) +{ + int timer_id = -1; + for (int i = 0; i < win32_timer_used; ++i) { + if ( !win32_timers[i].handle ) { + timer_id = i; + break; + } + } + if (timer_id == -1) { + if (win32_timer_used == win32_timer_alloc) { + realloc_timers(); + } + timer_id = win32_timer_used++; + } + unsigned int elapsed = (unsigned int)(time * 1000); + + if ( !s_TimerWnd ) { + const char* timer_class = "FLTimer"; + WNDCLASSEX wc; + memset(&wc, 0, sizeof(wc)); + wc.cbSize = sizeof (wc); + wc.style = CS_CLASSDC; + wc.lpfnWndProc = (WNDPROC)s_TimerProc; + wc.hInstance = fl_display; + wc.lpszClassName = timer_class; + /*ATOM atom =*/ RegisterClassEx(&wc); + // create a zero size window to handle timer events + s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW, + timer_class, "", + WS_POPUP, + 0, 0, 0, 0, + NULL, NULL, fl_display, NULL); + // just in case this OS won't let us create a 0x0 size window: + if (!s_TimerWnd) + s_TimerWnd = CreateWindowEx(WS_EX_LEFT | WS_EX_TOOLWINDOW, + timer_class, "", + WS_POPUP, + 0, 0, 1, 1, + NULL, NULL, fl_display, NULL); + ShowWindow(s_TimerWnd, SW_SHOWNOACTIVATE); + } + + win32_timers[timer_id].callback = cb; + win32_timers[timer_id].data = data; + + win32_timers[timer_id].handle = + SetTimer(s_TimerWnd, timer_id + 1, elapsed, NULL); +} + +int Fl::has_timeout(Fl_Timeout_Handler cb, void* data) +{ + for (int i = 0; i < win32_timer_used; ++i) { + Win32Timer& t = win32_timers[i]; + if (t.handle && t.callback == cb && t.data == data) { + return 1; + } + } + return 0; +} + +void Fl::remove_timeout(Fl_Timeout_Handler cb, void* data) +{ + int i; + for (i = 0; i < win32_timer_used; ++i) { + Win32Timer& t = win32_timers[i]; + if (t.handle && t.callback == cb && + (t.data == data || data == NULL)) { + delete_timer(t); + } + } +} + +/// END TIMERS +///////////////////////////////////////////////////////////////////////////// + + + +//////////////////////////////////////////////////////////////// + +HINSTANCE fl_display = GetModuleHandle(NULL); + +void Fl_Window::size_range_() { + size_range_set = 1; +} + +void Fl_X::set_minmax(LPMINMAXINFO minmax) +{ + int td, wd, hd, dummy_x, dummy_y; + + fake_X_wm(w, dummy_x, dummy_y, td, wd, hd); + wd *= 2; + hd *= 2; + hd += td; + + minmax->ptMinTrackSize.x = w->minw + wd; + minmax->ptMinTrackSize.y = w->minh + hd; + if (w->maxw) { + minmax->ptMaxTrackSize.x = w->maxw + wd; + minmax->ptMaxSize.x = w->maxw + wd; + } + if (w->maxh) { + minmax->ptMaxTrackSize.y = w->maxh + hd; + minmax->ptMaxSize.y = w->maxh + hd; + } +} + +//////////////////////////////////////////////////////////////// + +#include // need so FL_EXPORT fl_filename_name works + +// returns pointer to the filename, or null if name ends with '/' +const char *fl_filename_name(const char *name) { + const char *p,*q; + if (!name) return (0); + q = name; + if (q[0] && q[1]==':') q += 2; // skip leading drive letter + for (p = q; *p; p++) if (*p == '/' || *p == '\\') q = p+1; + return q; +} + +void Fl_Window::label(const char *name,const char *iname) { + Fl_Widget::label(name); + iconlabel_ = iname; + if (shown() && !parent()) { + if (!name) name = ""; + SetWindowText(i->xid, name); + // if (!iname) iname = fl_filename_name(name); + // should do something with iname here... + } +} + +//////////////////////////////////////////////////////////////// +// Implement the virtual functions for the base Fl_Window class: + +// If the box is a filled rectangle, we can make the redisplay *look* +// faster by using X's background pixel erasing. We can make it +// actually *be* faster by drawing the frame only, this is done by +// setting fl_boxcheat, which is seen by code in fl_drawbox.cxx: +// For WIN32 it looks like all windows share a background color, so +// I use FL_GRAY for this and only do this cheat for windows that are +// that color. +// Actually it is totally disabled. +// Fl_Widget *fl_boxcheat; +//static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);} + +void Fl_Window::show() { + image(Fl::scheme_bg_); + if (Fl::scheme_bg_) { + labeltype(FL_NORMAL_LABEL); + align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP); + } else { + labeltype(FL_NO_LABEL); + } + Fl_Tooltip::exit(this); + if (!shown()) { + // if (can_boxcheat(box())) fl_background_pixel = fl_xpixel(color()); + Fl_X::make(this); + } else { + // Once again, we would lose the capture if we activated the window. + if (IsIconic(i->xid)) OpenIcon(i->xid); + if (!fl_capture) BringWindowToTop(i->xid); + //ShowWindow(i->xid,fl_capture?SW_SHOWNOACTIVATE:SW_RESTORE); + } +} + +Fl_Window *Fl_Window::current_; +// the current context +HDC fl_gc = 0; +// the current window handle, initially set to -1 so we can correctly +// allocate fl_GetDC(0) +HWND fl_window = NULL; + +// Here we ensure only one GetDC is ever in place. +HDC fl_GetDC(HWND w) { + if (fl_gc) { + if (w == fl_window && fl_window != NULL) return fl_gc; + if (fl_window) fl_release_dc(fl_window, fl_gc); // ReleaseDC + } + fl_gc = GetDC(w); + fl_save_dc(w, fl_gc); + fl_window = w; + // calling GetDC seems to always reset these: (?) + SetTextAlign(fl_gc, TA_BASELINE|TA_LEFT); + SetBkMode(fl_gc, TRANSPARENT); + return fl_gc; +} + +// make X drawing go into this window (called by subclass flush() impl.) +void Fl_Window::make_current() { + fl_GetDC(fl_xid(this)); + +#if USE_COLORMAP + // Windows maintains a hardware and software color palette; the + // SelectPalette() call updates the current soft->hard mapping + // for all drawing calls, so we must select it here before any + // code does any drawing... + + fl_select_palette(); +#endif // USE_COLORMAP + + current_ = this; + fl_clip_region(0); +} + +/* Make sure that all allocated fonts are released. This works only if + Fl::run() is allowed to exit by closing all windows. Calling 'exit(int)' + will not automatically free any fonts. */ +void fl_free_fonts(void) +{ +// remove the Fl_FontSize chains + int i; + Fl_Fontdesc * s; + Fl_FontSize * f; + Fl_FontSize * ff; + for (i=0; ifirst; f; f=ff) { + ff = f->next; + delete f; + s->first = ff; + } + } +} + + +/////////////////////////////////////////////////////////////////////// +// +// The following routines help fix a problem with the leaking of Windows +// Device Context (DC) objects. The 'proper' protocol is for a program to +// acquire a DC, save its state, do the modifications needed for drawing, +// perform the drawing, restore the initial state, and release the DC. In +// FLTK, the save and restore steps have previously been omitted and DCs are +// not properly released, leading to a great number of DC leaks. As some +// Windows "OSs" will hang when any process exceeds roughly 10,000 GDI objects, +// it is important to control GDI leaks, which are much more important than memory +// leaks. The following struct, global variable, and routines help implement +// the above protocol for those cases where the GetDC and RestoreDC are not in +// the same routine. For each GetDC, fl_save_dc is used to create an entry in +// a linked list that saves the window handle, the DC handle, and the initial +// state. When the DC is to be released, 'fl_release_dc' is called. It restores +// the initial state and releases the DC. When the program exits, 'fl_cleanup_dc_list' +// frees any remaining nodes in the list. + +struct Win_DC_List { // linked list + HWND window; // window handle + HDC dc; // device context handle + int saved_dc; // initial state of DC + Win_DC_List * next; // pointer to next item +}; + +static Win_DC_List * win_DC_list = 0; + +void fl_save_dc( HWND w, HDC dc) { + Win_DC_List * t; + t = new Win_DC_List; + t->window = w; + t->dc = dc; + t->saved_dc = SaveDC(dc); + if (win_DC_list) + t->next = win_DC_list; + else + t->next = NULL; + win_DC_list = t; +} + +void fl_release_dc(HWND w, HDC dc) { + Win_DC_List * t= win_DC_list; + Win_DC_List * prev = 0; + if (!t) + return; + do { + if (t->dc == dc) { + RestoreDC(dc, t->saved_dc); + ReleaseDC(w, dc); + if (!prev) { + win_DC_list = t->next; // delete first item + } else { + prev->next = t->next; // one in the middle + } + delete (t); + return; + } + prev = t; + t = t->next; + } while (t); +} + +void fl_cleanup_dc_list(void) { // clean up the list + Win_DC_List * t = win_DC_list; + if (!t)return; + do { + RestoreDC(t->dc, t->saved_dc); + ReleaseDC(t->window, t->dc); + win_DC_list = t->next; + delete (t); + t = win_DC_list; + } while(t); +} + + +// +// End of "$Id: Fl_win32.cxx 6553 2008-12-07 11:05:41Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Fl_x.cxx b/third_party/windows/fltk-1.1.10/src/Fl_x.cxx new file mode 100644 index 0000000..b83ace6 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Fl_x.cxx @@ -0,0 +1,1413 @@ +// +// "$Id: Fl_x.cxx 5914 2007-06-18 13:08:57Z matt $" +// +// X specific code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2007 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#ifdef WIN32 +//# include "Fl_win32.cxx" +#elif defined(__APPLE__) +//# include "Fl_mac.cxx" +#else + +# define CONSOLIDATE_MOTION 1 +/**** Define this if your keyboard lacks a backspace key... ****/ +/* #define BACKSPACE_HACK 1 */ + +# include +# include +# include +# include +# include +# include +# include "flstring.h" +# include +# include + +//////////////////////////////////////////////////////////////// +// interface to poll/select call: + +# if USE_POLL + +# include +static pollfd *pollfds = 0; + +# else +# if HAVE_SYS_SELECT_H +# include +# endif /* HAVE_SYS_SELECT_H */ + +// The following #define is only needed for HP-UX 9.x and earlier: +//#define select(a,b,c,d,e) select((a),(int *)(b),(int *)(c),(int *)(d),(e)) + +static fd_set fdsets[3]; +static int maxfd; +# define POLLIN 1 +# define POLLOUT 4 +# define POLLERR 8 + +# endif /* USE_POLL */ + +static int nfds = 0; +static int fd_array_size = 0; +struct FD { +# if !USE_POLL + int fd; + short events; +# endif + void (*cb)(int, void*); + void* arg; +}; + +static FD *fd = 0; + +void Fl::add_fd(int n, int events, void (*cb)(int, void*), void *v) { + remove_fd(n,events); + int i = nfds++; + if (i >= fd_array_size) { + FD *temp; + fd_array_size = 2*fd_array_size+1; + + if (!fd) temp = (FD*)malloc(fd_array_size*sizeof(FD)); + else temp = (FD*)realloc(fd, fd_array_size*sizeof(FD)); + + if (!temp) return; + fd = temp; + +# if USE_POLL + pollfd *tpoll; + + if (!pollfds) tpoll = (pollfd*)malloc(fd_array_size*sizeof(pollfd)); + else tpoll = (pollfd*)realloc(pollfds, fd_array_size*sizeof(pollfd)); + + if (!tpoll) return; + pollfds = tpoll; +# endif + } + fd[i].cb = cb; + fd[i].arg = v; +# if USE_POLL + pollfds[i].fd = n; + pollfds[i].events = events; +# else + fd[i].fd = n; + fd[i].events = events; + if (events & POLLIN) FD_SET(n, &fdsets[0]); + if (events & POLLOUT) FD_SET(n, &fdsets[1]); + if (events & POLLERR) FD_SET(n, &fdsets[2]); + if (n > maxfd) maxfd = n; +# endif +} + +void Fl::add_fd(int n, void (*cb)(int, void*), void* v) { + Fl::add_fd(n, POLLIN, cb, v); +} + +void Fl::remove_fd(int n, int events) { + int i,j; + maxfd = -1; // recalculate maxfd on the fly + for (i=j=0; i maxfd) maxfd = fd[i].fd; + // move it down in the array if necessary: + if (j0 if any callbacks were done. +int fl_wait(double time_to_wait) { + + // OpenGL and other broken libraries call XEventsQueued + // unnecessarily and thus cause the file descriptor to not be ready, + // so we must check for already-read events: + if (fl_display && XQLength(fl_display)) {do_queued_events(); return 1;} + +# if !USE_POLL + fd_set fdt[3]; + fdt[0] = fdsets[0]; + fdt[1] = fdsets[1]; + fdt[2] = fdsets[2]; +# endif + int n; + + fl_unlock_function(); + + if (time_to_wait < 2147483.648) { +# if USE_POLL + n = ::poll(pollfds, nfds, int(time_to_wait*1000 + .5)); +# else + timeval t; + t.tv_sec = int(time_to_wait); + t.tv_usec = int(1000000 * (time_to_wait-t.tv_sec)); + n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t); +# endif + } else { +# if USE_POLL + n = ::poll(pollfds, nfds, -1); +# else + n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],0); +# endif + } + + fl_lock_function(); + + if (n > 0) { + for (int i=0; irequest_code); + XGetErrorDatabaseText(d,"",buf1,buf1,buf2,128); + XGetErrorText(d, e->error_code, buf1, 128); + Fl::warning("%s: %s 0x%lx", buf2, buf1, e->resourceid); + return 0; + } +} + +void fl_open_display() { + if (fl_display) return; + + XSetIOErrorHandler(io_error_handler); + XSetErrorHandler(xerror_handler); + + Display *d = XOpenDisplay(0); + if (!d) Fl::fatal("Can't open display: %s",XDisplayName(0)); + + fl_open_display(d); +} + +void fl_open_display(Display* d) { + fl_display = d; + + WM_DELETE_WINDOW = XInternAtom(d, "WM_DELETE_WINDOW", 0); + WM_PROTOCOLS = XInternAtom(d, "WM_PROTOCOLS", 0); + fl_MOTIF_WM_HINTS = XInternAtom(d, "_MOTIF_WM_HINTS", 0); + TARGETS = XInternAtom(d, "TARGETS", 0); + CLIPBOARD = XInternAtom(d, "CLIPBOARD", 0); + fl_XdndAware = XInternAtom(d, "XdndAware", 0); + fl_XdndSelection = XInternAtom(d, "XdndSelection", 0); + fl_XdndEnter = XInternAtom(d, "XdndEnter", 0); + fl_XdndTypeList = XInternAtom(d, "XdndTypeList", 0); + fl_XdndPosition = XInternAtom(d, "XdndPosition", 0); + fl_XdndLeave = XInternAtom(d, "XdndLeave", 0); + fl_XdndDrop = XInternAtom(d, "XdndDrop", 0); + fl_XdndStatus = XInternAtom(d, "XdndStatus", 0); + fl_XdndActionCopy = XInternAtom(d, "XdndActionCopy", 0); + fl_XdndFinished = XInternAtom(d, "XdndFinished", 0); + //fl_XdndProxy = XInternAtom(d, "XdndProxy", 0); + fl_XdndEnter = XInternAtom(d, "XdndEnter", 0); + fl_XdndURIList = XInternAtom(d, "text/uri-list", 0); + + Fl::add_fd(ConnectionNumber(d), POLLIN, fd_callback); + + fl_screen = DefaultScreen(d); + + fl_message_window = + XCreateSimpleWindow(d, RootWindow(d,fl_screen), 0,0,1,1,0, 0, 0); + +// construct an XVisualInfo that matches the default Visual: + XVisualInfo templt; int num; + templt.visualid = XVisualIDFromVisual(DefaultVisual(d, fl_screen)); + fl_visual = XGetVisualInfo(d, VisualIDMask, &templt, &num); + fl_colormap = DefaultColormap(d, fl_screen); + +#if !USE_COLORMAP + Fl::visual(FL_RGB); +#endif +} + +void fl_close_display() { + Fl::remove_fd(ConnectionNumber(fl_display)); + XCloseDisplay(fl_display); +} + +static int fl_workarea_xywh[4] = { -1, -1, -1, -1 }; + +static void fl_init_workarea() { + fl_open_display(); + + Atom _NET_WORKAREA = XInternAtom(fl_display, "_NET_WORKAREA", 0); + Atom actual; + unsigned long count, remaining; + int format; + unsigned *xywh; + + if (XGetWindowProperty(fl_display, RootWindow(fl_display, fl_screen), + _NET_WORKAREA, 0, 4 * sizeof(unsigned), False, + XA_CARDINAL, &actual, &format, &count, &remaining, + (unsigned char **)&xywh) || !xywh || !xywh[2] || + !xywh[3]) + { + fl_workarea_xywh[0] = 0; + fl_workarea_xywh[1] = 0; + fl_workarea_xywh[2] = DisplayWidth(fl_display, fl_screen); + fl_workarea_xywh[3] = DisplayHeight(fl_display, fl_screen); + } + else + { + fl_workarea_xywh[0] = (int)xywh[0]; + fl_workarea_xywh[1] = (int)xywh[1]; + fl_workarea_xywh[2] = (int)xywh[2]; + fl_workarea_xywh[3] = (int)xywh[3]; + XFree(xywh); + } +} + +int Fl::x() { + if (fl_workarea_xywh[0] < 0) fl_init_workarea(); + return fl_workarea_xywh[0]; +} + +int Fl::y() { + if (fl_workarea_xywh[0] < 0) fl_init_workarea(); + return fl_workarea_xywh[1]; +} + +int Fl::w() { + if (fl_workarea_xywh[0] < 0) fl_init_workarea(); + return fl_workarea_xywh[2]; +} + +int Fl::h() { + if (fl_workarea_xywh[0] < 0) fl_init_workarea(); + return fl_workarea_xywh[3]; +} + +void Fl::get_mouse(int &xx, int &yy) { + fl_open_display(); + Window root = RootWindow(fl_display, fl_screen); + Window c; int mx,my,cx,cy; unsigned int mask; + XQueryPointer(fl_display,root,&root,&c,&mx,&my,&cx,&cy,&mask); + xx = mx; + yy = my; +} + +//////////////////////////////////////////////////////////////// +// Code used for paste and DnD into the program: + +Fl_Widget *fl_selection_requestor; +char *fl_selection_buffer[2]; +int fl_selection_length[2]; +int fl_selection_buffer_length[2]; +char fl_i_own_selection[2]; + +// Call this when a "paste" operation happens: +void Fl::paste(Fl_Widget &receiver, int clipboard) { + if (fl_i_own_selection[clipboard]) { + // We already have it, do it quickly without window server. + // Notice that the text is clobbered if set_selection is + // called in response to FL_PASTE! + Fl::e_text = fl_selection_buffer[clipboard]; + Fl::e_length = fl_selection_length[clipboard]; + if (!Fl::e_text) Fl::e_text = (char *)""; + receiver.handle(FL_PASTE); + return; + } + // otherwise get the window server to return it: + fl_selection_requestor = &receiver; + Atom property = clipboard ? CLIPBOARD : XA_PRIMARY; + XConvertSelection(fl_display, property, XA_STRING, property, + fl_xid(Fl::first_window()), fl_event_time); +} + +Window fl_dnd_source_window; +Atom *fl_dnd_source_types; // null-terminated list of data types being supplied +Atom fl_dnd_type; +Atom fl_dnd_source_action; +Atom fl_dnd_action; + +void fl_sendClientMessage(Window window, Atom message, + unsigned long d0, + unsigned long d1=0, + unsigned long d2=0, + unsigned long d3=0, + unsigned long d4=0) +{ + XEvent e; + e.xany.type = ClientMessage; + e.xany.window = window; + e.xclient.message_type = message; + e.xclient.format = 32; + e.xclient.data.l[0] = (long)d0; + e.xclient.data.l[1] = (long)d1; + e.xclient.data.l[2] = (long)d2; + e.xclient.data.l[3] = (long)d3; + e.xclient.data.l[4] = (long)d4; + XSendEvent(fl_display, window, 0, 0, &e); +} + +//////////////////////////////////////////////////////////////// +// Code for copying to clipboard and DnD out of the program: + +void Fl::copy(const char *stuff, int len, int clipboard) { + if (!stuff || len<0) return; + if (len+1 > fl_selection_buffer_length[clipboard]) { + delete[] fl_selection_buffer[clipboard]; + fl_selection_buffer[clipboard] = new char[len+100]; + fl_selection_buffer_length[clipboard] = len+100; + } + memcpy(fl_selection_buffer[clipboard], stuff, len); + fl_selection_buffer[clipboard][len] = 0; // needed for direct paste + fl_selection_length[clipboard] = len; + fl_i_own_selection[clipboard] = 1; + Atom property = clipboard ? CLIPBOARD : XA_PRIMARY; + XSetSelectionOwner(fl_display, property, fl_message_window, fl_event_time); +} + +//////////////////////////////////////////////////////////////// + +const XEvent* fl_xevent; // the current x event +ulong fl_event_time; // the last timestamp from an x event + +char fl_key_vector[32]; // used by Fl::get_key() + +// Record event mouse position and state from an XEvent: + +static int px, py; +static ulong ptime; + +static void set_event_xy() { +# if CONSOLIDATE_MOTION + send_motion = 0; +# endif + Fl::e_x_root = fl_xevent->xbutton.x_root; + Fl::e_x = fl_xevent->xbutton.x; + Fl::e_y_root = fl_xevent->xbutton.y_root; + Fl::e_y = fl_xevent->xbutton.y; + Fl::e_state = fl_xevent->xbutton.state << 16; + fl_event_time = fl_xevent->xbutton.time; +# ifdef __sgi + // get the meta key off PC keyboards: + if (fl_key_vector[18]&0x18) Fl::e_state |= FL_META; +# endif + // turn off is_click if enough time or mouse movement has passed: + if (abs(Fl::e_x_root-px)+abs(Fl::e_y_root-py) > 3 || + fl_event_time >= ptime+1000) + Fl::e_is_click = 0; +} + +// if this is same event as last && is_click, increment click count: +static inline void checkdouble() { + if (Fl::e_is_click == Fl::e_keysym) + Fl::e_clicks++; + else { + Fl::e_clicks = 0; + Fl::e_is_click = Fl::e_keysym; + } + px = Fl::e_x_root; + py = Fl::e_y_root; + ptime = fl_event_time; +} + +static Fl_Window* resize_bug_fix; + +extern "C" { + static Bool fake_keyup_test(Display*, XEvent* event, char* previous) { + return + event->type == KeyPress && + event->xkey.keycode == ((XKeyEvent*)previous)->keycode && + event->xkey.time == ((XKeyEvent*)previous)->time; + } +} + +//////////////////////////////////////////////////////////////// + +static char unknown[] = ""; +const int unknown_len = 10; + +int fl_handle(const XEvent& thisevent) +{ + XEvent xevent = thisevent; + fl_xevent = &thisevent; + Window xid = xevent.xany.window; + + switch (xevent.type) { + + case KeymapNotify: + memcpy(fl_key_vector, xevent.xkeymap.key_vector, 32); + return 0; + + case MappingNotify: + XRefreshKeyboardMapping((XMappingEvent*)&xevent.xmapping); + return 0; + + case SelectionNotify: { + if (!fl_selection_requestor) return 0; + static unsigned char* buffer; + if (buffer) {XFree(buffer); buffer = 0;} + long bytesread = 0; + if (fl_xevent->xselection.property) for (;;) { + // The Xdnd code pastes 64K chunks together, possibly to avoid + // bugs in X servers, or maybe to avoid an extra round-trip to + // get the property length. I copy this here: + Atom actual; int format; unsigned long count, remaining; + unsigned char* portion; + if (XGetWindowProperty(fl_display, + fl_xevent->xselection.requestor, + fl_xevent->xselection.property, + bytesread/4, 65536, 1, 0, + &actual, &format, &count, &remaining, + &portion)) break; // quit on error + if (bytesread) { // append to the accumulated buffer + buffer = (unsigned char*)realloc(buffer, bytesread+count*format/8+remaining); + memcpy(buffer+bytesread, portion, count*format/8); + XFree(portion); + } else { // Use the first section without moving the memory: + buffer = portion; + } + bytesread += count*format/8; + if (!remaining) break; + } + Fl::e_text = buffer ? (char*)buffer : (char *)""; + Fl::e_length = bytesread; + int old_event = Fl::e_number; + fl_selection_requestor->handle(Fl::e_number = FL_PASTE); + Fl::e_number = old_event; + // Detect if this paste is due to Xdnd by the property name (I use + // XA_SECONDARY for that) and send an XdndFinished message. It is not + // clear if this has to be delayed until now or if it can be done + // immediatly after calling XConvertSelection. + if (fl_xevent->xselection.property == XA_SECONDARY && + fl_dnd_source_window) { + fl_sendClientMessage(fl_dnd_source_window, fl_XdndFinished, + fl_xevent->xselection.requestor); + fl_dnd_source_window = 0; // don't send a second time + } + return 1;} + + case SelectionClear: { + int clipboard = fl_xevent->xselectionclear.selection == CLIPBOARD; + fl_i_own_selection[clipboard] = 0; + return 1;} + + case SelectionRequest: { + XSelectionEvent e; + e.type = SelectionNotify; + e.requestor = fl_xevent->xselectionrequest.requestor; + e.selection = fl_xevent->xselectionrequest.selection; + int clipboard = e.selection == CLIPBOARD; + e.target = fl_xevent->xselectionrequest.target; + e.time = fl_xevent->xselectionrequest.time; + e.property = fl_xevent->xselectionrequest.property; + if (e.target == TARGETS) { + Atom a = XA_STRING; + XChangeProperty(fl_display, e.requestor, e.property, + XA_ATOM, sizeof(Atom)*8, 0, (unsigned char*)&a, 1); + } else if (/*e.target == XA_STRING &&*/ fl_selection_length[clipboard]) { + XChangeProperty(fl_display, e.requestor, e.property, + e.target, 8, 0, + (unsigned char *)fl_selection_buffer[clipboard], + fl_selection_length[clipboard]); + } else { +// char* x = XGetAtomName(fl_display,e.target); +// fprintf(stderr,"selection request of %s\n",x); +// XFree(x); + e.property = 0; + } + XSendEvent(fl_display, e.requestor, 0, 0, (XEvent *)&e);} + return 1; + + // events where interesting window id is in a different place: + case CirculateNotify: + case CirculateRequest: + case ConfigureNotify: + case ConfigureRequest: + case CreateNotify: + case DestroyNotify: + case GravityNotify: + case MapNotify: + case MapRequest: + case ReparentNotify: + case UnmapNotify: + xid = xevent.xmaprequest.window; + break; + } + + int event = 0; + Fl_Window* window = fl_find(xid); + + if (window) switch (xevent.type) { + + case ClientMessage: { + Atom message = fl_xevent->xclient.message_type; + const long* data = fl_xevent->xclient.data.l; + if ((Atom)(data[0]) == WM_DELETE_WINDOW) { + event = FL_CLOSE; + } else if (message == fl_XdndEnter) { + fl_xmousewin = window; + in_a_window = true; + fl_dnd_source_window = data[0]; + // version number is data[1]>>24 +// printf("XdndEnter, version %ld\n", data[1] >> 24); + if (data[1]&1) { + // get list of data types: + Atom actual; int format; unsigned long count, remaining; + unsigned char *buffer = 0; + XGetWindowProperty(fl_display, fl_dnd_source_window, fl_XdndTypeList, + 0, 0x8000000L, False, XA_ATOM, &actual, &format, + &count, &remaining, &buffer); + if (actual != XA_ATOM || format != 32 || count<4 || !buffer) + goto FAILED; + delete [] fl_dnd_source_types; + fl_dnd_source_types = new Atom[count+1]; + for (unsigned i = 0; i < count; i++) + fl_dnd_source_types[i] = ((Atom*)buffer)[i]; + fl_dnd_source_types[count] = 0; + } else { + FAILED: + // less than four data types, or if the above messes up: + if (!fl_dnd_source_types) fl_dnd_source_types = new Atom[4]; + fl_dnd_source_types[0] = data[2]; + fl_dnd_source_types[1] = data[3]; + fl_dnd_source_types[2] = data[4]; + fl_dnd_source_types[3] = 0; + } + + // Loop through the source types and pick the first text type... + int i; + + for (i = 0; fl_dnd_source_types[i]; i ++) + { +// printf("fl_dnd_source_types[%d] = %ld (%s)\n", i, +// fl_dnd_source_types[i], +// XGetAtomName(fl_display, fl_dnd_source_types[i])); + + if (!strncmp(XGetAtomName(fl_display, fl_dnd_source_types[i]), + "text/", 5)) + break; + } + + if (fl_dnd_source_types[i]) + fl_dnd_type = fl_dnd_source_types[i]; + else + fl_dnd_type = fl_dnd_source_types[0]; + + event = FL_DND_ENTER; + Fl::e_text = unknown; + Fl::e_length = unknown_len; + break; + + } else if (message == fl_XdndPosition) { + fl_xmousewin = window; + in_a_window = true; + fl_dnd_source_window = data[0]; + Fl::e_x_root = data[2]>>16; + Fl::e_y_root = data[2]&0xFFFF; + if (window) { + Fl::e_x = Fl::e_x_root-window->x(); + Fl::e_y = Fl::e_y_root-window->y(); + } + fl_event_time = data[3]; + fl_dnd_source_action = data[4]; + fl_dnd_action = fl_XdndActionCopy; + Fl::e_text = unknown; + Fl::e_length = unknown_len; + int accept = Fl::handle(FL_DND_DRAG, window); + fl_sendClientMessage(data[0], fl_XdndStatus, + fl_xevent->xclient.window, + accept ? 1 : 0, + 0, // used for xy rectangle to not send position inside + 0, // used for width+height of rectangle + accept ? fl_dnd_action : None); + return 1; + + } else if (message == fl_XdndLeave) { + fl_dnd_source_window = 0; // don't send a finished message to it + event = FL_DND_LEAVE; + Fl::e_text = unknown; + Fl::e_length = unknown_len; + break; + + } else if (message == fl_XdndDrop) { + fl_xmousewin = window; + in_a_window = true; + fl_dnd_source_window = data[0]; + fl_event_time = data[2]; + Window to_window = fl_xevent->xclient.window; + Fl::e_text = unknown; + Fl::e_length = unknown_len; + if (Fl::handle(FL_DND_RELEASE, window)) { + fl_selection_requestor = Fl::belowmouse(); + XConvertSelection(fl_display, fl_XdndSelection, + fl_dnd_type, XA_SECONDARY, + to_window, fl_event_time); + } else { + // Send the finished message if I refuse the drop. + // It is not clear whether I can just send finished always, + // or if I have to wait for the SelectionNotify event as the + // code is currently doing. + fl_sendClientMessage(fl_dnd_source_window, fl_XdndFinished, to_window); + fl_dnd_source_window = 0; + } + return 1; + + } + break;} + + case UnmapNotify: + event = FL_HIDE; + break; + + case Expose: + Fl_X::i(window)->wait_for_expose = 0; +# if 0 + // try to keep windows on top even if WM_TRANSIENT_FOR does not work: + // opaque move/resize window managers do not like this, so I disabled it. + if (Fl::first_window()->non_modal() && window != Fl::first_window()) + Fl::first_window()->show(); +# endif + + case GraphicsExpose: + window->damage(FL_DAMAGE_EXPOSE, xevent.xexpose.x, xevent.xexpose.y, + xevent.xexpose.width, xevent.xexpose.height); + return 1; + + case FocusIn: + event = FL_FOCUS; + break; + + case FocusOut: + event = FL_UNFOCUS; + break; + + case KeyPress: + case KeyRelease: { + KEYPRESS: + int keycode = xevent.xkey.keycode; + fl_key_vector[keycode/8] |= (1 << (keycode%8)); + static char buffer[21]; + int len; + KeySym keysym; + if (xevent.type == KeyPress) { + event = FL_KEYDOWN; + //static XComposeStatus compose; + len = XLookupString((XKeyEvent*)&(xevent.xkey), + buffer, 20, &keysym, 0/*&compose*/); + if (keysym && keysym < 0x400) { // a character in latin-1,2,3,4 sets + // force it to type a character (not sure if this ever is needed): + if (!len) {buffer[0] = char(keysym); len = 1;} + // ignore all effects of shift on the keysyms, which makes it a lot + // easier to program shortcuts and is Windoze-compatable: + keysym = XKeycodeToKeysym(fl_display, keycode, 0); + } + // MRS: Can't use Fl::event_state(FL_CTRL) since the state is not + // set until set_event_xy() is called later... + if ((xevent.xkey.state & ControlMask) && keysym == '-') buffer[0] = 0x1f; // ^_ + buffer[len] = 0; + Fl::e_text = buffer; + Fl::e_length = len; + } else { + // Stupid X sends fake key-up events when a repeating key is held + // down, probably due to some back compatability problem. Fortunately + // we can detect this because the repeating KeyPress event is in + // the queue, get it and execute it instead: + XEvent temp; + if (XCheckIfEvent(fl_display,&temp,fake_keyup_test,(char*)(&xevent))){ + xevent = temp; + goto KEYPRESS; + } + event = FL_KEYUP; + fl_key_vector[keycode/8] &= ~(1 << (keycode%8)); + // keyup events just get the unshifted keysym: + keysym = XKeycodeToKeysym(fl_display, keycode, 0); + } +# ifdef __sgi + // You can plug a microsoft keyboard into an sgi but the extra shift + // keys are not translated. Make them translate like XFree86 does: + if (!keysym) switch(keycode) { + case 147: keysym = FL_Meta_L; break; + case 148: keysym = FL_Meta_R; break; + case 149: keysym = FL_Menu; break; + } +# endif +# if BACKSPACE_HACK + // Attempt to fix keyboards that send "delete" for the key in the + // upper-right corner of the main keyboard. But it appears that + // very few of these remain? + static int got_backspace; + if (!got_backspace) { + if (keysym == FL_Delete) keysym = FL_BackSpace; + else if (keysym == FL_BackSpace) got_backspace = 1; + } +# endif + // We have to get rid of the XK_KP_function keys, because they are + // not produced on Windoze and thus case statements tend not to check + // for them. There are 15 of these in the range 0xff91 ... 0xff9f + if (keysym >= 0xff91 && keysym <= 0xff9f) { + // Map keypad keysym to character or keysym depending on + // numlock state... + unsigned long keysym1 = XKeycodeToKeysym(fl_display, keycode, 1); + if (keysym1 <= 0x7f || (keysym1 > 0xff9f && keysym1 <= FL_KP_Last)) + Fl::e_original_keysym = (int)(keysym1 | FL_KP); + if ((xevent.xkey.state & Mod2Mask) && + (keysym1 <= 0x7f || (keysym1 > 0xff9f && keysym1 <= FL_KP_Last))) { + // Store ASCII numeric keypad value... + keysym = keysym1 | FL_KP; + buffer[0] = char(keysym1) & 0x7F; + len = 1; + } else { + // Map keypad to special key... + static const unsigned short table[15] = { + FL_F+1, FL_F+2, FL_F+3, FL_F+4, + FL_Home, FL_Left, FL_Up, FL_Right, + FL_Down, FL_Page_Up, FL_Page_Down, FL_End, + 0xff0b/*XK_Clear*/, FL_Insert, FL_Delete}; + keysym = table[keysym-0xff91]; + } + } else { + // Store this so we can later know if the KP was used + Fl::e_original_keysym = (int)keysym; + } + Fl::e_keysym = int(keysym); + set_event_xy(); + Fl::e_is_click = 0; + break;} + + case ButtonPress: + Fl::e_keysym = FL_Button + xevent.xbutton.button; + set_event_xy(); + if (xevent.xbutton.button == Button4) { + Fl::e_dy = -1; // Up + event = FL_MOUSEWHEEL; + } else if (xevent.xbutton.button == Button5) { + Fl::e_dy = +1; // Down + event = FL_MOUSEWHEEL; + } else { + Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1)); + event = FL_PUSH; + checkdouble(); + } + + fl_xmousewin = window; + in_a_window = true; + break; + + case MotionNotify: + set_event_xy(); +# if CONSOLIDATE_MOTION + send_motion = fl_xmousewin = window; + in_a_window = true; + return 0; +# else + event = FL_MOVE; + fl_xmousewin = window; + in_a_window = true; + break; +# endif + + case ButtonRelease: + Fl::e_keysym = FL_Button + xevent.xbutton.button; + set_event_xy(); + Fl::e_state &= ~(FL_BUTTON1 << (xevent.xbutton.button-1)); + if (xevent.xbutton.button == Button4 || + xevent.xbutton.button == Button5) return 0; + event = FL_RELEASE; + + fl_xmousewin = window; + in_a_window = true; + break; + + case EnterNotify: + if (xevent.xcrossing.detail == NotifyInferior) break; + // XInstallColormap(fl_display, Fl_X::i(window)->colormap); + set_event_xy(); + Fl::e_state = xevent.xcrossing.state << 16; + event = FL_ENTER; + + fl_xmousewin = window; + in_a_window = true; + break; + + case LeaveNotify: + if (xevent.xcrossing.detail == NotifyInferior) break; + set_event_xy(); + Fl::e_state = xevent.xcrossing.state << 16; + fl_xmousewin = 0; + in_a_window = false; // make do_queued_events produce FL_LEAVE event + return 0; + + // We cannot rely on the x,y position in the configure notify event. + // I now think this is an unavoidable problem with X: it is impossible + // for a window manager to prevent the "real" notify event from being + // sent when it resizes the contents, even though it can send an + // artificial event with the correct position afterwards (and some + // window managers do not send this fake event anyway) + // So anyway, do a round trip to find the correct x,y: + case MapNotify: + event = FL_SHOW; + + case ConfigureNotify: { + if (window->parent()) break; // ignore child windows + + // figure out where OS really put window + XWindowAttributes actual; + XGetWindowAttributes(fl_display, fl_xid(window), &actual); + Window cr; int X, Y, W = actual.width, H = actual.height; + XTranslateCoordinates(fl_display, fl_xid(window), actual.root, + 0, 0, &X, &Y, &cr); + + // tell Fl_Window about it and set flag to prevent echoing: + resize_bug_fix = window; + window->resize(X, Y, W, H); + break; // allow add_handler to do something too + } + + case ReparentNotify: { + int xpos, ypos; + Window junk; + + //ReparentNotify gives the new position of the window relative to + //the new parent. FLTK cares about the position on the root window. + XTranslateCoordinates(fl_display, xevent.xreparent.parent, + XRootWindow(fl_display, fl_screen), + xevent.xreparent.x, xevent.xreparent.y, + &xpos, &ypos, &junk); + + // tell Fl_Window about it and set flag to prevent echoing: + resize_bug_fix = window; + window->position(xpos, ypos); + break; + } + } + + return Fl::handle(event, window); +} + +//////////////////////////////////////////////////////////////// + +void Fl_Window::resize(int X,int Y,int W,int H) { + int is_a_move = (X != x() || Y != y()); + int is_a_resize = (W != w() || H != h()); + int resize_from_program = (this != resize_bug_fix); + if (!resize_from_program) resize_bug_fix = 0; + if (is_a_move && resize_from_program) set_flag(FL_FORCE_POSITION); + else if (!is_a_resize && !is_a_move) return; + if (is_a_resize) { + Fl_Group::resize(X,Y,W,H); + if (shown()) {redraw(); i->wait_for_expose = 1;} + } else { + x(X); y(Y); + } + + if (resize_from_program && is_a_resize && !resizable()) { + size_range(w(), h(), w(), h()); + } + + if (resize_from_program && shown()) { + if (is_a_resize) { + if (!resizable()) size_range(w(),h(),w(),h()); + if (is_a_move) { + XMoveResizeWindow(fl_display, i->xid, X, Y, W>0 ? W : 1, H>0 ? H : 1); + } else { + XResizeWindow(fl_display, i->xid, W>0 ? W : 1, H>0 ? H : 1); + } + } else + XMoveWindow(fl_display, i->xid, X, Y); + } +} + +//////////////////////////////////////////////////////////////// + +// A subclass of Fl_Window may call this to associate an X window it +// creates with the Fl_Window: + +void fl_fix_focus(); // in Fl.cxx + +Fl_X* Fl_X::set_xid(Fl_Window* win, Window winxid) { + Fl_X* xp = new Fl_X; + xp->xid = winxid; + xp->other_xid = 0; + xp->setwindow(win); + xp->next = Fl_X::first; + xp->region = 0; + xp->wait_for_expose = 1; + xp->backbuffer_bad = 1; + Fl_X::first = xp; + if (win->modal()) {Fl::modal_ = win; fl_fix_focus();} + return xp; +} + +// More commonly a subclass calls this, because it hides the really +// ugly parts of X and sets all the stuff for a window that is set +// normally. The global variables like fl_show_iconic are so that +// subclasses of *that* class may change the behavior... + +char fl_show_iconic; // hack for iconize() +int fl_background_pixel = -1; // hack to speed up bg box drawing +int fl_disable_transient_for; // secret method of removing TRANSIENT_FOR + +static const int childEventMask = ExposureMask; + +static const int XEventMask = +ExposureMask|StructureNotifyMask +|KeyPressMask|KeyReleaseMask|KeymapStateMask|FocusChangeMask +|ButtonPressMask|ButtonReleaseMask +|EnterWindowMask|LeaveWindowMask +|PointerMotionMask; + +void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap) +{ + Fl_Group::current(0); // get rid of very common user bug: forgot end() + + int X = win->x(); + int Y = win->y(); + int W = win->w(); + if (W <= 0) W = 1; // X don't like zero... + int H = win->h(); + if (H <= 0) H = 1; // X don't like zero... + if (!win->parent() && !Fl::grab()) { + // center windows in case window manager does not do anything: +#ifdef FL_CENTER_WINDOWS + if (!(win->flags() & Fl_Window::FL_FORCE_POSITION)) { + win->x(X = scr_x+(scr_w-W)/2); + win->y(Y = scr_y+(scr_h-H)/2); + } +#endif // FL_CENTER_WINDOWS + + // force the window to be on-screen. Usually the X window manager + // does this, but a few don't, so we do it here for consistency: + int scr_x, scr_y, scr_w, scr_h; + Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h, X, Y); + + if (win->border()) { + // ensure border is on screen: + // (assumme extremely minimal dimensions for this border) + const int top = 20; + const int left = 1; + const int right = 1; + const int bottom = 1; + if (X+W+right > scr_x+scr_w) X = scr_x+scr_w-right-W; + if (X-left < scr_x) X = scr_x+left; + if (Y+H+bottom > scr_y+scr_h) Y = scr_y+scr_h-bottom-H; + if (Y-top < scr_y) Y = scr_y+top; + } + // now insure contents are on-screen (more important than border): + if (X+W > scr_x+scr_w) X = scr_x+scr_w-W; + if (X < scr_x) X = scr_x; + if (Y+H > scr_y+scr_h) Y = scr_y+scr_h-H; + if (Y < scr_y) Y = scr_y; + } + + // if the window is a subwindow and our parent is not mapped yet, we + // mark this window visible, so that mapping the parent at a later + // point in time will call this function again to finally map the subwindow. + if (win->parent() && !Fl_X::i(win->window())) { + win->set_visible(); + return; + } + + ulong root = win->parent() ? + fl_xid(win->window()) : RootWindow(fl_display, fl_screen); + + XSetWindowAttributes attr; + int mask = CWBorderPixel|CWColormap|CWEventMask|CWBitGravity; + attr.event_mask = win->parent() ? childEventMask : XEventMask; + attr.colormap = colormap; + attr.border_pixel = 0; + attr.bit_gravity = 0; // StaticGravity; + if (win->override()) { + attr.override_redirect = 1; + attr.save_under = 1; + mask |= CWOverrideRedirect | CWSaveUnder; + } else attr.override_redirect = 0; + if (Fl::grab()) { + attr.save_under = 1; mask |= CWSaveUnder; + if (!win->border()) {attr.override_redirect = 1; mask |= CWOverrideRedirect;} + } + if (fl_background_pixel >= 0) { + attr.background_pixel = fl_background_pixel; + fl_background_pixel = -1; + mask |= CWBackPixel; + } + + Fl_X* xp = + set_xid(win, XCreateWindow(fl_display, + root, + X, Y, W, H, + 0, // borderwidth + visual->depth, + InputOutput, + visual->visual, + mask, &attr)); + int showit = 1; + + if (!win->parent() && !attr.override_redirect) { + // Communicate all kinds 'o junk to the X Window Manager: + + win->label(win->label(), win->iconlabel()); + + XChangeProperty(fl_display, xp->xid, WM_PROTOCOLS, + XA_ATOM, 32, 0, (uchar*)&WM_DELETE_WINDOW, 1); + + // send size limits and border: + xp->sendxjunk(); + + // set the class property, which controls the icon used: + if (win->xclass()) { + char buffer[1024]; + char *p; const char *q; + // truncate on any punctuation, because they break XResource lookup: + for (p = buffer, q = win->xclass(); isalnum(*q)||(*q&128);) *p++ = *q++; + *p++ = 0; + // create the capitalized version: + q = buffer; + *p = toupper(*q++); if (*p++ == 'X') *p++ = toupper(*q++); + while ((*p++ = *q++)); + XChangeProperty(fl_display, xp->xid, XA_WM_CLASS, XA_STRING, 8, 0, + (unsigned char *)buffer, p-buffer-1); + } + + if (win->non_modal() && xp->next && !fl_disable_transient_for) { + // find some other window to be "transient for": + Fl_Window* wp = xp->next->w; + while (wp->parent()) wp = wp->window(); + XSetTransientForHint(fl_display, xp->xid, fl_xid(wp)); + if (!wp->visible()) showit = 0; // guess that wm will not show it + } + + // Make sure that borderless windows do not show in the task bar + if (!win->border()) { + Atom net_wm_state = XInternAtom (fl_display, "_NET_WM_STATE", 0); + Atom net_wm_state_skip_taskbar = XInternAtom (fl_display, "_NET_WM_STATE_SKIP_TASKBAR", 0); + XChangeProperty (fl_display, xp->xid, net_wm_state, XA_ATOM, 32, + PropModeAppend, (unsigned char*) &net_wm_state_skip_taskbar, 1); + } + + // Make it receptive to DnD: + long version = 4; + XChangeProperty(fl_display, xp->xid, fl_XdndAware, + XA_ATOM, sizeof(int)*8, 0, (unsigned char*)&version, 1); + + XWMHints *hints = XAllocWMHints(); + hints->input = True; + hints->flags = InputHint; + if (fl_show_iconic) { + hints->flags |= StateHint; + hints->initial_state = IconicState; + fl_show_iconic = 0; + showit = 0; + } + if (win->icon()) { + hints->icon_pixmap = (Pixmap)win->icon(); + hints->flags |= IconPixmapHint; + } + XSetWMHints(fl_display, xp->xid, hints); + XFree(hints); + } + + XMapWindow(fl_display, xp->xid); + if (showit) { + win->set_visible(); + int old_event = Fl::e_number; + win->handle(Fl::e_number = FL_SHOW); // get child windows to appear + Fl::e_number = old_event; + win->redraw(); + } +} + +//////////////////////////////////////////////////////////////// +// Send X window stuff that can be changed over time: + +void Fl_X::sendxjunk() { + if (w->parent() || w->override()) return; // it's not a window manager window! + + if (!w->size_range_set) { // default size_range based on resizable(): + if (w->resizable()) { + Fl_Widget *o = w->resizable(); + int minw = o->w(); if (minw > 100) minw = 100; + int minh = o->h(); if (minh > 100) minh = 100; + w->size_range(w->w() - o->w() + minw, w->h() - o->h() + minh, 0, 0); + } else { + w->size_range(w->w(), w->h(), w->w(), w->h()); + } + return; // because this recursively called here + } + + XSizeHints *hints = XAllocSizeHints(); + // memset(&hints, 0, sizeof(hints)); jreiser suggestion to fix purify? + hints->min_width = w->minw; + hints->min_height = w->minh; + hints->max_width = w->maxw; + hints->max_height = w->maxh; + hints->width_inc = w->dw; + hints->height_inc = w->dh; + hints->win_gravity = StaticGravity; + + // see the file /usr/include/X11/Xm/MwmUtil.h: + // fill all fields to avoid bugs in kwm and perhaps other window managers: + // 0, MWM_FUNC_ALL, MWM_DECOR_ALL + long prop[5] = {0, 1, 1, 0, 0}; + + if (hints->min_width != hints->max_width || + hints->min_height != hints->max_height) { // resizable + hints->flags = PMinSize|PWinGravity; + if (hints->max_width >= hints->min_width || + hints->max_height >= hints->min_height) { + hints->flags = PMinSize|PMaxSize|PWinGravity; + // unfortunately we can't set just one maximum size. Guess a + // value for the other one. Some window managers will make the + // window fit on screen when maximized, others will put it off screen: + if (hints->max_width < hints->min_width) hints->max_width = Fl::w(); + if (hints->max_height < hints->min_height) hints->max_height = Fl::h(); + } + if (hints->width_inc && hints->height_inc) hints->flags |= PResizeInc; + if (w->aspect) { + // stupid X! It could insist that the corner go on the + // straight line between min and max... + hints->min_aspect.x = hints->max_aspect.x = hints->min_width; + hints->min_aspect.y = hints->max_aspect.y = hints->min_height; + hints->flags |= PAspect; + } + } else { // not resizable: + hints->flags = PMinSize|PMaxSize|PWinGravity; + prop[0] = 1; // MWM_HINTS_FUNCTIONS + prop[1] = 1|2|16; // MWM_FUNC_ALL | MWM_FUNC_RESIZE | MWM_FUNC_MAXIMIZE + } + + if (w->flags() & Fl_Window::FL_FORCE_POSITION) { + hints->flags |= USPosition; + hints->x = w->x(); + hints->y = w->y(); + } + + if (!w->border()) { + prop[0] |= 2; // MWM_HINTS_DECORATIONS + prop[2] = 0; // no decorations + } + + XSetWMNormalHints(fl_display, xid, hints); + XChangeProperty(fl_display, xid, + fl_MOTIF_WM_HINTS, fl_MOTIF_WM_HINTS, + 32, 0, (unsigned char *)prop, 5); + XFree(hints); +} + +void Fl_Window::size_range_() { + size_range_set = 1; + if (shown()) i->sendxjunk(); +} + +//////////////////////////////////////////////////////////////// + +// returns pointer to the filename, or null if name ends with '/' +const char *fl_filename_name(const char *name) { + const char *p,*q; + if (!name) return (0); + for (p=q=name; *p;) if (*p++ == '/') q = p; + return q; +} + +void Fl_Window::label(const char *name,const char *iname) { + Fl_Widget::label(name); + iconlabel_ = iname; + if (shown() && !parent()) { + if (!name) name = ""; + XChangeProperty(fl_display, i->xid, XA_WM_NAME, + XA_STRING, 8, 0, (uchar*)name, strlen(name)); + if (!iname) iname = fl_filename_name(name); + XChangeProperty(fl_display, i->xid, XA_WM_ICON_NAME, + XA_STRING, 8, 0, (uchar*)iname, strlen(iname)); + } +} + +//////////////////////////////////////////////////////////////// +// Implement the virtual functions for the base Fl_Window class: + +// If the box is a filled rectangle, we can make the redisplay *look* +// faster by using X's background pixel erasing. We can make it +// actually *be* faster by drawing the frame only, this is done by +// setting fl_boxcheat, which is seen by code in fl_drawbox.cxx: +// +// On XFree86 (and prehaps all X's) this has a problem if the window +// is resized while a save-behind window is atop it. The previous +// contents are restored to the area, but this assummes the area +// is cleared to background color. So this is disabled in this version. +// Fl_Window *fl_boxcheat; +static inline int can_boxcheat(uchar b) {return (b==1 || (b&2) && b<=15);} + +void Fl_Window::show() { + image(Fl::scheme_bg_); + if (Fl::scheme_bg_) { + labeltype(FL_NORMAL_LABEL); + align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE | FL_ALIGN_CLIP); + } else { + labeltype(FL_NO_LABEL); + } + Fl_Tooltip::exit(this); + if (!shown()) { + fl_open_display(); + // Don't set background pixel for double-buffered windows... + if (type() == FL_WINDOW && can_boxcheat(box())) { + fl_background_pixel = int(fl_xpixel(color())); + } + Fl_X::make_xid(this); + } else { + XMapRaised(fl_display, i->xid); + } +} + +Window fl_window; +Fl_Window *Fl_Window::current_; +GC fl_gc; + +// make X drawing go into this window (called by subclass flush() impl.) +void Fl_Window::make_current() { + static GC gc; // the GC used by all X windows + if (!gc) gc = XCreateGC(fl_display, i->xid, 0, 0); + fl_window = i->xid; + fl_gc = gc; + current_ = this; + fl_clip_region(0); +} + +#endif + +// +// End of "$Id: Fl_x.cxx 5914 2007-06-18 13:08:57Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/Makefile b/third_party/windows/fltk-1.1.10/src/Makefile new file mode 100644 index 0000000..c9c7556 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/Makefile @@ -0,0 +1,726 @@ +# +# "$Id: Makefile 6817 2009-07-02 09:42:17Z AlbrechtS $" +# +# Library makefile for the Fast Light Tool Kit (FLTK). +# +# Copyright 1998-2009 by Bill Spitzak and others. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. +# +# Please report all bugs and problems on the following page: +# +# http://www.fltk.org/str.php +# + +CPPFILES = \ + Fl.cxx \ + Fl_Adjuster.cxx \ + Fl_Bitmap.cxx \ + Fl_Browser.cxx \ + Fl_Browser_.cxx \ + Fl_Browser_load.cxx \ + Fl_Box.cxx \ + Fl_Button.cxx \ + Fl_Chart.cxx \ + Fl_Check_Browser.cxx \ + Fl_Check_Button.cxx \ + Fl_Choice.cxx \ + Fl_Clock.cxx \ + Fl_Color_Chooser.cxx \ + Fl_Counter.cxx \ + Fl_Dial.cxx \ + Fl_Double_Window.cxx \ + Fl_File_Browser.cxx \ + Fl_File_Chooser.cxx \ + Fl_File_Chooser2.cxx \ + Fl_File_Icon.cxx \ + Fl_File_Input.cxx \ + Fl_Group.cxx \ + Fl_Help_View.cxx \ + Fl_Image.cxx \ + Fl_Input.cxx \ + Fl_Input_.cxx \ + Fl_Light_Button.cxx \ + Fl_Menu.cxx \ + Fl_Menu_.cxx \ + Fl_Menu_Bar.cxx \ + Fl_Sys_Menu_Bar.cxx \ + Fl_Menu_Button.cxx \ + Fl_Menu_Window.cxx \ + Fl_Menu_add.cxx \ + Fl_Menu_global.cxx \ + Fl_Multi_Label.cxx \ + Fl_Overlay_Window.cxx \ + Fl_Pack.cxx \ + Fl_Pixmap.cxx \ + Fl_Positioner.cxx \ + Fl_Preferences.cxx \ + Fl_Progress.cxx \ + Fl_Repeat_Button.cxx \ + Fl_Return_Button.cxx \ + Fl_Roller.cxx \ + Fl_Round_Button.cxx \ + Fl_Scroll.cxx \ + Fl_Scrollbar.cxx \ + Fl_Shared_Image.cxx \ + Fl_Single_Window.cxx \ + Fl_Slider.cxx \ + Fl_Tabs.cxx \ + Fl_Text_Buffer.cxx \ + Fl_Text_Display.cxx \ + Fl_Text_Editor.cxx \ + Fl_Tile.cxx \ + Fl_Tiled_Image.cxx \ + Fl_Tooltip.cxx \ + Fl_Valuator.cxx \ + Fl_Value_Input.cxx \ + Fl_Value_Output.cxx \ + Fl_Value_Slider.cxx \ + Fl_Widget.cxx \ + Fl_Window.cxx \ + Fl_Window_fullscreen.cxx \ + Fl_Window_hotspot.cxx \ + Fl_Window_iconize.cxx \ + Fl_Wizard.cxx \ + Fl_XBM_Image.cxx \ + Fl_XPM_Image.cxx \ + Fl_abort.cxx \ + Fl_add_idle.cxx \ + Fl_arg.cxx \ + Fl_compose.cxx \ + Fl_display.cxx \ + Fl_get_key.cxx \ + Fl_get_system_colors.cxx \ + Fl_grab.cxx \ + Fl_lock.cxx \ + Fl_own_colormap.cxx \ + Fl_visual.cxx \ + Fl_x.cxx \ + filename_absolute.cxx \ + filename_expand.cxx \ + filename_ext.cxx \ + filename_isdir.cxx \ + filename_list.cxx \ + filename_match.cxx \ + filename_setext.cxx \ + fl_arc.cxx \ + fl_arci.cxx \ + fl_ask.cxx \ + fl_boxtype.cxx \ + fl_color.cxx \ + fl_cursor.cxx \ + fl_curve.cxx \ + fl_diamond_box.cxx \ + fl_dnd.cxx \ + fl_draw.cxx \ + fl_draw_image.cxx \ + fl_draw_pixmap.cxx \ + fl_encoding_latin1.cxx \ + fl_encoding_mac_roman.cxx \ + fl_engraved_label.cxx \ + fl_file_dir.cxx \ + fl_font.cxx \ + fl_gtk.cxx \ + fl_labeltype.cxx \ + fl_line_style.cxx \ + fl_open_uri.cxx \ + fl_oval_box.cxx \ + fl_overlay.cxx \ + fl_overlay_visual.cxx \ + fl_plastic.cxx \ + fl_read_image.cxx \ + fl_rect.cxx \ + fl_round_box.cxx \ + fl_rounded_box.cxx \ + fl_set_font.cxx \ + fl_set_fonts.cxx \ + fl_scroll_area.cxx \ + fl_shadow_box.cxx \ + fl_shortcut.cxx \ + fl_show_colormap.cxx \ + fl_symbols.cxx \ + fl_vertex.cxx \ + screen_xywh.cxx + +FLCPPFILES = \ + forms_compatability.cxx \ + forms_bitmap.cxx \ + forms_free.cxx \ + forms_fselect.cxx \ + forms_pixmap.cxx \ + forms_timer.cxx + +GLCPPFILES = \ + Fl_Gl_Choice.cxx \ + Fl_Gl_Overlay.cxx \ + Fl_Gl_Window.cxx \ + freeglut_geometry.cxx \ + freeglut_stroke_mono_roman.cxx \ + freeglut_stroke_roman.cxx \ + freeglut_teapot.cxx \ + gl_draw.cxx \ + gl_start.cxx \ + glut_compatability.cxx \ + glut_font.cxx + +IMGCPPFILES = \ + fl_images_core.cxx \ + Fl_BMP_Image.cxx \ + Fl_File_Icon2.cxx \ + Fl_GIF_Image.cxx \ + Fl_Help_Dialog.cxx \ + Fl_JPEG_Image.cxx \ + Fl_PNG_Image.cxx \ + Fl_PNM_Image.cxx + +CFILES = fl_call_main.c flstring.c scandir.c numericsort.c vsnprintf.c + +################################################################ + +include ../makeinclude + +OBJECTS = $(CPPFILES:.cxx=.o) $(CFILES:.c=.o) +GLOBJECTS = $(GLCPPFILES:.cxx=.o) +FLOBJECTS = $(FLCPPFILES:.cxx=.o) +IMGOBJECTS = $(IMGCPPFILES:.cxx=.o) + +all: $(LIBNAME) $(DSONAME) \ + $(FLLIBNAME) $(FLDSONAME) \ + $(GLLIBNAME) $(GLDSONAME) \ + $(IMGLIBNAME) $(IMGDSONAME) + +$(LIBNAME): $(OBJECTS) + echo $(LIBCOMMAND) $@ ... + $(RM) $@ + $(LIBCOMMAND) $@ $(OBJECTS) + $(RANLIB) $@ + +libfltk.so.1.1: $(OBJECTS) + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ $(OBJECTS) + $(RM) libfltk.so + $(LN) libfltk.so.1.1 libfltk.so + +libfltk.sl.1.1: $(OBJECTS) + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ $(OBJECTS) + $(RM) libfltk.sl + $(LN) libfltk.sl.1.1 libfltk.sl + +libfltk.1.1.dylib: $(OBJECTS) + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ \ + -install_name $(libdir)/$@ \ + -current_version 1.1.4 \ + -compatibility_version 1.1.0 \ + $(OBJECTS) $(LDLIBS) + $(RM) libfltk.dylib + $(LN) libfltk.1.1.dylib libfltk.dylib + +libfltk_s.a: $(OBJECTS) + echo $(DSOCOMMAND) libfltk_s.o ... + $(DSOCOMMAND) libfltk_s.o $(OBJECTS) $(IMAGELIBS) + echo $(LIBCOMMAND) libfltk_s.a libfltk_s.o + $(RM) $@ + $(LIBCOMMAND) libfltk_s.a libfltk_s.o + $(CHMOD) +x libfltk_s.a + +$(FLLIBNAME): $(FLOBJECTS) + echo $(LIBCOMMAND) $@ ... + $(RM) $@ + $(LIBCOMMAND) $@ $(FLOBJECTS) + $(RANLIB) $@ + +libfltk_forms.so.1.1: $(FLOBJECTS) libfltk.so.1.1 + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ $(FLOBJECTS) -L. -lfltk + $(RM) libfltk_forms.so + $(LN) libfltk_forms.so.1.1 libfltk_forms.so + +libfltk_forms.sl.1.1: $(FLOBJECTS) libfltk.sl.1.1 + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ $(FLOBJECTS) -L. -lfltk + $(RM) libfltk_forms.sl + $(LN) libfltk_forms.sl.1.1 libfltk_forms.sl + +libfltk_forms.1.1.dylib: $(FLOBJECTS) libfltk.1.1.dylib + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ \ + -install_name $(libdir)/$@ \ + -current_version 1.1.4 \ + -compatibility_version 1.1.0 \ + $(FLOBJECTS) -L. $(LDLIBS) -lfltk + $(RM) libfltk_forms.dylib + $(LN) libfltk_forms.1.1.dylib libfltk_forms.dylib + +libfltk_forms_s.a: $(FLOBJECTS) + echo $(DSOCOMMAND) libfltk_forms_s.o ... + $(DSOCOMMAND) libfltk_forms_s.o $(FLOBJECTS) + echo $(LIBCOMMAND) libfltk_forms_s.a libfltk_forms_s.o + $(RM) $@ + $(LIBCOMMAND) libfltk_forms_s.a libfltk_forms_s.o + $(CHMOD) +x libfltk_forms_s.a + +$(GLLIBNAME): $(GLOBJECTS) + echo $(LIBCOMMAND) $@ ... + $(RM) $@ + $(LIBCOMMAND) $@ $(GLOBJECTS) + $(RANLIB) $@ + +libfltk_gl.so.1.1: $(GLOBJECTS) libfltk.so.1.1 + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ $(GLOBJECTS) -L. -lfltk + $(RM) libfltk_gl.so + $(LN) libfltk_gl.so.1.1 libfltk_gl.so + +libfltk_gl.sl.1.1: $(GLOBJECTS) libfltk.sl.1.1 + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ $(GLOBJECTS) -L. -lfltk + $(RM) libfltk_gl.sl + $(LN) libfltk_gl.sl.1.1 libfltk_gl.sl + +libfltk_gl.1.1.dylib: $(GLOBJECTS) libfltk.1.1.dylib + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ \ + -install_name $(libdir)/$@ \ + -current_version 1.1.4 \ + -compatibility_version 1.1.0 \ + $(GLOBJECTS) -L. $(GLDLIBS) -lfltk + $(RM) libfltk_gl.dylib + $(LN) libfltk_gl.1.1.dylib libfltk_gl.dylib + +libfltk_gl_s.a: $(GLOBJECTS) + echo $(DSOCOMMAND) libfltk_gl_s.o ... + $(DSOCOMMAND) libfltk_gl_s.o $(GLOBJECTS) + echo $(LIBCOMMAND) libfltk_gl_s.a libfltk_gl_s.o + $(RM) $@ + $(LIBCOMMAND) libfltk_gl_s.a libfltk_gl_s.o + $(CHMOD) +x libfltk_gl_s.a + +$(IMGLIBNAME): $(IMGOBJECTS) + echo $(LIBCOMMAND) $@ ... + $(RM) $@ + $(LIBCOMMAND) $@ $(IMGOBJECTS) + $(RANLIB) $@ + +libfltk_images.so.1.1: $(IMGOBJECTS) libfltk.so.1.1 + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ $(IMGOBJECTS) -L. $(IMAGELIBS) -lfltk + $(RM) libfltk_images.so + $(LN) libfltk_images.so.1.1 libfltk_images.so + +libfltk_images.sl.1.1: $(IMGOBJECTS) libfltk.sl.1.1 + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ $(IMGOBJECTS) -L. $(IMAGELIBS) -lfltk + $(RM) libfltk_images.sl + $(LN) libfltk_images.sl.1.1 libfltk_images.sl + +libfltk_images.1.1.dylib: $(IMGOBJECTS) libfltk.1.1.dylib + echo $(DSOCOMMAND) $@ ... + $(DSOCOMMAND) $@ \ + -install_name $(libdir)/$@ \ + -current_version 1.1.4 \ + -compatibility_version 1.1.0 \ + $(IMGOBJECTS) -L. $(LDLIBS) $(IMAGELIBS) -lfltk + $(RM) libfltk_images.dylib + $(LN) libfltk_images.1.1.dylib libfltk_images.dylib + +libfltk_images_s.a: $(IMGOBJECTS) + echo $(DSOCOMMAND) libfltk_images_s.o ... + $(DSOCOMMAND) libfltk_images_s.o $(IMGOBJECTS) + echo $(LIBCOMMAND) libfltk_images_s.a libfltk_images_s.o + $(RM) $@ + $(LIBCOMMAND) libfltk_images_s.a libfltk_images_s.o + $(CHMOD) +x libfltk_images_s.a + +#----------------------------------------------------------------- +# - the import libraries libfltk*.dll.a and the .dll files +# are created from the libfltk*.a files. They are built +# into the src dir. +# - The _images, _gl, _forms and dlls must be linked +# against the import libraries in the src dir. +#----------------------------------------------------------------- + +cygfltknox-1.1.dll: $(LIBNAME) + echo $(DSOCOMMAND) $(LIBNAME) ... + $(DSOCOMMAND) $(LIBNAME) -Wl,--no-whole-archive \ + -Wl,--out-implib=libfltk.dll.a $(LDLIBS) + +cygfltknox_forms-1.1.dll: $(FLLIBNAME) cygfltknox-1.1.dll + echo $(DSOCOMMAND) $(FLLIBNAME) ... + $(DSOCOMMAND) $(FLLIBNAME) -Wl,--no-whole-archive \ + -Wl,--out-implib=libfltk_forms.dll.a \ + -L. -lfltk $(LDLIBS) + +cygfltknox_gl-1.1.dll: $(GLLIBNAME) cygfltknox-1.1.dll + echo $(DSOCOMMAND) $(GLLIBNAME) ... + $(DSOCOMMAND) $(GLLIBNAME) -Wl,--no-whole-archive \ + -Wl,--out-implib=libfltk_gl.dll.a \ + -L. -lfltk $(GLDLIBS) + +cygfltknox_images-1.1.dll: $(IMGLIBNAME) cygfltknox-1.1.dll + echo $(DSOCOMMAND) $(IMGLIBNAME) ... + $(DSOCOMMAND) $(IMGLIBNAME) -Wl,--no-whole-archive \ + -Wl,--out-implib=libfltk_images.dll.a \ + -L. -lfltk -Wl,--exclude-libs -Wl,libfltk_png.a \ + $(IMAGELIBS) $(LDLIBS) + +mgwfltknox-1.1.dll: $(LIBNAME) + echo $(DSOCOMMAND) $(LIBNAME) ... + $(DSOCOMMAND) $(LIBNAME) -Wl,--no-whole-archive \ + -Wl,--out-implib=libfltk.dll.a $(LDLIBS) + +mgwfltknox_forms-1.1.dll: $(FLLIBNAME) mgwfltknox-1.1.dll + echo $(DSOCOMMAND) $(FLLIBNAME) ... + $(DSOCOMMAND) $(FLLIBNAME) -Wl,--no-whole-archive \ + -Wl,--out-implib=libfltk_forms.dll.a \ + -L. -lfltk $(LDLIBS) + +mgwfltknox_gl-1.1.dll: $(GLLIBNAME) mgwfltknox-1.1.dll + echo $(DSOCOMMAND) $(GLLIBNAME) ... + $(DSOCOMMAND) $(GLLIBNAME) -Wl,--no-whole-archive \ + -Wl,--out-implib=libfltk_gl.dll.a \ + -L. -lfltk $(GLDLIBS) + +#----------------------------------------------------- +# See STR #1585 for --exclude-libs +#----------------------------------------------------- + +mgwfltknox_images-1.1.dll: $(IMGLIBNAME) mgwfltknox-1.1.dll + echo $(DSOCOMMAND) $(IMGLIBNAME) ... + $(DSOCOMMAND) $(IMGLIBNAME) -Wl,--no-whole-archive \ + -Wl,--out-implib=libfltk_images.dll.a \ + -L. -lfltk -Wl,--exclude-libs -Wl,libfltk_png.a \ + $(IMAGELIBS) $(LDLIBS) + +clean: + -$(RM) *.o *.dll.a core.* *~ *.bck *.bck + -$(RM) $(DSONAME) $(FLDSONAME) $(GLDSONAME) $(IMGDSONAME) \ + $(LIBNAME) $(FLLIBNAME) $(GLLIBNAME) \ + $(IMGLIBNAME) \ + libfltk.so libfltk_forms.so libfltk_gl.so libfltk_images.so \ + libfltk.sl libfltk_forms.sl libfltk_gl.sl libfltk_images.sl \ + libfltk.dylib libfltk_forms.dylib \ + libfltk_gl.dylib libfltk_images.dylib \ + cmap core + +depend: $(CPPFILES) $(FLCPPFILES) $(GLCPPFILES) $(IMGCPPFILES) $(CFILES) + makedepend -Y -I.. -f makedepend $(CPPFILES) $(FLCPPFILES) \ + $(GLCPPFILES) $(IMGCPPFILES) $(CFILES) + +# Automatically generated dependencies... +include makedepend + +# These dependencies aren't part of the makedepend file since +# they are part of the WIN32 and MacOS code base... +Fl_get_key.o: Fl_get_key_mac.cxx Fl_get_key_win32.cxx +Fl.o: Fl_mac.cxx Fl_win32.cxx +fl_color.o: fl_color_mac.cxx fl_color_win32.cxx +fl_dnd.o: fl_dnd_mac.cxx fl_dnd_win32.cxx fl_dnd_x.cxx +fl_draw_image.o: fl_draw_image_mac.cxx fl_draw_image_win32.cxx +fl_font.o: fl_font_mac.cxx fl_font_x.cxx fl_font_xft.cxx fl_font_win32.cxx +fl_read_image.o: fl_read_image_mac.cxx fl_read_image_win32.cxx +fl_set_fonts.o: fl_set_fonts_mac.cxx fl_set_fonts_x.cxx \ + fl_set_fonts_xft.cxx fl_set_fonts_win32.cxx + +fl_arci.o: ../FL/mac.H ../FL/win32.H +Fl_arg.o: ../FL/mac.H ../FL/win32.H +fl_ask.o: ../FL/mac.H ../FL/win32.H +Fl_Bitmap.o: ../FL/mac.H ../FL/win32.H +fl_color.o: ../FL/mac.H ../FL/win32.H +fl_cursor.o: ../FL/mac.H ../FL/win32.H +fl_dnd.o: ../FL/mac.H ../FL/win32.H +Fl.o: ../FL/mac.H ../FL/win32.H Fl_win32.cxx Fl_mac.cxx +Fl_Double_Window.o: ../FL/mac.H ../FL/win32.H +fl_draw_image.o: ../FL/mac.H ../FL/win32.H +fl_draw_image_mac.o: ../FL/mac.H ../FL/win32.H +fl_draw_image_win32.o: ../FL/mac.H ../FL/win32.H +fl_draw_pixmap.o: ../FL/mac.H ../FL/win32.H +fl_encoding_latin1.o: ../FL/mac.H ../FL/win32.H +fl_encoding_mac_roman.o: ../FL/mac.H ../FL/win32.H +Fl_File_Chooser2.o: ../FL/mac.H ../FL/win32.H +fl_font.o: ../FL/mac.H ../FL/win32.H +Fl_get_key.o: ../FL/mac.H ../FL/win32.H +Fl_get_system_colors.o: ../FL/mac.H ../FL/win32.H +Fl_Gl_Choice.o: ../FL/mac.H ../FL/win32.H +Fl_Gl_Overlay.o: ../FL/mac.H ../FL/win32.H +Fl_Gl_Window.o: ../FL/mac.H ../FL/win32.H +Fl_grab.o: ../FL/mac.H ../FL/win32.H +Fl_Image.o: ../FL/mac.H ../FL/win32.H +fl_line_style.o: ../FL/mac.H ../FL/win32.H +Fl_mac.o: ../FL/mac.H ../FL/win32.H +Fl_Menu_Window.o: ../FL/mac.H ../FL/win32.H +fl_overlay.o: ../FL/mac.H ../FL/win32.H +fl_overlay_visual.o: ../FL/mac.H ../FL/win32.H +Fl_Overlay_Window.o: ../FL/mac.H ../FL/win32.H +Fl_own_colormap.o: ../FL/mac.H ../FL/win32.H +Fl_Pixmap.o: ../FL/mac.H ../FL/win32.H +fl_read_image.o: ../FL/mac.H ../FL/win32.H +fl_read_image_mac.o: ../FL/mac.H ../FL/win32.H +fl_read_image_win32.o: ../FL/mac.H ../FL/win32.H +fl_rect.o: ../FL/mac.H ../FL/win32.H +fl_scroll_area.o: ../FL/mac.H ../FL/win32.H +fl_set_font.o: ../FL/mac.H ../FL/win32.H +fl_set_fonts.o: ../FL/mac.H ../FL/win32.H +fl_shortcut.o: ../FL/mac.H ../FL/win32.H +fl_vertex.o: ../FL/mac.H ../FL/win32.H +Fl_visual.o: ../FL/mac.H ../FL/win32.H +Fl_Window_fullscreen.o: ../FL/mac.H ../FL/win32.H +Fl_Window_iconize.o: ../FL/mac.H ../FL/win32.H +Fl_x.o: ../FL/mac.H ../FL/win32.H +gl_draw.o: ../FL/mac.H ../FL/win32.H +gl_start.o: ../FL/mac.H ../FL/win32.H + +################################################################ + +install: $(LIBNAME) $(DSONAME) \ + $(FLLIBNAME) $(FLDSONAME) \ + $(GLLIBNAME) $(GLDSONAME) \ + $(IMGLIBNAME) $(IMGDSONAME) + echo "Installing libraries in $(DESTDIR)$(libdir)..." + -$(INSTALL_DIR) $(DESTDIR)$(libdir) + -$(INSTALL_DIR) $(DESTDIR)$(bindir) + $(RM) $(DESTDIR)$(libdir)/$(LIBBASENAME) + $(INSTALL_LIB) $(LIBNAME) $(DESTDIR)$(libdir) + $(INSTALL_LIB) $(FLLIBNAME) $(DESTDIR)$(libdir) + $(INSTALL_LIB) $(IMGLIBNAME) $(DESTDIR)$(libdir) + $(RANLIB) $(DESTDIR)$(libdir)/$(LIBBASENAME) + $(RANLIB) $(DESTDIR)$(libdir)/$(FLLIBBASENAME) + if test x$(GLLIBNAME) != x; then \ + $(INSTALL_LIB) $(GLLIBNAME) $(DESTDIR)$(libdir); \ + $(RANLIB) $(DESTDIR)$(libdir)/$(GLLIBBASENAME); \ + fi + $(RANLIB) $(DESTDIR)$(libdir)/$(IMGLIBBASENAME) + if test x$(DSONAME) = xlibfltk.so.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk.so*;\ + $(INSTALL_LIB) libfltk.so.1.1 $(DESTDIR)$(libdir); \ + $(LN) libfltk.so.1.1 $(DESTDIR)$(libdir)/libfltk.so;\ + fi + if test x$(DSONAME) = xlibfltk.sl.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk.sl*;\ + $(INSTALL_LIB) libfltk.sl.1.1 $(DESTDIR)$(libdir); \ + $(LN) libfltk.sl.1.1 $(DESTDIR)$(libdir)/libfltk.sl;\ + fi + if test x$(DSONAME) = xlibfltk.1.1.dylib; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk.*dylib;\ + $(INSTALL_LIB) libfltk.1.1.dylib $(DESTDIR)$(libdir); \ + $(LN) libfltk.1.1.dylib $(DESTDIR)$(libdir)/libfltk.dylib;\ + fi + if test x$(DSONAME) = xlibfltk_s.a; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_s.a;\ + $(INSTALL_LIB) libfltk_s.a $(DESTDIR)$(libdir); \ + fi + if test x$(DSONAME) = xcygfltknox-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(DSONAME);\ + $(INSTALL_LIB) $(DSONAME) $(DESTDIR)$(bindir); \ + $(RM) $(DESTDIR)$(libdir)/libfltk.dll.a;\ + $(INSTALL_LIB) libfltk.dll.a $(DESTDIR)$(libdir); \ + fi + if test x$(DSONAME) = xmgwfltknox-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(DSONAME);\ + $(INSTALL_LIB) $(DSONAME) $(DESTDIR)$(bindir); \ + $(RM) $(DESTDIR)$(libdir)/libfltk.dll.a;\ + $(INSTALL_LIB) libfltk.dll.a $(DESTDIR)$(libdir); \ + fi + if test x$(FLDSONAME) = xlibfltk_forms.so.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms.so*;\ + $(INSTALL_LIB) libfltk_forms.so.1.1 $(DESTDIR)$(libdir); \ + $(LN) libfltk_forms.so.1.1 $(DESTDIR)$(libdir)/libfltk_forms.so;\ + fi + if test x$(FLDSONAME) = xlibfltk_forms.sl.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms.sl*;\ + $(INSTALL_LIB) libfltk_forms.sl.1.1 $(DESTDIR)$(libdir); \ + $(LN) libfltk_forms.sl.1.1 $(DESTDIR)$(libdir)/libfltk_forms.sl;\ + fi + if test x$(FLDSONAME) = xlibfltk_forms.1.1.dylib; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms.*dylib;\ + $(INSTALL_LIB) libfltk_forms.1.1.dylib $(DESTDIR)$(libdir); \ + $(LN) libfltk_forms.1.1.dylib $(DESTDIR)$(libdir)/libfltk_forms.dylib;\ + fi + if test x$(FLDSONAME) = xlibfltk_forms_s.a; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms_s.a;\ + $(INSTALL_LIB) libfltk_forms_s.a $(DESTDIR)$(libdir); \ + fi + if test x$(FLDSONAME) = xcygfltknox_forms-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(FLDSONAME);\ + $(INSTALL_LIB) $(FLDSONAME) $(DESTDIR)$(bindir); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms.dll.a;\ + $(INSTALL_LIB) libfltk_forms.dll.a $(DESTDIR)$(libdir); \ + fi + if test x$(FLDSONAME) = xmgwfltknox_forms-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(FLDSONAME);\ + $(INSTALL_LIB) $(FLDSONAME) $(DESTDIR)$(bindir); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms.dll.a;\ + $(INSTALL_LIB) libfltk_forms.dll.a $(DESTDIR)$(libdir); \ + fi + if test x$(GLDSONAME) = xlibfltk_gl.so.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl.so*;\ + $(INSTALL_LIB) libfltk_gl.so.1.1 $(DESTDIR)$(libdir); \ + $(LN) libfltk_gl.so.1.1 $(DESTDIR)$(libdir)/libfltk_gl.so;\ + fi + if test x$(GLDSONAME) = xlibfltk_gl.sl.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl.sl*;\ + $(INSTALL_LIB) libfltk_gl.sl.1.1 $(DESTDIR)$(libdir); \ + $(LN) libfltk_gl.sl.1.1 $(DESTDIR)$(libdir)/libfltk_gl.sl;\ + fi + if test x$(GLDSONAME) = xlibfltk_gl.1.1.dylib; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl.*dylib;\ + $(INSTALL_LIB) libfltk_gl.1.1.dylib $(DESTDIR)$(libdir); \ + $(LN) libfltk_gl.1.1.dylib $(DESTDIR)$(libdir)/libfltk_gl.dylib;\ + fi + if test x$(GLDSONAME) = xlibfltk_gl_s.a; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl_s.a;\ + $(INSTALL_LIB) libfltk_gl_s.a $(DESTDIR)$(libdir); \ + fi + if test x$(GLDSONAME) = xcygfltknox_gl-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(GLDSONAME);\ + $(INSTALL_LIB) $(GLDSONAME) $(DESTDIR)$(bindir); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl.dll.a;\ + $(INSTALL_LIB) libfltk_gl.dll.a $(DESTDIR)$(libdir); \ + fi + if test x$(GLDSONAME) = xmgwfltknox_gl-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(GLDSONAME);\ + $(INSTALL_LIB) $(GLDSONAME) $(DESTDIR)$(bindir); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl.dll.a;\ + $(INSTALL_LIB) libfltk_gl.dll.a $(DESTDIR)$(libdir); \ + fi + if test x$(IMGDSONAME) = xlibfltk_images.so.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_images.so*;\ + $(INSTALL_LIB) libfltk_images.so.1.1 $(DESTDIR)$(libdir); \ + $(LN) libfltk_images.so.1.1 $(DESTDIR)$(libdir)/libfltk_images.so;\ + fi + if test x$(IMGDSONAME) = xlibfltk_images.sl.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_images.sl*;\ + $(INSTALL_LIB) libfltk_images.sl.1.1 $(DESTDIR)$(libdir); \ + $(LN) libfltk_images.sl.1.1 $(DESTDIR)$(libdir)/libfltk_images.sl;\ + fi + if test x$(IMGDSONAME) = xlibfltk_images.1.1.dylib; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_images.*dylib;\ + $(INSTALL_LIB) libfltk_images.1.1.dylib $(DESTDIR)$(libdir); \ + $(LN) libfltk_images.1.1.dylib $(DESTDIR)$(libdir)/libfltk_images.dylib;\ + fi + if test x$(IMGDSONAME) = xlibfltk_images_s.a; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_images_s.a;\ + $(INSTALL_LIB) libfltk_images_s.a $(DESTDIR)$(libdir); \ + fi + if test x$(IMGDSONAME) = xcygfltknox_images-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(IMGDSONAME); \ + $(INSTALL_LIB) $(IMGDSONAME) $(DESTDIR)$(bindir); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_images.dll.a;\ + $(INSTALL_LIB) libfltk_images.dll.a $(DESTDIR)$(libdir); \ + fi + if test x$(IMGDSONAME) = xmgwfltknox_images-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(IMGDSONAME); \ + $(INSTALL_LIB) $(IMGDSONAME) $(DESTDIR)$(bindir); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_images.dll.a;\ + $(INSTALL_LIB) libfltk_images.dll.a $(DESTDIR)$(libdir); \ + fi + +uninstall: + echo "Uninstalling libraries..." + $(RM) $(DESTDIR)$(libdir)/$(LIBBASENAME) + if test x$(DSONAME) = xlibfltk.so.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk.so*;\ + fi + if test x$(DSONAME) = xlibfltk.sl.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk.sl*;\ + fi + if test x$(DSONAME) = xlibfltk.1.1.dylib; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk.*dylib;\ + fi + if test x$(DSONAME) = xlibfltk_s.a; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_s.a;\ + fi + if test x$(DSONAME) = xcygfltknox-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(DSONAME); \ + $(RM) $(DESTDIR)$(libdir)/libfltk.dll.a;\ + fi + if test x$(DSONAME) = xmgwfltknox-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(DSONAME); \ + $(RM) $(DESTDIR)$(libdir)/libfltk.dll.a;\ + fi + $(RM) $(DESTDIR)$(libdir)/$(FLLIBBASENAME); + if test x$(FLDSONAME) = xlibfltk_forms.so.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms.so*;\ + fi + if test x$(FLDSONAME) = xlibfltk_forms.sl.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms.sl*;\ + fi + if test x$(FLDSONAME) = xlibfltk_forms.1.1.dylib; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms.*dylib;\ + fi + if test x$(FLDSONAME) = xlibfltk_forms_s.a; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms_s.a;\ + fi + if test x$(FLDSONAME) = xcygfltknox_forms-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(FLDSONAME); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms.dll.a;\ + fi + if test x$(FLDSONAME) = xmgwfltknox_forms-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(FLDSONAME); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_forms.dll.a;\ + fi + if test x$(GLLIBNAME) != x; then\ + $(RM) $(DESTDIR)$(libdir)/$(GLLIBBASENAME);\ + fi + if test x$(GLDSONAME) = xlibfltk_gl.so.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl.so*;\ + fi + if test x$(GLDSONAME) = xlibfltk_gl.sl.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl.sl*;\ + fi + if test x$(GLDSONAME) = xlibfltk_gl.1.1.dylib; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl.*dylib;\ + fi + if test x$(GLDSONAME) = xlibfltk_gl_s.a; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl_s.a;\ + fi + if test x$(GLDSONAME) = xcygfltknox_gl-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(GLDSONAME); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl.dll.a;\ + fi + if test x$(GLDSONAME) = xmgwfltknox_gl-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(GLDSONAME); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_gl.dll.a;\ + fi + if test x$(IMGLIBNAME) != x; then\ + $(RM) $(DESTDIR)$(libdir)/$(IMGLIBBASENAME);\ + fi + if test x$(IMGDSONAME) = xlibfltk_images.so.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_images.so*;\ + fi + if test x$(IMGDSONAME) = xlibfltk_images.sl.1.1; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_images.sl*;\ + fi + if test x$(IMGDSONAME) = xlibfltk_images.1.1.dylib; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_images.*dylib;\ + fi + if test x$(IMGDSONAME) = xlibfltk_images_s.a; then\ + $(RM) $(DESTDIR)$(libdir)/libfltk_images_s.a;\ + fi + if test x$(IMGDSONAME) = xcygfltknox_images-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(IMGDSONAME); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_images.dll.a;\ + fi + if test x$(IMGDSONAME) = xmgwfltknox_images-1.1.dll; then\ + $(RM) $(DESTDIR)$(bindir)/$(IMGDSONAME); \ + $(RM) $(DESTDIR)$(libdir)/libfltk_images.dll.a;\ + fi + + +# +# End of "$Id: Makefile 6817 2009-07-02 09:42:17Z AlbrechtS $". +# diff --git a/third_party/windows/fltk-1.1.10/src/allfiles.xbm b/third_party/windows/fltk-1.1.10/src/allfiles.xbm new file mode 100644 index 0000000..5aaec59 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/allfiles.xbm @@ -0,0 +1,6 @@ +#define allfiles_width 16 +#define allfiles_height 16 +static unsigned char allfiles_bits[] = { + 0xfc, 0x3f, 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0x84, 0x21, 0xa4, 0x25, + 0xc4, 0x23, 0xf4, 0x2f, 0xf4, 0x2f, 0xc4, 0x23, 0xa4, 0x25, 0x84, 0x21, + 0x04, 0x20, 0x04, 0x20, 0x04, 0x20, 0xfc, 0x3f}; diff --git a/third_party/windows/fltk-1.1.10/src/cgdebug.h b/third_party/windows/fltk-1.1.10/src/cgdebug.h new file mode 100644 index 0000000..1217f15 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/cgdebug.h @@ -0,0 +1,215 @@ +// +// "$Id:$" +// +// OS X Core Graphics debugging help for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This file allows easier debugging of Mac OS X Core Graphics +// code. This file is normally not included into any FLTK builds, +// but since it has proven to be tremendously useful in debugging +// the FLTK port to "Quartz", I decided to add this file in case +// more bugs show up. +// +// This header is activated by adding the following +// line to "config.h" +// #include "src/cgdebug.h" +// +// Running "./configure" will remove this line from "config.h". +// +// When used erreanously, Core Graphics prints warnings to +// stderr. This is helpful, however it is not possible to +// associate a line number or source file with the warning message. +// This headr file outputs a trace of CG calls, interweaveing +// them with CG warnings. +// +// Matthias + +#ifndef CGDEBUG +#define CGDEBUG + +#include +#include + +//+BitmapContextCreate +//+BitmapContextGetData +// ClipCGContextToRegion +// QDBeginCGContext +// QDEndCGContext + +//+AddArc +//+AddLineToPoint +// ClipToRect +// ClosePath +//+ConcatCTM +//+DrawImage +// FillPath +// FillRect +// Flush +//+GetCTM +// MoveToPoint +//+Release +// RestoreGState +// SaveGState +//+ScaleCTM +//+SetLineCap +//+SetLineDash +//+SetLineJoin +//+SetLineWidth +//+SetRGBFillColor +//+SetRGBStrokeColor +//+SetShouldAntialias +//+SetTextMatrix +//+StrokePath +//+TranslateCTM + +inline OSStatus dbgLocation(const char *file, int line) +{ + fprintf(stderr, "%s:%d ", file, line); + return 0; +} + +inline OSStatus dbgEndl() +{ + fprintf(stderr, "\n"); + return 0; +} + + +inline void dbgCGContextClipToRect(CGContextRef a, CGRect b) +{ + CGContextClipToRect(a, b); +} + +#define CGContextClipToRect(a, b) { \ + fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ + dbgCGContextClipToRect(a, b); \ + fprintf(stderr, "\n"); } + +inline void dbgCGContextFillRect(CGContextRef a, CGRect b) +{ + CGContextFillRect(a, b); +} + +#define CGContextFillRect(a, b) { \ + fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ + dbgCGContextFillRect(a, b); \ + fprintf(stderr, "\n"); } + +inline OSStatus dbgQDEndCGContext(CGrafPtr a, CGContextRef *b) +{ + return QDEndCGContext(a, b); +} + +#define QDEndCGContext(a, b) ( \ + dbgLocation(__FILE__, __LINE__) + \ + dbgQDEndCGContext(a, b) + \ + dbgEndl() ) + +inline OSStatus dbgQDBeginCGContext(CGrafPtr a, CGContextRef *b) +{ + return QDBeginCGContext(a, b); +} + +#define QDBeginCGContext(a, b) ( \ + dbgLocation(__FILE__, __LINE__) + \ + dbgQDBeginCGContext(a, b) + \ + dbgEndl() ) + +inline void dbgClipCGContextToRegion(CGContextRef a, const Rect *b, RgnHandle c) +{ + ClipCGContextToRegion(a, b, c); +} + +#define ClipCGContextToRegion(a, b, c) { \ + fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ + dbgClipCGContextToRegion(a, b, c); \ + fprintf(stderr, "\n"); } + +inline void dbgCGContextMoveToPoint(CGContextRef context, float x, float y) +{ + CGContextMoveToPoint(context, x, y); +} + +#define CGContextMoveToPoint(a, b, c) { \ + fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ + dbgCGContextMoveToPoint(a, b, c); \ + fprintf(stderr, "\n"); } + +inline void dbgCGContextFillPath(CGContextRef context) +{ + CGContextFillPath(context); +} + +#define CGContextFillPath(a) { \ + fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ + dbgCGContextFillPath(a); \ + fprintf(stderr, "\n"); } + +inline void dbgCGContextClosePath(CGContextRef context) +{ + CGContextClosePath(context); +} + +#define CGContextClosePath(a) { \ + fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ + dbgCGContextClosePath(a); \ + fprintf(stderr, "\n"); } + +inline void dbgCGContextFlush(CGContextRef context) +{ + CGContextFlush(context); +} + +#define CGContextFlush(a) { \ + fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ + dbgCGContextFlush(a); \ + fprintf(stderr, "\n"); } + +inline void dbgCGContextSaveGState(CGContextRef context) +{ + CGContextSaveGState(context); +} + +#define CGContextSaveGState(a) { \ + fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ + dbgCGContextSaveGState(a); \ + fprintf(stderr, "\n"); } + +inline void dbgCGContextRestoreGState(CGContextRef context) +{ + CGContextRestoreGState(context); +} + +#define CGContextRestoreGState(a) { \ + fprintf(stderr, "%s:%d ", __FILE__, __LINE__); \ + dbgCGContextRestoreGState(a); \ + fprintf(stderr, "\n"); } + + +#endif + +// +// End of "$Id:$". +// + diff --git a/third_party/windows/fltk-1.1.10/src/cmap.cxx b/third_party/windows/fltk-1.1.10/src/cmap.cxx new file mode 100644 index 0000000..75a1f98 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/cmap.cxx @@ -0,0 +1,179 @@ +// +// "$Id: cmap.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Colormap generation program for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to "fltk-bugs@easysw.com". +// + +// This program produces the contents of "fl_cmap.h" as stdout + +// #include +#include + +// This table is initialized with color values I got by reading the +// colormap on an IRIX 4.3 machine: + +// "full intensity colors" have been turned down some to make white +// background less intense by default. The hope is that this will make +// fltk programs more friendly on color-adjusted screens. If you want +// pure colors you should get them out of the colormap. + +//#define III 244 // maximum intensity of the basic colors + +// that results in errors and unshared colormap entries, so full intensity: +#define III 255 // maximum intensity of the basic colors + +static short cmap[256][3] = { +// 3-bit colormap: + { 0, 0, 0}, // black + {III, 0, 0}, // red + { 0,III, 0}, // green + {III,III, 0}, // yellow + { 0, 0,III}, // blue + {III, 0,III}, // magenta + { 0,III,III}, // cyan + {III,III,III}, // white +// pastel versions of those colors, from SGI's standard color map: + { 85, 85, 85}, // 1/3 gray + {198,113,113}, // salmon? pale red? + {113,198,113}, // pale green + {142,142, 56}, // khaki + {113,113,198}, // pale blue + {142, 56,142}, // purple, orchid, pale magenta + { 56,142,142}, // cadet blue, aquamarine, pale cyan +// The next location is used for FL_SELECTION_COLOR. It formerly was 2/3 gray +// but this is changed to be the Windows blue color. This allows the default +// behavior on both X and Windows to match: + { 0, 0,128}, +//{170,170,170}, // old 2/3 gray color +// These next 16 are the FL_FREE_COLOR area. In some versions of fltk +// these were filled with random colors that a Irix 5.3 machine placed +// in these locations. Other versions of fltk filled this with the 1/3 +// gray above to discourage their use. This newest version uses colors +// that NewTek has assigned for their GUI: +#if 0 + // The Irix 5.3 colors: + { 16, 16, 16}, + {128, 40,128}, + {198, 30, 30}, + { 66, 30, 30}, + {176,140,140}, + { 0, 20, 20}, + { 20, 10, 10}, + { 40, 20, 20}, + { 60, 30, 30}, + { 0, 80, 80}, + { 0, 40, 40}, + { 20, 20, 0}, + { 40, 40, 0}, + { 80, 80, 10}, + {150,150, 20}, + {160, 10, 10}, +#else + // The NewTek colors: (from George Yohng) + {168,168,152}, + {232,232,216}, + {104,104, 88}, + {152,168,168}, + {216,232,232}, + { 88,104,104}, + {156,156,168}, + {220,220,232}, + { 92, 92,104}, + {156,168,156}, + {220,232,220}, + { 92,104, 92}, + {144,144,144}, + {192,192,192}, + { 80, 80, 80}, + {160,160,160}, +#endif +// The rest of the colormap is a gray ramp and table, filled in below: +}; + +// This is Fl::background from Fl_get_system_colors.cxx, with modifications: + +#define FL_GRAY_RAMP 32 +#define FL_NUM_GRAY 24 +#define FL_GRAY 49 // old value is 47 +typedef unsigned char uchar; +#include + +void background(uchar r, uchar g, uchar b) { + // replace the gray ramp so that color 47 (by default 2/3) is this color + if (!r) r = 1; else if (r==255) r = 254; + double powr = log(r/255.0)/log((FL_GRAY-FL_GRAY_RAMP)/(FL_NUM_GRAY-1.0)); + if (!g) g = 1; else if (g==255) g = 254; + double powg = log(g/255.0)/log((FL_GRAY-FL_GRAY_RAMP)/(FL_NUM_GRAY-1.0)); + if (!b) b = 1; else if (b==255) b = 254; + double powb = log(b/255.0)/log((FL_GRAY-FL_GRAY_RAMP)/(FL_NUM_GRAY-1.0)); + for (int i = 0; i < FL_NUM_GRAY; i++) { + double gray = i/(FL_NUM_GRAY-1.0); + cmap[i+FL_GRAY_RAMP][0] = uchar(pow(gray,powr)*255+.5); + cmap[i+FL_GRAY_RAMP][1] = uchar(pow(gray,powg)*255+.5); + cmap[i+FL_GRAY_RAMP][2] = uchar(pow(gray,powb)*255+.5); + } +} + +int main() { + int i,r,g,b; +#if 0 + /* Read colormap colors into internal table */ + long cmwin; + noport(); + cmwin = winopen("CM"); + for (i=0; i<256; i++) + getmcolor(i,&cmap[i][0],&cmap[i][1],&cmap[i][2]); + winclose(cmwin); +#endif +// overwrite the X allocation area with one color so people are +// discouraged from using it: + //for (i=16; i<32; i++) {cmap[i][0]=cmap[i][1]=cmap[i][2] = 85;} + + // fill in the gray ramp: + background(0xc0, 0xc0, 0xc0); // microsoft colors + // background(170, 170, 170); // old fltk colors + // copy the 1/3 and 2/3 gray to the closest locations in gray ramp: + cmap[39][0] = cmap[39][1] = cmap[39][2] = 85; + cmap[47][0] = cmap[47][1] = cmap[47][2] = 170; + + // fill in the color cube + i = 56; + for (b=0; b<5; b++) + for (r=0; r<5; r++) + for (g=0; g<8; g++) { + cmap[i][0] = r*255/4; + cmap[i][1] = g*255/7; + cmap[i][2] = b*255/4; + i++; + } + + for (i=0; i<256; i++) { + printf("\t0x%02x%02x%02x00",cmap[i][0],cmap[i][1],cmap[i][2]); + if (i < 255) printf(",\n"); + } + printf("\n"); + return 0; +} + +// +// End of "$Id: cmap.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/d1.xbm b/third_party/windows/fltk-1.1.10/src/d1.xbm new file mode 100644 index 0000000..7bb1232 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/d1.xbm @@ -0,0 +1,6 @@ +#define d1_width 16 +#define d1_height 16 +static unsigned char d1_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x38, 0x00, 0x78, 0x00, + 0xe8, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x1c, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/third_party/windows/fltk-1.1.10/src/d1_mask.xbm b/third_party/windows/fltk-1.1.10/src/d1_mask.xbm new file mode 100644 index 0000000..6cbaca8 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/d1_mask.xbm @@ -0,0 +1,6 @@ +#define d1_mask_width 16 +#define d1_mask_height 16 +static unsigned char d1_mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x7c, 0x00, 0xfc, 0x00, + 0xfc, 0x01, 0xec, 0x03, 0xc0, 0x37, 0x80, 0x3f, 0x00, 0x3f, 0x00, 0x3e, + 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00}; diff --git a/third_party/windows/fltk-1.1.10/src/dump_compose.c b/third_party/windows/fltk-1.1.10/src/dump_compose.c new file mode 100644 index 0000000..94c4e44 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/dump_compose.c @@ -0,0 +1,26 @@ +/* write out the documentation for the compose key */ + +/* copy the string from Fl_Input.C */ +static const char* const compose_pairs = +" ! @ # $ y=| & : c a <<~ - r _ * +-2 3 ' u p . , 1 o >>141234? " +"A`A'A^A~A:A*AEC,E`E'E^E:I`I'I^I:D-N~O`O'O^O~O:x O/U`U'U^U:Y'DDss" +"a`a'a^a~a:a*aec,e`e'e^e:i`i'i^i:d-n~o`o'o^o~o:-:o/u`u'u^u:y'ddy:"; + +#include + +int main() { + int x,y; + for (x = 0; x<16; x++) { + for (y = 0; y<6; y++) { + const char *p = compose_pairs + (16*y+x)*2; + if (p[1] == ' ') + printf("%c    %c\n", + p[0],(p-compose_pairs)/2+0xA0); + else + printf("%c%c   %c\n", + p[0],p[1],(p-compose_pairs)/2+0xA0); + } + printf(""); + } + return 0; +} diff --git a/third_party/windows/fltk-1.1.10/src/ew.xbm b/third_party/windows/fltk-1.1.10/src/ew.xbm new file mode 100644 index 0000000..0994e9c --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/ew.xbm @@ -0,0 +1,8 @@ +#define ew_width 16 +#define ew_height 16 +#define ew_x_hot 8 +#define ew_y_hot 8 +static unsigned char ew_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, + 0x0c, 0x30, 0xfe, 0x7f, 0xfe, 0x7f, 0x0c, 0x30, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/third_party/windows/fltk-1.1.10/src/ew_mask.xbm b/third_party/windows/fltk-1.1.10/src/ew_mask.xbm new file mode 100644 index 0000000..e0c6898 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/ew_mask.xbm @@ -0,0 +1,8 @@ +#define ew_mask_width 16 +#define ew_mask_height 16 +#define ew_mask_x_hot 8 +#define ew_mask_y_hot 8 +static unsigned char ew_mask_bits[] = { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x1c, 0x38, + 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x1c, 0x38, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; diff --git a/third_party/windows/fltk-1.1.10/src/fastarrow.h b/third_party/windows/fltk-1.1.10/src/fastarrow.h new file mode 100644 index 0000000..f662930 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fastarrow.h @@ -0,0 +1,6 @@ +#define fastarrow_width 16 +#define fastarrow_height 16 +static unsigned char fastarrow_bits[] = { + 0x00, 0x00, 0x00, 0x07, 0xe0, 0x07, 0xfc, 0x03, 0xff, 0xff, 0xfc, 0x03, + 0xe0, 0x07, 0x00, 0x07, 0xe0, 0x00, 0xe0, 0x07, 0xc0, 0x3f, 0xff, 0xff, + 0xc0, 0x3f, 0xe0, 0x07, 0xe0, 0x00, 0x00, 0x00}; diff --git a/third_party/windows/fltk-1.1.10/src/filename_absolute.cxx b/third_party/windows/fltk-1.1.10/src/filename_absolute.cxx new file mode 100644 index 0000000..202519c --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/filename_absolute.cxx @@ -0,0 +1,212 @@ +// +// "$Id: filename_absolute.cxx 6644 2009-01-23 10:47:53Z AlbrechtS $" +// +// Filename expansion routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +/* expand a file name by prepending current directory, deleting . and + .. (not really correct for symbolic links) between the prepended + current directory. Use $PWD if it exists. + Returns true if any changes were made. +*/ + +#include +#include +#include "flstring.h" +#include +#if defined(WIN32) && !defined(__CYGWIN__) +# include +// Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs +// on Windows, which is supposed to be POSIX compliant... +# define getcwd _getcwd +#else +# include +# ifdef __EMX__ +# define getcwd _getcwd2 +# endif +#endif + +#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) +inline int isdirsep(char c) {return c=='/' || c=='\\';} +#else +#define isdirsep(c) ((c)=='/') +#endif + +int fl_filename_absolute(char *to, int tolen, const char *from) { + if (isdirsep(*from) || *from == '|' +#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) + || from[1]==':' +#endif + ) { + strlcpy(to, from, tolen); + return 0; + } + + char *a; + char *temp = new char[tolen]; + const char *start = from; + + a = getcwd(temp, tolen); + if (!a) { + strlcpy(to, from, tolen); + delete[] temp; + return 0; + } +#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) + for (a = temp; *a; a++) if (*a=='\\') *a = '/'; // ha ha +#else + a = temp+strlen(temp); +#endif + if (isdirsep(*(a-1))) a--; + /* remove intermediate . and .. names: */ + while (*start == '.') { + if (start[1]=='.' && isdirsep(start[2])) { + char *b; + for (b = a-1; b >= temp && !isdirsep(*b); b--); + if (b < temp) break; + a = b; + start += 3; + } else if (isdirsep(start[1])) { + start += 2; + } else if (!start[1]) { + start ++; // Skip lone "." + break; + } else + break; + } + + *a++ = '/'; + strlcpy(a,start,tolen - (a - temp)); + + strlcpy(to, temp, tolen); + + delete[] temp; + + return 1; +} + +/* + * 'fl_filename_relative()' - Make a filename relative to the current working directory. + */ + +int // O - 0 if no change, 1 if changed +fl_filename_relative(char *to, // O - Relative filename + int tolen, // I - Size of "to" buffer + const char *from) {// I - Absolute filename + char *newslash; // Directory separator + const char *slash; // Directory separator + char cwd_buf[1024]; // Current directory + char *cwd = cwd_buf; + + + // return if "from" is not an absolute path +#if defined(WIN32) || defined(__EMX__) + if (from[0] == '\0' || + (!isdirsep(*from) && !isalpha(*from) && from[1] != ':' && + !isdirsep(from[2]))) { +#else + if (from[0] == '\0' || !isdirsep(*from)) { +#endif // WIN32 || __EMX__ + strlcpy(to, from, tolen); + return 0; + } + + // get the current directory and return if we can't + if (!getcwd(cwd_buf, sizeof(cwd_buf))) { + strlcpy(to, from, tolen); + return 0; + } + +#if defined(WIN32) || defined(__EMX__) + // convert all backslashes into forward slashes + for (newslash = strchr(cwd, '\\'); newslash; newslash = strchr(newslash + 1, '\\')) + *newslash = '/'; + + // test for the exact same string and return "." if so + if (!strcasecmp(from, cwd)) { + strlcpy(to, ".", tolen); + return (1); + } + + // test for the same drive. Return the absolute path if not + if (tolower(*from & 255) != tolower(*cwd & 255)) { + strlcpy(to, from, tolen); + return 0; + } + + // compare the path name without the drive prefix + from += 2; cwd += 2; +#else + // test for the exact same string and return "." if so + if (!strcmp(from, cwd)) { + strlcpy(to, ".", tolen); + return (1); + } +#endif // WIN32 || __EMX__ + + // compare both path names until we find a difference + for (slash = from, newslash = cwd; + *slash != '\0' && *newslash != '\0'; + slash ++, newslash ++) + if (isdirsep(*slash) && isdirsep(*newslash)) continue; +#if defined(WIN32) || defined(__EMX__) || defined(__APPLE__) + else if (tolower(*slash & 255) != tolower(*newslash & 255)) break; +#else + else if (*slash != *newslash) break; +#endif // WIN32 || __EMX__ || __APPLE__ + + // skip over trailing slashes + if ( *newslash == '\0' && *slash != '\0' && !isdirsep(*slash) + &&(newslash==cwd || !isdirsep(newslash[-1])) ) + newslash--; + + // now go back to the first character of the first differing paths segment + while (!isdirsep(*slash) && slash > from) slash --; + if (isdirsep(*slash)) slash ++; + + // do the same for the current dir + if (*newslash != '\0') + while (!isdirsep(*newslash) && newslash > cwd) newslash --; + + // prepare the destination buffer + to[0] = '\0'; + to[tolen - 1] = '\0'; + + // now add a "previous dir" sequence for every following slash in the cwd + while (*newslash != '\0') { + if (isdirsep(*newslash)) strlcat(to, "../", tolen); + + newslash ++; + } + + // finally add the differing path from "from" + strlcat(to, slash, tolen); + + return 1; +} + + +// +// End of "$Id: filename_absolute.cxx 6644 2009-01-23 10:47:53Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/filename_expand.cxx b/third_party/windows/fltk-1.1.10/src/filename_expand.cxx new file mode 100644 index 0000000..e1c14c3 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/filename_expand.cxx @@ -0,0 +1,110 @@ +// +// "$Id: filename_expand.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Filename expansion routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +/* expand a file name by substuting environment variables and + home directories. Returns true if any changes were made. + to & from may be the same buffer. +*/ + +#include +#include +#include "flstring.h" +#if defined(WIN32) && !defined(__CYGWIN__) +#else +# include +# include +#endif + +#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) +static inline int isdirsep(char c) {return c=='/' || c=='\\';} +#else +#define isdirsep(c) ((c)=='/') +#endif + +int fl_filename_expand(char *to,int tolen, const char *from) { + + char *temp = new char[tolen]; + strlcpy(temp,from, tolen); + char *start = temp; + char *end = temp+strlen(temp); + + int ret = 0; + + for (char *a=temp; apw_dir; +#endif + } + break; + case '$': /* an environment variable */ + {char t = *e; *(char *)e = 0; value = getenv(a+1); *(char *)e = t;} + break; + } + if (value) { + // substitutions that start with slash delete everything before them: + if (isdirsep(value[0])) start = a; +#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) + // also if it starts with "A:" + if (value[0] && value[1]==':') start = a; +#endif + int t = strlen(value); if (isdirsep(value[t-1])) t--; + if ((end+1-e+t) >= tolen) end += tolen - (end+1-e+t); + memmove(a+t, e, end+1-e); + end = a+t+(end-e); + *end = '\0'; + memcpy(a, value, t); + ret++; + } else { + a = e+1; +#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) + if (*e == '\\') {*e = '/'; ret++;} // ha ha! +#endif + } + } + + strlcpy(to, start, tolen); + + delete[] temp; + + return ret; +} + + +// +// End of "$Id: filename_expand.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/filename_ext.cxx b/third_party/windows/fltk-1.1.10/src/filename_ext.cxx new file mode 100644 index 0000000..45f57c4 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/filename_ext.cxx @@ -0,0 +1,47 @@ +// +// "$Id: filename_ext.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Filename extension routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// returns pointer to the last '.' or to the null if none: + +#include + +const char *fl_filename_ext(const char *buf) { + const char *q = 0; + const char *p = buf; + for (p=buf; *p; p++) { + if (*p == '/') q = 0; +#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) + else if (*p == '\\') q = 0; +#endif + else if (*p == '.') q = p; + } + return q ? q : p; +} + +// +// End of "$Id: filename_ext.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/filename_isdir.cxx b/third_party/windows/fltk-1.1.10/src/filename_isdir.cxx new file mode 100644 index 0000000..45216a9 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/filename_isdir.cxx @@ -0,0 +1,91 @@ +// +// "$Id: filename_isdir.cxx 5948 2007-10-07 10:12:32Z matt $" +// +// Directory detection routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Used by fl_file_chooser + +#include "flstring.h" +#include +#include +#include +#include + + +#if defined(WIN32) || defined(__EMX__) && !defined(__CYGWIN__) +static inline int isdirsep(char c) {return c=='/' || c=='\\';} +#else +#define isdirsep(c) ((c)=='/') +#endif + +int _fl_filename_isdir_quick(const char* n) { + // Do a quick optimization for filenames with a trailing slash... + if (*n && isdirsep(n[strlen(n) - 1])) return 1; + return fl_filename_isdir(n); +} + +int fl_filename_isdir(const char* n) { + struct stat s; + char fn[1024]; + int length; + + length = strlen(n); + +#ifdef WIN32 + // This workaround brought to you by the fine folks at Microsoft! + // (read lots of sarcasm in that...) + if (length < (int)(sizeof(fn) - 1)) { + if (length < 4 && isalpha(n[0]) && n[1] == ':' && + (isdirsep(n[2]) || !n[2])) { + // Always use D:/ for drive letters + fn[0] = n[0]; + strcpy(fn + 1, ":/"); + n = fn; + } else if (length > 0 && isdirsep(n[length - 1])) { + // Strip trailing slash from name... + length --; + memcpy(fn, n, length); + fn[length] = '\0'; + n = fn; + } + } +#else + // Matt: Just in case, we strip the slash for other operating + // systems as well, avoid bugs by sloppy implementations + // of "stat". + if (length > 1 && isdirsep(n[length - 1])) { + length --; + memcpy(fn, n, length); + fn[length] = '\0'; + n = fn; + } +#endif + + return !stat(n, &s) && (s.st_mode&0170000)==0040000; +} + +// +// End of "$Id: filename_isdir.cxx 5948 2007-10-07 10:12:32Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/filename_list.cxx b/third_party/windows/fltk-1.1.10/src/filename_list.cxx new file mode 100644 index 0000000..7f4de5d --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/filename_list.cxx @@ -0,0 +1,107 @@ +// +// "$Id: filename_list.cxx 6832 2009-07-23 22:36:04Z AlbrechtS $" +// +// Filename list routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Wrapper for scandir with const-correct function prototypes. + +#include +#include "flstring.h" +#include + + +extern "C" { +#ifndef HAVE_SCANDIR + int fl_scandir (const char *dir, dirent ***namelist, + int (*select)(dirent *), + int (*compar)(dirent **, dirent **)); +# define scandir fl_scandir +#endif +} + +int fl_alphasort(struct dirent **a, struct dirent **b) { + return strcmp((*a)->d_name, (*b)->d_name); +} + +int fl_casealphasort(struct dirent **a, struct dirent **b) { + return strcasecmp((*a)->d_name, (*b)->d_name); +} + + +int fl_filename_list(const char *d, dirent ***list, + Fl_File_Sort_F *sort) { +#ifndef HAVE_SCANDIR + int n = scandir(d, list, 0, sort); +#elif defined(HAVE_SCANDIR_POSIX) + // POSIX (2008) defines the comparison function like this: + int n = scandir(d, list, 0, (int(*)(const dirent **, const dirent **))sort); +#elif defined(__osf__) + // OSF, DU 4.0x + int n = scandir(d, list, 0, (int(*)(dirent **, dirent **))sort); +#elif defined(_AIX) + // AIX is almost standard... + int n = scandir(d, list, 0, (int(*)(void*, void*))sort); +#elif !defined(__sgi) + // The vast majority of UNIX systems want the sort function to have this + // prototype, most likely so that it can be passed to qsort without any + // changes: + int n = scandir(d, list, 0, (int(*)(const void*,const void*))sort); +#else + // This version is when we define our own scandir (WIN32 and perhaps + // some Unix systems) and apparently on IRIX: + int n = scandir(d, list, 0, sort); +#endif + +#if defined(WIN32) && !defined(__CYGWIN__) + // we did this already during fl_scandir/win32 +#else + // append a '/' to all filenames that are directories + int i, dirlen = strlen(d); + char *fullname = (char*)malloc(dirlen+FL_PATH_MAX+3); // Add enough extra for two /'s and a nul + // Use memcpy for speed since we already know the length of the string... + memcpy(fullname, d, dirlen+1); + char *name = fullname + dirlen; + if (name!=fullname && name[-1]!='/') *name++ = '/'; + for (i=0; id_name); + if (de->d_name[len-1]=='/' || len>FL_PATH_MAX) continue; + // Use memcpy for speed since we already know the length of the string... + memcpy(name, de->d_name, len+1); + if (fl_filename_isdir(fullname)) { + (*list)[i] = de = (dirent*)realloc(de, de->d_name - (char*)de + len + 2); + char *dst = de->d_name + len; + *dst++ = '/'; + *dst = 0; + } + } + free(fullname); +#endif + return n; +} + +// +// End of "$Id: filename_list.cxx 6832 2009-07-23 22:36:04Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/filename_match.cxx b/third_party/windows/fltk-1.1.10/src/filename_match.cxx new file mode 100644 index 0000000..81da653 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/filename_match.cxx @@ -0,0 +1,106 @@ +// +// "$Id: filename_match.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Pattern matching routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +/* Adapted from Rich Salz. */ +#include +#include + +int fl_filename_match(const char *s, const char *p) { + int matched; + + for (;;) { + switch(*p++) { + + case '?' : // match any single character + if (!*s++) return 0; + break; + + case '*' : // match 0-n of any characters + if (!*p) return 1; // do trailing * quickly + while (!fl_filename_match(s, p)) if (!*s++) return 0; + return 1; + + case '[': { // match one character in set of form [abc-d] or [^a-b] + if (!*s) return 0; + int reverse = (*p=='^' || *p=='!'); if (reverse) p++; + matched = 0; + char last = 0; + while (*p) { + if (*p=='-' && last) { + if (*s <= *++p && *s >= last ) matched = 1; + last = 0; + } else { + if (*s == *p) matched = 1; + } + last = *p++; + if (*p==']') break; + } + if (matched == reverse) return 0; + s++; p++;} + break; + + case '{' : // {pattern1|pattern2|pattern3} + NEXTCASE: + if (fl_filename_match(s,p)) return 1; + for (matched = 0;;) { + switch (*p++) { + case '\\': if (*p) p++; break; + case '{': matched++; break; + case '}': if (!matched--) return 0; break; + case '|': case ',': if (matched==0) goto NEXTCASE; + case 0: return 0; + } + } + case '|': // skip rest of |pattern|pattern} when called recursively + case ',': + for (matched = 0; *p && matched >= 0;) { + switch (*p++) { + case '\\': if (*p) p++; break; + case '{': matched++; break; + case '}': matched--; break; + } + } + break; + case '}': + break; + + case 0: // end of pattern + return !*s; + + case '\\': // quote next character + if (*p) p++; + default: + if (tolower(*s) != tolower(*(p-1))) return 0; + s++; + break; + } + } +} + +// +// End of "$Id: filename_match.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/filename_setext.cxx b/third_party/windows/fltk-1.1.10/src/filename_setext.cxx new file mode 100644 index 0000000..8887383 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/filename_setext.cxx @@ -0,0 +1,46 @@ +// +// "$Id: filename_setext.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Filename extension routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Replace .ext with new extension +// If no . in name, append new extension +// If new extension is null, act like it is "" + +#include +#include "flstring.h" + +char *fl_filename_setext(char *buf, int buflen, const char *ext) { + char *q = (char *)fl_filename_ext(buf); + if (ext) { + strlcpy(q,ext,buflen - (q - buf)); + } else *q = 0; + return(buf); +} + + +// +// End of "$Id: filename_setext.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_arc.cxx b/third_party/windows/fltk-1.1.10/src/fl_arc.cxx new file mode 100644 index 0000000..2ff9ef0 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_arc.cxx @@ -0,0 +1,87 @@ +// +// "$Id: fl_arc.cxx 5349 2006-08-23 14:43:07Z matt $" +// +// Arc functions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Utility for drawing arcs and circles. They are added to +// the current fl_begin/fl_vertex/fl_end path. +// Incremental math implementation: + +#include +#include + +// avoid problems with some platforms that don't +// implement hypot. +static double _fl_hypot(double x, double y) { + return sqrt(x*x + y*y); +} + + +void fl_arc(double x, double y, double r, double start, double end) { + + // draw start point accurately: + + double A = start*(M_PI/180); // Initial angle (radians) + double X = r*cos(A); // Initial displacement, (X,Y) + double Y = -r*sin(A); // from center to initial point + fl_vertex(x+X,y+Y); // Insert initial point + + // Maximum arc length to approximate with chord with error <= 0.125 + + double epsilon; { + double r1 = _fl_hypot(fl_transform_dx(r,0), // Horizontal "radius" + fl_transform_dy(r,0)); + double r2 = _fl_hypot(fl_transform_dx(0,r), // Vertical "radius" + fl_transform_dy(0,r)); + + if (r1 > r2) r1 = r2; // r1 = minimum "radius" + if (r1 < 2.) r1 = 2.; // radius for circa 9 chords/circle + + epsilon = 2*acos(1.0 - 0.125/r1); // Maximum arc angle + } + A = end*(M_PI/180) - A; // Displacement angle (radians) + int i = int(ceil(fabs(A)/epsilon)); // Segments in approximation + + if (i) { + epsilon = A/i; // Arc length for equal-size steps + double cos_e = cos(epsilon); // Rotation coefficients + double sin_e = sin(epsilon); + do { + double Xnew = cos_e*X + sin_e*Y; + Y = -sin_e*X + cos_e*Y; + fl_vertex(x + (X=Xnew), y + Y); + } while (--i); + } +} + +#if 0 // portable version. X-specific one in fl_vertex.cxx +void fl_circle(double x,double y,double r) { + _fl_arc(x, y, r, r, 0, 360); +} +#endif + +// +// End of "$Id: fl_arc.cxx 5349 2006-08-23 14:43:07Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_arci.cxx b/third_party/windows/fltk-1.1.10/src/fl_arci.cxx new file mode 100644 index 0000000..1189bf2 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_arci.cxx @@ -0,0 +1,126 @@ +// +// "$Id: fl_arci.cxx 5518 2006-10-11 01:23:52Z mike $" +// +// Arc (integer) drawing functions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// "integer" circle drawing functions. These draw the limited +// circle types provided by X and NT graphics. The advantage of +// these is that small ones draw quite nicely (probably due to stored +// hand-drawn bitmaps of small circles!) and may be implemented by +// hardware and thus are fast. + +// Probably should add fl_chord. + +// 3/10/98: created + +#include +#include +#ifdef WIN32 +# include +#endif +#ifdef __APPLE__ +# include +#endif + +void fl_arc(int x,int y,int w,int h,double a1,double a2) { + if (w <= 0 || h <= 0) return; +#ifdef WIN32 + int xa = x+w/2+int(w*cos(a1/180.0*M_PI)); + int ya = y+h/2-int(h*sin(a1/180.0*M_PI)); + int xb = x+w/2+int(w*cos(a2/180.0*M_PI)); + int yb = y+h/2-int(h*sin(a2/180.0*M_PI)); + if (fabs(a1 - a2) < 90) { + if (xa == xb && ya == yb) SetPixel(fl_gc, xa, ya, fl_RGB()); + else Arc(fl_gc, x, y, x+w, y+h, xa, ya, xb, yb); + } else Arc(fl_gc, x, y, x+w, y+h, xa, ya, xb, yb); +#elif defined(__APPLE_QD__) + Rect r; r.left=x; r.right=x+w; r.top=y; r.bottom=y+h; + a1 = a2-a1; a2 = 450-a2; + FrameArc(&r, (short int)a2, (short int)a1); +#elif defined(__APPLE_QUARTZ__) + a1 = (-a1)/180.0f*M_PI; a2 = (-a2)/180.0f*M_PI; + float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f; + if (w!=h) { + CGContextSaveGState(fl_gc); + CGContextTranslateCTM(fl_gc, cx, cy); + CGContextScaleCTM(fl_gc, w-1.0f, h-1.0f); + CGContextAddArc(fl_gc, 0, 0, 0.5, a1, a2, 1); + CGContextRestoreGState(fl_gc); + } else { + float r = (w+h)*0.25f-0.5f; + CGContextAddArc(fl_gc, cx, cy, r, a1, a2, 1); + } + CGContextStrokePath(fl_gc); +#else + XDrawArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64)); +#endif +} + +void fl_pie(int x,int y,int w,int h,double a1,double a2) { + if (w <= 0 || h <= 0) return; +#ifdef WIN32 + if (a1 == a2) return; + int xa = x+w/2+int(w*cos(a1/180.0*M_PI)); + int ya = y+h/2-int(h*sin(a1/180.0*M_PI)); + int xb = x+w/2+int(w*cos(a2/180.0*M_PI)); + int yb = y+h/2-int(h*sin(a2/180.0*M_PI)); + SelectObject(fl_gc, fl_brush()); + if (fabs(a1 - a2) < 90) { + if (xa == xb && ya == yb) { + MoveToEx(fl_gc, x+w/2, y+h/2, 0L); + LineTo(fl_gc, xa, ya); + SetPixel(fl_gc, xa, ya, fl_RGB()); + } else Pie(fl_gc, x, y, x+w, y+h, xa, ya, xb, yb); + } else Pie(fl_gc, x, y, x+w, y+h, xa, ya, xb, yb); +#elif defined(__APPLE_QD__) + Rect r; r.left=x; r.right=x+w; r.top=y; r.bottom=y+h; + a1 = a2-a1; a2 = 450-a2; + PaintArc(&r, (short int)a2, (short int)a1); +#elif defined(__APPLE_QUARTZ__) + a1 = (-a1)/180.0f*M_PI; a2 = (-a2)/180.0f*M_PI; + float cx = x + 0.5f*w - 0.5f, cy = y + 0.5f*h - 0.5f; + if (w!=h) { + CGContextSaveGState(fl_gc); + CGContextTranslateCTM(fl_gc, cx, cy); + CGContextScaleCTM(fl_gc, w, h); + CGContextAddArc(fl_gc, 0, 0, 0.5, a1, a2, 1); + CGContextAddLineToPoint(fl_gc, 0, 0); + CGContextClosePath(fl_gc); + CGContextRestoreGState(fl_gc); + } else { + float r = (w+h)*0.25f; + CGContextAddArc(fl_gc, cx, cy, r, a1, a2, 1); + CGContextAddLineToPoint(fl_gc, cx, cy); + CGContextClosePath(fl_gc); + } + CGContextFillPath(fl_gc); +#else + XFillArc(fl_display, fl_window, fl_gc, x,y,w-1,h-1, int(a1*64),int((a2-a1)*64)); +#endif +} + +// +// End of "$Id: fl_arci.cxx 5518 2006-10-11 01:23:52Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_ask.cxx b/third_party/windows/fltk-1.1.10/src/fl_ask.cxx new file mode 100644 index 0000000..8328566 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_ask.cxx @@ -0,0 +1,396 @@ +// +// "$Id: fl_ask.cxx 6870 2009-09-13 22:02:30Z AlbrechtS $" +// +// Standard dialog functions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Implementation of fl_message, fl_ask, fl_choice, fl_input +// The three-message fl_show_x functions are for forms compatibility +// mostly. In most cases it is easier to get a multi-line message +// by putting newlines in the message. + +#include +#include +#include "flstring.h" + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +static Fl_Window *message_form; +static Fl_Box *message; +static Fl_Box *icon; +static Fl_Button *button[3]; +static Fl_Input *input; +static const char *iconlabel = "?"; +Fl_Font fl_message_font_ = FL_HELVETICA; +uchar fl_message_size_ = 14; + +static char avoidRecursion = 0; + +static Fl_Window *makeform() { + if (message_form) { + message_form->size(410,103); + return message_form; + } + // make sure that the dialog does not become the child of some + // current group + Fl_Group *previously_current_group = Fl_Group::current(); + Fl_Group::current(0); + // create a new top level window + Fl_Window *w = message_form = new Fl_Window(410,103,""); + // w->clear_border(); + // w->box(FL_UP_BOX); + (message = new Fl_Box(60, 25, 340, 20)) + ->align(FL_ALIGN_LEFT|FL_ALIGN_INSIDE|FL_ALIGN_WRAP); + (input = new Fl_Input(60, 37, 340, 23))->hide(); + {Fl_Box* o = icon = new Fl_Box(10, 10, 50, 50); + o->box(FL_THIN_UP_BOX); + o->labelfont(FL_TIMES_BOLD); + o->labelsize(34); + o->color(FL_WHITE); + o->labelcolor(FL_BLUE); + } + button[0] = new Fl_Button(310, 70, 90, 23); + button[0]->shortcut(FL_Escape); + button[0]->align(FL_ALIGN_INSIDE|FL_ALIGN_WRAP); + button[1] = new Fl_Return_Button(210, 70, 90, 23); + button[1]->align(FL_ALIGN_INSIDE|FL_ALIGN_WRAP); + button[2] = new Fl_Button(110, 70, 90, 23); + button[2]->align(FL_ALIGN_INSIDE|FL_ALIGN_WRAP); + w->resizable(new Fl_Box(60,10,110-60,27)); + w->end(); + w->set_modal(); + Fl_Group::current(previously_current_group); + return w; +} + +/* + * 'resizeform()' - Resize the form and widgets so that they hold everything + * that is asked of them... + */ + +void resizeform() { + int i; + int message_w, message_h; + int text_height; + int button_w[3], button_h[3]; + int x, w, h, max_w, max_h; + const int icon_size = 50; + + fl_font(fl_message_font_, fl_message_size_); + message_w = message_h = 0; + fl_measure(message->label(), message_w, message_h); + + message_w += 10; + message_h += 10; + if (message_w < 340) + message_w = 340; + if (message_h < 30) + message_h = 30; + + fl_font(button[0]->labelfont(), button[0]->labelsize()); + + memset(button_w, 0, sizeof(button_w)); + memset(button_h, 0, sizeof(button_h)); + + for (max_h = 25, i = 0; i < 3; i ++) + if (button[i]->visible()) + { + fl_measure(button[i]->label(), button_w[i], button_h[i]); + + if (i == 1) + button_w[1] += 20; + + button_w[i] += 30; + button_h[i] += 10; + + if (button_h[i] > max_h) + max_h = button_h[i]; + } + + if (input->visible()) text_height = message_h + 25; + else text_height = message_h; + + max_w = message_w + 10 + icon_size; + w = button_w[0] + button_w[1] + button_w[2] - 10; + + if (w > max_w) + max_w = w; + + message_w = max_w - 10 - icon_size; + + w = max_w + 20; + h = max_h + 30 + text_height; + + message_form->size(w, h); + message_form->size_range(w, h, w, h); + + message->resize(20 + icon_size, 10, message_w, message_h); + icon->resize(10, 10, icon_size, icon_size); + icon->labelsize((uchar)(icon_size - 10)); + input->resize(20 + icon_size, 10 + message_h, message_w, 25); + + for (x = w, i = 0; i < 3; i ++) + if (button_w[i]) + { + x -= button_w[i]; + button[i]->resize(x, h - 10 - max_h, button_w[i] - 10, max_h); + +// printf("button %d (%s) is %dx%d+%d,%d\n", i, button[i]->label(), +// button[i]->w(), button[i]->h(), +// button[i]->x(), button[i]->y()); + } +} + +static int innards(const char* fmt, va_list ap, + const char *b0, + const char *b1, + const char *b2) +{ + Fl::pushed(0); // stop dragging (STR #2159) + + avoidRecursion = 1; + + makeform(); + char buffer[1024]; + if (!strcmp(fmt,"%s")) { + message->label(va_arg(ap, const char*)); + } else { + //: matt: MacOS provides two equally named vsnprintf's... + ::vsnprintf(buffer, 1024, fmt, ap); + message->label(buffer); + } + + message->labelfont(fl_message_font_); + message->labelsize(fl_message_size_); + if (b0) {button[0]->show(); button[0]->label(b0); button[1]->position(210,70);} + else {button[0]->hide(); button[1]->position(310,70);} + if (b1) {button[1]->show(); button[1]->label(b1);} + else button[1]->hide(); + if (b2) {button[2]->show(); button[2]->label(b2);} + else button[2]->hide(); + const char* prev_icon_label = icon->label(); + if (!prev_icon_label) icon->label(iconlabel); + + resizeform(); + + if (button[1]->visible() && !input->visible()) + button[1]->take_focus(); + message_form->hotspot(button[0]); + if (b0 && Fl_Widget::label_shortcut(b0)) + button[0]->shortcut(0); + else + button[0]->shortcut(FL_Escape); + + message_form->show(); + // deactivate Fl::grab(), because it is incompatible with Fl::readqueue() + Fl_Window* g = Fl::grab(); + if (g) Fl::grab(0); + int r = 0; + for (;;) { + Fl_Widget *o = Fl::readqueue(); + if (!o) Fl::wait(); + else if (o == button[0]) {r = 0; break;} + else if (o == button[1]) {r = 1; break;} + else if (o == button[2]) {r = 2; break;} + else if (o == message_form) {r = 0; break;} + } + if (g) // regrab the previous popup menu, if there was one + Fl::grab(g); + message_form->hide(); + icon->label(prev_icon_label); + + avoidRecursion = 0; + return r; +} + +// pointers you can use to change FLTK to a foreign language: +const char* fl_no = "No"; +const char* fl_yes= "Yes"; +const char* fl_ok = "OK"; +const char* fl_cancel= "Cancel"; +const char* fl_close= "Close"; + +// fltk functions: +void fl_beep(int type) { +#ifdef WIN32 + switch (type) { + case FL_BEEP_QUESTION : + case FL_BEEP_PASSWORD : + MessageBeep(MB_ICONQUESTION); + break; + case FL_BEEP_MESSAGE : + MessageBeep(MB_ICONASTERISK); + break; + case FL_BEEP_NOTIFICATION : + MessageBeep(MB_ICONASTERISK); + break; + case FL_BEEP_ERROR : + MessageBeep(MB_ICONERROR); + break; + default : + MessageBeep(0xFFFFFFFF); + break; + } +#elif defined(__APPLE__) + switch (type) { + case FL_BEEP_DEFAULT : + case FL_BEEP_ERROR : + SysBeep(30); + break; + default : + break; + } +#else + switch (type) { + case FL_BEEP_DEFAULT : + case FL_BEEP_ERROR : + if (!fl_display) fl_open_display(); + + XBell(fl_display, 100); + break; + default : + if (!fl_display) fl_open_display(); + + XBell(fl_display, 50); + break; + } +#endif // WIN32 +} + +void fl_message(const char *fmt, ...) { + + if (avoidRecursion) return; + + va_list ap; + + fl_beep(FL_BEEP_MESSAGE); + + va_start(ap, fmt); + iconlabel = "i"; + innards(fmt, ap, 0, fl_close, 0); + va_end(ap); + iconlabel = "?"; +} + +void fl_alert(const char *fmt, ...) { + + if (avoidRecursion) return; + + va_list ap; + + fl_beep(FL_BEEP_ERROR); + + va_start(ap, fmt); + iconlabel = "!"; + innards(fmt, ap, 0, fl_close, 0); + va_end(ap); + iconlabel = "?"; +} + +int fl_ask(const char *fmt, ...) { + + if (avoidRecursion) return 0; + + va_list ap; + + fl_beep(FL_BEEP_QUESTION); + + va_start(ap, fmt); + int r = innards(fmt, ap, fl_no, fl_yes, 0); + va_end(ap); + + return r; +} + +int fl_choice(const char*fmt,const char *b0,const char *b1,const char *b2,...){ + + if (avoidRecursion) return 0; + + va_list ap; + + fl_beep(FL_BEEP_QUESTION); + + va_start(ap, b2); + int r = innards(fmt, ap, b0, b1, b2); + va_end(ap); + return r; +} + +Fl_Widget *fl_message_icon() {makeform(); return icon;} + +static const char* input_innards(const char* fmt, va_list ap, + const char* defstr, uchar type) { + makeform(); + message->position(60,10); + input->type(type); + input->show(); + input->value(defstr); + input->take_focus(); + + int r = innards(fmt, ap, fl_cancel, fl_ok, 0); + input->hide(); + message->position(60,25); + return r ? input->value() : 0; +} + +const char* fl_input(const char *fmt, const char *defstr, ...) { + + if (avoidRecursion) return 0; + + fl_beep(FL_BEEP_QUESTION); + + va_list ap; + va_start(ap, defstr); + const char* r = input_innards(fmt, ap, defstr, FL_NORMAL_INPUT); + va_end(ap); + return r; +} + +const char *fl_password(const char *fmt, const char *defstr, ...) { + + if (avoidRecursion) return 0; + + fl_beep(FL_BEEP_PASSWORD); + + va_list ap; + va_start(ap, defstr); + const char* r = input_innards(fmt, ap, defstr, FL_SECRET_INPUT); + va_end(ap); + return r; +} + +// +// End of "$Id: fl_ask.cxx 6870 2009-09-13 22:02:30Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_boxtype.cxx b/third_party/windows/fltk-1.1.10/src/fl_boxtype.cxx new file mode 100644 index 0000000..f0d1e05 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_boxtype.cxx @@ -0,0 +1,322 @@ +// +// "$Id: fl_boxtype.cxx 5505 2006-10-03 02:35:12Z mike $" +// +// Box drawing code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Box drawing code for the common box types and the table of +// boxtypes. Other box types are in seperate files so they are not +// linked in if not used. + +#include +#include +#include +#include + +//////////////////////////////////////////////////////////////// + +static uchar active_ramp[24] = { + FL_GRAY_RAMP+0, FL_GRAY_RAMP+1, FL_GRAY_RAMP+2, FL_GRAY_RAMP+3, + FL_GRAY_RAMP+4, FL_GRAY_RAMP+5, FL_GRAY_RAMP+6, FL_GRAY_RAMP+7, + FL_GRAY_RAMP+8, FL_GRAY_RAMP+9, FL_GRAY_RAMP+10,FL_GRAY_RAMP+11, + FL_GRAY_RAMP+12,FL_GRAY_RAMP+13,FL_GRAY_RAMP+14,FL_GRAY_RAMP+15, + FL_GRAY_RAMP+16,FL_GRAY_RAMP+17,FL_GRAY_RAMP+18,FL_GRAY_RAMP+19, + FL_GRAY_RAMP+20,FL_GRAY_RAMP+21,FL_GRAY_RAMP+22,FL_GRAY_RAMP+23}; +static uchar inactive_ramp[24] = { + 43, 43, 44, 44, + 44, 45, 45, 46, + 46, 46, 47, 47, + 48, 48, 48, 49, + 49, 49, 50, 50, + 51, 51, 52, 52}; +static int draw_it_active = 1; + +int Fl::draw_box_active() { return draw_it_active; } + +uchar *fl_gray_ramp() {return (draw_it_active?active_ramp:inactive_ramp)-'A';} + +void fl_frame(const char* s, int x, int y, int w, int h) { + uchar *g = fl_gray_ramp(); + if (h > 0 && w > 0) for (;*s;) { + // draw top line: + fl_color(g[*s++]); + fl_xyline(x, y, x+w-1); + y++; if (--h <= 0) break; + // draw left line: + fl_color(g[*s++]); + fl_yxline(x, y+h-1, y); + x++; if (--w <= 0) break; + // draw bottom line: + fl_color(g[*s++]); + fl_xyline(x, y+h-1, x+w-1); + if (--h <= 0) break; + // draw right line: + fl_color(g[*s++]); + fl_yxline(x+w-1, y+h-1, y); + if (--w <= 0) break; + } +} + +void fl_frame2(const char* s, int x, int y, int w, int h) { + uchar *g = fl_gray_ramp(); + if (h > 0 && w > 0) for (;*s;) { + // draw bottom line: + fl_color(g[*s++]); + fl_xyline(x, y+h-1, x+w-1); + if (--h <= 0) break; + // draw right line: + fl_color(g[*s++]); + fl_yxline(x+w-1, y+h-1, y); + if (--w <= 0) break; + // draw top line: + fl_color(g[*s++]); + fl_xyline(x, y, x+w-1); + y++; if (--h <= 0) break; + // draw left line: + fl_color(g[*s++]); + fl_yxline(x, y+h-1, y); + x++; if (--w <= 0) break; + } +} + +void fl_no_box(int, int, int, int, Fl_Color) {} + +void fl_thin_down_frame(int x, int y, int w, int h, Fl_Color) { + fl_frame2("WWHH",x,y,w,h); +} + +void fl_thin_down_box(int x, int y, int w, int h, Fl_Color c) { + fl_thin_down_frame(x,y,w,h,c); + fl_color(draw_it_active ? c : fl_inactive(c)); + fl_rectf(x+1, y+1, w-2, h-2); +} + +void fl_thin_up_frame(int x, int y, int w, int h, Fl_Color) { + fl_frame2("HHWW",x,y,w,h); +} + +void fl_thin_up_box(int x, int y, int w, int h, Fl_Color c) { + fl_thin_up_frame(x,y,w,h,c); + fl_color(draw_it_active ? c : fl_inactive(c)); + fl_rectf(x+1, y+1, w-2, h-2); +} + +void fl_up_frame(int x, int y, int w, int h, Fl_Color) { +#if BORDER_WIDTH == 1 + fl_frame2("HHWW",x,y,w,h); +#else +#if BORDER_WIDTH == 2 + fl_frame2("AAWWMMTT",x,y,w,h); +#else + fl_frame("AAAAWWJJUTNN",x,y,w,h); +#endif +#endif +} + +#define D1 BORDER_WIDTH +#define D2 (BORDER_WIDTH+BORDER_WIDTH) + +void fl_up_box(int x, int y, int w, int h, Fl_Color c) { + fl_up_frame(x,y,w,h,c); + fl_color(draw_it_active ? c : fl_inactive(c)); + fl_rectf(x+D1, y+D1, w-D2, h-D2); +} + +void fl_down_frame(int x, int y, int w, int h, Fl_Color) { +#if BORDER_WIDTH == 1 + fl_frame2("WWHH",x,y,w,h); +#else +#if BORDER_WIDTH == 2 + fl_frame2("WWMMPPAA",x,y,w,h); +#else + fl_frame("NNTUJJWWAAAA",x,y,w,h); +#endif +#endif +} + +void fl_down_box(int x, int y, int w, int h, Fl_Color c) { + fl_down_frame(x,y,w,h,c); + fl_color(c); fl_rectf(x+D1, y+D1, w-D2, h-D2); +} + +void fl_engraved_frame(int x, int y, int w, int h, Fl_Color) { + fl_frame("HHWWWWHH",x,y,w,h); +} + +void fl_engraved_box(int x, int y, int w, int h, Fl_Color c) { + fl_engraved_frame(x,y,w,h,c); + fl_color(draw_it_active ? c : fl_inactive(c)); + fl_rectf(x+2, y+2, w-4, h-4); +} + +void fl_embossed_frame(int x, int y, int w, int h, Fl_Color) { + fl_frame("WWHHHHWW",x,y,w,h); +} + +void fl_embossed_box(int x, int y, int w, int h, Fl_Color c) { + fl_embossed_frame(x,y,w,h,c); + fl_color(draw_it_active ? c : fl_inactive(c)); + fl_rectf(x+2, y+2, w-4, h-4); +} + +void fl_rectbound(int x, int y, int w, int h, Fl_Color bgcolor) { + fl_color(draw_it_active ? FL_BLACK : fl_inactive(FL_BLACK)); + fl_rect(x, y, w, h); + fl_color(draw_it_active ? bgcolor : fl_inactive(bgcolor)); + fl_rectf(x+1, y+1, w-2, h-2); +} +#define fl_border_box fl_rectbound + +void fl_border_frame(int x, int y, int w, int h, Fl_Color c) { + fl_color(draw_it_active ? c : fl_inactive(c)); + fl_rect(x, y, w, h); +} + +//////////////////////////////////////////////////////////////// + +static struct { + Fl_Box_Draw_F *f; + uchar dx, dy, dw, dh; + int set; +} fl_box_table[256] = { +// must match list in Enumerations.H!!! + {fl_no_box, 0,0,0,0,1}, + {fl_rectf, 0,0,0,0,1}, // FL_FLAT_BOX + {fl_up_box, D1,D1,D2,D2,1}, + {fl_down_box, D1,D1,D2,D2,1}, + {fl_up_frame, D1,D1,D2,D2,1}, + {fl_down_frame, D1,D1,D2,D2,1}, + {fl_thin_up_box, 1,1,2,2,1}, + {fl_thin_down_box, 1,1,2,2,1}, + {fl_thin_up_frame, 1,1,2,2,1}, + {fl_thin_down_frame, 1,1,2,2,1}, + {fl_engraved_box, 2,2,4,4,1}, + {fl_embossed_box, 2,2,4,4,1}, + {fl_engraved_frame, 2,2,4,4,1}, + {fl_embossed_frame, 2,2,4,4,1}, + {fl_border_box, 1,1,2,2,1}, + {fl_border_box, 1,1,5,5,0}, // _FL_SHADOW_BOX, + {fl_border_frame, 1,1,2,2,1}, + {fl_border_frame, 1,1,5,5,0}, // _FL_SHADOW_FRAME, + {fl_border_box, 1,1,2,2,0}, // _FL_ROUNDED_BOX, + {fl_border_box, 1,1,2,2,0}, // _FL_RSHADOW_BOX, + {fl_border_frame, 1,1,2,2,0}, // _FL_ROUNDED_FRAME + {fl_rectf, 0,0,0,0,0}, // _FL_RFLAT_BOX, + {fl_up_box, 3,3,6,6,0}, // _FL_ROUND_UP_BOX + {fl_down_box, 3,3,6,6,0}, // _FL_ROUND_DOWN_BOX, + {fl_up_box, 0,0,0,0,0}, // _FL_DIAMOND_UP_BOX + {fl_down_box, 0,0,0,0,0}, // _FL_DIAMOND_DOWN_BOX + {fl_border_box, 1,1,2,2,0}, // _FL_OVAL_BOX, + {fl_border_box, 1,1,2,2,0}, // _FL_OVAL_SHADOW_BOX, + {fl_border_frame, 1,1,2,2,0}, // _FL_OVAL_FRAME + {fl_rectf, 0,0,0,0,0}, // _FL_OVAL_FLAT_BOX, + {fl_up_box, 4,4,8,8,0}, // _FL_PLASTIC_UP_BOX, + {fl_down_box, 2,2,4,4,0}, // _FL_PLASTIC_DOWN_BOX, + {fl_up_frame, 2,2,4,4,0}, // _FL_PLASTIC_UP_FRAME, + {fl_down_frame, 2,2,4,4,0}, // _FL_PLASTIC_DOWN_FRAME, + {fl_up_box, 2,2,4,4,0}, // _FL_PLASTIC_THIN_UP_BOX, + {fl_down_box, 2,2,4,4,0}, // _FL_PLASTIC_THIN_DOWN_BOX, + {fl_up_box, 2,2,4,4,0}, // _FL_PLASTIC_ROUND_UP_BOX, + {fl_down_box, 2,2,4,4,0}, // _FL_PLASTIC_ROUND_DOWN_BOX, + {fl_up_box, 2,2,4,4,0}, // _FL_GTK_UP_BOX, + {fl_down_box, 2,2,4,4,0}, // _FL_GTK_DOWN_BOX, + {fl_up_frame, 2,2,4,4,0}, // _FL_GTK_UP_FRAME, + {fl_down_frame, 2,2,4,4,0}, // _FL_GTK_DOWN_FRAME, + {fl_up_frame, 1,1,2,2,0}, // _FL_GTK_THIN_UP_FRAME, + {fl_down_frame, 1,1,2,2,0}, // _FL_GTK_THIN_DOWN_FRAME, + {fl_up_box, 1,1,2,2,0}, // _FL_GTK_THIN_ROUND_UP_BOX, + {fl_down_box, 1,1,2,2,0}, // _FL_GTK_THIN_ROUND_DOWN_BOX, + {fl_up_box, 2,2,4,4,0}, // _FL_GTK_ROUND_UP_BOX, + {fl_down_box, 2,2,4,4,0}, // _FL_GTK_ROUND_DOWN_BOX, + {fl_up_box, 3,3,6,6,0}, // FL_FREE_BOX+0 + {fl_down_box, 3,3,6,6,0}, // FL_FREE_BOX+1 + {fl_up_box, 3,3,6,6,0}, // FL_FREE_BOX+2 + {fl_down_box, 3,3,6,6,0}, // FL_FREE_BOX+3 + {fl_up_box, 3,3,6,6,0}, // FL_FREE_BOX+4 + {fl_down_box, 3,3,6,6,0}, // FL_FREE_BOX+5 + {fl_up_box, 3,3,6,6,0}, // FL_FREE_BOX+6 + {fl_down_box, 3,3,6,6,0}, // FL_FREE_BOX+7 +}; + +int Fl::box_dx(Fl_Boxtype t) {return fl_box_table[t].dx;} +int Fl::box_dy(Fl_Boxtype t) {return fl_box_table[t].dy;} +int Fl::box_dw(Fl_Boxtype t) {return fl_box_table[t].dw;} +int Fl::box_dh(Fl_Boxtype t) {return fl_box_table[t].dh;} + +void fl_internal_boxtype(Fl_Boxtype t, Fl_Box_Draw_F* f) { + if (!fl_box_table[t].set) { + fl_box_table[t].f = f; + fl_box_table[t].set = 1; + } +} + +Fl_Box_Draw_F *Fl::get_boxtype(Fl_Boxtype t) { + return fl_box_table[t].f; +} + +void Fl::set_boxtype(Fl_Boxtype t, Fl_Box_Draw_F* f, + uchar a, uchar b, uchar c, uchar d) { + fl_box_table[t].f = f; + fl_box_table[t].set = 1; + fl_box_table[t].dx = a; + fl_box_table[t].dy = b; + fl_box_table[t].dw = c; + fl_box_table[t].dh = d; +} + +void Fl::set_boxtype(Fl_Boxtype t, Fl_Boxtype f) { + fl_box_table[t] = fl_box_table[f]; +} + +void fl_draw_box(Fl_Boxtype t, int x, int y, int w, int h, Fl_Color c) { + if (t && fl_box_table[t].f) fl_box_table[t].f(x,y,w,h,c); +} + +//extern Fl_Widget *fl_boxcheat; // hack set by Fl_Window.cxx + +void Fl_Widget::draw_box() const { + int t = box_; + if (!t) return; +// if (this == fl_boxcheat) { +// fl_boxcheat = 0; +// if (t == FL_FLAT_BOX) return; +// t += 2; // convert box to frame +// } + draw_box((Fl_Boxtype)t, x_, y_, w_, h_, (Fl_Color)color_); +} + +void Fl_Widget::draw_box(Fl_Boxtype b, Fl_Color c) const { + draw_box(b, x_, y_, w_, h_, c); +} + +void Fl_Widget::draw_box(Fl_Boxtype b, int X, int Y, int W, int H, Fl_Color c) +const { + draw_it_active = active_r(); + fl_box_table[b].f(X, Y, W, H, c); + draw_it_active = 1; +} + +// +// End of "$Id: fl_boxtype.cxx 5505 2006-10-03 02:35:12Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_call_main.c b/third_party/windows/fltk-1.1.10/src/fl_call_main.c new file mode 100644 index 0000000..5865497 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_call_main.c @@ -0,0 +1,107 @@ +/* + * "$Id: fl_call_main.c 5848 2007-05-20 16:18:31Z mike $" + * + * Copyright 1998-2005 by Bill Spitzak and others. + * + * fl_call_main() calls main() for you Windows people. Needs to be done in C + * because Borland C++ won't let you call main() from C++. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems on the following page: + * + * http://www.fltk.org/str.php + */ + +/* + * This WinMain() function can be overridden by an application and + * is provided for compatibility with programs written for other + * operating systems that conform to the ANSI standard entry point + * "main()". This will allow you to build a WIN32 Application + * without any special settings. + * + * Because of problems with the Microsoft Visual C++ header files + * and/or compiler, you cannot have a WinMain function in a DLL. + * I don't know why. Thus, this nifty feature is only available + * if you link to the static library. + * + * Currently the debug version of this library will create a + * console window for your application so you can put printf() + * statements for debugging or informational purposes. Ultimately + * we want to update this to always use the parent's console, + * but at present we have not identified a function or API in + * Microsoft(r) Windows(r) that allows for it. + */ + +#if defined(WIN32) && !defined(FL_DLL) && !defined (__GNUC__) + +# include +# include +# include + +# ifdef __MWERKS__ +# include +# endif + +extern int main(int, char *[]); + +# ifdef BORLAND5 +# define __argc _argc +# define __argv _argv +# endif /* BORLAND5 */ + +int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, + LPSTR lpCmdLine, int nCmdShow) { + int rc; + +# ifdef _DEBUG + /* + * If we are using compiling in debug mode, open a console window so + * we can see any printf's, etc... + * + * While we can detect if the program was run from the command-line - + * look at the CMDLINE environment variable, it will be "WIN" for + * programs started from the GUI - the shell seems to run all WIN32 + * applications in the background anyways... + */ + + AllocConsole(); + freopen("conin$", "r", stdin); + freopen("conout$", "w", stdout); + freopen("conout$", "w", stderr); +# endif /* _DEBUG */ + + /* Run the standard main entry point function... */ + rc = main(__argc, __argv); + +# ifdef _DEBUG + fclose(stdin); + fclose(stdout); + fclose(stderr); +# endif /* _DEBUG */ + + return rc; +} + +#elif defined(__hpux) +/* This code to prevent "empty translation unit" or similar warnings... */ +static void dummy(void) {} +#endif // WIN32 && !FL_DLL && !__GNUC__ + +/* + * End of "$Id: fl_call_main.c 5848 2007-05-20 16:18:31Z mike $". + */ + diff --git a/third_party/windows/fltk-1.1.10/src/fl_cmap.h b/third_party/windows/fltk-1.1.10/src/fl_cmap.h new file mode 100644 index 0000000..19b4202 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_cmap.h @@ -0,0 +1,256 @@ + 0x00000000, + 0xff000000, + 0x00ff0000, + 0xffff0000, + 0x0000ff00, + 0xff00ff00, + 0x00ffff00, + 0xffffff00, + 0x55555500, + 0xc6717100, + 0x71c67100, + 0x8e8e3800, + 0x7171c600, + 0x8e388e00, + 0x388e8e00, + 0x00008000, + 0xa8a89800, + 0xe8e8d800, + 0x68685800, + 0x98a8a800, + 0xd8e8e800, + 0x58686800, + 0x9c9ca800, + 0xdcdce800, + 0x5c5c6800, + 0x9ca89c00, + 0xdce8dc00, + 0x5c685c00, + 0x90909000, + 0xc0c0c000, + 0x50505000, + 0xa0a0a000, + 0x00000000, + 0x0d0d0d00, + 0x1a1a1a00, + 0x26262600, + 0x31313100, + 0x3d3d3d00, + 0x48484800, + 0x55555500, + 0x5f5f5f00, + 0x6a6a6a00, + 0x75757500, + 0x80808000, + 0x8a8a8a00, + 0x95959500, + 0xa0a0a000, + 0xaaaaaa00, + 0xb5b5b500, + 0xc0c0c000, + 0xcbcbcb00, + 0xd5d5d500, + 0xe0e0e000, + 0xeaeaea00, + 0xf5f5f500, + 0xffffff00, + 0x00000000, + 0x00240000, + 0x00480000, + 0x006d0000, + 0x00910000, + 0x00b60000, + 0x00da0000, + 0x00ff0000, + 0x3f000000, + 0x3f240000, + 0x3f480000, + 0x3f6d0000, + 0x3f910000, + 0x3fb60000, + 0x3fda0000, + 0x3fff0000, + 0x7f000000, + 0x7f240000, + 0x7f480000, + 0x7f6d0000, + 0x7f910000, + 0x7fb60000, + 0x7fda0000, + 0x7fff0000, + 0xbf000000, + 0xbf240000, + 0xbf480000, + 0xbf6d0000, + 0xbf910000, + 0xbfb60000, + 0xbfda0000, + 0xbfff0000, + 0xff000000, + 0xff240000, + 0xff480000, + 0xff6d0000, + 0xff910000, + 0xffb60000, + 0xffda0000, + 0xffff0000, + 0x00003f00, + 0x00243f00, + 0x00483f00, + 0x006d3f00, + 0x00913f00, + 0x00b63f00, + 0x00da3f00, + 0x00ff3f00, + 0x3f003f00, + 0x3f243f00, + 0x3f483f00, + 0x3f6d3f00, + 0x3f913f00, + 0x3fb63f00, + 0x3fda3f00, + 0x3fff3f00, + 0x7f003f00, + 0x7f243f00, + 0x7f483f00, + 0x7f6d3f00, + 0x7f913f00, + 0x7fb63f00, + 0x7fda3f00, + 0x7fff3f00, + 0xbf003f00, + 0xbf243f00, + 0xbf483f00, + 0xbf6d3f00, + 0xbf913f00, + 0xbfb63f00, + 0xbfda3f00, + 0xbfff3f00, + 0xff003f00, + 0xff243f00, + 0xff483f00, + 0xff6d3f00, + 0xff913f00, + 0xffb63f00, + 0xffda3f00, + 0xffff3f00, + 0x00007f00, + 0x00247f00, + 0x00487f00, + 0x006d7f00, + 0x00917f00, + 0x00b67f00, + 0x00da7f00, + 0x00ff7f00, + 0x3f007f00, + 0x3f247f00, + 0x3f487f00, + 0x3f6d7f00, + 0x3f917f00, + 0x3fb67f00, + 0x3fda7f00, + 0x3fff7f00, + 0x7f007f00, + 0x7f247f00, + 0x7f487f00, + 0x7f6d7f00, + 0x7f917f00, + 0x7fb67f00, + 0x7fda7f00, + 0x7fff7f00, + 0xbf007f00, + 0xbf247f00, + 0xbf487f00, + 0xbf6d7f00, + 0xbf917f00, + 0xbfb67f00, + 0xbfda7f00, + 0xbfff7f00, + 0xff007f00, + 0xff247f00, + 0xff487f00, + 0xff6d7f00, + 0xff917f00, + 0xffb67f00, + 0xffda7f00, + 0xffff7f00, + 0x0000bf00, + 0x0024bf00, + 0x0048bf00, + 0x006dbf00, + 0x0091bf00, + 0x00b6bf00, + 0x00dabf00, + 0x00ffbf00, + 0x3f00bf00, + 0x3f24bf00, + 0x3f48bf00, + 0x3f6dbf00, + 0x3f91bf00, + 0x3fb6bf00, + 0x3fdabf00, + 0x3fffbf00, + 0x7f00bf00, + 0x7f24bf00, + 0x7f48bf00, + 0x7f6dbf00, + 0x7f91bf00, + 0x7fb6bf00, + 0x7fdabf00, + 0x7fffbf00, + 0xbf00bf00, + 0xbf24bf00, + 0xbf48bf00, + 0xbf6dbf00, + 0xbf91bf00, + 0xbfb6bf00, + 0xbfdabf00, + 0xbfffbf00, + 0xff00bf00, + 0xff24bf00, + 0xff48bf00, + 0xff6dbf00, + 0xff91bf00, + 0xffb6bf00, + 0xffdabf00, + 0xffffbf00, + 0x0000ff00, + 0x0024ff00, + 0x0048ff00, + 0x006dff00, + 0x0091ff00, + 0x00b6ff00, + 0x00daff00, + 0x00ffff00, + 0x3f00ff00, + 0x3f24ff00, + 0x3f48ff00, + 0x3f6dff00, + 0x3f91ff00, + 0x3fb6ff00, + 0x3fdaff00, + 0x3fffff00, + 0x7f00ff00, + 0x7f24ff00, + 0x7f48ff00, + 0x7f6dff00, + 0x7f91ff00, + 0x7fb6ff00, + 0x7fdaff00, + 0x7fffff00, + 0xbf00ff00, + 0xbf24ff00, + 0xbf48ff00, + 0xbf6dff00, + 0xbf91ff00, + 0xbfb6ff00, + 0xbfdaff00, + 0xbfffff00, + 0xff00ff00, + 0xff24ff00, + 0xff48ff00, + 0xff6dff00, + 0xff91ff00, + 0xffb6ff00, + 0xffdaff00, + 0xffffff00 diff --git a/third_party/windows/fltk-1.1.10/src/fl_color.cxx b/third_party/windows/fltk-1.1.10/src/fl_color.cxx new file mode 100644 index 0000000..a08fe8a --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_color.cxx @@ -0,0 +1,389 @@ +// +// "$Id: fl_color.cxx 5835 2007-05-16 11:46:07Z matt $" +// +// Color functions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Implementation of fl_color(i), fl_color(r,g,b). + +#ifdef WIN32 +# include "fl_color_win32.cxx" +#elif defined(__APPLE__) +# include "fl_color_mac.cxx" +#else + +// Also code to look at the X visual and figure out the best way to turn +// a color into a pixel value. + +// SGI compiler seems to have problems with unsigned char arguments +// being used to index arrays. So I always copy them to an integer +// before use. + +# include "Fl_XColor.H" +# include +# include +# include + +//////////////////////////////////////////////////////////////// +// figure_out_visual() calculates masks & shifts for generating +// pixels in true-color visuals: + +uchar fl_redmask, fl_greenmask, fl_bluemask; +int fl_redshift, fl_greenshift, fl_blueshift, fl_extrashift; +static uchar beenhere; + +static void figure_out_visual() { + beenhere = 1; + if (!fl_visual->red_mask || !fl_visual->green_mask || !fl_visual->blue_mask){ +# if USE_COLORMAP + fl_redmask = 0; + return; +# else + Fl::fatal("Requires true color visual"); +# endif + } + + // get the bit masks into a more useful form: + int i,j,m; + + for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->red_mask & m) break; + for (j = i; m; j++, m<<=1) if (!(fl_visual->red_mask & m)) break; + fl_redshift = j-8; + fl_redmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); + + for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->green_mask & m) break; + for (j = i; m; j++, m<<=1) if (!(fl_visual->green_mask & m)) break; + fl_greenshift = j-8; + fl_greenmask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); + + for (i = 0, m = 1; m; i++, m<<=1) if (fl_visual->blue_mask & m) break; + for (j = i; m; j++, m<<=1) if (!(fl_visual->blue_mask & m)) break; + fl_blueshift = j-8; + fl_bluemask = (j-i >= 8) ? 0xFF : 0xFF-(255>>(j-i)); + + i = fl_redshift; + if (fl_greenshift < i) i = fl_greenshift; + if (fl_blueshift < i) i = fl_blueshift; + if (i < 0) { + fl_extrashift = -i; + fl_redshift -= i; fl_greenshift -= i; fl_blueshift -= i; + } else + fl_extrashift = 0; + +} + +static unsigned fl_cmap[256] = { +#include "fl_cmap.h" // this is a file produced by "cmap.cxx": +}; + +# if HAVE_OVERLAY +Fl_XColor fl_xmap[2][256]; +uchar fl_overlay; +Colormap fl_overlay_colormap; +XVisualInfo* fl_overlay_visual; +ulong fl_transparent_pixel; +# else +Fl_XColor fl_xmap[1][256]; +# define fl_overlay 0 +# endif + +//////////////////////////////////////////////////////////////// +// Get an rgb color. This is easy for a truecolor visual. For +// colormapped it picks the closest color out of the cube in the +// fltk colormap. However if this color cube entry has been +// requested before, you will get the earlier requested color, and +// even this may be approximated if the X colormap was full. + +ulong fl_xpixel(uchar r,uchar g,uchar b) { + if (!beenhere) figure_out_visual(); +# if USE_COLORMAP + if (!fl_redmask) { + // find closest entry in the colormap: + Fl_Color i = + fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256); + Fl_XColor &xmap = fl_xmap[fl_overlay][i]; + if (xmap.mapped) return xmap.pixel; + // if not black or white, change the entry to be an exact match: + if (i != FL_COLOR_CUBE && i != 0xFF) + fl_cmap[i] = (r<<24)|(g<<16)|(b<<8); + return fl_xpixel(i); // allocate an X color + } +# endif + return + (((r&fl_redmask) << fl_redshift)+ + ((g&fl_greenmask)<> fl_extrashift; +} + +void fl_color(uchar r,uchar g,uchar b) { + fl_color_ = fl_rgb_color(r, g, b); + XSetForeground(fl_display, fl_gc, fl_xpixel(r,g,b)); +} + +//////////////////////////////////////////////////////////////// +// Get a color out of the the fltk colormap. Again for truecolor +// visuals this is easy. For colormap this actually tries to allocate +// an X color, and does a least-squares match to find the closest +// color if X cannot allocate that color. + +// calculate what color is actually on the screen for a mask: +static inline uchar realcolor(uchar color, uchar mask) { +# if 0 + // accurate version if the display has linear gamma, but fl_draw_image + // works better with the simpler version on most screens... + uchar m = mask; + uchar result = color&m; + for (;;) { + while (m&mask) {m>>=1; color>>=1;} + if (!m) break; + mask = m; + result |= color&m; + } + return result; +# else + return (color&mask) | (~mask)&(mask>>1); +# endif +} + +ulong fl_xpixel(Fl_Color i) { + if (i & 0xffffff00) { + return fl_xpixel((i >> 24) & 255, (i >> 16) & 255, (i >> 8) & 255); + } + + Fl_XColor &xmap = fl_xmap[fl_overlay][i]; + if (xmap.mapped) return xmap.pixel; + + if (!beenhere) figure_out_visual(); + + uchar r,g,b; + {unsigned c = fl_cmap[i]; r=uchar(c>>24); g=uchar(c>>16); b=uchar(c>>8);} + +# if USE_COLORMAP + Colormap colormap = fl_colormap; +# if HAVE_OVERLAY + if (fl_overlay) colormap = fl_overlay_colormap; else +# endif + if (fl_redmask) { +# endif + // return color for a truecolor visual: + xmap.mapped = 2; // 2 prevents XFreeColor from being called + xmap.r = realcolor(r, fl_redmask); + xmap.g = realcolor(g, fl_greenmask); + xmap.b = realcolor(b, fl_bluemask); + return xmap.pixel = + (((r&fl_redmask) << fl_redshift)+ + ((g&fl_greenmask)<> fl_extrashift; +# if USE_COLORMAP + } +# if HAVE_OVERLAY + static XColor* ac[2]; + XColor*& allcolors = ac[fl_overlay]; + static int nc[2]; + int& numcolors = nc[fl_overlay]; +# else + static XColor *allcolors; + static int numcolors; +# endif + + // I don't try to allocate colors with XAllocColor once it fails + // with any color. It is possible that it will work, since a color + // may have been freed, but some servers are extremely slow and this + // avoids one round trip: + if (!numcolors) { // don't try after a failure + XColor xcol; + xcol.red = r<<8; xcol.green = g<<8; xcol.blue = b<<8; + if (XAllocColor(fl_display, colormap, &xcol)) { + xmap.mapped = 1; + xmap.r = xcol.red>>8; + xmap.g = xcol.green>>8; + xmap.b = xcol.blue>>8; + return xmap.pixel = xcol.pixel; + } + + // I only read the colormap once. Again this is due to the slowness + // of round-trips to the X server, even though other programs may alter + // the colormap after this and make decisions here wrong. +# if HAVE_OVERLAY + if (fl_overlay) numcolors = fl_overlay_visual->colormap_size; else +# endif + numcolors = fl_visual->colormap_size; + if (!allcolors) allcolors = new XColor[numcolors]; + for (int p = numcolors; p--;) allcolors[p].pixel = p; + XQueryColors(fl_display, colormap, allcolors, numcolors); + } + + // find least-squares match: + int mindist = 0x7FFFFFFF; + unsigned int bestmatch = 0; + for (unsigned int n = numcolors; n--;) { +# if HAVE_OVERLAY + if (fl_overlay && n == fl_transparent_pixel) continue; +# endif + XColor &a = allcolors[n]; + int d, t; + t = int(r)-int(a.red>>8); d = t*t; + t = int(g)-int(a.green>>8); d += t*t; + t = int(b)-int(a.blue>>8); d += t*t; + if (d <= mindist) {bestmatch = n; mindist = d;} + } + XColor &p = allcolors[bestmatch]; + + // It appears to "work" to not call this XAllocColor, which will + // avoid another round-trip to the server. But then X does not + // know that this program "owns" this value, and can (and will) + // change it when the program that did allocate it exits: + if (XAllocColor(fl_display, colormap, &p)) { + xmap.mapped = 1; + xmap.pixel = p.pixel; + } else { + // However, if that XAllocColor fails, I have to give up and + // assumme the pixel is ok for the duration of the program. This + // is due to bugs (?) in the Solaris X and some X terminals + // where XAllocColor *always* fails when the colormap is full, + // even if we ask for a color already in it... + xmap.mapped = 2; // 2 prevents XFreeColor from being called + xmap.pixel = bestmatch; + } + xmap.r = p.red>>8; + xmap.g = p.green>>8; + xmap.b = p.blue>>8; + return xmap.pixel; +# endif +} + +Fl_Color fl_color_; + +void fl_color(Fl_Color i) { + if (i & 0xffffff00) { + unsigned rgb = (unsigned)i; + fl_color((uchar)(rgb >> 24), (uchar)(rgb >> 16), (uchar)(rgb >> 8)); + } else { + fl_color_ = i; + XSetForeground(fl_display, fl_gc, fl_xpixel(i)); + } +} + +void Fl::free_color(Fl_Color i, int overlay) { +# if HAVE_OVERLAY +# else + if (overlay) return; +# endif + if (fl_xmap[overlay][i].mapped) { +# if USE_COLORMAP +# if HAVE_OVERLAY + Colormap colormap = overlay ? fl_overlay_colormap : fl_colormap; +# else + Colormap colormap = fl_colormap; +# endif + if (fl_xmap[overlay][i].mapped == 1) + XFreeColors(fl_display, colormap, &(fl_xmap[overlay][i].pixel), 1, 0); +# endif + fl_xmap[overlay][i].mapped = 0; + } +} + +void Fl::set_color(Fl_Color i, unsigned c) { + if (fl_cmap[i] != c) { + free_color(i,0); +# if HAVE_OVERLAY + free_color(i,1); +# endif + fl_cmap[i] = c; + } +} + +#endif // end of X-specific code + +unsigned Fl::get_color(Fl_Color i) { + if (i & 0xffffff00) return (i); + else return fl_cmap[i]; +} + +void Fl::set_color(Fl_Color i, uchar red, uchar green, uchar blue) { + Fl::set_color((Fl_Color)(i & 255), + ((unsigned)red<<24)+((unsigned)green<<16)+((unsigned)blue<<8)); +} + +void Fl::get_color(Fl_Color i, uchar &red, uchar &green, uchar &blue) { + unsigned c; + + if (i & 0xffffff00) c = (unsigned)i; + else c = fl_cmap[i]; + + red = uchar(c>>24); + green = uchar(c>>16); + blue = uchar(c>>8); +} + +Fl_Color fl_color_average(Fl_Color color1, Fl_Color color2, float weight) { + unsigned rgb1; + unsigned rgb2; + uchar r, g, b; + + if (color1 & 0xffffff00) rgb1 = color1; + else rgb1 = fl_cmap[color1 & 255]; + + if (color2 & 0xffffff00) rgb2 = color2; + else rgb2 = fl_cmap[color2 & 255]; + + r = (uchar)(((uchar)(rgb1>>24))*weight + ((uchar)(rgb2>>24))*(1-weight)); + g = (uchar)(((uchar)(rgb1>>16))*weight + ((uchar)(rgb2>>16))*(1-weight)); + b = (uchar)(((uchar)(rgb1>>8))*weight + ((uchar)(rgb2>>8))*(1-weight)); + + return fl_rgb_color(r, g, b); +} + +Fl_Color fl_inactive(Fl_Color c) { + return fl_color_average(c, FL_GRAY, .33f); +} + +Fl_Color fl_contrast(Fl_Color fg, Fl_Color bg) { + unsigned c1, c2; // RGB colors + int l1, l2; // Luminosities + + + // Get the RGB values for each color... + if (fg & 0xffffff00) c1 = (unsigned)fg; + else c1 = fl_cmap[fg]; + + if (bg & 0xffffff00) c2 = (unsigned)bg; + else c2 = fl_cmap[bg]; + + // Compute the luminosity... + l1 = ((c1 >> 24) * 30 + ((c1 >> 16) & 255) * 59 + ((c1 >> 8) & 255) * 11) / 100; + l2 = ((c2 >> 24) * 30 + ((c2 >> 16) & 255) * 59 + ((c2 >> 8) & 255) * 11) / 100; + + // Compare and return the contrasting color... + if ((l1 - l2) > 99) return fg; + else if ((l2 - l1) > 99) return fg; + else if (l2 > 127) return FL_BLACK; + else return FL_WHITE; +} + +// +// End of "$Id: fl_color.cxx 5835 2007-05-16 11:46:07Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_color_mac.cxx b/third_party/windows/fltk-1.1.10/src/fl_color_mac.cxx new file mode 100644 index 0000000..55f3e29 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_color_mac.cxx @@ -0,0 +1,114 @@ +// +// "$Id: fl_color_mac.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// MacOS color functions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// The fltk "colormap". This allows ui colors to be stored in 8-bit +// locations, and provides a level of indirection so that global color +// changes can be made. Not to be confused with the X colormap, which +// I try to hide completely. + +// matt: Neither Quartz nor Quickdraw support colormaps in this implementation +// matt: Quartz support done + +#include +#include +#include +#include + +static unsigned fl_cmap[256] = { +#include "fl_cmap.h" // this is a file produced by "cmap.cxx": +}; + +// Translations to mac data structures: +Fl_XMap fl_xmap[256]; + +Fl_XMap* fl_current_xmap; + +Fl_Color fl_color_; + +void fl_color(Fl_Color i) { + fl_color_ = i; + int index; + uchar r, g, b; + if (i & 0xFFFFFF00) { + // translate rgb colors into color index + r = i>>24; + g = i>>16; + b = i>> 8; + } else { + // translate index into rgb: + index = i; + unsigned c = fl_cmap[i]; + r = c>>24; + g = c>>16; + b = c>> 8; + } +#ifdef __APPLE_QD__ + RGBColor rgb; + rgb.red = (r<<8)|r; + rgb.green = (g<<8)|g; + rgb.blue = (b<<8)|b; + RGBForeColor(&rgb); +#elif defined(__APPLE_QUARTZ__) + if (!fl_gc) return; // no context yet? We will assign the color later. + float fr = r/255.0f; + float fg = g/255.0f; + float fb = b/255.0f; + CGContextSetRGBFillColor(fl_gc, fr, fg, fb, 1.0f); + CGContextSetRGBStrokeColor(fl_gc, fr, fg, fb, 1.0f); +#else +# error : neither Quickdraw nor Quartz defined +#endif +} + +void fl_color(uchar r, uchar g, uchar b) { + fl_color_ = fl_rgb_color(r, g, b); +#ifdef __APPLE_QD__ + RGBColor rgb; + rgb.red = (r<<8)|r; + rgb.green = (g<<8)|g; + rgb.blue = (b<<8)|b; + RGBForeColor(&rgb); +#elif defined(__APPLE_QUARTZ__) + float fr = r/255.0f; + float fg = g/255.0f; + float fb = b/255.0f; + CGContextSetRGBFillColor(fl_gc, fr, fg, fb, 1.0f); + CGContextSetRGBStrokeColor(fl_gc, fr, fg, fb, 1.0f); +#else +# error : neither Quickdraw nor Quartz defined +#endif +} + +void Fl::set_color(Fl_Color i, unsigned c) { + if (fl_cmap[i] != c) { + fl_cmap[i] = c; + } +} + +// +// End of "$Id: fl_color_mac.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_color_win32.cxx b/third_party/windows/fltk-1.1.10/src/fl_color_win32.cxx new file mode 100644 index 0000000..1e2a7da --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_color_win32.cxx @@ -0,0 +1,254 @@ +// +// "$Id: fl_color_win32.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// WIN32 color functions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// The fltk "colormap". This allows ui colors to be stored in 8-bit +// locations, and provides a level of indirection so that global color +// changes can be made. Not to be confused with the X colormap, which +// I try to hide completely. + +// SGI compiler seems to have problems with unsigned char arguments +// being used to index arrays. So I always copy them to an integer +// before use. + +#include +#include +#include +#include + +static unsigned fl_cmap[256] = { +#include "fl_cmap.h" // this is a file produced by "cmap.cxx": +}; + +// Translations to win32 data structures: +Fl_XMap fl_xmap[256]; + +Fl_XMap* fl_current_xmap; + +HPALETTE fl_palette; +static HGDIOBJ tmppen=0; +static HPEN savepen=0; + +void fl_cleanup_pens(void) { + for (int i=0; i<256; i++) { + if (fl_xmap[i].pen) DeleteObject(fl_xmap[i].pen); + } +} + +void fl_save_pen(void) { + if(!tmppen) tmppen = CreatePen(PS_SOLID, 1, 0); + savepen = (HPEN)SelectObject(fl_gc, tmppen); +} + +void fl_restore_pen(void) { + if (savepen) SelectObject(fl_gc, savepen); + DeleteObject(tmppen); + tmppen = 0; + savepen = 0; +} + +static void clear_xmap(Fl_XMap& xmap) { + if (xmap.pen) { + HGDIOBJ tmppen = GetStockObject(BLACK_PEN); + HGDIOBJ oldpen = SelectObject(fl_gc, tmppen); // Push out the current pen of the gc + if(oldpen != xmap.pen) SelectObject(fl_gc, oldpen); // Put it back if it is not the one we are about to delete + DeleteObject((HGDIOBJ)(xmap.pen)); + xmap.pen = 0; + xmap.brush = -1; + } +} + +static void set_xmap(Fl_XMap& xmap, COLORREF c) { + xmap.rgb = c; + if (xmap.pen) { + HGDIOBJ oldpen = SelectObject(fl_gc,GetStockObject(BLACK_PEN)); // replace current pen with safe one + if (oldpen != xmap.pen)SelectObject(fl_gc,oldpen); // if old one not xmap.pen, need to put it back + DeleteObject(xmap.pen); // delete pen + } + xmap.pen = CreatePen(PS_SOLID, 1, xmap.rgb); // get a pen into xmap.pen + xmap.brush = -1; +} + +Fl_Color fl_color_; + +void fl_color(Fl_Color i) { + if (i & 0xffffff00) { + unsigned rgb = (unsigned)i; + fl_color((uchar)(rgb >> 24), (uchar)(rgb >> 16), (uchar)(rgb >> 8)); + } else { + fl_color_ = i; + Fl_XMap &xmap = fl_xmap[i]; + if (!xmap.pen) { +#if USE_COLORMAP + if (fl_palette) { + set_xmap(xmap, PALETTEINDEX(i)); + } else { +#endif + unsigned c = fl_cmap[i]; + set_xmap(xmap, RGB(uchar(c>>24), uchar(c>>16), uchar(c>>8))); +#if USE_COLORMAP + } +#endif + } + fl_current_xmap = ⟼ + SelectObject(fl_gc, (HGDIOBJ)(xmap.pen)); + } +} + +void fl_color(uchar r, uchar g, uchar b) { + static Fl_XMap xmap; + COLORREF c = RGB(r,g,b); + fl_color_ = fl_rgb_color(r, g, b); + if (!xmap.pen || c != xmap.rgb) { + clear_xmap(xmap); + set_xmap(xmap, c); + } + fl_current_xmap = ⟼ + SelectObject(fl_gc, (HGDIOBJ)(xmap.pen)); +} + +HBRUSH fl_brush() { + return fl_brush_action(0); +} + +HBRUSH fl_brush_action(int action) { + Fl_XMap *xmap = fl_current_xmap; + // Wonko: we use some statistics to cache only a limited number + // of brushes: +#define FL_N_BRUSH 16 + static struct Fl_Brush { + HBRUSH brush; + unsigned short usage; + Fl_XMap* backref; + } brushes[FL_N_BRUSH]; + + if (action) { + SelectObject(fl_gc, GetStockObject(BLACK_BRUSH)); // Load stock object + for (int i=0; ibrush; // find the associated brush + if (i != -1) { // if the brush was allready allocated + if (brushes[i].brush == NULL) goto CREATE_BRUSH; + if ( (++brushes[i].usage) > 32000 ) { // keep a usage statistic + for (int j=0; j16000) + brushes[j].usage -= 16000; + else + brushes[j].usage = 0; + } + } + return brushes[i].brush; + } else { + int umin = 32000, imin = 0; + for (i=0; ibrush = -1; + } +CREATE_BRUSH: + brushes[i].brush = CreateSolidBrush(xmap->rgb); + brushes[i].usage = 0; + brushes[i].backref = xmap; + xmap->brush = i; + return brushes[i].brush; +} + +void Fl::free_color(Fl_Color i, int overlay) { + if (overlay) return; // do something about GL overlay? + clear_xmap(fl_xmap[i]); +} + +void Fl::set_color(Fl_Color i, unsigned c) { + if (fl_cmap[i] != c) { + clear_xmap(fl_xmap[i]); + fl_cmap[i] = c; + } +} + +#if USE_COLORMAP + +// 'fl_select_palette()' - Make a color palette for 8-bit displays if necessary +// Thanks to Michael Sweet @ Easy Software Products for this + +HPALETTE +fl_select_palette(void) +{ + static char beenhere; + if (!beenhere) { + beenhere = 1; + + //if (GetDeviceCaps(fl_gc, BITSPIXEL) > 8) return NULL; + int nColors = GetDeviceCaps(fl_gc, SIZEPALETTE); + if (nColors <= 0 || nColors > 256) return NULL; + // this will try to work on < 256 color screens, but will probably + // come out quite badly. + + // I lamely try to get this variable-sized object allocated on stack: + ulong foo[(sizeof(LOGPALETTE)+256*sizeof(PALETTEENTRY))/sizeof(ulong)+1]; + LOGPALETTE *pPal = (LOGPALETTE*)foo; + + pPal->palVersion = 0x300; + pPal->palNumEntries = nColors; + + // Build 256 colors from the standard FLTK colormap... + + for (int i = 0; i < nColors; i ++) { + pPal->palPalEntry[i].peRed = (fl_cmap[i] >> 24) & 255; + pPal->palPalEntry[i].peGreen = (fl_cmap[i] >> 16) & 255; + pPal->palPalEntry[i].peBlue = (fl_cmap[i] >> 8) & 255; + pPal->palPalEntry[i].peFlags = 0; + }; + + // Create the palette: + fl_palette = CreatePalette(pPal); + } + if (fl_palette) { + SelectPalette(fl_gc, fl_palette, FALSE); + RealizePalette(fl_gc); + } + return fl_palette; +} + +#endif + +// +// End of "$Id: fl_color_win32.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_cursor.cxx b/third_party/windows/fltk-1.1.10/src/fl_cursor.cxx new file mode 100644 index 0000000..0e91169 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_cursor.cxx @@ -0,0 +1,335 @@ +// +// "$Id: fl_cursor.cxx 5654 2007-02-02 13:52:37Z matt $" +// +// Mouse cursor support for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Change the current cursor. +// Under X the cursor is attached to the X window. I tried to hide +// this and pretend that changing the cursor is a drawing function. +// This avoids a field in the Fl_Window, and I suspect is more +// portable to other systems. + +#include +#include +#include +#if !defined(WIN32) && !defined(__APPLE__) +# include +#endif +#include + +void fl_cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) { + if (Fl::first_window()) Fl::first_window()->cursor(c,fg,bg); +} + +void Fl_Window::default_cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) { +// if (c == FL_CURSOR_DEFAULT) c = FL_CURSOR_ARROW; + + cursor_default = c; + cursor_fg = fg; + cursor_bg = bg; + + cursor(c, fg, bg); +} + +#ifdef WIN32 + +# ifndef IDC_HAND +# define IDC_HAND MAKEINTRESOURCE(32649) +# endif // !IDC_HAND + +void Fl_Window::cursor(Fl_Cursor c, Fl_Color c1, Fl_Color c2) { + if (!shown()) return; + // the cursor must be set for the top level window, not for subwindows + Fl_Window *w = window(), *toplevel = this; + while (w) { toplevel = w; w = w->window(); } + if (toplevel != this) { toplevel->cursor(c, c1, c2); return; } + // now set the actual cursor + if (c == FL_CURSOR_DEFAULT) { + c = cursor_default; + } + if (c > FL_CURSOR_NESW) { + i->cursor = 0; + } else if (c == FL_CURSOR_DEFAULT) { + i->cursor = fl_default_cursor; + } else { + LPSTR n; + switch (c) { + case FL_CURSOR_ARROW: n = IDC_ARROW; break; + case FL_CURSOR_CROSS: n = IDC_CROSS; break; + case FL_CURSOR_WAIT: n = IDC_WAIT; break; + case FL_CURSOR_INSERT: n = IDC_IBEAM; break; + case FL_CURSOR_HELP: n = IDC_HELP; break; + case FL_CURSOR_HAND: { + OSVERSIONINFO osvi; + + // Get the OS version: Windows 98 and 2000 have a standard + // hand cursor. + memset(&osvi, 0, sizeof(OSVERSIONINFO)); + osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO); + GetVersionEx(&osvi); + + if (osvi.dwMajorVersion > 4 || + (osvi.dwMajorVersion == 4 && osvi.dwMinorVersion > 0 && + osvi.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)) n = IDC_HAND; + else n = IDC_UPARROW; + } break; + case FL_CURSOR_MOVE: n = IDC_SIZEALL; break; + case FL_CURSOR_N: + case FL_CURSOR_S: + case FL_CURSOR_NS: n = IDC_SIZENS; break; + case FL_CURSOR_NE: + case FL_CURSOR_SW: + case FL_CURSOR_NESW: n = IDC_SIZENESW; break; + case FL_CURSOR_E: + case FL_CURSOR_W: + case FL_CURSOR_WE: n = IDC_SIZEWE; break; + case FL_CURSOR_SE: + case FL_CURSOR_NW: + case FL_CURSOR_NWSE: n = IDC_SIZENWSE; break; + default: n = IDC_NO; break; + } + i->cursor = LoadCursor(NULL, n); + } + SetCursor(i->cursor); +} + +#elif defined(__APPLE__) + +#ifdef __BIG_ENDIAN__ +# define E(x) x +#elif defined __LITTLE_ENDIAN__ +// Don't worry. This will be resolved at compile time +# define E(x) (x>>8)|((x<<8)&0xff00) +#else +# error "Either __LITTLE_ENDIAN__ or __BIG_ENDIAN__ must be defined" +#endif + +static Cursor crsrHAND = +{ + { E(0x0600), E(0x0900), E(0x0900), E(0x0900), E(0x09C0), E(0x0938), E(0x6926), E(0x9805), + E(0x8801), E(0x4801), E(0x2002), E(0x2002), E(0x1004), E(0x0804), E(0x0408), E(0x0408) }, + { E(0x0600), E(0x0F00), E(0x0F00), E(0x0F00), E(0x0FC0), E(0x0FF8), E(0x6FFE), E(0xFFFF), + E(0xFFFF), E(0x7FFF), E(0x3FFE), E(0x3FFE), E(0x1FFC), E(0x0FFC), E(0x07F8), E(0x07F8) }, + { 1, 5 } // Hotspot: ( y, x ) +}, *crsrHANDptr = &crsrHAND; +static Cursor crsrHELP = +{ + { E(0x0000), E(0x4000), E(0x6000), E(0x7000), E(0x783C), E(0x7C7E), E(0x7E66), E(0x7F06), + E(0x7F8C), E(0x7C18), E(0x6C18), E(0x4600), E(0x0618), E(0x0318), E(0x0300), E(0x0000) }, + { E(0xC000), E(0xE000), E(0xF000), E(0xF83C), E(0xFC7E), E(0xFEFF), E(0xFFFF), E(0xFFFF), + E(0xFFFE), E(0xFFFC), E(0xFE3C), E(0xEF3C), E(0xCF3C), E(0x07BC), E(0x0798), E(0x0380) }, + { 1, 1 } +}, *crsrHELPptr = &crsrHELP; +static Cursor crsrMOVE = +{ + { E(0x0000), E(0x0180), E(0x03C0), E(0x07E0), E(0x07E0), E(0x1998), E(0x399C), E(0x7FFE), + E(0x7FFE), E(0x399C), E(0x1998), E(0x07E0), E(0x07E0), E(0x03C0), E(0x0180), E(0x0000) }, + { E(0x0180), E(0x03C0), E(0x07E0), E(0x0FF0), E(0x1FF8), E(0x3FFC), E(0x7FFE), E(0xFFFF), + E(0xFFFF), E(0x7FFE), E(0x3FFC), E(0x1FF8), E(0x0FF0), E(0x07E0), E(0x03C0), E(0x0180) }, + { 8, 8 } +}, *crsrMOVEptr = &crsrMOVE; +static Cursor crsrNS = +{ + { E(0x0000), E(0x0180), E(0x03C0), E(0x07E0), E(0x0FF0), E(0x0180), E(0x0180), E(0x0180), + E(0x0180), E(0x0180), E(0x0180), E(0x0FF0), E(0x07E0), E(0x03C0), E(0x0180), E(0x0000) }, + { E(0x0180), E(0x03C0), E(0x07E0), E(0x0FF0), E(0x1FF8), E(0x1FF8), E(0x03C0), E(0x03C0), + E(0x03C0), E(0x03C0), E(0x1FF8), E(0x1FF8), E(0x0FF0), E(0x07E0), E(0x03C0), E(0x0180) }, + { 8, 8 } +}, *crsrNSptr = &crsrNS; +static Cursor crsrWE = +{ + { E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0810), E(0x1818), E(0x381C), E(0x7FFE), + E(0x7FFE), E(0x381C), E(0x1818), E(0x0810), E(0x0000), E(0x0000), E(0x0000), E(0x0000) }, + { E(0x0000), E(0x0000), E(0x0000), E(0x0C30), E(0x1C38), E(0x3C3C), E(0x7FFE), E(0xFFFF), + E(0xFFFF), E(0x7FFE), E(0x3C3C), E(0x1C38), E(0x0C30), E(0x0000), E(0x0000), E(0x0000) }, + { 8, 8 } +}, *crsrWEptr = &crsrWE; +static Cursor crsrNWSE = +{ + { E(0x0000), E(0x7E00), E(0x7C00), E(0x7800), E(0x7C00), E(0x6E00), E(0x4710), E(0x03B0), + E(0x01F0), E(0x00F0), E(0x01F0), E(0x03F0), E(0x0000), E(0x0000), E(0x0000), E(0x0000) }, + { E(0xFF00), E(0xFF00), E(0xFE00), E(0xFC00), E(0xFE00), E(0xFF18), E(0xEFB8), E(0xC7F8), + E(0x03F8), E(0x01F8), E(0x03F8), E(0x07F8), E(0x07F8), E(0x0000), E(0x0000), E(0x0000) }, + { 8, 8 } +}, *crsrNWSEptr = &crsrNWSE; +static Cursor crsrNESW = +{ + { E(0x0000), E(0x03F0), E(0x01F0), E(0x00F0), E(0x01F0), E(0x03B0), E(0x4710), E(0x6E00), + E(0x7C00), E(0x7800), E(0x7C00), E(0x7E00), E(0x0000), E(0x0000), E(0x0000), E(0x0000) }, + { E(0x07F8), E(0x07F8), E(0x03F8), E(0x01F8), E(0x03F8), E(0xC7F8), E(0xEFB8), E(0xFF18), + E(0xFE00), E(0xFC00), E(0xFE00), E(0xFF00), E(0xFF00), E(0x0000), E(0x0000), E(0x0000) }, + { 8, 8 } +}, *crsrNESWptr = &crsrNESW; +static Cursor crsrNONE = +{ + { E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), + E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000) }, + { E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), + E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000), E(0x0000) }, + { 0, 0 } +}, *crsrNONEptr = &crsrNONE; +static Cursor crsrARROW = +{ + { E(0x0000), E(0x4000), E(0x6000), E(0x7000), E(0x7800), E(0x7C00), E(0x7E00), E(0x7F00), + E(0x7F80), E(0x7C00), E(0x6C00), E(0x4600), E(0x0600), E(0x0300), E(0x0300), E(0x0000) }, + { E(0xC000), E(0xE000), E(0xF000), E(0xF800), E(0xFC00), E(0xFE00), E(0xFF00), E(0xFF80), + E(0xFFC0), E(0xFFC0), E(0xFE00), E(0xEF00), E(0xCF00), E(0x0780), E(0x0780), E(0x0380) }, + { 1, 1 } +}, *crsrARROWptr = &crsrARROW; + +#undef E + +void Fl_Window::cursor(Fl_Cursor c, Fl_Color, Fl_Color) { + if (c == FL_CURSOR_DEFAULT) { + c = cursor_default; + } + CursHandle icrsr = fl_default_cursor; + switch (c) { + case FL_CURSOR_CROSS: icrsr = GetCursor( crossCursor ); break; + case FL_CURSOR_WAIT: icrsr = GetCursor( watchCursor ); break; + case FL_CURSOR_INSERT: icrsr = GetCursor( iBeamCursor ); break; + case FL_CURSOR_N: + case FL_CURSOR_S: + case FL_CURSOR_NS: icrsr = &crsrNSptr; break; + case FL_CURSOR_HELP: icrsr = &crsrHELPptr; break; + case FL_CURSOR_HAND: icrsr = &crsrHANDptr; break; + case FL_CURSOR_MOVE: icrsr = &crsrMOVEptr; break; + case FL_CURSOR_NE: + case FL_CURSOR_SW: + case FL_CURSOR_NESW: icrsr = &crsrNESWptr; break; + case FL_CURSOR_E: + case FL_CURSOR_W: + case FL_CURSOR_WE: icrsr = &crsrWEptr; break; + case FL_CURSOR_SE: + case FL_CURSOR_NW: + case FL_CURSOR_NWSE: icrsr = &crsrNWSEptr; break; + case FL_CURSOR_NONE: icrsr = &crsrNONEptr; break; + case FL_CURSOR_ARROW: icrsr = &crsrARROWptr; break; + case FL_CURSOR_DEFAULT: + default: break; + } + SetCursor( *icrsr ); + if (i) { + i->cursor = icrsr; + } +} + +#else + +// I like the MSWindows resize cursors, so I duplicate them here: + +#define CURSORSIZE 16 +#define HOTXY 7 +static struct TableEntry { + uchar bits[CURSORSIZE*CURSORSIZE/8]; + uchar mask[CURSORSIZE*CURSORSIZE/8]; + Cursor cursor; +} table[] = { + {{ // FL_CURSOR_NS + 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0x80, 0x01, 0x80, 0x01, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, + 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00}, + { + 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0xf0, 0x0f, 0xc0, 0x03, + 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xf0, 0x0f, + 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01}}, + {{ // FL_CURSOR_EW + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x10, + 0x0c, 0x30, 0xfe, 0x7f, 0xfe, 0x7f, 0x0c, 0x30, 0x08, 0x10, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x1c, 0x38, + 0xfe, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xfe, 0x7f, 0x1c, 0x38, 0x18, 0x18, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{ // FL_CURSOR_NWSE + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x00, 0x38, 0x00, 0x78, 0x00, + 0xe8, 0x00, 0xc0, 0x01, 0x80, 0x03, 0x00, 0x17, 0x00, 0x1e, 0x00, 0x1c, + 0x00, 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { + 0x00, 0x00, 0x00, 0x00, 0xfc, 0x00, 0xfc, 0x00, 0x7c, 0x00, 0xfc, 0x00, + 0xfc, 0x01, 0xec, 0x03, 0xc0, 0x37, 0x80, 0x3f, 0x00, 0x3f, 0x00, 0x3e, + 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x00, 0x00, 0x00}}, + {{ // FL_CURSOR_NESW + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1e, 0x00, 0x1c, 0x00, 0x1e, + 0x00, 0x17, 0x80, 0x03, 0xc0, 0x01, 0xe8, 0x00, 0x78, 0x00, 0x38, 0x00, + 0x78, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, + { + 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x00, 0x3f, 0x00, 0x3e, 0x00, 0x3f, + 0x80, 0x3f, 0xc0, 0x37, 0xec, 0x03, 0xfc, 0x01, 0xfc, 0x00, 0x7c, 0x00, + 0xfc, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00, 0x00}}, + {{0}, {0}} // FL_CURSOR_NONE & unknown +}; + +void Fl_Window::cursor(Fl_Cursor c, Fl_Color fg, Fl_Color bg) { + if (!shown()) return; + Cursor xc; + int deleteit = 0; + if (c == FL_CURSOR_DEFAULT) { + c = cursor_default; + fg = cursor_fg; + bg = cursor_bg; + } + + if (!c) { + xc = None; + } else { + if (c >= FL_CURSOR_NS) { + TableEntry *q = (c > FL_CURSOR_NESW) ? table+4 : table+(c-FL_CURSOR_NS); + if (!(q->cursor)) { + XColor dummy = { 0 }; + Pixmap p = XCreateBitmapFromData(fl_display, + RootWindow(fl_display, fl_screen), (const char*)(q->bits), + CURSORSIZE, CURSORSIZE); + Pixmap m = XCreateBitmapFromData(fl_display, + RootWindow(fl_display, fl_screen), (const char*)(q->mask), + CURSORSIZE, CURSORSIZE); + q->cursor = XCreatePixmapCursor(fl_display, p,m,&dummy, &dummy, + HOTXY, HOTXY); + XFreePixmap(fl_display, m); + XFreePixmap(fl_display, p); + } + xc = q->cursor; + } else { + xc = XCreateFontCursor(fl_display, (c-1)*2); + deleteit = 1; + } + XColor fgc; + uchar r,g,b; + Fl::get_color(fg,r,g,b); + fgc.red = r<<8; fgc.green = g<<8; fgc.blue = b<<8; + XColor bgc; + Fl::get_color(bg,r,g,b); + bgc.red = r<<8; bgc.green = g<<8; bgc.blue = b<<8; + XRecolorCursor(fl_display, xc, &fgc, &bgc); + } + XDefineCursor(fl_display, fl_xid(this), xc); + if (deleteit) XFreeCursor(fl_display, xc); +} + +#endif + +// +// End of "$Id: fl_cursor.cxx 5654 2007-02-02 13:52:37Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_curve.cxx b/third_party/windows/fltk-1.1.10/src/fl_curve.cxx new file mode 100644 index 0000000..5007e9a --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_curve.cxx @@ -0,0 +1,106 @@ +// +// "$Id: fl_curve.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Bezier curve functions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Utility for drawing Bezier curves, adding the points to +// the current fl_begin/fl_vertex/fl_end path. +// Incremental math implementation: +// I very much doubt this is optimal! From Foley/vanDam page 511. +// If anybody has a better algorithim, please send it! + +#include +#include + +void fl_curve(double X0, double Y0, + double X1, double Y1, + double X2, double Y2, + double X3, double Y3) { + + double x = fl_transform_x(X0,Y0); + double y = fl_transform_y(X0,Y0); + + // draw point 0: + fl_transformed_vertex(x,y); + + double x1 = fl_transform_x(X1,Y1); + double yy1 = fl_transform_y(X1,Y1); + double x2 = fl_transform_x(X2,Y2); + double y2 = fl_transform_y(X2,Y2); + double x3 = fl_transform_x(X3,Y3); + double y3 = fl_transform_y(X3,Y3); + + // find the area: + double a = fabs((x-x2)*(y3-yy1)-(y-y2)*(x3-x1)); + double b = fabs((x-x3)*(y2-yy1)-(y-y3)*(x2-x1)); + if (b > a) a = b; + + // use that to guess at the number of segments: + int n = int(sqrt(a)/4); + if (n > 1) { + if (n > 100) n = 100; // make huge curves not hang forever + + double e = 1.0/n; + + // calculate the coefficients of 3rd order equation: + double xa = (x3-3*x2+3*x1-x); + double xb = 3*(x2-2*x1+x); + double xc = 3*(x1-x); + // calculate the forward differences: + double dx1 = ((xa*e+xb)*e+xc)*e; + double dx3 = 6*xa*e*e*e; + double dx2 = dx3 + 2*xb*e*e; + + // calculate the coefficients of 3rd order equation: + double ya = (y3-3*y2+3*yy1-y); + double yb = 3*(y2-2*yy1+y); + double yc = 3*(yy1-y); + // calculate the forward differences: + double dy1 = ((ya*e+yb)*e+yc)*e; + double dy3 = 6*ya*e*e*e; + double dy2 = dy3 + 2*yb*e*e; + + // draw points 1 .. n-2: + for (int m=2; m +#include + +extern uchar* fl_gray_ramp(); + +static void fl_diamond_up_box(int x,int y,int w,int h,Fl_Color bgcolor) { + w &= -2; + h &= -2; + int x1 = x+w/2; + int y1 = y+h/2; + fl_color(bgcolor); fl_polygon(x+3, y1, x1,y+3, x+w-3,y1, x1,y+h-3); + uchar *g = fl_gray_ramp(); + fl_color(g['W']); fl_line(x+1, y1, x1, y+1, x+w-1, y1); + fl_color(g['U']); fl_line(x+2, y1, x1, y+2, x+w-2, y1); + fl_color(g['S']); fl_line(x+3, y1, x1, y+3, x+w-3, y1); + fl_color(g['P']); fl_line(x+3, y1, x1, y+h-3, x+w-3, y1); + fl_color(g['N']); fl_line(x+2, y1, x1, y+h-2, x+w-2, y1); + fl_color(g['H']); fl_line(x+1, y1, x1, y+h-1, x+w-1, y1); + fl_color(g['A']); fl_loop(x, y1, x1, y, x+w, y1, x1, y+h); +} + +static void fl_diamond_down_box(int x,int y,int w,int h,Fl_Color bgcolor) { + w &= -2; + h &= -2; + int x1 = x+w/2; + int y1 = y+h/2; + uchar *g = fl_gray_ramp(); + fl_color(g['P']); fl_line(x+0, y1, x1, y+0, x+w-0, y1); + fl_color(g['N']); fl_line(x+1, y1, x1, y+1, x+w-1, y1); + fl_color(g['H']); fl_line(x+2, y1, x1, y+2, x+w-2, y1); + fl_color(g['W']); fl_line(x+2, y1, x1, y+h-2, x+w-2, y1); + fl_color(g['U']); fl_line(x+1, y1, x1, y+h-1, x+w-1, y1); + fl_color(g['S']); fl_line(x+0, y1, x1, y+h-0, x+w-0, y1); + fl_color(bgcolor); fl_polygon(x+3, y1, x1,y+3, x+w-3,y1, x1,y+h-3); + fl_color(g['A']); fl_loop(x+3, y1, x1, y+3, x+w-3, y1, x1, y+h-3); +} + +extern void fl_internal_boxtype(Fl_Boxtype, Fl_Box_Draw_F*); +Fl_Boxtype fl_define_FL_DIAMOND_BOX() { + fl_internal_boxtype(_FL_DIAMOND_DOWN_BOX, fl_diamond_down_box); + fl_internal_boxtype(_FL_DIAMOND_UP_BOX,fl_diamond_up_box); + return _FL_DIAMOND_UP_BOX; +} + +// +// End of "$Id: fl_diamond_box.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_dnd.cxx b/third_party/windows/fltk-1.1.10/src/fl_dnd.cxx new file mode 100644 index 0000000..9193505 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_dnd.cxx @@ -0,0 +1,38 @@ +// +// "$Id: fl_dnd.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Drag & Drop code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#ifdef WIN32 +# include "fl_dnd_win32.cxx" +#elif defined(__APPLE__) +# include "fl_dnd_mac.cxx" +#else +# include "fl_dnd_x.cxx" +#endif + +// +// End of "$Id: fl_dnd.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_dnd_mac.cxx b/third_party/windows/fltk-1.1.10/src/fl_dnd_mac.cxx new file mode 100644 index 0000000..7415b7b --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_dnd_mac.cxx @@ -0,0 +1,90 @@ +// +// "$Id: fl_dnd_mac.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Drag & Drop code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to "fltk-bugs@fltk.org + +// This file contains win32-specific code for fltk which is always linked +// in. Search other files for "WIN32" or filenames ending in _win32.cxx +// for other system-specific code. + +#include +#include +#include +#include + +// warning: this function is only implemented in Quickdraw. The function +// below may not work If FLTK is compiled with Quartz enabled + +extern EventRef fl_os_event; +extern char *fl_selection_buffer; +extern int fl_selection_length; + + +/** + * drag and drop whatever is in the cut-copy-paste buffer + * - create a selection first using: + * Fl::copy(const char *stuff, int len, 0) + */ +int Fl::dnd() +{ + OSErr result; + DragReference dragRef; + result = NewDrag( &dragRef ); + if ( result != noErr ) return false; + + result = AddDragItemFlavor( dragRef, 1, 'TEXT', fl_selection_buffer, fl_selection_length, 0 ); + if ( result != noErr ) { DisposeDrag( dragRef ); return false; } + + Point mp; + GetMouse(&mp); + LocalToGlobal( &mp ); + RgnHandle region = NewRgn(); + SetRectRgn( region, mp.h-10, mp.v-10, mp.h+10, mp.v+10 ); + RgnHandle r2 = NewRgn(); + SetRectRgn( r2, mp.h-8, mp.v-8, mp.h+8, mp.v+8 ); + DiffRgn( region, r2, region ); + DisposeRgn( r2 ); + + EventRecord event; + ConvertEventRefToEventRecord( fl_os_event, &event ); + result = TrackDrag( dragRef, &event, region ); + + Fl_Widget *w = Fl::pushed(); + if ( w ) + { + int old_event = Fl::e_number; + w->handle(Fl::e_number = FL_RELEASE); + Fl::e_number = old_event; + Fl::pushed( 0 ); + } + + if ( result != noErr ) { DisposeRgn( region ); DisposeDrag( dragRef ); return false; } + + DisposeRgn( region ); + DisposeDrag( dragRef ); + return true; +} + + +// +// End of "$Id: fl_dnd_mac.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_dnd_win32.cxx b/third_party/windows/fltk-1.1.10/src/fl_dnd_win32.cxx new file mode 100644 index 0000000..cd7511b --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_dnd_win32.cxx @@ -0,0 +1,404 @@ +// +// "$Id: fl_dnd_win32.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Drag & Drop code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems to "fltk-bugs@fltk.org + +// This file contains win32-specific code for fltk which is always linked +// in. Search other files for "WIN32" or filenames ending in _win32.cxx +// for other system-specific code. + +#include +#include +#include +#include "flstring.h" +#include +#include +#include +#include +#if defined(__CYGWIN__) +#include +#include +#else +#include +#endif + +extern char *fl_selection_buffer[2]; +extern int fl_selection_length[2]; +extern int fl_selection_buffer_length[2]; +extern char fl_i_own_selection[2]; + +Fl_Window *fl_dnd_target_window = 0; + +// All of the following code requires GCC 3.x or a non-GNU compiler... +#if !defined(__GNUC__) || __GNUC__ >= 3 + +#include +#include + +/** + * subclass the IDropTarget to receive data from DnD operations + */ +class FLDropTarget : public IDropTarget +{ + DWORD m_cRefCount; + DWORD lastEffect; + int px, py; +public: + FLDropTarget() : m_cRefCount(0) { } // initialize + HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) { + if (IID_IUnknown==riid || IID_IDropTarget==riid) + { + *ppvObject=this; + ((LPUNKNOWN)*ppvObject)->AddRef(); + return S_OK; + } + *ppvObject = NULL; + return E_NOINTERFACE; + } + ULONG STDMETHODCALLTYPE AddRef() { return ++m_cRefCount; } + ULONG STDMETHODCALLTYPE Release() { + long nTemp; + nTemp = --m_cRefCount; + if(nTemp==0) + delete this; + return nTemp; + } + HRESULT STDMETHODCALLTYPE DragEnter( IDataObject *pDataObj, DWORD /*grfKeyState*/, POINTL pt, DWORD *pdwEffect) { + if( !pDataObj ) return E_INVALIDARG; + // set e_modifiers here from grfKeyState, set e_x and e_root_x + // check if FLTK handles this drag and return if it can't (i.e. BMP drag without filename) + POINT ppt; + Fl::e_x_root = ppt.x = pt.x; + Fl::e_y_root = ppt.y = pt.y; + HWND hWnd = WindowFromPoint( ppt ); + Fl_Window *target = fl_find( hWnd ); + if (target) { + Fl::e_x = Fl::e_x_root-target->x(); + Fl::e_y = Fl::e_y_root-target->y(); + } + fl_dnd_target_window = target; + px = pt.x; py = pt.y; + if (fillCurrentDragData(pDataObj)) { + // FLTK has no mechanism yet for the different drop effects, so we allow move and copy + if ( target && Fl::handle( FL_DND_ENTER, target ) ) + *pdwEffect = DROPEFFECT_MOVE|DROPEFFECT_COPY; //|DROPEFFECT_LINK; + else + *pdwEffect = DROPEFFECT_NONE; + } else { + *pdwEffect = DROPEFFECT_NONE; + } + lastEffect = *pdwEffect; + return S_OK; + } + HRESULT STDMETHODCALLTYPE DragOver( DWORD /*grfKeyState*/, POINTL pt, DWORD *pdwEffect) { + if ( px==pt.x && py==pt.y ) + { + *pdwEffect = lastEffect; + return S_OK; + } + if ( !fl_dnd_target_window ) + { + *pdwEffect = lastEffect = DROPEFFECT_NONE; + return S_OK; + } + // set e_modifiers here from grfKeyState, set e_x and e_root_x + Fl::e_x_root = pt.x; + Fl::e_y_root = pt.y; + if (fl_dnd_target_window) { + Fl::e_x = Fl::e_x_root-fl_dnd_target_window->x(); + Fl::e_y = Fl::e_y_root-fl_dnd_target_window->y(); + } + if (fillCurrentDragData(0)) { + // Fl_Group will change DND_DRAG into DND_ENTER and DND_LEAVE if needed + if ( Fl::handle( FL_DND_DRAG, fl_dnd_target_window ) ) + *pdwEffect = DROPEFFECT_MOVE|DROPEFFECT_COPY; //|DROPEFFECT_LINK; + else + *pdwEffect = DROPEFFECT_NONE; + } else { + *pdwEffect = DROPEFFECT_NONE; + } + px = pt.x; py = pt.y; + lastEffect = *pdwEffect; + return S_OK; + } + HRESULT STDMETHODCALLTYPE DragLeave() { + if ( fl_dnd_target_window && fillCurrentDragData(0)) + { + Fl::handle( FL_DND_LEAVE, fl_dnd_target_window ); + fl_dnd_target_window = 0; + clearCurrentDragData(); + } + return S_OK; + } + HRESULT STDMETHODCALLTYPE Drop( IDataObject *data, DWORD /*grfKeyState*/, POINTL pt, DWORD* /*pdwEffect*/) { + if ( !fl_dnd_target_window ) + return S_OK; + Fl_Window *target = fl_dnd_target_window; + fl_dnd_target_window = 0; + Fl::e_x_root = pt.x; + Fl::e_y_root = pt.y; + if (target) { + Fl::e_x = Fl::e_x_root-target->x(); + Fl::e_y = Fl::e_y_root-target->y(); + } + // tell FLTK that the user released an object on this widget + if ( !Fl::handle( FL_DND_RELEASE, target ) ) + return S_OK; + + Fl_Widget *w = target; + while (w->parent()) w = w->window(); + HWND hwnd = fl_xid( (Fl_Window*)w ); + if (fillCurrentDragData(data)) { + int old_event = Fl::e_number; + Fl::belowmouse()->handle(Fl::e_number = FL_PASTE); // e_text will be invalid after this call + Fl::e_number = old_event; + SetForegroundWindow( hwnd ); + clearCurrentDragData(); + return S_OK; + } + return S_OK; + } +private: + + static IDataObject *currDragRef; + static char *currDragData; + static int currDragSize; + static char currDragResult; + + static void clearCurrentDragData() { + currDragRef = 0; + if (currDragData) free(currDragData); + currDragData = 0; + currDragSize = 0; + currDragResult = 0; + } + static char fillCurrentDragData(IDataObject *data) { + // shortcut through this whole procedure if there is no fresh data + if (!data) + return currDragResult; + // shortcut through this whole procedure if this is still the same drag event + // (* this is safe, because 'currDragRef' is cleared on Leave and Drop events) + if (data==currDragRef) + return currDragResult; + + // clear currDrag* for a new drag event + clearCurrentDragData(); + + // fill currDrag* with ASCII data, if available + FORMATETC fmt = { 0 }; + STGMEDIUM medium = { 0 }; + fmt.tymed = TYMED_HGLOBAL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.cfFormat = CF_TEXT; + // if it is ASCII text, return a copy of it + if ( data->GetData( &fmt, &medium )==S_OK ) + { + void *stuff = GlobalLock( medium.hGlobal ); + Fl::e_length = strlen((char*)stuff); + Fl::e_text = strdup((char*)stuff); + GlobalUnlock( medium.hGlobal ); + ReleaseStgMedium( &medium ); + currDragResult = 1; + return currDragResult; + } + // else fill currDrag* with filenames, if possible + memset(&fmt, 0, sizeof(fmt)); + fmt.tymed = TYMED_HGLOBAL; + fmt.dwAspect = DVASPECT_CONTENT; + fmt.lindex = -1; + fmt.cfFormat = CF_HDROP; + // if it is a pathname list, send an FL_PASTE with a \n seperated list of filepaths + if ( data->GetData( &fmt, &medium )==S_OK ) + { + HDROP hdrop = (HDROP)medium.hGlobal; + int i, n, nn = 0, nf = DragQueryFile( hdrop, (UINT)-1, 0, 0 ); + for ( i=0; iAddRef(); + return S_OK; + } + *ppvObject = NULL; + return E_NOINTERFACE; + } + ULONG STDMETHODCALLTYPE AddRef() { return ++m_cRefCount; } + ULONG STDMETHODCALLTYPE Release() { + long nTemp; + nTemp = --m_cRefCount; + if(nTemp==0) + delete this; + return nTemp; + } + STDMETHODIMP GiveFeedback( ulong ) { return DRAGDROP_S_USEDEFAULTCURSORS; } + STDMETHODIMP QueryContinueDrag( BOOL esc, DWORD keyState ) { + if ( esc ) + return DRAGDROP_S_CANCEL; + if ( !(keyState & (MK_LBUTTON|MK_MBUTTON|MK_RBUTTON)) ) + return DRAGDROP_S_DROP; + return S_OK; + } +}; + +/** + * this is the actual object that FLTK can drop somewhere + * - the implementation is minimal, but it should work with all decent Win32 drop targets + */ +class FLDataObject : public IDataObject +{ + DWORD m_cRefCount; +public: + FLDataObject() { m_cRefCount = 1; } + HRESULT STDMETHODCALLTYPE QueryInterface( REFIID riid, LPVOID *ppvObject ) { + if (IID_IUnknown==riid || IID_IDataObject==riid) + { + *ppvObject=this; + ((LPUNKNOWN)*ppvObject)->AddRef(); + return S_OK; + } + *ppvObject = NULL; + return E_NOINTERFACE; + } + ULONG STDMETHODCALLTYPE AddRef() { return ++m_cRefCount; } + ULONG STDMETHODCALLTYPE Release() { + long nTemp; + nTemp = --m_cRefCount; + if(nTemp==0) + delete this; + return nTemp; + } + // GetData currently allows ASCII text through Global Memory only + HRESULT STDMETHODCALLTYPE GetData( FORMATETC *pformatetcIn, STGMEDIUM *pmedium ) { + if ((pformatetcIn->dwAspect & DVASPECT_CONTENT) && + (pformatetcIn->tymed & TYMED_HGLOBAL) && + (pformatetcIn->cfFormat == CF_TEXT)) + { + HGLOBAL gh = GlobalAlloc( GHND, fl_selection_length[0]+1 ); + char *pMem = (char*)GlobalLock( gh ); + memmove( pMem, fl_selection_buffer[0], fl_selection_length[0] ); + pMem[ fl_selection_length[0] ] = 0; + pmedium->tymed = TYMED_HGLOBAL; + pmedium->hGlobal = gh; + pmedium->pUnkForRelease = NULL; + GlobalUnlock( gh ); + return S_OK; + } + return DV_E_FORMATETC; + } + HRESULT STDMETHODCALLTYPE QueryGetData( FORMATETC *pformatetc ) + { + if ((pformatetc->dwAspect & DVASPECT_CONTENT) && + (pformatetc->tymed & TYMED_HGLOBAL) && + (pformatetc->cfFormat == CF_TEXT)) + return S_OK; + return DV_E_FORMATETC; + } + // all the following methods are not really needed for a DnD object + HRESULT STDMETHODCALLTYPE GetDataHere( FORMATETC* /*pformatetcIn*/, STGMEDIUM* /*pmedium*/) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE GetCanonicalFormatEtc( FORMATETC* /*in*/, FORMATETC* /*out*/) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE SetData( FORMATETC* /*pformatetc*/, STGMEDIUM* /*pmedium*/, BOOL /*fRelease*/) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE EnumFormatEtc( DWORD /*dir*/, IEnumFORMATETC** /*ppenumFormatEtc*/) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE DAdvise( FORMATETC* /*pformatetc*/, DWORD /*advf*/, + IAdviseSink* /*pAdvSink*/, DWORD* /*pdwConnection*/) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE DUnadvise( DWORD /*dwConnection*/) { return E_NOTIMPL; } + HRESULT STDMETHODCALLTYPE EnumDAdvise( IEnumSTATDATA** /*ppenumAdvise*/) { return E_NOTIMPL; } +}; + + +/** + * drag and drop whatever is in the cut-copy-paste buffer + * - create a selection first using: + * Fl::copy(const char *stuff, int len, 0) + */ +int Fl::dnd() +{ + DWORD dropEffect; + ReleaseCapture(); + + FLDataObject *fdo = new FLDataObject; + fdo->AddRef(); + FLDropSource *fds = new FLDropSource; + fds->AddRef(); + + HRESULT ret = DoDragDrop( fdo, fds, DROPEFFECT_MOVE|DROPEFFECT_LINK|DROPEFFECT_COPY, &dropEffect ); + + fdo->Release(); + fds->Release(); + + Fl_Widget *w = Fl::pushed(); + if ( w ) + { + int old_event = Fl::e_number; + w->handle(Fl::e_number = FL_RELEASE); + Fl::e_number = old_event; + Fl::pushed( 0 ); + } + if ( ret==DRAGDROP_S_DROP ) return 1; // or DD_S_CANCEL + return 0; +} +#else +int Fl::dnd() +{ + // Always indicate DnD failed when using GCC < 3... + return 1; +} +#endif // !__GNUC__ || __GNUC__ >= 3 + + +// +// End of "$Id: fl_dnd_win32.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_dnd_x.cxx b/third_party/windows/fltk-1.1.10/src/fl_dnd_x.cxx new file mode 100644 index 0000000..56368a2 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_dnd_x.cxx @@ -0,0 +1,201 @@ +// +// "$Id: fl_dnd_x.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Drag & Drop code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include "flstring.h" + + +extern Atom fl_XdndAware; +extern Atom fl_XdndSelection; +extern Atom fl_XdndEnter; +extern Atom fl_XdndTypeList; +extern Atom fl_XdndPosition; +extern Atom fl_XdndLeave; +extern Atom fl_XdndDrop; +extern Atom fl_XdndStatus; +extern Atom fl_XdndActionCopy; +extern Atom fl_XdndFinished; +//extern Atom fl_XdndProxy; +extern Atom fl_XdndURIList; + +extern char fl_i_own_selection[2]; +extern char *fl_selection_buffer[2]; + +extern void fl_sendClientMessage(Window window, Atom message, + unsigned long d0, + unsigned long d1=0, + unsigned long d2=0, + unsigned long d3=0, + unsigned long d4=0); + +// return version # of Xdnd this window supports. Also change the +// window to the proxy if it uses a proxy: +static int dnd_aware(Window& window) { + Atom actual; int format; unsigned long count, remaining; + unsigned char *data = 0; + XGetWindowProperty(fl_display, window, fl_XdndAware, + 0, 4, False, XA_ATOM, + &actual, &format, + &count, &remaining, &data); + if (actual == XA_ATOM && format==32 && count && data) + return int(*(Atom*)data); + return 0; +} + +static int grabfunc(int event) { + if (event == FL_RELEASE) Fl::pushed(0); + return 0; +} + +extern int (*fl_local_grab)(int); // in Fl.cxx + +// send an event to an fltk window belonging to this program: +static int local_handle(int event, Fl_Window* window) { + fl_local_grab = 0; + Fl::e_x = Fl::e_x_root-window->x(); + Fl::e_y = Fl::e_y_root-window->y(); + int ret = Fl::handle(event,window); + fl_local_grab = grabfunc; + return ret; +} + +int Fl::dnd() { + Fl_Window *source_fl_win = Fl::first_window(); + Fl::first_window()->cursor((Fl_Cursor)21); + Window source_window = fl_xid(Fl::first_window()); + fl_local_grab = grabfunc; + Window target_window = 0; + Fl_Window* local_window = 0; + int dndversion = 4; int dest_x, dest_y; + XSetSelectionOwner(fl_display, fl_XdndSelection, fl_message_window, fl_event_time); + + while (Fl::pushed()) { + + // figure out what window we are pointing at: + Window new_window = 0; int new_version = 0; + Fl_Window* new_local_window = 0; + for (Window child = RootWindow(fl_display, fl_screen);;) { + Window root; unsigned int junk3; + XQueryPointer(fl_display, child, &root, &child, + &e_x_root, &e_y_root, &dest_x, &dest_y, &junk3); + if (!child) { + if (!new_window && (new_version = dnd_aware(root))) new_window = root; + break; + } + new_window = child; + if ((new_local_window = fl_find(child))) break; + if ((new_version = dnd_aware(new_window))) break; + } + + if (new_window != target_window) { + if (local_window) { + local_handle(FL_DND_LEAVE, local_window); + } else if (dndversion) { + fl_sendClientMessage(target_window, fl_XdndLeave, source_window); + } + dndversion = new_version; + target_window = new_window; + local_window = new_local_window; + if (local_window) { + local_handle(FL_DND_ENTER, local_window); + } else if (dndversion) { + // Send an X-DND message to the target window. In order to + // support dragging of files/URLs as well as arbitrary text, + // we look at the selection buffer - if the buffer starts + // with a common URI scheme, does not contain spaces, and + // contains at least one CR LF, then we flag the data as + // both a URI list (MIME media type "text/uri-list") and + // plain text. Otherwise, we just say it is plain text. + if ((!strncmp(fl_selection_buffer[0], "file:///", 8) || + !strncmp(fl_selection_buffer[0], "ftp://", 6) || + !strncmp(fl_selection_buffer[0], "http://", 7) || + !strncmp(fl_selection_buffer[0], "https://", 8) || + !strncmp(fl_selection_buffer[0], "ipp://", 6) || + !strncmp(fl_selection_buffer[0], "ldap:", 5) || + !strncmp(fl_selection_buffer[0], "mailto:", 7) || + !strncmp(fl_selection_buffer[0], "news:", 5) || + !strncmp(fl_selection_buffer[0], "smb://", 6)) && + !strchr(fl_selection_buffer[0], ' ') && + strstr(fl_selection_buffer[0], "\r\n")) { + // Send file/URI list... + fl_sendClientMessage(target_window, fl_XdndEnter, source_window, + dndversion<<24, fl_XdndURIList, XA_STRING, 0); + } else { + // Send plain text... + fl_sendClientMessage(target_window, fl_XdndEnter, source_window, + dndversion<<24, XA_STRING, 0, 0); + } + } + } + if (local_window) { + local_handle(FL_DND_DRAG, local_window); + } else if (dndversion) { + fl_sendClientMessage(target_window, fl_XdndPosition, source_window, + 0, (e_x_root<<16)|e_y_root, fl_event_time, + fl_XdndActionCopy); + } + Fl::wait(); + } + + if (local_window) { + fl_i_own_selection[0] = 1; + if (local_handle(FL_DND_RELEASE, local_window)) paste(*belowmouse(), 0); + } else if (dndversion) { + fl_sendClientMessage(target_window, fl_XdndDrop, source_window, + 0, fl_event_time); + } else if (target_window) { + // fake a drop by clicking the middle mouse button: + XButtonEvent msg; + msg.type = ButtonPress; + msg.window = target_window; + msg.root = RootWindow(fl_display, fl_screen); + msg.subwindow = 0; + msg.time = fl_event_time+1; + msg.x = dest_x; + msg.y = dest_y; + msg.x_root = Fl::e_x_root; + msg.y_root = Fl::e_y_root; + msg.state = 0x0; + msg.button = Button2; + XSendEvent(fl_display, target_window, False, 0L, (XEvent*)&msg); + msg.time++; + msg.state = 0x200; + msg.type = ButtonRelease; + XSendEvent(fl_display, target_window, False, 0L, (XEvent*)&msg); + } + + fl_local_grab = 0; + source_fl_win->cursor(FL_CURSOR_DEFAULT); + return 1; +} + + +// +// End of "$Id: fl_dnd_x.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_draw.cxx b/third_party/windows/fltk-1.1.10/src/fl_draw.cxx new file mode 100644 index 0000000..006cc45 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_draw.cxx @@ -0,0 +1,336 @@ +// +// "$Id: fl_draw.cxx 5565 2006-12-21 19:39:26Z mike $" +// +// Label drawing code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Implementation of fl_draw(const char*,int,int,int,int,Fl_Align) +// Used to draw all the labels and text, this routine: +// Word wraps the labels to fit into their bounding box. +// Breaks them into lines at the newlines. +// Expands all unprintable characters to ^X or \nnn notation +// Aligns them against the inside of the box. + +#define min(a,b) ((a)<(b)?(a):(b)) +#include +#include + +#include "flstring.h" +#include +#include + +#define MAXBUF 1024 + +char fl_draw_shortcut; // set by fl_labeltypes.cxx + +static char* underline_at; + +// Copy p to buf, replacing unprintable characters with ^X and \nnn +// Stop at a newline or if MAXBUF characters written to buffer. +// Also word-wrap if width exceeds maxw. +// Returns a pointer to the start of the next line of caharcters. +// Sets n to the number of characters put into the buffer. +// Sets width to the width of the string in the current font. + +static const char* +expand(const char* from, char* buf, double maxw, int& n, double &width, + int wrap, int draw_symbols) { + char* o = buf; + char* e = buf+(MAXBUF-4); + underline_at = 0; + char* word_end = o; + const char* word_start = from; + double w = 0; + + const char* p = from; + for (;; p++) { + + int c = *p & 255; + + if (!c || c == ' ' || c == '\n') { + // test for word-wrap: + if (word_start < p && wrap) { + double newwidth = w + fl_width(word_end, o-word_end); + if (word_end > buf && newwidth > maxw) { // break before this word + o = word_end; + p = word_start; + break; + } + word_end = o; + w = newwidth; + } + if (!c) break; + else if (c == '\n') {p++; break;} + word_start = p+1; + } + + if (o > e) break; // don't overflow buffer + + if (c == '\t') { + for (c = (o-buf)%8; c<8 && o (str + 1) && p[-1] != '@') { + strlcpy(symbol[1], p, sizeof(symbol[1])); + symwidth[1] = min(w,h); + } + } + + symtotal = symwidth[0] + symwidth[1]; + + for (p = str, lines=0; p;) { + e = expand(p, buf, w - symtotal, buflen, width, align&FL_ALIGN_WRAP, + draw_symbols); + lines++; + if (!*e || (*e == '@' && e[1] != '@' && draw_symbols)) break; + p = e; + } + + if ((symwidth[0] || symwidth[1]) && lines) { + if (symwidth[0]) symwidth[0] = lines * fl_height(); + if (symwidth[1]) symwidth[1] = lines * fl_height(); + } + + symtotal = symwidth[0] + symwidth[1]; + + // figure out vertical position of the first line: + int xpos; + int ypos; + int height = fl_height(); + int imgh = img ? img->h() : 0; + + symoffset = 0; + + if (align & FL_ALIGN_BOTTOM) ypos = y+h-(lines-1)*height-imgh; + else if (align & FL_ALIGN_TOP) ypos = y+height; + else ypos = y+(h-lines*height-imgh)/2+height; + + // draw the image unless the "text over image" alignment flag is set... + if (img && !(align & FL_ALIGN_TEXT_OVER_IMAGE)) { + if (img->w() > symoffset) symoffset = img->w(); + + if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0]; + else if (align & FL_ALIGN_RIGHT) xpos = x + w - img->w() - symwidth[1]; + else xpos = x + (w - img->w() - symtotal) / 2 + symwidth[0]; + + img->draw(xpos, ypos - height); + ypos += img->h(); + } + + // now draw all the lines: + if (str) { + int desc = fl_descent(); + for (p=str; ; ypos += height) { + if (lines>1) e = expand(p, buf, w - symtotal, buflen, width, + align&FL_ALIGN_WRAP, draw_symbols); + else e = ""; + + if (width > symoffset) symoffset = (int)(width + 0.5); + + if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0]; + else if (align & FL_ALIGN_RIGHT) xpos = x + w - (int)(width + .5) - symwidth[1]; + else xpos = x + (w - (int)(width + .5) - symtotal) / 2 + symwidth[0]; + + callthis(buf,buflen,xpos,ypos-desc); + + if (underline_at && underline_at >= buf && underline_at < (buf + buflen)) + callthis("_",1,xpos+int(fl_width(buf,underline_at-buf)),ypos-desc); + + if (!*e || (*e == '@' && e[1] != '@')) break; + p = e; + } + } + + // draw the image if the "text over image" alignment flag is set... + if (img && (align & FL_ALIGN_TEXT_OVER_IMAGE)) { + if (img->w() > symoffset) symoffset = img->w(); + + if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0]; + else if (align & FL_ALIGN_RIGHT) xpos = x + w - img->w() - symwidth[1]; + else xpos = x + (w - img->w() - symtotal) / 2 + symwidth[0]; + + img->draw(xpos, ypos); + } + + // draw the symbols, if any... + if (symwidth[0]) { + // draw to the left + if (align & FL_ALIGN_LEFT) xpos = x; + else if (align & FL_ALIGN_RIGHT) xpos = x + w - symtotal - symoffset; + else xpos = x + (w - symoffset - symtotal) / 2; + + if (align & FL_ALIGN_BOTTOM) ypos = y + h - symwidth[0]; + else if (align & FL_ALIGN_TOP) ypos = y; + else ypos = y + (h - symwidth[0]) / 2; + + fl_draw_symbol(symbol[0], xpos, ypos, symwidth[0], symwidth[0], fl_color()); + } + + if (symwidth[1]) { + // draw to the right + if (align & FL_ALIGN_LEFT) xpos = x + symoffset + symwidth[0]; + else if (align & FL_ALIGN_RIGHT) xpos = x + w - symwidth[1]; + else xpos = x + (w - symoffset - symtotal) / 2 + symoffset + symwidth[0]; + + if (align & FL_ALIGN_BOTTOM) ypos = y + h - symwidth[1]; + else if (align & FL_ALIGN_TOP) ypos = y; + else ypos = y + (h - symwidth[1]) / 2; + + fl_draw_symbol(symbol[1], xpos, ypos, symwidth[1], symwidth[1], fl_color()); + } +} + +void fl_draw( + const char* str, // the (multi-line) string + int x, int y, int w, int h, // bounding box + Fl_Align align, + Fl_Image* img, + int draw_symbols) { + if ((!str || !*str) && !img) return; + if (w && h && !fl_not_clipped(x, y, w, h) && (align & FL_ALIGN_INSIDE)) return; + if (align & FL_ALIGN_CLIP) fl_clip(x, y, w, h); + fl_draw(str, x, y, w, h, align, fl_draw, img, draw_symbols); + if (align & FL_ALIGN_CLIP) fl_pop_clip(); +} + +void fl_measure(const char* str, int& w, int& h, int draw_symbols) { + if (!str || !*str) {w = 0; h = 0; return;} + h = fl_height(); + const char* p; + const char* e; + char buf[MAXBUF]; + int buflen; + int lines; + double width; + int W = 0; + char symbol[2][255], *symptr; + int symwidth[2], symtotal; + + // count how many lines and put the last one into the buffer: + symbol[0][0] = '\0'; + symwidth[0] = 0; + + symbol[1][0] = '\0'; + symwidth[1] = 0; + + if (draw_symbols) { + if (str && str[0] == '@' && str[1] && str[1] != '@') { + // Start with a symbol... + for (symptr = symbol[0]; + *str && !isspace(*str) && symptr < (symbol[0] + sizeof(symbol[0]) - 1); + *symptr++ = *str++); + *symptr = '\0'; + if (isspace(*str)) str++; + symwidth[0] = h; + } + + if (str && (p = strrchr(str, '@')) != NULL && p > (str + 1) && p[-1]!='@') { + strlcpy(symbol[1], p, sizeof(symbol[1])); + symwidth[1] = h; + } + } + + symtotal = symwidth[0] + symwidth[1]; + + for (p = str, lines=0; p;) { + e = expand(p, buf, w - symtotal, buflen, width, w != 0, draw_symbols); + if ((int)ceil(width) > W) W = (int)ceil(width); + lines++; + if (!*e || (*e == '@' && draw_symbols)) break; + p = e; + } + + if ((symwidth[0] || symwidth[1]) && lines) { + if (symwidth[0]) symwidth[0] = lines * fl_height(); + if (symwidth[1]) symwidth[1] = lines * fl_height(); + } + + symtotal = symwidth[0] + symwidth[1]; + + w = W + symtotal; + h = lines*h; +} + +// +// End of "$Id: fl_draw.cxx 5565 2006-12-21 19:39:26Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_draw_image.cxx b/third_party/windows/fltk-1.1.10/src/fl_draw_image.cxx new file mode 100644 index 0000000..74ff178 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_draw_image.cxx @@ -0,0 +1,576 @@ +// +// "$Id: fl_draw_image.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Image drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// I hope a simple and portable method of drawing color and monochrome +// images. To keep this simple, only a single storage type is +// supported: 8 bit unsigned data, byte order RGB, and pixels are +// stored packed into rows with the origin at the top-left. It is +// possible to alter the size of pixels with the "delta" argument, to +// add alpha or other information per pixel. It is also possible to +// change the origin and direction of the image data by messing with +// the "delta" and "linedelta", making them negative, though this may +// defeat some of the shortcuts in translating the image for X. + +#ifdef WIN32 +# include "fl_draw_image_win32.cxx" +#elif defined(__APPLE__) +# include "fl_draw_image_mac.cxx" +#else + +// A list of assumptions made about the X display: + +// bits_per_pixel must be one of 8, 16, 24, 32. + +// scanline_pad must be a power of 2 and greater or equal to 8. + +// PsuedoColor visuals must have 8 bits_per_pixel (although the depth +// may be less than 8). This is the only limitation that affects any +// modern X displays, you can't use 12 or 16 bit colormaps. + +// The mask bits in TrueColor visuals for each color are +// contiguous and have at least one bit of each color. This +// is not checked for. + +// For 24 and 32 bit visuals there must be at least 8 bits of each color. + +//////////////////////////////////////////////////////////////// + +# include +# include +# include +# include "Fl_XColor.H" +# include "flstring.h" + +static XImage xi; // template used to pass info to X +static int bytes_per_pixel; +static int scanline_add; +static int scanline_mask; + +static void (*converter)(const uchar *from, uchar *to, int w, int delta); +static void (*mono_converter)(const uchar *from, uchar *to, int w, int delta); + +static int dir; // direction-alternator +static int ri,gi,bi; // saved error-diffusion value + +# if USE_COLORMAP +//////////////////////////////////////////////////////////////// +// 8-bit converter with error diffusion + +static void color8_converter(const uchar *from, uchar *to, int w, int delta) { + int r=ri, g=gi, b=bi; + int d, td; + if (dir) { + dir = 0; + from = from+(w-1)*delta; + to = to+(w-1); + d = -delta; + td = -1; + } else { + dir = 1; + d = delta; + td = 1; + } + for (; w--; from += d, to += td) { + r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255; + g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255; + b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255; + Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256); + Fl_XColor& xmap = fl_xmap[0][i]; + if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);} + r -= xmap.r; + g -= xmap.g; + b -= xmap.b; + *to = uchar(xmap.pixel); + } + ri = r; gi = g; bi = b; +} + +static void mono8_converter(const uchar *from, uchar *to, int w, int delta) { + int r=ri, g=gi, b=bi; + int d, td; + if (dir) { + dir = 0; + from = from+(w-1)*delta; + to = to+(w-1); + d = -delta; + td = -1; + } else { + dir = 1; + d = delta; + td = 1; + } + for (; w--; from += d, to += td) { + r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255; + g += from[0]; if (g < 0) g = 0; else if (g>255) g = 255; + b += from[0]; if (b < 0) b = 0; else if (b>255) b = 255; + Fl_Color i = fl_color_cube(r*FL_NUM_RED/256,g*FL_NUM_GREEN/256,b*FL_NUM_BLUE/256); + Fl_XColor& xmap = fl_xmap[0][i]; + if (!xmap.mapped) {if (!fl_redmask) fl_xpixel(r,g,b); else fl_xpixel(i);} + r -= xmap.r; + g -= xmap.g; + b -= xmap.b; + *to = uchar(xmap.pixel); + } + ri = r; gi = g; bi = b; +} + +# endif + +//////////////////////////////////////////////////////////////// +// 16 bit TrueColor converters with error diffusion +// Cray computers have no 16-bit type, so we use character pointers +// (which may be slow) + +# ifdef U16 +# define OUTTYPE U16 +# define OUTSIZE 1 +# define OUTASSIGN(v) *t = v +# else +# define OUTTYPE uchar +# define OUTSIZE 2 +# define OUTASSIGN(v) int tt=v; t[0] = uchar(tt>>8); t[1] = uchar(tt) +# endif + +static void color16_converter(const uchar *from, uchar *to, int w, int delta) { + OUTTYPE *t = (OUTTYPE *)to; + int d, td; + if (dir) { + dir = 0; + from = from+(w-1)*delta; + t = t+(w-1)*OUTSIZE; + d = -delta; + td = -OUTSIZE; + } else { + dir = 1; + d = delta; + td = OUTSIZE; + } + int r=ri, g=gi, b=bi; + for (; w--; from += d, t += td) { + r = (r&~fl_redmask) +from[0]; if (r>255) r = 255; + g = (g&~fl_greenmask)+from[1]; if (g>255) g = 255; + b = (b&~fl_bluemask) +from[2]; if (b>255) b = 255; + OUTASSIGN(( + ((r&fl_redmask)<> fl_extrashift); + } + ri = r; gi = g; bi = b; +} + +static void mono16_converter(const uchar *from,uchar *to,int w, int delta) { + OUTTYPE *t = (OUTTYPE *)to; + int d, td; + if (dir) { + dir = 0; + from = from+(w-1)*delta; + t = t+(w-1)*OUTSIZE; + d = -delta; + td = -OUTSIZE; + } else { + dir = 1; + d = delta; + td = OUTSIZE; + } + uchar mask = fl_redmask & fl_greenmask & fl_bluemask; + int r=ri; + for (; w--; from += d, t += td) { + r = (r&~mask) + *from; if (r > 255) r = 255; + uchar m = r&mask; + OUTASSIGN(( + (m<> fl_extrashift); + } + ri = r; +} + +// special-case the 5r6g5b layout used by XFree86: + +static void c565_converter(const uchar *from, uchar *to, int w, int delta) { + OUTTYPE *t = (OUTTYPE *)to; + int d, td; + if (dir) { + dir = 0; + from = from+(w-1)*delta; + t = t+(w-1)*OUTSIZE; + d = -delta; + td = -OUTSIZE; + } else { + dir = 1; + d = delta; + td = OUTSIZE; + } + int r=ri, g=gi, b=bi; + for (; w--; from += d, t += td) { + r = (r&7)+from[0]; if (r>255) r = 255; + g = (g&3)+from[1]; if (g>255) g = 255; + b = (b&7)+from[2]; if (b>255) b = 255; + OUTASSIGN(((r&0xf8)<<8) + ((g&0xfc)<<3) + (b>>3)); + } + ri = r; gi = g; bi = b; +} + +static void m565_converter(const uchar *from,uchar *to,int w, int delta) { + OUTTYPE *t = (OUTTYPE *)to; + int d, td; + if (dir) { + dir = 0; + from = from+(w-1)*delta; + t = t+(w-1)*OUTSIZE; + d = -delta; + td = -OUTSIZE; + } else { + dir = 1; + d = delta; + td = OUTSIZE; + } + int r=ri; + for (; w--; from += d, t += td) { + r = (r&7) + *from; if (r > 255) r = 255; + OUTASSIGN((r>>3) * 0x841); + } + ri = r; +} + +//////////////////////////////////////////////////////////////// +// 24bit TrueColor converters: + +static void rgb_converter(const uchar *from, uchar *to, int w, int delta) { + int d = delta-3; + for (; w--; from += d) { + *to++ = *from++; + *to++ = *from++; + *to++ = *from++; + } +} + +static void bgr_converter(const uchar *from, uchar *to, int w, int delta) { + for (; w--; from += delta) { + uchar r = from[0]; + uchar g = from[1]; + *to++ = from[2]; + *to++ = g; + *to++ = r; + } +} + +static void rrr_converter(const uchar *from, uchar *to, int w, int delta) { + for (; w--; from += delta) { + *to++ = *from; + *to++ = *from; + *to++ = *from; + } +} + +//////////////////////////////////////////////////////////////// +// 32bit TrueColor converters on a 32 or 64-bit machine: + +# ifdef U64 +# define STORETYPE U64 +# if WORDS_BIGENDIAN +# define INNARDS32(f) \ + U64 *t = (U64*)to; \ + int w1 = (w+1)/2; \ + for (; w1--; from += delta) {U64 i = f; from += delta; *t++ = (i<<32)|(f);} +# else +# define INNARDS32(f) \ + U64 *t = (U64*)to; \ + int w1 = (w+1)/2; \ + for (; w1--; from += delta) {U64 i=f; from+= delta; *t++ = ((U64)(f)<<32)|i;} +# endif +# else +# define STORETYPE U32 +# define INNARDS32(f) \ + U32 *t = (U32*)to; for (; w--; from += delta) *t++ = f +# endif + +static void rgbx_converter(const uchar *from, uchar *to, int w, int delta) { + INNARDS32((unsigned(from[0])<<24)+(from[1]<<16)+(from[2]<<8)); +} + +static void xbgr_converter(const uchar *from, uchar *to, int w, int delta) { + INNARDS32((from[0])+(from[1]<<8)+(from[2]<<16)); +} + +static void xrgb_converter(const uchar *from, uchar *to, int w, int delta) { + INNARDS32((from[0]<<16)+(from[1]<<8)+(from[2])); +} + +static void bgrx_converter(const uchar *from, uchar *to, int w, int delta) { + INNARDS32((from[0]<<8)+(from[1]<<16)+(unsigned(from[2])<<24)); +} + +static void rrrx_converter(const uchar *from, uchar *to, int w, int delta) { + INNARDS32(unsigned(*from) * 0x1010100U); +} + +static void xrrr_converter(const uchar *from, uchar *to, int w, int delta) { + INNARDS32(*from * 0x10101U); +} + +static void +color32_converter(const uchar *from, uchar *to, int w, int delta) { + INNARDS32( + (from[0]<depth == fl_visual->depth) break; + xi.format = ZPixmap; + xi.byte_order = ImageByteOrder(fl_display); +//i.bitmap_unit = 8; +//i.bitmap_bit_order = MSBFirst; +//i.bitmap_pad = 8; + xi.depth = fl_visual->depth; + xi.bits_per_pixel = pfv->bits_per_pixel; + + if (xi.bits_per_pixel & 7) bytes_per_pixel = 0; // produce fatal error + else bytes_per_pixel = xi.bits_per_pixel/8; + + unsigned int n = pfv->scanline_pad/8; + if (pfv->scanline_pad & 7 || (n&(n-1))) + Fl::fatal("Can't do scanline_pad of %d",pfv->scanline_pad); + if (n < sizeof(STORETYPE)) n = sizeof(STORETYPE); + scanline_add = n-1; + scanline_mask = -n; + +# if USE_COLORMAP + if (bytes_per_pixel == 1) { + converter = color8_converter; + mono_converter = mono8_converter; + return; + } + if (!fl_visual->red_mask) + Fl::fatal("Can't do %d bits_per_pixel colormap",xi.bits_per_pixel); +# endif + + // otherwise it is a TrueColor visual: + + int rs = fl_redshift; + int gs = fl_greenshift; + int bs = fl_blueshift; + + switch (bytes_per_pixel) { + + case 2: + // All 16-bit TrueColor visuals are supported on any machine with + // 24 or more bits per integer. +# ifdef U16 + xi.byte_order = WORDS_BIGENDIAN; +# else + xi.byte_order = 1; +# endif + if (rs == 11 && gs == 6 && bs == 0 && fl_extrashift == 3) { + converter = c565_converter; + mono_converter = m565_converter; + } else { + converter = color16_converter; + mono_converter = mono16_converter; + } + break; + + case 3: + if (xi.byte_order) {rs = 16-rs; gs = 16-gs; bs = 16-bs;} + if (rs == 0 && gs == 8 && bs == 16) { + converter = rgb_converter; + mono_converter = rrr_converter; + } else if (rs == 16 && gs == 8 && bs == 0) { + converter = bgr_converter; + mono_converter = rrr_converter; + } else { + Fl::fatal("Can't do arbitrary 24bit color"); + } + break; + + case 4: + if ((xi.byte_order!=0) != WORDS_BIGENDIAN) + {rs = 24-rs; gs = 24-gs; bs = 24-bs;} + if (rs == 0 && gs == 8 && bs == 16) { + converter = xbgr_converter; + mono_converter = xrrr_converter; + } else if (rs == 24 && gs == 16 && bs == 8) { + converter = rgbx_converter; + mono_converter = rrrx_converter; + } else if (rs == 8 && gs == 16 && bs == 24) { + converter = bgrx_converter; + mono_converter = rrrx_converter; + } else if (rs == 16 && gs == 8 && bs == 0) { + converter = xrgb_converter; + mono_converter = xrrr_converter; + } else { + xi.byte_order = WORDS_BIGENDIAN; + converter = color32_converter; + mono_converter = mono32_converter; + } + break; + + default: + Fl::fatal("Can't do %d bits_per_pixel",xi.bits_per_pixel); + } + +} + +# define MAXBUFFER 0x40000 // 256k + +static void innards(const uchar *buf, int X, int Y, int W, int H, + int delta, int linedelta, int mono, + Fl_Draw_Image_Cb cb, void* userdata) +{ + if (!linedelta) linedelta = W*delta; + + int dx, dy, w, h; + fl_clip_box(X,Y,W,H,dx,dy,w,h); + if (w<=0 || h<=0) return; + dx -= X; + dy -= Y; + + if (!bytes_per_pixel) figure_out_visual(); + xi.width = w; + xi.height = h; + + void (*conv)(const uchar *from, uchar *to, int w, int delta) = converter; + if (mono) conv = mono_converter; + + // See if the data is already in the right format. Unfortunately + // some 32-bit x servers (XFree86) care about the unknown 8 bits + // and they must be zero. I can't confirm this for user-supplied + // data, so the 32-bit shortcut is disabled... + // This can set bytes_per_line negative if image is bottom-to-top + // I tested it on Linux, but it may fail on other Xlib implementations: + if (buf && ( +# if 0 // set this to 1 to allow 32-bit shortcut + delta == 4 && +# if WORDS_BIGENDIAN + conv == rgbx_converter +# else + conv == xbgr_converter +# endif + || +# endif + conv == rgb_converter && delta==3 + ) && !(linedelta&scanline_add)) { + xi.data = (char *)(buf+delta*dx+linedelta*dy); + xi.bytes_per_line = linedelta; + + } else { + int linesize = ((w*bytes_per_pixel+scanline_add)&scanline_mask)/sizeof(STORETYPE); + int blocking = h; + static STORETYPE *buffer; // our storage, always word aligned + static long buffer_size; + {int size = linesize*h; + if (size > MAXBUFFER) { + size = MAXBUFFER; + blocking = MAXBUFFER/linesize; + } + if (size > buffer_size) { + delete[] buffer; + buffer_size = size; + buffer = new STORETYPE[size]; + }} + xi.data = (char *)buffer; + xi.bytes_per_line = linesize*sizeof(STORETYPE); + if (buf) { + buf += delta*dx+linedelta*dy; + for (int j=0; j-3),0,0); +} +void fl_draw_image(Fl_Draw_Image_Cb cb, void* data, + int x, int y, int w, int h,int d) { + innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data); +} +void fl_draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){ + innards(buf,x,y,w,h,d,l,1,0,0); +} +void fl_draw_image_mono(Fl_Draw_Image_Cb cb, void* data, + int x, int y, int w, int h,int d) { + innards(0,x,y,w,h,d,0,1,cb,data); +} + +void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) { + if (fl_visual->depth > 16) { + fl_color(r,g,b); + fl_rectf(x,y,w,h); + } else { + uchar c[3]; + c[0] = r; c[1] = g; c[2] = b; + innards(c,x,y,w,h,0,0,0,0,0); + } +} + +#endif + +// +// End of "$Id: fl_draw_image.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_draw_image_mac.cxx b/third_party/windows/fltk-1.1.10/src/fl_draw_image_mac.cxx new file mode 100644 index 0000000..63abe27 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_draw_image_mac.cxx @@ -0,0 +1,274 @@ +// +// "$Id: fl_draw_image_mac.cxx 5614 2007-01-18 15:25:09Z matt $" +// +// MacOS image drawing code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +//////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#define MAXBUFFER 0x40000 // 256k + +/** + * draw an image based on the input parameters + * + * buf: image source data + * X, Y: position (in buffer?!) + * W, H: size of picture (in pixel?) + * delta: distance from pixel to pixel in buf in bytes + * linedelta: distance from line to line in buf in bytes + * mono: if set, pixel is one byte - if zero, pixel is 3 byte + * cb: callback to copy image data into (RGB?) buffer + * buf: pointer to first byte in image source + * x, y: position in buffer + * w: width (in bytes?) + * dst: destination buffer + * userdata: ? + */ +static void innards(const uchar *buf, int X, int Y, int W, int H, + int delta, int linedelta, int mono, + Fl_Draw_Image_Cb cb, void* userdata) +{ + if (!linedelta) linedelta = W*delta; + +#ifdef __APPLE_QD__ + // theoretically, if the current GPort permits, we could write + // directly into it, avoiding the temporary GWorld. For now I + // will go the safe way... . + char direct = 0; + GWorldPtr gw; + Rect bounds; + bounds.left=0; bounds.right=W; bounds.top=0; bounds.bottom=H; + QDErr err = NewGWorld( &gw, 32, &bounds, 0L, 0L, useTempMem ); + if (err==noErr && gw) { + PixMapHandle pm = GetGWorldPixMap( gw ); + if ( pm ) { + LockPixels( pm ); + if ( *pm ) { + uchar *base = (uchar*)GetPixBaseAddr( pm ); + if ( base ) { + PixMapPtr pmp = *pm; + // make absolutely sure that we can use a direct memory write to + // create the pixmap! + if ( pmp->pixelType == 16 || pmp->pixelSize == 32 || pmp->cmpCount == 3 || pmp->cmpSize == 8 ) { + int rowBytes = pmp->rowBytes & 0x3fff; + if ( cb ) + { + uchar *tmpBuf = new uchar[ W*delta ]; + if ( mono ) delta -= 1; else delta -= 3; + for ( int i=0; i-3),0,0); +} +void fl_draw_image(Fl_Draw_Image_Cb cb, void* data, + int x, int y, int w, int h,int d) { + innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data); +} +void fl_draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){ + innards(buf,x,y,w,h,d,l,1,0,0); +} +void fl_draw_image_mono(Fl_Draw_Image_Cb cb, void* data, + int x, int y, int w, int h,int d) { + innards(0,x,y,w,h,d,0,1,cb,data); +} + +void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) { + fl_color(r,g,b); + fl_rectf(x,y,w,h); +} + +// +// End of "$Id: fl_draw_image_mac.cxx 5614 2007-01-18 15:25:09Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_draw_image_win32.cxx b/third_party/windows/fltk-1.1.10/src/fl_draw_image_win32.cxx new file mode 100644 index 0000000..2f505a1 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_draw_image_win32.cxx @@ -0,0 +1,325 @@ +// +// "$Id: fl_draw_image_win32.cxx 6843 2009-08-24 19:53:06Z AlbrechtS $" +// +// WIN32 image drawing code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// I hope a simple and portable method of drawing color and monochrome +// images. To keep this simple, only a single storage type is +// supported: 8 bit unsigned data, byte order RGB, and pixels are +// stored packed into rows with the origin at the top-left. It is +// possible to alter the size of pixels with the "delta" argument, to +// add alpha or other information per pixel. It is also possible to +// change the origin and direction of the image data by messing with +// the "delta" and "linedelta", making them negative, though this may +// defeat some of the shortcuts in translating the image for X. + +// Unbelievably (since it conflicts with how most PC software works) +// Micro$oft picked a bottom-up and BGR storage format for their +// DIB images. I'm pretty certain there is a way around this, but +// I can't find any other than the brute-force method of drawing +// each line as a seperate image. This may also need to be done +// if the delta is any amount other than 1, 3, or 4. + +//////////////////////////////////////////////////////////////// + +#include +#include +#include +#include + +#define MAXBUFFER 0x40000 // 256k + +#if USE_COLORMAP + +// error-diffusion dither into the FLTK colormap +static void dither(uchar* to, const uchar* from, int w, int delta) { + static int ri, gi, bi, dir; + int r=ri, g=gi, b=bi; + int d, td; + if (dir) { + dir = 0; + from = from+(w-1)*delta; + to = to+(w-1); + d = -delta; + td = -1; + } else { + dir = 1; + d = delta; + td = 1; + } + for (; w--; from += d, to += td) { + r += from[0]; if (r < 0) r = 0; else if (r>255) r = 255; + int rr = r*FL_NUM_RED/256; + r -= rr*255/(FL_NUM_RED-1); + g += from[1]; if (g < 0) g = 0; else if (g>255) g = 255; + int gg = g*FL_NUM_GREEN/256; + g -= gg*255/(FL_NUM_GREEN-1); + b += from[2]; if (b < 0) b = 0; else if (b>255) b = 255; + int bb = b*FL_NUM_BLUE/256; + b -= bb*255/(FL_NUM_BLUE-1); + *to = uchar(FL_COLOR_CUBE+(bb*FL_NUM_RED+rr)*FL_NUM_GREEN+gg); + } + ri = r; gi = g; bi = b; +} + +// error-diffusion dither into the FLTK colormap +static void monodither(uchar* to, const uchar* from, int w, int delta) { + static int ri,dir; + int r=ri; + int d, td; + if (dir) { + dir = 0; + from = from+(w-1)*delta; + to = to+(w-1); + d = -delta; + td = -1; + } else { + dir = 1; + d = delta; + td = 1; + } + for (; w--; from += d, to += td) { + r += *from; if (r < 0) r = 0; else if (r>255) r = 255; + int rr = r*FL_NUM_GRAY/256; + r -= rr*255/(FL_NUM_GRAY-1); + *to = uchar(FL_GRAY_RAMP+rr); + } + ri = r; +} + +#endif // USE_COLORMAP + +static void innards(const uchar *buf, int X, int Y, int W, int H, + int delta, int linedelta, int depth, + Fl_Draw_Image_Cb cb, void* userdata) +{ + char indexed = 0; + +#if USE_COLORMAP + indexed = (fl_palette != 0); +#endif + + if (depth==0) depth = 3; + if (indexed || !fl_can_do_alpha_blending()) + depth = (depth-1)|1; + + if (!linedelta) linedelta = W*delta; + + int x, y, w, h; + fl_clip_box(X,Y,W,H,x,y,w,h); + if (w<=0 || h<=0) return; + if (buf) buf += (x-X)*delta + (y-Y)*linedelta; + + static U32 bmibuffer[256+12]; + BITMAPINFO &bmi = *((BITMAPINFO*)bmibuffer); + if (!bmi.bmiHeader.biSize) { + bmi.bmiHeader.biSize = sizeof(bmi)-4; // does it use this to determine type? + bmi.bmiHeader.biPlanes = 1; + bmi.bmiHeader.biCompression = BI_RGB; + bmi.bmiHeader.biXPelsPerMeter = 0; + bmi.bmiHeader.biYPelsPerMeter = 0; + bmi.bmiHeader.biClrUsed = 0; + bmi.bmiHeader.biClrImportant = 0; + } +#if USE_COLORMAP + if (indexed) { + for (short i=0; i<256; i++) { + *((short*)(bmi.bmiColors)+i) = i; + } + } else +#endif + if (depth<3) { + for (int i=0; i<256; i++) { + bmi.bmiColors[i].rgbBlue = (uchar)i; + bmi.bmiColors[i].rgbGreen = (uchar)i; + bmi.bmiColors[i].rgbRed = (uchar)i; + bmi.bmiColors[i].rgbReserved = (uchar)0; // must be zero + } + } + bmi.bmiHeader.biWidth = w; +#if USE_COLORMAP + bmi.bmiHeader.biBitCount = indexed ? 8 : depth*8; + int pixelsize = indexed ? 1 : depth; +#else + bmi.bmiHeader.biBitCount = depth*8; + int pixelsize = depth; +#endif + if (depth==2) { // special case: gray with alpha + bmi.bmiHeader.biBitCount = 32; + pixelsize = 4; + } + int linesize = (pixelsize*w+3)&~3; + + static U32* buffer; + int blocking = h; + {int size = linesize*h; + if (size > MAXBUFFER) { + size = MAXBUFFER; + blocking = MAXBUFFER/linesize; + } + static long buffer_size; + if (size > buffer_size) { + delete[] buffer; + buffer_size = size; + buffer = new U32[(size+3)/4]; + }} + bmi.bmiHeader.biHeight = blocking; + static U32* line_buffer; + if (!buf) { + int size = W*delta; + static int line_buf_size; + if (size > line_buf_size) { + delete[] line_buffer; + line_buf_size = size; + line_buffer = new U32[(size+3)/4]; + } + } + for (int j=0; j>8; + to[0] = gray; + to[1] = gray; + to[2] = gray; + to[3] = a; + } + break; + case 3: + for (i=w; i--; from += delta, to += 3) { + uchar r = from[0]; + to[0] = from[2]; + to[1] = from[1]; + to[2] = r; + } + break; + case 4: + for (i=w; i--; from += delta, to += 4) { + uchar a = from[3]; + uchar r = from[0]; + to[0] = (from[2]*a)>>8; + to[1] = (from[1]*a)>>8; + to[2] = (r*a)>>8; + to[3] = from[3]; + } + break; + } + } + } + SetDIBitsToDevice(fl_gc, x, y+j-k, w, k, 0, 0, 0, k, + (LPSTR)((uchar*)buffer+(blocking-k)*linesize), + &bmi, +#if USE_COLORMAP + indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS +#else + DIB_RGB_COLORS +#endif + ); + } +} + +static int fl_abs(int v) { return v<0 ? -v : v; } + +void fl_draw_image(const uchar* buf, int x, int y, int w, int h, int d, int l){ + if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { + d ^= FL_IMAGE_WITH_ALPHA; + innards(buf,x,y,w,h,d,l,fl_abs(d),0,0); + } else { + innards(buf,x,y,w,h,d,l,(d<3&&d>-3),0,0); + } +} + +void fl_draw_image(Fl_Draw_Image_Cb cb, void* data, + int x, int y, int w, int h,int d) { + if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { + d ^= FL_IMAGE_WITH_ALPHA; + innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data); + } else { + innards(0,x,y,w,h,d,0,(d<3&&d>-3),cb,data); + } +} + +void fl_draw_image_mono(const uchar* buf, int x, int y, int w, int h, int d, int l){ + if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { + d ^= FL_IMAGE_WITH_ALPHA; + innards(buf,x,y,w,h,d,l,1,0,0); + } else { + innards(buf,x,y,w,h,d,l,1,0,0); + } +} + +void fl_draw_image_mono(Fl_Draw_Image_Cb cb, void* data, + int x, int y, int w, int h,int d) { + if (fl_abs(d)&FL_IMAGE_WITH_ALPHA) { + d ^= FL_IMAGE_WITH_ALPHA; + innards(0,x,y,w,h,d,0,1,cb,data); + } else { + innards(0,x,y,w,h,d,0,1,cb,data); + } +} + +void fl_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) { +#if USE_COLORMAP + // use the error diffusion dithering code to produce a much nicer block: + if (fl_palette) { + uchar c[3]; + c[0] = r; c[1] = g; c[2] = b; + innards(c,x,y,w,h,0,0,0,0,0); + return; + } +#endif + fl_color(r,g,b); + fl_rectf(x,y,w,h); +} + +// +// End of "$Id: fl_draw_image_win32.cxx 6843 2009-08-24 19:53:06Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_draw_pixmap.cxx b/third_party/windows/fltk-1.1.10/src/fl_draw_pixmap.cxx new file mode 100644 index 0000000..c76be55 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_draw_pixmap.cxx @@ -0,0 +1,340 @@ +// +// "$Id: fl_draw_pixmap.cxx 6026 2008-02-14 18:17:06Z matt $" +// +// Pixmap drawing code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Implemented without using the xpm library (which I can't use because +// it interferes with the color cube used by fl_draw_image). +// Current implementation is cheap and slow, and works best on a full-color +// display. Transparency is not handled, and colors are dithered to +// the color cube. Color index is achieved by adding the id +// characters together! Also mallocs a lot of temporary memory! +// Notice that there is no pixmap file interface. This is on purpose, +// as I want to discourage programs that require support files to work. +// All data needed by a program ui should be compiled in!!! + +#include +#include +#include +#include +#include "flstring.h" + +static int ncolors, chars_per_pixel; + +int fl_measure_pixmap(/*const*/ char* const* data, int &w, int &h) { + return fl_measure_pixmap((const char*const*)data,w,h); +} + +int fl_measure_pixmap(const char * const *data, int &w, int &h) { + int i = sscanf(data[0],"%d%d%d%d",&w,&h,&ncolors,&chars_per_pixel); + if (i<4 || w<=0 || h<=0 || + chars_per_pixel!=1 && chars_per_pixel!=2) return w=0; + return 1; +} + +#ifdef U64 + +// The callback from fl_draw_image to get a row of data passes this: +struct pixmap_data { + int w, h; + const uchar*const* data; + union { + U64 colors[256]; + U64* byte1[256]; + }; +}; + +// callback for 1 byte per pixel: +static void cb1(void*v, int x, int y, int w, uchar* buf) { + pixmap_data& d = *(pixmap_data*)v; + const uchar* p = d.data[y]+x; + U64* q = (U64*)buf; + for (int X=w; X>0; X-=2, p += 2) { + if (X>1) { +# if WORDS_BIGENDIAN + *q++ = (d.colors[p[0]]<<32) | d.colors[p[1]]; +# else + *q++ = (d.colors[p[1]]<<32) | d.colors[p[0]]; +# endif + } else { +# if WORDS_BIGENDIAN + *q++ = d.colors[p[0]]<<32; +# else + *q++ = d.colors[p[0]]; +# endif + } + } +} + +// callback for 2 bytes per pixel: +static void cb2(void*v, int x, int y, int w, uchar* buf) { + pixmap_data& d = *(pixmap_data*)v; + const uchar* p = d.data[y]+2*x; + U64* q = (U64*)buf; + for (int X=w; X>0; X-=2) { + U64* colors = d.byte1[*p++]; + int index = *p++; + if (X>1) { + U64* colors1 = d.byte1[*p++]; + int index1 = *p++; +# if WORDS_BIGENDIAN + *q++ = (colors[index]<<32) | colors1[index1]; +# else + *q++ = (colors1[index1]<<32) | colors[index]; +# endif + } else { +# if WORDS_BIGENDIAN + *q++ = colors[index]<<32; +# else + *q++ = colors[index]; +# endif + } + } +} + +#else // U32 + +// The callback from fl_draw_image to get a row of data passes this: +struct pixmap_data { + int w, h; + const uchar*const* data; + union { + U32 colors[256]; + U32* byte1[256]; + }; +}; + +# ifndef __APPLE_QUARTZ__ + +// callback for 1 byte per pixel: +static void cb1(void*v, int x, int y, int w, uchar* buf) { + pixmap_data& d = *(pixmap_data*)v; + const uchar* p = d.data[y]+x; + U32* q = (U32*)buf; + for (int X=w; X--;) *q++ = d.colors[*p++]; +} + +// callback for 2 bytes per pixel: +static void cb2(void*v, int x, int y, int w, uchar* buf) { + pixmap_data& d = *(pixmap_data*)v; + const uchar* p = d.data[y]+2*x; + U32* q = (U32*)buf; + for (int X=w; X--;) { + U32* colors = d.byte1[*p++]; + *q++ = colors[*p++]; + } +} + +# endif // !__APPLE_QUARTZ__ + +#endif // U64 else U32 + +uchar **fl_mask_bitmap; // if non-zero, create bitmap and store pointer here + +int fl_draw_pixmap(/*const*/ char* const* data, int x,int y,Fl_Color bg) { + return fl_draw_pixmap((const char*const*)data,x,y,bg); +} + +int fl_draw_pixmap(const char*const* di, int x, int y, Fl_Color bg) { + pixmap_data d; + if (!fl_measure_pixmap(di, d.w, d.h)) return 0; + const uchar*const* data = (const uchar*const*)(di+1); + int transparent_index = -1; + + if (ncolors < 0) { // FLTK (non standard) compressed colormap + ncolors = -ncolors; + const uchar *p = *data++; + // if first color is ' ' it is transparent (put it later to make + // it not be transparent): + if (*p == ' ') { + uchar* c = (uchar*)&d.colors[(int)' ']; +#ifdef U64 + *(U64*)c = 0; +# if WORDS_BIGENDIAN + c += 4; +# endif +#endif + transparent_index = ' '; + Fl::get_color(bg, c[0], c[1], c[2]); c[3] = 0; + p += 4; + ncolors--; + } + // read all the rest of the colors: + for (int i=0; i < ncolors; i++) { + uchar* c = (uchar*)&d.colors[*p++]; +#ifdef U64 + *(U64*)c = 0; +# if WORDS_BIGENDIAN + c += 4; +# endif +#endif + *c++ = *p++; + *c++ = *p++; + *c++ = *p++; +#ifdef __APPLE_QUARTZ__ + *c = 255; +#else + *c = 0; +#endif + } + } else { // normal XPM colormap with names + if (chars_per_pixel>1) memset(d.byte1, 0, sizeof(d.byte1)); + for (int i=0; i1) { +#ifdef U64 + U64* colors = d.byte1[ind]; + if (!colors) colors = d.byte1[ind] = new U64[256]; +#else + U32* colors = d.byte1[ind]; + if (!colors) colors = d.byte1[ind] = new U32[256]; +#endif + c = (uchar*)&colors[*p]; + ind = (ind<<8)|*p++; + } else { + c = (uchar *)&d.colors[ind]; + } + // look for "c word", or last word if none: + const uchar *previous_word = p; + for (;;) { + while (*p && isspace(*p)) p++; + uchar what = *p++; + while (*p && !isspace(*p)) p++; + while (*p && isspace(*p)) p++; + if (!*p) {p = previous_word; break;} + if (what == 'c') break; + previous_word = p; + while (*p && !isspace(*p)) p++; + } +#ifdef U64 + *(U64*)c = 0; +# if WORDS_BIGENDIAN + c += 4; +# endif +#endif +#ifdef __APPLE_QUARTZ__ + c[3] = 255; +#endif + if (!fl_parse_color((const char*)p, c[0], c[1], c[2])) { + // assume "None" or "#transparent" for any errors + // "bg" should be transparent... + Fl::get_color(bg, c[0], c[1], c[2]); +#ifdef __APPLE_QUARTZ__ + c[3] = 0; +#endif + transparent_index = ind; + } + } + } + d.data = data; + +#ifndef __APPLE_QUARTZ__ + + // build the mask bitmap used by Fl_Pixmap: + if (fl_mask_bitmap && transparent_index >= 0) { + int W = (d.w+7)/8; + uchar* bitmap = new uchar[W * d.h]; + *fl_mask_bitmap = bitmap; + for (int Y = 0; Y < d.h; Y++) { + const uchar* p = data[Y]; + if (chars_per_pixel <= 1) { + int dw = d.w; + for (int X = 0; X < W; X++) { + uchar b = (dw-->0 && *p++ != transparent_index); + if (dw-->0 && *p++ != transparent_index) b |= 2; + if (dw-->0 && *p++ != transparent_index) b |= 4; + if (dw-->0 && *p++ != transparent_index) b |= 8; + if (dw-->0 && *p++ != transparent_index) b |= 16; + if (dw-->0 && *p++ != transparent_index) b |= 32; + if (dw-->0 && *p++ != transparent_index) b |= 64; + if (dw-->0 && *p++ != transparent_index) b |= 128; + *bitmap++ = b; + } + } else { + uchar b = 0, bit = 1; + for (int X = 0; X < d.w; X++) { + int ind = *p++; + ind = (ind<<8) | (*p++); + if (ind != transparent_index) b |= bit; + + if (bit < 128) bit <<= 1; + else { + *bitmap++ = b; + b = 0; + bit = 1; + } + } + + if (bit > 1) *bitmap++ = b; + } + } + } + + fl_draw_image(chars_per_pixel==1 ? cb1 : cb2, &d, x, y, d.w, d.h, 4); + +#else // __APPLE_QUARTZ__ + + bool transparent = (transparent_index>=0); + transparent = true; + U32 *array = new U32[d.w * d.h], *q = array; + for (int Y = 0; Y < d.h; Y++) { + const uchar* p = data[Y]; + if (chars_per_pixel <= 1) { + for (int X = 0; X < d.w; X++) { + *q++ = d.colors[*p++]; + } + } else { + for (int X = 0; X < d.w; X++) { + U32* colors = d.byte1[*p++]; + *q++ = colors[*p++]; + } + } + } + CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); + CGDataProviderRef src = CGDataProviderCreateWithData( 0L, array, d.w * d.h * 4, 0L); + CGImageRef img = CGImageCreate(d.w, d.h, 8, 4*8, 4*d.w, + lut, transparent?kCGImageAlphaLast:kCGImageAlphaNoneSkipLast, + src, 0L, false, kCGRenderingIntentDefault); + CGColorSpaceRelease(lut); + CGDataProviderRelease(src); + CGRect rect = { { x, y} , { d.w, d.h } }; + Fl_X::q_begin_image(rect, 0, 0, d.w, d.h); + CGContextDrawImage(fl_gc, rect, img); + Fl_X::q_end_image(); + CGImageRelease(img); + delete array; + +#endif // !__APPLE_QUARTZ__ + + if (chars_per_pixel > 1) for (int i = 0; i < 256; i++) delete[] d.byte1[i]; + return 1; +} + +// +// End of "$Id: fl_draw_pixmap.cxx 6026 2008-02-14 18:17:06Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_encoding_latin1.cxx b/third_party/windows/fltk-1.1.10/src/fl_encoding_latin1.cxx new file mode 100644 index 0000000..a3ef041 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_encoding_latin1.cxx @@ -0,0 +1,137 @@ +// +// "$Id: fl_encoding_latin1.cxx 6922 2009-10-29 20:00:12Z matt $" +// +// Convert MSWindows-1252 (Latin-1) encoded text to the local encoding. +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include "flstring.h" + +#ifdef __APPLE__ + +// These function assume a western code page. If you need to support +// scripts that are not part of this code page, you might want to +// take a look at FLTK2, which uses utf8 for text encoding. +// +// By keeping these conversion tables in their own module, they will not +// be statically linked (by a smart linker) unless actually used. +// +// On MS-Windows, nothing need to be converted. We simply return the +// original pointer. +// +// Most X11 implementations seem to default to Latin-1 as a code since it +// is a superset of ISO 8859-1, the original wetsern codepage on X11. +// +// Apple's OS X however renders text in MacRoman for western settings. The +// lookup tables below will convert all common character codes and replace +// unknown characters with an upsidedown question mark. + +// This table converts MSWindows-1252/Latin 1 into MacRoman encoding +static uchar latin2roman[128] = { +0xdb, 0xc0, 0xe2, 0xc4, 0xe3, 0xc9, 0xa0, 0xe0, 0xf6, 0xe4, 0xc0, 0xdc, 0xce, 0xc0, 0xc0, 0xc0, +0xc0, 0xd4, 0xd5, 0xd2, 0xd3, 0xa5, 0xd0, 0xd1, 0xf7, 0xaa, 0xc0, 0xdd, 0xcf, 0xc0, 0xc0, 0xd9, +0xca, 0xc1, 0xa2, 0xa3, 0xc0, 0xb4, 0xc0, 0xa4, 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0xc0, 0xa8, 0xf8, +0xa1, 0xb1, 0xc0, 0xc0, 0xab, 0xb5, 0xa6, 0xe1, 0xfc, 0xc0, 0xbc, 0xc8, 0xc0, 0xc0, 0xc0, 0xc0, +0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, +0xc0, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0xc0, 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xc0, 0xc0, 0xa7, +0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, +0xc0, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xc0, 0xc0, 0xd8 +}; + +// This table converts MacRoman into MSWindows-1252/Latin 1 +static uchar roman2latin[128] = { +0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, +0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, +0x86, 0xb0, 0xa2, 0xa3, 0xa7, 0x95, 0xb6, 0xdf, 0xae, 0xa9, 0x99, 0xb4, 0xa8, 0xbf, 0xc6, 0xd8, +0xbf, 0xb1, 0xbf, 0xbf, 0xa5, 0xb5, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xaa, 0xba, 0xbf, 0xe6, 0xf8, +0xbf, 0xa1, 0xac, 0xbf, 0x83, 0xbf, 0xbf, 0xab, 0xbb, 0x85, 0xa0, 0xc0, 0xc3, 0xd5, 0x8c, 0x9c, +0x96, 0x97, 0x93, 0x94, 0x91, 0x92, 0xf7, 0xbf, 0xff, 0x9f, 0xbf, 0x80, 0x8b, 0x9b, 0xbf, 0xbf, +0x87, 0xb7, 0x82, 0x84, 0x89, 0xc2, 0xca, 0xc1, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, +0xbf, 0xd2, 0xda, 0xdb, 0xd9, 0xbf, 0x88, 0x98, 0xaf, 0xbf, 0xbf, 0xbf, 0xb8, 0xbf, 0xbf, 0xbf +}; + +static char *buf = 0; +static int n_buf = 0; + +const char *fl_latin1_to_local(const char *t, int n) +{ + if (n==-1) n = strlen(t)+1; + if (n>=n_buf) { + n_buf = (n + 257) & 0x7fffff00; + if (buf) free(buf); + buf = (char*)malloc(n_buf); + } + const uchar *src = (const uchar*)t; + uchar *dst = (uchar*)buf; + for ( ; n>0; n--) { + uchar c = *src++; + if (c>127) + *dst++ = latin2roman[c-128]; + else + *dst++ = c; + } + //*dst = 0; // this would be wrong! + return buf; +} + +const char *fl_local_to_latin1(const char *t, int n) +{ + if (n==-1) n = strlen(t)+1; + if (n>=n_buf) { + n_buf = (n + 257) & 0x7fffff00; + if (buf) free(buf); + buf = (char*)malloc(n_buf); + } + const uchar *src = (const uchar*)t; + uchar *dst = (uchar*)buf; + for ( ; n>0; n--) { + uchar c = *src++; + if (c>127) + *dst++ = roman2latin[c-128]; + else + *dst++ = c; + } + //*dst = 0; // this would be wrong + return buf; +} + +#else + +const char *fl_latin1_to_local(const char *t, int) +{ + return t; +} + +const char *fl_local_to_latin1(const char *t, int) +{ + return t; +} + +#endif + +// +// End of "$Id: fl_encoding_latin1.cxx 6922 2009-10-29 20:00:12Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_encoding_mac_roman.cxx b/third_party/windows/fltk-1.1.10/src/fl_encoding_mac_roman.cxx new file mode 100644 index 0000000..838a8b0 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_encoding_mac_roman.cxx @@ -0,0 +1,134 @@ +// +// "$Id: fl_encoding_mac_roman.cxx 6922 2009-10-29 20:00:12Z matt $" +// +// Convert Mac Roman encoded text to the local encoding. +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include "flstring.h" + +// These function assume a western code page. If you need to support +// scripts that are not part of this code page, you might want to +// take a look at FLTK2, which uses utf8 for text encoding. +// +// By keeping these conversion tables in their own module, they will not +// be statically linked (by a smart linker) unless actually used. +// +// On Mac OS X, nothing need to be converted. We simply return the +// original pointer. +// +// MSWindows and X11 render text in ISO or Latin-1 for western settings. The +// lookup tables below will convert all common character codes and replace +// unknown characters with an upsidedown question mark. + +#ifdef __APPLE__ + +const char *fl_mac_roman_to_local(const char *t, int) +{ + return t; +} + +const char *fl_local_to_mac_roman(const char *t, int) +{ + return t; +} + +#else + +// This table converts MSWindows-1252/Latin 1 into MacRoman encoding +static uchar latin2roman[128] = { +0xdb, 0xc0, 0xe2, 0xc4, 0xe3, 0xc9, 0xa0, 0xe0, 0xf6, 0xe4, 0xc0, 0xdc, 0xce, 0xc0, 0xc0, 0xc0, +0xc0, 0xd4, 0xd5, 0xd2, 0xd3, 0xa5, 0xd0, 0xd1, 0xf7, 0xaa, 0xc0, 0xdd, 0xcf, 0xc0, 0xc0, 0xd9, +0xca, 0xc1, 0xa2, 0xa3, 0xc0, 0xb4, 0xc0, 0xa4, 0xac, 0xa9, 0xbb, 0xc7, 0xc2, 0xc0, 0xa8, 0xf8, +0xa1, 0xb1, 0xc0, 0xc0, 0xab, 0xb5, 0xa6, 0xe1, 0xfc, 0xc0, 0xbc, 0xc8, 0xc0, 0xc0, 0xc0, 0xc0, +0xcb, 0xe7, 0xe5, 0xcc, 0x80, 0x81, 0xae, 0x82, 0xe9, 0x83, 0xe6, 0xe8, 0xed, 0xea, 0xeb, 0xec, +0xc0, 0x84, 0xf1, 0xee, 0xef, 0xcd, 0x85, 0xc0, 0xaf, 0xf4, 0xf2, 0xf3, 0x86, 0xc0, 0xc0, 0xa7, +0x88, 0x87, 0x89, 0x8b, 0x8a, 0x8c, 0xbe, 0x8d, 0x8f, 0x8e, 0x90, 0x91, 0x93, 0x92, 0x94, 0x95, +0xc0, 0x96, 0x98, 0x97, 0x99, 0x9b, 0x9a, 0xd6, 0xbf, 0x9d, 0x9c, 0x9e, 0x9f, 0xc0, 0xc0, 0xd8 +}; + +// This table converts MacRoman into MSWindows-1252/Latin 1 +static uchar roman2latin[128] = { +0xc4, 0xc5, 0xc7, 0xc9, 0xd1, 0xd6, 0xdc, 0xe1, 0xe0, 0xe2, 0xe4, 0xe3, 0xe5, 0xe7, 0xe9, 0xe8, +0xea, 0xeb, 0xed, 0xec, 0xee, 0xef, 0xf1, 0xf3, 0xf2, 0xf4, 0xf6, 0xf5, 0xfa, 0xf9, 0xfb, 0xfc, +0x86, 0xb0, 0xa2, 0xa3, 0xa7, 0x95, 0xb6, 0xdf, 0xae, 0xa9, 0x99, 0xb4, 0xa8, 0xbf, 0xc6, 0xd8, +0xbf, 0xb1, 0xbf, 0xbf, 0xa5, 0xb5, 0xbf, 0xbf, 0xbf, 0xbf, 0xbf, 0xaa, 0xba, 0xbf, 0xe6, 0xf8, +0xbf, 0xa1, 0xac, 0xbf, 0x83, 0xbf, 0xbf, 0xab, 0xbb, 0x85, 0xa0, 0xc0, 0xc3, 0xd5, 0x8c, 0x9c, +0x96, 0x97, 0x93, 0x94, 0x91, 0x92, 0xf7, 0xbf, 0xff, 0x9f, 0xbf, 0x80, 0x8b, 0x9b, 0xbf, 0xbf, +0x87, 0xb7, 0x82, 0x84, 0x89, 0xc2, 0xca, 0xc1, 0xcb, 0xc8, 0xcd, 0xce, 0xcf, 0xcc, 0xd3, 0xd4, +0xbf, 0xd2, 0xda, 0xdb, 0xd9, 0xbf, 0x88, 0x98, 0xaf, 0xbf, 0xbf, 0xbf, 0xb8, 0xbf, 0xbf, 0xbf +}; + +static char *buf = 0; +static int n_buf = 0; + +const char *fl_local_to_mac_roman(const char *t, int n) +{ + if (n==-1) n = strlen(t)+1; + if (n>=n_buf) { + n_buf = (n + 257) & 0x7fffff00; + if (buf) free(buf); + buf = (char*)malloc(n_buf); + } + const uchar *src = (const uchar*)t; + uchar *dst = (uchar*)buf; + for ( ; n>0; n--) { + uchar c = *src; + if (c>127) + *dst++ = latin2roman[c-128]; + else + *dst++ = c; + } + //*dst = 0; // this would be wrong! + return buf; +} + +const char *fl_mac_roman_to_local(const char *t, int n) +{ + if (n==-1) n = strlen(t)+1; + if (n>=n_buf) { + n_buf = (n + 257) & 0x7fffff00; + if (buf) free(buf); + buf = (char*)malloc(n_buf); + } + const uchar *src = (const uchar*)t; + uchar *dst = (uchar*)buf; + for ( ; n>0; n--) { + uchar c = *src++; + if (c>127) + *dst++ = roman2latin[c-128]; + else + *dst++ = c; + } + //*dst = 0; // this would be wrong + return buf; +} + +#endif + +// +// End of "$Id: fl_encoding_mac_roman.cxx 6922 2009-10-29 20:00:12Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_engraved_label.cxx b/third_party/windows/fltk-1.1.10/src/fl_engraved_label.cxx new file mode 100644 index 0000000..f882265 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_engraved_label.cxx @@ -0,0 +1,93 @@ +// +// "$Id: fl_engraved_label.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Engraved label drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Drawing code for XForms style engraved & embossed labels + +#include +#include +#include + +// data[] is dx, dy, color triples + +static void innards( + const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align, + int data[][3], int n) +{ + Fl_Align a1 = align; + if (a1 & FL_ALIGN_CLIP) { + fl_clip(X, Y, W, H); a1 = (Fl_Align)(a1&~FL_ALIGN_CLIP);} + fl_font((Fl_Font)o->font, o->size); + for (int i = 0; i < n; i++) { + fl_color((Fl_Color)(i < n-1 ? data[i][2] : o->color)); + fl_draw(o->value, X+data[i][0], Y+data[i][1], W, H, a1); + } + if (align & FL_ALIGN_CLIP) fl_pop_clip(); +} + +static void fl_shadow_label( + const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) +{ + static int data[2][3] = {{2,2,FL_DARK3},{0,0,0}}; + innards(o, X, Y, W, H, align, data, 2); +} + +static void fl_engraved_label( + const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) +{ + static int data[7][3] = { + {1,0,FL_LIGHT3},{1,1,FL_LIGHT3},{0,1,FL_LIGHT3}, + {-1,0,FL_DARK3},{-1,-1,FL_DARK3},{0,-1,FL_DARK3}, + {0,0,0}}; + innards(o, X, Y, W, H, align, data, 7); +} + +static void fl_embossed_label( + const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) +{ + static int data[7][3] = { + {-1,0,FL_LIGHT3},{-1,-1,FL_LIGHT3},{0,-1,FL_LIGHT3}, + {1,0,FL_DARK3},{1,1,FL_DARK3},{0,1,FL_DARK3}, + {0,0,0}}; + innards(o, X, Y, W, H, align, data, 7); +} + +Fl_Labeltype fl_define_FL_SHADOW_LABEL() { + Fl::set_labeltype(_FL_SHADOW_LABEL, fl_shadow_label, 0); + return _FL_SHADOW_LABEL; +} +Fl_Labeltype fl_define_FL_ENGRAVED_LABEL() { + Fl::set_labeltype(_FL_ENGRAVED_LABEL, fl_engraved_label, 0); + return _FL_ENGRAVED_LABEL; +} +Fl_Labeltype fl_define_FL_EMBOSSED_LABEL() { + Fl::set_labeltype(_FL_EMBOSSED_LABEL, fl_embossed_label, 0); + return _FL_EMBOSSED_LABEL; +} + +// +// End of "$Id: fl_engraved_label.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_file_dir.cxx b/third_party/windows/fltk-1.1.10/src/fl_file_dir.cxx new file mode 100644 index 0000000..f38c2dc --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_file_dir.cxx @@ -0,0 +1,178 @@ +// +// "$Id: fl_file_dir.cxx 5417 2006-09-05 09:57:41Z matt $" +// +// File chooser widget for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include "flstring.h" +#include +#include +#include + + +static Fl_File_Chooser *fc = (Fl_File_Chooser *)0; +static void (*current_callback)(const char*) = 0; +static const char *current_label = fl_ok; + + +// Do a file chooser callback... +static void callback(Fl_File_Chooser *, void*) { + if (current_callback && fc->value()) + (*current_callback)(fc->value()); +} + + +// Set the file chooser callback +void fl_file_chooser_callback(void (*cb)(const char*)) { + current_callback = cb; +} + + +// Set the "OK" button label +void fl_file_chooser_ok_label(const char *l) { + if (l) current_label = l; + else current_label = fl_ok; +} + + +// +// 'fl_file_chooser()' - Show a file chooser dialog and get a filename. +// + +char * // O - Filename or NULL +fl_file_chooser(const char *message, // I - Message in titlebar + const char *pat, // I - Filename pattern + const char *fname, // I - Initial filename selection + int relative) { // I - 0 for absolute path + static char retname[1024]; // Returned filename + + if (!fc) { + if (!fname || !*fname) fname = "."; + + fc = new Fl_File_Chooser(fname, pat, Fl_File_Chooser::CREATE, message); + fc->callback(callback, 0); + } else { + fc->type(Fl_File_Chooser::CREATE); + // see, if we use the same pattern between calls + char same_pattern = 0; + const char *fcf = fc->filter(); + if ( fcf && pat && strcmp(fcf, pat)==0) + same_pattern = 1; + else if ( (fcf==0L || *fcf==0) && (pat==0L || *pat==0) ) + same_pattern = 1; + // now set the pattern to the new pattern (even if they are the same) + fc->filter(pat); + fc->label(message); + + if (!fname) { // null pointer reuses same filename if pattern didn't change + if (!same_pattern && fc->value()) { + // if pattern is different, remove name but leave old directory: + strlcpy(retname, fc->value(), sizeof(retname)); + + char *p = strrchr(retname, '/'); + + if (p) { + // If the filename is "/foo", then the directory will be "/", not + // ""... + if (p == retname) + retname[1] = '\0'; + else + *p = '\0'; + } + // Set the directory... + fc->value(retname); + } else { + // re-use the previously selected name + } + } else if (!*fname) { // empty filename reuses directory with empty name + const char *fcv = fc->value(); + if (fcv) + strlcpy(retname, fc->value(), sizeof(retname)); + else + *retname = 0; + const char *n = fl_filename_name(retname); + if (n) *((char*)n) = 0; + fc->value(""); + fc->directory(retname); + } else { + fc->value(fname); + } + } + + fc->ok_label(current_label); + fc->show(); + + while (fc->shown()) + Fl::wait(); + + if (fc->value() && relative) { + fl_filename_relative(retname, sizeof(retname), fc->value()); + + return retname; + } else if (fc->value()) return (char *)fc->value(); + else return 0; +} + + +// +// 'fl_dir_chooser()' - Show a file chooser dialog and get a directory. +// + +char * // O - Directory or NULL +fl_dir_chooser(const char *message, // I - Message for titlebar + const char *fname, // I - Initial directory name + int relative) // I - 0 for absolute +{ + static char retname[1024]; // Returned directory name + + if (!fc) { + if (!fname || !*fname) fname = "."; + + fc = new Fl_File_Chooser(fname, "*", Fl_File_Chooser::CREATE | + Fl_File_Chooser::DIRECTORY, message); + fc->callback(callback, 0); + } else { + fc->type(Fl_File_Chooser::CREATE | Fl_File_Chooser::DIRECTORY); + fc->filter("*"); + if (fname && *fname) fc->value(fname); + fc->label(message); + } + + fc->show(); + + while (fc->shown()) + Fl::wait(); + + if (fc->value() && relative) { + fl_filename_relative(retname, sizeof(retname), fc->value()); + + return retname; + } else if (fc->value()) return (char *)fc->value(); + else return 0; +} + + +// +// End of "$Id: fl_file_dir.cxx 5417 2006-09-05 09:57:41Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_font.cxx b/third_party/windows/fltk-1.1.10/src/fl_font.cxx new file mode 100644 index 0000000..fa35c02 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_font.cxx @@ -0,0 +1,60 @@ +// +// "$Id: fl_font.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Font selection code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Select fonts from the FLTK font table. +#include "flstring.h" +#include +#include +#include +#include "Fl_Font.H" + +#include +#include + +#ifdef WIN32 +# include "fl_font_win32.cxx" +#elif defined(__APPLE__) +# include "fl_font_mac.cxx" +#elif USE_XFT +# include "fl_font_xft.cxx" +#else +# include "fl_font_x.cxx" +#endif // WIN32 + + +double fl_width(const char* c) { + if (c) return fl_width(c, strlen(c)); + else return 0.0f; +} + +void fl_draw(const char* str, int x, int y) { + fl_draw(str, strlen(str), x, y); +} + +// +// End of "$Id: fl_font.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_font_mac.cxx b/third_party/windows/fltk-1.1.10/src/fl_font_mac.cxx new file mode 100644 index 0000000..4b7d081 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_font_mac.cxx @@ -0,0 +1,379 @@ +// +// "$Id: fl_font_mac.cxx 5651 2007-02-01 20:13:57Z matt $" +// +// MacOS font selection routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include + +Fl_FontSize::Fl_FontSize(const char* name, int Size) { + next = 0; +# if HAVE_GL + listbase = 0; +# endif +#ifdef __APPLE_QD__ + knowMetrics = 0; + switch (*name++) { + case 'I': face = italic; break; + case 'P': face = italic | bold; break; + case 'B': face = bold; break; + default: face = 0; break; + } + unsigned char fn[80]; + fn[0] = strlen(name); strcpy((char*)(fn+1), name); + GetFNum(fn, &font); + size = Size; + FMInput fIn = { font, size, face, 0, 0, { 1, 1}, { 1, 1} }; + FMOutput *fOut = FMSwapFont(&fIn); + ascent = fOut->ascent; //: the following three lines give only temporary aproimations + descent = fOut->descent; + for (int i=0; i<256; i++) width[i] = fOut->widMax; + minsize = maxsize = size; +#elif defined(__APPLE_QUARTZ__) + knowWidths = 0; + // OpenGL needs those for its font handling + q_name = strdup(name); + size = Size; + OSStatus err; + // fill our structure with a few default values + ascent = Size*3/4; + descent = Size-ascent; + q_width = Size*2/3; + minsize = maxsize = Size; + // now use ATS to get the actual Glyph size information + CFStringRef cfname = CFStringCreateWithCString(0L, name, kCFStringEncodingASCII); + ATSFontRef font = ATSFontFindFromName(cfname, kATSOptionFlagsDefault); + if (font) { + ATSFontMetrics m = { 0 }; + ATSFontGetHorizontalMetrics(font, kATSOptionFlagsDefault, &m); + if (m.avgAdvanceWidth) q_width = int(m.avgAdvanceWidth*Size); + // playing with the offsets a little to make standard sizes fit + if (m.ascent) ascent = int(m.ascent*Size-0.5f); + if (m.descent) descent = -int(m.descent*Size-1.5f); + } + CFRelease(cfname); + // now we allocate everything needed to render text in this font later + // get us the default layout and style + err = ATSUCreateTextLayout(&layout); + UniChar mTxt[2] = { 65, 0 }; + err = ATSUSetTextPointerLocation(layout, mTxt, kATSUFromTextBeginning, 1, 1); + err = ATSUCreateStyle(&style); + err = ATSUSetRunStyle(layout, style, kATSUFromTextBeginning, kATSUToTextEnd); + // now set the actual font, size and attributes. We also set the font matrix to + // render our font up-side-down, so when rendered through our inverted CGContext, + // text will appear normal again. + Fixed fsize = IntToFixed(Size); + ATSUFontID fontID = FMGetFontFromATSFontRef(font); + static CGAffineTransform font_mx = { 1, 0, 0, -1, 0, 0 }; + ATSUAttributeTag sTag[] = { kATSUFontTag, kATSUSizeTag, kATSUFontMatrixTag }; + ByteCount sBytes[] = { sizeof(ATSUFontID), sizeof(Fixed), sizeof(CGAffineTransform) }; + ATSUAttributeValuePtr sAttr[] = { &fontID, &fsize, &font_mx }; + err = ATSUSetAttributes(style, 3, sTag, sBytes, sAttr); + // next, make sure that Quartz will only render at integer coordinates + ATSLineLayoutOptions llo = kATSLineUseDeviceMetrics|kATSLineDisableAllLayoutOperations; + ATSUAttributeTag aTag[] = { kATSULineLayoutOptionsTag }; + ByteCount aBytes[] = { sizeof(ATSLineLayoutOptions) }; + ATSUAttributeValuePtr aAttr[] = { &llo }; + err = ATSUSetLineControls (layout, kATSUFromTextBeginning, 1, aTag, aBytes, aAttr); + // now we are finally ready to measure some letter to get the bounding box + Fixed bBefore, bAfter, bAscent, bDescent; + err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, 1, &bBefore, &bAfter, &bAscent, &bDescent); + // Requesting a certain height font on Mac does not guarantee that ascent+descent + // equal the requested height. fl_height will reflect the actual height that we got. + // The font "Apple Chancery" is a pretty extreme example of overlapping letters. + float fa = -FixedToFloat(bAscent), fd = -FixedToFloat(bDescent); + if (fa>0.0f && fd>0.0f) { + //float f = Size/(fa+fd); + ascent = fa; //int(fa*f+0.5f); + descent = fd; //Size - ascent; + } + int w = FixedToInt(bAfter); + if (w) + q_width = FixedToInt(bAfter); +#endif +} + +Fl_FontSize* fl_fontsize = 0L; + +Fl_FontSize::~Fl_FontSize() { +/* +#if HAVE_GL + // ++ todo: remove OpenGL font alocations +// Delete list created by gl_draw(). This is not done by this code +// as it will link in GL unnecessarily. There should be some kind +// of "free" routine pointer, or a subclass? +// if (listbase) { +// int base = font->min_char_or_byte2; +// int size = font->max_char_or_byte2-base+1; +// int base = 0; int size = 256; +// glDeleteLists(listbase+base,size); +// } +#endif + */ + if (this == fl_fontsize) fl_fontsize = 0; +#ifdef __APPLE_QUARTZ__ + ATSUDisposeTextLayout(layout); + ATSUDisposeStyle(style); +#endif +} + +//////////////////////////////////////////////////////////////// + +static Fl_Fontdesc built_in_table[] = { +#ifdef __APPLE_QD__ +{" Arial"}, +{"BArial"}, +{"IArial"}, +{"PArial"}, +{" Courier New"}, +{"BCourier New"}, +{"ICourier New"}, +{"PCourier New"}, +{" Times New Roman"}, +{"BTimes New Roman"}, +{"ITimes New Roman"}, +{"PTimes New Roman"}, +{" Symbol"}, +{" Chicago"}, +{"BChicago"}, +{" Webdings"}, +#elif defined(__APPLE_QUARTZ__) +{"Arial"}, +{"Arial Bold"}, +{"Arial Italic"}, +{"Arial Bold Italic"}, +{"Courier New"}, +{"Courier New Bold"}, +{"Courier New Italic"}, +{"Courier New Bold Italic"}, +{"Times New Roman"}, +{"Times New Roman Bold"}, +{"Times New Roman Italic"}, +{"Times New Roman Bold Italic"}, +{"Symbol"}, +{"Monaco"}, +{"Andale Mono"}, // there is no bold Monaco font on standard Mac +{"Webdings"}, +#endif +}; + +#ifdef __APPLE_QUARTZ__ +static UniChar utf16lut[128] = { + 0x00c4, 0x00c5, 0x00c7, 0x00c9, 0x00d1, 0x00d6, 0x00dc, 0x00e1, + 0x00e0, 0x00e2, 0x00e4, 0x00e3, 0x00e5, 0x00e7, 0x00e9, 0x00e8, + 0x00ea, 0x00eb, 0x00ed, 0x00ec, 0x00ee, 0x00ef, 0x00f1, 0x00f3, + 0x00f2, 0x00f4, 0x00f6, 0x00f5, 0x00fa, 0x00f9, 0x00fb, 0x00fc, + 0x2020, 0x00b0, 0x00a2, 0x00a3, 0x00a7, 0x2022, 0x00b6, 0x00df, + 0x00ae, 0x00a9, 0x2122, 0x00b4, 0x00a8, 0x2260, 0x00c6, 0x00d8, + 0x221e, 0x00b1, 0x2264, 0x2265, 0x00a5, 0x00b5, 0x2202, 0x2211, + 0x220f, 0x03c0, 0x222b, 0x00aa, 0x00ba, 0x03a9, 0x00e6, 0x00f8, + 0x00bf, 0x00a1, 0x00ac, 0x221a, 0x0192, 0x2248, 0x2206, 0x00ab, + 0x00bb, 0x2026, 0x00a0, 0x00c0, 0x00c3, 0x00d5, 0x0152, 0x0153, + 0x2013, 0x2014, 0x201c, 0x201d, 0x2018, 0x2019, 0x00f7, 0x25ca, + 0x00ff, 0x0178, 0x2044, 0x20ac, 0x2039, 0x203a, 0xfb01, 0xfb02, + 0x2021, 0x00b7, 0x201a, 0x201e, 0x2030, 0x00c2, 0x00ca, 0x00c1, + 0x00cb, 0x00c8, 0x00cd, 0x00ce, 0x00cf, 0x00cc, 0x00d3, 0x00d4, + 0xf8ff, 0x00d2, 0x00da, 0x00db, 0x00d9, 0x0131, 0x02c6, 0x02dc, + 0x00af, 0x02d8, 0x02d9, 0x02da, 0x00b8, 0x02dd, 0x02db, 0x02c7, +}; +static UniChar *utf16buf = 0; +static int utf16len = 0; +UniChar *fl_macToUtf16(const char *txt, int len) +{ + if ((len+1)>utf16len) { + utf16len = len+100; + free(utf16buf); + utf16buf = (UniChar*)malloc((utf16len+1)*sizeof(UniChar)); + } + int i; + unsigned char c; + const unsigned char *src = (unsigned char const*)txt; + UniChar *dst = utf16buf; + for (i=0; ifont); //: select font into current QuickDraw GC + TextFace(fl_fontsize->face); + TextSize(fl_fontsize->size); + if (!fl_fontsize->knowMetrics) { //: get the true metrics for the currnet GC + //: (fails on multiple monitors with different dpi's!) + FontInfo fi; GetFontInfo(&fi); + fl_fontsize->ascent = fi.ascent; + fl_fontsize->descent = fi.descent; + FMetricRec mr; FontMetrics(&mr); + short *f = (short*)*mr.wTabHandle; //: get the char size table + for (int i=0; i<256; i++) fl_fontsize->width[i] = f[2*i]; + fl_fontsize->knowMetrics = 1; + } +#elif defined(__APPLE_QUARTZ__) + // we will use fl_fontsize later to access the required style and layout +#else +# error : need to defined either Quartz or Quickdraw +#endif +} + +static Fl_FontSize* find(int fnum, int size) { + Fl_Fontdesc* s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // use 0 if fnum undefined + Fl_FontSize* f; + for (f = s->first; f; f = f->next) + if (f->minsize <= size && f->maxsize >= size) return f; + f = new Fl_FontSize(s->name, size); + f->next = s->first; + s->first = f; + return f; +} + +//////////////////////////////////////////////////////////////// +// Public interface: + +int fl_font_ = 0; +int fl_size_ = 0; + +void fl_font(int fnum, int size) { + if (fnum==-1) { + fl_font_ = 0; + fl_size_ = 0; + return; + } + fl_font_ = fnum; + fl_size_ = size; + fl_font(find(fnum, size)); +} + +int fl_height() { + if (fl_fontsize) return fl_fontsize->ascent+fl_fontsize->descent; + else return -1; +} + +int fl_descent() { + if (fl_fontsize) return fl_fontsize->descent; + else return -1; +} + +double fl_width(const char* txt, int n) { +#ifdef __APPLE_QD__ + return (double)TextWidth( txt, 0, n ); +#else + if (!fl_fontsize) { + fl_font(0, 12); // avoid a crash! + if (!fl_fontsize) + return 8*n; // user must select a font first! + } + if (!fl_fontsize->knowWidths) { + if (!fl_gc) { + Fl_Window *w = Fl::first_window(); + if (w) w->make_current(); + if (!fl_gc) { + if (fl_fontsize) return fl_fontsize->q_width*n; + return 8*n; + // We fall back to some internal QuickDraw port. + // The result should be the same. + } + } + char buf[2]; + for (int i=0; i<256; i++) { + OSStatus err; + buf[0] = (char)i; + // convert to UTF-16 first + UniChar *uniStr = fl_macToUtf16(buf, 1); + // now collect our ATSU resources + ATSUTextLayout layout = fl_fontsize->layout; + // activate the current GC + ByteCount iSize = sizeof(CGContextRef); + ATSUAttributeTag iTag = kATSUCGContextTag; + ATSUAttributeValuePtr iValuePtr=&fl_gc; + ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr); + // now measure the bounding box + err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, 1, 1); + Fixed bBefore, bAfter, bAscent, bDescent; + err = ATSUGetUnjustifiedBounds(layout, kATSUFromTextBeginning, 1, &bBefore, &bAfter, &bAscent, &bDescent); + fl_fontsize->width[i] = FixedToInt(bAfter); + } + fl_fontsize->knowWidths = 1; + } + int len = 0; + const char *src = txt; + for (int j=0; jwidth[c]; + } + return len; +#endif +} + +double fl_width(uchar c) { + return fl_width((const char*)(&c), 1); +} + +void fl_draw(const char *str, int n, float x, float y); + +void fl_draw(const char* str, int n, int x, int y) { +#ifdef __APPLE_QD__ + MoveTo(x, y); + DrawText((const char *)str, 0, n); +#elif defined(__APPLE_QUARTZ__) + fl_draw(str, n, (float)x-0.0f, (float)y-0.5f); +#else +# error : neither Quartz no Quickdraw chosen +#endif +} + +void fl_draw(const char *str, int n, float x, float y) { +#ifdef __APPLE_QD__ + fl_draw(str, n, (int)x, (int)y); +#elif defined(__APPLE_QUARTZ__) + OSStatus err; + // convert to UTF-16 first + UniChar *uniStr = fl_macToUtf16(str, n); + // now collect our ATSU resources + ATSUTextLayout layout = fl_fontsize->layout; + + ByteCount iSize = sizeof(CGContextRef); + ATSUAttributeTag iTag = kATSUCGContextTag; + ATSUAttributeValuePtr iValuePtr=&fl_gc; + ATSUSetLayoutControls(layout, 1, &iTag, &iSize, &iValuePtr); + + err = ATSUSetTextPointerLocation(layout, uniStr, kATSUFromTextBeginning, n, n); + err = ATSUDrawText(layout, kATSUFromTextBeginning, n, FloatToFixed(x), FloatToFixed(y)); +#else +# error : neither Quartz no Quickdraw chosen +#endif +} + +// +// End of "$Id: fl_font_mac.cxx 5651 2007-02-01 20:13:57Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_font_win32.cxx b/third_party/windows/fltk-1.1.10/src/fl_font_win32.cxx new file mode 100644 index 0000000..cfa0bda --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_font_win32.cxx @@ -0,0 +1,173 @@ +// +// "$Id: fl_font_win32.cxx 5420 2006-09-05 11:16:15Z matt $" +// +// WIN32 font selection routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +Fl_FontSize::Fl_FontSize(const char* name, int size) { + int weight = FW_NORMAL; + int italic = 0; + switch (*name++) { + case 'I': italic = 1; break; + case 'P': italic = 1; + case 'B': weight = FW_BOLD; break; + case ' ': break; + default: name--; + } + fid = CreateFont( + -size, // negative makes it use "char size" + 0, // logical average character width + 0, // angle of escapement + 0, // base-line orientation angle + weight, + italic, + FALSE, // underline attribute flag + FALSE, // strikeout attribute flag + DEFAULT_CHARSET, // character set identifier + OUT_DEFAULT_PRECIS, // output precision + CLIP_DEFAULT_PRECIS,// clipping precision + DEFAULT_QUALITY, // output quality + DEFAULT_PITCH, // pitch and family + name // pointer to typeface name string + ); + if (!fl_gc) fl_GetDC(0); + SelectObject(fl_gc, fid); + GetTextMetrics(fl_gc, &metr); +// BOOL ret = GetCharWidthFloat(fl_gc, metr.tmFirstChar, metr.tmLastChar, font->width+metr.tmFirstChar); +// ...would be the right call, but is not implemented into Window95! (WinNT?) + GetCharWidth(fl_gc, 0, 255, width); +#if HAVE_GL + listbase = 0; +#endif + minsize = maxsize = size; +} + +Fl_FontSize* fl_fontsize; + +Fl_FontSize::~Fl_FontSize() { +#if HAVE_GL +// Delete list created by gl_draw(). This is not done by this code +// as it will link in GL unnecessarily. There should be some kind +// of "free" routine pointer, or a subclass? +// if (listbase) { +// int base = font->min_char_or_byte2; +// int size = font->max_char_or_byte2-base+1; +// int base = 0; int size = 256; +// glDeleteLists(listbase+base,size); +// } +#endif + if (this == fl_fontsize) fl_fontsize = 0; + DeleteObject(fid); +} + +//////////////////////////////////////////////////////////////// + +// WARNING: if you add to this table, you must redefine FL_FREE_FONT +// in Enumerations.H & recompile!! +static Fl_Fontdesc built_in_table[] = { +{" Arial"}, +{"BArial"}, +{"IArial"}, +{"PArial"}, +{" Courier New"}, +{"BCourier New"}, +{"ICourier New"}, +{"PCourier New"}, +{" Times New Roman"}, +{"BTimes New Roman"}, +{"ITimes New Roman"}, +{"PTimes New Roman"}, +{" Symbol"}, +{" Terminal"}, +{"BTerminal"}, +{" Wingdings"}, +}; + +Fl_Fontdesc* fl_fonts = built_in_table; + +static Fl_FontSize* find(int fnum, int size) { + Fl_Fontdesc* s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // use 0 if fnum undefined + Fl_FontSize* f; + for (f = s->first; f; f = f->next) + if (f->minsize <= size && f->maxsize >= size) return f; + f = new Fl_FontSize(s->name, size); + f->next = s->first; + s->first = f; + return f; +} + +//////////////////////////////////////////////////////////////// +// Public interface: + +int fl_font_ = 0; +int fl_size_ = 0; +//static HDC font_gc; + +void fl_font(int fnum, int size) { + if (fnum==-1) { // just make sure that we will load a new font next time + fl_font_ = 0; fl_size_ = 0; + return; + } + if (fnum == fl_font_ && size == fl_size_) return; + fl_font_ = fnum; fl_size_ = size; + fl_fontsize = find(fnum, size); +} + +int fl_height() { + if (fl_fontsize) return (fl_fontsize->metr.tmAscent + fl_fontsize->metr.tmDescent); + else return -1; +} + +int fl_descent() { + if (fl_fontsize) return fl_fontsize->metr.tmDescent; + else return -1; +} + +double fl_width(const char* c, int n) { + if (!fl_fontsize) return -1.0; + double w = 0.0; + while (n--) w += fl_fontsize->width[uchar(*c++)]; + return w; +} + +double fl_width(uchar c) { + if (fl_fontsize) return fl_fontsize->width[c]; + else return -1.0; +} + +void fl_draw(const char* str, int n, int x, int y) { + COLORREF oldColor = SetTextColor(fl_gc, fl_RGB()); + if (fl_fontsize) SelectObject(fl_gc, fl_fontsize->fid); + TextOut(fl_gc, x, y, str, n); + SetTextColor(fl_gc, oldColor); +} + +void fl_draw(const char* str, int n, float x, float y) { + fl_draw(str, n, (int)x, (int)y); +} + +// +// End of "$Id: fl_font_win32.cxx 5420 2006-09-05 11:16:15Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_font_x.cxx b/third_party/windows/fltk-1.1.10/src/fl_font_x.cxx new file mode 100644 index 0000000..4db151c --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_font_x.cxx @@ -0,0 +1,269 @@ +// +// "$Id: fl_font_x.cxx 5421 2006-09-05 11:26:41Z matt $" +// +// Standard X11 font selection code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +Fl_FontSize::Fl_FontSize(const char* name) { + font = XLoadQueryFont(fl_display, name); + if (!font) { + Fl::warning("bad font: %s", name); + font = XLoadQueryFont(fl_display, "fixed"); // if fixed fails we crash + } +# if HAVE_GL + listbase = 0; +# endif +} + +Fl_FontSize* fl_fontsize; + +Fl_FontSize::~Fl_FontSize() { +# if HAVE_GL +// Delete list created by gl_draw(). This is not done by this code +// as it will link in GL unnecessarily. There should be some kind +// of "free" routine pointer, or a subclass? +// if (listbase) { +// int base = font->min_char_or_byte2; +// int size = font->max_char_or_byte2-base+1; +// int base = 0; int size = 256; +// glDeleteLists(listbase+base,size); +// } +# endif + if (this == fl_fontsize) fl_fontsize = 0; + XFreeFont(fl_display, font); +} + +//////////////////////////////////////////////////////////////// + +// WARNING: if you add to this table, you must redefine FL_FREE_FONT +// in Enumerations.H & recompile!! +static Fl_Fontdesc built_in_table[] = { +{"-*-helvetica-medium-r-normal--*"}, +{"-*-helvetica-bold-r-normal--*"}, +{"-*-helvetica-medium-o-normal--*"}, +{"-*-helvetica-bold-o-normal--*"}, +{"-*-courier-medium-r-normal--*"}, +{"-*-courier-bold-r-normal--*"}, +{"-*-courier-medium-o-normal--*"}, +{"-*-courier-bold-o-normal--*"}, +{"-*-times-medium-r-normal--*"}, +{"-*-times-bold-r-normal--*"}, +{"-*-times-medium-i-normal--*"}, +{"-*-times-bold-i-normal--*"}, +{"-*-symbol-*"}, +{"-*-lucidatypewriter-medium-r-normal-sans-*"}, +{"-*-lucidatypewriter-bold-r-normal-sans-*"}, +{"-*-*zapf dingbats-*"} +}; + +Fl_Fontdesc* fl_fonts = built_in_table; + +#define MAXSIZE 32767 + +// return dash number N, or pointer to ending null if none: +const char* fl_font_word(const char* p, int n) { + while (*p) {if (*p=='-') {if (!--n) break;} p++;} + return p; +} + +// return a pointer to a number we think is "point size": +char* fl_find_fontsize(char* name) { + char* c = name; + // for standard x font names, try after 7th dash: + if (*c == '-') { + c = (char*)fl_font_word(c,7); + if (*c++ && isdigit(*c)) return c; + return 0; // malformed x font name? + } + char* r = 0; + // find last set of digits: + for (c++;* c; c++) + if (isdigit(*c) && !isdigit(*(c-1))) r = c; + return r; +} + +const char* fl_encoding = "iso8859-1"; + +// return true if this matches fl_encoding: +int fl_correct_encoding(const char* name) { + if (*name != '-') return 0; + const char* c = fl_font_word(name,13); + return (*c++ && !strcmp(c,fl_encoding)); +} + +// locate or create an Fl_FontSize for a given Fl_Fontdesc and size: +static Fl_FontSize* find(int fnum, int size) { + Fl_Fontdesc* s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // use font 0 if still undefined + Fl_FontSize* f; + for (f = s->first; f; f = f->next) + if (f->minsize <= size && f->maxsize >= size) return f; + fl_open_display(); + if (!s->xlist) { + s->xlist = XListFonts(fl_display, s->name, 100, &(s->n)); + if (!s->xlist) { // use fixed if no matching font... + s->first = new Fl_FontSize("fixed"); + s->first->minsize = 0; + s->first->maxsize = 32767; + return s->first; + } + } + // search for largest <= font size: + char* name = s->xlist[0]; int ptsize = 0; // best one found so far + int matchedlength = 32767; + char namebuffer[1024]; // holds scalable font name + int found_encoding = 0; + int m = s->n; if (m<0) m = -m; + for (int n=0; n < m; n++) { + + char* thisname = s->xlist[n]; + if (fl_correct_encoding(thisname)) { + if (!found_encoding) ptsize = 0; // force it to choose this + found_encoding = 1; + } else { + if (found_encoding) continue; + } + char* c = fl_find_fontsize(thisname); + int thissize = c ? atoi(c) : MAXSIZE; + int thislength = strlen(thisname); + if (thissize == size && thislength < matchedlength) { + // exact match, use it: + name = thisname; + ptsize = size; + matchedlength = thislength; + } else if (!thissize && ptsize!=size) { + // whoa! A scalable font! Use unless exact match found: + int l = c-thisname; + memcpy(namebuffer,thisname,l); + l += sprintf(namebuffer+l,"%d",size); + while (*c == '0') c++; + strcpy(namebuffer+l,c); + name = namebuffer; + ptsize = size; + } else if (!ptsize || // no fonts yet + thissize < ptsize && ptsize > size || // current font too big + thissize > ptsize && thissize <= size // current too small + ) { + name = thisname; ptsize = thissize; + matchedlength = thislength; + } + } + + if (ptsize != size) { // see if we already found this unscalable font: + for (f = s->first; f; f = f->next) { + if (f->minsize <= ptsize && f->maxsize >= ptsize) { + if (f->minsize > size) f->minsize = size; + if (f->maxsize < size) f->maxsize = size; + return f; + } + } + } + + // okay, we definately have some name, make the font: + f = new Fl_FontSize(name); + if (ptsize < size) {f->minsize = ptsize; f->maxsize = size;} + else {f->minsize = size; f->maxsize = ptsize;} + f->next = s->first; + s->first = f; + return f; + +} + +//////////////////////////////////////////////////////////////// +// Public interface: + +int fl_font_ = 0; +int fl_size_ = 0; +XFontStruct* fl_xfont = 0; +void *fl_xftfont = 0; +static GC font_gc; + +void fl_font(int fnum, int size) { + if (fnum==-1) { + fl_font_ = 0; fl_size_ = 0; + return; + } + if (fnum == fl_font_ && size == fl_size_) return; + fl_font_ = fnum; fl_size_ = size; + Fl_FontSize* f = find(fnum, size); + if (f != fl_fontsize) { + fl_fontsize = f; + fl_xfont = f->font; + font_gc = 0; + } +} + +int fl_height() { + if (fl_xfont) return (fl_xfont->ascent + fl_xfont->descent); + else return -1; +} + +int fl_descent() { + if (fl_xfont) return fl_xfont->descent; + else return -1; +} + +double fl_width(const char* c, int n) { + if (!fl_xfont) return -1.0; + XCharStruct* p = fl_xfont->per_char; + if (!p) return n*fl_xfont->min_bounds.width; + int a = fl_xfont->min_char_or_byte2; + int b = fl_xfont->max_char_or_byte2 - a; + int w = 0; + while (n--) { + int x = *(uchar*)c++ - a; + if (x >= 0 && x <= b) w += p[x].width; + else w += fl_xfont->min_bounds.width; + } + return w; +} + +double fl_width(uchar c) { + if (!fl_xfont) return -1; + XCharStruct* p = fl_xfont->per_char; + if (p) { + int a = fl_xfont->min_char_or_byte2; + int b = fl_xfont->max_char_or_byte2 - a; + int x = c-a; + if (x >= 0 && x <= b) return p[x].width; + } + return fl_xfont->min_bounds.width; +} + +void fl_draw(const char* str, int n, int x, int y) { + if (font_gc != fl_gc) { + if (!fl_xfont) fl_font(FL_HELVETICA, 14); + font_gc = fl_gc; + XSetFont(fl_display, fl_gc, fl_xfont->fid); + } + XDrawString(fl_display, fl_window, fl_gc, x, y, str, n); +} + +void fl_draw(const char* str, int n, float x, float y) { + fl_draw(str, n, (int)x, (int)y); +} + +// +// End of "$Id: fl_font_x.cxx 5421 2006-09-05 11:26:41Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_font_xft.cxx b/third_party/windows/fltk-1.1.10/src/fl_font_xft.cxx new file mode 100644 index 0000000..a9ea6b7 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_font_xft.cxx @@ -0,0 +1,445 @@ +// +// "$Id: fl_font_xft.cxx 6871 2009-09-15 20:33:55Z matt $" +// +// Xft font code for the Fast Light Tool Kit (FLTK). +// +// Copyright 2001-2007 Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// +// Draw fonts using Keith Packard's Xft library to provide anti- +// aliased text. Yow! +// +// Many thanks to Carl for making the original version of this. +// +// This font code only requires libXft to work. Contrary to popular +// belief there is no need to have FreeType, or the Xrender extension +// available to use this code. You will just get normal Xlib fonts +// (Xft calls them "core" fonts) The Xft algorithms for choosing +// these is about as good as the FLTK ones (I hope to fix it so it is +// exactly as good...), plus it can cache it's results and share them +// between programs, so using this should be a win in all cases. Also +// it should be obvious by comparing this file and fl_font_x.cxx that +// it is a lot easier to program with Xft than with Xlib. +// +// Also, Xft supports UTF-8 text rendering directly, which will allow +// us to support UTF-8 on all platforms more easily. +// +// To actually get antialiasing you need the following: +// +// 1. You have XFree86 4 +// 2. You have the XRender extension +// 3. Your X device driver supports the render extension +// 4. You have libXft +// 5. Your libXft has FreeType2 support compiled in +// 6. You have the FreeType2 library +// +// Distributions that have XFree86 4.0.3 or later should have all of this... +// +// Unlike some other Xft packages, I tried to keep this simple and not +// to work around the current problems in Xft by making the "patterns" +// complicated. I belive doing this defeats our ability to improve Xft +// itself. You should edit the ~/.xftconfig file to "fix" things, there +// are several web pages of information on how to do this. +// + +#include + +// The predefined fonts that FLTK has: +static Fl_Fontdesc built_in_table[] = { +{" sans"}, +{"Bsans"}, +{"Isans"}, +{"Psans"}, +{" mono"}, +{"Bmono"}, +{"Imono"}, +{"Pmono"}, +{" serif"}, +{"Bserif"}, +{"Iserif"}, +{"Pserif"}, +{" symbol"}, +{" screen"}, +{"Bscreen"}, +{" dingbats"}, +}; + +Fl_Fontdesc* fl_fonts = built_in_table; + +#define current_font (fl_fontsize->font) + +int fl_font_ = 0; +int fl_size_ = 0; +XFontStruct* fl_xfont = 0; +void *fl_xftfont = 0; +const char* fl_encoding_ = "iso8859-1"; +Fl_FontSize* fl_fontsize = 0; + +void fl_font(int fnum, int size) { + if (fnum==-1) { // special case to stop font caching + fl_font_ = 0; fl_size_ = 0; + return; + } + if (fnum == fl_font_ && size == fl_size_ + && fl_fontsize + && !strcasecmp(fl_fontsize->encoding, fl_encoding_)) + return; + fl_font_ = fnum; fl_size_ = size; + Fl_Fontdesc *font = fl_fonts + fnum; + Fl_FontSize* f; + // search the fontsizes we have generated already + for (f = font->first; f; f = f->next) { + if (f->size == size && !strcasecmp(f->encoding, fl_encoding_)) + break; + } + if (!f) { + f = new Fl_FontSize(font->name); + f->next = font->first; + font->first = f; + } + fl_fontsize = f; +#if XFT_MAJOR < 2 + fl_xfont = f->font->u.core.font; +#endif // XFT_MAJOR < 2 + fl_xftfont = (void*)f->font; +} + +static XftFont* fontopen(const char* name, bool core) { + // Check: does it look like we have been passed an old-school XLFD fontname? + bool is_xlfd = false; + int hyphen_count = 0; + int comma_count = 0; + unsigned len = strlen(name); + if (len > 512) len = 512; // ensure we are not passed an unbounded font name + for(unsigned idx = 0; idx < len; idx++) { + if(name[idx] == '-') hyphen_count++; // check for XLFD hyphens + if(name[idx] == ',') comma_count++; // are there multiple names? + } + if(hyphen_count >= 14) is_xlfd = true; // Not a robust check, but good enough? + + fl_open_display(); + + if(!is_xlfd) { // Not an XLFD - open as a XFT style name + XftFont *the_font; // the font we will return; + XftPattern *fnt_pat = XftPatternCreate(); // the pattern we will use for matching + int slant = XFT_SLANT_ROMAN; + int weight = XFT_WEIGHT_MEDIUM; + + /* This "converts" FLTK-style font names back into "regular" names, extracting + * the BOLD and ITALIC codes as it does so - all FLTK font names are prefixed + * by 'I' (italic) 'B' (bold) 'P' (bold italic) or ' ' (regular) modifiers. + * This gives a fairly limited font selection ability, but is retained for + * compatability reasons. If you really need a more complex choice, you are best + * calling Fl::set_fonts(*) then selecting the font by font-index rather than by + * name anyway. Probably. + * If you want to load a font who's name does actually begin with I, B or P, you + * MUST use a leading space OR simply use lowercase for the name... + */ + /* This may be efficient, but it is non-obvious. */ + switch (*name++) { + case 'I': slant = XFT_SLANT_ITALIC; break; // italic + case 'P': slant = XFT_SLANT_ITALIC; // bold-italic (falls-through) + case 'B': weight = XFT_WEIGHT_BOLD; break; // bold + case ' ': break; // regular + default: name--; // no prefix, restore name + } + + if(comma_count) { // multiple comma-spearated names were passed + char *local_name = strdup(name); // duplicate the full name so we can edit the copy + char *curr = local_name; // points to first name in string + char *nxt; // next name in string + do { + nxt = strchr(curr, ','); // find comma seperator + if (nxt) { + *nxt = 0; // terminate first name + nxt++; // first char of next name + } + + // Add the current name to the match pattern + XftPatternAddString(fnt_pat, XFT_FAMILY, curr); + + if(nxt) curr = nxt; // move onto next name (if it exists) + // Now do a cut-down version of the FLTK name conversion. + // NOTE: we only use the slant and weight of the first name, + // subsequent names we ignore this for... But we still need to do the check. + switch (*curr++) { + case 'I': break; // italic + case 'P': // bold-italic (falls-through) + case 'B': break; // bold + case ' ': break; // regular + default: curr--; // no prefix, restore name + } + + comma_count--; // decrement name sections count + } while (comma_count >= 0); + free(local_name); // release our local copy of font names + } + else { // single name was passed - add it directly + XftPatternAddString(fnt_pat, XFT_FAMILY, name); + } + + // Construct a match pattern for the font we want... + XftPatternAddInteger(fnt_pat, XFT_WEIGHT, weight); + XftPatternAddInteger(fnt_pat, XFT_SLANT, slant); + XftPatternAddDouble (fnt_pat, XFT_PIXEL_SIZE, (double)fl_size_); + XftPatternAddString (fnt_pat, XFT_ENCODING, fl_encoding_); + if (core) { + XftPatternAddBool(fnt_pat, XFT_CORE, FcTrue); + XftPatternAddBool(fnt_pat, XFT_RENDER, FcFalse); + } + + XftPattern *match_pat; // the best available match on the system + XftResult match_result; // the result of our matching attempt + // query the system to find a match for this font + match_pat = XftFontMatch(fl_display, fl_screen, fnt_pat, &match_result); + // open the matched font + the_font = XftFontOpenPattern(fl_display, match_pat); + // Tidy up the resources we allocated + XftPatternDestroy(fnt_pat); +// XftPatternDestroy(match_pat); // FontConfig will destroy this resource for us. We must not! + return the_font; + } + else { // We were passed a font name in XLFD format + char *local_name = strdup(name); + if(comma_count) { // This means we were passed multiple XLFD's + char *pc = strchr(local_name, ','); + *pc = 0; // terminate the XLFD at the first comma + } + XftFont *the_font = XftFontOpenXlfd(fl_display, fl_screen, local_name); + free(local_name); + return the_font; + } +} // end of fontopen + +Fl_FontSize::Fl_FontSize(const char* name) { + encoding = fl_encoding_; + size = fl_size_; +#if HAVE_GL + listbase = 0; +#endif // HAVE_GL + font = fontopen(name, false); +} + +Fl_FontSize::~Fl_FontSize() { + if (this == fl_fontsize) fl_fontsize = 0; +// XftFontClose(fl_display, font); +} + +int fl_height() { + if (current_font) return current_font->ascent + current_font->descent; + else return -1; +} + +int fl_descent() { + if (current_font) return current_font->descent; + else return -1; +} + +double fl_width(const char *str, int n) { + if (!current_font) return -1.0; + XGlyphInfo i; + XftTextExtents8(fl_display, current_font, (XftChar8 *)str, n, &i); + return i.xOff; +} + +double fl_width(uchar c) { + return fl_width((const char *)(&c), 1); +} + +#if HAVE_GL +/* This code is used by opengl to get a bitmapped font. The original XFT-1 code + * used XFT's "core" fonts methods to load an XFT font that was actually a + * X-bitmap font, that could then be readily used with GL. + * But XFT-2 does not provide that ability, and there is no easy method to use + * an XFT font directly with GL. So... +*/ + +# if XFT_MAJOR > 1 +// This function attempts, on XFT2 systems, to find a suitable "core" Xfont +// for GL to use, since we dont have an XglUseXftFont(...) function. +// There's probably a better way to do this. I can't believe it is this hard... +// Anyway... This code attempts to make an XLFD out of the fltk-style font +// name it is passed, then tries to load that font. Surprisingly, this quite +// often works - boxes that have XFT generally also have a fontserver that +// can serve TTF and other fonts to X, and so the font name that fltk makes +// from the XFT name often also "exists" as an "core" X font... +// If this code fails to load the requested font, it falls back through a +// series of tried 'n tested alternatives, ultimately resorting to what the +// original fltk code did. +// NOTE: +// On my test boxes (FC6, FC7) this works well for the fltk "built-in" font names. +static XFontStruct* load_xfont_for_xft2(void) { + XFontStruct* xgl_font = 0; + int size = fl_size_; + const char *weight = "medium"; // no specifc weight requested - accept any + char slant = 'r'; // regular non-italic by default + char xlfd[128]; // we will put our synthetic XLFD in here + char *pc = strdup(fl_fonts[fl_font_].name); // what font were we asked for? + const char *name = pc; // keep a handle to the original name for freeing later + // Parse the "fltk-name" of the font + switch (*name++) { + case 'I': slant = 'i'; break; // italic + case 'P': slant = 'i'; // bold-italic (falls-through) + case 'B': weight = "bold"; break; // bold + case ' ': break; // regular + default: name--; // no prefix, restore name + } + + // map generic Xft names to customary XLFD faces + if (!strcmp(name, "sans")) { + name = "helvetica"; + } else if (!strcmp(name, "mono")) { + name = "courier"; + } else if (!strcmp(name, "serif")) { + name = "times"; + } else if (!strcmp(name, "screen")) { + name = "lucidatypewriter"; + } else if (!strcmp(name, "dingbats")) { + name = "zapf dingbats"; + } + + // first, we do a query with no prefered size, to see if the font exists at all + snprintf(xlfd, 128, "-*-*%s*-%s-%c-*--*-*-*-*-*-*-*-*", name, weight, slant); // make up xlfd style name + xgl_font = XLoadQueryFont(fl_display, xlfd); + if(xgl_font) { // the face exists, but can we get it in a suitable size? + XFreeFont(fl_display, xgl_font); // release the non-sized version + snprintf(xlfd, 128, "-*-*%s*-%s-%c-*--*-%d-*-*-*-*-*-*", name, weight, slant, (size*10)); + xgl_font = XLoadQueryFont(fl_display, xlfd); // attempt to load the font at the right size + } + free(pc); // release our copy of the font name + + // if we have nothing loaded, try a generic proportional font + if(!xgl_font) { + snprintf(xlfd, 128, "-*-helvetica-*-%c-*--*-%d-*-*-*-*-*-*", slant, (size*10)); + xgl_font = XLoadQueryFont(fl_display, xlfd); + } + // If that still didn't work, try this instead + if(!xgl_font) { + snprintf(xlfd, 128, "-*-courier-medium-%c-*--*-%d-*-*-*-*-*-*", slant, (size*10)); + xgl_font = XLoadQueryFont(fl_display, xlfd); + } + // Last chance fallback - this usually loads something... + if (!xgl_font) xgl_font = XLoadQueryFont(fl_display, "fixed"); + + return xgl_font; +} // end of load_xfont_for_xft2 +# endif + +XFontStruct* fl_xxfont() { +# if XFT_MAJOR > 1 + // kludge! XFT 2 and later does not provide core fonts for us to use with GL + // try to load a bitmap X font instead + static XFontStruct* xgl_font = 0; + static int glsize = 0; + static int glfont = -1; + // Do we need to load a new font? + if ((!xgl_font) || (glsize != fl_size_) || (glfont != fl_font_)) { + if (xgl_font) XFreeFont(fl_display, xgl_font); // font already loaded, free it + glsize = fl_size_; // record current font size + glfont = fl_font_; // and face + // create a dummy XLFD for some font of the appropriate size... + xgl_font = load_xfont_for_xft2(); + } + return xgl_font; +# else // XFT-1 provides a means to load a "core" font directly + if (current_font->core) return current_font->u.core.font; // is the current font a "core" font? If so, use it. + static XftFont* xftfont; + if (xftfont) XftFontClose (fl_display, xftfont); + xftfont = fontopen(fl_fonts[fl_font_].name, true); // else request XFT to load a suitable "core" font instead. + return xftfont->u.core.font; +# endif // XFT_MAJOR > 1 +} +#endif // HAVE_GL + +#if USE_OVERLAY +// Currently Xft does not work with colormapped visuals, so this probably +// does not work unless you have a true-color overlay. +extern bool fl_overlay; +extern Colormap fl_overlay_colormap; +extern XVisualInfo* fl_overlay_visual; +#endif + +// For some reason Xft produces errors if you destroy a window whose id +// still exists in an XftDraw structure. It would be nice if this is not +// true, a lot of junk is needed to try to stop this: + +static XftDraw* draw; +static Window draw_window; +#if USE_OVERLAY +static XftDraw* draw_overlay; +static Window draw_overlay_window; +#endif + +void fl_destroy_xft_draw(Window id) { + if (id == draw_window) + XftDrawChange(draw, draw_window = fl_message_window); +#if USE_OVERLAY + if (id == draw_overlay_window) + XftDrawChange(draw_overlay, draw_overlay_window = fl_message_window); +#endif +} + +void fl_draw(const char *str, int n, int x, int y) { + if ( !current_font ) { + fl_font(FL_HELVETICA, 14); + } +#if USE_OVERLAY + XftDraw*& draw = fl_overlay ? draw_overlay : ::draw; + if (fl_overlay) { + if (!draw) + draw = XftDrawCreate(fl_display, draw_overlay_window = fl_window, + fl_overlay_visual->visual, fl_overlay_colormap); + else //if (draw_overlay_window != fl_window) + XftDrawChange(draw, draw_overlay_window = fl_window); + } else +#endif + if (!draw) + draw = XftDrawCreate(fl_display, draw_window = fl_window, + fl_visual->visual, fl_colormap); + else //if (draw_window != fl_window) + XftDrawChange(draw, draw_window = fl_window); + + Region region = fl_clip_region(); + if (region && XEmptyRegion(region)) return; + XftDrawSetClip(draw, region); + + // Use fltk's color allocator, copy the results to match what + // XftCollorAllocValue returns: + XftColor color; + color.pixel = fl_xpixel(fl_color_); + uchar r,g,b; Fl::get_color(fl_color_, r,g,b); + color.color.red = ((int)r)*0x101; + color.color.green = ((int)g)*0x101; + color.color.blue = ((int)b)*0x101; + color.color.alpha = 0xffff; + + XftDrawString8(draw, &color, current_font, x, y, (XftChar8 *)str, n); +} + +void fl_draw(const char* str, int n, float x, float y) { + fl_draw(str, n, (int)x, (int)y); +} + +// +// End of "$Id: fl_font_xft.cxx 6871 2009-09-15 20:33:55Z matt $" +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_gtk.cxx b/third_party/windows/fltk-1.1.10/src/fl_gtk.cxx new file mode 100644 index 0000000..5a674f0 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_gtk.cxx @@ -0,0 +1,304 @@ +// +// "$Id: fl_gtk.cxx 5721 2007-02-27 19:23:24Z matt $" +// +// "GTK" drawing routines for the Fast Light Tool Kit (FLTK). +// +// These box types provide a GTK+ look, based on Red Hat's Bluecurve +// theme... +// +// Copyright 2006 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Box drawing code for an obscure box type. +// These box types are in seperate files so they are not linked +// in if not used. + +#include +#include + +extern void fl_internal_boxtype(Fl_Boxtype, Fl_Box_Draw_F*); + + +static void gtk_color(Fl_Color c) { + if (Fl::draw_box_active()) fl_color(c); + else fl_color(fl_inactive(c)); +} + + +static void gtk_up_frame(int x, int y, int w, int h, Fl_Color c) { + gtk_color(fl_color_average(FL_WHITE, c, 0.5)); + fl_xyline(x + 2, y + 1, x + w - 3); + fl_yxline(x + 1, y + 2, y + h - 3); + + gtk_color(fl_color_average(FL_BLACK, c, 0.5)); + fl_begin_loop(); + fl_vertex(x, y + 2); + fl_vertex(x + 2, y); + fl_vertex(x + w - 3, y); + fl_vertex(x + w - 1, y + 2); + fl_vertex(x + w - 1, y + h - 3); + fl_vertex(x + w - 3, y + h - 1); + fl_vertex(x + 2, y + h - 1); + fl_vertex(x, y + h - 3); + fl_end_loop(); +} + + +static void gtk_up_box(int x, int y, int w, int h, Fl_Color c) { + gtk_up_frame(x, y, w, h, c); + + gtk_color(fl_color_average(FL_WHITE, c, 0.4f)); + fl_xyline(x + 2, y + 2, x + w - 3); + gtk_color(fl_color_average(FL_WHITE, c, 0.2f)); + fl_xyline(x + 2, y + 3, x + w - 3); + gtk_color(fl_color_average(FL_WHITE, c, 0.1f)); + fl_xyline(x + 2, y + 4, x + w - 3); + gtk_color(c); + fl_rectf(x + 2, y + 5, w - 4, h - 7); + gtk_color(fl_color_average(FL_BLACK, c, 0.025f)); + fl_xyline(x + 2, y + h - 4, x + w - 3); + gtk_color(fl_color_average(FL_BLACK, c, 0.05f)); + fl_xyline(x + 2, y + h - 3, x + w - 3); + gtk_color(fl_color_average(FL_BLACK, c, 0.1f)); + fl_xyline(x + 2, y + h - 2, x + w - 3); + fl_yxline(x + w - 2, y + 2, y + h - 3); +} + + +static void gtk_down_frame(int x, int y, int w, int h, Fl_Color c) { + gtk_color(fl_color_average(FL_BLACK, c, 0.5)); + fl_begin_loop(); + fl_vertex(x, y + 2); + fl_vertex(x + 2, y); + fl_vertex(x + w - 3, y); + fl_vertex(x + w - 1, y + 2); + fl_vertex(x + w - 1, y + h - 3); + fl_vertex(x + w - 3, y + h - 1); + fl_vertex(x + 2, y + h - 1); + fl_vertex(x, y + h - 3); + fl_end_loop(); + + gtk_color(fl_color_average(FL_BLACK, c, 0.1f)); + fl_xyline(x + 2, y + 1, x + w - 3); + fl_yxline(x + 1, y + 2, y + h - 3); + + gtk_color(fl_color_average(FL_BLACK, c, 0.05f)); + fl_yxline(x + 2, y + h - 2, y + 2, x + w - 2); +} + + +static void gtk_down_box(int x, int y, int w, int h, Fl_Color c) { + gtk_down_frame(x, y, w, h, c); + + gtk_color(c); + fl_rectf(x + 3, y + 3, w - 5, h - 4); + fl_yxline(x + w - 2, y + 3, y + h - 3); +} + + +static void gtk_thin_up_frame(int x, int y, int w, int h, Fl_Color c) { + gtk_color(fl_color_average(FL_WHITE, c, 0.6f)); + fl_xyline(x + 1, y, x + w - 2); + fl_yxline(x, y + 1, y + h - 2); + + gtk_color(fl_color_average(FL_BLACK, c, 0.4f)); + fl_xyline(x + 1, y + h - 1, x + w - 2); + fl_yxline(x + w - 1, y + 1, y + h - 2); +} + + +static void gtk_thin_up_box(int x, int y, int w, int h, Fl_Color c) { + gtk_thin_up_frame(x, y, w, h, c); + + gtk_color(fl_color_average(FL_WHITE, c, 0.4f)); + fl_xyline(x + 1, y + 1, x + w - 2); + gtk_color(fl_color_average(FL_WHITE, c, 0.2f)); + fl_xyline(x + 1, y + 2, x + w - 2); + gtk_color(fl_color_average(FL_WHITE, c, 0.1f)); + fl_xyline(x + 1, y + 3, x + w - 2); + gtk_color(c); + fl_rectf(x + 1, y + 4, w - 2, h - 8); + gtk_color(fl_color_average(FL_BLACK, c, 0.025f)); + fl_xyline(x + 1, y + h - 4, x + w - 2); + gtk_color(fl_color_average(FL_BLACK, c, 0.05f)); + fl_xyline(x + 1, y + h - 3, x + w - 2); + gtk_color(fl_color_average(FL_BLACK, c, 0.1f)); + fl_xyline(x + 1, y + h - 2, x + w - 2); +} + + +static void gtk_thin_down_frame(int x, int y, int w, int h, Fl_Color c) { + gtk_color(fl_color_average(FL_BLACK, c, 0.4f)); + fl_xyline(x + 1, y, x + w - 2); + fl_yxline(x, y + 1, y + h - 2); + + gtk_color(fl_color_average(FL_WHITE, c, 0.6f)); + fl_xyline(x + 1, y + h - 1, x + w - 2); + fl_yxline(x + w - 1, y + 1, y + h - 2); +} + + +static void gtk_thin_down_box(int x, int y, int w, int h, Fl_Color c) { + gtk_thin_down_frame(x, y, w, h, c); + + gtk_color(c); + fl_rectf(x + 1, y + 1, w - 2, h - 2); +} + +//------------------------ +// new GTK+ style for round buttons +#if 1 + +static void fl_arc_i(int x,int y,int w,int h,double a1,double a2) { + fl_arc(x,y,w,h,a1,a2); +} + +enum {UPPER_LEFT, LOWER_RIGHT, CLOSED, FILL}; + +static void draw(int which, int x,int y,int w,int h, int inset) +{ + if (inset*2 >= w) inset = (w-1)/2; + if (inset*2 >= h) inset = (h-1)/2; + x += inset; + y += inset; + w -= 2*inset; + h -= 2*inset; + int d = w <= h ? w : h; + if (d <= 1) return; + void (*f)(int,int,int,int,double,double); + f = (which==FILL) ? fl_pie : fl_arc_i; + if (which >= CLOSED) { + f(x+w-d, y, d, d, w<=h ? 0 : -90, w<=h ? 180 : 90); + f(x, y+h-d, d, d, w<=h ? 180 : 90, w<=h ? 360 : 270); + } else if (which == UPPER_LEFT) { + f(x+w-d, y, d, d, 45, w<=h ? 180 : 90); + f(x, y+h-d, d, d, w<=h ? 180 : 90, 225); + } else { // LOWER_RIGHT + f(x, y+h-d, d, d, 225, w<=h ? 360 : 270); + f(x+w-d, y, d, d, w<=h ? 360 : 270, 360+45); + } + if (which == FILL) { + if (w < h) + fl_rectf(x, y+d/2, w, h-(d&-2)); + else if (w > h) + fl_rectf(x+d/2, y, w-(d&-2), h); + } else { + if (w < h) { + if (which != UPPER_LEFT) fl_yxline(x+w-1, y+d/2-1, y+h-d/2+1); + if (which != LOWER_RIGHT) fl_yxline(x, y+d/2-1, y+h-d/2+1); + } else if (w > h) { + if (which != UPPER_LEFT) fl_xyline(x+d/2-1, y+h-1, x+w-d/2+1); + if (which != LOWER_RIGHT) fl_xyline(x+d/2-1, y, x+w-d/2+1); + } + } +} + +void gtk_round_up_box(int x, int y, int w, int h, Fl_Color c) { + fl_color(c); + draw(FILL, x, y, w, h, 2); + + gtk_color(fl_color_average(FL_BLACK, c, 0.025f)); + draw(LOWER_RIGHT, x+1, y, w-2, h, 2); + draw(LOWER_RIGHT, x, y, w, h, 3); + gtk_color(fl_color_average(FL_BLACK, c, 0.05f)); + draw(LOWER_RIGHT, x+1, y, w-2, h, 1); + draw(LOWER_RIGHT, x, y, w, h, 2); + gtk_color(fl_color_average(FL_BLACK, c, 0.1f)); + draw(LOWER_RIGHT, x+1, y, w-2, h, 0); + draw(LOWER_RIGHT, x, y, w, h, 1); + + gtk_color(fl_color_average(FL_WHITE, c, 0.1f)); + draw(UPPER_LEFT, x, y, w, h, 4); + draw(UPPER_LEFT, x+1, y, w-2, h, 3); + gtk_color(fl_color_average(FL_WHITE, c, 0.2f)); + draw(UPPER_LEFT, x, y, w, h, 3); + draw(UPPER_LEFT, x+1, y, w-2, h, 2); + gtk_color(fl_color_average(FL_WHITE, c, 0.4f)); + draw(UPPER_LEFT, x, y, w, h, 2); + draw(UPPER_LEFT, x+1, y, w-2, h, 1); + gtk_color(fl_color_average(FL_WHITE, c, 0.5f)); + draw(UPPER_LEFT, x, y, w, h, 1); + draw(UPPER_LEFT, x+1, y, w-2, h, 0); + + gtk_color(fl_color_average(FL_BLACK, c, 0.5f)); + draw(CLOSED, x, y, w, h, 0); +} + +void gtk_round_down_box(int x, int y, int w, int h, Fl_Color c) { + fl_color(c); + draw(FILL, x, y, w, h, 2); + + gtk_color(fl_color_average(FL_BLACK, c, 0.05f)); + draw(UPPER_LEFT, x, y, w, h, 2); + draw(UPPER_LEFT, x+1, y, w-2, h, 1); + gtk_color(fl_color_average(FL_BLACK, c, 0.1f)); + draw(UPPER_LEFT, x, y, w, h, 1); + draw(UPPER_LEFT, x+1, y, w-2, h, 0); + + gtk_color(fl_color_average(FL_BLACK, c, 0.5f)); + draw(CLOSED, x, y, w, h, 0); +} + +#else + +static void gtk_round_up_box(int x, int y, int w, int h, Fl_Color c) { + gtk_color(c); + fl_pie(x, y, w, h, 0.0, 360.0); + gtk_color(fl_color_average(FL_WHITE, c, 0.5f)); + fl_arc(x, y, w, h, 45.0, 180.0); + gtk_color(fl_color_average(FL_WHITE, c, 0.25f)); + fl_arc(x, y, w, h, 180.0, 405.0); + gtk_color(fl_color_average(FL_BLACK, c, 0.5f)); + fl_arc(x, y, w, h, 225.0, 360.0); +} + + +static void gtk_round_down_box(int x, int y, int w, int h, Fl_Color c) { + gtk_color(c); + fl_pie(x, y, w, h, 0.0, 360.0); + gtk_color(fl_color_average(FL_BLACK, c, 0.2)); + fl_arc(x + 1, y, w, h, 90.0, 210.0); + gtk_color(fl_color_average(FL_BLACK, c, 0.6)); + fl_arc(x, y, w, h, 0.0, 360.0); +} + +#endif + +Fl_Boxtype fl_define_FL_GTK_UP_BOX() { + fl_internal_boxtype(_FL_GTK_UP_BOX, gtk_up_box); + fl_internal_boxtype(_FL_GTK_DOWN_BOX, gtk_down_box); + fl_internal_boxtype(_FL_GTK_UP_FRAME, gtk_up_frame); + fl_internal_boxtype(_FL_GTK_DOWN_FRAME, gtk_down_frame); + fl_internal_boxtype(_FL_GTK_THIN_UP_BOX, gtk_thin_up_box); + fl_internal_boxtype(_FL_GTK_THIN_DOWN_BOX, gtk_thin_down_box); + fl_internal_boxtype(_FL_GTK_THIN_UP_FRAME, gtk_thin_up_frame); + fl_internal_boxtype(_FL_GTK_THIN_DOWN_FRAME, gtk_thin_down_frame); + fl_internal_boxtype(_FL_GTK_ROUND_UP_BOX, gtk_round_up_box); + fl_internal_boxtype(_FL_GTK_ROUND_DOWN_BOX, gtk_round_down_box); + + return _FL_GTK_UP_BOX; +} + + +// +// End of "$Id: fl_gtk.cxx 5721 2007-02-27 19:23:24Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_images_core.cxx b/third_party/windows/fltk-1.1.10/src/fl_images_core.cxx new file mode 100644 index 0000000..eff0055 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_images_core.cxx @@ -0,0 +1,103 @@ +// +// "$Id: fl_images_core.cxx 5845 2007-05-20 00:01:06Z mike $" +// +// FLTK images library core. +// +// Copyright 1997-2005 by Easy Software Products. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// Contents: +// +// fl_register_images() - Register the image formats. +// fl_check_images() - Check for a supported image format. +// + +// +// Include necessary header files... +// + +#include +#include +#include +#include +#include +#include +#include +#include +#include "flstring.h" + + +// +// Define a simple global image registration function that registers +// the extra image formats that aren't part of the core FLTK library. +// + +static Fl_Image *fl_check_images(const char *name, uchar *header, int headerlen); + + +// +// 'fl_register_images()' - Register the image formats. +// + +void fl_register_images() { + Fl_Shared_Image::add_handler(fl_check_images); +} + + +// +// 'fl_check_images()' - Check for a supported image format. +// + +Fl_Image * // O - Image, if found +fl_check_images(const char *name, // I - Filename + uchar *header, // I - Header data from file + int) { // I - Amount of data (not used) + if (memcmp(header, "GIF87a", 6) == 0 || + memcmp(header, "GIF89a", 6) == 0) // GIF file + return new Fl_GIF_Image(name); + + if (memcmp(header, "BM", 2) == 0) // BMP file + return new Fl_BMP_Image(name); + + if (header[0] == 'P' && header[1] >= '1' && header[1] <= '7') + // Portable anymap + return new Fl_PNM_Image(name); + +#ifdef HAVE_LIBPNG + if (memcmp(header, "\211PNG", 4) == 0)// PNG file + return new Fl_PNG_Image(name); +#endif // HAVE_LIBPNG + +#ifdef HAVE_LIBJPEG + if (memcmp(header, "\377\330\377", 3) == 0 && + // Start-of-Image + header[3] >= 0xc0 && header[3] <= 0xef) + // APPn for JPEG file + return new Fl_JPEG_Image(name); +#endif // HAVE_LIBJPEG + + return 0; +} + + +// +// End of "$Id: fl_images_core.cxx 5845 2007-05-20 00:01:06Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_labeltype.cxx b/third_party/windows/fltk-1.1.10/src/fl_labeltype.cxx new file mode 100644 index 0000000..dc2289e --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_labeltype.cxx @@ -0,0 +1,133 @@ +// +// "$Id: fl_labeltype.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Label drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Drawing code for the (one) common label types. +// Other label types (symbols) are in their own source files +// to avoid linking if not used. + +#include +#include +#include +#include +#include + +void +fl_no_label(const Fl_Label*,int,int,int,int,Fl_Align) {} + +void +fl_normal_label(const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) +{ + fl_font(o->font, o->size); + fl_color((Fl_Color)o->color); + fl_draw(o->value, X, Y, W, H, align, o->image); +} + +void +fl_normal_measure(const Fl_Label* o, int& W, int& H) { + fl_font(o->font, o->size); + fl_measure(o->value, W, H); + if (o->image) { + if (o->image->w() > W) W = o->image->w(); + H += o->image->h(); + } +} + +#define MAX_LABELTYPE 16 + +static Fl_Label_Draw_F* table[MAX_LABELTYPE] = { + fl_normal_label, + fl_no_label, + fl_normal_label, // _FL_SHADOW_LABEL, + fl_normal_label, // _FL_ENGRAVED_LABEL, + fl_normal_label, // _FL_EMBOSSED_LABEL, + fl_no_label, // _FL_MULTI_LABEL, + fl_no_label, // _FL_ICON_LABEL, + // FL_FREE_LABELTYPE+n: + fl_no_label, fl_no_label, fl_no_label, + fl_no_label, fl_no_label, fl_no_label, + fl_no_label, fl_no_label, fl_no_label +}; + +static Fl_Label_Measure_F* measure[MAX_LABELTYPE]; + +void Fl::set_labeltype(Fl_Labeltype t,Fl_Label_Draw_F* f,Fl_Label_Measure_F*m) +{ + table[t] = f; measure[t] = m; +} + +//////////////////////////////////////////////////////////////// + +// draw label with arbitrary alignment in arbitrary box: +void Fl_Label::draw(int X, int Y, int W, int H, Fl_Align align) const { + if (!value && !image) return; + table[type](this, X, Y, W, H, align); +} + +void Fl_Label::measure(int& W, int& H) const { + if (!value && !image) { + W = H = 0; + return; + } + + Fl_Label_Measure_F* f = ::measure[type]; if (!f) f = fl_normal_measure; + f(this, W, H); +} + +// The normal call for a draw() method: +void Fl_Widget::draw_label() const { + int X = x_+Fl::box_dx(box()); + int W = w_-Fl::box_dw(box()); + if (W > 11 && align()&(FL_ALIGN_LEFT|FL_ALIGN_RIGHT)) {X += 3; W -= 6;} + draw_label(X, y_+Fl::box_dy(box()), W, h_-Fl::box_dh(box())); +} + +// draw() can use this instead to change the bounding box: +void Fl_Widget::draw_label(int X, int Y, int W, int H) const { + // quit if we are not drawing a label inside the widget: + if ((align()&15) && !(align() & FL_ALIGN_INSIDE)) return; + draw_label(X,Y,W,H,align()); +} + +// Anybody can call this to force the label to draw anywhere: +void Fl_Widget::draw_label(int X, int Y, int W, int H, Fl_Align a) const { + if (flags()&SHORTCUT_LABEL) fl_draw_shortcut = 1; + Fl_Label l1 = label_; + if (!active_r()) { + l1.color = fl_inactive((Fl_Color)l1.color); + if (l1.deimage) l1.image = l1.deimage; + } + l1.draw(X,Y,W,H,a); + fl_draw_shortcut = 0; +} + +// include these vars here so they can be referenced without including +// Fl_Input_ code: +#include + +// +// End of "$Id: fl_labeltype.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_line_style.cxx b/third_party/windows/fltk-1.1.10/src/fl_line_style.cxx new file mode 100644 index 0000000..3798da5 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_line_style.cxx @@ -0,0 +1,165 @@ +// +// "$Id: fl_line_style.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Line style code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include "flstring.h" +#include + +#ifdef __APPLE_QUARTZ__ +float fl_quartz_line_width_ = 1.0f; +static enum CGLineCap fl_quartz_line_cap_ = kCGLineCapButt; +static enum CGLineJoin fl_quartz_line_join_ = kCGLineJoinMiter; +static float *fl_quartz_line_pattern = 0; +static int fl_quartz_line_pattern_size = 0; +void fl_quartz_restore_line_style_() { + CGContextSetLineWidth(fl_gc, fl_quartz_line_width_); + CGContextSetLineCap(fl_gc, fl_quartz_line_cap_); + CGContextSetLineJoin(fl_gc, fl_quartz_line_join_); + CGContextSetLineDash(fl_gc, 0, fl_quartz_line_pattern, fl_quartz_line_pattern_size); +} +#endif + +void fl_line_style(int style, int width, char* dashes) { +#ifdef WIN32 + // According to Bill, the "default" cap and join should be the + // "fastest" mode supported for the platform. I don't know why + // they should be different (same graphics cards, etc., right?) MRS + static DWORD Cap[4]= {PS_ENDCAP_FLAT, PS_ENDCAP_FLAT, PS_ENDCAP_ROUND, PS_ENDCAP_SQUARE}; + static DWORD Join[4]={PS_JOIN_ROUND, PS_JOIN_MITER, PS_JOIN_ROUND, PS_JOIN_BEVEL}; + int s1 = PS_GEOMETRIC | Cap[(style>>8)&3] | Join[(style>>12)&3]; + DWORD a[16]; int n = 0; + if (dashes && dashes[0]) { + s1 |= PS_USERSTYLE; + for (n = 0; n < 16 && *dashes; n++) a[n] = *dashes++; + } else { + s1 |= style & 0xff; // allow them to pass any low 8 bits for style + } + if ((style || n) && !width) width = 1; // fix cards that do nothing for 0? + LOGBRUSH penbrush = {BS_SOLID,fl_RGB(),0}; // can this be fl_brush()? + HPEN newpen = ExtCreatePen(s1, width, &penbrush, n, n ? a : 0); + if (!newpen) { + Fl::error("fl_line_style(): Could not create GDI pen object."); + return; + } + HPEN oldpen = (HPEN)SelectObject(fl_gc, newpen); + DeleteObject(oldpen); + DeleteObject(fl_current_xmap->pen); + fl_current_xmap->pen = newpen; +#elif defined(__APPLE_QD__) + // QuickDraw supports pen size and pattern, but no arbitrary line styles. + static Pattern styles[] = { + { { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff } }, // FL_SOLID + { { 0xf0, 0xf0, 0xf0, 0xf0, 0x0f, 0x0f, 0x0f, 0x0f } }, // FL_DASH + { { 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55 } } // FL_DOT + }; + + if (!width) width = 1; + PenSize(width, width); + + style &= 0xff; + if (style > 2) style = 2; + PenPat(styles + style); +#elif defined(__APPLE_QUARTZ__) + static enum CGLineCap Cap[4] = { kCGLineCapButt, kCGLineCapButt, + kCGLineCapRound, kCGLineCapSquare }; + static enum CGLineJoin Join[4] = { kCGLineJoinMiter, kCGLineJoinMiter, + kCGLineJoinRound, kCGLineJoinBevel }; + if (width<1) width = 1; + fl_quartz_line_width_ = (float)width; + fl_quartz_line_cap_ = Cap[(style>>8)&3]; + fl_quartz_line_join_ = Join[(style>>12)&3]; + char *d = dashes; + static float pattern[16]; + if (d && *d) { + float *p = pattern; + while (*d) { *p++ = (float)*d++; } + fl_quartz_line_pattern = pattern; + fl_quartz_line_pattern_size = d-dashes; + } else if (style & 0xff) { + char dash, dot, gap; + // adjust lengths to account for cap: + if (style & 0x200) { + dash = char(2*width); + dot = 1; + gap = char(2*width-1); + } else { + dash = char(3*width); + dot = gap = char(width); + } + float *p = pattern; + switch (style & 0xff) { + case FL_DASH: *p++ = dash; *p++ = gap; break; + case FL_DOT: *p++ = dot; *p++ = gap; break; + case FL_DASHDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; break; + case FL_DASHDOTDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; *p++ = dot; *p++ = gap; break; + } + fl_quartz_line_pattern_size = p-pattern; + fl_quartz_line_pattern = pattern; + } else { + fl_quartz_line_pattern = 0; fl_quartz_line_pattern_size = 0; + } + fl_quartz_restore_line_style_(); +#else + int ndashes = dashes ? strlen(dashes) : 0; + // emulate the WIN32 dash patterns on X + char buf[7]; + if (!ndashes && (style&0xff)) { + int w = width ? width : 1; + char dash, dot, gap; + // adjust lengths to account for cap: + if (style & 0x200) { + dash = char(2*w); + dot = 1; // unfortunately 0 does not work + gap = char(2*w-1); + } else { + dash = char(3*w); + dot = gap = char(w); + } + char* p = dashes = buf; + switch (style & 0xff) { + case FL_DASH: *p++ = dash; *p++ = gap; break; + case FL_DOT: *p++ = dot; *p++ = gap; break; + case FL_DASHDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; break; + case FL_DASHDOTDOT: *p++ = dash; *p++ = gap; *p++ = dot; *p++ = gap; *p++ = dot; *p++ = gap; break; + } + ndashes = p-buf; + } + static int Cap[4] = {CapButt, CapButt, CapRound, CapProjecting}; + static int Join[4] = {JoinMiter, JoinMiter, JoinRound, JoinBevel}; + XSetLineAttributes(fl_display, fl_gc, width, + ndashes ? LineOnOffDash : LineSolid, + Cap[(style>>8)&3], Join[(style>>12)&3]); + if (ndashes) XSetDashes(fl_display, fl_gc, 0, dashes, ndashes); +#endif +} + + +// +// End of "$Id: fl_line_style.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_open_uri.cxx b/third_party/windows/fltk-1.1.10/src/fl_open_uri.cxx new file mode 100644 index 0000000..f0b5e4f --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_open_uri.cxx @@ -0,0 +1,370 @@ +// +// "$Id: fl_open_uri.cxx 5636 2007-01-23 20:45:28Z mike $" +// +// fl_open_uri() code for FLTK. +// +// Test with: +// +// gcc -I/fltk/dir -I/fltk/dir/src -DTEST -o fl_open_uri fl_open_uri.cxx -lfltk +// +// Copyright 2003-2007 by Michael R Sweet +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// + +// +// Include necessary headers... +// + +#include +#include +#include +#include +#include +#include "flstring.h" +#ifdef WIN32 +# include +# include +#else +# include +# include +# include +# include +#endif // WIN32 + + +// +// Local functions... +// + +#if !defined(WIN32) && !defined(__APPLE__) +static char *path_find(const char *program, char *filename, int filesize); +#endif // !WIN32 && !__APPLE__ +#ifndef WIN32 +static int run_program(const char *program, char **argv, char *msg, int msglen); +#endif // !WIN32 + + +/** + * Open the specified URI. + * + * fl_open_uri() opens the specified Uniform Resource Identifier (URI) + * using an operating-system dependent program or interface. For URIs + * using the "ftp", "http", or "https" schemes, the system default web + * browser is used to open the URI, while "mailto" and "news" URIs are + * typically opened using the system default mail reader and "file" URIs + * are opened using the file system navigator. + * + * On success, the (optional) msg buffer is filled with the command that + * was run to open the URI; on Windows, this will always be "open uri". + * + * On failure, the msg buffer is filled with an English error message. + * + * @param uri The URI to open + * @param msg Optional buffer which contains the command or error message + * @param msglen Length of optional buffer + * @return 1 on success, 0 on failure + */ + +int +fl_open_uri(const char *uri, char *msg, int msglen) { + // Supported URI schemes... + static const char * const schemes[] = { + "file://", + "ftp://", + "http://", + "https://", + "mailto:", + "news://", + NULL + }; + + // Validate the URI scheme... + int i; + for (i = 0; schemes[i]; i ++) + if (!strncmp(uri, schemes[i], strlen(schemes[i]))) + break; + + if (!schemes[i]) { + if (msg) { + char scheme[255]; + if (sscanf(uri, "%254[^:]", scheme) == 1) { + snprintf(msg, msglen, "URI scheme \"%s\" not supported.", scheme); + } else { + snprintf(msg, msglen, "Bad URI \"%s\"", uri); + } + } + + return 0; + } + +#ifdef WIN32 + if (msg) snprintf(msg, msglen, "open %s", uri); + + return (int)ShellExecute(HWND_DESKTOP, "open", uri, NULL, NULL, SW_SHOW) > 32; + +#elif defined(__APPLE__) + char *argv[3]; // Command-line arguments + + argv[0] = "open"; + argv[1] = (char *)uri; + argv[2] = 0; + + if (msg) snprintf(msg, msglen, "open %s", uri); + + return run_program("/usr/bin/open", argv, msg, msglen) != 0; + +#else // !WIN32 && !__APPLE__ + // Run any of several well-known commands to open the URI. + // + // We give preference to the Portland group's xdg-utils + // programs which run the user's preferred web browser, etc. + // based on the current desktop environment in use. We fall + // back on older standards and then finally test popular programs + // until we find one we can use. + // + // Note that we specifically do not support the MAILER and + // BROWSER environment variables because we have no idea whether + // we need to run the listed commands in a terminal program. + + char command[1024], // Command to run... + *argv[4], // Command-line arguments + remote[1024]; // Remote-mode command... + const char * const *commands; // Array of commands to check... + static const char * const browsers[] = { + "xdg-open", // Portland + "htmlview", // Freedesktop.org + "firefox", + "mozilla", + "netscape", + "konqueror", // KDE + "opera", + "hotjava", // Solaris + "mosaic", + NULL + }; + static const char * const readers[] = { + "xdg-email", // Portland + "thunderbird", + "mozilla", + "netscape", + "evolution", // GNOME + "kmailservice", // KDE + NULL + }; + static const char * const managers[] = { + "xdg-open", // Portland + "fm", // IRIX + "dtaction", // CDE + "nautilus", // GNOME + "konqueror", // KDE + NULL + }; + + // Figure out which commands to check for... + if (!strncmp(uri, "file://", 7)) commands = managers; + else if (!strncmp(uri, "mailto:", 7) || + !strncmp(uri, "news:", 5)) commands = readers; + else commands = browsers; + + // Find the command to run... + for (i = 0; commands[i]; i ++) + if (path_find(commands[i], command, sizeof(command))) break; + + if (!commands[i]) { + if (msg) { + snprintf(msg, msglen, "No helper application found for \"%s\"", uri); + } + + return 0; + } + + // Handle command-specific arguments... + argv[0] = (char *)commands[i]; + + if (!strcmp(commands[i], "firefox") || + !strcmp(commands[i], "mozilla") || + !strcmp(commands[i], "netscape") || + !strcmp(commands[i], "thunderbird")) { + // program -remote openURL(uri) + snprintf(remote, sizeof(remote), "openURL(%s)", uri); + + argv[1] = (char *)"-remote"; + argv[2] = remote; + argv[3] = 0; + } else if (!strcmp(commands[i], "dtaction")) { + // dtaction open uri + argv[1] = (char *)"open"; + argv[2] = (char *)uri; + argv[3] = 0; + } else { + // program uri + argv[1] = (char *)uri; + argv[2] = 0; + } + + if (msg) { + strlcpy(msg, argv[0], msglen); + + for (i = 1; argv[i]; i ++) { + strlcat(msg, " ", msglen); + strlcat(msg, argv[i], msglen); + } + } + + return run_program(command, argv, msg, msglen) != 0; +#endif // WIN32 +} + + +#if !defined(WIN32) && !defined(__APPLE__) +// Find a program in the path... +static char *path_find(const char *program, char *filename, int filesize) { + const char *path; // Search path + char *ptr, // Pointer into filename + *end; // End of filename buffer + + + if ((path = getenv("PATH")) == NULL) path = "/bin:/usr/bin"; + + for (ptr = filename, end = filename + filesize - 1; *path; path ++) { + if (*path == ':') { + if (ptr > filename && ptr[-1] != '/' && ptr < end) *ptr++ = '/'; + + strlcpy(ptr, program, end - ptr + 1); + + if (!access(filename, X_OK)) return filename; + + ptr = filename; + } else if (ptr < end) *ptr++ = *path; + } + + if (ptr > filename) { + if (ptr[-1] != '/' && ptr < end) *ptr++ = '/'; + + strlcpy(ptr, program, end - ptr + 1); + + if (!access(filename, X_OK)) return filename; + } + + return 0; +} +#endif // !WIN32 && !__APPLE__ + + +#ifndef WIN32 +// Run the specified program, returning 1 on success and 0 on failure +static int +run_program(const char *program, char **argv, char *msg, int msglen) { + pid_t pid; // Process ID of first child + int status; // Exit status from first child + sigset_t set, oldset; // Signal masks + + + // Block SIGCHLD while we run the program... + // + // Note that I only use the POSIX signal APIs, however older operating + // systems may either not support POSIX signals or have side effects. + // IRIX, for example, provides three separate and incompatible signal + // APIs, so it is possible that an application setting a signal handler + // via signal() or sigset() will not have its SIGCHLD signals blocked... + + sigemptyset(&set); + sigaddset(&set, SIGCHLD); + sigprocmask(SIG_BLOCK, &set, &oldset); + + // Create child processes that actually run the program for us... + if ((pid = fork()) == 0) { + // First child comes here, fork a second child and exit... + if (!fork()) { + // Second child comes here, redirect stdin/out/err to /dev/null... + close(0); + open("/dev/null", O_RDONLY); + + close(1); + open("/dev/null", O_WRONLY); + + close(2); + open("/dev/null", O_WRONLY); + + // Detach from the current process group... + setsid(); + + // Run the program... + execv(program, argv); + _exit(0); + } else { + // First child gets here, exit immediately... + _exit(0); + } + } else if (pid < 0) { + // Restore signal handling... + sigprocmask(SIG_SETMASK, &oldset, NULL); + + // Return indicating failure... + return 0; + } + + // Wait for the first child to exit... + while (waitpid(pid, &status, 0) < 0) { + if (errno != EINTR) { + // Someone else grabbed the child status... + if (msg) snprintf(msg, msglen, "waitpid(%ld) failed: %s", (long)pid, + strerror(errno)); + + // Restore signal handling... + sigprocmask(SIG_SETMASK, &oldset, NULL); + + // Return indicating failure... + return 0; + } + } + + // Restore signal handling... + sigprocmask(SIG_SETMASK, &oldset, NULL); + + // Return indicating success... + return 1; +} +#endif // !WIN32 + + +#ifdef TEST +// +// Test code... +// + +// Open the URI on the command-line... +int main(int argc, char **argv) { + char msg[1024]; + + + if (argc != 2) { + puts("Usage: fl_open_uri URI"); + return 1; + } + + if (!fl_open_uri(argv[1], msg, sizeof(msg))) { + puts(msg); + return 1; + } else return 0; +} +#endif // TEST + + +// +// End of "$Id: fl_open_uri.cxx 5636 2007-01-23 20:45:28Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_oval_box.cxx b/third_party/windows/fltk-1.1.10/src/fl_oval_box.cxx new file mode 100644 index 0000000..06132de --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_oval_box.cxx @@ -0,0 +1,66 @@ +// +// "$Id: fl_oval_box.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Oval box drawing code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + + +// Less-used box types are in seperate files so they are not linked +// in if not used. + +#include +#include + +static void fl_oval_flat_box(int x, int y, int w, int h, Fl_Color c) { + fl_color(c); + fl_pie(x, y, w, h, 0, 360); +} + +static void fl_oval_frame(int x, int y, int w, int h, Fl_Color c) { + fl_color(c); + fl_arc(x, y, w, h, 0, 360); +} + +static void fl_oval_box(int x, int y, int w, int h, Fl_Color c) { + fl_oval_flat_box(x,y,w,h,c); + fl_oval_frame(x,y,w,h,FL_BLACK); +} + +static void fl_oval_shadow_box(int x, int y, int w, int h, Fl_Color c) { + fl_oval_flat_box(x+3,y+3,w,h,FL_DARK3); + fl_oval_box(x,y,w,h,c); +} + +extern void fl_internal_boxtype(Fl_Boxtype, Fl_Box_Draw_F*); +Fl_Boxtype fl_define_FL_OVAL_BOX() { + fl_internal_boxtype(_FL_OSHADOW_BOX,fl_oval_shadow_box); + fl_internal_boxtype(_FL_OVAL_FRAME,fl_oval_frame); + fl_internal_boxtype(_FL_OFLAT_BOX,fl_oval_flat_box); + fl_internal_boxtype(_FL_OVAL_BOX,fl_oval_box); + return _FL_OVAL_BOX; +} + +// +// End of "$Id: fl_oval_box.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_overlay.cxx b/third_party/windows/fltk-1.1.10/src/fl_overlay.cxx new file mode 100644 index 0000000..6082b69 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_overlay.cxx @@ -0,0 +1,125 @@ +// +// "$Id: fl_overlay.cxx 5614 2007-01-18 15:25:09Z matt $" +// +// Overlay support for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Extremely limited "overlay" support. You can use this to drag out +// a rectangle in response to mouse events. It is your responsibility +// to erase the overlay before drawing anything that might intersect +// it. + +#include +#include +#ifdef __APPLE__ +#include +#endif + +//#define USE_XOR + +static int px,py,pw,ph; + +#ifndef USE_XOR +#include +static uchar *bgN = 0L, *bgS = 0L, *bgE = 0L, *bgW = 0L; +static int bgx, bgy, bgw, bgh; +#endif + +static void draw_current_rect() { +#ifdef USE_XOR +# ifdef WIN32 + int old = SetROP2(fl_gc, R2_NOT); + fl_rect(px, py, pw, ph); + SetROP2(fl_gc, old); +# elif defined(__APPLE_QD__) + PenMode( patXor ); + fl_rect(px, py, pw, ph); + PenMode( patCopy ); +# elif defined(__APPLE_QUARTZ__) + // warning: Quartz does not support xor drawing + // Use the Fl_Overlay_Window instead. + fl_color(FL_WHITE); + fl_rect(px, py, pw, ph); +# else + XSetFunction(fl_display, fl_gc, GXxor); + XSetForeground(fl_display, fl_gc, 0xffffffff); + XDrawRectangle(fl_display, fl_window, fl_gc, px, py, pw, ph); + XSetFunction(fl_display, fl_gc, GXcopy); +# endif +#else + if (bgN) { free(bgN); bgN = 0L; } + if (bgS) { free(bgS); bgS = 0L; } + if (bgE) { free(bgE); bgE = 0L; } + if (bgW) { free(bgW); bgW = 0L; } + if (pw>0 && ph>0) { + bgE = fl_read_image(0L, px+pw-1, py, 1, ph); + bgW = fl_read_image(0L, px, py, 1, ph); + bgS = fl_read_image(0L, px, py+ph-1, pw, 1); + bgN = fl_read_image(0L, px, py, pw, 1); + bgx = px; bgy = py; + bgw = pw; bgh = ph; + } + fl_color(FL_WHITE); + fl_line_style(FL_SOLID); + fl_rect(px, py, pw, ph); + fl_color(FL_BLACK); + fl_line_style(FL_DOT); + fl_rect(px, py, pw, ph); + fl_line_style(FL_SOLID); +#endif +} + +static void erase_current_rect() { +#ifdef USE_XOR +# ifdef __APPLE_QUARTZ__ + fl_rect(px, py, pw, ph); +# else + draw_current_rect(); +# endif +#else + if (bgN) fl_draw_image(bgN, bgx, bgy, bgw, 1); + if (bgS) fl_draw_image(bgS, bgx, bgy+bgh-1, bgw, 1); + if (bgW) fl_draw_image(bgW, bgx, bgy, 1, bgh); + if (bgE) fl_draw_image(bgE, bgx+bgw-1, bgy, 1, bgh); +#endif +} + +void fl_overlay_clear() { + if (pw > 0) {erase_current_rect(); pw = 0;} +} + +void fl_overlay_rect(int x, int y, int w, int h) { + if (w < 0) {x += w; w = -w;} else if (!w) w = 1; + if (h < 0) {y += h; h = -h;} else if (!h) h = 1; + if (pw > 0) { + if (x==px && y==py && w==pw && h==ph) return; + erase_current_rect(); + } + px = x; py = y; pw = w; ph = h; + draw_current_rect(); +} + +// +// End of "$Id: fl_overlay.cxx 5614 2007-01-18 15:25:09Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_overlay_visual.cxx b/third_party/windows/fltk-1.1.10/src/fl_overlay_visual.cxx new file mode 100644 index 0000000..4c72fb1 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_overlay_visual.cxx @@ -0,0 +1,105 @@ +// +// "$Id: fl_overlay_visual.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// X overlay support for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Return an overlay visual, if any. Also allocate a colormap and +// record the depth for fl_color() to use. +// Another disgusting X interface, based on code extracted and +// purified with great difficulty from XLayerUtil.cxx: + +#include +#if HAVE_OVERLAY +#include +#include + +// SERVER_OVERLAY_VISUALS property element: +struct OverlayInfo { + long overlay_visual; + long transparent_type; + long value; + long layer; +}; + +extern Colormap fl_overlay_colormap; +extern XVisualInfo* fl_overlay_visual; +extern ulong fl_transparent_pixel; + +XVisualInfo *fl_find_overlay_visual() { + static char beenhere; + if (beenhere) return fl_overlay_visual; + beenhere = 1; + + fl_open_display(); + Atom overlayVisualsAtom = + XInternAtom(fl_display,"SERVER_OVERLAY_VISUALS",1); + if (!overlayVisualsAtom) return 0; + OverlayInfo *overlayInfo; + ulong sizeData, bytesLeft; + Atom actualType; + int actualFormat; + if (XGetWindowProperty(fl_display, RootWindow(fl_display, fl_screen), + overlayVisualsAtom, 0L, 10000L, False, + overlayVisualsAtom, &actualType, &actualFormat, + &sizeData, &bytesLeft, + (unsigned char **) &overlayInfo)) return 0; + + if (actualType == overlayVisualsAtom && actualFormat == 32) { + int n = int(sizeData/4); + XVisualInfo* v = 0; + // find the greatest depth that has a transparent pixel: + for (int i = 0; i < n; i++) { + if (overlayInfo[i].transparent_type != 1) continue; + if (overlayInfo[i].layer <= 0) continue; + XVisualInfo templt; + templt.visualid = overlayInfo[i].overlay_visual; + int num; + XVisualInfo *v1=XGetVisualInfo(fl_display, VisualIDMask, &templt, &num); + if (v1->screen == fl_screen && v1->c_class == PseudoColor + && (!v || v1->depth > v->depth && v1->depth <= 8)) { + if (v) XFree((char*)v); + v = v1; + fl_transparent_pixel = overlayInfo[i].value; + } else { + XFree((char*)v1); + } + } + if (v) { + fl_overlay_visual = v; + fl_overlay_colormap = + XCreateColormap(fl_display, RootWindow(fl_display, fl_screen), + v->visual, AllocNone); + } + } + XFree((char*)overlayInfo); + //printf("overlay visual %ld selected\n", fl_overlay_visual->visualid); + return fl_overlay_visual; +} + +#endif + +// +// End of "$Id: fl_overlay_visual.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_plastic.cxx b/third_party/windows/fltk-1.1.10/src/fl_plastic.cxx new file mode 100644 index 0000000..af09ed9 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_plastic.cxx @@ -0,0 +1,381 @@ +// +// "$Id: fl_plastic.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// "Plastic" drawing routines for the Fast Light Tool Kit (FLTK). +// +// These box types provide a cross between Aqua and KDE buttons; kindof +// like translucent plastic buttons... +// +// Copyright 2001-2005 by Michael Sweet. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Box drawing code for an obscure box type. +// These box types are in seperate files so they are not linked +// in if not used. + +#include +#include +#include "flstring.h" + +// +// Uncomment the following line to restore the old plastic box type +// appearance. +// + +//#define USE_OLD_PLASTIC_BOX +#define USE_OLD_PLASTIC_COLOR + +extern uchar *fl_gray_ramp(); + +inline Fl_Color shade_color(uchar gc, Fl_Color bc) { +#ifdef USE_OLD_PLASTIC_COLOR + return fl_color_average((Fl_Color)gc, bc, 0.75f); +#else + unsigned grgb = Fl::get_color((Fl_Color)gc), + brgb = Fl::get_color(bc); + int red, green, blue, gray; + + + gray = ((grgb >> 24) & 255); + red = gray * ((brgb >> 24) & 255) / 255 + gray * gray / 510; + gray = ((grgb >> 16) & 255); + green = gray * ((brgb >> 16) & 255) / 255 + gray * gray / 510; + gray = ((grgb >> 8) & 255); + blue = gray * ((brgb >> 8) & 255) / 255 + gray * gray / 510; + + if (red > 255) + red = 255; + + if (green > 255) + green = 255; + + if (blue > 255) + blue = 255; + + if (Fl::draw_box_active()) + return fl_rgb_color(red, green, blue); + else + return fl_color_average(FL_GRAY, fl_rgb_color(red, green, blue), 0.75f); +#endif // USE_OLD_PLASTIC_COLOR +} + + +static void frame_rect(int x, int y, int w, int h, const char *c, Fl_Color bc) { + uchar *g = fl_gray_ramp(); + int b = strlen(c) / 4 + 1; + + for (x += b, y += b, w -= 2 * b, h -= 2 * b; b > 1; b --) + { + // Draw lines around the perimeter of the button, 4 colors per + // circuit. + fl_color(shade_color(g[*c++], bc)); + fl_line(x, y + h + b, x + w - 1, y + h + b, x + w + b - 1, y + h); + fl_color(shade_color(g[*c++], bc)); + fl_line(x + w + b - 1, y + h, x + w + b - 1, y, x + w - 1, y - b); + fl_color(shade_color(g[*c++], bc)); + fl_line(x + w - 1, y - b, x, y - b, x - b, y); + fl_color(shade_color(g[*c++], bc)); + fl_line(x - b, y, x - b, y + h, x, y + h + b); + } +} + + +static void frame_round(int x, int y, int w, int h, const char *c, Fl_Color bc) { + uchar *g = fl_gray_ramp(); + int b = strlen(c) / 4 + 1; + + if (w==h) { + for (; b > 1; b --, x ++, y ++, w -= 2, h -= 2) + { + fl_color(shade_color(g[*c++], bc)); + fl_arc(x, y, w, h, 45.0, 135.0); + fl_color(shade_color(g[*c++], bc)); + fl_arc(x, y, w, h, 315.0, 405.0); + fl_color(shade_color(g[*c++], bc)); + fl_arc(x, y, w, h, 225.0, 315.0); + fl_color(shade_color(g[*c++], bc)); + fl_arc(x, y, w, h, 135.0, 225.0); + } + } else if (w>h) { + int d = h/2; + for (; b > 1; d--, b --, x ++, y ++, w -= 2, h -= 2) + { + fl_color(shade_color(g[*c++], bc)); + fl_arc(x, y, h, h, 90.0, 135.0); + fl_xyline(x+d, y, x+w-d); + fl_arc(x+w-h, y, h, h, 45.0, 90.0); + fl_color(shade_color(g[*c++], bc)); + fl_arc(x+w-h, y, h, h, 315.0, 405.0); + fl_color(shade_color(g[*c++], bc)); + fl_arc(x+w-h, y, h, h, 270.0, 315.0); + fl_xyline(x+d, y+h-1, x+w-d); + fl_arc(x, y, h, h, 225.0, 270.0); + fl_color(shade_color(g[*c++], bc)); + fl_arc(x, y, h, h, 135.0, 225.0); + } + } else if (w 1; d--, b --, x ++, y ++, w -= 2, h -= 2) + { + fl_color(shade_color(g[*c++], bc)); + fl_arc(x, y, w, w, 45.0, 135.0); + fl_color(shade_color(g[*c++], bc)); + fl_arc(x, y, w, w, 0.0, 45.0); + fl_yxline(x+w-1, y+d, y+h-d); + fl_arc(x, y+h-w, w, w, 315.0, 360.0); + fl_color(shade_color(g[*c++], bc)); + fl_arc(x, y+h-w, w, w, 225.0, 315.0); + fl_color(shade_color(g[*c++], bc)); + fl_arc(x, y+h-w, w, w, 180.0, 225.0); + fl_yxline(x, y+d, y+h-d); + fl_arc(x, y, w, w, 135.0, 180.0); + } + } +} + + +static void shade_rect(int x, int y, int w, int h, const char *c, Fl_Color bc) { + uchar *g = fl_gray_ramp(); + int i, j; + int clen = strlen(c) - 1; + int chalf = clen / 2; + int cstep = 1; + + if (h < (w * 2)) { + // Horizontal shading... + if (clen >= h) cstep = 2; + + for (i = 0, j = 0; j < chalf; i ++, j += cstep) { + // Draw the top line and points... + fl_color(shade_color(g[c[i]], bc)); + fl_xyline(x + 1, y + i, x + w - 2); + + fl_color(shade_color(g[c[i] - 2], bc)); + fl_point(x, y + i + 1); + fl_point(x + w - 1, y + i + 1); + + // Draw the bottom line and points... + fl_color(shade_color(g[c[clen - i]], bc)); + fl_xyline(x + 1, y + h - i, x + w - 2); + + fl_color(shade_color(g[c[clen - i] - 2], bc)); + fl_point(x, y + h - i); + fl_point(x + w - 1, y + h - i); + } + + // Draw the interior and sides... + i = chalf / cstep; + + fl_color(shade_color(g[c[chalf]], bc)); + fl_rectf(x + 1, y + i, w - 2, h - 2 * i + 1); + + fl_color(shade_color(g[c[chalf] - 2], bc)); + fl_yxline(x, y + i, y + h - i); + fl_yxline(x + w - 1, y + i, y + h - i); + } else { + // Vertical shading... + if (clen >= w) cstep = 2; + + for (i = 0, j = 0; j < chalf; i ++, j += cstep) { + // Draw the left line and points... + fl_color(shade_color(g[c[i]], bc)); + fl_yxline(x + i, y + 1, y + h - 1); + + fl_color(shade_color(g[c[i] - 2], bc)); + fl_point(x + i + 1, y); + fl_point(x + i + 1, y + h); + + // Draw the right line and points... + fl_color(shade_color(g[c[clen - i]], bc)); + fl_yxline(x + w - 1 - i, y + 1, y + h - 1); + + fl_color(shade_color(g[c[clen - i] - 2], bc)); + fl_point(x + w - 2 - i, y); + fl_point(x + w - 2 - i, y + h); + } + + // Draw the interior, top, and bottom... + i = chalf / cstep; + + fl_color(shade_color(g[c[chalf]], bc)); + fl_rectf(x + i, y + 1, w - 2 * i, h - 1); + + fl_color(shade_color(g[c[chalf] - 2], bc)); + fl_xyline(x + i, y, x + w - i); + fl_xyline(x + i, y + h, x + w - i); + } +} + +static void shade_round(int x, int y, int w, int h, const char *c, Fl_Color bc) { + uchar *g = fl_gray_ramp(); + int i; + int clen = strlen(c) - 1; + int chalf = clen / 2; + + if (w>h) { + int d = h/2; + const int na = 8; + for (i=0; i 1) { + fl_xyline(x+1, y, x+w-2); + fl_xyline(x+1, y+h-1, x+w-2); + } + if (h > 1) { + fl_yxline(x, y+1, y+h-2); + fl_yxline(x+w-1, y+1, y+h-2); + } +} + + +static void thin_up_box(int x, int y, int w, int h, Fl_Color c) { +#ifdef USE_OLD_PLASTIC_BOX + shade_rect(x + 2, y + 2, w - 4, h - 5, "RVQNOPQRSTUVWVQ", c); + up_frame(x, y, w, h, c); +#else + if (w > 4 && h > 4) { + shade_rect(x + 1, y + 1, w - 2, h - 3, "RQOQSUWQ", c); + frame_rect(x, y, w, h - 1, "IJLM", c); + } else { + narrow_thin_box(x, y, w, h, c); + } +#endif // USE_OLD_PLASTIC_BOX +} + + +static void up_box(int x, int y, int w, int h, Fl_Color c) { +#ifdef USE_OLD_PLASTIC_BOX + shade_rect(x + 2, y + 2, w - 4, h - 5, "RVQNOPQRSTUVWVQ", c); + up_frame(x, y, w, h, c); +#else + if (w > 8 && h > 8) { + shade_rect(x + 1, y + 1, w - 2, h - 3, "RVQNOPQRSTUVWVQ", c); + frame_rect(x, y, w, h - 1, "IJLM", c); + } else { + thin_up_box(x, y, w, h, c); + } +#endif // USE_OLD_PLASTIC_BOX +} + + +static void up_round(int x, int y, int w, int h, Fl_Color c) { + shade_round(x, y, w, h, "RVQNOPQRSTUVWVQ", c); + frame_round(x, y, w, h, "IJLM", c); +} + + +static void down_frame(int x, int y, int w, int h, Fl_Color c) { + frame_rect(x, y, w, h - 1, "LLLLTTRR", c); +} + + +static void down_box(int x, int y, int w, int h, Fl_Color c) { + if (w > 6 && h > 6) { + shade_rect(x + 2, y + 2, w - 4, h - 5, "STUVWWWVT", c); + down_frame(x, y, w, h, c); + } + else { + narrow_thin_box(x, y, w, h, c); + } +} + + +static void down_round(int x, int y, int w, int h, Fl_Color c) { + shade_round(x, y, w, h, "STUVWWWVT", c); + frame_round(x, y, w, h, "IJLM", c); +} + + +extern void fl_internal_boxtype(Fl_Boxtype, Fl_Box_Draw_F*); + + +Fl_Boxtype fl_define_FL_PLASTIC_UP_BOX() { + fl_internal_boxtype(_FL_PLASTIC_UP_BOX, up_box); + fl_internal_boxtype(_FL_PLASTIC_DOWN_BOX, down_box); + fl_internal_boxtype(_FL_PLASTIC_UP_FRAME, up_frame); + fl_internal_boxtype(_FL_PLASTIC_DOWN_FRAME, down_frame); + fl_internal_boxtype(_FL_PLASTIC_THIN_UP_BOX, thin_up_box); + fl_internal_boxtype(_FL_PLASTIC_THIN_DOWN_BOX, down_box); + fl_internal_boxtype(_FL_PLASTIC_ROUND_UP_BOX, up_round); + fl_internal_boxtype(_FL_PLASTIC_ROUND_DOWN_BOX, down_round); + + return _FL_PLASTIC_UP_BOX; +} + + +// +// End of "$Id: fl_plastic.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_read_image.cxx b/third_party/windows/fltk-1.1.10/src/fl_read_image.cxx new file mode 100644 index 0000000..44e5545 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_read_image.cxx @@ -0,0 +1,503 @@ +// +// "$Id: fl_read_image.cxx 6475 2008-10-19 20:35:32Z matt $" +// +// X11 image reading routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include +#include "flstring.h" + +#ifdef DEBUG +# include +#endif // DEBUG + +#ifdef WIN32 +# include "fl_read_image_win32.cxx" +#elif defined(__APPLE__) +# include "fl_read_image_mac.cxx" +#else +# include +# ifdef __sgi +# include +# else +# include +# endif // __sgi + +// Defined in fl_color.cxx +extern uchar fl_redmask, fl_greenmask, fl_bluemask; +extern int fl_redshift, fl_greenshift, fl_blueshift, fl_extrashift; + +// +// 'fl_subimage_offsets()' - Calculate subimage offsets for an axis +static inline int +fl_subimage_offsets(int a, int aw, int b, int bw, int &obw) +{ + int off; + int ob; + + if (b >= a) { + ob = b; + off = 0; + } else { + ob = a; + off = a - b; + } + + bw -= off; + + if (ob + bw <= a + aw) { + obw = bw; + } else { + obw = (a + aw) - ob; + } + + return off; +} + +// this handler will catch and ignore exceptions during XGetImage +// to avoid an application crash +static int xgetimageerrhandler(Display *display, XErrorEvent *error) { + return 0; +} + +// +// 'fl_read_image()' - Read an image from the current window. +// + +uchar * // O - Pixel buffer or NULL if failed +fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate + int X, // I - Left position + int Y, // I - Top position + int w, // I - Width of area to read + int h, // I - Height of area to read + int alpha) { // I - Alpha value for image (0 for none) + XImage *image; // Captured image + int i, maxindex; // Looping vars + int x, y; // Current X & Y in image + int d; // Depth of image + unsigned char *line, // Array to hold image row + *line_ptr; // Pointer to current line image + unsigned char *pixel; // Current color value + XColor colors[4096]; // Colors from the colormap... + unsigned char cvals[4096][3]; // Color values from the colormap... + unsigned index_mask, + index_shift, + red_mask, + red_shift, + green_mask, + green_shift, + blue_mask, + blue_shift; + + + // + // Under X11 we have the option of the XGetImage() interface or SGI's + // ReadDisplay extension which does all of the really hard work for + // us... + // + +# ifdef __sgi + if (XReadDisplayQueryExtension(fl_display, &i, &i)) { + image = XReadDisplay(fl_display, fl_window, X, Y, w, h, 0, NULL); + } else +# else + image = 0; +# endif // __sgi + + if (!image) { + // fetch absolute coordinates + int dx, dy, sx, sy, sw, sh; + Window child_win; + Fl_Window *win = fl_find(fl_window); + if (win) { + XTranslateCoordinates(fl_display, fl_window, + RootWindow(fl_display, fl_screen), X, Y, &dx, &dy, &child_win); + // screen dimensions + Fl::screen_xywh(sx, sy, sw, sh, fl_screen); + } + if (!win || (dx >= sx && dy >= sy && dx + w <= sw && dy + h <= sh)) { + // the image is fully contained, we can use the traditional method + // however, if the window is obscured etc. the function will still fail. Make sure we + // catch the error and continue, otherwise an exception will be thrown. + XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler); + image = XGetImage(fl_display, fl_window, X, Y, w, h, AllPlanes, ZPixmap); + XSetErrorHandler(old_handler); + } else { + // image is crossing borders, determine visible region + int nw, nh, noffx, noffy; + noffx = fl_subimage_offsets(sx, sw, dx, w, nw); + noffy = fl_subimage_offsets(sy, sh, dy, h, nh); + if (nw <= 0 || nh <= 0) return 0; + + // allocate the image + int bpp = fl_visual->depth + ((fl_visual->depth / 8) % 2) * 8; + char* buf = (char*)malloc(bpp / 8 * w * h); + image = XCreateImage(fl_display, fl_visual->visual, + fl_visual->depth, ZPixmap, 0, buf, w, h, bpp, 0); + if (!image) { + if (buf) free(buf); + return 0; + } + + XErrorHandler old_handler = XSetErrorHandler(xgetimageerrhandler); + XImage *subimg = XGetSubImage(fl_display, fl_window, X + noffx, Y + noffy, + nw, nh, AllPlanes, ZPixmap, image, noffx, noffy); + XSetErrorHandler(old_handler); + if (!subimg) { + XDestroyImage(image); + return 0; + } + } + } + + if (!image) return 0; + +#ifdef DEBUG + printf("width = %d\n", image->width); + printf("height = %d\n", image->height); + printf("xoffset = %d\n", image->xoffset); + printf("format = %d\n", image->format); + printf("data = %p\n", image->data); + printf("byte_order = %d\n", image->byte_order); + printf("bitmap_unit = %d\n", image->bitmap_unit); + printf("bitmap_bit_order = %d\n", image->bitmap_bit_order); + printf("bitmap_pad = %d\n", image->bitmap_pad); + printf("depth = %d\n", image->depth); + printf("bytes_per_line = %d\n", image->bytes_per_line); + printf("bits_per_pixel = %d\n", image->bits_per_pixel); + printf("red_mask = %08x\n", image->red_mask); + printf("green_mask = %08x\n", image->green_mask); + printf("blue_mask = %08x\n", image->blue_mask); + printf("map_entries = %d\n", fl_visual->visual->map_entries); +#endif // DEBUG + + d = alpha ? 4 : 3; + + // Allocate the image data array as needed... + if (!p) p = new uchar[w * h * d]; + + // Initialize the default colors/alpha in the whole image... + memset(p, alpha, w * h * d); + + // Check that we have valid mask/shift values... + if (!image->red_mask && image->bits_per_pixel > 12) { + // Greater than 12 bits must be TrueColor... + image->red_mask = fl_visual->visual->red_mask; + image->green_mask = fl_visual->visual->green_mask; + image->blue_mask = fl_visual->visual->blue_mask; + +#ifdef DEBUG + puts("\n---- UPDATED ----"); + printf("fl_redmask = %08x\n", fl_redmask); + printf("fl_redshift = %d\n", fl_redshift); + printf("fl_greenmask = %08x\n", fl_greenmask); + printf("fl_greenshift = %d\n", fl_greenshift); + printf("fl_bluemask = %08x\n", fl_bluemask); + printf("fl_blueshift = %d\n", fl_blueshift); + printf("red_mask = %08x\n", image->red_mask); + printf("green_mask = %08x\n", image->green_mask); + printf("blue_mask = %08x\n", image->blue_mask); +#endif // DEBUG + } + + // Check if we have colormap image... + if (!image->red_mask) { + // Get the colormap entries for this window... + maxindex = fl_visual->visual->map_entries; + + for (i = 0; i < maxindex; i ++) colors[i].pixel = i; + + XQueryColors(fl_display, fl_colormap, colors, maxindex); + + for (i = 0; i < maxindex; i ++) { + cvals[i][0] = colors[i].red >> 8; + cvals[i][1] = colors[i].green >> 8; + cvals[i][2] = colors[i].blue >> 8; + } + + // Read the pixels and output an RGB image... + for (y = 0; y < image->height; y ++) { + pixel = (unsigned char *)(image->data + y * image->bytes_per_line); + line = p + y * w * d; + + switch (image->bits_per_pixel) { + case 1 : + for (x = image->width, line_ptr = line, index_mask = 128; + x > 0; + x --, line_ptr += d) { + if (*pixel & index_mask) { + line_ptr[0] = cvals[1][0]; + line_ptr[1] = cvals[1][1]; + line_ptr[2] = cvals[1][2]; + } else { + line_ptr[0] = cvals[0][0]; + line_ptr[1] = cvals[0][1]; + line_ptr[2] = cvals[0][2]; + } + + if (index_mask > 1) { + index_mask >>= 1; + } else { + index_mask = 128; + pixel ++; + } + } + break; + + case 2 : + for (x = image->width, line_ptr = line, index_shift = 6; + x > 0; + x --, line_ptr += d) { + i = (*pixel >> index_shift) & 3; + + line_ptr[0] = cvals[i][0]; + line_ptr[1] = cvals[i][1]; + line_ptr[2] = cvals[i][2]; + + if (index_shift > 0) { + index_mask >>= 2; + index_shift -= 2; + } else { + index_mask = 192; + index_shift = 6; + pixel ++; + } + } + break; + + case 4 : + for (x = image->width, line_ptr = line, index_shift = 4; + x > 0; + x --, line_ptr += d) { + if (index_shift == 4) i = (*pixel >> 4) & 15; + else i = *pixel & 15; + + line_ptr[0] = cvals[i][0]; + line_ptr[1] = cvals[i][1]; + line_ptr[2] = cvals[i][2]; + + if (index_shift > 0) { + index_shift = 0; + } else { + index_shift = 4; + pixel ++; + } + } + break; + + case 8 : + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel ++) { + line_ptr[0] = cvals[*pixel][0]; + line_ptr[1] = cvals[*pixel][1]; + line_ptr[2] = cvals[*pixel][2]; + } + break; + + case 12 : + for (x = image->width, line_ptr = line, index_shift = 0; + x > 0; + x --, line_ptr += d) { + if (index_shift == 0) { + i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095; + } else { + i = ((pixel[1] << 8) | pixel[2]) & 4095; + } + + line_ptr[0] = cvals[i][0]; + line_ptr[1] = cvals[i][1]; + line_ptr[2] = cvals[i][2]; + + if (index_shift == 0) { + index_shift = 4; + } else { + index_shift = 0; + pixel += 3; + } + } + break; + } + } + } else { + // RGB(A) image, so figure out the shifts & masks... + red_mask = image->red_mask; + red_shift = 0; + + while ((red_mask & 1) == 0) { + red_mask >>= 1; + red_shift ++; + } + + green_mask = image->green_mask; + green_shift = 0; + + while ((green_mask & 1) == 0) { + green_mask >>= 1; + green_shift ++; + } + + blue_mask = image->blue_mask; + blue_shift = 0; + + while ((blue_mask & 1) == 0) { + blue_mask >>= 1; + blue_shift ++; + } + + // Read the pixels and output an RGB image... + for (y = 0; y < image->height; y ++) { + pixel = (unsigned char *)(image->data + y * image->bytes_per_line); + line = p + y * w * d; + + switch (image->bits_per_pixel) { + case 8 : + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel ++) { + i = *pixel; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + break; + + case 12 : + for (x = image->width, line_ptr = line, index_shift = 0; + x > 0; + x --, line_ptr += d) { + if (index_shift == 0) { + i = ((pixel[0] << 4) | (pixel[1] >> 4)) & 4095; + } else { + i = ((pixel[1] << 8) | pixel[2]) & 4095; + } + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + + if (index_shift == 0) { + index_shift = 4; + } else { + index_shift = 0; + pixel += 3; + } + } + break; + + case 16 : + if (image->byte_order == LSBFirst) { + // Little-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 2) { + i = (pixel[1] << 8) | pixel[0]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } else { + // Big-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 2) { + i = (pixel[0] << 8) | pixel[1]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } + break; + + case 24 : + if (image->byte_order == LSBFirst) { + // Little-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 3) { + i = (((pixel[2] << 8) | pixel[1]) << 8) | pixel[0]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } else { + // Big-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 3) { + i = (((pixel[0] << 8) | pixel[1]) << 8) | pixel[2]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } + break; + + case 32 : + if (image->byte_order == LSBFirst) { + // Little-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 4) { + i = (((((pixel[3] << 8) | pixel[2]) << 8) | pixel[1]) << 8) | pixel[0]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } else { + // Big-endian... + for (x = image->width, line_ptr = line; + x > 0; + x --, line_ptr += d, pixel += 4) { + i = (((((pixel[0] << 8) | pixel[1]) << 8) | pixel[2]) << 8) | pixel[3]; + + line_ptr[0] = 255 * ((i >> red_shift) & red_mask) / red_mask; + line_ptr[1] = 255 * ((i >> green_shift) & green_mask) / green_mask; + line_ptr[2] = 255 * ((i >> blue_shift) & blue_mask) / blue_mask; + } + } + break; + } + } + } + + // Destroy the X image we've read and return the RGB(A) image... + XDestroyImage(image); + + return p; +} + +#endif + +// +// End of "$Id: fl_read_image.cxx 6475 2008-10-19 20:35:32Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_read_image_mac.cxx b/third_party/windows/fltk-1.1.10/src/fl_read_image_mac.cxx new file mode 100644 index 0000000..80f467a --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_read_image_mac.cxx @@ -0,0 +1,137 @@ +// +// "$Id: fl_read_image_mac.cxx 5614 2007-01-18 15:25:09Z matt $" +// +// WIN32 image reading routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include + +// warning: this function is only implemented in Quickdraw. The function +// below may not work If FLTK is compiled with Quartz enabled + +// +// 'fl_read_image()' - Read an image from the current window. +// + +uchar * // O - Pixel buffer or NULL if failed +fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate + int x, // I - Left position + int y, // I - Top position + int w, // I - Width of area to read + int h, // I - Height of area to read + int alpha) { // I - Alpha value for image (0 for none) + Rect src, // Source rectangle + dst; // Destination rectangle + GWorldPtr osbuffer; // Temporary off-screen buffer for copy + GrafPtr srcPort; // Source port + RGBColor rgb; // RGB colors for copy mask... + PixMapHandle pm; // Pixmap handle for off-screen buffer + uchar *base, // Base address of off-screen buffer + *psrc, // Pointer into off-screen buffer + *pdst; // Pointer into pixel buffer + int idx, idy; // Current X & Y in image + int d; // Depth of image + int rowBytes; // Number of bytes per row... + + // Set the source and destination rectangles... + src.top = y; + src.left = x; + src.bottom = y + h; + src.right = x + w; + + dst.top = 0; + dst.left = 0; + dst.bottom = h; + dst.right = w; + + // Get an off-screen buffer for copying the image... + QDErr err = NewGWorld(&osbuffer, 0, &dst, 0L, 0L, 0); + if (!osbuffer) return 0; + if (err!=noErr) { + DisposeGWorld(osbuffer); + return 0; + } + + // Get the source port... + GetPort(&srcPort); + + // Set the RGB copy mask via the foreground/background colors... + rgb.red = 0xffff; + rgb.green = 0xffff; + rgb.blue = 0xffff; + RGBBackColor(&rgb); + + rgb.red = 0x0000; + rgb.green = 0x0000; + rgb.blue = 0x0000; + RGBForeColor(&rgb); + + // Copy the screen image to the off-screen buffer... + CopyBits(GetPortBitMapForCopyBits(srcPort), + GetPortBitMapForCopyBits(osbuffer), &src, &dst, srcCopy, 0L); + + // Allocate the image data array as needed... + d = alpha ? 4 : 3; + + if (!p) p = new uchar[w * h * d]; + + // Initialize the default colors/alpha in the whole image... + memset(p, alpha, w * h * d); + + // Set the correct port for the off-screen buffer and lock the buffer + SetGWorld(osbuffer, 0); + + pm = GetGWorldPixMap(osbuffer); + LockPixels(pm); + + base = (uchar *)GetPixBaseAddr(pm); + rowBytes = (*pm)->rowBytes & 0x3fff; + + // Copy the image from the off-screen buffer to the memory buffer. + for (idy = 0, pdst = p; idy < h; idy ++) +#ifdef __i386__ + for (idx = 0, psrc = base + idy * rowBytes; idx < w; idx ++, psrc += 4, pdst += d) { + pdst[0] = psrc[2]; + pdst[1] = psrc[1]; + pdst[2] = psrc[0]; + } +#else + for (idx = 0, psrc = base + idy * rowBytes + 1; idx < w; idx ++, psrc += 4, pdst += d) { + pdst[0] = psrc[0]; + pdst[1] = psrc[1]; + pdst[2] = psrc[2]; + } +#endif // __i386__ + // Unlock and delete the off-screen buffer, then return... + UnlockPixels(pm); + DisposeGWorld(osbuffer); + + SetPort(srcPort); + return p; +} + + +// +// End of "$Id: fl_read_image_mac.cxx 5614 2007-01-18 15:25:09Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_read_image_win32.cxx b/third_party/windows/fltk-1.1.10/src/fl_read_image_win32.cxx new file mode 100644 index 0000000..cf4731c --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_read_image_win32.cxx @@ -0,0 +1,72 @@ +// +// "$Id: fl_read_image_win32.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// WIN32 image reading routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// +// 'fl_read_image()' - Read an image from the current window. +// + +uchar * // O - Pixel buffer or NULL if failed +fl_read_image(uchar *p, // I - Pixel buffer or NULL to allocate + int X, // I - Left position + int Y, // I - Top position + int w, // I - Width of area to read + int h, // I - Height of area to read + int alpha) { // I - Alpha value for image (0 for none) + int x, y; // Looping vars + int d; // Depth of image + uchar *ptr; // Pointer in image data + + + // Allocate the image data array as needed... + d = alpha ? 4 : 3; + + if (!p) p = new uchar[w * h * d]; + + // Initialize the default colors/alpha in the whole image... + memset(p, alpha, w * h * d); + + // Grab all of the pixels in the image, one at a time... + // MRS: there has to be a better way than this! + for (y = 0, ptr = p; y < h; y ++) { + for (x = 0; x < w; x ++, ptr += d) { + COLORREF c = GetPixel(fl_gc, X + x, Y + y); + + ptr[0] = (uchar)c; + c >>= 8; + ptr[1] = (uchar)c; + c >>= 8; + ptr[2] = (uchar)c; + } + } + + return p; +} + + +// +// End of "$Id: fl_read_image_win32.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_rect.cxx b/third_party/windows/fltk-1.1.10/src/fl_rect.cxx new file mode 100644 index 0000000..b4b6351 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_rect.cxx @@ -0,0 +1,685 @@ +// +// "$Id: fl_rect.cxx 5692 2007-02-12 16:41:41Z matt $" +// +// Rectangle drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// These routines from fl_draw.H are used by the standard boxtypes +// and thus are always linked into an fltk program. +// Also all fl_clip routines, since they are always linked in so +// that minimal update works. + +#include +#include +#include +#include +#include + +#ifdef __APPLE_QUARTZ__ +extern float fl_quartz_line_width_; +#endif + +void fl_rect(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; +#ifdef WIN32 + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x+w-1, y); + LineTo(fl_gc, x+w-1, y+h-1); + LineTo(fl_gc, x, y+h-1); + LineTo(fl_gc, x, y); +#elif defined(__APPLE_QD__) + Rect rect; + SetRect(&rect, x, y, x+w, y+h); + FrameRect(&rect); +#elif defined(__APPLE_QUARTZ__) + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false); + CGRect rect = CGRectMake(x, y, w-1, h-1); + CGContextStrokeRect(fl_gc, rect); + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true); +#else + XDrawRectangle(fl_display, fl_window, fl_gc, x, y, w-1, h-1); +#endif +} + +void fl_rectf(int x, int y, int w, int h) { + if (w<=0 || h<=0) return; +#ifdef WIN32 + RECT rect; + rect.left = x; rect.top = y; + rect.right = x + w; rect.bottom = y + h; + FillRect(fl_gc, &rect, fl_brush()); +#elif defined(__APPLE_QD__) + Rect rect; + SetRect(&rect, x, y, x+w, y+h); + PaintRect(&rect); +#elif defined(__APPLE_QUARTZ__) + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false); + CGRect rect = CGRectMake(x, y, w-1, h-1); + CGContextFillRect(fl_gc, rect); + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true); +#else + if (w && h) XFillRectangle(fl_display, fl_window, fl_gc, x, y, w, h); +#endif +} + +void fl_xyline(int x, int y, int x1) { +#ifdef WIN32 + MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x1+1, y); +#elif defined(__APPLE_QD__) + MoveTo(x, y); LineTo(x1, y); +#elif defined(__APPLE_QUARTZ__) + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true); +#else + XDrawLine(fl_display, fl_window, fl_gc, x, y, x1, y); +#endif +} + +void fl_xyline(int x, int y, int x1, int y2) { +#ifdef WIN32 + if (y2 < y) y2--; + else y2++; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y); + LineTo(fl_gc, x1, y2); +#elif defined(__APPLE_QD__) + MoveTo(x, y); + LineTo(x1, y); + LineTo(x1, y2); +#elif defined(__APPLE_QUARTZ__) + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextAddLineToPoint(fl_gc, x1, y2); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true); +#else + XPoint p[3]; + p[0].x = x; p[0].y = p[1].y = y; + p[1].x = p[2].x = x1; p[2].y = y2; + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +#endif +} + +void fl_xyline(int x, int y, int x1, int y2, int x3) { +#ifdef WIN32 + if(x3 < x1) x3--; + else x3++; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x1, y); + LineTo(fl_gc, x1, y2); + LineTo(fl_gc, x3, y2); +#elif defined(__APPLE_QD__) + MoveTo(x, y); + LineTo(x1, y); + LineTo(x1, y2); + LineTo(x3, y2); +#elif defined(__APPLE_QUARTZ__) + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x1, y); + CGContextAddLineToPoint(fl_gc, x1, y2); + CGContextAddLineToPoint(fl_gc, x3, y2); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true); +#else + XPoint p[4]; + p[0].x = x; p[0].y = p[1].y = y; + p[1].x = p[2].x = x1; p[2].y = p[3].y = y2; + p[3].x = x3; + XDrawLines(fl_display, fl_window, fl_gc, p, 4, 0); +#endif +} + +void fl_yxline(int x, int y, int y1) { +#ifdef WIN32 + if (y1 < y) y1--; + else y1++; + MoveToEx(fl_gc, x, y, 0L); LineTo(fl_gc, x, y1); +#elif defined(__APPLE_QD__) + MoveTo(x, y); LineTo(x, y1); +#elif defined(__APPLE_QUARTZ__) + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true); +#else + XDrawLine(fl_display, fl_window, fl_gc, x, y, x, y1); +#endif +} + +void fl_yxline(int x, int y, int y1, int x2) { +#ifdef WIN32 + if (x2 > x) x2++; + else x2--; + MoveToEx(fl_gc, x, y, 0L); + LineTo(fl_gc, x, y1); + LineTo(fl_gc, x2, y1); +#elif defined(__APPLE_QD__) + MoveTo(x, y); + LineTo(x, y1); + LineTo(x2, y1); +#elif defined(__APPLE_QUARTZ__) + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, false); + CGContextMoveToPoint(fl_gc, x, y); + CGContextAddLineToPoint(fl_gc, x, y1); + CGContextAddLineToPoint(fl_gc, x2, y1); + CGContextStrokePath(fl_gc); + if (fl_quartz_line_width_==1.0f) CGContextSetShouldAntialias(fl_gc, true); +#else + XPoint p[3]; + p[0].x = p[1].x = x; p[0].y = y; + p[1].y = p[2].y = y1; p[2].x = x2; + XDrawLines(fl_display, fl_window, fl_gc, p, 3, 0); +#endif +} + +void fl_yxline(int x, int y, int y1, int x2, int y3) { +#ifdef WIN32 + if(y3 0 && h > 0) { + r = XRectangleRegion(x,y,w,h); + Fl_Region current = rstack[rstackptr]; + if (current) { +#ifdef WIN32 + CombineRgn(r,r,current,RGN_AND); +#elif defined(__APPLE_QD__) + SectRgn(r, current, r); +#elif defined(__APPLE_QUARTZ__) + SectRgn(r, current, r); +#else + Fl_Region temp = XCreateRegion(); + XIntersectRegion(current, r, temp); + XDestroyRegion(r); + r = temp; +#endif + } + } else { // make empty clip region: +#ifdef WIN32 + r = CreateRectRgn(0,0,0,0); +#elif defined(__APPLE_QD__) + r = NewRgn(); + SetEmptyRgn(r); +#elif defined(__APPLE_QUARTZ__) + r = NewRgn(); + SetEmptyRgn(r); +#else + r = XCreateRegion(); +#endif + } + if (rstackptr < STACK_MAX) rstack[++rstackptr] = r; + else Fl::warning("fl_push_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// make there be no clip (used by fl_begin_offscreen() only!) +void fl_push_no_clip() { + if (rstackptr < STACK_MAX) rstack[++rstackptr] = 0; + else Fl::warning("fl_push_no_clip: clip stack overflow!\n"); + fl_restore_clip(); +} + +// pop back to previous clip: +void fl_pop_clip() { + if (rstackptr > 0) { + Fl_Region oldr = rstack[rstackptr--]; + if (oldr) XDestroyRegion(oldr); + } else Fl::warning("fl_pop_clip: clip stack underflow!\n"); + fl_restore_clip(); +} + +// does this rectangle intersect current clip? +int fl_not_clipped(int x, int y, int w, int h) { + if (x+w <= 0 || y+h <= 0) return 0; + Fl_Region r = rstack[rstackptr]; +#ifdef WIN32 + if (!r) return 1; + RECT rect; + rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h; + return RectInRegion(r,&rect); +#elif defined(__APPLE_QD__) + if (!r) return 1; + Rect rect; + rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h; + return RectInRgn(&rect, r); +#elif defined(__APPLE_QUARTZ__) + if (!r) return 1; + Rect rect; + rect.left = x; rect.top = y; rect.right = x+w; rect.bottom = y+h; + return RectInRgn(&rect, r); +#else + return r ? XRectInRegion(r, x, y, w, h) : 1; +#endif +} + +// return rectangle surrounding intersection of this rectangle and clip: +int fl_clip_box(int x, int y, int w, int h, int& X, int& Y, int& W, int& H){ + X = x; Y = y; W = w; H = h; + Fl_Region r = rstack[rstackptr]; + if (!r) return 0; +#ifdef WIN32 +// The win32 API makes no distinction between partial and complete +// intersection, so we have to check for partial intersection ourselves. +// However, given that the regions may be composite, we have to do +// some voodoo stuff... + Fl_Region rr = XRectangleRegion(x,y,w,h); + Fl_Region temp = CreateRectRgn(0,0,0,0); + int ret; + if (CombineRgn(temp, rr, r, RGN_AND) == NULLREGION) { // disjoint + W = H = 0; + ret = 2; + } else if (EqualRgn(temp, rr)) { // complete + ret = 0; + } else { // parital intersection + RECT rect; + GetRgnBox(temp, &rect); + X = rect.left; Y = rect.top; W = rect.right - X; H = rect.bottom - Y; + ret = 1; + } + DeleteObject(temp); + DeleteObject(rr); + return ret; +#elif defined(__APPLE_QD__) + RgnHandle rr = NewRgn(); + SetRectRgn( rr, x, y, x+w, y+h ); + SectRgn( r, rr, rr ); + Rect rp; GetRegionBounds(rr, &rp); + X = rp.left; + Y = rp.top; + W = rp.right - X; + H = rp.bottom - Y; + DisposeRgn( rr ); + if ( H==0 ) return 2; + if ( h==H && w==W ) return 0; + return 0; +#elif defined(__APPLE_QUARTZ__) + RgnHandle rr = NewRgn(); + SetRectRgn( rr, x, y, x+w, y+h ); + SectRgn( r, rr, rr ); + Rect rp; GetRegionBounds(rr, &rp); + X = rp.left; + Y = rp.top; + W = rp.right - X; + H = rp.bottom - Y; + DisposeRgn( rr ); + if ( H==0 ) return 2; + if ( h==H && w==W ) return 0; + return 0; +#else + switch (XRectInRegion(r, x, y, w, h)) { + case 0: // completely outside + W = H = 0; + return 2; + case 1: // completely inside: + return 0; + default: // partial: + break; + } + Fl_Region rr = XRectangleRegion(x,y,w,h); + Fl_Region temp = XCreateRegion(); + XIntersectRegion(r, rr, temp); + XRectangle rect; + XClipBox(temp, &rect); + X = rect.x; Y = rect.y; W = rect.width; H = rect.height; + XDestroyRegion(temp); + XDestroyRegion(rr); + return 1; +#endif +} + +// +// End of "$Id: fl_rect.cxx 5692 2007-02-12 16:41:41Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_round_box.cxx b/third_party/windows/fltk-1.1.10/src/fl_round_box.cxx new file mode 100644 index 0000000..babff30 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_round_box.cxx @@ -0,0 +1,122 @@ +// +// "$Id: fl_round_box.cxx 6537 2008-12-02 17:21:36Z matt $" +// +// Round box drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Box drawing code for an obscure box type. +// These box types are in seperate files so they are not linked +// in if not used. + +#include +#include + +// A compiler from a certain very large software company will not compile +// the function pointer assignment due to the name conflict with fl_arc. +// This function is to fix that: +void fl_arc_i(int x,int y,int w,int h,double a1,double a2) { + fl_arc(x,y,w,h,a1,a2); +} + +enum {UPPER_LEFT, LOWER_RIGHT, CLOSED, FILL}; + +static void draw(int which, int x,int y,int w,int h, int inset, unsigned int color) +{ + if (inset*2 >= w) inset = (w-1)/2; + if (inset*2 >= h) inset = (h-1)/2; + x += inset; + y += inset; + w -= 2*inset; + h -= 2*inset; + int d = w <= h ? w : h; + if (d <= 1) return; + fl_color(color); + void (*f)(int,int,int,int,double,double); + f = (which==FILL) ? fl_pie : fl_arc_i; + if (which >= CLOSED) { + f(x+w-d, y, d, d, w<=h ? 0 : -90, w<=h ? 180 : 90); + f(x, y+h-d, d, d, w<=h ? 180 : 90, w<=h ? 360 : 270); + } else if (which == UPPER_LEFT) { + f(x+w-d, y, d, d, 45, w<=h ? 180 : 90); + f(x, y+h-d, d, d, w<=h ? 180 : 90, 225); + } else { // LOWER_RIGHT + f(x, y+h-d, d, d, 225, w<=h ? 360 : 270); + f(x+w-d, y, d, d, w<=h ? 360 : 270, 360+45); + } + if (which == FILL) { + if (w < h) + fl_rectf(x, y+d/2, w, h-(d&-2)); + else if (w > h) + fl_rectf(x+d/2, y, w-(d&-2), h); + } else { + if (w < h) { + if (which != UPPER_LEFT) fl_yxline(x+w-1, y+d/2-1, y+h-d/2+1); + if (which != LOWER_RIGHT) fl_yxline(x, y+d/2-1, y+h-d/2+1); + } else if (w > h) { + if (which != UPPER_LEFT) fl_xyline(x+d/2-1, y+h-1, x+w-d/2+1); + if (which != LOWER_RIGHT) fl_xyline(x+d/2-1, y, x+w-d/2+1); + } + } +} + +extern uchar* fl_gray_ramp(); + +void fl_round_down_box(int x, int y, int w, int h, Fl_Color bgcolor) { + uchar *g = fl_gray_ramp(); + draw(FILL, x, y, w, h, 2, bgcolor); + draw(UPPER_LEFT, x+1, y, w-2, h, 0, g['N']); + draw(UPPER_LEFT, x+1, y, w-2, h, 1, g['H']); + draw(UPPER_LEFT, x, y, w, h, 0, g['N']); + draw(UPPER_LEFT, x, y, w, h, 1, g['H']); + draw(LOWER_RIGHT, x, y, w, h, 0, g['S']); + draw(LOWER_RIGHT, x+1, y, w-2, h, 0, g['U']); + draw(LOWER_RIGHT, x, y, w, h, 1, g['U']); + draw(LOWER_RIGHT, x+1, y, w-2, h, 1, g['W']); + draw(CLOSED, x, y, w, h, 2, g['A']); +} + +void fl_round_up_box(int x, int y, int w, int h, Fl_Color bgcolor) { + uchar *g = fl_gray_ramp(); + draw(FILL, x, y, w, h, 2, bgcolor); + draw(LOWER_RIGHT, x+1, y, w-2, h, 0, g['H']); + draw(LOWER_RIGHT, x+1, y, w-2, h, 1, g['N']); + draw(LOWER_RIGHT, x, y, w, h, 1, g['H']); + draw(LOWER_RIGHT, x, y, w, h, 2, g['N']); + draw(UPPER_LEFT, x, y, w, h, 2, g['U']); + draw(UPPER_LEFT, x+1, y, w-2, h, 1, g['S']); + draw(UPPER_LEFT, x, y, w, h, 1, g['W']); + draw(UPPER_LEFT, x+1, y, w-2, h, 0, g['U']); + draw(CLOSED, x, y, w, h, 0, g['A']); +} + +extern void fl_internal_boxtype(Fl_Boxtype, Fl_Box_Draw_F*); +Fl_Boxtype fl_define_FL_ROUND_UP_BOX() { + fl_internal_boxtype(_FL_ROUND_DOWN_BOX, fl_round_down_box); + fl_internal_boxtype(_FL_ROUND_UP_BOX, fl_round_up_box); + return _FL_ROUND_UP_BOX; +} + +// +// End of "$Id: fl_round_box.cxx 6537 2008-12-02 17:21:36Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_rounded_box.cxx b/third_party/windows/fltk-1.1.10/src/fl_rounded_box.cxx new file mode 100644 index 0000000..33f0d7a --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_rounded_box.cxx @@ -0,0 +1,99 @@ +// +// "$Id: fl_rounded_box.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Rounded box drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include + +#define RN 5 +#define RS 15 +#define BW 3 + +static double offset[RN] = { 0.0, 0.07612, 0.29289, 0.61732, 1.0}; + +static void rbox(int fill, int x, int y, int w, int h) { + int i; + int rsx ,rsy, rs; + rsx = w*2/5; rsy = h*2/5; + if (rsx > rsy) rs = rsy; else rs = rsx; + if (rs > RS) rs = RS; + rsx = rs; rsy = rs; + + if (fill) fl_begin_polygon(); else fl_begin_loop(); + for (i=0; i +#include +#include +#include + +// scroll a rectangle and redraw the newly exposed portions: +void fl_scroll(int X, int Y, int W, int H, int dx, int dy, + void (*draw_area)(void*, int,int,int,int), void* data) +{ + if (!dx && !dy) return; + if (dx <= -W || dx >= W || dy <= -H || dy >= H) { + // no intersection of old an new scroll + draw_area(data,X,Y,W,H); + return; + } + int src_x, src_w, dest_x, clip_x, clip_w; + if (dx > 0) { + src_x = X; + dest_x = X+dx; + src_w = W-dx; + clip_x = X; + clip_w = dx; + } else { + src_x = X-dx; + dest_x = X; + src_w = W+dx; + clip_x = X+src_w; + clip_w = W-src_w; + } + int src_y, src_h, dest_y, clip_y, clip_h; + if (dy > 0) { + src_y = Y; + dest_y = Y+dy; + src_h = H-dy; + clip_y = Y; + clip_h = dy; + } else { + src_y = Y-dy; + dest_y = Y; + src_h = H+dy; + clip_y = Y+src_h; + clip_h = H-src_h; + } +#ifdef WIN32 + typedef int (WINAPI* fl_GetRandomRgn_func)(HDC, HRGN, INT); + static fl_GetRandomRgn_func fl_GetRandomRgn = 0L; + static char first_time = 1; + + // We will have to do some Region magic now, so let's see if the + // required function is available (and it should be staring w/Win95) + if (first_time) { + HMODULE hMod = GetModuleHandle("GDI32.DLL"); + if (hMod) { + fl_GetRandomRgn = (fl_GetRandomRgn_func)GetProcAddress(hMod, "GetRandomRgn"); + } + first_time = 0; + } + + // Now check if the source scrolling area is fully visible. + // If it is, we will do a quick scroll and just update the + // newly exposed area. If it is not, we go the safe route and + // re-render the full area instead. + // Note 1: we could go and find the areas that are actually + // obscured and recursively call fl_scroll for the newly found + // rectangles. However, this practice would rely on the + // elements of the undocumented Rgn structure. + // Note 2: although this method should take care of most + // multi-screen solutions, it will not solve issues scrolling + // from a different resolution screen onto another. + // Note 3: this has been tested with image maps, too. + if (fl_GetRandomRgn) { + // get the DC region minus all overlapping windows + HRGN sys_rgn = CreateRectRgn(0, 0, 0, 0); + fl_GetRandomRgn(fl_gc, sys_rgn, 4); + // now get the source scrolling rectangle + HRGN src_rgn = CreateRectRgn(src_x, src_y, src_x+src_w, src_y+src_h); + POINT offset = { 0, 0 }; + if (GetDCOrgEx(fl_gc, &offset)) { + OffsetRgn(src_rgn, offset.x, offset.y); + } + // see if all source pixels are available in the system region + // Note: we could be a bit more merciful and subtract the + // scroll destination region as well. + HRGN dst_rgn = CreateRectRgn(0, 0, 0, 0); + int r = CombineRgn(dst_rgn, src_rgn, sys_rgn, RGN_DIFF); + DeleteObject(dst_rgn); + DeleteObject(src_rgn); + DeleteObject(sys_rgn); + if (r!=NULLREGION) { + draw_area(data,X,Y,W,H); + return; + } + } + + // Great, we can do an accelerated scroll insteasd of re-rendering + BitBlt(fl_gc, dest_x, dest_y, src_w, src_h, fl_gc, src_x, src_y,SRCCOPY); + +#elif defined(__APPLE_QD__) + Rect src = { src_y, src_x, src_y+src_h, src_x+src_w }; + Rect dst = { dest_y, dest_x, dest_y+src_h, dest_x+src_w }; + static RGBColor bg = { 0xffff, 0xffff, 0xffff }; RGBBackColor( &bg ); + static RGBColor fg = { 0x0000, 0x0000, 0x0000 }; RGBForeColor( &fg ); + CopyBits( GetPortBitMapForCopyBits( GetWindowPort(fl_window) ), + GetPortBitMapForCopyBits( GetWindowPort(fl_window) ), &src, &dst, srcCopy, 0L); +#elif defined(__APPLE_QUARTZ__) + // warning: there does not seem to be an equivalent to this function in Quartz + // ScrollWindowRect is a QuickDraw function and won't work here. + // Since on OS X all windows are fully double buffered, we need not + // worry about offscreen or obscured areas + Rect src = { src_y, src_x, src_y+src_h, src_x+src_w }; + Rect dst = { dest_y, dest_x, dest_y+src_h, dest_x+src_w }; + static RGBColor bg = { 0xffff, 0xffff, 0xffff }; RGBBackColor( &bg ); + static RGBColor fg = { 0x0000, 0x0000, 0x0000 }; RGBForeColor( &fg ); + CopyBits( GetPortBitMapForCopyBits( GetWindowPort(fl_window) ), + GetPortBitMapForCopyBits( GetWindowPort(fl_window) ), &src, &dst, srcCopy, 0L); +#else + XCopyArea(fl_display, fl_window, fl_window, fl_gc, + src_x, src_y, src_w, src_h, dest_x, dest_y); + // we have to sync the display and get the GraphicsExpose events! (sigh) + for (;;) { + XEvent e; XWindowEvent(fl_display, fl_window, ExposureMask, &e); + if (e.type == NoExpose) break; + // otherwise assumme it is a GraphicsExpose event: + draw_area(data, e.xexpose.x, e.xexpose.y, + e.xexpose.width, e.xexpose.height); + if (!e.xgraphicsexpose.count) break; + } +#endif + if (dx) draw_area(data, clip_x, dest_y, clip_w, src_h); + if (dy) draw_area(data, X, clip_y, W, clip_h); +} + +// +// End of "$Id: fl_scroll_area.cxx 5714 2007-02-25 00:00:49Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_set_font.cxx b/third_party/windows/fltk-1.1.10/src/fl_set_font.cxx new file mode 100644 index 0000000..c4f6d8b --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_set_font.cxx @@ -0,0 +1,90 @@ +// +// "$Id: fl_set_font.cxx 5420 2006-09-05 11:16:15Z matt $" +// +// Font utilities for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Add a font to the internal table. +// Also see fl_set_fonts.cxx which adds all possible fonts. + +#include +#include +#include +#include "flstring.h" +#include "Fl_Font.H" +#include + +static int table_size; + +void Fl::set_font(Fl_Font fnum, const char* name) { + while (fnum >= table_size) { + int i = table_size; + if (!i) { // don't realloc the built-in table + table_size = 2*FL_FREE_FONT; + i = FL_FREE_FONT; + Fl_Fontdesc* t = (Fl_Fontdesc*)malloc(table_size*sizeof(Fl_Fontdesc)); + memcpy(t, fl_fonts, FL_FREE_FONT*sizeof(Fl_Fontdesc)); + fl_fonts = t; + } else { + table_size = 2*table_size; + fl_fonts=(Fl_Fontdesc*)realloc(fl_fonts, table_size*sizeof(Fl_Fontdesc)); + } + for (; i < table_size; i++) { + fl_fonts[i].fontname[0] = 0; + fl_fonts[i].name = 0; +#if !defined(WIN32) && !defined(__APPLE__) + fl_fonts[i].xlist = 0; + fl_fonts[i].n = 0; +#endif // !WIN32 && !__APPLE__ + } + } + Fl_Fontdesc* s = fl_fonts+fnum; + if (s->name) { + if (!strcmp(s->name, name)) {s->name = name; return;} +#if !defined(WIN32) && !defined(__APPLE__) + if (s->xlist && s->n >= 0) XFreeFontNames(s->xlist); +#endif + for (Fl_FontSize* f = s->first; f;) { + Fl_FontSize* n = f->next; delete f; f = n; + } + s->first = 0; + } + s->name = name; + s->fontname[0] = 0; +#if !defined(WIN32) && !defined(__APPLE__) + s->xlist = 0; +#endif + s->first = 0; + fl_font(-1, 0); +} + +void Fl::set_font(Fl_Font fnum, Fl_Font from) { + Fl::set_font(fnum, get_font(from)); +} + +const char* Fl::get_font(Fl_Font fnum) {return fl_fonts[fnum].name;} + +// +// End of "$Id: fl_set_font.cxx 5420 2006-09-05 11:16:15Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_set_fonts.cxx b/third_party/windows/fltk-1.1.10/src/fl_set_fonts.cxx new file mode 100644 index 0000000..faafec4 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_set_fonts.cxx @@ -0,0 +1,46 @@ +// +// "$Id: fl_set_fonts.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// More font utilities for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include +#include "Fl_Font.H" +#include "flstring.h" +#include + +#ifdef WIN32 +# include "fl_set_fonts_win32.cxx" +#elif defined(__APPLE__) +# include "fl_set_fonts_mac.cxx" +#elif USE_XFT +# include "fl_set_fonts_xft.cxx" +#else +# include "fl_set_fonts_x.cxx" +#endif // WIN32 + +// +// End of "$Id: fl_set_fonts.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_set_fonts_mac.cxx b/third_party/windows/fltk-1.1.10/src/fl_set_fonts_mac.cxx new file mode 100644 index 0000000..b4c0246 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_set_fonts_mac.cxx @@ -0,0 +1,213 @@ +// +// "$Id: fl_set_fonts_mac.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// MacOS font utilities for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include + +// This function fills in the fltk font table with all the fonts that +// are found on the X server. It tries to place the fonts into families +// and to sort them so the first 4 in a family are normal, bold, italic, +// and bold italic. + +// Bug: older versions calculated the value for *ap as a side effect of +// making the name, and then forgot about it. To avoid having to change +// the header files I decided to store this value in the last character +// of the font name array. +#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1 + +// turn a stored font name into a pretty name: +const char* Fl::get_font_name(Fl_Font fnum, int* ap) { +#ifdef __APPLE_QD__ + Fl_Fontdesc *f = fl_fonts + fnum; + if (!f->fontname[0]) { + const char* p = f->name; + if (!p || !*p) {if (ap) *ap = 0; return "";} + int type; + switch (*p) { + case 'B': type = FL_BOLD; break; + case 'I': type = FL_ITALIC; break; + case 'P': type = FL_BOLD | FL_ITALIC; break; + default: type = 0; break; + } + strlcpy(f->fontname, p+1, ENDOFBUFFER); + if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER); + if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER); + f->fontname[ENDOFBUFFER] = (char)type; + } + if (ap) *ap = f->fontname[ENDOFBUFFER]; + return f->fontname; +#elif defined(__APPLE_QUARTZ__) + Fl_Fontdesc *f = fl_fonts + fnum; + if (!f->fontname[0]) { + const char* p = f->name; + if (!p || !*p) {if (ap) *ap = 0; return "";} + strlcpy(f->fontname, p, ENDOFBUFFER); + int type = 0; + if (strstr(f->name, "Bold")) type |= FL_BOLD; + if (strstr(f->name, "Italic")) type |= FL_ITALIC; + f->fontname[ENDOFBUFFER] = (char)type; + } + if (ap) *ap = f->fontname[ENDOFBUFFER]; + return f->fontname; +#endif +} + +static int fl_free_font = FL_FREE_FONT; + +Fl_Font Fl::set_fonts(const char* xstarname) { +#pragma unused ( xstarname ) +#ifdef __APPLE_QD__ + if (fl_free_font != FL_FREE_FONT) + return (Fl_Font)fl_free_font; + static char styleLU[] = " BIP"; + FMFontFamilyInstanceIterator ffiIterator; + FMFontFamilyIterator ffIterator; + FMFontFamily family; + FMFont font; + FMFontStyle style; // bits 0..6: bold, italic underline, outline, shadow, condens, extended (FLTK supports 0 and 1 ) + FMFontSize size; + //FMFilter filter; // do we need to set a specific (or multiple) filter(s) to get ALL fonts? + + Str255 buf; + //filter.format = kFMCurrentFilterFormat; + //filter.selector = kFMGenerationFilterSelector; + //filter.filter.generationFilter = + FMCreateFontFamilyIterator( NULL, NULL, kFMUseGlobalScopeOption, &ffIterator ); + OSStatus listFamilies, listInstances; + for (;;) + { + listFamilies = FMGetNextFontFamily( &ffIterator, &family ); + if ( listFamilies != 0 ) break; + FMGetFontFamilyName( family, buf ); + buf[ buf[0]+1 ] = 0; + //printf( "Font Family: %s\n", buf+1 ); + int i; + for (i=0; iname) s = fl_fonts; // empty slot in table, use entry 0 + int cnt = 0; + +#ifdef __APPLE_QD__ + Str255 name; + int len = strlen( s->name ); + memcpy(((char*)name)+1, s->name+1, len ); + name[0] = len-1; + FMFontFamily family = FMGetFontFamilyFromName( name ); + if ( family == kInvalidFontFamily ) return 0; + + sizep = array; + FMFont font; + FMFontStyle style, fStyle; + switch ( s->name[0] ) { + default : + fStyle=0; + break; + case 'B' : + fStyle=1; + break; + case 'I' : + fStyle=2; + break; + case 'P' : + fStyle=3; + break; + } + FMFontSize size, pSize = -1; + FMFontFamilyInstanceIterator ffiIterator; + FMCreateFontFamilyInstanceIterator( family, &ffiIterator ); + OSStatus listInstances; + for (;;) + { + listInstances = FMGetNextFontFamilyInstance( &ffiIterator, &font, &style, &size ); + if ( listInstances != 0 ) break; + if ( style==fStyle ) + { + if ( size>pSize ) + { + array[ cnt++ ] = size; + pSize = size; + } + } + } + FMDisposeFontFamilyInstanceIterator( &ffiIterator ); +#elif defined(__APPLE_QUARTZ__) + // ATS supports all font size + array[0] = 0; + sizep = array; + cnt = 1; +#endif + + return cnt; +} + +// +// End of "$Id: fl_set_fonts_mac.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_set_fonts_win32.cxx b/third_party/windows/fltk-1.1.10/src/fl_set_fonts_win32.cxx new file mode 100644 index 0000000..923f563 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_set_fonts_win32.cxx @@ -0,0 +1,149 @@ +// +// "$Id: fl_set_fonts_win32.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// WIN32 font utilities for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this7 library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This function fills in the FLTK font table with all the fonts that +// are found on the X server. It tries to place the fonts into families +// and to sort them so the first 4 in a family are normal, bold, italic, +// and bold italic. + +// Bug: older versions calculated the value for *ap as a side effect of +// making the name, and then forgot about it. To avoid having to change +// the header files I decided to store this value in the last character +// of the font name array. +#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1 + +// turn a stored font name into a pretty name: +const char* Fl::get_font_name(Fl_Font fnum, int* ap) { + Fl_Fontdesc *f = fl_fonts + fnum; + if (!f->fontname[0]) { + const char* p = f->name; + if (!p || !*p) {if (ap) *ap = 0; return "";} + int type; + switch (*p) { + case 'B': type = FL_BOLD; break; + case 'I': type = FL_ITALIC; break; + case 'P': type = FL_BOLD | FL_ITALIC; break; + default: type = 0; break; + } + strlcpy(f->fontname, p+1, ENDOFBUFFER); + if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER); + if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER); + f->fontname[ENDOFBUFFER] = (char)type; + } + if (ap) *ap = f->fontname[ENDOFBUFFER]; + return f->fontname; +} + +static int fl_free_font = FL_FREE_FONT; + +static int CALLBACK +enumcb(CONST LOGFONT *lpelf, + CONST TEXTMETRIC * /*lpntm*/, + DWORD /*FontType*/, + LPARAM p) { + if (!p && lpelf->lfCharSet != ANSI_CHARSET) return 1; + const char *n = lpelf->lfFaceName; + for (int i=0; ilfWeight <= 400) + buffer[0] = 'B', Fl::set_font((Fl_Font)(fl_free_font++), strdup(buffer)); + buffer[0] = 'I'; Fl::set_font((Fl_Font)(fl_free_font++), strdup(buffer)); + if (lpelf->lfWeight <= 400) + buffer[0] = 'P', Fl::set_font((Fl_Font)(fl_free_font++), strdup(buffer)); + return 1; +} + +Fl_Font Fl::set_fonts(const char* xstarname) { + if (fl_free_font == FL_FREE_FONT) {// if not already been called + if (!fl_gc) fl_GetDC(0); + EnumFontFamilies(fl_gc, NULL, (FONTENUMPROC)enumcb, xstarname != 0); + } + return (Fl_Font)fl_free_font; +} + + +static int nbSize; +static int cyPerInch; +static int sizes[128]; + +static int CALLBACK +EnumSizeCb(CONST LOGFONT * /*lpelf*/, + CONST TEXTMETRIC *lpntm, + DWORD fontType, + LPARAM /*p*/) { + if ((fontType & RASTER_FONTTYPE) == 0) { + sizes[0] = 0; + nbSize = 1; + + // Scalable font + return 0; + } + + int add = lpntm->tmHeight - lpntm->tmInternalLeading; + add = MulDiv(add, 72, cyPerInch); + + int start = 0; + while ((start < nbSize) && (sizes[start] < add)) { + start++; + } + + if ((start < nbSize) && (sizes[start] == add)) { + return 1; + } + + for (int i=nbSize; i>start; i--) sizes[i] = sizes[i - 1]; + + sizes[start] = add; + nbSize++; + + // Stop enum if buffer overflow + return nbSize < 128; +} + + +int +Fl::get_font_sizes(Fl_Font fnum, int*& sizep) { + nbSize = 0; + Fl_Fontdesc *s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 + + if (!fl_gc) fl_GetDC(0); + cyPerInch = GetDeviceCaps(fl_gc, LOGPIXELSY); + if (cyPerInch < 1) cyPerInch = 1; + EnumFontFamilies(fl_gc, s->name+1, (FONTENUMPROC)EnumSizeCb, 0); + + sizep = sizes; + return nbSize; +} + + +// +// End of "$Id: fl_set_fonts_win32.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_set_fonts_x.cxx b/third_party/windows/fltk-1.1.10/src/fl_set_fonts_x.cxx new file mode 100644 index 0000000..ca8709a --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_set_fonts_x.cxx @@ -0,0 +1,350 @@ +// +// "$Id: fl_set_fonts_x.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// X11 font utilities for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// This function fills in the fltk font table with all the fonts that +// are found on the X server. It tries to place the fonts into families +// and to sort them so the first 4 in a family are normal, bold, italic, +// and bold italic. + +// Standard X fonts are matched by a pattern that is always of +// this form, and this pattern is put in the table: +// "-*-family-weight-slant-width1-style-*-registry-encoding" + +// Non-standard font names (those not starting with '-') are matched +// by a pattern of the form "prefix*suffix", where the '*' is where +// fltk thinks the point size is, or by the actual font name if no +// point size is found. + +// Fltk knows how to pull an "attribute" out of a font name, such as +// bold or italic, by matching known x font field values. All words +// that don't match a known attribute are combined into the "name" +// of the font. Names are compared before attributes for sorting, this +// makes the bold and plain version of a font come out next to each +// other despite the poor X font naming scheme. + +// By default fl_set_fonts() only does iso8859-1 encoded fonts. You can +// do all normal X fonts by passing "-*" or every possible font with "*". + +// Fl::set_font will take strings other than the ones this stores +// and can identify any font on X that way. You may want to write your +// own system of font management and not use this code. + +// turn word N of a X font name into either some attribute bits +// (right now 0, FL_BOLD, or FL_ITALIC), or into -1 indicating that +// the word should be put into the name: + +static int attribute(int n, const char *p) { + // don't put blank things into name: + if (!*p || *p=='-' || *p=='*') return 0; + if (n == 3) { // weight + if (!strncmp(p,"normal",6) || + !strncmp(p,"light",5) || + !strncmp(p,"medium",6) || + !strncmp(p,"book",4)) return 0; + if (!strncmp(p,"bold",4) || !strncmp(p,"demi",4)) return FL_BOLD; + } else if (n == 4) { // slant + if (*p == 'r') return 0; + if (*p == 'i' || *p == 'o') return FL_ITALIC; + } else if (n == 5) { // sWidth + if (!strncmp(p,"normal",6)) return 0; + } + return -1; +} + +// return non-zero if the registry-encoding should be used: +extern const char* fl_encoding; +static int use_registry(const char *p) { + return *p && *p!='*' && strcmp(p,fl_encoding); +} + +// Bug: older versions calculated the value for *ap as a side effect of +// making the name, and then forgot about it. To avoid having to change +// the header files I decided to store this value in the last character +// of the font name array. +#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1 + +// turn a stored (with *'s) X font name into a pretty name: +const char* Fl::get_font_name(Fl_Font fnum, int* ap) { + Fl_Fontdesc *f = fl_fonts + fnum; + if (!f->fontname[0]) { + int type = 0; + const char* p = f->name; + if (!p) { + if (ap) *ap = 0; + return ""; + } + char *o = f->fontname; + + if (*p != '-') { // non-standard font, just replace * with spaces: + if (strstr(p,"bold")) type = FL_BOLD; + if (strstr(p,"ital")) type |= FL_ITALIC; + for (;*p; p++) { + if (*p == '*' || *p == ' ' || *p == '-') { + do p++; while (*p == '*' || *p == ' ' || *p == '-'); + if (!*p) break; + if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' '; + } + if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = *p; + } + *o = 0; + + } else { // standard dash-seperated font: + + // get the family: + const char *x = fl_font_word(p,2); if (*x) x++; if (*x=='*') x++; + if (!*x) { + if (ap) *ap = 0; + return p; + } + const char *e = fl_font_word(x,1); + if ((e - x) < (int)(ENDOFBUFFER - 1)) { + // MRS: we want strncpy here, not strlcpy... + strncpy(o,x,e-x); + o += e-x; + } else { + strlcpy(f->fontname, x, ENDOFBUFFER); + o = f->fontname+ENDOFBUFFER-1; + } + + // collect all the attribute words: + for (int n = 3; n <= 6; n++) { + // get the next word: + if (*e) e++; x = e; e = fl_font_word(x,1); + int t = attribute(n,x); + if (t < 0) { + if (o < (f->fontname + ENDOFBUFFER - 1)) *o++ = ' '; + if ((e - x) < (int)(ENDOFBUFFER - (o - f->fontname) - 1)) { + // MRS: we want strncpy here, not strlcpy... + strncpy(o,x,e-x); + o += e-x; + } else { + strlcpy(o,x, ENDOFBUFFER - (o - f->fontname) - 1); + o = f->fontname+ENDOFBUFFER-1; + } + } else type |= t; + } + + // skip over the '*' for the size and get the registry-encoding: + x = fl_font_word(e,2); + if (*x) {x++; *o++ = '('; while (*x) *o++ = *x++; *o++ = ')';} + + *o = 0; + if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER); + if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER); + } + f->fontname[ENDOFBUFFER] = (char)type; + } + if (ap) *ap = f->fontname[ENDOFBUFFER]; + return f->fontname; +} + +extern "C" { +// sort raw (non-'*') X font names into perfect order: + +static int ultrasort(const void *aa, const void *bb) { + const char *a = *(char **)aa; + const char *b = *(char **)bb; + + // sort all non x-fonts at the end: + if (*a != '-') { + if (*b == '-') return 1; + // 2 non-x fonts are matched by "numeric sort" + int ret = 0; + for (;;) { + if (isdigit(*a) && isdigit(*b)) { + int na = strtol(a, (char **)&a, 10); + int nb = strtol(b, (char **)&b, 10); + if (!ret) ret = na-nb; + } else if (*a != *b) { + return (*a-*b); + } else if (!*a) { + return ret; + } else { + a++; b++; + } + } + } else { + if (*b != '-') return -1; + } + + // skip the foundry (assumme equal): + for (a++; *a && *a++!='-';); + for (b++; *b && *b++!='-';); + + // compare the family and all the attribute words: + int atype = 0; + int btype = 0; + for (int n = 2; n <= 6; n++) { + int at = attribute(n,a); + int bt = attribute(n,b); + if (at < 0) { + if (bt >= 0) return 1; + for (;;) {if (*a!=*b) return *a-*b; b++; if (!*a || *a++=='-') break;} + } else { + if (bt < 0) return -1; + a = fl_font_word(a,1); if (*a) a++; + b = fl_font_word(b,1); if (*b) b++; + atype |= at; btype |= bt; + } + } + + // remember the pixel size: + int asize = atoi(a); + int bsize = atoi(b); + + // compare the registry/encoding: + a = fl_font_word(a,6); if (*a) a++; + b = fl_font_word(b,6); if (*b) b++; + if (use_registry(a)) { + if (!use_registry(b)) return 1; + int r = strcmp(a,b); if (r) return r; + } else { + if (use_registry(b)) return -1; + } + + if (atype != btype) return atype-btype; + if (asize != bsize) return asize-bsize; + + // something wrong, just do a string compare... + return strcmp(*(char**)aa, *(char**)bb); +} +} + +// converts a X font name to a standard starname, returns point size: +static int to_canonical(char *to, const char *from, size_t tolen) { + char* c = fl_find_fontsize((char*)from); + if (!c) return -1; // no point size found... + const char* endptr; + int size = strtol(c,(char**)&endptr,10); + if (from[0] == '-') { + // replace the "foundry" with -*-: + *to++ = '-'; *to++ = '*'; + for (from++; *from && *from != '-'; from++); + // skip to the registry-encoding: + endptr = (char*)fl_font_word(endptr,6); + if (*endptr && !use_registry(endptr+1)) endptr = ""; + } + int n = c-from; + // MRS: we want strncpy here, not strlcpy... + if (n > (int)(tolen - 1)) return -1; + strncpy(to,from,n); + to[n++] = '*'; + strlcpy(to+n,endptr, tolen - n); + return size; +} + +static int fl_free_font = FL_FREE_FONT; + +Fl_Font Fl::set_fonts(const char* xstarname) { + if (fl_free_font > FL_FREE_FONT) // already been here + return (Fl_Font)fl_free_font; + fl_open_display(); + int xlistsize; + char buf[20]; + if (!xstarname) { + strcpy(buf,"-*-"); strcpy(buf+3,fl_encoding); + xstarname = buf; + } + char **xlist = XListFonts(fl_display, xstarname, 10000, &xlistsize); + if (!xlist) return (Fl_Font)fl_free_font; + qsort(xlist, xlistsize, sizeof(*xlist), ultrasort); + int used_xlist = 0; + for (int i=0; i= 0) { + for (;;) { // find all matching fonts: + if (i >= xlistsize) break; + const char *q = xlist[i]; + char this_canon[1024]; + if (to_canonical(this_canon, q, sizeof(this_canon)) < 0) break; + if (strcmp(canon, this_canon)) break; + i++; + } + /*if (*p=='-' || i > first_xlist+1)*/ p = canon; + } + int j; + for (j = 0;; j++) { + if (j < FL_FREE_FONT) { + // see if it is one of our built-in fonts: + // if so, set the list of x fonts, since we have it anyway + if (fl_fonts[j].name && !strcmp(fl_fonts[j].name, p)) break; + } else { + j = fl_free_font++; + if (p == canon) p = strdup(p); else used_xlist = 1; + Fl::set_font((Fl_Font)j, p); + break; + } + } + if (!fl_fonts[j].xlist) { + fl_fonts[j].xlist = xlist+first_xlist; + fl_fonts[j].n = -(i-first_xlist); + used_xlist = 1; + } + } + if (!used_xlist) XFreeFontNames(xlist); + return (Fl_Font)fl_free_font; +} + +int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) { + Fl_Fontdesc *s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 + if (!s->xlist) { + fl_open_display(); + s->xlist = XListFonts(fl_display, s->name, 100, &(s->n)); + if (!s->xlist) return 0; + } + int listsize = s->n; if (listsize<0) listsize = -listsize; + static int sizes[128]; + int numsizes = 0; + for (int i = 0; i < listsize; i++) { + char *q = s->xlist[i]; + char *d = fl_find_fontsize(q); + if (!d) continue; + int s = strtol(d,0,10); + if (!numsizes || sizes[numsizes-1] < s) { + sizes[numsizes++] = s; + } else { + // insert-sort the new size into list: + int n; + for (n = numsizes-1; n > 0; n--) if (sizes[n-1] < s) break; + if (sizes[n] != s) { + for (int m = numsizes; m > n; m--) sizes[m] = sizes[m-1]; + sizes[n] = s; + numsizes++; + } + } + } + sizep = sizes; + return numsizes; +} + +// +// End of "$Id: fl_set_fonts_x.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_set_fonts_xft.cxx b/third_party/windows/fltk-1.1.10/src/fl_set_fonts_xft.cxx new file mode 100644 index 0000000..5192fda --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_set_fonts_xft.cxx @@ -0,0 +1,366 @@ +// +// "$Id: fl_set_fonts_xft.cxx 6832 2009-07-23 22:36:04Z AlbrechtS $" +// +// More font utilities for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2006 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include + +// This function fills in the fltk font table with all the fonts that +// are found on the X server. It tries to place the fonts into families +// and to sort them so the first 4 in a family are normal, bold, italic, +// and bold italic. + +// Bug: older versions calculated the value for *ap as a side effect of +// making the name, and then forgot about it. To avoid having to change +// the header files I decided to store this value in the last character +// of the font name array. +#define ENDOFBUFFER 127 // sizeof(Fl_Font.fontname)-1 + +// turn a stored font name into a pretty name: +const char* Fl::get_font_name(Fl_Font fnum, int* ap) { + Fl_Fontdesc *f = fl_fonts + fnum; + if (!f->fontname[0]) { + const char* p = f->name; + int type; + switch (p[0]) { + case 'B': type = FL_BOLD; break; + case 'I': type = FL_ITALIC; break; + case 'P': type = FL_BOLD | FL_ITALIC; break; + default: type = 0; break; + } + + // NOTE: This can cause duplications in fonts that already have Bold or Italic in + // their "name". Maybe we need to find a cleverer way? + strlcpy(f->fontname, p+1, ENDOFBUFFER); + if (type & FL_BOLD) strlcat(f->fontname, " bold", ENDOFBUFFER); + if (type & FL_ITALIC) strlcat(f->fontname, " italic", ENDOFBUFFER); + f->fontname[ENDOFBUFFER] = (char)type; + } + if (ap) *ap = f->fontname[ENDOFBUFFER]; + return f->fontname; +} + +/////////////////////////////////////////////////////////// +#define LOCAL_RAW_NAME_MAX 256 + +extern "C" { +// sort returned fontconfig font names +static int name_sort(const void *aa, const void *bb) { + // What should we do here? Just do a string compare for now... + // NOTE: This yeilds some oddities - in particular a Blah Bold font will be + // listed before Blah... + // Also - the fontconfig listing returns some faces that are effectively duplicates + // as far as fltk is concerned, e.g. where there are ko or ja variants that we + // can't distinguish (since we are not yet fully UTF-*) - should we strip them here? + return strcasecmp(*(char**)aa, *(char**)bb); +} // end of name_sort +} // end of extern C section + + +// Read the "pretty" name we have derived from fontconfig then convert +// it into the format fltk uses internally for Xft names... +// This is just a mess - I should have tokenised the strings and gone from there, +// but I really thought this would be easier! +static void make_raw_name(char *raw, char *pretty) +{ + // Input name will be "Some Name:style = Bold Italic" or whatever + // The plan is this: + // - the first char in the "raw" name becomes either I, B, P or " " for + // italic, bold, bold italic or normal - this seems to be the fltk way... + + char *style = strchr(pretty, ':'); + char *last = style + strlen(style) - 2; + + if (style) + { + *style = 0; // Terminate "name" string + style ++; // point to start of style section + } + raw[0] = ' '; raw[1] = 0; // Default start of "raw name" text + strncat(raw, pretty, LOCAL_RAW_NAME_MAX); + // At this point, the name is "marked" as regular... + if (style) + { +#define PLAIN 0 +#define BOLD 1 +#define ITALIC 2 +#define BITALIC (BOLD | ITALIC) + int mods = PLAIN; + // Now try and parse the style string - look for the "=" sign + style = strchr(style, '='); + while ((style) && (style < last)) + { + int type; + while ((*style == '=') || (*style == ' ') || (*style == '\t')) + { + style++; // Start of Style string + if ((style >= last) || (*style == 0)) continue; + } + type = toupper(style[0]); + switch (type) + { + // Things we might see: Regular Normal Bold Italic Oblique (??what??) Medium + // Roman Light Demi Sans SemiCondensed SuperBold Book... etc... + // Things we actually care about: Bold Italic Oblique SuperBold - Others??? + case 'I': + if (strncasecmp(style, "Italic", 6) == 0) + { + mods |= ITALIC; + } + goto NEXT_STYLE; + + case 'B': + if (strncasecmp(style, "Bold", 4) == 0) + { + mods |= BOLD; + } + goto NEXT_STYLE; + + case 'O': + if (strncasecmp(style, "Oblique", 7) == 0) + { + mods |= ITALIC; + } + goto NEXT_STYLE; + + case 's': + if (strncasecmp(style, "SuperBold", 9) == 0) + { + mods |= BOLD; + } + goto NEXT_STYLE; + + default: // find the next gap + goto NEXT_STYLE; + } // switch end +NEXT_STYLE: + while ((*style != ' ') && (*style != '\t')) + { + style++; + if ((style >= last) || (*style == 0)) goto STYLE_DONE; + } + } +STYLE_DONE: + // Set the "modifier" character in the raw string + switch(mods) + { + case BOLD: raw[0] = 'B'; + break; + case ITALIC: raw[0] = 'I'; + break; + case BITALIC: raw[0] = 'P'; + break; + default: raw[0] = ' '; + break; + } + } +} // make_raw_name + +/////////////////////////////////////////////////////////// + +static int fl_free_font = FL_FREE_FONT; + +// Uses the fontconfig lib to construct a list of all installed fonts. +// I tried using XftListFonts for this, but the API is tricky - and when +// I looked at the XftList* code, it calls the Fc* functions anyway, so... +// +// Also, for now I'm ignoring the "pattern_name" and just getting everything... +// AND I don't try and skip the fonts we've already loaded in the defaults. +// Blimey! What a hack! +Fl_Font Fl::set_fonts(const char* pattern_name) +{ + FcFontSet *fnt_set; // Will hold the list of fonts we find + FcPattern *fnt_pattern; // Holds the generic "match all names" pattern + FcObjectSet *fnt_obj_set = 0; // Holds the generic "match all objects" + + int j; // loop iterator variable + int font_count; // Total number of fonts found to process + char **full_list; // The list of font names we build + + if (fl_free_font > FL_FREE_FONT) // already been here + return (Fl_Font)fl_free_font; + + fl_open_display(); // Just in case... + + // Make sure fontconfig is ready... is this necessary? The docs say it is + // safe to call it multiple times, so just go for it anyway! + if (!FcInit()) + { + // What to do? Just return defaults... + return FL_FREE_FONT; + } + + // Create a search pattern that will match every font name - I think this + // does the Right Thing, but am not certain... + // + // This could possibly be "enhanced" to pay attention to the requested + // "pattern_name"? + fnt_pattern = FcPatternCreate(); + fnt_obj_set = FcObjectSetBuild(FC_FAMILY, FC_STYLE, (void *)0); + + // Hopefully, this is a set of all the fonts... + fnt_set = FcFontList(0, fnt_pattern, fnt_obj_set); + + // We don't need the fnt_pattern any more, release it + FcPatternDestroy(fnt_pattern); + + // Now, if we got any fonts, iterate through them... + if (fnt_set) + { + char *stop; + char *start; + char *first; + + font_count = fnt_set->nfont; // How many fonts? + + // Allocate array of char*'s to hold the name strings + full_list = (char **)malloc(sizeof(char *) * font_count); + + // iterate through all the font patterns and get the names out... + for (j = 0; j < font_count; j++) + { + // NOTE: FcChar8 is a typedef of "unsigned char"... + FcChar8 *font; // String to hold the font's name + + // Convert from fontconfig internal pattern to human readable name + // NOTE: This WILL malloc storage, so we need to free it later... + font = FcNameUnparse(fnt_set->fonts[j]); + + // The returned strings look like this... + // Century Schoolbook:style=Bold Italic,fed kursiv,Fett Kursiv,... + // So the bit we want is up to the first comma - BUT some strings have + // more than one name, separated by, guess what?, a comma... + stop = start = first = 0; + stop = strchr((char *)font, ','); + start = strchr((char *)font, ':'); + if ((stop) && (start) && (stop < start)) + { + first = stop + 1; // discard first version of name + // find first comma *after* the end of the name + stop = strchr((char *)start, ','); + } + else + { + first = (char *)font; // name is just what was returned + } + // Truncate the name after the (english) modifiers description + if (stop) + { + *stop = 0; // Terminate the string at the first comma, if there is one + } + + // Copy the font description into our list + if (first == (char *)font) + { // The listed name is still OK + full_list[j] = (char *)font; + } + else + { // The listed name has been modified + full_list[j] = strdup(first); + // Free the font name storage + free (font); + } + // replace "style=Regular" so strcmp sorts it first + if (start) { + char *reg = strstr(full_list[j], "=Regular"); + if (reg) reg[1]='.'; + } + } + + // Release the fnt_set - we don't need it any more + FcFontSetDestroy(fnt_set); + + // Sort the list into alphabetic order + qsort(full_list, font_count, sizeof(*full_list), name_sort); + + // Now let us add the names we got to fltk's font list... + for (j = 0; j < font_count; j++) + { + if (full_list[j]) + { + char xft_name[LOCAL_RAW_NAME_MAX]; + char *stored_name; + // Parse the strings into FLTK-XFT style.. + make_raw_name(xft_name, full_list[j]); + // NOTE: This just adds on AFTER the default fonts - no attempt is made + // to identify already loaded fonts. Is this bad? + stored_name = strdup(xft_name); + Fl::set_font((Fl_Font)(j + FL_FREE_FONT), stored_name); + fl_free_font ++; + + free(full_list[j]); // release that name from our internal array + } + } + // Now we are done with the list, release it fully + free(full_list); + } + return (Fl_Font)fl_free_font; +} // ::set_fonts +//////////////////////////////////////////////////////////////// + + +extern "C" { +static int int_sort(const void *aa, const void *bb) { + return (*(int*)aa)-(*(int*)bb); +} +} + +//////////////////////////////////////////////////////////////// + +// Return all the point sizes supported by this font: +// Suprisingly enough Xft works exactly like fltk does and returns +// the same list. Except there is no way to tell if the font is scalable. +int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) { + Fl_Fontdesc *s = fl_fonts+fnum; + if (!s->name) s = fl_fonts; // empty slot in table, use entry 0 + + fl_open_display(); + XftFontSet* fs = XftListFonts(fl_display, fl_screen, + XFT_FAMILY, XftTypeString, s->name+1, + (void *)0, + XFT_PIXEL_SIZE, + (void *)0); + static int* array = 0; + static int array_size = 0; + if (fs->nfont >= array_size) { + delete[] array; + array = new int[array_size = fs->nfont+1]; + } + array[0] = 0; int j = 1; // claim all fonts are scalable + for (int i = 0; i < fs->nfont; i++) { + double v; + if (XftPatternGetDouble(fs->fonts[i], XFT_PIXEL_SIZE, 0, &v) == XftResultMatch) { + array[j++] = int(v); + } + } + qsort(array+1, j-1, sizeof(int), int_sort); + XftFontSetDestroy(fs); + sizep = array; + return j; +} + +// +// End of "$Id: fl_set_fonts_xft.cxx 6832 2009-07-23 22:36:04Z AlbrechtS $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_shadow_box.cxx b/third_party/windows/fltk-1.1.10/src/fl_shadow_box.cxx new file mode 100644 index 0000000..808b874 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_shadow_box.cxx @@ -0,0 +1,56 @@ +// +// "$Id: fl_shadow_box.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Shadow box drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include +#include + +#define BW 3 + +static void fl_shadow_frame(int x, int y, int w, int h, Fl_Color c) { + fl_color(FL_DARK3); + fl_rectf(x+BW, y+h-BW, w - BW, BW); + fl_rectf(x+w-BW, y+BW, BW, h - BW); + fl_color(c); + fl_rect(x,y,w-BW,h-BW); +} + +static void fl_shadow_box(int x, int y, int w, int h, Fl_Color c) { + fl_color(c); + fl_rectf(x+1,y+1,w-2-BW,h-2-BW); + fl_shadow_frame(x,y,w,h,FL_GRAY0); +} + +extern void fl_internal_boxtype(Fl_Boxtype, Fl_Box_Draw_F*); +Fl_Boxtype fl_define_FL_SHADOW_BOX() { + fl_internal_boxtype(_FL_SHADOW_FRAME, fl_shadow_frame); + fl_internal_boxtype(_FL_SHADOW_BOX, fl_shadow_box); + return _FL_SHADOW_BOX; +} + +// +// End of "$Id: fl_shadow_box.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_shortcut.cxx b/third_party/windows/fltk-1.1.10/src/fl_shortcut.cxx new file mode 100644 index 0000000..221b4bd --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_shortcut.cxx @@ -0,0 +1,243 @@ +// +// "$Id: fl_shortcut.cxx 6803 2009-06-28 22:25:51Z matt $" +// +// Shortcut support routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Code to test and parse fltk shortcut numbers. +// +// A shortcut is a keysym or'd with shift flags. In the simplest +// sense a shortcut is matched if the shift state is exactly as +// given and the key returning that keysym is pressed. +// +// To make it easier to match some things it is more complex: +// +// Only FL_META, FL_ALT, FL_SHIFT, and FL_CTRL must be "off". A +// zero in the other shift flags indicates "dont care". +// +// It also checks against the first character of Fl::event_text(), +// and zero for FL_SHIFT means "don't care". +// This allows punctuation shortcuts like "#" to work (rather than +// calling it "shift+3") + +#include +#include +#include +#include +#include +#include "flstring.h" +#if !defined(WIN32) && !defined(__APPLE__) +#include +#endif + +int Fl::test_shortcut(int shortcut) { + if (!shortcut) return 0; + + int v = shortcut & 0xffff; +#ifdef __APPLE__ + if (v > 32 && v < 0x7f || v >= 0x80 && v <= 0xff) { +#else + // most X11 use MSWindows Latin-1 if set to Western encoding, so 0x80 to 0xa0 are defined + if (v > 32 && v < 0x7f || v >= 0x80 && v <= 0xff) { +#endif + if (isupper(v)) { + shortcut |= FL_SHIFT; + } + } + + int shift = Fl::event_state(); + // see if any required shift flags are off: + if ((shortcut&shift) != (shortcut&0x7fff0000)) return 0; + // record shift flags that are wrong: + int mismatch = (shortcut^shift)&0x7fff0000; + // these three must always be correct: + if (mismatch&(FL_META|FL_ALT|FL_CTRL)) return 0; + + int key = shortcut & 0xffff; + + // if shift is also correct, check for exactly equal keysyms: + if (!(mismatch&(FL_SHIFT)) && key == Fl::event_key()) return 1; + + // try matching ascii, ignore shift: + if (key == event_text()[0]) return 1; + + // kludge so that Ctrl+'_' works (as opposed to Ctrl+'^_'): + if ((shift&FL_CTRL) && key >= 0x3f && key <= 0x5F + && event_text()[0]==(key^0x40)) return 1; + return 0; +} + +#if defined(WIN32) || defined(__APPLE__) // if not X +// This table must be in numeric order by fltk (X) keysym number: +struct Keyname {int key; const char* name;}; +static Keyname table[] = { + {' ', "Space"}, + {FL_BackSpace, "Backspace"}, + {FL_Tab, "Tab"}, + {0xff0b/*XK_Clear*/, "Clear"}, + {FL_Enter, "Enter"}, // X says "Enter" + {FL_Pause, "Pause"}, + {FL_Scroll_Lock, "Scroll_Lock"}, + {FL_Escape, "Escape"}, + {FL_Home, "Home"}, + {FL_Left, "Left"}, + {FL_Up, "Up"}, + {FL_Right, "Right"}, + {FL_Down, "Down"}, + {FL_Page_Up, "Page_Up"}, // X says "Prior" + {FL_Page_Down,"Page_Down"}, // X says "Next" + {FL_End, "End"}, + {FL_Print, "Print"}, + {FL_Insert, "Insert"}, + {FL_Menu, "Menu"}, + {FL_Num_Lock, "Num_Lock"}, + {FL_KP_Enter, "KP_Enter"}, + {FL_Shift_L, "Shift_L"}, + {FL_Shift_R, "Shift_R"}, + {FL_Control_L,"Control_L"}, + {FL_Control_R,"Control_R"}, + {FL_Caps_Lock,"Caps_Lock"}, + {FL_Meta_L, "Meta_L"}, + {FL_Meta_R, "Meta_R"}, + {FL_Alt_L, "Alt_L"}, + {FL_Alt_R, "Alt_R"}, + {FL_Delete, "Delete"} +}; +#endif + +const char * fl_shortcut_label(int shortcut) { + static char buf[20]; + char *p = buf; + if (!shortcut) {*p = 0; return buf;} + // fix upper case shortcuts + int v = shortcut & 0xffff; +#ifdef __APPLE__ + if (v > 32 && v < 0x7f || v >= 0x80 && v <= 0xff) { +#else + if (v > 32 && v < 0x7f || v >= 0xa0 && v <= 0xff) { +#endif + if (isupper(v)) { + shortcut |= FL_SHIFT; + } + } +#ifdef __APPLE__ + // \todo Mac : we might want to change the symbols for Mac users - consider drawing Apple Symbols... . + if (shortcut & FL_SHIFT) {strcpy(p,"Shift+"); p += 6;} //: Mac hollow up arrow + if (shortcut & FL_META) {strcpy(p,"Cmd+"); p += 4;} //: Mac 'Apple' key + if (shortcut & FL_ALT) {strcpy(p,"Option+"); p += 7;} //: Mac 'Alt/Option' or fancy switch symbol + if (shortcut & FL_CTRL) {strcpy(p,"Ctrl+"); p += 5;} //: Mac ctrl key +#else + if (shortcut & FL_META) {strcpy(p,"Meta+"); p += 5;} + if (shortcut & FL_ALT) {strcpy(p,"Alt+"); p += 4;} + if (shortcut & FL_SHIFT) {strcpy(p,"Shift+"); p += 6;} + if (shortcut & FL_CTRL) {strcpy(p,"Ctrl+"); p += 5;} +#endif // __APPLE__ + int key = shortcut & 0xFFFF; +#if defined(WIN32) || defined(__APPLE__) // if not X + if (key >= FL_F && key <= FL_F_Last) { + *p++ = 'F'; + if (key > FL_F+9) *p++ = (key-FL_F)/10+'0'; + *p++ = (key-FL_F)%10 + '0'; + } else { + // binary search the table for a match: + int a = 0; + int b = sizeof(table)/sizeof(*table); + while (a < b) { + int c = (a+b)/2; + if (table[c].key == key) { + if (p > buf) {strcpy(p,table[c].name); return buf;} + return table[c].name; + } + if (table[c].key < key) a = c+1; + else b = c; + } + if (key >= FL_KP && key <= FL_KP_Last) { + // mark keypad keys with KP_ prefix + strcpy(p,"KP_"); p += 3; + *p++ = uchar(key & 127); + } else { + // if none found, use the keystroke as a match: + *p++ = uchar(toupper(key & 255)); + } + } + *p = 0; + return buf; +#else + const char* q; + if (key == FL_Enter || key == '\r') q="Enter"; // don't use Xlib's "Return": + else if (key > 32 && key < 0x100) q = 0; + else q = XKeysymToString(key); + if (!q) {*p++ = uchar(toupper(key & 255)); *p = 0; return buf;} + if (p > buf) {strcpy(p,q); return buf;} else return q; +#endif +} + +// Emulation of XForms named shortcuts +#include +int fl_old_shortcut(const char* s) { + if (!s || !*s) return 0; + int n = 0; + if (*s == '#') {n |= FL_ALT; s++;} + if (*s == '+') {n |= FL_SHIFT; s++;} + if (*s == '^') {n |= FL_CTRL; s++;} + if (*s && s[1]) return n | (int)strtol(s,0,0); // allow 0xf00 to get any key + return n | *s; +} + +// Tests for &x shortcuts in button labels: + +char Fl_Widget::label_shortcut(const char *t) { + if (!t) return 0; + for (;;) { + if (*t==0) return 0; + if (*t=='&') { + char s = t[1]; + if (s==0) return 0; + else if (s=='&') t++; + else return s; + } + t++; + } +} + +int Fl_Widget::test_shortcut(const char *t) { + #ifdef WIN32 + // on MSWindows, users expect shortcuts to work only when the Alt modifier is pressed + if (Fl::event_state(FL_ALT)==0) return 0; + #endif + char c = Fl::event_text()[0]; + if (!c || !t) return 0; + if (c == label_shortcut(t)) + return 1; + return 0; +} + +int Fl_Widget::test_shortcut() { + if (!(flags()&SHORTCUT_LABEL)) return 0; + return test_shortcut(label()); +} + +// +// End of "$Id: fl_shortcut.cxx 6803 2009-06-28 22:25:51Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_show_colormap.cxx b/third_party/windows/fltk-1.1.10/src/fl_show_colormap.cxx new file mode 100644 index 0000000..ea56a67 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_show_colormap.cxx @@ -0,0 +1,162 @@ +// +// "$Id: fl_show_colormap.cxx 6926 2009-11-07 21:01:08Z matt $" +// +// Colormap color selection dialog for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Select a color from the colormap. +// Pretty much unchanged from Forms. + +#include +#include +#include +#include +#include + +#define BOXSIZE 14 +#define BORDER 4 + +class ColorMenu : public Fl_Window { + Fl_Color initial; + Fl_Color which, previous; + int done; + void drawbox(Fl_Color); + void draw(); + int handle(int); +public: + ColorMenu(Fl_Color oldcol); + Fl_Color run(); +}; + +ColorMenu::ColorMenu(Fl_Color oldcol) : + Fl_Window(BOXSIZE*8+1+2*BORDER, BOXSIZE*32+1+2*BORDER) { + clear_border(); + set_modal(); + initial = which = previous = oldcol; + done = 0; +} + +void ColorMenu::drawbox(Fl_Color c) { + if (c < 0 || c > 255) return; + int X = (c%8)*BOXSIZE+BORDER; + int Y = (c/8)*BOXSIZE+BORDER; +#if BORDER_WIDTH < 3 + if (c == which) fl_draw_box(FL_DOWN_BOX, X+1, Y+1, BOXSIZE-1, BOXSIZE-1, c); + else fl_draw_box(FL_BORDER_BOX, X, Y, BOXSIZE+1, BOXSIZE+1, c); +#else + fl_draw_box(c == which ? FL_DOWN_BOX : FL_BORDER_BOX, + X, Y, BOXSIZE+1, BOXSIZE+1, c); +#endif +} + +void ColorMenu::draw() { + if (damage() != FL_DAMAGE_CHILD) { + fl_draw_box(FL_UP_BOX,0,0,w(),h(),color()); + for (int c = 0; c < 256; c++) drawbox((Fl_Color)c); + } else { + drawbox(previous); + drawbox(which); + } + previous = which; +} + +int ColorMenu::handle(int e) { + int c = which; + switch (e) { + case FL_PUSH: + case FL_DRAG: { + int X = (Fl::event_x_root() - x() - BORDER); + if (X >= 0) X = X/BOXSIZE; + int Y = (Fl::event_y_root() - y() - BORDER); + if (Y >= 0) Y = Y/BOXSIZE; + if (X >= 0 && X < 8 && Y >= 0 && Y < 32) + c = 8*Y + X; + else + c = initial; + } break; + case FL_RELEASE: + done = 1; + return 1; + case FL_KEYBOARD: + switch (Fl::event_key()) { + case FL_Up: if (c > 7) c -= 8; break; + case FL_Down: if (c < 256-8) c += 8; break; + case FL_Left: if (c > 0) c--; break; + case FL_Right: if (c < 255) c++; break; + case FL_Escape: which = initial; done = 1; return 1; + case FL_KP_Enter: + case FL_Enter: done = 1; return 1; + default: return 0; + } + break; + default: + return 0; + } + if (c != which) { + which = (Fl_Color)c; damage(FL_DAMAGE_CHILD); + int bx = (c%8)*BOXSIZE+BORDER; + int by = (c/8)*BOXSIZE+BORDER; + int px = x(); + int py = y(); + int scr_x, scr_y, scr_w, scr_h; + Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h); + if (px < scr_x) px = scr_x; + if (px+bx+BOXSIZE+BORDER >= scr_x+scr_w) px = scr_x+scr_w-bx-BOXSIZE-BORDER; + if (py < scr_y) py = scr_y; + if (py+by+BOXSIZE+BORDER >= scr_y+scr_h) py = scr_y+scr_h-by-BOXSIZE-BORDER; + if (px+bx < BORDER) px = BORDER-bx; + if (py+by < BORDER) py = BORDER-by; + position(px,py); + } + return 1; +} + +extern char fl_override_redirect; // hack for menus + +#ifdef _MSC_VER +#pragma optimize("a",off) // needed to get the done check to work +#endif +Fl_Color ColorMenu::run() { + if (which < 0 || which > 255) { + position(Fl::event_x_root()-w()/2, Fl::event_y_root()-y()/2); + } else { + position(Fl::event_x_root()-(initial%8)*BOXSIZE-BOXSIZE/2-BORDER, + Fl::event_y_root()-(initial/8)*BOXSIZE-BOXSIZE/2-BORDER); + } + show(); + Fl::grab(*this); + done = 0; + while (!done) Fl::wait(); + Fl::release(); + return which; +} + +Fl_Color fl_show_colormap(Fl_Color oldcol) { + ColorMenu m(oldcol); + return m.run(); +} + +// +// End of "$Id: fl_show_colormap.cxx 6926 2009-11-07 21:01:08Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_symbols.cxx b/third_party/windows/fltk-1.1.10/src/fl_symbols.cxx new file mode 100644 index 0000000..75abcdc --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_symbols.cxx @@ -0,0 +1,700 @@ +// +// "$Id: fl_symbols.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Symbol drawing code for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// These are small graphics drawn by the normal label-drawing +// code when the string starts with an '@' sign. + +// Adapted from original code written by: + +// Written by Mark Overmars +// Version 2.1 a +// Date: Oct 2, 1992 + +#include +#include +#include +#include "flstring.h" + +typedef struct { + const char *name; + void (*drawit)(Fl_Color); + char scalable; + char notempty; +} SYMBOL; + +#define MAXSYMBOL 211 + /* Maximal number of symbols in table. Only half of them are + used. Should be prime. */ + +static SYMBOL symbols[MAXSYMBOL]; /* The symbols */ +static int symbnumb = -1; /* Their number */ + +static int find(const char *name) { +// returns hash entry if it exists, or first empty slot: + int pos = name[0] ? ( + name[1] ? ( + name[2] ? 71*name[0]+31*name[1]+name[2] : 31*name[0]+name[1] + ) : + name[0] + ) : 0; + pos %= MAXSYMBOL; + int hh2 = name[0] ? ( + (name[1]) ? 51*name[0]+3*name[1] : 3*name[0] + ) : 1; + hh2 %= MAXSYMBOL; if (!hh2) hh2 = 1; + for (;;) { + if (!symbols[pos].notempty) return pos; + if (!strcmp(symbols[pos].name,name)) return pos; + pos = (pos + hh2) % MAXSYMBOL; + } +} + +static void fl_init_symbols(void); + +/**************** The routines seen by the user *************************/ + +int fl_add_symbol(const char *name, void (*drawit)(Fl_Color), int scalable) +/* Adds a symbol to the system. Returns whether correct. */ +{ + fl_init_symbols(); + int pos; + if (symbnumb > MAXSYMBOL / 2) return 0; // table is full + pos = find(name); + symbols[pos].name = name; + symbols[pos].drawit = drawit; + symbols[pos].notempty = 1; + symbols[pos].scalable = scalable; + symbnumb++; + return 1; +} + +int fl_return_arrow(int x,int y,int w,int h); + +// provided for back compatability: +int fl_draw_symbol(const char *label,int x,int y,int w,int h,Fl_Color col) { + const char *p = label; + if (*p++ != '@') return 0; + fl_init_symbols(); + int equalscale = 0; + if (*p == '#') {equalscale = 1; p++;} + if (*p == '-' && p[1]>='1' && p[1]<='9') { + int n = p[1]-'0'; + x += n; y += n; w -= 2*n; h -= 2*n; + p += 2; + } else if (*p == '+' && p[1]>='1' && p[1]<='9') { + int n = p[1]-'0'; + x -= n; y -= n; w += 2*n; h += 2*n; + p += 2; + } + if (w < 10) {x -= (10-w)/2; w = 10;} + if (h < 10) {y -= (10-h)/2; h = 10;} + w = (w-1)|1; h = (h-1)|1; + char flip_x = 0, flip_y = 0; + if (*p=='$') { + flip_x = 1; + p++; + } + if (*p=='%') { + flip_y = 1; + p++; + } + int rotangle; + switch (*p++) { + case '0': + rotangle = 1000*(p[1]-'0') + 100*(p[2]-'0') + 10*(p[3]-'0'); + p += 4; + break; + case '1': rotangle = 2250; break; + case '2': rotangle = 2700; break; + case '3': rotangle = 3150; break; + case '4': rotangle = 1800; break; + case '5': + case '6': rotangle = 0; break; + case '7': rotangle = 1350; break; + case '8': rotangle = 900; break; + case '9': rotangle = 450; break; + default: rotangle = 0; p--; break; + } + int pos = find(p); + if (!symbols[pos].notempty) return 0; + if (symbols[pos].scalable == 3) { // kludge to detect return arrow + fl_return_arrow(x,y,w,h); + return 1; + } + fl_push_matrix(); + fl_translate(x+w/2,y+h/2); + if (symbols[pos].scalable) { + if (equalscale) {if (w0; i--, a-=da, r-=dr1) { + double ar = a/180.0 * M_PI; + vv(cos(ar)*r, sin(ar)*r); + } + for (i=27; i>=0; a+=da, i--, r-=dr2) { + double ar = a/180.0 * M_PI; + vv(cos(ar)*r, sin(ar)*r); + } + if (j&1) { + EC; + } else { + ECP; + } + } +} + +static void draw_refresh(Fl_Color c) { + draw_round_arrow(c); + fl_rotate(180.0); + draw_round_arrow(c); + fl_rotate(-180.0); +} + +static void draw_reload(Fl_Color c) { + fl_rotate(-135.0); + draw_round_arrow(c, 10); + fl_rotate(135.0); +} + +static void draw_undo(Fl_Color c) { + fl_translate(0.0, 0.2); + fl_scale(1.0, -1.0); + draw_round_arrow(c, 6); + fl_scale(1.0, -1.0); + fl_translate(0.0, -0.2); +} + +static void draw_redo(Fl_Color c) { + fl_scale(-1.0, 1.0); + draw_undo(c); + fl_scale(-1.0, 1.0); +} + +static void fl_init_symbols(void) { + static char beenhere; + if (beenhere) return; + beenhere = 1; + symbnumb = 0; + + fl_add_symbol("", draw_arrow1, 1); + fl_add_symbol("->", draw_arrow1, 1); + fl_add_symbol(">", draw_arrow2, 1); + fl_add_symbol(">>", draw_arrow3, 1); + fl_add_symbol(">|", draw_arrowbar, 1); + fl_add_symbol(">[]", draw_arrowbox, 1); + fl_add_symbol("|>", draw_bararrow, 1); + fl_add_symbol("<-", draw_arrow01, 1); + fl_add_symbol("<", draw_arrow02, 1); + fl_add_symbol("<<", draw_arrow03, 1); + fl_add_symbol("|<", draw_0arrowbar, 1); + fl_add_symbol("[]<", draw_0arrowbox, 1); + fl_add_symbol("<|", draw_0bararrow, 1); + fl_add_symbol("<->", draw_doublearrow, 1); + fl_add_symbol("-->", draw_arrow, 1); + fl_add_symbol("+", draw_plus, 1); + fl_add_symbol("->|", draw_arrow1bar, 1); + fl_add_symbol("arrow", draw_arrow, 1); + fl_add_symbol("returnarrow", 0, 3); + fl_add_symbol("square", draw_square, 1); + fl_add_symbol("circle", draw_circle, 1); + fl_add_symbol("line", draw_line, 1); + fl_add_symbol("plus", draw_plus, 1); + fl_add_symbol("menu", draw_menu, 1); + fl_add_symbol("UpArrow", draw_uparrow, 1); + fl_add_symbol("DnArrow", draw_downarrow, 1); + fl_add_symbol("||", draw_doublebar, 1); + fl_add_symbol("search", draw_search, 1); + fl_add_symbol("FLTK", draw_fltk, 1); + + fl_add_symbol("filenew", draw_filenew, 1); + fl_add_symbol("fileopen", draw_fileopen, 1); + fl_add_symbol("filesave", draw_filesave, 1); + fl_add_symbol("filesaveas", draw_filesaveas, 1); + fl_add_symbol("fileprint", draw_fileprint, 1); + + fl_add_symbol("refresh", draw_refresh, 1); + fl_add_symbol("reload", draw_reload, 1); + fl_add_symbol("undo", draw_undo, 1); + fl_add_symbol("redo", draw_redo, 1); + +// fl_add_symbol("file", draw_file, 1); +} + +// +// End of "$Id: fl_symbols.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/fl_vertex.cxx b/third_party/windows/fltk-1.1.10/src/fl_vertex.cxx new file mode 100644 index 0000000..9ced185 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/fl_vertex.cxx @@ -0,0 +1,325 @@ +// +// "$Id: fl_vertex.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Portable drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Portable drawing code for drawing arbitrary shapes with +// simple 2D transformations. See also fl_arc.cxx + +// matt: the Quartz implementation purposly doesn't use the Quartz matrix +// operations for reasons of compatibility and maintainability + +#include +#include +#include +#include +#include +#include + +struct matrix {double a, b, c, d, x, y;}; + +static matrix m = {1, 0, 0, 1, 0, 0}; + +static matrix stack[32]; +static int sptr = 0; + +void fl_push_matrix() { + if (sptr==32) + Fl::error("fl_push_matrix(): matrix stack overflow."); + else + stack[sptr++] = m; +} + +void fl_pop_matrix() { + if (sptr==0) + Fl::error("fl_pop_matrix(): matrix stack underflow."); + else + m = stack[--sptr]; +} + +void fl_mult_matrix(double a, double b, double c, double d, double x, double y) { + matrix o; + o.a = a*m.a + b*m.c; + o.b = a*m.b + b*m.d; + o.c = c*m.a + d*m.c; + o.d = c*m.b + d*m.d; + o.x = x*m.a + y*m.c + m.x; + o.y = x*m.b + y*m.d + m.y; + m = o; +} + +void fl_scale(double x,double y) {fl_mult_matrix(x,0,0,y,0,0);} + +void fl_scale(double x) {fl_mult_matrix(x,0,0,x,0,0);} + +void fl_translate(double x,double y) {fl_mult_matrix(1,0,0,1,x,y);} + +void fl_rotate(double d) { + if (d) { + double s, c; + if (d == 0) {s = 0; c = 1;} + else if (d == 90) {s = 1; c = 0;} + else if (d == 180) {s = 0; c = -1;} + else if (d == 270 || d == -90) {s = -1; c = 0;} + else {s = sin(d*M_PI/180); c = cos(d*M_PI/180);} + fl_mult_matrix(c,-s,s,c,0,0); + } +} + +// typedef what the x,y fields in a point are: +#ifdef WIN32 +typedef int COORD_T; +# define XPOINT XPoint +#elif defined(__APPLE_QUARTZ__) +typedef float COORD_T; +typedef struct { float x; float y; } QPoint; +# define XPOINT QPoint +extern float fl_quartz_line_width_; +#else +typedef short COORD_T; +# define XPOINT XPoint +#endif + +static XPOINT *p = (XPOINT *)0; + +static int p_size; +static int n; +static int what; +enum {LINE, LOOP, POLYGON, POINT_}; + +void fl_begin_points() {n = 0; what = POINT_;} + +void fl_begin_line() {n = 0; what = LINE;} + +void fl_begin_loop() {n = 0; what = LOOP;} + +void fl_begin_polygon() {n = 0; what = POLYGON;} + +double fl_transform_x(double x, double y) {return x*m.a + y*m.c + m.x;} + +double fl_transform_y(double x, double y) {return x*m.b + y*m.d + m.y;} + +double fl_transform_dx(double x, double y) {return x*m.a + y*m.c;} + +double fl_transform_dy(double x, double y) {return x*m.b + y*m.d;} + +static void fl_transformed_vertex(COORD_T x, COORD_T y) { + if (!n || x != p[n-1].x || y != p[n-1].y) { + if (n >= p_size) { + p_size = p ? 2*p_size : 16; + p = (XPOINT*)realloc((void*)p, p_size*sizeof(*p)); + } + p[n].x = x; + p[n].y = y; + n++; + } +} + +void fl_transformed_vertex(double xf, double yf) { +#ifdef __APPLE_QUARTZ__ + fl_transformed_vertex(COORD_T(xf), COORD_T(yf)); +#else + fl_transformed_vertex(COORD_T(rint(xf)), COORD_T(rint(yf))); +#endif +} + +void fl_vertex(double x,double y) { + fl_transformed_vertex(x*m.a + y*m.c + m.x, x*m.b + y*m.d + m.y); +} + +void fl_end_points() { +#ifdef WIN32 + for (int i=0; i1) XDrawPoints(fl_display, fl_window, fl_gc, p, n, 0); +#endif +} + +void fl_end_line() { + if (n < 2) { + fl_end_points(); + return; + } +#ifdef WIN32 + if (n>1) Polyline(fl_gc, p, n); +#elif defined(__APPLE_QD__) + if (n<=1) return; + MoveTo(p[0].x, p[0].y); + for (int i=1; i1) XDrawLines(fl_display, fl_window, fl_gc, p, n, 0); +#endif +} + +static void fixloop() { // remove equal points from closed path + while (n>2 && p[n-1].x == p[0].x && p[n-1].y == p[0].y) n--; +} + +void fl_end_loop() { + fixloop(); + if (n>2) fl_transformed_vertex((COORD_T)p[0].x, (COORD_T)p[0].y); + fl_end_line(); +} + +void fl_end_polygon() { + fixloop(); + if (n < 3) { + fl_end_line(); + return; + } +#ifdef WIN32 + if (n>2) { + SelectObject(fl_gc, fl_brush()); + Polygon(fl_gc, p, n); + } +#elif defined(__APPLE_QD__) + if (n<=1) return; + PolyHandle ph = OpenPoly(); + MoveTo(p[0].x, p[0].y); + for (int i=1; i2) XFillPolygon(fl_display, fl_window, fl_gc, p, n, Convex, 0); +#endif +} + +static int gap; +#ifdef WIN32 +static int counts[20]; +static int numcount; +#endif + +void fl_begin_complex_polygon() { + fl_begin_polygon(); + gap = 0; +#ifdef WIN32 + numcount = 0; +#endif +} + +void fl_gap() { + while (n>gap+2 && p[n-1].x == p[gap].x && p[n-1].y == p[gap].y) n--; + if (n > gap+2) { + fl_transformed_vertex((COORD_T)p[gap].x, (COORD_T)p[gap].y); +#ifdef WIN32 + counts[numcount++] = n-gap; +#endif + gap = n; + } else { + n = gap; + } +} + +void fl_end_complex_polygon() { + fl_gap(); + if (n < 3) { + fl_end_line(); + return; + } +#ifdef WIN32 + if (n>2) { + SelectObject(fl_gc, fl_brush()); + PolyPolygon(fl_gc, p, counts, numcount); + } +#elif defined(__APPLE_QD__) + if (n<=1) return; + PolyHandle ph = OpenPoly(); + MoveTo(p[0].x, p[0].y); + for (int i=1; i2) XFillPolygon(fl_display, fl_window, fl_gc, p, n, 0, 0); +#endif +} + +// shortcut the closed circles so they use XDrawArc: +// warning: these do not draw rotated ellipses correctly! +// See fl_arc.c for portable version. + +void fl_circle(double x, double y,double r) { + double xt = fl_transform_x(x,y); + double yt = fl_transform_y(x,y); + double rx = r * (m.c ? sqrt(m.a*m.a+m.c*m.c) : fabs(m.a)); + double ry = r * (m.b ? sqrt(m.b*m.b+m.d*m.d) : fabs(m.d)); + int llx = (int)rint(xt-rx); + int w = (int)rint(xt+rx)-llx; + int lly = (int)rint(yt-ry); + int h = (int)rint(yt+ry)-lly; +#ifdef WIN32 + if (what==POLYGON) { + SelectObject(fl_gc, fl_brush()); + Pie(fl_gc, llx, lly, llx+w, lly+h, 0,0, 0,0); + } else + Arc(fl_gc, llx, lly, llx+w, lly+h, 0,0, 0,0); +#elif defined(__APPLE_QD__) + Rect rt; rt.left=llx; rt.right=llx+w; rt.top=lly; rt.bottom=lly+h; + (what == POLYGON ? PaintOval : FrameOval)(&rt); +#elif defined(__APPLE_QUARTZ__) + // Quartz warning : circle won't scale to current matrix! + CGContextAddArc(fl_gc, xt, yt, (w+h)*0.25f, 0, 2.0f*M_PI, 1); + (what == POLYGON ? CGContextFillPath : CGContextStrokePath)(fl_gc); +#else + (what == POLYGON ? XFillArc : XDrawArc) + (fl_display, fl_window, fl_gc, llx, lly, w, h, 0, 360*64); +#endif +} + +// +// End of "$Id: fl_vertex.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/flstring.c b/third_party/windows/fltk-1.1.10/src/flstring.c new file mode 100644 index 0000000..34c01d6 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/flstring.c @@ -0,0 +1,105 @@ +/* + * "$Id: flstring.c 4288 2005-04-16 00:13:17Z mike $" + * + * BSD string functions for the Fast Light Tool Kit (FLTK). + * + * Copyright 1998-2005 by Bill Spitzak and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems on the following page: + * + * http://www.fltk.org/str.php + */ + +#include "flstring.h" + + +/* + * 'fl_strlcat()' - Safely concatenate two strings. + */ + +size_t /* O - Length of string */ +fl_strlcat(char *dst, /* O - Destination string */ + const char *src, /* I - Source string */ + size_t size) { /* I - Size of destination string buffer */ + size_t srclen; /* Length of source string */ + size_t dstlen; /* Length of destination string */ + + + /* + * Figure out how much room is left... + */ + + dstlen = strlen(dst); + size -= dstlen + 1; + + if (!size) return (dstlen); /* No room, return immediately... */ + + /* + * Figure out how much room is needed... + */ + + srclen = strlen(src); + + /* + * Copy the appropriate amount... + */ + + if (srclen > size) srclen = size; + + memcpy(dst + dstlen, src, srclen); + dst[dstlen + srclen] = '\0'; + + return (dstlen + srclen); +} + + +/* + * 'fl_strlcpy()' - Safely copy two strings. + */ + +size_t /* O - Length of string */ +fl_strlcpy(char *dst, /* O - Destination string */ + const char *src, /* I - Source string */ + size_t size) { /* I - Size of destination string buffer */ + size_t srclen; /* Length of source string */ + + + /* + * Figure out how much room is needed... + */ + + size --; + + srclen = strlen(src); + + /* + * Copy the appropriate amount... + */ + + if (srclen > size) srclen = size; + + memcpy(dst, src, srclen); + dst[srclen] = '\0'; + + return (srclen); +} + + +/* + * End of "$Id: flstring.c 4288 2005-04-16 00:13:17Z mike $". + */ diff --git a/third_party/windows/fltk-1.1.10/src/flstring.h b/third_party/windows/fltk-1.1.10/src/flstring.h new file mode 100644 index 0000000..1a676f6 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/flstring.h @@ -0,0 +1,115 @@ +/* + * "$Id: flstring.h 5701 2007-02-20 18:43:10Z mike $" + * + * Common string header file for the Fast Light Tool Kit (FLTK). + * + * Copyright 1998-2007 by Bill Spitzak and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems on the following page: + * + * http://www.fltk.org/str.php + */ + +#ifndef flstring_h +# define flstring_h + +# include +# include +# include +# include +# include +# ifdef HAVE_STRINGS_H +# include +# endif /* HAVE_STRINGS_H */ +# include + +/* + * Apparently Unixware defines "index" to strchr (!) rather than + * providing a proper entry point or not providing the (obsolete) + * BSD function. Make sure index is not defined... + */ + +# ifdef index +# undef index +# endif /* index */ + +# if defined(WIN32) && !defined(__CYGWIN__) +# define strcasecmp(s,t) _stricmp((s), (t)) +# define strncasecmp(s,t,n) _strnicmp((s), (t), (n)) +// Visual C++ 2005 incorrectly displays a warning about the use of POSIX APIs +// on Windows, which is supposed to be POSIX compliant... Some of these +// functions are also defined in ISO C99... +# ifndef __WATCOMC__ +# define strdup _strdup +# define unlink _unlink +# endif // !__WATCOMC__ +# elif defined(__EMX__) +# define strcasecmp(s,t) stricmp((s), (t)) +# define strncasecmp(s,t,n) strnicmp((s), (t), (n)) +# endif /* WIN32 */ + +# ifdef __cplusplus +extern "C" { +# endif /* __cplusplus */ + +/* + * MetroWerks' CodeWarrior put thes "non-standard" functions in + * which unfortunatly does not play well otherwise + * when included - to be resolved... + */ + +# if defined(__APPLE__) && defined(__MWERKS__) && defined(_MSL_USING_MW_C_HEADERS) +int strcasecmp(const char*,const char*); +int strncasecmp(const char*,const char*,int); +char *strdup(const char*); +# endif + +FL_EXPORT extern int fl_snprintf(char *, size_t, const char *, ...); +# if !HAVE_SNPRINTF +# define snprintf fl_snprintf +# endif /* !HAVE_SNPRINTF */ + +FL_EXPORT extern int fl_vsnprintf(char *, size_t, const char *, va_list ap); +# if !HAVE_VSNPRINTF +# define vsnprintf fl_vsnprintf +# endif /* !HAVE_VSNPRINTF */ + +/* + * strlcpy() and strlcat() are some really useful BSD string functions + * that work the way strncpy() and strncat() *should* have worked. + */ + +FL_EXPORT extern size_t fl_strlcat(char *, const char *, size_t); +# if !HAVE_STRLCAT +# define strlcat fl_strlcat +# endif /* !HAVE_STRLCAT */ + +FL_EXPORT extern size_t fl_strlcpy(char *, const char *, size_t); +# if !HAVE_STRLCPY +# define strlcpy fl_strlcpy +# endif /* !HAVE_STRLCPY */ + +# ifdef __cplusplus +} +# endif /* __cplusplus */ +#endif /* !flstring_h */ + + +/* + * End of "$Id: flstring.h 5701 2007-02-20 18:43:10Z mike $". + */ diff --git a/third_party/windows/fltk-1.1.10/src/forms_bitmap.cxx b/third_party/windows/fltk-1.1.10/src/forms_bitmap.cxx new file mode 100644 index 0000000..f7e497e --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/forms_bitmap.cxx @@ -0,0 +1,52 @@ +// +// "$Id: forms_bitmap.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Forms compatible bitmap function for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include + +Fl_FormsBitmap::Fl_FormsBitmap( + Fl_Boxtype t, int X, int Y, int W, int H, const char* l) +: Fl_Widget(X, Y, W, H, l) { + box(t); + b = 0; + color(FL_BLACK); + align(FL_ALIGN_BOTTOM); +} + +void Fl_FormsBitmap::set(int W, int H, const uchar *bits) { + delete b; + bitmap(new Fl_Bitmap(bits, W, H)); +} + +void Fl_FormsBitmap::draw() { + draw_box(box(), selection_color()); + if (b) {fl_color(color()); b->draw(x(), y(), w(), h());} + draw_label(); +} + +// +// End of "$Id: forms_bitmap.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/forms_compatability.cxx b/third_party/windows/fltk-1.1.10/src/forms_compatability.cxx new file mode 100644 index 0000000..0608f30 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/forms_compatability.cxx @@ -0,0 +1,211 @@ +// +// "$Id: forms_compatability.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Forms compatibility functions for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Forms library compatability functions. +// Many more functions are defined as inlines in forms.h! + +#include +#include + +char fl_flip = 2; +void fl_end_form() { + while (Fl_Group::current()) Fl_Group::current()->forms_end(); +} +void Fl_Group::forms_end() { + // set the dimensions of a group to surround contents + if (children() && !w()) { + Fl_Widget*const* a = array(); + Fl_Widget* o = *a++; + int rx = o->x(); + int ry = o->y(); + int rw = rx+o->w(); + int rh = ry+o->h(); + for (int i=children_-1; i--;) { + o = *a++; + if (o->x() < rx) rx = o->x(); + if (o->y() < ry) ry = o->y(); + if (o->x()+o->w() > rw) rw = o->x()+o->w(); + if (o->y()+o->h() > rh) rh = o->y()+o->h(); + } + x(rx); + y(ry); + w(rw-rx); + h(rh-ry); + } + // flip all the children's coordinate systems: + if (fl_flip) { + Fl_Widget* o = (type()>=FL_WINDOW) ? this : window(); + int Y = o->h(); + Fl_Widget*const* a = array(); + for (int i=children(); i--;) { + Fl_Widget* ow = *a++; + int newy = Y-ow->y()-ow->h(); + ow->y(newy); + } + } + end(); +} + +static int initargc; +static char **initargv; + +void fl_initialize(int *argc, char **argv, const char *, FL_CMD_OPT *, int) { + initargc = *argc; + initargv = new char*[*argc+1]; + int i,j; + for (i=0; i<=*argc; i++) initargv[i] = argv[i]; + for (i=j=1; i<*argc; ) { + if (Fl::arg(*argc,argv,i)); + else argv[j++] = argv[i++]; + } + argv[j] = 0; + *argc = j; + if (fl_flip==2) fl_flip = 0; +} + +char fl_modal_next; // set by fl_freeze_forms() + +void fl_show_form(Fl_Window *f,int place,int b,const char *n) { + + f->label(n); + if (!b) f->clear_border(); + if (fl_modal_next || b==FL_TRANSIENT) {f->set_modal(); fl_modal_next = 0;} + + if (place & FL_PLACE_MOUSE) f->hotspot(f); + + if (place & FL_PLACE_CENTER) { + int scr_x, scr_y, scr_w, scr_h; + Fl::screen_xywh(scr_x, scr_y, scr_w, scr_h); + f->position(scr_x+(scr_w-f->w())/2, scr_y+(scr_h-f->h())/2); + } + + if (place & FL_PLACE_FULLSCREEN) + f->fullscreen(); + + if (place & (FL_PLACE_POSITION | FL_PLACE_GEOMETRY)) + f->position( + (f->x() < 0) ? Fl::w()-f->w()+f->x()-1 : f->x(), + (f->y() < 0) ? Fl::h()-f->h()+f->y()-1 : f->y()); + +// if (place & FL_PLACE_ASPECT) { +// this is not yet implemented +// it can be done by setting size_range(). + + if (place == FL_PLACE_FREE || place == FL_PLACE_SIZE) + f->free_position(); + + if (place == FL_PLACE_FREE || place & FL_FREE_SIZE) + if (!f->resizable()) f->resizable(f); + + if (initargc) {f->show(initargc,initargv); initargc = 0;} + else f->show(); +} + +Fl_Widget *fl_do_forms(void) { + Fl_Widget *obj; + while (!(obj = Fl::readqueue())) if (!Fl::wait()) exit(0); + return obj; +} + +Fl_Widget *fl_check_forms() { + Fl::check(); + return Fl::readqueue(); +} + +void fl_set_graphics_mode(int /*r*/,int /*d*/) {} + +void Fl_FormsText::draw() { + draw_box(); + align(align()|FL_ALIGN_INSIDE); // questionable method of compatability + draw_label(); +} + +// Create a forms button by selecting correct fltk subclass: + +#include +#include + +Fl_Button *fl_add_button(uchar t,int x,int y,int w,int h,const char *l) { + Fl_Button *b; + switch (t) { + case FL_RETURN_BUTTON: + case FL_HIDDEN_RET_BUTTON: + b = new Fl_Return_Button(x,y,w,h,l); + break; + case FL_TOUCH_BUTTON: + b = new Fl_Repeat_Button(x,y,w,h,l); + break; + default: + b = new Fl_Button(x,y,w,h,l); + } + switch (t) { + case FL_TOGGLE_BUTTON: + case FL_RADIO_BUTTON: + b->type(t); + break; + case FL_HIDDEN_BUTTON: + case FL_HIDDEN_RET_BUTTON: + b->type(FL_HIDDEN_BUTTON); + break; + case FL_INOUT_BUTTON: + b->when(FL_WHEN_CHANGED); + break; + } + return b; +} + +void fl_show_message(const char *q1,const char *q2,const char *q3) { + fl_message("%s\n%s\n%s", q1?q1:"", q2?q2:"", q3?q3:""); +} + +void fl_show_alert(const char *q1,const char *q2,const char *q3,int) { + fl_alert("%s\n%s\n%s", q1?q1:"", q2?q2:"", q3?q3:""); +} + +int fl_show_question(const char *q1,const char *q2,const char *q3) { + return fl_choice("%s\n%s\n%s", "No", "Yes", 0L, q1?q1:"", q2?q2:"", q3?q3:""); +} + +int fl_show_choice( + const char *q1, + const char *q2, + const char *q3, + int, // number of buttons, ignored + const char *b0, + const char *b1, + const char *b2) { + return fl_choice("%s\n%s\n%s", q1?q1:"", q2?q2:"", q3?q3:"", b0,b1,b2)+1; +} + +char *fl_show_simple_input(const char *str1, const char *defstr) { + const char *r = fl_input(str1, defstr); + return (char *)(r ? r : defstr); +} + +// +// End of "$Id: forms_compatability.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/forms_free.cxx b/third_party/windows/fltk-1.1.10/src/forms_free.cxx new file mode 100644 index 0000000..7b589e5 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/forms_free.cxx @@ -0,0 +1,81 @@ +// +// "$Id: forms_free.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Forms free widget routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Emulation of the Forms "free" widget. +// This emulation allows the free demo to run, and has allowed +// me to port several other programs, but it is in no way +// complete. + +#include +#include + +void Fl_Free::step(void *v) { + Fl_Free *f = (Fl_Free *)v; + int old_event = Fl::e_number; + f->handle(Fl::e_number == FL_STEP); + Fl::e_number = old_event; + Fl::add_timeout(.01,step,v); +} + +Fl_Free::Fl_Free(uchar t,int X, int Y, int W, int H,const char *l, + FL_HANDLEPTR hdl) : +Fl_Widget(X,Y,W,H,l) { + type(t); + hfunc = hdl; + if (t == FL_SLEEPING_FREE) set_flag(INACTIVE); + if (t == FL_CONTINUOUS_FREE || t == FL_ALL_FREE) + Fl::add_timeout(.01,step,this); +} + +Fl_Free::~Fl_Free() { + Fl::remove_timeout(step,this); + hfunc(this,FL_FREEMEM,0,0,0); +} + +void Fl_Free::draw() {hfunc(this,FL_DRAW,0,0,0);} + +int Fl_Free::handle(int e) { + char key = Fl::event_key(); + switch (e) { + case FL_FOCUS: + if (type()!=FL_INPUT_FREE && type()!=FL_ALL_FREE) return 0; + break; + case FL_PUSH: + case FL_DRAG: + case FL_RELEASE: + key = 4-Fl::event_button(); + break; + case FL_SHORTCUT: + return 0; + } + if (hfunc(this, e, float(Fl::event_x()), float(Fl::event_y()), key)) do_callback(); + return 1; +} + +// +// End of "$Id: forms_free.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/forms_fselect.cxx b/third_party/windows/fltk-1.1.10/src/forms_fselect.cxx new file mode 100644 index 0000000..5bad0f8 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/forms_fselect.cxx @@ -0,0 +1,67 @@ +// +// "$Id: forms_fselect.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Forms file selection routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Emulate the Forms file chooser using the fltk file chooser. + +#include +#include "flstring.h" + +static char fl_directory[1024]; +static const char *fl_pattern; // assummed passed value is static +static char fl_filename[1024]; + +char* fl_show_file_selector(const char *message,const char *dir, + const char *pat,const char *fname) { + if (dir && dir[0]) strlcpy(fl_directory,dir,sizeof(fl_directory)); + if (pat && pat[0]) fl_pattern = pat; + if (fname && fname[0]) strlcpy(fl_filename,fname,sizeof(fl_filename)); + char *p = fl_directory+strlen(fl_directory); + if (p > fl_directory && *(p-1)!='/' +#ifdef WIN32 + && *(p-1)!='\\' && *(p-1)!=':' +#endif + ) *p++ = '/'; + strlcpy(p,fl_filename,sizeof(fl_directory) - (p - fl_directory)); + const char *q = fl_file_chooser(message,fl_pattern,fl_directory); + if (!q) return 0; + strlcpy(fl_directory, q, sizeof(fl_directory)); + p = (char *)fl_filename_name(fl_directory); + strlcpy(fl_filename, p, sizeof(fl_filename)); + if (p > fl_directory+1) p--; + *p = 0; + return (char *)q; +} + +char* fl_get_directory() {return fl_directory;} + +char* fl_get_pattern() {return (char *)fl_pattern;} + +char* fl_get_filename() {return fl_filename;} + +// +// End of "$Id: forms_fselect.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/forms_pixmap.cxx b/third_party/windows/fltk-1.1.10/src/forms_pixmap.cxx new file mode 100644 index 0000000..6259a21 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/forms_pixmap.cxx @@ -0,0 +1,52 @@ +// +// "$Id: forms_pixmap.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// Forms pixmap drawing routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +#include + +Fl_FormsPixmap::Fl_FormsPixmap( + Fl_Boxtype t, int X, int Y, int W, int H, const char* l) +: Fl_Widget(X, Y, W, H, l) { + box(t); + b = 0; + color(FL_BLACK); + align(FL_ALIGN_BOTTOM); +} + +void Fl_FormsPixmap::set(char*const* bits) { + delete b; + b = new Fl_Pixmap(bits); +} + +void Fl_FormsPixmap::draw() { + draw_box(box(), selection_color()); + if (b) {fl_color(color()); b->draw(x(), y(), w(), h());} + draw_label(); +} + +// +// End of "$Id: forms_pixmap.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/forms_timer.cxx b/third_party/windows/fltk-1.1.10/src/forms_timer.cxx new file mode 100644 index 0000000..6dd41dc --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/forms_timer.cxx @@ -0,0 +1,170 @@ +// +// "$Id: forms_timer.cxx 6928 2009-11-07 21:11:16Z matt $" +// +// Forms timer object for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Emulate the Forms Timer object +// You don't want to use this if you just want a timeout, call +// Fl::add_timeout directly! + +#include +#include +#include +#ifdef WIN32 +# ifdef __MWERKS__ +# include +# else +# include +# include +# endif +#else +# include +# include +#endif +#include + +#define FL_TIMER_BLINKRATE 0.2 + +void fl_gettime(long* sec, long* usec) { +#ifdef WIN32 +# ifdef __MWERKS__ + time_t localTime = time(NULL); + struct tm *now = localtime(&localTime); + *sec = now->tm_sec + 60*now->tm_min + 3600*now->tm_hour + 24*3600*now->tm_yday; + *usec = 0; +# else + struct timeb tp; + ftime(&tp); + *sec = tp.time; + *usec = tp.millitm * 1000; +# endif +#else + struct timeval tp; + struct timezone tzp; + gettimeofday(&tp, &tzp); + *sec = tp.tv_sec; + *usec = tp.tv_usec; +#endif +} + +void Fl_Timer::draw() { + int tt; + Fl_Color col; + char str[32]; + if (!on || delay>0.0) + col = color(); + else if ((int) (delay / FL_TIMER_BLINKRATE) % 2) + col = color(); + else + col = selection_color(); + draw_box(box(), col); + if (type() == FL_VALUE_TIMER && delay>0.0) { + double d = direction_ ? total-delay : delay; + if (d < 60.0) + sprintf(str, "%.1f", d); + else { + tt = (int) ((d+0.05) / 60.0); + sprintf(str, "%d:%04.1f", tt, d - 60.0 * tt); + } + fl_font(labelfont(), labelsize()); + fl_color(labelcolor()); + fl_draw(str, x(), y(), w(), h(), FL_ALIGN_CENTER); + } else + draw_label(); +} + +void Fl_Timer::stepcb(void* v) { + ((Fl_Timer*)v)->step(); +} + +void Fl_Timer::step() { + if (!on) return; + double lastdelay = delay; + long sec, usec; fl_gettime(&sec, &usec); + delay -= (double) (sec - lastsec) + (double) (usec - lastusec) / 1000000.0; + lastsec = sec; lastusec = usec; + if (lastdelay > 0.0 && delay <= 0.0) { + if (type() == FL_HIDDEN_TIMER) { + on = 0; + delay = 0; + } else { + redraw(); + Fl::add_timeout(FL_TIMER_BLINKRATE, stepcb, this); + } + set_changed(); + do_callback(); + } else { + if (type() == FL_VALUE_TIMER) redraw(); + Fl::add_timeout(FL_TIMER_BLINKRATE, stepcb, this); + } +} + +int Fl_Timer::handle(int event) { + if (event == FL_RELEASE && delay <= 0) value(0.0); + return 0; +} + +Fl_Timer::~Fl_Timer() { + Fl::remove_timeout(stepcb, this); +} + +Fl_Timer::Fl_Timer(uchar t, int X, int Y, int W, int H, const char* l) +: Fl_Widget(X, Y, W, H, l) { + box(FL_DOWN_BOX); + selection_color(FL_RED); + delay = 0; + on = 0; + direction_ = 0; + lastsec = lastusec = total = 0; + type(t); + if (t == FL_HIDDEN_TIMER) clear_visible(); + if (t == FL_VALUE_TIMER) align(FL_ALIGN_LEFT); +} + +void Fl_Timer::value(double d) { + delay = total = d; + on = (d > 0.0); + fl_gettime(&(lastsec), &(lastusec)); + if (type() != FL_HIDDEN_TIMER) redraw(); + Fl::remove_timeout(stepcb, this); + if (on) Fl::add_timeout(FL_TIMER_BLINKRATE, stepcb, this); +} + +void Fl_Timer::suspended(char d) { + if (!d) { + if (on) return; + on = (delay > 0.0); + fl_gettime(&(lastsec), &(lastusec)); + if (on) Fl::add_timeout(FL_TIMER_BLINKRATE, stepcb, this); + } else { + if (!on) return; + on = 0; + Fl::remove_timeout(stepcb, this); + } +} + +// +// End of "$Id: forms_timer.cxx 6928 2009-11-07 21:11:16Z matt $". +// diff --git a/third_party/windows/fltk-1.1.10/src/freeglut_geometry.cxx b/third_party/windows/fltk-1.1.10/src/freeglut_geometry.cxx new file mode 100644 index 0000000..91bd9e3 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/freeglut_geometry.cxx @@ -0,0 +1,1110 @@ +/* + * freeglut_geometry.c + * + * Freeglut geometry rendering methods. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 3 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include + +/* + * TODO BEFORE THE STABLE RELEASE: + * + * Following functions have been contributed by Andreas Umbach. + * + * glutWireCube() -- looks OK + * glutSolidCube() -- OK + * + * Those functions have been implemented by John Fay. + * + * glutWireTorus() -- looks OK + * glutSolidTorus() -- looks OK + * glutWireDodecahedron() -- looks OK + * glutSolidDodecahedron() -- looks OK + * glutWireOctahedron() -- looks OK + * glutSolidOctahedron() -- looks OK + * glutWireTetrahedron() -- looks OK + * glutSolidTetrahedron() -- looks OK + * glutWireIcosahedron() -- looks OK + * glutSolidIcosahedron() -- looks OK + * + * The Following functions have been updated by Nigel Stewart, based + * on FreeGLUT 2.0.0 implementations: + * + * glutWireSphere() -- looks OK + * glutSolidSphere() -- looks OK + * glutWireCone() -- looks OK + * glutSolidCone() -- looks OK + */ + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Draws a wireframed cube. Code contributed by Andreas Umbach + */ +void glutWireCube( GLdouble dSize ) +{ + double size = dSize * 0.5; + +# define V(a,b,c) glVertex3d( a size, b size, c size ); +# define N(a,b,c) glNormal3d( a, b, c ); + + /* PWO: I dared to convert the code to use macros... */ + glBegin( GL_LINE_LOOP ); N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+); glEnd(); + glBegin( GL_LINE_LOOP ); N(-1.0, 0.0, 0.0); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0,-1.0, 0.0); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+); glEnd(); + glBegin( GL_LINE_LOOP ); N( 0.0, 0.0,-1.0); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-); glEnd(); + +# undef V +# undef N +} + +/* + * Draws a solid cube. Code contributed by Andreas Umbach + */ +void glutSolidCube( GLdouble dSize ) +{ + double size = dSize * 0.5; + +# define V(a,b,c) glVertex3d( a size, b size, c size ); +# define N(a,b,c) glNormal3d( a, b, c ); + + /* PWO: Again, I dared to convert the code to use macros... */ + glBegin( GL_QUADS ); + N( 1.0, 0.0, 0.0); V(+,-,+); V(+,-,-); V(+,+,-); V(+,+,+); + N( 0.0, 1.0, 0.0); V(+,+,+); V(+,+,-); V(-,+,-); V(-,+,+); + N( 0.0, 0.0, 1.0); V(+,+,+); V(-,+,+); V(-,-,+); V(+,-,+); + N(-1.0, 0.0, 0.0); V(-,-,+); V(-,+,+); V(-,+,-); V(-,-,-); + N( 0.0,-1.0, 0.0); V(-,-,+); V(-,-,-); V(+,-,-); V(+,-,+); + N( 0.0, 0.0,-1.0); V(-,-,-); V(-,+,-); V(+,+,-); V(+,-,-); + glEnd(); + +# undef V +# undef N +} + +/* + * Compute lookup table of cos and sin values forming a cirle + * + * Notes: + * It is the responsibility of the caller to free these tables + * The size of the table is (n+1) to form a connected loop + * The last entry is exactly the same as the first + * The sign of n can be flipped to get the reverse loop + */ + +static void fghCircleTable(double **sint,double **cost,const int n) +{ + int i; + + /* Table size, the sign of n flips the circle direction */ + + const int size = abs(n); + + /* Determine the angle between samples */ + + const double angle = 2*M_PI/(double)( ( n == 0 ) ? 1 : n ); + + /* Allocate memory for n samples, plus duplicate of first entry at the end */ + + *sint = (double *) calloc(sizeof(double), size+1); + *cost = (double *) calloc(sizeof(double), size+1); + + /* Bail out if memory allocation fails, fgError never returns */ + + if (!(*sint) || !(*cost)) + { + if (*sint) free(*sint); + if (*cost) free(*cost); + return; + } + + /* Compute cos and sin around the circle */ + + (*sint)[0] = 0.0; + (*cost)[0] = 1.0; + + for (i=1; i0)?1:0]; + r0 = 0.0; + r1 = sint2[(stacks>0)?1:0]; + + glBegin(GL_TRIANGLE_FAN); + + glNormal3d(0,0,1); + glVertex3d(0,0,radius); + + for (j=slices; j>=0; j--) + { + glNormal3d(cost1[j]*r1, sint1[j]*r1, z1 ); + glVertex3d(cost1[j]*r1*radius, sint1[j]*r1*radius, z1*radius); + } + + glEnd(); + + /* Cover each stack with a quad strip, except the top and bottom stacks */ + + for( i=1; i 0 ) ? stacks : 1 ); + const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 ); + + /* Scaling factors for vertex normals */ + + const double cosn = ( height / sqrt ( height * height + base * base )); + const double sinn = ( base / sqrt ( height * height + base * base )); + + /* Pre-computed circle */ + + double *sint,*cost; + + fghCircleTable(&sint,&cost,-slices); + + /* Cover the circular base with a triangle fan... */ + + z0 = 0.0; + z1 = zStep; + + r0 = base; + r1 = r0 - rStep; + + glBegin(GL_TRIANGLE_FAN); + + glNormal3d(0.0,0.0,-1.0); + glVertex3d(0.0,0.0, z0 ); + + for (j=0; j<=slices; j++) + glVertex3d(cost[j]*r0, sint[j]*r0, z0); + + glEnd(); + + /* Cover each stack with a quad strip, except the top stack */ + + for( i=0; i 0 ) ? stacks : 1 ); + const double rStep = base / ( ( stacks > 0 ) ? stacks : 1 ); + + /* Scaling factors for vertex normals */ + + const double cosn = ( height / sqrt ( height * height + base * base )); + const double sinn = ( base / sqrt ( height * height + base * base )); + + /* Pre-computed circle */ + + double *sint,*cost; + + fghCircleTable(&sint,&cost,-slices); + + /* Draw the stacks... */ + + for (i=0; i 0 ) ? stacks : 1 ); + + /* Pre-computed circle */ + + double *sint,*cost; + + fghCircleTable(&sint,&cost,-slices); + + /* Cover the base and top */ + + glBegin(GL_TRIANGLE_FAN); + glNormal3d(0.0, 0.0, -1.0 ); + glVertex3d(0.0, 0.0, 0.0 ); + for (j=0; j<=slices; j++) + glVertex3d(cost[j]*radius, sint[j]*radius, 0.0); + glEnd(); + + glBegin(GL_TRIANGLE_FAN); + glNormal3d(0.0, 0.0, 1.0 ); + glVertex3d(0.0, 0.0, height); + for (j=slices; j>=0; j--) + glVertex3d(cost[j]*radius, sint[j]*radius, height); + glEnd(); + + /* Do the stacks */ + + z0 = 0.0; + z1 = zStep; + + for (i=1; i<=stacks; i++) + { + if (i==stacks) + z1 = height; + + glBegin(GL_QUAD_STRIP); + for (j=0; j<=slices; j++ ) + { + glNormal3d(cost[j], sint[j], 0.0 ); + glVertex3d(cost[j]*radius, sint[j]*radius, z0 ); + glVertex3d(cost[j]*radius, sint[j]*radius, z1 ); + } + glEnd(); + + z0 = z1; z1 += zStep; + } + + /* Release sin and cos tables */ + + free(sint); + free(cost); +} + +/* + * Draws a wire cylinder + */ +void glutWireCylinder(GLdouble radius, GLdouble height, GLint slices, GLint stacks) +{ + int i,j; + + /* Step in z and radius as stacks are drawn. */ + + double z = 0.0; + const double zStep = height / ( ( stacks > 0 ) ? stacks : 1 ); + + /* Pre-computed circle */ + + double *sint,*cost; + + fghCircleTable(&sint,&cost,-slices); + + /* Draw the stacks... */ + + for (i=0; i<=stacks; i++) + { + if (i==stacks) + z = height; + + glBegin(GL_LINE_LOOP); + + for( j=0; j + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/* This file has been automatically generated by the genstroke utility. */ + +#include + +/* char: 0x20 */ + +static const Fl_Glut_StrokeStrip ch32st[] = +{ + { 0, 0 } +}; + +static const Fl_Glut_StrokeChar ch32 = {104.762f,0,ch32st}; + +/* char: 0x21 */ + +static const Fl_Glut_StrokeVertex ch33st0[] = +{ + {52.381f,100.0f}, + {52.381f,33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch33st1[] = +{ + {52.381f,9.5238f}, + {47.6191f,4.7619f}, + {52.381f,0.0f}, + {57.1429f,4.7619f}, + {52.381f,9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch33st[] = +{ + {2,ch33st0}, + {5,ch33st1} +}; + +static const Fl_Glut_StrokeChar ch33 = {104.762f,2,ch33st}; + +/* char: 0x22 */ + +static const Fl_Glut_StrokeVertex ch34st0[] = +{ + {33.3334f,100.0f}, + {33.3334f,66.6667f} +}; + +static const Fl_Glut_StrokeVertex ch34st1[] = +{ + {71.4286f,100.0f}, + {71.4286f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch34st[] = +{ + {2,ch34st0}, + {2,ch34st1} +}; + +static const Fl_Glut_StrokeChar ch34 = {104.762f,2,ch34st}; + +/* char: 0x23 */ + +static const Fl_Glut_StrokeVertex ch35st0[] = +{ + {54.7619f,119.048f}, + {21.4286f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch35st1[] = +{ + {83.3334f,119.048f}, + {50.0f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch35st2[] = +{ + {21.4286f,57.1429f}, + {88.0952f,57.1429f} +}; + +static const Fl_Glut_StrokeVertex ch35st3[] = +{ + {16.6667f,28.5714f}, + {83.3334f,28.5714f} +}; + +static const Fl_Glut_StrokeStrip ch35st[] = +{ + {2,ch35st0}, + {2,ch35st1}, + {2,ch35st2}, + {2,ch35st3} +}; + +static const Fl_Glut_StrokeChar ch35 = {104.762f,4,ch35st}; + +/* char: 0x24 */ + +static const Fl_Glut_StrokeVertex ch36st0[] = +{ + {42.8571f,119.048f}, + {42.8571f,-19.0476f} +}; + +static const Fl_Glut_StrokeVertex ch36st1[] = +{ + {61.9047f,119.048f}, + {61.9047f,-19.0476f} +}; + +static const Fl_Glut_StrokeVertex ch36st2[] = +{ + {85.7143f,85.7143f}, + {76.1905f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f}, + {28.5714f,95.2381f}, + {19.0476f,85.7143f}, + {19.0476f,76.1905f}, + {23.8095f,66.6667f}, + {28.5714f,61.9048f}, + {38.0952f,57.1429f}, + {66.6666f,47.619f}, + {76.1905f,42.8571f}, + {80.9524f,38.0952f}, + {85.7143f,28.5714f}, + {85.7143f,14.2857f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {19.0476f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch36st[] = +{ + {2,ch36st0}, + {2,ch36st1}, + {20,ch36st2} +}; + +static const Fl_Glut_StrokeChar ch36 = {104.762f,3,ch36st}; + +/* char: 0x25 */ + +static const Fl_Glut_StrokeVertex ch37st0[] = +{ + {95.2381f,100.0f}, + {9.5238f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch37st1[] = +{ + {33.3333f,100.0f}, + {42.8571f,90.4762f}, + {42.8571f,80.9524f}, + {38.0952f,71.4286f}, + {28.5714f,66.6667f}, + {19.0476f,66.6667f}, + {9.5238f,76.1905f}, + {9.5238f,85.7143f}, + {14.2857f,95.2381f}, + {23.8095f,100.0f}, + {33.3333f,100.0f}, + {42.8571f,95.2381f}, + {57.1428f,90.4762f}, + {71.4286f,90.4762f}, + {85.7143f,95.2381f}, + {95.2381f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch37st2[] = +{ + {76.1905f,33.3333f}, + {66.6667f,28.5714f}, + {61.9048f,19.0476f}, + {61.9048f,9.5238f}, + {71.4286f,0.0f}, + {80.9524f,0.0f}, + {90.4762f,4.7619f}, + {95.2381f,14.2857f}, + {95.2381f,23.8095f}, + {85.7143f,33.3333f}, + {76.1905f,33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch37st[] = +{ + {2,ch37st0}, + {16,ch37st1}, + {11,ch37st2} +}; + +static const Fl_Glut_StrokeChar ch37 = {104.762f,3,ch37st}; + +/* char: 0x26 */ + +static const Fl_Glut_StrokeVertex ch38st0[] = +{ + {100.0f,57.1429f}, + {100.0f,61.9048f}, + {95.2381f,66.6667f}, + {90.4762f,66.6667f}, + {85.7143f,61.9048f}, + {80.9524f,52.381f}, + {71.4286f,28.5714f}, + {61.9048f,14.2857f}, + {52.3809f,4.7619f}, + {42.8571f,0.0f}, + {23.8095f,0.0f}, + {14.2857f,4.7619f}, + {9.5238f,9.5238f}, + {4.7619f,19.0476f}, + {4.7619f,28.5714f}, + {9.5238f,38.0952f}, + {14.2857f,42.8571f}, + {47.619f,61.9048f}, + {52.3809f,66.6667f}, + {57.1429f,76.1905f}, + {57.1429f,85.7143f}, + {52.3809f,95.2381f}, + {42.8571f,100.0f}, + {33.3333f,95.2381f}, + {28.5714f,85.7143f}, + {28.5714f,76.1905f}, + {33.3333f,61.9048f}, + {42.8571f,47.619f}, + {66.6667f,14.2857f}, + {76.1905f,4.7619f}, + {85.7143f,0.0f}, + {95.2381f,0.0f}, + {100.0f,4.7619f}, + {100.0f,9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch38st[] = +{ + {34,ch38st0} +}; + +static const Fl_Glut_StrokeChar ch38 = {104.762f,1,ch38st}; + +/* char: 0x27 */ + +static const Fl_Glut_StrokeVertex ch39st0[] = +{ + {52.381f,100.0f}, + {52.381f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch39st[] = +{ + {2,ch39st0} +}; + +static const Fl_Glut_StrokeChar ch39 = {104.762f,1,ch39st}; + +/* char: 0x28 */ + +static const Fl_Glut_StrokeVertex ch40st0[] = +{ + {69.0476f,119.048f}, + {59.5238f,109.524f}, + {50.0f,95.2381f}, + {40.4762f,76.1905f}, + {35.7143f,52.381f}, + {35.7143f,33.3333f}, + {40.4762f,9.5238f}, + {50.0f,-9.5238f}, + {59.5238f,-23.8095f}, + {69.0476f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch40st[] = +{ + {10,ch40st0} +}; + +static const Fl_Glut_StrokeChar ch40 = {104.762f,1,ch40st}; + +/* char: 0x29 */ + +static const Fl_Glut_StrokeVertex ch41st0[] = +{ + {35.7143f,119.048f}, + {45.2381f,109.524f}, + {54.7619f,95.2381f}, + {64.2857f,76.1905f}, + {69.0476f,52.381f}, + {69.0476f,33.3333f}, + {64.2857f,9.5238f}, + {54.7619f,-9.5238f}, + {45.2381f,-23.8095f}, + {35.7143f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch41st[] = +{ + {10,ch41st0} +}; + +static const Fl_Glut_StrokeChar ch41 = {104.762f,1,ch41st}; + +/* char: 0x2a */ + +static const Fl_Glut_StrokeVertex ch42st0[] = +{ + {52.381f,71.4286f}, + {52.381f,14.2857f} +}; + +static const Fl_Glut_StrokeVertex ch42st1[] = +{ + {28.5715f,57.1429f}, + {76.1905f,28.5714f} +}; + +static const Fl_Glut_StrokeVertex ch42st2[] = +{ + {76.1905f,57.1429f}, + {28.5715f,28.5714f} +}; + +static const Fl_Glut_StrokeStrip ch42st[] = +{ + {2,ch42st0}, + {2,ch42st1}, + {2,ch42st2} +}; + +static const Fl_Glut_StrokeChar ch42 = {104.762f,3,ch42st}; + +/* char: 0x2b */ + +static const Fl_Glut_StrokeVertex ch43st0[] = +{ + {52.3809f,85.7143f}, + {52.3809f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch43st1[] = +{ + {9.5238f,42.8571f}, + {95.2381f,42.8571f} +}; + +static const Fl_Glut_StrokeStrip ch43st[] = +{ + {2,ch43st0}, + {2,ch43st1} +}; + +static const Fl_Glut_StrokeChar ch43 = {104.762f,2,ch43st}; + +/* char: 0x2c */ + +static const Fl_Glut_StrokeVertex ch44st0[] = +{ + {57.1429f,4.7619f}, + {52.381f,0.0f}, + {47.6191f,4.7619f}, + {52.381f,9.5238f}, + {57.1429f,4.7619f}, + {57.1429f,-4.7619f}, + {52.381f,-14.2857f}, + {47.6191f,-19.0476f} +}; + +static const Fl_Glut_StrokeStrip ch44st[] = +{ + {8,ch44st0} +}; + +static const Fl_Glut_StrokeChar ch44 = {104.762f,1,ch44st}; + +/* char: 0x2d */ + +static const Fl_Glut_StrokeVertex ch45st0[] = +{ + {9.5238f,42.8571f}, + {95.2381f,42.8571f} +}; + +static const Fl_Glut_StrokeStrip ch45st[] = +{ + {2,ch45st0} +}; + +static const Fl_Glut_StrokeChar ch45 = {104.762f,1,ch45st}; + +/* char: 0x2e */ + +static const Fl_Glut_StrokeVertex ch46st0[] = +{ + {52.381f,9.5238f}, + {47.6191f,4.7619f}, + {52.381f,0.0f}, + {57.1429f,4.7619f}, + {52.381f,9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch46st[] = +{ + {5,ch46st0} +}; + +static const Fl_Glut_StrokeChar ch46 = {104.762f,1,ch46st}; + +/* char: 0x2f */ + +static const Fl_Glut_StrokeVertex ch47st0[] = +{ + {19.0476f,-14.2857f}, + {85.7143f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch47st[] = +{ + {2,ch47st0} +}; + +static const Fl_Glut_StrokeChar ch47 = {104.762f,1,ch47st}; + +/* char: 0x30 */ + +static const Fl_Glut_StrokeVertex ch48st0[] = +{ + {47.619f,100.0f}, + {33.3333f,95.2381f}, + {23.8095f,80.9524f}, + {19.0476f,57.1429f}, + {19.0476f,42.8571f}, + {23.8095f,19.0476f}, + {33.3333f,4.7619f}, + {47.619f,0.0f}, + {57.1428f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,19.0476f}, + {85.7143f,42.8571f}, + {85.7143f,57.1429f}, + {80.9524f,80.9524f}, + {71.4286f,95.2381f}, + {57.1428f,100.0f}, + {47.619f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch48st[] = +{ + {17,ch48st0} +}; + +static const Fl_Glut_StrokeChar ch48 = {104.762f,1,ch48st}; + +/* char: 0x31 */ + +static const Fl_Glut_StrokeVertex ch49st0[] = +{ + {40.4762f,80.9524f}, + {50.0f,85.7143f}, + {64.2857f,100.0f}, + {64.2857f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch49st[] = +{ + {4,ch49st0} +}; + +static const Fl_Glut_StrokeChar ch49 = {104.762f,1,ch49st}; + +/* char: 0x32 */ + +static const Fl_Glut_StrokeVertex ch50st0[] = +{ + {23.8095f,76.1905f}, + {23.8095f,80.9524f}, + {28.5714f,90.4762f}, + {33.3333f,95.2381f}, + {42.8571f,100.0f}, + {61.9047f,100.0f}, + {71.4286f,95.2381f}, + {76.1905f,90.4762f}, + {80.9524f,80.9524f}, + {80.9524f,71.4286f}, + {76.1905f,61.9048f}, + {66.6666f,47.619f}, + {19.0476f,0.0f}, + {85.7143f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch50st[] = +{ + {14,ch50st0} +}; + +static const Fl_Glut_StrokeChar ch50 = {104.762f,1,ch50st}; + +/* char: 0x33 */ + +static const Fl_Glut_StrokeVertex ch51st0[] = +{ + {28.5714f,100.0f}, + {80.9524f,100.0f}, + {52.3809f,61.9048f}, + {66.6666f,61.9048f}, + {76.1905f,57.1429f}, + {80.9524f,52.381f}, + {85.7143f,38.0952f}, + {85.7143f,28.5714f}, + {80.9524f,14.2857f}, + {71.4286f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {23.8095f,9.5238f}, + {19.0476f,19.0476f} +}; + +static const Fl_Glut_StrokeStrip ch51st[] = +{ + {15,ch51st0} +}; + +static const Fl_Glut_StrokeChar ch51 = {104.762f,1,ch51st}; + +/* char: 0x34 */ + +static const Fl_Glut_StrokeVertex ch52st0[] = +{ + {64.2857f,100.0f}, + {16.6667f,33.3333f}, + {88.0952f,33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch52st1[] = +{ + {64.2857f,100.0f}, + {64.2857f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch52st[] = +{ + {3,ch52st0}, + {2,ch52st1} +}; + +static const Fl_Glut_StrokeChar ch52 = {104.762f,2,ch52st}; + +/* char: 0x35 */ + +static const Fl_Glut_StrokeVertex ch53st0[] = +{ + {76.1905f,100.0f}, + {28.5714f,100.0f}, + {23.8095f,57.1429f}, + {28.5714f,61.9048f}, + {42.8571f,66.6667f}, + {57.1428f,66.6667f}, + {71.4286f,61.9048f}, + {80.9524f,52.381f}, + {85.7143f,38.0952f}, + {85.7143f,28.5714f}, + {80.9524f,14.2857f}, + {71.4286f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {23.8095f,9.5238f}, + {19.0476f,19.0476f} +}; + +static const Fl_Glut_StrokeStrip ch53st[] = +{ + {17,ch53st0} +}; + +static const Fl_Glut_StrokeChar ch53 = {104.762f,1,ch53st}; + +/* char: 0x36 */ + +static const Fl_Glut_StrokeVertex ch54st0[] = +{ + {78.5714f,85.7143f}, + {73.8096f,95.2381f}, + {59.5238f,100.0f}, + {50.0f,100.0f}, + {35.7143f,95.2381f}, + {26.1905f,80.9524f}, + {21.4286f,57.1429f}, + {21.4286f,33.3333f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {50.0f,0.0f}, + {54.7619f,0.0f}, + {69.0476f,4.7619f}, + {78.5714f,14.2857f}, + {83.3334f,28.5714f}, + {83.3334f,33.3333f}, + {78.5714f,47.619f}, + {69.0476f,57.1429f}, + {54.7619f,61.9048f}, + {50.0f,61.9048f}, + {35.7143f,57.1429f}, + {26.1905f,47.619f}, + {21.4286f,33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch54st[] = +{ + {23,ch54st0} +}; + +static const Fl_Glut_StrokeChar ch54 = {104.762f,1,ch54st}; + +/* char: 0x37 */ + +static const Fl_Glut_StrokeVertex ch55st0[] = +{ + {85.7143f,100.0f}, + {38.0952f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch55st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch55st[] = +{ + {2,ch55st0}, + {2,ch55st1} +}; + +static const Fl_Glut_StrokeChar ch55 = {104.762f,2,ch55st}; + +/* char: 0x38 */ + +static const Fl_Glut_StrokeVertex ch56st0[] = +{ + {42.8571f,100.0f}, + {28.5714f,95.2381f}, + {23.8095f,85.7143f}, + {23.8095f,76.1905f}, + {28.5714f,66.6667f}, + {38.0952f,61.9048f}, + {57.1428f,57.1429f}, + {71.4286f,52.381f}, + {80.9524f,42.8571f}, + {85.7143f,33.3333f}, + {85.7143f,19.0476f}, + {80.9524f,9.5238f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {23.8095f,9.5238f}, + {19.0476f,19.0476f}, + {19.0476f,33.3333f}, + {23.8095f,42.8571f}, + {33.3333f,52.381f}, + {47.619f,57.1429f}, + {66.6666f,61.9048f}, + {76.1905f,66.6667f}, + {80.9524f,76.1905f}, + {80.9524f,85.7143f}, + {76.1905f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch56st[] = +{ + {29,ch56st0} +}; + +static const Fl_Glut_StrokeChar ch56 = {104.762f,1,ch56st}; + +/* char: 0x39 */ + +static const Fl_Glut_StrokeVertex ch57st0[] = +{ + {83.3334f,66.6667f}, + {78.5714f,52.381f}, + {69.0476f,42.8571f}, + {54.7619f,38.0952f}, + {50.0f,38.0952f}, + {35.7143f,42.8571f}, + {26.1905f,52.381f}, + {21.4286f,66.6667f}, + {21.4286f,71.4286f}, + {26.1905f,85.7143f}, + {35.7143f,95.2381f}, + {50.0f,100.0f}, + {54.7619f,100.0f}, + {69.0476f,95.2381f}, + {78.5714f,85.7143f}, + {83.3334f,66.6667f}, + {83.3334f,42.8571f}, + {78.5714f,19.0476f}, + {69.0476f,4.7619f}, + {54.7619f,0.0f}, + {45.2381f,0.0f}, + {30.9524f,4.7619f}, + {26.1905f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch57st[] = +{ + {23,ch57st0} +}; + +static const Fl_Glut_StrokeChar ch57 = {104.762f,1,ch57st}; + +/* char: 0x3a */ + +static const Fl_Glut_StrokeVertex ch58st0[] = +{ + {52.381f,66.6667f}, + {47.6191f,61.9048f}, + {52.381f,57.1429f}, + {57.1429f,61.9048f}, + {52.381f,66.6667f} +}; + +static const Fl_Glut_StrokeVertex ch58st1[] = +{ + {52.381f,9.5238f}, + {47.6191f,4.7619f}, + {52.381f,0.0f}, + {57.1429f,4.7619f}, + {52.381f,9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch58st[] = +{ + {5,ch58st0}, + {5,ch58st1} +}; + +static const Fl_Glut_StrokeChar ch58 = {104.762f,2,ch58st}; + +/* char: 0x3b */ + +static const Fl_Glut_StrokeVertex ch59st0[] = +{ + {52.381f,66.6667f}, + {47.6191f,61.9048f}, + {52.381f,57.1429f}, + {57.1429f,61.9048f}, + {52.381f,66.6667f} +}; + +static const Fl_Glut_StrokeVertex ch59st1[] = +{ + {57.1429f,4.7619f}, + {52.381f,0.0f}, + {47.6191f,4.7619f}, + {52.381f,9.5238f}, + {57.1429f,4.7619f}, + {57.1429f,-4.7619f}, + {52.381f,-14.2857f}, + {47.6191f,-19.0476f} +}; + +static const Fl_Glut_StrokeStrip ch59st[] = +{ + {5,ch59st0}, + {8,ch59st1} +}; + +static const Fl_Glut_StrokeChar ch59 = {104.762f,2,ch59st}; + +/* char: 0x3c */ + +static const Fl_Glut_StrokeVertex ch60st0[] = +{ + {90.4762f,85.7143f}, + {14.2857f,42.8571f}, + {90.4762f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch60st[] = +{ + {3,ch60st0} +}; + +static const Fl_Glut_StrokeChar ch60 = {104.762f,1,ch60st}; + +/* char: 0x3d */ + +static const Fl_Glut_StrokeVertex ch61st0[] = +{ + {9.5238f,57.1429f}, + {95.2381f,57.1429f} +}; + +static const Fl_Glut_StrokeVertex ch61st1[] = +{ + {9.5238f,28.5714f}, + {95.2381f,28.5714f} +}; + +static const Fl_Glut_StrokeStrip ch61st[] = +{ + {2,ch61st0}, + {2,ch61st1} +}; + +static const Fl_Glut_StrokeChar ch61 = {104.762f,2,ch61st}; + +/* char: 0x3e */ + +static const Fl_Glut_StrokeVertex ch62st0[] = +{ + {14.2857f,85.7143f}, + {90.4762f,42.8571f}, + {14.2857f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch62st[] = +{ + {3,ch62st0} +}; + +static const Fl_Glut_StrokeChar ch62 = {104.762f,1,ch62st}; + +/* char: 0x3f */ + +static const Fl_Glut_StrokeVertex ch63st0[] = +{ + {23.8095f,76.1905f}, + {23.8095f,80.9524f}, + {28.5714f,90.4762f}, + {33.3333f,95.2381f}, + {42.8571f,100.0f}, + {61.9047f,100.0f}, + {71.4285f,95.2381f}, + {76.1905f,90.4762f}, + {80.9524f,80.9524f}, + {80.9524f,71.4286f}, + {76.1905f,61.9048f}, + {71.4285f,57.1429f}, + {52.3809f,47.619f}, + {52.3809f,33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch63st1[] = +{ + {52.3809f,9.5238f}, + {47.619f,4.7619f}, + {52.3809f,0.0f}, + {57.1428f,4.7619f}, + {52.3809f,9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch63st[] = +{ + {14,ch63st0}, + {5,ch63st1} +}; + +static const Fl_Glut_StrokeChar ch63 = {104.762f,2,ch63st}; + +/* char: 0x40 */ + +static const Fl_Glut_StrokeVertex ch64st0[] = +{ + {64.2857f,52.381f}, + {54.7619f,57.1429f}, + {45.2381f,57.1429f}, + {40.4762f,47.619f}, + {40.4762f,42.8571f}, + {45.2381f,33.3333f}, + {54.7619f,33.3333f}, + {64.2857f,38.0952f} +}; + +static const Fl_Glut_StrokeVertex ch64st1[] = +{ + {64.2857f,57.1429f}, + {64.2857f,38.0952f}, + {69.0476f,33.3333f}, + {78.5714f,33.3333f}, + {83.3334f,42.8571f}, + {83.3334f,47.619f}, + {78.5714f,61.9048f}, + {69.0476f,71.4286f}, + {54.7619f,76.1905f}, + {50.0f,76.1905f}, + {35.7143f,71.4286f}, + {26.1905f,61.9048f}, + {21.4286f,47.619f}, + {21.4286f,42.8571f}, + {26.1905f,28.5714f}, + {35.7143f,19.0476f}, + {50.0f,14.2857f}, + {54.7619f,14.2857f}, + {69.0476f,19.0476f} +}; + +static const Fl_Glut_StrokeStrip ch64st[] = +{ + {8,ch64st0}, + {19,ch64st1} +}; + +static const Fl_Glut_StrokeChar ch64 = {104.762f,2,ch64st}; + +/* char: 0x41 */ + +static const Fl_Glut_StrokeVertex ch65st0[] = +{ + {52.3809f,100.0f}, + {14.2857f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch65st1[] = +{ + {52.3809f,100.0f}, + {90.4762f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch65st2[] = +{ + {28.5714f,33.3333f}, + {76.1905f,33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch65st[] = +{ + {2,ch65st0}, + {2,ch65st1}, + {2,ch65st2} +}; + +static const Fl_Glut_StrokeChar ch65 = {104.762f,3,ch65st}; + +/* char: 0x42 */ + +static const Fl_Glut_StrokeVertex ch66st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch66st1[] = +{ + {19.0476f,100.0f}, + {61.9047f,100.0f}, + {76.1905f,95.2381f}, + {80.9524f,90.4762f}, + {85.7143f,80.9524f}, + {85.7143f,71.4286f}, + {80.9524f,61.9048f}, + {76.1905f,57.1429f}, + {61.9047f,52.381f} +}; + +static const Fl_Glut_StrokeVertex ch66st2[] = +{ + {19.0476f,52.381f}, + {61.9047f,52.381f}, + {76.1905f,47.619f}, + {80.9524f,42.8571f}, + {85.7143f,33.3333f}, + {85.7143f,19.0476f}, + {80.9524f,9.5238f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch66st[] = +{ + {2,ch66st0}, + {9,ch66st1}, + {10,ch66st2} +}; + +static const Fl_Glut_StrokeChar ch66 = {104.762f,3,ch66st}; + +/* char: 0x43 */ + +static const Fl_Glut_StrokeVertex ch67st0[] = +{ + {88.0952f,76.1905f}, + {83.3334f,85.7143f}, + {73.8096f,95.2381f}, + {64.2857f,100.0f}, + {45.2381f,100.0f}, + {35.7143f,95.2381f}, + {26.1905f,85.7143f}, + {21.4286f,76.1905f}, + {16.6667f,61.9048f}, + {16.6667f,38.0952f}, + {21.4286f,23.8095f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {45.2381f,0.0f}, + {64.2857f,0.0f}, + {73.8096f,4.7619f}, + {83.3334f,14.2857f}, + {88.0952f,23.8095f} +}; + +static const Fl_Glut_StrokeStrip ch67st[] = +{ + {18,ch67st0} +}; + +static const Fl_Glut_StrokeChar ch67 = {104.762f,1,ch67st}; + +/* char: 0x44 */ + +static const Fl_Glut_StrokeVertex ch68st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch68st1[] = +{ + {19.0476f,100.0f}, + {52.3809f,100.0f}, + {66.6666f,95.2381f}, + {76.1905f,85.7143f}, + {80.9524f,76.1905f}, + {85.7143f,61.9048f}, + {85.7143f,38.0952f}, + {80.9524f,23.8095f}, + {76.1905f,14.2857f}, + {66.6666f,4.7619f}, + {52.3809f,0.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch68st[] = +{ + {2,ch68st0}, + {12,ch68st1} +}; + +static const Fl_Glut_StrokeChar ch68 = {104.762f,2,ch68st}; + +/* char: 0x45 */ + +static const Fl_Glut_StrokeVertex ch69st0[] = +{ + {21.4286f,100.0f}, + {21.4286f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch69st1[] = +{ + {21.4286f,100.0f}, + {83.3334f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch69st2[] = +{ + {21.4286f,52.381f}, + {59.5238f,52.381f} +}; + +static const Fl_Glut_StrokeVertex ch69st3[] = +{ + {21.4286f,0.0f}, + {83.3334f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch69st[] = +{ + {2,ch69st0}, + {2,ch69st1}, + {2,ch69st2}, + {2,ch69st3} +}; + +static const Fl_Glut_StrokeChar ch69 = {104.762f,4,ch69st}; + +/* char: 0x46 */ + +static const Fl_Glut_StrokeVertex ch70st0[] = +{ + {21.4286f,100.0f}, + {21.4286f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch70st1[] = +{ + {21.4286f,100.0f}, + {83.3334f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch70st2[] = +{ + {21.4286f,52.381f}, + {59.5238f,52.381f} +}; + +static const Fl_Glut_StrokeStrip ch70st[] = +{ + {2,ch70st0}, + {2,ch70st1}, + {2,ch70st2} +}; + +static const Fl_Glut_StrokeChar ch70 = {104.762f,3,ch70st}; + +/* char: 0x47 */ + +static const Fl_Glut_StrokeVertex ch71st0[] = +{ + {88.0952f,76.1905f}, + {83.3334f,85.7143f}, + {73.8096f,95.2381f}, + {64.2857f,100.0f}, + {45.2381f,100.0f}, + {35.7143f,95.2381f}, + {26.1905f,85.7143f}, + {21.4286f,76.1905f}, + {16.6667f,61.9048f}, + {16.6667f,38.0952f}, + {21.4286f,23.8095f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {45.2381f,0.0f}, + {64.2857f,0.0f}, + {73.8096f,4.7619f}, + {83.3334f,14.2857f}, + {88.0952f,23.8095f}, + {88.0952f,38.0952f} +}; + +static const Fl_Glut_StrokeVertex ch71st1[] = +{ + {64.2857f,38.0952f}, + {88.0952f,38.0952f} +}; + +static const Fl_Glut_StrokeStrip ch71st[] = +{ + {19,ch71st0}, + {2,ch71st1} +}; + +static const Fl_Glut_StrokeChar ch71 = {104.762f,2,ch71st}; + +/* char: 0x48 */ + +static const Fl_Glut_StrokeVertex ch72st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch72st1[] = +{ + {85.7143f,100.0f}, + {85.7143f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch72st2[] = +{ + {19.0476f,52.381f}, + {85.7143f,52.381f} +}; + +static const Fl_Glut_StrokeStrip ch72st[] = +{ + {2,ch72st0}, + {2,ch72st1}, + {2,ch72st2} +}; + +static const Fl_Glut_StrokeChar ch72 = {104.762f,3,ch72st}; + +/* char: 0x49 */ + +static const Fl_Glut_StrokeVertex ch73st0[] = +{ + {52.381f,100.0f}, + {52.381f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch73st[] = +{ + {2,ch73st0} +}; + +static const Fl_Glut_StrokeChar ch73 = {104.762f,1,ch73st}; + +/* char: 0x4a */ + +static const Fl_Glut_StrokeVertex ch74st0[] = +{ + {76.1905f,100.0f}, + {76.1905f,23.8095f}, + {71.4286f,9.5238f}, + {66.6667f,4.7619f}, + {57.1429f,0.0f}, + {47.6191f,0.0f}, + {38.0953f,4.7619f}, + {33.3334f,9.5238f}, + {28.5715f,23.8095f}, + {28.5715f,33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch74st[] = +{ + {10,ch74st0} +}; + +static const Fl_Glut_StrokeChar ch74 = {104.762f,1,ch74st}; + +/* char: 0x4b */ + +static const Fl_Glut_StrokeVertex ch75st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch75st1[] = +{ + {85.7143f,100.0f}, + {19.0476f,33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch75st2[] = +{ + {42.8571f,57.1429f}, + {85.7143f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch75st[] = +{ + {2,ch75st0}, + {2,ch75st1}, + {2,ch75st2} +}; + +static const Fl_Glut_StrokeChar ch75 = {104.762f,3,ch75st}; + +/* char: 0x4c */ + +static const Fl_Glut_StrokeVertex ch76st0[] = +{ + {23.8095f,100.0f}, + {23.8095f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch76st1[] = +{ + {23.8095f,0.0f}, + {80.9524f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch76st[] = +{ + {2,ch76st0}, + {2,ch76st1} +}; + +static const Fl_Glut_StrokeChar ch76 = {104.762f,2,ch76st}; + +/* char: 0x4d */ + +static const Fl_Glut_StrokeVertex ch77st0[] = +{ + {14.2857f,100.0f}, + {14.2857f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch77st1[] = +{ + {14.2857f,100.0f}, + {52.3809f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch77st2[] = +{ + {90.4762f,100.0f}, + {52.3809f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch77st3[] = +{ + {90.4762f,100.0f}, + {90.4762f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch77st[] = +{ + {2,ch77st0}, + {2,ch77st1}, + {2,ch77st2}, + {2,ch77st3} +}; + +static const Fl_Glut_StrokeChar ch77 = {104.762f,4,ch77st}; + +/* char: 0x4e */ + +static const Fl_Glut_StrokeVertex ch78st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch78st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch78st2[] = +{ + {85.7143f,100.0f}, + {85.7143f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch78st[] = +{ + {2,ch78st0}, + {2,ch78st1}, + {2,ch78st2} +}; + +static const Fl_Glut_StrokeChar ch78 = {104.762f,3,ch78st}; + +/* char: 0x4f */ + +static const Fl_Glut_StrokeVertex ch79st0[] = +{ + {42.8571f,100.0f}, + {33.3333f,95.2381f}, + {23.8095f,85.7143f}, + {19.0476f,76.1905f}, + {14.2857f,61.9048f}, + {14.2857f,38.0952f}, + {19.0476f,23.8095f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {42.8571f,0.0f}, + {61.9047f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,23.8095f}, + {90.4762f,38.0952f}, + {90.4762f,61.9048f}, + {85.7143f,76.1905f}, + {80.9524f,85.7143f}, + {71.4286f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch79st[] = +{ + {21,ch79st0} +}; + +static const Fl_Glut_StrokeChar ch79 = {104.762f,1,ch79st}; + +/* char: 0x50 */ + +static const Fl_Glut_StrokeVertex ch80st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch80st1[] = +{ + {19.0476f,100.0f}, + {61.9047f,100.0f}, + {76.1905f,95.2381f}, + {80.9524f,90.4762f}, + {85.7143f,80.9524f}, + {85.7143f,66.6667f}, + {80.9524f,57.1429f}, + {76.1905f,52.381f}, + {61.9047f,47.619f}, + {19.0476f,47.619f} +}; + +static const Fl_Glut_StrokeStrip ch80st[] = +{ + {2,ch80st0}, + {10,ch80st1} +}; + +static const Fl_Glut_StrokeChar ch80 = {104.762f,2,ch80st}; + +/* char: 0x51 */ + +static const Fl_Glut_StrokeVertex ch81st0[] = +{ + {42.8571f,100.0f}, + {33.3333f,95.2381f}, + {23.8095f,85.7143f}, + {19.0476f,76.1905f}, + {14.2857f,61.9048f}, + {14.2857f,38.0952f}, + {19.0476f,23.8095f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {42.8571f,0.0f}, + {61.9047f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,23.8095f}, + {90.4762f,38.0952f}, + {90.4762f,61.9048f}, + {85.7143f,76.1905f}, + {80.9524f,85.7143f}, + {71.4286f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch81st1[] = +{ + {57.1428f,19.0476f}, + {85.7143f,-9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch81st[] = +{ + {21,ch81st0}, + {2,ch81st1} +}; + +static const Fl_Glut_StrokeChar ch81 = {104.762f,2,ch81st}; + +/* char: 0x52 */ + +static const Fl_Glut_StrokeVertex ch82st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch82st1[] = +{ + {19.0476f,100.0f}, + {61.9047f,100.0f}, + {76.1905f,95.2381f}, + {80.9524f,90.4762f}, + {85.7143f,80.9524f}, + {85.7143f,71.4286f}, + {80.9524f,61.9048f}, + {76.1905f,57.1429f}, + {61.9047f,52.381f}, + {19.0476f,52.381f} +}; + +static const Fl_Glut_StrokeVertex ch82st2[] = +{ + {52.3809f,52.381f}, + {85.7143f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch82st[] = +{ + {2,ch82st0}, + {10,ch82st1}, + {2,ch82st2} +}; + +static const Fl_Glut_StrokeChar ch82 = {104.762f,3,ch82st}; + +/* char: 0x53 */ + +static const Fl_Glut_StrokeVertex ch83st0[] = +{ + {85.7143f,85.7143f}, + {76.1905f,95.2381f}, + {61.9047f,100.0f}, + {42.8571f,100.0f}, + {28.5714f,95.2381f}, + {19.0476f,85.7143f}, + {19.0476f,76.1905f}, + {23.8095f,66.6667f}, + {28.5714f,61.9048f}, + {38.0952f,57.1429f}, + {66.6666f,47.619f}, + {76.1905f,42.8571f}, + {80.9524f,38.0952f}, + {85.7143f,28.5714f}, + {85.7143f,14.2857f}, + {76.1905f,4.7619f}, + {61.9047f,0.0f}, + {42.8571f,0.0f}, + {28.5714f,4.7619f}, + {19.0476f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch83st[] = +{ + {20,ch83st0} +}; + +static const Fl_Glut_StrokeChar ch83 = {104.762f,1,ch83st}; + +/* char: 0x54 */ + +static const Fl_Glut_StrokeVertex ch84st0[] = +{ + {52.3809f,100.0f}, + {52.3809f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch84st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch84st[] = +{ + {2,ch84st0}, + {2,ch84st1} +}; + +static const Fl_Glut_StrokeChar ch84 = {104.762f,2,ch84st}; + +/* char: 0x55 */ + +static const Fl_Glut_StrokeVertex ch85st0[] = +{ + {19.0476f,100.0f}, + {19.0476f,28.5714f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {47.619f,0.0f}, + {57.1428f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,28.5714f}, + {85.7143f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch85st[] = +{ + {10,ch85st0} +}; + +static const Fl_Glut_StrokeChar ch85 = {104.762f,1,ch85st}; + +/* char: 0x56 */ + +static const Fl_Glut_StrokeVertex ch86st0[] = +{ + {14.2857f,100.0f}, + {52.3809f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch86st1[] = +{ + {90.4762f,100.0f}, + {52.3809f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch86st[] = +{ + {2,ch86st0}, + {2,ch86st1} +}; + +static const Fl_Glut_StrokeChar ch86 = {104.762f,2,ch86st}; + +/* char: 0x57 */ + +static const Fl_Glut_StrokeVertex ch87st0[] = +{ + {4.7619f,100.0f}, + {28.5714f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch87st1[] = +{ + {52.3809f,100.0f}, + {28.5714f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch87st2[] = +{ + {52.3809f,100.0f}, + {76.1905f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch87st3[] = +{ + {100.0f,100.0f}, + {76.1905f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch87st[] = +{ + {2,ch87st0}, + {2,ch87st1}, + {2,ch87st2}, + {2,ch87st3} +}; + +static const Fl_Glut_StrokeChar ch87 = {104.762f,4,ch87st}; + +/* char: 0x58 */ + +static const Fl_Glut_StrokeVertex ch88st0[] = +{ + {19.0476f,100.0f}, + {85.7143f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch88st1[] = +{ + {85.7143f,100.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch88st[] = +{ + {2,ch88st0}, + {2,ch88st1} +}; + +static const Fl_Glut_StrokeChar ch88 = {104.762f,2,ch88st}; + +/* char: 0x59 */ + +static const Fl_Glut_StrokeVertex ch89st0[] = +{ + {14.2857f,100.0f}, + {52.3809f,52.381f}, + {52.3809f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch89st1[] = +{ + {90.4762f,100.0f}, + {52.3809f,52.381f} +}; + +static const Fl_Glut_StrokeStrip ch89st[] = +{ + {3,ch89st0}, + {2,ch89st1} +}; + +static const Fl_Glut_StrokeChar ch89 = {104.762f,2,ch89st}; + +/* char: 0x5a */ + +static const Fl_Glut_StrokeVertex ch90st0[] = +{ + {85.7143f,100.0f}, + {19.0476f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch90st1[] = +{ + {19.0476f,100.0f}, + {85.7143f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch90st2[] = +{ + {19.0476f,0.0f}, + {85.7143f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch90st[] = +{ + {2,ch90st0}, + {2,ch90st1}, + {2,ch90st2} +}; + +static const Fl_Glut_StrokeChar ch90 = {104.762f,3,ch90st}; + +/* char: 0x5b */ + +static const Fl_Glut_StrokeVertex ch91st0[] = +{ + {35.7143f,119.048f}, + {35.7143f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch91st1[] = +{ + {40.4762f,119.048f}, + {40.4762f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch91st2[] = +{ + {35.7143f,119.048f}, + {69.0476f,119.048f} +}; + +static const Fl_Glut_StrokeVertex ch91st3[] = +{ + {35.7143f,-33.3333f}, + {69.0476f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch91st[] = +{ + {2,ch91st0}, + {2,ch91st1}, + {2,ch91st2}, + {2,ch91st3} +}; + +static const Fl_Glut_StrokeChar ch91 = {104.762f,4,ch91st}; + +/* char: 0x5c */ + +static const Fl_Glut_StrokeVertex ch92st0[] = +{ + {19.0476f,100.0f}, + {85.7143f,-14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch92st[] = +{ + {2,ch92st0} +}; + +static const Fl_Glut_StrokeChar ch92 = {104.762f,1,ch92st}; + +/* char: 0x5d */ + +static const Fl_Glut_StrokeVertex ch93st0[] = +{ + {64.2857f,119.048f}, + {64.2857f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch93st1[] = +{ + {69.0476f,119.048f}, + {69.0476f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch93st2[] = +{ + {35.7143f,119.048f}, + {69.0476f,119.048f} +}; + +static const Fl_Glut_StrokeVertex ch93st3[] = +{ + {35.7143f,-33.3333f}, + {69.0476f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch93st[] = +{ + {2,ch93st0}, + {2,ch93st1}, + {2,ch93st2}, + {2,ch93st3} +}; + +static const Fl_Glut_StrokeChar ch93 = {104.762f,4,ch93st}; + +/* char: 0x5e */ + +static const Fl_Glut_StrokeVertex ch94st0[] = +{ + {52.3809f,109.524f}, + {14.2857f,42.8571f} +}; + +static const Fl_Glut_StrokeVertex ch94st1[] = +{ + {52.3809f,109.524f}, + {90.4762f,42.8571f} +}; + +static const Fl_Glut_StrokeStrip ch94st[] = +{ + {2,ch94st0}, + {2,ch94st1} +}; + +static const Fl_Glut_StrokeChar ch94 = {104.762f,2,ch94st}; + +/* char: 0x5f */ + +static const Fl_Glut_StrokeVertex ch95st0[] = +{ + {0,-33.3333f}, + {104.762f,-33.3333f}, + {104.762f,-28.5714f}, + {0,-28.5714f}, + {0,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch95st[] = +{ + {5,ch95st0} +}; + +static const Fl_Glut_StrokeChar ch95 = {104.762f,1,ch95st}; + +/* char: 0x60 */ + +static const Fl_Glut_StrokeVertex ch96st0[] = +{ + {42.8572f,100.0f}, + {66.6667f,71.4286f} +}; + +static const Fl_Glut_StrokeVertex ch96st1[] = +{ + {42.8572f,100.0f}, + {38.0953f,95.2381f}, + {66.6667f,71.4286f} +}; + +static const Fl_Glut_StrokeStrip ch96st[] = +{ + {2,ch96st0}, + {3,ch96st1} +}; + +static const Fl_Glut_StrokeChar ch96 = {104.762f,2,ch96st}; + +/* char: 0x61 */ + +static const Fl_Glut_StrokeVertex ch97st0[] = +{ + {80.9524f,66.6667f}, + {80.9524f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch97st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch97st[] = +{ + {2,ch97st0}, + {14,ch97st1} +}; + +static const Fl_Glut_StrokeChar ch97 = {104.762f,2,ch97st}; + +/* char: 0x62 */ + +static const Fl_Glut_StrokeVertex ch98st0[] = +{ + {23.8095f,100.0f}, + {23.8095f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch98st1[] = +{ + {23.8095f,52.381f}, + {33.3333f,61.9048f}, + {42.8571f,66.6667f}, + {57.1428f,66.6667f}, + {66.6666f,61.9048f}, + {76.1905f,52.381f}, + {80.9524f,38.0952f}, + {80.9524f,28.5714f}, + {76.1905f,14.2857f}, + {66.6666f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {33.3333f,4.7619f}, + {23.8095f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch98st[] = +{ + {2,ch98st0}, + {14,ch98st1} +}; + +static const Fl_Glut_StrokeChar ch98 = {104.762f,2,ch98st}; + +/* char: 0x63 */ + +static const Fl_Glut_StrokeVertex ch99st0[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch99st[] = +{ + {14,ch99st0} +}; + +static const Fl_Glut_StrokeChar ch99 = {104.762f,1,ch99st}; + +/* char: 0x64 */ + +static const Fl_Glut_StrokeVertex ch100st0[] = +{ + {80.9524f,100.0f}, + {80.9524f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch100st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch100st[] = +{ + {2,ch100st0}, + {14,ch100st1} +}; + +static const Fl_Glut_StrokeChar ch100 = {104.762f,2,ch100st}; + +/* char: 0x65 */ + +static const Fl_Glut_StrokeVertex ch101st0[] = +{ + {23.8095f,38.0952f}, + {80.9524f,38.0952f}, + {80.9524f,47.619f}, + {76.1905f,57.1429f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch101st[] = +{ + {17,ch101st0} +}; + +static const Fl_Glut_StrokeChar ch101 = {104.762f,1,ch101st}; + +/* char: 0x66 */ + +static const Fl_Glut_StrokeVertex ch102st0[] = +{ + {71.4286f,100.0f}, + {61.9048f,100.0f}, + {52.381f,95.2381f}, + {47.6191f,80.9524f}, + {47.6191f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch102st1[] = +{ + {33.3334f,66.6667f}, + {66.6667f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch102st[] = +{ + {5,ch102st0}, + {2,ch102st1} +}; + +static const Fl_Glut_StrokeChar ch102 = {104.762f,2,ch102st}; + +/* char: 0x67 */ + +static const Fl_Glut_StrokeVertex ch103st0[] = +{ + {80.9524f,66.6667f}, + {80.9524f,-9.5238f}, + {76.1905f,-23.8095f}, + {71.4285f,-28.5714f}, + {61.9047f,-33.3333f}, + {47.619f,-33.3333f}, + {38.0952f,-28.5714f} +}; + +static const Fl_Glut_StrokeVertex ch103st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch103st[] = +{ + {7,ch103st0}, + {14,ch103st1} +}; + +static const Fl_Glut_StrokeChar ch103 = {104.762f,2,ch103st}; + +/* char: 0x68 */ + +static const Fl_Glut_StrokeVertex ch104st0[] = +{ + {26.1905f,100.0f}, + {26.1905f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch104st1[] = +{ + {26.1905f,47.619f}, + {40.4762f,61.9048f}, + {50.0f,66.6667f}, + {64.2857f,66.6667f}, + {73.8095f,61.9048f}, + {78.5715f,47.619f}, + {78.5715f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch104st[] = +{ + {2,ch104st0}, + {7,ch104st1} +}; + +static const Fl_Glut_StrokeChar ch104 = {104.762f,2,ch104st}; + +/* char: 0x69 */ + +static const Fl_Glut_StrokeVertex ch105st0[] = +{ + {47.6191f,100.0f}, + {52.381f,95.2381f}, + {57.1429f,100.0f}, + {52.381f,104.762f}, + {47.6191f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch105st1[] = +{ + {52.381f,66.6667f}, + {52.381f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch105st[] = +{ + {5,ch105st0}, + {2,ch105st1} +}; + +static const Fl_Glut_StrokeChar ch105 = {104.762f,2,ch105st}; + +/* char: 0x6a */ + +static const Fl_Glut_StrokeVertex ch106st0[] = +{ + {57.1429f,100.0f}, + {61.9048f,95.2381f}, + {66.6667f,100.0f}, + {61.9048f,104.762f}, + {57.1429f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch106st1[] = +{ + {61.9048f,66.6667f}, + {61.9048f,-14.2857f}, + {57.1429f,-28.5714f}, + {47.6191f,-33.3333f}, + {38.0953f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch106st[] = +{ + {5,ch106st0}, + {5,ch106st1} +}; + +static const Fl_Glut_StrokeChar ch106 = {104.762f,2,ch106st}; + +/* char: 0x6b */ + +static const Fl_Glut_StrokeVertex ch107st0[] = +{ + {26.1905f,100.0f}, + {26.1905f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch107st1[] = +{ + {73.8095f,66.6667f}, + {26.1905f,19.0476f} +}; + +static const Fl_Glut_StrokeVertex ch107st2[] = +{ + {45.2381f,38.0952f}, + {78.5715f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch107st[] = +{ + {2,ch107st0}, + {2,ch107st1}, + {2,ch107st2} +}; + +static const Fl_Glut_StrokeChar ch107 = {104.762f,3,ch107st}; + +/* char: 0x6c */ + +static const Fl_Glut_StrokeVertex ch108st0[] = +{ + {52.381f,100.0f}, + {52.381f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch108st[] = +{ + {2,ch108st0} +}; + +static const Fl_Glut_StrokeChar ch108 = {104.762f,1,ch108st}; + +/* char: 0x6d */ + +static const Fl_Glut_StrokeVertex ch109st0[] = +{ + {0,66.6667f}, + {0,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch109st1[] = +{ + {0,47.619f}, + {14.2857f,61.9048f}, + {23.8095f,66.6667f}, + {38.0952f,66.6667f}, + {47.619f,61.9048f}, + {52.381f,47.619f}, + {52.381f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch109st2[] = +{ + {52.381f,47.619f}, + {66.6667f,61.9048f}, + {76.1905f,66.6667f}, + {90.4762f,66.6667f}, + {100.0f,61.9048f}, + {104.762f,47.619f}, + {104.762f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch109st[] = +{ + {2,ch109st0}, + {7,ch109st1}, + {7,ch109st2} +}; + +static const Fl_Glut_StrokeChar ch109 = {104.762f,3,ch109st}; + +/* char: 0x6e */ + +static const Fl_Glut_StrokeVertex ch110st0[] = +{ + {26.1905f,66.6667f}, + {26.1905f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch110st1[] = +{ + {26.1905f,47.619f}, + {40.4762f,61.9048f}, + {50.0f,66.6667f}, + {64.2857f,66.6667f}, + {73.8095f,61.9048f}, + {78.5715f,47.619f}, + {78.5715f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch110st[] = +{ + {2,ch110st0}, + {7,ch110st1} +}; + +static const Fl_Glut_StrokeChar ch110 = {104.762f,2,ch110st}; + +/* char: 0x6f */ + +static const Fl_Glut_StrokeVertex ch111st0[] = +{ + {45.2381f,66.6667f}, + {35.7143f,61.9048f}, + {26.1905f,52.381f}, + {21.4286f,38.0952f}, + {21.4286f,28.5714f}, + {26.1905f,14.2857f}, + {35.7143f,4.7619f}, + {45.2381f,0.0f}, + {59.5238f,0.0f}, + {69.0476f,4.7619f}, + {78.5714f,14.2857f}, + {83.3334f,28.5714f}, + {83.3334f,38.0952f}, + {78.5714f,52.381f}, + {69.0476f,61.9048f}, + {59.5238f,66.6667f}, + {45.2381f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch111st[] = +{ + {17,ch111st0} +}; + +static const Fl_Glut_StrokeChar ch111 = {104.762f,1,ch111st}; + +/* char: 0x70 */ + +static const Fl_Glut_StrokeVertex ch112st0[] = +{ + {23.8095f,66.6667f}, + {23.8095f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch112st1[] = +{ + {23.8095f,52.381f}, + {33.3333f,61.9048f}, + {42.8571f,66.6667f}, + {57.1428f,66.6667f}, + {66.6666f,61.9048f}, + {76.1905f,52.381f}, + {80.9524f,38.0952f}, + {80.9524f,28.5714f}, + {76.1905f,14.2857f}, + {66.6666f,4.7619f}, + {57.1428f,0.0f}, + {42.8571f,0.0f}, + {33.3333f,4.7619f}, + {23.8095f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch112st[] = +{ + {2,ch112st0}, + {14,ch112st1} +}; + +static const Fl_Glut_StrokeChar ch112 = {104.762f,2,ch112st}; + +/* char: 0x71 */ + +static const Fl_Glut_StrokeVertex ch113st0[] = +{ + {80.9524f,66.6667f}, + {80.9524f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch113st1[] = +{ + {80.9524f,52.381f}, + {71.4285f,61.9048f}, + {61.9047f,66.6667f}, + {47.619f,66.6667f}, + {38.0952f,61.9048f}, + {28.5714f,52.381f}, + {23.8095f,38.0952f}, + {23.8095f,28.5714f}, + {28.5714f,14.2857f}, + {38.0952f,4.7619f}, + {47.619f,0.0f}, + {61.9047f,0.0f}, + {71.4285f,4.7619f}, + {80.9524f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch113st[] = +{ + {2,ch113st0}, + {14,ch113st1} +}; + +static const Fl_Glut_StrokeChar ch113 = {104.762f,2,ch113st}; + +/* char: 0x72 */ + +static const Fl_Glut_StrokeVertex ch114st0[] = +{ + {33.3334f,66.6667f}, + {33.3334f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch114st1[] = +{ + {33.3334f,38.0952f}, + {38.0953f,52.381f}, + {47.6191f,61.9048f}, + {57.1429f,66.6667f}, + {71.4286f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch114st[] = +{ + {2,ch114st0}, + {5,ch114st1} +}; + +static const Fl_Glut_StrokeChar ch114 = {104.762f,2,ch114st}; + +/* char: 0x73 */ + +static const Fl_Glut_StrokeVertex ch115st0[] = +{ + {78.5715f,52.381f}, + {73.8095f,61.9048f}, + {59.5238f,66.6667f}, + {45.2381f,66.6667f}, + {30.9524f,61.9048f}, + {26.1905f,52.381f}, + {30.9524f,42.8571f}, + {40.4762f,38.0952f}, + {64.2857f,33.3333f}, + {73.8095f,28.5714f}, + {78.5715f,19.0476f}, + {78.5715f,14.2857f}, + {73.8095f,4.7619f}, + {59.5238f,0.0f}, + {45.2381f,0.0f}, + {30.9524f,4.7619f}, + {26.1905f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch115st[] = +{ + {17,ch115st0} +}; + +static const Fl_Glut_StrokeChar ch115 = {104.762f,1,ch115st}; + +/* char: 0x74 */ + +static const Fl_Glut_StrokeVertex ch116st0[] = +{ + {47.6191f,100.0f}, + {47.6191f,19.0476f}, + {52.381f,4.7619f}, + {61.9048f,0.0f}, + {71.4286f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch116st1[] = +{ + {33.3334f,66.6667f}, + {66.6667f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch116st[] = +{ + {5,ch116st0}, + {2,ch116st1} +}; + +static const Fl_Glut_StrokeChar ch116 = {104.762f,2,ch116st}; + +/* char: 0x75 */ + +static const Fl_Glut_StrokeVertex ch117st0[] = +{ + {26.1905f,66.6667f}, + {26.1905f,19.0476f}, + {30.9524f,4.7619f}, + {40.4762f,0.0f}, + {54.7619f,0.0f}, + {64.2857f,4.7619f}, + {78.5715f,19.0476f} +}; + +static const Fl_Glut_StrokeVertex ch117st1[] = +{ + {78.5715f,66.6667f}, + {78.5715f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch117st[] = +{ + {7,ch117st0}, + {2,ch117st1} +}; + +static const Fl_Glut_StrokeChar ch117 = {104.762f,2,ch117st}; + +/* char: 0x76 */ + +static const Fl_Glut_StrokeVertex ch118st0[] = +{ + {23.8095f,66.6667f}, + {52.3809f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch118st1[] = +{ + {80.9524f,66.6667f}, + {52.3809f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch118st[] = +{ + {2,ch118st0}, + {2,ch118st1} +}; + +static const Fl_Glut_StrokeChar ch118 = {104.762f,2,ch118st}; + +/* char: 0x77 */ + +static const Fl_Glut_StrokeVertex ch119st0[] = +{ + {14.2857f,66.6667f}, + {33.3333f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch119st1[] = +{ + {52.3809f,66.6667f}, + {33.3333f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch119st2[] = +{ + {52.3809f,66.6667f}, + {71.4286f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch119st3[] = +{ + {90.4762f,66.6667f}, + {71.4286f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch119st[] = +{ + {2,ch119st0}, + {2,ch119st1}, + {2,ch119st2}, + {2,ch119st3} +}; + +static const Fl_Glut_StrokeChar ch119 = {104.762f,4,ch119st}; + +/* char: 0x78 */ + +static const Fl_Glut_StrokeVertex ch120st0[] = +{ + {26.1905f,66.6667f}, + {78.5715f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch120st1[] = +{ + {78.5715f,66.6667f}, + {26.1905f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch120st[] = +{ + {2,ch120st0}, + {2,ch120st1} +}; + +static const Fl_Glut_StrokeChar ch120 = {104.762f,2,ch120st}; + +/* char: 0x79 */ + +static const Fl_Glut_StrokeVertex ch121st0[] = +{ + {26.1905f,66.6667f}, + {54.7619f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch121st1[] = +{ + {83.3334f,66.6667f}, + {54.7619f,0.0f}, + {45.2381f,-19.0476f}, + {35.7143f,-28.5714f}, + {26.1905f,-33.3333f}, + {21.4286f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch121st[] = +{ + {2,ch121st0}, + {6,ch121st1} +}; + +static const Fl_Glut_StrokeChar ch121 = {104.762f,2,ch121st}; + +/* char: 0x7a */ + +static const Fl_Glut_StrokeVertex ch122st0[] = +{ + {78.5715f,66.6667f}, + {26.1905f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch122st1[] = +{ + {26.1905f,66.6667f}, + {78.5715f,66.6667f} +}; + +static const Fl_Glut_StrokeVertex ch122st2[] = +{ + {26.1905f,0.0f}, + {78.5715f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch122st[] = +{ + {2,ch122st0}, + {2,ch122st1}, + {2,ch122st2} +}; + +static const Fl_Glut_StrokeChar ch122 = {104.762f,3,ch122st}; + +/* char: 0x7b */ + +static const Fl_Glut_StrokeVertex ch123st0[] = +{ + {64.2857f,119.048f}, + {54.7619f,114.286f}, + {50.0f,109.524f}, + {45.2381f,100.0f}, + {45.2381f,90.4762f}, + {50.0f,80.9524f}, + {54.7619f,76.1905f}, + {59.5238f,66.6667f}, + {59.5238f,57.1429f}, + {50.0f,47.619f} +}; + +static const Fl_Glut_StrokeVertex ch123st1[] = +{ + {54.7619f,114.286f}, + {50.0f,104.762f}, + {50.0f,95.2381f}, + {54.7619f,85.7143f}, + {59.5238f,80.9524f}, + {64.2857f,71.4286f}, + {64.2857f,61.9048f}, + {59.5238f,52.381f}, + {40.4762f,42.8571f}, + {59.5238f,33.3333f}, + {64.2857f,23.8095f}, + {64.2857f,14.2857f}, + {59.5238f,4.7619f}, + {54.7619f,0.0f}, + {50.0f,-9.5238f}, + {50.0f,-19.0476f}, + {54.7619f,-28.5714f} +}; + +static const Fl_Glut_StrokeVertex ch123st2[] = +{ + {50.0f,38.0952f}, + {59.5238f,28.5714f}, + {59.5238f,19.0476f}, + {54.7619f,9.5238f}, + {50.0f,4.7619f}, + {45.2381f,-4.7619f}, + {45.2381f,-14.2857f}, + {50.0f,-23.8095f}, + {54.7619f,-28.5714f}, + {64.2857f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch123st[] = +{ + {10,ch123st0}, + {17,ch123st1}, + {10,ch123st2} +}; + +static const Fl_Glut_StrokeChar ch123 = {104.762f,3,ch123st}; + +/* char: 0x7c */ + +static const Fl_Glut_StrokeVertex ch124st0[] = +{ + {52.381f,119.048f}, + {52.381f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch124st[] = +{ + {2,ch124st0} +}; + +static const Fl_Glut_StrokeChar ch124 = {104.762f,1,ch124st}; + +/* char: 0x7d */ + +static const Fl_Glut_StrokeVertex ch125st0[] = +{ + {40.4762f,119.048f}, + {50.0f,114.286f}, + {54.7619f,109.524f}, + {59.5238f,100.0f}, + {59.5238f,90.4762f}, + {54.7619f,80.9524f}, + {50.0f,76.1905f}, + {45.2381f,66.6667f}, + {45.2381f,57.1429f}, + {54.7619f,47.619f} +}; + +static const Fl_Glut_StrokeVertex ch125st1[] = +{ + {50.0f,114.286f}, + {54.7619f,104.762f}, + {54.7619f,95.2381f}, + {50.0f,85.7143f}, + {45.2381f,80.9524f}, + {40.4762f,71.4286f}, + {40.4762f,61.9048f}, + {45.2381f,52.381f}, + {64.2857f,42.8571f}, + {45.2381f,33.3333f}, + {40.4762f,23.8095f}, + {40.4762f,14.2857f}, + {45.2381f,4.7619f}, + {50.0f,0.0f}, + {54.7619f,-9.5238f}, + {54.7619f,-19.0476f}, + {50.0f,-28.5714f} +}; + +static const Fl_Glut_StrokeVertex ch125st2[] = +{ + {54.7619f,38.0952f}, + {45.2381f,28.5714f}, + {45.2381f,19.0476f}, + {50.0f,9.5238f}, + {54.7619f,4.7619f}, + {59.5238f,-4.7619f}, + {59.5238f,-14.2857f}, + {54.7619f,-23.8095f}, + {50.0f,-28.5714f}, + {40.4762f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch125st[] = +{ + {10,ch125st0}, + {17,ch125st1}, + {10,ch125st2} +}; + +static const Fl_Glut_StrokeChar ch125 = {104.762f,3,ch125st}; + +/* char: 0x7e */ + +static const Fl_Glut_StrokeVertex ch126st0[] = +{ + {9.5238f,28.5714f}, + {9.5238f,38.0952f}, + {14.2857f,52.381f}, + {23.8095f,57.1429f}, + {33.3333f,57.1429f}, + {42.8571f,52.381f}, + {61.9048f,38.0952f}, + {71.4286f,33.3333f}, + {80.9524f,33.3333f}, + {90.4762f,38.0952f}, + {95.2381f,47.619f} +}; + +static const Fl_Glut_StrokeVertex ch126st1[] = +{ + {9.5238f,38.0952f}, + {14.2857f,47.619f}, + {23.8095f,52.381f}, + {33.3333f,52.381f}, + {42.8571f,47.619f}, + {61.9048f,33.3333f}, + {71.4286f,28.5714f}, + {80.9524f,28.5714f}, + {90.4762f,33.3333f}, + {95.2381f,47.619f}, + {95.2381f,57.1429f} +}; + +static const Fl_Glut_StrokeStrip ch126st[] = +{ + {11,ch126st0}, + {11,ch126st1} +}; + +static const Fl_Glut_StrokeChar ch126 = {104.762f,2,ch126st}; + +/* char: 0x7f */ + +static const Fl_Glut_StrokeVertex ch127st0[] = +{ + {71.4286f,100.0f}, + {33.3333f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch127st1[] = +{ + {47.619f,66.6667f}, + {33.3333f,61.9048f}, + {23.8095f,52.381f}, + {19.0476f,38.0952f}, + {19.0476f,23.8095f}, + {23.8095f,14.2857f}, + {33.3333f,4.7619f}, + {47.619f,0.0f}, + {57.1428f,0.0f}, + {71.4286f,4.7619f}, + {80.9524f,14.2857f}, + {85.7143f,28.5714f}, + {85.7143f,42.8571f}, + {80.9524f,52.381f}, + {71.4286f,61.9048f}, + {57.1428f,66.6667f}, + {47.619f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch127st[] = +{ + {2,ch127st0}, + {17,ch127st1} +}; + +static const Fl_Glut_StrokeChar ch127 = {104.762f,2,ch127st}; + +static const Fl_Glut_StrokeChar *chars[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + &ch32, &ch33, &ch34, &ch35, &ch36, &ch37, &ch38, &ch39, + &ch40, &ch41, &ch42, &ch43, &ch44, &ch45, &ch46, &ch47, + &ch48, &ch49, &ch50, &ch51, &ch52, &ch53, &ch54, &ch55, + &ch56, &ch57, &ch58, &ch59, &ch60, &ch61, &ch62, &ch63, + &ch64, &ch65, &ch66, &ch67, &ch68, &ch69, &ch70, &ch71, + &ch72, &ch73, &ch74, &ch75, &ch76, &ch77, &ch78, &ch79, + &ch80, &ch81, &ch82, &ch83, &ch84, &ch85, &ch86, &ch87, + &ch88, &ch89, &ch90, &ch91, &ch92, &ch93, &ch94, &ch95, + &ch96, &ch97, &ch98, &ch99, &ch100, &ch101, &ch102, &ch103, + &ch104, &ch105, &ch106, &ch107, &ch108, &ch109, &ch110, &ch111, + &ch112, &ch113, &ch114, &ch115, &ch116, &ch117, &ch118, &ch119, + &ch120, &ch121, &ch122, &ch123, &ch124, &ch125, &ch126, &ch127 +}; + +Fl_Glut_StrokeFont glutStrokeMonoRoman = {(char *)"MonoRoman",128,152.381f,chars}; diff --git a/third_party/windows/fltk-1.1.10/src/freeglut_stroke_roman.cxx b/third_party/windows/fltk-1.1.10/src/freeglut_stroke_roman.cxx new file mode 100644 index 0000000..1267637 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/freeglut_stroke_roman.cxx @@ -0,0 +1,2848 @@ +/* + * freeglut_stroke_roman.c + * + * freeglut Roman stroke font definition + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Thu Dec 16 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + + +/* This file has been automatically generated by the genstroke utility. */ + +#include + +/* char: 0x20 */ + +static const Fl_Glut_StrokeStrip ch32st[] = +{ + { 0, 0 } +}; + +static const Fl_Glut_StrokeChar ch32 = {104.762f,0,ch32st}; + +/* char: 0x21 */ + +static const Fl_Glut_StrokeVertex ch33st0[] = +{ + {13.3819f,100.0f}, + {13.3819f,33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch33st1[] = +{ + {13.3819f,9.5238f}, + {8.62f,4.7619f}, + {13.3819f,0.0f}, + {18.1438f,4.7619f}, + {13.3819f,9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch33st[] = +{ + {2,ch33st0}, + {5,ch33st1} +}; + +static const Fl_Glut_StrokeChar ch33 = {26.6238f,2,ch33st}; + +/* char: 0x22 */ + +static const Fl_Glut_StrokeVertex ch34st0[] = +{ + {4.02f,100.0f}, + {4.02f,66.6667f} +}; + +static const Fl_Glut_StrokeVertex ch34st1[] = +{ + {42.1152f,100.0f}, + {42.1152f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch34st[] = +{ + {2,ch34st0}, + {2,ch34st1} +}; + +static const Fl_Glut_StrokeChar ch34 = {51.4352f,2,ch34st}; + +/* char: 0x23 */ + +static const Fl_Glut_StrokeVertex ch35st0[] = +{ + {41.2952f,119.048f}, + {7.9619f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch35st1[] = +{ + {69.8667f,119.048f}, + {36.5333f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch35st2[] = +{ + {7.9619f,57.1429f}, + {74.6286f,57.1429f} +}; + +static const Fl_Glut_StrokeVertex ch35st3[] = +{ + {3.2f,28.5714f}, + {69.8667f,28.5714f} +}; + +static const Fl_Glut_StrokeStrip ch35st[] = +{ + {2,ch35st0}, + {2,ch35st1}, + {2,ch35st2}, + {2,ch35st3} +}; + +static const Fl_Glut_StrokeChar ch35 = {79.4886f,4,ch35st}; + +/* char: 0x24 */ + +static const Fl_Glut_StrokeVertex ch36st0[] = +{ + {28.6295f,119.048f}, + {28.6295f,-19.0476f} +}; + +static const Fl_Glut_StrokeVertex ch36st1[] = +{ + {47.6771f,119.048f}, + {47.6771f,-19.0476f} +}; + +static const Fl_Glut_StrokeVertex ch36st2[] = +{ + {71.4867f,85.7143f}, + {61.9629f,95.2381f}, + {47.6771f,100.0f}, + {28.6295f,100.0f}, + {14.3438f,95.2381f}, + {4.82f,85.7143f}, + {4.82f,76.1905f}, + {9.5819f,66.6667f}, + {14.3438f,61.9048f}, + {23.8676f,57.1429f}, + {52.439f,47.619f}, + {61.9629f,42.8571f}, + {66.7248f,38.0952f}, + {71.4867f,28.5714f}, + {71.4867f,14.2857f}, + {61.9629f,4.7619f}, + {47.6771f,0.0f}, + {28.6295f,0.0f}, + {14.3438f,4.7619f}, + {4.82f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch36st[] = +{ + {2,ch36st0}, + {2,ch36st1}, + {20,ch36st2} +}; + +static const Fl_Glut_StrokeChar ch36 = {76.2067f,3,ch36st}; + +/* char: 0x25 */ + +static const Fl_Glut_StrokeVertex ch37st0[] = +{ + {92.0743f,100.0f}, + {6.36f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch37st1[] = +{ + {30.1695f,100.0f}, + {39.6933f,90.4762f}, + {39.6933f,80.9524f}, + {34.9314f,71.4286f}, + {25.4076f,66.6667f}, + {15.8838f,66.6667f}, + {6.36f,76.1905f}, + {6.36f,85.7143f}, + {11.1219f,95.2381f}, + {20.6457f,100.0f}, + {30.1695f,100.0f}, + {39.6933f,95.2381f}, + {53.979f,90.4762f}, + {68.2648f,90.4762f}, + {82.5505f,95.2381f}, + {92.0743f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch37st2[] = +{ + {73.0267f,33.3333f}, + {63.5029f,28.5714f}, + {58.741f,19.0476f}, + {58.741f,9.5238f}, + {68.2648f,0.0f}, + {77.7886f,0.0f}, + {87.3124f,4.7619f}, + {92.0743f,14.2857f}, + {92.0743f,23.8095f}, + {82.5505f,33.3333f}, + {73.0267f,33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch37st[] = +{ + {2,ch37st0}, + {16,ch37st1}, + {11,ch37st2} +}; + +static const Fl_Glut_StrokeChar ch37 = {96.5743f,3,ch37st}; + +/* char: 0x26 */ + +static const Fl_Glut_StrokeVertex ch38st0[] = +{ + {101.218f,57.1429f}, + {101.218f,61.9048f}, + {96.4562f,66.6667f}, + {91.6943f,66.6667f}, + {86.9324f,61.9048f}, + {82.1705f,52.381f}, + {72.6467f,28.5714f}, + {63.1229f,14.2857f}, + {53.599f,4.7619f}, + {44.0752f,0.0f}, + {25.0276f,0.0f}, + {15.5038f,4.7619f}, + {10.7419f,9.5238f}, + {5.98f,19.0476f}, + {5.98f,28.5714f}, + {10.7419f,38.0952f}, + {15.5038f,42.8571f}, + {48.8371f,61.9048f}, + {53.599f,66.6667f}, + {58.361f,76.1905f}, + {58.361f,85.7143f}, + {53.599f,95.2381f}, + {44.0752f,100.0f}, + {34.5514f,95.2381f}, + {29.7895f,85.7143f}, + {29.7895f,76.1905f}, + {34.5514f,61.9048f}, + {44.0752f,47.619f}, + {67.8848f,14.2857f}, + {77.4086f,4.7619f}, + {86.9324f,0.0f}, + {96.4562f,0.0f}, + {101.218f,4.7619f}, + {101.218f,9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch38st[] = +{ + {34,ch38st0} +}; + +static const Fl_Glut_StrokeChar ch38 = {101.758f,1,ch38st}; + +/* char: 0x27 */ + +static const Fl_Glut_StrokeVertex ch39st0[] = +{ + {4.44f,100.0f}, + {4.44f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch39st[] = +{ + {2,ch39st0} +}; + +static const Fl_Glut_StrokeChar ch39 = {13.62f,1,ch39st}; + +/* char: 0x28 */ + +static const Fl_Glut_StrokeVertex ch40st0[] = +{ + {40.9133f,119.048f}, + {31.3895f,109.524f}, + {21.8657f,95.2381f}, + {12.3419f,76.1905f}, + {7.58f,52.381f}, + {7.58f,33.3333f}, + {12.3419f,9.5238f}, + {21.8657f,-9.5238f}, + {31.3895f,-23.8095f}, + {40.9133f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch40st[] = +{ + {10,ch40st0} +}; + +static const Fl_Glut_StrokeChar ch40 = {47.1733f,1,ch40st}; + +/* char: 0x29 */ + +static const Fl_Glut_StrokeVertex ch41st0[] = +{ + {5.28f,119.048f}, + {14.8038f,109.524f}, + {24.3276f,95.2381f}, + {33.8514f,76.1905f}, + {38.6133f,52.381f}, + {38.6133f,33.3333f}, + {33.8514f,9.5238f}, + {24.3276f,-9.5238f}, + {14.8038f,-23.8095f}, + {5.28f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch41st[] = +{ + {10,ch41st0} +}; + +static const Fl_Glut_StrokeChar ch41 = {47.5333f,1,ch41st}; + +/* char: 0x2a */ + +static const Fl_Glut_StrokeVertex ch42st0[] = +{ + {30.7695f,71.4286f}, + {30.7695f,14.2857f} +}; + +static const Fl_Glut_StrokeVertex ch42st1[] = +{ + {6.96f,57.1429f}, + {54.579f,28.5714f} +}; + +static const Fl_Glut_StrokeVertex ch42st2[] = +{ + {54.579f,57.1429f}, + {6.96f,28.5714f} +}; + +static const Fl_Glut_StrokeStrip ch42st[] = +{ + {2,ch42st0}, + {2,ch42st1}, + {2,ch42st2} +}; + +static const Fl_Glut_StrokeChar ch42 = {59.439f,3,ch42st}; + +/* char: 0x2b */ + +static const Fl_Glut_StrokeVertex ch43st0[] = +{ + {48.8371f,85.7143f}, + {48.8371f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch43st1[] = +{ + {5.98f,42.8571f}, + {91.6943f,42.8571f} +}; + +static const Fl_Glut_StrokeStrip ch43st[] = +{ + {2,ch43st0}, + {2,ch43st1} +}; + +static const Fl_Glut_StrokeChar ch43 = {97.2543f,2,ch43st}; + +/* char: 0x2c */ + +static const Fl_Glut_StrokeVertex ch44st0[] = +{ + {18.2838f,4.7619f}, + {13.5219f,0.0f}, + {8.76f,4.7619f}, + {13.5219f,9.5238f}, + {18.2838f,4.7619f}, + {18.2838f,-4.7619f}, + {13.5219f,-14.2857f}, + {8.76f,-19.0476f} +}; + +static const Fl_Glut_StrokeStrip ch44st[] = +{ + {8,ch44st0} +}; + +static const Fl_Glut_StrokeChar ch44 = {26.0638f,1,ch44st}; + +/* char: 0x2d */ + +static const Fl_Glut_StrokeVertex ch45st0[] = +{ + {7.38f,42.8571f}, + {93.0943f,42.8571f} +}; + +static const Fl_Glut_StrokeStrip ch45st[] = +{ + {2,ch45st0} +}; + +static const Fl_Glut_StrokeChar ch45 = {100.754f,1,ch45st}; + +/* char: 0x2e */ + +static const Fl_Glut_StrokeVertex ch46st0[] = +{ + {13.1019f,9.5238f}, + {8.34f,4.7619f}, + {13.1019f,0.0f}, + {17.8638f,4.7619f}, + {13.1019f,9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch46st[] = +{ + {5,ch46st0} +}; + +static const Fl_Glut_StrokeChar ch46 = {26.4838f,1,ch46st}; + +/* char: 0x2f */ + +static const Fl_Glut_StrokeVertex ch47st0[] = +{ + {7.24f,-14.2857f}, + {73.9067f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch47st[] = +{ + {2,ch47st0} +}; + +static const Fl_Glut_StrokeChar ch47 = {82.1067f,1,ch47st}; + +/* char: 0x30 */ + +static const Fl_Glut_StrokeVertex ch48st0[] = +{ + {33.5514f,100.0f}, + {19.2657f,95.2381f}, + {9.7419f,80.9524f}, + {4.98f,57.1429f}, + {4.98f,42.8571f}, + {9.7419f,19.0476f}, + {19.2657f,4.7619f}, + {33.5514f,0.0f}, + {43.0752f,0.0f}, + {57.361f,4.7619f}, + {66.8848f,19.0476f}, + {71.6467f,42.8571f}, + {71.6467f,57.1429f}, + {66.8848f,80.9524f}, + {57.361f,95.2381f}, + {43.0752f,100.0f}, + {33.5514f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch48st[] = +{ + {17,ch48st0} +}; + +static const Fl_Glut_StrokeChar ch48 = {77.0667f,1,ch48st}; + +/* char: 0x31 */ + +static const Fl_Glut_StrokeVertex ch49st0[] = +{ + {11.82f,80.9524f}, + {21.3438f,85.7143f}, + {35.6295f,100.0f}, + {35.6295f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch49st[] = +{ + {4,ch49st0} +}; + +static const Fl_Glut_StrokeChar ch49 = {66.5295f,1,ch49st}; + +/* char: 0x32 */ + +static const Fl_Glut_StrokeVertex ch50st0[] = +{ + {10.1819f,76.1905f}, + {10.1819f,80.9524f}, + {14.9438f,90.4762f}, + {19.7057f,95.2381f}, + {29.2295f,100.0f}, + {48.2771f,100.0f}, + {57.801f,95.2381f}, + {62.5629f,90.4762f}, + {67.3248f,80.9524f}, + {67.3248f,71.4286f}, + {62.5629f,61.9048f}, + {53.039f,47.619f}, + {5.42f,0.0f}, + {72.0867f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch50st[] = +{ + {14,ch50st0} +}; + +static const Fl_Glut_StrokeChar ch50 = {77.6467f,1,ch50st}; + +/* char: 0x33 */ + +static const Fl_Glut_StrokeVertex ch51st0[] = +{ + {14.5238f,100.0f}, + {66.9048f,100.0f}, + {38.3333f,61.9048f}, + {52.619f,61.9048f}, + {62.1429f,57.1429f}, + {66.9048f,52.381f}, + {71.6667f,38.0952f}, + {71.6667f,28.5714f}, + {66.9048f,14.2857f}, + {57.381f,4.7619f}, + {43.0952f,0.0f}, + {28.8095f,0.0f}, + {14.5238f,4.7619f}, + {9.7619f,9.5238f}, + {5.0f,19.0476f} +}; + +static const Fl_Glut_StrokeStrip ch51st[] = +{ + {15,ch51st0} +}; + +static const Fl_Glut_StrokeChar ch51 = {77.0467f,1,ch51st}; + +/* char: 0x34 */ + +static const Fl_Glut_StrokeVertex ch52st0[] = +{ + {51.499f,100.0f}, + {3.88f,33.3333f}, + {75.3086f,33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch52st1[] = +{ + {51.499f,100.0f}, + {51.499f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch52st[] = +{ + {3,ch52st0}, + {2,ch52st1} +}; + +static const Fl_Glut_StrokeChar ch52 = {80.1686f,2,ch52st}; + +/* char: 0x35 */ + +static const Fl_Glut_StrokeVertex ch53st0[] = +{ + {62.0029f,100.0f}, + {14.3838f,100.0f}, + {9.6219f,57.1429f}, + {14.3838f,61.9048f}, + {28.6695f,66.6667f}, + {42.9552f,66.6667f}, + {57.241f,61.9048f}, + {66.7648f,52.381f}, + {71.5267f,38.0952f}, + {71.5267f,28.5714f}, + {66.7648f,14.2857f}, + {57.241f,4.7619f}, + {42.9552f,0.0f}, + {28.6695f,0.0f}, + {14.3838f,4.7619f}, + {9.6219f,9.5238f}, + {4.86f,19.0476f} +}; + +static const Fl_Glut_StrokeStrip ch53st[] = +{ + {17,ch53st0} +}; + +static const Fl_Glut_StrokeChar ch53 = {77.6867f,1,ch53st}; + +/* char: 0x36 */ + +static const Fl_Glut_StrokeVertex ch54st0[] = +{ + {62.7229f,85.7143f}, + {57.961f,95.2381f}, + {43.6752f,100.0f}, + {34.1514f,100.0f}, + {19.8657f,95.2381f}, + {10.3419f,80.9524f}, + {5.58f,57.1429f}, + {5.58f,33.3333f}, + {10.3419f,14.2857f}, + {19.8657f,4.7619f}, + {34.1514f,0.0f}, + {38.9133f,0.0f}, + {53.199f,4.7619f}, + {62.7229f,14.2857f}, + {67.4848f,28.5714f}, + {67.4848f,33.3333f}, + {62.7229f,47.619f}, + {53.199f,57.1429f}, + {38.9133f,61.9048f}, + {34.1514f,61.9048f}, + {19.8657f,57.1429f}, + {10.3419f,47.619f}, + {5.58f,33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch54st[] = +{ + {23,ch54st0} +}; + +static const Fl_Glut_StrokeChar ch54 = {73.8048f,1,ch54st}; + +/* char: 0x37 */ + +static const Fl_Glut_StrokeVertex ch55st0[] = +{ + {72.2267f,100.0f}, + {24.6076f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch55st1[] = +{ + {5.56f,100.0f}, + {72.2267f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch55st[] = +{ + {2,ch55st0}, + {2,ch55st1} +}; + +static const Fl_Glut_StrokeChar ch55 = {77.2267f,2,ch55st}; + +/* char: 0x38 */ + +static const Fl_Glut_StrokeVertex ch56st0[] = +{ + {29.4095f,100.0f}, + {15.1238f,95.2381f}, + {10.3619f,85.7143f}, + {10.3619f,76.1905f}, + {15.1238f,66.6667f}, + {24.6476f,61.9048f}, + {43.6952f,57.1429f}, + {57.981f,52.381f}, + {67.5048f,42.8571f}, + {72.2667f,33.3333f}, + {72.2667f,19.0476f}, + {67.5048f,9.5238f}, + {62.7429f,4.7619f}, + {48.4571f,0.0f}, + {29.4095f,0.0f}, + {15.1238f,4.7619f}, + {10.3619f,9.5238f}, + {5.6f,19.0476f}, + {5.6f,33.3333f}, + {10.3619f,42.8571f}, + {19.8857f,52.381f}, + {34.1714f,57.1429f}, + {53.219f,61.9048f}, + {62.7429f,66.6667f}, + {67.5048f,76.1905f}, + {67.5048f,85.7143f}, + {62.7429f,95.2381f}, + {48.4571f,100.0f}, + {29.4095f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch56st[] = +{ + {29,ch56st0} +}; + +static const Fl_Glut_StrokeChar ch56 = {77.6667f,1,ch56st}; + +/* char: 0x39 */ + +static const Fl_Glut_StrokeVertex ch57st0[] = +{ + {68.5048f,66.6667f}, + {63.7429f,52.381f}, + {54.219f,42.8571f}, + {39.9333f,38.0952f}, + {35.1714f,38.0952f}, + {20.8857f,42.8571f}, + {11.3619f,52.381f}, + {6.6f,66.6667f}, + {6.6f,71.4286f}, + {11.3619f,85.7143f}, + {20.8857f,95.2381f}, + {35.1714f,100.0f}, + {39.9333f,100.0f}, + {54.219f,95.2381f}, + {63.7429f,85.7143f}, + {68.5048f,66.6667f}, + {68.5048f,42.8571f}, + {63.7429f,19.0476f}, + {54.219f,4.7619f}, + {39.9333f,0.0f}, + {30.4095f,0.0f}, + {16.1238f,4.7619f}, + {11.3619f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch57st[] = +{ + {23,ch57st0} +}; + +static const Fl_Glut_StrokeChar ch57 = {74.0648f,1,ch57st}; + +/* char: 0x3a */ + +static const Fl_Glut_StrokeVertex ch58st0[] = +{ + {14.0819f,66.6667f}, + {9.32f,61.9048f}, + {14.0819f,57.1429f}, + {18.8438f,61.9048f}, + {14.0819f,66.6667f} +}; + +static const Fl_Glut_StrokeVertex ch58st1[] = +{ + {14.0819f,9.5238f}, + {9.32f,4.7619f}, + {14.0819f,0.0f}, + {18.8438f,4.7619f}, + {14.0819f,9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch58st[] = +{ + {5,ch58st0}, + {5,ch58st1} +}; + +static const Fl_Glut_StrokeChar ch58 = {26.2238f,2,ch58st}; + +/* char: 0x3b */ + +static const Fl_Glut_StrokeVertex ch59st0[] = +{ + {12.9619f,66.6667f}, + {8.2f,61.9048f}, + {12.9619f,57.1429f}, + {17.7238f,61.9048f}, + {12.9619f,66.6667f} +}; + +static const Fl_Glut_StrokeVertex ch59st1[] = +{ + {17.7238f,4.7619f}, + {12.9619f,0.0f}, + {8.2f,4.7619f}, + {12.9619f,9.5238f}, + {17.7238f,4.7619f}, + {17.7238f,-4.7619f}, + {12.9619f,-14.2857f}, + {8.2f,-19.0476f} +}; + +static const Fl_Glut_StrokeStrip ch59st[] = +{ + {5,ch59st0}, + {8,ch59st1} +}; + +static const Fl_Glut_StrokeChar ch59 = {26.3038f,2,ch59st}; + +/* char: 0x3c */ + +static const Fl_Glut_StrokeVertex ch60st0[] = +{ + {79.2505f,85.7143f}, + {3.06f,42.8571f}, + {79.2505f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch60st[] = +{ + {3,ch60st0} +}; + +static const Fl_Glut_StrokeChar ch60 = {81.6105f,1,ch60st}; + +/* char: 0x3d */ + +static const Fl_Glut_StrokeVertex ch61st0[] = +{ + {5.7f,57.1429f}, + {91.4143f,57.1429f} +}; + +static const Fl_Glut_StrokeVertex ch61st1[] = +{ + {5.7f,28.5714f}, + {91.4143f,28.5714f} +}; + +static const Fl_Glut_StrokeStrip ch61st[] = +{ + {2,ch61st0}, + {2,ch61st1} +}; + +static const Fl_Glut_StrokeChar ch61 = {97.2543f,2,ch61st}; + +/* char: 0x3e */ + +static const Fl_Glut_StrokeVertex ch62st0[] = +{ + {2.78f,85.7143f}, + {78.9705f,42.8571f}, + {2.78f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch62st[] = +{ + {3,ch62st0} +}; + +static const Fl_Glut_StrokeChar ch62 = {81.6105f,1,ch62st}; + +/* char: 0x3f */ + +static const Fl_Glut_StrokeVertex ch63st0[] = +{ + {8.42f,76.1905f}, + {8.42f,80.9524f}, + {13.1819f,90.4762f}, + {17.9438f,95.2381f}, + {27.4676f,100.0f}, + {46.5152f,100.0f}, + {56.039f,95.2381f}, + {60.801f,90.4762f}, + {65.5629f,80.9524f}, + {65.5629f,71.4286f}, + {60.801f,61.9048f}, + {56.039f,57.1429f}, + {36.9914f,47.619f}, + {36.9914f,33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch63st1[] = +{ + {36.9914f,9.5238f}, + {32.2295f,4.7619f}, + {36.9914f,0.0f}, + {41.7533f,4.7619f}, + {36.9914f,9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch63st[] = +{ + {14,ch63st0}, + {5,ch63st1} +}; + +static const Fl_Glut_StrokeChar ch63 = {73.9029f,2,ch63st}; + +/* char: 0x40 */ + +static const Fl_Glut_StrokeVertex ch64st0[] = +{ + {49.2171f,52.381f}, + {39.6933f,57.1429f}, + {30.1695f,57.1429f}, + {25.4076f,47.619f}, + {25.4076f,42.8571f}, + {30.1695f,33.3333f}, + {39.6933f,33.3333f}, + {49.2171f,38.0952f} +}; + +static const Fl_Glut_StrokeVertex ch64st1[] = +{ + {49.2171f,57.1429f}, + {49.2171f,38.0952f}, + {53.979f,33.3333f}, + {63.5029f,33.3333f}, + {68.2648f,42.8571f}, + {68.2648f,47.619f}, + {63.5029f,61.9048f}, + {53.979f,71.4286f}, + {39.6933f,76.1905f}, + {34.9314f,76.1905f}, + {20.6457f,71.4286f}, + {11.1219f,61.9048f}, + {6.36f,47.619f}, + {6.36f,42.8571f}, + {11.1219f,28.5714f}, + {20.6457f,19.0476f}, + {34.9314f,14.2857f}, + {39.6933f,14.2857f}, + {53.979f,19.0476f} +}; + +static const Fl_Glut_StrokeStrip ch64st[] = +{ + {8,ch64st0}, + {19,ch64st1} +}; + +static const Fl_Glut_StrokeChar ch64 = {74.3648f,2,ch64st}; + +/* char: 0x41 */ + +static const Fl_Glut_StrokeVertex ch65st0[] = +{ + {40.5952f,100.0f}, + {2.5f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch65st1[] = +{ + {40.5952f,100.0f}, + {78.6905f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch65st2[] = +{ + {16.7857f,33.3333f}, + {64.4048f,33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch65st[] = +{ + {2,ch65st0}, + {2,ch65st1}, + {2,ch65st2} +}; + +static const Fl_Glut_StrokeChar ch65 = {80.4905f,3,ch65st}; + +/* char: 0x42 */ + +static const Fl_Glut_StrokeVertex ch66st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch66st1[] = +{ + {11.42f,100.0f}, + {54.2771f,100.0f}, + {68.5629f,95.2381f}, + {73.3248f,90.4762f}, + {78.0867f,80.9524f}, + {78.0867f,71.4286f}, + {73.3248f,61.9048f}, + {68.5629f,57.1429f}, + {54.2771f,52.381f} +}; + +static const Fl_Glut_StrokeVertex ch66st2[] = +{ + {11.42f,52.381f}, + {54.2771f,52.381f}, + {68.5629f,47.619f}, + {73.3248f,42.8571f}, + {78.0867f,33.3333f}, + {78.0867f,19.0476f}, + {73.3248f,9.5238f}, + {68.5629f,4.7619f}, + {54.2771f,0.0f}, + {11.42f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch66st[] = +{ + {2,ch66st0}, + {9,ch66st1}, + {10,ch66st2} +}; + +static const Fl_Glut_StrokeChar ch66 = {83.6267f,3,ch66st}; + +/* char: 0x43 */ + +static const Fl_Glut_StrokeVertex ch67st0[] = +{ + {78.0886f,76.1905f}, + {73.3267f,85.7143f}, + {63.8029f,95.2381f}, + {54.279f,100.0f}, + {35.2314f,100.0f}, + {25.7076f,95.2381f}, + {16.1838f,85.7143f}, + {11.4219f,76.1905f}, + {6.66f,61.9048f}, + {6.66f,38.0952f}, + {11.4219f,23.8095f}, + {16.1838f,14.2857f}, + {25.7076f,4.7619f}, + {35.2314f,0.0f}, + {54.279f,0.0f}, + {63.8029f,4.7619f}, + {73.3267f,14.2857f}, + {78.0886f,23.8095f} +}; + +static const Fl_Glut_StrokeStrip ch67st[] = +{ + {18,ch67st0} +}; + +static const Fl_Glut_StrokeChar ch67 = {84.4886f,1,ch67st}; + +/* char: 0x44 */ + +static const Fl_Glut_StrokeVertex ch68st0[] = +{ + {11.96f,100.0f}, + {11.96f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch68st1[] = +{ + {11.96f,100.0f}, + {45.2933f,100.0f}, + {59.579f,95.2381f}, + {69.1029f,85.7143f}, + {73.8648f,76.1905f}, + {78.6267f,61.9048f}, + {78.6267f,38.0952f}, + {73.8648f,23.8095f}, + {69.1029f,14.2857f}, + {59.579f,4.7619f}, + {45.2933f,0.0f}, + {11.96f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch68st[] = +{ + {2,ch68st0}, + {12,ch68st1} +}; + +static const Fl_Glut_StrokeChar ch68 = {85.2867f,2,ch68st}; + +/* char: 0x45 */ + +static const Fl_Glut_StrokeVertex ch69st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch69st1[] = +{ + {11.42f,100.0f}, + {73.3248f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch69st2[] = +{ + {11.42f,52.381f}, + {49.5152f,52.381f} +}; + +static const Fl_Glut_StrokeVertex ch69st3[] = +{ + {11.42f,0.0f}, + {73.3248f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch69st[] = +{ + {2,ch69st0}, + {2,ch69st1}, + {2,ch69st2}, + {2,ch69st3} +}; + +static const Fl_Glut_StrokeChar ch69 = {78.1848f,4,ch69st}; + +/* char: 0x46 */ + +static const Fl_Glut_StrokeVertex ch70st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch70st1[] = +{ + {11.42f,100.0f}, + {73.3248f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch70st2[] = +{ + {11.42f,52.381f}, + {49.5152f,52.381f} +}; + +static const Fl_Glut_StrokeStrip ch70st[] = +{ + {2,ch70st0}, + {2,ch70st1}, + {2,ch70st2} +}; + +static const Fl_Glut_StrokeChar ch70 = {78.7448f,3,ch70st}; + +/* char: 0x47 */ + +static const Fl_Glut_StrokeVertex ch71st0[] = +{ + {78.4886f,76.1905f}, + {73.7267f,85.7143f}, + {64.2029f,95.2381f}, + {54.679f,100.0f}, + {35.6314f,100.0f}, + {26.1076f,95.2381f}, + {16.5838f,85.7143f}, + {11.8219f,76.1905f}, + {7.06f,61.9048f}, + {7.06f,38.0952f}, + {11.8219f,23.8095f}, + {16.5838f,14.2857f}, + {26.1076f,4.7619f}, + {35.6314f,0.0f}, + {54.679f,0.0f}, + {64.2029f,4.7619f}, + {73.7267f,14.2857f}, + {78.4886f,23.8095f}, + {78.4886f,38.0952f} +}; + +static const Fl_Glut_StrokeVertex ch71st1[] = +{ + {54.679f,38.0952f}, + {78.4886f,38.0952f} +}; + +static const Fl_Glut_StrokeStrip ch71st[] = +{ + {19,ch71st0}, + {2,ch71st1} +}; + +static const Fl_Glut_StrokeChar ch71 = {89.7686f,2,ch71st}; + +/* char: 0x48 */ + +static const Fl_Glut_StrokeVertex ch72st0[] = +{ + {11.42f,100.0f}, + {11.42f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch72st1[] = +{ + {78.0867f,100.0f}, + {78.0867f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch72st2[] = +{ + {11.42f,52.381f}, + {78.0867f,52.381f} +}; + +static const Fl_Glut_StrokeStrip ch72st[] = +{ + {2,ch72st0}, + {2,ch72st1}, + {2,ch72st2} +}; + +static const Fl_Glut_StrokeChar ch72 = {89.0867f,3,ch72st}; + +/* char: 0x49 */ + +static const Fl_Glut_StrokeVertex ch73st0[] = +{ + {10.86f,100.0f}, + {10.86f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch73st[] = +{ + {2,ch73st0} +}; + +static const Fl_Glut_StrokeChar ch73 = {21.3f,1,ch73st}; + +/* char: 0x4a */ + +static const Fl_Glut_StrokeVertex ch74st0[] = +{ + {50.119f,100.0f}, + {50.119f,23.8095f}, + {45.3571f,9.5238f}, + {40.5952f,4.7619f}, + {31.0714f,0.0f}, + {21.5476f,0.0f}, + {12.0238f,4.7619f}, + {7.2619f,9.5238f}, + {2.5f,23.8095f}, + {2.5f,33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch74st[] = +{ + {10,ch74st0} +}; + +static const Fl_Glut_StrokeChar ch74 = {59.999f,1,ch74st}; + +/* char: 0x4b */ + +static const Fl_Glut_StrokeVertex ch75st0[] = +{ + {11.28f,100.0f}, + {11.28f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch75st1[] = +{ + {77.9467f,100.0f}, + {11.28f,33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch75st2[] = +{ + {35.0895f,57.1429f}, + {77.9467f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch75st[] = +{ + {2,ch75st0}, + {2,ch75st1}, + {2,ch75st2} +}; + +static const Fl_Glut_StrokeChar ch75 = {79.3267f,3,ch75st}; + +/* char: 0x4c */ + +static const Fl_Glut_StrokeVertex ch76st0[] = +{ + {11.68f,100.0f}, + {11.68f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch76st1[] = +{ + {11.68f,0.0f}, + {68.8229f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch76st[] = +{ + {2,ch76st0}, + {2,ch76st1} +}; + +static const Fl_Glut_StrokeChar ch76 = {71.3229f,2,ch76st}; + +/* char: 0x4d */ + +static const Fl_Glut_StrokeVertex ch77st0[] = +{ + {10.86f,100.0f}, + {10.86f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch77st1[] = +{ + {10.86f,100.0f}, + {48.9552f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch77st2[] = +{ + {87.0505f,100.0f}, + {48.9552f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch77st3[] = +{ + {87.0505f,100.0f}, + {87.0505f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch77st[] = +{ + {2,ch77st0}, + {2,ch77st1}, + {2,ch77st2}, + {2,ch77st3} +}; + +static const Fl_Glut_StrokeChar ch77 = {97.2105f,4,ch77st}; + +/* char: 0x4e */ + +static const Fl_Glut_StrokeVertex ch78st0[] = +{ + {11.14f,100.0f}, + {11.14f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch78st1[] = +{ + {11.14f,100.0f}, + {77.8067f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch78st2[] = +{ + {77.8067f,100.0f}, + {77.8067f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch78st[] = +{ + {2,ch78st0}, + {2,ch78st1}, + {2,ch78st2} +}; + +static const Fl_Glut_StrokeChar ch78 = {88.8067f,3,ch78st}; + +/* char: 0x4f */ + +static const Fl_Glut_StrokeVertex ch79st0[] = +{ + {34.8114f,100.0f}, + {25.2876f,95.2381f}, + {15.7638f,85.7143f}, + {11.0019f,76.1905f}, + {6.24f,61.9048f}, + {6.24f,38.0952f}, + {11.0019f,23.8095f}, + {15.7638f,14.2857f}, + {25.2876f,4.7619f}, + {34.8114f,0.0f}, + {53.859f,0.0f}, + {63.3829f,4.7619f}, + {72.9067f,14.2857f}, + {77.6686f,23.8095f}, + {82.4305f,38.0952f}, + {82.4305f,61.9048f}, + {77.6686f,76.1905f}, + {72.9067f,85.7143f}, + {63.3829f,95.2381f}, + {53.859f,100.0f}, + {34.8114f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch79st[] = +{ + {21,ch79st0} +}; + +static const Fl_Glut_StrokeChar ch79 = {88.8305f,1,ch79st}; + +/* char: 0x50 */ + +static const Fl_Glut_StrokeVertex ch80st0[] = +{ + {12.1f,100.0f}, + {12.1f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch80st1[] = +{ + {12.1f,100.0f}, + {54.9571f,100.0f}, + {69.2429f,95.2381f}, + {74.0048f,90.4762f}, + {78.7667f,80.9524f}, + {78.7667f,66.6667f}, + {74.0048f,57.1429f}, + {69.2429f,52.381f}, + {54.9571f,47.619f}, + {12.1f,47.619f} +}; + +static const Fl_Glut_StrokeStrip ch80st[] = +{ + {2,ch80st0}, + {10,ch80st1} +}; + +static const Fl_Glut_StrokeChar ch80 = {85.6667f,2,ch80st}; + +/* char: 0x51 */ + +static const Fl_Glut_StrokeVertex ch81st0[] = +{ + {33.8714f,100.0f}, + {24.3476f,95.2381f}, + {14.8238f,85.7143f}, + {10.0619f,76.1905f}, + {5.3f,61.9048f}, + {5.3f,38.0952f}, + {10.0619f,23.8095f}, + {14.8238f,14.2857f}, + {24.3476f,4.7619f}, + {33.8714f,0.0f}, + {52.919f,0.0f}, + {62.4429f,4.7619f}, + {71.9667f,14.2857f}, + {76.7286f,23.8095f}, + {81.4905f,38.0952f}, + {81.4905f,61.9048f}, + {76.7286f,76.1905f}, + {71.9667f,85.7143f}, + {62.4429f,95.2381f}, + {52.919f,100.0f}, + {33.8714f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch81st1[] = +{ + {48.1571f,19.0476f}, + {76.7286f,-9.5238f} +}; + +static const Fl_Glut_StrokeStrip ch81st[] = +{ + {21,ch81st0}, + {2,ch81st1} +}; + +static const Fl_Glut_StrokeChar ch81 = {88.0905f,2,ch81st}; + +/* char: 0x52 */ + +static const Fl_Glut_StrokeVertex ch82st0[] = +{ + {11.68f,100.0f}, + {11.68f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch82st1[] = +{ + {11.68f,100.0f}, + {54.5371f,100.0f}, + {68.8229f,95.2381f}, + {73.5848f,90.4762f}, + {78.3467f,80.9524f}, + {78.3467f,71.4286f}, + {73.5848f,61.9048f}, + {68.8229f,57.1429f}, + {54.5371f,52.381f}, + {11.68f,52.381f} +}; + +static const Fl_Glut_StrokeVertex ch82st2[] = +{ + {45.0133f,52.381f}, + {78.3467f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch82st[] = +{ + {2,ch82st0}, + {10,ch82st1}, + {2,ch82st2} +}; + +static const Fl_Glut_StrokeChar ch82 = {82.3667f,3,ch82st}; + +/* char: 0x53 */ + +static const Fl_Glut_StrokeVertex ch83st0[] = +{ + {74.6667f,85.7143f}, + {65.1429f,95.2381f}, + {50.8571f,100.0f}, + {31.8095f,100.0f}, + {17.5238f,95.2381f}, + {8.0f,85.7143f}, + {8.0f,76.1905f}, + {12.7619f,66.6667f}, + {17.5238f,61.9048f}, + {27.0476f,57.1429f}, + {55.619f,47.619f}, + {65.1429f,42.8571f}, + {69.9048f,38.0952f}, + {74.6667f,28.5714f}, + {74.6667f,14.2857f}, + {65.1429f,4.7619f}, + {50.8571f,0.0f}, + {31.8095f,0.0f}, + {17.5238f,4.7619f}, + {8.0f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch83st[] = +{ + {20,ch83st0} +}; + +static const Fl_Glut_StrokeChar ch83 = {80.8267f,1,ch83st}; + +/* char: 0x54 */ + +static const Fl_Glut_StrokeVertex ch84st0[] = +{ + {35.6933f,100.0f}, + {35.6933f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch84st1[] = +{ + {2.36f,100.0f}, + {69.0267f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch84st[] = +{ + {2,ch84st0}, + {2,ch84st1} +}; + +static const Fl_Glut_StrokeChar ch84 = {71.9467f,2,ch84st}; + +/* char: 0x55 */ + +static const Fl_Glut_StrokeVertex ch85st0[] = +{ + {11.54f,100.0f}, + {11.54f,28.5714f}, + {16.3019f,14.2857f}, + {25.8257f,4.7619f}, + {40.1114f,0.0f}, + {49.6352f,0.0f}, + {63.921f,4.7619f}, + {73.4448f,14.2857f}, + {78.2067f,28.5714f}, + {78.2067f,100.0f} +}; + +static const Fl_Glut_StrokeStrip ch85st[] = +{ + {10,ch85st0} +}; + +static const Fl_Glut_StrokeChar ch85 = {89.4867f,1,ch85st}; + +/* char: 0x56 */ + +static const Fl_Glut_StrokeVertex ch86st0[] = +{ + {2.36f,100.0f}, + {40.4552f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch86st1[] = +{ + {78.5505f,100.0f}, + {40.4552f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch86st[] = +{ + {2,ch86st0}, + {2,ch86st1} +}; + +static const Fl_Glut_StrokeChar ch86 = {81.6105f,2,ch86st}; + +/* char: 0x57 */ + +static const Fl_Glut_StrokeVertex ch87st0[] = +{ + {2.22f,100.0f}, + {26.0295f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch87st1[] = +{ + {49.839f,100.0f}, + {26.0295f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch87st2[] = +{ + {49.839f,100.0f}, + {73.6486f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch87st3[] = +{ + {97.4581f,100.0f}, + {73.6486f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch87st[] = +{ + {2,ch87st0}, + {2,ch87st1}, + {2,ch87st2}, + {2,ch87st3} +}; + +static const Fl_Glut_StrokeChar ch87 = {100.518f,4,ch87st}; + +/* char: 0x58 */ + +static const Fl_Glut_StrokeVertex ch88st0[] = +{ + {2.5f,100.0f}, + {69.1667f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch88st1[] = +{ + {69.1667f,100.0f}, + {2.5f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch88st[] = +{ + {2,ch88st0}, + {2,ch88st1} +}; + +static const Fl_Glut_StrokeChar ch88 = {72.3667f,2,ch88st}; + +/* char: 0x59 */ + +static const Fl_Glut_StrokeVertex ch89st0[] = +{ + {1.52f,100.0f}, + {39.6152f,52.381f}, + {39.6152f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch89st1[] = +{ + {77.7105f,100.0f}, + {39.6152f,52.381f} +}; + +static const Fl_Glut_StrokeStrip ch89st[] = +{ + {3,ch89st0}, + {2,ch89st1} +}; + +static const Fl_Glut_StrokeChar ch89 = {79.6505f,2,ch89st}; + +/* char: 0x5a */ + +static const Fl_Glut_StrokeVertex ch90st0[] = +{ + {69.1667f,100.0f}, + {2.5f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch90st1[] = +{ + {2.5f,100.0f}, + {69.1667f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch90st2[] = +{ + {2.5f,0.0f}, + {69.1667f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch90st[] = +{ + {2,ch90st0}, + {2,ch90st1}, + {2,ch90st2} +}; + +static const Fl_Glut_StrokeChar ch90 = {73.7467f,3,ch90st}; + +/* char: 0x5b */ + +static const Fl_Glut_StrokeVertex ch91st0[] = +{ + {7.78f,119.048f}, + {7.78f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch91st1[] = +{ + {12.5419f,119.048f}, + {12.5419f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch91st2[] = +{ + {7.78f,119.048f}, + {41.1133f,119.048f} +}; + +static const Fl_Glut_StrokeVertex ch91st3[] = +{ + {7.78f,-33.3333f}, + {41.1133f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch91st[] = +{ + {2,ch91st0}, + {2,ch91st1}, + {2,ch91st2}, + {2,ch91st3} +}; + +static const Fl_Glut_StrokeChar ch91 = {46.1133f,4,ch91st}; + +/* char: 0x5c */ + +static const Fl_Glut_StrokeVertex ch92st0[] = +{ + {5.84f,100.0f}, + {72.5067f,-14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch92st[] = +{ + {2,ch92st0} +}; + +static const Fl_Glut_StrokeChar ch92 = {78.2067f,1,ch92st}; + +/* char: 0x5d */ + +static const Fl_Glut_StrokeVertex ch93st0[] = +{ + {33.0114f,119.048f}, + {33.0114f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch93st1[] = +{ + {37.7733f,119.048f}, + {37.7733f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch93st2[] = +{ + {4.44f,119.048f}, + {37.7733f,119.048f} +}; + +static const Fl_Glut_StrokeVertex ch93st3[] = +{ + {4.44f,-33.3333f}, + {37.7733f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch93st[] = +{ + {2,ch93st0}, + {2,ch93st1}, + {2,ch93st2}, + {2,ch93st3} +}; + +static const Fl_Glut_StrokeChar ch93 = {46.3933f,4,ch93st}; + +/* char: 0x5e */ + +static const Fl_Glut_StrokeVertex ch94st0[] = +{ + {44.0752f,109.524f}, + {5.98f,42.8571f} +}; + +static const Fl_Glut_StrokeVertex ch94st1[] = +{ + {44.0752f,109.524f}, + {82.1705f,42.8571f} +}; + +static const Fl_Glut_StrokeStrip ch94st[] = +{ + {2,ch94st0}, + {2,ch94st1} +}; + +static const Fl_Glut_StrokeChar ch94 = {90.2305f,2,ch94st}; + +/* char: 0x5f */ + +static const Fl_Glut_StrokeVertex ch95st0[] = +{ + {-1.1f,-33.3333f}, + {103.662f,-33.3333f}, + {103.662f,-28.5714f}, + {-1.1f,-28.5714f}, + {-1.1f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch95st[] = +{ + {5,ch95st0} +}; + +static const Fl_Glut_StrokeChar ch95 = {104.062f,1,ch95st}; + +/* char: 0x60 */ + +static const Fl_Glut_StrokeVertex ch96st0[] = +{ + {33.0219f,100.0f}, + {56.8314f,71.4286f} +}; + +static const Fl_Glut_StrokeVertex ch96st1[] = +{ + {33.0219f,100.0f}, + {28.26f,95.2381f}, + {56.8314f,71.4286f} +}; + +static const Fl_Glut_StrokeStrip ch96st[] = +{ + {2,ch96st0}, + {3,ch96st1} +}; + +static const Fl_Glut_StrokeChar ch96 = {83.5714f,2,ch96st}; + +/* char: 0x61 */ + +static const Fl_Glut_StrokeVertex ch97st0[] = +{ + {63.8229f,66.6667f}, + {63.8229f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch97st1[] = +{ + {63.8229f,52.381f}, + {54.299f,61.9048f}, + {44.7752f,66.6667f}, + {30.4895f,66.6667f}, + {20.9657f,61.9048f}, + {11.4419f,52.381f}, + {6.68f,38.0952f}, + {6.68f,28.5714f}, + {11.4419f,14.2857f}, + {20.9657f,4.7619f}, + {30.4895f,0.0f}, + {44.7752f,0.0f}, + {54.299f,4.7619f}, + {63.8229f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch97st[] = +{ + {2,ch97st0}, + {14,ch97st1} +}; + +static const Fl_Glut_StrokeChar ch97 = {66.6029f,2,ch97st}; + +/* char: 0x62 */ + +static const Fl_Glut_StrokeVertex ch98st0[] = +{ + {8.76f,100.0f}, + {8.76f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch98st1[] = +{ + {8.76f,52.381f}, + {18.2838f,61.9048f}, + {27.8076f,66.6667f}, + {42.0933f,66.6667f}, + {51.6171f,61.9048f}, + {61.141f,52.381f}, + {65.9029f,38.0952f}, + {65.9029f,28.5714f}, + {61.141f,14.2857f}, + {51.6171f,4.7619f}, + {42.0933f,0.0f}, + {27.8076f,0.0f}, + {18.2838f,4.7619f}, + {8.76f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch98st[] = +{ + {2,ch98st0}, + {14,ch98st1} +}; + +static const Fl_Glut_StrokeChar ch98 = {70.4629f,2,ch98st}; + +/* char: 0x63 */ + +static const Fl_Glut_StrokeVertex ch99st0[] = +{ + {62.6629f,52.381f}, + {53.139f,61.9048f}, + {43.6152f,66.6667f}, + {29.3295f,66.6667f}, + {19.8057f,61.9048f}, + {10.2819f,52.381f}, + {5.52f,38.0952f}, + {5.52f,28.5714f}, + {10.2819f,14.2857f}, + {19.8057f,4.7619f}, + {29.3295f,0.0f}, + {43.6152f,0.0f}, + {53.139f,4.7619f}, + {62.6629f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch99st[] = +{ + {14,ch99st0} +}; + +static const Fl_Glut_StrokeChar ch99 = {68.9229f,1,ch99st}; + +/* char: 0x64 */ + +static const Fl_Glut_StrokeVertex ch100st0[] = +{ + {61.7829f,100.0f}, + {61.7829f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch100st1[] = +{ + {61.7829f,52.381f}, + {52.259f,61.9048f}, + {42.7352f,66.6667f}, + {28.4495f,66.6667f}, + {18.9257f,61.9048f}, + {9.4019f,52.381f}, + {4.64f,38.0952f}, + {4.64f,28.5714f}, + {9.4019f,14.2857f}, + {18.9257f,4.7619f}, + {28.4495f,0.0f}, + {42.7352f,0.0f}, + {52.259f,4.7619f}, + {61.7829f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch100st[] = +{ + {2,ch100st0}, + {14,ch100st1} +}; + +static const Fl_Glut_StrokeChar ch100 = {70.2629f,2,ch100st}; + +/* char: 0x65 */ + +static const Fl_Glut_StrokeVertex ch101st0[] = +{ + {5.72f,38.0952f}, + {62.8629f,38.0952f}, + {62.8629f,47.619f}, + {58.101f,57.1429f}, + {53.339f,61.9048f}, + {43.8152f,66.6667f}, + {29.5295f,66.6667f}, + {20.0057f,61.9048f}, + {10.4819f,52.381f}, + {5.72f,38.0952f}, + {5.72f,28.5714f}, + {10.4819f,14.2857f}, + {20.0057f,4.7619f}, + {29.5295f,0.0f}, + {43.8152f,0.0f}, + {53.339f,4.7619f}, + {62.8629f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch101st[] = +{ + {17,ch101st0} +}; + +static const Fl_Glut_StrokeChar ch101 = {68.5229f,1,ch101st}; + +/* char: 0x66 */ + +static const Fl_Glut_StrokeVertex ch102st0[] = +{ + {38.7752f,100.0f}, + {29.2514f,100.0f}, + {19.7276f,95.2381f}, + {14.9657f,80.9524f}, + {14.9657f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch102st1[] = +{ + {0.68f,66.6667f}, + {34.0133f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch102st[] = +{ + {5,ch102st0}, + {2,ch102st1} +}; + +static const Fl_Glut_StrokeChar ch102 = {38.6552f,2,ch102st}; + +/* char: 0x67 */ + +static const Fl_Glut_StrokeVertex ch103st0[] = +{ + {62.5029f,66.6667f}, + {62.5029f,-9.5238f}, + {57.741f,-23.8095f}, + {52.979f,-28.5714f}, + {43.4552f,-33.3333f}, + {29.1695f,-33.3333f}, + {19.6457f,-28.5714f} +}; + +static const Fl_Glut_StrokeVertex ch103st1[] = +{ + {62.5029f,52.381f}, + {52.979f,61.9048f}, + {43.4552f,66.6667f}, + {29.1695f,66.6667f}, + {19.6457f,61.9048f}, + {10.1219f,52.381f}, + {5.36f,38.0952f}, + {5.36f,28.5714f}, + {10.1219f,14.2857f}, + {19.6457f,4.7619f}, + {29.1695f,0.0f}, + {43.4552f,0.0f}, + {52.979f,4.7619f}, + {62.5029f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch103st[] = +{ + {7,ch103st0}, + {14,ch103st1} +}; + +static const Fl_Glut_StrokeChar ch103 = {70.9829f,2,ch103st}; + +/* char: 0x68 */ + +static const Fl_Glut_StrokeVertex ch104st0[] = +{ + {9.6f,100.0f}, + {9.6f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch104st1[] = +{ + {9.6f,47.619f}, + {23.8857f,61.9048f}, + {33.4095f,66.6667f}, + {47.6952f,66.6667f}, + {57.219f,61.9048f}, + {61.981f,47.619f}, + {61.981f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch104st[] = +{ + {2,ch104st0}, + {7,ch104st1} +}; + +static const Fl_Glut_StrokeChar ch104 = {71.021f,2,ch104st}; + +/* char: 0x69 */ + +static const Fl_Glut_StrokeVertex ch105st0[] = +{ + {10.02f,100.0f}, + {14.7819f,95.2381f}, + {19.5438f,100.0f}, + {14.7819f,104.762f}, + {10.02f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch105st1[] = +{ + {14.7819f,66.6667f}, + {14.7819f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch105st[] = +{ + {5,ch105st0}, + {2,ch105st1} +}; + +static const Fl_Glut_StrokeChar ch105 = {28.8638f,2,ch105st}; + +/* char: 0x6a */ + +static const Fl_Glut_StrokeVertex ch106st0[] = +{ + {17.3876f,100.0f}, + {22.1495f,95.2381f}, + {26.9114f,100.0f}, + {22.1495f,104.762f}, + {17.3876f,100.0f} +}; + +static const Fl_Glut_StrokeVertex ch106st1[] = +{ + {22.1495f,66.6667f}, + {22.1495f,-14.2857f}, + {17.3876f,-28.5714f}, + {7.8638f,-33.3333f}, + {-1.66f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch106st[] = +{ + {5,ch106st0}, + {5,ch106st1} +}; + +static const Fl_Glut_StrokeChar ch106 = {36.2314f,2,ch106st}; + +/* char: 0x6b */ + +static const Fl_Glut_StrokeVertex ch107st0[] = +{ + {9.6f,100.0f}, + {9.6f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch107st1[] = +{ + {57.219f,66.6667f}, + {9.6f,19.0476f} +}; + +static const Fl_Glut_StrokeVertex ch107st2[] = +{ + {28.6476f,38.0952f}, + {61.981f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch107st[] = +{ + {2,ch107st0}, + {2,ch107st1}, + {2,ch107st2} +}; + +static const Fl_Glut_StrokeChar ch107 = {62.521f,3,ch107st}; + +/* char: 0x6c */ + +static const Fl_Glut_StrokeVertex ch108st0[] = +{ + {10.02f,100.0f}, + {10.02f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch108st[] = +{ + {2,ch108st0} +}; + +static const Fl_Glut_StrokeChar ch108 = {19.34f,1,ch108st}; + +/* char: 0x6d */ + +static const Fl_Glut_StrokeVertex ch109st0[] = +{ + {9.6f,66.6667f}, + {9.6f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch109st1[] = +{ + {9.6f,47.619f}, + {23.8857f,61.9048f}, + {33.4095f,66.6667f}, + {47.6952f,66.6667f}, + {57.219f,61.9048f}, + {61.981f,47.619f}, + {61.981f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch109st2[] = +{ + {61.981f,47.619f}, + {76.2667f,61.9048f}, + {85.7905f,66.6667f}, + {100.076f,66.6667f}, + {109.6f,61.9048f}, + {114.362f,47.619f}, + {114.362f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch109st[] = +{ + {2,ch109st0}, + {7,ch109st1}, + {7,ch109st2} +}; + +static const Fl_Glut_StrokeChar ch109 = {123.962f,3,ch109st}; + +/* char: 0x6e */ + +static const Fl_Glut_StrokeVertex ch110st0[] = +{ + {9.18f,66.6667f}, + {9.18f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch110st1[] = +{ + {9.18f,47.619f}, + {23.4657f,61.9048f}, + {32.9895f,66.6667f}, + {47.2752f,66.6667f}, + {56.799f,61.9048f}, + {61.561f,47.619f}, + {61.561f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch110st[] = +{ + {2,ch110st0}, + {7,ch110st1} +}; + +static const Fl_Glut_StrokeChar ch110 = {70.881f,2,ch110st}; + +/* char: 0x6f */ + +static const Fl_Glut_StrokeVertex ch111st0[] = +{ + {28.7895f,66.6667f}, + {19.2657f,61.9048f}, + {9.7419f,52.381f}, + {4.98f,38.0952f}, + {4.98f,28.5714f}, + {9.7419f,14.2857f}, + {19.2657f,4.7619f}, + {28.7895f,0.0f}, + {43.0752f,0.0f}, + {52.599f,4.7619f}, + {62.1229f,14.2857f}, + {66.8848f,28.5714f}, + {66.8848f,38.0952f}, + {62.1229f,52.381f}, + {52.599f,61.9048f}, + {43.0752f,66.6667f}, + {28.7895f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch111st[] = +{ + {17,ch111st0} +}; + +static const Fl_Glut_StrokeChar ch111 = {71.7448f,1,ch111st}; + +/* char: 0x70 */ + +static const Fl_Glut_StrokeVertex ch112st0[] = +{ + {9.46f,66.6667f}, + {9.46f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch112st1[] = +{ + {9.46f,52.381f}, + {18.9838f,61.9048f}, + {28.5076f,66.6667f}, + {42.7933f,66.6667f}, + {52.3171f,61.9048f}, + {61.841f,52.381f}, + {66.6029f,38.0952f}, + {66.6029f,28.5714f}, + {61.841f,14.2857f}, + {52.3171f,4.7619f}, + {42.7933f,0.0f}, + {28.5076f,0.0f}, + {18.9838f,4.7619f}, + {9.46f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch112st[] = +{ + {2,ch112st0}, + {14,ch112st1} +}; + +static const Fl_Glut_StrokeChar ch112 = {70.8029f,2,ch112st}; + +/* char: 0x71 */ + +static const Fl_Glut_StrokeVertex ch113st0[] = +{ + {61.9829f,66.6667f}, + {61.9829f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch113st1[] = +{ + {61.9829f,52.381f}, + {52.459f,61.9048f}, + {42.9352f,66.6667f}, + {28.6495f,66.6667f}, + {19.1257f,61.9048f}, + {9.6019f,52.381f}, + {4.84f,38.0952f}, + {4.84f,28.5714f}, + {9.6019f,14.2857f}, + {19.1257f,4.7619f}, + {28.6495f,0.0f}, + {42.9352f,0.0f}, + {52.459f,4.7619f}, + {61.9829f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch113st[] = +{ + {2,ch113st0}, + {14,ch113st1} +}; + +static const Fl_Glut_StrokeChar ch113 = {70.7429f,2,ch113st}; + +/* char: 0x72 */ + +static const Fl_Glut_StrokeVertex ch114st0[] = +{ + {9.46f,66.6667f}, + {9.46f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch114st1[] = +{ + {9.46f,38.0952f}, + {14.2219f,52.381f}, + {23.7457f,61.9048f}, + {33.2695f,66.6667f}, + {47.5552f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch114st[] = +{ + {2,ch114st0}, + {5,ch114st1} +}; + +static const Fl_Glut_StrokeChar ch114 = {49.4952f,2,ch114st}; + +/* char: 0x73 */ + +static const Fl_Glut_StrokeVertex ch115st0[] = +{ + {57.081f,52.381f}, + {52.319f,61.9048f}, + {38.0333f,66.6667f}, + {23.7476f,66.6667f}, + {9.4619f,61.9048f}, + {4.7f,52.381f}, + {9.4619f,42.8571f}, + {18.9857f,38.0952f}, + {42.7952f,33.3333f}, + {52.319f,28.5714f}, + {57.081f,19.0476f}, + {57.081f,14.2857f}, + {52.319f,4.7619f}, + {38.0333f,0.0f}, + {23.7476f,0.0f}, + {9.4619f,4.7619f}, + {4.7f,14.2857f} +}; + +static const Fl_Glut_StrokeStrip ch115st[] = +{ + {17,ch115st0} +}; + +static const Fl_Glut_StrokeChar ch115 = {62.321f,1,ch115st}; + +/* char: 0x74 */ + +static const Fl_Glut_StrokeVertex ch116st0[] = +{ + {14.8257f,100.0f}, + {14.8257f,19.0476f}, + {19.5876f,4.7619f}, + {29.1114f,0.0f}, + {38.6352f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch116st1[] = +{ + {0.54f,66.6667f}, + {33.8733f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch116st[] = +{ + {5,ch116st0}, + {2,ch116st1} +}; + +static const Fl_Glut_StrokeChar ch116 = {39.3152f,2,ch116st}; + +/* char: 0x75 */ + +static const Fl_Glut_StrokeVertex ch117st0[] = +{ + {9.46f,66.6667f}, + {9.46f,19.0476f}, + {14.2219f,4.7619f}, + {23.7457f,0.0f}, + {38.0314f,0.0f}, + {47.5552f,4.7619f}, + {61.841f,19.0476f} +}; + +static const Fl_Glut_StrokeVertex ch117st1[] = +{ + {61.841f,66.6667f}, + {61.841f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch117st[] = +{ + {7,ch117st0}, + {2,ch117st1} +}; + +static const Fl_Glut_StrokeChar ch117 = {71.161f,2,ch117st}; + +/* char: 0x76 */ + +static const Fl_Glut_StrokeVertex ch118st0[] = +{ + {1.8f,66.6667f}, + {30.3714f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch118st1[] = +{ + {58.9429f,66.6667f}, + {30.3714f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch118st[] = +{ + {2,ch118st0}, + {2,ch118st1} +}; + +static const Fl_Glut_StrokeChar ch118 = {60.6029f,2,ch118st}; + +/* char: 0x77 */ + +static const Fl_Glut_StrokeVertex ch119st0[] = +{ + {2.5f,66.6667f}, + {21.5476f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch119st1[] = +{ + {40.5952f,66.6667f}, + {21.5476f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch119st2[] = +{ + {40.5952f,66.6667f}, + {59.6429f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch119st3[] = +{ + {78.6905f,66.6667f}, + {59.6429f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch119st[] = +{ + {2,ch119st0}, + {2,ch119st1}, + {2,ch119st2}, + {2,ch119st3} +}; + +static const Fl_Glut_StrokeChar ch119 = {80.4905f,4,ch119st}; + +/* char: 0x78 */ + +static const Fl_Glut_StrokeVertex ch120st0[] = +{ + {1.66f,66.6667f}, + {54.041f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch120st1[] = +{ + {54.041f,66.6667f}, + {1.66f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch120st[] = +{ + {2,ch120st0}, + {2,ch120st1} +}; + +static const Fl_Glut_StrokeChar ch120 = {56.401f,2,ch120st}; + +/* char: 0x79 */ + +static const Fl_Glut_StrokeVertex ch121st0[] = +{ + {6.5619f,66.6667f}, + {35.1333f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch121st1[] = +{ + {63.7048f,66.6667f}, + {35.1333f,0.0f}, + {25.6095f,-19.0476f}, + {16.0857f,-28.5714f}, + {6.5619f,-33.3333f}, + {1.8f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch121st[] = +{ + {2,ch121st0}, + {6,ch121st1} +}; + +static const Fl_Glut_StrokeChar ch121 = {66.0648f,2,ch121st}; + +/* char: 0x7a */ + +static const Fl_Glut_StrokeVertex ch122st0[] = +{ + {56.821f,66.6667f}, + {4.44f,0.0f} +}; + +static const Fl_Glut_StrokeVertex ch122st1[] = +{ + {4.44f,66.6667f}, + {56.821f,66.6667f} +}; + +static const Fl_Glut_StrokeVertex ch122st2[] = +{ + {4.44f,0.0f}, + {56.821f,0.0f} +}; + +static const Fl_Glut_StrokeStrip ch122st[] = +{ + {2,ch122st0}, + {2,ch122st1}, + {2,ch122st2} +}; + +static const Fl_Glut_StrokeChar ch122 = {61.821f,3,ch122st}; + +/* char: 0x7b */ + +static const Fl_Glut_StrokeVertex ch123st0[] = +{ + {31.1895f,119.048f}, + {21.6657f,114.286f}, + {16.9038f,109.524f}, + {12.1419f,100.0f}, + {12.1419f,90.4762f}, + {16.9038f,80.9524f}, + {21.6657f,76.1905f}, + {26.4276f,66.6667f}, + {26.4276f,57.1429f}, + {16.9038f,47.619f} +}; + +static const Fl_Glut_StrokeVertex ch123st1[] = +{ + {21.6657f,114.286f}, + {16.9038f,104.762f}, + {16.9038f,95.2381f}, + {21.6657f,85.7143f}, + {26.4276f,80.9524f}, + {31.1895f,71.4286f}, + {31.1895f,61.9048f}, + {26.4276f,52.381f}, + {7.38f,42.8571f}, + {26.4276f,33.3333f}, + {31.1895f,23.8095f}, + {31.1895f,14.2857f}, + {26.4276f,4.7619f}, + {21.6657f,0.0f}, + {16.9038f,-9.5238f}, + {16.9038f,-19.0476f}, + {21.6657f,-28.5714f} +}; + +static const Fl_Glut_StrokeVertex ch123st2[] = +{ + {16.9038f,38.0952f}, + {26.4276f,28.5714f}, + {26.4276f,19.0476f}, + {21.6657f,9.5238f}, + {16.9038f,4.7619f}, + {12.1419f,-4.7619f}, + {12.1419f,-14.2857f}, + {16.9038f,-23.8095f}, + {21.6657f,-28.5714f}, + {31.1895f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch123st[] = +{ + {10,ch123st0}, + {17,ch123st1}, + {10,ch123st2} +}; + +static const Fl_Glut_StrokeChar ch123 = {41.6295f,3,ch123st}; + +/* char: 0x7c */ + +static const Fl_Glut_StrokeVertex ch124st0[] = +{ + {11.54f,119.048f}, + {11.54f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch124st[] = +{ + {2,ch124st0} +}; + +static const Fl_Glut_StrokeChar ch124 = {23.78f,1,ch124st}; + +/* char: 0x7d */ + +static const Fl_Glut_StrokeVertex ch125st0[] = +{ + {9.18f,119.048f}, + {18.7038f,114.286f}, + {23.4657f,109.524f}, + {28.2276f,100.0f}, + {28.2276f,90.4762f}, + {23.4657f,80.9524f}, + {18.7038f,76.1905f}, + {13.9419f,66.6667f}, + {13.9419f,57.1429f}, + {23.4657f,47.619f} +}; + +static const Fl_Glut_StrokeVertex ch125st1[] = +{ + {18.7038f,114.286f}, + {23.4657f,104.762f}, + {23.4657f,95.2381f}, + {18.7038f,85.7143f}, + {13.9419f,80.9524f}, + {9.18f,71.4286f}, + {9.18f,61.9048f}, + {13.9419f,52.381f}, + {32.9895f,42.8571f}, + {13.9419f,33.3333f}, + {9.18f,23.8095f}, + {9.18f,14.2857f}, + {13.9419f,4.7619f}, + {18.7038f,0.0f}, + {23.4657f,-9.5238f}, + {23.4657f,-19.0476f}, + {18.7038f,-28.5714f} +}; + +static const Fl_Glut_StrokeVertex ch125st2[] = +{ + {23.4657f,38.0952f}, + {13.9419f,28.5714f}, + {13.9419f,19.0476f}, + {18.7038f,9.5238f}, + {23.4657f,4.7619f}, + {28.2276f,-4.7619f}, + {28.2276f,-14.2857f}, + {23.4657f,-23.8095f}, + {18.7038f,-28.5714f}, + {9.18f,-33.3333f} +}; + +static const Fl_Glut_StrokeStrip ch125st[] = +{ + {10,ch125st0}, + {17,ch125st1}, + {10,ch125st2} +}; + +static const Fl_Glut_StrokeChar ch125 = {41.4695f,3,ch125st}; + +/* char: 0x7e */ + +static const Fl_Glut_StrokeVertex ch126st0[] = +{ + {2.92f,28.5714f}, + {2.92f,38.0952f}, + {7.6819f,52.381f}, + {17.2057f,57.1429f}, + {26.7295f,57.1429f}, + {36.2533f,52.381f}, + {55.301f,38.0952f}, + {64.8248f,33.3333f}, + {74.3486f,33.3333f}, + {83.8724f,38.0952f}, + {88.6343f,47.619f} +}; + +static const Fl_Glut_StrokeVertex ch126st1[] = +{ + {2.92f,38.0952f}, + {7.6819f,47.619f}, + {17.2057f,52.381f}, + {26.7295f,52.381f}, + {36.2533f,47.619f}, + {55.301f,33.3333f}, + {64.8248f,28.5714f}, + {74.3486f,28.5714f}, + {83.8724f,33.3333f}, + {88.6343f,47.619f}, + {88.6343f,57.1429f} +}; + +static const Fl_Glut_StrokeStrip ch126st[] = +{ + {11,ch126st0}, + {11,ch126st1} +}; + +static const Fl_Glut_StrokeChar ch126 = {91.2743f,2,ch126st}; + +/* char: 0x7f */ + +static const Fl_Glut_StrokeVertex ch127st0[] = +{ + {52.381f,100.0f}, + {14.2857f,-33.3333f} +}; + +static const Fl_Glut_StrokeVertex ch127st1[] = +{ + {28.5714f,66.6667f}, + {14.2857f,61.9048f}, + {4.7619f,52.381f}, + {0.0f,38.0952f}, + {0.0f,23.8095f}, + {4.7619f,14.2857f}, + {14.2857f,4.7619f}, + {28.5714f,0.0f}, + {38.0952f,0.0f}, + {52.381f,4.7619f}, + {61.9048f,14.2857f}, + {66.6667f,28.5714f}, + {66.6667f,42.8571f}, + {61.9048f,52.381f}, + {52.381f,61.9048f}, + {38.0952f,66.6667f}, + {28.5714f,66.6667f} +}; + +static const Fl_Glut_StrokeStrip ch127st[] = +{ + {2,ch127st0}, + {17,ch127st1} +}; + +static const Fl_Glut_StrokeChar ch127 = {66.6667f,2,ch127st}; + +static const Fl_Glut_StrokeChar *chars[] = +{ + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + &ch32, &ch33, &ch34, &ch35, &ch36, &ch37, &ch38, &ch39, + &ch40, &ch41, &ch42, &ch43, &ch44, &ch45, &ch46, &ch47, + &ch48, &ch49, &ch50, &ch51, &ch52, &ch53, &ch54, &ch55, + &ch56, &ch57, &ch58, &ch59, &ch60, &ch61, &ch62, &ch63, + &ch64, &ch65, &ch66, &ch67, &ch68, &ch69, &ch70, &ch71, + &ch72, &ch73, &ch74, &ch75, &ch76, &ch77, &ch78, &ch79, + &ch80, &ch81, &ch82, &ch83, &ch84, &ch85, &ch86, &ch87, + &ch88, &ch89, &ch90, &ch91, &ch92, &ch93, &ch94, &ch95, + &ch96, &ch97, &ch98, &ch99, &ch100, &ch101, &ch102, &ch103, + &ch104, &ch105, &ch106, &ch107, &ch108, &ch109, &ch110, &ch111, + &ch112, &ch113, &ch114, &ch115, &ch116, &ch117, &ch118, &ch119, + &ch120, &ch121, &ch122, &ch123, &ch124, &ch125, &ch126, &ch127 +}; + +Fl_Glut_StrokeFont glutStrokeRoman = {(char *)"Roman",128,152.381f,chars}; diff --git a/third_party/windows/fltk-1.1.10/src/freeglut_teapot.cxx b/third_party/windows/fltk-1.1.10/src/freeglut_teapot.cxx new file mode 100644 index 0000000..bdb5f00 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/freeglut_teapot.cxx @@ -0,0 +1,164 @@ +/* + * freeglut_teapot.c + * + * Teapot(tm) rendering code. + * + * Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. + * Written by Pawel W. Olszta, + * Creation date: Fri Dec 24 1999 + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +/* + * Original teapot code copyright follows: + */ + +/* + * (c) Copyright 1993, Silicon Graphics, Inc. + * + * ALL RIGHTS RESERVED + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that + * both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of Silicon + * Graphics, Inc. not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU + * "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR + * OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO + * EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE + * ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, + * INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, + * SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR + * NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer + * Software clause at DFARS 252.227-7013 and/or in similar or + * successor clauses in the FAR or the DOD or NASA FAR + * Supplement. Unpublished-- rights reserved under the copyright + * laws of the United States. Contractor/manufacturer is Silicon + * Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA + * 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ + +#include +#include "freeglut_teapot_data.h" + +/* -- PRIVATE FUNCTIONS ---------------------------------------------------- */ + + +static void fghTeapot( GLint grid, GLdouble scale, GLenum type ) +{ + double p[4][4][3], q[4][4][3], r[4][4][3], s[4][4][3]; + long i, j, k, l; + + glPushAttrib( GL_ENABLE_BIT | GL_EVAL_BIT ); + glEnable( GL_AUTO_NORMAL ); + glEnable( GL_NORMALIZE ); + glEnable( GL_MAP2_VERTEX_3 ); + glEnable( GL_MAP2_TEXTURE_COORD_2 ); + + glPushMatrix(); + glRotated( 270.0, 1.0, 0.0, 0.0 ); + glScaled( 0.5 * scale, 0.5 * scale, 0.5 * scale ); + glTranslated( 0.0, 0.0, -1.5 ); + + for (i = 0; i < 10; i++) { + for (j = 0; j < 4; j++) { + for (k = 0; k < 4; k++) { + for (l = 0; l < 3; l++) { + p[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; + q[j][k][l] = cpdata[patchdata[i][j * 4 + (3 - k)]][l]; + if (l == 1) + q[j][k][l] *= -1.0; + if (i < 6) { + r[j][k][l] = + cpdata[patchdata[i][j * 4 + (3 - k)]][l]; + if (l == 0) + r[j][k][l] *= -1.0; + s[j][k][l] = cpdata[patchdata[i][j * 4 + k]][l]; + if (l == 0) + s[j][k][l] *= -1.0; + if (l == 1) + s[j][k][l] *= -1.0; + } + } + } + } + + glMap2d(GL_MAP2_TEXTURE_COORD_2, 0.0, 1.0, 2, 2, 0.0, 1.0, 4, 2, + &tex[0][0][0]); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &p[0][0][0]); + glMapGrid2d(grid, 0.0, 1.0, grid, 0.0, 1.0); + glEvalMesh2(type, 0, grid, 0, grid); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &q[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + if (i < 6) { + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &r[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + glMap2d(GL_MAP2_VERTEX_3, 0.0, 1.0, 3, 4, 0.0, 1.0, 12, 4, + &s[0][0][0]); + glEvalMesh2(type, 0, grid, 0, grid); + } + } + + glPopMatrix(); + glPopAttrib(); +} + + +/* -- INTERFACE FUNCTIONS -------------------------------------------------- */ + +/* + * Renders a beautiful wired teapot... + */ +void glutWireTeapot( GLdouble size ) +{ + /* We will use the general teapot rendering code */ + fghTeapot( 10, size, GL_LINE ); +} + +/* + * Renders a beautiful filled teapot... + */ +void glutSolidTeapot( GLdouble size ) +{ + /* We will use the general teapot rendering code */ + fghTeapot( 7, size, GL_FILL ); +} + +/*** END OF FILE ***/ diff --git a/third_party/windows/fltk-1.1.10/src/freeglut_teapot_data.h b/third_party/windows/fltk-1.1.10/src/freeglut_teapot_data.h new file mode 100644 index 0000000..83b6c38 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/freeglut_teapot_data.h @@ -0,0 +1,145 @@ +/* + * freeglut_teapot_data.h + * + * The freeglut library teapot data include file. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * PAWEL W. OLSZTA BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef FREEGLUT_TEAPOT_DATA_H +#define FREEGLUT_TEAPOT_DATA_H + +/* + * Original teapot code copyright follows: + */ + +/* + * (c) Copyright 1993, Silicon Graphics, Inc. + * + * ALL RIGHTS RESERVED + * + * Permission to use, copy, modify, and distribute this software + * for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that + * both the copyright notice and this permission notice appear in + * supporting documentation, and that the name of Silicon + * Graphics, Inc. not be used in advertising or publicity + * pertaining to distribution of the software without specific, + * written prior permission. + * + * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU + * "AS-IS" AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR + * OTHERWISE, INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF + * MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE. IN NO + * EVENT SHALL SILICON GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE + * ELSE FOR ANY DIRECT, SPECIAL, INCIDENTAL, INDIRECT OR + * CONSEQUENTIAL DAMAGES OF ANY KIND, OR ANY DAMAGES WHATSOEVER, + * INCLUDING WITHOUT LIMITATION, LOSS OF PROFIT, LOSS OF USE, + * SAVINGS OR REVENUE, OR THE CLAIMS OF THIRD PARTIES, WHETHER OR + * NOT SILICON GRAPHICS, INC. HAS BEEN ADVISED OF THE POSSIBILITY + * OF SUCH LOSS, HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, + * ARISING OUT OF OR IN CONNECTION WITH THE POSSESSION, USE OR + * PERFORMANCE OF THIS SOFTWARE. + * + * US Government Users Restricted Rights + * + * Use, duplication, or disclosure by the Government is subject to + * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph + * (c)(1)(ii) of the Rights in Technical Data and Computer + * Software clause at DFARS 252.227-7013 and/or in similar or + * successor clauses in the FAR or the DOD or NASA FAR + * Supplement. Unpublished-- rights reserved under the copyright + * laws of the United States. Contractor/manufacturer is Silicon + * Graphics, Inc., 2011 N. Shoreline Blvd., Mountain View, CA + * 94039-7311. + * + * OpenGL(TM) is a trademark of Silicon Graphics, Inc. + */ + +/* + * Rim, body, lid, and bottom data must be reflected in x and y; + * handle and spout data across the y axis only. + */ +static int patchdata[][16] = +{ + { 102, 103, 104, 105, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, /* rim */ + { 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 }, /* body */ + { 24, 25, 26, 27, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 }, + { 96, 96, 96, 96, 97, 98, 99, 100, 101, 101, 101, 101, 0, 1, 2, 3 }, /* lid */ + { 0, 1, 2, 3, 106, 107, 108, 109, 110, 111, 112, 113, 114, 115, 116, 117 }, + { 118, 118, 118, 118, 124, 122, 119, 121, 123, 126, 125, 120, 40, 39, 38, 37 }, /* bottom */ + { 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56 }, /* handle */ + { 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63, 64, 28, 65, 66, 67 }, + { 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83 }, /* spout */ + { 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95 } +}; + +static double cpdata[][3] = +{ + {0.2, 0, 2.7}, {0.2, -0.112, 2.7}, {0.112, -0.2, 2.7}, {0, + -0.2, 2.7}, {1.3375, 0, 2.53125}, {1.3375, -0.749, 2.53125}, + {0.749, -1.3375, 2.53125}, {0, -1.3375, 2.53125}, {1.4375, + 0, 2.53125}, {1.4375, -0.805, 2.53125}, {0.805, -1.4375, + 2.53125}, {0, -1.4375, 2.53125}, {1.5, 0, 2.4}, {1.5, -0.84, + 2.4}, {0.84, -1.5, 2.4}, {0, -1.5, 2.4}, {1.75, 0, 1.875}, + {1.75, -0.98, 1.875}, {0.98, -1.75, 1.875}, {0, -1.75, + 1.875}, {2, 0, 1.35}, {2, -1.12, 1.35}, {1.12, -2, 1.35}, + {0, -2, 1.35}, {2, 0, 0.9}, {2, -1.12, 0.9}, {1.12, -2, + 0.9}, {0, -2, 0.9}, {-2, 0, 0.9}, {2, 0, 0.45}, {2, -1.12, + 0.45}, {1.12, -2, 0.45}, {0, -2, 0.45}, {1.5, 0, 0.225}, + {1.5, -0.84, 0.225}, {0.84, -1.5, 0.225}, {0, -1.5, 0.225}, + {1.5, 0, 0.15}, {1.5, -0.84, 0.15}, {0.84, -1.5, 0.15}, {0, + -1.5, 0.15}, {-1.6, 0, 2.025}, {-1.6, -0.3, 2.025}, {-1.5, + -0.3, 2.25}, {-1.5, 0, 2.25}, {-2.3, 0, 2.025}, {-2.3, -0.3, + 2.025}, {-2.5, -0.3, 2.25}, {-2.5, 0, 2.25}, {-2.7, 0, + 2.025}, {-2.7, -0.3, 2.025}, {-3, -0.3, 2.25}, {-3, 0, + 2.25}, {-2.7, 0, 1.8}, {-2.7, -0.3, 1.8}, {-3, -0.3, 1.8}, + {-3, 0, 1.8}, {-2.7, 0, 1.575}, {-2.7, -0.3, 1.575}, {-3, + -0.3, 1.35}, {-3, 0, 1.35}, {-2.5, 0, 1.125}, {-2.5, -0.3, + 1.125}, {-2.65, -0.3, 0.9375}, {-2.65, 0, 0.9375}, {-2, + -0.3, 0.9}, {-1.9, -0.3, 0.6}, {-1.9, 0, 0.6}, {1.7, 0, + 1.425}, {1.7, -0.66, 1.425}, {1.7, -0.66, 0.6}, {1.7, 0, + 0.6}, {2.6, 0, 1.425}, {2.6, -0.66, 1.425}, {3.1, -0.66, + 0.825}, {3.1, 0, 0.825}, {2.3, 0, 2.1}, {2.3, -0.25, 2.1}, + {2.4, -0.25, 2.025}, {2.4, 0, 2.025}, {2.7, 0, 2.4}, {2.7, + -0.25, 2.4}, {3.3, -0.25, 2.4}, {3.3, 0, 2.4}, {2.8, 0, + 2.475}, {2.8, -0.25, 2.475}, {3.525, -0.25, 2.49375}, + {3.525, 0, 2.49375}, {2.9, 0, 2.475}, {2.9, -0.15, 2.475}, + {3.45, -0.15, 2.5125}, {3.45, 0, 2.5125}, {2.8, 0, 2.4}, + {2.8, -0.15, 2.4}, {3.2, -0.15, 2.4}, {3.2, 0, 2.4}, {0, 0, + 3.15}, {0.8, 0, 3.15}, {0.8, -0.45, 3.15}, {0.45, -0.8, + 3.15}, {0, -0.8, 3.15}, {0, 0, 2.85}, {1.4, 0, 2.4}, {1.4, + -0.784, 2.4}, {0.784, -1.4, 2.4}, {0, -1.4, 2.4}, {0.4, 0, + 2.55}, {0.4, -0.224, 2.55}, {0.224, -0.4, 2.55}, {0, -0.4, + 2.55}, {1.3, 0, 2.55}, {1.3, -0.728, 2.55}, {0.728, -1.3, + 2.55}, {0, -1.3, 2.55}, {1.3, 0, 2.4}, {1.3, -0.728, 2.4}, + {0.728, -1.3, 2.4}, {0, -1.3, 2.4}, {0, 0, 0}, {1.425, + -0.798, 0}, {1.5, 0, 0.075}, {1.425, 0, 0}, {0.798, -1.425, + 0}, {0, -1.5, 0.075}, {0, -1.425, 0}, {1.5, -0.84, 0.075}, + {0.84, -1.5, 0.075} +}; + +static double tex[2][2][2] = +{ + { {0.0, 0.0}, {1.0, 0.0} }, + { {0.0, 1.0}, {1.0, 1.0} } +}; + + +#endif /* FREEGLUT_TEAPOT_DATA_H */ + diff --git a/third_party/windows/fltk-1.1.10/src/gl_draw.cxx b/third_party/windows/fltk-1.1.10/src/gl_draw.cxx new file mode 100644 index 0000000..3e1ac8b --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/gl_draw.cxx @@ -0,0 +1,223 @@ +// +// "$Id: gl_draw.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// OpenGL drawing support routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Functions from +// See also Fl_Gl_Window and gl_start.cxx + +#include "flstring.h" +#if HAVE_GL + +#include +#include +#include +#include +#include "Fl_Gl_Choice.H" +#include "Fl_Font.H" + +#if USE_XFT +extern XFontStruct* fl_xxfont(); +#endif // USE_XFT + +int gl_height() {return fl_height();} +int gl_descent() {return fl_descent();} +double gl_width(const char* s) {return fl_width(s);} +double gl_width(const char* s, int n) {return fl_width(s,n);} +double gl_width(uchar c) {return fl_width(c);} + +void gl_font(int fontid, int size) { + fl_font(fontid, size); + if (!fl_fontsize->listbase) { +#ifdef WIN32 + int base = fl_fontsize->metr.tmFirstChar; + int count = fl_fontsize->metr.tmLastChar-base+1; + HFONT oldFid = (HFONT)SelectObject(fl_gc, fl_fontsize->fid); + fl_fontsize->listbase = glGenLists(256); + wglUseFontBitmaps(fl_gc, base, count, fl_fontsize->listbase+base); + SelectObject(fl_gc, oldFid); +#elif defined(__APPLE_QD__) + // undefined characters automatically receive an empty GL list in aglUseFont + fl_fontsize->listbase = glGenLists(256); + aglUseFont(aglGetCurrentContext(), fl_fontsize->font, fl_fontsize->face, + fl_fontsize->size, 0, 256, fl_fontsize->listbase); +#elif defined(__APPLE_QUARTZ__) + short font, face, size; + uchar fn[256]; + fn[0]=strlen(fl_fontsize->q_name); + strcpy((char*)(fn+1), fl_fontsize->q_name); + GetFNum(fn, &font); + face = 0; + size = fl_fontsize->size; + fl_fontsize->listbase = glGenLists(256); + aglUseFont(aglGetCurrentContext(), font, face, + size, 0, 256, fl_fontsize->listbase); +#else +# if USE_XFT + fl_xfont = fl_xxfont(); +# endif // USE_XFT + int base = fl_xfont->min_char_or_byte2; + int count = fl_xfont->max_char_or_byte2-base+1; + fl_fontsize->listbase = glGenLists(256); + glXUseXFont(fl_xfont->fid, base, count, fl_fontsize->listbase+base); +#endif + } + glListBase(fl_fontsize->listbase); +} + + +void gl_remove_displaylist_fonts() +{ +# if HAVE_GL + + // clear variables used mostly in fl_font + fl_font_ = 0; + fl_size_ = 0; + + for (int j = 0 ; j < FL_FREE_FONT ; ++j) + { + Fl_FontSize* past = 0; + Fl_Fontdesc* s = fl_fonts + j ; + Fl_FontSize* f = s->first; + while (f != 0) { + if(f->listbase) { + if(f == s->first) { + s->first = f->next; + } + else { + past->next = f->next; + } + + // It would be nice if this next line was in a descturctor somewhere + glDeleteLists(f->listbase, 256); + + Fl_FontSize* tmp = f; + f = f->next; + delete tmp; + } + else { + past = f; + f = f->next; + } + } + } + +#endif +} + +void gl_draw(const char* str, int n) { + glCallLists(n, GL_UNSIGNED_BYTE, str); +} + +void gl_draw(const char* str, int n, int x, int y) { + glRasterPos2i(x, y); + gl_draw(str, n); +} + +void gl_draw(const char* str, int n, float x, float y) { + glRasterPos2f(x, y); + gl_draw(str, n); +} + +void gl_draw(const char* str) { + gl_draw(str, strlen(str)); +} + +void gl_draw(const char* str, int x, int y) { + gl_draw(str, strlen(str), x, y); +} + +void gl_draw(const char* str, float x, float y) { + gl_draw(str, strlen(str), x, y); +} + +static void gl_draw_invert(const char* str, int n, int x, int y) { + glRasterPos2i(x, -y); + gl_draw(str, n); +} + +void gl_draw( + const char* str, // the (multi-line) string + int x, int y, int w, int h, // bounding box + Fl_Align align) { + fl_draw(str, x, -y-h, w, h, align, gl_draw_invert); +} + +void gl_measure(const char* str, int& x, int& y) {fl_measure(str,x,y);} + +void gl_rect(int x, int y, int w, int h) { + if (w < 0) {w = -w; x = x-w;} + if (h < 0) {h = -h; y = y-h;} + glBegin(GL_LINE_STRIP); + glVertex2i(x+w-1, y+h-1); + glVertex2i(x+w-1, y); + glVertex2i(x, y); + glVertex2i(x, y+h-1); + glVertex2i(x+w, y+h-1); + glEnd(); +} + +#if HAVE_GL_OVERLAY +extern uchar fl_overlay; +extern int fl_overlay_depth; +#endif + +void gl_color(Fl_Color i) { +#if HAVE_GL_OVERLAY +#ifdef WIN32 + if (fl_overlay && fl_overlay_depth) { + if (fl_overlay_depth < 8) { + // only black & white produce the expected colors. This could + // be improved by fixing the colormap set in Fl_Gl_Overlay.cxx + int size = 1<= size-2) glIndexi(size-1); + else glIndexi(i); + } else { + glIndexi(i ? i : FL_GRAY_RAMP); + } + return; + } +#else + if (fl_overlay) {glIndexi(int(fl_xpixel(i))); return;} +#endif +#endif + uchar red, green, blue; + Fl::get_color(i, red, green, blue); + glColor3ub(red, green, blue); +} + +void gl_draw_image(const uchar* b, int x, int y, int w, int h, int d, int ld) { + if (!ld) ld = w*d; + glPixelStorei(GL_UNPACK_ROW_LENGTH, ld/d); + glRasterPos2i(x,y); + glDrawPixels(w,h,d<4?GL_RGB:GL_RGBA,GL_UNSIGNED_BYTE,(const ulong*)b); +} + +#endif + +// +// End of "$Id: gl_draw.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/gl_start.cxx b/third_party/windows/fltk-1.1.10/src/gl_start.cxx new file mode 100644 index 0000000..37d4b6c --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/gl_start.cxx @@ -0,0 +1,134 @@ +// +// "$Id: gl_start.cxx 5190 2006-06-09 16:16:34Z mike $" +// +// OpenGL context routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// You MUST use gl_visual() to select the default visual before doing +// show() of any windows. Mesa will crash if you try to use a visual +// not returned by glxChooseVisual. + +// This does not work with Fl_Double_Window's! It will try to draw +// into the front buffer. Depending on the system this will either +// crash or do nothing (when pixmaps are being used as back buffer +// and GL is being done by hardware), work correctly (when GL is done +// with software, such as Mesa), or draw into the front buffer and +// be erased when the buffers are swapped (when double buffer hardware +// is being used) + +#include +#if HAVE_GL + +#include +#include +#include +#include +#include "Fl_Gl_Choice.H" + +extern int fl_clip_state_number; // in fl_rect.cxx + +static GLContext context; +static int clip_state_number=-1; +static int pw, ph; + +#ifdef WIN32 +static Fl_Gl_Choice* gl_choice; +#endif + +#ifdef __APPLE__ +static Fl_Gl_Choice* gl_choice; +#endif + +Fl_Region XRectangleRegion(int x, int y, int w, int h); // in fl_rect.cxx + +void gl_start() { + if (!context) { +#ifdef WIN32 + if (!gl_choice) Fl::gl_visual(0); + context = fl_create_gl_context(Fl_Window::current(), gl_choice); +#elif defined(__APPLE_QD__) + // \todo Mac : We need to check the code and verify it with Apple Sample code. The 'shiny'-test should at least work with the software OpenGL emulator + context = fl_create_gl_context(Fl_Window::current(), gl_choice); +#elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + context = fl_create_gl_context(Fl_Window::current(), gl_choice); +#else + context = fl_create_gl_context(fl_visual); +#endif + } + fl_set_gl_context(Fl_Window::current(), context); +#if !defined(WIN32) && !defined(__APPLE__) + glXWaitX(); +#endif + if (pw != Fl_Window::current()->w() || ph != Fl_Window::current()->h()) { + pw = Fl_Window::current()->w(); + ph = Fl_Window::current()->h(); + glLoadIdentity(); + glViewport(0, 0, pw, ph); + glOrtho(0, pw, 0, ph, -1, 1); + glDrawBuffer(GL_FRONT); + } + if (clip_state_number != fl_clip_state_number) { + clip_state_number = fl_clip_state_number; + int x, y, w, h; + if (fl_clip_box(0, 0, Fl_Window::current()->w(), Fl_Window::current()->h(), + x, y, w, h)) { + fl_clip_region(XRectangleRegion(x,y,w,h)); + glScissor(x, Fl_Window::current()->h()-(y+h), w, h); + glEnable(GL_SCISSOR_TEST); + } else { + glDisable(GL_SCISSOR_TEST); + } + } +} + +void gl_finish() { + glFlush(); +#if !defined(WIN32) && !defined(__APPLE__) + glXWaitGL(); +#endif +} + +int Fl::gl_visual(int mode, int *alist) { + Fl_Gl_Choice *c = Fl_Gl_Choice::find(mode,alist); + if (!c) return 0; +#ifdef WIN32 + gl_choice = c; +#elif defined(__APPLE_QD__) + gl_choice = c; +#elif defined(__APPLE_QUARTZ__) + // warning: the Quartz version should probably use Core GL (CGL) instead of AGL + gl_choice = c; +#else + fl_visual = c->vis; + fl_colormap = c->colormap; +#endif + return 1; +} + +#endif + +// +// End of "$Id: gl_start.cxx 5190 2006-06-09 16:16:34Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/glut_compatability.cxx b/third_party/windows/fltk-1.1.10/src/glut_compatability.cxx new file mode 100644 index 0000000..0b52b14 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/glut_compatability.cxx @@ -0,0 +1,504 @@ +// +// "$Id: glut_compatability.cxx 5845 2007-05-20 00:01:06Z mike $" +// +// GLUT emulation routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2007 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + +// Emulation of Glut using fltk. + +// GLUT is Copyright (c) Mark J. Kilgard, 1994, 1995, 1996. +// "This program is freely distributable without licensing fees and is +// provided without guarantee or warrantee expressed or implied. This +// program is -not- in the public domain." + +// Although I have copied the GLUT API, none of my code is based on +// any Glut implementation details and is therefore covered by the LGPL. + +#include "flstring.h" +#if HAVE_GL + +# include +# ifdef HAVE_GLXGETPROCADDRESSARB +# define GLX_GLXEXT_LEGACY +# include +# endif // HAVE_GLXGETPROCADDRESSARB +# ifdef HAVE_DLFCN_H +# include +# endif // HAVE_DLFCN_H +# define MAXWINDOWS 32 +static Fl_Glut_Window *windows[MAXWINDOWS+1]; + +Fl_Glut_Window *glut_window; +int glut_menu; +void (*glut_menustate_function)(int); +void (*glut_menustatus_function)(int,int,int); + +static void default_reshape(int w, int h) {glViewport(0,0,w,h);} +static void default_display() {} + +void Fl_Glut_Window::make_current() { + glut_window = this; + if (shown()) Fl_Gl_Window::make_current(); +} + +static int indraw; +void Fl_Glut_Window::draw() { + glut_window = this; + indraw = 1; + if (!valid()) {reshape(w(),h()); valid(1);} + display(); + indraw = 0; +} + +void glutSwapBuffers() { + if (!indraw) glut_window->swap_buffers(); +} + +void Fl_Glut_Window::draw_overlay() { + glut_window = this; + if (!valid()) {reshape(w(),h()); valid(1);} + overlaydisplay(); +} + +static void domenu(int, int, int); + +int Fl_Glut_Window::handle(int event) { + make_current(); + int ex = Fl::event_x(); + int ey = Fl::event_y(); + int button; + switch (event) { + + case FL_PUSH: + if (keyboard || special) Fl::focus(this); + button = Fl::event_button()-1; + if (button<0) button = 0; + if (button>2) button = 2; + if (menu[button]) {domenu(menu[button],ex,ey); return 1;} + mouse_down |= 1< 0) {mouse(4,GLUT_DOWN,ex,ey); --button;} + return 1; + + case FL_RELEASE: + for (button = 0; button < 3; button++) if (mouse_down & (1< FL_F && k <= FL_F_Last) k -= FL_F; + special(k,ex,ey); + return 1; + } + break; + } + + case FL_HIDE: + if (visibility) visibility(GLUT_NOT_VISIBLE); + break; + + case FL_SHOW: + if (visibility) visibility(GLUT_VISIBLE); + break; + } + + return Fl_Gl_Window::handle(event); +} + +static int glut_mode = GLUT_RGB | GLUT_SINGLE | GLUT_DEPTH; + +void Fl_Glut_Window::_init() { + for (number=1; numberresizable(W); + if (initargc) { + W->show(initargc,initargv); + initargc = 0; + } else { + W->show(); + } + W->valid(0); + W->context_valid(0); + W->make_current(); + return W->number; +} + +int glutCreateSubWindow(int win, int x, int y, int w, int h) { + Fl_Glut_Window *W = new Fl_Glut_Window(x,y,w,h,0); + windows[win]->add(W); + if (windows[win]->shown()) W->show(); + W->make_current(); + return W->number; +} + +Fl_Glut_Window::~Fl_Glut_Window() { + if (glut_window == this) glut_window = 0; + windows[number] = 0; +} + +void glutDestroyWindow(int win) { + // should destroy children!!! + delete windows[win]; +} + +void glutPostWindowRedisplay(int win) { + windows[win]->redraw(); +} + +void glutSetWindow(int win) { + windows[win]->make_current(); +} + +//////////////////////////////////////////////////////////////// +#include + +struct menu { + void (*cb)(int); + Fl_Menu_Item *m; + int size; + int alloc; +}; + +#define MAXMENUS 32 +static menu menus[MAXMENUS+1]; + +static void domenu(int n, int ex, int ey) { + glut_menu = n; + menu *m = &menus[n]; + if (glut_menustate_function) glut_menustate_function(1); + if (glut_menustatus_function) glut_menustatus_function(1,ex,ey); + const Fl_Menu_Item* g = m->m->popup(Fl::event_x(), Fl::event_y(), 0); + if (g && g->callback_) ((void (*)(int))(g->callback_))(int(g->argument())); + if (glut_menustatus_function) glut_menustatus_function(0,ex,ey); + if (glut_menustate_function) glut_menustate_function(0); +} + +int glutCreateMenu(void (*cb)(int)) { + int i; + for (i=1; icb = cb; + return glut_menu = i; +} + +void glutDestroyMenu(int n) { + menu *m = &menus[n]; + delete[] m->m; + m->m = 0; + m->cb = 0; + m->size = m->alloc = 0; +} + +static Fl_Menu_Item* additem(menu *m) { + if (m->size+1 >= m->alloc) { + m->alloc = m->size*2+10; + Fl_Menu_Item* nm = new Fl_Menu_Item[m->alloc]; + for (int i=0; isize; i++) nm[i] = m->m[i]; + delete[] m->m; + m->m = nm; + } + int n = m->size++; + m->m[n+1].text = 0; + Fl_Menu_Item* i = &(m->m[n]); + i->shortcut_ = 0; + i->flags = 0; + i->labeltype_ = i->labelfont_ = i->labelsize_ = i->labelcolor_ = 0; + return i; +} + +void glutAddMenuEntry(char *label, int value) { + menu *m = &menus[glut_menu]; + Fl_Menu_Item* i = additem(m); + i->text = label; + i->callback_ = (Fl_Callback*)(m->cb); + i->user_data_ = (void *)value; +} + +void glutAddSubMenu(char *label, int submenu) { + menu *m = &menus[glut_menu]; + Fl_Menu_Item* i = additem(m); + i->text = label; + i->callback_ = 0; + i->user_data_ = (void *)(menus[submenu].m); + i->flags = FL_PUP_SUBMENU; +} + +void glutChangeToMenuEntry(int item, char *label, int value) { + menu *m = &menus[glut_menu]; + Fl_Menu_Item* i = &m->m[item-1]; + i->text = label; + i->callback_ = (Fl_Callback*)(m->cb); + i->user_data_ = (void *)value; + i->flags = 0; +} + +void glutChangeToSubMenu(int item, char *label, int submenu) { + menu *m = &menus[glut_menu]; + Fl_Menu_Item* i = &m->m[item-1]; + i->text = label; + i->callback_ = 0; + i->user_data_ = (void *)(menus[submenu].m); + i->flags = FL_PUP_SUBMENU; +} + +void glutRemoveMenuItem(int item) { + menu *m = &menus[glut_menu]; + if (item > m->size || item < 1) return; + for (int i = item-1; i <= m->size; i++) m->m[i] = m->m[i+1]; + m->size--; +} + +//////////////////////////////////////////////////////////////// + +int glutGet(GLenum type) { + switch (type) { + case GLUT_RETURN_ZERO: return 0; + case GLUT_WINDOW_X: return glut_window->x(); + case GLUT_WINDOW_Y: return glut_window->y(); + case GLUT_WINDOW_WIDTH: return glut_window->w(); + case GLUT_WINDOW_HEIGHT: return glut_window->h(); + case GLUT_WINDOW_PARENT: + if (glut_window->parent()) + return ((Fl_Glut_Window *)(glut_window->parent()))->number; + else + return 0; +//case GLUT_WINDOW_NUM_CHILDREN: +//case GLUT_WINDOW_CURSOR: return + case GLUT_SCREEN_WIDTH: return Fl::w(); + case GLUT_SCREEN_HEIGHT: return Fl::h(); +//case GLUT_SCREEN_WIDTH_MM: +//case GLUT_SCREEN_HEIGHT_MM: + case GLUT_MENU_NUM_ITEMS: return menus[glut_menu].size; + case GLUT_DISPLAY_MODE_POSSIBLE: return Fl_Gl_Window::can_do(glut_mode); + case GLUT_INIT_WINDOW_X: return initx; + case GLUT_INIT_WINDOW_Y: return inity; + case GLUT_INIT_WINDOW_WIDTH: return initw; + case GLUT_INIT_WINDOW_HEIGHT: return inith; + case GLUT_INIT_DISPLAY_MODE: return glut_mode; +//case GLUT_ELAPSED_TIME: + case GLUT_WINDOW_BUFFER_SIZE: + if (glutGet(GLUT_WINDOW_RGBA)) + return glutGet(GLUT_WINDOW_RED_SIZE)+ + glutGet(GLUT_WINDOW_GREEN_SIZE)+ + glutGet(GLUT_WINDOW_BLUE_SIZE)+ + glutGet(GLUT_WINDOW_ALPHA_SIZE); + else + return glutGet(GLUT_WINDOW_COLORMAP_SIZE); + case GLUT_VERSION: return 20400; + default: {GLint p; glGetIntegerv(type, &p); return p;} + } +} + +int glutLayerGet(GLenum type) { + switch (type) { + case GLUT_OVERLAY_POSSIBLE: return glut_window->can_do_overlay(); +//case GLUT_LAYER_IN_USE: +//case GLUT_HAS_OVERLAY: + case GLUT_TRANSPARENT_INDEX: return 0; // true for SGI + case GLUT_NORMAL_DAMAGED: return glut_window->damage(); + case GLUT_OVERLAY_DAMAGED: return 1; // kind of works... + default: return 0; + } +} + +int glutDeviceGet(GLenum type) { + switch (type) { + case GLUT_HAS_KEYBOARD : return 1; + case GLUT_HAS_MOUSE : return 1; + case GLUT_NUM_MOUSE_BUTTONS : return 3; + default : return 0; + } +} + +// Get extension function address... +GLUTproc glutGetProcAddress(const char *procName) { +# ifdef WIN32 + return (GLUTproc)wglGetProcAddress((LPCSTR)procName); + +# elif defined(HAVE_DLSYM) && defined(HAVE_DLFCN_H) + char symbol[1024]; + + snprintf(symbol, sizeof(symbol), "_%s", procName); + +# ifdef RTLD_DEFAULT + return (GLUTproc)dlsym(RTLD_DEFAULT, symbol); + +# else // No RTLD_DEFAULT support, so open the current a.out symbols... + static void *rtld_default = 0; + + if (!rtld_default) rtld_default = dlopen(0, RTLD_LAZY); + + if (rtld_default) return (GLUTproc)dlsym(rtld_default, symbol); + else return 0; + +# endif // RTLD_DEFAULT + +# elif defined(HAVE_GLXGETPROCADDRESSARB) + return (GLUTproc)glXGetProcAddressARB((const GLubyte *)procName); + +# else + return (GLUTproc)0; +# endif // WIN32 +} + +// Parse the GL_EXTENSIONS string to see if the named extension is +// supported. +// +// This code was copied from FreeGLUT 2.4.0 which carries the +// following notice: +// +// Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. +int glutExtensionSupported( const char* extension ) +{ + if (!extension || strchr(extension, ' ')) return 0; + + const char *extensions, *start; + const int len = strlen( extension ); + + start = extensions = (const char *) glGetString(GL_EXTENSIONS); + + if (!extensions) return 0; + + for (;;) { + const char *p = strstr(extensions, extension); + if (!p) return 0; /* not found */ + /* check that the match isn't a super string */ + if ((p == start || p[-1] == ' ') && + (p[len] == ' ' || p[len] == 0)) return 1; + /* skip the false match and continue */ + extensions = p + len; + } +} + +#endif // HAVE_GL + +// +// End of "$Id: glut_compatability.cxx 5845 2007-05-20 00:01:06Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/glut_font.cxx b/third_party/windows/fltk-1.1.10/src/glut_font.cxx new file mode 100644 index 0000000..64991db --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/glut_font.cxx @@ -0,0 +1,199 @@ +// +// "$Id: glut_font.cxx 5650 2007-02-01 18:10:07Z mike $" +// +// GLUT font routines for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2007 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// +// The stroked text code was copied from FreeGLUT 2.4.0 which carries +// the following notice: +// +// Copyright (c) 1999-2000 Pawel W. Olszta. All Rights Reserved. +// + +// (sort of) emulation of Glut's bitmap drawing functions, using FL's +// font stuff. Not all the fonts match! + +#include +#if HAVE_GL +# include + +Fl_Glut_Bitmap_Font glutBitmap9By15 = {FL_SCREEN, 15}; +Fl_Glut_Bitmap_Font glutBitmap8By13 = {FL_SCREEN, 13}; +Fl_Glut_Bitmap_Font glutBitmapTimesRoman10 = {FL_TIMES, 10}; +Fl_Glut_Bitmap_Font glutBitmapTimesRoman24 = {FL_TIMES, 24}; +Fl_Glut_Bitmap_Font glutBitmapHelvetica10 = {FL_HELVETICA, 10}; +Fl_Glut_Bitmap_Font glutBitmapHelvetica12 = {FL_HELVETICA, 12}; +Fl_Glut_Bitmap_Font glutBitmapHelvetica18 = {FL_HELVETICA, 18}; + +void glutBitmapCharacter(void* font, int character) { + gl_font(((Fl_Glut_Bitmap_Font *)font)->font,((Fl_Glut_Bitmap_Font *)font)->size); + char a[1]; a[0] = character; + gl_draw(a,1); +} + +int glutBitmapHeight(void* font) { + gl_font(((Fl_Glut_Bitmap_Font *)font)->font,((Fl_Glut_Bitmap_Font *)font)->size); + return gl_height(); +} + +int glutBitmapLength(void *font, const unsigned char *string) { + gl_font(((Fl_Glut_Bitmap_Font *)font)->font,((Fl_Glut_Bitmap_Font *)font)->size); + const char *s = (const char*)string; + return int(gl_width(s)+.5); +} + +void glutBitmapString(void *font, const unsigned char *string) { + gl_font(((Fl_Glut_Bitmap_Font *)font)->font,((Fl_Glut_Bitmap_Font *)font)->size); + const char *s = (const char*)string; + gl_draw(s); +} + +int glutBitmapWidth(void* font, int character) { + gl_font(((Fl_Glut_Bitmap_Font *)font)->font,((Fl_Glut_Bitmap_Font *)font)->size); + return int(gl_width(character)+.5); +} + + +/* + * Draw a stroke character + */ +void glutStrokeCharacter(void* fontID, int character) { + const Fl_Glut_StrokeChar *schar; + const Fl_Glut_StrokeStrip *strip; + int i, j; + Fl_Glut_StrokeFont* font = (Fl_Glut_StrokeFont *)fontID; + + if (character < 0 || character >= font->Quantity) return; + + schar = font->Characters[character]; + if (!schar) return; + + strip = schar->Strips; + + for (i = 0; i < schar->Number; i++, strip++) + { + glBegin(GL_LINE_STRIP); + for (j = 0; j < strip->Number; j++) + glVertex2f(strip->Vertices[j].X, strip->Vertices[j].Y); + glEnd(); + } + + glTranslatef(schar->Right, 0.0, 0.0); +} + +void glutStrokeString(void* fontID, const unsigned char *string) { + unsigned char c; + int i, j; + float length = 0.0; + Fl_Glut_StrokeFont* font = (Fl_Glut_StrokeFont *)fontID; + + if (!string || ! *string) return; + + /* + * Step through the string, drawing each character. + * A newline will simply translate the next character's insertion + * point back to the start of the line and down one line. + */ + + while ((c = *string++) != 0) { + if (c < font->Quantity) { + if (c == '\n') { + glTranslatef(-length, -(float)(font->Height), 0.0); + length = 0.0; + } else { + /* Not an EOL, draw the bitmap character */ + const Fl_Glut_StrokeChar *schar = font->Characters[c]; + if (schar) { + const Fl_Glut_StrokeStrip *strip = schar->Strips; + + for (i = 0; i < schar->Number; i++, strip++) { + glBegin(GL_LINE_STRIP); + for (j = 0; j < strip->Number; j++) + glVertex2f(strip->Vertices[j].X, strip->Vertices[j].Y); + glEnd(); + } + + length += schar->Right; + glTranslatef(schar->Right, 0.0, 0.0); + } + } + } + } +} + +/* + * Return the width in pixels of a stroke character + */ +int glutStrokeWidth( void* fontID, int character ) +{ + const Fl_Glut_StrokeChar *schar; + Fl_Glut_StrokeFont* font = (Fl_Glut_StrokeFont *)fontID; + if (character < 0 || character >= font->Quantity) return 0; + schar = font->Characters[ character ]; + + return schar ? (int)(schar->Right + 0.5) : 0; +} + +/* + * Return the width of a string drawn using a stroke font + */ +int glutStrokeLength(void* fontID, const unsigned char* string) { + unsigned char c; + float length = 0.0; + float this_line_length = 0.0; + Fl_Glut_StrokeFont* font = (Fl_Glut_StrokeFont *)fontID; + + if (!string || ! *string) return 0; + + while ((c = *string++) != 0) { + if (c < font->Quantity) { + if (c == '\n') { + /* EOL; reset the length of this line */ + if (length < this_line_length) length = this_line_length; + this_line_length = 0.0; + } else { + /* Not an EOL, increment the length of this line */ + const Fl_Glut_StrokeChar *schar = font->Characters[c]; + if (schar) this_line_length += schar->Right; + } + } + } + + if (length < this_line_length) length = this_line_length; + + return (int)(length + 0.5); +} + +/* + * Returns the height of a stroke font + */ +GLfloat glutStrokeHeight(void* fontID) { + Fl_Glut_StrokeFont* font = (Fl_Glut_StrokeFont *)fontID; + return font->Height; +} + +#endif // HAVE_GL + +// +// End of "$Id: glut_font.cxx 5650 2007-02-01 18:10:07Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/makedepend b/third_party/windows/fltk-1.1.10/src/makedepend new file mode 100644 index 0000000..ded3d3f --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/makedepend @@ -0,0 +1,601 @@ +# DO NOT DELETE THIS LINE -- make depend depends on it. +Fl.o: Fl.cxx ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/x.H \ + ../FL/Fl_Window.H ../FL/Fl_Tooltip.H ../FL/Fl_Widget.H flstring.h \ + ../FL/Fl_Export.H ../config.h ../FL/fl_draw.H +Fl_Adjuster.o: Fl_Adjuster.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Adjuster.H ../FL/Fl_Valuator.H \ + ../FL/Fl_Widget.H ../FL/Fl_Bitmap.H ../FL/Fl_Image.H ../FL/fl_draw.H \ + fastarrow.h mediumarrow.h slowarrow.h +Fl_Bitmap.o: Fl_Bitmap.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/fl_draw.H ../FL/Fl_Widget.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H ../FL/Fl_Bitmap.H flstring.h \ + ../FL/Fl_Export.H ../config.h +Fl_Browser.o: Fl_Browser.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Browser.H ../FL/Fl_Browser_.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Scrollbar.H \ + ../FL/Fl_Slider.H ../FL/Fl_Valuator.H ../FL/fl_draw.H flstring.h \ + ../FL/Fl_Export.H ../config.h +Fl_Browser_.o: Fl_Browser_.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Widget.H ../FL/Fl_Browser_.H \ + ../FL/Fl_Group.H ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H \ + ../FL/Fl_Valuator.H ../FL/fl_draw.H +Fl_Browser_load.o: Fl_Browser_load.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Browser.H ../FL/Fl_Browser_.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Scrollbar.H \ + ../FL/Fl_Slider.H ../FL/Fl_Valuator.H +Fl_Box.o: Fl_Box.cxx ../FL/Fl_Widget.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Box.H +Fl_Button.o: Fl_Button.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Button.H ../FL/Fl_Widget.H ../FL/Fl_Group.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H +Fl_Chart.o: Fl_Chart.cxx ../FL/math.h ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Chart.H ../FL/Fl_Widget.H ../FL/fl_draw.H \ + flstring.h ../FL/Fl_Export.H ../config.h +Fl_Check_Browser.o: Fl_Check_Browser.cxx flstring.h ../FL/Fl_Export.H \ + ../config.h ../FL/fl_draw.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Check_Browser.H ../FL/Fl.H ../FL/Fl_Browser_.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Scrollbar.H \ + ../FL/Fl_Slider.H ../FL/Fl_Valuator.H +Fl_Check_Button.o: Fl_Check_Button.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Check_Button.H ../FL/Fl_Light_Button.H \ + ../FL/Fl_Button.H ../FL/Fl_Widget.H +Fl_Choice.o: Fl_Choice.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Choice.H ../FL/Fl_Menu_.H ../FL/Fl_Widget.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H ../FL/fl_draw.H flstring.h \ + ../FL/Fl_Export.H ../config.h +Fl_Clock.o: Fl_Clock.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Clock.H ../FL/Fl_Widget.H ../FL/fl_draw.H +Fl_Color_Chooser.o: Fl_Color_Chooser.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Color_Chooser.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/Fl_Box.H ../FL/Fl_Return_Button.H \ + ../FL/Fl_Button.H ../FL/Fl_Choice.H ../FL/Fl_Menu_.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H ../FL/Fl_Value_Input.H \ + ../FL/Fl_Valuator.H ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/fl_draw.H \ + ../FL/math.h ../FL/Fl_Window.H ../FL/Fl_Group.H +Fl_Counter.o: Fl_Counter.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Counter.H ../FL/Fl_Valuator.H \ + ../FL/Fl_Widget.H ../FL/fl_draw.H +Fl_Dial.o: Fl_Dial.cxx ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Dial.H ../FL/Fl_Valuator.H ../FL/Fl_Widget.H ../FL/fl_draw.H \ + ../FL/math.h +Fl_Double_Window.o: Fl_Double_Window.cxx ../config.h ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Double_Window.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/x.H \ + ../FL/fl_draw.H +Fl_File_Browser.o: Fl_File_Browser.cxx ../FL/Fl_File_Browser.H \ + ../FL/Fl_Browser.H ../FL/Fl_Browser_.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H \ + ../FL/Fl_File_Icon.H ../FL/Fl.H ../FL/filename.H ../FL/fl_draw.H \ + ../FL/filename.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_File_Chooser.o: Fl_File_Chooser.cxx ../FL/Fl_File_Chooser.H ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Double_Window.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Group.H \ + ../FL/Fl_Choice.H ../FL/Fl_Menu_.H ../FL/Fl_Menu_Item.H \ + ../FL/Fl_Image.H ../FL/Fl_Menu_Button.H ../FL/Fl_Button.H \ + ../FL/Fl_Preferences.H ../FL/Fl_Tile.H ../FL/Fl_File_Browser.H \ + ../FL/Fl_Browser.H ../FL/Fl_Browser_.H ../FL/Fl_Scrollbar.H \ + ../FL/Fl_Slider.H ../FL/Fl_Valuator.H ../FL/Fl_File_Icon.H ../FL/Fl.H \ + ../FL/filename.H ../FL/Fl_Box.H ../FL/Fl_Check_Button.H \ + ../FL/Fl_Light_Button.H ../FL/Fl_Button.H ../FL/Fl_File_Input.H \ + ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/Fl_Return_Button.H \ + ../FL/fl_ask.H ../FL/fl_draw.H ../FL/Fl_Bitmap.H +Fl_File_Chooser2.o: Fl_File_Chooser2.cxx ../FL/Fl_File_Chooser.H \ + ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Double_Window.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/Fl_Group.H ../FL/Fl_Choice.H ../FL/Fl_Menu_.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H ../FL/Fl_Menu_Button.H \ + ../FL/Fl_Button.H ../FL/Fl_Preferences.H ../FL/Fl_Tile.H \ + ../FL/Fl_File_Browser.H ../FL/Fl_Browser.H ../FL/Fl_Browser_.H \ + ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H \ + ../FL/Fl_File_Icon.H ../FL/Fl.H ../FL/filename.H ../FL/Fl_Box.H \ + ../FL/Fl_Check_Button.H ../FL/Fl_Light_Button.H ../FL/Fl_Button.H \ + ../FL/Fl_File_Input.H ../FL/Fl_Input.H ../FL/Fl_Input_.H \ + ../FL/Fl_Return_Button.H ../FL/fl_ask.H ../FL/filename.H ../FL/x.H \ + ../FL/Fl_Shared_Image.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_File_Icon.o: Fl_File_Icon.cxx flstring.h ../FL/Fl_Export.H ../config.h \ + ../FL/Fl_File_Icon.H ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Widget.H ../FL/fl_draw.H ../FL/filename.H +Fl_File_Input.o: Fl_File_Input.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_File_Input.H ../FL/Fl_Input.H \ + ../FL/Fl_Input_.H ../FL/Fl_Widget.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/fl_draw.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_Group.o: Fl_Group.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/fl_draw.H +Fl_Help_View.o: Fl_Help_View.cxx ../FL/Fl_Help_View.H ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H \ + ../FL/Fl_Valuator.H ../FL/fl_draw.H ../FL/Fl_Shared_Image.H \ + ../FL/Fl_Image.H ../FL/Fl_Window.H ../FL/Fl_Pixmap.H ../FL/x.H \ + ../FL/Fl_Window.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_Image.o: Fl_Image.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Widget.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H ../FL/Fl_Image.H flstring.h \ + ../FL/Fl_Export.H ../config.h +Fl_Input.o: Fl_Input.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/fl_draw.H ../FL/fl_ask.H \ + flstring.h ../FL/Fl_Export.H ../config.h +Fl_Input_.o: Fl_Input_.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Input_.H ../FL/Fl_Widget.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/fl_draw.H ../FL/fl_ask.H flstring.h \ + ../FL/Fl_Export.H ../config.h +Fl_Light_Button.o: Fl_Light_Button.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Light_Button.H ../FL/Fl_Button.H \ + ../FL/Fl_Widget.H ../FL/fl_draw.H flstring.h ../FL/Fl_Export.H \ + ../config.h +Fl_Menu.o: Fl_Menu.cxx ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Menu_Window.H ../FL/Fl_Single_Window.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Menu_.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H ../FL/fl_draw.H flstring.h \ + ../FL/Fl_Export.H ../config.h +Fl_Menu_.o: Fl_Menu_.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Menu_.H ../FL/Fl_Widget.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H flstring.h ../FL/Fl_Export.H \ + ../config.h +Fl_Menu_Bar.o: Fl_Menu_Bar.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Menu_Bar.H ../FL/Fl_Menu_.H \ + ../FL/Fl_Widget.H ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H ../FL/fl_draw.H +Fl_Sys_Menu_Bar.o: Fl_Sys_Menu_Bar.cxx +Fl_Menu_Button.o: Fl_Menu_Button.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Menu_Button.H ../FL/Fl_Menu_.H \ + ../FL/Fl_Widget.H ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H ../FL/fl_draw.H +Fl_Menu_Window.o: Fl_Menu_Window.cxx ../config.h ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/fl_draw.H \ + ../FL/Fl_Menu_Window.H ../FL/Fl_Single_Window.H +Fl_Menu_add.o: Fl_Menu_add.cxx ../FL/Fl_Menu_.H ../FL/Fl_Widget.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Menu_Item.H \ + ../FL/Fl_Image.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_Menu_global.o: Fl_Menu_global.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Menu_.H ../FL/Fl_Widget.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H +Fl_Multi_Label.o: Fl_Multi_Label.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Widget.H ../FL/Fl_Menu_Item.H \ + ../FL/Fl_Widget.H ../FL/Fl_Image.H ../FL/Fl_Multi_Label.H +Fl_Overlay_Window.o: Fl_Overlay_Window.cxx ../config.h ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Overlay_Window.H \ + ../FL/Fl_Double_Window.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/fl_draw.H ../FL/x.H +Fl_Pack.o: Fl_Pack.cxx ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Pack.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/fl_draw.H +Fl_Pixmap.o: Fl_Pixmap.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Widget.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H ../FL/Fl_Pixmap.H flstring.h \ + ../FL/Fl_Export.H ../config.h +Fl_Positioner.o: Fl_Positioner.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Positioner.H ../FL/Fl_Widget.H \ + ../FL/fl_draw.H +Fl_Preferences.o: Fl_Preferences.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Preferences.H ../FL/filename.H flstring.h \ + ../FL/Fl_Export.H ../config.h +Fl_Progress.o: Fl_Progress.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Progress.H ../FL/Fl_Widget.H ../FL/fl_draw.H +Fl_Repeat_Button.o: Fl_Repeat_Button.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Repeat_Button.H ../FL/Fl.H ../FL/Fl_Button.H \ + ../FL/Fl_Widget.H +Fl_Return_Button.o: Fl_Return_Button.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Return_Button.H ../FL/Fl_Button.H \ + ../FL/Fl_Widget.H ../FL/fl_draw.H +Fl_Roller.o: Fl_Roller.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Roller.H ../FL/Fl_Valuator.H \ + ../FL/Fl_Widget.H ../FL/fl_draw.H +Fl_Round_Button.o: Fl_Round_Button.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Round_Button.H ../FL/Fl_Light_Button.H \ + ../FL/Fl_Button.H ../FL/Fl_Widget.H +Fl_Scroll.o: Fl_Scroll.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Tiled_Image.H ../FL/Fl_Image.H \ + ../FL/Fl_Scroll.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H \ + ../FL/fl_draw.H +Fl_Scrollbar.o: Fl_Scrollbar.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H \ + ../FL/Fl_Valuator.H ../FL/Fl_Widget.H ../FL/fl_draw.H flstring.h \ + ../FL/Fl_Export.H ../config.h +Fl_Shared_Image.o: Fl_Shared_Image.cxx flstring.h ../FL/Fl_Export.H \ + ../config.h ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Shared_Image.H ../FL/Fl_Image.H ../FL/Fl_XBM_Image.H \ + ../FL/Fl_Bitmap.H ../FL/Fl_XPM_Image.H ../FL/Fl_Pixmap.H +Fl_Single_Window.o: Fl_Single_Window.cxx ../FL/Fl_Single_Window.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H +Fl_Slider.o: Fl_Slider.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H \ + ../FL/Fl_Widget.H ../FL/fl_draw.H flstring.h ../FL/Fl_Export.H \ + ../config.h +Fl_Tabs.o: Fl_Tabs.cxx ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Tabs.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/fl_draw.H \ + ../FL/Fl_Tooltip.H ../FL/Fl_Widget.H +Fl_Text_Buffer.o: Fl_Text_Buffer.cxx flstring.h ../FL/Fl_Export.H \ + ../config.h ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Text_Buffer.H +Fl_Text_Display.o: Fl_Text_Display.cxx flstring.h ../FL/Fl_Export.H \ + ../config.h ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Text_Buffer.H ../FL/Fl_Text_Display.H ../FL/fl_draw.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Scrollbar.H \ + ../FL/Fl_Slider.H ../FL/Fl_Valuator.H ../FL/Fl_Text_Buffer.H \ + ../FL/Fl_Window.H +Fl_Text_Editor.o: Fl_Text_Editor.cxx flstring.h ../FL/Fl_Export.H \ + ../config.h ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/Fl_Text_Editor.H ../FL/Fl_Text_Display.H ../FL/fl_draw.H \ + ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H ../FL/Fl_Valuator.H \ + ../FL/Fl_Text_Buffer.H ../FL/fl_ask.H +Fl_Tile.o: Fl_Tile.cxx ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Tile.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Window.H +Fl_Tiled_Image.o: Fl_Tiled_Image.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Tiled_Image.H ../FL/Fl_Image.H \ + ../FL/fl_draw.H +Fl_Tooltip.o: Fl_Tooltip.cxx ../FL/Fl_Tooltip.H ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Widget.H \ + ../FL/fl_draw.H ../FL/Fl_Menu_Window.H ../FL/Fl_Single_Window.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H +Fl_Valuator.o: Fl_Valuator.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Valuator.H ../FL/Fl_Widget.H ../FL/math.h \ + flstring.h ../FL/Fl_Export.H ../config.h +Fl_Value_Input.o: Fl_Value_Input.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Value_Input.H ../FL/Fl_Valuator.H \ + ../FL/Fl_Widget.H ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/Fl_Group.H \ + ../FL/math.h +Fl_Value_Output.o: Fl_Value_Output.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Value_Output.H ../FL/Fl_Valuator.H \ + ../FL/Fl_Widget.H ../FL/fl_draw.H +Fl_Value_Slider.o: Fl_Value_Slider.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Value_Slider.H ../FL/Fl_Slider.H \ + ../FL/Fl_Valuator.H ../FL/Fl_Widget.H ../FL/fl_draw.H +Fl_Widget.o: Fl_Widget.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Widget.H ../FL/Fl_Group.H ../FL/Fl_Tooltip.H \ + ../FL/fl_draw.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_Window.o: Fl_Window.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + flstring.h ../FL/Fl_Export.H ../config.h +Fl_Window_fullscreen.o: Fl_Window_fullscreen.cxx ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H +Fl_Window_hotspot.o: Fl_Window_hotspot.cxx ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/x.H ../FL/Fl_Window.H +Fl_Window_iconize.o: Fl_Window_iconize.cxx ../FL/x.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H +Fl_Wizard.o: Fl_Wizard.cxx ../FL/Fl_Wizard.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/fl_draw.H +Fl_XBM_Image.o: Fl_XBM_Image.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_XBM_Image.H ../FL/Fl_Bitmap.H \ + ../FL/Fl_Image.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_XPM_Image.o: Fl_XPM_Image.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_XPM_Image.H ../FL/Fl_Pixmap.H \ + ../FL/Fl_Image.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_abort.o: Fl_abort.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_add_idle.o: Fl_add_idle.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H +Fl_arg.o: Fl_arg.cxx ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/Fl_Window.H ../FL/Fl_Tooltip.H ../FL/Fl_Widget.H ../FL/filename.H \ + ../FL/fl_draw.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_compose.o: Fl_compose.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H +Fl_display.o: Fl_display.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_get_key.o: Fl_get_key.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H +Fl_get_system_colors.o: Fl_get_system_colors.cxx ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/fl_draw.H ../FL/x.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/math.h \ + flstring.h ../FL/Fl_Export.H ../config.h ../FL/Fl_Pixmap.H \ + ../FL/Fl_Image.H ../FL/Fl_Tiled_Image.H tile.xpm +Fl_grab.o: Fl_grab.cxx ../config.h ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H +Fl_lock.o: Fl_lock.cxx ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../config.h +Fl_own_colormap.o: Fl_own_colormap.cxx ../config.h ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H +Fl_visual.o: Fl_visual.cxx ../config.h ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H +Fl_x.o: Fl_x.cxx ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/Fl_Window.H ../FL/Fl_Tooltip.H ../FL/Fl_Widget.H flstring.h \ + ../FL/Fl_Export.H ../config.h +filename_absolute.o: filename_absolute.cxx ../FL/filename.H \ + ../FL/Fl_Export.H flstring.h ../FL/Fl_Export.H ../config.h +filename_expand.o: filename_expand.cxx ../FL/filename.H ../FL/Fl_Export.H \ + flstring.h ../FL/Fl_Export.H ../config.h +filename_ext.o: filename_ext.cxx ../FL/filename.H ../FL/Fl_Export.H +filename_isdir.o: filename_isdir.cxx flstring.h ../FL/Fl_Export.H \ + ../config.h ../FL/filename.H ../FL/Fl_Export.H +filename_list.o: filename_list.cxx ../FL/filename.H ../FL/Fl_Export.H \ + flstring.h ../FL/Fl_Export.H ../config.h +filename_match.o: filename_match.cxx ../FL/filename.H ../FL/Fl_Export.H +filename_setext.o: filename_setext.cxx ../FL/filename.H ../FL/Fl_Export.H \ + flstring.h ../FL/Fl_Export.H ../config.h +fl_arc.o: fl_arc.cxx ../FL/fl_draw.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/math.h +fl_arci.o: fl_arci.cxx ../FL/fl_draw.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H +fl_ask.o: fl_ask.cxx flstring.h ../FL/Fl_Export.H ../config.h ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/fl_ask.H ../FL/Fl_Box.H \ + ../FL/Fl_Widget.H ../FL/Fl_Button.H ../FL/Fl_Return_Button.H \ + ../FL/Fl_Button.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Input.H \ + ../FL/Fl_Input_.H ../FL/Fl_Secret_Input.H ../FL/Fl_Input.H ../FL/x.H \ + ../FL/Fl_Window.H ../FL/fl_draw.H +fl_boxtype.o: fl_boxtype.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Widget.H ../FL/fl_draw.H ../config.h +fl_color.o: fl_color.cxx Fl_XColor.H ../config.h ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl.H ../FL/Enumerations.H ../FL/x.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/fl_draw.H \ + fl_cmap.h +fl_cursor.o: fl_cursor.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/x.H ../FL/Fl_Window.H ../FL/fl_draw.H +fl_curve.o: fl_curve.cxx ../FL/fl_draw.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H +fl_diamond_box.o: fl_diamond_box.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H +fl_dnd.o: fl_dnd.cxx fl_dnd_x.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/x.H ../FL/Fl_Window.H flstring.h ../FL/Fl_Export.H ../config.h +fl_draw.o: fl_draw.cxx ../FL/fl_draw.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Image.H flstring.h ../FL/Fl_Export.H \ + ../config.h +fl_draw_image.o: fl_draw_image.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H Fl_XColor.H ../config.h \ + ../FL/Enumerations.H flstring.h ../FL/Fl_Export.H +fl_draw_pixmap.o: fl_draw_pixmap.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H flstring.h ../FL/Fl_Export.H \ + ../config.h +fl_encoding_latin1.o: fl_encoding_latin1.cxx ../FL/fl_draw.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Enumerations.H flstring.h \ + ../FL/Fl_Export.H ../config.h +fl_encoding_mac_roman.o: fl_encoding_mac_roman.cxx ../FL/fl_draw.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Enumerations.H flstring.h \ + ../FL/Fl_Export.H ../config.h +fl_engraved_label.o: fl_engraved_label.cxx ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Widget.H \ + ../FL/fl_draw.H +fl_file_dir.o: fl_file_dir.cxx flstring.h ../FL/Fl_Export.H ../config.h \ + ../FL/filename.H ../FL/Fl_Export.H ../FL/Fl_File_Chooser.H ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Double_Window.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Group.H ../FL/Fl_Choice.H \ + ../FL/Fl_Menu_.H ../FL/Fl_Menu_Item.H ../FL/Fl_Image.H \ + ../FL/Fl_Menu_Button.H ../FL/Fl_Button.H ../FL/Fl_Preferences.H \ + ../FL/Fl_Tile.H ../FL/Fl_File_Browser.H ../FL/Fl_Browser.H \ + ../FL/Fl_Browser_.H ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H \ + ../FL/Fl_Valuator.H ../FL/Fl_File_Icon.H ../FL/Fl.H ../FL/filename.H \ + ../FL/Fl_Box.H ../FL/Fl_Check_Button.H ../FL/Fl_Light_Button.H \ + ../FL/Fl_Button.H ../FL/Fl_File_Input.H ../FL/Fl_Input.H \ + ../FL/Fl_Input_.H ../FL/Fl_Return_Button.H ../FL/fl_ask.H +fl_font.o: fl_font.cxx flstring.h ../FL/Fl_Export.H ../config.h \ + ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/fl_draw.H \ + ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + Fl_Font.H fl_font_xft.cxx +fl_gtk.o: fl_gtk.cxx ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/fl_draw.H +fl_labeltype.o: fl_labeltype.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Widget.H ../FL/Fl_Group.H ../FL/fl_draw.H \ + ../FL/Fl_Image.H ../FL/Fl_Input_.H +fl_line_style.o: fl_line_style.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H flstring.h ../FL/Fl_Export.H \ + ../config.h +fl_open_uri.o: fl_open_uri.cxx ../FL/filename.H ../FL/Fl_Export.H \ + flstring.h ../FL/Fl_Export.H ../config.h +fl_oval_box.o: fl_oval_box.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H +fl_overlay.o: fl_overlay.cxx ../FL/x.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/fl_draw.H +fl_overlay_visual.o: fl_overlay_visual.cxx ../config.h +fl_plastic.o: fl_plastic.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H flstring.h ../FL/Fl_Export.H \ + ../config.h +fl_read_image.o: fl_read_image.cxx ../FL/x.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/fl_draw.H flstring.h ../FL/Fl_Export.H ../config.h +fl_rect.o: fl_rect.cxx ../config.h ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Widget.H ../FL/fl_draw.H ../FL/x.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H +fl_round_box.o: fl_round_box.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H +fl_rounded_box.o: fl_rounded_box.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H +fl_set_font.o: fl_set_font.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/fl_draw.H flstring.h ../FL/Fl_Export.H \ + ../config.h Fl_Font.H +fl_set_fonts.o: fl_set_fonts.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H Fl_Font.H ../config.h flstring.h ../FL/Fl_Export.H \ + fl_set_fonts_xft.cxx +fl_scroll_area.o: fl_scroll_area.cxx ../config.h ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/fl_draw.H +fl_shadow_box.o: fl_shadow_box.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H +fl_shortcut.o: fl_shortcut.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Widget.H ../FL/Fl_Button.H ../FL/fl_draw.H \ + flstring.h ../FL/Fl_Export.H ../config.h ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H +fl_show_colormap.o: fl_show_colormap.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Single_Window.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/fl_draw.H \ + ../FL/fl_show_colormap.H ../config.h +fl_symbols.o: fl_symbols.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/fl_draw.H ../FL/math.h flstring.h \ + ../FL/Fl_Export.H ../config.h +fl_vertex.o: fl_vertex.cxx ../config.h ../FL/fl_draw.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl.H ../FL/math.h +screen_xywh.o: screen_xywh.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../config.h +forms_compatability.o: forms_compatability.cxx ../FL/forms.H ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/Fl_Window.H ../FL/fl_draw.H \ + ../FL/Fl_FormsBitmap.H ../FL/Fl_Bitmap.H ../FL/Fl_Image.H \ + ../FL/Fl_FormsPixmap.H ../FL/Fl_Pixmap.H ../FL/Fl_Box.H \ + ../FL/Fl_Browser.H ../FL/Fl_Browser_.H ../FL/Fl_Scrollbar.H \ + ../FL/Fl_Slider.H ../FL/Fl_Valuator.H ../FL/Fl_Button.H \ + ../FL/Fl_Light_Button.H ../FL/Fl_Round_Button.H ../FL/Fl_Check_Button.H \ + ../FL/Fl_Chart.H ../FL/Fl_Choice.H ../FL/Fl_Menu_.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Clock.H ../FL/Fl_Counter.H \ + ../FL/Fl_Dial.H ../FL/Fl_Free.H ../FL/fl_ask.H ../FL/fl_show_colormap.H \ + ../FL/filename.H ../FL/Fl_File_Chooser.H ../FL/Fl.H \ + ../FL/Fl_Double_Window.H ../FL/Fl_Group.H ../FL/Fl_Choice.H \ + ../FL/Fl_Menu_Button.H ../FL/Fl_Button.H ../FL/Fl_Preferences.H \ + ../FL/Fl_Tile.H ../FL/Fl_File_Browser.H ../FL/Fl_File_Icon.H \ + ../FL/Fl_Box.H ../FL/Fl_Check_Button.H ../FL/Fl_File_Input.H \ + ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/Fl_Return_Button.H \ + ../FL/fl_ask.H ../FL/Fl_Input.H ../FL/Fl_Menu_Button.H \ + ../FL/Fl_Positioner.H ../FL/Fl_Value_Slider.H ../FL/Fl_Timer.H \ + ../FL/Fl_Repeat_Button.H +forms_bitmap.o: forms_bitmap.cxx ../FL/forms.H ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/Fl_Window.H ../FL/fl_draw.H \ + ../FL/Fl_FormsBitmap.H ../FL/Fl_Bitmap.H ../FL/Fl_Image.H \ + ../FL/Fl_FormsPixmap.H ../FL/Fl_Pixmap.H ../FL/Fl_Box.H \ + ../FL/Fl_Browser.H ../FL/Fl_Browser_.H ../FL/Fl_Scrollbar.H \ + ../FL/Fl_Slider.H ../FL/Fl_Valuator.H ../FL/Fl_Button.H \ + ../FL/Fl_Light_Button.H ../FL/Fl_Round_Button.H ../FL/Fl_Check_Button.H \ + ../FL/Fl_Chart.H ../FL/Fl_Choice.H ../FL/Fl_Menu_.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Clock.H ../FL/Fl_Counter.H \ + ../FL/Fl_Dial.H ../FL/Fl_Free.H ../FL/fl_ask.H ../FL/fl_show_colormap.H \ + ../FL/filename.H ../FL/Fl_File_Chooser.H ../FL/Fl.H \ + ../FL/Fl_Double_Window.H ../FL/Fl_Group.H ../FL/Fl_Choice.H \ + ../FL/Fl_Menu_Button.H ../FL/Fl_Button.H ../FL/Fl_Preferences.H \ + ../FL/Fl_Tile.H ../FL/Fl_File_Browser.H ../FL/Fl_File_Icon.H \ + ../FL/Fl_Box.H ../FL/Fl_Check_Button.H ../FL/Fl_File_Input.H \ + ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/Fl_Return_Button.H \ + ../FL/fl_ask.H ../FL/Fl_Input.H ../FL/Fl_Menu_Button.H \ + ../FL/Fl_Positioner.H ../FL/Fl_Value_Slider.H ../FL/Fl_Timer.H +forms_free.o: forms_free.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Free.H ../FL/Fl_Widget.H +forms_fselect.o: forms_fselect.cxx ../FL/forms.H ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/Fl_Window.H ../FL/fl_draw.H \ + ../FL/Fl_FormsBitmap.H ../FL/Fl_Bitmap.H ../FL/Fl_Image.H \ + ../FL/Fl_FormsPixmap.H ../FL/Fl_Pixmap.H ../FL/Fl_Box.H \ + ../FL/Fl_Browser.H ../FL/Fl_Browser_.H ../FL/Fl_Scrollbar.H \ + ../FL/Fl_Slider.H ../FL/Fl_Valuator.H ../FL/Fl_Button.H \ + ../FL/Fl_Light_Button.H ../FL/Fl_Round_Button.H ../FL/Fl_Check_Button.H \ + ../FL/Fl_Chart.H ../FL/Fl_Choice.H ../FL/Fl_Menu_.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Clock.H ../FL/Fl_Counter.H \ + ../FL/Fl_Dial.H ../FL/Fl_Free.H ../FL/fl_ask.H ../FL/fl_show_colormap.H \ + ../FL/filename.H ../FL/Fl_File_Chooser.H ../FL/Fl.H \ + ../FL/Fl_Double_Window.H ../FL/Fl_Group.H ../FL/Fl_Choice.H \ + ../FL/Fl_Menu_Button.H ../FL/Fl_Button.H ../FL/Fl_Preferences.H \ + ../FL/Fl_Tile.H ../FL/Fl_File_Browser.H ../FL/Fl_File_Icon.H \ + ../FL/Fl_Box.H ../FL/Fl_Check_Button.H ../FL/Fl_File_Input.H \ + ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/Fl_Return_Button.H \ + ../FL/fl_ask.H ../FL/Fl_Input.H ../FL/Fl_Menu_Button.H \ + ../FL/Fl_Positioner.H ../FL/Fl_Value_Slider.H ../FL/Fl_Timer.H \ + flstring.h ../FL/Fl_Export.H ../config.h +forms_pixmap.o: forms_pixmap.cxx ../FL/forms.H ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H ../FL/Fl_Window.H ../FL/fl_draw.H \ + ../FL/Fl_FormsBitmap.H ../FL/Fl_Bitmap.H ../FL/Fl_Image.H \ + ../FL/Fl_FormsPixmap.H ../FL/Fl_Pixmap.H ../FL/Fl_Box.H \ + ../FL/Fl_Browser.H ../FL/Fl_Browser_.H ../FL/Fl_Scrollbar.H \ + ../FL/Fl_Slider.H ../FL/Fl_Valuator.H ../FL/Fl_Button.H \ + ../FL/Fl_Light_Button.H ../FL/Fl_Round_Button.H ../FL/Fl_Check_Button.H \ + ../FL/Fl_Chart.H ../FL/Fl_Choice.H ../FL/Fl_Menu_.H \ + ../FL/Fl_Menu_Item.H ../FL/Fl_Clock.H ../FL/Fl_Counter.H \ + ../FL/Fl_Dial.H ../FL/Fl_Free.H ../FL/fl_ask.H ../FL/fl_show_colormap.H \ + ../FL/filename.H ../FL/Fl_File_Chooser.H ../FL/Fl.H \ + ../FL/Fl_Double_Window.H ../FL/Fl_Group.H ../FL/Fl_Choice.H \ + ../FL/Fl_Menu_Button.H ../FL/Fl_Button.H ../FL/Fl_Preferences.H \ + ../FL/Fl_Tile.H ../FL/Fl_File_Browser.H ../FL/Fl_File_Icon.H \ + ../FL/Fl_Box.H ../FL/Fl_Check_Button.H ../FL/Fl_File_Input.H \ + ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/Fl_Return_Button.H \ + ../FL/fl_ask.H ../FL/Fl_Input.H ../FL/Fl_Menu_Button.H \ + ../FL/Fl_Positioner.H ../FL/Fl_Value_Slider.H ../FL/Fl_Timer.H +forms_timer.o: forms_timer.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Timer.H ../FL/Fl_Widget.H ../FL/fl_draw.H +Fl_Gl_Choice.o: Fl_Gl_Choice.cxx ../config.h ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H Fl_Gl_Choice.H ../FL/gl_draw.H \ + ../FL/gl.h flstring.h ../FL/Fl_Export.H +Fl_Gl_Overlay.o: Fl_Gl_Overlay.cxx ../config.h ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/x.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H Fl_Gl_Choice.H ../FL/Fl_Gl_Window.H +Fl_Gl_Window.o: Fl_Gl_Window.cxx flstring.h ../FL/Fl_Export.H ../config.h \ + ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/x.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H Fl_Gl_Choice.H \ + ../FL/Fl_Gl_Window.H +freeglut_geometry.o: freeglut_geometry.cxx ../FL/glut.H ../FL/gl.h \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl.H ../FL/Fl_Gl_Window.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/math.h +freeglut_stroke_mono_roman.o: freeglut_stroke_mono_roman.cxx ../FL/glut.H \ + ../FL/gl.h ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl.H \ + ../FL/Fl_Gl_Window.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H +freeglut_stroke_roman.o: freeglut_stroke_roman.cxx ../FL/glut.H \ + ../FL/gl.h ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl.H \ + ../FL/Fl_Gl_Window.H ../FL/Fl_Window.H ../FL/Fl_Group.H \ + ../FL/Fl_Widget.H +freeglut_teapot.o: freeglut_teapot.cxx ../FL/glut.H ../FL/gl.h \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl.H ../FL/Fl_Gl_Window.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + freeglut_teapot_data.h +gl_draw.o: gl_draw.cxx flstring.h ../FL/Fl_Export.H ../config.h \ + ../FL/Fl.H ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/gl.h ../FL/x.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/fl_draw.H \ + Fl_Gl_Choice.H Fl_Font.H +gl_start.o: gl_start.cxx ../config.h ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H \ + ../FL/x.H ../FL/Fl_Window.H ../FL/fl_draw.H Fl_Gl_Choice.H +glut_compatability.o: glut_compatability.cxx flstring.h ../FL/Fl_Export.H \ + ../config.h ../FL/glut.H ../FL/gl.h ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl.H ../FL/Fl_Gl_Window.H ../FL/Fl_Window.H \ + ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Menu_Item.H \ + ../FL/Fl_Image.H +glut_font.o: glut_font.cxx ../config.h ../FL/glut.H ../FL/gl.h \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl.H ../FL/Fl_Gl_Window.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H +fl_images_core.o: fl_images_core.cxx ../FL/Fl_Shared_Image.H \ + ../FL/Fl_Image.H ../FL/Enumerations.H ../FL/Fl_Export.H \ + ../FL/Fl_BMP_Image.H ../FL/Fl_GIF_Image.H ../FL/Fl_Pixmap.H \ + ../FL/Fl_JPEG_Image.H ../FL/Fl_PNG_Image.H ../FL/Fl_PNM_Image.H \ + flstring.h ../FL/Fl_Export.H ../config.h +Fl_BMP_Image.o: Fl_BMP_Image.cxx ../FL/Fl_BMP_Image.H ../FL/Fl_Image.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../config.h +Fl_File_Icon2.o: Fl_File_Icon2.cxx flstring.h ../FL/Fl_Export.H \ + ../config.h ../FL/math.h ../FL/Fl_File_Icon.H ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Shared_Image.H \ + ../FL/Fl_Image.H ../FL/Fl_Widget.H ../FL/fl_draw.H ../FL/filename.H +Fl_GIF_Image.o: Fl_GIF_Image.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_GIF_Image.H ../FL/Fl_Pixmap.H \ + ../FL/Fl_Image.H flstring.h ../FL/Fl_Export.H ../config.h +Fl_Help_Dialog.o: Fl_Help_Dialog.cxx ../FL/Fl_Help_Dialog.H ../FL/Fl.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../FL/Fl_Double_Window.H \ + ../FL/Fl_Window.H ../FL/Fl_Group.H ../FL/Fl_Widget.H ../FL/Fl_Group.H \ + ../FL/Fl_Button.H ../FL/Fl_Input.H ../FL/Fl_Input_.H ../FL/Fl_Box.H \ + ../FL/Fl_Help_View.H ../FL/Fl.H ../FL/Fl_Scrollbar.H ../FL/Fl_Slider.H \ + ../FL/Fl_Valuator.H ../FL/fl_draw.H ../FL/Fl_Shared_Image.H \ + ../FL/Fl_Image.H flstring.h ../FL/Fl_Export.H ../config.h \ + ../FL/fl_ask.H +Fl_JPEG_Image.o: Fl_JPEG_Image.cxx ../FL/Fl_JPEG_Image.H ../FL/Fl_Image.H \ + ../FL/Enumerations.H ../FL/Fl_Export.H ../config.h +Fl_PNG_Image.o: Fl_PNG_Image.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_PNG_Image.H ../FL/Fl_Image.H ../config.h +Fl_PNM_Image.o: Fl_PNM_Image.cxx ../FL/Fl.H ../FL/Enumerations.H \ + ../FL/Fl_Export.H ../FL/Fl_PNM_Image.H ../FL/Fl_Image.H flstring.h \ + ../FL/Fl_Export.H ../config.h +fl_call_main.o: fl_call_main.c +flstring.o: flstring.c flstring.h ../FL/Fl_Export.H ../config.h +scandir.o: scandir.c flstring.h ../FL/Fl_Export.H ../config.h +numericsort.o: numericsort.c ../config.h ../FL/filename.H \ + ../FL/Fl_Export.H +vsnprintf.o: vsnprintf.c flstring.h ../FL/Fl_Export.H ../config.h diff --git a/third_party/windows/fltk-1.1.10/src/makefile.wat b/third_party/windows/fltk-1.1.10/src/makefile.wat new file mode 100644 index 0000000..4f347dc --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/makefile.wat @@ -0,0 +1,235 @@ +# +# "$Id: makefile.wat 5699 2007-02-20 17:02:41Z matt $" +# +# Library makefile for the Fast Light Tool Kit (FLTK). +# +# Copyright 1998-2004 by Bill Spitzak and others. +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Library General Public +# License as published by the Free Software Foundation; either +# version 2 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Library General Public License for more details. +# +# You should have received a copy of the GNU Library General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +# USA. +# +# Please report all bugs and problems to "fltk-bugs@fltk.org". +# + +CPPFILES = & + Fl.obj & + Fl_Adjuster.obj & + Fl_Bitmap.obj & + Fl_Browser.obj & + Fl_Browser_.obj & + Fl_Browser_load.obj & + Fl_Box.obj & + Fl_Button.obj & + Fl_Chart.obj & + Fl_Check_Browser.obj & + Fl_Check_Button.obj & + Fl_Choice.obj & + Fl_Clock.obj & + Fl_Color_Chooser.obj & + Fl_Counter.obj & + Fl_Dial.obj & + Fl_Double_Window.obj & + Fl_File_Browser.obj & + Fl_File_Chooser.obj & + Fl_File_Chooser2.obj & + Fl_File_Icon.obj & + Fl_File_Input.obj & + Fl_Group.obj & + Fl_Help_View.obj & + Fl_Image.obj & + Fl_Input.obj & + Fl_Input_.obj & + Fl_Light_Button.obj & + Fl_Menu.obj & + Fl_Menu_.obj & + Fl_Menu_Bar.obj & + Fl_Sys_Menu_Bar.obj & + Fl_Menu_Button.obj & + Fl_Menu_Window.obj & + Fl_Menu_add.obj & + Fl_Menu_global.obj & + Fl_Multi_Label.obj & + Fl_Overlay_Window.obj & + Fl_Pack.obj & + Fl_Pixmap.obj & + Fl_Positioner.obj & + Fl_Preferences.obj & + Fl_Progress.obj & + Fl_Repeat_Button.obj & + Fl_Return_Button.obj & + Fl_Roller.obj & + Fl_Round_Button.obj & + Fl_Scroll.obj & + Fl_Scrollbar.obj & + Fl_Shared_Image.obj & + Fl_Single_Window.obj & + Fl_Slider.obj & + Fl_Tabs.obj & + Fl_Text_Buffer.obj & + Fl_Text_Display.obj & + Fl_Text_Editor.obj & + Fl_Tile.obj & + Fl_Tiled_Image.obj & + Fl_Tooltip.obj & + Fl_Valuator.obj & + Fl_Value_Input.obj & + Fl_Value_Output.obj & + Fl_Value_Slider.obj & + Fl_Widget.obj & + Fl_Window.obj & + Fl_Window_fullscreen.obj & + Fl_Window_hotspot.obj & + Fl_Window_iconize.obj & + Fl_Wizard.obj & + Fl_XBM_Image.obj & + Fl_XPM_Image.obj & + Fl_abort.obj & + Fl_add_idle.obj & + Fl_arg.obj & + Fl_compose.obj & + Fl_display.obj & + Fl_get_key.obj & + Fl_get_system_colors.obj & + Fl_grab.obj & + Fl_lock.obj & + Fl_own_colormap.obj & + Fl_visual.obj & + Fl_x.obj & + filename_absolute.obj & + filename_expand.obj & + filename_ext.obj & + filename_isdir.obj & + filename_list.obj & + filename_match.obj & + filename_setext.obj & + fl_arc.obj & + fl_arci.obj & + fl_ask.obj & + fl_boxtype.obj & + fl_color.obj & + fl_cursor.obj & + fl_curve.obj & + fl_diamond_box.obj & + fl_dnd.obj & + fl_draw.obj & + fl_draw_image.obj & + fl_draw_pixmap.obj & + fl_encoding_latin1.obj & + fl_encoding_mac_roman.obj & + fl_engraved_label.obj & + fl_file_dir.obj & + fl_font.obj & + fl_gtk.obj & + fl_labeltype.obj & + fl_line_style.obj & + fl_open_uri.obj & + fl_oval_box.obj & + fl_overlay.obj & + fl_overlay_visual.obj & + fl_plastic.obj & + fl_read_image.obj & + fl_rect.obj & + fl_round_box.obj & + fl_rounded_box.obj & + fl_set_font.obj & + fl_set_fonts.obj & + fl_scroll_area.obj & + fl_shadow_box.obj & + fl_shortcut.obj & + fl_show_colormap.obj & + fl_symbols.obj & + fl_vertex.obj & + screen_xywh.obj + +FLCPPFILES = & + forms_compatability.obj & + forms_bitmap.obj & + forms_free.obj & + forms_fselect.obj & + forms_pixmap.obj & + forms_timer.obj + +GLCPPFILES = & + Fl_Gl_Choice.obj & + Fl_Gl_Overlay.obj & + Fl_Gl_Window.obj & + freeglut_geometry.obj & + freeglut_stroke_mono_roman.obj & + freeglut_stroke_roman.obj & + freeglut_teapot.obj & + gl_draw.obj & + gl_start.obj & + glut_compatability.obj & + glut_font.obj + +IMGCPPFILES = & + fl_images_core.obj & + Fl_BMP_Image.obj & + Fl_File_Icon2.obj & + Fl_GIF_Image.obj & + Fl_Help_Dialog.obj & + Fl_JPEG_Image.obj & + Fl_PNG_Image.obj & + Fl_PNM_Image.obj + +CFILES = fl_call_main.obj flstring.obj scandir.obj numericsort.obj vsnprintf.obj + +################################################################ + +!include ../watcom.mif + +OBJECTS = $(CPPFILES) $(CFILES) +FLOBJECTS = $(FLCPPFILES) +GLOBJECTS = $(GLCPPFILES) +IMGOBJECTS = $(IMGCPPFILES) + +# The four basic fltk libraries are defined in ../watcom.mif, so that appliactions +# can also use them. +all: $(LIBNAME) & + $(LIBNAMEFL) & + $(LIBNAMEGL) & + $(LIBNAMEIMG) + +# $(DSONAME) & +# $(FLDSONAME) & +# $(GLDSONAME) & +# $(IMGDSONAME) + + +$(LIBNAME): $(OBJECTS) + $(LIB) $(LIBOPTS) $@ $< + +$(LIBNAMEFL): $(FLOBJECTS) + $(LIB) $(LIBOPTS) $@ $< + +$(LIBNAMEGL): $(GLOBJECTS) + $(LIB) $(LIBOPTS) $@ $< + +$(LIBNAMEIMG): $(IMGOBJECTS) + $(LIB) $(LIBOPTS) $@ $< + +# +# Clean all directories +# +clean : .SYMBOLIC + @echo Cleaning up. +CLEANEXTS = exe map sym obj lk1 + @for %a in ($(CLEANEXTS)) do -rm -f $(ODIR)\*.%a + -rm -f *.err + -rm -f $(LIBNAME) + -rm -f $(LIBNAMEFL) + -rm -f $(LIBNAMEGL) + -rm -f $(LIBNAMEIMG) + diff --git a/third_party/windows/fltk-1.1.10/src/mediumarrow.h b/third_party/windows/fltk-1.1.10/src/mediumarrow.h new file mode 100644 index 0000000..9952e20 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/mediumarrow.h @@ -0,0 +1,6 @@ +#define mediumarrow_width 16 +#define mediumarrow_height 16 +static unsigned char mediumarrow_bits[] = { + 0x40, 0x00, 0x60, 0x00, 0x70, 0x00, 0x78, 0x00, 0xfc, 0x3f, 0x78, 0x00, + 0x70, 0x00, 0x60, 0x02, 0x40, 0x06, 0x00, 0x0e, 0x00, 0x1e, 0xfc, 0x3f, + 0x00, 0x1e, 0x00, 0x0e, 0x00, 0x06, 0x00, 0x02}; diff --git a/third_party/windows/fltk-1.1.10/src/new.xbm b/third_party/windows/fltk-1.1.10/src/new.xbm new file mode 100644 index 0000000..4f8665b --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/new.xbm @@ -0,0 +1,6 @@ +#define new_width 16 +#define new_height 16 +static unsigned char new_bits[] = { + 0x00, 0x00, 0x78, 0x00, 0x84, 0x00, 0x02, 0x01, 0x01, 0xfe, 0x01, 0x80, + 0x31, 0x80, 0x31, 0x80, 0xfd, 0x80, 0xfd, 0x80, 0x31, 0x80, 0x31, 0x80, + 0x01, 0x80, 0x01, 0x80, 0xff, 0xff, 0x00, 0x00}; diff --git a/third_party/windows/fltk-1.1.10/src/ns.xbm b/third_party/windows/fltk-1.1.10/src/ns.xbm new file mode 100644 index 0000000..208f952 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/ns.xbm @@ -0,0 +1,8 @@ +#define ns_width 16 +#define ns_height 16 +#define ns_x_hot 8 +#define ns_y_hot 8 +static unsigned char ns_bits[] = { + 0x00, 0x00, 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0x80, 0x01, 0x80, 0x01, + 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, 0x80, 0x01, + 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01, 0x00, 0x00}; diff --git a/third_party/windows/fltk-1.1.10/src/ns_mask.xbm b/third_party/windows/fltk-1.1.10/src/ns_mask.xbm new file mode 100644 index 0000000..6607ac2 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/ns_mask.xbm @@ -0,0 +1,8 @@ +#define ns_mask_width 16 +#define ns_mask_height 16 +#define ns_mask_x_hot 8 +#define ns_mask_y_hot 8 +static unsigned char ns_mask_bits[] = { + 0x80, 0x01, 0xc0, 0x03, 0xe0, 0x07, 0xf0, 0x0f, 0xf0, 0x0f, 0xc0, 0x03, + 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xc0, 0x03, 0xf0, 0x0f, + 0xf0, 0x0f, 0xe0, 0x07, 0xc0, 0x03, 0x80, 0x01}; diff --git a/third_party/windows/fltk-1.1.10/src/numericsort.c b/third_party/windows/fltk-1.1.10/src/numericsort.c new file mode 100644 index 0000000..cbc8971 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/numericsort.c @@ -0,0 +1,111 @@ +/* + * "$Id: numericsort.c 4288 2005-04-16 00:13:17Z mike $" + * + * Numeric sorting routine for the Fast Light Tool Kit (FLTK). + * + * Copyright 1998-2005 by Bill Spitzak and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems on the following page: + * + * http://www.fltk.org/str.php + */ + +/* My own scandir sorting function, useful for the film industry where + we have many files with numbers in their names: */ + +#include +#include +#include +#include + +#include + +#if !defined(WIN32) || defined(__CYGWIN__) +# ifdef HAVE_DIRENT_H +# include +# else +# define dirent direct +# if HAVE_SYS_NDIR_H +# include +# endif /* HAVE_SYS_NDIR_H */ +# if HAVE_SYS_DIR_H +# include +# endif /* HAVE_SYS_DIR_H */ +# if HAVE_NDIR_H +# include +# endif /* HAVE_NDIR_H */ +# endif /* HAVE_DIRENT_H */ +#endif /* !WIN32 || __CYGWIN__ */ + +/* + * 'numericsort()' - Compare two directory entries, possibly with + * a case-insensitive comparison... + */ + +static int numericsort(struct dirent **A, struct dirent **B, int cs) { + const char* a = (*A)->d_name; + const char* b = (*B)->d_name; + int ret = 0; + for (;;) { + if (isdigit(*a & 255) && isdigit(*b & 255)) { + int diff,magdiff; + while (*a == '0') a++; + while (*b == '0') b++; + while (isdigit(*a & 255) && *a == *b) {a++; b++;} + diff = (isdigit(*a & 255) && isdigit(*b & 255)) ? *a - *b : 0; + magdiff = 0; + while (isdigit(*a & 255)) {magdiff++; a++;} + while (isdigit(*b & 255)) {magdiff--; b++;} + if (magdiff) {ret = magdiff; break;} /* compare # of significant digits*/ + if (diff) {ret = diff; break;} /* compare first non-zero digit */ + } else { + if (cs) { + /* compare case-sensitive */ + if ((ret = *a-*b)) break; + } else { + /* compare case-insensitve */ + if ((ret = tolower(*a & 255)-tolower(*b & 255))) break; + } + + if (!*a) break; + a++; b++; + } + } + if (!ret) return 0; + else return (ret < 0) ? -1 : 1; +} + +/* + * 'fl_casenumericsort()' - Compare directory entries with case-sensitivity. + */ + +int fl_casenumericsort(struct dirent **A, struct dirent **B) { + return numericsort(A, B, 0); +} + +/* + * 'fl_numericsort()' - Compare directory entries with case-sensitivity. + */ + +int fl_numericsort(struct dirent **A, struct dirent **B) { + return numericsort(A, B, 1); +} + +/* + * End of "$Id: numericsort.c 4288 2005-04-16 00:13:17Z mike $". + */ diff --git a/third_party/windows/fltk-1.1.10/src/scandir.c b/third_party/windows/fltk-1.1.10/src/scandir.c new file mode 100644 index 0000000..5e01215 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/scandir.c @@ -0,0 +1,124 @@ +/* Copyright (C) 1992, 1993, 1994, 1995, 1996 Free Software Foundation, Inc. +This file is part of the GNU C Library. + +The GNU C Library is free software; you can redistribute it and/or +modify it under the terms of the GNU Library General Public License as +published by the Free Software Foundation; either version 2 of the +License, or (at your option) any later version. + +The GNU C Library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Library General Public License for more details. + +You should have received a copy of the GNU Library General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +USA. */ + +#if defined(WIN32) && !defined(__CYGWIN__) +# include "scandir_win32.c" +#else + +# include "flstring.h" + +# if !HAVE_SCANDIR +# include +# include +# include + +# if HAVE_DIRENT_H +# include +# define NAMLEN(dirent) strlen((dirent)->d_name) +# else +# define dirent direct +# define NAMLEN(dirent) (dirent)->d_namlen +# if HAVE_SYS_NDIR_H +# include +# endif +# if HAVE_SYS_DIR_H +# include +# endif +# if HAVE_NDIR_H +# include +# endif +# endif + +int +fl_scandir(const char *dir, struct dirent ***namelist, + int (*select)(struct dirent *), + int (*compar)(struct dirent **, struct dirent **)) +{ + DIR *dp = opendir (dir); + struct dirent **v = NULL; + size_t vsize = 0, i; + struct dirent *d; + int save; + + if (dp == NULL) + return -1; + + save = errno; + errno = 0; + + i = 0; + while ((d = readdir (dp)) != NULL) + if (select == NULL || (*select) (d)) + { + size_t dsize; + + if (i == vsize) + { + struct dirent **newv; + if (vsize == 0) + vsize = 10; + else + vsize *= 2; + newv = (struct dirent **) realloc (v, vsize * sizeof (*v)); + if (newv == NULL) + { + lose: + errno = ENOMEM; + break; + } + v = newv; + } + +# define _D_EXACT_NAMLEN(d) (strlen ((d)->d_name)) +# define _D_ALLOC_NAMLEN(d) (sizeof (d)->d_name > 1 ? sizeof (d)->d_name : \ + _D_EXACT_NAMLEN (d) + 1) + + dsize = &d->d_name[_D_ALLOC_NAMLEN (d)] - (char *) d; + v[i] = (struct dirent *) malloc (dsize); + if (v[i] == NULL) + goto lose; + + memcpy (v[i++], d, dsize); + } + + if (errno != 0) + { + save = errno; + (void) closedir (dp); + while (i > 0) + free (v[--i]); + free (v); + errno = save; + return -1; + } + + (void) closedir (dp); + errno = save; + + /* Sort the list if we have a comparison function to sort with. */ + if (compar) qsort (v, i, sizeof (*v), (int (*)(const void *, const void *))compar); + *namelist = v; + return i; +} + +# endif +#endif + +/* + * End of "$Id: scandir.c 4052 2005-02-24 21:55:12Z mike $". + */ diff --git a/third_party/windows/fltk-1.1.10/src/scandir_win32.c b/third_party/windows/fltk-1.1.10/src/scandir_win32.c new file mode 100644 index 0000000..128060b --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/scandir_win32.c @@ -0,0 +1,115 @@ +/* + * "$Id: scandir_win32.c 4548 2005-08-29 20:16:36Z matt $" + * + * WIN32 scandir function for the Fast Light Tool Kit (FLTK). + * + * Copyright 1998-2005 by Bill Spitzak and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems on the following page: + * + * http://www.fltk.org/str.php + */ + +#ifndef __CYGWIN__ +/* Emulation of posix scandir() call */ + +#include +#include "flstring.h" +#include +#include + +int fl_scandir(const char *dirname, struct dirent ***namelist, + int (*select)(struct dirent *), + int (*compar)(struct dirent **, struct dirent **)) { + int len; + char *findIn, *d, is_dir = 0; + WIN32_FIND_DATA find; + HANDLE h; + int nDir = 0, NDir = 0; + struct dirent **dir = 0, *selectDir; + unsigned long ret; + + len = strlen(dirname); + findIn = (char *)malloc((size_t)(len+5)); + + if (!findIn) return -1; + + strcpy(findIn, dirname); + for (d = findIn; *d; d++) if (*d=='/') *d='\\'; + if ((len==0)) { strcpy(findIn, ".\\*"); } + if ((len==2)&&findIn[1]==':'&&isalpha(findIn[0])) { *d++ = '\\'; *d = 0; } + if ((len==1)&& (d[-1]=='.')) { strcpy(findIn, ".\\*"); is_dir = 1; } + if ((len>0) && (d[-1]=='\\')) { *d++ = '*'; *d = 0; is_dir = 1; } + if ((len>1) && (d[-1]=='.') && (d[-2]=='\\')) { d[-1] = '*'; is_dir = 1; } + if (!is_dir) { /* this file may still be a directory that we need to list */ + DWORD attr = GetFileAttributes(findIn); + if (attr&FILE_ATTRIBUTE_DIRECTORY) + strcpy(d, "\\*"); + } + if ((h=FindFirstFile(findIn, &find))==INVALID_HANDLE_VALUE) { + free(findIn); + ret = GetLastError(); + if (ret != ERROR_NO_MORE_FILES) { + nDir = -1; + } + *namelist = dir; + return nDir; + } + do { + selectDir=(struct dirent*)malloc(sizeof(struct dirent)+strlen(find.cFileName)+2); + strcpy(selectDir->d_name, find.cFileName); + if (find.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) { + /* Append a trailing slash to directory names... */ + strcat(selectDir->d_name, "/"); + } + if (!select || (*select)(selectDir)) { + if (nDir==NDir) { + struct dirent **tempDir = (struct dirent **)calloc(sizeof(struct dirent*), (size_t)(NDir+33)); + if (NDir) memcpy(tempDir, dir, sizeof(struct dirent*)*NDir); + if (dir) free(dir); + dir = tempDir; + NDir += 32; + } + dir[nDir] = selectDir; + nDir++; + dir[nDir] = 0; + } else { + free(selectDir); + } + } while (FindNextFile(h, &find)); + ret = GetLastError(); + if (ret != ERROR_NO_MORE_FILES) { + /* don't return an error code, because the dir list may still be valid + up to this point */ + } + FindClose(h); + + free (findIn); + + if (compar) qsort(dir, (size_t)nDir, sizeof(*dir), + (int(*)(const void*, const void*))compar); + + *namelist = dir; + return nDir; +} + +#endif + +/* + * End of "$Id: scandir_win32.c 4548 2005-08-29 20:16:36Z matt $". + */ diff --git a/third_party/windows/fltk-1.1.10/src/screen_xywh.cxx b/third_party/windows/fltk-1.1.10/src/screen_xywh.cxx new file mode 100644 index 0000000..a393666 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/screen_xywh.cxx @@ -0,0 +1,256 @@ +// +// "$Id: screen_xywh.cxx 5848 2007-05-20 16:18:31Z mike $" +// +// Screen/monitor bounding box API for the Fast Light Tool Kit (FLTK). +// +// Copyright 1998-2005 by Bill Spitzak and others. +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Library General Public +// License as published by the Free Software Foundation; either +// version 2 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Library General Public License for more details. +// +// You should have received a copy of the GNU Library General Public +// License along with this library; if not, write to the Free Software +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 +// USA. +// +// Please report all bugs and problems on the following page: +// +// http://www.fltk.org/str.php +// + + +#include +#include +#include + + +// Number of screens... +static int num_screens = 0; + +#ifdef WIN32 +# if !defined(HMONITOR_DECLARED) && (_WIN32_WINNT < 0x0500) +# define COMPILE_MULTIMON_STUBS +# include +# endif // !HMONITOR_DECLARED && _WIN32_WINNT < 0x0500 + +// We go the much more difficult route of individually picking some multi-screen +// functions from the USER32.DLL . If these functions are not available, we +// will gracefully fall back to single monitor support. +// +// If we were to insist on the existence of "EnumDisplayMonitors" and +// "GetMonitorInfoA", it would be impossible to use FLTK on Windows 2000 +// before SP2 or earlier. + +// BOOL EnumDisplayMonitors(HDC, LPCRECT, MONITORENUMPROC, LPARAM) +typedef BOOL (WINAPI* fl_edm_func)(HDC, LPCRECT, MONITORENUMPROC, LPARAM); +// BOOL GetMonitorInfo(HMONITOR, LPMONITORINFO) +typedef BOOL (WINAPI* fl_gmi_func)(HMONITOR, LPMONITORINFO); + +static fl_gmi_func fl_gmi = NULL; // used to get a proc pointer for GetMonitorInfoA + +static RECT screens[16]; + +static BOOL CALLBACK screen_cb(HMONITOR mon, HDC, LPRECT r, LPARAM) { + if (num_screens >= 16) return TRUE; + + MONITORINFO mi; + mi.cbSize = sizeof(mi); + +// GetMonitorInfo(mon, &mi); +// (but we use our self-aquired function pointer instead) + if (fl_gmi(mon, &mi)) { + screens[num_screens] = mi.rcWork; + num_screens ++; + } + return TRUE; +} + +static void screen_init() { + // Since not all versions of Windows include multiple monitor support, + // we do a run-time check for the required functions... + HMODULE hMod = GetModuleHandle("USER32.DLL"); + + if (hMod) { + // check that EnumDisplayMonitors is available + fl_edm_func fl_edm = (fl_edm_func)GetProcAddress(hMod, "EnumDisplayMonitors"); + + if (fl_edm) { + // We do have EnumDisplayMonitors, so lets find out how many monitors... + num_screens = GetSystemMetrics(SM_CMONITORS); + + if (num_screens > 1) { + // If there is more than 1 monitor, enumerate them... + fl_gmi = (fl_gmi_func)GetProcAddress(hMod, "GetMonitorInfoA"); + + if (fl_gmi) { + // We have GetMonitorInfoA, enumerate all the screens... + num_screens = 0; +// EnumDisplayMonitors(0,0,screen_cb,0); +// (but we use our self-aquired function pointer instead) + fl_edm(0, 0, screen_cb, 0); + return; + } + } + } + } + + // If we get here, assume we have 1 monitor... + num_screens = 1; +} +#elif defined(__APPLE__) +XRectangle screens[16]; + +static void screen_init() { + GDHandle gd; + + for (gd = GetDeviceList(), num_screens = 0; gd; gd = GetNextDevice(gd)) { + GDPtr gp = *gd; + screens[num_screens].x = gp->gdRect.left; + screens[num_screens].y = gp->gdRect.top; + screens[num_screens].width = gp->gdRect.right - gp->gdRect.left; + screens[num_screens].height = gp->gdRect.bottom - gp->gdRect.top; + + num_screens ++; + if (num_screens >= 16) break; + } +} +#elif HAVE_XINERAMA +# include + +// Screen data... +static XineramaScreenInfo *screens; + +static void screen_init() { + if (!fl_display) fl_open_display(); + + if (XineramaIsActive(fl_display)) { + screens = XineramaQueryScreens(fl_display, &num_screens); + } else num_screens = 1; +} +#else +static void screen_init() { + num_screens = 1; +} +#endif // WIN32 + + +// Return the number of screens... +int Fl::screen_count() { + if (!num_screens) screen_init(); + + return num_screens; +} + +// Return the screen bounding rect for the given mouse position... +void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int mx, int my) { + if (!num_screens) screen_init(); + +#ifdef WIN32 + if (num_screens > 1) { + int i; + + for (i = 0; i < num_screens; i ++) { + if (mx >= screens[i].left && mx < screens[i].right && + my >= screens[i].top && my < screens[i].bottom) { + X = screens[i].left; + Y = screens[i].top; + W = screens[i].right - screens[i].left; + H = screens[i].bottom - screens[i].top; + return; + } + } + } +#elif defined(__APPLE__) + if (num_screens > 1) { + int i; + + for (i = 0; i < num_screens; i ++) { + if (mx >= screens[i].x && + mx < (screens[i].x + screens[i].width) && + my >= screens[i].y && + my < (screens[i].y + screens[i].height)) { + X = screens[i].x; + Y = screens[i].y; + W = screens[i].width; + H = screens[i].height; + return; + } + } + } +#elif HAVE_XINERAMA + if (num_screens > 1) { + int i; + + for (i = 0; i < num_screens; i ++) { + if (mx >= screens[i].x_org && + mx < (screens[i].x_org + screens[i].width) && + my >= screens[i].y_org && + my < (screens[i].y_org + screens[i].height)) { + X = screens[i].x_org; + Y = screens[i].y_org; + W = screens[i].width; + H = screens[i].height; + return; + } + } + } +#else + (void)mx; + (void)my; +#endif // WIN32 + + X = Fl::x(); + Y = Fl::y(); + W = Fl::w(); + H = Fl::h(); +} + +// Return the screen bounding rect for the given screen... +void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int n) { + if (!num_screens) screen_init(); + +#ifdef WIN32 + if (num_screens > 1 && n >= 0 && n < num_screens) { + X = screens[n].left; + Y = screens[n].top; + W = screens[n].right - screens[n].left; + H = screens[n].bottom - screens[n].top; + return; + } +#elif defined(__APPLE__) + if (num_screens > 1 && n >= 0 && n < num_screens) { + X = screens[n].x; + Y = screens[n].y; + W = screens[n].width; + H = screens[n].height; + return; + } +#elif HAVE_XINERAMA + if (num_screens > 1 && n >= 0 && n < num_screens) { + X = screens[n].x_org; + Y = screens[n].y_org; + W = screens[n].width; + H = screens[n].height; + return; + } +#else + (void)n; +#endif // WIN32 + + X = Fl::x(); + Y = Fl::y(); + W = Fl::w(); + H = Fl::h(); +} + + +// +// End of "$Id: screen_xywh.cxx 5848 2007-05-20 16:18:31Z mike $". +// diff --git a/third_party/windows/fltk-1.1.10/src/slowarrow.h b/third_party/windows/fltk-1.1.10/src/slowarrow.h new file mode 100644 index 0000000..0958377 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/slowarrow.h @@ -0,0 +1,6 @@ +#define slowarrow_width 16 +#define slowarrow_height 16 +static unsigned char slowarrow_bits[] = { + 0x40, 0x00, 0x40, 0x00, 0x60, 0x00, 0x60, 0x00, 0xf0, 0x0f, 0x60, 0x00, + 0x60, 0x00, 0x40, 0x02, 0x40, 0x02, 0x00, 0x06, 0x00, 0x06, 0xf0, 0x0f, + 0x00, 0x06, 0x00, 0x06, 0x00, 0x02, 0x00, 0x02}; diff --git a/third_party/windows/fltk-1.1.10/src/tile.xpm b/third_party/windows/fltk-1.1.10/src/tile.xpm new file mode 100644 index 0000000..9d4087a --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/tile.xpm @@ -0,0 +1,91 @@ +/* XPM */ +static char tile_cmap[3][32] = { +"O c #FFFFFF", +"o c #EFEFEF", +". c #E8E8E8" +}; +static const char * tile_xpm[] = { +"64 64 3 1", +tile_cmap[0], +tile_cmap[1], +tile_cmap[2], + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO", + +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"................................................................", +"oooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooooo", +"OOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO"}; diff --git a/third_party/windows/fltk-1.1.10/src/up.xbm b/third_party/windows/fltk-1.1.10/src/up.xbm new file mode 100644 index 0000000..af566b0 --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/up.xbm @@ -0,0 +1,6 @@ +#define up_width 16 +#define up_height 16 +static unsigned char up_bits[] = { + 0x00, 0x00, 0x78, 0x00, 0x84, 0x00, 0x02, 0x01, 0x31, 0xfe, 0x79, 0x80, + 0xfd, 0x80, 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, 0x31, 0x80, + 0x01, 0x80, 0x01, 0x80, 0xff, 0xff, 0x00, 0x00}; diff --git a/third_party/windows/fltk-1.1.10/src/vsnprintf.c b/third_party/windows/fltk-1.1.10/src/vsnprintf.c new file mode 100644 index 0000000..77961be --- /dev/null +++ b/third_party/windows/fltk-1.1.10/src/vsnprintf.c @@ -0,0 +1,281 @@ +/* + * "$Id: vsnprintf.c 5850 2007-05-21 15:56:17Z matt $" + * + * snprintf() and vsnprintf() functions for the Fast Light Tool Kit (FLTK). + * + * Copyright 1998-2007 by Bill Spitzak and others. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 + * USA. + * + * Please report all bugs and problems on the following page: + * + * http://www.fltk.org/str.php + */ + +#include +#include "flstring.h" + +#ifdef HAVE_SYS_STDTYPES_H +# include +#endif /* HAVE_SYS_STDTYPES_H */ + +#ifdef __cplusplus +extern "C" { +#endif + +int fl_vsnprintf(char* buffer, size_t bufsize, const char* format, va_list ap) { + char *bufptr, /* Pointer to position in buffer */ + *bufend, /* Pointer to end of buffer */ + sign, /* Sign of format width */ + size, /* Size character (h, l, L) */ + type; /* Format type character */ + int width, /* Width of field */ + prec; /* Number of characters of precision */ + char tformat[100], /* Temporary format string for sprintf() */ + *tptr, /* Pointer into temporary format */ + temp[1024]; /* Buffer for formatted numbers */ + char *s; /* Pointer to string */ + int slen; /* Length of string */ + int bytes; /* Total number of bytes needed */ + + + /* + * Loop through the format string, formatting as needed... + */ + + bufptr = buffer; + bufend = buffer + bufsize - 1; + bytes = 0; + + while (*format) { + if (*format == '%') { + tptr = tformat; + *tptr++ = *format++; + + if (*format == '%') { + if (bufptr && bufptr < bufend) *bufptr++ = *format; + bytes ++; + format ++; + continue; + } else if (strchr(" -+#\'", *format)) { + *tptr++ = *format; + sign = *format++; + } else sign = 0; + + if (*format == '*') { + /* Get width from argument... */ + format ++; + width = va_arg(ap, int); + snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", width); + tptr += strlen(tptr); + } else { + width = 0; + while (isdigit(*format & 255)) { + if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; + width = width * 10 + *format++ - '0'; + } + } + + if (*format == '.') { + if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; + format ++; + + if (*format == '*') { + /* Get precision from argument... */ + format ++; + prec = va_arg(ap, int); + snprintf(tptr, sizeof(tformat) - (tptr - tformat), "%d", prec); + tptr += strlen(tptr); + } else { + prec = 0; + while (isdigit(*format & 255)) { + if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; + prec = prec * 10 + *format++ - '0'; + } + } + } else prec = -1; + + size = '\0'; + + if (*format == 'l' && format[1] == 'l') { + size = 'L'; + if (tptr < (tformat + sizeof(tformat) - 2)) { + *tptr++ = 'l'; + *tptr++ = 'l'; + } + format += 2; + } else if (*format == 'h' || *format == 'l' || *format == 'L') { + if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; + size = *format++; + } + + if (!*format) break; + + if (tptr < (tformat + sizeof(tformat) - 1)) *tptr++ = *format; + type = *format++; + *tptr = '\0'; + + switch (type) { + case 'E' : /* Floating point formats */ + case 'G' : + case 'e' : + case 'f' : + case 'g' : + if ((width + 2) > sizeof(temp)) break; + + sprintf(temp, tformat, va_arg(ap, double)); + + bytes += strlen(temp); + + if (bufptr) { + if ((bufptr + strlen(temp)) > bufend) { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } else { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; + + case 'B' : /* Integer formats */ + case 'X' : + case 'b' : + case 'd' : + case 'i' : + case 'o' : + case 'u' : + case 'x' : + if ((width + 2) > sizeof(temp)) break; + +#ifdef HAVE_LONG_LONG + if (size == 'L') + sprintf(temp, tformat, va_arg(ap, long long)); + else +#endif /* HAVE_LONG_LONG */ + if (size == 'l') + sprintf(temp, tformat, va_arg(ap, long)); + else + sprintf(temp, tformat, va_arg(ap, int)); + + bytes += strlen(temp); + + if (bufptr) { + if ((bufptr + strlen(temp)) > bufend) { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } else { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; + + case 'p' : /* Pointer value */ + if ((width + 2) > sizeof(temp)) break; + + sprintf(temp, tformat, va_arg(ap, void *)); + + bytes += strlen(temp); + + if (bufptr) { + if ((bufptr + strlen(temp)) > bufend) { + strncpy(bufptr, temp, (size_t)(bufend - bufptr)); + bufptr = bufend; + } else { + strcpy(bufptr, temp); + bufptr += strlen(temp); + } + } + break; + + case 'c' : /* Character or character array */ + bytes += width; + + if (bufptr) { + if (width <= 1) *bufptr++ = va_arg(ap, int); + else { + if ((bufptr + width) > bufend) width = bufend - bufptr; + + memcpy(bufptr, va_arg(ap, char *), (size_t)width); + bufptr += width; + } + } + break; + + case 's' : /* String */ + if ((s = va_arg(ap, char *)) == NULL) s = "(null)"; + + slen = strlen(s); + if (slen > width && prec != width) width = slen; + + bytes += width; + + if (bufptr) { + if ((bufptr + width) > bufend) width = bufend - bufptr; + + if (slen > width) slen = width; + + if (sign == '-') { + strncpy(bufptr, s, (size_t)slen); + memset(bufptr + slen, ' ', (size_t)(width - slen)); + } else { + memset(bufptr, ' ', (size_t)(width - slen)); + strncpy(bufptr + width - slen, s, (size_t)slen); + } + + bufptr += width; + } + break; + + case 'n' : /* Output number of chars so far */ + *(va_arg(ap, int *)) = bytes; + break; + } + } else { + bytes ++; + + if (bufptr && bufptr < bufend) *bufptr++ = *format; + format ++; + } + } + + /* + * Nul-terminate the string and return the number of characters needed. + */ + + if (bufptr) *bufptr = '\0'; + + return (bytes); +} + +int fl_snprintf(char* str, size_t size, const char* fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = vsnprintf(str, size, fmt, ap); + va_end(ap); + return ret; +} + +#ifdef __cplusplus +} +#endif + +/* + * End of "$Id: vsnprintf.c 5850 2007-05-21 15:56:17Z matt $". + */ + -- cgit v1.3.1