diff --git a/.github/workflows/cmake.yml b/.github/workflows/cmake.yml index 71fd1ab31a..756700177c 100644 --- a/.github/workflows/cmake.yml +++ b/.github/workflows/cmake.yml @@ -76,13 +76,13 @@ jobs: obsidian.exe retention-days: ${{env.RETENTION_DAYS}} build-linux: - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 steps: - uses: actions/checkout@v4 - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y libxft-dev libfontconfig1-dev libgl-dev + sudo apt-get install -y libxft-dev libfontconfig1-dev libgl-dev libfltk1.3-dev - name: Configure CMake Ubuntu run: mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build Ubuntu @@ -108,6 +108,8 @@ jobs: runs-on: macos-latest steps: - uses: actions/checkout@v4 + - name: Install HomeBrew FLTK + run: brew install fltk - name: Configure CMake MacOS run: mkdir build && cd build && cmake .. -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} - name: Build MacOS diff --git a/libraries/fltk/ANNOUNCEMENT b/libraries/fltk/ANNOUNCEMENT index 9b3afe13e7..f05fd253c7 100644 --- a/libraries/fltk/ANNOUNCEMENT +++ b/libraries/fltk/ANNOUNCEMENT @@ -1,15 +1,49 @@ -FLTK 1.4 is based on the final release of FLTK 1.3.4. +FLTK 1.4 is based on the final release of FLTK 1.3.4. Later updates +have been backported to 1.3.5 - 1.3.10. -Technically the branch was forked earlier, but all changes in FLTK 1.3.4 -have also been (modified and) committed in branch-1.3-porting, which is -the base of branch-1.4. - -FLTK 1.4 is intended to be mostly API compatible with FLTK 1.3.4 so +FLTK 1.4 is intended to be mostly API compatible with FLTK 1.3.x so you don't need to change source code when you switch to FLTK 1.4. +However, all programs must be recompiled with FLTK 1.4 because the +ABI (Application Binary Interface) has changed. + +Potential source code conflicts are documented in chapter "Migrating +Code from FLTK 1.3 to 1.4" of the user documentation [1]. + +FLTK 1.4 adds some new widgets (e.g. Fl_Flex, Fl_Grid) for flexible GUI +layout, Fl_Scheme_Choice for scheme selection by users, and more. +Other widgets (Fl_Tabs, Fl_Tile, Fl_Spinner etc.) have been improved +for better user experience. + +FLTK 1.4 supports HighDPI displays under Linux/Unix and Windows and +improves HighDPI support on macOS. The initial screen scaling factor is +read from the system and application windows can be zoomed (in/out/reset) +by the user with ctrl/+/-/0 shortcuts, respectively. + +CMake support has been improved significantly and requires CMake 3.15 or +higher, autotools/configure/make is still supported. The latter will be +dropped in the next minor release (1.5.0). + +macOS is supported up to 15.0 "Sequoia". + +The platform dependent code in FLTK 1.4 was rewritten to enable easier +porting to new platforms. Basically all platform dependent code has +been isolated and implemented in virtual methods of "driver" classes. +For details see 'src/drivers' and subdirectories. + +FLTK is now compatible with the Wayland platform on current Linux +distributions and FreeBSD. The default build of the library on these +platforms supports both X11 and Wayland in a "hybrid" library. Programs +compiled and linked to this library start using Wayland if it is +available at runtime and fall back to using X11 if not. Programs using +X11 specific code that are not yet ported to Wayland can still be used +on pure X11 systems or by disabling the Wayland support on startup so +they fall back to using X11 only. This requires 'XWayland' support on +Wayland enabled (Linux) systems. -However, the platform dependent code in FLTK 1.4 was rewritten to enable -better porting to new platforms. Basically all platform dependent code -has been isolated and implemented in virtual methods of "driver" classes. -See src/drivers and subdirectories. +The current development branch on GitHub [2] is `master`. This will be +changed to `branch-1.4` when development of FLTK 1.5.0 begins and 1.4 +will be switched to maintenance mode. -More to come ... +[1] https://www.fltk.org/doc-1.4/ (HTML) and + https://www.fltk.org/doc-1.4/fltk.pdf (PDF) +[2] https://github.com/fltk/fltk.git diff --git a/libraries/fltk/CHANGES.txt b/libraries/fltk/CHANGES.txt index 282830c8db..dd01b94bc9 100644 --- a/libraries/fltk/CHANGES.txt +++ b/libraries/fltk/CHANGES.txt @@ -1,20 +1,77 @@ -Changes in FLTK 1.4.0 Released: Feb ?? 2024 +Changes in FLTK 1.4.0 Released: Nov 17 2024 + + Bug Fixes: + + - Windows: Fix "fullscreen_off does not correctly preserve window size" (#1116) + - Fix rounding issues with Fl_RGB_Image::draw() + Fl_Copy_Surface (#1120, #1124) + - Windows: Fix "Keyboard shortcut (alt+letter) does not work in input widget" (#1122) + - macOS: Fix Alt-modifier handling in Fl_Shorcut_Button + - Windows: Fix flicker/animation when transitioning from fullscreen to maximized + - Wayland: protect against rounding errors in copy_region() + + Documentation and other Improvements: + + - Revert gtk+ specific "chevron style" arrow drawing (#1117) + - Update CREDITS.txt + - Improve 'test/fltk-versions' demo program + + +Changes in FLTK 1.4.0 RC3 Released: Nov 08 2024 + + Bug Fixes: + + - Windows: "Fullscreen doesn't always pick the correct display" (#1097) + - macOS: "Mixing native fullscreen button with Fl_Window::fullscreen()" (#1098) + - Wayland: Issue in maximization of a borderless window (#1099) + - macOS: "Merge All Windows" fails if focused window is borderless (#1100) + - macOS: Fl_Window::fullscreen() doesn't work for unfocused tabbed window (#1101) + - Fl_Tile resizing for "sudden" size changes (#1102) + - macOS: Weak linking error with latest SDK 15 (#1103, #1105) + - X11: test/checkers drawing artifacts when window is scaled (#1109) + - X11: test/curve "points" mode not drawn correctly (#1110) + - X11: test/gl_overlay stale overlay rendering (#1111) + - fl_draw_image() with horizontal flip reads out of bounds (#1112) + - macOS: Very minor high DPI rounding issue with fl_rect (#1113) + - macOS: Prevent changing window border if window is fullscreen or maximized + - Mac/XQuartz: Restore Fl_Widget_Surface::draw_decorated_window() + + Other Improvements: + + - Improve member function Fl_Wayland_Graphics_Driver::copy_offscreen() + - Make Fl_Window::flush() public for consistency with subclasses + - Improve UI layout of 'fltk-options' + - Fix compiler warnings + - Improve and clarify documentation, including README.CMake.txt + + +Changes in FLTK 1.4.0 RC2 Released: Oct 27 2024 + + - Add range check to Fl_Group::child(int) + - Fix Windows Ctrl character handling for scaling shortcuts + - Fluid: Add missing code for Fl_Grid and Fl_Flex live preview (#1092) + - Enhance documentation + - Mention HighDPI support in 'ANNOUNCEMENT' + - Update CHANGES.txt + + +Changes in FLTK 1.4.0 RC1 Released: Oct 20 2024 General Information about this Release - - FLTK 1.4.0 is based on FLTK 1.3.4 (released Nov 15 2016), - see CHANGES_1.3.txt for more information. + - FLTK 1.4.0 is based on FLTK 1.3.4 (released Nov 15 2016). + Later updates have partially been backported to 1.3.x releases, see + CHANGES_1.3.txt for more information. - CMake is the primary supported build system in FLTK 1.4.0 and later. - CMake can be used to generate Makefiles, IDE project files, and - several other build systems by using different "generators" provided + CMake can be used to generate Makefiles, IDE project files, and files + for several other build systems by using different "generators" provided by CMake (for instance Ninja, CodeBlocks, Eclipse, KDevelop3, Xcode, etc.). FLTK uses "Modern CMake" since release 1.4.0 which simplifies user project build systems significantly. See README.CMake.txt and documentation chapter "Migrating Code from FLTK 1.3 to 1.4" for more information. - - autoconf/configure is still supported by the FLTK team for backwards + - autoconf/configure is still supported by the FLTK Team for backwards compatibility with older systems that lack CMake support. Support of autoconf/configure will be dropped in FLTK 1.5.0. @@ -23,6 +80,35 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 New Features and Extensions + - fltk-config allows to compile multiple files with more compiler and linker + options given on the commandline. + - fl_contrast() functionality has been improved, adding a new contrast + calculation method based on human contrast perception. This new function + is now the default but the old, less accurate, contrast function can be + chosen as an option. + - Timeout handling has been unified across platforms (#379), see documentation + in chapter "Migrating Code from FLTK 1.3 to 1.4". + - New Fl::remove_next_timeout(...) to remove only one timeout (#992). + - New fltk-options executable, improved Fl::option documentation. + - New function `Fl_Window::get_size_range()` (#981). + - New FL_DEPRECATED macro to flag deprecated functions and methods. + - Enable suppression of "deprecated" warnings by macro FL_NO_DEPRECATE. + - New animated GIF images support (Fl_Anim_GIF_Image class) (#375). + - GIF and BMP files can now be "read" from memory, i.e. they can be included + in source code (use their new constructors). + - New Fl_Scheme_Choice widget can be used to easily switch schemes in apps. + - A new scheme named "oxy" has been added (STR 2675, STR 3477). + - Drawing "Arrows" has been unified in all core widgets. + - Drawing "Radio Buttons" has been unified in all core widgets. + - Drawing "Check Marks" has been unified in all core widgets. + - New methods Fl_Group::on_insert/on_remove/on_move (#527) can be used in + derived classes to detect addition or removal of children. + - FLTK widgets can now be used in OpenGL 3 windows. + - The new convenience function Fl::hide_all_windows() can be used to close + all open windows, for instance to exit the running program. + - Windows platform: optionally use GDI+ to antialias oblique lines and curves. + - Windows: The new function Fl::args_to_utf8() can be used to convert + "wide character" commandline arguments to UTF-8. - X11 and Wayland platforms: Added support of HiDPI displays. FLTK apps detect the current display scaling factor and use it to scale all windows. - MSWindows platform: FLTK applications detect the display scaling factor and @@ -38,10 +124,21 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 This supports desktops mixing screens with distinct resolutions. In addition, use environment variable FLTK_SCALING_FACTOR to further adjust the starting scaling factor of all FLTK apps. + - Note: On some platforms and with some international keyboard layouts you may + need to set Fl::option(OPTION_SIMPLE_ZOOM_SHORTCUT) to be able to use one or + more of the scaling shortcuts above with or without pressing the Shift key. + The new executable `fltk-options` can be used to set this option either + system wide or for a single user. + - New horizontal and vertical label margins. + - Fluid got a lot of UI and functional improvements and the Fluid docs have + been reworked and put in an own "Fluid User Manual" (HTML and PDF). + Fluid supports the new Fl_Flex and Fl_Grid widgets. + For more details please see the manual. - New Fl_Grid class to layout multiple columns and rows of widgets. - New Fl_Flex class to layout one row or one column of widgets. - - New Fl_Terminal widget supporting Unicode/utf-8, ANSI/xterm escape codes + - New Fl_Terminal widget supporting Unicode/UTF-8, ANSI/xterm escape codes with full RGB color control. + - New Fl_Copy_Surface to copy drawings to the clipboard. - New Fl::keyboard_screen_scaling(0) call stops recognition of ctrl/+/-/0/ keystrokes as scaling all windows of a screen. - New member function Fl_Image::scale(int width, int height) to set @@ -53,6 +150,9 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 Fl_Widget::bind_deimage(Fl_Image *img) to bind an image to a widget, that is, to set an image to be used as part of the widget label and also to be deleted when the widget is deleted. + - New member function Fl_Menu_::menu_end() to ensure that the menu is fully + constructed in its final location after dynamic modifications. This is + called automatically before the menu is shown. - New Fl_SVG_Image class: gives support of scalable vector graphics images to FLTK using the nanosvg software. - New Fl_ICO_Image class to read Windows .ico icon files. @@ -65,6 +165,8 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 - Fl_Tabs widget now supports close buttons for individual tabs. - Fl_Tabs widget now supports four different modes for handling an overflowing number of tabs. + - Mouse buttons 4 + 5 (aka "side buttons") are now supported (#1076, #1068). + These are typically used as "back" and "forward" functions, e.g. in browsers. - Windows platform: added support for using a manifest to set the application's level of DPI awareness (issue #309). - class Fl_Native_File_Chooser on the X11/Wayland platform relies on external @@ -101,6 +203,8 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 - New member functions Fl_Paged_Device::begin_job() and begin_page() replace start_job() and start_page(). The start_... names are maintained for API compatibility. + - Fl_Gl_Window can now contain FLTK widgets that are drawn on top of the + OpenGL scene. - OpenGL draws text using textures on all platforms, when the necessary hardware support is present (a backup mechanism is available in absence of this support). Thus, all text drawable in Fl_Window's can be drawn @@ -138,6 +242,11 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 receiving graphics commands. - New macros for easy function and method callbacks with multiple type safe arguments (see FL_METHOD_CALLBACK_1 etc.) . + - The value box size of Fl_Value_Slider is now user settable (STR 3222). + - The new header file FL/fl_config.h replaces FL/abi-version.h and + includes some more build configuration settings. This file is always + included automatically. + - Nested (aka recursive) common dialogs are now possible (STR 3242, #282). Removed Features @@ -145,15 +254,19 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 and the CMake option 'OPTION_USE_XDBE' have been removed because XDBE was unreliable and rarely supported by X servers. Double buffering support in Fl_Double_Window is not affected. + - Hardware "overlay" support has been removed. This was rarely implemented + and should not affect user code because overlay support is simulated. New Configuration Options (ABI Version) + - Add --without-fluid configure option (#725) if Fluid is not needed. - X11 platform: Added support for drawing text with the pango library which allows to draw most scripts supported by Unicode, including CJK and right-to-left scripts. FLTK now outputs PostScript that draws those scripts in vectorial form. The corresponding CMake option is FLTK_USE_PANGO. The corresponding configure option is --enable-pango. - This option is OFF by default. + This option is OFF by default when the build is only for X11 and ON + when Wayland support is built as well. - Configure option --enable-wayland allows to build the FLTK library for the new Wayland platform while remaining compatible with X11. The corresponding CMake option is FLTK_BACKEND_WAYLAND. This option is ON by default. @@ -172,6 +285,9 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 Fl_EPS_File_Surface and Fl_Printer (under X11 platform only) ineffective. - FLTK's ABI version can be configured with 'configure' and CMake. See documentation in README.abi-version.txt. + - Building the 'Forms' compatibility library 'fltk_forms' is now optional, + default is ON. This may be turned to OFF in a later FLTK release. + - CMake/Windows/MSVC: New option to select MSVC Runtime when linking apps. Bundled libraries @@ -185,9 +301,15 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 Other Improvements - - (add new items here) - - Added support of macOS 14.0 "Sonoma", 13.0 "Ventura", 12.0 "Monterey", - and 11.0 "Big Sur". + - Fl_Image::copy() is now 'const', including all derived classes. + Note: This may require code changes in classes derived from Fl_Image, + see documentation in chapter "Migrating Code from FLTK 1.3 to 1.4". + - Fl_Native_File_Chooser can now use kdialog, zenity, and/or GTK3 native + file choosers on Linux. + - Contrast of check marks and radio buttons has been improved (#443). + - Improve X11 (16-bit) clipping of lines and rectangles. + - Added support of macOS 15.0 "Sequoia", 14.0 "Sonoma", + 13.0 "Ventura", 12.0 "Monterey", and 11.0 "Big Sur". - Added macOS support for the arm64 architecture since 11.0 (Big Sur). - Added support for macOS 10.15 "Catalina" - Added support for macOS 10.14 "Mojave": all drawing to windows is done @@ -197,6 +319,10 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 widget (issue #270). - Fixed X11 copy-paste and drag-and-drop target selection (issue #182). This fix has been backported to 1.3.6 as well. + - The user can now copy standard dialog text to the clipboard by + hitting Ctrl/C (#388). + - The selected color in Fl_Color_Chooser can now be copied to the + clipboard by hitting Ctrl/C. - Add optional argument to Fl_Printer::begin_job() to receive a string describing the error when an error occurs. - Fix Windows-specific bug when the program tries to enlarge a @@ -207,9 +333,8 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 - Fix Fl::add_timeout() in draw() under Linux (STR 3188) - Improved documentation for '@' symbols in labels (STR #2940). - Fl_Roller can now be controlled via the mouse wheel (STR #3120). + - Handle Shift + mousewheel event as horizontal scrolling (STR 3521). - Tooltips hide by themselves after 12 seconds (STR #2584). - - Added widget visibility indicator to Fluid (STR #2669). - - Improved shell script support in FLUID - Improved constructor for creating Fl_Preferences files with flags for the correct locale and for overwriting existing files. - Added Fl_Input_::append() method (STR #2953). @@ -233,13 +358,16 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 documentations to make clear that the leading underscore must not be used in user code, although the enum documentation still contains leading underscores for technical reasons (internal use). + - Boxtypes can now be configured to draw their own custom focus box. - The blocks demo program got a new keyboard shortcut (ALT+SHIFT+H) to reset the user's high score. It is now slower than before in higher levels, hence you can expect higher scores (due to a bug fix in the timer code). You can use the '+' key to increase the level at all times. - Some methods of Fl_Tabs are now virtual and/or protected for easier subclassing without code duplication (STR #3211 and others). - To be continued... + - Fl_Tabs now has an option to delete tabs by the user (UI), and tab + overflow has been largely improved with several options. + - glutAddMenuEntry() now has a *const* label argument (STR #3323) - Separated Fl_Input_Choice.H and Fl_Input_Choice.cxx (STR #2750, #2752). - Separated Fl_Spinner.H and Fl_Spinner.cxx (STR #2776). - New method Fl_Spinner::wrap(int) allows to set wrap mode at bounds if @@ -248,12 +376,16 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 keyboard focus (STR #2989). - Renamed test/help.cxx demo program to test/help_dialog.cxx to avoid name conflict with CMake's auto-generated target 'help'. + - Fl_Menu_Bar: left and right arrow keys now wrap to the menu at the + other end of the menubar when pressed in the first (resp. last) menu. + - Previously "public" members Fl::awake_ring_*_ are now "private" (#559). + - The test/clipboard demo program can now save PNG images. + - New virtual int Fl_Group::delete_child(int n) (STR 3218). - Many documentation fixes, clarifications, and enhancements. Bug Fixes - - (add new items here) - Fixed all Pixmaps to be '*const' (STR #3108). - Fixed Fl_Text_Editor selection range after paste (STR #3248). - Fixed crash for very small Fl_Color_Chooser (STR #3490). @@ -261,15 +393,12 @@ Changes in FLTK 1.4.0 Released: Feb ?? 2024 - Fixed pulldown menu position when at the bottom of the screen (STR #2880). - Fixed missing item handling in Fl_Check_Browser (STR #3480). - Fixed Delete key in Fl_Input deleting entire widgets in Fluid (STR #2841). - - Reorganized Fluid Template feature (STR #3336). - - Updated Fluid documentation and image (STR #3328). - - FLUID recognizes `override` and `FL_OVERRIDE` keywords (Github #801) - Duplicating Widget Class in Fluid no longer crashes (STR #3445). + - Fixed 'fluid.app' on case sensitive macOS (was: 'Fluid.app'). - Fl_Check_Browser::add(item) now accepts NULL (STR #3498). - Interface to set maximum width of spinner text field (STR #3386). - Fl_Text_Display no longer wiggles (STR #2531). - Fixed Help_View return value (STR #3430). - - Fix 'fluid.app' on case sensitive macOS (was: Fluid.app). - Fix FL_PUSH event handling of Fl_Check_Browser (STR #3004). - Fix a potential crash when a program exits before it opens a window (Windows only, STR #3484). diff --git a/libraries/fltk/CHANGES_1.3.txt b/libraries/fltk/CHANGES_1.3.txt index 8844aa0270..cac1ab7215 100644 --- a/libraries/fltk/CHANGES_1.3.txt +++ b/libraries/fltk/CHANGES_1.3.txt @@ -1,3 +1,187 @@ +CHANGES IN FLTK 1.3.9 RELEASED: Dec 09 2023 + +FLTK 1.3.9 is a maintenance release with some fixes and enhancements. + +Highlights in this release: + + - Support macOS up to macOS 14 "Sonoma". + - Update bundled libraries to current versions (see below). + - Introduce bundled image library "prefixing" to avoid conflicts + with system libraries. + - New CMake option FLTK_MSVC_RUNTIME_DLL to select Visual Studio + Runtime version: DLL (/MDx) or static (/MTx), see README.CMake.txt + + +Bundled library versions (see also README.bundled-libs.txt): + + Library Version Release date + --------------------------------------------- + jpeg jpeg-9e 2022-01-16 + png libpng-1.6.40 2023-06-21 + zlib zlib-1.3 2023-08-18 + + +Details: + + Albrecht Schlosser: + Backport X11 INCR protocol fixes from 1.4.0 (issue #451) + X11: Suppress compiler warnings when using gcc or clang + Fix crash if a program exits before it opens a window (STR 3484). + Fix compilation error with current Visual Studio 2022 + Windows: #define WIN32 if not defined by user + Backport warning fixes from 1.4.0 in src/fl_draw.cxx (#693) + Fix compiler warning as pointed out in PR #693 + Fix another compiler warning (#693) + Remove unused variable, fix "type issue" (#445, part 2) + Fix stack buffer overflow found by address sanitizer + Fix "gtk+ rendering" (GitHub Issue #443) + Fix doxygen warnings + Bump version numbers, prepare release 1.3.9 + Fix several compiler warnings + Update bundled image libraries and zlib to current versions + Update README, README.CMake.txt, and some support files + Fix compiler warnings: backported from 1.4 (git 'master') + CMake/MSVC: remove confusing recommendation to rerun CMake + Documentation: remove dark color on title page + Raise CMake minimum required version to 3.15 and more + + ManoloFLTK: + macOS platform: Issue #325 "Disabling IM disables Greek and Cyrillic layouts" + Fix fullscreen window level corner cases on macOS + Fix issue #373 apparent with macOS platform and SDK ≤ 10.13 + Issue #452: Fl::get_font_name failure on OS-X. + Issue #454: crash in Fl::get_font_name(). + Issue #469: Fl_Sys_Menu_Bar menu item shortcuts using Esc or Tab don't work on Mac + Fix "Focus is lost leaving full screen on macOS 13" (#608) + Add support of macOS Ventura 13.0 and macOS Sonoma 14.0 + macOS: remove configure option --enable-x11 and CMake OPTION_APPLE_X11; + this functionality remains in FLTK 1.4. + configure.ac: make sure local-png and local-zlib always run together + Remove the -mwindows argument from CFLAGS and CXXFLAGS + +Matthias Melcher: + Issue #188: Fix reference counts and search for Fl_Shared_Image original + + YX: + Fix IME problem (issue #270) + + +CHANGES IN FLTK 1.3.8 RELEASED: Nov 20 2021 + +FLTK 1.3.8 is a maintenance release with some fixes and enhancements. + +Details: + + Albrecht Schlosser: + Make "FLTK_CONSOLIDATE_MOTION" user-definable (issue #76) + Fix compiler warnings (backported from 1.4) + Add new dialog fl_choice_n() with extended return values (#282) + + ManoloFLTK: + Account for deprecation of [NSBitmapImageRep initWithFocusedViewRect:] + in macOS 10.14 + macOS: fix fullscreen window when other windows were created before + Fix issue #287: "FLTK 1.3.6 doesn't handle fullscreen on macOS" + Fix issue #288: "FLTK 1.3.6+ doesn't notify window movement on macOS" + Fix issue #279: "HiDpi issue on macOS with retina display" + macOS: Allow building with non-Apple compiler that may not support blocks + + +CHANGES IN FLTK 1.3.7 RELEASED: Jul 25 2021 + +FLTK 1.3.7 is a maintenance release for macOS only. It fixes one +regression introduced in FLTK 1.3.6 and two long standing timer +issues on macOS. + +Other platforms than macOS are not concerned. + +Changes: + + Avoid premature FL_RELEASE event at start of drag-n-drop operation + Fix a timer inconsistency and prevent a crash + Fl::add_timeout() must always create a new timer (#248) + + + +CHANGES IN FLTK 1.3.6 RELEASED: May 15 2021 + +There have been no changes since FLTK 1.3.6rc2. + + +CHANGES IN FLTK 1.3.6rc2 RELEASED: May 04 2021 + +FLTK 1.3.6rc2 fixes some minor issues of 1.3.6rc1, particularly macOS +bundle generation. It addresses an issue that bundles can't be executed +on macOS 11.3 Big Sur if built with configure/make after downloading +the release tarball because of the macOS "quarantine" feature. + +Details: + + Albrecht Schlosser: + Rename file 'VERSION' to 'fltk_version.dat' (#191) + Fix version number in doxygen docs + Fix build with Cairo for CMake < 3.13 + CMake: fix old (pre 3.13) link_directories() usage + Enhance CMake build configuration summary + Refactor macOS bundle generation to avoid "quarantine" + Fix a new compiler warning + + +CHANGES IN FLTK 1.3.6rc1 RELEASED: Apr 26 2021 + +FLTK 1.3.6 is a maintenance release with new macOS Big Sur support +and some bug fixes. macOS Big Sur is supported on both Intel and the +new Apple Silicon (M1) chips. + +CMake support has been improved but is not yet "perfect". Documentation +has been enhanced, bundled image libraries have been updated to current +versions. + +The following lists are subsets of all commits. References in '(...)' +are either STR numbers (STR xxxx) or GitHub Issues or Pull Requests +(#nnn). + + +Bug fixes and other improvements + + Albrecht Schlosser: + Fix Fl::add_timeout() in draw() under Linux (STR 3188) + X11: Fix X Input Methods (XIM) (STR 3502, 3192) + Fix overly restrictive JPEG filter (#81) + Fix DND in read-only Fl_Input (Fl_Output) (#113) + Fix offscreen drawing under X11 (STR 3384) + Fix potential fluid crashes (STR 3420) + memory leak + Fix X11 copy-paste and drag-and-drop target selection (#182) + Fix CMake install procedure (#212) + Avoid "Bogus FL_MOVE/FL_DRAG events" (#76) + CMake: Document FLTKConfig.cmake and set FLTK_INCLUDE_DIR + + Greg Ercolano: + Fix issue92, added -d debug flag to fluid (#92) + Merge pull request #176 from ComputerNerd/errmsg-fix-13 + + ManoloFLTK: + X11: add support for copy+paste of image within one app + Windows: add bitmap version of graphics when copying to clipboard + Fix use of Xrender extension with old, 16-bit framebuffers. + Fix for Fl_Native_File_Chooser under macOS 10.15 Catalina and ... + Restore macOS capacity to turn window fullscreen encompassing several screens. + Improve Fl_Copy_Surface under macOS + Set OPTION_USE_SYSTEM_LIBPNG/JPEG off under macOS by default + Have Fl_Pack::draw() call Fl_Group::init_sizes() on its parent group. + CMake support of the Darwin+XQuartz test platform + Add support of macOS "Big Sur" 11.0 + Fix when building with SDK 10.15 and running with 11.0 Big Sur + Backport fix for issue #185 "Shared Image reload() loses initial dimensions" from branch 1.4 + Fix fl_endpoints() for macOS platform that was not effective. + Fix stack corruption when loading GIF (pull request #200) + Restore ./configure --enable-x11 on macOS + Fix crash when terminating any macOS app by cmd-Q + + OKAMURA, Yasunobu: + Fix JIS Keyboard dead keys + + CHANGES IN FLTK 1.3.5 RELEASED: Mar 03 2019 Bug fixes and other improvements diff --git a/libraries/fltk/CMake/macOSMaxAllowed.c b/libraries/fltk/CMake/macOSMaxAllowed.c new file mode 100644 index 0000000000..665d243895 --- /dev/null +++ b/libraries/fltk/CMake/macOSMaxAllowed.c @@ -0,0 +1,6 @@ + +#include +#if __MAC_OS_X_VERSION_MAX_ALLOWED < SDK_VERSION_CHECK +#error __MAC_OS_X_VERSION_MAX_ALLOWED < SDK_VERSION_CHECK +#endif +int main(int argc, char** argv) { return 0; } diff --git a/libraries/fltk/CMake/options.cmake b/libraries/fltk/CMake/options.cmake index 247e311bef..b24aca28e7 100644 --- a/libraries/fltk/CMake/options.cmake +++ b/libraries/fltk/CMake/options.cmake @@ -85,16 +85,23 @@ set(FL_ABI_VERSION ${FLTK_ABI_VERSION}) # Note: this might be handled better by the 'MSVC_RUNTIME_LIBRARY' # target property for each target rather than setting a global # CMake variable - but this version does the latter. +# This also applies when using LLVM/clang on Windows (#1058). ####################################################################### -if(MSVC) +if(WIN32 AND NOT MINGW AND NOT MSYS) option(FLTK_MSVC_RUNTIME_DLL "use MSVC Runtime-DLL (/MDx)" ON) if(FLTK_MSVC_RUNTIME_DLL) set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>DLL") else() set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$:Debug>") endif() -endif(MSVC) +else(WIN32 AND NOT MINGW AND NOT MSYS) + # suppress CMake warning if the user sets FLTK_MSVC_RUNTIME_DLL on other platforms + if(DEFINED FLTK_MSVC_RUNTIME_DLL) + unset(FLTK_MSVC_RUNTIME_DLL) + unset(FLTK_MSVC_RUNTIME_DLL CACHE) + endif() +endif(WIN32 AND NOT MINGW AND NOT MSYS) ####################################################################### @@ -111,15 +118,21 @@ endif(APPLE) # Bundled Library Options ####################################################################### -option(FLTK_USE_SYSTEM_LIBJPEG "use system libjpeg" OFF) -option(FLTK_USE_SYSTEM_LIBPNG "use system libpng" OFF) -option(FLTK_USE_SYSTEM_ZLIB "use system zlib" OFF) +if(WIN32 OR (APPLE AND NOT FLTK_BACKEND_X11)) + option(FLTK_USE_SYSTEM_LIBJPEG "use system libjpeg" OFF) + option(FLTK_USE_SYSTEM_LIBPNG "use system libpng" OFF) + option(FLTK_USE_SYSTEM_ZLIB "use system zlib" OFF) +else() + option(FLTK_USE_SYSTEM_LIBJPEG "use system libjpeg" ON) + option(FLTK_USE_SYSTEM_LIBPNG "use system libpng" ON) + option(FLTK_USE_SYSTEM_ZLIB "use system zlib" ON) +endif() # Set default values of internal build options -set(FLTK_USE_BUNDLED_JPEG TRUE) -set(FLTK_USE_BUNDLED_PNG TRUE) -set(FLTK_USE_BUNDLED_ZLIB TRUE) +set(FLTK_USE_BUNDLED_JPEG FALSE) +set(FLTK_USE_BUNDLED_PNG FALSE) +set(FLTK_USE_BUNDLED_ZLIB FALSE) # Collect libraries to build fltk_images (starting empty) @@ -418,7 +431,7 @@ option(FLTK_USE_POLL "use poll if available" OFF) mark_as_advanced(FLTK_USE_POLL) if(FLTK_USE_POLL) - check_function_exists(poll USE_POLL) + check_symbol_exists(poll "poll.h" USE_POLL) endif(FLTK_USE_POLL) ####################################################################### @@ -605,7 +618,7 @@ endif(FLTK_OPTION_SVG) ####################################################################### -# FIXME: GL libs have already been searched in resources.cmake +# FIXME: GLU libs have already been searched in resources.cmake set(HAVE_GL LIB_GL OR LIB_MesaGL) set(FLTK_USE_GL FALSE) @@ -675,8 +688,8 @@ set(FLTK_GL_FOUND FALSE) if(OPENGL_FOUND) set(FLTK_GL_FOUND TRUE) - find_path(OPENGL_GLU_INCLUDE_DIR NAMES GL/glu.h OpenGL/glu.h HINTS ${OPENGL_INCLUDE_DIR} ${X11_INCLUDE_DIR}) - set(CMAKE_REQUIRED_INCLUDES ${OPENGL_INCLUDE_DIR}/GL ${OPENGL_GLU_INCLUDE_DIR}) + find_path(FLTK_OPENGL_GLU_INCLUDE_DIR NAMES GL/glu.h OpenGL/glu.h HINTS ${OPENGL_INCLUDE_DIR} ${X11_INCLUDE_DIR}) + set(CMAKE_REQUIRED_INCLUDES ${OPENGL_INCLUDE_DIR}/GL ${FLTK_OPENGL_GLU_INCLUDE_DIR}) if(WIN32) list(APPEND GLLIBS -lglu32 -lopengl32) @@ -693,7 +706,7 @@ if(OPENGL_FOUND) # check if function glXGetProcAddressARB exists set(TEMP_REQUIRED_LIBRARIES ${CMAKE_REQUIRED_LIBRARIES}) set(CMAKE_REQUIRED_LIBRARIES ${OPENGL_LIBRARIES}) - check_function_exists(glXGetProcAddressARB HAVE_GLXGETPROCADDRESSARB) + check_symbol_exists(glXGetProcAddressARB "glx.h" HAVE_GLXGETPROCADDRESSARB) set(CMAKE_REQUIRED_LIBRARIES ${TEMP_REQUIRED_LIBRARIES}) unset(TEMP_REQUIRED_LIBRARIES) endif(OPENGL_FOUND) diff --git a/libraries/fltk/CMake/resources.cmake b/libraries/fltk/CMake/resources.cmake index eaea18c078..bad4279beb 100644 --- a/libraries/fltk/CMake/resources.cmake +++ b/libraries/fltk/CMake/resources.cmake @@ -27,6 +27,8 @@ set(CMAKE_REQUIRED_QUIET 1) include(CheckIncludeFiles) +include(CheckSymbolExists) + macro(fl_find_header VAR HEADER) check_include_files("${HEADER}" ${VAR}) @@ -35,6 +37,55 @@ macro(fl_find_header VAR HEADER) endif(NOT CMAKE_REQUIRED_QUIET) endmacro(fl_find_header) + +####################################################################### +# find git revision and store it in the CMake cache for reference +####################################################################### + +# (1) Get current Git revision from `git rev-parse ...` +# (2) Read Git revision from file `fltk_git_rev.dat` +# +# (1) This can fail if the FLTK source directory is not a Git checkout, +# i.e. FLTK was downloaded as a distro (tarball). +# (2) If (1) fails the file `fltk_git_rev.dat` is read. This file is +# generated by the process to generate the distribution (makesrcdist). +# + +set(git_rev_file ${FLTK_SOURCE_DIR}/fltk_git_rev.dat) + +set(git_revision "") # temporary variable + +execute_process(COMMAND + git rev-parse HEAD # --short=${git_rev_size} HEAD + OUTPUT_VARIABLE git_revision + OUTPUT_STRIP_TRAILING_WHITESPACE + WORKING_DIRECTORY ${FLTK_SOURCE_DIR} + ERROR_QUIET +) + +if(git_revision STREQUAL "") + + # Read git revision from a file generated by makesrcdist. + # This file is located in the FLTK source directory + + if(EXISTS ${git_rev_file}) + file(READ ${git_rev_file} git_revision) + string(STRIP "${git_revision}" git_revision) + else() + set(git_revision "unknown") + endif() +endif() + +set(FLTK_GIT_REVISION "${git_revision}" + CACHE STRING + "FLTK Git revision (do not change)" + FORCE) + +# debug and unset temporary variables +# fl_debug_var(git_revision) +unset(git_rev_file) +unset(git_revision) + ####################################################################### # Include FindPkgConfig for later use of pkg-config ####################################################################### @@ -45,6 +96,26 @@ include(FindPkgConfig) # fl_debug_var(PKG_CONFIG_EXECUTABLE) # fl_debug_var(PKG_CONFIG_VERSION_STRING) +####################################################################### +# GitHub Issue #1001: try to "repair" the CMake Cache +# GitHub Issue #1046: don't try "too hard" (see GitHub Issue) +####################################################################### +# +# Note: we renamed "our" CMake cache variable OPENGL_GLU_INCLUDE_DIR +# to FLTK_OPENGL_GLU_INCLUDE_DIR because the former is now defined +# in find_package(OpenGL) (FindOpenGL.cmake) since CMake 3.29.0. +# +# We remove "our" cache variable if OPENGL_GLU_INCLUDE_DIR is defined +# but FLTK_OPENGL_GLU_INCLUDE_DIR is not yet defined which indicates +# the first execution after the rename. +# +# FIXME: we can remove this code some time after the release of FLTK 1.4.0. + +if(DEFINED OPENGL_GLU_INCLUDE_DIR AND NOT DEFINED FLTK_OPENGL_GLU_INCLUDE_DIR) + unset(OPENGL_GLU_INCLUDE_DIR) + unset(OPENGL_GLU_INCLUDE_DIR CACHE) +endif() # (DEFINED OPENGL_GLU_INCLUDE_DIR AND NOT ...) + ####################################################################### # Find header files... ####################################################################### @@ -183,39 +254,41 @@ if(HAVE_DLFCN_H) endif(HAVE_DLFCN_H) set(CMAKE_REQUIRED_LIBRARIES ${CMAKE_DL_LIBS}) -check_function_exists(dlsym HAVE_DLSYM) +check_symbol_exists(dlsym "dlfcn.h" HAVE_DLSYM) set(CMAKE_REQUIRED_LIBRARIES) -check_function_exists(localeconv HAVE_LOCALECONV) +check_symbol_exists(localeconv "locale.h" HAVE_LOCALECONV) if(LIB_png) set(CMAKE_REQUIRED_LIBRARIES ${LIB_png}) - check_function_exists(png_get_valid HAVE_PNG_GET_VALID) - check_function_exists(png_set_tRNS_to_alpha HAVE_PNG_SET_TRNS_TO_ALPHA) + check_symbol_exists(png_get_valid "png.h" HAVE_PNG_GET_VALID) + check_symbol_exists(png_set_tRNS_to_alpha "png.h" HAVE_PNG_SET_TRNS_TO_ALPHA) set(CMAKE_REQUIRED_LIBRARIES) endif(LIB_png) -check_function_exists(scandir HAVE_SCANDIR) -check_function_exists(snprintf HAVE_SNPRINTF) +check_symbol_exists(scandir "dirent.h" HAVE_SCANDIR) +check_symbol_exists(snprintf "stdio.h" HAVE_SNPRINTF) # not really true but we convert strcasecmp calls to _stricmp calls in flstring.h if(MSVC) set(HAVE_STRCASECMP 1) endif(MSVC) -check_function_exists(strcasecmp HAVE_STRCASECMP) +check_symbol_exists(strcasecmp "strings.h" HAVE_STRCASECMP) -check_function_exists(strlcat HAVE_STRLCAT) -check_function_exists(strlcpy HAVE_STRLCPY) -check_function_exists(vsnprintf HAVE_VSNPRINTF) +check_symbol_exists(strlcat "string.h" HAVE_STRLCAT) +check_symbol_exists(strlcpy "string.h" HAVE_STRLCPY) +check_symbol_exists(vsnprintf "stdio.h" HAVE_VSNPRINTF) -check_function_exists(setenv HAVE_SETENV) +check_symbol_exists(setenv "stdlib.h" HAVE_SETENV) # Windows doesn't require '-lm' for trunc(), other platforms do if(LIB_m AND NOT WIN32) set(CMAKE_REQUIRED_LIBRARIES ${LIB_m}) endif() -check_function_exists(trunc HAVE_TRUNC) + +check_symbol_exists(trunc "math.h" HAVE_TRUNC) + set(CMAKE_REQUIRED_LIBRARIES) if(HAVE_SCANDIR AND NOT HAVE_SCANDIR_POSIX) diff --git a/libraries/fltk/CMake/setup.cmake b/libraries/fltk/CMake/setup.cmake index 5419fb7f24..4d0315e92a 100644 --- a/libraries/fltk/CMake/setup.cmake +++ b/libraries/fltk/CMake/setup.cmake @@ -96,7 +96,7 @@ set(STATICIMAGELIBS "") if(WIN32 AND NOT CYGWIN) set(FLTK_CONFIG_PATH CMake) elseif(APPLE AND NOT FLTK_BACKEND_X11) - set(FLTK_CONFIG_PATH FLTK.framework/Resources/CMake) + set(FLTK_CONFIG_PATH ${FLTK_DATADIR}/fltk) else() set(FLTK_CONFIG_PATH ${FLTK_DATADIR}/fltk) endif(WIN32 AND NOT CYGWIN) @@ -111,6 +111,25 @@ if(CMAKE_GENERATOR MATCHES "Xcode") endif() if(APPLE) + # Check if the __MAC_OS_X_VERSION_MAX_ALLOWED compile time macro is at least + # the version encoded in SDK_VERSION and return TRUE or FALSE in RESULT. + # Note 1: try_compile() always creates an *internal* CMake cache variable for + # the result which we set to 'FLTK_CHECK_OSX_MAX_ALLOWED_${SDK_VERSION}'. + # Note 2: 'FLTK_' to avoid polluting the cache if FLTK is built as a subproject. + # Note 3: We don't care about the cache, i.e. we run try_compile() unconditionally + # so users can switch SDK's, particularly if they *upgrade* Xcode. + + function(CHECK_OSX_MAX_ALLOWED SDK_VERSION RESULT) + set(_result FLTK_CHECK_OSX_MAX_ALLOWED_${SDK_VERSION}) + try_compile(${_result} + ${CMAKE_CURRENT_BINARY_DIR}/CHECK_OSX_MAX_ALLOWED_${SDK_VERSION} + SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/CMake/macOSMaxAllowed.c + COMPILE_DEFINITIONS -DSDK_VERSION_CHECK=${SDK_VERSION} + ) + set(${RESULT} ${${_result}} PARENT_SCOPE) + endfunction() + + # APPLE macOS setup set(HAVE_STRCASECMP 1) set(HAVE_DIRENT_H 1) set(HAVE_SNPRINTF 1) @@ -123,22 +142,17 @@ if(APPLE) endif(NOT(${CMAKE_SYSTEM_VERSION} VERSION_LESS 17.0.0)) else() set(FLTK_COCOA_FRAMEWORKS "-framework Cocoa") - set(UTI_CONDITION FALSE) - string(LENGTH "${CMAKE_OSX_DEPLOYMENT_TARGET}" TARGET_LEN) - string(LENGTH "${CMAKE_SYSTEM_VERSION}" SDK_LEN) - if(TARGET_LEN GREATER 0) - if( ${CMAKE_OSX_DEPLOYMENT_TARGET} VERSION_GREATER_EQUAL 11.0) - set(UTI_CONDITION TRUE) - endif() - elseif(SDK_LEN GREATER 0) - if( ${CMAKE_SYSTEM_VERSION} VERSION_GREATER_EQUAL 20.0 ) - set(UTI_CONDITION TRUE) - endif() - endif() - if(UTI_CONDITION) # a.k.a. macOS version ≥ 11.0 - if (NOT (CMAKE_OSX_ARCHITECTURES STREQUAL "ppc" OR CMAKE_OSX_ARCHITECTURES STREQUAL "i386")) - list(APPEND FLTK_COCOA_FRAMEWORKS "-framework UniformTypeIdentifiers") - endif() + if (NOT (CMAKE_OSX_ARCHITECTURES STREQUAL "ppc" OR CMAKE_OSX_ARCHITECTURES STREQUAL "i386")) + CHECK_OSX_MAX_ALLOWED(150000 SDK_15_AVAILABLE) # at least SDK 15.0.0 ? + if (SDK_15_AVAILABLE) + list(APPEND FLTK_COCOA_FRAMEWORKS "-weak_framework ScreenCaptureKit") # 15.0 + list(APPEND FLTK_COCOA_FRAMEWORKS "-weak_framework UniformTypeIdentifiers") # 11.0 + else(SDK_15_AVAILABLE) + CHECK_OSX_MAX_ALLOWED(110000 SDK_11_AVAILABLE) # at least SDK 11.0.0 ? + if (SDK_11_AVAILABLE) + list(APPEND FLTK_COCOA_FRAMEWORKS "-weak_framework UniformTypeIdentifiers") + endif(SDK_11_AVAILABLE) + endif(SDK_15_AVAILABLE) endif() endif(FLTK_BACKEND_X11) endif(APPLE) @@ -162,29 +176,7 @@ endif(WIN32) ####################################################################### # size of ints -include(CheckTypeSize) - -CHECK_TYPE_SIZE(short SIZEOF_SHORT) -CHECK_TYPE_SIZE(int SIZEOF_INT) -CHECK_TYPE_SIZE(long SIZEOF_LONG) -CHECK_TYPE_SIZE("long long" HAVE_LONG_LONG) - -if(${SIZEOF_SHORT} MATCHES "^2$") - set(U16 "unsigned short") -endif(${SIZEOF_SHORT} MATCHES "^2$") -if(${SIZEOF_INT} MATCHES "^4$") - set(U32 "unsigned") -else() - if(${SIZEOF_LONG} MATCHES "^4$") - set(U32 "unsigned long") - endif(${SIZEOF_LONG} MATCHES "^4$") -endif(${SIZEOF_INT} MATCHES "^4$") - -if(${SIZEOF_INT} MATCHES "^8$") - set(U64 "unsigned") -else() - if(${SIZEOF_LONG} MATCHES "^8$") - set(U64 "unsigned long") - endif(${SIZEOF_LONG} MATCHES "^8$") -endif(${SIZEOF_INT} MATCHES "^8$") +set(U16 "unsigned short") +set(U32 "unsigned") +set(U64 "unsigned long long") \ No newline at end of file diff --git a/libraries/fltk/CMake/variables.cmake b/libraries/fltk/CMake/variables.cmake index cb5d624812..4d1be9f2d1 100644 --- a/libraries/fltk/CMake/variables.cmake +++ b/libraries/fltk/CMake/variables.cmake @@ -40,7 +40,7 @@ endif(DEBUG_VARIABLES_CMAKE) # FIXME: check fontconfig conditions (only if Xft is used or ...) if(WIN32) - list(APPEND FLTK_LDLIBS -lole32 -luuid -lcomctl32 -lws2_32) + list(APPEND FLTK_LDLIBS -lole32 -luuid -lcomctl32 -lws2_32 -lwinspool) elseif(APPLE AND NOT FLTK_BACKEND_X11) list(APPEND FLTK_LDLIBS ${FLTK_COCOA_FRAMEWORKS}) elseif(FLTK_BACKEND_WAYLAND) diff --git a/libraries/fltk/CMakeLists.txt b/libraries/fltk/CMakeLists.txt index be0ede6664..171d946a19 100644 --- a/libraries/fltk/CMakeLists.txt +++ b/libraries/fltk/CMakeLists.txt @@ -177,6 +177,22 @@ if(FLTK_BUILD_EXAMPLES) add_subdirectory(examples) endif(FLTK_BUILD_EXAMPLES) +####################################################################### +# Create and install version config file 'FLTKConfigVersion.cmake' +####################################################################### + +include(CMakePackageConfigHelpers) + +write_basic_package_version_file(FLTKConfigVersion.cmake + # [VERSION requiredVersion] # defaults to project version + COMPATIBILITY SameMinorVersion +) + +install(FILES + ${CMAKE_CURRENT_BINARY_DIR}/FLTKConfigVersion.cmake + DESTINATION ${FLTK_CONFIG_PATH} +) + ####################################################################### # installation ####################################################################### diff --git a/libraries/fltk/CREDITS.txt b/libraries/fltk/CREDITS.txt index 215b9fdb9b..5e29cc9e4e 100644 --- a/libraries/fltk/CREDITS.txt +++ b/libraries/fltk/CREDITS.txt @@ -1,5 +1,5 @@ -CREDITS.txt - Fast Light Tool Kit (FLTK) Version 1.4.0 ------------------------------------------------------- +CREDITS - Fast Light Tool Kit (FLTK) +------------------------------------- This file lists the people responsible for the toolkit you are now using. If you've been looking for your name in lights @@ -39,8 +39,7 @@ CORE DEVELOPERS OTHER CONTRIBUTORS - The following people have contributed fixes or enhancements - for FLTK: + The following people have contributed fixes or enhancements to FLTK: Laszlo Z. Antal (LZA) Teun Burgers @@ -51,6 +50,7 @@ OTHER CONTRIBUTORS Yuri Fedorchenko George Garvey Duncan Gibson + Daniel Harding Mikael Hultgren Stuart Levy Jean-Marc Lienher (OksiD) diff --git a/libraries/fltk/FL/Enumerations.H b/libraries/fltk/FL/Enumerations.H index ff2f163e10..97b4c70297 100644 --- a/libraries/fltk/FL/Enumerations.H +++ b/libraries/fltk/FL/Enumerations.H @@ -407,8 +407,8 @@ enum Fl_Event { // events /** A zoom event (ctrl/+/-/0/ or cmd/+/-/0/) was processed. Use Fl::add_handler() to be notified of this event. */ - FL_ZOOM_EVENT = 27 -// DEV NOTE: Keep this list in sync with FL/names.h + FL_ZOOM_EVENT = 27 + // DEV NOTE: Keep this list in sync with FL/names.h }; /** \name When Conditions */ @@ -548,9 +548,11 @@ enum Fl_Callback_Reason { /**@{*/ -#define FL_LEFT_MOUSE 1 ///< The left mouse button -#define FL_MIDDLE_MOUSE 2 ///< The middle mouse button -#define FL_RIGHT_MOUSE 3 ///< The right mouse button +#define FL_LEFT_MOUSE 1 ///< The left mouse button +#define FL_MIDDLE_MOUSE 2 ///< The middle mouse button +#define FL_RIGHT_MOUSE 3 ///< The right mouse button +#define FL_BACK_MOUSE 4 ///< The back mouse button (side button 1) +#define FL_FORWARD_MOUSE 5 ///< The forward mouse button (side button 2) /**@}*/ // group: Mouse Buttons @@ -562,8 +564,8 @@ enum Fl_Callback_Reason { /**@{*/ // group: Event States -// FIXME: it would be nice to have the modifiers in the upper 8 bit so that -// a unicode key (24bit) can be sent as an unsigned with the modifiers. +// FIXME: it would be nice to have the modifiers in the upper 8 bits so that +// a unicode key (21 bits) can be sent as an unsigned with the modifiers. #define FL_SHIFT 0x00010000 ///< One of the shift keys is down #define FL_CAPS_LOCK 0x00020000 ///< The caps lock is on @@ -575,14 +577,20 @@ enum Fl_Callback_Reason { // correct for XFree86 #define FL_SCROLL_LOCK 0x00800000 ///< The scroll lock is on // correct for XFree86 -#define FL_BUTTON1 0x01000000 ///< Mouse button 1 is pushed -#define FL_BUTTON2 0x02000000 ///< Mouse button 2 is pushed -#define FL_BUTTON3 0x04000000 ///< Mouse button 3 is pushed -#define FL_BUTTONS 0x7f000000 ///< Any mouse button is pushed -#define FL_BUTTON(n) (0x00800000<<(n)) ///< Mouse button n (n > 0) is pushed - -#define FL_KEY_MASK 0x0000ffff ///< All keys are 16 bit for now - // FIXME: Unicode needs 24 bits! +// Mouse buttons + +#define FL_BUTTON1 0x01000000 ///< Mouse button 1 is pushed (L) +#define FL_BUTTON2 0x02000000 ///< Mouse button 2 is pushed (M) +#define FL_BUTTON3 0x04000000 ///< Mouse button 3 is pushed (R) +#define FL_BUTTON4 0x08000000 ///< Mouse button 4 is pushed (BACK) +#define FL_BUTTON5 0x10000000 ///< Mouse button 5 is pushed (FORWARD) +#define FL_BUTTONS 0x1f000000 ///< Bitmask: any mouse button (1-5) is pushed + +#define FL_BUTTON(n) (0x00800000<<(n)) ///< Mouse button n (n = 1..5) is pushed, + ///< *undefined* if n outside 1..5 + +#define FL_KEY_MASK 0x0000ffff ///< All keys are 16 bit for now + // FIXME: Unicode needs 21 bits! /**@}*/ // group: Event States diff --git a/libraries/fltk/FL/Fl.H b/libraries/fltk/FL/Fl.H index fef27fa93d..769dcadc6c 100644 --- a/libraries/fltk/FL/Fl.H +++ b/libraries/fltk/FL/Fl.H @@ -479,6 +479,7 @@ public: static void repeat_timeout(double t, Fl_Timeout_Handler cb, void *data = 0); static int has_timeout(Fl_Timeout_Handler cb, void *data = 0); static void remove_timeout(Fl_Timeout_Handler cb, void *data = 0); + static int remove_next_timeout(Fl_Timeout_Handler cb, void *data = 0, void **data_return = 0); static void add_check(Fl_Timeout_Handler, void* = 0); static int has_check(Fl_Timeout_Handler, void* = 0); @@ -704,34 +705,51 @@ public: This returns garbage if the most recent event was not a FL_PUSH or FL_RELEASE event. \retval FL_LEFT_MOUSE \retval FL_MIDDLE_MOUSE - \retval FL_RIGHT_MOUSE. - \see Fl::event_buttons() + \retval FL_RIGHT_MOUSE + \retval FL_BACK_MOUSE + \retval FL_FORWARD_MOUSE + \see Fl::event_buttons(), Fl::event_state() */ - static int event_button() {return e_keysym-FL_Button;} + static int event_button() { return e_keysym - FL_Button; } /** Returns the keyboard and mouse button states of the last event. This is a bitfield of what shift states were on and what mouse buttons were held down during the most recent event. - The legal event state bits are: - - - FL_SHIFT - - FL_CAPS_LOCK - - FL_CTRL - - FL_ALT - - FL_NUM_LOCK - - FL_META - - FL_SCROLL_LOCK - - FL_BUTTON1 - - FL_BUTTON2 - - FL_BUTTON3 - - X servers do not agree on shift states, and FL_NUM_LOCK, FL_META, and - FL_SCROLL_LOCK may not work. The values were selected to match the - XFree86 server on Linux. In addition there is a bug in the way X works - so that the shift state is not correctly reported until the first event - after the shift key is pressed or released. + \note FLTK platforms differ in what Fl::event_state() returns when it is called + while a modifier key or mouse button is being pressed or released. + + - Under X11 and Wayland, Fl::event_state() indicates the state of the modifier keys and + mouse buttons just \b prior to the event. Thus, during the \c FL_KEYDOWN event generated + when pressing the shift key, for example, the \c FL_SHIFT bit of event_state() is 0 and + becomes 1 only at the next event which can be any other event, including e.g. \c FL_MOVE. + - Under other platforms the reported state of modifier keys or mouse buttons includes that + of the key or button being pressed or released. + - Fl::event_state() returns the same value under all platforms when it's called while a + non-modifier key (e.g. a letter or function key) is being pressed or released. + - X servers do not agree on shift states, and \c FL_NUM_LOCK, \c FL_META, and \c FL_SCROLL_LOCK + may not work. + - The values were selected to match the XFree86 server on Linux. + + \note This inconsistency \b may be fixed (on X11 and Wayland) in a later release. + + The legal event state bits are: + + | Device | State Bit | Key or Button | Since | + |----------|----------------|-------------------------|--------| + | Keyboard | FL_SHIFT | Shift | | + | Keyboard | FL_CAPS_LOCK | Caps Lock | | + | Keyboard | FL_CTRL | Ctrl | | + | Keyboard | FL_ALT | Alt | | + | Keyboard | FL_NUM_LOCK | Num Lock | | + | Keyboard | FL_META | Meta, e.g. "Windows" | | + | Keyboard | FL_SCROLL_LOCK | Scroll Lock | | + | Mouse | FL_BUTTON1 | left button | | + | Mouse | FL_BUTTON2 | middle button | | + | Mouse | FL_BUTTON3 | right button | | + | Mouse | FL_BUTTON4 | side button 1 (back) | 1.3.10 | + | Mouse | FL_BUTTON5 | side button 2 (forward) | 1.3.10 | */ static int event_state() {return e_state;} @@ -1219,7 +1237,7 @@ public: // boxtypes: static Fl_Box_Draw_F *get_boxtype(Fl_Boxtype); static void set_boxtype(Fl_Boxtype, Fl_Box_Draw_F*, - uchar, uchar, uchar, uchar, + uchar, uchar, uchar, uchar, Fl_Box_Draw_Focus_F* =NULL); static void set_boxtype(Fl_Boxtype, Fl_Boxtype from); static int box_dx(Fl_Boxtype); @@ -1260,24 +1278,34 @@ public: time of the event. During an FL_RELEASE event, the state of the released button will be 0. To find out, which button caused an FL_RELEASE event, you can use Fl::event_button() instead. - \return a bit mask value like { [FL_BUTTON1] | [FL_BUTTON2] | [FL_BUTTON3] } + \return a bit mask value like { [FL_BUTTON1] | [FL_BUTTON2] | ... | [FL_BUTTON5] } */ - static int event_buttons() {return e_state&0x7f000000;} + static int event_buttons() {return e_state & FL_BUTTONS;} /** Returns non-zero if mouse button 1 is currently held down. For more details, see Fl::event_buttons(). */ - static int event_button1() {return e_state&FL_BUTTON1;} + static int event_button1() {return e_state & FL_BUTTON1;} /** - Returns non-zero if button 2 is currently held down. + Returns non-zero if mouse button 2 is currently held down. For more details, see Fl::event_buttons(). */ - static int event_button2() {return e_state&FL_BUTTON2;} + static int event_button2() {return e_state & FL_BUTTON2;} /** - Returns non-zero if button 3 is currently held down. + Returns non-zero if mouse button 3 is currently held down. For more details, see Fl::event_buttons(). */ - static int event_button3() {return e_state&FL_BUTTON3;} + static int event_button3() {return e_state & FL_BUTTON3;} + /** + Returns non-zero if mouse button 4 is currently held down. + For more details, see Fl::event_buttons(). + */ + static int event_button4() {return e_state & FL_BUTTON4;} + /** + Returns non-zero if mouse button 5 is currently held down. + For more details, see Fl::event_buttons(). + */ + static int event_button5() {return e_state & FL_BUTTON5;} /** @} */ /** diff --git a/libraries/fltk/FL/Fl_Browser_.H b/libraries/fltk/FL/Fl_Browser_.H index 37ae59c5e0..5db510ffd0 100644 --- a/libraries/fltk/FL/Fl_Browser_.H +++ b/libraries/fltk/FL/Fl_Browser_.H @@ -246,11 +246,11 @@ public: \see position(), hposition() */ int vposition() const { return position_; } - FL_DEPRECATED("in 1.4.0 - use vposition() instead", + FL_DEPRECATED("since 1.4.0 - use vposition() instead", int position() const) { return vposition(); } void vposition(int pos); // scroll to here - FL_DEPRECATED("in 1.4.0 - use vposition(pos) instead", + FL_DEPRECATED("since 1.4.0 - use vposition(pos) instead", void position(int pos)) { return vposition(pos); } void position(int x, int y) { Fl_Group::position(x, y); } diff --git a/libraries/fltk/FL/Fl_Choice.H b/libraries/fltk/FL/Fl_Choice.H index eaa04e8031..944f4d3a4e 100644 --- a/libraries/fltk/FL/Fl_Choice.H +++ b/libraries/fltk/FL/Fl_Choice.H @@ -1,7 +1,7 @@ // // Choice header file for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2010 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this diff --git a/libraries/fltk/FL/Fl_Device.H b/libraries/fltk/FL/Fl_Device.H index ab216a0e0e..764bcd1142 100644 --- a/libraries/fltk/FL/Fl_Device.H +++ b/libraries/fltk/FL/Fl_Device.H @@ -38,16 +38,17 @@ class Fl_Image_Surface; an instance of the Fl_Display_Device class. A drawing surface other than the computer's display, is typically used as follows: -
  1. Create \c surface, an object from a particular Fl_Surface_Device derived class (e.g., Fl_Copy_Surface, Fl_Printer). +
    1. Create \c surface, an object from an Fl_Surface_Device derived class (e.g., Fl_Image_Surface, Fl_Printer, Fl_Copy_Surface).
    2. Call \c Fl_Surface_Device::push_current(surface); to redirect all graphics requests to - \c surface which becomes the new current drawing surface (not necessary with classes Fl_Printer / Fl_PostScript_File_Device - because it is done by Fl_Paged_Device::begin_page()). + \c surface which becomes the new current drawing surface (not necessary with classes Fl_Printer / Fl_PostScript_File_Device / + Fl_PDF_File_Surface because it is done by Fl_Paged_Device::begin_page()).
    3. At this point all of the \ref fl_drawings (e.g., fl_rect()) or the \ref fl_attributes or \ref drawing_images functions (e.g., fl_draw_image(), Fl_Image::draw()) operate on the new current drawing surface. - Drawing surfaces from Fl_Widget_Surface derived classes allow additional ways - to draw to them (e.g., Fl_Printer::print_widget(), Fl_Image_Surface::draw()). + It's also possible to draw to the current surface any widget with Fl_Widget_Surface::draw(Fl_Widget*, int, int), a window and its + titlebar with Fl_Widget_Surface::draw_decorated_window(), or the content of a rectangular zone of a window + with Fl_Widget_Surface::print_window_part().
    4. After all drawing requests have been performed, redirect graphics requests back to their previous destination - with \c Fl_Surface_Device::pop_current(); (not necessary with classes Fl_Printer / Fl_PostScript_File_Device). + with \c Fl_Surface_Device::pop_current(); (not necessary with classes Fl_Printer / Fl_PostScript_File_Device / Fl_PDF_File_Surface).
    5. Delete \c surface.
    For back-compatibility, it is also possible to use the Fl_Surface_Device::set_current() member function diff --git a/libraries/fltk/FL/Fl_Fill_Dial.H b/libraries/fltk/FL/Fl_Fill_Dial.H index fc66cea62d..3b6bf7fc54 100644 --- a/libraries/fltk/FL/Fl_Fill_Dial.H +++ b/libraries/fltk/FL/Fl_Fill_Dial.H @@ -26,7 +26,7 @@ class FL_EXPORT Fl_Fill_Dial : public Fl_Dial { public: /** Creates a filled dial, also setting its type to FL_FILL_DIAL. */ - Fl_Fill_Dial(int X,int Y,int W,int H, const char *L); + Fl_Fill_Dial(int X,int Y,int W,int H, const char *L = NULL); }; #endif diff --git a/libraries/fltk/FL/Fl_Flex.H b/libraries/fltk/FL/Fl_Flex.H index 20b4f50f5a..ef46daca30 100644 --- a/libraries/fltk/FL/Fl_Flex.H +++ b/libraries/fltk/FL/Fl_Flex.H @@ -2,7 +2,7 @@ // Fl_Flex widget header file for the Fast Light Tool Kit (FLTK). // // Copyright 2020 by Karsten Pedersen -// Copyright 2022-2023 by Bill Spitzak and others. +// Copyright 2022-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -70,10 +70,10 @@ is undefined, i.e. widgets may overlap and/or shrink to zero size. \b Hint: In many cases Fl_Flex can be used as a drop-in replacement - for Fl_Pack. This is the recommended single row/column container since - FLTK 1.4.0. Its resizing behavior is much more predictable (as expected) - than that of Fl_Pack which "resizes itself to shrink-wrap itself around - all of the children". + for Fl_Pack. This is the recommended single row/column container + since FLTK 1.4.0. Its resizing behavior is much more predictable + than that of Fl_Pack which "resizes itself to shrink-wrap itself + around all of the children". Fl_Flex containers can be nested so you can create flexible layouts with multiple columns and rows. However, if your UI design is more complex you @@ -106,7 +106,7 @@ window.size_range(300, 30); window.show(argc, argv); return Fl::run(); -} + } \endcode \since 1.4.0 diff --git a/libraries/fltk/FL/Fl_Gl_Window.H b/libraries/fltk/FL/Fl_Gl_Window.H index 67c3c40506..8506359a2a 100644 --- a/libraries/fltk/FL/Fl_Gl_Window.H +++ b/libraries/fltk/FL/Fl_Gl_Window.H @@ -173,8 +173,12 @@ public: mode() must not be called within draw() since it changes the current context. - The FL_OPENGL3 flag is required to access OpenGL version 3 or more - under the X11 and MacOS platforms; it's optional under Windows and Wayland. + The FL_OPENGL3 flag is recommended to use OpenGL version 3 or more. + This flag is required (not just recommended) if GL ≥ 3.0 is in use + and at least one of these conditions applies: + - the program runs on the macOS platform; + - the Fl_Gl_Window has child widgets. + See more details in \ref opengl3. \version the FL_OPENGL3 flag appeared in version 1.3.4 diff --git a/libraries/fltk/FL/Fl_Graphics_Driver.H b/libraries/fltk/FL/Fl_Graphics_Driver.H index 3adf6d6c92..2ac70ba035 100644 --- a/libraries/fltk/FL/Fl_Graphics_Driver.H +++ b/libraries/fltk/FL/Fl_Graphics_Driver.H @@ -413,10 +413,7 @@ class FL_EXPORT Fl_Scalable_Graphics_Driver : public Fl_Graphics_Driver { Fl_Fontsize fontsize_; // scale-independent font size value public: Fl_Scalable_Graphics_Driver(); - // This function aims to compute accurately int(x * s) in - // presence of rounding errors existing with floating point numbers - // and that sometimes differ between 32 and 64 bits. - static inline int floor(int x, float s) { return int(x * s + 0.001f); } + static int floor(int x, float s); inline int floor(int x) { return Fl_Scalable_Graphics_Driver::floor(x, scale()); } protected: int line_width_; @@ -426,6 +423,7 @@ protected: virtual void point_unscaled(float x, float y); void rect(int x, int y, int w, int h) FL_OVERRIDE; void rectf(int x, int y, int w, int h) FL_OVERRIDE; + virtual void rect_unscaled(int x, int y, int w, int h); virtual void rectf_unscaled(int x, int y, int w, int h); void line(int x, int y, int x1, int y1) FL_OVERRIDE; virtual void line_unscaled(int x, int y, int x1, int y1); diff --git a/libraries/fltk/FL/Fl_Group.H b/libraries/fltk/FL/Fl_Group.H index 173f8754bb..27c68ef8af 100644 --- a/libraries/fltk/FL/Fl_Group.H +++ b/libraries/fltk/FL/Fl_Group.H @@ -29,7 +29,7 @@ class Fl_Rect; /** - The Fl_Group class is the FLTK container widget. It maintains + The Fl_Group class is the main FLTK container widget. It maintains an array of child widgets. These children can themselves be any widget including Fl_Group. The most important subclass of Fl_Group is Fl_Window, however groups can also be used to control radio buttons @@ -95,11 +95,23 @@ public: /** Returns how many child widgets the group has. */ - int children() const {return children_;} + int children() const { return children_; } + /** - Returns array()[n]. No range checking is done! + Returns the n'th child. + + Returns \c NULL if \c n is out of range (since FLTK 1.4.0). + + No range checking was done in FLTK 1.3 and older versions! + + \param[in] n index of child (0 .. children() - 1) + \return pointer to the n'th child or NULL if out of range */ - Fl_Widget* child(int n) const {return array()[n];} + Fl_Widget *child(int n) const { + if (n < 0 || n > children() - 1) return NULL; + return array()[n]; + } + int find(const Fl_Widget*) const; /** See int Fl_Group::find(const Fl_Widget *w) const diff --git a/libraries/fltk/FL/Fl_Help_View.H b/libraries/fltk/FL/Fl_Help_View.H index 6f19a9a542..2c73926c01 100644 --- a/libraries/fltk/FL/Fl_Help_View.H +++ b/libraries/fltk/FL/Fl_Help_View.H @@ -235,20 +235,20 @@ class FL_EXPORT Fl_Help_View : public Fl_Group { // Help viewer widget Fl_Scrollbar scrollbar_, ///< Vertical scrollbar for document hscrollbar_; ///< Horizontal scrollbar - static int selection_first; - static int selection_last; - static int selection_push_first; - static int selection_push_last; - static int selection_drag_first; - static int selection_drag_last; - static int selected; - static int draw_mode; - static int mouse_x; - static int mouse_y; - static int current_pos; - static Fl_Help_View *current_view; - static Fl_Color hv_selection_color; - static Fl_Color hv_selection_text_color; + static int selection_first_; + static int selection_last_; + static int selection_push_first_; + static int selection_push_last_; + static int selection_drag_first_; + static int selection_drag_last_; + static int selected_; + static int draw_mode_; + static int mouse_x_; + static int mouse_y_; + static int current_pos_; + static Fl_Help_View *current_view_; + static Fl_Color hv_selection_color_; + static Fl_Color hv_selection_text_color_; void initfont(Fl_Font &f, Fl_Fontsize &s, Fl_Color &c) { f = textfont_; s = textsize_; c = textcolor_; fstack_.init(f, s, c); } @@ -286,6 +286,8 @@ private: public: + static const char *copy_menu_text; + Fl_Help_View(int xx, int yy, int ww, int hh, const char *l = 0); ~Fl_Help_View(); /** Returns the current directory for the text in the buffer. */ @@ -383,6 +385,12 @@ public: void scrollbar_size(int newSize) { scrollbar_size_ = newSize; } + + // Check if the user selected text in this view. + int text_selected(); + + // If text is selected in this view, copy it to a clipboard. + int copy(int clipboard=1); }; #endif // !Fl_Help_View_H diff --git a/libraries/fltk/FL/Fl_Input_.H b/libraries/fltk/FL/Fl_Input_.H index e7087e418a..2e87b115db 100644 --- a/libraries/fltk/FL/Fl_Input_.H +++ b/libraries/fltk/FL/Fl_Input_.H @@ -304,7 +304,7 @@ public: \see insert_position(int, int) */ int insert_position() const { return position_; } - FL_DEPRECATED("in 1.4.0 - use insert_position() instead", + FL_DEPRECATED("since 1.4.0 - use insert_position() instead", int position() const ) { return insert_position(); } /** Gets the current selection mark. @@ -313,7 +313,7 @@ public: /* Sets the index for the cursor and mark. */ int insert_position(int p, int m); - FL_DEPRECATED("in 1.4.0 - use insert_position(p, m) or Fl_Widget::position(x, y) instead", + FL_DEPRECATED("since 1.4.0 - use insert_position(p, m) or Fl_Widget::position(x, y) instead", int position(int p, int m)) { return insert_position(p, m); } /** Sets the cursor position and mark. @@ -323,7 +323,7 @@ public: \see insert_position(int, int), insert_position(), mark(int) */ int insert_position(int p) { return insert_position(p, p); } - FL_DEPRECATED("in 1.4.0 - use insert_position(p) instead", + FL_DEPRECATED("since 1.4.0 - use insert_position(p) instead", int position(int p)) { return insert_position(p); } /** Sets the current selection mark. diff --git a/libraries/fltk/FL/Fl_Input_Choice.H b/libraries/fltk/FL/Fl_Input_Choice.H index f61d664b6b..4c840b6704 100644 --- a/libraries/fltk/FL/Fl_Input_Choice.H +++ b/libraries/fltk/FL/Fl_Input_Choice.H @@ -6,7 +6,7 @@ // |______________||____| // // Copyright 2004 by Greg Ercolano. -// Copyright 1998-2021 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -72,7 +72,7 @@ protected: /** See inp_x() for info. */ virtual int inp_y() const { return(y() + Fl::box_dy(box())); } /** See inp_x() for info. */ - virtual int inp_w() const { return(w() - Fl::box_dw(box()) - 20); } + virtual int inp_w() const { return(w() - Fl::box_dw(box()) - menu_w()); } /** See inp_x() for info. */ virtual int inp_h() const { return(h() - Fl::box_dh(box())); } @@ -81,13 +81,15 @@ protected: These can be overridden by a subclass to redefine positioning. See code example in the Description for subclassing details. */ - virtual int menu_x() const { return(x() + w() - 20 - Fl::box_dx(box())); } + virtual int menu_x() const { return x() + w() - menu_w() - Fl::box_dx(box()); } /** See menu_x() for info. */ - virtual int menu_y() const { return(y() + Fl::box_dy(box())); } + virtual int menu_y() const { return y() + Fl::box_dy(box()); } /** See menu_x() for info. */ - virtual int menu_w() const { return(20); } + virtual int menu_w() const { return 20; } /** See menu_x() for info. */ - virtual int menu_h() const { return(h() - Fl::box_dh(box())); } + virtual int menu_h() const { return h() - Fl::box_dh(box()); } + + void draw() FL_OVERRIDE; public: diff --git a/libraries/fltk/FL/Fl_Menu_.H b/libraries/fltk/FL/Fl_Menu_.H index 0c5fa9a688..b89949c160 100644 --- a/libraries/fltk/FL/Fl_Menu_.H +++ b/libraries/fltk/FL/Fl_Menu_.H @@ -228,7 +228,7 @@ public: /** This box type is used to surround the currently-selected items in the - menus. + menus. */ Fl_Boxtype down_box() const {return (Fl_Boxtype)down_box_;} /** Sets the box type used to surround the currently-selected items in the menus. */ diff --git a/libraries/fltk/FL/Fl_Menu_Item.H b/libraries/fltk/FL/Fl_Menu_Item.H index a4f760645b..3073dd2d0f 100644 --- a/libraries/fltk/FL/Fl_Menu_Item.H +++ b/libraries/fltk/FL/Fl_Menu_Item.H @@ -34,8 +34,8 @@ enum { // values for flags: FL_SUBMENU_POINTER = 0x20, ///< Indicates user_data() is a pointer to another menu array FL_SUBMENU = 0x40, ///< Item is a submenu to other items FL_MENU_DIVIDER = 0x80, ///< Creates divider line below this item. Also ends a group of radio buttons - FL_MENU_HORIZONTAL = 0x100, ///< ??? -- reserved, internal (do not use) - FL_MENU_RESERVED = 0xffffff00 ///< These bits are reserved for internal or future usage (do not use) + FL_MENU_HORIZONTAL = 0x100 ///< ??? -- reserved, internal (do not use) + ///< Note: \b ALL other bits in \p flags are reserved: do not use them for your own purposes! }; extern FL_EXPORT Fl_Shortcut fl_old_shortcut(const char*); @@ -67,10 +67,19 @@ class Fl_Menu_; FL_SUBMENU_POINTER = 0x20, // Indicates user_data() is a pointer to another menu array FL_SUBMENU = 0x40, // This item is a submenu to other items FL_MENU_DIVIDER = 0x80, // Creates divider line below this item. Also ends a group of radio buttons. - FL_MENU_HORIZONTAL = 0x100, // ??? -- reserved, internal (do not use) - FL_MENU_RESERVED = 0xffffff00 // These bits are reserved for internal or future usage (do not use) + FL_MENU_HORIZONTAL = 0x100 // ??? -- reserved, internal (do not use) }; \endcode + + \note \b All other bits in \p flags are reserved for FLTK usage, do not use any bits of the + \p flags variable for your own purposes. Even \b undocumented bits can be used for internal + purposes in this or any future FLTK version. + + Some \p flags bits may be changed during runtime by user code, particularly if you need to change + the value of a menu item (ON/OFF) or make it active or inactive. Such changes must be done with + caution so they don't affect other (maybe undocumented) bits, i.e. you need to make proper bit + operations to set or clear only these particular bits. + Typically menu items are statically defined; for example: \code Fl_Menu_Item popup[] = { diff --git a/libraries/fltk/FL/Fl_Pack.H b/libraries/fltk/FL/Fl_Pack.H index 1f8db01551..3da236b193 100644 --- a/libraries/fltk/FL/Fl_Pack.H +++ b/libraries/fltk/FL/Fl_Pack.H @@ -93,6 +93,9 @@ public: uchar horizontal() const {return type();} void resize(int X, int Y, int W, int H) FL_OVERRIDE; + /** Deletes all child widgets with Fl_Group::clear(). + And sets to NULL the resizable() widget. */ + void clear() { Fl_Group::clear(); resizable(NULL); } }; #endif diff --git a/libraries/fltk/FL/Fl_Preferences.H b/libraries/fltk/FL/Fl_Preferences.H index 98cc425238..6c6407a579 100644 --- a/libraries/fltk/FL/Fl_Preferences.H +++ b/libraries/fltk/FL/Fl_Preferences.H @@ -32,10 +32,10 @@ /** \brief Fl_Preferences store user settings between application starts. - Fl_Preferences are similar to the Registry on Windows and Preferences on MacOS, - providing a simple method to store customizable user settings between app - launches, for instance the previous window position or a history of previously - used documents. + FLTK Preferences are similar to the Registry on Windows and Preferences on + MacOS, providing a simple method to store customizable user settings between + application launches. A typical use is storing the last window position or a + history of previously used documents. Preferences are organized in a hierarchy of groups. Every group can contain more groups and any number of key/value pairs. Keys can be text strings @@ -43,29 +43,31 @@ in a key name are treated as subgroups, i.e. the key 'window/width' would actually refer to the key 'width' inside the group 'window'. - Keys usually have a unique name within their group. Duplicate keys are - possible though and can be accessed using the index based functions. - - A value can be an UTF-8 string. Control characters and UTF-8 sequences are - stored as octal values. Long strings are wrapped at the line ending and will - be reassembled when reading the file back. + Keys have a unique name within their group. A value can be any string including + control characters 0x00 to 0x1f, 0x7f, and UTF-8 octets. Several methods allow setting and getting numerical values and binary data. - Preferences are stored in text files that can be edited manually if needed. - The file format is easy to read and relatively forgiving. Preference files are - the same on all platforms. User comments in preference files are preserved. - Filenames are unique for each application by using a vendor/application naming - scheme. The user must provide default values for all entries to ensure proper - operation should preferences be corrupted or not yet exist. + Preferences files are the same across platforms. User comments in preference + files are preserved. Filenames are unique for each application by using a + vendor/application naming scheme. The developer app must provide default values + for all entries to ensure proper operation should preferences be corrupted + or not yet exist. + + \note The format of preferences files is not part of the FLTK specification + and intentionally undocumented. The only valid way to read or write prefs + files is via the API from your app. The fact that the current + implementation looks like human-readable text is purely coincidental and + may change at any time. Preferences files are not meant to be created + or edited "by hand." - FLTK preferences are not meant to replace a fully features database. No merging + FLTK preferences are not meant to replace a fully featured database. No merging of data takes place. If several instances of an app access the same database at the same time, only the most recent changes will persist. - Preferences should no be used to store document data. The .prefs file should + Preferences should not be used to store document data. The .prefs file should be kept small for performance reasons. One application can have multiple - preference files. Extensive binary data however should be stored in separate + preferences files. Extensive binary data however should be stored in separate files: see \a Fl_Preferences::get_userdata_path() . Fl_Preferences are not thread-safe. They can temporarily change the locale @@ -97,13 +99,12 @@ \see Fl_Preferences::Fl_Preferences(Root root, const char *vendor, const char *application) - As a special case, Fl_Preferences can be memory mapped and not be associated - with a file on disk. - - \see Fl_Preferences::Fl_Preferences(Fl_Preferences *parent, const char *group) - for more details on memory mapped preferences. + \see As a special case, Fl_Preferences can be memory mapped and not be associated + with a file on disk. See + Fl_Preferences::Fl_Preferences(Fl_Preferences *parent, const char *group) + and Fl_Preferences::MEMORY for more details on memory mapped preferences. - \note Starting with FLTK 1.3, preference databases are expected to + \note Starting with FLTK 1.3, preferences databases are expected to be in UTF-8 encoding. Previous databases were stored in the current character set or code page which renders them incompatible for text entries using international characters. @@ -134,9 +135,9 @@ public: MEMORY, ///< Returned if querying memory mapped preferences ROOT_MASK = 0x00FF, ///< Mask for the values above CORE = 0x0100, ///< OR'd by FLTK to read and write core library preferences and options - C_LOCALE = 0x1000, ///< This flag should always be set, it makes sure that floating point + C_LOCALE = 0x1000, ///< This flag should always be set to ensure that floating point values + ///< are written and read correctly independently of the current locale CLEAR = 0x2000, ///< Don't read a possibly existing database. Instead, start with an empty set of preferences. - ///< values are written correctly independently of the current locale SYSTEM_L = SYSTEM | C_LOCALE, ///< Preferences are used system-wide, locale independent USER_L = USER | C_LOCALE, ///< Preferences apply only to the current user, locale independent CORE_SYSTEM_L = CORE | SYSTEM_L, ///< Same as CORE | SYSTEM | C_LOCALE @@ -202,7 +203,7 @@ public: Fl_Preferences( ID id ); virtual ~Fl_Preferences(); - FL_DEPRECATED("in 1.4.0 - use Fl_Preferences(path, vendor, application, flags) instead", + FL_DEPRECATED("since 1.4.0 - use Fl_Preferences(path, vendor, application, flags) instead", Fl_Preferences( const char *path, const char *vendor, const char *application ) ); Root filename( char *buffer, size_t buffer_size); diff --git a/libraries/fltk/FL/Fl_Single_Window.H b/libraries/fltk/FL/Fl_Single_Window.H index 8cd101e543..7cbb387225 100644 --- a/libraries/fltk/FL/Fl_Single_Window.H +++ b/libraries/fltk/FL/Fl_Single_Window.H @@ -1,7 +1,7 @@ // // Single-buffered window header file for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2015 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -32,8 +32,8 @@ class FL_EXPORT Fl_Single_Window : public Fl_Window { public: void show() FL_OVERRIDE; - /** Same as Fl_Window::show(int a, char **b) */ - void show(int a, char **b) {Fl_Window::show(a,b);} + /** Same as Fl_Window::show(int argc, char **argv) */ + void show(int argc, char **argv) { Fl_Window::show(argc, argv);} /** Creates a new Fl_Single_Window widget using the given @@ -46,6 +46,16 @@ public: position, size, and label (title) string. */ Fl_Single_Window(int X, int Y, int W, int H, const char *l=0); + + /** + Same as Fl_Window::make_current() + */ + void make_current() { Fl_Window::make_current(); } + + /** + Same as Fl_Window::flush() + */ + void flush() FL_OVERRIDE { Fl_Window::flush(); } }; #endif diff --git a/libraries/fltk/FL/Fl_Tabs.H b/libraries/fltk/FL/Fl_Tabs.H index 2b1d97ca99..8fe21daa5d 100644 --- a/libraries/fltk/FL/Fl_Tabs.H +++ b/libraries/fltk/FL/Fl_Tabs.H @@ -251,6 +251,8 @@ protected: Fl_Align tab_align_; ///< tab label alignment int has_overflow_menu;///< set in OVERFLOW_PULLDOWN mode if tabs overflow. The actual menu array is created only on demand + void take_focus(Fl_Widget *o); + int maybe_do_callback(Fl_Widget *o); void check_overflow_menu(); void handle_overflow_menu(); void draw_overflow_menu_button(); @@ -258,7 +260,6 @@ protected: int on_insert(Fl_Widget*, int) FL_OVERRIDE; int on_move(int, int) FL_OVERRIDE; void on_remove(int) FL_OVERRIDE; - void resize(int, int, int, int) FL_OVERRIDE; virtual void redraw_tabs(); virtual int tab_positions(); // allocate and calculate tab positions @@ -274,7 +275,10 @@ protected: public: Fl_Tabs(int X, int Y, int W, int H, const char *L = 0); - virtual ~Fl_Tabs(); + ~Fl_Tabs() FL_OVERRIDE; + + void resize(int, int, int, int) FL_OVERRIDE; + void show() FL_OVERRIDE; int handle(int) FL_OVERRIDE; Fl_Widget *value(); diff --git a/libraries/fltk/FL/Fl_Terminal.H b/libraries/fltk/FL/Fl_Terminal.H index d6580a1066..dc11e311ca 100644 --- a/libraries/fltk/FL/Fl_Terminal.H +++ b/libraries/fltk/FL/Fl_Terminal.H @@ -852,6 +852,8 @@ public: */ Fl_Scrollbar *hscrollbar; // horizontal scrollbar private: + // Special utf8 symbols + const char *error_char_; // utf8 string shown for invalid utf8, bad ANSI, etc bool fontsize_defer_; // flag defers font calcs until first draw() (issue 837) int scrollbar_size_; // local preference for scrollbar size ScrollbarStyle hscrollbar_style_; @@ -897,7 +899,6 @@ protected: private: void create_ring(int drows, int dcols, int hrows); void init_(int X,int Y,int W,int H,const char*L,int rows,int cols,int hist,bool fontsize_defer); -private: // Tabstops void init_tabstops(int newsize); void default_tabstops(void); @@ -999,6 +1000,7 @@ public: private: void handle_lf(void); void handle_cr(void); + void handle_esc(void); // Printing void handle_ctrl(char c); bool is_printable(char c); @@ -1168,12 +1170,16 @@ private: public: float redraw_rate(void) const; void redraw_rate(float val); - // API: Show unknown/unprintable chars + // API: Show unknown/invalid utf8/ANSI sequences with an error character (¿). bool show_unknown(void) const; void show_unknown(bool val); -protected: - static const char *unknown_char; ///< "unknown" replacement character -public: + /// Sets the "error character" utf8 string shown for invalid utf8 + /// or bad ANSI sequences if show_unknown() is true. Default: "¿". + /// \see show_unknown(bool) + void error_char(const char* val) { error_char_ = val; } + /// Returns the "error character" utf8 string, which is shown for invalid utf8 + /// or bad ANSI sequences if show_unknown() is true. \see show_unknown(bool) + const char* error_char(void) const { return error_char_; } // API: ANSI sequences bool ansi(void) const; void ansi(bool val); diff --git a/libraries/fltk/FL/Fl_Text_Buffer.H b/libraries/fltk/FL/Fl_Text_Buffer.H index fa3916eba4..f548f1e4e9 100644 --- a/libraries/fltk/FL/Fl_Text_Buffer.H +++ b/libraries/fltk/FL/Fl_Text_Buffer.H @@ -167,7 +167,7 @@ public: // Returns true if selected() and the positions of this selection. int selected(int *startpos, int *endpos) const; - FL_DEPRECATED("in 1.4.0 - use selected(startpos, endpos) instead", + FL_DEPRECATED("since 1.4.0 - use selected(startpos, endpos) instead", int position(int *startpos, int *endpos) const) { return selected(startpos, endpos); } protected: @@ -635,6 +635,13 @@ public: */ int count_lines(int startPos, int endPos) const; + /** + Estimate the number of newlines between \p startPos and \p endPos in buffer. + This call takes line wrapping into account. It assumes a line break at every + `lineLen` characters after the beginning of a line. + */ + int estimate_lines(int startPos, int endPos, int lineLen) const; + /** Finds the first character of the line \p nLines forward from \p startPos in the buffer and returns its position. diff --git a/libraries/fltk/FL/Fl_Text_Display.H b/libraries/fltk/FL/Fl_Text_Display.H index c736db1e0e..533839a046 100644 --- a/libraries/fltk/FL/Fl_Text_Display.H +++ b/libraries/fltk/FL/Fl_Text_Display.H @@ -433,6 +433,7 @@ public: void wrap_mode(int wrap, int wrap_margin); virtual void recalc_display(); + virtual void display_needs_recalc(); void resize(int X, int Y, int W, int H) FL_OVERRIDE; /** @@ -571,7 +572,10 @@ protected: int mCursorPreferredXPos; /* Pixel position for vert. cursor movement */ int mNVisibleLines; /* # of visible (displayed) lines. This is also the size of the mLineStarts[] array. */ - int mNBufferLines; /* # of newlines in the buffer */ + int mNBufferLines; /* # of newlines in the buffer, or number of + wraps if line wrapping is enabled. Note that + partial lines at the end of the buffer are + not counted, so you may want to add 1. */ Fl_Text_Buffer* mBuffer; /* Contains text to be displayed */ Fl_Text_Buffer* mStyleBuffer; /* Optional parallel buffer containing color and font information */ @@ -628,6 +632,9 @@ protected: needs to be mutable so that it can be calculated within a method marked as "const" */ + bool display_needs_recalc_; /* Set to true when the display needs + to be recalculated. */ + Fl_Color mCursor_color; Fl_Scrollbar* mHScrollBar; diff --git a/libraries/fltk/FL/Fl_Tile.H b/libraries/fltk/FL/Fl_Tile.H index 64a3ba530c..189e0f6da5 100644 --- a/libraries/fltk/FL/Fl_Tile.H +++ b/libraries/fltk/FL/Fl_Tile.H @@ -32,7 +32,7 @@ public: void resize(int X, int Y, int W, int H) FL_OVERRIDE; virtual void move_intersection(int oldx, int oldy, int newx, int newy); virtual void drag_intersection(int oldx, int oldy, int newx, int newy); - FL_DEPRECATED("in 1.4.0 - use move_intersection(p) instead", + FL_DEPRECATED("since 1.4.0 - use move_intersection(p) instead", void position(int oldx, int oldy, int newx, int newy)) { move_intersection(oldx, oldy, newx, newy); } void position(int x, int y) { Fl_Group::position(x, y); } void size_range(int index, int minw, int minh, int maxw=0x7FFFFFFF, int maxh=0x7FFFFFFF); diff --git a/libraries/fltk/FL/Fl_Tree_Item.H b/libraries/fltk/FL/Fl_Tree_Item.H index d0e68d4e7c..b763953343 100644 --- a/libraries/fltk/FL/Fl_Tree_Item.H +++ b/libraries/fltk/FL/Fl_Tree_Item.H @@ -392,7 +392,16 @@ public: int is_visible() const { return(is_flag(VISIBLE)); } - int visible_r() const; + /// See if item and all its parents are open() and visible(). + /// Alias for is_visible_r(). + /// \returns + /// 1 -- item and its parents are open() and visible() + /// 0 -- item (or one of its parents) are not visible or close()ed. + /// + int visible_r() const { + return(is_visible_r()); + } + int is_visible_r() const; /// Set the item's user icon to an Fl_Image. Use '0' to disable. /// No internal copy is made, caller must manage icon's memory. diff --git a/libraries/fltk/FL/Fl_Tree_Prefs.H b/libraries/fltk/FL/Fl_Tree_Prefs.H index addae10e71..be4e3e21e7 100644 --- a/libraries/fltk/FL/Fl_Tree_Prefs.H +++ b/libraries/fltk/FL/Fl_Tree_Prefs.H @@ -298,6 +298,8 @@ public: inline Fl_Image *openicon() const { return(_openimage); } + inline int openicon_w() const { return _openimage ? _openimage->w() : 11; } + inline int openicon_h() const { return _openimage ? _openimage->h() : 11; } void openicon(Fl_Image *val); /// Gets the default 'close' icon /// Returns the Fl_Image* of the icon, or 0 if none. @@ -305,6 +307,8 @@ public: inline Fl_Image *closeicon() const { return(_closeimage); } + inline int closeicon_w() const { return _closeimage ? _closeimage->w() : 11; } + inline int closeicon_h() const { return _closeimage ? _closeimage->h() : 11; } void closeicon(Fl_Image *val); /// Gets the default 'user icon' (default is 0) inline Fl_Image *usericon() const { diff --git a/libraries/fltk/FL/Fl_Widget.H b/libraries/fltk/FL/Fl_Widget.H index cc616bcf09..c0ede955b3 100644 --- a/libraries/fltk/FL/Fl_Widget.H +++ b/libraries/fltk/FL/Fl_Widget.H @@ -63,6 +63,12 @@ struct FL_EXPORT Fl_Label { Fl_Align align_; /** type of label. \see Fl_Labeltype */ uchar type; + /** Spacing between label and the horizontally aligned side of the widget. */ + signed char h_margin_; + /** Spacing between label and the vertically aligned side of the widget. */ + signed char v_margin_; + /** Spacing between an image and the label text */ + uchar spacing; /** Draws the label aligned to the given box */ void draw(int,int,int,int, Fl_Align) const ; @@ -72,8 +78,8 @@ struct FL_EXPORT Fl_Label { /** A class prototype that allows for additional data in callbacks. - Users can extend this class and pass it to widget callbacks. Widgets can - take ownership of the callback data, deleting the data when the widget + Users can derive this class and pass objects of such derived classes to widget callbacks. + Widgets can take ownership of the callback data, deleting the data when the widget itself is deleted. The destructor of this class is virtual, allowing for additional code to @@ -83,9 +89,11 @@ struct FL_EXPORT Fl_Label { \see Fl_Widget::callback(Fl_Callback*, Fl_Callback_User_Data*, bool) \see Fl_Widget::user_data(Fl_Callback_User_Data*, bool) */ -class Fl_Callback_User_Data { +class FL_EXPORT Fl_Callback_User_Data { +protected: + Fl_Callback_User_Data() {} ///< Protected constructor public: - virtual ~Fl_Callback_User_Data() { } + virtual ~Fl_Callback_User_Data() { } ///< Destructor }; @@ -685,6 +693,37 @@ public: */ void bind_deimage(int f) { if (f) set_flag(DEIMAGE_BOUND); else clear_flag(DEIMAGE_BOUND); } + /** Set the gap between the label and the image in pixels. + This value is limited to 0..255. + \param[in] gap spacing in pixels + */ + void label_image_spacing(int gap) { label_.spacing = (uchar)gap; } + + /** Return the gap size between the label and the image. + \return spacing in pixels + */ + int label_image_spacing() { return label_.spacing; } + + /** Set the spacing between the label and the horizontal edge of the widget. + \param[in] px gap in pixels + */ + void horizontal_label_margin(int px) { label_.h_margin_ = (signed char)px; } + + /** Get the spacing between the label and the horizontal edge of the widget. + \return px gap in pixels + */ + int horizontal_label_margin() { return label_.h_margin_; } + + /** Set the spacing between the label and the vertical edge of the widget. + \param[in] px gap in pixels + */ + void vertical_label_margin(int px) { label_.v_margin_ = (signed char)px; } + + /** Get the spacing between the label and the vertical edge of the widget. + \return px gap in pixels + */ + int vertical_label_margin() { return label_.v_margin_; } + /** Gets the current tooltip text. \return a pointer to the tooltip text or NULL \see tooltip(const char*), copy_tooltip(const char*) diff --git a/libraries/fltk/FL/Fl_Window.H b/libraries/fltk/FL/Fl_Window.H index 3df78092e4..c684927ab5 100644 --- a/libraries/fltk/FL/Fl_Window.H +++ b/libraries/fltk/FL/Fl_Window.H @@ -98,9 +98,14 @@ protected: /** Stores the last window that was made current. See current() const */ static Fl_Window *current_; void draw() FL_OVERRIDE; + +public: + /** Forces the window to be drawn, this window is also made current and calls draw(). */ virtual void flush(); +protected: + /** Sets an internal flag that tells FLTK and the window manager to honor position requests. @@ -212,7 +217,9 @@ public: */ void resize(int X,int Y,int W,int H) FL_OVERRIDE; /** Sets whether or not the window manager border is around the window. - The default value is true. With some X window + The default value is true. The macOS platform ignores requests to change the + border state of a fullscreen or maximized window. + With some X window managers, this does not work after show() has been called. */ void border(int b); @@ -629,9 +636,9 @@ public: static char show_next_window_iconic() { return show_next_window_iconic_; } - + void allow_expand_outside_parent(); - + }; #endif diff --git a/libraries/fltk/FL/Makefile.in b/libraries/fltk/FL/Makefile.in index 04a115c9de..f8d46ff783 100644 --- a/libraries/fltk/FL/Makefile.in +++ b/libraries/fltk/FL/Makefile.in @@ -24,24 +24,24 @@ depend: install: echo "Installing include files in $(DESTDIR)$(includedir)..." - $(RMDIR) $(DESTDIR)$(includedir)/FL - $(INSTALL_DIR) $(DESTDIR)$(includedir)/FL + $(RMDIR) "$(DESTDIR)$(includedir)/FL" + $(INSTALL_DIR) "$(DESTDIR)$(includedir)/FL" for file in *.[hH]; do \ - $(INSTALL_DATA) $$file $(DESTDIR)$(includedir)/FL; \ + $(INSTALL_DATA) $$file "$(DESTDIR)$(includedir)/FL"; \ done -@HLINKS@ cd $(DESTDIR)$(includedir)/FL;\ +@HLINKS@ cd "$(DESTDIR)$(includedir)/FL";\ @HLINKS@ for file in *.H; do\ @HLINKS@ $(RM) "`basename $$file H`h";\ @HLINKS@ $(LN) $$file "`basename $$file H`h";\ @HLINKS@ done -@HLINKS@ $(RM) $(DESTDIR)$(includedir)/FL/fl_file_chooser.H -@HLINKS@ $(LN) Fl_File_Chooser.H $(DESTDIR)$(includedir)/FL/fl_file_chooser.H -@HLINKS@ $(RM) $(DESTDIR)$(includedir)/FL/fl_file_chooser.h -@HLINKS@ $(LN) Fl_File_Chooser.H $(DESTDIR)$(includedir)/FL/fl_file_chooser.h -@HLINKS@ $(RM) $(DESTDIR)$(includedir)/Fl -@HLINKS@ $(LN) FL $(DESTDIR)$(includedir)/Fl +@HLINKS@ $(RM) "$(DESTDIR)$(includedir)/FL/fl_file_chooser.H" +@HLINKS@ $(LN) Fl_File_Chooser.H "$(DESTDIR)$(includedir)/FL/fl_file_chooser.H" +@HLINKS@ $(RM) "$(DESTDIR)$(includedir)/FL/fl_file_chooser.h" +@HLINKS@ $(LN) Fl_File_Chooser.H "$(DESTDIR)$(includedir)/FL/fl_file_chooser.h" +@HLINKS@ $(RM) "$(DESTDIR)$(includedir)/Fl" +@HLINKS@ $(LN) FL "$(DESTDIR)$(includedir)/Fl" uninstall: echo "Uninstalling include files..." - $(RMDIR) $(DESTDIR)$(includedir)/FL -@HLINKS@ $(RM) $(DESTDIR)$(includedir)/Fl + $(RMDIR) "$(DESTDIR)$(includedir)/FL" +@HLINKS@ $(RM) "$(DESTDIR)$(includedir)/Fl" diff --git a/libraries/fltk/FL/fl_draw.H b/libraries/fltk/FL/fl_draw.H index 14137c5d74..6535d031a3 100644 --- a/libraries/fltk/FL/fl_draw.H +++ b/libraries/fltk/FL/fl_draw.H @@ -223,8 +223,11 @@ inline void fl_point(int x, int y) { If you change this it is your responsibility to set it back to the default using \c fl_line_style(0). - \param[in] style A bitmask which is a bitwise-OR of a line style, a cap - style, and a join style. If you don't specify a dash type you + \image html fl_line_style.png "fl_line_style() styles" + \image latex fl_line_style.png "fl_line_style() styles" width=12cm + + \param[in] style A bitmask which is a bitwise-OR of \ref LineStyles "Line Styles", + a cap style, and a join style. If you don't specify a dash type you will get a solid line. If you don't specify a cap or join type you will get a system-defined default of whatever value is fastest. \param[in] width The thickness of the lines in pixels. Zero results in the @@ -249,12 +252,18 @@ inline void fl_point(int x, int y) { inline void fl_line_style(int style, int width = 0, char *dashes = 0) { fl_graphics_driver->line_style(style, width, dashes); } + +/// \anchor LineStyles +/// +/// \image html fl_line_style.png "fl_line_style() styles" +/// \image latex fl_line_style.png "fl_line_style() styles" width=12cm +/// enum { - FL_SOLID = 0, ///< line style: ___________ - FL_DASH = 1, ///< line style: _ _ _ _ _ _ - FL_DOT = 2, ///< line style: . . . . . . - FL_DASHDOT = 3, ///< line style: _ . _ . _ . - FL_DASHDOTDOT = 4, ///< line style: _ . . _ . . + FL_SOLID = 0, ///< line style: solid line + FL_DASH = 1, ///< line style: 75% dashed line + FL_DOT = 2, ///< line style: 50% pixel dotted + FL_DASHDOT = 3, ///< line style: dash / dot pattern + FL_DASHDOTDOT = 4, ///< line style: dash / two dot pattern FL_CAP_FLAT = 0x100, ///< cap style: end is flat FL_CAP_ROUND = 0x200, ///< cap style: end is round @@ -411,7 +420,7 @@ inline void fl_loop(int x, int y, int x1, int y1, int x2, int y2, int x3, int y3 // filled polygons /** - Fill a 3-sided polygon. The polygon must be convex. + Fill a 3-sided polygon. */ inline void fl_polygon(int x, int y, int x1, int y1, int x2, int y2) { fl_graphics_driver->polygon(x, y, x1, y1, x2, y2); @@ -623,7 +632,7 @@ inline void fl_curve(double X0, double Y0, double X1, double Y1, double X2, doub } /** Add a series of points to the current path on the arc of a circle. - + The arc is drawn counter-clockwise from 3 o'clock. If \p end is less than \p start then it draws the arc in a clockwise direction. To draw an arc across the 3 o'clock line, \p start and \p end can be greater than 360 or less than 0. @@ -966,10 +975,49 @@ inline void fl_rtl_draw(const char *str, int n, int x, int y) { fl_graphics_driver->rtl_draw(str, n, x, y); } FL_EXPORT void fl_measure(const char *str, int &x, int &y, int draw_symbols = 1); -FL_EXPORT void fl_draw(const char *str, int x, int y, int w, int h, Fl_Align align, Fl_Image *img = 0, - int draw_symbols = 1); +/** + Fancy string drawing function which is used to draw all the labels. + + The string is formatted and aligned inside the passed box. + Handles '\\t' and '\\n', expands all other control characters to '^X', + and aligns inside or against the edges of the box. + See Fl_Widget::align() for values of \p align. The value FL_ALIGN_INSIDE + is ignored, as this function always prints inside the box. + If \p img is provided and is not \p NULL, the image is drawn above or + below the text as specified by the \p align value. + The \p draw_symbols argument specifies whether or not to look for symbol + names starting with the '\@' character' + + \param[in] str UTF-8 string, can start and end with an '\@sym' symbol, + can contain '\\n' + \param[in] x,y,w,h bounding box + \param[in] align label and image alignment in bounding box + \param[in] img pointer to image + \param[in] draw_symbols if true, interprete leading and trailing '\@sym' + as graphical symbols + \param[in] spacing spacing between text and image + */ +FL_EXPORT void fl_draw(const char *str, int x, int y, int w, int h, + Fl_Align align, Fl_Image *img = 0, + int draw_symbols = 1, int spacing = 0); +/** + The same as fl_draw(const char*,int,int,int,int,Fl_Align,Fl_Image*,int) with + the addition of the \p callthis parameter, which is a pointer to a text drawing + function such as fl_draw(const char*, int, int, int) to do the real work. + + \param[in] str UTF-8 string, can start and end with an '\@sym' symbol, + can contain '\\n' + \param[in] x,y,w,h bounding box + \param[in] align label and image alignment in bounding box + \param[in] callthis pointer to text drawing function + \param[in] img pointer to image + \param[in] draw_symbols if true, interprete leading and trailing '\@sym' + as graphical symbols + \param[in] spacing spacing between text and image + */ FL_EXPORT void fl_draw(const char *str, int x, int y, int w, int h, Fl_Align align, - void (*callthis)(const char *, int, int, int), Fl_Image *img = 0, int draw_symbols = 1); + void (*callthis)(const char *, int, int, int), + Fl_Image *img = 0, int draw_symbols = 1, int spacing = 0); // boxtypes: diff --git a/libraries/fltk/FL/mac.H b/libraries/fltk/FL/mac.H index 8982057a19..b0a2b84f53 100644 --- a/libraries/fltk/FL/mac.H +++ b/libraries/fltk/FL/mac.H @@ -99,6 +99,9 @@ typedef class FLWindow *Window; // pointer to the FLWindow objective-c class #ifndef MAC_OS_VERSION_14_0 #define MAC_OS_VERSION_14_0 140000 #endif +#ifndef MAC_OS_VERSION_15_0 +#define MAC_OS_VERSION_15_0 150000 +#endif #ifndef NSINTEGER_DEFINED // appears with 10.5 in NSObjCRuntime.h diff --git a/libraries/fltk/FL/names.h b/libraries/fltk/FL/names.h index 15a491f841..984afbfe0a 100644 --- a/libraries/fltk/FL/names.h +++ b/libraries/fltk/FL/names.h @@ -1,7 +1,7 @@ // -// Event names header file for the Fast Light Tool Kit (FLTK). +// Event and other names header file for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -116,7 +116,7 @@ const char * const fl_fontnames[] = }; /** - This is an array of callback reason names you can use to convert font numbers into names. + This is an array of callback reason names you can use to convert callback reasons into names. The array gets defined inline wherever your '\#include ' appears. */ diff --git a/libraries/fltk/FL/wayland.H b/libraries/fltk/FL/wayland.H index 34098a9d5d..71981d974c 100644 --- a/libraries/fltk/FL/wayland.H +++ b/libraries/fltk/FL/wayland.H @@ -43,6 +43,8 @@ extern FL_EXPORT cairo_t *fl_wl_gc(); \endcode */ extern FL_EXPORT struct wl_compositor *fl_wl_compositor(); +/** Returns the current buffer scaling factor for \p window. */ +extern FL_EXPORT int fl_wl_buffer_scale(Fl_Window *window); typedef void *EGLContext; /** Returns the EGLContext corresponding to the given GLContext */ extern FL_EXPORT EGLContext fl_wl_glcontext(GLContext rc); diff --git a/libraries/fltk/Makefile b/libraries/fltk/Makefile index 41e1121f1f..d4115d3a05 100644 --- a/libraries/fltk/Makefile +++ b/libraries/fltk/Makefile @@ -31,9 +31,9 @@ test: all (cd test; $(MAKE) $(MFLAGS)) || exit 1 install: makeinclude - -mkdir -p $(DESTDIR)$(bindir) - $(RM) $(DESTDIR)$(bindir)/fltk-config - $(INSTALL_SCRIPT) fltk-config $(DESTDIR)$(bindir) + -mkdir -p "$(DESTDIR)$(bindir)" + $(RM) "$(DESTDIR)$(bindir)/fltk-config" + $(INSTALL_SCRIPT) fltk-config "$(DESTDIR)$(bindir)" for dir in FL $(DIRS); do\ echo "=== installing $$dir ===";\ (cd $$dir; $(MAKE) $(MFLAGS) install) || exit 1;\ @@ -46,7 +46,7 @@ install-desktop: makeinclude cd test; $(MAKE) $(MFLAGS) $(INSTALL_DESKTOP) uninstall: makeinclude - $(RM) $(DESTDIR)$(bindir)/fltk-config + $(RM) "$(DESTDIR)$(bindir)/fltk-config" for dir in FL $(DIRS); do\ echo "=== uninstalling $$dir ===";\ (cd $$dir; $(MAKE) $(MFLAGS) uninstall) || exit 1;\ diff --git a/libraries/fltk/README.CMake.txt b/libraries/fltk/README.CMake.txt index 0d63fa8ab3..cc96899c05 100644 --- a/libraries/fltk/README.CMake.txt +++ b/libraries/fltk/README.CMake.txt @@ -1,5 +1,5 @@ README.CMake.txt - Building and using FLTK with CMake ------------------------------------------------------ +------------------------------------------------------ CONTENTS @@ -11,17 +11,19 @@ README.CMake.txt - Building and using FLTK with CMake 2.1 Prerequisites 2.2 Options - 2.2.1 General CMake Options - 2.2.2 FLTK Specific Build Options + 2.2.1 CMake Specific Configuration Options + 2.2.2 FLTK Specific Configuration Options 2.2.3 Documentation Options 2.2.4 Special Options - 2.3 Building under Linux with Unix Makefiles - 2.4 Building under Windows with Visual Studio and/or NMake - 2.4.1 Building under Windows with Visual Studio - 2.4.2 Building under Windows with NMake - 2.5 Building under Windows with MinGW using Makefiles - 2.6 Building under MacOS with Xcode - 2.7 Crosscompiling + 2.3 Building FLTK with CMake (all Platforms) + 2.4 Building under Linux with Unix Makefiles + 2.5 Building under Windows with Visual Studio and/or NMake + 2.5.1 Building under Windows with Visual Studio + 2.5.2 Building under Windows with NMake + 2.6 Building under Windows with MinGW using Makefiles + 2.7 Building under Windows WSL with Clang using Makefiles + 2.8 Building under macOS with Xcode + 2.9 Crosscompiling 3 Using CMake with FLTK @@ -106,8 +108,8 @@ All options have sensible defaults so you won't usually need to specify them explicitly. - 2.2.1 General CMake Options ------------------------------- + 2.2.1 CMake Specific Configuration Options +--------------------------------------------- There are only three CMake options that you may want to specify: @@ -131,8 +133,8 @@ Note: the CMake variable BUILD_SHARED_LIBS is ignored by FLTK. FLTK builds Please see FLTK_BUILD_SHARED_LIBS instead. - 2.2.2 FLTK Specific Build Options ------------------------------------- + 2.2.2 FLTK Specific Configuration Options +-------------------------------------------- Following are the FLTK specific options. Platform specific options are ignored on other platforms. For convenience the list of options is ordered @@ -216,10 +218,11 @@ FLTK_GRAPHICS_GDIPLUS - default ON (Windows only). Make FLTK use GDI+ to draw oblique lines and curves resulting in antialiased graphics. If this option is OFF standard GDI is used. -FLTK_MSVC_RUNTIME_DLL - default ON (Windows only: Visual Studio and NMake). +FLTK_MSVC_RUNTIME_DLL - default ON (Windows: Visual Studio, NMake, clang). Select whether the build uses the MS runtime DLL (ON) or not (OFF). Default is ON: either /MD or /MDd for Release or Debug, respectively. Select OFF for either /MT or /MTd for Release or Debug, respectively. + If this variable is defined on other platforms it is silently ignored. FLTK_OPTION_CAIRO_EXT - default OFF Enable extended libcairo support - see README.Cairo.txt. @@ -235,7 +238,8 @@ FLTK_OPTION_LARGE_FILE - default ON FLTK_OPTION_OPTIM - default EMPTY Extra optimization flags for the C and C++ compilers, for instance - "-Wall -Wno-deprecated-declarations". + "-Wall -Wno-deprecated-declarations". Example: + cmake -D FLTK_BUILD_EXAMPLES=on -D FLTK_OPTION_OPTIM="-Wall -Wextra -pedantic" .. FLTK_OPTION_PRINT_SUPPORT - default ON When turned off, the Fl_Printer class does nothing and the @@ -261,6 +265,8 @@ FLTK_USE_LIBDECOR_GTK - default ON (Wayland only). is always 'ON' if FLTK_USE_SYSTEM_LIBDECOR is 'ON'. FLTK_USE_PANGO - default OFF (see note below) + This option is highly recommended under X11 if FLTK is expected to draw + text that does not use the latin alphabet. Enables use of the Pango library for drawing text. Pango supports all unicode-defined scripts and gives FLTK limited support of right-to-left scripts. This option makes sense only under X11 or Wayland, and also @@ -318,9 +324,9 @@ FLTK_BUILD_PDF_DOCS - default ON because the docs are not built automatically. FLTK_BUILD_FLUID_DOCS - default OFF - If this option is ON, the FLUID user documentation will be built. If + If this option is ON, the FLUID user documentation will be built. If FLTK_BUILD_PDF_DOCS is ON, the FLUID documentation will be generated - in PDF forma. To generate the screen shots used in the handbook, + in PDF form. To generate the screen shots used in the handbook, the CMake build mode must be set to "Debug". FLTK_INCLUDE_DRIVER_DOCS - default OFF @@ -333,7 +339,7 @@ FLTK_INSTALL_HTML_DOCS - default OFF FLTK_INSTALL_FLUID_DOCS - default OFF FLTK_INSTALL_PDF_DOCS - default OFF If these options are ON then the HTML, FLUID, and/or PDF docs are installed - when the 'install' target is executed, e.g. with `make install'. You + when the 'install' target is executed, e.g. with `make install'. You need to select above options FLTK_BUILD_*_DOCS as well. @@ -347,22 +353,80 @@ FLTK_INSTALL_LINKS - default OFF better cross-platform compatibility. - 2.3 Building under Linux with Unix Makefiles + 2.3 Building FLTK with CMake (all Platforms) +----------------------------------------------- + +CMake is used to generate a build system that will subsequently be used +to build and install the FLTK library and test and demo applications. + +Note that "installing" FLTK is optional: you can skip this step if you +like to build your own applications directly from the FLTK build tree. +This has advantages if you are building FLTK with different options or +are developing FLTK (changing sources) or if you pull new FLTK versions +from git frequently. + +The following generic commands may need some changes on Windows where +you may not have an adequate (POSIX) shell (command window). + +(1) Generate the build system in the FLTK root directory: + + cmake -B build [ -G "Generator" -D "Options" … ] + + This command creates the 'build' subdirectory if it does not exist yet + and generates the build (project) files in the 'build' directory. + See above for usable options. + + Note: Although this 'build' directory is part of the source tree it + is considered an out-of-source build because CMake does not create + any files in source directories. You can also use CMake to build FLTK + in an arbitrary build folder elsewhere on the system: + + cmake -B /path/to/my-fltk-build [ -G "Generator" -D "Options" … ] + + Commandline elements in […] are optional. + + Use `cmake --help` to find out which generators are available on your + platform. The default generator is marked with '*'. + +(2) Build FLTK with the generated build system: + + No matter which generator you selected in (1), the following CMake + command can always be used to build the library: + + cmake --build build + + This uses the previously generated build system in the 'build' folder. + This works even with Visual Studio where the build will be executed + without opening the Visual Studio GUI, similar to NMake. + + Instead of using the above command you can also `cd build` and run + the native build command, for instance `make -j7` or `ninja`, or + you can open the IDE project (Xcode, Visual Studio, ...). + +(3) Install FLTK (optional): + + cmake --install build + + This command installs the previously built library and headers in the + installation folder. On Unix/Linux/macOS systems this requires root + privileges if the target is a system directory. + +The following chapters describe some special cases in more detail. Skip +chapters you don't need... + + + 2.4 Building under Linux with Unix Makefiles ----------------------------------------------- After unpacking the FLTK source, go to the root of the FLTK tree and type the following. - mkdir build + cmake -B build -G "Unix Makefiles" [options] cd build - cmake .. - make + make [ -j 3 ] sudo make install (optional) -IMPORTANT: The trailing ".." on the cmake command must be specified -(it is NOT an ellipsis). ^^^^^^^^^^^^^^^^^ - -This will build and install a default configuration FLTK. +This will build and optionally install a default configuration FLTK. Some flags can be changed during the 'make' command, such as: @@ -383,7 +447,7 @@ options, then use subdirectories in the build directory, like this: sudo make install (optional) - 2.4 Building under Windows with Visual Studio and/or NMake + 2.5 Building under Windows with Visual Studio and/or NMake ------------------------------------------------------------- Building with CMake under Visual Studio may require to specify the CMake @@ -393,7 +457,7 @@ are not sure which one to select use `cmake --help` which lists all generators known to CMake on your system. - 2.4.1 Building under Windows with Visual Studio + 2.5.1 Building under Windows with Visual Studio ------------------------------------------------- CMake often finds an installed Visual Studio generator and uses it w/o @@ -452,7 +516,7 @@ using the commandline switch, particularly if you are using a special build\FL - *and* [1] in the source folder where you downloade FLTK, e.g. in + *and* [1] in the source folder where you downloaded FLTK, e.g. in C:\fltk-1.4.x\FL @@ -468,12 +532,12 @@ using the commandline switch, particularly if you are using a special tree in the compiler's header search list. - 2.4.2 Building under Windows with NMake + 2.5.2 Building under Windows with NMake ----------------------------------------- This example uses cmake to generate + build FLTK in Release mode using nmake, using purely the command line (never need to open the Visual Studio IDE) - using Multithreaded (/MT): + using the static Multithreaded runtime (/MT): mkdir build-nmake cd build-nmake @@ -488,7 +552,7 @@ using the commandline switch, particularly if you are using a special cmake --build . - 2.5 Building under Windows with MinGW using Makefiles + 2.6 Building under Windows with MinGW using Makefiles -------------------------------------------------------- Building with CMake under MinGW requires you to specify the CMake Generator @@ -512,14 +576,47 @@ Note the path to FLTK ".." in the last command line. Depending on where you installed CMake you may need to adjust the path's in the alias commands. -2.6 Building under MacOS with Xcode ------------------------------------- + 2.7 Building under Windows WSL with Clang and Makefiles +---------------------------------------------------------- + +WSL, the Windows Subsystem for Linux allows developers to run a Linux +environment without the need for a separate virtual machine or dual booting. +WSL 2 runs inside a managed virtual machine that implements the full +Linux kernel. WSL requires Windows 11. + +FLTK apps generated using WSL are Linux compatible binaries. To run those +binaries on Windows, WSL comes with a limited built-in X11 server. Third +party X11 servers can be installed that better support all features of FLTK. -Building with CMake under Xcode requires the CMake generator -with the -G command line switch. This step need to be done only once. If any -of the cmake related files are updated, Xcode will rerun cmake for you. +1) Install WSL from PowerShell with admin privileges: + > wsl --install -1) Open the MacOS Terminal +2) Reboot and open the Linux terminal. You will need to install the following + Linux packages to compile FLTK + > sudo apt update + > sudo apt install clang cmake freeglut3-dev + +3) Change to the directory containing the FLTK project. For example: + > cd ~/dev/fltk-1.4.x + +4) Use CMake to configure the build system + > cmake -B build + +5) Use CMake to build the demo app and all dependencies + > cmake --build build + +6) Run the demo app + > ./build/bin/test/demo + + +2.8 Building under macOS with Xcode +------------------------------------- + +Building with CMake under Xcode requires the CMake generator with +the -G command line switch. This step need to be done only once. If any +of the CMake related files are updated, Xcode will rerun CMake for you. + +1) Open the macOS Terminal 2) Change to the directory containing the FLTK project. For example: > cd ~/dev/fltk-1.4.x @@ -551,12 +648,15 @@ of the cmake related files are updated, Xcode will rerun cmake for you. 8) The interactive user interface tool "Fluid" will be located in build/Xcode/bin/Debug. The example apps are in .../bin/examples/Debug. - Static libraries are in .../lib/Debug/ + Static libraries are in .../lib/Debug/. + Replace 'Debug' with 'Release' for a Release build. -9) The "install" Scheme currently fails because it is run with user permission. +9) The "install" Scheme may fail because it is run with user permissions. + You may want to configure the build to install in a folder below your + home directory. - 2.7 Crosscompiling + 2.9 Crosscompiling --------------------- Once you have a crosscompiler going, to use CMake to build FLTK you need @@ -630,6 +730,10 @@ This howto assumes that you have FLTK libraries which were built using CMake, installed. Building them with CMake generates some CMake helper files which are installed in standard locations, making FLTK easy to find and use. +If FLTK is not installed in a standard system location where it is found +automatically, you may need to set a CMake variable to point CMake to the +right location. + In the following examples we set the CMake cache variable 'FLTK_DIR' so CMake knows where to find the FLTK configuration file 'FLTKConfig.cmake'. It is important (recommended practice) to set this as a CMake cache variable @@ -637,6 +741,7 @@ which enables the user executing 'cmake' to override this path either on the commandline or interactively using the CMake GUI 'cmake-gui' or 'ccmake' on Unix/Linux, for instance like this: + $ cd my-project $ mkdir build $ cd build $ cmake -G "Unix Makefiles" -S.. -D "FLTK_DIR=/home/me/fltk" @@ -677,7 +782,7 @@ consumer projects (projects that use FLTK) for several reasons which are beyond the scope of this README file. The following table shows the FLTK libraries and their aliases in the FLTK build tree. - Library Name Alias Shared Library Alias Notes + Library Name Alias Shared Library Alias Notes -------------------------------------------------------------- fltk fltk::fltk fltk::fltk-shared [1] fltk_forms fltk::forms fltk::forms-shared [2] @@ -696,7 +801,7 @@ libraries and their aliases in the FLTK build tree. automatically. [3] The bundled libraries are only built if requested and are usually not needed in user projects. They are linked in with fltk::images - automatically if they were built with FLTK. + automatically if they were built together with FLTK. The only reason you may need them would be if you used libpng, libjpeg, or zlib functions directly in your application and need to use the bundled FLTK libs (e.g. on Windows). @@ -710,7 +815,7 @@ CMake files export targets and its CONFIG module FLTKConfig.cmake imports targets so user projects can use them. Hence, if you use CMake's CONFIG mode to find FLTK all library targets will be defined using the namespace convention listed above in the "Alias" column. This is what user projects -are intended to use. +are recommended to use. In addition to the library targets FLTK defines the "imported target" 'fltk::fluid' which can be used to generate source (.cxx) and header (.h) @@ -739,7 +844,7 @@ project(hello) set(FLTK_DIR "/path/to/fltk" CACHE FILEPATH "FLTK installation or build directory") -find_package(FLTK CONFIG REQUIRED) +find_package(FLTK 1.4 CONFIG REQUIRED) add_executable (hello WIN32 MACOSX_BUNDLE hello.cxx) target_link_libraries(hello PRIVATE fltk::fltk) @@ -750,7 +855,7 @@ building projects that use FLTK. Lower CMake versions may work for user projects but this is not tested by FLTK developers. The optional `set(FLTK_DIR ...)` command is a superhint to the find_package -command. This is very useful if you don't install or have a non-standard +command. This is useful if you don't install FLTK or have a non-standard install location. The path you give to it must be that of a directory that contains the file FLTKConfig.cmake. @@ -759,10 +864,13 @@ without it. This variable is stored in the CMake Cache so users can change it with the ususal CMake GUI interfaces (ccmake, cmake-gui) or on the CMake commandline (-D FLTK_DIR=...). -The find_package command tells CMake to find the package FLTK, REQUIRED -means that it is an error if it's not found. CONFIG tells it to search +The find_package command tells CMake to find the package FLTK, '1.4' says +that we want FLTK 1.4.x: any patch version of 1.4 will march. 'REQUIRED' +means that it is an error if it's not found. 'CONFIG' tells it to search only for the FLTKConfig.cmake file, not using the FindFLTK.cmake "module" -supplied with CMake, which doesn't work with this version of FLTK. +supplied with CMake, which doesn't work with this version of FLTK. Since +we specify a version (1.4) the file 'FLTKConfigVersion.cmake' must also +be found. This file is created since FLTK 1.3.10. "WIN32 MACOSX_BUNDLE" in the add_executable() command tells CMake that this is a GUI app. It is ignored on other platforms than Windows or macOS, @@ -809,7 +917,7 @@ project(CubeView) set(FLTK_DIR "/path/to/fltk" CACHE FILEPATH "FLTK installation or build directory") -find_package(FLTK CONFIG REQUIRED) +find_package(FLTK 1.4 CONFIG REQUIRED) # run fluid -c to generate CubeViewUI.cxx and CubeViewUI.h files add_custom_command( @@ -889,5 +997,5 @@ Unfortunately this module has to be used if the FLTK library wasn't built with CMake and thus CONFIG mode can't be used. In this case CMake falls back to MODULE mode and find_package() uses this old CMake module. -There are plans to provide a FindFLTK.cmake module with FLTK 1.4.0 but this -module is not yet written. Look here for further info if you need it... +There are plans to provide a FindFLTK.cmake module with a later FLTK release. +Look here for further info if you need it... diff --git a/libraries/fltk/README.Wayland.txt b/libraries/fltk/README.Wayland.txt index f586d80751..ea834c4cc4 100644 --- a/libraries/fltk/README.Wayland.txt +++ b/libraries/fltk/README.Wayland.txt @@ -72,7 +72,7 @@ should run with a Wayland-enabled FLTK 1.4 library with this single change. Note 1: this may require some linker flags to enable exporting symbols from *executable* programs which FLTK uses to "read" the global symbol -'fl_disable_wayland'. For for GNU `ld` or any GNU compiler this would +'fl_disable_wayland'. For GNU `ld` or any GNU compiler this would be "-rdynamic". @@ -85,15 +85,16 @@ the following techniques: Option 1: Set target property 'ENABLE_EXPORTS' on all executable targets that require to disable the Wayland backend. - This is the preferred solution. + This is the preferred solution because it works per target. CMake example: set_target_properties(myprog PROPERTIES ENABLE_EXPORTS TRUE) -Option 2: Set CMake policy CMP0065 to 'OLD' (to pre-3.4 behavior) +Option 2: Set CMake policy CMP0065 to 'OLD' (i.e. pre-3.4 behavior) This is a quick solution but discouraged because setting CMake policies to 'OLD' is "deprecated by definition". + CMake may issue warnings or ignore this in the future. CMake code: @@ -171,6 +172,10 @@ Feedback for other writing systems would be helpful. * Using OpenGL inside Wayland windows doesn't seem to work on RaspberryPi hardware, although it works inside X11 windows on the same hardware. +* Drag-and-drop initiation from a subwindow doesn't work under the KDE/Plasma desktop. +That is most probably a KWin bug because no such problem occurs with 3 other +Wayland compositors (Mutter, Weston, Sway). A workaround is proposed in issue #997 +of the FLTK github repository (https://github.com/fltk/fltk/issues/997). 3 Platform Specific Notes ========================= diff --git a/libraries/fltk/README.md b/libraries/fltk/README.md index 3e568423fe..9982f06b71 100644 --- a/libraries/fltk/README.md +++ b/libraries/fltk/README.md @@ -4,13 +4,18 @@ The Fast Light Tool Kit is a cross-platform C++ GUI toolkit for UNIX®/Linux® (X11 or Wayland), Microsoft® Windows®, and macOS®. - FLTK provides modern GUI functionality without the bloat and + FLTK provides modern GUI functionality without bloat and supports 3D graphics via OpenGL® and its built-in GLUT emulation. It was originally developed by Mr. Bill Spitzak and is currently maintained by a small group of developers across the world with a central repository on GitHub. + https://www.fltk.org/ + https://github.com/fltk/fltk/ + For more information see README.txt: https://github.com/fltk/fltk/blob/master/README.txt ![Build](https://github.com/fltk/fltk/actions/workflows/build.yml/badge.svg) + +[![Build FLUID User Manual.](https://github.com/Albrecht-S/fltk/actions/workflows/build_fluid_docs.yml/badge.svg)](https://github.com/Albrecht-S/fltk/actions/workflows/build_fluid_docs.yml) diff --git a/libraries/fltk/README.txt b/libraries/fltk/README.txt index fbf1e65364..85840f38e8 100644 --- a/libraries/fltk/README.txt +++ b/libraries/fltk/README.txt @@ -4,12 +4,12 @@ README - Fast Light Tool Kit (FLTK) Version 1.4.0 WHAT IS FLTK? The Fast Light Tool Kit is a cross-platform C++ GUI toolkit for - UNIX(r)/Linux(r) (X11 or Wayland), Microsoft(r) Windows(r), and - macOS(r). FLTK provides modern GUI functionality without bloat - and supports 3D graphics via OpenGL(r) and its built-in GLUT - emulation. It was originally developed by Mr. Bill Spitzak and is - currently maintained by a small group of developers across - the world with a central repository on GitHub. + UNIX®/Linux® (X11 or Wayland), Microsoft® Windows®, and macOS®. + FLTK provides modern GUI functionality without bloat and + supports 3D graphics via OpenGL® and its built-in GLUT + emulation. It was originally developed by Mr. Bill Spitzak + and is currently maintained by a small group of developers + across the world with a central repository on GitHub. https://www.fltk.org/ https://github.com/fltk/fltk/ @@ -201,7 +201,7 @@ TRADEMARKS COPYRIGHT - FLTK is copyright 1998-2023 by Bill Spitzak and others, + FLTK is copyright 1998-2024 by Bill Spitzak and others, see the CREDITS.txt file for more info. This library is free software. Distribution and use rights are diff --git a/libraries/fltk/configure.ac b/libraries/fltk/configure.ac index 8b22fc9af8..ac5154d328 100644 --- a/libraries/fltk/configure.ac +++ b/libraries/fltk/configure.ac @@ -766,7 +766,22 @@ AS_IF([test x$enable_localzlib != xyes], [ # but only, if the builtin lib is not requested syspnglib_ok=no syspnginc_ok=no -AS_IF([test x$enable_localpng != xyes], [ +AS_IF([test x$enable_localpng != xyes -a x$PKGCONFIG != x], [ + AC_MSG_CHECKING([for libpng-1.6.x]) + AS_IF([$PKGCONFIG --exists libpng16], [ + AC_MSG_RESULT([yes]) + AC_DEFINE([HAVE_PNG_H], 1, [Have PNG library?]) + syspnginc_ok=yes + syspnglib_ok=yes + PNGINC="$($PKGCONFIG --cflags libpng16)" + IMAGELIBS="$($PKGCONFIG --libs libpng16) $IMAGELIBS" + STATICIMAGELIBS="$($PKGCONFIG --libs libpng16) $STATICIMAGELIBS" + ], [ + AC_MSG_RESULT([no]) + ]) +]) + +AS_IF([test x$enable_localpng != xyes -a $syspnglib_ok = no], [ AC_CHECK_LIB([png], [png_read_info], [ AC_CHECK_HEADER([png.h], [ AC_DEFINE([HAVE_PNG_H]) @@ -1008,10 +1023,29 @@ AS_CASE([$host_os_gui], [cygwin* | mingw*], [ # MacOS X uses Cocoa for graphics. LIBS="$LIBS -framework Cocoa" - macosversion_maj=$(sw_vers -productVersion | cut -d. -f1) - AS_IF([test $macosversion_maj -ge 11], [ - LIBS="$LIBS -framework UniformTypeIdentifiers" - ]) + # Add weak-linked additional frameworks for increasingly high macOS versions + AC_LANG_PUSH([C]) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + #if __MAC_OS_X_VERSION_MAX_ALLOWED < 110000 + #error __MAC_OS_X_VERSION_MAX_ALLOWED < 110000 + #endif + ]], [[ + ]])], + [LIBS="$LIBS -weak_framework UniformTypeIdentifiers"], + []) + AC_COMPILE_IFELSE( + [AC_LANG_PROGRAM( + [[#include + #if __MAC_OS_X_VERSION_MAX_ALLOWED < 150000 + #error __MAC_OS_X_VERSION_MAX_ALLOWED < 150000 + #endif + ]], [[ + ]])], + [LIBS="$LIBS -weak_framework ScreenCaptureKit"], + []) + AC_LANG_POP([]) AS_IF([test x$have_pthread = xyes], [ AC_DEFINE([HAVE_PTHREAD]) diff --git a/libraries/fltk/documentation/.gitignore b/libraries/fltk/documentation/.gitignore deleted file mode 100644 index 44b0f2ba3c..0000000000 --- a/libraries/fltk/documentation/.gitignore +++ /dev/null @@ -1,45 +0,0 @@ -# -# Files to be ignored by Git (do not commit) -# - -# /documentation/ -.xvpics -blocks.0 -blocks.6 -blocks.z -checkers.0 -checkers.6 -checkers.z -copyright.dox -Doxybook -Doxyfile -fltk.0 -fltk.3 -fltk-config.0 -fltk-config.1 -fltk-config.z -fltk.d -fltk.pdf -fltk.z -fluid.0 -fluid.1 -fluid.z -generated.dox -html -latex -sudoku.0 -sudoku.6 -sudoku.z -*.bck -*.bak -*.log - -# /documentation/src/ -src/*.0 -src/*.1 -src/*.3 -src/*.6 -src/*.z -src/fltk-book.tex -src/fltk-book.tex.in -src/fltk-title.tex diff --git a/libraries/fltk/documentation/CMakeLists.txt b/libraries/fltk/documentation/CMakeLists.txt index cf9699449b..f93d0cba57 100644 --- a/libraries/fltk/documentation/CMakeLists.txt +++ b/libraries/fltk/documentation/CMakeLists.txt @@ -1,7 +1,7 @@ # # CMakeLists.txt to build docs for the FLTK project using CMake (www.cmake.org) # -# Copyright 1998-2023 by Bill Spitzak and others. +# Copyright 1998-2024 by Bill Spitzak and others. # # This library is free software. Distribution and use rights are outlined in # the file "COPYING" which should have been included with this file. If this @@ -16,7 +16,6 @@ set(DOCS) set(GENERATE_DOCS FALSE) -set(GIT_REVISION "") set(YEAR "") set(CURRENT_DATE "") @@ -49,28 +48,8 @@ if(GENERATE_DOCS) OUTPUT_STRIP_TRAILING_WHITESPACE ) - # find git revision - - # FIXME: This must also work with tarballs where git is not available. - # For now we just ignore errors and set GIT_REVISION = "unknown". - # In the future tarball/zip generation should create a file - # that contains the git revision. - - execute_process(COMMAND - git rev-parse --short=10 HEAD - OUTPUT_VARIABLE GIT_REVISION - OUTPUT_STRIP_TRAILING_WHITESPACE - WORKING_DIRECTORY ${FLTK_SOURCE_DIR} - ERROR_QUIET - ) - - # set to "'unknown'" if git is not available - if(GIT_REVISION STREQUAL "") - set(GIT_REVISION "'unknown'") - endif() - # Find "short" doxygen version if it was built from Git - # Note: this is still needed in CMake 3.12.0 but later CMake versions + # Note: this is still needed in CMake 3.15 but later CMake versions # (notably 3.25) remove the Git revision in 'DOXYGEN_VERSION'. # Todo: Find the "first good" CMake version and remove this redundant # code once we require this as our minimal version and replace the @@ -98,7 +77,7 @@ if(GENERATE_DOCS) if(0) # debug fl_debug_var(YEAR) fl_debug_var(CURRENT_DATE) - fl_debug_var(GIT_REVISION) + fl_debug_var(FLTK_GIT_REVISION) fl_debug_var(DOXYGEN_FOUND) fl_debug_var(DOXYGEN_EXECUTABLE) fl_debug_var(DOXYGEN_VERSION) @@ -182,6 +161,12 @@ if(FLTK_BUILD_PDF_DOCS) # convert Doxybook to current doxygen version + # set DOXY_VERSION for compatibility with configure/make, + # to be replaced in fltk-title.tex.in + # FIXME: this can be simplified when configure/make is no longer supported + + set(DOXY_VERSION "${DOXYGEN_VERSION_SHORT}") # + add_custom_command( OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/${DOXYFILE} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} diff --git a/libraries/fltk/documentation/Makefile b/libraries/fltk/documentation/Makefile index 6760e4622e..972c1b791e 100644 --- a/libraries/fltk/documentation/Makefile +++ b/libraries/fltk/documentation/Makefile @@ -55,6 +55,17 @@ MANPAGES = $(SRC_DOCDIR)/fltk.$(CAT3EXT) $(SRC_DOCDIR)/fltk-config.$(CAT1EXT) \ $(SRC_DOCDIR)/checkers.$(CAT6EXT) $(SRC_DOCDIR)/sudoku.$(CAT6EXT) \ $(SRC_DOCDIR)/fltk-options.$(CAT1EXT) +# Get FLTK's Git Revision either from Git /or/ from fltk_git_rev.dat (Issue #499) +# +# Note: this may fail (return "unknown") if the sources were downloaded +# from GitHub as a "release" (zip) archive. This is not supported. + +# Test/debug only: should be commented out unless used (see: debug_git_rev) +# GIT_REV_FROM_GIT := "$$(git rev-parse HEAD 2>/dev/null)" +# GIT_REV_FROM_FILE := "$$(cat ../fltk_git_rev.dat 2>/dev/null)" + +FLTK_GIT_REVISION := "`( (git rev-parse HEAD || cat ../fltk_git_rev.dat;) || echo 'unknown'; ) 2>/dev/null`" + all: $(MANPAGES) # Use `make docs' to create all docs for distribution files. @@ -67,6 +78,11 @@ docs: all html pdf alldocs: docs dist: docs +debug_git_rev: + # echo "GIT_REV_FROM_GIT = $(GIT_REV_FROM_GIT)" + # echo "GIT_REV_FROM_FILE = $(GIT_REV_FROM_FILE)" + echo "FLTK_GIT_REVISION = $(FLTK_GIT_REVISION)" + clean: $(RM) Doxyfile Doxybook $(RM) copyright.dox generated.dox @@ -79,59 +95,59 @@ depend: install: $(MANPAGES) echo "Installing documentation files in $(DESTDIR)$(docdir) ..." - -$(INSTALL_DIR) $(DESTDIR)$(docdir) + -$(INSTALL_DIR) "$(DESTDIR)$(docdir)" if test -f html/index.html ; then \ for file in html/* ; do \ - $(INSTALL_DATA) $$file $(DESTDIR)$(docdir); \ + $(INSTALL_DATA) $$file "$(DESTDIR)$(docdir)"; \ done \ fi if test -f fltk.pdf ; then \ echo "Installing fltk.pdf in $(DESTDIR)$(docdir) ..."; \ - $(INSTALL_DATA) fltk.pdf $(DESTDIR)$(docdir); \ + $(INSTALL_DATA) fltk.pdf "$(DESTDIR)$(docdir)"; \ fi echo "Installing man pages in $(DESTDIR)$(mandir) ..." - -$(INSTALL_DIR) $(DESTDIR)$(mandir)/cat1 - $(INSTALL_MAN) $(SRC_DOCDIR)/fluid.$(CAT1EXT) $(DESTDIR)$(mandir)/cat1 - $(INSTALL_MAN) $(SRC_DOCDIR)/fltk-config.$(CAT1EXT) $(DESTDIR)$(mandir)/cat1 - $(INSTALL_MAN) $(SRC_DOCDIR)/fltk-options.$(CAT1EXT) $(DESTDIR)$(mandir)/cat1 - -$(INSTALL_DIR) $(DESTDIR)$(mandir)/cat3 - $(INSTALL_MAN) $(SRC_DOCDIR)/fltk.$(CAT3EXT) $(DESTDIR)$(mandir)/cat3 - -$(INSTALL_DIR) $(DESTDIR)$(mandir)/man1 - $(INSTALL_MAN) $(SRC_DOCDIR)/fluid.man $(DESTDIR)$(mandir)/man1/fluid.1 - $(INSTALL_MAN) $(SRC_DOCDIR)/fltk-config.man $(DESTDIR)$(mandir)/man1/fltk-config.1 - $(INSTALL_MAN) $(SRC_DOCDIR)/fltk-options.man $(DESTDIR)$(mandir)/man1/fltk-options.1 - -$(INSTALL_DIR) $(DESTDIR)$(mandir)/man3 - $(INSTALL_MAN) $(SRC_DOCDIR)/fltk.man $(DESTDIR)$(mandir)/man3/fltk.3 + -$(INSTALL_DIR) "$(DESTDIR)$(mandir)/cat1" + $(INSTALL_MAN) $(SRC_DOCDIR)/fluid.$(CAT1EXT) "$(DESTDIR)$(mandir)/cat1" + $(INSTALL_MAN) $(SRC_DOCDIR)/fltk-config.$(CAT1EXT) "$(DESTDIR)$(mandir)/cat1" + $(INSTALL_MAN) $(SRC_DOCDIR)/fltk-options.$(CAT1EXT) "$(DESTDIR)$(mandir)/cat1" + -$(INSTALL_DIR) "$(DESTDIR)$(mandir)/cat3" + $(INSTALL_MAN) $(SRC_DOCDIR)/fltk.$(CAT3EXT) "$(DESTDIR)$(mandir)/cat3" + -$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man1" + $(INSTALL_MAN) $(SRC_DOCDIR)/fluid.man "$(DESTDIR)$(mandir)/man1/fluid.1" + $(INSTALL_MAN) $(SRC_DOCDIR)/fltk-config.man "$(DESTDIR)$(mandir)/man1/fltk-config.1" + $(INSTALL_MAN) $(SRC_DOCDIR)/fltk-options.man "$(DESTDIR)$(mandir)/man1/fltk-options.1" + -$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man3" + $(INSTALL_MAN) $(SRC_DOCDIR)/fltk.man "$(DESTDIR)$(mandir)/man3/fltk.3" install-linux install-osx: - -$(INSTALL_DIR) $(DESTDIR)$(mandir)/cat6 - $(INSTALL_MAN) $(SRC_DOCDIR)/blocks.$(CAT6EXT) $(DESTDIR)$(mandir)/cat6 - $(INSTALL_MAN) $(SRC_DOCDIR)/checkers.$(CAT6EXT) $(DESTDIR)$(mandir)/cat6 - $(INSTALL_MAN) $(SRC_DOCDIR)/sudoku.$(CAT6EXT) $(DESTDIR)$(mandir)/cat6 - -$(INSTALL_DIR) $(DESTDIR)$(mandir)/man6 - $(INSTALL_MAN) $(SRC_DOCDIR)/blocks.man $(DESTDIR)$(mandir)/man6/blocks.6 - $(INSTALL_MAN) $(SRC_DOCDIR)/checkers.man $(DESTDIR)$(mandir)/man6/checkers.6 - $(INSTALL_MAN) $(SRC_DOCDIR)/sudoku.man $(DESTDIR)$(mandir)/man6/sudoku.6 + -$(INSTALL_DIR) "$(DESTDIR)$(mandir)/cat6" + $(INSTALL_MAN) $(SRC_DOCDIR)/blocks.$(CAT6EXT) "$(DESTDIR)$(mandir)/cat6" + $(INSTALL_MAN) $(SRC_DOCDIR)/checkers.$(CAT6EXT) "$(DESTDIR)$(mandir)/cat6" + $(INSTALL_MAN) $(SRC_DOCDIR)/sudoku.$(CAT6EXT) "$(DESTDIR)$(mandir)/cat6" + -$(INSTALL_DIR) "$(DESTDIR)$(mandir)/man6" + $(INSTALL_MAN) $(SRC_DOCDIR)/blocks.man "$(DESTDIR)$(mandir)/man6/blocks.6" + $(INSTALL_MAN) $(SRC_DOCDIR)/checkers.man "$(DESTDIR)$(mandir)/man6/checkers.6" + $(INSTALL_MAN) $(SRC_DOCDIR)/sudoku.man "$(DESTDIR)$(mandir)/man6/sudoku.6" uninstall: - $(RMDIR) $(DESTDIR)$(docdir) - $(RM) $(DESTDIR)$(mandir)/cat1/fluid.$(CAT1EXT) - $(RM) $(DESTDIR)$(mandir)/man1/fluid.1 - $(RM) $(DESTDIR)$(mandir)/cat1/fltk-config.$(CAT1EXT) - $(RM) $(DESTDIR)$(mandir)/man1/fltk-config.1 - $(RM) $(DESTDIR)$(mandir)/cat1/fltk-options.$(CAT1EXT) - $(RM) $(DESTDIR)$(mandir)/man1/fltk-options.1 - $(RM) $(DESTDIR)$(mandir)/cat3/fltk.$(CAT3EXT) - $(RM) $(DESTDIR)$(mandir)/man3/fltk.3 + $(RMDIR) "$(DESTDIR)$(docdir)" + $(RM) "$(DESTDIR)$(mandir)/cat1/fluid.$(CAT1EXT)" + $(RM) "$(DESTDIR)$(mandir)/man1/fluid.1" + $(RM) "$(DESTDIR)$(mandir)/cat1/fltk-config.$(CAT1EXT)" + $(RM) "$(DESTDIR)$(mandir)/man1/fltk-config.1" + $(RM) "$(DESTDIR)$(mandir)/cat1/fltk-options.$(CAT1EXT)" + $(RM) "$(DESTDIR)$(mandir)/man1/fltk-options.1" + $(RM) "$(DESTDIR)$(mandir)/cat3/fltk.$(CAT3EXT)" + $(RM) "$(DESTDIR)$(mandir)/man3/fltk.3" uninstall-linux uninstall-osx: - $(RM) $(DESTDIR)$(mandir)/cat6/blocks.$(CAT6EXT) - $(RM) $(DESTDIR)$(mandir)/cat6/checkers.$(CAT6EXT) - $(RM) $(DESTDIR)$(mandir)/cat6/sudoku.$(CAT6EXT) - $(RM) $(DESTDIR)$(mandir)/man6/blocks.6 - $(RM) $(DESTDIR)$(mandir)/man6/checkers.6 - $(RM) $(DESTDIR)$(mandir)/man6/sudoku.6 + $(RM) "$(DESTDIR)$(mandir)/cat6/blocks.$(CAT6EXT)" + $(RM) "$(DESTDIR)$(mandir)/cat6/checkers.$(CAT6EXT)" + $(RM) "$(DESTDIR)$(mandir)/cat6/sudoku.$(CAT6EXT)" + $(RM) "$(DESTDIR)$(mandir)/man6/blocks.6" + $(RM) "$(DESTDIR)$(mandir)/man6/checkers.6" + $(RM) "$(DESTDIR)$(mandir)/man6/sudoku.6" # The documentation is generated using doxygen. There are two control files # for doxygen: Doxyfile for html documentation and Doxybook for pdf docs. @@ -203,8 +219,7 @@ refman.pdf: $(HTMLFILES) Doxybook src/fltk-book.tex src/fltk-title.tex: src/fltk-title.tex.in echo "Generating $@ ..." - GIT_REVISION=`git rev-parse --short=10 HEAD`; \ - sed -e"s/@GIT_REVISION@/$$GIT_REVISION/g" \ + sed -e"s/@FLTK_GIT_REVISION@/$(FLTK_GIT_REVISION)/g" \ < $< > $@ src/fltk-book.tex.in: src/fltk-title.tex @@ -223,10 +238,9 @@ src/fltk-book.tex: src/fltk-book.tex.in generated.dox: generated.dox.in echo "Generating $@ ..." CURRENT_DATE=`date "+%b %d, %Y"`; \ - GIT_REVISION=`git rev-parse --short=10 HEAD`; \ DOXYGEN_VERSION_SHORT=`"$(DOXYDOC)" --version|cut -f1 -d' '`; \ sed -e"s/@CURRENT_DATE@/$$CURRENT_DATE/g" \ - -e"s/@GIT_REVISION@/$$GIT_REVISION/g" \ + -e"s/@FLTK_GIT_REVISION@/$(FLTK_GIT_REVISION)/g" \ -e"s/@DOXYGEN_VERSION_SHORT@/$$DOXYGEN_VERSION_SHORT/g" \ < $< > $@ diff --git a/libraries/fltk/documentation/README.txt b/libraries/fltk/documentation/README.txt index bcd9459b99..7871737a57 100644 --- a/libraries/fltk/documentation/README.txt +++ b/libraries/fltk/documentation/README.txt @@ -18,7 +18,7 @@ Online Documentation (Latest Release): A documentation version is available online at the FLTK web site, along with the PDF version of the manual. The docs on the web site are usually somewhat older (latest release). The active development -version (currently 1.4.0) is updated from time to time. +version is updated from time to time. Use this URL to find the current online documentation: diff --git a/libraries/fltk/documentation/generated.dox.in b/libraries/fltk/documentation/generated.dox.in index 9ab6987e03..fc6afa0091 100644 --- a/libraries/fltk/documentation/generated.dox.in +++ b/libraries/fltk/documentation/generated.dox.in @@ -1,6 +1,6 @@
    Generated on @CURRENT_DATE@ - from Git revision @GIT_REVISION@ - by Doxygen @DOXYGEN_VERSION_SHORT@ + from Git revision @FLTK_GIT_REVISION@ + by Doxygen version @DOXYGEN_VERSION_SHORT@ diff --git a/libraries/fltk/documentation/src/basics.dox b/libraries/fltk/documentation/src/basics.dox index e875108ab6..8e6a350fde 100644 --- a/libraries/fltk/documentation/src/basics.dox +++ b/libraries/fltk/documentation/src/basics.dox @@ -395,7 +395,7 @@ fltk-config --use-forms --use-gl --use-images --compile filename.cpp Before version 1.4.0 \p fltk-config accepted only a single source file and no additional compiler options or libraries. -As of FLTK 1.4.0 it is possible to use additional compiler flags, more than +Since FLTK 1.4.0 it is possible to use additional compiler flags, more than one source file, and additional link libraries. This is intended to be used for quick prototyping and not for production code diff --git a/libraries/fltk/documentation/src/common.dox b/libraries/fltk/documentation/src/common.dox index c8536e0959..dc8843eeeb 100644 --- a/libraries/fltk/documentation/src/common.dox +++ b/libraries/fltk/documentation/src/common.dox @@ -130,8 +130,16 @@ with FLTK: \li Fl_Double_Window - A double-buffered window on the screen. +\li Fl_Flex - A flexible container of one row or column of widgets. + Fl_Flex widgets may be nested, but see also Fl_Grid. + \li Fl_Gl_Window - An OpenGL window on the screen. +\li Fl_Grid - A flexible container of one or more rows and columns of widgets + arranged in a "grid" with auto-layout features. Fl_Grid widgets can be nested + with other Fl_Grid or many Fl_Group type widgets. Nesting with other self-resizing + containers like Fl_Pack and Fl_Tile is not recommended but \b may work. + \li Fl_Group - The base container class; can be used to group any widgets together. @@ -150,8 +158,7 @@ with FLTK: \section common_sizeposition Setting the Size and Position of Widgets The size and position of widgets is usually set when you create them. -You can access them with the \p x(), \p y(), \p w(), and \p h() -methods. +You can access them with the \p x(), \p y(), \p w(), and \p h() methods. You can change the size and position by using the \p position(), \p resize(), and \p size() methods: @@ -421,9 +428,9 @@ The following standard label types are included: the widget's align() flag. FL_MULTI_LABEL was designed to be used with Fl_Menu_Item's to support icons or small images, typically left of the menu text.\n - As of this writing (FLTK 1.4.0, Sep 2017) Fl_Menu_Items support only - one label part (text \b or image), but using Fl_Multi_Label as the - label can extend this to more than one part. + As of this writing (FLTK 1.4.0) Fl_Menu_Items support only one label + part (text \b or image), but using Fl_Multi_Label as the label can extend + this to more than one part. \see class Fl_Multi_Label, Fl_Widget::align() diff --git a/libraries/fltk/documentation/src/development.dox b/libraries/fltk/documentation/src/development.dox index 89d67f4315..4b976d1832 100644 --- a/libraries/fltk/documentation/src/development.dox +++ b/libraries/fltk/documentation/src/development.dox @@ -117,9 +117,14 @@ These comments will not be visible in the generated document. will be shown as: - The following text is a developer comment. - - This will be visible again. + The following text is a developer comment. + + This will be visible again. + +\note Since an unknown Doxygen version indentation by four or more bytes + is automatically displayed as if it was framed by \\code and \\endcode. + You need to take care that "normal" text is not indented that much to + avoid mis-interpretation and formatting as code.

    Different Headlines

    @@ -131,29 +136,29 @@ there seems to be no difference in the font sizes of \

    and \

    in the pdf output, whereas the html output uses different font sizes. \code -

    Headline in big text (H1)

    -

    Headline in big text (H2)

    -

    Headline in big text (H3)

    -

    Headline in big text (H4)

    +

    Headline in big text (H1)

    +

    Headline in big text (H2)

    +

    Headline in big text (H3)

    +

    Headline in big text (H4)

    \endcode -

    Headline in big text (H1)

    -

    Headline in big text (H2)

    -

    Headline in big text (H3)

    -

    Headline in big text (H4)

    +

    Headline in big text (H1)

    +

    Headline in big text (H2)

    +

    Headline in big text (H3)

    +

    Headline in big text (H4)

    \section development_non_ascii Non-ASCII Characters \code - Doxygen understands many HTML quoting characters like - ", ü, ç, Ç, but not all HTML quoting characters. + Doxygen understands many HTML quoting characters like + ", ü, ç, Ç, but not all HTML quoting characters. \endcode This will appear in the document: - Doxygen understands many HTML quoting characters like - ", ü, ç, Ç, but not all HTML quoting characters. + Doxygen understands many HTML quoting characters like + ", ü, ç, Ç, but not all HTML quoting characters. For further informations about HTML quoting characters see
    \b http://www.doxygen.org/manual/htmlcmds.html @@ -190,18 +195,18 @@ links \b from normal (e.g. class) documentation \b to documentation sections This page has \code - \page development I - Developer Information + \page development Developer Information \endcode at its top. This section is \code - \section development_structure Document Structure + \section development_structure Document Structure \endcode The following section is \code - \section development_links Creating Links + \section development_links Creating Links \endcode @@ -307,7 +312,9 @@ Each introduction (tutorial) page ends with navigation elements. These elements must only be included in the html documentation, therefore they must be separated with \\htmlonly and \\endhtmlonly. -The following code gives the navigation bar at the bottom of this page: +The following code creates the navigation bar at the bottom of the +\ref basics HTML page as an example of all pages in the "FLTK Programming Manual" +section. Note that \b this \b page is one of the appendices w/o navigation bar. \verbatim \htmlonly @@ -315,17 +322,17 @@ The following code gives the navigation bar at the bottom of this page: @@ -334,28 +341,4 @@ The following code gives the navigation bar at the bottom of this page: \endhtmlonly \endverbatim - -\htmlonly -
    -
    - + [Prev] - Migrating Code from FLTK 1.3 to 1.4 + Introduction to FLTK [Index] - - Software License + + Common Widgets and Attributes [Next]
    - - - - - -
    - - [Prev] - Migrating Code from FLTK 1.3 to 1.4 - - - [Index] - - - Software License - [Next] - -
    -\endhtmlonly - */ diff --git a/libraries/fltk/documentation/src/drawing.dox b/libraries/fltk/documentation/src/drawing.dox index 89b1a68309..42f313e513 100644 --- a/libraries/fltk/documentation/src/drawing.dox +++ b/libraries/fltk/documentation/src/drawing.dox @@ -125,6 +125,7 @@ header file. FLTK provides the following types of drawing functions: \li \ref drawing_boxes \li \ref drawing_clipping \li \ref drawing_colors +\li \ref drawing_contrast \li \ref drawing_lines \li \ref drawing_fast \li \ref drawing_complex @@ -370,25 +371,78 @@ button->color(0xffffff00); // RGB: white If TrueColor is not available, any RGB colors will be set to the nearest entry in the colormap. + +\subsection drawing_contrast Color Contrast + +Although these are not real "drawing" functions, creating readable contrast is +essential in a good GUI design. FLTK tries to help with this by providing +fl_contrast() and related functions. + +The basic function is Fl_Color fl_contrast(Fl_Color fg, Fl_Color bg, int context, int size); + +The parameters \c context and \c size are optional and reserved for future use +(since FLTK 1.4.0). + +The return value can be used to substitute the foreground color \c fg used for drawing +(usually the "text" or "label" color) on a particular background color \c bg with +either black (FL_BLACK) or white (FL_WHITE). This is useful if the background color +is not known or can be changed by the user or a system "theme". + +FLTK calculates the contrast between \c fg and \c bg and returns the same color +(\c fg) if the contrast is considered sufficient or one of FL_BLACK or FL_WHITE +if the contrast of the given foreground color would be insufficient. Then +either FL_BLACK or FL_WHITE is chosen, whichever has the higher contrast with +the background color. + +Example, may be used in a widget's draw() method: + + \code + Fl_Color bg = color(); // background color of the widget + Fl_Color fg = FL_BLUE; // the chosen foreground (drawing) color + fl_color(fl_contrast(fg, bg)); // set the drawing color + fl_rect(..); // draw a rectangle with sufficient contrast + \endcode + +FLTK 1.4.0 introduced a new contrast algorithm which is superior to the one +used up to FLTK 1.3.x. You can use + + fl_contrast_mode(FL_CONTRAST_LEGACY); + +early in your program to select the old behavior if you really need strict backwards +compatibility. This is discouraged because the new algorithm is much better with +regard to human contrast perception. The default mode since FLTK 1.4.0 is + + fl_contrast_mode(FL_CONTRAST_CIELAB); + +For more info please see the linked documentation of these functions. + +Additionally the old and new contrast calculations can be fine tuned with the new +function (since 1.4.0) + + fl_contrast_level(int level); + +This is not recommended but can be useful for some border cases. Please refer to +the documentation of fl_contrast_level(). + +Finally, developers can define their own contrast calculation function with + + void fl_contrast_function(Fl_Contrast_Function *f); + +Please see the documentation for details. + + \subsection drawing_lines Line Dashes and Thickness -FLTK supports drawing of lines with different styles and -widths. Full functionality is not available under Windows 95, 98, -and Me due to the reduced drawing functionality these operating -systems provide. +FLTK supports drawing of lines with different styles and widths. -void fl_line_style(int style, int width, char* dashes) + void fl_line_style(int style, int width, char* dashes) -\par -Set how to draw lines (the "pen"). If you change this it is your -responsibility to set it back to the default with -\p fl_line_style(0). + \image html fl_line_style.png "fl_line_style() styles" + \image latex fl_line_style.png "fl_line_style() styles" width=12cm \par -\b Note: -Because of how line styles are implemented on Windows systems, you \e must -set the line style \e after setting the drawing color. If you set the -color after the line style you will lose the line style settings! +Set how to draw lines (the "pen"). If you change this it is your +responsibility to set it back to the default with \p fl_line_style(0). \par \p style is a bitmask which is a bitwise-OR of the following @@ -397,17 +451,17 @@ line. If you don't specify a cap or join type you will get a system-defined default of whatever value is fastest. \par -\li FL_SOLID      ------- -\li FL_DASH       - - - - -\li FL_DOT        ....... -\li FL_DASHDOT    - . - . -\li FL_DASHDOTDOT - .. - -\li FL_CAP_FLAT -\li FL_CAP_ROUND -\li FL_CAP_SQUARE (extends past end point 1/2 line width) -\li FL_JOIN_MITER (pointed) -\li FL_JOIN_ROUND -\li FL_JOIN_BEVEL (flat) +\li FL_SOLID solid line +\li FL_DASH 75% dashed line +\li FL_DOT 50% pixel dotted +\li FL_DASHDOT dash / dot pattern +\li FL_DASHDOTDOT dash / two dot pattern +\li FL_CAP_FLAT end is flat +\li FL_CAP_ROUND end is round +\li FL_CAP_SQUARE extends past end point 1/2 line width +\li FL_JOIN_MITER line join extends to a point +\li FL_JOIN_ROUND line join is rounded +\li FL_JOIN_BEVEL line join is flat (tidied) \par \p width is the number of \ref drawing_DrawingUnit "FLTK units" thick to draw the lines. @@ -422,10 +476,18 @@ terminated with a zero-length entry. A \p NULL pointer or a zero-length array results in a solid line. Odd array sizes are not supported and result in undefined behavior. + +\note +- Full functionality is not available under Windows 95, 98, and Me due to + the reduced drawing functionality these operating systems provide. +- Because of how line styles are implemented on Windows systems, you \e must + set the line style \e after setting the drawing color. If you set the + color after the line style you will lose the line style settings! +- The dashes array does not work under Windows 95, 98, or Me, since those + operating systems do not support complex line styles. \subsection drawing_fast Drawing Fast Shapes @@ -713,7 +775,7 @@ void fl_rtl_draw(const char *str, int n, int x, int y) \par Draw a UTF-8 string of length n bytes right to left starting at the given x, y location. -void fl_draw(const char* str, int x, int y, int w, int h, Fl_Align align, Fl_Image* img, int draw_symbols) +void fl_draw(const char* str, int x, int y, int w, int h, Fl_Align align, Fl_Image* img, int draw_symbols, int spacing) \par Fancy string drawing function which is used to draw all the @@ -723,7 +785,7 @@ characters to ^X, and aligns inside or against the edges of the box described by \p x, \p y, \p w and \p h. See Fl_Widget::align() for values for \p align. The value \p FL_ALIGN_INSIDE is ignored, as this function always -prints inside the box. +prints inside the box. Parameter \p spacing controls the space between text and image. \par If \p img is provided and is not \p NULL, the diff --git a/libraries/fltk/documentation/src/editor.dox b/libraries/fltk/documentation/src/editor.dox index 299af9ff67..fb93e63b7e 100644 --- a/libraries/fltk/documentation/src/editor.dox +++ b/libraries/fltk/documentation/src/editor.dox @@ -979,7 +979,7 @@ set correctly. Lastly, we add a menu item with a callback. app_window->end(); app_window->resizable(app_tile); app_tile->resizable(app_editor); - app_menu_bar->add("Window/Split", FL_COMMAND+'2', menu_split_callback, NULL, FL_MENU_TOGGLE); + app_menu_bar->add("Window/Split", FL_COMMAND+'i', menu_split_callback, NULL, FL_MENU_TOGGLE); } \endcode diff --git a/libraries/fltk/documentation/src/enumerations.dox b/libraries/fltk/documentation/src/enumerations.dox index 889be58bea..e9e7e87b53 100644 --- a/libraries/fltk/documentation/src/enumerations.dox +++ b/libraries/fltk/documentation/src/enumerations.dox @@ -95,9 +95,11 @@ The following constants determine when a callback is performed: The following constants define the button numbers for FL_PUSH and FL_RELEASE events: - - FL_LEFT_MOUSE - the left mouse button - - FL_MIDDLE_MOUSE - the middle mouse button - - FL_RIGHT_MOUSE - the right mouse button + - FL_LEFT_MOUSE - the left mouse button + - FL_MIDDLE_MOUSE - the middle mouse button + - FL_RIGHT_MOUSE - the right mouse button + - FL_BACK_MOUSE - the back mouse button (side button 1) + - FL_FORWARD_MOUSE - the forward mouse button (side button 2) \section enumerations_event_key Fl::event_key() Values @@ -140,6 +142,7 @@ FL_KEYBOARD and FL_SHORTCUT events: - FL_Alt_L - The left alt key. - FL_Alt_R - The right alt key. - FL_Delete - The delete key. + - FL_Alt_Gr - The AltGr key on some international keyboards. \section enumerations_event_state Fl::event_state() Values @@ -161,7 +164,9 @@ value: - FL_BUTTON1 - Mouse button 1 is pushed. - FL_BUTTON2 - Mouse button 2 is pushed. - FL_BUTTON3 - Mouse button 3 is pushed. - - FL_BUTTONS - Any mouse button is pushed. + - FL_BUTTON4 - Mouse button 4 (back) is pushed. + - FL_BUTTON5 - Mouse button 5 (forward) is pushed. + - FL_BUTTONS - Any mouse button (1..5) is pushed. - FL_BUTTON(n) - Mouse button \p n ( where n > 0) is pushed. \section enumerations_alignment Alignment Values diff --git a/libraries/fltk/documentation/src/events.dox b/libraries/fltk/documentation/src/events.dox index 8ac2747dcb..9ca663a74e 100644 --- a/libraries/fltk/documentation/src/events.dox +++ b/libraries/fltk/documentation/src/events.dox @@ -23,7 +23,7 @@ This static information remains valid until the next event is read from the window system, so it is ok to look at it outside of the \p handle() -method. +method, for instance in a callback. Event numbers can be converted to their actual names using the \ref fl_eventnames[] array defined in \#include <FL/names.h>; see next chapter for details. @@ -36,6 +36,40 @@ method to accept and process specific events. \section events_mouse Mouse Events +Classic mice provide two or three buttons: + - a primary (left) button, typically used to point and click on objects + - a secondary (right) button, typically used to open special menus etc. + - a middle button for other special events. + +The primary and secondary mouse buttons can usually be inverted by system +setup functions for left handed usage. FLTK always sends the mouse button +number according to the "logical" mouse button, i.e. such a setup is +transparent for application programmers. + +The middle button was later replaced by a scroll wheel to allow scrolling +text or other objects in a window or widget vertically. Pushing the scroll +wheel down acts like pushing the middle mouse button. + +If the scroll wheel is used to scroll while the Shift key is held, the +scrolling direction is horizontal rather than vertical. + +Some mice may even have a "scroll ball" or similar (touch) feature. These +mice support horizontal and vertical scrolling simultaneously. + +Newer mice add even more buttons, called "side buttons": + - a "back" button, typically used to "go back", e.g. in browsers + - a "forward" button, typically used to "go forward", e.g. in browsers + +FLTK handles up to five buttons since version 1.4.0 across all supported +platforms. Note that Windows doesn't support more than five buttons +whereas other platforms may support more. FLTK ignores other buttons as +long as they send "mouse button" events. + +Some gaming mice with five or more buttons may send their button clicks +as keyboard events which will be handled like normal text input by FLTK. +This has not been tested though. + + \subsection events_fl_push FL_PUSH A mouse button has gone down with the mouse pointing at this @@ -63,7 +97,7 @@ another widget. \subsection events_fl_drag FL_DRAG -The mouse has moved with a button held down. The current +The mouse has moved with at least one button held down. The current button state is in Fl::event_state(). The mouse position is in @@ -74,6 +108,22 @@ Fl::event_y(). In order to receive \p FL_DRAG events, the widget must return non-zero when handling \p FL_PUSH. +Moving the mouse keeps sending FL_DRAG events as long as at least one +button is held down. If any buttons are pushed and released during the +drag operation FLTK sends FL_PUSH and FL_RELEASE events even while dragging. +The current button status can be found in Fl::event_state() and in +Fl::event_buttons(). + +When the last button has been released FLTK sends FL_MOVE events again. +Note: The button released last need not necessarily be the one that +started the drag operation. + +Since FLTK 1.4.0 dragging is supported for all five supported mouse buttons, +for instance the user can drag the mouse while the "back" button is held down. +Warning: This may or may not be compatible with other applications for +drag-and-drop operations \b between applications and lead to unexpected behavior. + + \subsection events_fl_release FL_RELEASE A mouse button has been released. You can find out what button by calling @@ -82,6 +132,7 @@ Fl::event_button(). In order to receive the \p FL_RELEASE event, the widget must return non-zero when handling \p FL_PUSH. + \subsection events_fl_move FL_MOVE The mouse has moved without any mouse buttons held down. @@ -92,14 +143,17 @@ widget. In order to receive \p FL_MOVE events, the widget must return non-zero when handling \p FL_ENTER. + \subsection events_fl_mousewheel FL_MOUSEWHEEL The user has moved the mouse wheel. The Fl::event_dx() and Fl::event_dy() -methods can be used to find the amount to scroll horizontally and -vertically. +methods can be used to find the amount to scroll horizontally (dx) and +vertically (dy). On mice with a single scroll wheel holding the Shift key +on the keyboard while scrolling sends horizontal scroll events. + \section events_focus Focus Events diff --git a/libraries/fltk/documentation/src/examples.dox b/libraries/fltk/documentation/src/examples.dox index 992b855233..0bca5dcddb 100644 --- a/libraries/fltk/documentation/src/examples.dox +++ b/libraries/fltk/documentation/src/examples.dox @@ -36,86 +36,87 @@ you build FLTK, unlike those in the 'test' directory shown below. \ref examples_checkers + \ref examples_clipboard \ref examples_clock \ref examples_colbrowser \ref examples_color_chooser \ref examples_cube \ref examples_CubeView - \ref examples_cursor + \ref examples_cursor \ref examples_curve \ref examples_demo \ref examples_device \ref examples_doublebuffer \ref examples_editor - \ref examples_fast_slow + \ref examples_fast_slow \ref examples_file_chooser \ref examples_fluid \ref examples_fonts \ref examples_forms \ref examples_fractals - \ref examples_fullscreen + \ref examples_fullscreen \ref examples_gl_overlay \ref examples_glpuzzle \ref examples_hello \ref examples_help_dialog \ref examples_icon - \ref examples_iconize + \ref examples_iconize \ref examples_image \ref examples_inactive \ref examples_input \ref examples_input_choice \ref examples_keyboard - \ref examples_label + \ref examples_label \ref examples_line_style \ref examples_list_visuals \ref examples_mandelbrot \ref examples_menubar \ref examples_message - \ref examples_minimum + \ref examples_minimum \ref examples_native-filechooser \ref examples_navigation \ref examples_offscreen \ref examples_output \ref examples_overlay - \ref examples_pack + \ref examples_pack \ref examples_pixmap \ref examples_pixmap_browser \ref examples_preferences \ref examples_radio \ref examples_resize - \ref examples_resizebox + \ref examples_resizebox \ref examples_rotated_text \ref examples_scroll \ref examples_shape \ref examples_subwindow \ref examples_sudoku - \ref examples_symbols + \ref examples_symbols \ref examples_table \ref examples_tabs \ref examples_threads \ref examples_tile \ref examples_tiled_image - \ref examples_tree + \ref examples_tree \ref examples_twowin \ref examples_unittests \ref examples_utf8 @@ -204,7 +205,8 @@ The \c button test is a simple demo of push-buttons and callbacks. \par \c cairo_test shows a sample of drawing with Cairo in an Fl_Cairo_Window. -This program can only be built if FLTK was configured with Cairo support. +This program can only be built completely if FLTK was configured with Cairo +support. It displays a message box if Cairo support was not included. \subsection examples_checkers checkers @@ -217,6 +219,16 @@ pieces, and how the pieces are drawn by layering. Then tell me how to beat the computer at Checkers. +\subsection examples_clipboard clipboard + +\par +The \c clipboard demo can be used to view the contents of the +system clipboard, either text or image contents. Currently an +image is preferred if the clipboard contains both formats. +Images can be stored as PNG files so screenshots can be +stored on disk with this little FLTK demo program. + + \subsection examples_clock clock \par @@ -273,9 +285,8 @@ on few systems (some version of Irix for example). \subsection examples_demo demo \par -This tool allows quick access to all programs in the \c test directory. -\c demo is based on the visuals of the IrixGL demo program. The menu -tree can be changed by editing test/demo.menu. +This tool allows quick access to most programs in the \c test directory. +The menu tree can be changed by editing test/demo.menu. \subsection examples_device device @@ -283,9 +294,9 @@ tree can be changed by editing test/demo.menu. \par Exercises the Fl_Image_Surface, Fl_Copy_Surface, and Fl_Printer classes to draw to an Fl_Image object, copy graphical data to the clipboard, and for print support. -\note The clipboard.cxx program of the 'examples' directory is a clipboard watching +\note The clipboard.cxx program of the 'test' directory is a clipboard watching application that continuously displays the textual or graphical content of the system -clipboard (a.k.a pasteboard on Mac OS X) exercising Fl::paste(). +clipboard (a.k.a pasteboard on macOS) exercising Fl::paste(). \subsection examples_doublebuffer doublebuffer @@ -307,6 +318,7 @@ and derived classes are rather light weight, however Fl_Text_Editor is a complete port of nedit (with permission). The \c editor test is almost a full application, showing custom syntax highlighting and dialog creation. +See chapter \ref editor for a tutorial about creating this program. \subsection examples_fast_slow fast_slow @@ -795,7 +807,7 @@ image drawing example: [Index] - + Frequently Asked Questions [Next] diff --git a/libraries/fltk/documentation/src/fl_line_style.png b/libraries/fltk/documentation/src/fl_line_style.png new file mode 100644 index 0000000000..eab01492cd Binary files /dev/null and b/libraries/fltk/documentation/src/fl_line_style.png differ diff --git a/libraries/fltk/documentation/src/fltk-title.tex.in b/libraries/fltk/documentation/src/fltk-title.tex.in index c4c7c18139..cc7f853c96 100644 --- a/libraries/fltk/documentation/src/fltk-title.tex.in +++ b/libraries/fltk/documentation/src/fltk-title.tex.in @@ -11,7 +11,7 @@ \end{DoxyImageNoCaption}\\ \vspace*{2cm} {\Large -By F. Costantini, D. Gibson, M. Melcher, \\ +By F. Costantini, M. Melcher, \\ A. Schlosser, B. Spitzak, and M. Sweet.}\\ \vspace*{1.5cm} {\large Copyright © 1998 - @YEAR@ by Bill Spitzak and others.}\\ @@ -27,7 +27,7 @@ provided this copyright and permission notice are preserved.}\\ \vspace*{0.5cm} \today{}\\ \vspace*{0.5cm} -{\small Git revision @GIT_REVISION@}\\ +{\small Git revision @FLTK_GIT_REVISION@}\\ \end{center} \end{titlepage} % diff --git a/libraries/fltk/documentation/src/forms.dox b/libraries/fltk/documentation/src/forms.dox index 1aa1571d50..816da55e67 100644 --- a/libraries/fltk/documentation/src/forms.dox +++ b/libraries/fltk/documentation/src/forms.dox @@ -5,16 +5,25 @@ This appendix describes the Forms compatibility included with FLTK. -
    - - - - -
    -Warning: The Forms compatibility is deprecated and no longer maintained -since FLTK 1.3.0 and is likely to be removed completely in FLTK 1.4 or 1.5 -
    -
    +\note The Forms compatibility library is deprecated, no longer actively + maintained since FLTK 1.3.0, and likely to be removed completely + in FLTK 1.5. + +Since FLTK 1.4 building the Forms compatibility library \c fltk_forms +(configure/Makefiles) or \c fltk::forms (CMake) can be disabled with +one of these commands: + \code + - ./configure --disable-forms ... + - cmake -D FLTK_BUILD_FORMS:BOOL=OFF ... + - cmake-gui ... + \endcode + +Fluid can still import Forms and XForms designer (.fd) files but w/o +any guarantees for working results. Manual fixes may be necessary. + +In the next minor or major release (1.5 or higher) the Forms compatibility +library will not be built by default or will be removed entirely. + \section forms_importing Importing Forms Layout Files diff --git a/libraries/fltk/documentation/src/glut.dox b/libraries/fltk/documentation/src/glut.dox index 0effbe5a42..5fad54ca14 100644 --- a/libraries/fltk/documentation/src/glut.dox +++ b/libraries/fltk/documentation/src/glut.dox @@ -235,7 +235,7 @@ Switches all drawing functions to the GLUT window. [Prev] - FLTK Enumerations + Constants and Enumerations diff --git a/libraries/fltk/documentation/src/index.dox b/libraries/fltk/documentation/src/index.dox index e82bccfd66..f64c85be9a 100644 --- a/libraries/fltk/documentation/src/index.dox +++ b/libraries/fltk/documentation/src/index.dox @@ -10,7 +10,7 @@
    FLTK 1.4.0 Programming Manual - By F. Costantini, D. Gibson, M. Melcher, + By F. Costantini, M. Melcher, A. Schlosser, B. Spitzak and M. Sweet. \include{doc} copyright.dox diff --git a/libraries/fltk/documentation/src/license.dox b/libraries/fltk/documentation/src/license.dox index 1110280ede..ff4bc4ac14 100644 --- a/libraries/fltk/documentation/src/license.dox +++ b/libraries/fltk/documentation/src/license.dox @@ -497,9 +497,9 @@ DAMAGES. diff --git a/libraries/fltk/documentation/src/opengl.dox b/libraries/fltk/documentation/src/opengl.dox index 14f33a6251..c1ce8a9fd4 100644 --- a/libraries/fltk/documentation/src/opengl.dox +++ b/libraries/fltk/documentation/src/opengl.dox @@ -39,34 +39,7 @@ To make a subclass of Fl_Gl_Window, you must provide: If your subclass provides static controls in the window, they must be redrawn whenever the \p FL_DAMAGE_ALL bit is set -in the value returned by \p damage(). For double-buffered -windows you will need to surround the drawing code with the -following code to make sure that both buffers are redrawn: - -\code -#ifndef MESA -glDrawBuffer(GL_FRONT_AND_BACK); -#endif // !MESA -... draw stuff here ... -#ifndef MESA -glDrawBuffer(GL_BACK); -#endif // !MESA -\endcode - -
    - + [Prev] - Developer Information + Migrating Code from FLTK 1.3 to 1.4 diff --git a/libraries/fltk/documentation/src/migration_1_4.dox b/libraries/fltk/documentation/src/migration_1_4.dox index acbe75f935..51ab17d1b3 100644 --- a/libraries/fltk/documentation/src/migration_1_4.dox +++ b/libraries/fltk/documentation/src/migration_1_4.dox @@ -8,10 +8,10 @@ to change source code. We also explain how code can be made compatible so it can be compiled by both FLTK 1.3.x and 1.4.x. If you need to migrate your code from prior FLTK versions to FLTK 1.4, -then you should first consult the relevant appendices in the FLTK 1.3 -online documentation or by downloading the FLTK 1.3 documentation. -See https://www.fltk.org/doc-1.3/index.html and/or -https://www.fltk.org/software.php , respectively. +please consult the relevant appendices in the FLTK 1.3 online documentation +or by downloading the FLTK 1.3 documentation. +See https://www.fltk.org/doc-1.3/migration_1_3.html and/or +https://www.fltk.org/software.php, respectively. \section migration_1_4_headers Changes in Header Files @@ -20,34 +20,34 @@ We strive to include only necessary header files in the public headers of the FLTK library to reduce dependencies and hence compile times. We try to avoid including system header files as far as possible. Known -exceptions are \ where file system structures and functions are -visible in the public API, for instance \p FILE*, and sometimes essential -header files like \ and/or \. Some required system -headers \b may be included in platform specific header files like -\ or \. +exceptions are \c \ where file system structures and functions are +visible in the public API, for instance \c FILE*, and sometimes essential +header files like \c \ and/or \c \. Some required +system headers \b may be included in platform specific header files like +\c \ or \c \. In earlier versions (1.3.x) some of the public FLTK headers included some not strictly required system headers by accident. -The consequence for building user programs with FLTK 1.4 is that if you +The consequence for building user programs with FLTK 1.4 is: if you require a system or FLTK header in your user program that you don't -\e \#include explicitly but which has been included by FLTK 1.3.x your -FLTK 1.3 program may issue compiler errors or warnings about missing header -files or missing declarations when compiled with FLTK 1.4. +\c \#include explicitly but which has been included by FLTK 1.3.x your +FLTK 1.3 program may issue compiler errors or warnings about missing +header files or missing declarations when compiled with FLTK 1.4. This is not a fault of FLTK 1.4 but a fault of the source code that did not include all required headers. -In FLTK 1.4 inclusion of \ is no longer a strict requirement as -it was required and documented in FLTK 1.3.x. In FLTK 1.4 you may still -need to '\#include \' if you are using enumerations or methods +In FLTK 1.4 inclusion of \c \ is no longer a strict requirement +as it was required and documented in FLTK 1.3.x. In FLTK 1.4 you may still +need to \c '\#include \c \' if you are using enumerations or methods of class \c Fl like Fl::run() but there are exceptions where this header -is included by other FLTK headers, like Fl_Window.H and other subclasses. +is included by other FLTK headers, like \c Fl_Window.H and other subclasses. Suggested solution: include all FLTK and system header files your source code requires explicitly and don't rely on FLTK headers to include a particular header file. If you want your code to be as much as possible -compatible with FLTK 1.3.x, then you should \c '\#include \' +compatible with FLTK 1.3.x, then you should \c '\#include \c \' as required by 1.3.x. You don't need to include headers of base classes - this is done by all @@ -94,7 +94,7 @@ change your program to use these new constants instead of those without the \p "_L" suffix. For more information see the documentation of Fl_Preferences. -\section migration_1_4_add_timeout Fl::add_timeout and friends +\section migration_1_4_timeout Fl::add_timeout and friends Since FLTK 1.4.0 internal timeout handling has been unified across platforms. This ensures equal timeout handling, improved accuracy of Fl::repeat_timeout(), @@ -180,6 +180,87 @@ Code example in header file: Note the \p 'const' attribute \b and the \p FL_OVERRIDE macro. +\section migration_1_4_x11_compat Using X11 specific code with a "hybrid" FLTK library + +Read this section if your FLTK 1.3 program uses X11 specific code with platform +specific guards like +\code + #if defined(WIN32) + // Windows specific code here + #elif defined(__APPLE__) + // macOS specific code here + #else + // X11 specific code here + #endif +\endcode + +or similar. + +You may skip this section if you don't use platform (X11) specific code. + +FLTK 1.4 introduced Wayland support on Unix-like systems that support Wayland +at runtime. The default build selects the Wayland runtime if it exists at +program startup and falls back to using X11 if Wayland is not supported. +On all currently known Wayland-enabled systems X11 programs are still supported +by using "XWayland" which must be installed and enabled on the system. This is +usually the case (as of this writing in November 2024). + +Since using the Wayland runtime is the default you may get runtime errors +if your program uses X11 specific code with the Wayland runtime. + +There are two solutions: + + -# Change the conditional code shown above everywhere in your program. This + is the best and recommended long-term solution but may require some work. + -# Disable the Wayland backend (runtime) for your program. This can be a + short-term solution for quick "porting" success. + +Details about solution 1 are beyond the scope of this documentation but here's +an example how such code can be rewritten in FLTK 1.4 for all platforms. This +code is now in test/fltk-versions.cxx but may be changed in the future. Change +this as you need. + + \code + static const char *get_platform() { + #if defined(_WIN32) + return "Windows"; + #elif defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND) + # if defined(FLTK_USE_X11) + if (fl_x11_display()) + return "Unix/Linux (X11)"; + # endif + # if defined(FLTK_USE_WAYLAND) + if (fl_wl_display()) + return "Unix/Linux (Wayland)"; + # endif + return "X11 or Wayland (backend unknown or display not opened)"; + #elif defined(__APPLE__) + return "macOS (native)"; + #endif + return "platform unknown, unsupported, or display not opened"; + } + \endcode + + +Solution 2 is described in chapter 2.1 of README.Wayland.txt. Please read this +chapter if you need to support X11 specific code w/o the Wayland runtime. + +Excerpt from README.Wayland.txt: + + It is possible to force a program linked to a Wayland-enabled FLTK library + to use X11 in all situations by putting this declaration somewhere in the + source code: + + \code + FL_EXPORT bool fl_disable_wayland = true; + \endcode + +Please note that you may need to do more to link and run your program +successfully, depending on the build system. + +Additional info can be found in chapter \ref osissues_wl_x11_hybrid. + + \section migration_1_4_modern_cmake Modern CMake FLTK 1.4.0 supports "modern" CMake rather than old or "classic" CMake @@ -317,8 +398,8 @@ OPTION_WAYLAND_ONLY | FLTK_BACKEND_X11=OFF [Index] - - Developer Information + + Software License [Next]
    - - - - -
    Note: - - If you are using the Mesa graphics library, the call - to \p glDrawBuffer() is not required and will slow - down drawing considerably. The preprocessor instructions - shown above will optimize your code based upon the - graphics library used. - -
    +in the value returned by \p damage(). \subsection opengl_defining Defining the Subclass diff --git a/libraries/fltk/documentation/src/preface.dox b/libraries/fltk/documentation/src/preface.dox index fd67376278..035a175e37 100644 --- a/libraries/fltk/documentation/src/preface.dox +++ b/libraries/fltk/documentation/src/preface.dox @@ -2,9 +2,9 @@ \page preface Preface -This manual describes the Fast Light Tool Kit ("FLTK") -version 1.4.0, a C++ Graphical User Interface -("GUI") toolkit for UNIX, Microsoft Windows and Apple macOS. +This manual describes the Fast Light Tool Kit ("FLTK") version 1.4.0, +a C++ Graphical User Interface ("GUI") toolkit for UNIX, Microsoft Windows, +and Apple macOS. Version 1.4.0 introduces support for a new windowing system under Linux/Unix: Wayland. FLTK applications under Linux/Unix run unchanged diff --git a/libraries/fltk/documentation/src/subclassing.dox b/libraries/fltk/documentation/src/subclassing.dox index e37924bf97..384e510f69 100644 --- a/libraries/fltk/documentation/src/subclassing.dox +++ b/libraries/fltk/documentation/src/subclassing.dox @@ -47,8 +47,8 @@ pass the same arguments: \code MyClass::MyClass(int x, int y, int w, int h, const char *label) -: Fl_Widget(x, y, w, h, label) { -// do initialization stuff... + : Fl_Widget(x, y, w, h, label) { + // do initialization stuff... } \endcode @@ -57,19 +57,19 @@ Fl_Widget's protected constructor sets \p x(), \p y(), and initializes the other instance variables to: \code -type(0); -box(FL_NO_BOX); -color(FL_BACKGROUND_COLOR); -selection_color(FL_BACKGROUND_COLOR); -labeltype(FL_NORMAL_LABEL); -labelstyle(FL_NORMAL_STYLE); -labelsize(FL_NORMAL_SIZE); -labelcolor(FL_FOREGROUND_COLOR); -align(FL_ALIGN_CENTER); -callback(default_callback,0); -flags(ACTIVE|VISIBLE); -image(0); -deimage(0); + type(0); + box(FL_NO_BOX); + color(FL_BACKGROUND_COLOR); + selection_color(FL_BACKGROUND_COLOR); + labeltype(FL_NORMAL_LABEL); + labelstyle(FL_NORMAL_STYLE); + labelsize(FL_NORMAL_SIZE); + labelcolor(FL_FOREGROUND_COLOR); + align(FL_ALIGN_CENTER); + callback(default_callback,0); + flags(ACTIVE|VISIBLE); + image(0); + deimage(0); \endcode \section subclassing_protected Protected Methods of Fl_Widget @@ -118,22 +118,22 @@ see what parts of your widget need redrawing.
    The \p handle() method can then set individual damage bits to limit the amount of drawing that needs to be done: \code -MyClass::handle(int event) { - ... - if (change_to_part1) damage(1); - if (change_to_part2) damage(2); - if (change_to_part3) damage(4); -} - -MyClass::draw() { - if (damage() & FL_DAMAGE_ALL) { - ... draw frame/box and other static stuff ... + int MyClass::handle(int event) { + // ... + if (change_to_part1) damage(1); + if (change_to_part2) damage(2); + if (change_to_part3) damage(4); } - if (damage() & (FL_DAMAGE_ALL | 1)) draw_part1(); - if (damage() & (FL_DAMAGE_ALL | 2)) draw_part2(); - if (damage() & (FL_DAMAGE_ALL | 4)) draw_part3(); -} + void MyClass::draw() { + if (damage() & FL_DAMAGE_ALL) { + // ... draw frame/box and other static stuff ... + } + + if (damage() & (FL_DAMAGE_ALL | 1)) draw_part1(); + if (damage() & (FL_DAMAGE_ALL | 2)) draw_part2(); + if (damage() & (FL_DAMAGE_ALL | 4)) draw_part3(); + } \endcode \todo Clarify Fl_Window::damage(uchar) handling - seems confused/wrong? @@ -259,18 +259,18 @@ a pushbutton and also accepts the keystroke \p 'x' to cause the callback: \code int MyClass::handle(int event) { - switch(event) { + switch (event) { case FL_PUSH: highlight = 1; redraw(); return 1; case FL_DRAG: { - int t = Fl::event_inside(this); - if (t != highlight) { - highlight = t; - redraw(); - } + int t = Fl::event_inside(this); + if (t != highlight) { + highlight = t; + redraw(); } + } return 1; case FL_RELEASE: if (highlight) { @@ -416,14 +416,16 @@ that a child needs to be drawn. It is fastest if you avoid drawing anything else in this case: \code -int MyClass::draw() { +void MyClass::draw() { Fl_Widget *const*a = array(); if (damage() == FL_DAMAGE_CHILD) { // only redraw some children - for (int i = children(); i --; a ++) update_child(**a); + for (int i = children(); i--; a++) { + update_child(**a); + } } else { // total redraw - ... draw background graphics ... + // ... draw background graphics ... // now draw all the children atop the background: - for (int i = children_; i --; a ++) { + for (int i = children(); i--; a++) { draw_child(**a); draw_outside_label(**a); // you may not need to do this } diff --git a/libraries/fltk/documentation/src/unicode.dox b/libraries/fltk/documentation/src/unicode.dox index 4d74f99314..31bae7756b 100644 --- a/libraries/fltk/documentation/src/unicode.dox +++ b/libraries/fltk/documentation/src/unicode.dox @@ -525,7 +525,7 @@ converts the strings to lower case Unicode as part of the comparison. - FLTK Enumerations + Constants and Enumerations [Next] diff --git a/libraries/fltk/examples/.gitignore b/libraries/fltk/examples/.gitignore deleted file mode 100644 index 2aaf8b559d..0000000000 --- a/libraries/fltk/examples/.gitignore +++ /dev/null @@ -1,52 +0,0 @@ -# -# Files to be ignored by Git (do not commit) -# -# Note: *.exe will be ignored by means of ../.gitignore -# -animgifimage -animgifimage-play -animgifimage-resize -animgifimage-simple -browser-simple -callbacks -cairo-draw-x -chart-simple -draggable-group -grid-simple -howto-add_fd-and-popen -howto-browser-with-icons -howto-drag-and-drop -howto-draw-an-x -howto-flex-simple -howto-menu-with-images -howto-parse-args -howto-remap-numpad-keyboard-keys -howto-simple-svg -howto-text-over-image-button -menubar-add -nativefilechooser-simple -nativefilechooser-simple-app -OpenGL3-glut-test -OpenGL3test -progress-simple -shapedwindow -simple-terminal -SVG_File_Surface -table-as-container -table-simple -table-sort -table-spreadsheet -table-spreadsheet-with-keyboard-nav -table-with-keynav -table-with-right-column-stretch-fit -table-with-right-click-menu -tabs-simple -textdisplay-with-colors -texteditor-simple -texteditor-with-dynamic-colors -tree-as-container -tree-custom-draw-items -tree-custom-sort -tree-of-tables -tree-simple -wizard-simple diff --git a/libraries/fltk/examples/shapedwindow.cxx b/libraries/fltk/examples/shapedwindow.cxx index 36433fb13e..22f3052b69 100644 --- a/libraries/fltk/examples/shapedwindow.cxx +++ b/libraries/fltk/examples/shapedwindow.cxx @@ -1,7 +1,7 @@ // // shapedwindow example source file for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2014 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -93,7 +93,8 @@ int main(int argc, char **argv) { Fl_RGB_Image *img = prepare_shape(dim); win->shape(img); dragbox *box = new dragbox(0, 0, win->w(), win->h()); - box->image(new Fl_Tiled_Image(new Fl_Pixmap((const char * const *)tile_xpm))); + Fl_Pixmap *pxm = new Fl_Pixmap((const char * const *)tile_xpm); + box->bind_image(new Fl_Tiled_Image(pxm)); // Fl_Tiled_Image will be auto-released Fl_Group *g = new Fl_Group(10, 20, 80, 20); g->box(FL_NO_BOX); Fl_Button *b = new Fl_Button(10, 20, 80, 20, "Close"); @@ -113,7 +114,11 @@ int main(int argc, char **argv) { win->end(); win->resizable(win); win->show(argc, argv); - Fl::run(); + // Test for memory leaks: this is not necessary, it's just for demonstration. + // Memory checkers like Address Sanitizer or Valgrind would flag leaks. + int ret = Fl::run(); delete win; - return 0; + delete pxm; + delete img; + return ret; } diff --git a/libraries/fltk/fltk-config.in b/libraries/fltk/fltk-config.in index 29dde790dd..dee2cf008b 100644 --- a/libraries/fltk/fltk-config.in +++ b/libraries/fltk/fltk-config.in @@ -2,7 +2,7 @@ # # FLTK configuration utility. # -# Copyright 2000-2023 by Bill Spitzak and others. +# Copyright 2000-2024 by Bill Spitzak and others. # Original version Copyright 2000 by James Dean Palmer # Adapted by Vincent Penne and Michael Sweet # @@ -44,12 +44,12 @@ CAIROFLAGS="@CAIROFLAGS@" # otherwise it is an empty string BINARY_DIR=@BINARY_DIR@ -prefix=@prefix@ -exec_prefix=@exec_prefix@ +prefix="@prefix@" +exec_prefix="@exec_prefix@" exec_prefix_set=no -includedir=@includedir@ -libdir=@libdir@ -srcdir=@srcdir@ +includedir="@includedir@" +libdir="@libdir@" +srcdir="@srcdir@" # BEGIN fltk-config code @@ -88,7 +88,7 @@ fi # Check bundled image libraries in installation folder. # Note: jpeg, png, and zlib headers are installed in FL/images -if test -d $includedir/FL/images; then +if test -d "$includedir/FL/images"; then CFLAGS="-I$includedir/FL/images $CFLAGS" CXXFLAGS="-I$includedir/FL/images $CXXFLAGS" fi @@ -254,7 +254,7 @@ do done if test "$includedir" != /usr/include; then - includes=-I$includedir + includes="-I$includedir" else includes= fi @@ -265,7 +265,7 @@ if test -n "$BINARY_DIR"; then fi if test "$libdir" != /usr/lib -a "$libdir" != /usr/lib32; then - libs=-L$libdir + libs="-L$libdir" else libs= fi @@ -392,10 +392,10 @@ fi if test "$echo_ldflags" = "yes"; then my_libs= - libdirs=$libs + libdirs="$libs" for i in $LDLIBS ; do - if test $i != -L$libdir ; then + if test $i != "-L$libdir" ; then if test -z "$my_libs" ; then my_libs="$i" else @@ -425,7 +425,7 @@ if test "$echo_libs" = "yes"; then USELIBS="$libdir/libfltk_images.a $USELIBS" for lib in fltk_jpeg fltk_png fltk_z; do - if test -f $libdir/lib$lib.a; then + if test -f "$libdir/lib$lib.a"; then USELIBS="$libdir/lib$lib.a $USELIBS" fi done diff --git a/libraries/fltk/fltk-options/.gitignore b/libraries/fltk/fltk-options/.gitignore deleted file mode 100644 index bf43c199ea..0000000000 --- a/libraries/fltk/fltk-options/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -# -# Files to be ignored by Git (do not commit) -# - -fltk-options -fltk-options-shared -fltk-options.app diff --git a/libraries/fltk/fltk-options/Makefile b/libraries/fltk/fltk-options/Makefile index 06b3b710bf..c860bad4d8 100644 --- a/libraries/fltk/fltk-options/Makefile +++ b/libraries/fltk/fltk-options/Makefile @@ -1,7 +1,7 @@ # # fltk-options Makefile for the Fast Light Tool Kit (FLTK). # -# Copyright 2023 by Bill Spitzak and others. +# Copyright 2023-2024 by Bill Spitzak and others. # # This library is free software. Distribution and use rights are outlined in # the file "COPYING" which should have been included with this file. If this @@ -55,39 +55,39 @@ include makedepend install: all echo "Installing fltk-options in $(DESTDIR)$(bindir)..." - -$(INSTALL_DIR) $(DESTDIR)$(bindir) - $(INSTALL_BIN) $(FLTK_OPTIONS) $(DESTDIR)$(bindir)/fltk-options$(EXEEXT) + -$(INSTALL_DIR) "$(DESTDIR)$(bindir)" + $(INSTALL_BIN) $(FLTK_OPTIONS) "$(DESTDIR)$(bindir)/fltk-options$(EXEEXT)" install-linux: - -$(INSTALL_DIR) $(DESTDIR)/usr/share/applications - $(INSTALL_DATA) fltk-options.desktop $(DESTDIR)/usr/share/applications + -$(INSTALL_DIR) "$(DESTDIR)/usr/share/applications" + $(INSTALL_DATA) fltk-options.desktop "$(DESTDIR)/usr/share/applications" for size in 16 32 48 64 128; do \ - if test ! -d $(DESTDIR)/usr/share/icons/hicolor/$${size}x$${size}/apps; then \ - $(INSTALL_DIR) $(DESTDIR)/usr/share/icons/hicolor/$${size}x$${size}/apps; \ + if test ! -d "$(DESTDIR)/usr/share/icons/hicolor/$${size}x$${size}/apps"; then \ + $(INSTALL_DIR) "$(DESTDIR)/usr/share/icons/hicolor/$${size}x$${size}/apps"; \ fi; \ - $(INSTALL_DATA) icons/fltk-options-$$size.png $(DESTDIR)/usr/share/icons/hicolor/$${size}x$${size}/apps/fltk-options.png; \ + $(INSTALL_DATA) icons/fltk-options-$$size.png "$(DESTDIR)/usr/share/icons/hicolor/$${size}x$${size}/apps/fltk-options.png"; \ done - -$(INSTALL_DIR) $(DESTDIR)/usr/share/mimelnk/application - $(INSTALL_DATA) x-fltk-options.desktop $(DESTDIR)/usr/share/mimelnk/application + -$(INSTALL_DIR) "$(DESTDIR)/usr/share/mimelnk/application" + $(INSTALL_DATA) x-fltk-options.desktop "$(DESTDIR)/usr/share/mimelnk/application" install-osx: echo Installing fltk-options in $(DESTDIR)/Applications... - -$(INSTALL_DIR) $(DESTDIR)/Applications/fltk-options.app - -$(INSTALL_DIR) $(DESTDIR)/Applications/fltk-options.app/Contents - $(INSTALL_DATA) fltk-options.app/Contents/Info.plist $(DESTDIR)/Applications/fltk-options.app/Contents/Info.plist - -$(INSTALL_DIR) $(DESTDIR)/Applications/fltk-options.app/Contents/MacOS - $(RM) $(DESTDIR)/Applications/fltk-options.app/Contents/MacOS/fltk-options - $(LN) $(bindir)/fltk-options $(DESTDIR)/Applications/fltk-options.app/Contents/MacOS/fltk-options - -$(INSTALL_DIR) $(DESTDIR)/Applications/fltk-options.app/Contents/Resources - $(INSTALL_DATA) fltk-options.app/Contents/Resources/fltk-options.icns $(DESTDIR)/Applications/fltk-options.app/Contents/Resources + -$(INSTALL_DIR) "$(DESTDIR)/Applications/fltk-options.app" + -$(INSTALL_DIR) "$(DESTDIR)/Applications/fltk-options.app/Contents" + $(INSTALL_DATA) fltk-options.app/Contents/Info.plist "$(DESTDIR)/Applications/fltk-options.app/Contents/Info.plist" + -$(INSTALL_DIR) "$(DESTDIR)/Applications/fltk-options.app/Contents/MacOS" + $(RM) "$(DESTDIR)/Applications/fltk-options.app/Contents/MacOS/fltk-options" + $(LN) $(bindir)/fltk-options "$(DESTDIR)/Applications/fltk-options.app/Contents/MacOS/fltk-options" + -$(INSTALL_DIR) "$(DESTDIR)/Applications/fltk-options.app/Contents/Resources" + $(INSTALL_DATA) fltk-options.app/Contents/Resources/fltk-options.icns "$(DESTDIR)/Applications/fltk-options.app/Contents/Resources" uninstall: - $(RM) $(DESTDIR)$(bindir)/fltk-options$(EXEEXT) + $(RM) "$(DESTDIR)$(bindir)/fltk-options$(EXEEXT)" uninstall-linux: - $(RM) $(DESTDIR)/usr/share/applications/fltk-options.desktop - $(RM) $(DESTDIR)/usr/share/icons/hicolor/*/fltk-options.png - $(RM) $(DESTDIR)/usr/share/mimelnk/application/x-fltk-options.desktop + $(RM) "$(DESTDIR)/usr/share/applications/fltk-options.desktop" + $(RM) "$(DESTDIR)/usr/share/icons/hicolor/*/fltk-options.png" + $(RM) "$(DESTDIR)/usr/share/mimelnk/application/x-fltk-options.desktop" uninstall-osx: - $(RM) -r $(DESTDIR)/Applications/fltk-options.app + $(RM) -r "$(DESTDIR)/Applications/fltk-options.app" diff --git a/libraries/fltk/fltk-options/fltk-options.cxx b/libraries/fltk/fltk-options/fltk-options.cxx index 46648f6bf2..1f9846b98c 100644 --- a/libraries/fltk/fltk-options/fltk-options.cxx +++ b/libraries/fltk/fltk-options/fltk-options.cxx @@ -1,7 +1,7 @@ // // fltk-options for the Fast Light Tool Kit (FLTK). // -// Copyright 2022-2023 by Bill Spitzak and others. +// Copyright 2022-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -34,9 +34,9 @@ // user interface sizes // |<->|<- group browser ->|<->|<- options ->|<->| const int FO_GAP = 10; -const int FO_BROWSER_W = 200; -const int FO_SCROLL_W = 16 + 4; //Fl::scrollbar_size() + Fl::box_dw(FL_DOWN_BOX); -const int FO_CHOICE_W = 75; +const int FO_BROWSER_W = 220; +const int FO_SCROLL_W = 16 + 4; // Fl::scrollbar_size() + Fl::box_dw(FL_DOWN_BOX); +const int FO_CHOICE_W = 80; const int FO_OPTIONS_W = 420; const int FO_BUTTON_W = 75; const int FO_WINDOW_W = FO_GAP + FO_BROWSER_W + FO_GAP + FO_SCROLL_W + FO_OPTIONS_W + FO_SCROLL_W + FO_GAP; @@ -44,7 +44,7 @@ const int FO_SYSTEM_X = FO_OPTIONS_W - 2*FO_GAP - 2*FO_CHOICE_W; const int FO_USER_X = FO_OPTIONS_W - FO_GAP - FO_CHOICE_W; const int FO_TITLE_H = 20; -const int FO_BROWSER_H = 340; +const int FO_BROWSER_H = 370; const int FO_BUTTON_H = 25; const int FO_CHOICE_H = 22; const int FO_WINDOW_H = FO_GAP + FO_BROWSER_H + FO_GAP + FO_BUTTON_H + FO_GAP; @@ -136,13 +136,13 @@ Fo_Option_Descr g_option_list[] = { "platfom. If disabled, the Fl_Native_File_Chooser class always uses FLTK's " "own file dialog (i.e., Fl_File_Chooser) even if GTK is available." }, { FO_OPTION_BOOL, "Native File Chooser uses Zenity:", - Fl::OPTION_FNFC_USES_ZENITY, "OPTION_FNFC_USES_ZENITY", "UseZenity", true, + Fl::OPTION_FNFC_USES_ZENITY, "OPTION_FNFC_USES_ZENITY", "UseZenity", false, "Fl_Native_File_Chooser uses the 'zenity' command if possible.", "Meaningful for the Wayland/X11 platform only. When switched on, " "the library uses a Zenity-based file dialog if command 'zenity' is available. " "When switched off (default), command 'zenity' is not used."}, { FO_OPTION_BOOL, "Native File Chooser uses Kdialog:", - Fl::OPTION_FNFC_USES_KDIALOG, "OPTION_FNFC_USES_KDIALOG", "UseKdialog", true, + Fl::OPTION_FNFC_USES_KDIALOG, "OPTION_FNFC_USES_KDIALOG", "UseKdialog", false, "Fl_Native_File_Chooser uses the 'kdialog' command if possible.", "Meaningful for the Wayland/X11 platform. " "When switched on, the library uses a kdialog-based file dialog if command 'kdialog' is " @@ -289,7 +289,7 @@ void list_options(char cmd) { Fo_Option_Descr *opt; for (opt = g_option_list; opt->type!=FO_END_OF_LIST; ++opt) { if (opt->name) { - printf("%-24s", opt->name); + printf("%-28s", opt->name); if (cmd == 'S' || cmd == 0) { int value = get_option(FO_SYSTEM, opt->prefs_name); printf(" system:%2d", value); @@ -679,7 +679,7 @@ Fl_Window* build_ui() { "Close"); close->callback(close_cb); g_window->end(); - g_window->size_range(FO_WINDOW_W, 200, FO_WINDOW_W, 32767); + g_window->size_range(FO_WINDOW_W, FO_WINDOW_H); return g_window; } diff --git a/libraries/fltk/fltk-options/fltk-options.plist b/libraries/fltk/fltk-options/fltk-options.plist index 7e168ea0c7..728b8ff3a4 100644 --- a/libraries/fltk/fltk-options/fltk-options.plist +++ b/libraries/fltk/fltk-options/fltk-options.plist @@ -13,7 +13,7 @@ CFBundleDevelopmentRegion English NSHumanReadableCopyright - Copyright 2023 by Bill Spitzak and others + Copyright 2023-2024 by Bill Spitzak and others CFAppleHelpAnchor help CFBundleName @@ -27,7 +27,7 @@ CFBundleShortVersionString 1.4.0 CFBundleGetInfoString - 1.4.0, Copyright 2023 by Bill Spitzak and others + 1.4.0, Copyright 2023-2024 by Bill Spitzak and others NSHighResolutionCapable diff --git a/libraries/fltk/fltk-options/icons/fltk-options-32.xpm b/libraries/fltk/fltk-options/icons/fltk-options-32.xpm index 1b44473fa0..144967ba6b 100644 --- a/libraries/fltk/fltk-options/icons/fltk-options-32.xpm +++ b/libraries/fltk/fltk-options/icons/fltk-options-32.xpm @@ -1,5 +1,5 @@ /* XPM */ -static char *_bae769a99384303e21a66e415de0b1aBvKpx6NXTDEGsJa6[] = { +static const char *_bae769a99384303e21a66e415de0b1aBvKpx6NXTDEGsJa6[] = { /* columns rows colors chars-per-pixel */ "32 32 32 1 ", " c #1A1C1C", diff --git a/libraries/fltk/fltk-options/icons/fltk-options-96.xpm b/libraries/fltk/fltk-options/icons/fltk-options-96.xpm index 31a903de69..56cce36121 100644 --- a/libraries/fltk/fltk-options/icons/fltk-options-96.xpm +++ b/libraries/fltk/fltk-options/icons/fltk-options-96.xpm @@ -1,5 +1,5 @@ /* XPM */ -static char *_e101498a8b740e7b97aa74122d70714MqWFs5PhLjx31lZ1[] = { +static const char *_e101498a8b740e7b97aa74122d70714MqWFs5PhLjx31lZ1[] = { /* columns rows colors chars-per-pixel */ "96 96 32 1 ", " c #1A1C1C", diff --git a/libraries/fltk/fltk.xpm b/libraries/fltk/fltk.xpm index b275af51e8..78732f901f 100644 --- a/libraries/fltk/fltk.xpm +++ b/libraries/fltk/fltk.xpm @@ -1,5 +1,5 @@ /* XPM */ -static char * const fltk_xpm[] = { +static const char * const fltk_xpm[] = { "229 70 152 2", " c None", ". c #000066", diff --git a/libraries/fltk/fluid/.gitignore b/libraries/fltk/fluid/.gitignore deleted file mode 100644 index f1c3b079f0..0000000000 --- a/libraries/fltk/fluid/.gitignore +++ /dev/null @@ -1,14 +0,0 @@ -# -# Files to be ignored by Git (do not commit) -# - -fluid -fluid-shared -TAGS -fluid.app -pixmaps/*.bck - -# local documentation generation - -documentation/html/ -documentation/html-dev/ diff --git a/libraries/fltk/fluid/Fl_Function_Type.cxx b/libraries/fltk/fluid/Fl_Function_Type.cxx index 2f26a2a687..f490c9e115 100644 --- a/libraries/fltk/fluid/Fl_Function_Type.cxx +++ b/libraries/fltk/fluid/Fl_Function_Type.cxx @@ -206,12 +206,17 @@ Fl_Function_Type::~Fl_Function_Type() { \return the new node */ Fl_Type *Fl_Function_Type::make(Strategy strategy) { - Fl_Type *p = Fl_Type::current; - while (p && !p->is_decl_block()) p = p->parent; + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && !p->is_decl_block()) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } Fl_Function_Type *o = new Fl_Function_Type(); o->name("make_window()"); o->return_type = 0; - o->add(p, strategy); + o->add(anchor, strategy); o->factory = this; o->public_ = 1; o->cdecl_ = 0; @@ -590,15 +595,20 @@ Fl_Code_Type::Fl_Code_Type() : \return new Code node */ Fl_Type *Fl_Code_Type::make(Strategy strategy) { - Fl_Type *p = Fl_Type::current; - while (p && !p->is_code_block()) p = p->parent; + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && !p->is_code_block()) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } if (!p) { fl_message("Please select a function"); return 0; } Fl_Code_Type *o = new Fl_Code_Type(); o->name("printf(\"Hello, World!\\n\");"); - o->add(p, strategy); + o->add(anchor, strategy); o->factory = this; return o; } @@ -752,8 +762,13 @@ Fl_CodeBlock_Type::~Fl_CodeBlock_Type() { \return new CodeBlock */ Fl_Type *Fl_CodeBlock_Type::make(Strategy strategy) { - Fl_Type *p = Fl_Type::current; - while (p && !p->is_code_block()) p = p->parent; + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && !p->is_code_block()) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } if (!p) { fl_message("Please select a function"); return 0; @@ -761,7 +776,7 @@ Fl_Type *Fl_CodeBlock_Type::make(Strategy strategy) { Fl_CodeBlock_Type *o = new Fl_CodeBlock_Type(); o->name("if (test())"); o->after = 0; - o->add(p, strategy); + o->add(anchor, strategy); o->factory = this; return o; } @@ -888,13 +903,18 @@ int Fl_Decl_Type::is_public() const \return new Declaration node */ Fl_Type *Fl_Decl_Type::make(Strategy strategy) { - Fl_Type *p = Fl_Type::current; - while (p && !p->is_decl_block()) p = p->parent; + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && !p->is_decl_block()) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } Fl_Decl_Type *o = new Fl_Decl_Type(); o->public_ = 0; o->static_ = 1; o->name("int x;"); - o->add(p, strategy); + o->add(anchor, strategy); o->factory = this; return o; } @@ -1110,15 +1130,20 @@ Fl_Data_Type::~Fl_Data_Type() { \return new inline data node */ Fl_Type *Fl_Data_Type::make(Strategy strategy) { - Fl_Type *p = Fl_Type::current; - while (p && !p->is_decl_block()) p = p->parent; + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && !p->is_decl_block()) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } Fl_Data_Type *o = new Fl_Data_Type(); o->public_ = 1; o->static_ = 1; o->filename_ = 0; o->text_mode_ = 0; o->name("myInlineData"); - o->add(p, strategy); + o->add(anchor, strategy); o->factory = this; return o; } @@ -1448,13 +1473,18 @@ int Fl_DeclBlock_Type::is_public() const { \return new Declaration Block node */ Fl_Type *Fl_DeclBlock_Type::make(Strategy strategy) { - Fl_Type *p = Fl_Type::current; - while (p && !p->is_decl_block()) p = p->parent; + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && !p->is_decl_block()) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } Fl_DeclBlock_Type *o = new Fl_DeclBlock_Type(); o->name("#if 1"); o->write_map_ = CODE_IN_SOURCE; o->after = fl_strdup("#endif"); - o->add(p, strategy); + o->add(anchor, strategy); o->factory = this; return o; } @@ -1675,14 +1705,19 @@ Fl_Comment_Type::Fl_Comment_Type() : \return new Comment node */ Fl_Type *Fl_Comment_Type::make(Strategy strategy) { - Fl_Type *p = Fl_Type::current; - while (p && !p->is_code_block()) p = p->parent; + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && !p->is_code_block()) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } Fl_Comment_Type *o = new Fl_Comment_Type(); o->in_c_ = 1; o->in_h_ = 1; o->style_ = 0; o->name("my comment"); - o->add(p, strategy); + o->add(anchor, strategy); o->factory = this; return o; } @@ -1949,14 +1984,19 @@ void Fl_Class_Type::prefix(const char*p) { \return new Class node */ Fl_Type *Fl_Class_Type::make(Strategy strategy) { - Fl_Type *p = Fl_Type::current; - while (p && !p->is_decl_block()) p = p->parent; + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && !p->is_decl_block()) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } Fl_Class_Type *o = new Fl_Class_Type(); o->name("UserInterface"); o->class_prefix = NULL; o->subclass_of = NULL; o->public_ = 1; - o->add(p, strategy); + o->add(anchor, strategy); o->factory = this; return o; } diff --git a/libraries/fltk/fluid/Fl_Function_Type.h b/libraries/fltk/fluid/Fl_Function_Type.h index 740792c627..91a0e521ae 100644 --- a/libraries/fltk/fluid/Fl_Function_Type.h +++ b/libraries/fltk/fluid/Fl_Function_Type.h @@ -60,7 +60,7 @@ class Fl_Function_Type : public Fl_Type const char *title() FL_OVERRIDE { return name() ? name() : "main()"; } - int is_parent() const FL_OVERRIDE {return 1;} + int can_have_children() const FL_OVERRIDE {return 1;} int is_code_block() const FL_OVERRIDE {return 1;} int is_public() const FL_OVERRIDE; ID id() const FL_OVERRIDE { return ID_Function; } @@ -113,7 +113,7 @@ class Fl_CodeBlock_Type : public Fl_Type void open() FL_OVERRIDE; const char *type_name() FL_OVERRIDE {return "codeblock";} int is_code_block() const FL_OVERRIDE {return 1;} - int is_parent() const FL_OVERRIDE {return 1;} + int can_have_children() const FL_OVERRIDE {return 1;} int is_public() const FL_OVERRIDE { return -1; } ID id() const FL_OVERRIDE { return ID_CodeBlock; } bool is_a(ID inID) const FL_OVERRIDE { return (inID==ID_CodeBlock) ? true : super::is_a(inID); } @@ -193,7 +193,7 @@ class Fl_DeclBlock_Type : public Fl_Type const char *type_name() FL_OVERRIDE {return "declblock";} void write_properties(Fd_Project_Writer &f) FL_OVERRIDE; void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE; - int is_parent() const FL_OVERRIDE {return 1;} + int can_have_children() const FL_OVERRIDE {return 1;} int is_decl_block() const FL_OVERRIDE {return 1;} int is_public() const FL_OVERRIDE; ID id() const FL_OVERRIDE { return ID_DeclBlock; } @@ -242,7 +242,7 @@ class Fl_Class_Type : public Fl_Type void write_code2(Fd_Code_Writer& f) FL_OVERRIDE; void open() FL_OVERRIDE; const char *type_name() FL_OVERRIDE {return "class";} - int is_parent() const FL_OVERRIDE {return 1;} + int can_have_children() const FL_OVERRIDE {return 1;} int is_decl_block() const FL_OVERRIDE {return 1;} int is_class() const FL_OVERRIDE {return 1;} int is_public() const FL_OVERRIDE; diff --git a/libraries/fltk/fluid/Fl_Grid_Type.cxx b/libraries/fltk/fluid/Fl_Grid_Type.cxx index b27a8be7c5..45110a8806 100644 --- a/libraries/fltk/fluid/Fl_Grid_Type.cxx +++ b/libraries/fltk/fluid/Fl_Grid_Type.cxx @@ -291,17 +291,51 @@ Fl_Widget *Fl_Grid_Type::widget(int X,int Y,int W,int H) { return g; } +Fl_Widget *Fl_Grid_Type::enter_live_mode(int top) { + Fl_Grid *grid = new Fl_Grid(o->x(), o->y(), o->w(), o->h()); + return propagate_live_mode(grid); +} + +void Fl_Grid_Type::leave_live_mode() { +} + void Fl_Grid_Type::copy_properties() { super::copy_properties(); Fl_Grid *d = (Fl_Grid*)live_widget, *s =(Fl_Grid*)o; + d->layout(s->rows(), s->cols()); int lm, tm, rm, bm; s->margin(&lm, &tm, &rm, &bm); d->margin(lm, tm, rm, bm); int rg, cg; s->gap(&rg, &cg); d->gap(rg, cg); - // TODO: lots to do! + // copy col widths, heights, and gaps + for (int c=0; ccols(); c++) { + d->col_width(c, s->col_width(c)); + d->col_gap(c, s->col_gap(c)); + d->col_weight(c, s->col_weight(c)); + } + // copy row widths, heights, and gaps + for (int r=0; rrows(); r++) { + d->row_height(r, s->row_height(r)); + d->row_gap(r, s->row_gap(r)); + d->row_weight(r, s->row_weight(r)); + } +} + +void Fl_Grid_Type::copy_properties_for_children() { + Fl_Grid *d = (Fl_Grid*)live_widget, *s =(Fl_Grid*)o; + for (int i=0; ichildren(); i++) { + Fl_Grid::Cell *cell = s->cell(s->child(i)); + if (cell && ichildren()) { + d->widget(d->child(i), + cell->row(), cell->col(), + cell->rowspan(), cell->colspan(), + cell->align()); + } + } + d->layout(); } void Fl_Grid_Type::write_properties(Fd_Project_Writer &f) diff --git a/libraries/fltk/fluid/Fl_Grid_Type.h b/libraries/fltk/fluid/Fl_Grid_Type.h index 4c922f97d3..2098cf7831 100644 --- a/libraries/fltk/fluid/Fl_Grid_Type.h +++ b/libraries/fltk/fluid/Fl_Grid_Type.h @@ -61,7 +61,10 @@ class Fl_Grid_Type : public Fl_Group_Type void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE; void write_parent_properties(Fd_Project_Writer &f, Fl_Type *child, bool encapsulate) FL_OVERRIDE; void read_parent_property(Fd_Project_Reader &f, Fl_Type *child, const char *property) FL_OVERRIDE; + Fl_Widget *enter_live_mode(int top=0) FL_OVERRIDE; + void leave_live_mode() FL_OVERRIDE; void copy_properties() FL_OVERRIDE; + void copy_properties_for_children() FL_OVERRIDE; void write_code1(Fd_Code_Writer& f) FL_OVERRIDE; void write_code2(Fd_Code_Writer& f) FL_OVERRIDE; void add_child(Fl_Type*, Fl_Type*) FL_OVERRIDE; diff --git a/libraries/fltk/fluid/Fl_Group_Type.cxx b/libraries/fltk/fluid/Fl_Group_Type.cxx index f42607b2d7..bac04a462f 100644 --- a/libraries/fltk/fluid/Fl_Group_Type.cxx +++ b/libraries/fltk/fluid/Fl_Group_Type.cxx @@ -89,59 +89,95 @@ void fix_group_size(Fl_Type *tt) { t->o->resize(X,Y,R-X,B-Y); } +extern void group_selected_menuitems(); + void group_cb(Fl_Widget *, void *) { - // Find the current widget: - Fl_Type *qq = Fl_Type::current; - while (qq && !qq->is_true_widget()) qq = qq->parent; - if (!qq || qq->level < 1 || (qq->level == 1 && qq->is_a(ID_Widget_Class))) { - fl_message("Please select widgets to group"); + if (!Fl_Type::current) { + fl_message("No widgets selected."); + return; + } + if (!Fl_Type::current->is_widget()) { + fl_message("Only widgets and menu items can be grouped."); + return; + } + if (Fl_Type::current->is_a(ID_Menu_Item)) { + group_selected_menuitems(); + return; + } + // The group will be created in the parent group of the current widget + Fl_Type *qq = Fl_Type::current->parent; + Fl_Widget_Type *q = static_cast(Fl_Type::current); + while (qq && !qq->is_a(ID_Group)) { + qq = qq->parent; + } + if (!qq) { + fl_message("Can't create a new group here."); return; } undo_checkpoint(); undo_suspend(); - Fl_Widget_Type* q = (Fl_Widget_Type*)qq; - force_parent = 1; + Fl_Type::current = qq; Fl_Group_Type *n = (Fl_Group_Type*)(Fl_Group_type.make(kAddAsLastChild)); n->move_before(q); n->o->resize(q->o->x(),q->o->y(),q->o->w(),q->o->h()); - for (Fl_Type *t = Fl_Type::first; t;) { + for (Fl_Type *t = qq->next; t && (t->level > qq->level);) { if (t->level != n->level || t == n || !t->selected) { - t = t->next; continue;} + t = t->next; + continue; + } Fl_Type *nxt = t->remove(); t->add(n, kAddAsLastChild); t = nxt; } fix_group_size(n); + Fl_Type::current = q; n->layout_widget(); widget_browser->rebuild(); undo_resume(); set_modflag(1); } +extern void ungroup_selected_menuitems(); + void ungroup_cb(Fl_Widget *, void *) { - // Find the group: - Fl_Type *q = Fl_Type::current; - while (q && !q->is_true_widget()) q = q->parent; - if (q) q = q->parent; - if (!q || q->level < 1 || (q->level == 1 && q->is_a(ID_Widget_Class))) { - fl_message("Please select widgets in a group"); + if (!Fl_Type::current) { + fl_message("No widgets selected."); return; } - Fl_Type* n; - for (n = q->next; n && n->level > q->level; n = n->next) { - if (n->level == q->level+1 && !n->selected) { - fl_message("Please select all widgets in group"); - return; - } + if (!Fl_Type::current->is_widget()) { + fl_message("Only widgets and menu items can be ungrouped."); + return; + } + if (Fl_Type::current->is_a(ID_Menu_Item)) { + ungroup_selected_menuitems(); + return; + } + + Fl_Widget_Type *q = static_cast(Fl_Type::current); + int q_level = q->level; + Fl_Type *qq = Fl_Type::current->parent; + while (qq && !qq->is_true_widget()) qq = qq->parent; + if (!qq || !qq->is_a(ID_Group)) { + fl_message("Only menu widgets inside a group can be ungrouped."); + return; } undo_checkpoint(); undo_suspend(); - for (n = q->next; n && n->level > q->level;) { - Fl_Type *nxt = n->remove(); - n->insert(q); - n = nxt; + Fl_Type::current = qq; + for (Fl_Type *t = qq->next; t && (t->level > qq->level);) { + if (t->level != q_level || !t->selected) { + t = t->next; + continue; + } + Fl_Type *nxt = t->remove(); + t->insert(qq); + t = nxt; } - delete q; + if (!qq->next || (qq->next->level <= qq->level)) { + qq->remove(); + delete qq; // qq has no children that need to be delete + } + Fl_Type::current = q; widget_browser->rebuild(); undo_resume(); set_modflag(1); @@ -298,6 +334,20 @@ void Fl_Flex_Type::copy_properties() d->gap( s->gap() ); } +void Fl_Flex_Type::copy_properties_for_children() { + Fl_Flex *d = (Fl_Flex*)live_widget, *s =(Fl_Flex*)o; + for (int i=0; ichildren(); i++) { + if (s->fixed(s->child(i)) && ichildren()) { + if (s->horizontal()) { + d->fixed(d->child(i), d->child(i)->w()); + } else { + d->fixed(d->child(i), d->child(i)->h()); + } + } + } + d->layout(); +} + void Fl_Flex_Type::write_properties(Fd_Project_Writer &f) { Fl_Group_Type::write_properties(f); diff --git a/libraries/fltk/fluid/Fl_Group_Type.h b/libraries/fltk/fluid/Fl_Group_Type.h index 694d2a01f9..1f7bc27478 100644 --- a/libraries/fltk/fluid/Fl_Group_Type.h +++ b/libraries/fltk/fluid/Fl_Group_Type.h @@ -59,7 +59,7 @@ class Fl_Group_Type : public Fl_Widget_Type void add_child(Fl_Type*, Fl_Type*) FL_OVERRIDE; void move_child(Fl_Type*, Fl_Type*) FL_OVERRIDE; void remove_child(Fl_Type*) FL_OVERRIDE; - int is_parent() const FL_OVERRIDE {return 1;} + int can_have_children() const FL_OVERRIDE {return 1;} ID id() const FL_OVERRIDE { return ID_Group; } bool is_a(ID inID) const FL_OVERRIDE { return (inID==ID_Group) ? true : super::is_a(inID); } Fl_Widget *enter_live_mode(int top=0) FL_OVERRIDE; @@ -118,6 +118,7 @@ class Fl_Flex_Type : public Fl_Group_Type void read_property(Fd_Project_Reader &f, const char *) FL_OVERRIDE; Fl_Widget *enter_live_mode(int top=0) FL_OVERRIDE; void copy_properties() FL_OVERRIDE; + void copy_properties_for_children() FL_OVERRIDE; void postprocess_read() FL_OVERRIDE; void write_code2(Fd_Code_Writer& f) FL_OVERRIDE; // void add_child(Fl_Type*, Fl_Type*) FL_OVERRIDE; diff --git a/libraries/fltk/fluid/Fl_Menu_Type.cxx b/libraries/fltk/fluid/Fl_Menu_Type.cxx index 6ab652e14d..23a7868fb0 100644 --- a/libraries/fltk/fluid/Fl_Menu_Type.cxx +++ b/libraries/fltk/fluid/Fl_Menu_Type.cxx @@ -29,6 +29,8 @@ #include "Fluid_Image.h" #include "custom_widgets.h" #include "mergeback.h" +#include "undo.h" +#include "widget_browser.h" #include #include @@ -52,9 +54,6 @@ Fl_Menu_Item menu_item_type_menu[] = { {"Radio",0,0,(void*)FL_MENU_RADIO}, {0}}; -static char submenuflag; -static uchar menuitemtype = 0; - static void delete_dependents(Fl_Menu_Item *m) { if (!m) return; @@ -87,7 +86,7 @@ void Fl_Input_Choice_Type::build_menu() { int n = 0; Fl_Type* q; for (q = next; q && q->level > level; q = q->next) { - if (q->is_parent()) n++; // space for null at end of submenu + if (q->can_have_children()) n++; // space for null at end of submenu n++; } if (!n) { @@ -134,7 +133,7 @@ void Fl_Input_Choice_Type::build_menu() { m->labelfont(i->o->labelfont()); m->labelsize(i->o->labelsize()); m->labelcolor(i->o->labelcolor()); - if (q->is_parent()) {lvl++; m->flags |= FL_SUBMENU;} + if (q->can_have_children()) {lvl++; m->flags |= FL_SUBMENU;} m++; int l1 = (q->next && q->next->is_a(ID_Menu_Item)) ? q->next->level : level; @@ -151,40 +150,119 @@ void Fl_Input_Choice_Type::build_menu() { \return new Menu Item node */ Fl_Type *Fl_Menu_Item_Type::make(Strategy strategy) { - // Find the current menu item: - Fl_Type* q = Fl_Type::current; - Fl_Type* p = q; - if (p) { - if ( (force_parent && q->is_a(ID_Menu_Item)) || !q->is_parent()) p = p->parent; - } - force_parent = 0; - if (!p || !(p->is_a(ID_Menu_Manager_) || p->is_a(ID_Submenu))) { - fl_message("Please select a menu to add to"); + return Fl_Menu_Item_Type::make(0, strategy); +} + +/** + Create an add a specific Menu Item node. + \param[in] flags set to 0, FL_MENU_RADIO, FL_MENU_TOGGLE, or FL_SUBMENU + \param[in] strategy add after current or as last child + \return new Menu Item node + */ +Fl_Type* Fl_Menu_Item_Type::make(int flags, Strategy strategy) { + // Find a good insert position based on the current marked node + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && !(p->is_a(ID_Menu_Manager_) || p->is_a(ID_Submenu))) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } + if (!p) { + fl_message("Please select a menu widget or a menu item"); return 0; } if (!o) { o = new Fl_Button(0,0,100,20); // create template widget } - Fl_Menu_Item_Type* t = submenuflag ? new Fl_Submenu_Type() : new Fl_Menu_Item_Type(); + Fl_Menu_Item_Type* t = NULL; + if (flags==FL_SUBMENU) { + t = new Fl_Submenu_Type(); + } else { + t = new Fl_Menu_Item_Type(); + } t->o = new Fl_Button(0,0,100,20); - t->o->type(menuitemtype); + t->o->type(flags); t->factory = this; - t->add(p, strategy); - if (!reading_file) t->label(submenuflag ? "submenu" : "item"); + t->add(anchor, strategy); + if (!reading_file) { + if (flags==FL_SUBMENU) { + t->label("submenu"); + } else { + t->label("item"); + } + } return t; } +void group_selected_menuitems() { + // The group will be created in the parent group of the current menuitem + if (!Fl_Type::current->is_a(ID_Menu_Item)) { + return; + } + Fl_Menu_Item_Type *q = static_cast(Fl_Type::current); + Fl_Type *qq = Fl_Type::current->parent; + if (!qq || !(qq->is_a(ID_Menu_Manager_) || qq->is_a(ID_Submenu))) { + fl_message("Can't create a new submenu here."); + return; + } + undo_checkpoint(); + undo_suspend(); + Fl_Widget_Type *n = (Fl_Widget_Type*)(q->make(FL_SUBMENU, kAddAfterCurrent)); + for (Fl_Type *t = qq->next; t && (t->level > qq->level);) { + if (t->level != n->level || t == n || !t->selected) { + t = t->next; + continue; + } + Fl_Type *nxt = t->remove(); + t->add(n, kAddAsLastChild); + t = nxt; + } + widget_browser->rebuild(); + undo_resume(); + set_modflag(1); +} + +void ungroup_selected_menuitems() { + // Find the submenu + Fl_Type *qq = Fl_Type::current->parent; + Fl_Widget_Type *q = static_cast(Fl_Type::current); + int q_level = q->level; + if (!qq || !qq->is_a(ID_Submenu)) { + fl_message("Only menu items inside a submenu can be ungrouped."); + return; + } + undo_checkpoint(); + undo_suspend(); + Fl_Type::current = qq; + for (Fl_Type *t = qq->next; t && (t->level > qq->level);) { + if (t->level != q_level || !t->selected) { + t = t->next; + continue; + } + Fl_Type *nxt = t->remove(); + t->insert(qq); + t = nxt; + } + if (!qq->next || (qq->next->level <= qq->level)) { + qq->remove(); + delete qq; // qq has no children that need to be delete + } + Fl_Type::current = q; + widget_browser->rebuild(); + undo_resume(); + set_modflag(1); +} + + /** Create and add a new Checkbox Menu Item node. \param[in] strategy add after current or as last child \return new node */ Fl_Type *Fl_Checkbox_Menu_Item_Type::make(Strategy strategy) { - menuitemtype = FL_MENU_TOGGLE; - Fl_Type* t = Fl_Menu_Item_Type::make(strategy); - menuitemtype = 0; - return t; + return Fl_Menu_Item_Type::make(FL_MENU_TOGGLE, strategy); } /** @@ -193,10 +271,7 @@ Fl_Type *Fl_Checkbox_Menu_Item_Type::make(Strategy strategy) { \return new node */ Fl_Type *Fl_Radio_Menu_Item_Type::make(Strategy strategy) { - menuitemtype = FL_MENU_RADIO; - Fl_Type* t = Fl_Menu_Item_Type::make(strategy); - menuitemtype = 0; - return t; + return Fl_Menu_Item_Type::make(FL_MENU_RADIO, strategy); } /** @@ -205,10 +280,7 @@ Fl_Type *Fl_Radio_Menu_Item_Type::make(Strategy strategy) { \return new node */ Fl_Type *Fl_Submenu_Type::make(Strategy strategy) { - submenuflag = 1; - Fl_Type* t = Fl_Menu_Item_Type::make(strategy); - submenuflag = 0; - return t; + return Fl_Menu_Item_Type::make(FL_SUBMENU, strategy); } Fl_Menu_Item_Type Fl_Menu_Item_type; @@ -234,7 +306,7 @@ const char* Fl_Menu_Item_Type::menu_name(Fd_Code_Writer& f, int& i) { // be sure to count the {0} that ends a submenu: if (t->level > t->next->level) i += (t->level - t->next->level); // detect empty submenu: - else if (t->level == t->next->level && t->is_parent()) i++; + else if (t->level == t->next->level && t->can_have_children()) i++; t = t->prev; i++; } @@ -290,19 +362,49 @@ void Fl_Menu_Item_Type::write_static(Fd_Code_Writer& f) { f.write_c("\n"); // Matt: disabled f.tag(FD_TAG_MENU_CALLBACK, get_uid()); f.write_c("}\n"); + + // If the menu item is part of a Class or Widget Class, FLUID generates + // a dummy static callback which retrieves a pointer to the class and then + // calls the original callback from within the class context. + // k is the name of the enclosing class (or classes) if (k) { + // Implement the callback as a static member function f.write_c("void %s::%s(Fl_Menu_* o, %s v) {\n", k, cn, ut); - f.write_c("%s((%s*)(o", f.indent(1), k); + // Find the Fl_Menu_ container for this menu item Fl_Type* t = parent; while (t->is_a(ID_Menu_Item)) t = t->parent; - Fl_Type *q = 0; - // Go up one more level for Fl_Input_Choice, as these are groups themselves - if (t && t->is_a(ID_Input_Choice)) - f.write_c("->parent()"); - for (t = t->parent; t && t->is_widget() && !is_class(); q = t, t = t->parent) - f.write_c("->parent()"); - if (!q || !q->is_a(ID_Widget_Class)) - f.write_c("->user_data()"); - f.write_c("))->%s_i(o,v);\n}\n", cn); + if (t) { + Fl_Widget_Type *tw = (t->is_widget()) ? static_cast(t) : NULL; + Fl_Type *q = NULL; + // Generate code to call the callback + if (tw->is_a(ID_Menu_Bar) && ((Fl_Menu_Bar_Type*)tw)->is_sys_menu_bar()) { + // Fl_Sys_Menu_Bar removes itself from any parent on macOS, so we + // wrapped it in a class and remeber the parent class in a new + // class memeber variable. + Fl_Menu_Bar_Type *tmb = (Fl_Menu_Bar_Type*)tw; + f.write_c("%s%s* sys_menu_bar = ((%s*)o);\n", f.indent(1), + tmb->sys_menubar_proxy_name(), tmb->sys_menubar_proxy_name()); + f.write_c("%s%s* parent_class = ((%s*)sys_menu_bar->_parent_class);\n", + f.indent(1), k, k); + f.write_c("%sparent_class->%s_i(o,v);\n}\n", + f.indent(1), cn); + } else { + f.write_c("%s((%s*)(o", f.indent(1), k); + // The class pointer is in the user_data field of the top widget + if (t && t->is_a(ID_Input_Choice)) { + // Go up one more level for Fl_Input_Choice, as these are groups themselves + f.write_c("->parent()"); + } + // Now generate code to find the topmost widget in this class + for (t = t->parent; t && t->is_widget() && !is_class(); q = t, t = t->parent) + f.write_c("->parent()"); + // user_data is cast into a pointer to the + if (!q || !q->is_a(ID_Widget_Class)) + f.write_c("->user_data()"); + f.write_c("))->%s_i(o,v);\n}\n", cn); + } + } else { + f.write_c("#error Enclosing Fl_Menu_* not found\n"); + } } } if (image) { @@ -323,7 +425,7 @@ void Fl_Menu_Item_Type::write_static(Fd_Code_Writer& f) { Fl_Type* t = prev; while (t && t->is_a(ID_Menu_Item)) t = t->prev; for (Fl_Type* q = t->next; q && q->is_a(ID_Menu_Item); q = q->next) { ((Fl_Menu_Item_Type*)q)->write_item(f); - int thislevel = q->level; if (q->is_parent()) thislevel++; + int thislevel = q->level; if (q->can_have_children()) thislevel++; int nextlevel = (q->next && q->next->is_a(ID_Menu_Item)) ? q->next->level : t->level+1; while (thislevel > nextlevel) {f.write_c(" {0,0,0,0,0,0,0,0,0},\n"); thislevel--;} @@ -357,7 +459,7 @@ int Fl_Menu_Item_Type::flags() { if (((Fl_Button*)o)->value()) i |= FL_MENU_VALUE; if (!o->active()) i |= FL_MENU_INACTIVE; if (!o->visible()) i |= FL_MENU_INVISIBLE; - if (is_parent()) { + if (can_have_children()) { if (user_data() == NULL) i |= FL_SUBMENU; else i |= FL_SUBMENU_POINTER; } @@ -549,7 +651,7 @@ void Fl_Menu_Base_Type::build_menu() { int n = 0; Fl_Type* q; for (q = next; q && q->level > level; q = q->next) { - if (q->is_parent()) n++; // space for null at end of submenu + if (q->can_have_children()) n++; // space for null at end of submenu n++; } if (!n) { @@ -596,7 +698,7 @@ void Fl_Menu_Base_Type::build_menu() { m->labelfont(i->o->labelfont()); m->labelsize(i->o->labelsize()); m->labelcolor(i->o->labelcolor()); - if (q->is_parent()) {lvl++; m->flags |= FL_SUBMENU;} + if (q->can_have_children()) {lvl++; m->flags |= FL_SUBMENU;} m++; int l1 = (q->next && q->next->is_a(ID_Menu_Item)) ? q->next->level : level; @@ -700,10 +802,80 @@ Fl_Type* Fl_Input_Choice_Type::click_test(int, int) { Fl_Menu_Bar_Type Fl_Menu_Bar_type; -//////////////////////////////////////////////////////////////// -// Shortcut entry item in panel: +Fl_Menu_Item menu_bar_type_menu[] = { + {"Fl_Menu_Bar",0,0,(void*)0}, + {"Fl_Sys_Menu_Bar",0,0,(void*)1}, + {0}}; + +Fl_Menu_Bar_Type::Fl_Menu_Bar_Type() +: _proxy_name(NULL) +{ +} + +Fl_Menu_Bar_Type::~Fl_Menu_Bar_Type() { + if (_proxy_name) + ::free(_proxy_name); +} + +/** + \brief Return true if this is an Fl_Sys_Menu_Bar. + This test fails if subclass() is the name of a class that the user may have + derived from Fl_Sys_Menu_Bar. + */ +bool Fl_Menu_Bar_Type::is_sys_menu_bar() { + if (o->type()==1) return true; + return ( subclass() && (strcmp(subclass(), "Fl_Sys_Menu_Bar")==0) ); +} +const char *Fl_Menu_Bar_Type::sys_menubar_name() { + if (subclass()) + return subclass(); + else + return "Fl_Sys_Menu_Bar"; +} + +const char *Fl_Menu_Bar_Type::sys_menubar_proxy_name() { + if (!_proxy_name) + _proxy_name = (char*)::malloc(128); + ::snprintf(_proxy_name, 63, "%s_Proxy", sys_menubar_name()); + return _proxy_name; +} + +void Fl_Menu_Bar_Type::write_static(Fd_Code_Writer& f) { + super::write_static(f); + if (is_sys_menu_bar()) { + f.write_h_once("#include "); + if (is_in_class()) { + // Make room for a pointer to the enclosing class. + f.write_c_once( // must be less than 1024 bytes! + "\nclass %s: public %s {\n" + "public:\n" + " %s(int x, int y, int w, int h, const char *l=NULL)\n" + " : %s(x, y, w, h, l) { }\n" + " void *_parent_class;\n" + "};\n", + sys_menubar_proxy_name(), sys_menubar_name(), + sys_menubar_proxy_name(), sys_menubar_name() + ); + } + } +} + +void Fl_Menu_Bar_Type::write_code1(Fd_Code_Writer& f) { + super::write_code1(f); + if (is_sys_menu_bar() && is_in_class()) { + f.write_c("%s((%s*)%s)->_parent_class = (void*)this;\n", + f.indent(), sys_menubar_proxy_name(), name() ? name() : "o"); + } +} + +//void Fl_Menu_Bar_Type::write_code2(Fd_Code_Writer& f) { +// super::write_code2(f); +//} + +//////////////////////////////////////////////////////////////// +// Shortcut entry item in panel: void shortcut_in_cb(Fl_Shortcut_Button* i, void* v) { if (v == LOAD) { if (current_widget->is_button()) diff --git a/libraries/fltk/fluid/Fl_Menu_Type.h b/libraries/fltk/fluid/Fl_Menu_Type.h index 3824270a67..41bddced6c 100644 --- a/libraries/fltk/fluid/Fl_Menu_Type.h +++ b/libraries/fltk/fluid/Fl_Menu_Type.h @@ -35,6 +35,7 @@ extern Fl_Menu_Item dummymenu[]; extern Fl_Menu_Item button_type_menu[]; extern Fl_Menu_Item menu_item_type_menu[]; +extern Fl_Menu_Item menu_bar_type_menu[]; /** \brief Manage all types on menu items. @@ -50,6 +51,7 @@ class Fl_Menu_Item_Type : public Fl_Button_Type const char* type_name() FL_OVERRIDE {return "MenuItem";} const char* alt_type_name() FL_OVERRIDE {return "fltk::Item";} Fl_Type* make(Strategy strategy) FL_OVERRIDE; + Fl_Type* make(int flags, Strategy strategy); int is_button() const FL_OVERRIDE {return 1;} // this gets shortcut to work Fl_Widget* widget(int,int,int,int) FL_OVERRIDE {return 0;} Fl_Widget_Type* _make() FL_OVERRIDE {return 0;} @@ -104,7 +106,7 @@ class Fl_Submenu_Type : public Fl_Menu_Item_Type Fl_Menu_Item* subtypes() FL_OVERRIDE {return 0;} const char* type_name() FL_OVERRIDE {return "Submenu";} const char* alt_type_name() FL_OVERRIDE {return "fltk::ItemGroup";} - int is_parent() const FL_OVERRIDE {return 1;} + int can_have_children() const FL_OVERRIDE {return 1;} int is_button() const FL_OVERRIDE {return 0;} // disable shortcut Fl_Type* make(Strategy strategy) FL_OVERRIDE; // changes to submenu must propagate up so build_menu is called @@ -132,7 +134,7 @@ class Fl_Menu_Manager_Type : public Fl_Widget_Type w = layout->textsize_not_null() * 6 + 8; Fd_Snap_Action::better_size(w, h); } - int is_parent() const FL_OVERRIDE {return 1;} + int can_have_children() const FL_OVERRIDE {return 1;} int menusize; virtual void build_menu() = 0; Fl_Menu_Manager_Type() : Fl_Widget_Type() {menusize = 0;} @@ -204,7 +206,7 @@ class Fl_Menu_Base_Type : public Fl_Menu_Manager_Type return 1; } public: - int is_parent() const FL_OVERRIDE {return 1;} + int can_have_children() const FL_OVERRIDE {return 1;} void build_menu() FL_OVERRIDE; ~Fl_Menu_Base_Type() { if (menusize) delete[] (Fl_Menu_Item*)(((Fl_Menu_*)o)->menu()); @@ -261,13 +263,24 @@ class Fl_Choice_Type : public Fl_Menu_Base_Type class Fl_Menu_Bar_Type : public Fl_Menu_Base_Type { typedef Fl_Menu_Base_Type super; + Fl_Menu_Item *subtypes() FL_OVERRIDE {return menu_bar_type_menu;} public: + Fl_Menu_Bar_Type(); + ~Fl_Menu_Bar_Type() FL_OVERRIDE; const char *type_name() FL_OVERRIDE {return "Fl_Menu_Bar";} const char *alt_type_name() FL_OVERRIDE {return "fltk::MenuBar";} Fl_Widget *widget(int X,int Y,int W,int H) FL_OVERRIDE {return new Fl_Menu_Bar(X,Y,W,H);} Fl_Widget_Type *_make() FL_OVERRIDE {return new Fl_Menu_Bar_Type();} + void write_static(Fd_Code_Writer& f) FL_OVERRIDE; + void write_code1(Fd_Code_Writer& f) FL_OVERRIDE; +// void write_code2(Fd_Code_Writer& f) FL_OVERRIDE; ID id() const FL_OVERRIDE { return ID_Menu_Bar; } bool is_a(ID inID) const FL_OVERRIDE { return (inID==ID_Menu_Bar) ? true : super::is_a(inID); } + bool is_sys_menu_bar(); + const char *sys_menubar_name(); + const char *sys_menubar_proxy_name(); +protected: + char *_proxy_name; }; diff --git a/libraries/fltk/fluid/Fl_Type.cxx b/libraries/fltk/fluid/Fl_Type.cxx index 1654bfd209..eada84e5e4 100644 --- a/libraries/fltk/fluid/Fl_Type.cxx +++ b/libraries/fltk/fluid/Fl_Type.cxx @@ -130,6 +130,143 @@ Fl_Type *in_this_only; // set if menu popped-up in window // ---- various functions +#if 0 +#ifndef NDEBUG +/** + Print the current project tree to stderr. + */ +void print_project_tree() { + fprintf(stderr, "---- %s --->\n", g_project.projectfile_name().c_str()); + for (Fl_Type *t = Fl_Type::first; t; t = t->next) { + for (int i = t->level; i > 0; i--) + fprintf(stderr, ". "); + fprintf(stderr, "%s\n", subclassname(t)); + } +} +#endif + +#ifndef NDEBUG +/** + Check the validity of the project tree. + + Write problems with the project tree to stderr. + + \return true if the project tree is valid + */ +bool validate_project_tree() { + // Validate `first` and `last` + if (Fl_Type::first == NULL) { + if (Fl_Type::last == NULL) { + return true; + } else { + fprintf(stderr, "ERROR: `first` is NULL, but `last` is not!\n"); + return false; + } + } + if (Fl_Type::last == NULL) { + fprintf(stderr, "ERROR: `last` is NULL, but `first` is not!\n"); + return false; + } + // Validate the branch linkage, parent links, etc. + return validate_branch(Fl_Type::first); +} +#endif + +#ifndef NDEBUG +/** + Check the validity of a Type branch that is not connected to the project. + + Write problems with the branch to stderr. + + \param[in] root the first node in a branch + \return true if the branch is correctly separated and valid + */ +bool validate_independent_branch(class Fl_Type *root) { + // Make sure that `first` and `last` do not point at any node in this branch + if (Fl_Type::first) { + for (Fl_Type *t = root; t; t = t->next) { + if (Fl_Type::first == t) { + fprintf(stderr, "ERROR: Branch is not independent, `first` is pointing to branch member!\n"); + return false; + } + } + } + if (Fl_Type::last) { + for (Fl_Type *t = root; t; t = t->next) { + if (Fl_Type::last == t) { + fprintf(stderr, "ERROR: Branch is not independent, `last` is pointing to branch member!\n"); + return false; + } + } + } + // Validate the branch linkage, parent links, etc. + return validate_branch(root); +} +#endif + +#ifndef NDEBUG +/** + Check the validity of a Type branch. + + Write problems with the branch to stderr. + + \param[in] root the first node in a branch + \return true if the branch is valid + */ +bool validate_branch(class Fl_Type *root) { + // Only check real branches + if (!root) { + fprintf(stderr, "WARNING: Branch is empty!\n"); + return false; + } + // Check relation between this and next node + for (Fl_Type *t = root; t; t = t->next) { + if (t->level < root->level) { + fprintf(stderr, "ERROR: Node in tree is above root level!\n"); + return false; + } + if (t->next) { + // Make sure that all `next` types have the `prev` member link back + if (t->next->prev != t) { + fprintf(stderr, "ERROR: Doubly linked list broken!\n"); + return false; + } + if (t->next->level > t->level) { + // Validate `level` changes + if (t->next->level - t->level > 1) { + fprintf(stderr, "ERROR: Child level increment greater than one!\n"); + return false; + } + // Ensure that this node can actually have children + if (!t->can_have_children()) { + fprintf(stderr, "ERROR: This parent must not have children!\n"); + return false; + } + } + } + // Validate the `parent` entry + for (Fl_Type *p = t->prev; ; p = p->prev) { + if (p == NULL) { + if (t->parent != NULL) { + fprintf(stderr, "ERROR: `parent` pointer should be NULL!\n"); + return false; + } + break; + } + if (p->level < t->level) { + if (t->parent != p) { + fprintf(stderr, "ERROR: `parent` points to wrong parent!\n"); + return false; + } + break; + } + } + } + return true; +} +#endif +#endif + void select_all_cb(Fl_Widget *,void *) { Fl_Type *p = Fl_Type::current ? Fl_Type::current->parent : 0; if (in_this_only) { @@ -317,7 +454,7 @@ int storestring(const char *n, const char * & p, int nostrip) { void update_visibility_flag(Fl_Type *p) { Fl_Type *t = p; for (;;) { - if (t->parent) t->visible = t->parent->visible && t->parent->open_; + if (t->parent) t->visible = t->parent->visible && !t->parent->folded_; else t->visible = 1; t = t->next; if (!t || t->level <= p->level) break; @@ -352,30 +489,33 @@ void update_visibility_flag(Fl_Type *p) { Constructor and base for any node in the widget tree. */ Fl_Type::Fl_Type() : -uid_(0), -code_static_start(-1), code_static_end(-1), -code1_start(-1), code1_end(-1), -code2_start(-1), code2_end(-1), -header1_start(-1), header1_end(-1), -header2_start(-1), header2_end(-1), -header_static_start(-1), header_static_end(-1), -proj1_start(-1), proj1_end(-1), -proj2_start(-1), proj2_end(-1) + name_(NULL), + label_(NULL), + callback_(NULL), + user_data_(NULL), + user_data_type_(NULL), + comment_(NULL), + uid_(0), + parent(NULL), + new_selected(0), + selected(0), + folded_(0), + visible(0), + level(0), + next(NULL), prev(NULL), + factory(NULL), + code_static_start(-1), code_static_end(-1), + code1_start(-1), code1_end(-1), + code2_start(-1), code2_end(-1), + header1_start(-1), header1_end(-1), + header2_start(-1), header2_end(-1), + header_static_start(-1), header_static_end(-1), + proj1_start(-1), proj1_end(-1), + proj2_start(-1), proj2_end(-1) { - factory = 0; - parent = 0; - next = prev = 0; - selected = new_selected = 0; - visible = 0; - name_ = 0; - label_ = 0; - user_data_ = 0; - user_data_type_ = 0; - callback_ = 0; - comment_ = 0; - level = 0; } + /** Destructor for any node in the tree. @@ -470,42 +610,85 @@ Fl_Group_Type *Fl_Type::group() { \param[in] p insert \c this tree as a child of \c p \param[in] strategy is kAddAsLastChild or kAddAfterCurrent */ -void Fl_Type::add(Fl_Type *p, Strategy strategy) { - if (p && parent == p) return; - undo_checkpoint(); - parent = p; - // 'this' is not in the Widget_Browser, so we must run the linked list to find the last entry +void Fl_Type::add(Fl_Type *anchor, Strategy strategy) { +#if 0 +#ifndef NDEBUG + // print_project_tree(); + // fprintf(stderr, "Validating project\n"); + validate_project_tree(); + // fprintf(stderr, "Validating branch\n"); + validate_independent_branch(this); +#endif +#endif + + Fl_Type *target = NULL; // insert self before target node, if NULL, insert last + Fl_Type *target_parent = NULL; // this will be the new parent for branch + int target_level = 0; // adjust self to this new level + + // Find the node after our insertion position + switch (strategy) { + case kAddAsFirstChild: + if (anchor == NULL) { + target = Fl_Type::first; + } else { + target = anchor->next; + target_level = anchor->level + 1; + target_parent = anchor; + } + break; + case kAddAsLastChild: + if (anchor == NULL) { + /* empty */ + } else { + for (target = anchor->next; target && target->level > anchor->level; target = target->next) {/*empty*/} + target_level = anchor->level + 1; + target_parent = anchor; + } + break; + case kAddAfterCurrent: + if (anchor == NULL) { + target = Fl_Type::first; + } else { + for (target = anchor->next; target && target->level > anchor->level; target = target->next) {/*empty*/} + target_level = anchor->level; + target_parent = anchor->parent; + } + break; + } + + + // Find the last node of our tree Fl_Type *end = this; while (end->next) end = end->next; - // run the list again to set the future node levels - Fl_Type *q; // insert 'this' before q - int newlevel; - if (p) { - // find the last node that is a child or grandchild of p - for (q = p->next; q && q->level > p->level; q = q->next) {/*empty*/} - newlevel = p->level+1; + + // Everything is prepared, now insert ourself in front of the target node + undo_checkpoint(); + + // Walk the tree to update parent pointers and levels + int source_level = level; + for (Fl_Type *t = this; t; t = t->next) { + t->level += (target_level-source_level); + if (t->level == target_level) + t->parent = target_parent; + } + + // Now link ourselves and our children before 'target', or last, if 'target' is NULL + if (target) { + prev = target->prev; + target->prev = end; + end->next = target; } else { - q = 0; - newlevel = 0; + prev = Fl_Type::last; + end->next = NULL; + Fl_Type::last = end; } - for (Fl_Type *t = this->next; t; t = t->next) t->level += (newlevel-level); - level = newlevel; - // now link 'this' and its children before 'q', or last, if 'q' is NULL - if (q) { - prev = q->prev; + if (prev) { prev->next = this; - q->prev = end; - end->next = q; - } else if (first) { - prev = last; - prev->next = this; - end->next = 0; - last = end; } else { - first = this; - last = end; - prev = end->next = 0; + Fl_Type::first = this; } + +#if 0 { // make sure that we have no duplicate uid's Fl_Type *tp = this; do { @@ -513,28 +696,24 @@ void Fl_Type::add(Fl_Type *p, Strategy strategy) { tp = tp->next; } while (tp!=end && tp!=NULL); } +#endif - // tell this that it was added, so it can update itself - if (p) p->add_child(this,0); - open_ = 1; - update_visibility_flag(this); - set_modflag(1); - - if (strategy==kAddAfterCurrent && current) { - // we have current, t is the new node, p is the parent - // find the next child of the parent after current - //t->add(p); // add as a last child - Fl_Type *cc; - for (cc = current->next; cc; cc = cc->next) { - if (cc->level <= this->level) - break; - } - if (cc && cc->level==this->level && cc!=this) { - this->move_before(cc); - } - select(this, 1); + // Give the widgets in our tree a chance to update themselves + for (Fl_Type *t = this; t && t!=end->next; t = t->next) { + if (target_parent && (t->level == target_level)) + target_parent->add_child(t, 0); + update_visibility_flag(t); } + + set_modflag(1); widget_browser->redraw(); + +#if 0 +#ifndef NDEBUG + // fprintf(stderr, "Validating project after adding branch\n"); + validate_project_tree(); +#endif +#endif } /** @@ -713,7 +892,7 @@ void Fl_Type::write(Fd_Project_Writer &f) { if (parent) parent->write_parent_properties(f, this, true); f.write_close(level); if (f.write_codeview()) proj1_end = (int)ftell(f.file()); - if (!is_parent()) { + if (!can_have_children()) { if (f.write_codeview()) proj2_end = (int)ftell(f.file()); return; } @@ -757,7 +936,7 @@ void Fl_Type::write_properties(Fd_Project_Writer &f) { f.write_word("comment"); f.write_word(comment()); } - if (is_parent() && open_) f.write_word("open"); + if (can_have_children() && !folded_) f.write_word("open"); if (selected) f.write_word("selected"); } @@ -779,7 +958,7 @@ void Fl_Type::read_property(Fd_Project_Reader &f, const char *c) { else if (!strcmp(c,"comment")) comment(f.read_word()); else if (!strcmp(c,"open")) - open_ = 1; + folded_ = 0; else if (!strcmp(c,"selected")) select(this,1); else if (!strcmp(c,"parent_properties")) @@ -1006,6 +1185,19 @@ const char *Fl_Type::callback_name(Fd_Code_Writer& f) { return f.unique_id(this, "cb", name(), label()); } +/** + \brief Return the class name if this type is inside a Class or Widget Class. + + This methods traverses up the hirarchy to find out if this Type is located + inside a Class or Widget Class. It then return the name of that class. If + need_nest is set, class_name searches all the way up the tree and concatenates + the names of classes within classes, separated by a "::". + + \param need_nest if clear, search up one level to the first enclosing class. + If set, recurse all the way up to the top node. + \return the name of the enclosing class, or names of the enclosing classes + in a static buffe (don't call free), or NULL if this Type is not inside a class + */ const char* Fl_Type::class_name(const int need_nest) const { Fl_Type* p = parent; while (p) { diff --git a/libraries/fltk/fluid/Fl_Type.h b/libraries/fltk/fluid/Fl_Type.h index 7a3a5fc72b..59bd895562 100644 --- a/libraries/fltk/fluid/Fl_Type.h +++ b/libraries/fltk/fluid/Fl_Type.h @@ -29,8 +29,25 @@ class Fl_Window_Type; class Fd_Project_Reader; class Fd_Project_Writer; +/** + Declare where a new type is placed in the hierarchy. + + Note that a type can also be the start of a hierarchy of types. In that case, + + \see Fl_Type *Fl_..._Type::make(Strategy strategy) calls `add()` + Add single Type: + Fl_Type *add_new_widget_from_user(Fl_Type *inPrototype, Strategy strategy, bool and_open) + Fl_Type *add_new_widget_from_user(const char *inName, Strategy strategy, bool and_open) + Fl_Type *add_new_widget_from_file(const char *inName, Strategy strategy) + Add a hierarchy of Types + void Fl_Type::add(Fl_Type *p, Strategy strategy) + int read_file(const char *filename, int merge, Strategy strategy) + Fl_Type *Fd_Project_Reader::read_children(Fl_Type *p, int merge, Strategy strategy, char skip_options) + int Fd_Project_Reader::read_project(const char *filename, int merge, Strategy strategy) + */ typedef enum { - kAddAsLastChild = 0, + kAddAsFirstChild = 0, + kAddAsLastChild, kAddAfterCurrent } Strategy; @@ -76,6 +93,13 @@ void select_none_cb(Fl_Widget *,void *); void earlier_cb(Fl_Widget*,void*); void later_cb(Fl_Widget*,void*); +#ifndef NDEBUG +void print_project_tree(); +bool validate_project_tree(); +bool validate_independent_branch(class Fl_Type *root); +bool validate_branch(class Fl_Type *root); +#endif + /** \brief This is the base class for all elements in the project tree. @@ -134,7 +158,7 @@ class Fl_Type { (see `haderror`). It seems that this is often confused with new_selected which seems to hold the true and visible selection state. */ char selected; // copied here by selection_changed() - char open_; // state of triangle in browser + char folded_; // if set, children are not shown in browser char visible; // true if all parents are open int level; // number of parents over this static Fl_Type *first, *last; @@ -229,12 +253,13 @@ class Fl_Type { virtual Fl_Widget *enter_live_mode(int top=0); // build widgets needed for live mode virtual void leave_live_mode(); // free allocated resources virtual void copy_properties(); // copy properties from this type into a potential live object + virtual void copy_properties_for_children() { } // copy remaining properties after children were added // get message number for I18N int msgnum(); /** Return 1 if the Type can have children. */ - virtual int is_parent() const {return 0;} + virtual int can_have_children() const {return 0;} /** Return 1 if the type is a widget or menu item. */ virtual int is_widget() const {return 0;} /** Return 1 if the type is a widget but not a menu item. */ diff --git a/libraries/fltk/fluid/Fl_Widget_Type.cxx b/libraries/fltk/fluid/Fl_Widget_Type.cxx index 5864b6ab61..4048933bc0 100644 --- a/libraries/fltk/fluid/Fl_Widget_Type.cxx +++ b/libraries/fltk/fluid/Fl_Widget_Type.cxx @@ -1,7 +1,7 @@ // // Widget type code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -54,12 +54,17 @@ int Fl_Widget_Type::is_widget() const {return 1;} int Fl_Widget_Type::is_public() const {return public_;} const char* subclassname(Fl_Type* l) { + if (l->is_a(ID_Menu_Bar)) { + Fl_Menu_Bar_Type *mb = static_cast(l); + if (mb->is_sys_menu_bar()) + return mb->sys_menubar_name(); + } if (l->is_widget()) { Fl_Widget_Type* p = (Fl_Widget_Type*)l; const char* c = p->subclass(); if (c) return c; if (l->is_class()) return "Fl_Group"; - if (p->o->type() == FL_WINDOW+1) return "Fl_Double_Window"; + if (p->o->type() == FL_DOUBLE_WINDOW) return "Fl_Double_Window"; if (p->id() == ID_Input) { if (p->o->type() == FL_FLOAT_INPUT) return "Fl_Float_Input"; if (p->o->type() == FL_INT_INPUT) return "Fl_Int_Input"; @@ -82,19 +87,20 @@ Fl_Widget_Type::ideal_size(int &w, int &h) { \return new node */ Fl_Type *Fl_Widget_Type::make(Strategy strategy) { - // Find the current widget, or widget to copy: - Fl_Type *qq = Fl_Type::current; - while (qq && (!qq->is_true_widget() || !qq->is_parent())) qq = qq->parent; - if (!qq) { + Fl_Type *anchor = Fl_Type::current, *pp = anchor; + if (pp && (strategy == kAddAfterCurrent)) pp = pp->parent; + while (pp && !pp->is_a(ID_Group)) { + anchor = pp; + strategy = kAddAfterCurrent; + pp = pp->parent; + } + if (!pp || !pp->is_true_widget() || !anchor->is_true_widget()) { fl_message("Please select a group widget or window"); return 0; } - Fl_Widget_Type* q = (Fl_Widget_Type*)qq; - // find the parent widget: - Fl_Widget_Type* p = q; - if ((force_parent || !p->is_a(ID_Group)) && p->parent && p->parent->is_widget()) - p = (Fl_Widget_Type*)(p->parent); - force_parent = 0; + + Fl_Widget_Type* p = (Fl_Widget_Type*)pp; + Fl_Widget_Type* q = (Fl_Widget_Type*)anchor; // Figure out a border between widget and window: int B = p->o->w()/2; if (p->o->h()/2 < B) B = p->o->h()/2; if (B>25) B = 25; @@ -141,7 +147,7 @@ Fl_Type *Fl_Widget_Type::make(Strategy strategy) { // Put it in the parent: // ((Fl_Group *)(p->o))->add(t->o); (done by Fl_Type::add()) // add to browser: - t->add(p, strategy); + t->add(anchor, strategy); t->redraw(); return t; } @@ -1962,6 +1968,93 @@ void textcolor_menu_cb(Fl_Menu_Button* i, void* v) { } } +void image_spacing_cb(Fl_Value_Input* i, void* v) { + int s; + if (v == LOAD) { + if (!current_widget->is_true_widget()) { + i->deactivate(); + i->value(0); + } else { + i->activate(); + i->value(((Fl_Widget_Type*)current_widget)->o->label_image_spacing()); + } + } else { + int mod = 0; + s = int(i->value()); + for (Fl_Type *o = Fl_Type::first; o; o = o->next) { + if (o->selected && o->is_true_widget()) { + Fl_Widget_Type* q = (Fl_Widget_Type*)o; + if (q->o->label_image_spacing() != s) { + q->o->label_image_spacing(s); + if (!(q->o->align() & FL_ALIGN_INSIDE) && q->o->window()) + q->o->window()->damage(FL_DAMAGE_EXPOSE); // outside labels + q->o->redraw(); + mod = 1; + } + } + } + if (mod) set_modflag(1); + } +} + +void h_label_margin_cb(Fl_Value_Input* i, void* v) { + int s; + if (v == LOAD) { + if (!current_widget->is_true_widget()) { + i->deactivate(); + i->value(0); + } else { + i->activate(); + i->value(((Fl_Widget_Type*)current_widget)->o->horizontal_label_margin()); + } + } else { + int mod = 0; + s = int(i->value()); + for (Fl_Type *o = Fl_Type::first; o; o = o->next) { + if (o->selected && o->is_true_widget()) { + Fl_Widget_Type* q = (Fl_Widget_Type*)o; + if (q->o->horizontal_label_margin() != s) { + q->o->horizontal_label_margin(s); + if (!(q->o->align() & FL_ALIGN_INSIDE) && q->o->window()) + q->o->window()->damage(FL_DAMAGE_EXPOSE); // outside labels + q->o->redraw(); + mod = 1; + } + } + } + if (mod) set_modflag(1); + } +} + +void v_label_margin_cb(Fl_Value_Input* i, void* v) { + int s; + if (v == LOAD) { + if (!current_widget->is_true_widget()) { + i->deactivate(); + i->value(0); + } else { + i->activate(); + i->value(((Fl_Widget_Type*)current_widget)->o->vertical_label_margin()); + } + } else { + int mod = 0; + s = int(i->value()); + for (Fl_Type *o = Fl_Type::first; o; o = o->next) { + if (o->selected && o->is_true_widget()) { + Fl_Widget_Type* q = (Fl_Widget_Type*)o; + if (q->o->vertical_label_margin() != s) { + q->o->vertical_label_margin(s); + if (!(q->o->align() & FL_ALIGN_INSIDE) && q->o->window()) + q->o->window()->damage(FL_DAMAGE_EXPOSE); // outside labels + q->o->redraw(); + mod = 1; + } + } + } + if (mod) set_modflag(1); + } +} + //////////////////////////////////////////////////////////////// // Kludges to the panel for subclasses: @@ -2929,7 +3022,7 @@ void Fl_Widget_Type::write_code1(Fd_Code_Writer& f) { f.varused = wused; if (!name() && !f.varused) { - f.varused |= is_parent(); + f.varused |= can_have_children(); if (!f.varused) { f.varused_test = 1; @@ -2991,6 +3084,12 @@ void Fl_Widget_Type::write_code1(Fd_Code_Writer& f) { f.write_c("new %s(0, 0, %d, %d", t, o->w(), o->h()); else f.write_c("new %s(%d, %d", t, o->w(), o->h()); + } else if (is_a(ID_Menu_Bar) + && ((Fl_Menu_Bar_Type*)this)->is_sys_menu_bar() + && is_in_class()) { + f.write_c("(%s*)new %s(%d, %d, %d, %d", + t, ((Fl_Menu_Bar_Type*)this)->sys_menubar_proxy_name(), + o->x(), o->y(), o->w(), o->h()); } else { f.write_c("new %s(%d, %d, %d, %d", t, o->x(), o->y(), o->w(), o->h()); } @@ -3178,6 +3277,12 @@ void Fl_Widget_Type::write_widget_code(Fd_Code_Writer& f) { f.write_c("%s%s->labelsize(%d);\n", f.indent(), var, o->labelsize()); if (o->labelcolor() != tplate->labelcolor() || subclass()) write_color(f, "labelcolor", o->labelcolor()); + if (o->horizontal_label_margin() != tplate->horizontal_label_margin()) + f.write_c("%s%s->horizontal_label_margin(%d);\n", f.indent(), var, o->horizontal_label_margin()); + if (o->vertical_label_margin() != tplate->vertical_label_margin()) + f.write_c("%s%s->vertical_label_margin(%d);\n", f.indent(), var, o->vertical_label_margin()); + if (o->label_image_spacing() != tplate->label_image_spacing()) + f.write_c("%s%s->label_image_spacing(%d);\n", f.indent(), var, o->label_image_spacing()); if (is_a(ID_Valuator_)) { Fl_Valuator* v = (Fl_Valuator*)o; Fl_Valuator* t = (Fl_Valuator*)(tplate); @@ -3357,6 +3462,12 @@ void Fl_Widget_Type::write_properties(Fd_Project_Writer &f) { f.write_string("labelcolor %d", o->labelcolor()); if (o->align()!=tplate->align()) f.write_string("align %d", o->align()); + if (o->horizontal_label_margin()!=tplate->horizontal_label_margin()) + f.write_string("h_label_margin %d", o->horizontal_label_margin()); + if (o->vertical_label_margin()!=tplate->vertical_label_margin()) + f.write_string("v_label_margin %d", o->vertical_label_margin()); + if (o->label_image_spacing()!=tplate->label_image_spacing()) + f.write_string("image_spacing %d", o->label_image_spacing()); if (o->when() != tplate->when()) f.write_string("when %d", o->when()); if (is_a(ID_Valuator_)) { @@ -3526,6 +3637,12 @@ void Fl_Widget_Type::read_property(Fd_Project_Reader &f, const char *c) { if (sscanf(f.read_word(),"%d",&x) == 1) o->labelcolor(x); } else if (!strcmp(c,"align")) { if (sscanf(f.read_word(),"%d",&x) == 1) o->align(x); + } else if (!strcmp(c,"h_label_margin")) { + if (sscanf(f.read_word(),"%d",&x) == 1) o->horizontal_label_margin(x); + } else if (!strcmp(c,"v_label_margin")) { + if (sscanf(f.read_word(),"%d",&x) == 1) o->vertical_label_margin(x); + } else if (!strcmp(c,"image_spacing")) { + if (sscanf(f.read_word(),"%d",&x) == 1) o->label_image_spacing(x); } else if (!strcmp(c,"when")) { if (sscanf(f.read_word(),"%d",&x) == 1) o->when(x); } else if (!strcmp(c,"minimum")) { @@ -3717,6 +3834,8 @@ Fl_Widget* Fl_Widget_Type::propagate_live_mode(Fl_Group* grp) { } } grp->end(); + live_widget = grp; + copy_properties_for_children(); return live_widget; } diff --git a/libraries/fltk/fluid/Fl_Window_Type.cxx b/libraries/fltk/fluid/Fl_Window_Type.cxx index 2e77d386c9..e539d671aa 100644 --- a/libraries/fltk/fluid/Fl_Window_Type.cxx +++ b/libraries/fltk/fluid/Fl_Window_Type.cxx @@ -5,7 +5,7 @@ // for interacting with the overlay, which allows the user to // select, move, and resize the children widgets. // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -108,7 +108,7 @@ void show_settings_cb(Fl_Widget *, void *) { Fl_Menu_Item window_type_menu[] = { {"Single",0,0,(void*)FL_WINDOW}, - {"Double",0,0,(void*)(FL_WINDOW+1)}, + {"Double",0,0,(void*)(FL_DOUBLE_WINDOW)}, {0}}; static int overlays_invisible; @@ -227,8 +227,13 @@ int Overlay_Window::handle(int e) { \return new node */ Fl_Type *Fl_Window_Type::make(Strategy strategy) { - Fl_Type *p = Fl_Type::current; - while (p && (!p->is_code_block() || p->is_a(ID_Widget_Class))) p = p->parent; + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && (!p->is_code_block() || p->is_a(ID_Widget_Class))) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } if (!p) { fl_message("Please select a function"); return 0; @@ -245,7 +250,7 @@ Fl_Type *Fl_Window_Type::make(Strategy strategy) { w->size_range(10, 10); w->window = myo; myo->o = w; - myo->add(p, strategy); + myo->add(anchor, strategy); myo->modal = 0; myo->non_modal = 0; return myo; @@ -408,7 +413,12 @@ Fl_Window_Type Fl_Window_type; // Resize from window manager... void Overlay_Window::resize(int X,int Y,int W,int H) { - Fl_Widget* t = resizable(); resizable(0); + undo_checkpoint_once(kUndoWindowResize); + + Fl_Widget* t = resizable(); + if (Fl_Type::allow_layout == 0) { + resizable(0); + } // do not set the mod flag if the window was not resized. In FLUID, all // windows are opened without a given x/y position, so modifying x/y @@ -1358,8 +1368,13 @@ Fl_Widget_Class_Type *current_widget_class = 0; \return new node */ Fl_Type *Fl_Widget_Class_Type::make(Strategy strategy) { - Fl_Type *p = Fl_Type::current; - while (p && (!p->is_decl_block() || (p->is_widget() && p->is_class()))) p = p->parent; + Fl_Type *anchor = Fl_Type::current, *p = anchor; + if (p && (strategy == kAddAfterCurrent)) p = p->parent; + while (p && (!p->is_decl_block() || (p->is_widget() && p->is_class()))) { + anchor = p; + strategy = kAddAfterCurrent; + p = p->parent; + } Fl_Widget_Class_Type *myo = new Fl_Widget_Class_Type(); myo->name("UserInterface"); @@ -1374,7 +1389,7 @@ Fl_Type *Fl_Widget_Class_Type::make(Strategy strategy) { w->size_range(10, 10); w->window = myo; myo->o = w; - myo->add(p, strategy); + myo->add(anchor, strategy); myo->modal = 0; myo->non_modal = 0; myo->wc_relative = 0; @@ -1530,6 +1545,9 @@ void Fl_Window_Type::leave_live_mode() { copy all properties from the edit widget to the live widget */ void Fl_Window_Type::copy_properties() { + Fl_Window *self = static_cast(o); + Fl_Window *live = static_cast(live_widget); + if (self->resizable() == self) + live->resizable(live); Fl_Widget_Type::copy_properties(); - /// \todo copy resizing constraints over } diff --git a/libraries/fltk/fluid/Fl_Window_Type.h b/libraries/fltk/fluid/Fl_Window_Type.h index 779c7b787f..3b9a03e625 100644 --- a/libraries/fltk/fluid/Fl_Window_Type.h +++ b/libraries/fltk/fluid/Fl_Window_Type.h @@ -113,7 +113,7 @@ class Fl_Window_Type : public Fl_Group_Type void move_child(Fl_Type*, Fl_Type*) FL_OVERRIDE; void remove_child(Fl_Type*) FL_OVERRIDE; - int is_parent() const FL_OVERRIDE {return 1;} + int can_have_children() const FL_OVERRIDE {return 1;} Fl_Widget *enter_live_mode(int top=0) FL_OVERRIDE; void leave_live_mode() FL_OVERRIDE; @@ -148,7 +148,7 @@ class Fl_Widget_Class_Type : private Fl_Window_Type const char *type_name() FL_OVERRIDE {return "widget_class";} ID id() const FL_OVERRIDE { return ID_Widget_Class; } bool is_a(ID inID) const FL_OVERRIDE { return (inID==ID_Widget_Class) ? true : super::is_a(inID); } - int is_parent() const FL_OVERRIDE {return 1;} + int can_have_children() const FL_OVERRIDE {return 1;} int is_code_block() const FL_OVERRIDE {return 1;} int is_decl_block() const FL_OVERRIDE {return 1;} int is_class() const FL_OVERRIDE {return 1;} diff --git a/libraries/fltk/fluid/Makefile b/libraries/fltk/fluid/Makefile index eb5b8c192a..ae8037441a 100644 --- a/libraries/fltk/fluid/Makefile +++ b/libraries/fltk/fluid/Makefile @@ -1,7 +1,7 @@ # # FLUID Makefile for the Fast Light Tool Kit (FLTK). # -# Copyright 1998-2023 by Bill Spitzak and others. +# Copyright 1998-2024 by Bill Spitzak and others. # # This library is free software. Distribution and use rights are outlined in # the file "COPYING" which should have been included with this file. If this @@ -97,45 +97,45 @@ include makedepend install: all echo "Installing FLUID in $(DESTDIR)$(bindir)..." - -$(INSTALL_DIR) $(DESTDIR)$(bindir) - $(INSTALL_BIN) $(FLUID) $(DESTDIR)$(bindir)/fluid$(EXEEXT) + -$(INSTALL_DIR) "$(DESTDIR)$(bindir)" + $(INSTALL_BIN) $(FLUID) "$(DESTDIR)$(bindir)/fluid$(EXEEXT)" install-linux: - -$(INSTALL_DIR) $(DESTDIR)/usr/share/applications - $(INSTALL_DATA) fluid.desktop $(DESTDIR)/usr/share/applications + -$(INSTALL_DIR) "$(DESTDIR)$(datadir)/applications" + $(INSTALL_DATA) fluid.desktop "$(DESTDIR)$(datadir)/applications" for size in 16 32 48 64 128; do \ - if test ! -d $(DESTDIR)/usr/share/icons/hicolor/$${size}x$${size}/apps; then \ - $(INSTALL_DIR) $(DESTDIR)/usr/share/icons/hicolor/$${size}x$${size}/apps; \ + if test ! -d "$(DESTDIR)$(datadir)/icons/hicolor/$${size}x$${size}/apps"; then \ + $(INSTALL_DIR) "$(DESTDIR)$(datadir)/icons/hicolor/$${size}x$${size}/apps"; \ fi; \ - $(INSTALL_DATA) icons/fluid-$$size.png $(DESTDIR)/usr/share/icons/hicolor/$${size}x$${size}/apps/fluid.png; \ + $(INSTALL_DATA) icons/fluid-$$size.png "$(DESTDIR)$(datadir)/icons/hicolor/$${size}x$${size}/apps/fluid.png"; \ done - -$(INSTALL_DIR) $(DESTDIR)/usr/share/mimelnk/application - $(INSTALL_DATA) x-fluid.desktop $(DESTDIR)/usr/share/mimelnk/application + -$(INSTALL_DIR) "$(DESTDIR)$(datadir)/mimelnk/application" + $(INSTALL_DATA) x-fluid.desktop "$(DESTDIR)$(datadir)/mimelnk/application" install-osx: echo Installing Fluid in $(DESTDIR)/Applications... - -$(INSTALL_DIR) $(DESTDIR)/Applications/fluid.app - -$(INSTALL_DIR) $(DESTDIR)/Applications/fluid.app/Contents - $(INSTALL_DATA) fluid.app/Contents/Info.plist $(DESTDIR)/Applications/fluid.app/Contents/Info.plist - -$(INSTALL_DIR) $(DESTDIR)/Applications/fluid.app/Contents/MacOS - $(RM) $(DESTDIR)/Applications/fluid.app/Contents/MacOS/fluid - $(LN) $(bindir)/fluid $(DESTDIR)/Applications/fluid.app/Contents/MacOS/fluid - -$(INSTALL_DIR) $(DESTDIR)/Applications/fluid.app/Contents/Resources - $(INSTALL_DATA) fluid.app/Contents/Resources/fluid.icns $(DESTDIR)/Applications/fluid.app/Contents/Resources + -$(INSTALL_DIR) "$(DESTDIR)/Applications/fluid.app" + -$(INSTALL_DIR) "$(DESTDIR)/Applications/fluid.app/Contents" + $(INSTALL_DATA) fluid.app/Contents/Info.plist "$(DESTDIR)/Applications/fluid.app/Contents/Info.plist" + -$(INSTALL_DIR) "$(DESTDIR)/Applications/fluid.app/Contents/MacOS" + $(RM) "$(DESTDIR)/Applications/fluid.app/Contents/MacOS/fluid" + $(LN) "$(bindir)/fluid" "$(DESTDIR)/Applications/fluid.app/Contents/MacOS/fluid" + -$(INSTALL_DIR) "$(DESTDIR)/Applications/fluid.app/Contents/Resources" + $(INSTALL_DATA) fluid.app/Contents/Resources/fluid.icns "$(DESTDIR)/Applications/fluid.app/Contents/Resources" uninstall: - $(RM) $(DESTDIR)$(bindir)/fluid$(EXEEXT) + $(RM) "$(DESTDIR)$(bindir)/fluid$(EXEEXT)" uninstall-linux: - $(RM) $(DESTDIR)/usr/share/applications/fluid.desktop - $(RM) $(DESTDIR)/usr/share/icons/hicolor/*/fluid.png - $(RM) $(DESTDIR)/usr/share/mimelnk/application/x-fluid.desktop + $(RM) "$(DESTDIR)$(datadir)/applications/fluid.desktop" + $(RM) "$(DESTDIR)$(datadir)/icons/hicolor"/*/fluid.png + $(RM) "$(DESTDIR)$(datadir)/mimelnk/application/x-fluid.desktop" uninstall-osx: - $(RM) -r $(DESTDIR)/Applications/fluid.app + $(RM) -r "$(DESTDIR)/Applications/fluid.app" # Note: The rebuild target can only be used if you have the original .fl -# files. This is normally only used by the FLTK maintainers... +# files. This is normally only used by FLTK maintainers... # It *must* be executed *after* fluid has been built and # fluid must be rebuilt if any {.fl|.cxx|.h} files were changed. diff --git a/libraries/fltk/fluid/README_fl.txt b/libraries/fltk/fluid/README_fl.txt index 056ddeb51e..c52b4d091c 100644 --- a/libraries/fltk/fluid/README_fl.txt +++ b/libraries/fltk/fluid/README_fl.txt @@ -468,6 +468,9 @@ Type "Fl_Widget" : C++ variable name "labelsize" : integer "labelcolor" : integer, color index "align" : integer, see Fl_Align + "h_label_margin" : integer, horizontal label margin + "v_label_margin" : integer, vertical label margin + "image_spacing" : integer, see Fl_Widget::label_image_spacing() "when" : integer, see Fl_When "minimum" : (is_valuator(), is_spinner()) double "maximum" : (is_valuator(), is_spinner()) double diff --git a/libraries/fltk/fluid/autodoc.cxx b/libraries/fltk/fluid/autodoc.cxx index b12a848fa9..0f2ea8e4ad 100644 --- a/libraries/fltk/fluid/autodoc.cxx +++ b/libraries/fltk/fluid/autodoc.cxx @@ -417,7 +417,7 @@ void run_autodoc(const Fl_String &target_dir) { main_window->size(350, 320); fl_snapshot((target_dir + "main_window.png").c_str(), main_window, win_margin, win_blend); fl_snapshot((target_dir + "main_menubar.png").c_str(), main_menubar, row_margin, row_blend); - fl_snapshot((target_dir + "main_browser.png").c_str(), widget_browser, FL_SNAP_AREA_CLEAR, + fl_snapshot((target_dir + "main_browser.png").c_str(), widget_browser, FL_SNAP_AREA_CLEAR, Fl_Rect(0, 30, FL_SNAP_TO_WINDOW, 100), row_blend, 2.0); @@ -437,7 +437,8 @@ void run_autodoc(const Fl_String &target_dir) { // explain widgets types an their dnd option // explain menu arrays // list exceptions (subwindow, scroll) - if (!widgetbin_panel) make_widgetbin(); + Fl::wait(0.2); + Fl::flush(); fl_snapshot((target_dir + "widgetbin_panel.png").c_str(), widgetbin_panel, win_margin, win_blend); // ---- code view @@ -446,8 +447,13 @@ void run_autodoc(const Fl_String &target_dir) { // show various tabs // explain find and locate if (!codeview_panel) make_codeview(); - update_codeview_cb(NULL, NULL); + codeview_panel->show(); + Fl::wait(0.2); + Fl::flush(); + update_codeview_cb(NULL, NULL); // must be visible on screen for this to work cv_tab->value(cv_source_tab); + codeview_panel->redraw(); + Fl::flush(); fl_snapshot((target_dir + "codeview_panel.png").c_str(), codeview_panel, win_margin, win_blend); fl_snapshot((target_dir + "cv_find_row.png").c_str(), cv_find_row, row_margin, row_blend); fl_snapshot((target_dir + "cv_settings_row.png").c_str(), cv_settings_row, row_margin, row_blend); diff --git a/libraries/fltk/fluid/code.cxx b/libraries/fltk/fluid/code.cxx index 873b9d7896..f10777c3e1 100644 --- a/libraries/fltk/fluid/code.cxx +++ b/libraries/fltk/fluid/code.cxx @@ -1,7 +1,7 @@ // // Code output routines for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -1091,7 +1091,7 @@ int Fd_Code_Writer::crc_puts(const char *text) { /** Write a single ASCII character to the code file. If MergeBack is enabled, the CRC calculation is continued. - \note to wrote UTF8 characters, use Fd_Code_Writer::crc_puts(const char *text) + \note to write UTF-8 characters, use Fd_Code_Writer::crc_puts(const char *text) \param[in] c any character between 0 and 127 inclusive \return see fputc(int, FILE*) */ diff --git a/libraries/fltk/fluid/codeview_panel.cxx b/libraries/fltk/fluid/codeview_panel.cxx index 0ca8c0d3a4..6246d66411 100644 --- a/libraries/fltk/fluid/codeview_panel.cxx +++ b/libraries/fltk/fluid/codeview_panel.cxx @@ -32,7 +32,7 @@ extern void reveal_in_browser(Fl_Type *t); /** Update the header and source code highlighting depending on the currently selected object - + The Code View system offers an immediate preview of the code files that will be generated by FLUID. It also marks the code generated for the last selected item in the header and the source diff --git a/libraries/fltk/fluid/documentation/CMakeLists.txt b/libraries/fltk/fluid/documentation/CMakeLists.txt index fb2fac442b..fccdeac97a 100644 --- a/libraries/fltk/fluid/documentation/CMakeLists.txt +++ b/libraries/fltk/fluid/documentation/CMakeLists.txt @@ -15,7 +15,6 @@ # set(DOCS) -set(GIT_REVISION "") set(YEAR "") set(CURRENT_DATE "") @@ -38,26 +37,6 @@ if(FLTK_BUILD_FLUID_DOCS OR FLTK_BUILD_PDF_DOCS) OUTPUT_STRIP_TRAILING_WHITESPACE ) - # find git revision - - # FIXME: This must also work with tarballs where git is not available. - # For now we just ignore errors and set GIT_REVISION = "unknown". - # In the future tarball/zip generation should create a file - # that contains the git revision. - - execute_process(COMMAND - git rev-parse --short=10 HEAD - OUTPUT_VARIABLE GIT_REVISION - OUTPUT_STRIP_TRAILING_WHITESPACE - WORKING_DIRECTORY ${FLTK_SOURCE_DIR} - ERROR_QUIET - ) - - # set to "'unknown'" if git is not available - if(GIT_REVISION STREQUAL "") - set(GIT_REVISION "'unknown'") - endif() - # Find "short" doxygen version if it was built from Git # Note: this is still needed in CMake 3.12.0 but later CMake versions # (notably 3.25) remove the Git revision in 'DOXYGEN_VERSION'. diff --git a/libraries/fltk/fluid/documentation/generated.dox.in b/libraries/fltk/fluid/documentation/generated.dox.in index 9ab6987e03..fc6afa0091 100644 --- a/libraries/fltk/fluid/documentation/generated.dox.in +++ b/libraries/fltk/fluid/documentation/generated.dox.in @@ -1,6 +1,6 @@
    Generated on @CURRENT_DATE@ - from Git revision @GIT_REVISION@ - by Doxygen @DOXYGEN_VERSION_SHORT@ + from Git revision @FLTK_GIT_REVISION@ + by Doxygen version @DOXYGEN_VERSION_SHORT@ diff --git a/libraries/fltk/fluid/documentation/src/fluid-title.tex.in b/libraries/fltk/fluid/documentation/src/fluid-title.tex.in index f0036d417f..7cd13d794a 100644 --- a/libraries/fltk/fluid/documentation/src/fluid-title.tex.in +++ b/libraries/fltk/fluid/documentation/src/fluid-title.tex.in @@ -11,7 +11,7 @@ \end{DoxyImageNoCaption}\\ \vspace*{2cm} {\Large -By F. Costantini, D. Gibson, M. Melcher, \\ +By F. Costantini, M. Melcher, \\ A. Schlosser, B. Spitzak, and M. Sweet.}\\ \vspace*{1.5cm} {\large Copyright © 1998 - @YEAR@ by Bill Spitzak and others.}\\ @@ -23,11 +23,11 @@ Permission is granted to reproduce this manual or any portion for any purpose,}\ {\small provided this copyright and permission notice are preserved.}\\ \vspace*{1.5cm} -{\large Generated by Doxygen @DOXY_VERSION@}\\ +{\large Generated by Doxygen @DOXYGEN_VERSION_SHORT@}\\ \vspace*{0.5cm} \today{}\\ \vspace*{0.5cm} -{\small Git revision @GIT_REVISION@}\\ +{\small Git revision @FLTK_GIT_REVISION@}\\ \end{center} \end{titlepage} % diff --git a/libraries/fltk/fluid/documentation/src/index.dox b/libraries/fltk/fluid/documentation/src/index.dox index 984981de36..9e858fcd63 100644 --- a/libraries/fltk/fluid/documentation/src/index.dox +++ b/libraries/fltk/fluid/documentation/src/index.dox @@ -16,7 +16,7 @@
    FLUID 1.4.0 User Manual - By F. Costantini, D. Gibson, M. Melcher, + By F. Costantini, M. Melcher, A. Schlosser, B. Spitzak and M. Sweet. Copyright © 1998 - 2024 by Bill Spitzak and others. diff --git a/libraries/fltk/fluid/documentation/src/page_main_window.dox b/libraries/fltk/fluid/documentation/src/page_main_window.dox index 005ce01ec4..4cb7777e5f 100644 --- a/libraries/fltk/fluid/documentation/src/page_main_window.dox +++ b/libraries/fltk/fluid/documentation/src/page_main_window.dox @@ -51,7 +51,7 @@ project windows. The *New From Template* item opens a dialog that provides access to a small number of sample projects. More projects can be added using *Save as Template*. - + Use *Write Code* to write the header and source code files, and *Write Strings* to write the translation file if one of the internationalization options is active. @@ -257,10 +257,11 @@ __Edit > Later (F3)__: Move all of the selected widgets one later in order among the children of their parent (if possible). __Edit > Group (F7)__: Create a new Fl_Group and make all the currently -selected widgets children of it. +selected widgets children of that group. -__Edit > Ungroup (F8)__: Delete the parent group if all the children of a -group are selected. +__Edit > Ungroup (F8)__: Move the selected children of a group out of the +group and up one level in the hierarchy. If all children of a group are +selected and moved, the remaining empty group is deleted. __Edit > Show or Hide Overlays (Ctrl+Shift+O)__: Toggle the display of the red overlays off, without changing the selection. This makes it easier to see @@ -345,6 +346,11 @@ the first selected widget. __Layout > Center in Group > ...__: Center all selected widgets relative to their parent widget +__Layout > Synchronized Resize__: If unchecked, groups and windows can be +resized without resizing their children. If set, the layout of the children +is changed according to their `resize()` settings. Try __Live Resize__ to +verify the effects before permanently modifying the layout. + __Layout > Grid and Size Settings... (Ctrl+g)__: Display the grid settings panel. See \ref setting_layout . diff --git a/libraries/fltk/fluid/documentation/src/page_widget_panel.dox b/libraries/fltk/fluid/documentation/src/page_widget_panel.dox index eac9d7c635..7a1261d62b 100644 --- a/libraries/fltk/fluid/documentation/src/page_widget_panel.dox +++ b/libraries/fltk/fluid/documentation/src/page_widget_panel.dox @@ -212,6 +212,11 @@ using hierarchies of groups. Resizing of a window or group can be tested using the *live resize* button. + Note that the *Resizable* indicator is ambiguous when a window is selected. + Making a window resizable will resize all children proportionally. Setting + a child of a window will make that child the center of the resize operation. + In both cases, the *Resizable* indicator of the window will be set. + The *Hotspot* button causes the parent window to be positioned with that widget centered on the mouse. This position is determined when the FLUID function is called, diff --git a/libraries/fltk/fluid/factory.cxx b/libraries/fltk/fluid/factory.cxx index a4072967f8..56077020c4 100644 --- a/libraries/fltk/fluid/factory.cxx +++ b/libraries/fltk/fluid/factory.cxx @@ -1342,11 +1342,11 @@ Fl_Type *add_new_widget_from_user(const char *inName, Strategy strategy, bool an } /** - Callback for all menu items. + Callback for all non-widget menu items. */ static void cbf(Fl_Widget *, void *v) { Fl_Type *t = NULL; - if (Fl_Type::current && Fl_Type::current->is_a(ID_Group)) + if (Fl_Type::current && Fl_Type::current->can_have_children()) t = ((Fl_Type*)v)->make(kAddAsLastChild); else t = ((Fl_Type*)v)->make(kAddAfterCurrent); @@ -1354,11 +1354,11 @@ static void cbf(Fl_Widget *, void *v) { } /** - Callback for all menu items. + Callback for all widget menu items. */ static void cb(Fl_Widget *, void *v) { Fl_Type *t = NULL; - if (Fl_Type::current && Fl_Type::current->is_a(ID_Group)) + if (Fl_Type::current && Fl_Type::current->can_have_children()) t = add_new_widget_from_user((Fl_Type*)v, kAddAsLastChild); else t = add_new_widget_from_user((Fl_Type*)v, kAddAfterCurrent); diff --git a/libraries/fltk/fluid/file.cxx b/libraries/fltk/fluid/file.cxx index e71f4b9a6d..cdbf10d624 100644 --- a/libraries/fltk/fluid/file.cxx +++ b/libraries/fltk/fluid/file.cxx @@ -227,6 +227,7 @@ int Fd_Project_Reader::read_quoted() { // read whatever character is after Fl_Type *Fd_Project_Reader::read_children(Fl_Type *p, int merge, Strategy strategy, char skip_options) { Fl_Type::current = p; Fl_Type *last_child_read = NULL; + Fl_Type *t = NULL; for (;;) { const char *c = read_word(); REUSE_C: @@ -353,44 +354,43 @@ Fl_Type *Fd_Project_Reader::read_children(Fl_Type *p, int merge, Strategy strate goto CONTINUE; } } - { - Fl_Type *t = add_new_widget_from_file(c, strategy); - if (!t) { - read_error("Unknown word \"%s\"", c); - continue; - } - last_child_read = t; - // After reading the first widget, we no longer need to look for options - skip_options = 1; + t = add_new_widget_from_file(c, strategy); + if (!t) { + read_error("Unknown word \"%s\"", c); + continue; + } + last_child_read = t; + // After reading the first widget, we no longer need to look for options + skip_options = 1; - t->name(read_word()); + t->name(read_word()); + c = read_word(1); + if (strcmp(c,"{") && t->is_class()) { // + ((Fl_Class_Type*)t)->prefix(t->name()); + t->name(c); c = read_word(1); - if (strcmp(c,"{") && t->is_class()) { // - ((Fl_Class_Type*)t)->prefix(t->name()); - t->name(c); - c = read_word(1); - } + } - if (strcmp(c,"{")) { - read_error("Missing property list for %s\n",t->title()); - goto REUSE_C; - } + if (strcmp(c,"{")) { + read_error("Missing property list for %s\n",t->title()); + goto REUSE_C; + } - t->open_ = 0; - for (;;) { - const char *cc = read_word(); - if (!cc || !strcmp(cc,"}")) break; - t->read_property(*this, cc); - } + t->folded_ = 1; + for (;;) { + const char *cc = read_word(); + if (!cc || !strcmp(cc,"}")) break; + t->read_property(*this, cc); + } - if (!t->is_parent()) continue; + if (t->can_have_children()) { c = read_word(1); if (strcmp(c,"{")) { read_error("Missing child list for %s\n",t->title()); goto REUSE_C; } - read_children(t, 0, strategy, skip_options); + read_children(t, 0, kAddAsLastChild, skip_options); t->postprocess_read(); // FIXME: this has no business in the file reader! // TODO: this is called whenever something is pasted from the top level into a grid @@ -406,7 +406,14 @@ Fl_Type *Fd_Project_Reader::read_children(Fl_Type *p, int merge, Strategy strate t->layout_widget(); } - Fl_Type::current = p; + if (strategy == kAddAsFirstChild) { + strategy = kAddAfterCurrent; + } + if (strategy == kAddAfterCurrent) { + Fl_Type::current = t; + } else { + Fl_Type::current = p; + } CONTINUE:; } diff --git a/libraries/fltk/fluid/fluid.cxx b/libraries/fltk/fluid/fluid.cxx index 01f9a93a14..44814574e0 100644 --- a/libraries/fltk/fluid/fluid.cxx +++ b/libraries/fltk/fluid/fluid.cxx @@ -106,11 +106,6 @@ int G_debug = 0; char G_external_editor_command[512]; -/// If set, if the `current` node is a group, and a new group is added, it will -/// be added as sibling to the first group instead of inside the group. -/// \todo Needs to be verified. -int force_parent = 0; - /// This is set to create different labels when creating new widgets. /// \todo Details unclear. int reading_file = 0; @@ -1360,6 +1355,7 @@ void copy_cb(Fl_Widget*, void*) { fl_beep(); return; } + flush_text_widgets(); ipasteoffset = 10; if (!write_file(cutfname(),1)) { fl_message("Can't write %s: %s", cutfname(), strerror(errno)); @@ -1375,6 +1371,7 @@ void cut_cb(Fl_Widget *, void *) { fl_beep(); return; } + flush_text_widgets(); if (!write_file(cutfname(),1)) { fl_message("Can't write %s: %s", cutfname(), strerror(errno)); return; @@ -1409,15 +1406,25 @@ void delete_cb(Fl_Widget *, void *) { /** User chose to paste the widgets from the cut buffer. + + This function will paste the widgets in the cut buffer after the currently + selected widget. If the currently selected widget is a group widget and + it is not folded, the new widgets will be added inside the group. */ void paste_cb(Fl_Widget*, void*) { - //if (ipasteoffset) force_parent = 1; pasteoffset = ipasteoffset; undo_checkpoint(); undo_suspend(); Strategy strategy = kAddAfterCurrent; - if (Fl_Type::current && Fl_Type::current->is_a(ID_Group)) - strategy = kAddAsLastChild; + if (Fl_Type::current && Fl_Type::current->can_have_children()) { + if (Fl_Type::current->folded_ == 0) { + // If the current widget is a group widget and it is not folded, + // add the new widgets inside the group. + strategy = kAddAsLastChild; + // The following alternative also works quite nicely + //strategy = kAddAsFirstChild; + } + } if (!read_file(cutfname(), 1, strategy)) { widget_browser->rebuild(); fl_message("Can't read %s: %s", cutfname(), strerror(errno)); @@ -1427,11 +1434,14 @@ void paste_cb(Fl_Widget*, void*) { widget_browser->rebuild(); pasteoffset = 0; ipasteoffset += 10; - force_parent = 0; } /** Duplicate the selected widgets. + + This code is a bit complex because it needs to find the last selected + widget with the lowest level, so that the new widgets are inserted after + this one. */ void duplicate_cb(Fl_Widget*, void*) { if (!Fl_Type::current) { @@ -1439,16 +1449,31 @@ void duplicate_cb(Fl_Widget*, void*) { return; } + // flush the text widgets to make sure the user's changes are saved: flush_text_widgets(); + // find the last selected node with the lowest level: + int lowest_level = 9999; + Fl_Type *new_insert = NULL; + if (Fl_Type::current->selected) { + for (Fl_Type *t = Fl_Type::first; t; t = t->next) { + if (t->selected && (t->level <= lowest_level)) { + lowest_level = t->level; + new_insert = t; + } + } + } + if (new_insert) + Fl_Type::current = new_insert; + + // write the selected widgets to a file: if (!write_file(cutfname(1),1)) { fl_message("Can't write %s: %s", cutfname(1), strerror(errno)); return; } + // read the file and add the widgets after the current one: pasteoffset = 0; - force_parent = 1; - undo_checkpoint(); undo_suspend(); if (!read_file(cutfname(1), 1, kAddAfterCurrent)) { @@ -1458,8 +1483,6 @@ void duplicate_cb(Fl_Widget*, void*) { widget_browser->display(Fl_Type::current); widget_browser->rebuild(); undo_resume(); - - force_parent = 0; } /** @@ -1637,7 +1660,8 @@ static void menu_file_new_from_template_cb(Fl_Widget *, void *) { new_project_fr static void menu_file_open_cb(Fl_Widget *, void *) { open_project_file(""); } static void menu_file_insert_cb(Fl_Widget *, void *) { merge_project_file(""); } static void menu_file_open_history_cb(Fl_Widget *, void *v) { open_project_file(Fl_String((const char*)v)); } - +static void menu_layout_sync_resize_cb(Fl_Menu_ *m, void*) { + if (m->mvalue()->value()) Fl_Type::allow_layout = 1; else Fl_Type::allow_layout = 0; } /** This is the main Fluid menu. @@ -1722,10 +1746,11 @@ Fl_Menu_Item Main_Menu[] = { {"&Height",0,(Fl_Callback *)align_widget_cb,(void*)31}, {"&Both",0,(Fl_Callback *)align_widget_cb,(void*)32}, {0}, - {"&Center In Group",0,0,0,FL_SUBMENU|FL_MENU_DIVIDER}, + {"&Center In Group",0,0,0,FL_SUBMENU}, {"&Horizontal",0,(Fl_Callback *)align_widget_cb,(void*)40}, {"&Vertical",0,(Fl_Callback *)align_widget_cb,(void*)41}, {0}, + {"Synchronized Resize", 0, (Fl_Callback*)menu_layout_sync_resize_cb, NULL, FL_MENU_TOGGLE|FL_MENU_DIVIDER }, {"&Grid and Size Settings...",FL_COMMAND+'g',show_grid_cb, NULL, FL_MENU_DIVIDER}, {"Presets", 0, layout_suite_marker, (void*)main_layout_submenu_, FL_SUBMENU_POINTER }, {"Application", 0, select_layout_preset_cb, (void*)0, FL_MENU_RADIO|FL_MENU_VALUE }, diff --git a/libraries/fltk/fluid/fluid.h b/libraries/fltk/fluid/fluid.h index 95f4dc4ddd..2f92a6e11c 100644 --- a/libraries/fltk/fluid/fluid.h +++ b/libraries/fltk/fluid/fluid.h @@ -51,8 +51,6 @@ typedef enum { // ---- global variables -extern int force_parent; - extern Fl_Preferences fluid_prefs; extern Fl_Menu_Item Main_Menu[]; extern Fl_Menu_Bar *main_menubar; diff --git a/libraries/fltk/fluid/fluid.plist b/libraries/fltk/fluid/fluid.plist index 4f0333f0ae..6c4d68946b 100644 --- a/libraries/fltk/fluid/fluid.plist +++ b/libraries/fltk/fluid/fluid.plist @@ -13,7 +13,7 @@ CFBundleDevelopmentRegion English NSHumanReadableCopyright - Copyright 1998-2021 by Bill Spitzak and others + Copyright 1998-2024 by Bill Spitzak and others CFAppleHelpAnchor help CFBundleName @@ -27,7 +27,7 @@ CFBundleShortVersionString 1.4.0 CFBundleGetInfoString - 1.4.0, Copyright 1998-2021 by Bill Spitzak and others + 1.4.0, Copyright 1998-2024 by Bill Spitzak and others CFBundleDocumentTypes diff --git a/libraries/fltk/fluid/function_panel.cxx b/libraries/fltk/fluid/function_panel.cxx index 856a1dddd2..a9c4eb265e 100644 --- a/libraries/fltk/fluid/function_panel.cxx +++ b/libraries/fltk/fluid/function_panel.cxx @@ -765,7 +765,7 @@ Fl_Double_Window* make_comment_panel() { void type_make_cb(Fl_Widget*,void*d) { const char *type_name = (const char*)d; - if (Fl_Type::current && Fl_Type::current->is_parent()) + if (Fl_Type::current && Fl_Type::current->can_have_children()) add_new_widget_from_user(type_name, kAddAsLastChild); else add_new_widget_from_user(type_name, kAddAfterCurrent); diff --git a/libraries/fltk/fluid/function_panel.fl b/libraries/fltk/fluid/function_panel.fl index 6e153ded30..faa465e8d9 100644 --- a/libraries/fltk/fluid/function_panel.fl +++ b/libraries/fltk/fluid/function_panel.fl @@ -588,7 +588,7 @@ Function {make_comment_panel()} {open Function {type_make_cb(Fl_Widget*,void*d)} {open return_type void } { code {const char *type_name = (const char*)d; -if (Fl_Type::current && Fl_Type::current->is_parent()) +if (Fl_Type::current && Fl_Type::current->can_have_children()) add_new_widget_from_user(type_name, kAddAsLastChild); else add_new_widget_from_user(type_name, kAddAfterCurrent);} {} diff --git a/libraries/fltk/fluid/icons/fluid-32.xpm b/libraries/fltk/fluid/icons/fluid-32.xpm index 9fb63f5a61..24eb3bb263 100644 --- a/libraries/fltk/fluid/icons/fluid-32.xpm +++ b/libraries/fltk/fluid/icons/fluid-32.xpm @@ -1,5 +1,5 @@ /* XPM */ -static char * const fluid_32_xpm[] = { +static const char * const fluid_32_xpm[] = { "32 32 32 1", " c None", ". c #000200", diff --git a/libraries/fltk/fluid/icons/fluid-96.xpm b/libraries/fltk/fluid/icons/fluid-96.xpm index 0e0b11d4e1..bec9958d34 100644 --- a/libraries/fltk/fluid/icons/fluid-96.xpm +++ b/libraries/fltk/fluid/icons/fluid-96.xpm @@ -1,5 +1,5 @@ /* XPM */ -static char * const fluid_96_xpm[] = { +static const char * const fluid_96_xpm[] = { "96 96 32 1", " c None", ". c #000100", diff --git a/libraries/fltk/fluid/makedepend b/libraries/fltk/fluid/makedepend index cdef22f261..f91d59377a 100644 --- a/libraries/fltk/fluid/makedepend +++ b/libraries/fltk/fluid/makedepend @@ -26,89 +26,6 @@ about_panel.o: ../FL/Fl_Window.H about_panel.o: ../FL/platform_types.h about_panel.o: ../src/flstring.h about_panel.o: about_panel.h -settings_panel.o: ../config.h -settings_panel.o: ../FL/Enumerations.H -settings_panel.o: ../FL/filename.H -settings_panel.o: ../FL/Fl.H -settings_panel.o: ../FL/fl_ask.H -settings_panel.o: ../FL/fl_attr.h -settings_panel.o: ../FL/Fl_Bitmap.H -settings_panel.o: ../FL/Fl_Box.H -settings_panel.o: ../FL/Fl_Browser.H -settings_panel.o: ../FL/Fl_Browser_.H -settings_panel.o: ../FL/Fl_Button.H -settings_panel.o: ../FL/Fl_Cairo.H -settings_panel.o: ../FL/fl_casts.H -settings_panel.o: ../FL/Fl_Check_Button.H -settings_panel.o: ../FL/Fl_Choice.H -settings_panel.o: ../FL/fl_config.h -settings_panel.o: ../FL/Fl_Device.H -settings_panel.o: ../FL/Fl_Double_Window.H -settings_panel.o: ../FL/fl_draw.H -settings_panel.o: ../FL/Fl_Export.H -settings_panel.o: ../FL/Fl_File_Browser.H -settings_panel.o: ../FL/Fl_File_Chooser.H -settings_panel.o: ../FL/Fl_File_Icon.H -settings_panel.o: ../FL/Fl_File_Input.H -settings_panel.o: ../FL/Fl_Flex.H -settings_panel.o: ../FL/Fl_Graphics_Driver.H -settings_panel.o: ../FL/Fl_Group.H -settings_panel.o: ../FL/Fl_Image.H -settings_panel.o: ../FL/Fl_Input.H -settings_panel.o: ../FL/Fl_Input_.H -settings_panel.o: ../FL/Fl_Int_Input.H -settings_panel.o: ../FL/Fl_Light_Button.H -settings_panel.o: ../FL/Fl_Menu_.H -settings_panel.o: ../FL/Fl_Menu_Button.H -settings_panel.o: ../FL/Fl_Menu_Item.H -settings_panel.o: ../FL/Fl_Multi_Label.H -settings_panel.o: ../FL/Fl_Native_File_Chooser.H -settings_panel.o: ../FL/Fl_Pack.H -settings_panel.o: ../FL/Fl_Pixmap.H -settings_panel.o: ../FL/Fl_Plugin.H -settings_panel.o: ../FL/Fl_PNG_Image.H -settings_panel.o: ../FL/Fl_Preferences.H -settings_panel.o: ../FL/Fl_Rect.H -settings_panel.o: ../FL/Fl_Repeat_Button.H -settings_panel.o: ../FL/Fl_Return_Button.H -settings_panel.o: ../FL/Fl_RGB_Image.H -settings_panel.o: ../FL/Fl_Scheme.H -settings_panel.o: ../FL/Fl_Scheme_Choice.H -settings_panel.o: ../FL/Fl_Scrollbar.H -settings_panel.o: ../FL/Fl_Shortcut_Button.H -settings_panel.o: ../FL/fl_show_colormap.H -settings_panel.o: ../FL/Fl_Slider.H -settings_panel.o: ../FL/Fl_Spinner.H -settings_panel.o: ../FL/fl_string_functions.h -settings_panel.o: ../FL/Fl_Tabs.H -settings_panel.o: ../FL/Fl_Terminal.H -settings_panel.o: ../FL/Fl_Text_Buffer.H -settings_panel.o: ../FL/Fl_Text_Display.H -settings_panel.o: ../FL/Fl_Text_Editor.H -settings_panel.o: ../FL/Fl_Tile.H -settings_panel.o: ../FL/Fl_Tooltip.H -settings_panel.o: ../FL/fl_types.h -settings_panel.o: ../FL/fl_utf8.h -settings_panel.o: ../FL/Fl_Valuator.H -settings_panel.o: ../FL/Fl_Value_Input.H -settings_panel.o: ../FL/Fl_Widget.H -settings_panel.o: ../FL/Fl_Window.H -settings_panel.o: ../FL/Fl_Wizard.H -settings_panel.o: ../FL/platform_types.h -settings_panel.o: ../src/flstring.h -settings_panel.o: ../src/Fl_String.H -settings_panel.o: settings_panel.h -settings_panel.o: code.h -settings_panel.o: Fd_Snap_Action.h -settings_panel.o: fluid.h -settings_panel.o: fluid_filename.h -settings_panel.o: Fl_Group_Type.h -settings_panel.o: Fl_Type.h -settings_panel.o: Fl_Widget_Type.h -settings_panel.o: Fl_Window_Type.h -settings_panel.o: shell_command.h -settings_panel.o: undo.h -settings_panel.o: widget_browser.h align_widget.o: ../FL/Enumerations.H align_widget.o: ../FL/filename.H align_widget.o: ../FL/Fl.H @@ -148,6 +65,98 @@ align_widget.o: Fl_Group_Type.h align_widget.o: Fl_Type.h align_widget.o: Fl_Widget_Type.h align_widget.o: undo.h +autodoc.o: ../FL/Enumerations.H +autodoc.o: ../FL/filename.H +autodoc.o: ../FL/Fl.H +autodoc.o: ../FL/fl_ask.H +autodoc.o: ../FL/fl_attr.h +autodoc.o: ../FL/Fl_Bitmap.H +autodoc.o: ../FL/Fl_Box.H +autodoc.o: ../FL/Fl_Browser.H +autodoc.o: ../FL/Fl_Browser_.H +autodoc.o: ../FL/Fl_Button.H +autodoc.o: ../FL/Fl_Cairo.H +autodoc.o: ../FL/fl_casts.H +autodoc.o: ../FL/Fl_Check_Button.H +autodoc.o: ../FL/Fl_Choice.H +autodoc.o: ../FL/fl_config.h +autodoc.o: ../FL/Fl_Device.H +autodoc.o: ../FL/Fl_Double_Window.H +autodoc.o: ../FL/fl_draw.H +autodoc.o: ../FL/Fl_Export.H +autodoc.o: ../FL/Fl_File_Browser.H +autodoc.o: ../FL/Fl_File_Chooser.H +autodoc.o: ../FL/Fl_File_Icon.H +autodoc.o: ../FL/Fl_File_Input.H +autodoc.o: ../FL/Fl_Flex.H +autodoc.o: ../FL/Fl_Graphics_Driver.H +autodoc.o: ../FL/Fl_Group.H +autodoc.o: ../FL/Fl_Image.H +autodoc.o: ../FL/Fl_Image_Surface.H +autodoc.o: ../FL/Fl_Input.H +autodoc.o: ../FL/Fl_Input_.H +autodoc.o: ../FL/Fl_Input_Choice.H +autodoc.o: ../FL/Fl_Int_Input.H +autodoc.o: ../FL/Fl_Light_Button.H +autodoc.o: ../FL/Fl_Menu_.H +autodoc.o: ../FL/Fl_Menu_Bar.H +autodoc.o: ../FL/Fl_Menu_Button.H +autodoc.o: ../FL/Fl_Menu_Item.H +autodoc.o: ../FL/Fl_Multi_Label.H +autodoc.o: ../FL/Fl_Native_File_Chooser.H +autodoc.o: ../FL/Fl_Pack.H +autodoc.o: ../FL/Fl_Pixmap.H +autodoc.o: ../FL/Fl_Plugin.H +autodoc.o: ../FL/Fl_PNG_Image.H +autodoc.o: ../FL/Fl_Preferences.H +autodoc.o: ../FL/Fl_Rect.H +autodoc.o: ../FL/Fl_Repeat_Button.H +autodoc.o: ../FL/Fl_Return_Button.H +autodoc.o: ../FL/Fl_RGB_Image.H +autodoc.o: ../FL/Fl_Scheme.H +autodoc.o: ../FL/Fl_Scheme_Choice.H +autodoc.o: ../FL/Fl_Scrollbar.H +autodoc.o: ../FL/Fl_Shared_Image.H +autodoc.o: ../FL/Fl_Shortcut_Button.H +autodoc.o: ../FL/fl_show_colormap.H +autodoc.o: ../FL/Fl_Slider.H +autodoc.o: ../FL/Fl_Spinner.H +autodoc.o: ../FL/fl_string_functions.h +autodoc.o: ../FL/Fl_Tabs.H +autodoc.o: ../FL/Fl_Terminal.H +autodoc.o: ../FL/Fl_Text_Buffer.H +autodoc.o: ../FL/Fl_Text_Display.H +autodoc.o: ../FL/Fl_Text_Editor.H +autodoc.o: ../FL/Fl_Tile.H +autodoc.o: ../FL/fl_types.h +autodoc.o: ../FL/fl_utf8.h +autodoc.o: ../FL/Fl_Valuator.H +autodoc.o: ../FL/Fl_Value_Input.H +autodoc.o: ../FL/Fl_Widget.H +autodoc.o: ../FL/Fl_Widget_Surface.H +autodoc.o: ../FL/Fl_Window.H +autodoc.o: ../FL/Fl_Wizard.H +autodoc.o: ../FL/platform_types.h +autodoc.o: ../src/Fl_String.H +autodoc.o: autodoc.h +autodoc.o: code.h +autodoc.o: CodeEditor.h +autodoc.o: codeview_panel.h +autodoc.o: custom_widgets.h +autodoc.o: factory.h +autodoc.o: Fd_Snap_Action.h +autodoc.o: fluid.h +autodoc.o: fluid_filename.h +autodoc.o: Fl_Group_Type.h +autodoc.o: Fl_Type.h +autodoc.o: Fl_Widget_Type.h +autodoc.o: Fl_Window_Type.h +autodoc.o: function_panel.h +autodoc.o: settings_panel.h +autodoc.o: shell_command.h +autodoc.o: StyleParse.h +autodoc.o: widget_browser.h +autodoc.o: widget_panel.h code.o: ../config.h code.o: ../FL/Enumerations.H code.o: ../FL/filename.H @@ -226,6 +235,59 @@ CodeEditor.o: ../FL/Fl_Widget.H CodeEditor.o: ../FL/platform_types.h CodeEditor.o: CodeEditor.h CodeEditor.o: StyleParse.h +codeview_panel.o: ../config.h +codeview_panel.o: ../FL/Enumerations.H +codeview_panel.o: ../FL/filename.H +codeview_panel.o: ../FL/Fl.H +codeview_panel.o: ../FL/fl_attr.h +codeview_panel.o: ../FL/Fl_Bitmap.H +codeview_panel.o: ../FL/Fl_Box.H +codeview_panel.o: ../FL/Fl_Button.H +codeview_panel.o: ../FL/Fl_Cairo.H +codeview_panel.o: ../FL/fl_casts.H +codeview_panel.o: ../FL/Fl_Choice.H +codeview_panel.o: ../FL/fl_config.h +codeview_panel.o: ../FL/Fl_Device.H +codeview_panel.o: ../FL/Fl_Double_Window.H +codeview_panel.o: ../FL/fl_draw.H +codeview_panel.o: ../FL/Fl_Export.H +codeview_panel.o: ../FL/Fl_Graphics_Driver.H +codeview_panel.o: ../FL/Fl_Group.H +codeview_panel.o: ../FL/Fl_Image.H +codeview_panel.o: ../FL/Fl_Input.H +codeview_panel.o: ../FL/Fl_Input_.H +codeview_panel.o: ../FL/Fl_Light_Button.H +codeview_panel.o: ../FL/Fl_Menu_.H +codeview_panel.o: ../FL/Fl_Menu_Item.H +codeview_panel.o: ../FL/Fl_Multi_Label.H +codeview_panel.o: ../FL/Fl_Pixmap.H +codeview_panel.o: ../FL/Fl_Plugin.H +codeview_panel.o: ../FL/Fl_Preferences.H +codeview_panel.o: ../FL/Fl_Rect.H +codeview_panel.o: ../FL/Fl_RGB_Image.H +codeview_panel.o: ../FL/Fl_Scrollbar.H +codeview_panel.o: ../FL/Fl_Slider.H +codeview_panel.o: ../FL/fl_string_functions.h +codeview_panel.o: ../FL/Fl_Tabs.H +codeview_panel.o: ../FL/Fl_Text_Buffer.H +codeview_panel.o: ../FL/Fl_Text_Display.H +codeview_panel.o: ../FL/Fl_Text_Editor.H +codeview_panel.o: ../FL/fl_types.h +codeview_panel.o: ../FL/fl_utf8.h +codeview_panel.o: ../FL/Fl_Valuator.H +codeview_panel.o: ../FL/Fl_Widget.H +codeview_panel.o: ../FL/Fl_Window.H +codeview_panel.o: ../FL/platform_types.h +codeview_panel.o: ../src/flstring.h +codeview_panel.o: ../src/Fl_String.H +codeview_panel.o: code.h +codeview_panel.o: CodeEditor.h +codeview_panel.o: codeview_panel.h +codeview_panel.o: file.h +codeview_panel.o: fluid.h +codeview_panel.o: fluid_filename.h +codeview_panel.o: Fl_Type.h +codeview_panel.o: StyleParse.h custom_widgets.o: ../config.h custom_widgets.o: ../FL/Enumerations.H custom_widgets.o: ../FL/filename.H @@ -476,7 +538,6 @@ Fd_Snap_Action.o: ../FL/Fl_Window.H Fd_Snap_Action.o: ../FL/Fl_Wizard.H Fd_Snap_Action.o: ../FL/platform_types.h Fd_Snap_Action.o: ../src/Fl_String.H -Fd_Snap_Action.o: settings_panel.h Fd_Snap_Action.o: code.h Fd_Snap_Action.o: Fd_Snap_Action.h Fd_Snap_Action.o: file.h @@ -486,6 +547,7 @@ Fd_Snap_Action.o: Fl_Group_Type.h Fd_Snap_Action.o: Fl_Type.h Fd_Snap_Action.o: Fl_Widget_Type.h Fd_Snap_Action.o: Fl_Window_Type.h +Fd_Snap_Action.o: settings_panel.h Fd_Snap_Action.o: shell_command.h Fd_Snap_Action.o: widget_browser.h file.o: ../config.h @@ -561,7 +623,6 @@ file.o: ../FL/Fl_Wizard.H file.o: ../FL/platform_types.h file.o: ../src/flstring.h file.o: ../src/Fl_String.H -file.o: settings_panel.h file.o: code.h file.o: ExternalCodeEditor_UNIX.h file.o: factory.h @@ -576,6 +637,7 @@ file.o: Fl_Group_Type.h file.o: Fl_Type.h file.o: Fl_Widget_Type.h file.o: Fl_Window_Type.h +file.o: settings_panel.h file.o: shell_command.h file.o: undo.h file.o: widget_browser.h @@ -658,9 +720,10 @@ fluid.o: ../FL/platform_types.h fluid.o: ../src/flstring.h fluid.o: ../src/Fl_String.H fluid.o: about_panel.h -fluid.o: settings_panel.h +fluid.o: autodoc.h fluid.o: code.h fluid.o: CodeEditor.h +fluid.o: codeview_panel.h fluid.o: ExternalCodeEditor_UNIX.h fluid.o: factory.h fluid.o: Fd_Snap_Action.h @@ -676,8 +739,8 @@ fluid.o: Fl_Window_Type.h fluid.o: function_panel.h fluid.o: mergeback.h fluid.o: pixmaps.h +fluid.o: settings_panel.h fluid.o: shell_command.h -fluid.o: codeview_panel.h fluid.o: StyleParse.h fluid.o: template_panel.h fluid.o: undo.h @@ -1004,6 +1067,7 @@ Fl_Menu_Type.o: ../FL/Fl.H Fl_Menu_Type.o: ../FL/fl_ask.H Fl_Menu_Type.o: ../FL/fl_attr.h Fl_Menu_Type.o: ../FL/Fl_Bitmap.H +Fl_Menu_Type.o: ../FL/Fl_Browser_.H Fl_Menu_Type.o: ../FL/Fl_Button.H Fl_Menu_Type.o: ../FL/Fl_Cairo.H Fl_Menu_Type.o: ../FL/fl_casts.H @@ -1064,6 +1128,8 @@ Fl_Menu_Type.o: Fl_Type.h Fl_Menu_Type.o: Fl_Widget_Type.h Fl_Menu_Type.o: Fl_Window_Type.h Fl_Menu_Type.o: mergeback.h +Fl_Menu_Type.o: undo.h +Fl_Menu_Type.o: widget_browser.h Fl_Type.o: ../config.h Fl_Type.o: ../FL/Enumerations.H Fl_Type.o: ../FL/filename.H @@ -1195,7 +1261,6 @@ Fl_Widget_Type.o: ../FL/Fl_Wizard.H Fl_Widget_Type.o: ../FL/platform_types.h Fl_Widget_Type.o: ../src/flstring.h Fl_Widget_Type.o: ../src/Fl_String.H -Fl_Widget_Type.o: settings_panel.h Fl_Widget_Type.o: code.h Fl_Widget_Type.o: CodeEditor.h Fl_Widget_Type.o: custom_widgets.h @@ -1213,6 +1278,7 @@ Fl_Widget_Type.o: Fl_Type.h Fl_Widget_Type.o: Fl_Widget_Type.h Fl_Widget_Type.o: Fl_Window_Type.h Fl_Widget_Type.o: mergeback.h +Fl_Widget_Type.o: settings_panel.h Fl_Widget_Type.o: shell_command.h Fl_Widget_Type.o: StyleParse.h Fl_Widget_Type.o: undo.h @@ -1296,7 +1362,6 @@ Fl_Window_Type.o: ../FL/platform_types.h Fl_Window_Type.o: ../FL/x11.H Fl_Window_Type.o: ../src/flstring.h Fl_Window_Type.o: ../src/Fl_String.H -Fl_Window_Type.o: settings_panel.h Fl_Window_Type.o: code.h Fl_Window_Type.o: CodeEditor.h Fl_Window_Type.o: custom_widgets.h @@ -1310,6 +1375,7 @@ Fl_Window_Type.o: Fl_Group_Type.h Fl_Window_Type.o: Fl_Type.h Fl_Window_Type.o: Fl_Widget_Type.h Fl_Window_Type.o: Fl_Window_Type.h +Fl_Window_Type.o: settings_panel.h Fl_Window_Type.o: shell_command.h Fl_Window_Type.o: StyleParse.h Fl_Window_Type.o: undo.h @@ -1325,6 +1391,7 @@ function_panel.o: ../FL/Fl_Browser_.H function_panel.o: ../FL/Fl_Button.H function_panel.o: ../FL/Fl_Cairo.H function_panel.o: ../FL/fl_casts.H +function_panel.o: ../FL/Fl_Check_Button.H function_panel.o: ../FL/Fl_Choice.H function_panel.o: ../FL/fl_config.h function_panel.o: ../FL/Fl_Device.H @@ -1456,6 +1523,89 @@ pixmaps.o: pixmaps/flWizard.xpm pixmaps.o: pixmaps/invisible.xpm pixmaps.o: pixmaps/lock.xpm pixmaps.o: pixmaps/protected.xpm +settings_panel.o: ../config.h +settings_panel.o: ../FL/Enumerations.H +settings_panel.o: ../FL/filename.H +settings_panel.o: ../FL/Fl.H +settings_panel.o: ../FL/fl_ask.H +settings_panel.o: ../FL/fl_attr.h +settings_panel.o: ../FL/Fl_Bitmap.H +settings_panel.o: ../FL/Fl_Box.H +settings_panel.o: ../FL/Fl_Browser.H +settings_panel.o: ../FL/Fl_Browser_.H +settings_panel.o: ../FL/Fl_Button.H +settings_panel.o: ../FL/Fl_Cairo.H +settings_panel.o: ../FL/fl_casts.H +settings_panel.o: ../FL/Fl_Check_Button.H +settings_panel.o: ../FL/Fl_Choice.H +settings_panel.o: ../FL/fl_config.h +settings_panel.o: ../FL/Fl_Device.H +settings_panel.o: ../FL/Fl_Double_Window.H +settings_panel.o: ../FL/fl_draw.H +settings_panel.o: ../FL/Fl_Export.H +settings_panel.o: ../FL/Fl_File_Browser.H +settings_panel.o: ../FL/Fl_File_Chooser.H +settings_panel.o: ../FL/Fl_File_Icon.H +settings_panel.o: ../FL/Fl_File_Input.H +settings_panel.o: ../FL/Fl_Flex.H +settings_panel.o: ../FL/Fl_Graphics_Driver.H +settings_panel.o: ../FL/Fl_Group.H +settings_panel.o: ../FL/Fl_Image.H +settings_panel.o: ../FL/Fl_Input.H +settings_panel.o: ../FL/Fl_Input_.H +settings_panel.o: ../FL/Fl_Int_Input.H +settings_panel.o: ../FL/Fl_Light_Button.H +settings_panel.o: ../FL/Fl_Menu_.H +settings_panel.o: ../FL/Fl_Menu_Button.H +settings_panel.o: ../FL/Fl_Menu_Item.H +settings_panel.o: ../FL/Fl_Multi_Label.H +settings_panel.o: ../FL/Fl_Native_File_Chooser.H +settings_panel.o: ../FL/Fl_Pack.H +settings_panel.o: ../FL/Fl_Pixmap.H +settings_panel.o: ../FL/Fl_Plugin.H +settings_panel.o: ../FL/Fl_PNG_Image.H +settings_panel.o: ../FL/Fl_Preferences.H +settings_panel.o: ../FL/Fl_Rect.H +settings_panel.o: ../FL/Fl_Repeat_Button.H +settings_panel.o: ../FL/Fl_Return_Button.H +settings_panel.o: ../FL/Fl_RGB_Image.H +settings_panel.o: ../FL/Fl_Scheme.H +settings_panel.o: ../FL/Fl_Scheme_Choice.H +settings_panel.o: ../FL/Fl_Scrollbar.H +settings_panel.o: ../FL/Fl_Shortcut_Button.H +settings_panel.o: ../FL/fl_show_colormap.H +settings_panel.o: ../FL/Fl_Slider.H +settings_panel.o: ../FL/Fl_Spinner.H +settings_panel.o: ../FL/fl_string_functions.h +settings_panel.o: ../FL/Fl_Tabs.H +settings_panel.o: ../FL/Fl_Terminal.H +settings_panel.o: ../FL/Fl_Text_Buffer.H +settings_panel.o: ../FL/Fl_Text_Display.H +settings_panel.o: ../FL/Fl_Text_Editor.H +settings_panel.o: ../FL/Fl_Tile.H +settings_panel.o: ../FL/Fl_Tooltip.H +settings_panel.o: ../FL/fl_types.h +settings_panel.o: ../FL/fl_utf8.h +settings_panel.o: ../FL/Fl_Valuator.H +settings_panel.o: ../FL/Fl_Value_Input.H +settings_panel.o: ../FL/Fl_Widget.H +settings_panel.o: ../FL/Fl_Window.H +settings_panel.o: ../FL/Fl_Wizard.H +settings_panel.o: ../FL/platform_types.h +settings_panel.o: ../src/flstring.h +settings_panel.o: ../src/Fl_String.H +settings_panel.o: code.h +settings_panel.o: Fd_Snap_Action.h +settings_panel.o: fluid.h +settings_panel.o: fluid_filename.h +settings_panel.o: Fl_Group_Type.h +settings_panel.o: Fl_Type.h +settings_panel.o: Fl_Widget_Type.h +settings_panel.o: Fl_Window_Type.h +settings_panel.o: settings_panel.h +settings_panel.o: shell_command.h +settings_panel.o: undo.h +settings_panel.o: widget_browser.h shell_command.o: ../FL/Enumerations.H shell_command.o: ../FL/filename.H shell_command.o: ../FL/Fl.H @@ -1525,7 +1675,6 @@ shell_command.o: ../FL/Fl_Window.H shell_command.o: ../FL/Fl_Wizard.H shell_command.o: ../FL/platform_types.h shell_command.o: ../src/Fl_String.H -shell_command.o: settings_panel.h shell_command.o: code.h shell_command.o: Fd_Snap_Action.h shell_command.o: file.h @@ -1535,60 +1684,9 @@ shell_command.o: Fl_Group_Type.h shell_command.o: Fl_Type.h shell_command.o: Fl_Widget_Type.h shell_command.o: Fl_Window_Type.h +shell_command.o: settings_panel.h shell_command.o: shell_command.h shell_command.o: widget_browser.h -codeview_panel.o: ../config.h -codeview_panel.o: ../FL/Enumerations.H -codeview_panel.o: ../FL/filename.H -codeview_panel.o: ../FL/Fl.H -codeview_panel.o: ../FL/fl_attr.h -codeview_panel.o: ../FL/Fl_Bitmap.H -codeview_panel.o: ../FL/Fl_Box.H -codeview_panel.o: ../FL/Fl_Button.H -codeview_panel.o: ../FL/Fl_Cairo.H -codeview_panel.o: ../FL/fl_casts.H -codeview_panel.o: ../FL/Fl_Choice.H -codeview_panel.o: ../FL/fl_config.h -codeview_panel.o: ../FL/Fl_Device.H -codeview_panel.o: ../FL/Fl_Double_Window.H -codeview_panel.o: ../FL/fl_draw.H -codeview_panel.o: ../FL/Fl_Export.H -codeview_panel.o: ../FL/Fl_Graphics_Driver.H -codeview_panel.o: ../FL/Fl_Group.H -codeview_panel.o: ../FL/Fl_Image.H -codeview_panel.o: ../FL/Fl_Input.H -codeview_panel.o: ../FL/Fl_Input_.H -codeview_panel.o: ../FL/Fl_Light_Button.H -codeview_panel.o: ../FL/Fl_Menu_.H -codeview_panel.o: ../FL/Fl_Menu_Item.H -codeview_panel.o: ../FL/Fl_Multi_Label.H -codeview_panel.o: ../FL/Fl_Pixmap.H -codeview_panel.o: ../FL/Fl_Plugin.H -codeview_panel.o: ../FL/Fl_Preferences.H -codeview_panel.o: ../FL/Fl_Rect.H -codeview_panel.o: ../FL/Fl_RGB_Image.H -codeview_panel.o: ../FL/Fl_Scrollbar.H -codeview_panel.o: ../FL/Fl_Slider.H -codeview_panel.o: ../FL/Fl_Tabs.H -codeview_panel.o: ../FL/Fl_Text_Buffer.H -codeview_panel.o: ../FL/Fl_Text_Display.H -codeview_panel.o: ../FL/Fl_Text_Editor.H -codeview_panel.o: ../FL/fl_types.h -codeview_panel.o: ../FL/fl_utf8.h -codeview_panel.o: ../FL/Fl_Valuator.H -codeview_panel.o: ../FL/Fl_Widget.H -codeview_panel.o: ../FL/Fl_Window.H -codeview_panel.o: ../FL/platform_types.h -codeview_panel.o: ../src/flstring.h -codeview_panel.o: ../src/Fl_String.H -codeview_panel.o: code.h -codeview_panel.o: CodeEditor.h -codeview_panel.o: file.h -codeview_panel.o: fluid.h -codeview_panel.o: fluid_filename.h -codeview_panel.o: Fl_Type.h -codeview_panel.o: codeview_panel.h -codeview_panel.o: StyleParse.h StyleParse.o: StyleParse.h template_panel.o: ../config.h template_panel.o: ../FL/Enumerations.H diff --git a/libraries/fltk/fluid/undo.cxx b/libraries/fltk/fluid/undo.cxx index 0d5cb4d9ba..67c800baa7 100644 --- a/libraries/fltk/fluid/undo.cxx +++ b/libraries/fltk/fluid/undo.cxx @@ -1,7 +1,7 @@ // // FLUID undo support for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2021 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -53,6 +53,7 @@ int undo_last = 0; // Last undo level in buffer int undo_max = 0; // Maximum undo level used int undo_save = -1; // Last undo level that was saved static int undo_paused = 0; // Undo checkpointing paused? +int undo_once_type = 0; // Suspend further undos of the same type // Return the undo filename. @@ -80,6 +81,7 @@ static char *undo_filename(int level) { void redo_cb(Fl_Widget *, void *) { // int undo_item = main_menubar->find_index(undo_cb); // int redo_item = main_menubar->find_index(redo_cb); + undo_once_type = 0; if (undo_current >= undo_last) { fl_beep(); @@ -120,6 +122,7 @@ void redo_cb(Fl_Widget *, void *) { void undo_cb(Fl_Widget *, void *) { // int undo_item = main_menubar->find_index(undo_cb); // int redo_item = main_menubar->find_index(redo_cb); + undo_once_type = 0; if (undo_current <= 0) { fl_beep(); @@ -133,19 +136,23 @@ void undo_cb(Fl_Widget *, void *) { undo_suspend(); // Undo first deletes all widgets which resets the widget_tree browser. // Save the current scroll position, so we don't scroll back to 0 at undo. + // TODO: make the scroll position part of the .fl project file if (widget_browser) widget_browser->save_scroll_position(); int reload_panel = (the_panel && the_panel->visible()); if (!read_file(undo_filename(undo_current - 1), 0)) { // Unable to read checkpoint file, don't undo... widget_browser->rebuild(); g_project.update_settings_dialog(); + set_modflag(0, 0); undo_resume(); return; } if (reload_panel) { for (Fl_Type *t = Fl_Type::first; t; t=t->next) { - if (t->is_widget() && t->selected) + if (t->is_widget() && t->selected) { t->open(); + break; + } } } // Restore old browser position. @@ -165,6 +172,16 @@ void undo_cb(Fl_Widget *, void *) { undo_resume(); } +void undo_checkpoint_once(int type) { + if (undo_paused) return; + if (undo_once_type != type) { + undo_checkpoint(); + undo_once_type = type; + } else { + // do not add more checkpoints for the same undo typw + } +} + // Save current file to undo buffer void undo_checkpoint() { // printf("undo_checkpoint(): undo_current=%d, undo_paused=%d, modflag=%d\n", @@ -175,6 +192,7 @@ void undo_checkpoint() { // int undo_item = main_menubar->find_index(undo_cb); // int redo_item = main_menubar->find_index(redo_cb); + undo_once_type = 0; // Save the current UI to a checkpoint file... const char *filename = undo_filename(undo_current); diff --git a/libraries/fltk/fluid/undo.h b/libraries/fltk/fluid/undo.h index 171fe062f3..c5fae3306d 100644 --- a/libraries/fltk/fluid/undo.h +++ b/libraries/fltk/fluid/undo.h @@ -1,7 +1,7 @@ // // FLUID undo definitions for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2010 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -19,13 +19,17 @@ class Fl_Widget; +#define kUndoWindowResize 1 + extern int undo_current; // Current undo level in buffer extern int undo_last; // Last undo level in buffer extern int undo_save; // Last undo level that was saved +extern int undo_once_type; // Suspend further undos of the same type void redo_cb(Fl_Widget *, void *); // Redo menu callback void undo_cb(Fl_Widget *, void *); // Undo menu callback void undo_checkpoint(); // Save current file to undo buffer +void undo_checkpoint_once(int type); // Save undo buffer once until a different checkpoint type is called void undo_clear(); // Clear undo buffer void undo_resume(); // Resume undo checkpoints void undo_suspend(); // Suspend undo checkpoints diff --git a/libraries/fltk/fluid/widget_browser.cxx b/libraries/fltk/fluid/widget_browser.cxx index b3c7548f2a..1540c6d75f 100644 --- a/libraries/fltk/fluid/widget_browser.cxx +++ b/libraries/fltk/fluid/widget_browser.cxx @@ -120,8 +120,8 @@ void reveal_in_browser(Fl_Type *t) { Fl_Type *p = t->parent; if (p) { for (;;) { - if (!p->open_) - p->open_ = 1; + if (p->folded_) + p->folded_ = 0; if (!p->parent) break; p = p->parent; } @@ -337,10 +337,10 @@ void Widget_Browser::item_draw(void *v, int X, int Y, int, int) const { else fl_color(FL_FOREGROUND_COLOR); // Width=10: Draw the triangle that indicates possible children - if (l->is_parent()) { + if (l->can_have_children()) { X = X - 18 - 13; if (!l->next || l->next->level <= l->level) { - if (l->open_!=(l==pushedtitle)) { + if (l->folded_==(l==pushedtitle)) { // an outlined triangle to the right indicates closed item, no children fl_loop(X,Y+7,X+5,Y+12,X+10,Y+7); } else { @@ -348,7 +348,7 @@ void Widget_Browser::item_draw(void *v, int X, int Y, int, int) const { fl_loop(X+2,Y+2,X+7,Y+7,X+2,Y+12); } } else { - if (l->open_!=(l==pushedtitle)) { + if (l->folded_==(l==pushedtitle)) { // a filled triangle to the right indicates closed item, with children fl_polygon(X,Y+7,X+5,Y+12,X+10,Y+7); } else { @@ -507,7 +507,7 @@ int Widget_Browser::handle(int e) { l = (Fl_Type*)find_item(Fl::event_y()); if (l) { X += 3 + 12*l->level - hposition(); - if (l->is_parent() && Fl::event_x()>X && Fl::event_x()can_have_children() && Fl::event_x()>X && Fl::event_x()level - hposition(); - if (l->is_parent() && Fl::event_x()>X && Fl::event_x()can_have_children() && Fl::event_x()>X && Fl::event_x()open_) { - l->open_ = 0; + if (!l->folded_) { + l->folded_ = 1; for (Fl_Type*k = l->next; k&&k->level>l->level; k = k->next) k->visible = 0; } else { - l->open_ = 1; + l->folded_ = 0; for (Fl_Type*k=l->next; k&&k->level>l->level;) { k->visible = 1; - if (k->is_parent() && !k->open_) { + if (k->can_have_children() && k->folded_) { Fl_Type *j; for (j = k->next; j && j->level>k->level; j = j->next) {/*empty*/} k = j; diff --git a/libraries/fltk/fluid/widget_panel.cxx b/libraries/fltk/fluid/widget_panel.cxx index b52cf3be56..61ea1314e7 100644 --- a/libraries/fltk/fluid/widget_panel.cxx +++ b/libraries/fltk/fluid/widget_panel.cxx @@ -1088,7 +1088,7 @@ Fl_Double_Window* make_widget_panel() { } // Fl_Button* o o->end(); } // Fl_Group* o - { wp_gui_alignment = new Fl_Group(95, 115, 310, 20, "Alignment:"); + { wp_gui_alignment = new Fl_Group(95, 115, 312, 20, "Alignment:"); wp_gui_alignment->labelfont(1); wp_gui_alignment->labelsize(11); wp_gui_alignment->callback((Fl_Callback*)propagate_load); @@ -1166,7 +1166,7 @@ Fl_Double_Window* make_widget_panel() { o->labelcolor(FL_INACTIVE_COLOR); o->callback((Fl_Callback*)align_cb, (void*)((fl_intptr_t)FL_ALIGN_INSIDE)); } // Fl_Button* o - { Fl_Box* o = new Fl_Box(404, 115, 0, 20); + { Fl_Box* o = new Fl_Box(406, 115, 1, 20); o->labelsize(11); Fl_Group::current()->resizable(o); } // Fl_Box* o @@ -1538,12 +1538,12 @@ Fl_Double_Window* make_widget_panel() { wp_style_tab->callback((Fl_Callback*)propagate_load); wp_style_tab->when(FL_WHEN_NEVER); wp_style_tab->hide(); - { wp_style_label = new Fl_Group(95, 40, 309, 20, "Label Font:"); + { wp_style_label = new Fl_Group(99, 40, 305, 20, "Label Font:"); wp_style_label->labelfont(1); wp_style_label->labelsize(11); wp_style_label->callback((Fl_Callback*)propagate_load); wp_style_label->align(Fl_Align(FL_ALIGN_LEFT)); - { Fl_Choice* o = new Fl_Choice(95, 40, 152, 20); + { Fl_Choice* o = new Fl_Choice(99, 40, 148, 20); o->tooltip("The style of the label text."); o->box(FL_THIN_UP_BOX); o->down_box(FL_BORDER_BOX); @@ -1574,12 +1574,12 @@ Fl_Double_Window* make_widget_panel() { } // Fl_Menu_Button* o wp_style_label->end(); } // Fl_Group* wp_style_label - { wp_style_box = new Fl_Group(95, 65, 309, 20, "Box:"); + { wp_style_box = new Fl_Group(99, 65, 305, 20, "Box:"); wp_style_box->labelfont(1); wp_style_box->labelsize(11); wp_style_box->callback((Fl_Callback*)propagate_load); wp_style_box->align(Fl_Align(FL_ALIGN_LEFT)); - { Fl_Choice* o = new Fl_Choice(95, 65, 201, 20); + { Fl_Choice* o = new Fl_Choice(100, 65, 196, 20); o->tooltip("The \"up\" box of the widget."); o->box(FL_THIN_UP_BOX); o->down_box(FL_BORDER_BOX); @@ -1601,12 +1601,12 @@ Fl_Double_Window* make_widget_panel() { } // Fl_Menu_Button* o wp_style_box->end(); } // Fl_Group* wp_style_box - { wp_style_downbox = new Fl_Group(95, 90, 309, 20, "Down Box:"); + { wp_style_downbox = new Fl_Group(99, 90, 305, 20, "Down Box:"); wp_style_downbox->labelfont(1); wp_style_downbox->labelsize(11); wp_style_downbox->callback((Fl_Callback*)propagate_load); wp_style_downbox->align(Fl_Align(FL_ALIGN_LEFT)); - { Fl_Choice* o = new Fl_Choice(95, 90, 201, 20); + { Fl_Choice* o = new Fl_Choice(99, 90, 197, 20); o->tooltip("The \"down\" box of the widget."); o->box(FL_THIN_UP_BOX); o->down_box(FL_BORDER_BOX); @@ -1628,12 +1628,12 @@ Fl_Double_Window* make_widget_panel() { } // Fl_Menu_Button* o wp_style_downbox->end(); } // Fl_Group* wp_style_downbox - { wp_style_text = new Fl_Group(95, 115, 309, 20, "Text Font:"); + { wp_style_text = new Fl_Group(99, 115, 305, 20, "Text Font:"); wp_style_text->labelfont(1); wp_style_text->labelsize(11); wp_style_text->callback((Fl_Callback*)propagate_load); wp_style_text->align(Fl_Align(FL_ALIGN_LEFT)); - { Fl_Choice* o = new Fl_Choice(95, 115, 152, 20); + { Fl_Choice* o = new Fl_Choice(99, 115, 148, 20); o->tooltip("The value text style."); o->box(FL_DOWN_BOX); o->down_box(FL_BORDER_BOX); @@ -1664,16 +1664,57 @@ Fl_Double_Window* make_widget_panel() { } // Fl_Menu_Button* o wp_style_text->end(); } // Fl_Group* wp_style_text - { Fl_Box* o = new Fl_Box(95, 165, 300, 40); + { Fl_Group* o = new Fl_Group(99, 150, 242, 20, "Label Margin:"); + o->labelfont(1); o->labelsize(11); - Fl_Group::current()->resizable(o); - } // Fl_Box* o - { Fl_Light_Button* o = new Fl_Light_Button(95, 140, 90, 20, "Compact"); + o->callback((Fl_Callback*)propagate_load); + o->align(Fl_Align(FL_ALIGN_LEFT)); + { Fl_Value_Input* o = new Fl_Value_Input(99, 150, 55, 20, "Horizontal:"); + o->tooltip("Spacing between label and the horizontally aligned side of the widget."); + o->labelsize(11); + o->minimum(-127); + o->maximum(128); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)h_label_margin_cb); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(159, 150, 55, 20, "Vertical:"); + o->tooltip("Spacing between label and the vertically aligned side of the widget."); + o->labelsize(11); + o->minimum(-127); + o->maximum(127); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)v_label_margin_cb); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Value_Input* o = new Fl_Value_Input(219, 150, 55, 20, "Text to Image:"); + o->tooltip("Gap between label image and text in pixels"); + o->labelsize(11); + o->maximum(255); + o->step(1); + o->textsize(11); + o->callback((Fl_Callback*)image_spacing_cb); + o->align(Fl_Align(FL_ALIGN_TOP_LEFT)); + } // Fl_Value_Input* o + { Fl_Box* o = new Fl_Box(281, 150, 60, 20); + o->labelsize(11); + o->hide(); + Fl_Group::current()->resizable(o); + } // Fl_Box* o + o->end(); + } // Fl_Group* o + { Fl_Light_Button* o = new Fl_Light_Button(99, 175, 90, 20, "Compact"); o->tooltip("use compact box types for closely set buttons"); o->selection_color((Fl_Color)1); o->labelsize(11); o->callback((Fl_Callback*)compact_cb); } // Fl_Light_Button* o + { Fl_Box* o = new Fl_Box(195, 205, 40, 40); + o->labelsize(11); + Fl_Group::current()->resizable(o); + } // Fl_Box* o wp_style_tab->end(); } // Fl_Group* wp_style_tab { wp_cpp_tab = new Fl_Group(10, 30, 400, 330, "C++"); diff --git a/libraries/fltk/fluid/widget_panel.fl b/libraries/fltk/fluid/widget_panel.fl index 1427b91f34..5d01fa96d7 100644 --- a/libraries/fltk/fluid/widget_panel.fl +++ b/libraries/fltk/fluid/widget_panel.fl @@ -332,8 +332,8 @@ Function {make_widget_panel()} { comment {Create a panel that can be used with all known widgets} open } { Fl_Window {} { - comment {Use a Double Window to avoid flickering.} open - xywh {430 217 420 400} type Double labelsize 11 align 80 resizable hotspot + comment {Use a Double Window to avoid flickering.} open selected + xywh {372 208 420 400} type Double labelsize 11 align 80 resizable hotspot code0 {o->size_range(o->w(), o->h());} size_range {420 400 0 0} visible } { Fl_Tabs widget_tabs { @@ -343,7 +343,7 @@ Function {make_widget_panel()} { } { Fl_Group wp_gui_tab { label GUI - callback propagate_load open selected + callback propagate_load open xywh {10 30 400 330} labelsize 11 when 0 resizable } { Fl_Group {} { @@ -402,8 +402,8 @@ Use Ctrl-J for newlines.} xywh {95 40 190 20} labelfont 1 labelsize 11 when 15 t } Fl_Group wp_gui_alignment { label {Alignment:} - callback propagate_load - xywh {95 115 310 20} labelfont 1 labelsize 11 align 4 + callback propagate_load open + xywh {95 115 312 20} labelfont 1 labelsize 11 align 4 } { Fl_Button {} { label Clip @@ -442,7 +442,7 @@ Use Ctrl-J for newlines.} xywh {95 40 190 20} labelfont 1 labelsize 11 when 15 t tooltip {Bottom-align the label.} xywh {353 115 20 20} type Toggle selection_color 8 labelsize 11 labelcolor 8 hide } Fl_Choice {} { - callback align_text_image_cb open + callback align_text_image_cb xywh {172 115 116 20} down_box BORDER_BOX labelsize 11 textsize 11 } { MenuItem {} { @@ -477,7 +477,7 @@ Use Ctrl-J for newlines.} xywh {95 40 190 20} labelfont 1 labelsize 11 when 15 t } } Fl_Choice {} { - callback align_position_cb open + callback align_position_cb xywh {293 115 86 20} down_box BORDER_BOX labelsize 11 textsize 11 } { MenuItem {} { @@ -563,7 +563,7 @@ Use Ctrl-J for newlines.} xywh {95 40 190 20} labelfont 1 labelsize 11 when 15 t tooltip {Show the label inside the widget.} xywh {384 115 20 20} type Toggle selection_color 8 labelsize 11 labelcolor 8 } Fl_Box {} { - xywh {404 115 0 20} labelsize 11 resizable + xywh {406 115 1 20} labelsize 11 resizable } } Fl_Group {} { @@ -838,11 +838,11 @@ Use Ctrl-J for newlines.} xywh {95 285 310 20} labelfont 1 labelsize 11 textsize Fl_Group wp_style_label { label {Label Font:} callback propagate_load open - xywh {95 40 309 20} labelfont 1 labelsize 11 align 4 + xywh {99 40 305 20} labelfont 1 labelsize 11 align 4 } { Fl_Choice {} { callback labelfont_cb open - tooltip {The style of the label text.} xywh {95 40 152 20} box THIN_UP_BOX down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 resizable + tooltip {The style of the label text.} xywh {99 40 148 20} box THIN_UP_BOX down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 resizable code0 {extern Fl_Menu_Item fontmenu[];} code1 {o->menu(fontmenu);} } {} @@ -865,11 +865,11 @@ Use Ctrl-J for newlines.} xywh {95 285 310 20} labelfont 1 labelsize 11 textsize Fl_Group wp_style_box { label {Box:} callback propagate_load open - xywh {95 65 309 20} labelfont 1 labelsize 11 align 4 + xywh {99 65 305 20} labelfont 1 labelsize 11 align 4 } { Fl_Choice {} { callback box_cb open - tooltip {The "up" box of the widget.} xywh {95 65 201 20} box THIN_UP_BOX down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 resizable + tooltip {The "up" box of the widget.} xywh {100 65 196 20} box THIN_UP_BOX down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 resizable code0 {extern Fl_Menu_Item boxmenu[];} code1 {o->menu(boxmenu);} } {} @@ -888,11 +888,11 @@ Use Ctrl-J for newlines.} xywh {95 285 310 20} labelfont 1 labelsize 11 textsize Fl_Group wp_style_downbox { label {Down Box:} callback propagate_load open - xywh {95 90 309 20} labelfont 1 labelsize 11 align 4 + xywh {99 90 305 20} labelfont 1 labelsize 11 align 4 } { Fl_Choice {} { callback down_box_cb open - tooltip {The "down" box of the widget.} xywh {95 90 201 20} box THIN_UP_BOX down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 resizable + tooltip {The "down" box of the widget.} xywh {99 90 197 20} box THIN_UP_BOX down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 resizable code0 {extern Fl_Menu_Item boxmenu[];} code1 {o->menu(boxmenu);} } {} @@ -911,11 +911,11 @@ Use Ctrl-J for newlines.} xywh {95 285 310 20} labelfont 1 labelsize 11 textsize Fl_Group wp_style_text { label {Text Font:} callback propagate_load open - xywh {95 115 309 20} labelfont 1 labelsize 11 align 4 + xywh {99 115 305 20} labelfont 1 labelsize 11 align 4 } { Fl_Choice {} { callback textfont_cb open - tooltip {The value text style.} xywh {95 115 152 20} box DOWN_BOX down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 resizable + tooltip {The value text style.} xywh {99 115 148 20} box DOWN_BOX down_box BORDER_BOX labelfont 1 labelsize 11 textsize 11 resizable code0 {extern Fl_Menu_Item fontmenu[];} code1 {o->menu(fontmenu);} } {} @@ -935,13 +935,37 @@ Use Ctrl-J for newlines.} xywh {95 285 310 20} labelfont 1 labelsize 11 textsize code1 {o->menu(colormenu);} } {} } - Fl_Box {} { - xywh {95 165 300 40} labelsize 11 resizable + Fl_Group {} { + label {Label Margin:} + callback propagate_load open + xywh {99 150 242 20} labelfont 1 labelsize 11 align 4 + } { + Fl_Value_Input {} { + label {Horizontal:} + callback h_label_margin_cb + tooltip {Spacing between label and the horizontally aligned side of the widget.} xywh {99 150 55 20} labelsize 11 align 5 minimum -127 maximum 128 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Vertical:} + callback v_label_margin_cb + tooltip {Spacing between label and the vertically aligned side of the widget.} xywh {159 150 55 20} labelsize 11 align 5 minimum -127 maximum 127 step 1 textsize 11 + } + Fl_Value_Input {} { + label {Text to Image:} + callback image_spacing_cb + tooltip {Gap between label image and text in pixels} xywh {219 150 55 20} labelsize 11 align 5 maximum 255 step 1 textsize 11 + } + Fl_Box {} { + xywh {281 150 60 20} labelsize 11 hide resizable + } } Fl_Light_Button {} { label Compact callback compact_cb - tooltip {use compact box types for closely set buttons} xywh {95 140 90 20} selection_color 1 labelsize 11 + tooltip {use compact box types for closely set buttons} xywh {99 175 90 20} selection_color 1 labelsize 11 + } + Fl_Box {} { + xywh {195 205 40 40} labelsize 11 resizable } } Fl_Group wp_cpp_tab { diff --git a/libraries/fltk/fluid/widget_panel.h b/libraries/fltk/fluid/widget_panel.h index 14f11abc86..96022286c3 100644 --- a/libraries/fltk/fluid/widget_panel.h +++ b/libraries/fltk/fluid/widget_panel.h @@ -144,6 +144,9 @@ extern void textsize_cb(Fl_Value_Input*, void*); extern void textcolor_cb(Fl_Button*, void*); extern Fl_Button *w_textcolor; extern void textcolor_menu_cb(Fl_Menu_Button*, void*); +extern void h_label_margin_cb(Fl_Value_Input*, void*); +extern void v_label_margin_cb(Fl_Value_Input*, void*); +extern void image_spacing_cb(Fl_Value_Input*, void*); extern void compact_cb(Fl_Light_Button*, void*); extern Fl_Group *wp_cpp_tab; extern Fl_Group *wp_cpp_class; diff --git a/libraries/fltk/jpeg/Makefile b/libraries/fltk/jpeg/Makefile index c83b4bb7a8..e90ede88fd 100644 --- a/libraries/fltk/jpeg/Makefile +++ b/libraries/fltk/jpeg/Makefile @@ -4,7 +4,7 @@ # # JPEG library makefile for the Fast Light Toolkit (FLTK). # -# Copyright 1997-2023 by Bill Spitzak and others. +# Copyright 1997-2024 by Bill Spitzak and others. # # This library is free software. Distribution and use rights are outlined in # the file "COPYING" which should have been included with this file. If this @@ -93,16 +93,16 @@ clean: install: $(LIBJPEG) echo "Installing $(LIBJPEG) in $(libdir)..." - -$(INSTALL_DIR) $(DESTDIR)$(libdir) - $(INSTALL_LIB) $(LIBJPEG) $(DESTDIR)$(libdir) - $(RANLIB) $(DESTDIR)$(libdir)/libfltk_jpeg$(LIBEXT) + -$(INSTALL_DIR) "$(DESTDIR)$(libdir)" + $(INSTALL_LIB) $(LIBJPEG) "$(DESTDIR)$(libdir)" + $(RANLIB) "$(DESTDIR)$(libdir)/libfltk_jpeg$(LIBEXT)" echo "Installing jpeg headers in $(includedir)/FL/images..." - -$(INSTALL_DIR) $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) jconfig.h $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) jerror.h $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) jmorecfg.h $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) jpeglib.h $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) fltk_jpeg_prefix.h $(DESTDIR)$(includedir)/FL/images + -$(INSTALL_DIR) "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) jconfig.h "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) jerror.h "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) jmorecfg.h "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) jpeglib.h "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) fltk_jpeg_prefix.h "$(DESTDIR)$(includedir)/FL/images" # # Uninstall everything... @@ -110,13 +110,13 @@ install: $(LIBJPEG) uninstall: echo "Uninstalling libfltk_jpeg$(LIBEXT) in $(libdir)..." - $(RM) $(libdir)/libfltk_jpeg$(LIBEXT) + $(RM) "$(libdir)/libfltk_jpeg$(LIBEXT)" echo "Uninstalling jpeg headers in $(includedir)/FL/images..." - $(RM) $(includedir)/FL/images/jconfig.h - $(RM) $(includedir)/FL/images/jerror.h - $(RM) $(includedir)/FL/images/jmorecfg.h - $(RM) $(includedir)/FL/images/jpeglib.h - $(RM) $(includedir)/FL/images/fltk_jpeg_prefix.h + $(RM) "$(includedir)/FL/images/jconfig.h" + $(RM) "$(includedir)/FL/images/jerror.h" + $(RM) "$(includedir)/FL/images/jmorecfg.h" + $(RM) "$(includedir)/FL/images/jpeglib.h" + $(RM) "$(includedir)/FL/images/fltk_jpeg_prefix.h" # # libfltk_jpeg.a @@ -132,7 +132,7 @@ $(LIBJPEG): $(OBJS) # Make dependencies... # -depend: $(OBJS:.o=.c) +depend: $(OBJS:.o=.c) makedepend -Y -I.. -f makedepend -w 20 $(OBJS:.o=.c) echo "# DO NOT DELETE THIS LINE -- make depend depends on it." > makedepend.tmp echo "" >> makedepend.tmp diff --git a/libraries/fltk/makesrcdist b/libraries/fltk/makesrcdist deleted file mode 100644 index 26a35e68fc..0000000000 --- a/libraries/fltk/makesrcdist +++ /dev/null @@ -1,184 +0,0 @@ -#!/bin/sh -# -# makesrcdist - make a distribution of FLTK. -# -# There are 3 different modes of operation, dependent on commandline arguments: -# -# (1) Create snapshot: -# -# makesrcdist [snapshot] -# -# Use no arguments or "snapshot" (verbatim). -# -# (2) Create distribution tarballs for test and verification: -# -# makesrcdist -# -# Use a version number as argument, e.g. "1.3.3" or "1.3.4rc2". -# This can be used for local testing. -# -# Note: the release tarballs will be created from the current -# 'HEAD' revision of your local Git repository. -# -# (3) Create distribution tarballs (final): -# -# makesrcdist tag -# -# Same as (2), but create Git tag with version number. -# Enter "tag" (verbatim) as 2nd argument. -# This will create the Git tag "release-" for the -# current revision in the (local) FLTK Git repository and export the -# FLTK sources from this tag for creation of distribution files. -# -# Note: You need to 'git push' the Git tag manually when you -# are satisfied with the result. You may use: -# $ git push origin release- -# where '' is the version number (argument #1) -# -# Note: define FLTK_TAR if you want to use a different compatible tar -# command than "tar", e.g. to use "gtar" (bash syntax): -# $ export FLTK_TAR="gtar" -# - -TAR="tar" -if test "x$FLTK_TAR" != "x"; then - TAR="$FLTK_TAR" -fi - -# These are the release and snapshot download URL's currently in use: - -DOWNLOAD='https://www.fltk.org/pub/fltk' -SNAPSHOT='https://www.fltk.org/pub/fltk/snapshots' - -DATE="`date +'%Y%m%d'`" - -# VS = short version number ('major.minor'), for instance '1.4'. -# Note: VS is used only for snapshot generation -# fltk_version = full version number w/o 'rcN' (from file fltk_version.dat) - -fltk_version="`cat fltk_version.dat`" -VS="`echo $fltk_version | cut -f 1-2 -d '.'`" - -echo "Getting distribution..." - -if test $# = 0 -o "x$1" = "xsnapshot"; then - echo Getting snapshot revision... - rev="`git rev-parse --short=8 HEAD`" - version="${VS}-${rev}" - fileversion="${VS}.x-${DATE}-$rev" - fileurl="$SNAPSHOT/fltk-$fileversion.tar.gz" -else - if test ! -e "documentation/html/"; then - echo "ERROR: Please generate the HTML documentation before distributing:" - echo " autoconf" - echo " ./configure" - echo " cd documentation; make dist" - exit - fi - if test ! -e "documentation/fltk.pdf"; then - echo "ERROR: Please generate the PDF documentation before distributing:" - echo " autoconf" - echo " ./configure" - echo " cd documentation; make dist" - exit - fi - rev="1" - version=$1 - fileversion=$1 - fileurl="$DOWNLOAD/$version/fltk-$fileversion-source.tar.gz" - - if test "x$2" = "xtag"; then - echo "Creating Git tag 'release-$version' ..." - git tag -a -m "Release $version" release-$version || exit 1 - fi -fi - -# Debug: -# echo "fltk_version = $fltk_version" -# echo "version = $version" -# echo "fileversion = $fileversion" -# echo "fileurl = $fileurl" - -echo Exporting $fltk_version to /tmp/fltk-$version/... -rm -rf /tmp/fltk-$version -mkdir /tmp/fltk-$version -git archive --format=tar HEAD | $TAR -C /tmp/fltk-$version -x -- - -if test $# != 0 -a "x$1" != "xsnapshot"; then - echo "Copying HTML and PDF documentation..." - cp -r documentation/html /tmp/fltk-$version/documentation/ - cp documentation/fltk.pdf /tmp/fltk-$version/documentation/ -fi - -echo Applying version number... -cd /tmp/fltk-$version - -sed -e '1,$s/@VERSION@/'$version'/' \ - -e '1,$s/@RELEASE@/'$rev'/' \ - -e '1,$s#^Source:.*#Source: '$fileurl'#' \ - fltk.spec - -echo Creating configure script... -autoconf -f - -echo Cleaning developer files... -rm -rf OpenGL autom4te* bc5 config forms glut images packages themes - -cd .. - -if test $# != 0 -a "x$1" != "xsnapshot"; then - echo "Making HTML docs distribution..." - $TAR czf fltk-$fileversion-docs-html.tar.gz fltk-$version/documentation/html/ - - echo "Making PDF docs distribution..." - $TAR czf fltk-$fileversion-docs-pdf.tar.gz fltk-$version/documentation/fltk.pdf -fi - -echo "Removing documentation..." -rm -rf fltk-$version/documentation/html/ -rm -f fltk-$version/documentation/fltk.pdf - -echo "Making UNIX (.tar.gz) distribution..." -$TAR czf fltk-$fileversion-source.tar.gz fltk-$version - -echo "Making UNIX (.tar.bz2) distribution..." -$TAR cjf fltk-$fileversion-source.tar.bz2 fltk-$version - -# echo "Making Windows (.zip) distribution..." -# rm -f fltk-$fileversion-source.zip -# zip -r9 fltk-$fileversion-source.zip fltk-$version - -echo "Removing distribution directory..." - -rm -rf fltk-$version - -# Create MD5 sums - -out="`pwd`/fltk-$fileversion-md5sums.txt" -echo "Creating MD5 sums in $out" -rm -f $out -touch $out - -# make sure the order is source - html - pdf - -for f in source docs-html docs-pdf; do - if [ -f fltk-$fileversion-$f.tar.bz2 ] ; then - md5sum fltk-$fileversion-$f.tar.bz2 >> $out - fi - if [ -f fltk-$fileversion-$f.tar.gz ] ; then - md5sum fltk-$fileversion-$f.tar.gz >> $out - fi -done - -sed -e"s# # $fltk_version fltk/$fltk_version/#" -i $out - -if test "x$2" = "xtag"; then - echo "" - echo "Don't forget to push the Git tag" - echo "(assuming your remote Git repository is 'origin'):" - echo "" - echo "Use: \$ git push origin release-$version" - echo "" -fi - -echo "Done!" diff --git a/libraries/fltk/misc/abi-compliance-checker.txt b/libraries/fltk/misc/abi-compliance-checker.txt index 649878eccc..9f6889e6df 100644 --- a/libraries/fltk/misc/abi-compliance-checker.txt +++ b/libraries/fltk/misc/abi-compliance-checker.txt @@ -8,6 +8,10 @@ adjust versions and directory names as appropriate on your system. In this howto we compare FLTK 1.3.4-1 (last 1.3.x release as of Jan 02, 2019) with the current version (1.3.5) before it will be released. +For documentation on its usage please refer to: + + https://lvc.github.io/abi-compliance-checker/ + (1) Download 'abi-compliance-checker' from GitHub: diff --git a/libraries/fltk/png/Makefile b/libraries/fltk/png/Makefile index 7fd9a8765c..53efddb8a6 100644 --- a/libraries/fltk/png/Makefile +++ b/libraries/fltk/png/Makefile @@ -2,7 +2,7 @@ # PNG library Makefile for the Fast Light Toolkit (FLTK). # # Copyright 1997-2011 by Easy Software Products. -# Copyright 2012-2023 by Bill Spitzak and others. +# Copyright 2012-2024 by Bill Spitzak and others. # # This library is free software. Distribution and use rights are outlined in # the file "COPYING" which should have been included with this file. If this @@ -52,15 +52,15 @@ clean: install: $(LIBPNG) echo "Installing libfltk_png$(LIBEXT) in $(libdir)..." - -$(INSTALL_DIR) $(DESTDIR)$(libdir) - $(INSTALL_LIB) $(LIBPNG) $(DESTDIR)$(libdir) - $(RANLIB) $(DESTDIR)$(libdir)/libfltk_png$(LIBEXT) + -$(INSTALL_DIR) "$(DESTDIR)$(libdir)" + $(INSTALL_LIB) $(LIBPNG) "$(DESTDIR)$(libdir)" + $(RANLIB) "$(DESTDIR)$(libdir)/libfltk_png$(LIBEXT)" echo "Installing png headers in $(includedir)/FL/images..." - -$(INSTALL_DIR) $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) png.h $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) pngconf.h $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) pnglibconf.h $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) pngprefix.h $(DESTDIR)$(includedir)/FL/images + -$(INSTALL_DIR) "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) png.h "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) pngconf.h "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) pnglibconf.h "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) pngprefix.h "$(DESTDIR)$(includedir)/FL/images" # @@ -69,12 +69,12 @@ install: $(LIBPNG) uninstall: echo "Uninstalling libfltk_png$(LIBEXT) in $(libdir)..." - $(RM) $(DESTDIR)$(libdir)/libfltk_png$(LIBEXT) + $(RM) "$(DESTDIR)$(libdir)/libfltk_png$(LIBEXT)" echo "Uninstalling png headers in $(includedir)/FL/images..." - $(RM) $(DESTDIR)$(includedir)/FL/images/png.h - $(RM) $(DESTDIR)$(includedir)/FL/images/pngconf.h - $(RM) $(DESTDIR)$(includedir)/FL/images/pnglibconf.h - $(RM) $(DESTDIR)$(includedir)/FL/images/pngprefix.h + $(RM) "$(DESTDIR)$(includedir)/FL/images/png.h" + $(RM) "$(DESTDIR)$(includedir)/FL/images/pngconf.h" + $(RM) "$(DESTDIR)$(includedir)/FL/images/pnglibconf.h" + $(RM) "$(DESTDIR)$(includedir)/FL/images/pngprefix.h" # @@ -92,7 +92,7 @@ $(LIBPNG): $(OBJS) # Make dependencies... # -depend: $(OBJS:.o=.c) +depend: $(OBJS:.o=.c) makedepend -Y -I.. -f makedepend -w 20 $(OBJS:.o=.c) echo "# DO NOT DELETE THIS LINE -- make depend depends on it." > makedepend.tmp echo "" >> makedepend.tmp diff --git a/libraries/fltk/src/CMakeLists.txt b/libraries/fltk/src/CMakeLists.txt index a543b4f934..614d93cac1 100644 --- a/libraries/fltk/src/CMakeLists.txt +++ b/libraries/fltk/src/CMakeLists.txt @@ -849,8 +849,8 @@ if(FLTK_USE_GL) target_link_libraries(fltk_gl PRIVATE ${OPTIONAL_LIBS}) target_include_directories(fltk_gl PRIVATE ${OPTIONAL_INCLUDES}) - if(OPENGL_GLU_INCLUDE_DIR) - target_include_directories(fltk_gl PUBLIC ${OPENGL_GLU_INCLUDE_DIR}) + if(FLTK_OPENGL_GLU_INCLUDE_DIR) + target_include_directories(fltk_gl PUBLIC ${FLTK_OPENGL_GLU_INCLUDE_DIR}) endif() endif(FLTK_USE_GL) @@ -912,8 +912,8 @@ if(FLTK_BUILD_SHARED_LIBS AND NOT MSVC) target_link_libraries(fltk_gl-shared PRIVATE ${OPTIONAL_LIBS}) target_include_directories(fltk_gl-shared PRIVATE ${OPTIONAL_INCLUDES}) - if(OPENGL_GLU_INCLUDE_DIR) - target_include_directories(fltk_gl-shared PUBLIC ${OPENGL_GLU_INCLUDE_DIR}) + if(FLTK_OPENGL_GLU_INCLUDE_DIR) + target_include_directories(fltk_gl-shared PUBLIC ${FLTK_OPENGL_GLU_INCLUDE_DIR}) endif() endif(FLTK_USE_GL) @@ -956,8 +956,8 @@ if(FLTK_BUILD_SHARED_LIBS AND MSVC) if(OPENGL_FOUND) target_link_libraries(fltk-shared PUBLIC ${OPENGL_LIBRARIES}) target_include_directories(fltk-shared PUBLIC ${OPENGL_INCLUDE_DIR} ${OPENGL_INCLUDE_DIRS}) - if(OPENGL_GLU_INCLUDE_DIR) - target_include_directories(fltk-shared PUBLIC ${OPENGL_GLU_INCLUDE_DIR}) + if(FLTK_OPENGL_GLU_INCLUDE_DIR) + target_include_directories(fltk-shared PUBLIC ${FLTK_OPENGL_GLU_INCLUDE_DIR}) endif() endif(OPENGL_FOUND) diff --git a/libraries/fltk/src/Fl.cxx b/libraries/fltk/src/Fl.cxx index 43517ee20e..bae7f13280 100644 --- a/libraries/fltk/src/Fl.cxx +++ b/libraries/fltk/src/Fl.cxx @@ -1,7 +1,7 @@ // // Main event handling code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -164,6 +164,7 @@ void Fl::scrollbar_size(int W) { /** Gets the default line spacing used by menus. \returns The default line spacing, in pixels. + \since 1.4.0 */ int Fl::menu_linespacing() { return menu_linespacing_; @@ -173,6 +174,7 @@ int Fl::menu_linespacing() { Sets the default line spacing used by menus. Default is 4. \param[in] H The new default line spacing between menu items, in pixels. + \since 1.4.0 */ void Fl::menu_linespacing(int H) { menu_linespacing_ = H; @@ -344,24 +346,69 @@ int Fl::has_timeout(Fl_Timeout_Handler cb, void *data) { } /** - Removes a timeout callback from the timer queue. + Remove one or more matching timeout callbacks from the timer queue. - This method removes all matching timeouts, not just the first one. - This may change in the future. + This method removes \b all matching timeouts, not just the first one. If the \p data argument is \p NULL (the default!) only the callback \p cb must match, i.e. all timer entries with this callback are removed. It is harmless to remove a timeout callback that no longer exists. + If you want to remove only the next matching timeout you can use + Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) + (available since FLTK 1.4.0). + \param[in] cb Timer callback to be removed (must match) \param[in] data Wildcard if NULL (default), must match otherwise + + \see Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) */ void Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) { Fl_Timeout::remove_timeout(cb, data); } +/** + Remove the next matching timeout callback and return its \p data pointer. + + This method removes only the next matching timeout and returns in + \p data_return (if non-NULL) the \p data member given when the timeout + was scheduled. + + This method is useful if you remove a timeout before it is scheduled + and you need to get and use its data value, for instance to free() or + delete the data associated with the timeout. + + This method returns non-zero if a matching timeout was found and zero + if no timeout matched the request. + + If the return value is \c N \> 1 then there are N - 1 more matching + timeouts pending. + + If you need to remove all timeouts with a particular callback \p cb + you must repeat this call until it returns 1 (all timeouts removed) + or zero (no matching timeout), whichever occurs first. + + + \param[in] cb Timer callback to be removed (must match) + \param[in] data Wildcard if NULL, must match otherwise + \param[inout] data_return Pointer to (void *) to receive the data value + + \return non-zero if a timer was found and removed + \retval 0 no matching timer was found + \retval 1 the last matching timeout was found and removed + \retval N>1 a matching timeout was removed and there are \n + (N - 1) matching timeouts pending + + \see Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) + + \since 1.4.0 +*/ +int Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) { + return Fl_Timeout::remove_next_timeout(cb, data, data_return); +} + //////////////////////////////////////////////////////////////// // Checks are just stored in a list. They are called in the reverse @@ -827,19 +874,23 @@ void Fl::add_handler(Fl_Event_Handler ha) { } -/** Returns the last function installed by a call to Fl::add_handler() */ +/** Returns the last function installed by a call to Fl::add_handler(). + + \since 1.4.0 +*/ Fl_Event_Handler Fl::last_handler() { return handlers ? handlers->handle : NULL; } /** Install a function to parse unrecognized events with less priority than another function. - Install function \p ha to handle unrecognized events - giving it the priority just lower than that of function \p before - which was previously installed. - \see Fl::add_handler(Fl_Event_Handler) - \see Fl::last_handler() - */ + Install function \p ha to handle unrecognized events + giving it the priority just lower than that of function \p before + which was previously installed. + \see Fl::add_handler(Fl_Event_Handler) + \see Fl::last_handler() + \since 1.4.0 +*/ void Fl::add_handler(Fl_Event_Handler ha, Fl_Event_Handler before) { if (!before) return Fl::add_handler(ha); handler_link *l = handlers; @@ -915,6 +966,7 @@ static system_handler_link *sys_handlers = 0; - X11: XEvent - Windows: MSG - OS X: NSEvent + - Wayland: NULL (FLTK runs the event handler(s) just before calling \e wl_display_dispatch()) \param ha The event handler function to register \param data User data to include on each call @@ -982,10 +1034,10 @@ Fl_Widget* fl_oldfocus; // kludge for Fl_Group... \e test if the widget wants the focus (by it returning non-zero from handle()). - Widgets can set the NEEDS_KEYBOARD flag to indicate that a keyboard is - essential for the widget to function. Touchscreen devices will be sent a - request to show an on-screen keyboard if no hardware keyboard is - connected. + Since FLTK 1.4.0 widgets can set the NEEDS_KEYBOARD flag to indicate that + a keyboard is essential for the widget to function. Touchscreen devices + will be sent a request to show an on-screen keyboard if no hardware keyboard + is connected. \see Fl_Widget::take_focus() \see Fl_Widget::needs_keyboard() const @@ -1227,9 +1279,11 @@ static int send_event(int event, Fl_Widget* to, Fl_Window* window) { } /** - \brief Give the reason for calling a callback. - \return the reason for the current callback - \see Fl_Widget::when(), Fl_Widget::do_callback(), Fl_Widget::callback() + Give the reason for calling a callback. + + \return the reason for the current callback + \see Fl_Widget::when(), Fl_Widget::do_callback(), Fl_Widget::callback() + \since 1.4.0 */ Fl_Callback_Reason Fl::callback_reason() { return callback_reason_; @@ -1954,12 +2008,22 @@ void Fl::clear_widget_pointer(Fl_Widget const *w) /** \brief FLTK library options management. - This function needs to be documented in more detail. It can be used for more - optional settings, such as using a native file chooser instead of the FLTK one + Options provide a way for the user to modify the behavior of an FLTK + application. For example, clearing the `OPTION_SHOW_TOOLTIPS` will disable + tooltips for all FLTK applications. + + Options are set by the user or the administrator on user or machine level. + In 1.3, FLUID has an Options dialog for that. In 1.4, there is an app named + `fltk-options` that can be used from the command line or as a GUI tool. + The machine level setting is read first, and the user setting can override + the machine setting. + + This function is used throughout FLTK to quickly query the user's wishes. + There are options for using a native file chooser instead of the FLTK one wherever possible, disabling tooltips, disabling visible focus, disabling FLTK file chooser preview, etc. . - There should be a command line option interface. + See `Fl::Fl_Option` for a list of available options. Example: \code @@ -1969,12 +2033,14 @@ void Fl::clear_widget_pointer(Fl_Widget const *w) { ..off.. } \endcode - \note Options can be managed with the \c fltk-options program, new in FLTK 1.4.0. + \note Since FLTK 1.4.0 options can be managed with the \c fltk-options program. + In FLTK 1.3.x options can be set in FLUID. \param opt which option \return true or false \see enum Fl::Fl_Option \see Fl::option(Fl_Option, bool) + \see fltk-options application in command line and GUI mode \since FLTK 1.3.0 */ @@ -2051,27 +2117,33 @@ bool Fl::option(Fl_Option opt) } /** - \brief Override an option while the application is running. + Override an option while the application is running. - This function does not change any system or user settings. + Apps can override the machine settings and the user settings by calling + `Fl::option(option, bool)`. The override takes effect immediately for this + option for all widgets in the app for the life time of the app. - Example: - \code - Fl::option(Fl::OPTION_ARROW_FOCUS, true); // on - Fl::option(Fl::OPTION_ARROW_FOCUS, false); // off - \endcode + The override is not saved anywhere, and relaunching the app will restore the + old settings. + + Example: + \code + Fl::option(Fl::OPTION_ARROW_FOCUS, true); // on + Fl::option(Fl::OPTION_ARROW_FOCUS, false); // off + \endcode + + \param opt which option + \param val set to true or false - \param opt which option - \param val set to true or false \see enum Fl::Fl_Option \see bool Fl::option(Fl_Option) - */ +*/ void Fl::option(Fl_Option opt, bool val) { if (opt<0 || opt>=OPTION_LAST) return; if (!options_read_) { - // first read this option, so we don't override our setting later + // make sure that the options_ array is filled in option(opt); } options_[opt] = val; @@ -2198,7 +2270,7 @@ void Fl::disable_im() Opens the display. Automatically called by the library when the first window is show()'n. Does nothing if the display is already open. - \note Requires ##include + \note Requires \#include */ void fl_open_display() { @@ -2209,7 +2281,7 @@ void fl_open_display() You do \e not need to call this to exit, and in fact it is faster to not do so. It may be useful to call this if you want your program to continue without a GUI. You cannot open the display again, and cannot call any FLTK functions. - \note Requires ##include + \note Requires \#include */ void fl_close_display() { @@ -2217,16 +2289,24 @@ void fl_close_display() } #ifdef FL_DOXYGEN -/** Prevent the FLTK library from using its Wayland backend and forces it to use its X11 backend. - Put this declaration somewhere in your code outside the body of any function : - \code - FL_EXPORT bool fl_disable_wayland = true; - \endcode - This declaration makes sure source code developed for FLTK 1.3, including X11-specific code, - will build and run with FLTK 1.4 and its Wayland platform with this single source code level change. - This declaration has no effect on non-Wayland platforms. - Don't put this declaration if you want the Wayland backend to be used when it's available. - */ +/** Prevent the FLTK library from using its Wayland backend and force it to use its X11 backend. + + Put this declaration somewhere in your source code outside the body of any function: + \code + FL_EXPORT bool fl_disable_wayland = true; + \endcode + This declaration makes sure that source code developed for FLTK 1.3, including + X11-specific code, will build and run with FLTK 1.4 and its Wayland platform + with a single line source code level change. + This declaration has no effect on non-Wayland platforms. + Don't add this declaration if you want the Wayland backend to be used when + it's available. + + \note Please see also chapter 2.1 of README.Wayland.txt for further information + on how to build your application to ensure that this declaration is effective. + + \since 1.4.0 +*/ FL_EXPORT bool fl_disable_wayland = true; #endif // FL_DOXYGEN @@ -2267,15 +2347,44 @@ int Fl::get_font_sizes(Fl_Font fnum, int*& sizep) { return Fl_Graphics_Driver::default_driver().get_font_sizes(fnum, sizep); } -/** Current value of the GUI scaling factor for screen number \p n (n ∈ [0 , Fl::screen_count()-1]) */ +/** Gets the GUI scaling factor of screen number \p n. + + The valid range of \p n is 0 .. Fl::screen_count() - 1. + + The return value is \c 1.0 if screen scaling is not supported or + \p n is outside the valid range. + + \return Current screen scaling factor (default: \c 1.0) + + \see Fl::screen_count() + \see Fl::screen_scaling_supported() + + \since 1.4.0 +*/ float Fl::screen_scale(int n) { - if (!Fl::screen_scaling_supported() || n < 0 || n >= Fl::screen_count()) return 1.; + if (!Fl::screen_scaling_supported() || n < 0 || n >= Fl::screen_count()) + return 1.; return Fl::screen_driver()->scale(n); } -/** Sets the value of the GUI scaling factor for screen number \p n (n ∈ [0 , Fl::screen_count()-1]). - Also sets the scale factor value of all windows mapped to screen number \p n, if any. - */ +/** Sets the GUI scaling factor of screen number \p n. + + The valid range of \p n is 0 .. Fl::screen_count() - 1. + + This method does nothing if \p n is out of range or screen scaling + is not supported by this platform. + + Otherwise it also sets the scaling factor of all windows mapped to + screen number \p n or all screens, depending on the type of screen + scaling support on the platform. + + \param[in] n screen number + \param[in] factor scaling factor of screen \p n + + \see Fl::screen_scaling_supported() + + \since 1.4.0 +*/ void Fl::screen_scale(int n, float factor) { Fl_Screen_Driver::APP_SCALING_CAPABILITY capability = Fl::screen_driver()->rescalable(); if (!capability || n < 0 || n >= Fl::screen_count()) return; @@ -2283,16 +2392,21 @@ void Fl::screen_scale(int n, float factor) { for (int s = 0; s < Fl::screen_count(); s++) { Fl::screen_driver()->rescale_all_windows_from_screen(s, factor, factor); } - } else Fl::screen_driver()->rescale_all_windows_from_screen(n, factor, factor); + } else + Fl::screen_driver()->rescale_all_windows_from_screen(n, factor, factor); } /** - See if scaling factors are supported by this platform. - \return 0 if scaling factors are not supported by this platform, - 1 if a single scaling factor value is shared by all screens, 2 if each screen - can have its own scaling factor value. + Returns whether scaling factors are supported by this platform. + + \retval 0 scaling factors are not supported by this platform + \retval 1 a single scaling factor is shared by all screens + \retval 2 each screen can have its own scaling factor + \see Fl::screen_scale(int) - */ + + \since 1.4.0 +*/ int Fl::screen_scaling_supported() { return Fl::screen_driver()->rescalable(); } @@ -2309,6 +2423,8 @@ int Fl::screen_scaling_supported() { \param value 0 to stop recognition of ctrl/+/-/0/ (or cmd/+/-/0/ under macOS) keys as window scaling. + + \since 1.4.0 */ void Fl::keyboard_screen_scaling(int value) { Fl_Screen_Driver::keyboard_screen_scaling = value; diff --git a/libraries/fltk/src/Fl_Browser.cxx b/libraries/fltk/src/Fl_Browser.cxx index 46546fb66f..9228529e2d 100644 --- a/libraries/fltk/src/Fl_Browser.cxx +++ b/libraries/fltk/src/Fl_Browser.cxx @@ -1,7 +1,7 @@ // // Browser widget for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2017 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -526,9 +526,9 @@ void Fl_Browser::item_draw(void* item, int X, int Y, int W, int H) const { Fl_Color lcol = textcolor(); Fl_Align talign = FL_ALIGN_LEFT; // check for all the @-lines recognized by XForms: - //#if defined(__GNUC__) - //#warning FIXME This maybe needs to be more UTF8 aware now...? - //#endif /*__GNUC__*/ + // #if defined(__GNUC__) + // #warning FIXME This maybe needs to be more UTF-8 aware now...? + // #endif /*__GNUC__*/ if ( format_char() ) { // can be NULL while (*str == format_char() && *++str && *str != format_char()) { switch (*str++) { diff --git a/libraries/fltk/src/Fl_Button.cxx b/libraries/fltk/src/Fl_Button.cxx index 5ea3e45c0a..4df8626c65 100644 --- a/libraries/fltk/src/Fl_Button.cxx +++ b/libraries/fltk/src/Fl_Button.cxx @@ -250,7 +250,7 @@ void Fl_Button::key_release_timeout(void *d) Derived classes may handle this differently. - A button may reequest callbacks with \p whne() \p FL_WHEN_CHANGED, + A button may request callbacks with \p when() \p FL_WHEN_CHANGED, \p FL_WHEN_NOT_CHANGED, and \p FL_WHEN_RELEASE, triggering the callback reasons \p FL_REASON_CHANGED, \p FL_REASON_SELECTED, and \p FL_REASON_DESELECTED. diff --git a/libraries/fltk/src/Fl_Choice.cxx b/libraries/fltk/src/Fl_Choice.cxx index 66bd57ab6d..e5a0276af4 100644 --- a/libraries/fltk/src/Fl_Choice.cxx +++ b/libraries/fltk/src/Fl_Choice.cxx @@ -1,7 +1,7 @@ // // Choice widget for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2022 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -36,9 +36,7 @@ void Fl_Choice::draw() { // Arrow area int H = h() - 2 * dy; - int W = Fl::is_scheme("gtk+") ? 20 : // gtk+ -- fixed size - Fl::is_scheme("gleam") ? 20 // gleam -- fixed size - : ((H > 20) ? 20 : H); // else: shrink if H<20 + int W = 20; int X = x() + w() - W - dx; int Y = y() + dy; @@ -76,14 +74,15 @@ void Fl_Choice::draw() { Fl::is_scheme("gleam") || Fl::is_scheme("oxy")) { // draw the divider - int x1 = x() + w() - 20 - dx; - int y1 = y() + h() / 2; + int x1 = x() + w() - W - 2 * dx; + int y1 = y() + dy; + int y2 = y() + h() - dy; fl_color(fl_darker(color())); - fl_yxline(x1, y1 - 8, y1 + 8); + fl_yxline(x1, y1, y2); fl_color(fl_lighter(color())); - fl_yxline(x1 + 1, y1 - 8, y1 + 8); + fl_yxline(x1 + 1, y1, y2); } } else { // Default scheme ("None") // Draw arrow box @@ -114,6 +113,7 @@ void Fl_Choice::draw() { l.font = m.labelsize_ || m.labelfont_ ? m.labelfont_ : textfont(); l.size = m.labelsize_ ? m.labelsize_ : textsize(); l.color= m.labelcolor_ ? m.labelcolor_ : textcolor(); + l.h_margin_ = l.v_margin_ = l.spacing = 0; 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); diff --git a/libraries/fltk/src/Fl_Device.cxx b/libraries/fltk/src/Fl_Device.cxx index 966516aca3..cd86ddfd75 100644 --- a/libraries/fltk/src/Fl_Device.cxx +++ b/libraries/fltk/src/Fl_Device.cxx @@ -61,6 +61,7 @@ +- Fl_Scalable_Graphics_Driver: helper class to support GUI scaling +- Fl_Xlib_Graphics_Driver: X11-specific graphics driver +- Fl_GDI_Graphics_Driver: Windows-specific graphics driver + +- Fl_GDIplus_Graphics_Driver: overrides oblique lines, arcs and circles +- Fl_GDI_Printer_Graphics_Driver: overrides a few member functions especially for output to printer +- Fl_Cairo_Graphics_Driver: full FLTK drawing API based on Cairo and Pango +- Fl_Wayland_Graphics_Driver: Wayland-specific graphics driver @@ -71,17 +72,22 @@ */ /** Make this surface the current drawing surface. - This surface will receive all future graphics requests. - \p Starting from FLTK 1.4.0, the preferred API to change the current drawing surface - is Fl_Surface_Device::push_current( ) / Fl_Surface_Device::pop_current(). - \note It's recommended to use this function only as follows : - \li The current drawing surface is the display; - \li make current another surface, e.g., an Fl_Printer or an Fl_Image_Surface object, calling set_current() on this object; - \li draw to that surface; - \li make the display current again with Fl_Display_Device::display_device()->set_current(); . Don't do any other call to set_current() before this one. - - Other scenarios of drawing surface changes should be performed via Fl_Surface_Device::push_current( ) / Fl_Surface_Device::pop_current(). - */ + This surface will receive all future graphics requests. + + Since FLTK 1.4.0 the preferred API to change the current drawing surface + is Fl_Surface_Device::push_current( ) / Fl_Surface_Device::pop_current(). + + \note It is recommended to use this function only as follows : + - The current drawing surface is the display; + - make current another surface, e.g., an Fl_Printer or an Fl_Image_Surface object, + calling set_current() on this object; + - draw to that surface; + - make the display current again with Fl_Display_Device::display_device()->set_current();\n + don't do any other call to set_current() before this one. + + Other scenarios of drawing surface changes should be performed via + Fl_Surface_Device::push_current() and Fl_Surface_Device::pop_current(). +*/ void Fl_Surface_Device::set_current(void) { if (surface_) surface_->end_current(); diff --git a/libraries/fltk/src/Fl_File_Chooser.cxx b/libraries/fltk/src/Fl_File_Chooser.cxx index 6c27c6c94b..86c9c24ccf 100644 --- a/libraries/fltk/src/Fl_File_Chooser.cxx +++ b/libraries/fltk/src/Fl_File_Chooser.cxx @@ -312,7 +312,7 @@ Fl_File_Chooser::Fl_File_Chooser(const char *pathname, const char *pattern, int callback_ = 0; data_ = 0; directory_[0] = 0; - window->size_range(window->w(), window->h(), Fl::w(), Fl::h()); + window->size_range(window->w(), window->h()); type(type_val); filter(pattern); update_favorites(); diff --git a/libraries/fltk/src/Fl_File_Chooser.fl b/libraries/fltk/src/Fl_File_Chooser.fl index caa695ce89..b7d6362e13 100644 --- a/libraries/fltk/src/Fl_File_Chooser.fl +++ b/libraries/fltk/src/Fl_File_Chooser.fl @@ -242,7 +242,7 @@ hide();} code {callback_ = 0; data_ = 0; directory_[0] = 0; -window->size_range(window->w(), window->h(), Fl::w(), Fl::h()); +window->size_range(window->w(), window->h()); type(type_val); filter(pattern); update_favorites(); diff --git a/libraries/fltk/src/Fl_File_Chooser2.cxx b/libraries/fltk/src/Fl_File_Chooser2.cxx index 56cce99508..46e902c18f 100644 --- a/libraries/fltk/src/Fl_File_Chooser2.cxx +++ b/libraries/fltk/src/Fl_File_Chooser2.cxx @@ -2,7 +2,7 @@ // More Fl_File_Chooser routines. // // Copyright 1999-2007 by Michael Sweet. -// Copyright 2008-2020 by Bill Spitzak and others. +// Copyright 2008-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -794,7 +794,8 @@ Fl_File_Chooser::fileNameCB() if (dirIsRelative) { fl_filename_absolute(pathname, sizeof(pathname), filename); value(pathname); - fileName->mark(fileName->insert_position()); // no selection after expansion + int flen = (int)strlen(pathname); + fileName->insert_position(flen, flen); // no selection after expansion } else if (filename != pathname) { // Finally, make sure that we have a writable copy... strlcpy(pathname, filename, sizeof(pathname)); @@ -1314,7 +1315,7 @@ Fl_File_Chooser::update_preview() window->cursor(FL_CURSOR_DEFAULT); Fl::check(); - // Scan the buffer for printable UTF8 chars... + // Scan the buffer for printable UTF-8 chars... for (ptr = preview_text_; *ptr; ptr++) { uchar c = uchar(*ptr); if ( (c&0x80)==0 ) { @@ -1466,6 +1467,21 @@ Fl_File_Chooser::value(int f) // I - File number /** Sets the current value of the selected file. + + If a relative path is provided in \c filename it is converted to + an absolute path. + + If \c NULL or an empty string is provided, the working directory is + changed to the user's current directory and the filename is set to "". + + After assigning the filename the entire string (if any) is selected, i.e. + - insert_position() is 0 (zero) + - mark() is strlen(\). + + \note The selection of the entire string may not always be desired but + it is kept for backwards compatibility. + + \param[in] filename relative or absolute filename, may be NULL or "" */ void Fl_File_Chooser::value(const char *filename) diff --git a/libraries/fltk/src/Fl_Graphics_Driver.cxx b/libraries/fltk/src/Fl_Graphics_Driver.cxx index 6142c8672c..95716530a4 100644 --- a/libraries/fltk/src/Fl_Graphics_Driver.cxx +++ b/libraries/fltk/src/Fl_Graphics_Driver.cxx @@ -751,13 +751,23 @@ Fl_Scalable_Graphics_Driver::Fl_Scalable_Graphics_Driver() : Fl_Graphics_Driver( void Fl_Scalable_Graphics_Driver::rect(int x, int y, int w, int h) { if (w > 0 && h > 0) { - xyline(x, y, x+w-1); - yxline(x, y, y+h-1); - yxline(x+w-1, y, y+h-1); - xyline(x, y+h-1, x+w-1); + int s = (int)scale(); + int d = s / 2; + rect_unscaled(this->floor(x) + d, this->floor(y) + d, + this->floor(x + w) - this->floor(x) - s, + this->floor(y + h) - this->floor(y) - s); } } +// This function aims to compute accurately int(x * s) in +// presence of rounding errors existing with floating point numbers +// and that sometimes differ between 32 and 64 bits. +int Fl_Scalable_Graphics_Driver::floor(int x, float s) { + if (s == 1) return x; + int retval = int(abs(x) * s + 0.001f); + return (x >= 0 ? retval : -retval); +} + void Fl_Scalable_Graphics_Driver::rectf(int x, int y, int w, int h) { if (w <= 0 || h <= 0) return; @@ -794,6 +804,7 @@ void Fl_Scalable_Graphics_Driver::xyline(int x, int y, int x1) { } else { y = this->floor(y); if (line_width_ <= s_int) y += int(s/2.f); + else y += s_int/2; xyline_unscaled(this->floor(xx), y, this->floor(xx1+1) - 1); } } @@ -813,6 +824,7 @@ void Fl_Scalable_Graphics_Driver::yxline(int x, int y, int y1) { } else { x = this->floor(x); if (line_width_ <= s_int) x += int(s/2.f); + else x += s_int/2; yxline_unscaled(x, this->floor(yy), this->floor(yy1+1) - 1); } } @@ -1074,14 +1086,13 @@ Fl_Region Fl_Scalable_Graphics_Driver::scale_clip(float f) { return 0; } void Fl_Scalable_Graphics_Driver::point_unscaled(float x, float y) {} +void Fl_Scalable_Graphics_Driver::rect_unscaled(int x, int y, int w, int h) {} + void Fl_Scalable_Graphics_Driver::rectf_unscaled(int x, int y, int w, int h) {} void Fl_Scalable_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1) {} -void Fl_Scalable_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1, int x2, int y2) { - line_unscaled(x, y, x1, y1); - line_unscaled(x1, y1, x2, y2); -} +void Fl_Scalable_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1, int x2, int y2) {} void Fl_Scalable_Graphics_Driver::xyline_unscaled(int x, int y, int x1) {} diff --git a/libraries/fltk/src/Fl_Group.cxx b/libraries/fltk/src/Fl_Group.cxx index 2576efea74..07079cf8c7 100644 --- a/libraries/fltk/src/Fl_Group.cxx +++ b/libraries/fltk/src/Fl_Group.cxx @@ -375,6 +375,8 @@ Fl_Group::Fl_Group(int X,int Y,int W,int H,const char *l) \internal If the Fl_Group widget contains the Fl::focus() or the Fl::pushed() widget these are set to sensible values (other widgets or the Fl_Group widget itself). + + \see Fl_Group::remove(int), Fl_Group::delete_child(int), Fl_Group::~Fl_Group() */ void Fl_Group::clear() { savedfocus_ = 0; diff --git a/libraries/fltk/src/Fl_Help_View.cxx b/libraries/fltk/src/Fl_Help_View.cxx index f83c8a126b..d77d5caeec 100644 --- a/libraries/fltk/src/Fl_Help_View.cxx +++ b/libraries/fltk/src/Fl_Help_View.cxx @@ -50,6 +50,7 @@ #include #include #include +#include #include "Fl_Int_Vector.H" #include "Fl_String.H" @@ -130,6 +131,14 @@ static const char * const broken_xpm[] = static Fl_Pixmap broken_image(broken_xpm); +/** [this text may be customized at run-time] */ +const char *Fl_Help_View::copy_menu_text = "Copy"; + +static Fl_Menu_Item rmb_menu[] = { + { NULL, 0, NULL, (void*)1 }, // Copy + { NULL } +}; + // // Simple margin stack for Fl_Help_View::format()... // @@ -210,51 +219,51 @@ img->draw() // We don't put the offscreen buffer in the help view class because // we'd need to include platform.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; +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_; /* * This function must be optimized for speed! */ void Fl_Help_View::hv_draw(const char *t, int x, int y, int entity_extra_length) { - if (selected && current_view==this && current_pos=selection_first) { + if (selected_ && current_view_==this && current_pos_=selection_first_) { Fl_Color c = fl_color(); - fl_color(hv_selection_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 = (int) current_pos; + if (mouse_x_>=x && mouse_x_=y-fl_height()+fl_descent()&&mouse_y_<=y+fl_descent()) { + int f = (int) current_pos_; int l = (int) (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; + if (draw_mode_==1) { + selection_push_first_ = f; + selection_push_last_ = l; } else { - selection_drag_first = f; - selection_drag_last = l + entity_extra_length; + selection_drag_first_ = f; + selection_drag_last_ = l + entity_extra_length; } } } @@ -556,11 +565,11 @@ Fl_Help_View::draw() if (!value_) return; - if (current_view == this && selected) { - hv_selection_color = FL_SELECTION_COLOR; - hv_selection_text_color = fl_contrast(textcolor_, FL_SELECTION_COLOR); + if (current_view_ == this && selected_) { + hv_selection_color_ = FL_SELECTION_COLOR; + hv_selection_text_color_ = fl_contrast(textcolor_, FL_SELECTION_COLOR); } - current_pos = 0; + 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), @@ -613,7 +622,7 @@ Fl_Help_View::draw() fl_xyline(xx + x() - leftline_, yy + y() + 1, xx + x() - leftline_ + ww + xtra_ww); } - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); xx += ww; if ((fsize + 2) > hh) @@ -631,7 +640,7 @@ Fl_Help_View::draw() if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, xx + x() - leftline_ + buf.width()); buf.clear(); - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); if (line < 31) line ++; xx = block->line[line]; @@ -662,7 +671,7 @@ Fl_Help_View::draw() if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, xx + x() - leftline_ + ww); xx += ww; - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); } needspace = 0; @@ -673,7 +682,7 @@ Fl_Help_View::draw() while (isspace((*ptr)&255)) ptr ++; - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); } } @@ -705,7 +714,7 @@ Fl_Help_View::draw() ptr ++; // end of command reached, set the supposed start of printed eord here - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); if (buf.cmp("HEAD")) head = 1; else if (buf.cmp("BR")) @@ -964,7 +973,7 @@ Fl_Help_View::draw() needspace = 0; ptr ++; - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); } else if (isspace((*ptr)&255)) { @@ -982,7 +991,7 @@ Fl_Help_View::draw() } ptr ++; - if (!pre) current_pos = (int) (ptr-value_); + if (!pre) current_pos_ = (int) (ptr-value_); needspace = 1; } else if (*ptr == '&') // process html entity @@ -1036,7 +1045,7 @@ Fl_Help_View::draw() hv_draw(buf.c_str(), xx + x() - leftline_, yy + y()); if (underline) fl_xyline(xx + x() - leftline_, yy + y() + 1, xx + x() - leftline_ + ww); - current_pos = (int) (ptr-value_); + current_pos_ = (int) (ptr-value_); } } @@ -2837,7 +2846,7 @@ void Fl_Help_View::follow_link(Fl_Help_Link *linkp) /** Removes the current text selection. */ void Fl_Help_View::clear_selection() { - if (current_view==this) + if (current_view_==this) clear_global_selection(); } /** Selects all the text in the view. */ @@ -2845,18 +2854,18 @@ void Fl_Help_View::select_all() { clear_global_selection(); if (!value_) return; - current_view = this; - selection_drag_last = selection_last = (int) strlen(value_); - selected = 1; + current_view_ = this; + selection_drag_last_ = selection_last_ = (int) 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; + 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() @@ -2865,18 +2874,18 @@ char Fl_Help_View::begin_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; + mouse_x_ = Fl::event_x(); + mouse_y_ = Fl::event_y(); + draw_mode_ = 1; - current_view = this; + current_view_ = this; fl_begin_offscreen(fl_help_view_buffer); draw(); fl_end_offscreen(); - draw_mode = 0; + draw_mode_ = 0; - if (selection_push_last) return 1; + if (selection_push_last_) return 1; else return 0; } @@ -2885,38 +2894,44 @@ 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); + // Give this widget the focus during the selection process. This will + // deselect other text selection and make sure, we receive the Copy + // keyboard shortcut. + if (Fl::focus()!=this) + Fl::focus(this); - int sf = selection_first, sl = selection_last; +// printf("old selection_first_=%d, selection_last_=%d\n", +// selection_first_, selection_last_); - selected = 1; - mouse_x = Fl::event_x(); - mouse_y = Fl::event_y(); - draw_mode = 2; + 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; + draw_mode_ = 0; - if (selection_push_first < selection_drag_first) { - selection_first = selection_push_first; + if (selection_push_first_ < selection_drag_first_) { + selection_first_ = selection_push_first_; } else { - selection_first = selection_drag_first; + selection_first_ = selection_drag_first_; } - if (selection_push_last > selection_drag_last) { - selection_last = selection_push_last; + if (selection_push_last_ > selection_drag_last_) { + selection_last_ = selection_push_last_; } else { - selection_last = selection_drag_last; + selection_last_ = selection_drag_last_; } -// printf("new selection_first=%d, selection_last=%d\n", -// selection_first, selection_last); +// printf("new selection_first_=%d, selection_last_=%d\n", +// selection_first_, selection_last_); - if (sf!=selection_first || sl!=selection_last) { + if (sf!=selection_first_ || sl!=selection_last_) { // puts("REDRAW!!!\n"); return 1; } else { @@ -2947,7 +2962,7 @@ static unsigned int command(const char *cmd) void Fl_Help_View::end_selection(int clipboard) { - if (!selected || current_view!=this) + if (!selected_ || current_view_!=this) return; // convert the select part of our html text into some kind of somewhat readable UTF-8 // and store it in the selection buffer @@ -2995,7 +3010,7 @@ void Fl_Help_View::end_selection(int clipboard) case CMD('d','d', 0 , 0 ): src = "\n - "; break; } int n = (int) (s-value_); - if (src && n>selection_first && n<=selection_last) { + if (src && n>selection_first_ && n<=selection_last_) { while (*src) { *d++ = *src++; } @@ -3016,7 +3031,7 @@ void Fl_Help_View::end_selection(int clipboard) } } int n = (int) (s2-value_); - if (n>selection_first && n<=selection_last) { + if (n>selection_first_ && n<=selection_last_) { if (!pre && c < 256 && isspace(c)) c = ' '; if (p != ' ' || c != ' ') { if (s2 != s) { // c was an HTML entity @@ -3026,7 +3041,7 @@ void Fl_Help_View::end_selection(int clipboard) } p = c; } - if (n>selection_last) break; // stop parsing html after end of selection + if (n>selection_last_) break; // stop parsing html after end of selection } *d = 0; Fl::copy(txt, (int) strlen(txt), clipboard); @@ -3034,6 +3049,31 @@ void Fl_Help_View::end_selection(int clipboard) free(txt); } +/** + \brief Check if the user selected text in this view. + \return 1 if text is selected, 0 if no text is selected + */ +int Fl_Help_View::text_selected() { + if (current_view_==this) + return selected_; + else + return 0; +} + +/** + \brief If text is selected in this view, copy it to a clipboard. + \param[in] clipboard for x11 only, 0=selection buffer, 1=clipboard, 2=both + \return 1 if text is selected, 0 if no text is selected + */ +int Fl_Help_View::copy(int clipboard) { + if (text_selected()) { + end_selection(clipboard); + return 1; + } else { + return 0; + } +} + /** Handles events in the widget. */ int // O - 1 if we handled it, 0 otherwise Fl_Help_View::handle(int event) // I - Event to handle @@ -3063,6 +3103,20 @@ Fl_Help_View::handle(int event) // I - Event to handle else fl_cursor(FL_CURSOR_DEFAULT); return 1; case FL_PUSH: + if (Fl::event_button() == FL_RIGHT_MOUSE) { + rmb_menu[0].label(copy_menu_text); + if (text_selected()) + rmb_menu[0].activate(); + else + rmb_menu[0].deactivate(); + fl_cursor(FL_CURSOR_DEFAULT); + const Fl_Menu_Item *mi = rmb_menu->popup(Fl::event_x(), Fl::event_y()); + if (mi) switch (mi->argument()) { + case 1: + copy(); + break; + } + } if (Fl_Group::handle(event)) return 1; linkp = find_link(xx, yy); if (linkp) { @@ -3084,7 +3138,7 @@ Fl_Help_View::handle(int event) // I - Event to handle } return 1; } - if (current_view==this && selection_push_last) { + if (current_view_==this && selection_push_last_) { if (extend_selection()) redraw(); fl_cursor(FL_CURSOR_INSERT); return 1; @@ -3100,7 +3154,7 @@ Fl_Help_View::handle(int event) // I - Event to handle linkp = 0; return 1; } - if (current_view==this && selection_push_last) { + if (current_view_==this && selection_push_last_) { end_selection(); return 1; } diff --git a/libraries/fltk/src/Fl_Image.cxx b/libraries/fltk/src/Fl_Image.cxx index fe68f457a9..21a7db2b92 100644 --- a/libraries/fltk/src/Fl_Image.cxx +++ b/libraries/fltk/src/Fl_Image.cxx @@ -80,6 +80,10 @@ void Fl_Image::draw_empty(int X, int Y) { /** Creates a resized copy of the image. + It is recommended not to call this member function to reduce the size + of an image to the size of the area where this image will be drawn, + and to use Fl_Image::scale() instead. + The new image should be released when you are done with it. Note: since FLTK 1.4.0 you can use Fl_Image::release() for all types diff --git a/libraries/fltk/src/Fl_Input.cxx b/libraries/fltk/src/Fl_Input.cxx index 948354d19f..fd66d8f24e 100644 --- a/libraries/fltk/src/Fl_Input.cxx +++ b/libraries/fltk/src/Fl_Input.cxx @@ -320,13 +320,30 @@ int Fl_Input::kf_copy_cut() { class. It handles compose key sequences and can also be used e.g. in Fl_Multiline_Input, Fl_Float_Input and several more derived classes. - The details are way too complicated to be documented here and can be - changed as required. If in doubt, please consult the source code. + The method first checks in Fl::compose if the keystroke is a text entry or + a control key. If it is text, the method inserts the composed characters into + the input field, taking into account the input type (e.g., numeric fields). + + If the keystroke is a control key as determined by Fl::compose, the method + handles key combinations for Insert, Enter, and Tab depending on the + widget's input_type(). + + The method then checks for Ctrl key combinations, such as Ctrl-A, Ctrl-C, + Ctrl-V, Ctrl-X, and Ctrl-Z, which are commonly used for select all, copy, + paste, cut, and undo operations. + + Finally, the method checks for ASCII control characters, such as Ctrl-H, + Ctrl-I, Ctrl-J, Ctrl-L, and Ctrl-M, which can be used to insert literal + control characters into the input field. + + If none of the above cases match, the method returns 0, indicating that the + keystroke was not handled. \returns 1 if the keystroke is handled by us, 0 if not. */ int Fl_Input::handle_key() { + // This is unicode safe: only character codes < 128 are queried char ascii = Fl::event_text()[0]; int del; diff --git a/libraries/fltk/src/Fl_Input_.cxx b/libraries/fltk/src/Fl_Input_.cxx index 244644c09e..18945c242f 100644 --- a/libraries/fltk/src/Fl_Input_.cxx +++ b/libraries/fltk/src/Fl_Input_.cxx @@ -1095,7 +1095,7 @@ int Fl_Input_::undo() { /** Check if the last operation can be undone. - \return true if the widget can unod the last change + \return true if the widget can undo the last change */ bool Fl_Input_::can_undo() const { return (undo_->undocut || undo_->undoinsert); diff --git a/libraries/fltk/src/Fl_Input_Choice.cxx b/libraries/fltk/src/Fl_Input_Choice.cxx index f18eb3ac9e..77a7d937e9 100644 --- a/libraries/fltk/src/Fl_Input_Choice.cxx +++ b/libraries/fltk/src/Fl_Input_Choice.cxx @@ -5,7 +5,7 @@ // | input area || \/ | // |______________||____| // -// Copyright 1998-2022 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // Copyright 2004 by Greg Ercolano. // // This library is free software. Distribution and use rights are outlined in @@ -125,7 +125,6 @@ */ /** Constructor for private menu button. */ - Fl_Input_Choice::InputMenuButton::InputMenuButton(int x,int y,int w,int h,const char*l) :Fl_Menu_Button(x,y,w,h,l) { @@ -133,14 +132,22 @@ Fl_Input_Choice::InputMenuButton::InputMenuButton(int x,int y,int w,int h,const } /** Draws the private menu button. */ - void Fl_Input_Choice::InputMenuButton::draw() { - draw_box(); - Fl_Color arrow_color = parent()->active_r() ? parent()->labelcolor() : fl_inactive(parent()->labelcolor()); - Fl_Rect ab(this); - ab.inset(1); - fl_draw_arrow(ab, FL_ARROW_CHOICE, FL_ORIENT_NONE, arrow_color); - if (Fl::focus() == this) draw_focus(); + if (!box()) return; + + // Draw box for default scheme only + // For all other schemes, let parent group's box show through + // + if (!Fl::scheme()) + draw_box(pressed_menu_button_ == this ? fl_down(box()) : box(), color()); + if (Fl::focus() == this) { + int woff = Fl::scheme() ? 2 : 1; // helps center focus box + draw_focus(FL_UP_BOX, x(), y(), w()+woff, h(), color()); + } + + // draw the arrow (choice button) + Fl_Color arrow_color = active_r() ? labelcolor() : fl_inactive(labelcolor()); + fl_draw_arrow(Fl_Rect(x(), y(), w(), h()), FL_ARROW_CHOICE, FL_ORIENT_NONE, arrow_color); } // Make pulldown menu appear under entire width of widget @@ -251,7 +258,7 @@ void Fl_Input_Choice::inp_cb(Fl_Widget*, void *data) { Inherited destructor destroys the widget and any values associated with it. */ -Fl_Input_Choice::Fl_Input_Choice (int X, int Y, int W, int H, const char *L) +Fl_Input_Choice::Fl_Input_Choice(int X, int Y, int W, int H, const char *L) : Fl_Group(X,Y,W,H,L) { Fl_Group::box(FL_DOWN_BOX); align(FL_ALIGN_LEFT); // default like Fl_Input @@ -337,3 +344,63 @@ int Fl_Input_Choice::update_menubutton() { } return 0; // not found } + +void Fl_Input_Choice::draw() { + // This is copied from Fl_Choice::draw() and customized + Fl_Boxtype btype = Fl::scheme() ? FL_UP_BOX // non-default uses up box + : FL_DOWN_BOX; // default scheme uses down box + int dx = Fl::box_dx(btype); + int dy = Fl::box_dy(btype); + + // From "original" code: modify the box color *only* for the default scheme. + // This is weird (why?). I believe we should either make sure that the text + // color contrasts well when the text is rendered *or* we should do this for + // *all* schemes. Anyway, adapting the old code... (Albrecht) + // + Fl_Color box_color = color(); + if (!Fl::scheme()) { // default scheme only, see comment above + if (fl_contrast(textcolor(), FL_BACKGROUND2_COLOR) == textcolor()) + box_color = FL_BACKGROUND2_COLOR; + else + box_color = fl_lighter(color()); + } + + // Draw the widget box + draw_box(btype, box_color); + + // Draw menu button + draw_child(*menu_); + + // Draw vertical divider lines for: gtk+, gleam, oxy + // + // Scheme: Box or divider line + // ---------------------------------------- + // Default (None): Arrow box (FL_UP_BOX) + // gtk+, gleam, oxy: Divider line + // else: Nothing - Fl_Group::box() shows through + // + int woff = 0; + if (Fl::is_scheme("gtk+") || + Fl::is_scheme("gleam") || + Fl::is_scheme("oxy")) { + // draw the vertical divider line + int x1 = menu_x() - dx; + int y1 = y() + dy; + int y2 = y() + h() - dy; + + fl_color(fl_darker(color())); + fl_yxline(x1+0, y1, y2); + + fl_color(fl_lighter(color())); + fl_yxline(x1+1, y1, y2); + woff = 2; // prevent Fl_Input from overdrawing divider + } + + // Draw the input field + fl_push_clip(inp_x(), inp_y(), inp_w() - woff, inp_h()); + draw_child(*inp_); + fl_pop_clip(); + + // Widget's label + draw_label(); +} diff --git a/libraries/fltk/src/Fl_MacOS_Sys_Menu_Bar.mm b/libraries/fltk/src/Fl_MacOS_Sys_Menu_Bar.mm index de7e7b00c5..b76deb27e0 100644 --- a/libraries/fltk/src/Fl_MacOS_Sys_Menu_Bar.mm +++ b/libraries/fltk/src/Fl_MacOS_Sys_Menu_Bar.mm @@ -378,7 +378,9 @@ static void createSubMenu( NSMenu *mh, pFl_Menu_Item &mm, const Fl_Menu_Item *m mm = mm->next(0); continue; } - miCnt = [FLMenuItem addNewItem:mm menu:submenu action:selector]; + miCnt = [FLMenuItem addNewItem:mm menu:submenu + action:( (mm->flags & (FL_SUBMENU+FL_SUBMENU_POINTER) && !mm->callback()) ? nil : selector) + ]; setMenuFlags( submenu, miCnt, mm ); setMenuShortcut( submenu, miCnt, mm ); if (mitem && (mm->flags & FL_MENU_INACTIVE || mitem->flags & FL_MENU_INACTIVE)) { @@ -591,10 +593,12 @@ static void move_tab_cb(Fl_Widget *, void *data) static void merge_all_windows_cb(Fl_Widget *, void *) { - Fl_Window *first = Fl::first_window(); - if (first) { - [(NSWindow*)fl_xid(first) mergeAllWindows:nil]; - } + Fl_Window *first = Fl::first_window(); + while (first && (first->parent() || !first->border())) + first = Fl::next_window(first); + if (first) { + [(NSWindow*)fl_xid(first) mergeAllWindows:nil]; + } } #endif @@ -737,10 +741,10 @@ void fl_mac_set_about(Fl_Callback *cb, void *user_data, int shortcut) { free(label); AXUIElementRef appElement = AXUIElementCreateApplication(getpid()); AXUIElementRef menu_bar = NULL; - AXError error = AXUIElementCopyAttributeValue(appElement, kAXMenuBarAttribute, + AXError error = AXUIElementCopyAttributeValue(appElement, kAXMenuBarAttribute, (CFTypeRef *)&menu_bar); if (!error) error = AXUIElementGetAttributeValueCount(menu_bar, kAXChildrenAttribute, &count); - if (!error) error = AXUIElementCopyAttributeValues(menu_bar, kAXChildrenAttribute, 0, count, + if (!error) error = AXUIElementCopyAttributeValues(menu_bar, kAXChildrenAttribute, 0, count, &children); if (!error) { NSEnumerator *enumerator = [(NSArray*)children objectEnumerator]; diff --git a/libraries/fltk/src/Fl_Menu.cxx b/libraries/fltk/src/Fl_Menu.cxx index ed362a921b..6332673da5 100644 --- a/libraries/fltk/src/Fl_Menu.cxx +++ b/libraries/fltk/src/Fl_Menu.cxx @@ -261,6 +261,7 @@ int Fl_Menu_Item::measure(int* hp, const Fl_Menu_* m) const { l.font = labelsize_ || labelfont_ ? labelfont_ : (m ? m->textfont() : FL_HELVETICA); l.size = labelsize_ ? labelsize_ : m ? m->textsize() : FL_NORMAL_SIZE; l.color = FL_FOREGROUND_COLOR; // this makes no difference? + l.h_margin_ = l.v_margin_ = l.spacing = 0; fl_draw_shortcut = 1; int w = 0; int h = 0; l.measure(w, hp ? *hp : h); @@ -280,6 +281,7 @@ void Fl_Menu_Item::draw(int x, int y, int w, int h, const Fl_Menu_* m, l.font = labelsize_ || labelfont_ ? labelfont_ : (m ? m->textfont() : FL_HELVETICA); l.size = labelsize_ ? labelsize_ : m ? m->textsize() : FL_NORMAL_SIZE; l.color = labelcolor_ ? labelcolor_ : m ? m->textcolor() : int(FL_FOREGROUND_COLOR); + l.h_margin_ = l.v_margin_ = l.spacing = 0; if (!active()) l.color = fl_inactive((Fl_Color)l.color); if (selected) { Fl_Color r = m ? m->selection_color() : FL_SELECTION_COLOR; @@ -491,8 +493,11 @@ void menuwindow::autoscroll(int n) { int xx, ww; Fl_Window_Driver::driver(this)->menu_window_area(xx, scr_y, ww, scr_h); - if (Y <= scr_y) Y = scr_y-Y+10; - else { + if (n==0 && Y <= scr_y + itemheight) { + Y = scr_y - Y + 10; + } else if (Y <= scr_y + itemheight) { + Y = scr_y - Y + 10 + itemheight; + } else { Y = Y+itemheight-scr_h-scr_y; if (Y < 0) return; Y = -Y-10; @@ -694,15 +699,19 @@ static void setitem(int m, int n) { static int forward(int menu) { // go to next item in menu menu if possible menustate &pp = *p; - // Fl_Menu_Button can generate menu=-1. This line fixes it and selectes the first item. + // Fl_Menu_Button can generate menu=-1. This line fixes it and selects 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;} + do { + while (++item < m.numitems) { + const Fl_Menu_Item* m1 = m.menu->next(item); + if (m1->activevisible()) {setitem(m1, menu, item); return 1;} + } + item = -1; } + while (pp.menubar && Fl::event_key() == FL_Right); return 0; } @@ -713,11 +722,14 @@ 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;} + do { + while (--item >= 0) { + const Fl_Menu_Item* m1 = m.menu->next(item); + if (m1->activevisible()) {setitem(m1, menu, item); return 1;} + } + item = m.numitems; } + while (pp.menubar && Fl::event_key() == FL_Left); return 0; } @@ -812,7 +824,8 @@ int menuwindow::handle_part1(int e) { } return 1; case FL_Right: - if (pp.menubar && (pp.menu_number<=0 || (pp.menu_number==1 && pp.nummenus==2))) + RIGHT: + if (pp.menubar && (pp.menu_number<=0 || (pp.menu_number == pp.nummenus-1))) forward(0); else if (pp.menu_number < pp.nummenus-1) forward(pp.menu_number+1); return 1; @@ -824,6 +837,11 @@ int menuwindow::handle_part1(int e) { case FL_Enter: case FL_KP_Enter: case ' ': + // if the current item is a submenu with no callback, + // simulate FL_Right to enter the submenu + if (pp.current_item && (!pp.menubar || pp.menu_number > 0) && + pp.current_item->activevisible() && pp.current_item->submenu() && !pp.current_item->callback_) + goto RIGHT; pp.state = DONE_STATE; return 1; case FL_Escape: @@ -887,8 +905,7 @@ int menuwindow::handle_part1(int e) { return 0; } } - if (my == 0 && item > 0) setitem(mymenu, item - 1); - else setitem(mymenu, item); + 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 @@ -913,8 +930,9 @@ int menuwindow::handle_part1(int e) { 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()) + // do nothing if they try to pick an inactive item, or a submenu with no callback + if (!pp.current_item || (pp.current_item->activevisible() && + (!pp.current_item->submenu() || pp.current_item->callback_ || (pp.menubar && pp.menu_number <= 0)))) pp.state = DONE_STATE; } return 1; @@ -1148,6 +1166,10 @@ const Fl_Menu_Item* Fl_Menu_Item::popup( return pulldown(X, Y, 0, 0, picked, menu_button, title ? &dummy : 0); } +static bool is_special_labeltype(uchar t) { + return t == _FL_MULTI_LABEL || t == _FL_ICON_LABEL || t == _FL_IMAGE_LABEL; +} + /** Search only the top level menu for a shortcut. Either &x in the label or the shortcut fields are used. @@ -1165,7 +1187,13 @@ const Fl_Menu_Item* Fl_Menu_Item::find_shortcut(int* ip, const bool require_alt) if (m) for (int ii = 0; m->text; m = next_visible_or_not(m), ii++) { if (m->active()) { if (Fl::test_shortcut(m->shortcut_) - || Fl_Widget::test_shortcut(m->text, require_alt)) { + || (!is_special_labeltype(m->labeltype_) && Fl_Widget::test_shortcut(m->text, require_alt)) + || (m->labeltype_ == _FL_MULTI_LABEL + && !is_special_labeltype(((Fl_Multi_Label*)m->text)->typea) + && Fl_Widget::test_shortcut(((Fl_Multi_Label*)m->text)->labela, require_alt)) + || (m->labeltype_ == _FL_MULTI_LABEL + && !is_special_labeltype(((Fl_Multi_Label*)m->text)->typeb) + && Fl_Widget::test_shortcut(((Fl_Multi_Label*)m->text)->labelb, require_alt))) { if (ip) *ip=ii; return m; } diff --git a/libraries/fltk/src/Fl_Menu_.cxx b/libraries/fltk/src/Fl_Menu_.cxx index b935fb3661..20964e7481 100644 --- a/libraries/fltk/src/Fl_Menu_.cxx +++ b/libraries/fltk/src/Fl_Menu_.cxx @@ -533,7 +533,7 @@ void Fl_Menu_::menu(const Fl_Menu_Item* m) { See void Fl_Menu_::menu(const Fl_Menu_Item* m). */ void Fl_Menu_::copy(const Fl_Menu_Item* m, void* ud) { - int n = m->size(); + unsigned int n = m->size(); Fl_Menu_Item* newMenu = new Fl_Menu_Item[n]; memcpy(newMenu, m, n*sizeof(Fl_Menu_Item)); menu(newMenu); diff --git a/libraries/fltk/src/Fl_Native_File_Chooser_GTK.cxx b/libraries/fltk/src/Fl_Native_File_Chooser_GTK.cxx index 49b99f6239..e0826e3e2f 100644 --- a/libraries/fltk/src/Fl_Native_File_Chooser_GTK.cxx +++ b/libraries/fltk/src/Fl_Native_File_Chooser_GTK.cxx @@ -972,6 +972,6 @@ Fl_Native_File_Chooser::Fl_Native_File_Chooser(int val) { } } #endif // HAVE_DLSYM && HAVE_DLFCN_H - + if (!platform_fnfc) platform_fnfc = new Fl_Native_File_Chooser_FLTK_Driver(val); } diff --git a/libraries/fltk/src/Fl_Native_File_Chooser_MAC.mm b/libraries/fltk/src/Fl_Native_File_Chooser_MAC.mm index 5d87414603..002e0a4046 100644 --- a/libraries/fltk/src/Fl_Native_File_Chooser_MAC.mm +++ b/libraries/fltk/src/Fl_Native_File_Chooser_MAC.mm @@ -532,16 +532,15 @@ - (NSString *)panel:(id)sender userEnteredFilename:(NSString *)filename confirme - (void)control_allowed_types:(const char *)p { NSString *ext = [NSString stringWithUTF8String:p]; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0 && \ - MAC_OS_X_VERSION_MIN_REQUIRED >= MAC_OS_VERSION_11_0 - if (fl_mac_os_version >= 110000) { - UTType *type = [UTType typeWithFilenameExtension:ext]; // 11.0 + framework UniformTypeIdentifiers - [dialog setAllowedContentTypes:[NSArray arrayWithObject:type]]; // 11.0 +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_11_0 + if (@available(macOS 11.0, *)) { + UTType *type = [UTType typeWithFilenameExtension:ext]; // 11.0 + framework UniformTypeIdentifiers + [dialog setAllowedContentTypes:[NSArray arrayWithObject:type]]; // 11.0 } else #endif if (fl_mac_os_version >= 100900) { - [dialog performSelector:@selector(setAllowedFileTypes:) + [dialog performSelector:@selector(setAllowedFileTypes:) withObject:[NSArray arrayWithObject:ext]]; } } diff --git a/libraries/fltk/src/Fl_Preferences.cxx b/libraries/fltk/src/Fl_Preferences.cxx index d4284af194..586416bf5c 100644 --- a/libraries/fltk/src/Fl_Preferences.cxx +++ b/libraries/fltk/src/Fl_Preferences.cxx @@ -32,6 +32,125 @@ #include #endif +/* + The format of preferences files is not part of the FLTK specification + and intentionally undocumented in Doxygen. The following documentation is FOR + CORE DEVELOPERS ONLY. Don't let any app developer see this! + + This is the unofficial documentation of the file format as it currently stands. + The format may change at any point (although it really should stay backwards + compatible). Preferences files are *not* supposed to be edited manually. + Nevertheless, here are the docs: + + A .prefs file contains multiple lines. A line is defined by 0 or more ASCII + characters in the range from 0x20 to 0x7e, followed by a single '\n' line + ending character. Note that there are no tabs, \0 characters, or '\r' + characters anywhere in a line. Some parts of a line may allow 0x80 to 0xff + to support Unicode UTF-8 octets. + + The first line is always "; FLTK preferences file format 1.0", followed by a + '\n' to indicate the end of the line. The version number may change some time + in the future if the file format ever changes. + + The second line contains the vendor information when the file was created: + "; vendor: VENDOR\n" + + The third line contains the application name + "; application: APPLICATION_NAME\n" + + Any following line that starts with a ';' is not relevant for data and seen + as a comment. Fl_Preferences tries to preserve comments, but has no API to set + or read comments. + + All data is stored in key/value pairs. All key/value pairs are stored inside + their group. There can be multiple groups. Group naming is used to + indicate a hierarchy. + + A line starting with a '[' starts a group. Before and after a group line, + there is always an empty line (no characters, just a '\n'). A group line ends + in "]\n". Directly between the '[' and ']' is the name of the group. The first + ("root")-group is always declared with the line "[.]\n". + + Simple group names are written starting with "./", for example "[./name]\n". + To generate a hierarchy of groups, deeper nested names are generated by adding + more '/name" segments (just like a Unix file path), + for example "[./dialog/button/position]\n". + + Remember that there is an empty line after the group line. + + A group line is followed by 0 or more lines containing key/value pairs for the + given group. + + A key is a sequence of ASCII letters, numbers, ".", or "_". The key should not + be longer than 32 characters. The key is followed by the ":" character and + the value. There is no space before or after the ":". The value may contain + more ":" characters. + + The value is a text of ASCII characters 0x20 to 0x7e or UTF-8 Unicode octets + 0x80 to 0xff. + + The key/value line ends in a "\n". Key/value lines wrap before or at column 80 + with a "\n" and continue in the next line, starting with a "+" which indicates + that this is an overflow line and is furthermore ignored. The type of a value + is not stored in the file. It is not an error to call Fl_Preferences::set with + a "double" and read back a string. + + * Integers are written as signed int using "%d". + * Floating point values are written with decimal points if C_LOCALE is set + when creating the file. + * When text is written, "\r", "\n", and the "\" character are escaped by + prepending them with an additional "\", other characters <0x20 and 0x7f + are encoded in octal format: "\001", UTF-8 is allowed. + * Binary data is written as lower case hex digits, two digits per byte. + + Example data as generated by the test/preferences app: + + ``` + ; FLTK preferences file format 1.0 + ; vendor: fltk.org + ; application: test/preferences + + [.] + + + [./Bed] + + ; The value is "8:00". Values can contain a ':' character + alarm:8:00 + ; Some integer values + ampm:0 + wear:2 + side:1 + taskFlags:5 + + [./Breakfast] + + drink:1 + wMilk:1 + bread:1 + wButter:1 + nEggs:2 + ; A floating point value + minutes:4.91 + newspaper:NY Tymes + ; A text value containing newlines and two other control codes + foo:bar\nfly\rBackslash: \\ and bell: \007 and delete: \177\n + ; A key can be numeric, but the numeric value has no special meaning + 3:Test3 + ; Short binary data block. Data is written verbatim, + ; CPU endianess has no meaning here + binFoo:2387efcd + ; A long binary data block, generating wrapped lines + binFoo2:7c0802a6bfc1fff8900100089421ff707c3e0b78429f00057fe802a6381e + +00487c030378388000013c5f000538a287c43c5f000538c287d04801be31381e0050385e00487c03 + +03787c4413783c5f000538a287e44801b6f93c5f00053842dc70800200007c030378480450197c69 + +1b78381e00507c0303783c5f0005388287e87d254b784801ab253c5f00053842dc6c800200007c03 + +0378480450097c691b78381e00507c0303783c5f0005388287f87d254b784801af8d3c5f00053842 + +dc14800200007c03037848044fd97c691b78381e00507c0303783c5f0005388288007d254b784801 + +af5d38000000901e00403c5f00053842db84800200007c030378 + ``` + */ + char Fl_Preferences::nameBuffer[128]; char Fl_Preferences::uuidBuffer[40]; Fl_Preferences *Fl_Preferences::runtimePrefs = 0; @@ -122,7 +241,7 @@ unsigned int Fl_Preferences::file_access() } /** - Determine the file name and path to preferences that would be openend with + Determine the file name and path to preferences that would be opened with these parameters. Find the possible location of a preference file on disk without touching any @@ -208,7 +327,7 @@ Fl_Preferences::Root Fl_Preferences::filename( char *buffer, size_t buffer_size, For backward compatibility, the old \c USER `.prefs` file naming scheme \$(directory)/.fltk/\$(vendor)/\$(application).prefs is checked first. If that file does not exist, the environment variable `$XDG_CONFIG_HOME` is - read as a base directory. If `$XDG_CONFIG_HOME` not set, the base directory + read as a base directory. If `$XDG_CONFIG_HOME` is not set, the base directory defaults to `$HOME/.config/`. The user preferences will be stored in diff --git a/libraries/fltk/src/Fl_Screen_Driver.cxx b/libraries/fltk/src/Fl_Screen_Driver.cxx index 2956b7b3a4..05461a2a1e 100644 --- a/libraries/fltk/src/Fl_Screen_Driver.cxx +++ b/libraries/fltk/src/Fl_Screen_Driver.cxx @@ -481,10 +481,33 @@ int Fl_Screen_Driver::scale_handler(int event) if (Fl::test_shortcut(FL_COMMAND+'+')) zoom = zoom_in; else if (Fl::test_shortcut(FL_COMMAND+'-')) zoom = zoom_out; else if (Fl::test_shortcut(FL_COMMAND+'0')) zoom = zoom_reset; + + // Kludge to recognize shortcut FL_COMMAND+'+' without pressing SHIFT. if (Fl::option(Fl::OPTION_SIMPLE_ZOOM_SHORTCUT)) { - // kludge to recognize shortcut FL_COMMAND+'+' without pressing SHIFT - if ((Fl::event_state()&(FL_META|FL_ALT|FL_CTRL|FL_SHIFT)) == FL_COMMAND && - Fl::event_key() == '=') zoom = zoom_in; + if ((Fl::event_state() & (FL_META|FL_ALT|FL_CTRL|FL_SHIFT)) == FL_COMMAND) { + // We use Ctrl + key '=|+' for instance on US, UK, and FR keyboards. + // This works as expected on all keyboard layouts that have the '=' key in the + // lower and the '+' key in the upper position on the same key. + // This test would be "false positive" if a keyboard layout had the '=' key in + // the lower and any other key than '+' in the upper position! + + if (Fl::event_key() == '=') zoom = zoom_in; + + // Note: Fl::event_key() is often incorrect under X11 *if* the selected keyboard + // layout is *not* the primary one in the keyboard selection list, e.g. under Gnome. + // The observation is that Fl::event_key() is erroneously derived from the primary + // keyboard layout instead. This can be very confusing and I don't know why this + // happens. Albrecht-S, Oct 2024, on Debian 12 (Bookworm aka Stable as of now). + + // Example: 0xfe51 ("dead_acute") is sent by the '=' key of the US layout if the + // primary layout is German. This *would* be the correct key value for the German + // keyboard layout but not for the US layout. + // The following statement would work around this for this very special case but + // this should IMHO not be done. A valid workaround by the user is to make the + // *used* layout the first in the keyboard layout selection list! + + // else if (Fl::event_key() == 0xfe51) zoom = zoom_in; // dead_acute, see above + } } if (zoom != none) { int i, count; diff --git a/libraries/fltk/src/Fl_Shortcut_Button.cxx b/libraries/fltk/src/Fl_Shortcut_Button.cxx index 9f19fa0b48..7e04183bc3 100644 --- a/libraries/fltk/src/Fl_Shortcut_Button.cxx +++ b/libraries/fltk/src/Fl_Shortcut_Button.cxx @@ -19,6 +19,7 @@ #include #include #include +#include "Fl_System_Driver.H" #include "flstring.h" #include @@ -174,6 +175,7 @@ void Fl_Shortcut_Button::do_end_hot_callback() { Handle keystrokes to catch the user's shortcut. */ int Fl_Shortcut_Button::handle(int e) { + static int alt_modifier_extra_handler = Fl::system_driver()->need_test_shortcut_extra(); #if 0 bool inside_default_button = false; if (default_set_ && ( (e == FL_PUSH) || (e == FL_DRAG) || (e == FL_RELEASE) ) ) { @@ -235,6 +237,17 @@ int Fl_Shortcut_Button::handle(int e) { // type, so we don't handle them here either // Todo: use fl_utf_tolower and fl_utf_toupper int v = fl_utf8decode(Fl::event_text(), 0, 0); + if (alt_modifier_extra_handler && Fl::event_state(FL_ALT)) { + // MacOS returns special characters when the alt modifier is held down. + // FLTK handles shortcuts as ASCII keys, so let's convert the keystroke. + int c = Fl::event_key(); + if ( (c>32) && (c<128) && (isalnum(c)) ) { + v = c; + if (Fl::event_state(FL_SHIFT)) { + v = toupper(c); + } + } + } if ( (v > 32 && v < 0x7f) || (v > 0xa0 && v <= 0xff) ) { if (isupper(v)) { v = tolower(v); diff --git a/libraries/fltk/src/Fl_System_Driver.H b/libraries/fltk/src/Fl_System_Driver.H index 3dad3d7547..e1bb6b7d39 100644 --- a/libraries/fltk/src/Fl_System_Driver.H +++ b/libraries/fltk/src/Fl_System_Driver.H @@ -200,12 +200,8 @@ public: // the implementations of local_to_mac_roman() and mac_roman_to_local() are in fl_encoding_mac_roman.cxx virtual const char *local_to_mac_roman(const char *t, int n); virtual const char *mac_roman_to_local(const char *t, int n); - // the default implementations of tree_openpixmap() and tree_closepixmap() are - // in Fl_Tree_Prefs.cxx and can be enough - virtual Fl_Pixmap *tree_openpixmap(); - virtual Fl_Pixmap *tree_closepixmap(); - static const char *const tree_open_xpm[]; // used by tree_openpixmap() - static const char * const tree_close_xpm[]; // used by tree_closepixmap() + // draw default tree view expando button + virtual void tree_draw_expando_button(int x, int y, bool state, bool active); // the default implementation of tree_connector_style() is in Fl_Tree_Prefs.cxx and can be enough virtual int tree_connector_style(); virtual void add_fd(int fd, int when, Fl_FD_Handler cb, void* = 0); diff --git a/libraries/fltk/src/Fl_Tabs.cxx b/libraries/fltk/src/Fl_Tabs.cxx index ed6b45a5c7..89394ac059 100644 --- a/libraries/fltk/src/Fl_Tabs.cxx +++ b/libraries/fltk/src/Fl_Tabs.cxx @@ -31,6 +31,7 @@ #include #define BORDER 2 +#define OV_BORDER 2 #define EXTRASPACE 10 #define SELECTION_BORDER 5 #define EXTRAGAP 2 @@ -72,6 +73,12 @@ void Fl_Tabs::resize(int X, int Y, int W, int H) { Fl_Group::resize(X, Y, W, H); } +/** Ensure proper placement of selected tab. */ +void Fl_Tabs::show() { + Fl::damage(FL_DAMAGE_SCROLL); + Fl_Group::show(); +} + /** Calculate tab positions and widths. This protected method calculates the horizontal display positions and @@ -330,7 +337,7 @@ int Fl_Tabs::hit_overflow_menu(int event_x, int event_y) { if (!has_overflow_menu) return 0; int H = tab_height(); - if (event_x < x()+w()-abs(H)) + if (event_x < x()+w()-abs(H)+OV_BORDER) return 0; if (H >= 0) { if (event_y > y()+H) @@ -356,7 +363,7 @@ int Fl_Tabs::hit_tabs_area(int event_x, int event_y) { if (event_y < y()+h()+H) return 0; } - if (has_overflow_menu && event_x > x()+w()-abs(H)) + if (has_overflow_menu && event_x > x()+w()-abs(H)+OV_BORDER) return 0; return 1; } @@ -367,13 +374,51 @@ int Fl_Tabs::hit_tabs_area(int event_x, int event_y) { void Fl_Tabs::check_overflow_menu() { int nc = children(); int H = tab_height(); if (H < 0) H = -H; - if (tab_pos[nc] > w()-H) { + if (tab_pos[nc] > w()-H+OV_BORDER) { has_overflow_menu = 1; } else { has_overflow_menu = 0; } } +/** + Take keyboard focus if o is not NULL. + \param[in] o selected tab + */ +void Fl_Tabs::take_focus(Fl_Widget *o) { + if (o && Fl::visible_focus() && Fl::focus()!=this) { + Fl::focus(this); + redraw_tabs(); + } +} + +/** + Set tab o as selected an call callbacks if needed. + \param[in] o the newly selected tab + \return 0 if o is invalide or was deleted by the callback and must no longer be used + */ +int Fl_Tabs::maybe_do_callback(Fl_Widget *o) { + // chaeck if o is valid + if ( o == NULL ) + return 0; + + // set the new tab value + int tab_changed = value(o); + if ( tab_changed ) + set_changed(); + + // do we need to call the callback? + if ( tab_changed || ( when() & (FL_WHEN_NOT_CHANGED) ) ) { + Fl_Widget_Tracker wp(o); // we want to know if the widget lives on + do_callback(FL_REASON_SELECTED); // this may delete the tab + if (wp.deleted()) return 0; // if it did, return 0 + } + + // if o is still valid, do remaining tasks + Fl_Tooltip::current(o); + return 1; +} + /** This is called when the user clicks the overflow pulldown menu button. @@ -395,7 +440,7 @@ void Fl_Tabs::handle_overflow_menu() { // count visible children for (i = 0; i < nc; i++) { if (tab_pos[i]+tab_offset < 0) fv = i; - if (tab_pos[i]+tab_width[i]+tab_offset <= w()-H) lv = i; + if (tab_pos[i]+tab_width[i]+tab_offset <= w()-H+OV_BORDER) lv = i; } // create a menu with all children @@ -413,9 +458,13 @@ void Fl_Tabs::handle_overflow_menu() { } // show the menu and handle the selection - const Fl_Menu_Item *m = overflow_menu->popup(x()+w()-H, (tab_height()>0)?(y()+H):(y()+h())); - if (m) - value((Fl_Widget*)m->user_data()); + const Fl_Menu_Item *m = overflow_menu->popup(x()+w()-H+OV_BORDER, (tab_height()>0)?(y()+H):(y()+h()-OV_BORDER)); + if (m) { + Fl_Widget *o = (Fl_Widget*)m->user_data(); + push(0); + take_focus(o); + maybe_do_callback(o); + } // delete the menu until we need it next time if (overflow_menu) { @@ -431,16 +480,26 @@ void Fl_Tabs::draw_overflow_menu_button() { int H = tab_height(); int X, Y; if (H > 0) { - X = x() + w() - H; - Y = y(); + X = x() + w() - H + OV_BORDER; + if (OV_BORDER > 0) + fl_rectf(X, y(), H - OV_BORDER, OV_BORDER, color()); + Y = y() + OV_BORDER; } else { H = -H; - X = x() + w() - H; - Y = y() + h() - H - 1; + X = x() + w() - H + OV_BORDER; + Y = y() + h() - H; + if (OV_BORDER > 0) + fl_rectf(X, Y + H - OV_BORDER, H - OV_BORDER, OV_BORDER, color()); } + H -= OV_BORDER; draw_box(box(), X, Y, H, H, color()); Fl_Rect r(X, Y, H, H); - Fl_Color arrow_color = active_r() ? labelcolor() : fl_inactive(labelcolor()); + // labelcolor() is historically used to contrast selectioncolor() and is + // useless her, so we fall back to contrast the background color on the + // gray ramp. + Fl_Color arrow_color = fl_contrast(FL_GRAY_RAMP+0, color()); + if (!active_r()) + arrow_color = fl_inactive(arrow_color); fl_draw_arrow(r, FL_ARROW_CHOICE, FL_ORIENT_NONE, arrow_color); } @@ -469,6 +528,7 @@ int Fl_Tabs::handle(int event) { static int initial_x = 0; static int initial_tab_offset = 0; static int forward_motion_to_group = 0; + static Fl_Widget *o_push_drag = NULL; Fl_Widget *o; int i; @@ -504,18 +564,22 @@ int Fl_Tabs::handle(int event) { } /* FALLTHROUGH */ case FL_DRAG: + o_push_drag = which(Fl::event_x(), Fl::event_y()); case FL_RELEASE: if (forward_motion_to_group) { return Fl_Group::handle(event); } o = which(Fl::event_x(), Fl::event_y()); + if (event == FL_RELEASE && o != o_push_drag) { // see issue #1075 + return 1; + } if ( (overflow_type == OVERFLOW_DRAG) || (overflow_type == OVERFLOW_PULLDOWN) ) { if (tab_pos[children()] < w() && tab_offset == 0) { // fall through } else if (!Fl::event_is_click()) { tab_offset = initial_tab_offset + Fl::event_x() - initial_x; int m = 0; - if (overflow_type == OVERFLOW_PULLDOWN) m = abs(tab_height()); + if (overflow_type == OVERFLOW_PULLDOWN) m = abs(tab_height()) - OV_BORDER; if (tab_offset > 0) { initial_tab_offset -= tab_offset; tab_offset = 0; @@ -532,25 +596,12 @@ int Fl_Tabs::handle(int event) { } if (event == FL_RELEASE) { push(0); - if (o && Fl::visible_focus() && Fl::focus()!=this) { - Fl::focus(this); - redraw_tabs(); - } + take_focus(o); if (o && (o->when() & FL_WHEN_CLOSED) && hit_close(o, Fl::event_x(), Fl::event_y())) { o->do_callback(FL_REASON_CLOSED); return 1; // o may be deleted at this point } - if (o && // Released on a tab and.. - (value(o) || // tab changed value or.. - (when()&(FL_WHEN_NOT_CHANGED)) // ..no change but WHEN_NOT_CHANGED set, - ) // handles FL_WHEN_RELEASE_ALWAYS too. - ) { - Fl_Widget_Tracker wp(o); - set_changed(); - do_callback(FL_REASON_SELECTED); - if (wp.deleted()) return 1; - } - Fl_Tooltip::current(o); + maybe_do_callback(o); } else { push(o); } @@ -705,16 +756,15 @@ int Fl_Tabs::value(Fl_Widget *newvalue) { o->hide(); } } - // make sure that the selected tab is visible + // always make sure that the selected tab is visible if ( (selected >= 0) - && (ret == 1) && ( (overflow_type == OVERFLOW_DRAG) || (overflow_type == OVERFLOW_PULLDOWN) ) ) { int m = MARGIN; - if ( (selected == 0) || (selected == children()-1) ) m = 0; + if ( (selected == 0) || (selected == children()-1) ) m = BORDER; int mr = m; - if (overflow_type == OVERFLOW_PULLDOWN) mr += abs(tab_height()); tab_positions(); + if (overflow_type == OVERFLOW_PULLDOWN) mr += abs(tab_height() - OV_BORDER); if (tab_pos[selected]+tab_width[selected]+tab_offset+mr > w()) { tab_offset = w() - tab_pos[selected] - tab_width[selected] - mr; } else if (tab_pos[selected]+tab_offset-m < 0) { @@ -735,14 +785,16 @@ void Fl_Tabs::draw() { // FL_DAMAGE_EXPOSE : this is set if some setting in a widget changed // Fl_Tabs uses this to indicate that the tabs area needs a full redraw // FL_DAMAGE_SCROLL : this is used as a custom flag in various widgets - // Fl_Tabs honors this flag for back compatibly as FL_DAMAGE_EXPOSE - // FL_DAMAGE_ALL : just redraw everything + // Fl_Tabs uses FL_DAMAGE_EXPOSE to indicate that the + // tabs bar needs repositioning and teh tabs must be + // redrawn + // FL_DAMAGE_ALL : just recalculate and redraw everything // Anatomy of tabs on top: - // +------+ +---+ <<-- selected tabs start at y() - // | text | +------+ | V | <-- other tabs are offset down by BORDER - // | | | text | +---+ <-- the pulldown button width equals H - // ++ +-----------------+ <-- tab_height() to tab_height + Fl::box_dx(box()) + // +------+ <<-- selected tabs start at y() + // | text | +------+ +---+ <-- other tabs are offset down by BORDER + // | | | text | | ▼ | <-- the pulldown button width equals H - OV_BORDER + // ++ +-------------+---+ <-- tab_height() to tab_height + Fl::box_dx(box()) // +-------------------------+ <-- tab_height + SELECTION_BORDER // | | // ↑____↑ this area within the SELECTION_BORDER is called "stem" @@ -800,6 +852,13 @@ void Fl_Tabs::draw() { clipped_child_area_h = h() - tabs_h - selection_border_h; } + // ---- recalculate the tabs so that the selected tab is visible + if (damage() & (FL_DAMAGE_ALL|FL_DAMAGE_SCROLL)) { + Fl_Widget *selected_tab = value(); + if (selected_tab) + value(selected_tab); + } + // ---- draw the tabs and the selection border if (damage() & (FL_DAMAGE_ALL|FL_DAMAGE_EXPOSE|FL_DAMAGE_SCROLL)) { @@ -957,7 +1016,10 @@ void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int flags, in // Draw the "close" button if requested if ( (o->when() & FL_WHEN_CLOSED) && !(flags & 1) ) { int sz = labelsize()/2, sy = (H - sz)/2; - fl_draw_symbol("@3+", x1 + EXTRASPACE/2, y() + yofs/2 + sy, sz, sz, o->labelcolor()); + Fl_Color close_color = fl_contrast(FL_GRAY_RAMP+0, bc); + if (!active_r()) + close_color = fl_inactive(close_color); + fl_draw_symbol("@3+", x1 + EXTRASPACE/2, y() + yofs/2 + sy, sz, sz, close_color); wc = sz + EXTRAGAP; } @@ -979,7 +1041,10 @@ void Fl_Tabs::draw_tab(int x1, int x2, int W, int H, Fl_Widget* o, int flags, in // Draw the "close" button if requested if ( (o->when() & FL_WHEN_CLOSED) && (x1+W < x2) ) { int sz = labelsize()/2, sy = (H - sz)/2; - fl_draw_symbol("@3+", x1 + EXTRASPACE/2, y() + h() - H -yofs/2 + sy, sz, sz, o->labelcolor()); + Fl_Color close_color = fl_contrast(FL_GRAY_RAMP+0, bc); + if (!active_r()) + close_color = fl_inactive(close_color); + fl_draw_symbol("@3+", x1 + EXTRASPACE/2, y() + h() - H -yofs/2 + sy, sz, sz, close_color); wc = sz + EXTRAGAP; } @@ -1137,7 +1202,7 @@ void Fl_Tabs::handle_overflow(int ov) { overflow_type = ov; tab_offset = 0; has_overflow_menu = 0; - damage(FL_DAMAGE_EXPOSE); + damage(FL_DAMAGE_SCROLL); redraw(); } diff --git a/libraries/fltk/src/Fl_Terminal.cxx b/libraries/fltk/src/Fl_Terminal.cxx index 29cac10d25..0bf5665313 100644 --- a/libraries/fltk/src/Fl_Terminal.cxx +++ b/libraries/fltk/src/Fl_Terminal.cxx @@ -37,12 +37,6 @@ #include #include "Fl_String.H" -///////////////////////////////// -////// Static Class Data //////// -///////////////////////////////// - -const char *Fl_Terminal::unknown_char = "¿"; - ///////////////////////////////// ////// Static Functions ///////// ///////////////////////////////// @@ -181,6 +175,7 @@ bool Fl_Terminal::Selection::get_selection(int &srow,int &scol, // Always returns true. // bool Fl_Terminal::Selection::start(int row, int col, bool char_right) { + (void) char_right; // silence warning srow_ = erow_ = row; scol_ = ecol_ = col; state_ = 1; // state: "started selection" @@ -2558,6 +2553,16 @@ void Fl_Terminal::handle_lf(void) { else cursor_down(1, do_scroll); } +// Handle '\e' escape character. +void Fl_Terminal::handle_esc(void) { + if (!ansi_) // not in ansi mode? + { handle_unknown_char(); return; } // ..show unknown char, early exit + if (escseq.esc_mode() == 0x1b) // already in esc mode? + { handle_unknown_char(); } // ..show 1st esc as unknown char, parse 2nd + if (escseq.parse(0x1b) == EscapeSeq::fail) // parse esc + { handle_unknown_char(); return; } // ..error? show unknown char +} + /** Sets the combined output translation flags to \p val. @@ -2599,9 +2604,7 @@ void Fl_Terminal::handle_ctrl(char c) { case '\r': handle_cr(); return; // CR? case '\n': handle_lf(); return; // LF? case '\t': cursor_tab_right(); return; // TAB? - case 0x1b: if (ansi_) escseq.parse(c); // ESC? - else append_utf8("␛"); - return; + case 0x1b: handle_esc(); return; // ESC? default: handle_unknown_char(); return; // Unknown ctrl char? } } @@ -2731,12 +2734,16 @@ void Fl_Terminal::handle_escseq(char c) { // NOTE: Use xterm to test. gnome-terminal has bugs, even in 2022. const bool do_scroll = true; const bool no_scroll = false; - //UNUSED const bool do_wrap = true; - //UNUSED const bool no_wrap = false; switch (escseq.parse(c)) { // parse char, advance s.. - case EscapeSeq::fail: escseq.reset(); return; // failed? reset, done - case EscapeSeq::success: return; // keep parsing.. - case EscapeSeq::completed: break; // parsed complete esc sequence? + case EscapeSeq::fail: // failed? + escseq.reset(); // ..reset to let error_char be visible + handle_unknown_char(); // ..show error char (if enabled) + print_char(c); // ..show char we couldn't handle + return; // ..done. + case EscapeSeq::success: // success? + return; // ..keep parsing + case EscapeSeq::completed: // parsed complete esc sequence? + break; // ..fall through to handle operation } // Shortcut varnames for escseq parsing.. EscapeSeq &esc = escseq; @@ -3254,7 +3261,7 @@ void Fl_Terminal::append(const char *s, int len/*=-1*/) { int Fl_Terminal::handle_unknown_char(void) { if (!show_unknown_) return 0; escseq.reset(); // disable any pending esc seq to prevent eating unknown char - print_char(unknown_char); + print_char(error_char_); return 1; } @@ -3270,9 +3277,9 @@ int Fl_Terminal::handle_unknown_char(void) { */ int Fl_Terminal::handle_unknown_char(int drow, int dcol) { if (!show_unknown_) return 0; - int len = (int)strlen(unknown_char); + int len = (int)strlen(error_char_); Utf8Char *u8c = u8c_disp_row(drow) + dcol; - u8c->text_utf8(unknown_char, len, *current_style_); + u8c->text_utf8(error_char_, len, *current_style_); return 1; } @@ -3384,6 +3391,7 @@ Fl_Terminal::Fl_Terminal(int X,int Y,int W,int H,const char*L,int rows,int cols, // Private constructor method void Fl_Terminal::init_(int X,int Y,int W,int H,const char*L,int rows,int cols,int hist,bool fontsize_defer) { + error_char_ = "¿"; scrollbar = hscrollbar = 0; // avoid problems w/update_screen_xywh() // currently unused params (void)X; (void)Y; (void)W; (void)H; (void)L; @@ -4039,7 +4047,7 @@ void Fl_Terminal::redraw_rate(float val) { /** Return the "show unknown" flag. - See show_unknown(bool) for more info. + \see show_unknown(bool), error_char(const char*). */ bool Fl_Terminal::show_unknown(void) const { return show_unknown_; @@ -4048,12 +4056,12 @@ bool Fl_Terminal::show_unknown(void) const { /** Set the "show unknown" flag. - If true, unknown escape sequences and unprintable control characters - will be shown with the error character "¿". + If true, invalid utf8 and invalid ANSI sequences will be shown + with the error character "¿". - If false, those sequences and characters will be ignored. + If false, errors characters won't be shown. - \see handle_unknown_char() + \see handle_unknown_char(), error_char(const char*). */ void Fl_Terminal::show_unknown(bool val) { show_unknown_ = val; diff --git a/libraries/fltk/src/Fl_Text_Buffer.cxx b/libraries/fltk/src/Fl_Text_Buffer.cxx index 3bb8a10f0f..f26afb39d1 100644 --- a/libraries/fltk/src/Fl_Text_Buffer.cxx +++ b/libraries/fltk/src/Fl_Text_Buffer.cxx @@ -1166,6 +1166,48 @@ int Fl_Text_Buffer::count_lines(int startPos, int endPos) const { return lineCount; } +/** + Estimate the number of newlines between \p startPos and \p endPos in buffer. + This call takes line wrapping into account. It assumes a line break at every + `lineLen` characters after the beginning of a line. + */ +int Fl_Text_Buffer::estimate_lines(int startPos, int endPos, int lineLen) const +{ + IS_UTF8_ALIGNED2(this, (startPos)) + IS_UTF8_ALIGNED2(this, (endPos)) + + int gapLen = mGapEnd - mGapStart; + int lineCount = 0; + int softLineBreaks = 0, softLineBreakCount = lineLen; + + int pos = startPos; + while (pos < mGapStart) + { + if (pos == endPos) + return lineCount + softLineBreaks; + if (mBuf[pos++] == '\n') { + softLineBreakCount = lineLen; + lineCount++; + } + if (--softLineBreakCount == 0) { + softLineBreakCount = lineLen; + softLineBreaks++; + } + } + while (pos < mLength) { + if (pos == endPos) + return lineCount + softLineBreaks; + if (mBuf[pos++ + gapLen] == '\n') { + softLineBreakCount = lineLen; + lineCount++; + } + if (--softLineBreakCount == 0) { + softLineBreakCount = lineLen; + softLineBreaks++; + } + } + return lineCount + softLineBreaks; +} /* Skip to the first character, n lines ahead. diff --git a/libraries/fltk/src/Fl_Text_Display.cxx b/libraries/fltk/src/Fl_Text_Display.cxx index c91c98a797..c1f575b1bf 100644 --- a/libraries/fltk/src/Fl_Text_Display.cxx +++ b/libraries/fltk/src/Fl_Text_Display.cxx @@ -160,6 +160,8 @@ Fl_Text_Display::Fl_Text_Display(int X, int Y, int W, int H, const char* l) mVScrollBar = new Fl_Scrollbar(0,0,1,1); mVScrollBar->callback((Fl_Callback*)v_scrollbar_cb, this); + display_needs_recalc_ = false; + scrollbar_width_ = 0; // 0: default from Fl::scrollbar_size() scrollbar_align_ = FL_ALIGN_BOTTOM_RIGHT; @@ -236,7 +238,7 @@ Fl_Text_Display::~Fl_Text_Display() { void Fl_Text_Display::linenumber_width(int width) { if (width < 0) return; mLineNumWidth = width; - recalc_display(); // recalc line#s // resize(x(), y(), w(), h()); + display_needs_recalc(); // recalc line#s // resize(x(), y(), w(), h()); if (width > 0) reset_absolute_top_line_number(); } @@ -390,7 +392,7 @@ void Fl_Text_Display::buffer( Fl_Text_Buffer *buf ) { } /* Resize the widget to update the screen... */ - recalc_display(); // resize(x(), y(), w(), h()); + display_needs_recalc(); // resize(x(), y(), w(), h()); } @@ -489,11 +491,23 @@ void Fl_Text_Display::resize(int X, int Y, int W, int H) { Fl_Widget::resize(X,Y,W,H); mColumnScale = 0; // force recomputation of the width of a column when display is rescaled - recalc_display(); + display_needs_recalc(); +} + +/** + Schedule a recalc_display() to be done on next draw(). + Call this from methods that might be called repeatedly, to defers potentially + CPU intensive recalc_display() until it's actually needed just before draw(). +*/ +void Fl_Text_Display::display_needs_recalc() { + display_needs_recalc_ = true; + redraw(); // ensure draw() gets called } /** - Recalculate the display's visible lines and scrollbar sizes. + Recalculate the display's visible lines and scrollbar sizes. + Beware calling this directly may cause a lot of CPU if called repeatedly (issue 300). + Better to call display_needs_recalc() to flag a recalc to be done during next draw(). */ void Fl_Text_Display::recalc_display() { if (!buffer()) return; @@ -560,9 +574,9 @@ void Fl_Text_Display::recalc_display() { if (mContinuousWrap && !mWrapMarginPix && text_area.w != oldTAWidth) { int oldFirstChar = mFirstChar; - mNBufferLines = count_lines(0, buffer()->length(), true); mFirstChar = line_start(mFirstChar); mTopLineNum = count_lines(0, mFirstChar, true)+1; + mNBufferLines = mTopLineNum-1 + count_lines(mFirstChar, buffer()->length(), true); absolute_top_line_number(oldFirstChar); #ifdef DEBUG2 printf(" mNBufferLines=%d\n", mNBufferLines); @@ -688,7 +702,7 @@ void Fl_Text_Display::recalc_display() { scroll_(mTopLineNumHint, mHorizOffsetHint); // everything will fit in the viewport - if (mNBufferLines < mNVisibleLines || mBuffer == NULL || mBuffer->length() == 0) { + if ((mNBufferLines+1 < 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 */ @@ -982,7 +996,7 @@ void Fl_Text_Display::wrap_mode(int wrap, int wrapMargin) { mAbsTopLineNum = 1; // changed from 0 to 1 -- LZA / STR#2621 } - recalc_display(); // resize(x(), y(), w(), h()); + display_needs_recalc(); // resize(x(), y(), w(), h()); } @@ -1289,7 +1303,7 @@ void Fl_Text_Display::display_insert() { */ void Fl_Text_Display::show_insert_position() { display_insert_position_hint = 1; - recalc_display(); // resize(x(), y(), w(), h()); + display_needs_recalc(); // resize(x(), y(), w(), h()); } @@ -1436,16 +1450,66 @@ int Fl_Text_Display::count_lines(int startPos, int endPos, if (!mContinuousWrap) return buffer()->count_lines(startPos, endPos); - wrapped_line_counter(buffer(), startPos, endPos, INT_MAX, - startPosIsLineStart, 0, &retPos, &retLines, &retLineStart, - &retLineEnd); + /* + Correctly counting wrapped lines is very slow. We have to query the length + of every segment of text for every line change and style change and find + potential soft line breaks. + + Most of the resulting information is needed for calculating the vertical + scroll bar size. After a certain text length, the scroll bar size is no + longer very precise anyway, so we optimize line count for all lines but + the visible ones (plus minus a few lines for rounding). + + The optimized code is several magnitudes faster and makes scrolling and + window resizing of long texts quite responsive. There is a slight but IMHO + tollerable drawback: when walking huge files using arrow up and down, the + text display sometimes jumps 2 or 3 lines instead of 1, but the overall + buffer stays intact as well as the scroll position. + */ + if (buffer()->length() > 16384) { + // Optimized line counting + int nLines = 0; + int firstVisibleChar = buffer()->rewind_lines(mFirstChar, 3); + int lastVisibleChar = buffer()->skip_lines(mLastChar, 3); + // Calculate the averga number of characters up to a soft line break + if (mColumnScale==0.0) x_to_col(1.0); + int avgCharsPerLine = mWrapMarginPix; + if (!avgCharsPerLine) avgCharsPerLine = text_area.w; + avgCharsPerLine = (int)(avgCharsPerLine / mColumnScale) + 1; + + // first segment, lines up to display, count fast + if (startPos < firstVisibleChar) { + int tmpEnd = endPosestimate_lines(startPos, tmpEnd, avgCharsPerLine); + startPos = tmpEnd; + } + // second segement, count displayed liens + if (startPos < endPos && startPos < mLastChar) { + // Precisse line counting only for visible text: + int tmpEnd = endPos= lastVisibleChar) { + nLines += buffer()->estimate_lines(startPos, endPos, avgCharsPerLine); + } + return nLines; + } else { + // Precise line counting only for small text buffer sizes: + 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); + printf(" # after WLC: retPos=%d, retLines=%d, retLineStart=%d, retLineEnd=%d\n", + retPos, retLines, retLineStart, retLineEnd); #endif // DEBUG - - return retLines; + return retLines; + } } @@ -1757,7 +1821,7 @@ void Fl_Text_Display::buffer_modified_cb( int pos, int nInserted, int nDeleted, } // refigure scrollbars & stuff - textD->resize(textD->x(), textD->y(), textD->w(), textD->h()); + textD->display_needs_recalc(); // 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; @@ -1796,7 +1860,7 @@ void Fl_Text_Display::buffer_modified_cb( int pos, int nInserted, int nDeleted, } if (linesInserted > 1) { // textD->draw_line_numbers(false); // can't do this b/c not called from virtual draw(); - textD->damage(::FL_DAMAGE_EXPOSE); + textD->damage(FL_DAMAGE_EXPOSE); } } else { endDispPos = buf->next_char(textD->mLastChar); @@ -2075,7 +2139,7 @@ int Fl_Text_Display::handle_vline( // find x pos inside block free(lineStr); if (cursor_pos && (startX+w/2next_char(pos); } fl_text_drag_me(pos, this); return 1; diff --git a/libraries/fltk/src/Fl_Text_Editor.cxx b/libraries/fltk/src/Fl_Text_Editor.cxx index 55da11cb85..9fe2b5b01a 100644 --- a/libraries/fltk/src/Fl_Text_Editor.cxx +++ b/libraries/fltk/src/Fl_Text_Editor.cxx @@ -310,10 +310,10 @@ int Fl_Text_Editor::kf_move(int c, Fl_Text_Editor* e) { Fl::copy("", 0, 0); switch (c) { case FL_Home: - e->insert_position(e->buffer()->line_start(e->insert_position())); + e->insert_position(e->line_start(e->insert_position())); break; case FL_End: - e->insert_position(e->buffer()->line_end(e->insert_position())); + e->insert_position(e->line_end(e->insert_position(), false)); break; case FL_Left: e->move_left(); diff --git a/libraries/fltk/src/Fl_Tile.cxx b/libraries/fltk/src/Fl_Tile.cxx index efc2478b7d..0eb7e0a70b 100644 --- a/libraries/fltk/src/Fl_Tile.cxx +++ b/libraries/fltk/src/Fl_Tile.cxx @@ -482,6 +482,7 @@ void Fl_Tile::move_intersection(int oldx, int oldy, int newx, int newy) { } } + /** Drags the intersection at (\p oldx,\p oldy) to (\p newx,\p newy). @@ -584,7 +585,7 @@ void Fl_Tile::resize(int X,int Y,int W,int H) { c->position(c->x()+dx, c->y()+dy); } } - // check the bounding box of all children at minimum size + // check the current bounding box of all children init_sizes(); Fl_Rect *p = bounds(); int bbr = X, bbb = Y; @@ -604,11 +605,34 @@ void Fl_Tile::resize(int X,int Y,int W,int H) { // perform the actual resize within a safe range if ((dw!=0) || (dh!=0)) { Fl_Widget *r = resizable(); + // Find the target right and bottom position of the resizable child. + int trr = 0, trb = 0; + if (r) { + trr = r->x() + r->w() - dw; + trb = r->y() + r->h() - dh; + } + // Grow width and/or height of tile and adjust all children as needed. + if ((dw < 0) && (dh < 0)) { + move_intersection(bbr, bbb, bbr-dw, bbb-dh); + } else if (dw < 0) { + move_intersection(bbr, bbb, bbr-dw, bbb); + } else if (dh < 0) { + move_intersection(bbr, bbb, bbr, bbb-dh); + } + // Fix the resizable child, trying to keep its size plus all other + // widgets within their limits. if (r) { int rr = r->x() + r->w(), rb = r->y() + r->h(); - move_intersection(rr, rb, rr-dw, rb-dh); + move_intersection(rr, rb, trr, trb); + } + // Shrink width and/or height of tile and adjust all children as needed. + if ((dw > 0) && (dh > 0)) { + move_intersection(bbr, bbb, bbr-dw, bbb-dh); + } else if (dw > 0) { + move_intersection(bbr, bbb, bbr-dw, bbb); + } else if (dh > 0) { + move_intersection(bbr, bbb, bbr, bbb-dh); } - move_intersection(bbr, bbb, bbr-dw, bbb-dh); init_sizes(); } // resize the tile itself diff --git a/libraries/fltk/src/Fl_Timeout.cxx b/libraries/fltk/src/Fl_Timeout.cxx index 3c04cae17a..9aa89b8391 100644 --- a/libraries/fltk/src/Fl_Timeout.cxx +++ b/libraries/fltk/src/Fl_Timeout.cxx @@ -210,7 +210,9 @@ void Fl_Timeout::insert() { \retval 0 not found \retval 1 found - Implements Fl::has_timeout(Fl_Timeout_Handler cb, void *data) + Implements: + + int Fl::has_timeout(Fl_Timeout_Handler cb, void *data) \see Fl::has_timeout(Fl_Timeout_Handler cb, void *data) */ @@ -232,7 +234,9 @@ int Fl_Timeout::has_timeout(Fl_Timeout_Handler cb, void *data) { \param[in] cb callback function \param[in] data optional user data (default: \p NULL) - Implements Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *data) + Implements: + + void Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *data) \see Fl::add_timeout(double time, Fl_Timeout_Handler cb, void *data) */ @@ -250,7 +254,9 @@ void Fl_Timeout::add_timeout(double time, Fl_Timeout_Handler cb, void *data) { \param[in] cb callback function \param[in] data optional user data (default: \p NULL) - Implements Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data) + Implements: + + void Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data) \see Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data) */ @@ -276,7 +282,9 @@ void Fl_Timeout::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data) \param[in] cb Timer callback to be removed (must match) \param[in] data Wildcard if NULL, must match otherwise - Implements Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) + Implements: + + void Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) \see Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) */ @@ -293,6 +301,49 @@ void Fl_Timeout::remove_timeout(Fl_Timeout_Handler cb, void *data) { } } +/** + Remove the next matching timeout callback and return its \p data pointer. + + Implements: + + int Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) + + \param[in] cb Timer callback to be removed (must match) + \param[in] data Wildcard if NULL, must match otherwise + \param[inout] data_return pointer to void * to receive the data value + + \return non-zero if a timer was found and removed + \retval 0 no matching timer was found + \retval 1 the last matching timeout was found and removed + \retval N>1 a matching timeout was removed and there are\n + (N - 1) matching timeouts pending + + For details + \see Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) +*/ +int Fl_Timeout::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) { + int ret = 0; + for (Fl_Timeout** p = &first_timeout; *p;) { // scan all timeouts + Fl_Timeout* t = *p; + if (t->callback == cb && (t->data == data || !data)) { // timeout matches + ret++; + if (ret == 1) { // first timeout: remove + if (data_return) + *data_return = t->data; + *p = t->next; + t->next = free_timeout; + free_timeout = t; + continue; + } + p = &(t->next); + } // timeout matches + else { // no match + p = &(t->next); + } + } // scan all timeouts + return ret; +} + /** Remove the timeout from the active timer queue and push it onto the stack of currently running callbacks. diff --git a/libraries/fltk/src/Fl_Timeout.h b/libraries/fltk/src/Fl_Timeout.h index f6a54a7a60..9d9cc23371 100644 --- a/libraries/fltk/src/Fl_Timeout.h +++ b/libraries/fltk/src/Fl_Timeout.h @@ -2,7 +2,7 @@ // Header for timeout support functions for the Fast Light Tool Kit (FLTK). // // Author: Albrecht Schlosser -// Copyright 2021-2022 by Bill Spitzak and others. +// Copyright 2021-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -31,6 +31,7 @@ - Fl::repeat_timeout() - Fl::has_timeout() - Fl::remove_timeout() + - Fl::remove_next_timeout() and related methods of class Fl_Timeout. */ @@ -49,6 +50,7 @@ - Fl::repeat_timeout(double time, Fl_Timeout_Handler cb, void *data) - Fl::has_timeout(Fl_Timeout_Handler cb, void *data) - Fl::remove_timeout(Fl_Timeout_Handler cb, void *data) + - Fl::remove_next_timeout(Fl_Timeout_Handler cb, void *data, void **data_return) */ class Fl_Timeout { @@ -106,6 +108,7 @@ class Fl_Timeout { static void add_timeout(double time, Fl_Timeout_Handler cb, void *data); static void repeat_timeout(double time, Fl_Timeout_Handler cb, void *data); static void remove_timeout(Fl_Timeout_Handler cb, void *data); + static int remove_next_timeout(Fl_Timeout_Handler cb, void *data = NULL, void **data_return = NULL); // Elapse timeouts, i.e. calculate new delay time of all timers. // This does not call the timer callbacks. diff --git a/libraries/fltk/src/Fl_Tree.cxx b/libraries/fltk/src/Fl_Tree.cxx index 40c28039d1..08c8aa1f22 100644 --- a/libraries/fltk/src/Fl_Tree.cxx +++ b/libraries/fltk/src/Fl_Tree.cxx @@ -676,8 +676,8 @@ void Fl_Tree::calc_tree() { int W = _tiw; // Adjust root's X/W if connectors off if (_prefs.connectorstyle() == FL_TREE_CONNECTOR_NONE) { - X -= _prefs.openicon()->w(); - W += _prefs.openicon()->w(); + X -= _prefs.openicon_w(); + W += _prefs.openicon_w(); } int xmax = 0, render = 0, ytop = Y; fl_font(_prefs.labelfont(), _prefs.labelsize()); @@ -718,8 +718,8 @@ void Fl_Tree::draw() { int W = _tiw - X + _tix; // Adjust root's X/W if connectors off if (_prefs.connectorstyle() == FL_TREE_CONNECTOR_NONE) { - X -= _prefs.openicon()->w(); - W += _prefs.openicon()->w(); + X -= _prefs.openicon_w(); + W += _prefs.openicon_w(); } // Draw entire tree, starting with root fl_push_clip(_tix,_tiy,_tiw,_tih); @@ -1228,7 +1228,7 @@ Fl_Tree_Item* Fl_Tree::last_visible() { Fl_Tree_Item* Fl_Tree::last_visible_item() { Fl_Tree_Item *item = last(); while ( item ) { - if ( item->visible() ) { + if ( item->visible_r() ) { if ( item == _root && !showroot() ) { return(0); } else { diff --git a/libraries/fltk/src/Fl_Tree_Item.cxx b/libraries/fltk/src/Fl_Tree_Item.cxx index 544170a324..616a773925 100644 --- a/libraries/fltk/src/Fl_Tree_Item.cxx +++ b/libraries/fltk/src/Fl_Tree_Item.cxx @@ -9,6 +9,7 @@ #include #include #include +#include "Fl_System_Driver.H" ////////////////////// // Fl_Tree_Item.cxx @@ -137,8 +138,8 @@ Fl_Tree_Item::Fl_Tree_Item(const Fl_Tree_Item *o) { void Fl_Tree_Item::show_self(const char *indent) const { const char *thelabel = label() ? label() : "(NULL)"; printf("%s-%s (%d children, this=%p, parent=%p, prev=%p, next=%p, depth=%d)\n", - indent,thelabel,children(),(void*)this, (void*)_parent, - _prev_sibling, _next_sibling, depth()); + indent, thelabel, children(), (void*)this, (void*)_parent, + (void*)_prev_sibling, (void*)_next_sibling, depth()); if ( children() ) { char *i2 = new char [strlen(indent)+3]; // 2 + nul byte strcpy(i2, indent); @@ -399,6 +400,7 @@ Fl_Tree_Item *Fl_Tree_Item::add(const Fl_Tree_Prefs &prefs, \see Fl_Tree::insert() */ Fl_Tree_Item *Fl_Tree_Item::insert(const Fl_Tree_Prefs &prefs, const char *new_label, int pos) { + (void) prefs; // quiet warnings unused params Fl_Tree_Item *item = new Fl_Tree_Item(_tree); item->label(new_label); item->_parent = this; @@ -713,13 +715,11 @@ void Fl_Tree_Item::draw_horizontal_connector(int x1, int x2, int y, const Fl_Tre fl_color(prefs.connectorcolor()); switch ( prefs.connectorstyle() ) { case FL_TREE_CONNECTOR_SOLID: - y |= 1; // force alignment w/dot pattern fl_line(x1,y,x2,y); return; case FL_TREE_CONNECTOR_DOTTED: { - y |= 1; // force alignment w/dot pattern - x1 |= 1; + x1 |= 1; // force alignment w/dot pattern for ( int xx=x1; xx<=x2; xx+=2 ) { fl_point(xx, y); } @@ -804,7 +804,7 @@ Fl_Tree_Item *Fl_Tree_Item::find_clicked(const Fl_Tree_Prefs &prefs, int yonly) /// - visibility (if !is_visible(), returns 0) /// - labelfont() height: if label() != NULL /// - widget() height: if widget() != NULL -/// - openicon() height (if not NULL) +/// - openicon() height (if has children) /// - usericon() height (if not NULL) /// Does NOT include Fl_Tree::linespacing(); /// \returns maximum pixel height @@ -821,8 +821,8 @@ int Fl_Tree_Item::calc_item_height(const Fl_Tree_Prefs &prefs) const { H < widget()->h()) { H = widget()->h(); } - if ( has_children() && prefs.openicon() && Hh() ) - H = prefs.openicon()->h(); + if ( has_children() && H < prefs.openicon_h() ) + H = prefs.openicon_h(); if ( usericon() && Hh() ) H = usericon()->h(); return(H); @@ -989,14 +989,14 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus, // Note: calculate collapse icon's xywh for possible mouse click detection. // We don't care about items clipped off the viewport; they won't get mouse events. // - int item_y_center = Y+(H/2); - _collapse_xywh[2] = prefs.openicon()->w(); + int item_y_center = (Y+(H/2))|1; // |1: force alignment w/dot pattern + _collapse_xywh[2] = prefs.openicon_w(); int &icon_w = _collapse_xywh[2]; _collapse_xywh[0] = X + (icon_w + prefs.connectorwidth())/2 - 3; int &icon_x = _collapse_xywh[0]; - _collapse_xywh[1] = item_y_center - (prefs.openicon()->h()/2); + _collapse_xywh[1] = item_y_center - prefs.openicon_h()/2; int &icon_y = _collapse_xywh[1]; - _collapse_xywh[3] = prefs.openicon()->h(); + _collapse_xywh[3] = prefs.openicon_h(); // Horizontal connector values // Must calculate these even if(clipped) because 'draw children' code (below) @@ -1063,10 +1063,8 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus, if ( (tree()->damage() & ~FL_DAMAGE_CHILD) || !render ) { // non-child damage? // Draw connectors if ( render && prefs.connectorstyle() != FL_TREE_CONNECTOR_NONE ) { - // Horiz connector between center of icon and text - // if this is root, the connector should not dangle in thin air on the left - if (is_root()) draw_horizontal_connector(hconn_x_center, hconn_x2, item_y_center, prefs); - else draw_horizontal_connector(hconn_x, hconn_x2, item_y_center, prefs); + // Horiz connector to center of icon + draw_horizontal_connector(hconn_x, hconn_x_center, item_y_center, prefs); // Small vertical line down to children if ( has_children() && is_open() ) draw_vertical_connector(hconn_x_center, item_y_center, Y+H2, prefs); @@ -1080,11 +1078,19 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus, if ( render && has_children() && prefs.showcollapse() ) { // Draw icon image if ( is_open() ) { - if ( active ) prefs.closeicon()->draw(icon_x,icon_y); - else prefs.closedeicon()->draw(icon_x,icon_y); + if ( prefs.closeicon() ) { + if ( active ) prefs.closeicon()->draw(icon_x, icon_y); + else prefs.closedeicon()->draw(icon_x, icon_y); + } else { + Fl::system_driver()->tree_draw_expando_button(icon_x, icon_y, false, active); + } } else { - if ( active ) prefs.openicon()->draw(icon_x,icon_y); - else prefs.opendeicon()->draw(icon_x,icon_y); + if ( prefs.openicon() ) { + if ( active ) prefs.openicon()->draw(icon_x, icon_y); + else prefs.opendeicon()->draw(icon_x, icon_y); + } else { + Fl::system_driver()->tree_draw_expando_button(icon_x, icon_y, true, active); + } } } // Draw user icon (if any) @@ -1138,11 +1144,34 @@ void Fl_Tree_Item::draw(int X, int &Y, int W, Fl_Tree_Item *itemfocus, Y += prefs.openchild_marginbottom(); // offset below open child tree } if ( ! lastchild ) { - // Special 'clipped' calculation. (intentional variable shadowing) - int is_clipped = ((child_y_start < tree_top) && (Y < tree_top)) || - ((child_y_start > tree_bot) && (Y > tree_bot)); - if (render && !is_clipped ) - draw_vertical_connector(hconn_x, child_y_start, Y, prefs); + // Draw vertical connector between this item and the bottom of its children. + // + // o Aaa <- Item we're drawing has >20k children. + // ytop → : :.. 0001 + // : :.. 0002 + // : : } ~20k items + // : :.. 19998 + // ┌──:──:.. 19999 ──┐ + // │ : :.. 20000 │ + // │ : :.. 20001 │ <- visible screen + // │ : :.. 20002 │ area + // └──:──:.. 20003 ──┘ + // : :.. 20004 + // : + // ybot → : ← we're drawing this long vertical connector + // : + // o Bbb + // + int ytop = child_y_start; + int ybot = Y; + int is_clipped = ((ytop < tree_top) && (ybot < tree_top)) || // completely off top of scrn? clip + ((ytop > tree_bot) && (ybot > tree_bot)); // completely off bot of scrn? clip + if (render && !is_clipped ) { + // Clip vert line to within screen area + ytop = (ytop < tree_top) ? tree_top : ytop; + ybot = (ybot > tree_bot) ? tree_bot : ybot; + draw_vertical_connector(hconn_x, ytop, ybot, prefs); + } } } } @@ -1185,11 +1214,13 @@ int Fl_Tree_Item::event_on_user_icon(const Fl_Tree_Prefs &prefs) const { /// Was event anywhere on the item? int Fl_Tree_Item::event_on_item(const Fl_Tree_Prefs &prefs) const { - return(event_inside(_xywh) ? 1 : 0); + (void) prefs; // quiet warnings unused params + return(event_inside(_xywh) ? 1 : 0); } /// Was event on the label() of this item? int Fl_Tree_Item::event_on_label(const Fl_Tree_Prefs &prefs) const { + (void) prefs; // quiet warnings unused params if ( is_visible() && is_active() ) { return(event_inside(_label_xywh) ? 1 : 0); } else { @@ -1428,9 +1459,9 @@ Fl_Tree_Item *Fl_Tree_Item::prev_displayed(Fl_Tree_Prefs &prefs) { /// See if item and all its parents are open() and visible(). /// \returns /// 1 -- item and its parents are open() and visible() -/// 0 -- item (or one of its parents) are invisible or close()ed. +/// 0 -- item or one of its parents are either not visible() or close()ed. /// -int Fl_Tree_Item::visible_r() const { +int Fl_Tree_Item::is_visible_r() const { if ( !visible() ) return(0); for (const Fl_Tree_Item *p=parent(); p; p=p->parent())// move up through parents if (!p->visible() || p->is_close()) return(0); // any parent not visible or closed? diff --git a/libraries/fltk/src/Fl_Tree_Prefs.cxx b/libraries/fltk/src/Fl_Tree_Prefs.cxx index aa0d17c3b1..f34675c9c7 100644 --- a/libraries/fltk/src/Fl_Tree_Prefs.cxx +++ b/libraries/fltk/src/Fl_Tree_Prefs.cxx @@ -22,12 +22,9 @@ #include "Fl_System_Driver.H" #include -#include +#include #include - -// INTERNAL: BUILT IN OPEN/STOW XPMS -// These can be replaced via prefs.openicon()/closeicon() -// +#include /** \cond DriverDev @@ -35,61 +32,16 @@ \{ */ -const char * const Fl_System_Driver::tree_open_xpm[] = { - "11 11 3 1", - ". c #fefefe", - "# c #444444", - "@ c #000000", - "###########", - "#.........#", - "#.........#", - "#....@....#", - "#....@....#", - "#..@@@@@..#", - "#....@....#", - "#....@....#", - "#.........#", - "#.........#", - "###########" -}; - -const char * const Fl_System_Driver::tree_close_xpm[] = { -"11 11 3 1", -". c #fefefe", -"# c #444444", -"@ c #000000", -"###########", -"#.........#", -"#.........#", -"#.........#", -"#.........#", -"#..@@@@@..#", -"#.........#", -"#.........#", -"#.........#", -"#.........#", -"###########" -}; - - -/** - Return the address of a pixmap that show a plus in a box. - - This pixmap is used to indicate a brach of a tree that is closed and - can be opened by clicking it. - - Other platforms may use other symbols which can be reimplemented in the - driver. Notably, Apple Mac systems mark a closed branch with a triangle - pointing to the right, and an open branch with a triangle pointing down. - */ -Fl_Pixmap *Fl_System_Driver::tree_openpixmap() { - static Fl_Pixmap *pixmap = new Fl_Pixmap(tree_open_xpm); - return pixmap; -} - -Fl_Pixmap *Fl_System_Driver::tree_closepixmap() { - static Fl_Pixmap *pixmap = new Fl_Pixmap(tree_close_xpm); - return pixmap; +// Draw non-OS specific Fl_Tree open/close icons +// ┌───┐ ┌───┐ +// │ + │ │ - │ +// └───┘ └───┘ +void Fl_System_Driver::tree_draw_expando_button(int x, int y, bool state, bool active) { + fl_rectf(x, y, 11, 11, active ? FL_BACKGROUND2_COLOR : fl_inactive(FL_BACKGROUND2_COLOR)); // fill + fl_rect(x, y, 11, 11, FL_INACTIVE_COLOR); // outline + fl_color(active ? FL_FOREGROUND_COLOR : FL_INACTIVE_COLOR); + fl_line(x + 3, y + 5, x + 7, y + 5); // horiz line + if (state) fl_line(x + 5, y + 3, x + 5, y + 7); // vert line } int Fl_System_Driver::tree_connector_style() { @@ -109,7 +61,7 @@ int Fl_System_Driver::tree_connector_style() { /// \param[in] val -- The new image, or zero to use the default [+] icon. /// void Fl_Tree_Prefs::openicon(Fl_Image *val) { - _openimage = val ? val : Fl::system_driver()->tree_openpixmap(); + _openimage = val ? val : 0; // Update deactivated version of icon.. if ( _opendeimage ) delete _opendeimage; if ( _openimage ) { @@ -126,7 +78,7 @@ void Fl_Tree_Prefs::openicon(Fl_Image *val) { /// \param[in] val -- The new image, or zero to use the default [-] icon. /// void Fl_Tree_Prefs::closeicon(Fl_Image *val) { - _closeimage = val ? val : Fl::system_driver()->tree_closepixmap(); + _closeimage = val ? val : 0; // Update deactivated version of icon.. if ( _closedeimage ) delete _closedeimage; if ( _closeimage ) { @@ -151,15 +103,13 @@ Fl_Tree_Prefs::Fl_Tree_Prefs() { _linespacing = 0; _labelfgcolor = FL_FOREGROUND_COLOR; _labelbgcolor = 0xffffffff; // we use this as 'transparent' - _connectorcolor = Fl_Color(43); + _connectorcolor = FL_INACTIVE_COLOR; _connectorstyle = (Fl_Tree_Connector)Fl::system_driver()->tree_connector_style(); - _openimage = Fl::system_driver()->tree_openpixmap(); - _closeimage = Fl::system_driver()->tree_closepixmap(); + _openimage = 0; + _closeimage = 0; _userimage = 0; - _opendeimage = _openimage->copy(); - _opendeimage->inactive(); - _closedeimage = _closeimage->copy(); - _closedeimage->inactive(); + _opendeimage = 0; + _closedeimage = 0; _userdeimage = 0; _showcollapse = 1; _showroot = 1; diff --git a/libraries/fltk/src/Fl_Widget.cxx b/libraries/fltk/src/Fl_Widget.cxx index bf2ff03d03..3a583ca4de 100644 --- a/libraries/fltk/src/Fl_Widget.cxx +++ b/libraries/fltk/src/Fl_Widget.cxx @@ -118,6 +118,8 @@ Fl_Widget::Fl_Widget(int X, int Y, int W, int H, const char* L) { label_.size = FL_NORMAL_SIZE; label_.color = FL_FOREGROUND_COLOR; label_.align_ = FL_ALIGN_CENTER; + label_.h_margin_ = label_.v_margin_ = 0; + label_.spacing = 0; tooltip_ = 0; callback_ = default_callback; user_data_ = 0; diff --git a/libraries/fltk/src/Fl_Widget_Surface.cxx b/libraries/fltk/src/Fl_Widget_Surface.cxx index f489897bae..98cc736ad1 100644 --- a/libraries/fltk/src/Fl_Widget_Surface.cxx +++ b/libraries/fltk/src/Fl_Widget_Surface.cxx @@ -198,7 +198,7 @@ int Fl_Widget_Surface::printable_rect(int *w, int *h) {return 1;} void Fl_Widget_Surface::draw_decorated_window(Fl_Window *win, int win_offset_x, int win_offset_y) { Fl_RGB_Image *top=0, *left=0, *bottom=0, *right=0; - if (win->border() && !win->parent()) { + if (win->shown() && win->border() && !win->parent()) { Fl_Window_Driver::driver(win)->capture_titlebar_and_borders(top, left, bottom, right); } bool need_push = !is_current(); diff --git a/libraries/fltk/src/Fl_Window.cxx b/libraries/fltk/src/Fl_Window.cxx index a8912f31f7..d5a82a41bd 100644 --- a/libraries/fltk/src/Fl_Window.cxx +++ b/libraries/fltk/src/Fl_Window.cxx @@ -1,7 +1,7 @@ // // Window widget class for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2022 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -526,6 +526,7 @@ void Fl_Window::draw_backdrop() { l1.image = image(); if (!active_r() && l1.image && l1.deimage) l1.image = l1.deimage; l1.type = labeltype(); + l1.h_margin_ = l1.v_margin_ = l1.spacing = 0; l1.draw(0,0,w(),h(),align()); } } @@ -678,16 +679,19 @@ void Fl_Window::size_range(int minWidth, int minHeight, } /** - Gets the allowable range to which the user can resize this window. + Gets the allowable range to which the user can resize this window. - \param[out] minWidth, minHeight, maxWidth, maxHeight, deltaX, deltaY, aspectRatio + \param[out] minWidth, minHeight, maxWidth, maxHeight, deltaX, deltaY, aspectRatio are all pointers to integers that will receive the current respective value during the call. Every pointer can be NULL if that value is not needed. - \retval 0 if size range not set - \retval 1 if the size range was explicitly set by a call to Fl_Window::size_range() - or has been calculated - \see Fl_Window::size_range(int minWidth, int minHeight, int maxWidth, int maxHeight, int deltaX, int deltaY, int aspectRatio) - */ + + \retval 0 if size range not set + \retval 1 if the size range was explicitly set by a call to Fl_Window::size_range() + or has been calculated + \see Fl_Window::size_range(int minWidth, int minHeight, int maxWidth, int maxHeight, int deltaX, int deltaY, int aspectRatio) + + \since 1.4.0 +*/ uchar Fl_Window::get_size_range(int *minWidth, int *minHeight, int *maxWidth, int *maxHeight, int *deltaX, int *deltaY, int *aspectRatio) { @@ -779,6 +783,8 @@ uchar Fl_Window::get_size_range(int *minWidth, int *minHeight, If this is not what you want, please use Fl_Window::size_range() explicitly so you can set any appropriate range. + + \since 1.4.0 */ void Fl_Window::default_size_range() { @@ -858,6 +864,8 @@ void Fl_Window::default_size_range() { \retval 3 the window is resizable in both directions (w and h) \see default_size_range() + + \since 1.4.0 */ int Fl_Window::is_resizable() { default_size_range(); @@ -867,27 +875,59 @@ int Fl_Window::is_resizable() { return ret; } -/** The number of the screen containing the mapped window */ +/** The number of the screen containing the mapped window. + + This method returns the screen number (0 .. n) of the window + if it is shown, otherwise the result value is undefined. + + \note The return value is undefined before the window is shown and + if the window has been hidden after it was previously shown. + + To position a window on a particular screen, use + Fl_Window::screen_num(int) \b before you show() it. + + \return screen number of the window if it is shown + + \see Fl_Window::screen_num(int) + + \since 1.4.0 + */ int Fl_Window::screen_num() { return pWindowDriver->screen_num(); } /** Set the number of the screen where to map the window. - Call this and set also the window's desired position before show()'ing the window. - This can be necessary when a system has several screens with - distinct scaling factor values because the window's x() and y() may not suffice to - uniquely identify one screen. - To see that, consider a system with two screens where the screen at left is A pixel-wide - and has a scale factor of 1 whereas the screen at right has a scale factor of 2. - For the sake of simplicity, consider only - the X coordinates of windows. FLTK coordinates translate directly to pixel coordinates on the - left screen, whereas FLTK coordinates multiplied by 2 correspond to pixel coordinates - on the right screen. Consequently, FLTK coordinates between A/2 + 1 and A-1 can map to both - screens. Both window coordinates and screen number are necessary to uniquely identify - where a window is to be mapped. - */ + + Call this and set also the window's desired x/y position before show()'ing + the window. This can be necessary if a system has several screens with + distinct scaling factors because the window's x() and y() may not suffice + to uniquely identify one screen. + + Consider a system with two screens where the left screen is A pixels wide and + has a scaling factor of 1 whereas the right screen has a scaling factor of 2. + For the sake of simplicity, consider only the X coordinate of the window. + FLTK coordinates translate directly to pixel coordinates on the left screen, + whereas FLTK coordinates multiplied by 2 correspond to pixel coordinates + on the right screen. Consequently, FLTK coordinates between A/2 + 1 and A-1 + can map to both screens. Therefore both the window coordinates and the screen + number are necessary to uniquely identify where a window is to be mapped. + + The valid range of \p screen_num is 0 .. Fl::screen_count() - 1. + + This method does nothing if + - the window is already shown() or + - the given screen number is out of range. + + \param[in] screen_num screen number where the window is to be mapped + + \see Fl_Window::screen_num() + \see Fl::screen_count() + + \since 1.4.0 +*/ void Fl_Window::screen_num(int screen_num) { - if (!shown() && screen_num >= 0 && screen_num < Fl::screen_count()) pWindowDriver->screen_num(screen_num); + if (!shown() && screen_num >= 0 && screen_num < Fl::screen_count()) + pWindowDriver->screen_num(screen_num); } /** Assigns a non-rectangular shape to the window. @@ -933,44 +973,60 @@ void Fl_Window::shape(const Fl_Image* img) {pWindowDriver->shape(img);} */ void Fl_Window::shape(const Fl_Image& img) {pWindowDriver->shape(&img);} -/** Returns the image controlling the window shape or NULL */ +/** Returns the image controlling the window shape or NULL. + + \since 1.4.0 +*/ const Fl_Image* Fl_Window::shape() {return pWindowDriver->shape();} -/** Returns true when a window is being rescaled */ +/** Returns true when a window is being rescaled. + + \since 1.4.0 +*/ bool Fl_Window::is_a_rescale() {return Fl_Window_Driver::is_a_rescale_;} /** Returns a platform-specific identification of a shown window, or 0 if not shown. - \note This identification may differ from the platform-specific reference of an - Fl_Window object used by functions fl_x11_xid(), fl_mac_xid(), fl_x11_find(), and fl_mac_find(). - \li X11 platform: the window's XID. - \li macOS platform: The window number of the window’s window device. - \li other platforms: 0. - */ + + \note This identification may differ from the platform-specific reference + of an Fl_Window object used by functions fl_x11_xid(), fl_mac_xid(), + fl_x11_find(), and fl_mac_find(). + + - X11 platform: the window's XID. + - macOS platform: The window number of the window’s window device. + - other platforms: 0. + + \since 1.4.0 +*/ fl_uintptr_t Fl_Window::os_id() { return pWindowDriver->os_id();} /** - Maximizes a top-level window to its current screen. + Maximizes a top-level window to its current screen. - This function is effective only with a show()'n, resizable, top-level window. - Bordered and borderless windows can be used. - \see Fl_Window::un_maximize(), Fl_Window::maximize_active() - */ + This function is effective only with a show()'n, resizable, top-level window. + Bordered and borderless windows can be used. + Fullscreen windows can't be used. + + \see Fl_Window::un_maximize(), Fl_Window::maximize_active() + + \since 1.4.0 +*/ void Fl_Window::maximize() { - if (!shown() || parent() || !is_resizable() || maximize_active()) return; + if (!shown() || parent() || !is_resizable() || maximize_active() || fullscreen_active()) + return; set_flag(MAXIMIZED); - if (border()) pWindowDriver->maximize(); - else pWindowDriver->Fl_Window_Driver::maximize(); + pWindowDriver->maximize(); } /** - Returns a previously maximized top-level window to its previous size. - \see Fl_Window::maximize() + Returns a previously maximized top-level window to its previous size. + \see Fl_Window::maximize() + + \since 1.4.0 */ void Fl_Window::un_maximize() { - if (!shown() || parent() || !is_resizable() || !maximize_active()) return; + if (!shown() || parent() || !is_resizable() || !maximize_active() || fullscreen_active()) return; clear_flag(MAXIMIZED); - if (border()) pWindowDriver->un_maximize(); - else pWindowDriver->Fl_Window_Driver::un_maximize(); + pWindowDriver->un_maximize(); } void Fl_Window::is_maximized_(bool b) { @@ -979,8 +1035,11 @@ void Fl_Window::is_maximized_(bool b) { } /** Allow this subwindow to expand outside the area of its parent window. - This is presently implemented only for the Wayland platform to help support window docking. - \since 1.4.0 + + This is presently implemented only for the Wayland platform to help + support window docking. + + \since 1.4.0 */ void Fl_Window::allow_expand_outside_parent() { if (parent()) pWindowDriver->allow_expand_outside_parent(); diff --git a/libraries/fltk/src/Fl_Window_fullscreen.cxx b/libraries/fltk/src/Fl_Window_fullscreen.cxx index f6919f87c1..e464a9fba8 100644 --- a/libraries/fltk/src/Fl_Window_fullscreen.cxx +++ b/libraries/fltk/src/Fl_Window_fullscreen.cxx @@ -37,10 +37,12 @@ void Fl_Window::border(int b) { */ void Fl_Window::fullscreen() { if (!is_resizable()) return; - no_fullscreen_x = x(); - no_fullscreen_y = y(); - no_fullscreen_w = w(); - no_fullscreen_h = h(); + if (!maximize_active()) { + no_fullscreen_x = x(); + no_fullscreen_y = y(); + no_fullscreen_w = w(); + no_fullscreen_h = h(); + } if (shown() && !(flags() & Fl_Widget::FULLSCREEN)) { pWindowDriver->fullscreen_on(); } else { @@ -54,7 +56,8 @@ void Fl_Window::fullscreen_off(int X,int Y,int W,int H) { } else { clear_flag(FULLSCREEN); } - no_fullscreen_x = no_fullscreen_y = no_fullscreen_w = no_fullscreen_h = 0; + if (!maximize_active()) + no_fullscreen_x = no_fullscreen_y = no_fullscreen_w = no_fullscreen_h = 0; } void Fl_Window::fullscreen_off() { diff --git a/libraries/fltk/src/Fl_XColor.H b/libraries/fltk/src/Fl_XColor.H index 4717620fec..5952f5c8ec 100644 --- a/libraries/fltk/src/Fl_XColor.H +++ b/libraries/fltk/src/Fl_XColor.H @@ -14,6 +14,7 @@ // https://www.fltk.org/bugs.php // +#ifndef FL_DOXYGEN #include #include @@ -29,3 +30,4 @@ 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; +#endif // FL_DOXYGEN diff --git a/libraries/fltk/src/Fl_arg.cxx b/libraries/fltk/src/Fl_arg.cxx index f0ec4d5434..46e9f7073f 100644 --- a/libraries/fltk/src/Fl_arg.cxx +++ b/libraries/fltk/src/Fl_arg.cxx @@ -316,7 +316,7 @@ void Fl_Window::show(int argc, char **argv) { // 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])); + else if (!xclass() || !strcmp(xclass(),"FLTK")) xclass(fl_filename_name(argv[0])); if (title) {label(title); title = 0;} else if (!label()) label(xclass()); diff --git a/libraries/fltk/src/Fl_cocoa.mm b/libraries/fltk/src/Fl_cocoa.mm index 3283143c24..ae40df4462 100644 --- a/libraries/fltk/src/Fl_cocoa.mm +++ b/libraries/fltk/src/Fl_cocoa.mm @@ -1,7 +1,7 @@ // // macOS-Cocoa specific code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -49,6 +49,9 @@ #include #import +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_15_0 +# import +#endif // #define DEBUG_SELECT // UNCOMMENT FOR SELECT()/THREAD DEBUGGING #ifdef DEBUG_SELECT @@ -1043,7 +1046,7 @@ static void cocoaMagnifyHandler(NSEvent *theEvent) */ static void cocoaMouseHandler(NSEvent *theEvent) { - static int keysym[] = { 0, FL_Button+1, FL_Button+3, FL_Button+2 }; + static int keysym[] = { 0, FL_Button+1, FL_Button+3, FL_Button+2, FL_Button+4, FL_Button+5 }; static int px, py; fl_lock_function(); @@ -1053,13 +1056,11 @@ static void cocoaMouseHandler(NSEvent *theEvent) fl_unlock_function(); return; } - Fl_Window *first = Fl::first_window(); - if (first != window && !(first->modal() || first->non_modal())) Fl::first_window(window); NSPoint pos = [theEvent locationInWindow]; float s = Fl::screen_driver()->scale(0); pos.x /= s; pos.y /= s; pos.y = window->h() - pos.y; - NSInteger btn = [theEvent buttonNumber] + 1; + NSInteger btn = [theEvent buttonNumber] + 1; NSUInteger mods = [theEvent modifierFlags]; int sendEvent = 0; @@ -1069,13 +1070,17 @@ static void cocoaMouseHandler(NSEvent *theEvent) if (btn == 1) Fl::e_state |= FL_BUTTON1; else if (btn == 3) Fl::e_state |= FL_BUTTON2; else if (btn == 2) Fl::e_state |= FL_BUTTON3; + else if (btn == 4) Fl::e_state |= FL_BUTTON4; + else if (btn == 5) Fl::e_state |= FL_BUTTON5; } else if (etype == NSEventTypeLeftMouseUp || etype == NSEventTypeRightMouseUp || etype == NSEventTypeOtherMouseUp) { if (btn == 1) Fl::e_state &= ~FL_BUTTON1; else if (btn == 3) Fl::e_state &= ~FL_BUTTON2; else if (btn == 2) Fl::e_state &= ~FL_BUTTON3; - } + else if (btn == 4) Fl::e_state &= ~FL_BUTTON4; + else if (btn == 5) Fl::e_state &= ~FL_BUTTON5; + } switch ( etype ) { case NSEventTypeLeftMouseDown: @@ -2384,7 +2389,7 @@ - (BOOL)did_view_resolution_change { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_14 if (views_use_CA && !window->as_gl_window() ) { [self reset_aux_bitmap]; - [self display]; + window->redraw(); } #endif } @@ -2533,9 +2538,9 @@ - (void)resetCursorRects { // We have to have at least one cursor rect for invalidateCursorRectsForView // to work, hence the "else" clause. if (Fl_Cocoa_Window_Driver::driver(w)->cursor) - [self addCursorRect:[self visibleRect] cursor:Fl_Cocoa_Window_Driver::driver(w)->cursor]; + [self addCursorRect:[self frame] cursor:Fl_Cocoa_Window_Driver::driver(w)->cursor]; else - [self addCursorRect:[self visibleRect] cursor:[NSCursor arrowCursor]]; + [self addCursorRect:[self frame] cursor:[NSCursor arrowCursor]]; } - (void)mouseUp:(NSEvent *)theEvent { cocoaMouseHandler(theEvent); @@ -3277,7 +3282,10 @@ - (void)draggingSession:(NSDraggingSession *)session #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 if (fl_mac_os_version >= 100700 && pWindow->border()) { # if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - FLWindow *nswin = fl_xid(pWindow); + NSWindow *nswin = fl_xid(pWindow); +# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 + if (fl_mac_os_version >= 101300) nswin = [[nswin tabGroup] selectedWindow]; +# endif [nswin toggleFullScreen:nil]; # endif } else if (fl_mac_os_version >= 100600) { @@ -3323,12 +3331,14 @@ - (void)draggingSession:(NSDraggingSession *)session void Fl_Cocoa_Window_Driver::maximize() { - [fl_xid(pWindow) performZoom:nil]; + if (border()) [fl_xid(pWindow) performZoom:nil]; + else Fl_Window_Driver::maximize(); } void Fl_Cocoa_Window_Driver::un_maximize() { - [fl_xid(pWindow) performZoom:nil]; + if (border()) [fl_xid(pWindow) performZoom:nil]; + else Fl_Window_Driver::un_maximize(); } @@ -3363,9 +3373,11 @@ static void restore_window_title_and_icon(Fl_Window *pWindow, NSImage *icon) { #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 if (fl_mac_os_version >= 100700 && pWindow->border()) { # if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_7 - FLWindow *nswin = fl_xid(pWindow); + NSWindow *nswin = fl_xid(pWindow); +# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_13 + if (fl_mac_os_version >= 101300) nswin = [[nswin tabGroup] selectedWindow]; +# endif [nswin toggleFullScreen:nil]; - pWindow->resize(*no_fullscreen_x(), *no_fullscreen_y(), *no_fullscreen_w(), *no_fullscreen_h()); # endif } else if (fl_mac_os_version >= 100600) { FLWindow *nswin = fl_xid(pWindow); @@ -3383,6 +3395,7 @@ static void restore_window_title_and_icon(Fl_Window *pWindow, NSImage *icon) { [nswin setStyleMask:calc_win_style(pWindow)]; //10.6 restore_window_title_and_icon(pWindow, icon_image); pWindow->resize(X, Y, W, H); + if (pWindow->maximize_active()) Fl_Window_Driver::maximize(); if (has_focus) [nswin makeKeyAndOrderFront:nil]; else [nswin orderFront:nil]; } else @@ -3399,6 +3412,17 @@ static void restore_window_title_and_icon(Fl_Window *pWindow, NSImage *icon) { if (!shown() || pWindow->parent()) return; #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_6 if (fl_mac_os_version >= 100600) { + if (pWindow->fullscreen_active() || pWindow->maximize_active()) { + // prevent changing border while window is fullscreen or maximized + static bool active = false; + if (!active) { + active = true; + bool b = !border(); + pWindow->border(b); + active = false; + } + return; + } [fl_xid(pWindow) setStyleMask:calc_win_style(pWindow)]; // 10.6 if (border()) restore_window_title_and_icon(pWindow, icon_image); pWindow->redraw(); @@ -4607,28 +4631,134 @@ static void nsbitmapProviderReleaseData (void *info, const void *data, size_t si return h() + bt/s; } +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_15_0 + +// Requires -weak_framework ScreenCaptureKit and used by FLTK for macOS ≥ 15.0 +static CGImageRef capture_decorated_window_SCK(NSWindow *nswin) { + if (@available(macOS 15.0, *)) { + __block CGImageRef capture = NULL; + __block BOOL capture_err = NO; + void (^block_to_stop_main_loop)(void) = ^{ CFRunLoopStop(CFRunLoopGetMain()); }; + // Fix for bug in ScreenCaptureKit that modifies a window's styleMask the first time + // it captures a non-resizable window. We memorize each non-resizable window's styleMask, + // and we restore modified styleMasks later, after the screen capture. + NSMutableArray *xid_array = [NSMutableArray arrayWithCapacity:2]; + NSMutableArray *mask_array = [NSMutableArray arrayWithCapacity:2]; + Fl_Window *win = Fl::first_window(); + while (win) { + if (!win->parent() && win->border()) { + FLWindow *xid = fl_mac_xid(win); + if (xid && !([xid styleMask] & NSWindowStyleMaskResizable)) { + [xid_array addObject:xid]; + NSUInteger mask = [xid styleMask]; + [mask_array addObject:[NSData dataWithBytes:&mask length:sizeof(NSUInteger)]]; + } + } + win = Fl::next_window(win); + } + CGWindowID target_id = [nswin windowNumber]; + NSRect r = [nswin frame]; + int W = r.size.width, H = r.size.height; + [SCShareableContent getCurrentProcessShareableContentWithCompletionHandler: // macOS 14.4 + ^(SCShareableContent *shareableContent, NSError *error) { + SCWindow *scwin = nil; + if (!error) { + NSEnumerator *enumerator = [[shareableContent windows] objectEnumerator]; + while ((scwin = (SCWindow*)[enumerator nextObject]) != nil) { + if ([scwin windowID] == target_id) { + break; + } + } + } + if (!scwin) { + capture_err = YES; + dispatch_async(dispatch_get_main_queue(), block_to_stop_main_loop); + return; + } + SCContentFilter *filter = [[[SCContentFilter alloc] initWithDesktopIndependentWindow:scwin] autorelease]; + int s = (int)[filter pointPixelScale]; + SCStreamConfiguration *config = [[[SCStreamConfiguration alloc] init] autorelease]; + [config setIgnoreShadowsSingleWindow:YES]; + [config setWidth:W*s]; + [config setHeight:H*s]; + [config setIncludeChildWindows:NO]; // macOS 14.2 + [SCScreenshotManager captureImageWithFilter:filter + configuration:config + completionHandler:^(CGImageRef sampleBuffer, NSError *error) { + if (error) capture_err = YES; + else { + capture = sampleBuffer; + CGImageRetain(capture); + } + dispatch_async(dispatch_get_main_queue(), block_to_stop_main_loop); + } + ]; + } + ]; + // run the main loop until the 1 or 2 blocks above have completed and have stopped the loop + while (!capture_err && !capture) CFRunLoopRun(); + if (capture_err) return NULL; + // ScreenCaptureKit bug cont'd: restore modified styleMasks. + for (int i = 0, count = [xid_array count]; i < count; i++) { + NSUInteger mask; + [(NSData*)[mask_array objectAtIndex:i] getBytes:&mask length:sizeof(NSUInteger)]; + NSWindow *xid = (NSWindow*)[xid_array objectAtIndex:i]; + if (mask != [xid styleMask]) [xid setStyleMask:mask]; + } + return capture; + } else return NULL; +} +#endif //MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_15_0 + + +CGImageRef Fl_Cocoa_Window_Driver::capture_decorated_window_10_6(NSWindow *nswin) { + // usable with 10.6 and above + CGImageRef img = NULL; +#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 +# if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_VERSION_15_0 + if (fl_mac_os_version >= 150000) + img = capture_decorated_window_SCK(nswin); + else +#endif + { +# if MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_VERSION_15_0 + NSInteger win_id = [nswin windowNumber]; + CFArrayRef array = CFArrayCreate(NULL, (const void**)&win_id, 1, NULL); + img = CGWindowListCreateImageFromArray(CGRectNull, array, kCGWindowImageBoundsIgnoreFraming); // 10.5 + CFRelease(array); +# endif + } +#endif // >= MAC_OS_X_VERSION_10_5 + return img; +} + + +static CGImageRef capture_window_titlebar(Fl_Window *win, Fl_Cocoa_Window_Driver *cocoa_dr) { + CGImageRef img; + if (fl_mac_os_version >= 100600) { // verified OK from 10.6 + FLWindow *nswin = fl_xid(win); + CGImageRef img_full = Fl_Cocoa_Window_Driver::capture_decorated_window_10_6(nswin); + int bt = [nswin frame].size.height - [[nswin contentView] frame].size.height; + int s = CGImageGetWidth(img_full) / [nswin frame].size.width; + CGRect cgr = CGRectMake(0, 0, CGImageGetWidth(img_full), bt * s); + img = CGImageCreateWithImageInRect(img_full, cgr); + CGImageRelease(img_full); + } else { + int w = win->w(), h = win->decorated_h() - win->h(); + Fl_Graphics_Driver::default_driver().scale(1); + img = cocoa_dr->CGImage_from_window_rect(0, -h, w, h, false); + Fl_Graphics_Driver::default_driver().scale(Fl::screen_driver()->scale(win->screen_num())); + } + return img; +} + + void Fl_Cocoa_Window_Driver::draw_titlebar_to_context(CGContextRef gc, int w, int h) { FLWindow *nswin = fl_xid(pWindow); if ([nswin canBecomeMainWindow]) [nswin makeMainWindow]; [NSApp nextEventMatchingMask:NSEventMaskAny untilDate:nil inMode:NSDefaultRunLoopMode dequeue:NO]; - CGImageRef img; -#if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_5 - if (fl_mac_os_version >= 100600) { // verified OK from 10.6 - NSInteger win_id = [nswin windowNumber]; - CFArrayRef array = CFArrayCreate(NULL, (const void**)&win_id, 1, NULL); - CGRect rr = NSRectToCGRect([nswin frame]); - rr.origin.y = CGDisplayBounds(CGMainDisplayID()).size.height - (rr.origin.y + rr.size.height); - rr.size.height = h; - img = CGWindowListCreateImageFromArray(rr, array, kCGWindowImageBoundsIgnoreFraming); // 10.5 - CFRelease(array); - } else -#endif - { - Fl_Graphics_Driver::default_driver().scale(1); - img = CGImage_from_window_rect(0, -h, w, h, false); - Fl_Graphics_Driver::default_driver().scale(Fl::screen_driver()->scale(screen_num())); - } + CGImageRef img = capture_window_titlebar(pWindow, this); if (img) { CGContextSaveGState(gc); if (fl_mac_os_version < 100600) clip_to_rounded_corners(gc, w, h); diff --git a/libraries/fltk/src/Fl_win32.cxx b/libraries/fltk/src/Fl_win32.cxx index 45474fd0f2..b87b055481 100644 --- a/libraries/fltk/src/Fl_win32.cxx +++ b/libraries/fltk/src/Fl_win32.cxx @@ -1,7 +1,7 @@ // // Windows-specific code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -90,6 +90,12 @@ void fl_cleanup_dc_list(void); # include #endif +// old versions of MinGW lack definition of GET_XBUTTON_WPARAM: + +#ifndef GET_XBUTTON_WPARAM +#define GET_XBUTTON_WPARAM(wParam) (HIWORD(wParam)) +#endif + static bool is_dpi_aware = false; extern bool fl_clipboard_notify_empty(void); @@ -1044,9 +1050,12 @@ static int mouse_event(Fl_Window *window, int what, int button, 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; + if (wParam & MK_LBUTTON) state |= FL_BUTTON1; // left + if (wParam & MK_MBUTTON) state |= FL_BUTTON2; // right + if (wParam & MK_RBUTTON) state |= FL_BUTTON3; // middle + if (wParam & MK_XBUTTON1) state |= FL_BUTTON4; // side button 1 (back) + if (wParam & MK_XBUTTON2) state |= FL_BUTTON5; // side button 2 (forward) + Fl::e_state = state; switch (what) { @@ -1147,7 +1156,7 @@ static const struct { {VK_LAUNCH_MAIL, FL_Mail}, #endif {0xba, ';'}, - {0xbb, '='}, + {0xbb, '='}, // 0xbb == VK_OEM_PLUS (see #1086) {0xbc, ','}, {0xbd, '-'}, {0xbe, '.'}, @@ -1347,6 +1356,21 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar case WM_RBUTTONUP: mouse_event(window, 2, 3, wParam, lParam); return 0; + case WM_XBUTTONDOWN: { + int xbutton = GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 4 : 5; + mouse_event(window, 0, xbutton, wParam, lParam); + return 0; + } + case WM_XBUTTONDBLCLK: { + int xbutton = GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 4 : 5; + mouse_event(window, 1, xbutton, wParam, lParam); + return 0; + } + case WM_XBUTTONUP: { + int xbutton = GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? 4 : 5; + mouse_event(window, 2, xbutton, wParam, lParam); + return 0; + } case WM_MOUSEMOVE: #ifdef USE_TRACK_MOUSE @@ -1439,6 +1463,10 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar case WM_SYSKEYUP: // save the keysym until we figure out the characters: Fl::e_keysym = Fl::e_original_keysym = ms2fltk(wParam, lParam & (1 << 24)); + // Kludge to allow recognizing ctrl+'-' on keyboards with digits in uppercase positions (e.g. French) + if (Fl::e_keysym == '6' && (VkKeyScanA('-') & 0xff) == '6') { + Fl::e_keysym = '-'; + } // See if TranslateMessage turned it into a WM_*CHAR message: if (PeekMessageW(&fl_msg, hWnd, WM_CHAR, WM_SYSDEADCHAR, PM_REMOVE)) { uMsg = fl_msg.message; @@ -1545,6 +1573,47 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar #endif } Fl::e_text = buffer; + + // Kludge to process the +-containing key in cross-platform way when used with Ctrl +/* Table of how Windows processes the '+'-containing key by keyboard layout + key virtual +content key keyboard layout + =|+ 0xbb US/UK/Fr/Arabic/Chinese/Hebrew/Brazil/Russian/Vietnam/Japan/Korean/Persian + +|* 0xbb German/Spanish/Italy/Greek/Portugal + +|? 0xbb Swedish/Finish/Norway + +|± 0xbb Dutch + 1|+ '1' Swiss/Luxemburg + 3|+ '3' Hungarian + 4|+ '4' Turkish +*/ + if ((Fl::e_state & FL_CTRL) && !(GetAsyncKeyState(VK_MENU) >> 15)) { + // extra processing necessary only when Ctrl is down and Alt is up + int vk_plus_key = (VkKeyScanA('+') & 0xff); // virtual key of '+'-containing key + bool plus_shift_pos = ((VkKeyScanA('+') & 0x100) != 0); // true means '+' in shifted position + int plus_other_char; // the other char on same key as '+' + if (plus_shift_pos) plus_other_char = ms2fltk(vk_plus_key, 0); + else if ((VkKeyScanA('*') & 0xff) == vk_plus_key) plus_other_char = '*'; // German + else if ((VkKeyScanA('?') & 0xff) == vk_plus_key) plus_other_char = '?'; // Swedish + else if ((VkKeyScanW(L'±') & 0xff) == vk_plus_key) plus_other_char = L'±'; // Dutch + else plus_other_char = '='; // fallback +//fprintf(stderr, "plus_shift_pos=%d plus_other_char='%c' vk+=0x%x\n", plus_shift_pos, +// plus_other_char, vk_plus_key); + if ( (vk_plus_key == 0xbb && Fl::e_keysym == '=') || // the '+'-containing key is down + (plus_shift_pos && Fl::e_keysym == plus_other_char) ) { + Fl::e_keysym = (plus_shift_pos ? plus_other_char : '+'); + static char plus_other_char_utf8[4]; + int lutf8 = fl_utf8encode(plus_other_char, plus_other_char_utf8); + plus_other_char_utf8[lutf8] = 0; + if (plus_shift_pos) { + Fl::e_text = ( (Fl::e_state & FL_SHIFT) ? (char*)"+" : plus_other_char_utf8 ); + } else { + Fl::e_text = ( (Fl::e_state & FL_SHIFT) ? plus_other_char_utf8 : (char*)"+" ); + } + Fl::e_length = strlen(Fl::e_text); + } + } + // end of processing of the +-containing key + if (lParam & (1 << 31)) { // key up events. if (Fl::handle(FL_KEYUP, window)) return 0; @@ -1630,7 +1699,16 @@ static LRESULT CALLBACK WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lPar Fl_WinAPI_Screen_Driver *sd = (Fl_WinAPI_Screen_Driver *)Fl::screen_driver(); Fl_WinAPI_Window_Driver *wd = Fl_WinAPI_Window_Driver::driver(window); int olds = wd->screen_num(); - int news = sd->screen_num_unscaled(nx + int(window->w() * scale / 2), ny + int(window->h() * scale / 2)); + // Issue #1097: when a fullscreen window is restored to its size, it receives first a WM_MOVE + // and then a WM_SIZE, so it still has its fullscreen size at the WM_MOVE event, which defeats + // using window->w()|h() to compute the center of the (small) window. We detect this situation + // with condition: !window->fullscreen_active() && *wd->no_fullscreen_w() + // and use *wd->no_fullscreen_w()|h() instead of window->w()|h(). + int trueW = window->w(), trueH = window->h(); + if (!window->fullscreen_active() && *wd->no_fullscreen_w()) { + trueW = *wd->no_fullscreen_w(); trueH = *wd->no_fullscreen_h(); + } + int news = sd->screen_num_unscaled(nx + int(trueW * scale / 2), ny + int(trueH * scale / 2)); if (news == -1) news = olds; float s = sd->scale(news); diff --git a/libraries/fltk/src/Fl_x.cxx b/libraries/fltk/src/Fl_x.cxx index ede3e16083..7d285d0b4a 100644 --- a/libraries/fltk/src/Fl_x.cxx +++ b/libraries/fltk/src/Fl_x.cxx @@ -580,7 +580,6 @@ void open_display_i(Display* d) { fl_XdndStatus = XInternAtom(d, "XdndStatus", 0); fl_XdndActionCopy = XInternAtom(d, "XdndActionCopy", 0); fl_XdndFinished = XInternAtom(d, "XdndFinished", 0); - fl_XdndEnter = XInternAtom(d, "XdndEnter", 0); fl_XdndURIList = XInternAtom(d, "text/uri-list", 0); fl_Xatextplainutf = XInternAtom(d, "text/plain;charset=UTF-8",0); fl_Xatextplainutf2 = XInternAtom(d, "text/plain;charset=utf-8",0); // Firefox/Thunderbird needs this - See STR#2930 @@ -973,6 +972,41 @@ char fl_key_vector[32]; // used by Fl::get_key() static int px, py; static ulong ptime; +// Citation from XButtonEvent and XKeyEvent docs: +// "The state member is set to indicate the logical state of the pointer buttons +// and modifier keys just prior to the event, which is the bitwise inclusive OR +// of one or more of the button or modifier key masks: +// Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask, +// ShiftMask, LockMask, ControlMask, +// Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, and Mod5Mask." +// +// Actual values in Debian Bookworm as of July 2024 (pseudo code): +// static int states[] = { +// ShiftMask, LockMask, ControlMask, // 1<<0 .. 1<<2 +// Mod1Mask, Mod2Mask, Mod3Mask, Mod4Mask, Mod5Mask, // 1<<3 .. 1<<7 +// Button1Mask, Button2Mask, Button3Mask, Button4Mask, Button5Mask // 1<<8 .. 1<<12 +// }; +// +// Note: some more (undefined?) state bits *may* be set if the user uses a keyboard +// other than the primary one (the top-most in keyboard settings). Therefore we must +// take care not to use these undefined bits (found by accident). +// These undefined bits are ignored and not set in Fl::event_state(), otherwise we +// might overwrite other valid bits (since FLTK 1.4.0, Sep 2024 or later). +// See definition of FL_BUTTONS in FL/Enumerations.H: +// there are only five "sticky" mouse buttons as of Sep 27, 2024. + +static unsigned int xbutton_state = 0; // extended button state (back, forward) + +// Define the state bits we're interested in for Fl::event_state(). +// Note that we ignore Button4Mask and Button5Mask (vertical scroll wheel). +// X11 doesn't define masks for Button6 and Button7 (horizontal scroll wheel) +// and any higher button numbers. + +static const unsigned int event_state_mask = + ShiftMask | LockMask | ControlMask | + Mod1Mask | Mod2Mask | Mod3Mask | Mod4Mask | Mod5Mask | + Button1Mask | Button2Mask | Button3Mask; + static void set_event_xy(Fl_Window *win) { # if FLTK_CONSOLIDATE_MOTION send_motion = 0; @@ -985,7 +1019,7 @@ static void set_event_xy(Fl_Window *win) { Fl::e_x = fl_xevent->xbutton.x/s; Fl::e_y_root = fl_xevent->xbutton.y_root/s; Fl::e_y = fl_xevent->xbutton.y/s; - Fl::e_state = fl_xevent->xbutton.state << 16; + Fl::e_state = ((fl_xevent->xbutton.state & event_state_mask) << 16) | xbutton_state; fl_event_time = fl_xevent->xbutton.time; # ifdef __sgi // get the meta key off PC keyboards: @@ -1471,13 +1505,19 @@ int fl_handle(const XEvent& thisevent) } 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 - // immediately 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); + // XA_SECONDARY for that) and send an XdndFinished message. + // This has to be delayed until now rather than sending it immediately + // after calling XConvertSelection because we need to send the success + // status (retval) and the performed action to the sender - at least + // since XDND protocol version 5 (see docs). + // [FIXME: is the condition below really correct?] + + if (fl_xevent->xselection.property == XA_SECONDARY && fl_dnd_source_window) { + fl_sendClientMessage(fl_dnd_source_window, // send to window + fl_XdndFinished, // XdndFinished message + fl_xevent->xselection.requestor, // data.l[0] target window + retval ? 1 : 0, // data.l[1] Bit 0: 1 = success + retval ? fl_dnd_action : None); // data.l[2] action performed fl_dnd_source_window = 0; // don't send a second time } return 1; @@ -1591,22 +1631,22 @@ int fl_handle(const XEvent& thisevent) - data.l[0] contains the XID of the source window. - data.l[1]: Bit 0 is set if the source supports more than three data types. - The high byte contains the protocol version to use (minimum of the source's and + The high byte contains the protocol version to use (minimum of the source's and target's highest supported versions). The rest of the bits are reserved for future use. - data.l[2,3,4] contain the first three types that the source supports. Unused slots are set to None. The ordering is arbitrary. - + If the Source supports more than three data types, bit 0 of data.l[1] is set. This tells the Target to check the property XdndTypeList on the Source window for the list of available types. This property should contain all the available types. - + BUT wayland gnome apps (e.g., gnome-text-editor) set bit 0 of data.l[1] even though their source supports 2 data types (UTF8 text + a gnome-specific type) and put None (==0) in each of data.l[2,3,4]. The same gnome apps run in X11 mode (GDK_BACKEND=x11) clear bit 0 of data.l[1] and support only UTF8 text announced in data.l[2]. FLTK wayland apps set bit 0 of data.l[1] and support only UTF8 text. - + Overall, the correct procedure is if (bit 0 of data.l[1] is set) { get the XdndTypeList property @@ -1988,33 +2028,95 @@ int fl_handle(const XEvent& thisevent) Fl::e_is_click = 0; } break; - case ButtonPress: - Fl::e_keysym = FL_Button + xevent.xbutton.button; + // Mouse button "press" event: + // --------------------------- + // X11 uses special conventions for mouse "button" numbers: + // 1-3: standard mouse buttons left, middle, right in this order + // 4-5: scroll wheel up, down - not reflected in Fl::event_state() + // 6-7: scroll wheel left, right - not reflected in Fl::event_state() + // 8-9: side buttons back, forward - mapped to 4-5, see below + // Since X11 pseudo button numbers 4-7 are useless for Fl::event_state() we map + // real button numbers 8 and 9 to 4 and 5, respectively in FLTK's button numbers + // and in the event state (Fl::event_state()). + // Variable `xbutton_state` is used internally to store the status of the extra + // mouse buttons 4 (back) and 5 (forward) since X11 doesn't keep their status. + + case ButtonPress: { + int mb = xevent.xbutton.button; // mouse button + if (mb < 1 || mb > 9) return 0; // unknown or unsupported button, ignore + + // FIXME(?): here we set some event related variables although we *might* + // ignore an event sent by X because we don't know or want it. This may lead to + // inconsistencies in Fl::event_key(), Fl::event_state() and more (see set_event_xy). + // For now we ignore this fact though, it's likely that it never happens. + // Albrecht, Sep 27, 2024 + + Fl::e_keysym = 0; // init: not used (zero) for scroll wheel events set_event_xy(window); Fl::e_dx = Fl::e_dy = 0; - if (xevent.xbutton.button == Button4 && !Fl::event_shift()) { - Fl::e_dy = -1; // Up + + if (mb == Button4 && !Fl::event_shift()) { + Fl::e_dy = -1; // up event = FL_MOUSEWHEEL; - } else if (xevent.xbutton.button == Button5 && !Fl::event_shift()) { - Fl::e_dy = +1; // Down + } else if (mb == Button5 && !Fl::event_shift()) { + Fl::e_dy = +1; // down event = FL_MOUSEWHEEL; - } else if (xevent.xbutton.button == 6 || (xevent.xbutton.button == Button4 && Fl::event_shift())) { - Fl::e_dx = -1; // Left - event = FL_MOUSEWHEEL; - } else if (xevent.xbutton.button == 7 || (xevent.xbutton.button == Button5 && Fl::event_shift())) { - Fl::e_dx = +1; // Right - event = FL_MOUSEWHEEL; - } else { - Fl::e_state |= (FL_BUTTON1 << (xevent.xbutton.button-1)); + } else if (mb == 6 || (mb == Button4 && Fl::event_shift())) { + Fl::e_dx = -1; // left + event = FL_MOUSEWHEEL; + } else if (mb == 7 || (mb == Button5 && Fl::event_shift())) { + Fl::e_dx = +1; // right + event = FL_MOUSEWHEEL; + } else if (mb < 4 || mb > 7) { // real mouse *buttons*, not scroll wheel + if (mb > 7) // 8 = back, 9 = forward + mb -= 4; // map to 4 and 5, resp. + Fl::e_keysym = FL_Button + mb; + Fl::e_state |= (FL_BUTTON1 << (mb-1)); // set button state + if (mb == 4) xbutton_state |= FL_BUTTON4; // save extra button state internally + if (mb == 5) xbutton_state |= FL_BUTTON5; // save extra button state internally event = FL_PUSH; checkdouble(); + } else { // unknown button or shift combination + return 0; + } + +#if FLTK_CONSOLIDATE_MOTION + fl_xmousewin = window; +#endif // FLTK_CONSOLIDATE_MOTION + in_a_window = true; + break; + } // ButtonPress + + // Mouse button release event: for details see ButtonPress above + + case ButtonRelease: { + int mb = xevent.xbutton.button; // mouse button + switch (mb) { // figure out which real button this is + case 1: // left + case 2: // middle + case 3: // right + break; // continue + case 8: // side button 1 (back) + case 9: // side button 2 (forward) + mb -= 4; // map to 4 and 5, respectively + break; // continue + default: // unknown button or scroll wheel: + return 0; // don't send FL_RELEASE event } + Fl::e_keysym = FL_Button + mb; // == FL_BUTTON1 .. FL_BUTTON5 + set_event_xy(window); + + Fl::e_state &= ~(FL_BUTTON1 << (mb-1)); + if (mb == 4) xbutton_state &= ~FL_BUTTON4; // clear internal button state + if (mb == 5) xbutton_state &= ~FL_BUTTON5; // clear internal button state + event = FL_RELEASE; #if FLTK_CONSOLIDATE_MOTION fl_xmousewin = window; #endif // FLTK_CONSOLIDATE_MOTION in_a_window = true; break; + } // ButtonRelease case PropertyNotify: if (xevent.xproperty.atom == fl_NET_WM_STATE) { @@ -2058,20 +2160,6 @@ int fl_handle(const XEvent& thisevent) break; # endif - case ButtonRelease: - Fl::e_keysym = FL_Button + xevent.xbutton.button; - set_event_xy(window); - Fl::e_state &= ~(FL_BUTTON1 << (xevent.xbutton.button-1)); - if (xevent.xbutton.button == Button4 || - xevent.xbutton.button == Button5) return 0; - event = FL_RELEASE; - -#if FLTK_CONSOLIDATE_MOTION - fl_xmousewin = window; -#endif // FLTK_CONSOLIDATE_MOTION - in_a_window = true; - break; - case EnterNotify: if (xevent.xcrossing.detail == NotifyInferior) break; // XInstallColormap(fl_display, Fl_X::flx(window)->colormap); @@ -2686,7 +2774,7 @@ void Fl_X::make_xid(Fl_Window* win, XVisualInfo *visual, Colormap colormap) } // Make it receptive to DnD: - long version = 4; + Atom version = 5; // max. XDND protocol version we understand XChangeProperty(fl_display, xp->xid, fl_XdndAware, XA_ATOM, sizeof(int)*8, 0, (unsigned char*)&version, 1); diff --git a/libraries/fltk/src/Makefile b/libraries/fltk/src/Makefile index ff151ace5e..2caf49923e 100644 --- a/libraries/fltk/src/Makefile +++ b/libraries/fltk/src/Makefile @@ -853,248 +853,248 @@ install: $(LIBNAME) $(DSONAME) \ $(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) + -$(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); \ + $(INSTALL_LIB) $(GLLIBNAME) "$(DESTDIR)$(libdir)"; \ + $(RANLIB) "$(DESTDIR)$(libdir)/$(GLLIBBASENAME)"; \ fi - $(RANLIB) $(DESTDIR)$(libdir)/$(IMGLIBBASENAME) + $(RANLIB) "$(DESTDIR)$(libdir)/$(IMGLIBBASENAME)" if test x$(DSONAME) = xlibfltk.so.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk.so*;\ - $(INSTALL_LIB) libfltk.so.$(FL_DSO_VERSION) $(DESTDIR)$(libdir); \ - $(LN) libfltk.so.$(FL_DSO_VERSION) $(DESTDIR)$(libdir)/libfltk.so;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk.so*;\ + $(INSTALL_LIB) libfltk.so.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk.so.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)/libfltk.so";\ fi if test x$(DSONAME) = xlibfltk.sl.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk.sl*;\ - $(INSTALL_LIB) libfltk.sl.$(FL_DSO_VERSION) $(DESTDIR)$(libdir); \ - $(LN) libfltk.sl.$(FL_DSO_VERSION) $(DESTDIR)$(libdir)/libfltk.sl;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk.sl*;\ + $(INSTALL_LIB) libfltk.sl.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk.sl.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)/libfltk.sl";\ fi if test x$(DSONAME) = xlibfltk.$(FL_DSO_VERSION).dylib; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk.*dylib;\ - $(INSTALL_LIB) libfltk.$(FL_DSO_VERSION).dylib $(DESTDIR)$(libdir); \ - $(LN) libfltk.$(FL_DSO_VERSION).dylib $(DESTDIR)$(libdir)/libfltk.dylib;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk.*dylib;\ + $(INSTALL_LIB) libfltk.$(FL_DSO_VERSION).dylib "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk.$(FL_DSO_VERSION).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); \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_s.a";\ + $(INSTALL_LIB) libfltk_s.a "$(DESTDIR)$(libdir)"; \ fi if test x$(DSONAME) = xcygfltknox-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(DSONAME);\ - $(INSTALL_LIB) $(DSONAME) $(DESTDIR)$(bindir); \ - $(RM) $(DESTDIR)$(libdir)/libfltk.dll.a;\ - $(INSTALL_LIB) libfltk.dll.a $(DESTDIR)$(libdir); \ + $(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-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(DSONAME);\ - $(INSTALL_LIB) $(DSONAME) $(DESTDIR)$(bindir); \ - $(RM) $(DESTDIR)$(libdir)/libfltk.dll.a;\ - $(INSTALL_LIB) libfltk.dll.a $(DESTDIR)$(libdir); \ + $(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.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_forms.so*;\ - $(INSTALL_LIB) libfltk_forms.so.$(FL_DSO_VERSION) $(DESTDIR)$(libdir); \ - $(LN) libfltk_forms.so.$(FL_DSO_VERSION) $(DESTDIR)$(libdir)/libfltk_forms.so;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_forms.so*;\ + $(INSTALL_LIB) libfltk_forms.so.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk_forms.so.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)/libfltk_forms.so";\ fi if test x$(FLDSONAME) = xlibfltk_forms.sl.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_forms.sl*;\ - $(INSTALL_LIB) libfltk_forms.sl.$(FL_DSO_VERSION) $(DESTDIR)$(libdir); \ - $(LN) libfltk_forms.sl.$(FL_DSO_VERSION) $(DESTDIR)$(libdir)/libfltk_forms.sl;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_forms.sl*;\ + $(INSTALL_LIB) libfltk_forms.sl.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk_forms.sl.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)/libfltk_forms.sl";\ fi if test x$(FLDSONAME) = xlibfltk_forms.$(FL_DSO_VERSION).dylib; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_forms.*dylib;\ - $(INSTALL_LIB) libfltk_forms.$(FL_DSO_VERSION).dylib $(DESTDIR)$(libdir); \ - $(LN) libfltk_forms.$(FL_DSO_VERSION).dylib $(DESTDIR)$(libdir)/libfltk_forms.dylib;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_forms.*dylib;\ + $(INSTALL_LIB) libfltk_forms.$(FL_DSO_VERSION).dylib "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk_forms.$(FL_DSO_VERSION).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); \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_forms_s.a";\ + $(INSTALL_LIB) libfltk_forms_s.a "$(DESTDIR)$(libdir)"; \ fi if test x$(FLDSONAME) = xcygfltknox_forms-$(FL_DSO_VERSION).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); \ + $(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-$(FL_DSO_VERSION).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); \ + $(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.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_gl.so*;\ - $(INSTALL_LIB) libfltk_gl.so.$(FL_DSO_VERSION) $(DESTDIR)$(libdir); \ - $(LN) libfltk_gl.so.$(FL_DSO_VERSION) $(DESTDIR)$(libdir)/libfltk_gl.so;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_gl.so*;\ + $(INSTALL_LIB) libfltk_gl.so.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk_gl.so.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)/libfltk_gl.so";\ fi if test x$(GLDSONAME) = xlibfltk_gl.sl.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_gl.sl*;\ - $(INSTALL_LIB) libfltk_gl.sl.$(FL_DSO_VERSION) $(DESTDIR)$(libdir); \ - $(LN) libfltk_gl.sl.$(FL_DSO_VERSION) $(DESTDIR)$(libdir)/libfltk_gl.sl;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_gl.sl*;\ + $(INSTALL_LIB) libfltk_gl.sl.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk_gl.sl.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)/libfltk_gl.sl";\ fi if test x$(GLDSONAME) = xlibfltk_gl.$(FL_DSO_VERSION).dylib; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_gl.*dylib;\ - $(INSTALL_LIB) libfltk_gl.$(FL_DSO_VERSION).dylib $(DESTDIR)$(libdir); \ - $(LN) libfltk_gl.$(FL_DSO_VERSION).dylib $(DESTDIR)$(libdir)/libfltk_gl.dylib;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_gl.*dylib;\ + $(INSTALL_LIB) libfltk_gl.$(FL_DSO_VERSION).dylib "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk_gl.$(FL_DSO_VERSION).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); \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_gl_s.a";\ + $(INSTALL_LIB) libfltk_gl_s.a "$(DESTDIR)$(libdir)"; \ fi if test x$(GLDSONAME) = xcygfltknox_gl-$(FL_DSO_VERSION).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); \ + $(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-$(FL_DSO_VERSION).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); \ + $(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.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_images.so*;\ - $(INSTALL_LIB) libfltk_images.so.$(FL_DSO_VERSION) $(DESTDIR)$(libdir); \ - $(LN) libfltk_images.so.$(FL_DSO_VERSION) $(DESTDIR)$(libdir)/libfltk_images.so;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_images.so*;\ + $(INSTALL_LIB) libfltk_images.so.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk_images.so.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)/libfltk_images.so";\ fi if test x$(IMGDSONAME) = xlibfltk_images.sl.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_images.sl*;\ - $(INSTALL_LIB) libfltk_images.sl.$(FL_DSO_VERSION) $(DESTDIR)$(libdir); \ - $(LN) libfltk_images.sl.$(FL_DSO_VERSION) $(DESTDIR)$(libdir)/libfltk_images.sl;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_images.sl*;\ + $(INSTALL_LIB) libfltk_images.sl.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk_images.sl.$(FL_DSO_VERSION) "$(DESTDIR)$(libdir)/libfltk_images.sl";\ fi if test x$(IMGDSONAME) = xlibfltk_images.$(FL_DSO_VERSION).dylib; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_images.*dylib;\ - $(INSTALL_LIB) libfltk_images.$(FL_DSO_VERSION).dylib $(DESTDIR)$(libdir); \ - $(LN) libfltk_images.$(FL_DSO_VERSION).dylib $(DESTDIR)$(libdir)/libfltk_images.dylib;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_images.*dylib;\ + $(INSTALL_LIB) libfltk_images.$(FL_DSO_VERSION).dylib "$(DESTDIR)$(libdir)"; \ + $(LN) libfltk_images.$(FL_DSO_VERSION).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); \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_images_s.a";\ + $(INSTALL_LIB) libfltk_images_s.a "$(DESTDIR)$(libdir)"; \ fi if test x$(IMGDSONAME) = xcygfltknox_images-$(FL_DSO_VERSION).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); \ + $(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-$(FL_DSO_VERSION).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); \ + $(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) + $(RM) "$(DESTDIR)$(libdir)/$(LIBBASENAME)" if test x$(DSONAME) = xlibfltk.so.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk.so*;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk.so*;\ fi if test x$(DSONAME) = xlibfltk.sl.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk.sl*;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk.sl*;\ fi if test x$(DSONAME) = xlibfltk.$(FL_DSO_VERSION).dylib; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk.*dylib;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk.*dylib;\ fi if test x$(DSONAME) = xlibfltk_s.a; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_s.a;\ + $(RM) "$(DESTDIR)$(libdir)/libfltk_s.a";\ fi if test x$(DSONAME) = xcygfltknox-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(DSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(DSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk.dll.a";\ fi if test x$(DSONAME) = xcygfltk-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(DSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(DSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk.dll.a";\ fi if test x$(DSONAME) = xmgwfltknox-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(DSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(DSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk.dll.a";\ fi - $(RM) $(DESTDIR)$(libdir)/$(FLLIBBASENAME); + $(RM) "$(DESTDIR)$(libdir)/$(FLLIBBASENAME)"; if test x$(FLDSONAME) = xlibfltk_forms.so.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_forms.so*;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_forms.so*;\ fi if test x$(FLDSONAME) = xlibfltk_forms.sl.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_forms.sl*;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_forms.sl*;\ fi if test x$(FLDSONAME) = xlibfltk_forms.$(FL_DSO_VERSION).dylib; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_forms.*dylib;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_forms.*dylib;\ fi if test x$(FLDSONAME) = xlibfltk_forms_s.a; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_forms_s.a;\ + $(RM) "$(DESTDIR)$(libdir)/libfltk_forms_s.a";\ fi if test x$(FLDSONAME) = xcygfltknox_forms-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(FLDSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk_forms.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(FLDSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_forms.dll.a";\ fi if test x$(FLDSONAME) = xcygfltk_forms-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(FLDSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk_forms.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(FLDSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_forms.dll.a";\ fi if test x$(FLDSONAME) = xmgwfltknox_forms-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(FLDSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk_forms.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(FLDSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_forms.dll.a";\ fi if test x$(GLLIBNAME) != x; then\ - $(RM) $(DESTDIR)$(libdir)/$(GLLIBBASENAME);\ + $(RM) "$(DESTDIR)$(libdir)/$(GLLIBBASENAME)";\ fi if test x$(GLDSONAME) = xlibfltk_gl.so.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_gl.so*;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_gl.so*;\ fi if test x$(GLDSONAME) = xlibfltk_gl.sl.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_gl.sl*;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_gl.sl*;\ fi if test x$(GLDSONAME) = xlibfltk_gl.$(FL_DSO_VERSION).dylib; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_gl.*dylib;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_gl.*dylib;\ fi if test x$(GLDSONAME) = xlibfltk_gl_s.a; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_gl_s.a;\ + $(RM) "$(DESTDIR)$(libdir)/libfltk_gl_s.a";\ fi if test x$(GLDSONAME) = xcygfltknox_gl-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(GLDSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk_gl.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(GLDSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_gl.dll.a";\ fi if test x$(GLDSONAME) = xcygfltk_gl-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(GLDSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk_gl.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(GLDSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_gl.dll.a";\ fi if test x$(GLDSONAME) = xmgwfltknox_gl-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(GLDSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk_gl.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(GLDSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_gl.dll.a";\ fi if test x$(IMGLIBNAME) != x; then\ - $(RM) $(DESTDIR)$(libdir)/$(IMGLIBBASENAME);\ + $(RM) "$(DESTDIR)$(libdir)/$(IMGLIBBASENAME)";\ fi if test x$(IMGDSONAME) = xlibfltk_images.so.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_images.so*;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_images.so*;\ fi if test x$(IMGDSONAME) = xlibfltk_images.sl.$(FL_DSO_VERSION); then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_images.sl*;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_images.sl*;\ fi if test x$(IMGDSONAME) = xlibfltk_images.$(FL_DSO_VERSION).dylib; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_images.*dylib;\ + $(RM) "$(DESTDIR)$(libdir)"/libfltk_images.*dylib;\ fi if test x$(IMGDSONAME) = xlibfltk_images_s.a; then\ - $(RM) $(DESTDIR)$(libdir)/libfltk_images_s.a;\ + $(RM) "$(DESTDIR)$(libdir)/libfltk_images_s.a";\ fi if test x$(IMGDSONAME) = xcygfltknox_images-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(IMGDSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk_images.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(IMGDSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_images.dll.a";\ fi if test x$(IMGDSONAME) = xcygfltk_images-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(IMGDSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk_images.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(IMGDSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_images.dll.a";\ fi if test x$(IMGDSONAME) = xmgwfltknox_images-$(FL_DSO_VERSION).dll; then\ - $(RM) $(DESTDIR)$(bindir)/$(IMGDSONAME); \ - $(RM) $(DESTDIR)$(libdir)/libfltk_images.dll.a;\ + $(RM) "$(DESTDIR)$(bindir)/$(IMGDSONAME)"; \ + $(RM) "$(DESTDIR)$(libdir)/libfltk_images.dll.a";\ fi diff --git a/libraries/fltk/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H b/libraries/fltk/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H index ffbb0308b0..5045790cc9 100644 --- a/libraries/fltk/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H +++ b/libraries/fltk/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.H @@ -49,6 +49,7 @@ protected: cairo_t *cairo_; PangoContext *pango_context_; PangoLayout *pango_layout_; + static Fl_Font font_count_; public: Fl_Cairo_Graphics_Driver(); ~Fl_Cairo_Graphics_Driver() FL_OVERRIDE; @@ -65,6 +66,7 @@ public: PangoLayout *pango_layout() {return pango_layout_;} void set_cairo(cairo_t *c, float f = 0); static cairo_pattern_t *calc_cairo_mask(const Fl_RGB_Image *rgb); + static const char *clean_utf8(const char* str, int &n); void check_status(void); @@ -123,7 +125,6 @@ public: void restore_clip() FL_OVERRIDE; int not_clipped(int x, int y, int w, int h) FL_OVERRIDE; - void begin_points() FL_OVERRIDE; void begin_line() FL_OVERRIDE; void begin_loop() FL_OVERRIDE; void begin_polygon() FL_OVERRIDE; diff --git a/libraries/fltk/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx b/libraries/fltk/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx index 4a6d9e6872..3d8774fe1e 100644 --- a/libraries/fltk/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx +++ b/libraries/fltk/src/drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx @@ -64,6 +64,9 @@ static Fl_Fontdesc built_in_table[] = { FL_EXPORT Fl_Fontdesc *fl_fonts = built_in_table; +// Number of fonts found by Fl::set_fonts(char*) beyond FL_FREE_FONT +// -1 denotes "not yet initialised" +Fl_Font Fl_Cairo_Graphics_Driver::font_count_ = -1; // duplicated from Fl_PostScript.cxx struct callback_data { @@ -423,13 +426,6 @@ void Fl_Cairo_Graphics_Driver::reconcat(){ cairo_transform(cairo_, &mat); } -void Fl_Cairo_Graphics_Driver::begin_points() { - cairo_save(cairo_); - concat(); - cairo_new_path(cairo_); - gap_=1; - what=POINTS; -} void Fl_Cairo_Graphics_Driver::begin_line() { cairo_save(cairo_); @@ -457,11 +453,7 @@ void Fl_Cairo_Graphics_Driver::begin_polygon() { void Fl_Cairo_Graphics_Driver::vertex(double x, double y) { if (what==POINTS){ - cairo_move_to(cairo_, x, y); - cairo_rectangle(cairo_, x-0.5, y-0.5, 1, 1); - cairo_fill(cairo_); - gap_=1; - return; + return Fl_Graphics_Driver::vertex(x, y); } if (gap_){ cairo_move_to(cairo_, x, y); @@ -538,7 +530,9 @@ void Fl_Cairo_Graphics_Driver::pie(int x, int y, int w, int h, double a1, double } void Fl_Cairo_Graphics_Driver::end_points() { - end_line(); + for (int i = 0; i < n; i++) { + point(xpoint[i].x, xpoint[i].y); + } } void Fl_Cairo_Graphics_Driver::end_line() { @@ -572,9 +566,7 @@ void Fl_Cairo_Graphics_Driver::end_polygon() { void Fl_Cairo_Graphics_Driver::transformed_vertex(double x, double y) { if (what == POINTS) { - cairo_move_to(cairo_, x, y); - point(x, y); - gap_ = 1; + Fl_Graphics_Driver::transformed_vertex(x, y); } else { reconcat(); if (gap_) { @@ -675,7 +667,6 @@ void Fl_Cairo_Graphics_Driver::draw_image_mono(const uchar *data, int ix, int iy struct callback_data cb_data; const size_t aD = abs(D); if (!LD) LD = iw * aD; - if (D<0) data += iw * aD; cb_data.data = data; cb_data.D = D; cb_data.LD = LD; @@ -748,7 +739,6 @@ void Fl_Cairo_Graphics_Driver::draw_image(const uchar *data, int ix, int iy, int } struct callback_data cb_data; if (!LD) LD = iw*abs(D); - if (D<0) data += iw*abs(D); cb_data.data = data; cb_data.D = D; cb_data.LD = LD; @@ -799,8 +789,10 @@ void Fl_Cairo_Graphics_Driver::draw_cached_pattern_(Fl_Image *img, cairo_pattern cairo_save(cairo_); bool need_extend = (cache_w != Ws || cache_h != Hs || (W >= 2 && H >= 2)); if (need_extend || cx || cy || W < img->w() || H < img->h()) { // clip when necessary - cairo_rectangle(cairo_, X - 0.5, Y - 0.5, W + 0.5, H + 0.5); + cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_NONE); + cairo_rectangle(cairo_, X - 0.5, Y - 0.5, W, H); cairo_clip(cairo_); + cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_DEFAULT); } // remove any scaling and the current "0.5" translation useful for lines but bad for images matrix.xx = matrix.yy = 1; @@ -1103,6 +1095,9 @@ static int font_sort(Fl_Fontdesc *fa, Fl_Fontdesc *fb) { Fl_Font Fl_Cairo_Graphics_Driver::set_fonts(const char* /*pattern_name*/) { + // Return immideatly if the fonts were already counted + if (font_count_ != -1) + return FL_FREE_FONT + font_count_; fl_open_display(); int n_families, count = 0; PangoFontFamily **families; @@ -1147,6 +1142,7 @@ Fl_Font Fl_Cairo_Graphics_Driver::set_fonts(const char* /*pattern_name*/) } // Sort the list into alphabetic order qsort(fl_fonts + FL_FREE_FONT, count, sizeof(Fl_Fontdesc), (sort_f_type)font_sort); + font_count_ = count; return FL_FREE_FONT + count; } @@ -1302,11 +1298,50 @@ void Fl_Cairo_Graphics_Driver::font(Fl_Font fnum, Fl_Fontsize s) { } +// Scans the input string str with fl_utf8decode() that, by default, accepts +// also non-UTF-8 and processes it as if encoded in CP1252. +// Returns a true UTF-8 string and its length, possibly transformed from CP1252. +// If the input string is true UTF-8, the returned string is the same pointer as input. +// Otherwise, the returned string is in private memory allocated inside clean_utf8() +// and extended when necessary. +const char *Fl_Cairo_Graphics_Driver::clean_utf8(const char* str, int &n) { + static char *utf8_buffer = NULL; + static int utf8_buffer_len = 0; + char *q = utf8_buffer; + const char *p = str; + const char *retval = str; + int len, len2; + const char *end = str + n; + char buf4[4]; + while (p < end) { + unsigned codepoint = fl_utf8decode(p, end, &len); + if (retval != str || (len == 1 && *(uchar*)p >= 0x80)) { // switch to using utf8_buffer + len2 = fl_utf8encode(codepoint, buf4); + if (!utf8_buffer_len || utf8_buffer_len < (q - utf8_buffer) + len2) { + utf8_buffer_len += (q - utf8_buffer) + len2 + 1000; + utf8_buffer = (char *)realloc(utf8_buffer, utf8_buffer_len); + } + if (retval == str) { + retval = utf8_buffer; + q = utf8_buffer; + if (p > str) { memcpy(q, str, p - str); q += (p - str); } + } + memcpy(q, buf4, len2); + q += len2; + } + p += len; + } + if (retval != str) n = q - retval; + return retval; +} + + void Fl_Cairo_Graphics_Driver::draw(const char* str, int n, float x, float y) { if (!n) return; cairo_save(cairo_); Fl_Cairo_Font_Descriptor *fd = (Fl_Cairo_Font_Descriptor*)font_descriptor(); cairo_translate(cairo_, x - 1, y - (fd->line_height - fd->descent) / float(PANGO_SCALE) - 1); + str = clean_utf8(str, n); pango_layout_set_text(pango_layout_, str, n); pango_cairo_show_layout(cairo_, pango_layout_); // 1.1O cairo_restore(cairo_); @@ -1374,6 +1409,7 @@ double Fl_Cairo_Graphics_Driver::width(const char* str, int n) { int Fl_Cairo_Graphics_Driver::do_width_unscaled_(const char* str, int n) { if (!n) return 0; + str = clean_utf8(str, n); pango_layout_set_text(pango_layout_, str, n); PangoRectangle p_rect; pango_layout_get_extents(pango_layout_, NULL, &p_rect); @@ -1382,6 +1418,7 @@ int Fl_Cairo_Graphics_Driver::do_width_unscaled_(const char* str, int n) { void Fl_Cairo_Graphics_Driver::text_extents(const char* txt, int n, int& dx, int& dy, int& w, int& h) { + txt = clean_utf8(txt, n); pango_layout_set_text(pango_layout_, txt, n); PangoRectangle ink_rect; pango_layout_get_extents(pango_layout_, &ink_rect, NULL); @@ -1438,7 +1475,9 @@ void Fl_Cairo_Graphics_Driver::restore_clip() { clip_->y = rect.y; clip_->w = rect.width; clip_->h = rect.height; + cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_NONE); cairo_clip(cairo_); + cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_DEFAULT ); } else if (clip_) { clip_->w = -1; } diff --git a/libraries/fltk/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H b/libraries/fltk/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H index 3c47c49c96..ef57a4607c 100644 --- a/libraries/fltk/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H +++ b/libraries/fltk/src/drivers/Cocoa/Fl_Cocoa_Window_Driver.H @@ -37,6 +37,7 @@ class Fl_Window; @class NSOpenGLContext; @class NSOpenGLPixelFormat; @class NSView; +@class NSWindow; #else class CALayer; class NSCursor; @@ -45,6 +46,7 @@ class FLWindow; class NSOpenGLContext; class NSOpenGLPixelFormat; class NSView; +class NSWindow; #endif // __OBJC__ /** @@ -95,6 +97,7 @@ public: NSCursor *cursor; static void q_release_context(Fl_Cocoa_Window_Driver *x = 0); // free all resources associated with gc static void clip_to_rounded_corners(CGContextRef gc, int w, int h); + static CGImageRef capture_decorated_window_10_6(NSWindow *nswin); void set_key_window(); bool mapped_to_retina(); // is window mapped to retina display? void mapped_to_retina(bool); // sets whether window is mapped to retina display diff --git a/libraries/fltk/src/drivers/Darwin/Fl_Darwin_System_Driver.H b/libraries/fltk/src/drivers/Darwin/Fl_Darwin_System_Driver.H index 776f687385..011bea7fff 100644 --- a/libraries/fltk/src/drivers/Darwin/Fl_Darwin_System_Driver.H +++ b/libraries/fltk/src/drivers/Darwin/Fl_Darwin_System_Driver.H @@ -64,10 +64,7 @@ public: const char *latin1_to_local(const char *t, int n) FL_OVERRIDE; const char *local_to_mac_roman(const char *t, int n) FL_OVERRIDE; const char *mac_roman_to_local(const char *t, int n) FL_OVERRIDE; - Fl_Pixmap *tree_openpixmap() FL_OVERRIDE; - static const char * const tree_open_xpm_darwin[]; // used by tree_openpixmap() - Fl_Pixmap *tree_closepixmap() FL_OVERRIDE; - static const char * const tree_close_xpm_darwin[]; // used by tree_closepixmap() + void tree_draw_expando_button(int x, int y, bool state, bool active) FL_OVERRIDE; int tree_connector_style() FL_OVERRIDE; const char *filename_name(const char *buf) FL_OVERRIDE; void add_fd(int fd, int when, Fl_FD_Handler cb, void* = 0) FL_OVERRIDE; diff --git a/libraries/fltk/src/drivers/Darwin/Fl_Darwin_System_Driver.cxx b/libraries/fltk/src/drivers/Darwin/Fl_Darwin_System_Driver.cxx index c44ba34c16..9b6a2a694d 100644 --- a/libraries/fltk/src/drivers/Darwin/Fl_Darwin_System_Driver.cxx +++ b/libraries/fltk/src/drivers/Darwin/Fl_Darwin_System_Driver.cxx @@ -21,6 +21,7 @@ #include #include #include +#include #include "../../flstring.h" #include #if MAC_OS_X_VERSION_MAX_ALLOWED >= MAC_OS_X_VERSION_10_4 @@ -357,50 +358,12 @@ Fl_Sys_Menu_Bar_Driver *Fl_Darwin_System_Driver::sys_menu_bar_driver() return Fl_MacOS_Sys_Menu_Bar_Driver::driver(); } -const char * const Fl_Darwin_System_Driver::tree_open_xpm_darwin[] = { - "11 11 2 1", - ". c None", - "@ c #000000", - "...@.......", - "...@@......", - "...@@@.....", - "...@@@@....", - "...@@@@@...", - "...@@@@@@..", - "...@@@@@...", - "...@@@@....", - "...@@@.....", - "...@@......", - "...@......." -}; - -const char * const Fl_Darwin_System_Driver::tree_close_xpm_darwin[] = { - "11 11 2 1", - ". c None", - "@ c #000000", - "...........", - "...........", - "...........", - "@@@@@@@@@@@", - ".@@@@@@@@@.", - "..@@@@@@@..", - "...@@@@@...", - "....@@@....", - ".....@.....", - "...........", - "..........." -}; - -Fl_Pixmap *Fl_Darwin_System_Driver::tree_openpixmap() { - static Fl_Pixmap *pixmap = new Fl_Pixmap(tree_open_xpm_darwin); - return pixmap; +// Draw Mac-specific Fl_Tree open/close icons +void Fl_Darwin_System_Driver::tree_draw_expando_button(int x, int y, bool state, bool active) { + fl_color(active ? FL_FOREGROUND_COLOR : FL_INACTIVE_COLOR); + if(state) fl_polygon(x + 3, y, x + 3, y + 11, x + 8, y + 5); // right arrow: ▶ + else fl_polygon(x, y + 3, x + 11, y + 3, x + 5, y + 8); // down arrow: ▼ } - -Fl_Pixmap *Fl_Darwin_System_Driver::tree_closepixmap() { - static Fl_Pixmap *pixmap = new Fl_Pixmap(tree_close_xpm_darwin); - return pixmap; -} - int Fl_Darwin_System_Driver::tree_connector_style() { return FL_TREE_CONNECTOR_NONE; } diff --git a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver.H b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver.H index 03371c8c43..c3449f1c94 100644 --- a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver.H +++ b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver.H @@ -60,6 +60,8 @@ protected: uchar *mask_bitmap_; uchar **mask_bitmap() FL_OVERRIDE {return &mask_bitmap_;} POINT *long_point; + bool is_solid_; + int style_; public: Fl_GDI_Graphics_Driver(); ~Fl_GDI_Graphics_Driver() FL_OVERRIDE; @@ -109,6 +111,7 @@ protected: void fixloop() FL_OVERRIDE; void point(int x, int y) FL_OVERRIDE; void focus_rect(int x, int y, int w, int h) FL_OVERRIDE; + void rect_unscaled(int x, int y, int w, int h) FL_OVERRIDE; void rectf_unscaled(int x, int y, int w, int h) FL_OVERRIDE; #if USE_COLORMAP void colored_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) FL_OVERRIDE; diff --git a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx index fac835d5f2..a7825e8215 100644 --- a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx +++ b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver.cxx @@ -96,6 +96,8 @@ Fl_GDI_Graphics_Driver::Fl_GDI_Graphics_Driver() { long_point = NULL; depth = -1; origins = NULL; + is_solid_ = true; + style_ = FL_SOLID; } Fl_GDI_Graphics_Driver::~Fl_GDI_Graphics_Driver() { diff --git a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx index 22f6d6d32a..3a8e706899 100644 --- a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx +++ b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_image.cxx @@ -1,7 +1,7 @@ // // Windows image drawing code for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2020 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -128,43 +128,44 @@ static void innards(const uchar *buf, int X, int Y, int W, int 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; + // bmibuffer: BITMAPINFOHEADER + 256 colors (RGBQUAD) + 1 (rounding effects ?) + static U32 bmibuffer[sizeof(BITMAPINFOHEADER)/4 + 257]; + BITMAPINFO *bmi = (BITMAPINFO*)bmibuffer; + if (!bmi->bmiHeader.biSize) { + bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); + 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; + *((short*)(bmi->bmiColors)+i) = i; } } else #endif if (depth<3) { - RGBQUAD *bmi_colors = &bmi.bmiColors[0]; // suppress warning (STR #3199) + RGBQUAD *bmi_colors = &(bmi->bmiColors[0]); // use pointer to suppress warning (STR #3199) for (int i=0; i<256; i++) { - bmi_colors[i].rgbBlue = (uchar)i; // bmi.bmiColors[i]... + bmi_colors[i].rgbBlue = (uchar)i; // = bmi->bmiColors[i] bmi_colors[i].rgbGreen = (uchar)i; bmi_colors[i].rgbRed = (uchar)i; bmi_colors[i].rgbReserved = (uchar)0; // must be zero } } - bmi.bmiHeader.biWidth = w; + bmi->bmiHeader.biWidth = w; #if USE_COLORMAP - bmi.bmiHeader.biBitCount = indexed ? 8 : depth*8; + bmi->bmiHeader.biBitCount = indexed ? 8 : depth*8; int pixelsize = indexed ? 1 : depth; #else - bmi.bmiHeader.biBitCount = depth*8; + bmi->bmiHeader.biBitCount = depth*8; int pixelsize = depth; #endif if (depth==2) { // special case: gray with alpha - bmi.bmiHeader.biBitCount = 32; + bmi->bmiHeader.biBitCount = 32; pixelsize = 4; } int linesize = (pixelsize*w+3)&~3; @@ -172,18 +173,20 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, static U32* buffer; static long buffer_size; int blocking = h; - {int size = linesize*h; - // when printing, don't limit buffer size not to get a crash in StretchDIBits - if (size > MAXBUFFER && !fl_graphics_driver->has_feature(Fl_Graphics_Driver::PRINTER)) { - size = MAXBUFFER; - blocking = MAXBUFFER/linesize; - } - if (size > buffer_size) { - delete[] buffer; - buffer_size = size; - buffer = new U32[(size+3)/4]; - }} - bmi.bmiHeader.biHeight = blocking; + { + int size = linesize * h; + // when printing, don't limit buffer size not to get a crash in StretchDIBits + if (size > MAXBUFFER && !fl_graphics_driver->has_feature(Fl_Graphics_Driver::PRINTER)) { + size = MAXBUFFER; + blocking = MAXBUFFER / linesize; + } + 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; @@ -212,7 +215,6 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, monodither(to, from, w, delta); else dither(to, from, w, delta); - to += w; } else #endif { @@ -251,13 +253,14 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, break; } } - } + } // for (k = 0; jhas_feature(Fl_Graphics_Driver::PRINTER)) { // if print context, device and logical units are not equal, so SetDIBitsToDevice // does not do the expected job, whereas StretchDIBits does it. StretchDIBits(gc, x, y+j-k, w, k, 0, 0, w, k, (LPSTR)((uchar*)buffer+(blocking-k)*linesize), - &bmi, + bmi, #if USE_COLORMAP indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS #else @@ -271,15 +274,15 @@ static void innards(const uchar *buf, int X, int Y, int W, int H, else { SetDIBitsToDevice(gc, x, y+j-k, w, k, 0, 0, 0, k, (LPSTR)((uchar*)buffer+(blocking-k)*linesize), - &bmi, + bmi, #if USE_COLORMAP indexed ? DIB_PAL_COLORS : DIB_RGB_COLORS #else DIB_RGB_COLORS #endif ); - } - } + } + } // for (int j=0; jd() % 2) == 0 ) { alpha_blend_(this->floor(XP), this->floor(YP), WP, HP, new_gc, 0, 0, rgb->data_w(), rgb->data_h()); } else { - SetStretchBltMode(gc_, HALFTONE); + SetStretchBltMode(gc_, (Fl_Image::scaling_algorithm() == FL_RGB_SCALING_BILINEAR ? HALFTONE : BLACKONWHITE)); StretchBlt(gc_, this->floor(XP), this->floor(YP), WP, HP, new_gc, 0, 0, rgb->data_w(), rgb->data_h(), SRCCOPY); } RestoreDC(new_gc, save); diff --git a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx index 8e56a7cc18..8b2eb47fbd 100644 --- a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx +++ b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_line_style.cxx @@ -58,6 +58,8 @@ void Fl_GDI_Graphics_Driver::line_style_unscaled(int style, int width, char* das DeleteObject(oldpen); DeleteObject(fl_current_xmap->pen); fl_current_xmap->pen = newpen; + is_solid_ = ((style & 0xff) == FL_SOLID && (!dashes || !*dashes)); + style_ = style; } #if USE_GDIPLUS diff --git a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx index 1b13ff0a9b..a86242e126 100644 --- a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx +++ b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_rect.cxx @@ -61,6 +61,21 @@ void Fl_GDI_Graphics_Driver::focus_rect(int x, int y, int w, int h) { for (yy = h; yy > 0; yy--, i++) if (i & 1) SetPixel(gc_, x, y+yy, c); } +void Fl_GDI_Graphics_Driver::rect_unscaled(int x, int y, int w, int h) { + if (is_solid_ && line_width_ > 1) { + line_style_unscaled(FL_CAP_SQUARE, line_width_, 0); // see issue #1052 + } + MoveToEx(gc_, x, y, 0L); + LineTo(gc_, x+w, y); + if (is_solid_ && line_width_ <= 1) LineTo(gc_, x+w, y+h+1); // see issue #1052 + LineTo(gc_, x+w, y+h); + LineTo(gc_, x, y+h); + LineTo(gc_, x, y); + if (is_solid_ && line_width_ > 1) { + line_style_unscaled(style_, line_width_, 0); + } +} + void Fl_GDI_Graphics_Driver::rectf_unscaled(int x, int y, int w, int h) { RECT rect; rect.left = x; rect.top = y; diff --git a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx index 441bddd70c..e469bb11b5 100644 --- a/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx +++ b/libraries/fltk/src/drivers/GDI/Fl_GDI_Graphics_Driver_vertex.cxx @@ -141,7 +141,7 @@ void Fl_GDIplus_Graphics_Driver::end_line() { void Fl_GDIplus_Graphics_Driver::end_loop() { if (!active) return Fl_GDI_Graphics_Driver::end_loop(); fixloop(); - if (n>2) { + if (n >= 2) { Gdiplus::GraphicsPath path; Gdiplus::Point *gdi2_p = new Gdiplus::Point[n]; for (int i = 0; i < n; i++) { diff --git a/libraries/fltk/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx b/libraries/fltk/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx index eff6ab5ec8..b8168c80c5 100644 --- a/libraries/fltk/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx +++ b/libraries/fltk/src/drivers/Posix/Fl_Posix_Printer_Driver.cxx @@ -43,8 +43,11 @@ class Fl_Posix_Printer_Driver : public Fl_PostScript_File_Device { #define GTK_PAPER_NAME_JB5 "jis_b5" #define GTK_PAPER_NAME_TABLOID "na_ledger" #define GTK_PAPER_NAME_DLE "iso_dl" -#define GTK_RESPONSE_NONE 0 +#define GTK_RESPONSE_NONE -1 +#define GTK_RESPONSE_REJECT -2 #define GTK_RESPONSE_OK -5 +#define GTK_RESPONSE_CANCEL -6 +#define GTK_RESPONSE_DELETE_EVENT -4 #define GTK_PRINT_PAGES_RANGES 2 class Fl_GTK_Printer_Driver : public Fl_PostScript_File_Device { public: @@ -195,7 +198,7 @@ int Fl_GTK_Printer_Driver::begin_job(int pagecount, int *firstpage, int *lastpag Fl_PostScript_File_Device::begin_job(output, 0, format, layout); response_id = GTK_RESPONSE_OK; } else { - response_id = GTK_RESPONSE_NONE + GTK_RESPONSE_OK + 1; + response_id = GTK_RESPONSE_REJECT; if (perr_message) { *perr_message = new char[strlen(line)+50]; snprintf(*perr_message, strlen(line)+50, "Can't open output file %s", line); @@ -211,7 +214,7 @@ int Fl_GTK_Printer_Driver::begin_job(int pagecount, int *firstpage, int *lastpag pjob = CALL_GTK(gtk_print_job_new)("FLTK print job", gprinter, psettings, psetup); //2.10 response_id = GTK_RESPONSE_OK; } else { - response_id = GTK_RESPONSE_NONE + GTK_RESPONSE_OK + 1; + response_id = GTK_RESPONSE_REJECT; if (perr_message) { *perr_message = new char[strlen(tmpfilename)+50]; snprintf(*perr_message, strlen(tmpfilename)+50, "Can't create temporary file %s", tmpfilename); @@ -231,7 +234,9 @@ int Fl_GTK_Printer_Driver::begin_job(int pagecount, int *firstpage, int *lastpag while (Fl::ready()) Fl::check(); Fl_Surface_Device::pop_current(); } - return (response_id == GTK_RESPONSE_OK ? 0 : (response_id == GTK_RESPONSE_NONE ? 1 : 2)); + if (response_id == GTK_RESPONSE_OK) return 0; + if (response_id == GTK_RESPONSE_CANCEL || response_id == GTK_RESPONSE_DELETE_EVENT) return 1; + return 2; } static void pJobCompleteFunc(Fl_GTK_Printer_Driver::GtkPrintJob *print_job, Fl_GTK_Printer_Driver::gboolean *user_data, const Fl_GTK_Printer_Driver::GError *error) { diff --git a/libraries/fltk/src/drivers/PostScript/Fl_PostScript.cxx b/libraries/fltk/src/drivers/PostScript/Fl_PostScript.cxx index 3b81789d0d..324d1c6f9f 100644 --- a/libraries/fltk/src/drivers/PostScript/Fl_PostScript.cxx +++ b/libraries/fltk/src/drivers/PostScript/Fl_PostScript.cxx @@ -1572,6 +1572,7 @@ void Fl_PostScript_Graphics_Driver::transformed_draw(const char* str, int n, dou pango_layout_set_font_description(pango_layout_, pfd); int pwidth, pheight; cairo_save(cairo_); + str = Fl_Cairo_Graphics_Driver::clean_utf8(str, n); pango_layout_set_text(pango_layout_, str, n); pango_layout_get_size(pango_layout_, &pwidth, &pheight); if (pwidth > 0) { @@ -1645,7 +1646,7 @@ static int update_format_layout(int rank, Fl_Paged_Device::Page_Layout layout, }); FL_INLINE_CALLBACK_2( modal, Fl_Window*, win, modal, Fl_Check_Button*, check_but, default_size, - { + { *((bool*)check_but->user_data()) = check_but->value(); win->hide(); } ); @@ -1676,7 +1677,7 @@ static int update_format_layout(int rank, Fl_Paged_Device::Page_Layout layout, int Fl_PDF_Pango_File_Surface::begin_job(const char *defaultname, char **perr_message) { static Page_Layout layout = PORTRAIT; - + Fl_Preferences print_prefs(Fl_Preferences::CORE_USER, "fltk.org", "printers"); char *pref_format; print_prefs.get("PDF/page_size", pref_format, "A4"); diff --git a/libraries/fltk/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx b/libraries/fltk/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx index 71daf0e100..234853ad67 100644 --- a/libraries/fltk/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx +++ b/libraries/fltk/src/drivers/Quartz/Fl_Quartz_Graphics_Driver_rect.cxx @@ -37,10 +37,9 @@ void Fl_Quartz_Graphics_Driver::point(int x, int y) { void Fl_Quartz_Graphics_Driver::rect(int x, int y, int w, int h) { if (w<=0 || h<=0) return; - if ( (!has_feature(PRINTER)) && quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, true); - CGRect rect = CGRectMake(x, y, w-1, h-1); + double offset = (quartz_line_width_ >= 2 ? quartz_line_width_/4 : 0); + CGRect rect = CGRectMake(x - offset, y - offset, w-1, h-1); CGContextStrokeRect(gc_, rect); - if ( (!has_feature(PRINTER)) && quartz_line_width_ > 1.5f) CGContextSetShouldAntialias(gc_, false); } void Fl_Quartz_Graphics_Driver::focus_rect(int x, int y, int w, int h) diff --git a/libraries/fltk/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx b/libraries/fltk/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx index 00fc63150e..5091f894bf 100644 --- a/libraries/fltk/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx +++ b/libraries/fltk/src/drivers/Quartz/Fl_Quartz_Image_Surface_Driver.cxx @@ -31,7 +31,8 @@ Fl_Quartz_Image_Surface_Driver::Fl_Quartz_Image_Surface_Driver(int w, int h, int if (high_res) { s = Fl_Graphics_Driver::default_driver().scale(); Fl_Window *cw = Fl_Window::current(); - if (cw && Fl_Cocoa_Window_Driver::driver(cw)->mapped_to_retina()) s *= 2; + Fl_Cocoa_Window_Driver *dr = cw ? Fl_Cocoa_Window_Driver::driver(cw) : NULL; + if (dr && dr->mapped_to_retina()) s *= 2; W *= s; H *= s; } CGColorSpaceRef lut = CGColorSpaceCreateDeviceRGB(); diff --git a/libraries/fltk/src/drivers/Unix/Fl_Unix_Screen_Driver.H b/libraries/fltk/src/drivers/Unix/Fl_Unix_Screen_Driver.H index 2b8a5a7ab6..36eb943f89 100644 --- a/libraries/fltk/src/drivers/Unix/Fl_Unix_Screen_Driver.H +++ b/libraries/fltk/src/drivers/Unix/Fl_Unix_Screen_Driver.H @@ -52,7 +52,9 @@ static pollfd *pollfds = 0; class Fl_Unix_Screen_Driver : public Fl_Screen_Driver { public: +# if !USE_POLL static fd_set fdsets[3]; +# endif static int maxfd; static int nfds; static struct FD { diff --git a/libraries/fltk/src/drivers/Unix/Fl_Unix_Screen_Driver.cxx b/libraries/fltk/src/drivers/Unix/Fl_Unix_Screen_Driver.cxx index 18f9362437..4988474cb6 100644 --- a/libraries/fltk/src/drivers/Unix/Fl_Unix_Screen_Driver.cxx +++ b/libraries/fltk/src/drivers/Unix/Fl_Unix_Screen_Driver.cxx @@ -18,7 +18,9 @@ #include #include "Fl_Unix_Screen_Driver.H" +#if !USE_POLL fd_set Fl_Unix_Screen_Driver::fdsets[3]; +#endif int Fl_Unix_Screen_Driver::maxfd = 0; int Fl_Unix_Screen_Driver::nfds = 0; Fl_Unix_Screen_Driver::FD *Fl_Unix_Screen_Driver::fd = NULL; diff --git a/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H b/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H index df321fc10d..75d313da7f 100644 --- a/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H +++ b/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H @@ -24,13 +24,6 @@ #include #include -/* Implementation note about OpenGL drawing on the Wayland platform - -After eglCreateWindowSurface() with attributes {EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER, EGL_NONE}, -eglQueryContext() reports that EGL_RENDER_BUFFER equals EGL_BACK_BUFFER. -This experiment suggests that the platform only supports double-buffer drawing. -Consequently, FL_DOUBLE is enforced in all Fl_Gl_Window::mode_ values under Wayland. -*/ class Fl_Wayland_Gl_Window_Driver : public Fl_Gl_Window_Driver { friend Fl_Gl_Window_Driver* Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *); @@ -56,8 +49,6 @@ private: void redraw_overlay() FL_OVERRIDE; void gl_start() FL_OVERRIDE; void gl_visual(Fl_Gl_Choice *c) FL_OVERRIDE; - char *alpha_mask_for_string( - const char *str, int n, int w, int h, Fl_Fontsize fs) FL_OVERRIDE; void init(); public: //virtual bool need_scissor() { return true; } // CONTROL_LEAKING_SUB_GL_WINDOWS diff --git a/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx b/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx index 5f96480aba..384c4a2052 100644 --- a/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx +++ b/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx @@ -107,35 +107,6 @@ void Fl_Wayland_Gl_Window_Driver::init() { } -char *Fl_Wayland_Gl_Window_Driver::alpha_mask_for_string(const char *str, int n, - int w, int h, Fl_Fontsize fs) -{ - // write str to a bitmap just big enough - Fl_Image_Surface *surf = new Fl_Image_Surface(w, h); - Fl_Font f = fl_font(); - Fl_Surface_Device::push_current(surf); - fl_color(FL_BLACK); - fl_rectf(0, 0, w, h); - fl_color(FL_WHITE); - fl_font(f, fs); - fl_draw(str, n, 0, fl_height() - fl_descent()); - // get the R channel only of the bitmap - char *alpha_buf = new char[w*h], *r = alpha_buf; - struct Fl_Wayland_Graphics_Driver::draw_buffer *off = - Fl_Wayland_Graphics_Driver::offscreen_buffer(surf->offscreen()); - for (int i = 0; i < h; i++) { - uchar *q = off->buffer + i * off->stride; - for (int j = 0; j < w; j++) { - *r++ = *q; - q += 4; - } - } - Fl_Surface_Device::pop_current(); - delete surf; - return alpha_buf; -} - - Fl_Gl_Choice *Fl_Wayland_Gl_Window_Driver::find(int m, const int *alistp) { m |= FL_DOUBLE; @@ -238,6 +209,11 @@ void Fl_Wayland_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context Fl::error("eglMakeCurrent() failed\n"); } } + if (!(mode() & FL_ALPHA)) { // useful at least for Linux on MacBook hardware + GLfloat vals[4]; + glGetFloatv(GL_COLOR_CLEAR_VALUE, vals); + if (vals[3] == 0.) glClearColor(vals[0], vals[1], vals[2], 1.); + } } /* CONTROL_LEAKING_SUB_GL_WINDOWS @@ -357,7 +333,7 @@ void Fl_Wayland_Gl_Window_Driver::swap_buffers() { } if (egl_surface) { - if (pWindow->parent()) { + if (pWindow->parent()) { // issue #967 struct wld_window *xid = fl_wl_xid(pWindow); if (xid->frame_cb) return; xid->frame_cb = wl_surface_frame(xid->wl_surface); diff --git a/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx index 1855bc20fd..5c9539a8c3 100644 --- a/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx +++ b/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx @@ -141,16 +141,20 @@ const struct wl_callback_listener *Fl_Wayland_Graphics_Driver::p_surface_frame_l // copy pixels in region r from the Cairo surface to the Wayland buffer static void copy_region(struct wld_window *window, cairo_region_t *r) { struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = window->buffer; - float f = Fl::screen_scale(window->fl_win->screen_num()) * - Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale(); + float f = Fl::screen_scale(window->fl_win->screen_num()); + int d = Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale(); int count = cairo_region_num_rectangles(r); cairo_rectangle_int_t rect; for (int i = 0; i < count; i++) { cairo_region_get_rectangle(r, i, &rect); - int left = rect.x * f; - int top = rect.y * f; - int width = rect.width * f; - int height = rect.height * f; + int left = d * int(rect.x * f); + int top = d * int(rect.y * f); + int right = d * ceil((rect.x + rect.width) * f); + if (right > d * int(window->fl_win->w() * f)) right = d * int(window->fl_win->w() * f); + int width = right - left; + int bottom = d * ceil((rect.y + rect.height) * f); + if (bottom > d * int(window->fl_win->h() * f)) bottom = d * int(window->fl_win->h() * f); + int height = bottom - top; int offset = top * buffer->draw_buffer.stride + 4 * left; int W4 = 4 * width; for (int l = 0; l < height; l++) { @@ -264,8 +268,10 @@ void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, cairo_get_matrix(cairo_, &matrix); double s = matrix.xx; cairo_save(cairo_); - cairo_rectangle(cairo_, x, y, w, h); + cairo_rectangle(cairo_, x - 0.5, y - 0.5, w, h); + cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_NONE); cairo_clip(cairo_); + cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_DEFAULT); cairo_surface_t *surf = cairo_get_target((cairo_t *)src); cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf); cairo_set_source(cairo_, pat); @@ -275,6 +281,7 @@ void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h, cairo_paint(cairo_); cairo_pattern_destroy(pat); cairo_restore(cairo_); + surface_needs_commit(); } diff --git a/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx b/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx index 98fcc5b8ef..4a7ace7685 100644 --- a/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx +++ b/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx @@ -300,13 +300,21 @@ static void pointer_button(void *data, int b = 0; // Fl::e_state &= ~FL_BUTTONS; // DO NOT reset the mouse button state! if (state == WL_POINTER_BUTTON_STATE_PRESSED) { - if (button == BTN_LEFT) { Fl::e_state |= FL_BUTTON1; b = 1; } - else if (button == BTN_RIGHT) { Fl::e_state |= FL_BUTTON3; b = 3; } - else if (button == BTN_MIDDLE) { Fl::e_state |= FL_BUTTON2; b = 2; } + if (button == BTN_LEFT) { Fl::e_state |= FL_BUTTON1; b = 1; } + else if (button == BTN_RIGHT) { Fl::e_state |= FL_BUTTON3; b = 3; } + else if (button == BTN_MIDDLE) { Fl::e_state |= FL_BUTTON2; b = 2; } + else if (button == BTN_BACK) { Fl::e_state |= FL_BUTTON4; b = 4; } // ? + else if (button == BTN_SIDE) { Fl::e_state |= FL_BUTTON4; b = 4; } // OK: Debian 12 + else if (button == BTN_FORWARD) { Fl::e_state |= FL_BUTTON5; b = 5; } // ? + else if (button == BTN_EXTRA) { Fl::e_state |= FL_BUTTON5; b = 5; } // OK: Debian 12 } else { // must be WL_POINTER_BUTTON_STATE_RELEASED - if (button == BTN_LEFT) { Fl::e_state &= ~FL_BUTTON1; b = 1; } - else if (button == BTN_RIGHT) { Fl::e_state &= ~FL_BUTTON3; b = 3; } - else if (button == BTN_MIDDLE) { Fl::e_state &= ~FL_BUTTON2; b = 2; } + if (button == BTN_LEFT) { Fl::e_state &= ~FL_BUTTON1; b = 1; } + else if (button == BTN_RIGHT) { Fl::e_state &= ~FL_BUTTON3; b = 3; } + else if (button == BTN_MIDDLE) { Fl::e_state &= ~FL_BUTTON2; b = 2; } + else if (button == BTN_BACK) { Fl::e_state &= ~FL_BUTTON4; b = 4; } // ? + else if (button == BTN_SIDE) { Fl::e_state &= ~FL_BUTTON4; b = 4; } // OK: Debian 12 + else if (button == BTN_FORWARD) { Fl::e_state &= ~FL_BUTTON5; b = 5; } // ? + else if (button == BTN_EXTRA) { Fl::e_state &= ~FL_BUTTON5; b = 5; } // OK: Debian 12 } Fl::e_keysym = FL_Button + b; Fl::e_dx = Fl::e_dy = 0; @@ -583,21 +591,19 @@ static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard, struct key_repeat_data_t { - uint32_t time; + uint32_t serial; Fl_Window *window; }; - +static uint32_t last_keydown_serial = 0; // serial of last keydown event #define KEY_REPEAT_DELAY 0.5 // sec #define KEY_REPEAT_INTERVAL 0.05 // sec static void key_repeat_timer_cb(key_repeat_data_t *key_repeat_data) { - if ((Fl::event() == FL_KEYDOWN || (Fl_Window_Driver::menu_parent() && - Fl::event() == FL_ENTER)) && wld_event_time == key_repeat_data->time) { + if (last_keydown_serial == key_repeat_data->serial) { Fl::handle(FL_KEYDOWN, key_repeat_data->window); - Fl::add_timeout(KEY_REPEAT_INTERVAL, (Fl_Timeout_Handler)key_repeat_timer_cb, - key_repeat_data); + Fl::add_timeout(KEY_REPEAT_INTERVAL, (Fl_Timeout_Handler)key_repeat_timer_cb, key_repeat_data); } else delete key_repeat_data; } @@ -680,7 +686,12 @@ int Fl_Wayland_Screen_Driver::compose(int& del) { // letter+modifier key int condition = (Fl::e_state & (FL_ALT | FL_META | FL_CTRL)) && ascii < 128 ; // pressing modifier key - condition |= (Fl::e_keysym >= FL_Shift_L && Fl::e_keysym <= FL_Alt_R); + // FL_Shift_L, FL_Shift_R, FL_Control_L, FL_Control_R, FL_Caps_Lock + // FL_Meta_L, FL_Meta_R, FL_Alt_L, FL_Alt_R + condition |= ((Fl::e_keysym >= FL_Shift_L && Fl::e_keysym <= FL_Alt_R) || + Fl::e_keysym == FL_Alt_Gr); + // FL_Home FL_Left FL_Up FL_Right FL_Down FL_Page_Up FL_Page_Down FL_End + // FL_Print FL_Insert FL_Menu FL_Help and more condition |= (Fl::e_keysym >= FL_Home && Fl::e_keysym <= FL_Help); condition |= Fl::e_keysym == FL_Tab; //fprintf(stderr, "compose: condition=%d e_state=%x ascii=%d\n", condition, Fl::e_state, ascii); @@ -772,10 +783,8 @@ static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, key_vector.push_back(for_key_vector); } } else { + last_keydown_serial = 0; remove_int_vector(key_vector, for_key_vector); - // Under KDE, the time value received doesn't change at each keystroke as it should, - // so we remove any key repeat timer at each FL_KEYUP event. - Fl::remove_timeout((Fl_Timeout_Handler)key_repeat_timer_cb); } Fl::e_text = buf; Fl::e_length = (int)strlen(buf); @@ -824,9 +833,19 @@ static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard, } if (event == FL_KEYDOWN && status == XKB_COMPOSE_NOTHING && !(sym >= FL_Shift_L && sym <= FL_Alt_R)) { + // Handling of key repeats : + // Use serial argument rather than time to detect repeated keys because + // serial value changes at each key up or down in all tested OS and compositors, + // whereas time value changes in Ubuntu24.04 KDE/Plasma 5.27.11 and Ubuntu22.04 KDE/Plasma 5.24.7 + // but not in Debian-testing KDE/Plasma 5.27.10. + // Unexplained difference in behaviors of KDE/Plasma compositor: + // Consider KDE settings -> input -> keyboard -> when a key is held: repeat/do nothing. + // This setting (repeat) has key-down wayland events repeated when key is held under Debian/KDE + // but not under Ubuntu/KDE ! key_repeat_data_t *key_repeat_data = new key_repeat_data_t; - key_repeat_data->time = time; + key_repeat_data->serial = serial; key_repeat_data->window = win; + last_keydown_serial = serial; Fl::add_timeout(KEY_REPEAT_DELAY, (Fl_Timeout_Handler)key_repeat_timer_cb, key_repeat_data); } @@ -838,6 +857,7 @@ static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard, struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data; //fprintf(stderr, "keyboard leave fl_win=%p\n", Fl_Wayland_Window_Driver::surface_to_window(surface)); seat->keyboard_surface = NULL; + last_keydown_serial = 0; Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface); if (!win && Fl::focus()) win = Fl::focus()->top_window(); if (win) Fl::handle(FL_UNFOCUS, win); @@ -1323,7 +1343,11 @@ static const struct wl_registry_listener registry_listener = { }; +extern int fl_send_system_handlers(void *); + + static void wayland_socket_callback(int fd, struct wl_display *display) { + if (fl_send_system_handlers(NULL)) return; struct pollfd fds = (struct pollfd) { fd, POLLIN, 0 }; do { if (wl_display_dispatch(display) == -1) { diff --git a/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx b/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx index 9546fde94c..79d26a03b5 100644 --- a/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx +++ b/libraries/fltk/src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx @@ -321,7 +321,7 @@ void Fl_Wayland_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image*& top, int width, height, stride; uchar *cairo_data = fl_libdecor_titlebar_buffer(wwin->frame, &width, &height, &stride); if (!cairo_data) return; - uchar *data = new uchar[width * height * 3]; + uchar *data = new uchar[width * height * 4]; uchar *p = data; for (int j = 0; j < height; j++) { uchar *q = cairo_data + j * stride; @@ -329,10 +329,11 @@ void Fl_Wayland_Window_Driver::capture_titlebar_and_borders(Fl_RGB_Image*& top, *p++ = *(q+2); // R *p++ = *(q+1); // G *p++ = *q; // B + *p++ = *(q+3); // A q += 4; } } - top = new Fl_RGB_Image(data, width, height, 3); + top = new Fl_RGB_Image(data, width, height, 4); top->alloc_array = 1; top->scale(pWindow->w(), htop); } @@ -989,17 +990,6 @@ static void handle_configure(struct libdecor_frame *frame, if (Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::WESTON || !is_1st_run) { window->fl_win->clear_damage(); } - - if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::OWL) { - Fl_Window *sub = Fl::first_window(); - while (sub) { // search still un-exposed sub-windows - if (sub->window() == window->fl_win) { - Fl_Window_Driver::driver(sub)->wait_for_expose_value = 0; - break; - } - sub = Fl::next_window(sub); - } - } } @@ -1361,12 +1351,19 @@ bool Fl_Wayland_Window_Driver::process_menu_or_tooltip(struct wld_window *new_wi xdg_positioner_set_anchor(positioner, XDG_POSITIONER_ANCHOR_BOTTOM_LEFT); xdg_positioner_set_gravity(positioner, XDG_POSITIONER_GRAVITY_BOTTOM_RIGHT); // prevent menuwindow from expanding beyond display limits - int constraint = XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | - XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y; - if (Fl_Window_Driver::menu_bartitle(pWindow) && !Fl_Window_Driver::menu_leftorigin(pWindow)) { - constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; + int constraint = 0; + if ( !(parent_win->fullscreen_active() && + Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::MUTTER && + ((!Fl_Window_Driver::menu_title(pWindow) && !Fl_Window_Driver::menu_leftorigin(pWindow)) || + Fl_Window_Driver::menu_bartitle(pWindow))) + ) { + // Condition above is only to bypass Mutter bug for fullscreen windows (see #1061) + constraint |= (XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_X | XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_SLIDE_Y); + if (Fl_Window_Driver::menu_bartitle(pWindow) && !Fl_Window_Driver::menu_leftorigin(pWindow)) { + constraint |= XDG_POSITIONER_CONSTRAINT_ADJUSTMENT_FLIP_Y; + } + xdg_positioner_set_constraint_adjustment(positioner, constraint); } - xdg_positioner_set_constraint_adjustment(positioner, constraint); if (!(Fl_Window_Driver::menu_title(pWindow) && Fl_Window_Driver::menu_bartitle(pWindow))) { xdg_positioner_set_offset(positioner, 0, popup_y); } @@ -1464,16 +1461,16 @@ void Fl_Wayland_Window_Driver::makeWindow() float f = Fl::screen_scale(pWindow->top_window()->screen_num()); wl_subsurface_set_position(new_window->subsurface, pWindow->x() * f, pWindow->y() * f); wl_subsurface_set_desync(new_window->subsurface); // important - // next 3 statements ensure the subsurface will be mapped because: - // "A sub-surface becomes mapped, when a non-NULL wl_buffer is applied - // and the parent surface is mapped." + // Next 5 statements ensure the subsurface will be mapped because: + // "The effect of adding a sub-surface becomes visible on the next time + // the state of the parent surface is applied." new_window->configured_width = pWindow->w(); new_window->configured_height = pWindow->h(); - if (Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::OWL) { - // With OWL, delay zeroing of subwindow's wait_for_expose_value until - // after their parent is configured, see handle_configure(). - wait_for_expose_value = 0; + if (!pWindow->as_gl_window()) { + parent->fl_win->wait_for_expose(); + wl_surface_commit(parent->wl_surface); } + wait_for_expose_value = 0; pWindow->border(0); checkSubwindowFrame(); // make sure subwindow doesn't leak outside parent @@ -1518,14 +1515,17 @@ void Fl_Wayland_Window_Driver::makeWindow() if (top_dr->xdg_toplevel()) xdg_toplevel_set_parent(new_window->xdg_toplevel, top_dr->xdg_toplevel()); } - if (scr_driver->seat->gtk_shell && pWindow->modal() && + if (scr_driver->seat->gtk_shell && pWindow->modal() && (new_window->kind == DECORATED || new_window->kind == UNFRAMED)) { // Useful to position modal windows above their parent with "gnome-shell --version" ≤ 45.2, // useless but harmless with "gnome-shell --version" ≥ 46.0. struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(scr_driver->seat->gtk_shell, new_window->wl_surface); gtk_surface1_set_modal(gtk_surface); - gtk_surface1_release(gtk_surface); // very necessary + if (gtk_surface1_get_version(gtk_surface) >= GTK_SURFACE1_RELEASE_SINCE_VERSION) + gtk_surface1_release(gtk_surface); // very necessary + else + gtk_surface1_destroy(gtk_surface); } } @@ -1778,7 +1778,35 @@ int Fl_Wayland_Window_Driver::set_cursor_4args(const Fl_RGB_Image *rgb, int hotx } +struct xid_and_rect { + struct wld_window *xid; + Fl_Window *win; + int X, Y, W, H; + bool need_resize; +}; + + +static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) { + struct xid_and_rect *xid_rect = (xid_and_rect *)data; + wl_callback_destroy(cb); + xid_rect->xid->frame_cb = NULL; + if (xid_rect->need_resize) { + xid_rect->win->Fl_Group::resize(xid_rect->X, xid_rect->Y, xid_rect->W, xid_rect->H); + xid_rect->win->redraw(); + } else { + xid_rect->win->Fl_Widget::resize(xid_rect->X, xid_rect->Y, xid_rect->W, xid_rect->H); + } + delete xid_rect; +} + + +static const struct wl_callback_listener surface_frame_listener = { + .done = surface_frame_done, +}; + + void Fl_Wayland_Window_Driver::resize(int X, int Y, int W, int H) { + static int depth = 0; struct wld_window *fl_win = fl_wl_xid(pWindow); if (fl_win && fl_win->kind == DECORATED && !xdg_toplevel()) { pWindow->wait_for_expose(); @@ -1796,20 +1824,34 @@ void Fl_Wayland_Window_Driver::resize(int X, int Y, int W, int H) { int is_a_resize = (W != w() || H != h() || true_rescale); if (is_a_move) force_position(1); else if (!is_a_resize && !is_a_move) return; + depth++; if (shown() && !(parent() || popup_window())) { X = Y = 0; } - if (is_a_resize) { - if (pWindow->parent()) { - if (W < 1) W = 1; - if (H < 1) H = 1; + Fl_Window *parent = this->parent() ? pWindow->window() : NULL; + struct wld_window *parent_xid = parent ? fl_wl_xid(parent) : NULL; + xid_and_rect *xid_rect = NULL; + if (parent_xid && parent_xid->frame_cb && wl_proxy_get_listener((struct wl_proxy*)parent_xid->frame_cb) == &surface_frame_listener) { + xid_rect = (xid_and_rect*)wl_callback_get_user_data(parent_xid->frame_cb); + if (xid_rect->win != pWindow) xid_rect = NULL; + } + // When moving or resizing a non-GL subwindow independently from its parent, this condition + // delays application of X,Y,W,H values until the compositor signals + // it's ready for a new frame using the frame callback mechanism. + if ((parent && parent->damage()) || depth > 1 || pWindow->as_gl_window() || !parent_xid || + wait_for_expose_value || (parent_xid->frame_cb && !xid_rect)) { + if (is_a_resize) { + if (pWindow->parent()) { + if (W < 1) W = 1; + if (H < 1) H = 1; + } + pWindow->Fl_Group::resize(X,Y,W,H); + //fprintf(stderr, "resize: win=%p to %dx%d\n", pWindow, W, H); + if (shown()) {pWindow->redraw();} + } else { + x(X); y(Y); + //fprintf(stderr, "move win=%p to %dx%d\n", pWindow, X, Y); } - pWindow->Fl_Group::resize(X,Y,W,H); -//fprintf(stderr, "resize: win=%p to %dx%d\n", pWindow, W, H); - if (shown()) {pWindow->redraw();} - } else { - x(X); y(Y); -//fprintf(stderr, "move win=%p to %dx%d\n", pWindow, X, Y); } if (shown()) { @@ -1861,19 +1903,38 @@ void Fl_Wayland_Window_Driver::resize(int X, int Y, int W, int H) { Fl::pushed(NULL); Fl::e_state = 0; } - } else if (fl_win->kind == SUBWINDOW && fl_win->subsurface) { + } else if (pWindow->as_gl_window() && fl_win->kind == SUBWINDOW && fl_win->subsurface) { wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f); } } } - if (fl_win && fl_win->kind == SUBWINDOW && fl_win->subsurface) { - // Interactive move or resize of a subwindow requires to commit the parent surface (#987) - Fl_Window *parent = pWindow->window(); - struct wld_window *xid = fl_wl_xid(parent); - if (xid) wl_surface_commit(xid->wl_surface); + if (fl_win && parent_xid) { + if (pWindow->as_gl_window()) { + if (fl_win->frame_cb) { + wl_callback_destroy(fl_win->frame_cb); + fl_win->frame_cb = NULL; + } + if (parent_xid->buffer) Fl_Wayland_Graphics_Driver::buffer_commit(parent_xid); + } else { + if (!(parent && parent->damage()) && !parent_xid->frame_cb) { + // use the frame callback mechanism and memorize current X,Y,W,H values + xid_rect = new xid_and_rect; + xid_rect->xid = parent_xid; + xid_rect->win = pWindow; + parent_xid->frame_cb = wl_surface_frame(parent_xid->wl_surface); + wl_callback_add_listener(parent_xid->frame_cb, &surface_frame_listener, xid_rect); + xid_rect->X = X; xid_rect->Y = Y; xid_rect->W = W; xid_rect->H = H; + xid_rect->need_resize = is_a_resize; + wl_subsurface_set_position(fl_win->subsurface, X * f, Y * f); + wl_surface_commit(parent_xid->wl_surface); + } else if (!xid_rect) { + wl_surface_commit(parent_xid->wl_surface); + } + } checkSubwindowFrame(); // make sure subwindow doesn't leak outside parent } + depth--; } @@ -2053,8 +2114,9 @@ void Fl_Wayland_Window_Driver::menu_window_area(int &X, int &Y, int &W, int &H, int Fl_Wayland_Window_Driver::wld_scale() { - struct wld_window *xid = (struct wld_window *)Fl_X::flx(pWindow)->xid; - if (wl_list_empty(&xid->outputs)) { + Fl_X *flx = Fl_X::flx(pWindow); + struct wld_window *xid = (flx ? (struct wld_window *)flx->xid : NULL); + if (!xid || wl_list_empty(&xid->outputs)) { int scale = 1; Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver(); Fl_Wayland_Screen_Driver::output *output; @@ -2095,6 +2157,11 @@ struct wl_compositor *fl_wl_compositor() { } +int fl_wl_buffer_scale(Fl_Window *window) { + return Fl_Wayland_Window_Driver::driver(window)->wld_scale(); +} + + Fl_Wayland_Plugin *Fl_Wayland_Window_Driver::gl_plugin() { static Fl_Wayland_Plugin *plugin = NULL; if (!plugin) { @@ -2108,10 +2175,12 @@ Fl_Wayland_Plugin *Fl_Wayland_Window_Driver::gl_plugin() { void Fl_Wayland_Window_Driver::maximize() { struct wld_window *xid = (struct wld_window *)Fl_X::flx(pWindow)->xid; if (xid->kind == DECORATED) libdecor_frame_set_maximized(xid->frame); + else Fl_Window_Driver::maximize(); } void Fl_Wayland_Window_Driver::un_maximize() { struct wld_window *xid = (struct wld_window *)Fl_X::flx(pWindow)->xid; if (xid->kind == DECORATED) libdecor_frame_unset_maximized(xid->frame); + else Fl_Window_Driver::un_maximize(); } diff --git a/libraries/fltk/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx b/libraries/fltk/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx index 894ce78d41..6fa7573069 100644 --- a/libraries/fltk/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx +++ b/libraries/fltk/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx @@ -300,6 +300,9 @@ static void data_offer_handle_offer(void *data, struct wl_data_offer *offer, } else if (strcmp(mime_type, "text/plain") == 0 && !fl_selection_type[1]) { fl_selection_type[1] = Fl::clipboard_plain_text; fl_selection_offer_type = "text/plain"; + } else if (strcmp(mime_type, "UTF8_STRING") == 0 && !fl_selection_type[1]) { + fl_selection_type[1] = Fl::clipboard_plain_text; + fl_selection_offer_type = "text/plain"; } } diff --git a/libraries/fltk/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx b/libraries/fltk/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx index 6f6d208287..a3a7ccf470 100644 --- a/libraries/fltk/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx +++ b/libraries/fltk/src/drivers/WinAPI/Fl_WinAPI_Screen_Driver.cxx @@ -332,7 +332,11 @@ void Fl_WinAPI_Screen_Driver::get_system_colors() int Fl_WinAPI_Screen_Driver::compose(int &del) { unsigned char ascii = (unsigned char)Fl::e_text[0]; - int condition = (Fl::e_state & (FL_ALT | FL_META)) && !(ascii & 128) ; + /* WARNING: The [AltGr] key on international keyboards sets FL_CTRL. + 2nd line in condition below asks [AltGr] key (a.k.a. VK_RMENU) not to be down. + */ + int condition = (Fl::e_state & (FL_ALT | FL_META | FL_CTRL)) && !(ascii & 128) && + !( (Fl::e_state & FL_CTRL) && (GetAsyncKeyState(VK_RMENU) >> 15) ); if (condition) { // this stuff is to be treated as a function key del = 0; return 0; diff --git a/libraries/fltk/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx b/libraries/fltk/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx index f6ad0bcad7..552f26dfcf 100644 --- a/libraries/fltk/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx +++ b/libraries/fltk/src/drivers/WinAPI/Fl_WinAPI_Window_Driver.cxx @@ -580,47 +580,57 @@ void Fl_WinAPI_Window_Driver::fullscreen_on() { void Fl_WinAPI_Window_Driver::fullscreen_off(int X, int Y, int W, int H) { pWindow->_clear_fullscreen(); DWORD style = GetWindowLong(fl_xid(pWindow), GWL_STYLE); + if (pWindow->border()) style |= WS_THICKFRAME | WS_SYSMENU | WS_MAXIMIZEBOX | WS_CAPTION; // Remove the xid temporarily so that Fl_WinAPI_Window_Driver::fake_X_wm() behaves like it // does in Fl_WinAPI_Window_Driver::makeWindow(). HWND xid = fl_xid(pWindow); Fl_X::flx(pWindow)->xid = 0; int wx, wy, bt, bx, by; - switch (fake_X_wm(wx, wy, bt, bx, by)) { + switch (fake_X_wm(wx, wy, bt, bx, by, style)) { case 0: break; case 1: style |= WS_CAPTION; break; case 2: - if (border()) { + /*if (border()) { style |= WS_THICKFRAME | WS_CAPTION; - } + }*/ break; } Fl_X::flx(pWindow)->xid = (fl_uintptr_t)xid; - // compute window position and size in scaled units - float s = Fl::screen_driver()->scale(screen_num()); - int scaledX = int(ceil(X*s)), scaledY= int(ceil(Y*s)), scaledW = int(ceil(W*s)), scaledH = int(ceil(H*s)); - // Adjust for decorations (but not if that puts the decorations - // outside the screen) - if ((X != x()) || (Y != y())) { - scaledX -= bx; - scaledY -= by+bt; - } - scaledW += bx*2; - scaledH += by*2+bt; SetWindowLong(fl_xid(pWindow), GWL_STYLE, style); - SetWindowPos(fl_xid(pWindow), 0, scaledX, scaledY, scaledW, scaledH, - SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); + if (!pWindow->maximize_active()) { + // compute window position and size in scaled units + float s = Fl::screen_driver()->scale(screen_num()); + int scaledX = int(ceil(X*s)), scaledY= int(ceil(Y*s)), scaledW = int(ceil(W*s)), scaledH = int(ceil(H*s)); + // Adjust for decorations (but not if that puts the decorations + // outside the screen) + if ((X != x()) || (Y != y())) { + scaledX -= bx; + scaledY -= by+bt; + } + scaledW += bx*2; + scaledH += by*2+bt; + SetWindowPos(fl_xid(pWindow), 0, scaledX, scaledY, scaledW, scaledH, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); + } else { + int WX, WY, WW, WH; + ((Fl_WinAPI_Screen_Driver*)Fl::screen_driver())->screen_xywh_unscaled(WX, WY, WW, WH, screen_num()); + SetWindowPos(fl_xid(pWindow), 0, WX, WY, WW, WH, + SWP_NOACTIVATE | SWP_NOZORDER | SWP_FRAMECHANGED); + } Fl::handle(FL_FULLSCREEN, pWindow); } void Fl_WinAPI_Window_Driver::maximize() { + if (!border()) return Fl_Window_Driver::maximize(); ShowWindow(fl_xid(pWindow), SW_SHOWMAXIMIZED); } void Fl_WinAPI_Window_Driver::un_maximize() { + if (!border()) return Fl_Window_Driver::un_maximize(); ShowWindow(fl_xid(pWindow), SW_SHOWNORMAL); } diff --git a/libraries/fltk/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx b/libraries/fltk/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx index 83bf283330..3a3f80c282 100644 --- a/libraries/fltk/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx +++ b/libraries/fltk/src/drivers/X11/Fl_X11_Gl_Window_Driver.cxx @@ -1,7 +1,7 @@ // // Class Fl_X11_Gl_Window_Driver for the Fast Light Tool Kit (FLTK). // -// Copyright 2021-2022 by Bill Spitzak and others. +// Copyright 2021-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -20,10 +20,7 @@ #include "../../Fl_Gl_Choice.H" #include "../../Fl_Screen_Driver.H" #include "Fl_X11_Gl_Window_Driver.H" -# include -# if ! defined(GLX_VERSION_1_3) -# typedef void *GLXFBConfig; -# endif +#include #if ! USE_XFT # include "../Xlib/Fl_Font.H" #endif @@ -35,12 +32,10 @@ class Fl_X11_Gl_Choice : public Fl_Gl_Choice { private: XVisualInfo *vis; /* the visual to use */ Colormap colormap; /* a colormap for that visual */ - GLXFBConfig best_fb; public: Fl_X11_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) { vis = NULL; colormap = 0; - best_fb = NULL; } }; @@ -120,53 +115,6 @@ Fl_Font_Descriptor** Fl_X11_Gl_Window_Driver::fontnum_to_fontdescriptor(int fnum #endif -static XVisualInfo *gl3_getvisual(const int *blist, GLXFBConfig *pbestFB) -{ - int glx_major, glx_minor; - - // FBConfigs were added in GLX version 1.3. - if ( !glXQueryVersion(fl_display, &glx_major, &glx_minor) || - ( ( glx_major == 1 ) && ( glx_minor < 3 ) ) || ( glx_major < 1 ) ) { - return NULL; - } - - //printf( "Getting matching framebuffer configs\n" ); - int fbcount; - GLXFBConfig* fbc = glXChooseFBConfig(fl_display, DefaultScreen(fl_display), blist, &fbcount); - if (!fbc) { - //printf( "Failed to retrieve a framebuffer config\n" ); - return NULL; - } - //printf( "Found %d matching FB configs.\n", fbcount ); - - // Pick the FB config/visual with the most samples per pixel - int best_fbc = -1, worst_fbc = -1, best_num_samp = -1, worst_num_samp = 999; - for (int i = 0; i < fbcount; ++i) - { - XVisualInfo *vi = glXGetVisualFromFBConfig( fl_display, fbc[i] ); - if (vi) { - int samp_buf, samples; - glXGetFBConfigAttrib(fl_display, fbc[i], GLX_SAMPLE_BUFFERS, &samp_buf); - glXGetFBConfigAttrib(fl_display, fbc[i], GLX_SAMPLES , &samples ); - /*printf( " Matching fbconfig %d, visual ID 0x%2lx: SAMPLE_BUFFERS = %d, SAMPLES = %d\n", - i, vi -> visualid, samp_buf, samples );*/ - if ( best_fbc < 0 || (samp_buf && samples > best_num_samp) ) - best_fbc = i, best_num_samp = samples; - if ( worst_fbc < 0 || !samp_buf || samples < worst_num_samp ) - worst_fbc = i, worst_num_samp = samples; - } - XFree(vi); - } - - GLXFBConfig bestFbc = fbc[ best_fbc ]; - // Be sure to free the FBConfig list allocated by glXChooseFBConfig() - XFree(fbc); - // Get a visual - XVisualInfo *vi = glXGetVisualFromFBConfig(fl_display, bestFbc); - *pbestFB = bestFbc; - return vi; -} - Fl_Gl_Choice *Fl_X11_Gl_Window_Driver::find(int m, const int *alistp) { Fl_X11_Gl_Choice *g = (Fl_X11_Gl_Choice*)Fl_Gl_Window_Driver::find_begin(m, alistp); @@ -222,26 +170,18 @@ Fl_Gl_Choice *Fl_X11_Gl_Window_Driver::find(int m, const int *alistp) } fl_open_display(); - XVisualInfo *visp = NULL; - GLXFBConfig best_fb = NULL; - if (m & FL_OPENGL3) { - visp = gl3_getvisual((const int *)blist, &best_fb); - } + XVisualInfo *visp = glXChooseVisual(fl_display, fl_screen, (int *)blist); if (!visp) { - 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 +# if defined(GLX_VERSION_1_1) && defined(GLX_SGIS_multisample) + if (m&FL_MULTISAMPLE) return find(m&~FL_MULTISAMPLE, 0); +# endif return 0; - } } g = new Fl_X11_Gl_Choice(m, alistp, first); first = g; g->vis = visp; - g->best_fb = best_fb; if (/*MaxCmapsOfScreen(ScreenOfDisplay(fl_display,fl_screen))==1 && */ visp->visualid == fl_visual->visualid && @@ -253,72 +193,20 @@ Fl_Gl_Choice *Fl_X11_Gl_Window_Driver::find(int m, const int *alistp) return g; } -static bool ctxErrorOccurred = false; -static int ctxErrorHandler( Display *, XErrorEvent * ) -{ - ctxErrorOccurred = true; - return 0; -} GLContext Fl_X11_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) { (void)window; GLContext shared_ctx = 0; if (context_list && nContext) shared_ctx = context_list[0]; - - typedef GLContext (*glXCreateContextAttribsARBProc)(Display*, GLXFBConfig, GLContext, Bool, const int*); - // It is not necessary to create or make current to a context before calling glXGetProcAddressARB - static glXCreateContextAttribsARBProc glXCreateContextAttribsARB = -#if defined(HAVE_GLXGETPROCADDRESSARB) - (glXCreateContextAttribsARBProc)glXGetProcAddressARB((const GLubyte *)"glXCreateContextAttribsARB"); -#else - NULL; -#endif - - GLContext ctx = 0; - // Check for the GLX_ARB_create_context extension string and the function. - // If either is not present, use GLX 1.3 context creation method. - const char *glxExts = glXQueryExtensionsString(fl_display, fl_screen); - if (((Fl_X11_Gl_Choice*)g)->best_fb && strstr(glxExts, "GLX_ARB_create_context") && glXCreateContextAttribsARB ) { - int context_attribs[] = - { - GLX_CONTEXT_MAJOR_VERSION_ARB, 3, - GLX_CONTEXT_MINOR_VERSION_ARB, 2, - //GLX_CONTEXT_FLAGS_ARB , GLX_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB, - GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB, - None - }; - ctxErrorOccurred = false; - XErrorHandler oldHandler = XSetErrorHandler(&ctxErrorHandler); - ctx = glXCreateContextAttribsARB(fl_display, ((Fl_X11_Gl_Choice*)g)->best_fb, shared_ctx, true, context_attribs); - XSync(fl_display, false); // Sync to ensure any errors generated are processed. - if (ctxErrorOccurred) ctx = 0; - if (!ctx) { // if did not work, try again asking for core profile - ctxErrorOccurred = false; - context_attribs[5] = GLX_CONTEXT_CORE_PROFILE_BIT_ARB; - ctx = glXCreateContextAttribsARB(fl_display, ((Fl_X11_Gl_Choice*)g)->best_fb, shared_ctx, true, context_attribs); - if (ctxErrorOccurred) ctx = 0; - } - XSetErrorHandler(oldHandler); - } - if (!ctx) { // use OpenGL 1-style context creation - ctx = glXCreateContext(fl_display, ((Fl_X11_Gl_Choice*)g)->vis, (GLXContext)shared_ctx, true); - } + // use OpenGL 1-style context creation + GLContext ctx = glXCreateContext(fl_display, ((Fl_X11_Gl_Choice*)g)->vis, (GLXContext)shared_ctx, true); if (ctx) add_context(ctx); //glXMakeCurrent(fl_display, fl_xid(window), ctx);printf("%s\n", glGetString(GL_VERSION)); return ctx; } -/* This is no longer used -GLContext Fl_X11_Gl_Window_Driver::create_gl_context(XVisualInfo *vis) { - GLContext shared_ctx = 0; - if (context_list && nContext) shared_ctx = context_list[0]; - GLContext context = glXCreateContext(fl_display, vis, (GLXContext)shared_ctx, 1); - if (context) - add_context(context); - return context; -}*/ void Fl_X11_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) { GLContext current_context = glXGetCurrentContext(); @@ -390,6 +278,33 @@ int Fl_X11_Gl_Window_Driver::mode_(int m, const int *a) { void Fl_X11_Gl_Window_Driver::swap_buffers() { if (!fl_xid(pWindow)) // window not shown return; + if (overlay()) { + int wo = pWindow->pixel_w(), ho = pWindow->pixel_h(); + GLint matrixmode; + GLfloat pos[4]; + glGetIntegerv(GL_MATRIX_MODE, &matrixmode); + glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); // save original glRasterPos + glMatrixMode(GL_PROJECTION); // save proj/model matrices + glPushMatrix(); + glLoadIdentity(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); + glLoadIdentity(); + glScalef(2.0f/wo, 2.0f/ho, 1.0f); + glTranslatef(-wo/2.0f, -ho/2.0f, 0.0f); // set transform so 0,0 is bottom/left of Gl_Window + glRasterPos2i(0,0); // set glRasterPos to bottom left corner + { + // Emulate overlay by doing copypixels + glReadBuffer(GL_BACK); + glDrawBuffer(GL_FRONT); + glCopyPixels(0, 0, wo, ho, GL_COLOR); // copy GL_BACK to GL_FRONT + } + glPopMatrix(); // GL_MODELVIEW // restore model/proj matrices + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(matrixmode); + glRasterPos3f(pos[0], pos[1], pos[2]); // restore original glRasterPos + } else glXSwapBuffers(fl_display, fl_xid(pWindow)); } diff --git a/libraries/fltk/src/drivers/X11/Fl_X11_Screen_Driver.cxx b/libraries/fltk/src/drivers/X11/Fl_X11_Screen_Driver.cxx index fffce8d35b..5f9acfb55e 100644 --- a/libraries/fltk/src/drivers/X11/Fl_X11_Screen_Driver.cxx +++ b/libraries/fltk/src/drivers/X11/Fl_X11_Screen_Driver.cxx @@ -706,8 +706,8 @@ Fl_RGB_Image *Fl_X11_Screen_Driver::read_win_rectangle(int X, int Y, int w, int hs = (h+1) * s; } #endif - if (!allow_outside && win && Xs + ws >= int(win->w()*s)) ws = win->w()*s - Xs -1; - if (!allow_outside && win && Ys + hs >= int(win->h()*s)) hs = win->h()*s - Ys -1; + if (!allow_outside && win && Xs + ws > int(win->w()*s)) ws = win->w()*s - Xs; + if (!allow_outside && win && Ys + hs > int(win->h()*s)) hs = win->h()*s - Ys; if (ws < 1) ws = 1; if (hs < 1) hs = 1; if (!win || (dx >= sx && dy >= sy && dx + ws <= sx+sw && dy + hs <= sy+sh) ) { diff --git a/libraries/fltk/src/drivers/X11/Fl_X11_Window_Driver.cxx b/libraries/fltk/src/drivers/X11/Fl_X11_Window_Driver.cxx index 39d01a7aea..4af030f492 100644 --- a/libraries/fltk/src/drivers/X11/Fl_X11_Window_Driver.cxx +++ b/libraries/fltk/src/drivers/X11/Fl_X11_Window_Driver.cxx @@ -87,11 +87,12 @@ bool Fl_X11_Window_Driver::decorated_win_size(int &w, int &h) // ignore them all: XWindowAttributes w_attributes; XGetWindowAttributes(fl_display, Fl_X::flx(win)->xid, &w_attributes); - bool true_sides = true; + bool true_sides = false; if (attributes.width - w_attributes.width >= 20) { attributes.height -= (attributes.width - w_attributes.width); attributes.width = w_attributes.width; - true_sides = false; + } else if (attributes.width > w_attributes.width) { + true_sides = true; } int nscreen = screen_num(); diff --git a/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx b/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx index 95ee14e99b..8fab122fe0 100644 --- a/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx +++ b/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Copy_Surface_Driver.cxx @@ -49,7 +49,6 @@ Fl_Xlib_Copy_Surface_Driver::Fl_Xlib_Copy_Surface_Driver(int w, int h) : Fl_Copy cairo_save(cairo_); ((Fl_X11_Cairo_Graphics_Driver*)driver())->set_cairo(cairo_); #endif - driver()->push_no_clip(); fl_window = xid->offscreen(); driver()->color(FL_WHITE); driver()->rectf(0, 0, w, h); @@ -58,7 +57,6 @@ Fl_Xlib_Copy_Surface_Driver::Fl_Xlib_Copy_Surface_Driver(int w, int h) : Fl_Copy Fl_Xlib_Copy_Surface_Driver::~Fl_Xlib_Copy_Surface_Driver() { - driver()->pop_clip(); Window old_win = fl_window; fl_window = xid->offscreen(); Fl_RGB_Image *rgb = Fl::screen_driver()->read_win_rectangle(0, 0, width, height, 0); diff --git a/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H b/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H index 177f0b9b73..b3e9ad444f 100644 --- a/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H +++ b/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver.H @@ -141,9 +141,11 @@ protected: void transformed_vertex0(float x, float y) FL_OVERRIDE; void fixloop() FL_OVERRIDE; void focus_rect(int x, int y, int w, int h) FL_OVERRIDE; + void rect_unscaled(int x, int y, int w, int h) FL_OVERRIDE; void rectf_unscaled(int x, int y, int w, int h) FL_OVERRIDE; void colored_rectf(int x, int y, int w, int h, uchar r, uchar g, uchar b) FL_OVERRIDE; void line_unscaled(int x, int y, int x1, int y1) FL_OVERRIDE; + void line_unscaled(int x, int y, int x1, int y1, int x2, int y2) FL_OVERRIDE; void xyline_unscaled(int x, int y, int x1) FL_OVERRIDE; void *change_pen_width(int lwidth) FL_OVERRIDE; void reset_pen_width(void *data) FL_OVERRIDE; diff --git a/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx b/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx index 959711b638..8c9e392e66 100644 --- a/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx +++ b/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx @@ -18,6 +18,9 @@ #include "../../flstring.h" #include "Fl_Xlib_Graphics_Driver.H" +#if USE_PANGO +# include "../Cairo/Fl_Cairo_Graphics_Driver.H" +#endif #include #include #include // fl_strdup() @@ -1208,6 +1211,7 @@ void Fl_Xlib_Graphics_Driver::draw_unscaled(int angle, const char *str, int n, i double l = width_unscaled(str, n); pango_matrix_rotate(&mat, angle); // 1.6 pango_context_set_matrix(pctxt_, &mat); // 1.6 + str = Fl_Cairo_Graphics_Driver::clean_utf8(str, n); pango_layout_set_text(playout_, str, n); int w, h; pango_layout_get_pixel_size(playout_, &w, &h); @@ -1263,6 +1267,7 @@ void Fl_Xlib_Graphics_Driver::do_draw(int from_right, const char *str, int n, in } const char *old = 0; if (!str2) old = pango_layout_get_text(playout_); + str = Fl_Cairo_Graphics_Driver::clean_utf8(str, n); if (!old || (int)strlen(old) != n || memcmp(str, old, n)) // do not re-set text if equal to text already in layout pango_layout_set_text(playout_, str, n); if (str2) free(str2); @@ -1335,6 +1340,7 @@ double Fl_Xlib_Graphics_Driver::do_width_unscaled_(const char* str, int n) { if (!playout_) context(); int width, height; pango_layout_set_font_description(playout_, pfd_array[font_]); + str = Fl_Cairo_Graphics_Driver::clean_utf8(str, n); pango_layout_set_text(playout_, str, n); pango_layout_get_pixel_size(playout_, &width, &height); return (double)width; @@ -1343,6 +1349,7 @@ double Fl_Xlib_Graphics_Driver::do_width_unscaled_(const char* str, int n) { void Fl_Xlib_Graphics_Driver::text_extents_unscaled(const char *str, int n, int &dx, int &dy, int &w, int &h) { if (!playout_) context(); pango_layout_set_font_description(playout_, pfd_array[font_]); + str = Fl_Cairo_Graphics_Driver::clean_utf8(str, n); pango_layout_set_text(playout_, str, n); int y_correction; fl_pango_layout_get_pixel_extents(playout_, dx, dy, w, h, descent_unscaled(), height_unscaled(), y_correction); diff --git a/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx b/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx index ea24eba34b..25cb6a2859 100644 --- a/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx +++ b/libraries/fltk/src/drivers/Xlib/Fl_Xlib_Graphics_Driver_rect.cxx @@ -227,6 +227,13 @@ void Fl_Xlib_Graphics_Driver::focus_rect(int x, int y, int w, int h) { } } +void Fl_Xlib_Graphics_Driver::rect_unscaled(int x, int y, int w, int h) { + void *old = NULL; + if (line_width_ == 0) old = change_pen_width(1); // #156, #1052 + XDrawRectangle(fl_display, fl_window, gc_, x, y, w, h); + if (old) reset_pen_width(old); +} + void Fl_Xlib_Graphics_Driver::rectf_unscaled(int x, int y, int w, int h) { x += floor(offset_x_); y += floor(offset_y_); @@ -239,6 +246,18 @@ void Fl_Xlib_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1) { x1 + this->floor(offset_x_) , y1 + this->floor(offset_y_) ); } +void Fl_Xlib_Graphics_Driver::line_unscaled(int x, int y, int x1, int y1, int x2, int y2) { + if (!clip_line(x1, y1, x, y) && !clip_line(x1, y1, x2, y2)) { + XPoint p[3]; + int x_offset = floor(offset_x_); + int y_offset = floor(offset_y_); + p[0].x = x + x_offset; p[0].y = y + y_offset; + p[1].x = x1 + x_offset; p[1].y = y1 + y_offset; + p[2].x = x2 + x_offset; p[2].y = y2 + y_offset; + XDrawLines(fl_display, fl_window, gc_, p, 3, 0); + } +} + void Fl_Xlib_Graphics_Driver::xyline_unscaled(int x, int y, int x1) { if (line_width_ >= 2) x1++; x += floor(offset_x_) ; diff --git a/libraries/fltk/src/fl_boxtype.cxx b/libraries/fltk/src/fl_boxtype.cxx index ea8571b935..a78c74b4a5 100644 --- a/libraries/fltk/src/fl_boxtype.cxx +++ b/libraries/fltk/src/fl_boxtype.cxx @@ -267,10 +267,13 @@ void fl_embossed_box(int x, int y, int w, int h, Fl_Color c) { Equivalent to drawing a box of type FL_BORDER_BOX. */ void fl_rectbound(int x, int y, int w, int h, Fl_Color bgcolor) { + // New algorithm (see Discussion #1089): + // 1) draw with adequate bg color a filled rectangle that covers also the rectangle border + // 2) draw with adequate border color the rectangle border overwriting what was drawn at 1) + Fl::set_box_color(bgcolor); + fl_rectf(x, y, w, h); Fl::set_box_color(FL_BLACK); fl_rect(x, y, w, h); - Fl::set_box_color(bgcolor); - fl_rectf(x+1, y+1, w-2, h-2); } #define fl_border_box fl_rectbound /**< allow consistent naming */ diff --git a/libraries/fltk/src/fl_draw.cxx b/libraries/fltk/src/fl_draw.cxx index b0598245ff..72823b0785 100644 --- a/libraries/fltk/src/fl_draw.cxx +++ b/libraries/fltk/src/fl_draw.cxx @@ -38,15 +38,36 @@ char fl_draw_shortcut; // set by fl_labeltypes.cxx static char* underline_at; -/* If called with maxbuf==0, use an internally allocated buffer and enlarge it as needed. +/* + Extract the part of text that fits into the given maximum width. + + If called with maxbuf==0, use an internally allocated buffer and enlarge it as needed. Otherwise, use buf as buffer but don't go beyond its length of maxbuf. + + \param[in] from input text, can contain '\n' and single or double '\@' characters + \param[out] buf buffer for the output text segment + \param[in] maxbuf size of the buffer, or 0 to use the internal buffer allocated in this function + \param[in] maxw maximum width in pixels of the output text + \param[out] n number of characters in the output text segment + \param[out] width actual width in pixels of the output text + \param[in] wrap if true, wrap at maxw, else wrap at newlines + \param[in] draw_symbols if true, double '\@' characters are escaped into a single '@' + + \return pointer to the next character in the input text */ static const char* expand_text_(const char* from, char*& buf, int maxbuf, double maxw, int& n, double &width, int wrap, int draw_symbols) { - underline_at = 0; + // Reset underline_at to null + underline_at = NULL; + + // Initialize the total width to 0 double w = 0; + + // Check if the caller wants to use the internal buffer static int l_local_buff = 500; static char *local_buf = (char*)malloc(l_local_buff); // initial buffer allocation + + // Calculate the end pointer of the buffer char* e; if (maxbuf == 0) { buf = local_buf; @@ -54,32 +75,48 @@ static const char* expand_text_(const char* from, char*& buf, int maxbuf, double } else { e = buf+(maxbuf-4); } + + // Initialize the output pointer to the buffer char* o = buf; + + // Initialize the word end pointer that points into the `out` buffer char* word_end = o; + + // Initialize the word start pointer that points into the `from` buffer const char* word_start = from; + // Iterate over the input text const char* p = from; for (;; p++) { - int c = *p & 255; + // Check for end of line, space, or '\n' if (!c || c == ' ' || c == '\n') { - // test for word-wrap: + // Check for word wrap if (word_start < p && wrap) { + // Calculate the new width double newwidth = w + fl_width(word_end, (int) (o-word_end) ); + + // Check if the new width exceeds the maximum width if (word_end > buf && int(newwidth) > maxw) { // break before this word o = word_end; p = word_start; break; } + // Update the word end pointer word_end = o; w = newwidth; } + + // Check for end of line if (!c) break; else if (c == '\n') {p++; break;} + + // Update the word start pointer word_start = p+1; } + // Check if the buffer needs to be enlarged if (o > e) { if (maxbuf) break; // don't overflow buffer l_local_buff += int(o - e) + 200; // enlarge buffer @@ -92,27 +129,37 @@ static const char* expand_text_(const char* from, char*& buf, int maxbuf, double word_end = local_buf + delta_end; } + // Process the character based on its type if (c == '\t') { + // Process tab character for (c = fl_utf_nb_char((uchar*)buf, (int) (o-buf) )%8; c<8 && ow() : 0; + // Image width if image is to the left or right of the text, else 0 + imgtotal = (img && (align&FL_ALIGN_IMAGE_NEXT_TO_TEXT)) ? img->w() + spacing : 0; - int strw = 0; - int strh; + int strw = 0; // Width of text only without symbols + int strh; // Height of text only without symbols + // Count how many lines and put the last one into the buffer: if (str) { for (p = str, lines=0; p;) { e = expand_text_(p, linebuf, 0, w - symtotal - imgtotal, buflen, width, @@ -197,74 +262,109 @@ void fl_draw( } } else lines = 0; - if ((symwidth[0] || symwidth[1]) && lines) { - if (symwidth[0]) symwidth[0] = lines * fl_height(); - if (symwidth[1]) symwidth[1] = lines * fl_height(); + // Fix the size of the symbols if there is at least one line of text to print + if (lines) { + if (symwidth[0]) symwidth[0] = lines * height; + if (symwidth[1]) symwidth[1] = lines * height; } + // Width and height of both symbols combined symtotal = symwidth[0] + symwidth[1]; + // Height of text only strh = lines * fl_height(); - // figure out vertical position of the first line: - int xpos; - int ypos; - int height = fl_height(); - int imgvert = ((align&FL_ALIGN_IMAGE_NEXT_TO_TEXT)==0); - int imgh = img && imgvert ? img->h() : 0; - int imgw[2] = {0, 0}; + // Figure out vertical position of the first element + int xpos; // Position of image or text + int ypos; // Position of image or text + int imgh = img && imgvert ? img->h() + spacing : 0; // Height of image if image is above or below text + int imgw[2] = {0, 0}; // Width of image on the left and right side of the text 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; + // Figure out vertical position of the first line of text or top image + 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... + // Draw the image if located *above* the text if (img && imgvert && !(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]; + 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(); + ypos += img->h() + spacing; } - // draw the image to the side of the text - if (img && !imgvert /* && (align & !FL_ALIGN_TEXT_NEXT_TO_IMAGE)*/ ) { - if (align & FL_ALIGN_TEXT_OVER_IMAGE) { // image is right of text - imgw[1] = img->w(); - if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0] + strw + 1; - else if (align & FL_ALIGN_RIGHT) xpos = x + w - symwidth[1] - imgw[1] + 1; - else xpos = x + (w - strw - symtotal - imgw[1]) / 2 + symwidth[0] + strw + 1; - } else { // image is to the left of the text - imgw[0] = img->w(); - if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0] - 1; - else if (align & FL_ALIGN_RIGHT) xpos = x + w - symwidth[1] - strw - imgw[0] - 1; - else xpos = x + (w - strw - symtotal - imgw[0]) / 2 - 1; + // Draw the image if either on the *left* or *right* side of the text + if (img && !imgvert) { + if (align & FL_ALIGN_TEXT_OVER_IMAGE) { + // Image is to the right of the text + imgw[1] = img->w() + spacing; + // Find the horizontal position of the image + if (align & FL_ALIGN_LEFT) { + xpos = x + symwidth[0] + strw + 1; + } else if (align & FL_ALIGN_RIGHT) { + xpos = x + w - symwidth[1] - imgw[1] + 1; + } else { + xpos = x + (w - strw - symtotal - imgw[1]) / 2 + symwidth[0] + strw + 1; + } + xpos += spacing; + } else { + // Image is to the left of the text + imgw[0] = img->w() + spacing; + // Find the horizontal position of the image + if (align & FL_ALIGN_LEFT) { + xpos = x + symwidth[0] - 1; + } else if (align & FL_ALIGN_RIGHT) { + xpos = x + w - symwidth[1] - strw - imgw[0] - 1; + } else { + xpos = x + (w - strw - symtotal - imgw[0]) / 2 - 1; + } } - int yimg = ypos - height; - if (align & FL_ALIGN_TOP) ; - else if (align & FL_ALIGN_BOTTOM) yimg += strh - img->h() - 1; - else yimg += (strh - img->h() - 1) / 2; + // Find the vertical position of the image + int yimg; + if (align & FL_ALIGN_TOP) { + yimg = ypos - height; + } else if (align & FL_ALIGN_BOTTOM) { + yimg = ypos - height + strh - img->h() - 1; + } else { + yimg = ypos - height + (strh - img->h() - 1) / 2; + } + // Draw the image img->draw(xpos, yimg); } - // now draw all the lines: + // Now draw all the text lines if (str) { int desc = fl_descent(); for (p=str; ; ypos += height) { - if (lines>1) + if (lines>1) { e = expand_text_(p, linebuf, 0, w - symtotal - imgtotal, buflen, width, align&FL_ALIGN_WRAP, draw_symbols); - else e = ""; + } else { + e = ""; + } if (width > symoffset) symoffset = (int)(width + 0.5); - if (align & FL_ALIGN_LEFT) xpos = x + symwidth[0] + imgw[0]; - else if (align & FL_ALIGN_RIGHT) xpos = x + w - (int)(width + .5) - symwidth[1] - imgw[1]; - else xpos = x + (w - (int)(width + .5) - symtotal - imgw[0] - imgw[1]) / 2 + symwidth[0] + imgw[0]; + if (align & FL_ALIGN_LEFT) { + xpos = x + symwidth[0] + imgw[0]; + } else if (align & FL_ALIGN_RIGHT) { + xpos = x + w - (int)(width + .5) - symwidth[1] - imgw[1]; + } else { + xpos = x + (w - (int)(width + .5) - symtotal - imgw[0] - imgw[1]) / 2 + symwidth[0] + imgw[0]; + } callthis(linebuf,buflen,xpos,ypos-desc); @@ -276,70 +376,80 @@ void fl_draw( } } - // draw the image if the "text over image" alignment flag is set... + // Draw the image if the image is *below* the text if (img && imgvert && (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]; + 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); + img->draw(xpos, ypos + spacing); } - // draw the symbols, if any... + // 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; + // Draw the leading symbol to the left of the text + 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; + 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]; + // Draw the trailing symbol to the right of the text + 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; + 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()); } } -/** - Fancy string drawing function which is used to draw all the labels. - - The string is formatted and aligned inside the passed box. - Handles '\\t' and '\\n', expands all other control characters to '^X', - and aligns inside or against the edges of the box. - See Fl_Widget::align() for values of \p align. The value FL_ALIGN_INSIDE - is ignored, as this function always prints inside the box. - If \p img is provided and is not \p NULL, the image is drawn above or - below the text as specified by the \p align value. - The \p draw_symbols argument specifies whether or not to look for symbol - names starting with the '\@' character' -*/ +// Caution: put the documentation next to the function's declaration in fl_draw.H for Doxygen +// to see default argument values. void fl_draw( const char* str, int x, int y, int w, int h, Fl_Align align, Fl_Image* img, - int draw_symbols) + int draw_symbols, + int spacing) { 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_push_clip(x, y, w, h); - fl_draw(str, x, y, w, h, align, fl_draw, img, draw_symbols); + fl_draw(str, x, y, w, h, align, fl_draw, img, draw_symbols, spacing); if (align & FL_ALIGN_CLIP) fl_pop_clip(); } @@ -361,7 +471,9 @@ void fl_draw( \p w to 0 before calling fl_measure() when wrap behavior isn't needed. \param[in] str nul-terminated string - \param[out] w,h width and height of string in current font + \param[in,out] w call with w=0, or with the prefered width for word wrapping, + returns with the width of the string in current font + \param[out] h height of string in current font \param[in] draw_symbols non-zero to enable @@symbol handling [default=1] \code diff --git a/libraries/fltk/src/fl_draw_arrow.cxx b/libraries/fltk/src/fl_draw_arrow.cxx index 3af5c68752..9bba380649 100644 --- a/libraries/fltk/src/fl_draw_arrow.cxx +++ b/libraries/fltk/src/fl_draw_arrow.cxx @@ -86,6 +86,21 @@ static int fl_draw_arrow_single(Fl_Rect r, Fl_Orientation o, Fl_Color col, int d int x1, y1; + // Revert gtk+ specific "chevron style" arrow drawing: see GitHub Issue #1117. + // - gtk_chevron == true : use gtk+ specific ("chevron style") arrows + // - gtk_chevron == false : use standard ("triangle") arrows + // + // Note 1: the "chevron style" was initially copied from Fl_Scrollbar and + // then used in all "arrow" drawings, e.g. in Fl_Menu to unify arrow + // appearance across all widgets and per scheme. This was probably + // too much as mentioned in GitHub Issue #1117. The consequence is to + // set 'gtk_chevron' to false to prevent the "chevron style". + // + // Note 2: In the future we may use more specific arrow types if needed and + // integrate arrow drawing in Fl_Scheme_* classes. + + static const bool gtk_chevron = false; // ... or: Fl::is_scheme("gtk+"); + x1 = r.x(); y1 = r.y(); if (d < 0) @@ -98,7 +113,7 @@ static int fl_draw_arrow_single(Fl_Rect r, Fl_Orientation o, Fl_Color col, int d case FL_ORIENT_LEFT: x1 += (r.w()-d)/2 - 1; y1 += r.h()/2; - if (Fl::is_scheme("gtk+")) + if (gtk_chevron) fl_polygon(x1, y1, x1+d, y1-d, x1+d-1, y1, x1+d, y1+d); else fl_polygon(x1, y1, x1+d, y1-d, x1+d, y1+d); @@ -107,7 +122,7 @@ static int fl_draw_arrow_single(Fl_Rect r, Fl_Orientation o, Fl_Color col, int d case FL_ORIENT_RIGHT: x1 += (r.w()-d)/2; y1 += r.h()/2; - if (Fl::is_scheme("gtk+")) + if (gtk_chevron) fl_polygon(x1, y1-d, x1+1, y1, x1, y1+d, x1+d, y1); else fl_polygon(x1, y1-d, x1, y1+d, x1+d, y1); @@ -116,7 +131,7 @@ static int fl_draw_arrow_single(Fl_Rect r, Fl_Orientation o, Fl_Color col, int d case FL_ORIENT_UP: x1 += r.w()/2; y1 += (r.h()-d)/2 - 1; - if (Fl::is_scheme("gtk+")) + if (gtk_chevron) fl_polygon(x1, y1, x1+d, y1+d, x1, y1+d-1, x1-d, y1+d); else fl_polygon(x1, y1, x1+d, y1+d, x1-d, y1+d); @@ -125,7 +140,7 @@ static int fl_draw_arrow_single(Fl_Rect r, Fl_Orientation o, Fl_Color col, int d case FL_ORIENT_DOWN: x1 += r.w()/2-d; y1 += (r.h()-d)/2; - if (Fl::is_scheme("gtk+")) { + if (gtk_chevron) { fl_polygon(x1, y1, x1+d, y1+1, x1+d, y1+d); fl_polygon(x1+d, y1+1, x1+2*d, y1, x1+d, y1+d); } else { diff --git a/libraries/fltk/src/fl_engraved_label.cxx b/libraries/fltk/src/fl_engraved_label.cxx index 137574c1bf..3f98e3155d 100644 --- a/libraries/fltk/src/fl_engraved_label.cxx +++ b/libraries/fltk/src/fl_engraved_label.cxx @@ -22,48 +22,81 @@ // data[] is dx, dy, color triples -static void innards( - const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align, - const int data[][3], int n) +static void innards(const char *str, int len, int X, int Y, const int data[][3], int n) { - Fl_Align a1 = align; - if (a1 & FL_ALIGN_CLIP) { - fl_push_clip(X, Y, W, H); a1 = (Fl_Align)(a1&~FL_ALIGN_CLIP);} - fl_font((Fl_Font)o->font, o->size); + Fl_Color c = fl_color(); 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); + fl_color((Fl_Color)(i < n-1 ? data[i][2] : c)); + fl_draw(str, len, X+data[i][0], Y+data[i][1]); } - if (align & FL_ALIGN_CLIP) fl_pop_clip(); + fl_color(c); } -static void fl_shadow_label( - const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) +static void dispatch(const Fl_Label* o, + int x, int y, int w, int h, Fl_Align align, + void (*callthis)(const char*,int,int,int)) { + if ((!o->value || !*(o->value)) && !o->image) return; + if (w && h && !fl_not_clipped(x, y, w, h) && (align & FL_ALIGN_INSIDE)) return; + if (align & FL_ALIGN_CLIP) + fl_push_clip(x, y, w, h); + fl_font(o->font, o->size); + fl_color((Fl_Color)o->color); + fl_draw(o->value, x, y, w, h, align, callthis, o->image, 1, o->spacing); + if (align & FL_ALIGN_CLIP) + fl_pop_clip(); +} + + + +// Draw text with shadow +static void fl_shadow_label_draw(const char *str, int len, int x, int y) { static const int data[2][3] = {{2,2,FL_DARK3},{0,0,0}}; - innards(o, X, Y, W, H, align, data, 2); + innards(str, len, x, y, data, 2); } -static void fl_engraved_label( +// Implement shadowed text label type +static void fl_shadow_label( const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) { + dispatch(o, X, Y, W, H, align, fl_shadow_label_draw); +} + + +// Draw text engraved +static void fl_engraved_label_draw(const char *str, int len, int x, int y) { static const 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); + innards(str, len, x, y, data, 7); } -static void fl_embossed_label( +// Implement engraved text label type +static void fl_engraved_label( const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) { + dispatch(o, X, Y, W, H, align, fl_engraved_label_draw); +} + + +// Draw text embossed +static void fl_embossed_label_draw(const char *str, int len, int x, int y) { static const 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); + innards(str, len, x, y, data, 7); } +// Implement embossed text label type +static void fl_embossed_label( + const Fl_Label* o, int X, int Y, int W, int H, Fl_Align align) +{ + dispatch(o, X, Y, W, H, align, fl_embossed_label_draw); +} + + Fl_Labeltype fl_define_FL_SHADOW_LABEL() { Fl::set_labeltype(_FL_SHADOW_LABEL, fl_shadow_label, 0); return _FL_SHADOW_LABEL; diff --git a/libraries/fltk/src/fl_labeltype.cxx b/libraries/fltk/src/fl_labeltype.cxx index 8698c277b0..0984b541d4 100644 --- a/libraries/fltk/src/fl_labeltype.cxx +++ b/libraries/fltk/src/fl_labeltype.cxx @@ -32,7 +32,7 @@ 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); + fl_draw(o->value, X, Y, W, H, align, o->image, 1, o->spacing); } void @@ -44,11 +44,11 @@ fl_normal_measure(const Fl_Label* o, int& W, int& H) { if (o->align_ & FL_ALIGN_IMAGE_BACKDROP) { // backdrop: ignore // ignore backdrop image for calculation } else if (o->align_ & FL_ALIGN_IMAGE_NEXT_TO_TEXT) { // text and image side by side - W += iw; + W += iw + o->spacing; if (ih > H) H = ih; } else { if (iw > W) W = iw; - H += ih; + H += ih + o->spacing; } } } @@ -82,6 +82,16 @@ void Fl::set_labeltype(Fl_Labeltype t,Fl_Label_Draw_F* f,Fl_Label_Measure_F*m) /** Draws a label with arbitrary alignment in an arbitrary box. */ void Fl_Label::draw(int X, int Y, int W, int H, Fl_Align align) const { if (!value && !image) return; + switch (align&(FL_ALIGN_TOP|FL_ALIGN_BOTTOM)) { + case 0: Y += v_margin_; H -= 2*v_margin_; break; + case FL_ALIGN_TOP: Y += v_margin_; H -= v_margin_; break; + case FL_ALIGN_BOTTOM: H -= v_margin_; break; + } + switch (align&(FL_ALIGN_LEFT|FL_ALIGN_RIGHT)) { + case 0: X += h_margin_; W -= 2*h_margin_; break; + case FL_ALIGN_LEFT: X += h_margin_; W -= h_margin_; break; + case FL_ALIGN_RIGHT: W -= h_margin_; break; + } table[type](this, X, Y, W, H, align); } /** @@ -95,6 +105,7 @@ void Fl_Label::measure(int& W, int& H) const { return; } +// if (W > 0) W -= h_margin_; Fl_Label_Measure_F* f = ::measure[type]; if (!f) f = fl_normal_measure; f(this, W, H); } diff --git a/libraries/fltk/src/fl_overlay.cxx b/libraries/fltk/src/fl_overlay.cxx index 31b79b5e48..82e4a13543 100644 --- a/libraries/fltk/src/fl_overlay.cxx +++ b/libraries/fltk/src/fl_overlay.cxx @@ -133,12 +133,28 @@ void fl_overlay_clear() { \see fl_overlay_clear() */ 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 there is already another overlay rect, erase it now if (pw > 0) { if (x==px && y==py && w==pw && h==ph) return; erase_current_rect(); } + // Width and hight must be positive, swap with coordinates if needed + if (w < 0) {x += w; w = -w;} + if (h < 0) {y += h; h = -h;} + // Clip the overlay to the window rect, or reading the background will fail + Fl_Window *win = Fl_Window::current(); + if (win) { + int d; + d = -x; if (d>0) { x += d; w -= d; } + d = (x+w)-win->w(); if (d>0) { w -= d; } + d = -y; if (d>0) { y += d; h -= d; } + d = (y+h)-win->h(); if (d>0) { h -= d; } + } + // + if (w<1) w = 1; + if (h<1) h = 1; + // Store the rect in global variables so we can erase it later px = x; py = y; pw = w; ph = h; + // Draw it draw_current_rect(); } diff --git a/libraries/fltk/src/fl_shadow_box.cxx b/libraries/fltk/src/fl_shadow_box.cxx index 57b0cf048e..16d874afcc 100644 --- a/libraries/fltk/src/fl_shadow_box.cxx +++ b/libraries/fltk/src/fl_shadow_box.cxx @@ -32,7 +32,7 @@ static void fl_shadow_frame(int x, int y, int w, int h, Fl_Color c) { static void fl_shadow_box(int x, int y, int w, int h, Fl_Color c) { Fl::set_box_color(c); - fl_rectf(x+1,y+1,w-2-BW,h-2-BW); + fl_rectf(x,y,w-BW,h-BW); fl_shadow_frame(x,y,w,h,FL_GRAY0); } diff --git a/libraries/fltk/src/gl_draw.cxx b/libraries/fltk/src/gl_draw.cxx index 82ee2b95d5..367990da5b 100644 --- a/libraries/fltk/src/gl_draw.cxx +++ b/libraries/fltk/src/gl_draw.cxx @@ -510,6 +510,11 @@ void Fl_Gl_Window_Driver::draw_string_legacy(const char* str, int n) /** draws a utf8 string using an OpenGL texture */ void Fl_Gl_Window_Driver::draw_string_with_texture(const char* str, int n) { + // Check if the raster pos is valid. + // If it's not, then drawing it results in undefined behaviour (#1006, #1007). + GLint valid; + glGetIntegerv(GL_CURRENT_RASTER_POSITION_VALID, &valid); + if (!valid) return; Fl_Gl_Window *gwin = Fl_Window::current()->as_gl_window(); gl_scale = (gwin ? gwin->pixels_per_unit() : 1); if (!gl_fifo) gl_fifo = new gl_texture_fifo(); diff --git a/libraries/fltk/src/makedepend b/libraries/fltk/src/makedepend index 93d019e16a..b2b83a6f5f 100644 --- a/libraries/fltk/src/makedepend +++ b/libraries/fltk/src/makedepend @@ -248,6 +248,7 @@ drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Box.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Browser.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Button.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Cairo.H +drivers/PostScript/Fl_PostScript.o: ../FL/fl_callback_macros.H drivers/PostScript/Fl_PostScript.o: ../FL/fl_casts.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Check_Button.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Choice.H @@ -272,6 +273,7 @@ drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Menu_Item.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Multi_Label.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Native_File_Chooser.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Paged_Device.H +drivers/PostScript/Fl_PostScript.o: ../FL/Fl_PDF_File_Surface.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Plugin.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_PostScript.H drivers/PostScript/Fl_PostScript.o: ../FL/Fl_Preferences.H @@ -1557,7 +1559,10 @@ Fl_Device.o: ../FL/fl_config.h Fl_Device.o: ../FL/Fl_Device.H Fl_Device.o: ../FL/Fl_Export.H Fl_Device.o: ../FL/Fl_Graphics_Driver.H +Fl_Device.o: ../FL/Fl_Group.H Fl_Device.o: ../FL/Fl_Image.H +Fl_Device.o: ../FL/Fl_Paged_Device.H +Fl_Device.o: ../FL/Fl_PDF_File_Surface.H Fl_Device.o: ../FL/Fl_Pixmap.H Fl_Device.o: ../FL/Fl_Plugin.H Fl_Device.o: ../FL/Fl_Preferences.H @@ -1565,6 +1570,8 @@ Fl_Device.o: ../FL/Fl_RGB_Image.H Fl_Device.o: ../FL/fl_types.h Fl_Device.o: ../FL/fl_utf8.h Fl_Device.o: ../FL/Fl_Widget.H +Fl_Device.o: ../FL/Fl_Widget_Surface.H +Fl_Device.o: ../FL/Fl_Window.H Fl_Device.o: ../FL/platform_types.h Fl_Dial.o: ../FL/Enumerations.H Fl_Dial.o: ../FL/Fl.H @@ -2352,6 +2359,8 @@ Fl_Help_View.o: ../FL/Fl_Graphics_Driver.H Fl_Help_View.o: ../FL/Fl_Group.H Fl_Help_View.o: ../FL/Fl_Help_View.H Fl_Help_View.o: ../FL/Fl_Image.H +Fl_Help_View.o: ../FL/Fl_Menu_Item.H +Fl_Help_View.o: ../FL/Fl_Multi_Label.H Fl_Help_View.o: ../FL/Fl_Pixmap.H Fl_Help_View.o: ../FL/Fl_Plugin.H Fl_Help_View.o: ../FL/Fl_Preferences.H @@ -3002,6 +3011,7 @@ Fl_Native_File_Chooser_Kdialog.o: drivers/Unix/Fl_Unix_Screen_Driver.H Fl_Native_File_Chooser_Kdialog.o: Fl_Native_File_Chooser_Kdialog.H Fl_Native_File_Chooser_Kdialog.o: Fl_Screen_Driver.H Fl_Native_File_Chooser_Kdialog.o: Fl_String.H +Fl_Native_File_Chooser_Kdialog.o: Fl_System_Driver.H Fl_Native_File_Chooser_Kdialog.o: Fl_Window_Driver.H Fl_Native_File_Chooser_Zenity.o: ../config.h Fl_Native_File_Chooser_Zenity.o: ../FL/Enumerations.H @@ -3691,6 +3701,7 @@ fl_shortcut.o: Fl_Screen_Driver.H fl_shortcut.o: Fl_System_Driver.H Fl_Shortcut_Button.o: ../config.h Fl_Shortcut_Button.o: ../FL/Enumerations.H +Fl_Shortcut_Button.o: ../FL/filename.H Fl_Shortcut_Button.o: ../FL/Fl.H Fl_Shortcut_Button.o: ../FL/fl_attr.h Fl_Shortcut_Button.o: ../FL/Fl_Button.H @@ -3699,6 +3710,7 @@ Fl_Shortcut_Button.o: ../FL/fl_casts.H Fl_Shortcut_Button.o: ../FL/fl_config.h Fl_Shortcut_Button.o: ../FL/fl_draw.H Fl_Shortcut_Button.o: ../FL/Fl_Export.H +Fl_Shortcut_Button.o: ../FL/Fl_Preferences.H Fl_Shortcut_Button.o: ../FL/Fl_Shortcut_Button.H Fl_Shortcut_Button.o: ../FL/fl_string_functions.h Fl_Shortcut_Button.o: ../FL/fl_types.h @@ -3706,6 +3718,7 @@ Fl_Shortcut_Button.o: ../FL/fl_utf8.h Fl_Shortcut_Button.o: ../FL/Fl_Widget.H Fl_Shortcut_Button.o: ../FL/platform_types.h Fl_Shortcut_Button.o: flstring.h +Fl_Shortcut_Button.o: Fl_System_Driver.H fl_show_colormap.o: ../config.h fl_show_colormap.o: ../FL/Enumerations.H fl_show_colormap.o: ../FL/Fl.H @@ -4068,6 +4081,7 @@ Fl_Tiled_Image.o: ../FL/fl_utf8.h Fl_Tiled_Image.o: ../FL/Fl_Widget.H Fl_Tiled_Image.o: ../FL/Fl_Window.H Fl_Tiled_Image.o: ../FL/platform_types.h +Fl_Timeout.o: ../config.h Fl_Timeout.o: ../FL/Enumerations.H Fl_Timeout.o: ../FL/filename.H Fl_Timeout.o: ../FL/Fl.H @@ -4145,6 +4159,7 @@ Fl_Tree.o: ../FL/Fl_Valuator.H Fl_Tree.o: ../FL/Fl_Widget.H Fl_Tree.o: ../FL/platform_types.h Fl_Tree_Item.o: ../FL/Enumerations.H +Fl_Tree_Item.o: ../FL/filename.H Fl_Tree_Item.o: ../FL/Fl.H Fl_Tree_Item.o: ../FL/fl_attr.h Fl_Tree_Item.o: ../FL/Fl_Cairo.H @@ -4154,6 +4169,7 @@ Fl_Tree_Item.o: ../FL/fl_draw.H Fl_Tree_Item.o: ../FL/Fl_Export.H Fl_Tree_Item.o: ../FL/Fl_Group.H Fl_Tree_Item.o: ../FL/Fl_Image.H +Fl_Tree_Item.o: ../FL/Fl_Preferences.H Fl_Tree_Item.o: ../FL/Fl_Scrollbar.H Fl_Tree_Item.o: ../FL/Fl_Slider.H Fl_Tree_Item.o: ../FL/fl_string_functions.h @@ -4166,6 +4182,7 @@ Fl_Tree_Item.o: ../FL/fl_utf8.h Fl_Tree_Item.o: ../FL/Fl_Valuator.H Fl_Tree_Item.o: ../FL/Fl_Widget.H Fl_Tree_Item.o: ../FL/platform_types.h +Fl_Tree_Item.o: Fl_System_Driver.H Fl_Tree_Item_Array.o: ../FL/Enumerations.H Fl_Tree_Item_Array.o: ../FL/Fl.H Fl_Tree_Item_Array.o: ../FL/fl_attr.h @@ -4190,13 +4207,14 @@ Fl_Tree_Prefs.o: ../FL/fl_attr.h Fl_Tree_Prefs.o: ../FL/Fl_Cairo.H Fl_Tree_Prefs.o: ../FL/fl_casts.H Fl_Tree_Prefs.o: ../FL/fl_config.h +Fl_Tree_Prefs.o: ../FL/fl_draw.H Fl_Tree_Prefs.o: ../FL/Fl_Export.H Fl_Tree_Prefs.o: ../FL/Fl_Image.H -Fl_Tree_Prefs.o: ../FL/Fl_Pixmap.H Fl_Tree_Prefs.o: ../FL/Fl_Preferences.H Fl_Tree_Prefs.o: ../FL/Fl_Tree_Prefs.H Fl_Tree_Prefs.o: ../FL/fl_types.h Fl_Tree_Prefs.o: ../FL/fl_utf8.h +Fl_Tree_Prefs.o: ../FL/Fl_Widget.H Fl_Tree_Prefs.o: ../FL/platform_types.h Fl_Tree_Prefs.o: Fl_System_Driver.H fl_utf8.o: ../FL/Enumerations.H diff --git a/libraries/fltk/src/nanosvg.cxx b/libraries/fltk/src/nanosvg.cxx index abb98310b7..69012712c4 100644 --- a/libraries/fltk/src/nanosvg.cxx +++ b/libraries/fltk/src/nanosvg.cxx @@ -40,12 +40,6 @@ static float nsvg__roundf(float x); // prototype (see nanosvgrast.h) // End of GitHub Issue #937. Remove this entire block when upstream is patched. -#if !defined(HAVE_LONG_LONG) -static double strtoll(const char *str, char **endptr, int base) { - return (double)strtol(str, endptr, base); -} -#endif - #ifdef _MSC_VER #pragma warning (disable: 4244) // Switch off conversion warnings #endif diff --git a/libraries/fltk/src/screen_xywh.cxx b/libraries/fltk/src/screen_xywh.cxx index 604611d6b2..60ad002873 100644 --- a/libraries/fltk/src/screen_xywh.cxx +++ b/libraries/fltk/src/screen_xywh.cxx @@ -1,7 +1,7 @@ // // Screen/monitor bounding box API for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2018 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -57,7 +57,7 @@ int Fl::h() /** Gets the total count of available screens. - \note Screen numbers range from 0 to Fl::screen_count()-1 in the FLTK API. + \note Screen numbers range from 0 to Fl::screen_count() - 1 in the FLTK API. */ int Fl::screen_count() { @@ -133,13 +133,16 @@ void Fl::screen_xywh(int &X, int &Y, int &W, int &H, int mx, int my, int mw, int /** - Gets the screen number of a screen - that contains the specified screen position \p x, \p y + Gets the screen number of a screen that contains the specified + screen position \p x, \p y. + \param[in] x, y the absolute screen position \return a screen number ∈ [0 , Fl::screen_count()-1] - \attention When the running system contains screens with different scaling factor values, this API - may become ambiguous because a given value pair (\p x, \p y) may belong to distinct screens. - In that situation, other APIs should be preferred, e.g., Fl_Window::screen_num() and Fl::screen_scale(int). + + \attention When the running system contains screens with different scaling + factors, this API may become ambiguous because a given value pair (\p x, \p y) + may belong to distinct screens. In that situation other APIs should be + preferred, e.g. Fl_Window::screen_num() and Fl::screen_scale(int). */ int Fl::screen_num(int x, int y) { @@ -148,12 +151,13 @@ int Fl::screen_num(int x, int y) /** - Gets the screen number for the screen - which intersects the most with the rectangle - defined by \p x, \p y, \p w, \p h. + Gets the screen number of the screen which intersects the most with + the rectangle defined by \p x, \p y, \p w, \p h. + \param[in] x, y, w, h the rectangle to search for intersection with + \return a screen number ∈ [0 , Fl::screen_count()-1] - */ +*/ int Fl::screen_num(int x, int y, int w, int h) { return screen_driver()->screen_num(x, y, w, h); diff --git a/libraries/fltk/test/.gitignore b/libraries/fltk/test/.gitignore deleted file mode 100644 index 0c1ef9d619..0000000000 --- a/libraries/fltk/test/.gitignore +++ /dev/null @@ -1,151 +0,0 @@ -# -# Files to be ignored by Git (do not commit) -# -# Note: *.exe will be ignored by means of ../.gitignore -# - -# Windows/MSVC files and maybe others - -*.bck -fltk*.dll -fltk*.exp -fltk*.lib -*.ilk - -# Linux/Unix/macOS executables - -adjuster -animated -arc -ask -bitmap -blocks -boxtype -browser -button -buttons -cairo_test -checkers -clipboard -clock -colbrowser -color_chooser -contrast -coordinates -cube -CubeView -cursor -curve -demo -device -doublebuffer -editor -fast_slow -file_chooser -flex_demo -flex_login -fltk-versions -fonts -forms -fractals -fullscreen -gl_overlay -glpuzzle -glut_test -grid_alignment -grid_buttons -grid_dialog -grid_login -handle_events -hello -help_dialog -icon -iconize -image -inactive -input -input_choice -keyboard -label -line_style -list_visuals -mandelbrot -menubar -message -minimum -native-filechooser -navigation -offscreen -output -overlay -pack -pixmap -pixmap_browser -preferences -radio -resize -resizebox -resize-example1 -resize-example2 -resize-example3a -resize-example3b -resize-example3c -resize-example3d -resize-example4a -resize-example4b -resize-example5a -resize-example5b -resize-example5c -rotated_text -scroll -shape -subwindow -sudoku -symbols -table -tabs -terminal -threads -tile -tiled_image -tree -twowin -unittests -utf8 -valuators -windowfocus -wizard - -# macOS binary files - -*.app - -# fluid generated source files and headers, generated using bash: -# > for f in *.fl;do b=`basename $f .fl`;echo $b.cxx;echo $b.h;done - -CubeViewUI.cxx -CubeViewUI.h -checkers_pieces.cxx -checkers_pieces.h -fast_slow.cxx -fast_slow.h -inactive.cxx -inactive.h -keyboard_ui.cxx -keyboard_ui.h -mandelbrot_ui.cxx -mandelbrot_ui.h -preferences.cxx -preferences.h -radio.cxx -radio.h -resize.cxx -resize.h -tabs.cxx -tabs.h -terminal.cxx -terminal.h -tree.cxx -tree.h -valuators.cxx -valuators.h diff --git a/libraries/fltk/test/CMakeLists.txt b/libraries/fltk/test/CMakeLists.txt index 692730db19..a92d700a31 100644 --- a/libraries/fltk/test/CMakeLists.txt +++ b/libraries/fltk/test/CMakeLists.txt @@ -129,6 +129,7 @@ fl_create_example(input_choice input_choice.cxx fltk::fltk) fl_create_example(keyboard "keyboard.cxx;keyboard_ui.fl" fltk::fltk) fl_create_example(label label.cxx fltk::fltk) fl_create_example(line_style line_style.cxx fltk::fltk) +fl_create_example(line_style_docs line_style_docs.cxx fltk::fltk) fl_create_example(list_visuals list_visuals.cxx fltk::fltk) fl_create_example(mandelbrot "mandelbrot_ui.fl;mandelbrot.cxx" fltk::fltk) fl_create_example(menubar menubar.cxx fltk::fltk) diff --git a/libraries/fltk/test/Makefile b/libraries/fltk/test/Makefile index 8145134af4..05fdf54eee 100644 --- a/libraries/fltk/test/Makefile +++ b/libraries/fltk/test/Makefile @@ -1,5 +1,5 @@ # -# Test/example program Makefile for the Fast Light Tool Kit (FLTK). +# Test/demo program Makefile for the Fast Light Tool Kit (FLTK). # # Copyright 1998-2024 by Bill Spitzak and others. # @@ -91,6 +91,7 @@ CPPFILES =\ keyboard.cxx \ label.cxx \ line_style.cxx \ + line_style_docs.cxx \ list_visuals.cxx \ mandelbrot.cxx \ menubar.cxx \ @@ -180,6 +181,7 @@ ALL = \ input_choice$(EXEEXT) \ label$(EXEEXT) \ line_style$(EXEEXT) \ + line_style_docs$(EXEEXT) \ list_visuals$(EXEEXT) \ menubar$(EXEEXT) \ message$(EXEEXT) \ @@ -280,60 +282,60 @@ clean: install: all echo "Installing example programs to $(DESTDIR)$(docdir)/examples..." - -$(INSTALL_DIR) $(DESTDIR)$(docdir)/examples + -$(INSTALL_DIR) "$(DESTDIR)$(docdir)/examples" for file in *.h *.cxx *.fl demo.menu; do \ - $(INSTALL_DATA) $$file $(DESTDIR)$(docdir)/examples; \ + $(INSTALL_DATA) $$file "$(DESTDIR)$(docdir)/examples"; \ done - -$(INSTALL_DIR) $(DESTDIR)$(docdir)/examples/pixmaps + -$(INSTALL_DIR) "$(DESTDIR)$(docdir)/examples/pixmaps" for file in pixmaps/*.xbm pixmaps/*.xpm; do \ - $(INSTALL_DATA) $$file $(DESTDIR)$(docdir)/examples/pixmaps; \ + $(INSTALL_DATA) $$file "$(DESTDIR)$(docdir)/examples/pixmaps"; \ done install-linux: echo Installing games to $(DESTDIR)$(bindir)... - -$(INSTALL_DIR) $(DESTDIR)$(bindir) - -$(INSTALL_DIR) $(DESTDIR)/usr/share/applications - -$(INSTALL_DIR) $(DESTDIR)/usr/share/icons/hicolor/32x32/apps - -$(INSTALL_DIR) $(DESTDIR)/usr/share/icons/hicolor/128x128/apps + -$(INSTALL_DIR) "$(DESTDIR)$(bindir)" + -$(INSTALL_DIR) "$(DESTDIR)$(datadir)/applications" + -$(INSTALL_DIR) "$(DESTDIR)$(datadir)/icons/hicolor/32x32/apps" + -$(INSTALL_DIR) "$(DESTDIR)$(datadir)/icons/hicolor/128x128/apps" for game in blocks checkers sudoku; do \ - $(INSTALL_BIN) $$game $(DESTDIR)$(bindir); \ - $(INSTALL_DATA) desktop/$$game.desktop $(DESTDIR)/usr/share/applications; \ - $(INSTALL_DATA) desktop/$$game-32.png $(DESTDIR)/usr/share/icons/hicolor/32x32/apps/$$game.png; \ - $(INSTALL_DATA) desktop/$$game-128.png $(DESTDIR)/usr/share/icons/hicolor/128x128/apps/$$game.png; \ + $(INSTALL_BIN) $$game "$(DESTDIR)$(bindir)"; \ + $(INSTALL_DATA) desktop/$$game.desktop "$(DESTDIR)$(datadir)/applications"; \ + $(INSTALL_DATA) desktop/$$game-32.png "$(DESTDIR)$(datadir)/icons/hicolor/32x32/apps/$$game.png"; \ + $(INSTALL_DATA) desktop/$$game-128.png "$(DESTDIR)$(datadir)/icons/hicolor/128x128/apps/$$game.png"; \ done install-osx: echo Installing games in $(DESTDIR)/Applications... for game in blocks checkers sudoku; do \ - if test ! -d $(DESTDIR)/Applications/$$game.app; then \ - $(INSTALL_DIR) $(DESTDIR)/Applications/$$game.app; \ - $(INSTALL_DIR) $(DESTDIR)/Applications/$$game.app/Contents; \ - $(INSTALL_DIR) $(DESTDIR)/Applications/$$game.app/Contents/MacOS; \ - $(INSTALL_DIR) $(DESTDIR)/Applications/$$game.app/Contents/Resources; \ + if test ! -d "$(DESTDIR)/Applications/$$game.app"; then \ + $(INSTALL_DIR) "$(DESTDIR)/Applications/$$game.app"; \ + $(INSTALL_DIR) "$(DESTDIR)/Applications/$$game.app/Contents"; \ + $(INSTALL_DIR) "$(DESTDIR)/Applications/$$game.app/Contents/MacOS"; \ + $(INSTALL_DIR) "$(DESTDIR)/Applications/$$game.app/Contents/Resources"; \ fi; \ - $(INSTALL_DATA) $$game.app/Contents/Info.plist $(DESTDIR)/Applications/$$game.app/Contents; \ - $(INSTALL_BIN) $$game.app/Contents/MacOS/$$game $(DESTDIR)/Applications/$$game.app/Contents/MacOS; \ - $(INSTALL_DATA) $$game.app/Contents/Resources/$$game.icns $(DESTDIR)/Applications/$$game.app/Contents/Resources; \ + $(INSTALL_DATA) $$game.app/Contents/Info.plist "$(DESTDIR)/Applications/$$game.app/Contents"; \ + $(INSTALL_BIN) $$game.app/Contents/MacOS/$$game "$(DESTDIR)/Applications/$$game.app/Contents/MacOS"; \ + $(INSTALL_DATA) $$game.app/Contents/Resources/$$game.icns "$(DESTDIR)/Applications/$$game.app/Contents/Resources"; \ done uninstall: echo "Removing examples programs from $(DESTDIR)$(docdir)/examples..." - -$(RMDIR) $(DESTDIR)$(docdir)/examples + -$(RMDIR) "$(DESTDIR)$(docdir)/examples" uninstall-linux: echo Removing games from $(DESTDIR)$(bindir)... for game in blocks checkers sudoku; do \ - $(RM) $(DESTDIR)$(bindir)/$$game; \ - $(RM) $(DESTDIR)/usr/share/applications/$$game.desktop; \ - $(RM) $(DESTDIR)/usr/share/icons/hicolor/32x32/apps/$$game.png; \ - $(RM) $(DESTDIR)/usr/share/icons/hicolor/128x128/apps/$$game.png; \ + $(RM) "$(DESTDIR)$(bindir)/$$game"; \ + $(RM) "$(DESTDIR)$(datadir)/applications/$$game.desktop"; \ + $(RM) "$(DESTDIR)$(datadir)/icons/hicolor/32x32/apps/$$game.png"; \ + $(RM) "$(DESTDIR)$(datadir)/icons/hicolor/128x128/apps/$$game.png"; \ done uninstall-osx: echo Removing games from $(DESTDIR)/Applications... - $(RMDIR) $(DESTDIR)/Applications/blocks.app - $(RMDIR) $(DESTDIR)/Applications/checkers.app - $(RMDIR) $(DESTDIR)/Applications/sudoku.app + $(RMDIR) "$(DESTDIR)/Applications/blocks.app" + $(RMDIR) "$(DESTDIR)/Applications/checkers.app" + $(RMDIR) "$(DESTDIR)/Applications/sudoku.app" # FLUID file rules .fl.cxx .fl.h: @@ -494,6 +496,8 @@ label$(EXEEXT): label.o line_style$(EXEEXT): line_style.o +line_style_docs$(EXEEXT): line_style_docs.o + list_visuals$(EXEEXT): list_visuals.o mandelbrot$(EXEEXT): mandelbrot_ui.o mandelbrot.o diff --git a/libraries/fltk/test/demo.menu b/libraries/fltk/test/demo.menu index e608f54e81..2869c6cf94 100644 --- a/libraries/fltk/test/demo.menu +++ b/libraries/fltk/test/demo.menu @@ -103,6 +103,7 @@ @i:clock:clock @i:popups:message @i:boxtypes:boxtype + @i:line styles:line_style_docs @i:Resize Examples\n...:@ir @ir:Example\n1:resize-example1 @ir:Example\n2:resize-example2 diff --git a/libraries/fltk/test/editor.cxx b/libraries/fltk/test/editor.cxx index 360e3eed7e..043066108e 100644 --- a/libraries/fltk/test/editor.cxx +++ b/libraries/fltk/test/editor.cxx @@ -658,7 +658,7 @@ void tut9_split_editor() { app_window->end(); app_window->resizable(app_tile); app_tile->resizable(app_editor); - app_menu_bar->add("Window/Split", FL_COMMAND+'2', menu_split_callback, NULL, FL_MENU_TOGGLE); + app_menu_bar->add("Window/Split", FL_COMMAND+'i', menu_split_callback, NULL, FL_MENU_TOGGLE); } #endif diff --git a/libraries/fltk/test/fltk-versions.cxx b/libraries/fltk/test/fltk-versions.cxx index ed80c7b1f6..2932f64354 100644 --- a/libraries/fltk/test/fltk-versions.cxx +++ b/libraries/fltk/test/fltk-versions.cxx @@ -1,7 +1,7 @@ // // Library version test program for the Fast Light Tool Kit (FLTK). // -// Copyright 1998-2017 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -14,65 +14,129 @@ // https://www.fltk.org/bugs.php // +// This program is work in progress and may not be "perfect". + #include +#include #include +#include #include #include - #include -static char version[8][80] = { "","","","","","","","" }; +static const int ww = 640, mw = 750; // initial, max. window width +static const int wh = 200, mh = 300; // initial, max. window height -int main(int argc, char **argv) { +// Function to determine the platform (system and backend). +// Note: the display must have been opened before this is called. +// Returns a string describing the system/platform and backend. - int versions = 0; +static const char *get_platform() { +#if defined(_WIN32) + return "Windows"; +#elif defined(FLTK_USE_X11) || defined(FLTK_USE_WAYLAND) +# if defined(FLTK_USE_X11) + if (fl_x11_display()) + return "Unix/Linux (X11)"; +# endif +# if defined(FLTK_USE_WAYLAND) + if (fl_wl_display()) + return "Unix/Linux (Wayland)"; +# endif + return "X11 or Wayland (backend unknown or display not opened)"; +#elif defined(__APPLE__) + return "macOS (native)"; +#endif + return "platform unknown, unsupported, or display not opened"; +} - sprintf(version[versions++],"FL_VERSION = %6.4f",FL_VERSION); - sprintf(version[versions++],"Fl::version() = %6.4f %s",Fl::version(), - (FL_VERSION == Fl::version()) ? "" : "***"); +// set box attributes and optionally set a background color (debug mode) -#ifdef FL_API_VERSION - sprintf(version[versions++],"FL_API_VERSION = %6d",FL_API_VERSION); - sprintf(version[versions++],"Fl::api_version() = %6d %s",Fl::api_version(), - (FL_API_VERSION == Fl::api_version()) ? "" : "***"); +static void set_attributes(Fl_Widget *w, Fl_Color col) { + w->labelfont(FL_COURIER); + w->labelsize(16); + w->align(FL_ALIGN_CENTER | FL_ALIGN_INSIDE); +#if (0) // 1 = debug: set a background color for a box (widget) + w->box(FL_FLAT_BOX); + w->color(col); #endif +} -#ifdef FL_ABI_VERSION - sprintf(version[versions++],"FL_ABI_VERSION = %6d",FL_ABI_VERSION); - sprintf(version[versions++],"Fl::abi_version() = %6d %s",Fl::abi_version(), - (FL_ABI_VERSION == Fl::abi_version()) ? "" : "***"); -#endif +static char version[9][80]; +static Fl_Box *box[9]; - for (int i=0; ilayout(4, 3, 20, 5); - for (int i=0; i<8; i++) { - box[i]->labelfont(FL_COURIER); - box[i]->align(FL_ALIGN_LEFT | FL_ALIGN_INSIDE); + Fl_Box *title = new Fl_Box(0, 0, 0, 0, platform); + set_attributes(title, FL_YELLOW); + title->labelfont(FL_HELVETICA_BOLD); + grid->widget(title, 0, 0, 1, 3); + grid->row_height(0, 40); + title->labelsize(20); + + for (int i = 0; i < 3; i += 1) { + box[3 * i ] = new Fl_Box(0, 0, 270, 0, version[3 * i]); + box[3 * i + 1] = new Fl_Box(0, 0, 270, 0, version[3 * i + 1]); + box[3 * i + 2] = new Fl_Box(0, 0, 40, 0, version[3 * i + 2]); + grid->widget(box[3 * i], i + 1, 0); + grid->widget(box[3 * i + 1], i + 1, 1); + grid->widget(box[3 * i + 2], i + 1, 2); + grid->row_height(i + 1, 30); } + for (int i = 0; i < 9; i++) + set_attributes(box[i], FL_GREEN); + window->end(); + window->resizable(grid); + window->size_range(ww, wh, mw, mh); window->show(argc, argv); return Fl::run(); } diff --git a/libraries/fltk/test/fractals.cxx b/libraries/fltk/test/fractals.cxx index bbdde0569b..d9cf9905fb 100644 --- a/libraries/fltk/test/fractals.cxx +++ b/libraries/fltk/test/fractals.cxx @@ -724,28 +724,28 @@ void MenuInit(void) int submenu3, submenu2, submenu1; submenu1 = glutCreateMenu(setlevel); - glutAddMenuEntry((char *)"0", 0); glutAddMenuEntry((char *)"1", 1); - glutAddMenuEntry((char *)"2", 2); glutAddMenuEntry((char *)"3", 3); - glutAddMenuEntry((char *)"4", 4); glutAddMenuEntry((char *)"5", 5); - glutAddMenuEntry((char *)"6", 6); glutAddMenuEntry((char *)"7", 7); - glutAddMenuEntry((char *)"8", 8); + glutAddMenuEntry("0", 0); glutAddMenuEntry("1", 1); + glutAddMenuEntry("2", 2); glutAddMenuEntry("3", 3); + glutAddMenuEntry("4", 4); glutAddMenuEntry("5", 5); + glutAddMenuEntry("6", 6); glutAddMenuEntry("7", 7); + glutAddMenuEntry("8", 8); submenu2 = glutCreateMenu(choosefract); - glutAddMenuEntry((char *)"Moutain", MOUNTAIN); - glutAddMenuEntry((char *)"Tree", TREE); - glutAddMenuEntry((char *)"Island", ISLAND); + glutAddMenuEntry("Moutain", MOUNTAIN); + glutAddMenuEntry("Tree", TREE); + glutAddMenuEntry("Island", ISLAND); submenu3 = glutCreateMenu(agvSwitchMoveMode); - glutAddMenuEntry((char *)"Flying", FLYING); - glutAddMenuEntry((char *)"Polar", POLAR); + glutAddMenuEntry("Flying", FLYING); + glutAddMenuEntry("Polar", POLAR); glutCreateMenu(handlemenu); glutAddSubMenu((char *)"Level", submenu1); glutAddSubMenu((char *)"Fractal", submenu2); glutAddSubMenu((char *)"Movement", submenu3); - glutAddMenuEntry((char *)"New Fractal", MENU_RAND); - glutAddMenuEntry((char *)"Toggle Axes", MENU_AXES); - glutAddMenuEntry((char *)"Quit", MENU_QUIT); + glutAddMenuEntry("New Fractal", MENU_RAND); + glutAddMenuEntry("Toggle Axes", MENU_AXES); + glutAddMenuEntry("Quit", MENU_QUIT); glutAttachMenu(GLUT_RIGHT_BUTTON); } diff --git a/libraries/fltk/test/fullscreen.cxx b/libraries/fltk/test/fullscreen.cxx index 780eae32d8..65c25036ab 100644 --- a/libraries/fltk/test/fullscreen.cxx +++ b/libraries/fltk/test/fullscreen.cxx @@ -1,6 +1,6 @@ // // -// Copyright 1998-2023 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -174,21 +174,22 @@ void double_cb(Fl_Widget *o, void *p) { void double_cb(Fl_Widget *, void *) {} #endif -void border_cb(Fl_Widget *o, void *p) { - Fl_Window *w = (Fl_Window *)p; - int d = ((Fl_Button *)o)->value(); + +void border_cb(Fl_Button *b, Fl_Window *w) { + int d = b->value(); w->border(d); + // border change may have been refused (e.g. with fullscreen window) + if ((int)w->border() != d) b->value(w->border()); } -void maximize_cb(Fl_Widget *o, void *p) { - Fl_Window *w = (Fl_Window *)p; +void maximize_cb(Fl_Button *b, Fl_Window *w) { if (w->maximize_active()) { w->un_maximize(); - //((Fl_Button*)o)->set(); + if (w->maximize_active()) b->set(); } else { w->maximize(); - //((Fl_Button*)o)->clear(); + if (!w->maximize_active()) b->clear(); } } @@ -337,7 +338,7 @@ int main(int argc, char **argv) { y+=30; Fl_Toggle_Light_Button b2(50,y,window.w()-60,30,"Border"); - b2.callback(border_cb,w); + b2.callback((Fl_Callback*)border_cb,w); b2.set(); border_button = &b2; y+=30; @@ -347,7 +348,7 @@ int main(int argc, char **argv) { y+=30; window.b3_maxi = new Fl_Toggle_Light_Button(50,y,window.w()-60,30,"Maximize"); - window.b3_maxi->callback(maximize_cb,w); + window.b3_maxi->callback((Fl_Callback*)maximize_cb,w); y+=30; window.b4 = new Fl_Toggle_Light_Button(50,y,window.w()-60,30,"All Screens"); diff --git a/libraries/fltk/test/glpuzzle.cxx b/libraries/fltk/test/glpuzzle.cxx index 2e8a307d5d..f6d1c529e6 100644 --- a/libraries/fltk/test/glpuzzle.cxx +++ b/libraries/fltk/test/glpuzzle.cxx @@ -4,7 +4,7 @@ // This is a GLUT demo program to demonstrate fltk's GLUT emulation. // Search for "fltk" to find all the changes // -// Copyright 1998-2020 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -1485,10 +1485,10 @@ main(int argc, char **argv) glutMouseFunc(mouse); glutVisibilityFunc(visibility); glutCreateMenu(menu); - glutAddMenuEntry((char *)"Normal pos", 1); - glutAddMenuEntry((char *)"Solve", 2); - glutAddMenuEntry((char *)"Reset", 3); - glutAddMenuEntry((char *)"Quit", 4); + glutAddMenuEntry("Normal pos", 1); + glutAddMenuEntry("Solve", 2); + glutAddMenuEntry("Reset", 3); + glutAddMenuEntry("Quit", 4); glutAttachMenu(GLUT_RIGHT_BUTTON); glutMainLoop(); return 0; /* ANSI C requires main to return int. */ diff --git a/libraries/fltk/test/handle_keys.cxx b/libraries/fltk/test/handle_keys.cxx index de38ef38c5..ea5474ffb9 100644 --- a/libraries/fltk/test/handle_keys.cxx +++ b/libraries/fltk/test/handle_keys.cxx @@ -35,9 +35,11 @@ Fl_Check_Button *scaling = NULL; // Text in the headline and after clearing the terminal buffer. For alignment ... // 1 2 3 4 5 6 7 8 -// 12345678901234567890123456789012345678901234567890123456789012345678901234567890 +// 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345 static const char *headline_text = - "[nnn] Event Key Name, Flags: C A S M N L Text Unicode UTF-8/hex"; + "[nnn] Event Key Name, Flags: C A S M N L Text Unicode UTF-8/hex"; + +static const int lkn = 14; // length of key name field // Tooltip for headline and terminal widgets static const char *tt = @@ -101,22 +103,21 @@ struct keycode_table { const char *get_keyname(int k, int &lg) { static char buffer[32]; + lg = 0; if (!k) { + lg = 1; return "0"; } else if (k < 32) { // control character - sprintf(buffer, "^%c", (char)(k + 64)); - lg = 2; + lg = sprintf(buffer, "^%c", (char)(k + 64)); } else if (k < 128) { // ASCII - snprintf(buffer, sizeof(buffer), "'%c'", k); - lg = 3; + lg = snprintf(buffer, sizeof(buffer), "'%c'", k); } else if (k >= 0xa0 && k <= 0xff) { // ISO-8859-1 (international keyboards) char key[8]; int kl = fl_utf8encode((unsigned)k, key); key[kl] = '\0'; - snprintf(buffer, sizeof(buffer), "'%s'", key); - lg = 3; + lg = snprintf(buffer, sizeof(buffer), "'%s'", key); } else if (k > FL_F && k <= FL_F_Last) { lg = snprintf(buffer, sizeof(buffer), "FL_F+%d", k - FL_F); } else if (k >= FL_KP && k <= FL_KP_Last) { @@ -197,12 +198,15 @@ int app::print_event(int ev) { switch(ev) { case FL_KEYBOARD: if (!keydown->value()) return 0; + tty->textfgcolor(FL_BLACK); break; case FL_KEYUP: if (!keyup->value()) return 0; + tty->textfgcolor(FL_BLUE); break; case FL_SHORTCUT: if (!shortcut->value()) return 0; + tty->textfgcolor(0x00aa0000); // dark green break; default: return 0; @@ -224,18 +228,23 @@ int app::handle(int ev) { const char *etxt = Fl::event_text(); int ekey = Fl::event_key(); int elen = Fl::event_length(); - char ctrl = (Fl::event_state() & FL_COMMAND) ? 'C' : '.'; + char ctrl = (Fl::event_state() & FL_CTRL) ? 'C' : '.'; char alt = (Fl::event_state() & FL_ALT) ? 'A' : '.'; char shift = (Fl::event_state() & FL_SHIFT) ? 'S' : '.'; char meta = (Fl::event_state() & FL_META) ? 'M' : '.'; char numlk = (Fl::event_state() & FL_NUM_LOCK) ? 'N' : '.'; char capslk = (Fl::event_state() & FL_CAPS_LOCK) ? 'L' : '.'; - tty->printf("%06x ", ekey); // event key number (hex) int lg = 0; + char ekns[12]; // event key (hex) as string + sprintf(ekns, "0x%04x", ekey); // may be up to 10 chars + tty->printf("%10s ", ekns); // event key number (hex) + tty->printf("%s", get_keyname(ekey, lg)); - for (int i = lg; i < 14; i++) { - tty->printf(" "); + if (lg < lkn) { + for (int i = 0; i < lkn - lg; i++) { + tty->append_ascii(" "); + } } tty->printf("%c %c %c %c %c %c ", ctrl, alt, shift, meta, numlk, capslk); @@ -254,6 +263,7 @@ int app::handle(int ev) { } else { tty->printf("'' "); } + tty->textfgcolor(FL_BLACK); tty->printf("\n"); return res; } // app::handle() @@ -302,6 +312,12 @@ void toggle_cb(Fl_Widget *w, void *) { void toggle_scaling(Fl_Widget *w, void *v) { int toggle = ((Fl_Button*)w)->value() ? 1 : 0; Fl::keyboard_screen_scaling(toggle); + if (toggle) { + Terminal *tty = ((app *)w->window())->tty; + int simple_zoom = Fl::option(Fl::OPTION_SIMPLE_ZOOM_SHORTCUT); + tty->printf("GUI-Scaling = %s, OPTION_SIMPLE_ZOOM_SHORTCUT = %s\n", + toggle ? "ON" : "OFF", simple_zoom ? "ON" : "OFF"); + } toggle_cb(w, v); // give focus to 'app' } @@ -316,21 +332,24 @@ void close_cb(Fl_Widget *win, void *) { int main(int argc, char **argv) { -// Set an appropriate font for Wine on Linux (test only). -// This is very likely not necessary on a real Windows system - -#if (1) // test/experimental for wine on Linux (maybe missing fonts) #ifdef _WIN32 - // Fl::set_font(FL_COURIER, " DejaVu Sans Mono"); // DejaVu Mono - // Fl::set_font(FL_COURIER, "BNimbus Mono PS"); // Nimbus Mono PS bold - Fl::set_font(FL_COURIER, " Liberation Mono"); // Liberation Mono + // Set an appropriate font for Wine on Linux (test only). + // This is very likely not necessary on a real Windows system. + // Set environment variable FLTK_USING_WINE to a non-empty string + // to enable this feature, e.g. (in bash) `export FLTK_USING_WINE=1`. + const char *using_wine = fl_getenv("FLTK_USING_WINE"); + printf("FLTK_USING_WINE = %s\n", using_wine ? using_wine : ""); + if (using_wine && *using_wine) { + // Fl::set_font(FL_COURIER, " DejaVu Sans Mono"); // DejaVu Mono + Fl::set_font(FL_COURIER, " Liberation Mono"); // Liberation Mono + } #endif -#endif // test const int WW = 700, WH = 400; app *win = new app(0, 0, WW, WH); win->tty->box(FL_DOWN_BOX); win->tty->show_unknown(true); + win->tty->textfgcolor(FL_BLACK); win->tty->printf("Please press any key ...\n"); Fl_Grid *grid = new Fl_Grid(0, WH - 75, WW, 75); diff --git a/libraries/fltk/test/input_choice.cxx b/libraries/fltk/test/input_choice.cxx index 853c79c3ad..d0a915369d 100644 --- a/libraries/fltk/test/input_choice.cxx +++ b/libraries/fltk/test/input_choice.cxx @@ -1,7 +1,7 @@ // -// Test program for Fl_Input_Choice +// Test program for Fl_Input_Choice and Fl_Choice // -// Copyright 1998-2010 by Bill Spitzak and others. +// Copyright 1998-2024 by Bill Spitzak and others. // // This library is free software. Distribution and use rights are outlined in // the file "COPYING" which should have been included with this file. If this @@ -14,50 +14,84 @@ // https://www.fltk.org/bugs.php // -#include -#include #include #include +#include +#include +#include #include -#define TERMINAL_HEIGHT 120 +#define TERMINAL_HEIGHT 150 // Globals Fl_Terminal *G_tty = 0; -void buttcb(Fl_Widget*,void*data) { - Fl_Input_Choice *in=(Fl_Input_Choice *)data; - static int flag = 1; - flag ^= 1; - if ( flag ) in->activate(); - else in->deactivate(); - if (in->changed()) { - G_tty->printf("Callback: changed() is set\n"); - in->clear_changed(); - } +void active_cb(Fl_Widget *w, void *data) { + Fl_Check_Button *b = (Fl_Check_Button *)w; + Fl_Group *g = (Fl_Group *)data; + if (b->value()) { + g->activate(); + G_tty->printf("activate group\n"); + } else { + g->deactivate(); + G_tty->printf("deactivate group\n"); + } + g->redraw(); + if (b->changed()) { + G_tty->printf("Callback: changed() is set\n"); + b->clear_changed(); + } } -void input_choice_cb(Fl_Widget*,void*data) { - Fl_Input_Choice *in=(Fl_Input_Choice *)data; - G_tty->printf("Value='%s'\n", (const char*)in->value()); +void input_choice_cb(Fl_Widget *, void *data) { + Fl_Input_Choice *in = (Fl_Input_Choice *)data; + G_tty->printf("Fl_Input_Choice value='%s'\n", (const char *)in->value()); +} + +void choice_cb(Fl_Widget *, void *data) { + Fl_Choice *in = (Fl_Choice *)data; + G_tty->printf("Fl_Choice value='%d'\n", in->value()); } int main(int argc, char **argv) { - Fl_Double_Window win(300, 200+TERMINAL_HEIGHT); - G_tty = new Fl_Terminal(0,200,win.w(),TERMINAL_HEIGHT); - - Fl_Input_Choice in(40,40,100,28,"Test"); - in.callback(input_choice_cb, (void*)&in); - in.add("one"); - in.add("two"); - in.add("three"); - in.value(1); - - Fl_Button onoff(40,150,200,28,"Activate/Deactivate"); - onoff.callback(buttcb, (void*)&in); - - win.end(); - win.resizable(win); - win.show(argc, argv); - return Fl::run(); + Fl_Window *win = new Fl_Double_Window(300, 200 + TERMINAL_HEIGHT); + + G_tty = new Fl_Terminal(0, 200, win->w(), TERMINAL_HEIGHT); + + // this group can be activated and deactivated: + Fl_Group *active_group = new Fl_Group(0, 0, 300, 120); + + // all *_Choice widgets must be aligned for easier visual comparison: + + Fl_Input_Choice *in = new Fl_Input_Choice(180, 40, 100, 25, "Fl_Input_Choice:"); + in->callback(input_choice_cb, (void *)in); + in->add("one"); + in->add("two"); + in->add("three"); + in->value(0); + + Fl_Choice *choice = new Fl_Choice(180, 70, 100, 25, "Fl_Choice:"); + choice->callback(choice_cb, (void *)choice); + choice->add("aaa"); + choice->add("bbb"); + choice->add("ccc"); + choice->value(1); + + active_group->end(); + + // Interactive control of scheme + Fl_Scheme_Choice *sch = new Fl_Scheme_Choice(180, 120, 100, 25, "Choose scheme:"); + sch->visible_focus(0); + + Fl_Check_Button *active = new Fl_Check_Button(50, 160, 160, 30, "Activate/deactivate"); + active->callback(active_cb, (void *)active_group); + active->value(1); + + win->end(); + win->resizable(win); + win->size_range(200, 160); + win->show(argc, argv); + Fl::run(); + delete win; + return 0; } diff --git a/libraries/fltk/test/keyboard_ui.fl b/libraries/fltk/test/keyboard_ui.fl index c0d29f3fd1..c5d40fc5c5 100644 --- a/libraries/fltk/test/keyboard_ui.fl +++ b/libraries/fltk/test/keyboard_ui.fl @@ -9,6 +9,14 @@ Function {make_window()} {open code0 {\#include "keyboard.h"} class MyWindow visible } { + Fl_Output key_output { + label {Fl::event_key():} + xywh {15 20 170 30} labelsize 9 align 5 + } + Fl_Output text_output { + label {Fl::event_text():} + xywh {195 20 190 30} labelsize 9 align 5 + } Fl_Button {} { label {Esc } user_data FL_Escape user_data_type {void*} @@ -105,6 +113,28 @@ Function {make_window()} {open callback key_cb xywh {365 70 20 20} labelsize 8 } + Fl_Button {} { + label Help + user_data FL_Help user_data_type {void*} + callback key_cb + xywh {400 70 20 20} labelsize 8 + } + Fl_Button {} { + label {=} + user_data {FL_KP+'='} user_data_type {void*} + callback key_cb + xywh {420 70 20 20} labelsize 10 + } + Fl_Dial roller_x { + label {x:} + callback wheel_cb + xywh {440 70 20 20} box ROUND_UP_BOX selection_color 49 labelsize 9 align 5 step 0.1 + } + Fl_Dial roller_y { + label {y:} + callback wheel_cb + xywh {460 70 20 20} box ROUND_UP_BOX selection_color 49 labelsize 9 align 5 step 0.1 + } Fl_Button {} { label {`} callback key_cb @@ -584,6 +614,10 @@ Function {make_window()} {open callback key_cb xywh {440 180 20 20} labelsize 10 } + Fl_Box {} { + label {Fl::event_state():} selected + xywh {400 15 80 0} labelsize 9 align 5 + } Fl_Button {} { label {shift } user_data FL_SHIFT user_data_type {void*} @@ -651,14 +685,14 @@ Function {make_window()} {open xywh {440 35 20 10} box THIN_UP_BOX selection_color 3 labelsize 8 } Fl_Button {} { - label whl - user_data 0x800 user_data_type {void*} + label bck + user_data FL_BUTTON4 user_data_type {void*} callback shift_cb xywh {460 35 20 10} box THIN_UP_BOX selection_color 3 labelsize 8 } Fl_Button {} { - label {?} - user_data 0x1000 user_data_type {void*} + label fwd + user_data FL_BUTTON5 user_data_type {void*} callback shift_cb xywh {400 45 20 10} box THIN_UP_BOX selection_color 3 labelsize 8 } @@ -680,39 +714,5 @@ Function {make_window()} {open callback shift_cb xywh {460 45 20 10} box THIN_UP_BOX selection_color 3 labelsize 8 } - Fl_Output key_output { - label {Fl::event_key():} - xywh {15 20 170 30} labelsize 9 align 5 - } - Fl_Box {} { - label {Fl::event_state():} selected - xywh {400 15 80 0} labelsize 9 align 5 - } - Fl_Output text_output { - label {Fl::event_text():} - xywh {195 20 190 30} labelsize 9 align 5 - } - Fl_Button {} { - label Help - user_data FL_Help user_data_type {void*} - callback key_cb - xywh {400 70 20 20} labelsize 8 - } - Fl_Button {} { - label {=} - user_data {FL_KP+'='} user_data_type {void*} - callback key_cb - xywh {420 70 20 20} labelsize 10 - } - Fl_Dial roller_x { - label {x:} - callback wheel_cb - xywh {440 70 20 20} box ROUND_UP_BOX selection_color 49 labelsize 9 align 5 step 0.1 - } - Fl_Dial roller_y { - label {y:} - callback wheel_cb - xywh {460 70 20 20} box ROUND_UP_BOX selection_color 49 labelsize 9 align 5 step 0.1 - } } } diff --git a/libraries/fltk/test/label.cxx b/libraries/fltk/test/label.cxx index 7ae739bc40..f155132eb7 100644 --- a/libraries/fltk/test/label.cxx +++ b/libraries/fltk/test/label.cxx @@ -32,6 +32,7 @@ Fl_Box *text; Fl_Input *input; Fl_Hor_Value_Slider *fonts; Fl_Hor_Value_Slider *sizes; +Fl_Hor_Value_Slider *h_margin, *v_margin, *img_spacing; Fl_Double_Window *window; Fl_Pixmap *img; @@ -64,6 +65,21 @@ void font_cb(Fl_Widget *,void *) { window->redraw(); } +void h_margin_cb(Fl_Widget *,void *) { + text->horizontal_label_margin(int(h_margin->value())); + window->redraw(); +} + +void v_margin_cb(Fl_Widget *,void *) { + text->vertical_label_margin(int(v_margin->value())); + window->redraw(); +} + +void spacing_cb(Fl_Widget *,void *) { + text->label_image_spacing(int(img_spacing->value())); + window->redraw(); +} + void size_cb(Fl_Widget *,void *) { text->labelsize(int(sizes->value())); window->redraw(); @@ -114,9 +130,9 @@ Fl_Menu_Item choices[] = { int main(int argc, char **argv) { img = new Fl_Pixmap(blast_xpm); - window = new Fl_Double_Window(440,420); + window = new Fl_Double_Window(440,495); - input = new Fl_Input(70,375,350,25,"Label:"); + input = new Fl_Input(70,435,350,25,"Label:"); input->static_value("The quick brown fox jumped over the lazy dog."); input->when(FL_WHEN_CHANGED); input->callback(input_cb); @@ -136,6 +152,31 @@ int main(int argc, char **argv) { fonts->value(0); fonts->callback(font_cb); + Fl_Box *margin = new Fl_Box(0, 380, 70, 25, "Margins"); + margin->box(FL_FLAT_BOX); + margin->align(FL_ALIGN_RIGHT|FL_ALIGN_INSIDE); + + h_margin = new Fl_Hor_Value_Slider(70+50,380,125,25,"Hor:"); + h_margin->align(FL_ALIGN_LEFT); + h_margin->bounds(-25,25); + h_margin->step(1); + h_margin->value(0); + h_margin->callback(h_margin_cb); + + v_margin = new Fl_Hor_Value_Slider(70+175+50,380,125,25,"Vert:"); + v_margin->align(FL_ALIGN_LEFT); + v_margin->bounds(-25,25); + v_margin->step(1); + v_margin->value(0); + v_margin->callback(v_margin_cb); + + img_spacing = new Fl_Hor_Value_Slider(70+50,405,125,25,"Image:"); + img_spacing->align(FL_ALIGN_LEFT); + img_spacing->bounds(0,50); + img_spacing->step(1); + img_spacing->value(0); + img_spacing->callback(spacing_cb); + Fl_Group *g = new Fl_Group(70,275,350,50); imageb = new Fl_Toggle_Button(70,275,50,25,"image"); imageb->callback(image_cb); diff --git a/libraries/fltk/test/line_style_docs.cxx b/libraries/fltk/test/line_style_docs.cxx new file mode 100644 index 0000000000..5bf45fd42c --- /dev/null +++ b/libraries/fltk/test/line_style_docs.cxx @@ -0,0 +1,151 @@ +// +// Line style image (docs) for the Fast Light Tool Kit (FLTK). +// +// Copyright 2024 by Bill Spitzak and others. +// +// This library is free software. Distribution and use rights are outlined in +// the file "COPYING" which should have been included with this file. If this +// file is missing or damaged, see the license at: +// +// https://www.fltk.org/COPYING.php +// +// Please see the following page on how to report bugs and issues: +// +// https://www.fltk.org/bugs.php +// + +// Notes to devs (and users): +// +// 1. Run this program to create the screenshot for the fl_line_style() docs. +// Save a screenshot of its original size to documentation/src/fl_line_style.png +// 2. For further tests it's possible to resize the window. Line sizes and widths +// are adjusted (resized) as well, depending on the window size. +// 3. Some lines may draw outside their boxes in unusual window width/height ratios. +// These effects are intentionally ignored. + +#include +#include +#include +#include +#include + +// constants + +static const int sep = 22; // separation between items +static int width[] = {1, 4}; // line widths (thin + thick/dyn.) + +// This class draws a box with one line style inside an Fl_Grid widget. +// Row and column parameters are used to position the box inside the grid. + +class StyleBox : public Fl_Box { + int style; // line style +public: + StyleBox(int S, int row, int col) // style, row, column + : Fl_Box(0, 0, 0, 0) { + box(FL_FLAT_BOX); + color(FL_WHITE); + style = S; + Fl_Grid *grid = (Fl_Grid *)parent(); + grid->widget(this, row, col, FL_GRID_FILL); + } + const char *style_str(int style) { + switch(style) { + case FL_SOLID : return "FL_SOLID" ; + case FL_DASH : return "FL_DASH" ; + case FL_DOT : return "FL_DOT" ; + case FL_DASHDOT : return "FL_DASHDOT" ; + case FL_DASHDOTDOT : return "FL_DASHDOTDOT" ; + case FL_CAP_FLAT : return "FL_CAP_FLAT" ; + case FL_CAP_ROUND : return "FL_CAP_ROUND" ; + case FL_CAP_SQUARE : return "FL_CAP_SQUARE" ; + case FL_JOIN_MITER : return "FL_JOIN_MITER" ; + case FL_JOIN_ROUND : return "FL_JOIN_ROUND" ; + case FL_JOIN_BEVEL : return "FL_JOIN_BEVEL" ; + default : return "(?)"; + } + } + void draw() FL_OVERRIDE { + draw_box(); + if (style < 0) // draw an empty box + return; + + // set font and measure widest text + fl_font(FL_HELVETICA, 12); + fl_color(FL_BLACK); + static int text_width = 0; + if (!text_width) { + int h = 0; // dummy + fl_measure("FL_DASHDOTDOT", text_width, h); + } + + // draw the text + int X = x() + sep / 2; + fl_draw(style_str(style), X, y() + h()/2 + fl_height()/2 - 2); + + // calculate dynamic line sizes and widths + X += text_width + sep / 2; + int dx = (w() - text_width - 5 * sep) / 4; // horizontal distance + int dy = h() - sep; + int Y = y() + sep / 2; + if (dx >= 80 || dy >= 80) + width[1] = 9; + else if (dx >= 60 || dy >= 60) + width[1] = 8; + else if (dx >= 40 || dy >= 40) + width[1] = 7; + else + width[1] = 5; + + // draw the lines + for (int i = 0; i < 2; i++, X += dx + sep) { // thin + thick lines + fl_line_style(style, width[i]); + // ___ + // | + // | + fl_line(X, Y, X + dx, Y, X + dx, Y + dy); + X += dx + sep; + // ___ + // / + // / + fl_line(X, Y, X + dx, Y, X, Y + dy); + } + + // restore line settings to default + fl_line_style(FL_SOLID, 0); + } +}; + +int main(int argc, char **argv) { + Fl_Double_Window win(740, 400, "fl_line_style()"); + win.color(FL_WHITE); + + // create grid with a nice white 4px border and a + // light gray background (color) so margins and gaps show thru + Fl_Grid grid(4, 4, win.w() - 8, win.h() - 8); + grid.box(FL_FLAT_BOX); + grid.color(0xd0d0d000); + grid.layout(6, 2, 4, 4); // 6 rows, 2 columns, ... + + // first column + StyleBox sb00(FL_SOLID, 0, 0); + StyleBox sb01(FL_DASH, 1, 0); + StyleBox sb02(FL_DOT, 2, 0); + StyleBox sb03(FL_DASHDOT, 3, 0); + StyleBox sb04(FL_DASHDOTDOT, 4, 0); + StyleBox sb05(-1, 5, 0); // empty box + + // second column + StyleBox sb10(FL_CAP_FLAT, 0, 1); + StyleBox sb11(FL_CAP_ROUND, 1, 1); + StyleBox sb12(FL_CAP_SQUARE, 2, 1); + StyleBox sb13(FL_JOIN_MITER, 3, 1); + StyleBox sb14(FL_JOIN_ROUND, 4, 1); + StyleBox sb15(FL_JOIN_BEVEL, 5, 1); + + grid.end(); + win.end(); + win.resizable(win); + win.size_range(660, 340); // don't allow to shrink too much + win.show(argc, argv); + return Fl::run(); +} diff --git a/libraries/fltk/test/mac-resources/editor.plist b/libraries/fltk/test/mac-resources/editor.plist index 6324e5cf2d..9f547d706e 100644 --- a/libraries/fltk/test/mac-resources/editor.plist +++ b/libraries/fltk/test/mac-resources/editor.plist @@ -36,7 +36,7 @@ CFBundleVersion 1.0 NSHumanReadableCopyright - Copyright 1998-2021 by Bill Spitzak and others. + Copyright 1998-2024 by Bill Spitzak and others. NSHighResolutionCapable diff --git a/libraries/fltk/test/makedepend b/libraries/fltk/test/makedepend index b060c7c166..0c0810c601 100644 --- a/libraries/fltk/test/makedepend +++ b/libraries/fltk/test/makedepend @@ -725,6 +725,7 @@ device.o: ../FL/Fl_Menu_Item.H device.o: ../FL/Fl_Multi_Label.H device.o: ../FL/Fl_Native_File_Chooser.H device.o: ../FL/Fl_Paged_Device.H +device.o: ../FL/Fl_PDF_File_Surface.H device.o: ../FL/Fl_Pixmap.H device.o: ../FL/Fl_Plugin.H device.o: ../FL/Fl_PostScript.H @@ -952,10 +953,16 @@ fltk-versions.o: ../FL/Fl_Cairo.H fltk-versions.o: ../FL/fl_casts.H fltk-versions.o: ../FL/fl_config.h fltk-versions.o: ../FL/Fl_Export.H +fltk-versions.o: ../FL/Fl_Grid.H +fltk-versions.o: ../FL/Fl_Group.H +fltk-versions.o: ../FL/Fl_Rect.H fltk-versions.o: ../FL/fl_types.h fltk-versions.o: ../FL/fl_utf8.h +fltk-versions.o: ../FL/Fl_Widget.H fltk-versions.o: ../FL/Fl_Window.H +fltk-versions.o: ../FL/platform.H fltk-versions.o: ../FL/platform_types.h +fltk-versions.o: ../FL/x11.H fonts.o: ../FL/Enumerations.H fonts.o: ../FL/filename.H fonts.o: ../FL/Fl.H @@ -1390,6 +1397,8 @@ input_choice.o: ../FL/Fl_Bitmap.H input_choice.o: ../FL/Fl_Button.H input_choice.o: ../FL/Fl_Cairo.H input_choice.o: ../FL/fl_casts.H +input_choice.o: ../FL/Fl_Check_Button.H +input_choice.o: ../FL/Fl_Choice.H input_choice.o: ../FL/fl_config.h input_choice.o: ../FL/Fl_Double_Window.H input_choice.o: ../FL/Fl_Export.H @@ -1398,11 +1407,14 @@ input_choice.o: ../FL/Fl_Image.H input_choice.o: ../FL/Fl_Input.H input_choice.o: ../FL/Fl_Input_.H input_choice.o: ../FL/Fl_Input_Choice.H +input_choice.o: ../FL/Fl_Light_Button.H input_choice.o: ../FL/Fl_Menu_.H input_choice.o: ../FL/Fl_Menu_Button.H input_choice.o: ../FL/Fl_Menu_Item.H input_choice.o: ../FL/Fl_Multi_Label.H input_choice.o: ../FL/Fl_Rect.H +input_choice.o: ../FL/Fl_Scheme.H +input_choice.o: ../FL/Fl_Scheme_Choice.H input_choice.o: ../FL/Fl_Scrollbar.H input_choice.o: ../FL/Fl_Terminal.H input_choice.o: ../FL/fl_types.h @@ -1502,6 +1514,32 @@ line_style.o: ../FL/Fl_Value_Slider.H line_style.o: ../FL/Fl_Widget.H line_style.o: ../FL/Fl_Window.H line_style.o: ../FL/platform_types.h +line_style_docs.o: ../FL/Enumerations.H +line_style_docs.o: ../FL/Fl.H +line_style_docs.o: ../FL/fl_attr.h +line_style_docs.o: ../FL/Fl_Bitmap.H +line_style_docs.o: ../FL/Fl_Box.H +line_style_docs.o: ../FL/Fl_Cairo.H +line_style_docs.o: ../FL/fl_casts.H +line_style_docs.o: ../FL/fl_config.h +line_style_docs.o: ../FL/Fl_Device.H +line_style_docs.o: ../FL/Fl_Double_Window.H +line_style_docs.o: ../FL/fl_draw.H +line_style_docs.o: ../FL/Fl_Export.H +line_style_docs.o: ../FL/Fl_Graphics_Driver.H +line_style_docs.o: ../FL/Fl_Grid.H +line_style_docs.o: ../FL/Fl_Group.H +line_style_docs.o: ../FL/Fl_Image.H +line_style_docs.o: ../FL/Fl_Pixmap.H +line_style_docs.o: ../FL/Fl_Plugin.H +line_style_docs.o: ../FL/Fl_Preferences.H +line_style_docs.o: ../FL/Fl_Rect.H +line_style_docs.o: ../FL/Fl_RGB_Image.H +line_style_docs.o: ../FL/fl_types.h +line_style_docs.o: ../FL/fl_utf8.h +line_style_docs.o: ../FL/Fl_Widget.H +line_style_docs.o: ../FL/Fl_Window.H +line_style_docs.o: ../FL/platform_types.h list_visuals.o: ../config.h list_visuals.o: ../FL/Enumerations.H list_visuals.o: ../FL/fl_config.h diff --git a/libraries/fltk/test/menubar.cxx b/libraries/fltk/test/menubar.cxx index a0424732dc..a5ccfc2345 100644 --- a/libraries/fltk/test/menubar.cxx +++ b/libraries/fltk/test/menubar.cxx @@ -37,6 +37,11 @@ #define TERMINAL_HEIGHT 120 +// Set the macro below to 1 to test shortcuts usually used for screen scaling. +// This should normally be set to 0, enable only for testing! +// Note: screen scaling does not work with ctrl/+/-/0 if enabled (1)! +#define OVERRIDE_SCALING_SHORTCUTS 0 + // Globals Fl_Terminal *G_tty = 0; @@ -66,6 +71,14 @@ Fl_Menu_Item menutable[] = { {"&Open", FL_ALT+'o', 0, 0, FL_MENU_INACTIVE}, {"&Close", 0, 0}, {"&Quit", FL_ALT+'q', quit_cb, 0, FL_MENU_DIVIDER}, + +#if (OVERRIDE_SCALING_SHORTCUTS) + {"CTRL/0", FL_COMMAND+'0', 0}, + {"CTRL/-", FL_COMMAND+'-', 0}, + {"CTRL/+", FL_COMMAND+'+', 0}, + {"CTRL/=", FL_COMMAND+'=', 0}, +#endif + {"shortcut",'a'}, {"shortcut",FL_SHIFT+'a'}, {"shortcut",FL_CTRL+'a'}, @@ -224,7 +237,6 @@ void about_cb(Fl_Widget*, void*) { } int main(int argc, char **argv) { - //Fl::set_color(Fl_Color(15),0,0,128); for (int i=0; i<99; i++) { char buf[100]; snprintf(buf, 100,"item %d",i); diff --git a/libraries/fltk/test/sudoku.cxx b/libraries/fltk/test/sudoku.cxx index 4063d4651f..c0d6bfd436 100644 --- a/libraries/fltk/test/sudoku.cxx +++ b/libraries/fltk/test/sudoku.cxx @@ -130,28 +130,42 @@ class SudokuSound { void play(char note); }; +typedef unsigned int State; +typedef State GameState[81]; // Sudoku cell class... class SudokuCell : public Fl_Widget { + int row_; + int col_; bool readonly_; int value_; - int test_value_[9]; + int hint_map_; public: - SudokuCell(int X, int Y, int W, int H); - void draw() FL_OVERRIDE; - int handle(int event) FL_OVERRIDE; + SudokuCell(int row, int col, int X, int Y, int W, int H); + int row() { return row_; } + int col() { return col_; } + void draw() FL_OVERRIDE; + int handle(int event) FL_OVERRIDE; void readonly(bool r) { readonly_ = r; redraw(); } bool readonly() const { return readonly_; } - void test_value(int v, int n) { test_value_[n] = v; redraw(); } - int test_value(int n) const { return test_value_[n]; } - void value(int v) { - value_ = v; - for (int i = 0; i < 8; i ++) test_value_[i] = 0; - redraw(); - } + void set_hint(int n) { hint_map_ |= (1<>1) | (value_<<12) | (readonly_<<9); } + void state(State s) { + hint_map_ = (s & 0x000001ff) << 1; + readonly_ = (s & 0x00000200) >> 9; + value_ = (s & 0x0000f000) >> 12; + if (readonly_) color(FL_GRAY); else color(FL_LIGHT3); + redraw(); + } }; @@ -165,6 +179,8 @@ class Sudoku : public Fl_Double_Window { Fl_Group *grid_groups_[3][3]; int difficulty_; SudokuSound *sound_; + GameState undo_stack[64]; + int undo_head_, undo_tail_, redo_head_; static void check_cb(Fl_Widget *widget, void *); static void close_cb(Fl_Widget *widget, void *); @@ -189,12 +205,20 @@ class Sudoku : public Fl_Double_Window { void load_game(); void new_game(time_t seed); int next_value(SudokuCell *c); - void resize(int X, int Y, int W, int H) FL_OVERRIDE; + void resize(int X, int Y, int W, int H) FL_OVERRIDE; void save_game(); void solve_game(); void update_helpers(); + void clear_hints_for(int row, int col, int val); + void save_state(GameState &s); + void load_state(GameState &s); + void undo(); + void redo(); + void clear_undo(); + void undo_checkpoint(); }; +Sudoku *sudoku = NULL; // Sound class globals... int SudokuSound::frequencies[9] = { @@ -211,7 +235,6 @@ int SudokuSound::frequencies[9] = { short *SudokuSound::sample_data[9] = { 0 }; int SudokuSound::sample_size = 0; - // Initialize the SudokuSound class SudokuSound::SudokuSound() { sample_size = 0; @@ -482,8 +505,9 @@ void SudokuSound::play(char note) { // Create a cell widget -SudokuCell::SudokuCell(int X, int Y, int W, int H) - : Fl_Widget(X, Y, W, H, 0) { +SudokuCell::SudokuCell(int row, int col, int X, int Y, int W, int H) + : Fl_Widget(X, Y, W, H, 0), row_(row), col_(col) +{ value(0); } @@ -491,15 +515,16 @@ SudokuCell::SudokuCell(int X, int Y, int W, int H) // Draw cell void SudokuCell::draw() { - static Fl_Align align[8] = { + static Fl_Align align[9] = { FL_ALIGN_TOP_LEFT, FL_ALIGN_TOP, FL_ALIGN_TOP_RIGHT, + FL_ALIGN_LEFT, + 0, FL_ALIGN_RIGHT, - FL_ALIGN_BOTTOM_RIGHT, - FL_ALIGN_BOTTOM, FL_ALIGN_BOTTOM_LEFT, - FL_ALIGN_LEFT + FL_ALIGN_BOTTOM, + FL_ALIGN_BOTTOM_RIGHT, }; @@ -522,17 +547,15 @@ SudokuCell::draw() { if (value_) { s[0] = value_ + '0'; - fl_font(FL_HELVETICA_BOLD, h() - 10); fl_draw(s, x(), y(), w(), h(), FL_ALIGN_CENTER); - } - - fl_font(FL_HELVETICA_BOLD, h() / 5); - - for (int i = 0; i < 8; i ++) { - if (test_value_[i]) { - s[0] = test_value_[i] + '0'; - fl_draw(s, x() + 5, y() + 5, w() - 10, h() - 10, align[i]); + } else { + fl_font(FL_HELVETICA_BOLD, h() / 5); + for (int i = 1; i <= 9; i ++) { + if (hint_set(i)) { + s[0] = i + '0'; + fl_draw(s, x() + 5, y() + 5, w() - 10, h() - 10, align[i-1]); + } } } } @@ -558,9 +581,9 @@ SudokuCell::handle(int event) { if (value()) { if (value() < 9) value(value() + 1); else value(1); - } else value(((Sudoku *)window())->next_value(this)); + } else value(sudoku->next_value(this)); } - + // TODO: add this to the undo process Fl::focus(this); redraw(); return 1; @@ -578,30 +601,17 @@ SudokuCell::handle(int event) { } if (Fl::event_state() & (FL_SHIFT | FL_CAPS_LOCK)) { - int i; - - for (i = 0; i < 8; i ++) - if (test_value_[i] == key) { - test_value_[i] = 0; - break; - } - - if (i >= 8) { - for (i = 0; i < 8; i ++) - if (!test_value_[i]) { - test_value_[i] = key; - break; - } + if (hint_set(key)) { + clear_hint(key); + } else { + set_hint(key); } - - if (i >= 8) { - for (i = 0; i < 7; i ++) test_value_[i] = test_value_[i + 1]; - test_value_[i] = key; - } - + sudoku->undo_checkpoint(); redraw(); } else { value(key); + sudoku->clear_hints_for(row(), col(), key); + sudoku->undo_checkpoint(); do_callback(); } return 1; @@ -611,9 +621,14 @@ SudokuCell::handle(int event) { fl_beep(FL_BEEP_ERROR); return 1; } - - value(0); - do_callback(); + if (Fl::event_state() & (FL_SHIFT | FL_CAPS_LOCK)) { + clear_hints(); + sudoku->undo_checkpoint(); + } else { + value(0); + do_callback(); + sudoku->undo_checkpoint(); + } return 1; } break; @@ -627,35 +642,49 @@ SudokuCell::handle(int event) { Fl_Help_Dialog *Sudoku::help_dialog_ = (Fl_Help_Dialog *)0; Fl_Preferences Sudoku::prefs_(Fl_Preferences::USER_L, "fltk.org", "sudoku"); +static void undo_cb(Fl_Widget*, void*) { + sudoku->undo(); +} + +static void redo_cb(Fl_Widget*, void*) { + sudoku->redo(); +} // Create a Sudoku game window... Sudoku::Sudoku() - : Fl_Double_Window(GROUP_SIZE * 3, GROUP_SIZE * 3 + MENU_OFFSET, "Sudoku") + : Fl_Double_Window(GROUP_SIZE * 3, GROUP_SIZE * 3 + MENU_OFFSET, "Sudoku"), + undo_head_(0), undo_tail_(0), redo_head_(0) { int j, k; Fl_Group *g; SudokuCell *cell; static Fl_Menu_Item items[] = { { "&Game", 0, 0, 0, FL_SUBMENU }, - { "&New Game", FL_COMMAND | 'n', new_cb, 0, FL_MENU_DIVIDER }, - { "&Check Game", FL_COMMAND | 'c', check_cb, 0, 0 }, - { "&Restart Game", FL_COMMAND | 'r', restart_cb, 0, 0 }, - { "&Solve Game", FL_COMMAND | 's', solve_cb, 0, FL_MENU_DIVIDER }, - { "&Update Helpers", 0, update_helpers_cb, 0, 0 }, - { "&Mute Sound", FL_COMMAND | 'm', mute_cb, 0, FL_MENU_TOGGLE | FL_MENU_DIVIDER }, + { "&New Game", FL_COMMAND | 'n', new_cb, 0, FL_MENU_DIVIDER }, + { "&Check Game", FL_COMMAND | 'c', check_cb, 0, 0 }, + { "&Restart Game", FL_COMMAND | 'r', restart_cb, 0, 0 }, + { "&Solve Game", FL_COMMAND | 's', solve_cb, 0, FL_MENU_DIVIDER }, + { "&Update Helpers", 0, update_helpers_cb, 0, 0 }, + { "&Mute Sound", FL_COMMAND | 'm', mute_cb, 0, FL_MENU_TOGGLE | FL_MENU_DIVIDER }, #ifndef USE_MACOS - { "&Quit", FL_COMMAND | 'q', close_cb, 0, 0 }, + { "&Quit", FL_COMMAND | 'q', close_cb, 0, 0 }, #endif - { 0 }, + { 0 }, + { "&Edit", 0, 0, 0, FL_SUBMENU }, + { "&Undo", FL_COMMAND | 'z', undo_cb }, + { "&Redo", FL_COMMAND | 'Z', redo_cb }, + { 0 }, { "&Difficulty", 0, 0, 0, FL_SUBMENU }, - { "&Easy", 0, diff_cb, (void *)"0", FL_MENU_RADIO }, - { "&Medium", 0, diff_cb, (void *)"1", FL_MENU_RADIO }, - { "&Hard", 0, diff_cb, (void *)"2", FL_MENU_RADIO }, - { "&Impossible", 0, diff_cb, (void *)"3", FL_MENU_RADIO }, - { 0 }, + { "&Easy", 0, diff_cb, (void *)"0", FL_MENU_RADIO }, + { "&Medium", 0, diff_cb, (void *)"1", FL_MENU_RADIO }, + { "&Hard", 0, diff_cb, (void *)"2", FL_MENU_RADIO }, + { "&Impossible", 0, diff_cb, (void *)"3", FL_MENU_RADIO }, + { 0 }, +#ifndef USE_MACOS { "&Help", 0, 0, 0, FL_SUBMENU }, - { "&About Sudoku", FL_F + 1, help_cb, 0, 0 }, - { 0 }, + { "&About Sudoku", FL_F + 1, help_cb, 0, 0 }, + { 0 }, +#endif { 0 } }; @@ -676,6 +705,9 @@ Sudoku::Sudoku() menubar_ = new Fl_Sys_Menu_Bar(0, 0, 3 * GROUP_SIZE, 25); menubar_->menu(items); +#ifdef USE_MACOS + menubar_->about(help_cb, NULL); +#endif // Create the grids... grid_ = new Fl_Group(0, MENU_OFFSET, 3 * GROUP_SIZE, 3 * GROUP_SIZE); @@ -694,7 +726,8 @@ Sudoku::Sudoku() for (j = 0; j < 9; j ++) for (k = 0; k < 9; k ++) { - cell = new SudokuCell(k * CELL_SIZE + CELL_OFFSET + + cell = new SudokuCell(j, k, + k * CELL_SIZE + CELL_OFFSET + (k / 3) * (GROUP_SIZE - 3 * CELL_SIZE), j * CELL_SIZE + CELL_OFFSET + MENU_OFFSET + (j / 3) * (GROUP_SIZE - 3 * CELL_SIZE), @@ -733,6 +766,7 @@ Sudoku::Sudoku() } set_title(); + clear_undo(); } @@ -745,7 +779,7 @@ Sudoku::~Sudoku() { // Check for a solution to the game... void Sudoku::check_cb(Fl_Widget *widget, void *) { - ((Sudoku *)(widget->window()))->check_game(); + sudoku->check_game(); } @@ -834,10 +868,8 @@ Sudoku::check_game(bool highlight) { // Close the window, saving the game first... void Sudoku::close_cb(Fl_Widget *widget, void *) { - Sudoku *s = (Sudoku *)(widget->window() ? widget->window() : widget); - - s->save_game(); - s->hide(); + sudoku->save_game(); + sudoku->hide(); if (help_dialog_) help_dialog_->hide(); } @@ -846,13 +878,12 @@ Sudoku::close_cb(Fl_Widget *widget, void *) { // Set the level of difficulty... void Sudoku::diff_cb(Fl_Widget *widget, void *d) { - Sudoku *s = (Sudoku *)(widget->window() ? widget->window() : widget); int diff = atoi((char *)d); - if (diff != s->difficulty_) { - s->difficulty_ = diff; - s->new_game(s->seed_); - s->set_title(); + if (diff != sudoku->difficulty_) { + sudoku->difficulty_ = diff; + sudoku->new_cb(widget, NULL); + sudoku->set_title(); if (diff > 1) { @@ -871,15 +902,14 @@ Sudoku::diff_cb(Fl_Widget *widget, void *d) { } } - prefs_.set("difficulty", s->difficulty_); + prefs_.set("difficulty", sudoku->difficulty_); } } // Update the little marker numbers in all cells void Sudoku::update_helpers_cb(Fl_Widget *widget, void *) { - Sudoku *s = (Sudoku *)(widget->window() ? widget->window() : widget); - s->update_helpers(); + sudoku->update_helpers(); } void @@ -890,9 +920,7 @@ Sudoku::update_helpers() { for (j = 0; j < 9; j ++) { for (k = 0; k < 9; k ++) { SudokuCell *cell = grid_cells_[j][k]; - for (m = 0; m < 8; m ++) { - cell->test_value(0, m); - } + cell->clear_hints(); } } @@ -927,13 +955,29 @@ Sudoku::update_helpers() { } } // transfer our findings to the markers - for (m = 1, k = 0; m <= 9; m ++) { + for (m = 1; m <= 9; m ++) { if (!taken[m]) - dst_cell->test_value(m, k ++); + dst_cell->set_hint(m); } } + undo_checkpoint(); } +void Sudoku::clear_hints_for(int row, int col, int val) { + int i, j; + // clear row + for (i = 0; i < 9; ++i) + grid_cells_[row][i]->clear_hint(val); + // clear column + for (i = 0; i < 9; ++i) + grid_cells_[i][col]->clear_hint(val); + // clear block + row = (row / 3) * 3; + col = (col / 3) * 3; + for (i = 0; i < 3; ++i) + for (j = 0; j < 3; ++j) + grid_cells_[row+i][col+j]->clear_hint(val); +} // Show the on-line help... void @@ -1031,31 +1075,28 @@ Sudoku::load_game() { solved = false; } - for (int m = 0; m < 8; m ++) { - snprintf(name, sizeof(name), "test%d%d.%d", m, j, k); - prefs_.get(name, val, 0); - cell->test_value(val, m); - } + snprintf(name, sizeof(name), "hint%d.%d", j, k); + prefs_.get(name, val, 0); + cell->set_hint_map(val); } // If we didn't load any values or the last game was solved, then // create a new game automatically... if (solved || !grid_values_[0][0]) new_game(time(NULL)); else check_game(false); + clear_undo(); } // Mute/unmute sound... void Sudoku::mute_cb(Fl_Widget *widget, void *) { - Sudoku *s = (Sudoku *)(widget->window() ? widget->window() : widget); - - if (s->sound_) { - delete s->sound_; - s->sound_ = NULL; + if (sudoku->sound_) { + delete sudoku->sound_; + sudoku->sound_ = NULL; prefs_.set("mute_sound", 1); } else { - s->sound_ = new SudokuSound(); + sudoku->sound_ = new SudokuSound(); prefs_.set("mute_sound", 0); } } @@ -1064,15 +1105,12 @@ Sudoku::mute_cb(Fl_Widget *widget, void *) { // Create a new game... void Sudoku::new_cb(Fl_Widget *widget, void *) { - Sudoku *s = (Sudoku *)(widget->window() ? widget->window() : widget); - - if (s->grid_cells_[0][0]->color() != FL_GREEN) { + if (sudoku->grid_cells_[0][0]->color() != FL_GREEN) { if (!fl_choice("Are you sure you want to change the difficulty level and " "discard the current game?", "Keep Current Game", "Start New Game", NULL)) return; } - - s->new_game(time(NULL)); + sudoku->new_game(time(NULL)); } @@ -1130,10 +1168,10 @@ Sudoku::new_game(time_t seed) { for (j = 0; j < 9; j ++) for (k = 0; k < 9; k ++) { cell = grid_cells_[j][k]; - cell->value(0); cell->readonly(0); cell->color(FL_LIGHT3); + cell->clear_hints(); } // Show N cells... @@ -1169,6 +1207,7 @@ Sudoku::new_game(time_t seed) { } } } + clear_undo(); } @@ -1234,23 +1273,25 @@ Sudoku::resize(int X, int Y, int W, int H) { // Restart game from beginning... void Sudoku::restart_cb(Fl_Widget *widget, void *) { - Sudoku *s = (Sudoku *)(widget->window()); bool solved = true; for (int j = 0; j < 9; j ++) for (int k = 0; k < 9; k ++) { - SudokuCell *cell = s->grid_cells_[j][k]; - + SudokuCell *cell = sudoku->grid_cells_[j][k]; + cell->clear_hints(); if (!cell->readonly()) { solved = false; int v = cell->value(); cell->value(0); cell->color(FL_LIGHT3); - if (v && s->sound_) s->sound_->play('A' + v - 1); + if (v && sudoku->sound_) sudoku->sound_->play('A' + v - 1); } } - if (solved) s->new_game(s->seed_); + if (solved) + sudoku->new_game(sudoku->seed_); + else + sudoku->clear_undo(); } @@ -1273,12 +1314,64 @@ Sudoku::save_game() { prefs_.set(name, cell->readonly()); for (int m = 0; m < 8; m ++) { - snprintf(name, sizeof(name), "test%d%d.%d", m, j, k); - prefs_.set(name, cell->test_value(m)); + snprintf(name, sizeof(name), "hint%d.%d", j, k); + prefs_.set(name, cell->get_hint_map()); } } } +void Sudoku::save_state(GameState &s) { + for (int j = 0; j < 9; j ++) { + for (int k = 0; k < 9; k ++) { + s[j*9+k] = grid_cells_[j][k]->state(); + } + } +} + +void Sudoku::load_state(GameState &s) { + for (int j = 0; j < 9; j ++) { + for (int k = 0; k < 9; k ++) { + grid_cells_[j][k]->state(s[j*9+k]); + } + } +} + +void Sudoku::undo() { + if (undo_head_ != undo_tail_) { + undo_head_ = ((undo_head_-1) & 63); + load_state(undo_stack[undo_head_]); + redraw(); + } else { + fl_beep(FL_BEEP_ERROR); + } +} + +void Sudoku::redo() { + if (undo_head_ != redo_head_) { + undo_head_ = ((undo_head_+1) & 63); + load_state(undo_stack[undo_head_]); + redraw(); + } else { + fl_beep(FL_BEEP_ERROR); + } +} + +void Sudoku::clear_undo() { + undo_head_ = undo_tail_ = redo_head_ = 0; + save_state(undo_stack[undo_head_]); +} + +void Sudoku::undo_checkpoint() { + if (undo_head_ == redo_head_) { + redo_head_ = ((redo_head_+1) & 63); + } + undo_head_ = ((undo_head_+1) & 63); + if (undo_head_ == undo_tail_) { + undo_tail_ = ((undo_tail_+1) & 63); + } + save_state(undo_stack[undo_head_]); +} + // Set title of window... void @@ -1297,7 +1390,7 @@ Sudoku::set_title() { // Solve the puzzle... void Sudoku::solve_cb(Fl_Widget *widget, void *) { - ((Sudoku *)(widget->window()))->solve_game(); + sudoku->solve_game(); } @@ -1317,6 +1410,7 @@ Sudoku::solve_game() { if (sound_) sound_->play('A' + grid_cells_[j][8]->value() - 1); } + undo_checkpoint(); } @@ -1324,6 +1418,7 @@ Sudoku::solve_game() { int main(int argc, char *argv[]) { Sudoku s; + sudoku = &s; // Show the game... s.show(argc, argv); diff --git a/libraries/fltk/test/tabs.fl b/libraries/fltk/test/tabs.fl index 25a610b9d7..78c9b9da8e 100644 --- a/libraries/fltk/test/tabs.fl +++ b/libraries/fltk/test/tabs.fl @@ -12,7 +12,13 @@ Function {} {open label {class Fl_Tabs} xywh {95 0 130 35} labeltype ENGRAVED_LABEL labelfont 1 } - Fl_Tabs tabs_group {open + Fl_Tabs tabs_group { + callback {Fl_Widget *sel_tab = o->value(); +if (sel_tab) { + printf("Callback called for tab \\"%s\\"\\n", sel_tab->label()); +} else { + printf("Callback called\\n"); +}} open selected tooltip {the various index cards test different aspects of the Fl_Tabs widget} xywh {10 35 315 260} selection_color 4 labelcolor 7 resizable code0 {// tabs_group->handle_overflow(Fl_Tabs::OVERFLOW_PULLDOWN);} } { @@ -159,7 +165,7 @@ Function {} {open } } Fl_Group {} { - label tab2 selected + label tab2 tooltip {tab2 tests among other things the cooperation of modal windows and tabs} xywh {330 60 320 235} selection_color 2 } { Fl_Button {} { diff --git a/libraries/fltk/test/terminal.fl b/libraries/fltk/test/terminal.fl index 490fcf3017..0d5dd3777b 100644 --- a/libraries/fltk/test/terminal.fl +++ b/libraries/fltk/test/terminal.fl @@ -97,7 +97,7 @@ class MyTerminal { decl {bool interactivecursor;} {private local } Function {MyTerminal(int X,int Y,int W,int H, const char *L=0):Fl_Terminal(X,Y,W,H,L)} { - comment CTOR + comment CTOR open } { code {ring_debug_win = 0; debug_tty = 0; @@ -368,7 +368,8 @@ return 1; // hit end of test, reset} {} Function {test_firstpage(bool reset)} { comment {--- 0000: Test unicode alignment} return_type {static int} } { - code {G_app->AppendTty( + code {(void) reset; // unused arg: quiets compiler warnings +G_app->AppendTty( "\\033[0m\\033[H\\033[2J\\033[3J" // color/attr reset, home, cls, clear history "hello.\\nLine one\\nLine two\\n" "\\033[0;0;2m Dim text:\\033[31m red\\033[32m grn\\033[33m yel" @@ -417,7 +418,7 @@ const char *test[] = { " \\033[2;9m Dim strikeout [█]\\033[0m \\033[9m Normal strikeout [█]\\033[0m \\033[1;9m Bold strikeout [█]\\033[0m\\n" "\\n" "Xterm Colors With Attributes\\n" - " \\033[2;3m(Dim+Bold attributes should affect brightness of all xterm colors)\033[0m\\n" + " \\033[2;3m(Dim+Bold attributes should affect brightness of all xterm colors)\\033\\n" " \\033[2;30m Dim Blk(30) [█]\\033[0m \\033[30m Normal Blk(30) [█]\\033[0m \\033[1;30m Bold Blk(30) [█]\\033[0m\\n" " \\033[2;31m Dim Red(31) [█]\\033[0m \\033[31m Normal Red(31) [█]\\033[0m \\033[1;31m Bold Red(31) [█]\\033[0m\\n" " \\033[2;32m Dim Grn(32) [█]\\033[0m \\033[32m Normal Grn(32) [█]\\033[0m \\033[1;32m Bold Grn(32) [█]\\033[0m\\n" @@ -451,7 +452,8 @@ const char *test[] = { }; if (reset) { index = 0; return 0; } -return show_test(test, index);} {} +return show_test(test, index);} {selected + } } Function {test_esc_rgbcolors(bool reset)} { comment {--- 0020: Test RGB Colors} return_type {static int} @@ -1353,8 +1355,7 @@ G_tty->append("\\033[2J\\033[H"); } // Restore fg/bg colors G_tty->textfgcolor(fgsave); -G_tty->textbgcolor(bgsave); -} {} +G_tty->textbgcolor(bgsave);} {} } Function {unicode_alignment()} { comment {Show unicode alignment test @@ -1434,7 +1435,7 @@ G_tty->redraw();} {} } { code {unsigned long ival; if (sscanf(val_str, "\#%lx", &ival) == 1 ) { col = Fl_Color(ival); return 0; } -if (sscanf(val_str, "%ld", &ival) == 1 ) { col = Fl_Color(ival); return 0; } +if (sscanf(val_str, "%lu", &ival) == 1 ) { col = Fl_Color(ival); return 0; } fl_alert("Illegal color value '%s'\\n(can be e.g. '12' or '\#0c', etc)", val_str); return -1;} {} @@ -1555,7 +1556,7 @@ G_tty->output_translate(Fl_Terminal::OutFlags(out));} {} Fl_Window win { label {Fl_Terminal Test} callback {exit(0);} open - xywh {1022 64 897 838} type Double size_range {897 330 0 0} visible + xywh {831 66 897 838} type Double size_range {897 330 0 0} visible } { Fl_Spinner scrollhistory_input { label {Scroll History} @@ -1853,9 +1854,7 @@ G_tty->textfgcolor_xterm(7); // XTERM_WHITE (influenced by Dim/Bold) G_tty->textbgcolor(0xffffffff); // "see through" color update_inputs(); -add_lines(5); - -} +add_lines(5);} tooltip {Sets text fg to XTERM White, text bg to "see through", and widget's color() to amber. Text fg can be influenced by Dim/Bold.} xywh {10 10 100 20} labelsize 9 } MenuItem {} { @@ -2098,7 +2097,7 @@ Hit ENTER to run command. The command's stdout will appear in terminal.} xywh {109 269 773 25} labelsize 12 when 12 textfont 4 } Fl_Terminal tty { - xywh {10 302 872 524} box DOWN_BOX + xywh {10 302 872 524} class MyTerminal } } diff --git a/libraries/fltk/test/tree.fl b/libraries/fltk/test/tree.fl index d96e3141dd..0f7176ea36 100644 --- a/libraries/fltk/test/tree.fl +++ b/libraries/fltk/test/tree.fl @@ -523,17 +523,17 @@ tree->redraw();} "11 11 2 1", ". c None", "@ c \#000000", - "...@.......", - "...@@......", - "...@@@.....", - "...@@@@....", - "...@@@@@...", - "...@@@@@@..", - "...@@@@@...", - "...@@@@....", - "...@@@.....", - "...@@......", - "...@......." + "...........", + "....@......", + "....@@.....", + "....@@@....", + "....@@@@...", + "....@@@@@..", + "....@@@@...", + "....@@@....", + "....@@.....", + "....@......", + "..........." \#endif }; static Fl_Pixmap L_openpixmap(L_open_xpm); @@ -563,13 +563,13 @@ static const char *L_close_xpm[] = { "...........", "...........", "...........", - "...........", - "@@@@@@@@@@@", ".@@@@@@@@@.", "..@@@@@@@..", "...@@@@@...", "....@@@....", - ".....@....." + ".....@.....", + "...........", + "..........." \#endif }; static Fl_Pixmap L_closepixmap(L_close_xpm); @@ -1744,7 +1744,7 @@ helpwin->show();} xywh {0 263 15 14} } Fl_Terminal tty {selected - xywh {16 571 1014 149} box DOWN_BOX + xywh {16 571 1014 149} } } code {// Initialize Tree diff --git a/libraries/fltk/test/valuators.fl b/libraries/fltk/test/valuators.fl index 142037d967..46809a104a 100644 --- a/libraries/fltk/test/valuators.fl +++ b/libraries/fltk/test/valuators.fl @@ -229,7 +229,7 @@ Function {} {open xywh {460 385 110 115} box BORDER_FRAME color 0 selection_color 0 labelsize 11 align 128 } Fl_Terminal tty {selected - xywh {10 513 560 117} box DOWN_BOX + xywh {10 513 560 117} code0 {o->ansi(true);} } } diff --git a/libraries/fltk/zlib/Makefile b/libraries/fltk/zlib/Makefile index 67fcdd8019..dea62afeeb 100644 --- a/libraries/fltk/zlib/Makefile +++ b/libraries/fltk/zlib/Makefile @@ -46,14 +46,14 @@ clean: install: $(LIBZ) echo "Installing libfltk_z$(LIBEXT) in $(libdir)..." - -$(INSTALL_DIR) $(DESTDIR)$(libdir) - $(INSTALL_LIB) $(LIBZ) $(DESTDIR)$(libdir) - $(RANLIB) $(DESTDIR)$(libdir)/libfltk_z$(LIBEXT) + -$(INSTALL_DIR) "$(DESTDIR)$(libdir)" + $(INSTALL_LIB) $(LIBZ) "$(DESTDIR)$(libdir)" + $(RANLIB) "$(DESTDIR)$(libdir)/libfltk_z$(LIBEXT)" echo "Installing zlib headers in $(includedir)/FL/images..." - -$(INSTALL_DIR) $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) zconf.h $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) zlib.h $(DESTDIR)$(includedir)/FL/images - $(INSTALL_DATA) zutil.h $(DESTDIR)$(includedir)/FL/images + -$(INSTALL_DIR) "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) zconf.h "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) zlib.h "$(DESTDIR)$(includedir)/FL/images" + $(INSTALL_DATA) zutil.h "$(DESTDIR)$(includedir)/FL/images" # # Uninstall everything... @@ -61,11 +61,11 @@ install: $(LIBZ) uninstall: echo "Uninstalling libfltk_z$(LIBEXT) in $(libdir)..." - $(RM) $(libdir)/libfltk_z$(LIBEXT) + $(RM) "$(libdir)/libfltk_z$(LIBEXT)" echo "Uninstalling zlib headers in $(includedir)/FL/images..." - $(RM) $(includedir)/FL/images/zconf.h - $(RM) $(includedir)/FL/images/zlib.h - $(RM) $(includedir)/FL/images/zutil.h + $(RM) "$(includedir)/FL/images/zconf.h" + $(RM) "$(includedir)/FL/images/zlib.h" + $(RM) "$(includedir)/FL/images/zutil.h" # # libfltk_z.a