diff --git a/.github/workflows/ubuntu.yml b/.github/workflows/ubuntu.yml index c4cca98f9..37ba9334c 100644 --- a/.github/workflows/ubuntu.yml +++ b/.github/workflows/ubuntu.yml @@ -13,7 +13,7 @@ jobs: - name: Check out repository code uses: actions/checkout@v4 # we are in /home/runner/work/nana/nana - - run: git clone --depth=1 --branch=develop https://github.com/qPCR4vir/nana-demo.git nana-demo + - run: git clone --depth=1 --branch=dev_dpi_system https://github.com/qPCR4vir/nana-demo.git nana-demo working-directory: ../ - run: mkdir nana-demo-build working-directory: ../ diff --git a/include/nana/basic_types.hpp b/include/nana/basic_types.hpp index 305614f85..35c04db69 100644 --- a/include/nana/basic_types.hpp +++ b/include/nana/basic_types.hpp @@ -21,7 +21,7 @@ namespace nana { /// A constant value for the invalid position. - const std::size_t npos = static_cast(-1); + constexpr std::size_t npos = static_cast(-1); template @@ -30,17 +30,17 @@ namespace nana { typedef CharT char_type; - static bool eq(char_type c1, char_type c2) noexcept + static constexpr bool eq(char_type c1, char_type c2) noexcept { return std::toupper(c1) == std::toupper(c2); } - static bool lt(char_type c1, char_type c2) noexcept + static constexpr bool lt(char_type c1, char_type c2) noexcept { return std::toupper(c1) < std::toupper(c2); } - static int compare(const char_type* s1, const char_type* s2, std::size_t n) + static constexpr int compare(const char_type* s1, const char_type* s2, std::size_t n) { while(n--) { @@ -54,7 +54,7 @@ namespace nana return 0; } - static const char_type* find(const char_type* s, std::size_t n, const char_type& a) + static constexpr const char_type* find(const char_type* s, std::size_t n, const char_type& a) { auto ua = std::toupper(a); const char_type * end = s + n; diff --git a/include/nana/config.hpp b/include/nana/config.hpp index bad764f0c..c8503dcca 100644 --- a/include/nana/config.hpp +++ b/include/nana/config.hpp @@ -25,13 +25,13 @@ #ifndef NANA_dpi_aware // uncomment your option: true to try experimental DPI aware nana - #define NANA_dpi_aware false - //#define NANA_dpi_aware true + //#define NANA_dpi_aware false + #define NANA_dpi_aware true #endif // NANA_dpi_aware inline bool config_dpi_aware = NANA_dpi_aware; /// \todo: replace by #ifdef DPI_DEBUGGING or just fully eliminate -static constexpr bool dpi_debugging = false; ///< set to true to print DPI relates values for debugging +static constexpr bool dpi_debugging = true; ///< set to true to print DPI relates values for debugging #include "c++defines.hpp" diff --git a/include/nana/deploy.hpp b/include/nana/deploy.hpp index 7bbaeed61..ed30f0c08 100644 --- a/include/nana/deploy.hpp +++ b/include/nana/deploy.hpp @@ -1,4 +1,4 @@ -/* +/** * The Deploy Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com) @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/deploy.hpp + * @file nana/deploy.hpp * * What follows is dependent on what defined in nana/config.hpp */ diff --git a/include/nana/gui/basis.hpp b/include/nana/gui/basis.hpp index c6893049a..a5b65916b 100644 --- a/include/nana/gui/basis.hpp +++ b/include/nana/gui/basis.hpp @@ -84,22 +84,22 @@ namespace nana { enum class flags { - super, - widget = 0x1, - lite_widget = 0x3, - root = 0x5 + super, // 000 + widget = 0x1, // 001 + lite_widget = 0x3, // 011 + root = 0x5 // 101 }; //wait for constexpr - struct widget_tag{ static const flags value = flags::widget; }; + struct widget_tag { static const flags value = flags::widget; }; struct lite_widget_tag : public widget_tag{ static const flags value = flags::lite_widget; }; - struct root_tag : public widget_tag{ static const flags value = flags::root; }; + struct root_tag : public widget_tag{ static const flags value = flags::root; }; }// end namespace category - using window = detail::basic_window*; ///< The window handle type representing nana window objects + using window = detail::basic_window*; ///< The window handle type representing nana window objects using native_window_type = detail::native_window_handle_impl*; ///< The native window handle type representing system native windows. E.g, HWND in windows, Window in X11 - using event_handle = detail::event_handle_impl*; ///< The event handle type representing nana window events - using native_drawable_type = detail::native_drawable_impl*; ///< The drawable handle type representing system native drawable objects. E.g. HDC in windows, Drawable in X11 + using event_handle = detail::event_handle_impl*; ///< The event handle type representing nana window events + using native_drawable_type = detail::native_drawable_impl*; ///< The drawable handle type representing system native drawable objects. E.g. HDC in windows, Drawable in X11 struct keyboard diff --git a/include/nana/gui/detail/bedrock.hpp b/include/nana/gui/detail/bedrock.hpp index 8d91f1994..5563b838d 100644 --- a/include/nana/gui/detail/bedrock.hpp +++ b/include/nana/gui/detail/bedrock.hpp @@ -14,6 +14,7 @@ #ifndef NANA_GUI_DETAIL_BEDROCK_HPP #define NANA_GUI_DETAIL_BEDROCK_HPP + #include "general_events.hpp" #include "color_schemes.hpp" #include "virtual_keyboard.hpp" @@ -28,7 +29,7 @@ namespace nana::detail struct window_platform_assoc; - /// @brief fundamental core component, it provides an abstraction to the OS platform and some basic functions. + /// fundamental core component, it provides an abstraction to the OS platform and some basic functions. class bedrock { bedrock(); @@ -67,7 +68,7 @@ namespace nana::detail void set_menubar_taken(basic_window*); - //Delay Restores focus when a menu which attached to menubar is closed + /// Delay Restores focus when a menu which attached to menubar is closed void delay_restore(int); bool close_menu_if_focus_other_window(native_window_type focus); void set_menu(native_window_type menu_window, bool is_keyboard_condition); @@ -111,7 +112,7 @@ namespace nana::detail void manage_form_loader(basic_window*, bool insert_or_remove); public: - // if 'bForce__EmitInternal', then ONLY internal (widget's) events are processed (even through explicit filtering) + /// if 'bForce__EmitInternal', then ONLY internal (widget's) events are processed (even through explicit filtering) bool emit(event_code, basic_window*, const event_arg&, bool ask_update, thread_context*, const bool bForce__EmitInternal = false); private: void _m_emit_core(event_code, basic_window*, bool draw_only, const event_arg&, const bool bForce__EmitInternal); diff --git a/include/nana/gui/detail/drawer.hpp b/include/nana/gui/detail/drawer.hpp index 9c8caf940..768afe426 100644 --- a/include/nana/gui/detail/drawer.hpp +++ b/include/nana/gui/detail/drawer.hpp @@ -122,7 +122,7 @@ namespace nana not_overridden }; public: - drawer(); + drawer(int dpi = 96); ~drawer(); void bind(basic_window*); @@ -195,7 +195,7 @@ namespace nana } } public: - nana::paint::graphics graphics; + nana::paint::graphics graphics; ///< The graphics object for drawing \todo: set dpi private: struct data_implement; diff --git a/include/nana/gui/detail/general_events.hpp b/include/nana/gui/detail/general_events.hpp index 87a68908e..2eb0e1e84 100644 --- a/include/nana/gui/detail/general_events.hpp +++ b/include/nana/gui/detail/general_events.hpp @@ -235,7 +235,7 @@ namespace nana { event_code evt_code; ///< what kind of mouse event? ::nana::window window_handle; ///< A handle to the event window - ::nana::point pos; ///< cursor position in the event window + ::nana::point pos; ///< cursor position in the event window, dpi user-side coordinate ::nana::mouse button; ///< indicates a button which triggers the event bool left_button; ///< true if mouse left button is pressed diff --git a/include/nana/gui/detail/native_window_interface.hpp b/include/nana/gui/detail/native_window_interface.hpp index 9fd8910c0..7bf832387 100644 --- a/include/nana/gui/detail/native_window_interface.hpp +++ b/include/nana/gui/detail/native_window_interface.hpp @@ -8,20 +8,46 @@ * http://www.boost.org/LICENSE_1_0.txt) * * @file nana/gui/detail/native_window_interface.hpp + * @contributors Jinhao, Ariel Vina-Rodriguez */ #ifndef NANA_GUI_DETAIL_NATIVE_WINDOW_INTERFACE_HPP #define NANA_GUI_DETAIL_NATIVE_WINDOW_INTERFACE_HPP #include +#include #include "../basis.hpp" #include +//#if defined(NANA_WINDOWS) +//#include +//#endif + namespace nana { namespace detail { + #if defined(NANA_WINDOWS) + nana::point scale_to_dpi(int x, int y, int dpi); + nana::point scale_to_dpi(native_window_type wd, int x, int y); + nana::point unscale_dpi(native_window_type wd, int x, int y); + + // create helper function to scale nana::rectangle to dpi + nana::rectangle scale_to_dpi(const nana::rectangle& r, int dpi); + nana::rectangle scale_to_dpi(native_window_type wd, const nana::rectangle& r); + nana::rectangle unscale_dpi(const nana::rectangle& r, int dpi); + + // create helper function to scale ::RECT to dpi + //::RECT scale_to_dpi(const ::RECT& r, int dpi); + //::RECT scale_to_dpi(native_window_type wd, const ::RECT& r); + //::RECT unscale_dpi(const ::RECT& r, int dpi); + + nana::size scale_to_dpi(const nana::size& sz, int dpi); + nana::size scale_to_dpi(native_window_type wd, const nana::size& sz); + nana::size unscale_dpi(const nana::size& sz, int dpi); + nana::size unscale_dpi(native_window_type wd, const nana::size& sz); +#endif struct native_interface { @@ -29,11 +55,12 @@ namespace detail { native_window_type native_handle; - unsigned width; ///< client size - unsigned height; ///< client size + size client_size; ///< client size unsigned extra_width; ///< extra border size, it is useful in Windows, ignore in X11 always 0 unsigned extra_height; ///< extra border size, it is useful in Windows, ignore in X11 always 0 + + int owner_dpi, dpi; ///< owner_dpi is the DPI of the owner window, dpi is the DPI of the window }; struct frame_extents @@ -47,65 +74,74 @@ namespace detail using native_string_type = ::nana::detail::native_string_type; /// Invokes a function in the thread of the specified window. - static void affinity_execute(native_window_type, bool post, std::function&&); + static void affinity_execute(native_window_type native_handle, bool post, std::function&& fn); - static nana::size primary_monitor_size(); ///< already 'DPI' scaled size - /// \todo: generalize dpi to v2 awareness - static rectangle screen_area_from_point(const point&); - static window_result create_window(native_window_type, bool nested, const rectangle&, const appearance&); - static native_window_type create_child_window(native_window_type, const rectangle&); + static nana::size primary_monitor_size(); ///< return 'DPI' unscaled size (user-side) + static rectangle screen_area_from_system_point(const point& system_point); ///< unused ? + + static window_result create_window(native_window_type owner, bool nested, const rectangle& r, const appearance& ap); + static native_window_type create_child_window(native_window_type owner, const rectangle& r); ///< unused ? #if defined(NANA_X11) static void set_modal(native_window_type); #endif - static void enable_dropfiles(native_window_type, bool); - static void enable_window(native_window_type, bool); - // (On Windows) The system displays the large icon in the ALT+TAB dialog box, and the small icon in the window caption. - static bool window_icon(native_window_type, const paint::image& big_icon, const paint::image& small_icon); - static void activate_owner(native_window_type); - static void activate_window(native_window_type); - static void close_window(native_window_type); - static void show_window(native_window_type, bool show, bool active); - static void restore_window(native_window_type); - static void zoom_window(native_window_type, bool ask_for_max); - static void refresh_window(native_window_type); - static bool is_window(native_window_type); - static bool is_window_visible(native_window_type); - static bool is_window_zoomed(native_window_type, bool ask_for_max); - - static nana::point window_position(native_window_type); - static void move_window(native_window_type, int x, int y); - static bool move_window(native_window_type, const rectangle&); - static void bring_top(native_window_type, bool activated); - static void set_window_z_order(native_window_type, native_window_type wd_after, z_order_action action_if_no_wd_after); - - static frame_extents window_frame_extents(native_window_type); - static bool window_size(native_window_type, const size&); - static void get_window_rect(native_window_type, rectangle&); - static void window_caption(native_window_type, const native_string_type&); - static native_string_type window_caption(native_window_type); - static void capture_window(native_window_type, bool); - static nana::point cursor_position(); - - static native_window_type get_window(native_window_type wd, window_relationship); + static void enable_dropfiles(native_window_type wd, bool enable); + static void enable_window (native_window_type wd, bool enable); + + /// (On Windows) The system displays the large icon in the ALT+TAB dialog box, and the small icon in the window caption. + static bool window_icon(native_window_type wd, const paint::image& big_icon, const paint::image& small_icon); + static void activate_owner (native_window_type wd); + static void activate_window(native_window_type wd); + static void close_window (native_window_type wd); ///< close the window, destroy the window + static void show_window (native_window_type wd, bool show, bool active); + static void restore_window (native_window_type wd); + static void zoom_window (native_window_type wd, bool ask_for_max); + static void refresh_window (native_window_type wd); + static bool is_window (native_window_type wd); + static bool is_window_visible(native_window_type wd); + static bool is_window_zoomed(native_window_type wd, bool ask_for_max); + + static nana::point window_position(native_window_type wd); ///< return 'DPI' unscaled size (user-side) + static void move_window (native_window_type wd, int x, int y); + static bool move_window (native_window_type wd, const rectangle&); + static void bring_top (native_window_type wd, bool activated); + static void set_window_z_order(native_window_type wd, native_window_type wd_after, z_order_action action_if_no_wd_after); + + static frame_extents window_frame_extents(native_window_type wd); + static bool window_size (native_window_type wd, const size& new_size); ///< change to new_size if possible + static void get_window_rect(native_window_type wd, rectangle& r); ///< unused ? + static void window_caption (native_window_type wd, const native_string_type& title); + static native_string_type window_caption(native_window_type wd); + static void capture_window (native_window_type wd, bool capture); + static nana::point cursor_sytem_position (); ///< return system point, scaled system-side + static nana::point cursor_screen_position(); ///< return unscaled point (user-side) for whole screen + static nana::point cursor_window_position(native_window_type wd); ///< return unscaled point (user-side) for wd + + static native_window_type get_window (native_window_type wd, window_relationship); static native_window_type parent_window(native_window_type child, native_window_type new_parent, bool returns_previous); + //For Caret - static void caret_create(native_window_type, const ::nana::size&); - static void caret_destroy(native_window_type); - static void caret_pos(native_window_type, const ::nana::point&); - static void caret_visible(native_window_type, bool); + static void caret_create (native_window_type wd, const ::nana::size&); + static void caret_destroy (native_window_type wd); + static void caret_pos (native_window_type wd, const ::nana::point&); + static void caret_visible (native_window_type wd, bool); - static void set_focus(native_window_type); + static void set_focus (native_window_type wd); static native_window_type get_focus_window(); - static bool calc_screen_point(native_window_type, nana::point&); - static bool calc_window_point(native_window_type, nana::point&); + static bool calc_screen_point(native_window_type wd, nana::point& window_point); ///< from client, user-side + static bool calc_window_point(native_window_type wd, nana::point& screen_point); ///< to client, user-side + static bool transform_window_system_point_into_screen_sytem_point(native_window_type wd, nana::point& system_system_point); ///< from client, system-side + static bool transform_screen_system_point_into_window_sytem_point(native_window_type wd, nana::point& screen_system_point); ///< to client, system-side + + static native_window_type find_window_from_system_screen_point(const nana::point& system_screen_point); + /// point will be the position of cursor the returned window, but if no window under cursor, the point will be on screen point + static native_window_type find_cursor_window(nana::point& point); - static native_window_type find_window(int x, int y); static nana::size check_track_size(nana::size sz, unsigned extra_width, unsigned extra_height, bool true_for_max); static void start_dpi_awareness(bool aware = false); - static std::size_t window_dpi(native_window_type); ///< if the window is not DPI aware return the system DPI - static std::size_t system_dpi(); ///< get the DPI of the main monitor + static int window_dpi(native_window_type, bool x_requested = true); ///< if the window is not DPI aware return the system DPI (usually x_dpi = y_dpi) + static int system_dpi(bool x_requested = true); ///< get the DPI of the main monitor (usually x_dpi = y_dpi) }; diff --git a/include/nana/gui/detail/window_layout.hpp b/include/nana/gui/detail/window_layout.hpp index 01256ce6d..8ce28159c 100644 --- a/include/nana/gui/detail/window_layout.hpp +++ b/include/nana/gui/detail/window_layout.hpp @@ -1,4 +1,4 @@ -/* +/** * Window Layout Implementation * Copyright(C) 2003-2017 Jinhao(cnjinhao@hotmail.com) * @@ -6,7 +6,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/detail/window_layout.hpp + * @file nana/gui/detail/window_layout.hpp * */ @@ -53,20 +53,18 @@ namespace detail static void paste_children_to_graphics(basic_window*, nana::paint::graphics& graph); - //read_visual_rectangle - //@brief: Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget, - // the visual rectangle is a rectangular block that a window should be displayed on screen. - // The result is a rectangle that is a visible area for its ancesters. + ///read_visual_rectangle + ///@brief: Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget, + /// the visual rectangle is a rectangular block that a window should be displayed on screen. + /// The result is a rectangle that is a visible area for its ancesters. static bool read_visual_rectangle(basic_window*, nana::rectangle& visual); - //read_overlaps - // reads the overlaps that are overlapped a rectangular block + /// reads the overlaps that are overlapped a rectangular block static bool read_overlaps(basic_window*, const nana::rectangle& vis_rect, std::vector& blocks); static bool enable_effects_bground(basic_window *, bool enabled); - //make_bground - // update the glass buffer of a glass window. + /// update the glass buffer of a glass window. static void make_bground(basic_window* const); private: diff --git a/include/nana/gui/detail/window_manager.hpp b/include/nana/gui/detail/window_manager.hpp index 56dc0f8a3..987f9fab3 100644 --- a/include/nana/gui/detail/window_manager.hpp +++ b/include/nana/gui/detail/window_manager.hpp @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/detail/window_manager.hpp + * @file nana/gui/detail/window_manager.hpp * * * destroy method destroys a window handle and the handles of its children, but it doesn't delete the handle which type is a root window @@ -61,9 +61,7 @@ namespace nana::detail basic_window* create_widget(basic_window*, const rectangle&, bool is_lite, widget*); void close(basic_window*); - //destroy - //@brief: Delete the window handle - void destroy(basic_window*); + void destroy(basic_window*); ///< Delete the window handle //destroy_handle //@brief: Delete window handle, the handle type must be a root and a frame. @@ -89,7 +87,7 @@ namespace nana::detail basic_window* root(native_window_type) const; - //Copy the root buffer that wnd specified into DeviceContext + /// Copy the root buffer that wnd specified into DeviceContext void map(basic_window*, bool forced, const rectangle* update_area = nullptr); bool update(basic_window*, bool redraw, bool force, const rectangle* update_area = nullptr); @@ -111,7 +109,7 @@ namespace nana::detail void enable_tabstop(basic_window*); void disable_tabstop(basic_window*); - basic_window* tabstop(basic_window*, bool forward) const; //forward means move to next in logic. + basic_window* tabstop(basic_window*, bool forward) const; ///< forward means move to next in logic. void remove_trash_handle(thread_t tid); diff --git a/include/nana/gui/drawing.hpp b/include/nana/gui/drawing.hpp index 65bca9f03..36aa67675 100644 --- a/include/nana/gui/drawing.hpp +++ b/include/nana/gui/drawing.hpp @@ -1,4 +1,4 @@ -/* +/** * A Drawing Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2014 Jinhao(cnjinhao@hotmail.com) @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/drawing.hpp + * @file nana/gui/drawing.hpp */ #ifndef NANA_DRAWING_REMOVED @@ -18,6 +18,7 @@ #include #include "widgets/widget.hpp" #include "../traits.hpp" + namespace nana { /// \brief Draw pictures on a widget by specifying a drawing method that will be employed every time the widget refreshes. diff --git a/include/nana/gui/programming_interface.hpp b/include/nana/gui/programming_interface.hpp index f4214165a..25dea1119 100644 --- a/include/nana/gui/programming_interface.hpp +++ b/include/nana/gui/programming_interface.hpp @@ -1,4 +1,4 @@ -/* +/** * Nana GUI Programming Interface Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2024 Jinhao(cnjinhao@hotmail.com) @@ -7,11 +7,14 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/programming_interface.hpp + * @file nana/gui/programming_interface.hpp */ #ifndef NANA_GUI_PROGRAMMING_INTERFACE_HPP #define NANA_GUI_PROGRAMMING_INTERFACE_HPP + +#include + #include #include "effects.hpp" #include "detail/general_events.hpp" @@ -19,7 +22,6 @@ #include "detail/widget_content_measurer_interface.hpp" #include "detail/virtual_keyboard.hpp" #include -#include namespace nana { @@ -361,7 +363,7 @@ namespace api bool window_text_editor_editable(window); ::std::optional window_text_editor_rectangle(window wd, bool including_scrollbars); ::std::optional window_rectangle(window); - bool get_window_rectangle(window, rectangle&); + bool get_window_rectangle(window, rectangle& r_in_parent); ///< the window rectangle in parent coordinates bool track_window_size(window, const size&, bool true_for_max); ///< Sets the minimum or maximum tracking size of a window. void window_enabled(window, bool); bool window_enabled(window); @@ -474,7 +476,9 @@ namespace api bool calc_screen_point(window, point&); ///> content_extent(window wd, unsigned limited_px, bool limit_width); - /// \todo: generalize dpi to v2 awareness - unsigned screen_dpi(bool x_requested); + int screen_dpi(bool x_requested = true); ///< unused ? - std::size_t window_dpi(window); + int window_dpi(window); dragdrop_status window_dragdrop_status(::nana::window); void keyboard_default_language(const std::string& lang); diff --git a/include/nana/gui/screen.hpp b/include/nana/gui/screen.hpp index 9954728df..6b712ff53 100644 --- a/include/nana/gui/screen.hpp +++ b/include/nana/gui/screen.hpp @@ -1,4 +1,4 @@ -/* +/** * Screen Informations * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) @@ -7,18 +7,20 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * -* @file: nana/gui/screen.hpp +* @file nana/gui/screen.hpp */ #ifndef NANA_GUI_SCREEN_HPP #define NANA_GUI_SCREEN_HPP -#include "basis.hpp" + #include #include +#include "basis.hpp" + namespace nana { - /// The monitor display metrics + /// The monitor display metrics class display { public: @@ -30,11 +32,17 @@ namespace nana virtual bool is_primary_monitor() const = 0; /// Returns the positional coordinates and size of the display device in reference to the desktop area - virtual const ::nana::rectangle& area() const = 0; - virtual const ::nana::rectangle& workarea() const = 0; + virtual ::nana::rectangle area() const = 0; + virtual ::nana::rectangle workarea() const = 0; + virtual int dpi() const = 0; + virtual double scaling() const = 0; }; - /// Provides some functions to get the metrics of the monitors \include screen.cpp + /// the Whole-System-Screen (WSS): a virtual screen that included all monitors placed in the relative positions specified by the user. + /// + /// Some parts of this WSS are not occupied by any monitor. May use User-side (WSS_US) or System-side (WSS_SS) scaling. + /// The O is in the left/top point of the main monitor. + /// Provides some functions to get the metrics of the monitors \include screen.cpp class screen { struct implement; diff --git a/include/nana/gui/timer.hpp b/include/nana/gui/timer.hpp index 0f28116ed..64eecfb07 100644 --- a/include/nana/gui/timer.hpp +++ b/include/nana/gui/timer.hpp @@ -1,4 +1,4 @@ -/* +/** * A Timer Implementation * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) * @@ -6,13 +6,13 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/timer.hpp - * @description: + * @file nana/gui/timer.hpp + * @description * A timer can repeatedly call a piece of code. The duration between * calls is specified in milliseconds. Timer is different from other graphics * controls, it has no graphics interface. * - * @contributors: rbrugo(#417) + * @contributors rbrugo(#417) */ #ifndef NANA_GUI_TIMER_HPP diff --git a/include/nana/gui/widgets/button.hpp b/include/nana/gui/widgets/button.hpp index 7bd4a7fc8..f689bb402 100644 --- a/include/nana/gui/widgets/button.hpp +++ b/include/nana/gui/widgets/button.hpp @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/widgets/button.hpp + * @file nana/gui/widgets/button.hpp * @contributor * besh81(pr#361) */ diff --git a/include/nana/gui/widgets/textbox.hpp b/include/nana/gui/widgets/textbox.hpp index e6f675146..286d0e8a7 100644 --- a/include/nana/gui/widgets/textbox.hpp +++ b/include/nana/gui/widgets/textbox.hpp @@ -9,15 +9,18 @@ * * @file: nana/gui/widgets/textbox.hpp */ + #ifndef NANA_GUI_WIDGET_TEXTBOX_HPP #define NANA_GUI_WIDGET_TEXTBOX_HPP + +#include + #include #include #include "skeletons/textbase_export_interface.hpp" #include "skeletons/text_editor_part.hpp" -#include namespace nana { diff --git a/include/nana/gui/widgets/treebox.hpp b/include/nana/gui/widgets/treebox.hpp index 45dc3e79d..9a2a20e2f 100644 --- a/include/nana/gui/widgets/treebox.hpp +++ b/include/nana/gui/widgets/treebox.hpp @@ -110,17 +110,14 @@ namespace nana public: struct treebox_node_type { - treebox_node_type(std::string = {}); - treebox_node_type& operator=(const treebox_node_type&); - - ::std::string text; - std::any value; - bool expanded{ false }; - bool hidden{ false }; - bool selected{ false }; - checkstate checked{ checkstate::unchecked }; - ::std::string img_idstr; - }; + std::string text; + std::any value; + bool expanded {false}; + bool hidden {false}; + bool selected {false}; + checkstate checked {checkstate::unchecked}; + std::string img_idstr; + }; using tree_cont_type = widgets::detail::tree_cont; using node_type = tree_cont_type::node_type; diff --git a/include/nana/paint/detail/native_paint_interface.hpp b/include/nana/paint/detail/native_paint_interface.hpp index a6cc4534a..3b66ae988 100644 --- a/include/nana/paint/detail/native_paint_interface.hpp +++ b/include/nana/paint/detail/native_paint_interface.hpp @@ -1,12 +1,12 @@ -/* +/** * Platform Implementation - * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2024 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/paint/detail/native_paint_interface.hpp + * @file nana/paint/detail/native_paint_interface.hpp */ #ifndef NANA_PAINT_DETAIL_PLATFORM_HPP @@ -19,23 +19,23 @@ namespace paint { namespace detail { - nana::size drawable_size(drawable_type); + nana::size drawable_size(drawable_type); ///< return dpi: system side - std::unique_ptr alloc_fade_table(double fade_rate); - void free_fade_table(const unsigned char*); + std::unique_ptr alloc_fade_table(double fade_rate); ///\todo: here ? //color = bgcolor * fade_rate + fgcolor * (1 - fade_rate); - nana::pixel_color_t fade_color(nana::pixel_color_t bgcolor, nana::pixel_color_t fgcolor, const unsigned char* const fade_table); - nana::pixel_color_t fade_color_intermedia(pixel_color_t fgcolor, const unsigned char* fade_table); + nana::pixel_color_t fade_color (pixel_color_t bgcolor, nana::pixel_color_t fgcolor , const unsigned char* const fade_table); + nana::pixel_color_t fade_color_intermedia (pixel_color_t fgcolor , const unsigned char* fade_table); nana::pixel_color_t fade_color_by_intermedia(pixel_color_t bgcolor, nana::pixel_color_t fgcolor_intermedia, const unsigned char* const fade_table); //dw color = dw color * fade_rate + bdcolor * (1 - fade_rate) void blend(drawable_type dw, const nana::rectangle& r, pixel_color_t bdcolor, double fade_rate); - nana::size real_text_extent_size(drawable_type, const char*, std::size_t len); - nana::size real_text_extent_size(drawable_type, const wchar_t*, std::size_t len); - nana::size text_extent_size(drawable_type, const char*, std::size_t len); - nana::size text_extent_size(drawable_type, const wchar_t*, std::size_t len); + /// \todo: take string_view? dpi: system side? all pos/size dpi scaled. Need to be unscaled to be pass to user side. + nana::size real_text_extent_size(drawable_type, const char*, std::size_t len); ///< dpi: system side \todo: take string_view? + nana::size real_text_extent_size(drawable_type, const wchar_t*, std::size_t len); ///< dpi: system side \todo: take string_view? + nana::size text_extent_size(drawable_type, const char*, std::size_t len); ///< dpi: system side \todo: take string_view? + nana::size text_extent_size(drawable_type, const wchar_t*, std::size_t len); ///< dpi: system side \todo: take string_view? void draw_string(drawable_type, const nana::point&, const wchar_t *, std::size_t len); }//end namespace detail diff --git a/include/nana/paint/detail/ptdefs.hpp b/include/nana/paint/detail/ptdefs.hpp index c381c9d73..65c1ee7cf 100644 --- a/include/nana/paint/detail/ptdefs.hpp +++ b/include/nana/paint/detail/ptdefs.hpp @@ -1,3 +1,17 @@ +/** + * Font styles and font information + * Nana C++ Library + * Documentation https://nana.acemind.cn/documentation + * Sources: https://github.com/cnjinhao/nana + * Copyright(C) 2003-2024 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/paint/detail/ptdefs.hpp + */ + #ifndef NANA_PAINT_PTDEFS_INCLUDED #define NANA_PAINT_PTDEFS_INCLUDED #include @@ -6,8 +20,7 @@ namespace nana { namespace detail { - struct native_font_signature; - + struct native_font_signature; ///< \todo unused? struct font_style { @@ -17,10 +30,6 @@ namespace nana bool strike_out{ false }; bool antialiasing{ true }; - font_style() = default; - font_style(unsigned weight, bool italic = false, bool underline = false, bool strike_out = false); - - font_style& change_weight(unsigned); font_style& change_italic(bool); font_style& change_underline(bool); @@ -31,12 +40,12 @@ namespace nana namespace paint { - using native_font_type = ::nana::detail::native_font_signature*; + using native_font_type = ::nana::detail::native_font_signature*; ///< \todo unused? struct font_info { - std::string family; ///< Font family - double size_pt; ///< Font Size, in pt. + std::string family; ///< Font family + double size_pt; ///< Font Size, in pt., 1 pt = 1 inch/72 (not scaled) nana::detail::font_style style; ///< Font Styles }; } diff --git a/include/nana/paint/graphics.hpp b/include/nana/paint/graphics.hpp index 6f657fc68..bb24f6cb3 100644 --- a/include/nana/paint/graphics.hpp +++ b/include/nana/paint/graphics.hpp @@ -1,4 +1,4 @@ -/* +/** * Paint Graphics Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2021 Jinhao(cnjinhao@hotmail.com) @@ -7,27 +7,27 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/paint/graphics.hpp + * @file nana/paint/graphics.hpp */ #ifndef NANA_PAINT_GRAPHICS_HPP #define NANA_PAINT_GRAPHICS_HPP +#include #include +#include +#include #include "../basic_types.hpp" #include "../gui/basis.hpp" -#include -#include #include "detail/ptdefs.hpp" -#include - namespace nana { namespace paint { + /// functions to create and set/get properties of fonts class font { friend class graphics; @@ -36,30 +36,30 @@ namespace nana using font_style = ::nana::detail::font_style; - font(); - font(drawable_type); - font(const font&); + font(); ///< use the application default font + font(drawable_type src); ///< extract the font of the drawable_type. Warnnig: assign only from fonts with the expected target dpi. + font(const font&); ///< Warnnig: copy only from fonts with the expected target dpi. /// \todo: generalize dpi to v2 awareness /// creates a font object. /// @param info Specifies the font family, size and styles. /// @param dpi Specifies the DPI for scaling the font, 0 indicates the system DPI. - font(const font_info& info, std::size_t dpi = 0); + font(const font_info& info, int dpi = 0); /// creates a font object. /// @param name The font family. /// @param size_pt The font size. /// @param fs The font style. /// @param dpi Specifies the DPI for scaling the font, 0 indicates the system DPI. - font(const ::std::string& name, double size_pt, const font_style& fs = {}, std::size_t dpi = 0); + font(const ::std::string& name, double size_pt, const font_style& fs = {}, int dpi = 0); - /// creates a font object with a truetype font file. + /// creates a font object from a TrueType font file. /// @param size_pt The font size. /// @param truetype The path to a truetype font file /// @param fs The font style. /// @param dpi Specifies the DPI for scaling the font, 0 indicates the system DPI. - font(double size_pt, const path_type& truetype, const font_style& fs = {}, std::size_t dpi = 0); + font(double size_pt, const path_type& truetype, const font_style& fs = {}, int dpi = 0); ~font(); bool empty() const; @@ -69,10 +69,13 @@ namespace nana /// Returns font size, in point. /** - * @param fixed Indicates whether to return a fixed font size. If this parameter is false, the method may return zero for default system font size. If the parameter is true, the method returns a fixed size of default font size if the font size that assigned by constructor is zero. + * @param fixed Indicates whether to return a fixed font size. If this parameter is false, + * the method may return zero for default system font size. If the parameter is true, + * the method returns a fixed size of default font size if the font size that assigned by constructor is zero. + * @param dpi Specifies the DPI for de-scaling the size to user-side, 0 indicates the system DPI. * @return The font size, in point. */ - double size(bool fixed = false) const; + double size(bool fixed = false, int dpi = 0) const; bool bold() const; unsigned weight() const; @@ -86,7 +89,7 @@ namespace nana std::optional info() const; - font& operator=(const font&); + font& operator=(const font&); ///< Warnnig: assign only from fonts with the expected target dpi. bool operator==(const font&) const; bool operator!=(const font&) const; private: @@ -105,8 +108,8 @@ namespace nana class graphics { public: - graphics(); - graphics(const ::nana::size&); ///< size in pixel + explicit graphics(int dpi = 0); + graphics(const ::nana::size& sz, int dpi );//= 96 ///< size in pixel graphics(const graphics&); ///< the resource is not copyed, the two graphics objects refer to the *SAME* resource graphics& operator=(const graphics&); @@ -115,7 +118,7 @@ namespace nana ~graphics(); - bool changed() const; ///< Returns true if the graphics object is operated + bool changed() const; ///< Returns true if the graphics object is operated \todo: not used ?? bool empty() const; ///< Returns true if the graphics object does not refer to any resource. explicit operator bool() const noexcept; @@ -129,15 +132,17 @@ namespace nana /** * @param sz The dimension of the graphics to be requested. If sz is empty, it performs as release(). */ - void make(const ::nana::size& sz); - void resize(const ::nana::size&); - void typeface(const font&); ///< Selects a specified font type into the graphics object. + void make(const ::nana::size& sz); ///\todo take dpi + void resize(const ::nana::size&); ///\todo take dpi + void set_dpi(int dpi); + int get_dpi() const; + void typeface(const font&); ///< Selects a specified font type into the graphics object. \todo: dpi? font typeface() const; - ::nana::size text_extent_size(std::string_view text) const; - ::nana::size text_extent_size(std::wstring_view text) const; + ::nana::size text_extent_size(std::string_view text) const; ///< dpi unscaled: user-side + ::nana::size text_extent_size(std::wstring_view text) const; ///< dpi unscaled: user-side #ifdef __cpp_char8_t - ::nana::size text_extent_size(std::u8string_view text) const; + ::nana::size text_extent_size(std::u8string_view text) const; ///< dpi unscaled: user-side #endif ///Only supports the wide string, because it is very hard to specify the begin and end position in a UTF-8 string. @@ -150,37 +155,46 @@ namespace nana */ std::unique_ptr glyph_pixels(std::wstring_view text) const; - ::nana::size bidi_extent_size(std::string_view utf8_text) const; - ::nana::size bidi_extent_size(std::wstring_view text) const; + ::nana::size bidi_extent_size(std::string_view utf8_text) const; ///< unscaled: user-side + ::nana::size bidi_extent_size(std::wstring_view text) const; ///< unscaled: user-side #ifdef __cpp_char8_t - ::nana::size bidi_extent_size(std::u8string_view text) const; + ::nana::size bidi_extent_size(std::u8string_view text) const; ///< unscaled: user-side #endif bool text_metrics(unsigned & ascent, unsigned& descent, unsigned& internal_leading) const; void line_begin(int x, int y); - void bitblt(int x, int y, const graphics& source); ///< Transfers the source to the specified point. - void bitblt(const ::nana::rectangle& r_dst, native_window_type src); ///< Transfers the color data corresponding to r_dst from the src window to this graphics. - void bitblt(const ::nana::rectangle& r_dst, native_window_type src, const point& p_src); ///< Transfers the color data corresponding to r_dst from the src window at point p_src to this graphics. - void bitblt(const ::nana::rectangle& r_dst, const graphics& src); ///< Transfers the color data corresponding to r_dst from the src graphics to this graphics. - void bitblt(const ::nana::rectangle& r_dst, const graphics& src, const point& p_src);///< Transfers the color data corresponding to r_dst from the src graphics at point p_src to this graphics. + + /// \todo: how to manage scaling here?? stretch if dpi_src != dpi_dst ?? + + // to , from + void bitblt( int x, int y, const graphics& src ); ///< Transfers the whole source to the specified point. + void bitblt(const nana::rectangle& r_dst, const graphics& src ); ///< Transfers the color data corresponding to r_dst from the src graphics to this graphics. + void bitblt(const nana::rectangle& r_dst, const graphics& src, const point& p_src); ///< Transfers the color data corresponding to r_dst from the src graphics at point p_src to this graphics. + void bitblt(const nana::rectangle& r_dst, native_window_type src ); ///< Transfers to r_dst of this graphics from the src window the corresponding color data \todo + void bitblt(const nana::rectangle& r_dst, native_window_type src, const point& p_src); ///< Transfers the color data corresponding to r_dst from the src window at point p_src to this graphics. + + // from , to + void paste( graphics& dst, int x, int y) const; ///< Paste the whole graphics object into the dest at (x, y) + void paste(const ::nana::rectangle& r_src, graphics& dst, int x, int y) const; ///< Paste r_src of graphics object into the dest at (x, y) + + // to , from + void paste(native_window_type dst, const ::nana::rectangle& r_dst , int sx, int sy) const; ///< Paste the graphics object into a platform-dependent window at (x, y) + void paste(native_window_type dst, int dx, int dy, unsigned width, unsigned height, int sx, int sy) const; + void paste( drawable_type dst, int x, int y ) const; + + // from , to + void stretch(const ::nana::rectangle& src_r, graphics& dst, const ::nana::rectangle& dst_r) const; + void stretch( graphics& dst, const ::nana::rectangle& dst_r) const; void blend(const ::nana::rectangle& r, const ::nana::color&, double fade_rate); void blend(const ::nana::rectangle& blend_r, const graphics& blend_graph, const point& blend_graph_point, double fade_rate);///< blends with the blend_graph. void blur(const ::nana::rectangle& r, std::size_t radius); ///< Blur process. - void paste(graphics& dst, int x, int y) const; ///< Paste the graphics object into the dest at (x, y) - void paste(native_window_type dst, const ::nana::rectangle&, int sx, int sy) const; ///< Paste the graphics object into a platform-dependent window at (x, y) - void paste(native_window_type dst, int dx, int dy, unsigned width, unsigned height, int sx, int sy) const; - void paste(drawable_type dst, int x, int y) const; - void paste(const ::nana::rectangle& r_src, graphics& dst, int x, int y) const; void rgb_to_wb(bool skip_transparent_pixels = false); ///< Transform a color graphics into black&white. - void stretch(const ::nana::rectangle& src_r, graphics& dst, const ::nana::rectangle& r) const; - void stretch(graphics& dst, const ::nana::rectangle&) const; - void flush(); unsigned width() const; ///< Returns the width of the off-screen buffer. diff --git a/include/nana/paint/image.hpp b/include/nana/paint/image.hpp index bc6cc0428..4b2e55c97 100644 --- a/include/nana/paint/image.hpp +++ b/include/nana/paint/image.hpp @@ -1,4 +1,4 @@ -/* +/** * Paint Image Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2021 Jinhao(cnjinhao@hotmail.com) @@ -7,8 +7,8 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/paint/image.hpp - * @description: class image is used for load an image file into memory. + * @file nana/paint/image.hpp + * @description class image is used for load an image file into memory. */ #ifndef NANA_PAINT_IMAGE_HPP @@ -47,7 +47,7 @@ namespace paint void close() noexcept; /// Saves the image as a Windows bitmap file - bool save(std::filesystem::path) const; + bool save(std::filesystem::path file) const; bool alpha() const noexcept; nana::size size() const noexcept; diff --git a/include/nana/paint/pixel_buffer.hpp b/include/nana/paint/pixel_buffer.hpp index 79f15d769..246b43b66 100644 --- a/include/nana/paint/pixel_buffer.hpp +++ b/include/nana/paint/pixel_buffer.hpp @@ -1,4 +1,4 @@ -/* +/** * Pixel Buffer Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2022 Jinhao(cnjinhao@hotmail.com) @@ -7,19 +7,20 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/paint/pixel_buffer.hpp + * @file nana/paint/pixel_buffer.hpp */ #ifndef NANA_PAINT_PIXEL_BUFFER_HPP #define NANA_PAINT_PIXEL_BUFFER_HPP -#include -#include #include +#include + +#include namespace nana{ namespace paint { - /// Alpha blend operations + /// Alpha blend operations enum class alpha_methods { straight_alpha, ///< DestColor = SrcColor * SrcAlpha + DestColor * (1 - SrcAlpha), DestAlpha = SrcAlpha * SrcAlpha + (1 - SrcAlpha) * DestAlpha @@ -27,7 +28,8 @@ namespace nana{ namespace paint direct_copy, ///< DestColor = SrcColor, DestAlpha = SrcAlpha }; - class pixel_buffer + /// dpi scaling SS: put after scaling + class pixel_buffer { struct pixel_buffer_storage; typedef bool (pixel_buffer:: * unspecified_bool_t)() const; diff --git a/include/nana/traits.hpp b/include/nana/traits.hpp index 558b7b56b..03cbbd79f 100644 --- a/include/nana/traits.hpp +++ b/include/nana/traits.hpp @@ -1,7 +1,12 @@ -/* +/** * Traits Implementation + * Nana C++ Library(http://www.nanapro.org) * Copyright(C) 2003-2024 Jinhao(cnjinhao@hotmail.com) * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * * @file nana/traits.hpp */ @@ -9,6 +14,8 @@ #define NANA_TRAITS_HPP #include +/// \todo: update + namespace nana { class null_type{}; diff --git a/source/detail/mswin/platform_spec.hpp b/source/detail/mswin/platform_spec.hpp index a0ae58b18..b46d12684 100644 --- a/source/detail/mswin/platform_spec.hpp +++ b/source/detail/mswin/platform_spec.hpp @@ -32,10 +32,9 @@ namespace nana namespace detail { - //struct messages - //@brief: This defines some messages that are used for remote thread invocation. - // Some Windows APIs are window-thread-dependent, the operation in other thread - // must be posted to its own thread. + ///@brief: This defines some messages that are used for remote thread invocation. + /// Some Windows APIs are window-thread-dependent, the operation in other thread + /// must be posted to its own thread. struct messages { struct caret @@ -78,12 +77,12 @@ namespace detail }; }; - struct drawable_impl_type + struct drawable_impl_type ///\todo: keep a dpi ? move to native_paint_interface.hpp ? { using font_type = ::std::shared_ptr; - HDC context; - HBITMAP pixmap; + HDC context; + HBITMAP pixmap; pixel_argb_t* pixbuf_ptr{nullptr}; std::size_t bytes_per_line{0}; @@ -91,23 +90,23 @@ namespace detail struct string_spec { - unsigned tab_length; - unsigned tab_pixels; - unsigned whitespace_pixels; + unsigned tab_length; ///< an application-defined tab length in whitespace characters + unsigned tab_pixels; ///< the width of a tab character, defined by the font + unsigned whitespace_pixels; ///< the width of a whitespace character, defined by the font }string; - unsigned fgcolor_rgb{ 0xFFFFFFFF }; - unsigned bgcolor_rgb{ 0xFFFFFFFF }; + unsigned fgcolor_rgb { 0xFFFFFFFF }; + unsigned bgcolor_rgb { 0xFFFFFFFF }; unsigned fgcolor_native{ 0xFFFFFFFF }; //Windows RGB format: 0xBBGGRR unsigned bgcolor_native{ 0xFFFFFFFF }; //Windows RGB format - drawable_impl_type(const drawable_impl_type&) = delete; + drawable_impl_type (const drawable_impl_type&) = delete; drawable_impl_type& operator=(const drawable_impl_type&) = delete; drawable_impl_type(); ~drawable_impl_type(); - void set_color(const ::nana::color&); + void set_color (const ::nana::color&); void set_text_color(const ::nana::color&); }; diff --git a/source/detail/platform_abstraction.cpp b/source/detail/platform_abstraction.cpp index 7467ebf26..108428d14 100644 --- a/source/detail/platform_abstraction.cpp +++ b/source/detail/platform_abstraction.cpp @@ -1,3 +1,19 @@ +/** + * Platform Abstraction Implementation + * Nana C++ Library + * Documentation https://nana.acemind.cn/documentation + * Sources: https://github.com/cnjinhao/nana + * Copyright(C) 2003-2024 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/source/detail/platform_abstraction.cpp + * @contributors Jinhao + */ + + #include #include @@ -12,12 +28,13 @@ #ifdef NANA_WINDOWS - +//# include # ifndef _WIN32_WINNT # define _WIN32_WINNT 0x0501 # endif # include + /////////////////////////////////////////////////////////////////////////////////////////////////////// /****************************************************************** @@ -761,7 +778,7 @@ namespace nana } } - std::shared_ptr open_font(font_info fi, std::size_t dpi, const path_type& ttf) + std::shared_ptr open_font(font_info fi, int dpi, const path_type& ttf) { if (0 == dpi) { @@ -866,7 +883,7 @@ namespace nana ); } - // Returns the DPI-dependent font size, in pixels + /// Returns the DPI-dependent font size, in pixels \todo: ?? static font_height_type _m_set_default_values(font_info& fi, std::size_t dpi) { #ifdef NANA_WINDOWS @@ -877,7 +894,7 @@ namespace nana //Translate pt to px auto hDC = ::GetDC(nullptr); - auto font_height = -static_cast(fi.size_pt * dpi / 72); + auto font_height = -static_cast(fi.size_pt * dpi / 72.0); if (wfont_family.empty() || (0 == font_height)) { @@ -906,9 +923,9 @@ namespace nana if (0 == font_height) { - auto correspond_dpi = detail::native_interface::system_dpi(); - fi.size_pt = static_cast(std::abs(metrics.lfMessageFont.lfHeight) * 72 / correspond_dpi); - font_height = -static_cast(fi.size_pt * dpi / 72); + auto correspond_dpi = detail::native_interface::system_dpi(); /// \todo OK + fi.size_pt = static_cast(std::abs(metrics.lfMessageFont.lfHeight) * 72.0 / correspond_dpi); + font_height = -static_cast(fi.size_pt * dpi / 72.0); } } @@ -931,8 +948,8 @@ namespace nana std::wstring wfont_family = nana::detail::to_nstring(fi.family); //Translate pt to px - auto hDC = ::GetDC(nullptr); - auto font_height = -static_cast(fi.size_pt * dpi / 72); + auto hDC = ::GetDC(nullptr); /// \todo OK?? + auto font_height = -static_cast(fi.size_pt * dpi / 72.0); ::ReleaseDC(nullptr, hDC); ::LOGFONT lf{}; @@ -1153,11 +1170,11 @@ namespace nana //end class revertible_mutex - /// \todo: generalize dpi to v2 awareness + /// \todo: generalize dpi to v2 awareness. Set for each monitor struct platform_runtime { platform_abstraction::revertible_mutex mutex; - std::size_t dpi{ 0 }; + int dpi{ 96 }; std::shared_ptr font; font_service font_svc; }; @@ -1260,8 +1277,8 @@ namespace nana void platform_abstraction::initialize() { - if (nullptr == data::storage) - data::storage = new platform_runtime; + if (data::storage) return; + data::storage = new platform_runtime{.dpi{screen_dpi()}}; } void platform_abstraction::shutdown() @@ -1288,8 +1305,7 @@ namespace nana { #ifdef NANA_WINDOWS //Create default font object. - NONCLIENTMETRICS metrics = {}; - metrics.cbSize = sizeof metrics; + NONCLIENTMETRICS metrics = {.cbSize = sizeof(NONCLIENTMETRICS)}; #if(WINVER >= 0x0600) #if defined(NANA_MINGW) OSVERSIONINFO osvi = {}; @@ -1340,37 +1356,31 @@ namespace nana return r.font; } - void platform_abstraction::set_current_dpi(std::size_t dpi) + void platform_abstraction::set_current_dpi(int dpi) { platform_storage().dpi = dpi; } /// \todo: generalize dpi to v2 awareness - std::size_t platform_abstraction::current_dpi() + int platform_abstraction::current_dpi() { return platform_storage().dpi; } - int platform_abstraction::dpi_scale(int size) + int platform_abstraction::dpi_scale(int scalar) { - double dpiScale = static_cast(current_dpi() / 96.0); - - return static_cast(size * dpiScale); + return dpi_scale(scalar, current_dpi()); } - nana::size platform_abstraction::dpi_scale(nana::size size) + nana::size platform_abstraction::dpi_scale(const nana::size& size) { - double dpiScale = static_cast(current_dpi() / 96.0); - - return { static_cast(size.width * dpiScale), static_cast(size.height * dpiScale) }; + return dpi_scale(size, current_dpi()); } - nana::point platform_abstraction::dpi_scale(nana::point point) - { - double dpiScale = static_cast(current_dpi() / 96.0); - - return { static_cast(point.x * dpiScale), static_cast(point.y * dpiScale) }; - } + nana::point platform_abstraction::dpi_scale(const nana::point& point) + { + return dpi_scale(point, current_dpi()); + } int platform_abstraction::dpi_scale(window wd, int scalar) { @@ -1400,12 +1410,120 @@ namespace nana return { static_cast(point.x * dpiScale), static_cast(point.y * dpiScale) }; } - std::shared_ptr platform_abstraction::open_font(const font_info& fi, std::size_t dpi, const path_type& ttf) + std::shared_ptr platform_abstraction::open_font(const font_info& fi, int dpi, const path_type& ttf) { nana::internal_scope_guard lock; return platform_storage().font_svc.open_font(fi, dpi, ttf); } + /// dpi scaling for int + int platform_abstraction::dpi_scale(const int scalar, int dpi) + { + return static_cast(static_cast (dpi) * scalar / 96); + } + int platform_abstraction::dpi_transform(int& scalar, int dpi) + { + return scalar = static_cast(static_cast (dpi) * scalar / 96); + } + int platform_abstraction::unscale_dpi(const int scalar, int dpi) + { + return static_cast(static_cast (scalar) * 96 / dpi); + } + int platform_abstraction::untransform_dpi(int& scalar, int dpi) + { + return scalar = static_cast(static_cast(scalar) * 96 / dpi); + } + /// dpi scaling for unsigned int + unsigned int platform_abstraction::dpi_scale(const unsigned int scalar, int dpi) + { + return static_cast(static_cast(dpi) * scalar / 96); + } + unsigned int platform_abstraction::dpi_transform(unsigned int& scalar, int dpi) + { + return scalar = static_cast(static_cast (dpi) * scalar / 96); + } + unsigned int platform_abstraction::unscale_dpi(const unsigned int scalar, int dpi) + { + return static_cast(static_cast (scalar) * 96 / dpi); + } + unsigned int platform_abstraction::untransform_dpi(unsigned int& scalar, int dpi) + { + return scalar = static_cast(static_cast (scalar) * 96 / dpi); + } + + /// dpi scaling for nana::size + nana::size platform_abstraction::dpi_scale(const nana::size& sz, int dpi) + { + return { static_cast(static_cast (dpi) * sz.width / 96), + static_cast(static_cast (dpi) * sz.height / 96) }; + } + nana::size platform_abstraction::dpi_transform(nana::size& sz, int dpi) + { + sz.width = static_cast(static_cast (dpi) * sz.width / 96); + sz.height = static_cast(static_cast (dpi) * sz.height / 96); + return sz; + } + nana::size platform_abstraction::unscale_dpi(const nana::size& sz, int dpi) + { + return { static_cast(static_cast(sz.width) * 96 / dpi), + static_cast(static_cast (sz.height) * 96 / dpi) }; + } + nana::size platform_abstraction::untransform_dpi(nana::size& sz, int dpi) + { + sz.width = static_cast(static_cast (sz.width) * 96 / dpi); + sz.height = static_cast(static_cast (sz.height) * 96 / dpi); + return sz; + } + + /// dpi scaling for nana::point + nana::point platform_abstraction::dpi_scale(const nana::point& pt, int dpi) + { + return { static_cast(static_cast (dpi) * pt.x / 96), + static_cast(static_cast (dpi) * pt.y / 96) }; + } + nana::point platform_abstraction::dpi_transform(nana::point& pt, int dpi) + { + pt.x = static_cast(static_cast (dpi) * pt.x / 96); + pt.y = static_cast(static_cast (dpi) * pt.y / 96); + return pt; + } + nana::point platform_abstraction::unscale_dpi(const nana::point& pt, int dpi) + { + return { static_cast(static_cast (pt.x) * 96 / dpi), + static_cast(static_cast (pt.y) * 96 / dpi) }; + } + nana::point platform_abstraction::untransform_dpi(nana::point& pt, int dpi) + { + pt.x = static_cast(static_cast (pt.x) * 96 / dpi); + pt.y = static_cast(static_cast (pt.y) * 96 / dpi); + return pt; + } + + /// dpi scaling for nana::rectangle + nana::rectangle platform_abstraction::dpi_scale(const nana::rectangle& r, int dpi) + { + return nana::rectangle{ dpi_scale(r.position(), dpi), + dpi_scale(r.dimension(), dpi) }; + } + nana::rectangle platform_abstraction::dpi_transform(nana::rectangle& r, int dpi) + { + r.position (dpi_scale( r.position(), dpi)); + r.dimension(dpi_scale(r.dimension(), dpi)); + return r; + } + nana::rectangle platform_abstraction::unscale_dpi(const nana::rectangle& r, int dpi) + { + return nana::rectangle{ unscale_dpi(r.position() , dpi), + unscale_dpi(r.dimension(), dpi) }; + } + nana::rectangle platform_abstraction::untransform_dpi(nana::rectangle& r, int dpi) + { + r.position (unscale_dpi( r.position(), dpi)); + r.dimension(unscale_dpi(r.dimension(), dpi)); + return r; + } + + void platform_abstraction::font_resource(bool try_add, const path_type& ttf) { #ifdef NANA_WINDOWS @@ -1427,29 +1545,9 @@ namespace nana } #endif } - /// \todo: generalize dpi to v2 awareness - unsigned platform_abstraction::screen_dpi(bool x_requested) + + int platform_abstraction::screen_dpi(bool x_requested) { -#ifdef NANA_WINDOWS - auto hdc = ::GetDC(nullptr); - auto dots = static_cast(::GetDeviceCaps(hdc, (x_requested ? LOGPIXELSX : LOGPIXELSY))); - ::ReleaseDC(nullptr, hdc); - return dots; -#else - auto & spec = ::nana::detail::platform_spec::instance(); - auto disp = spec.open_display(); - auto screen = ::XDefaultScreen(disp); - - double dots = 0.5; - - if (x_requested) - dots += ((((double)DisplayWidth(disp, screen)) * 25.4) / - ((double)DisplayWidthMM(disp, screen))); - else - dots += ((((double)DisplayHeight(disp, screen)) * 25.4) / - ((double)DisplayHeightMM(disp, screen))); - - return static_cast(dots); -#endif + return detail::native_interface::system_dpi(x_requested); } } diff --git a/source/detail/platform_abstraction.hpp b/source/detail/platform_abstraction.hpp index f8a0324cc..0901ba2c7 100644 --- a/source/detail/platform_abstraction.hpp +++ b/source/detail/platform_abstraction.hpp @@ -1,4 +1,4 @@ -/* +/** * Platform Abstraction * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2017-2022 Jinhao(cnjinhao@hotmail.com) @@ -7,17 +7,19 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/detail/platform_spec.hpp + * @file nana/detail/platform_spec.hpp * * The platform_abstraction provides some functions and types for the abstract * system platform. */ + #ifndef NANA_DETAIL_PLATFORM_ABSTRACTION_HEADER_INCLUDED #define NANA_DETAIL_PLATFORM_ABSTRACTION_HEADER_INCLUDED -#include "platform_abstraction_types.hpp" #include #include + +#include "platform_abstraction_types.hpp" #include #include @@ -46,9 +48,6 @@ namespace nana implementation* const impl_; }; public: - using font = font_interface; - using font_info = paint::font_info; - using path_type = ::std::filesystem::path; static void initialize(); @@ -57,30 +56,58 @@ namespace nana static revertible_mutex& internal_mutex(); + using font = font_interface; + using font_info = paint::font_info; static double font_default_pt(); - static void font_languages(const std::string&); - static ::std::shared_ptr default_font(const ::std::shared_ptr&); - - /// \todo: generalize dpi to v2 awareness + static void font_languages(const std::string& langs); + static ::std::shared_ptr default_font(const ::std::shared_ptr& new_font); + /// if ttf is specified, it ignores the font family name in font_info and creates the font using the TrueType File. + static std::shared_ptr open_font(const font_info&, int dpi, const path_type& ttf); + static void font_resource(bool try_add, const path_type& ttf); /// 'manuallay' set the current system DPI, this is used for DPI scaling. - static void set_current_dpi(std::size_t dpi); - static std::size_t current_dpi(); + static void set_current_dpi(int dpi); + static int current_dpi(); + static int screen_dpi(bool x_requested = true); ///< ask the system for the DPI of the main screen - static int dpi_scale(int scalar); - static nana::size dpi_scale(nana::size size); - static nana::point dpi_scale(nana::point point); + static int dpi_scale(int scalar); + static nana::size dpi_scale(const nana::size& size); + static nana::point dpi_scale(const nana::point& point); - static int dpi_scale(window wd, int scalar); + static int dpi_scale(window wd, int scalar); static unsigned int dpi_scale(window wd, unsigned int scalar); - static nana::size dpi_scale(window wd, nana::size size); - static nana::point dpi_scale(window wd, nana::point point); + static nana::size dpi_scale(window wd, nana::size size); + static nana::point dpi_scale(window wd, nana::point point); - /// Open the font, if ttf is specified, it ignores the font family name of font_info and creates the font using truetype file. - static std::shared_ptr open_font(const font_info&, std::size_t dpi, const path_type& ttf); - static void font_resource(bool try_add, const path_type& ttf); + /// dpi scaling for int + static int dpi_scale (const int scalar, int dpi); + static int dpi_transform (int& scalar, int dpi); + static int unscale_dpi (const int scalar, int dpi); + static int untransform_dpi(int& scalar, int dpi); + + /// dpi scaling for unsigned int + static unsigned int dpi_scale (const unsigned int scalar, int dpi); + static unsigned int dpi_transform (unsigned int& scalar, int dpi); + static unsigned int unscale_dpi (const unsigned int scalar, int dpi); + static unsigned int untransform_dpi(unsigned int& scalar, int dpi); + + /// dpi scaling for nana::size + static nana::size dpi_scale (const nana::size& size, int dpi); + static nana::size dpi_transform (nana::size& size, int dpi); + static nana::size unscale_dpi (const nana::size& size, int dpi); + static nana::size untransform_dpi(nana::size& size, int dpi); + + /// dpi scaling for nana::point + static nana::point dpi_scale (const nana::point& point, int dpi); + static nana::point dpi_transform (nana::point& point, int dpi); + static nana::point unscale_dpi (const nana::point& point, int dpi); + static nana::point untransform_dpi(nana::point& point, int dpi); - static unsigned screen_dpi(bool x_requested); + /// dpi scaling for nana::rectangle + static nana::rectangle dpi_scale (const nana::rectangle& rect, int dpi); + static nana::rectangle dpi_transform (nana::rectangle& rect, int dpi); + static nana::rectangle unscale_dpi (const nana::rectangle& rect, int dpi); + static nana::rectangle untransform_dpi(nana::rectangle& rect, int dpi); }; } diff --git a/source/detail/platform_abstraction_types.hpp b/source/detail/platform_abstraction_types.hpp index 0f45c3249..4f2f2c9d4 100644 --- a/source/detail/platform_abstraction_types.hpp +++ b/source/detail/platform_abstraction_types.hpp @@ -1,10 +1,24 @@ +/** +* A Bedrock Platform-Independent Implementation +* Nana C++ Library + * Documentation https://nana.acemind.cn/documentation + * Sources: https://github.com/cnjinhao/nana +* Copyright(C) 2003-2024 Jinhao(cnjinhao@hotmail.com) +* +* Distributed under the Boost Software License, Version 1.0. +* (See accompanying file LICENSE_1_0.txt or copy at +* http://www.boost.org/LICENSE_1_0.txt) +* +* @file nana\source\detail\platform_abstraction_types.hpp +* @contributors Jinhao +*/ + #ifndef NANA_DETAIL_PLATFORM_ABSTRACTION_TYPES_HEADER_INCLUDED #define NANA_DETAIL_PLATFORM_ABSTRACTION_TYPES_HEADER_INCLUDED + #include #include -#include - #ifdef NANA_X11 # define NANA_USE_XFT #endif @@ -14,7 +28,7 @@ namespace nana class font_interface { public: - using font_style = detail::font_style; + using font_style = detail::font_style; using native_font_type = paint::native_font_type; virtual ~font_interface() = default; diff --git a/source/gui/detail/basic_window.cpp b/source/gui/detail/basic_window.cpp index 92f9be619..d88f2a0ca 100644 --- a/source/gui/detail/basic_window.cpp +++ b/source/gui/detail/basic_window.cpp @@ -1,4 +1,4 @@ -/* +/** * A Basic Window Widget Definition * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2022 Jinhao(cnjinhao@hotmail.com) @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * -* @file: nana/gui/detail/basic_window.cpp +* @file nana/gui/detail/basic_window.cpp */ #include "basic_window.hpp" @@ -39,7 +39,7 @@ namespace nana native_interface::caret_create(owner_->root, size_); visibility_ = visible_state::invisible; - this->position(position_); + this->position(position_); /// \todo: position_ = position_; ? just call update() } else native_interface::caret_destroy(owner_->root); @@ -214,8 +214,11 @@ namespace nana //struct basic_window //struct basic_window::other_tag - basic_window::other_tag::other_tag(category::flags categ) - : category(categ), active_window(nullptr), upd_state(update_state::none) + basic_window::other_tag::other_tag(category::flags categ, int dpi) + : category (categ), + active_window(nullptr), + glass_buffer (dpi), + upd_state (update_state::none) { if (category::flags::root == categ) attribute.root = new attr_root_tag; @@ -230,11 +233,18 @@ namespace nana } //end struct basic_window::other_tag - //basic_window - //@brief: constructor for the root window - basic_window::basic_window(basic_window* owner, std::unique_ptr&& wdg_notifier, category::root_tag**) - : widget_notifier(std::move(wdg_notifier)), other(category::flags::root) + + /// constructor for the root window + basic_window::basic_window(basic_window* owner, + std::unique_ptr&& wdg_notifier, + category::root_tag**, + int dpi) + : dpi (dpi), + drawer (dpi), + widget_notifier(std::move(wdg_notifier)), + other (category::flags::root, dpi) { + if (owner) dpi = owner->dpi; ///\todo: set dpi anyway? in all graphics? drawer.bind(this); _m_init_pos_and_size(nullptr, rectangle()); this->_m_initialize(owner); @@ -259,6 +269,7 @@ namespace nana if(category::flags::root == this->other.category) { this->root = wd; + this->dpi = native_interface::window_dpi(wd); ///< \todo: cache the dpi?? dimension.width = width; dimension.height = height; this->extra_width = extra_width; @@ -404,6 +415,7 @@ namespace nana owner = nullptr; root_widget = wd->root_widget; root = wd->root; + dpi = wd->dpi; root_graph = wd->root_graph; index = static_cast(wd->children.size()); wd->children.emplace_back(this); diff --git a/source/gui/detail/basic_window.hpp b/source/gui/detail/basic_window.hpp index b1bcc3e70..c762a7818 100644 --- a/source/gui/detail/basic_window.hpp +++ b/source/gui/detail/basic_window.hpp @@ -13,6 +13,7 @@ #ifndef NANA_GUI_DETAIL_BASIC_WINDOW_HPP #define NANA_GUI_DETAIL_BASIC_WINDOW_HPP + #include #include #include @@ -22,6 +23,7 @@ #include #include #include +#include namespace nana::widgets::skeletons { @@ -101,11 +103,23 @@ namespace nana::detail }; /// constructor for the root window - basic_window(basic_window* owner, std::unique_ptr&&, category::root_tag**); + basic_window(basic_window* owner, + std::unique_ptr&&, + category::root_tag**, + int dpi ///< the dpi or scaling is needed to intitialize any bitmap graphics + ); template - basic_window(basic_window* parent, std::unique_ptr&& wdg_notifier, const rectangle& r, Category**) - : widget_notifier(std::move(wdg_notifier)), other(Category::value) + basic_window(basic_window* parent, + std::unique_ptr&& wdg_notifier, + const rectangle& r, + Category**, + int dpi ///< the dpi or scaling is needed to intitialize any bitmap graphics + ) + : dpi (dpi), + drawer(dpi), + widget_notifier(std::move(wdg_notifier)), + other(Category::value, dpi) { drawer.bind(this); if(parent) @@ -142,12 +156,13 @@ namespace nana::detail void _m_init_pos_and_size(basic_window* parent, const rectangle&); void _m_initialize(basic_window* parent); public: + int dpi{ 96 }; ///< \todo: DPI of the window, cached value of the root, root_widget's and root_graph. #if defined(NANA_POSIX) point pos_native; #endif - point pos_root; ///< coordinates of the root window - point pos_owner; - size dimension; + point pos_root; ///< coordinates of the root window \todo: dpi? user or system-side ? + point pos_owner; ///< coordinates of the owner window \todo: dpi? user or system-side ? + size dimension; ///< size of thes window \todo: dpi? user or system-side ? ::nana::size min_track_size; ::nana::size max_track_size; @@ -189,7 +204,6 @@ namespace nana::detail mouse_action action_before; }flags; - struct annex_components { caret* caret_ptr{ nullptr }; @@ -239,7 +253,7 @@ namespace nana::detail attr_root_tag * root; }attribute; - other_tag(category::flags); + other_tag(category::flags, int dpi); ~other_tag(); }other; diff --git a/source/gui/detail/bedrock_pi.cpp b/source/gui/detail/bedrock_pi.cpp index 138efdc31..3e6028c2e 100644 --- a/source/gui/detail/bedrock_pi.cpp +++ b/source/gui/detail/bedrock_pi.cpp @@ -1,4 +1,4 @@ -/* +/** * A Bedrock Platform-Independent Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2023 Jinhao(cnjinhao@hotmail.com) @@ -7,9 +7,13 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * -* @file: nana/gui/detail/bedrock_pi.cpp +* @file nana/gui/detail/bedrock_pi.cpp +* @contributors Jinhao, Ariel Vina-Rodriguez */ +#include +#include + #include "../../detail/platform_spec_selector.hpp" #include "basic_window.hpp" #include "bedrock_types.hpp" @@ -22,9 +26,6 @@ #include #include -#include -#include - namespace nana { //class event_arg @@ -245,15 +246,12 @@ namespace nana if (wd_manager().available(wd)) { auto * thrd = get_thread_context(wd->thread_id); - if (nullptr == thrd) - return; + if (nullptr == thrd) return; - auto pos = native_interface::cursor_position(); - auto native_handle = native_interface::find_window(pos.x, pos.y); - if (!native_handle) - return; + nana::point pos; + auto native_handle = native_interface::find_cursor_window(pos); + if (!native_handle) return; - native_interface::calc_window_point(native_handle, pos); if (wd != wd_manager().find_window(native_handle, pos)) return; diff --git a/source/gui/detail/bedrock_posix.cpp b/source/gui/detail/bedrock_posix.cpp index 3b1f62d6d..fc2bfe1bf 100644 --- a/source/gui/detail/bedrock_posix.cpp +++ b/source/gui/detail/bedrock_posix.cpp @@ -613,9 +613,8 @@ namespace detail { if(native_interface::is_window(msgwnd->root)) { - nana::point pos = native_interface::cursor_position(); - auto recv = native_interface::find_window(pos.x, pos.y); - + nana::point pos; + auto recv = native_interface::find_cursor_window(pos); brock.event_focus_changed(msgwnd, recv, false); } } @@ -686,10 +685,7 @@ namespace detail //If a root window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event. if (msgwnd->root != native_interface::get_focus_window()) { - auto pos = native_interface::cursor_position(); - auto rootwd = native_interface::find_window(pos.x, pos.y); - native_interface::calc_window_point(rootwd, pos); - if(msgwnd != wd_manager.find_window(rootwd, pos)) + if(msgwnd != api::find_window_cursor()) { //call the drawer mouse up event for restoring the surface graphics msgwnd->set_action(mouse_action::normal); @@ -1327,13 +1323,7 @@ namespace detail wd->root_widget->other.attribute.root->state_cursor = nana::cursor::arrow; wd->root_widget->other.attribute.root->state_cursor_window = nullptr; - auto pos = native_interface::cursor_position(); - auto native_handle = native_interface::find_window(pos.x, pos.y); - if (!native_handle) - return; - - native_interface::calc_window_point(native_handle, pos); - auto rev_wd = wd_manager().find_window(native_handle, pos); + auto rev_wd = api::find_window_cursor(); if (rev_wd) set_cursor(rev_wd, rev_wd->predef_cursor, thrd); } diff --git a/source/gui/detail/bedrock_windows.cpp b/source/gui/detail/bedrock_windows.cpp index 1a329bf30..489330482 100644 --- a/source/gui/detail/bedrock_windows.cpp +++ b/source/gui/detail/bedrock_windows.cpp @@ -16,6 +16,7 @@ #include "../../detail/platform_spec_selector.hpp" #if defined(NANA_WINDOWS) +//#include #include //use std::cerr @@ -55,6 +56,45 @@ namespace nana namespace detail { + ///\todo: here temp, to avoid including windef.h in native_window_interface.hpp + ::RECT scale_to_dpi_(const ::RECT& r, int dpi) + { + ::RECT scaled_r {.left = MulDiv(r.left, dpi, 96), + .top = MulDiv(r.top, dpi, 96), + .right = MulDiv(r.right, dpi, 96), + .bottom= MulDiv(r.bottom, dpi, 96) } ; + + if constexpr (dpi_debugging) + { + std::cout << " orig rect= " << r.left << ", " << r.top << + " with size= " << r.right - r.left << ", " << r.bottom - r.top << '\n'; + std::cout << " scaled rect= " << scaled_r.left << ", " << scaled_r.top << + " with size= " << scaled_r.right - scaled_r.left << ", " << scaled_r.bottom - scaled_r.top << '\n'; + } + return scaled_r; + } + ::RECT scale_to_dpi_(native_window_type wd, const ::RECT& r) + { + int dpi = static_cast(native_interface::window_dpi(wd)); + return scale_to_dpi_(r, dpi); + } + + ::RECT unscale_dpi_(const ::RECT& r, int dpi) + { + ::RECT scaled_r {.left = MulDiv(r.left, 96, dpi), + .top = MulDiv(r.top, 96, dpi), + .right = MulDiv(r.right, 96, dpi), + .bottom= MulDiv(r.bottom, 96, dpi) } ; + + if constexpr (dpi_debugging) + { + std::cout << " unscaled rect= " << scaled_r.left << ", " << scaled_r.top << + " with size= " << scaled_r.right - scaled_r.left << ", " << scaled_r.bottom - scaled_r.top << '\n'; + } + return scaled_r; + } + + namespace restrict { typedef struct tagTRACKMOUSEEVENT{ @@ -174,8 +214,7 @@ namespace detail std::map> accel_commands; }; - //class bedrock defines a static object itself to implement a static singleton - //here is the definition of this object + /// class bedrock defines a static object itself to implement a static singleton, here is the definition of this object bedrock bedrock::bedrock_object; static LRESULT WINAPI Bedrock_WIN32_WindowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); @@ -192,22 +231,22 @@ namespace detail : pi_data_(new pi_data), impl_(new private_impl) { - detail::native_interface::start_dpi_awareness(config_dpi_aware); + native_interface::start_dpi_awareness(config_dpi_aware); nana::detail::platform_spec::instance(); //to guaranty the platform_spec object is initialized before using. WNDCLASSEX wincl; - wincl.hInstance = windows_module_handle(); + wincl.hInstance = windows_module_handle(); wincl.lpszClassName = L"NanaWindowInternal"; - wincl.lpfnWndProc = &Bedrock_WIN32_WindowProc; - wincl.style = CS_DBLCLKS | CS_OWNDC; - wincl.cbSize = sizeof(wincl); - wincl.hIcon = ::LoadIcon (0, IDI_APPLICATION); - wincl.hIconSm = wincl.hIcon; - wincl.hCursor = ::LoadCursor (0, IDC_ARROW); - wincl.lpszMenuName = 0; - wincl.cbClsExtra = 0; - wincl.cbWndExtra = 0; + wincl.lpfnWndProc = &Bedrock_WIN32_WindowProc; + wincl.style = CS_DBLCLKS | CS_OWNDC; + wincl.cbSize = sizeof(wincl); + wincl.hIcon = ::LoadIcon (0, IDI_APPLICATION); + wincl.hIconSm = wincl.hIcon; + wincl.hCursor = ::LoadCursor (0, IDC_ARROW); + wincl.lpszMenuName = 0; + wincl.cbClsExtra = 0; + wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH)(COLOR_BTNFACE + 1); ::RegisterClassEx(&wincl); @@ -234,7 +273,6 @@ namespace detail restrict::imm_get_composition_string = reinterpret_cast( ::GetProcAddress(imm32, "ImmGetCompositionStringW")); - /// \todo: generalize dpi to v2 awareness platform_abstraction::set_current_dpi(detail::native_interface::system_dpi()); } @@ -320,11 +358,13 @@ namespace detail return bedrock_object; } + /// uses *update_area for direct call to PostMessage: \todo: dpi_scale ?? Use US void bedrock::flush_surface(basic_window* wd, bool forced, const rectangle* update_area) { if (nana::system::this_thread_id() != wd->thread_id) { - auto stru = reinterpret_cast(::HeapAlloc(::GetProcessHeap(), 0, sizeof(detail::messages::map_thread))); + auto stru = reinterpret_cast( + ::HeapAlloc(::GetProcessHeap(), 0, sizeof(detail::messages::map_thread))); if (stru) { stru->forced = forced; @@ -333,10 +373,14 @@ namespace detail if (update_area) { stru->ignore_update_area = false; - stru->update_area = *update_area; + stru->update_area = *update_area; ///\todo: dpi_scale ?? no: obtained directly from lParam to be PostMessage (system-side) } - if (FALSE == ::PostMessage(reinterpret_cast(wd->root), nana::detail::messages::remote_flush_surface, reinterpret_cast(wd), reinterpret_cast(stru))) + if (FALSE == ::PostMessage(reinterpret_cast(wd->root), + nana::detail::messages::remote_flush_surface, + reinterpret_cast(wd), + reinterpret_cast(stru)) // pointer to a nana defined and controled structure: US not SS !! \todo: no dpi scale ! + ) ::HeapFree(::GetProcessHeap(), 0, stru); } } @@ -541,8 +585,11 @@ namespace detail if (set_key_state) { - arg.pos.x = pmdec.mouse.x - wd->pos_root.x; - arg.pos.y = pmdec.mouse.y - wd->pos_root.y; + arg.pos.x = static_cast(pmdec.mouse.x); /// \todo: is system-side dpi to user-side ok here? + arg.pos.y = static_cast(pmdec.mouse.y); + platform_abstraction::untransform_dpi(arg.pos, wd->dpi); + arg.pos -= wd->pos_root; + arg.alt = (::GetKeyState(VK_MENU) < 0); arg.shift = pmdec.mouse.button.shift; arg.ctrl = pmdec.mouse.button.ctrl; @@ -563,8 +610,11 @@ namespace detail arg.upwards = (pmdec.mouse.button.wheel_delta >= 0); arg.distance = static_cast(arg.upwards ? pmdec.mouse.button.wheel_delta : -pmdec.mouse.button.wheel_delta); - arg.pos.x = static_cast(point.x) - wd->pos_root.x; - arg.pos.y = static_cast(point.y) - wd->pos_root.y; + arg.pos.x = static_cast(point.x); /// \todo: is system-side dpi to user-side ok here? + arg.pos.y = static_cast(point.y); + platform_abstraction::untransform_dpi(arg.pos, wd->dpi); + arg.pos -= wd->pos_root; + arg.left_button = pmdec.mouse.button.left; arg.mid_button = pmdec.mouse.button.middle; arg.right_button = pmdec.mouse.button.right; @@ -572,24 +622,25 @@ namespace detail arg.shift = pmdec.mouse.button.shift; } - //trivial_message - // The Windows messaging always sends a message to the window thread queue when the calling is in other thread. - //If messages can be finished without expecting Nana's window manager, the trivail_message function would - //handle those messages. This is a method to avoid a deadlock, that calling waits for the handling and they require - //Nana's window manager. + + /// The Windows messaging always sends a message to the window thread queue when the calling is in other thread. + /// + /// If messages can be finished without expecting Nana's window manager, the trivail_message function would + /// handle those messages. This is a method to avoid a deadlock, that calling waits for the handling and they require + /// Nana's window manager. bool trivial_message(HWND wd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT & ret) { bedrock & bedrock = bedrock::instance(); switch(msg) { - case nana::detail::messages::async_activate: - ::EnableWindow(wd, true); + case nana::detail::messages::async_activate: //wParam = 0, lParam = window . Not send back to Windows DefWindowProc + ::EnableWindow(wd, true); ::SetActiveWindow(wd); return true; - case nana::detail::messages::async_set_focus: + case nana::detail::messages::async_set_focus: //wParam = 0, lParam = window . Not send back to Windows DefWindowProc ::SetFocus(wd); return true; - case nana::detail::messages::operate_caret: + case nana::detail::messages::operate_caret: //Refer to basis.hpp for this specification. switch(wParam) { @@ -597,14 +648,16 @@ namespace detail ::DestroyCaret(); break; case 2: //SetPos - ::SetCaretPos(reinterpret_cast(lParam)->x, reinterpret_cast(lParam)->y); + ::SetCaretPos(reinterpret_cast(lParam)->x, + reinterpret_cast(lParam)->y); + /// \todo: system-side dpi ok? direct use of lParam set in native_interface::caret_pos? delete reinterpret_cast(lParam); break; } return true; - case nana::detail::messages::remote_flush_surface: + case nana::detail::messages::remote_flush_surface: // wParam = window, lParam = detail::messages::map_thread. Not send back to Windows DefWindowProc { - auto stru = reinterpret_cast(lParam); + auto stru = reinterpret_cast(lParam); //lParam \todo: User-side dpi bedrock.wd_manager().map(reinterpret_cast(wParam), stru->forced, (stru->ignore_update_area ? nullptr : &stru->update_area)); ::UpdateWindow(wd); ::HeapFree(::GetProcessHeap(), 0, stru); @@ -671,6 +724,7 @@ namespace detail case WM_MOUSELEAVE: case WM_MOUSEWHEEL: //The WM_MOUSELAST may not include the WM_MOUSEWHEEL/WM_MOUSEHWHEEL when the version of SDK is low. case WM_MOUSEHWHEEL: + // The messages above are not trivial messages - not send back to Windows DefWindowProc return false; default: if((WM_MOUSEFIRST <= msg && msg <= WM_MOUSELAST) || (WM_KEYFIRST <= msg && msg <= WM_KEYLAST)) @@ -683,18 +737,16 @@ namespace detail void adjust_sizing(basic_window* wd, ::RECT * const r, int edge, unsigned req_width, unsigned req_height) { - unsigned width = static_cast(r->right - r->left) - wd->extra_width; - unsigned height = static_cast(r->bottom - r->top) - wd->extra_height; + ///\todo: all here user-side dpi ?? r from *r = unscale_dpi_(*r, msgwnd->dpi); in Bedrock_WIN32_WindowProc ///\todo: to user-side dpi ok?) - if(wd->max_track_size.width && (wd->max_track_size.width < req_width)) - req_width = wd->max_track_size.width; - else if(wd->min_track_size.width && (wd->min_track_size.width > req_width)) - req_width = wd->min_track_size.width; + unsigned width = static_cast(r->right - r->left) - wd->extra_width; + unsigned height = static_cast(r->bottom - r->top ) - wd->extra_height; - if(wd->max_track_size.height && (wd->max_track_size.height < req_height)) - req_height = wd->max_track_size.height; - else if(wd->min_track_size.height && (wd->min_track_size.height > req_height)) - req_height = wd->min_track_size.height; + if (wd->max_track_size.width && (wd->max_track_size.width < req_width )) req_width = wd->max_track_size.width; + if (wd->min_track_size.width && (wd->min_track_size.width > req_width )) req_width = wd->min_track_size.width; + + if (wd->max_track_size.height && (wd->max_track_size.height < req_height)) req_height = wd->max_track_size.height; + if (wd->min_track_size.height && (wd->min_track_size.height > req_height)) req_height = wd->min_track_size.height; if(req_width != width) { @@ -702,16 +754,12 @@ namespace detail { case WMSZ_LEFT: case WMSZ_BOTTOMLEFT: - case WMSZ_TOPLEFT: - r->left = r->right - static_cast(req_width) - wd->extra_width; - break; + case WMSZ_TOPLEFT: r->left = r->right - static_cast(req_width) - wd->extra_width; break; case WMSZ_RIGHT: case WMSZ_BOTTOMRIGHT: case WMSZ_TOPRIGHT: case WMSZ_TOP: - case WMSZ_BOTTOM: - r->right = r->left + static_cast(req_width) + wd->extra_width; - break; + case WMSZ_BOTTOM: r->right = r->left + static_cast(req_width) + wd->extra_width; break; } } @@ -721,16 +769,12 @@ namespace detail { case WMSZ_TOP: case WMSZ_TOPLEFT: - case WMSZ_TOPRIGHT: - r->top = r->bottom - static_cast(req_height) - wd->extra_height; - break; + case WMSZ_TOPRIGHT: r->top = r->bottom - static_cast(req_height) - wd->extra_height; break; case WMSZ_BOTTOM: case WMSZ_BOTTOMLEFT: case WMSZ_BOTTOMRIGHT: case WMSZ_LEFT: - case WMSZ_RIGHT: - r->bottom = r->top + static_cast(req_height) + wd->extra_height; - break; + case WMSZ_RIGHT: r->bottom = r->top + static_cast(req_height) + wd->extra_height; break; } } } @@ -802,6 +846,7 @@ namespace detail auto msgwnd = root_wd; detail::bedrock::root_guard rw_guard{ brock, root_wd }; + ::nana::point pos; switch (message) { @@ -814,13 +859,20 @@ namespace detail } break; case WM_DPICHANGED: /// \todo: generalize dpi to v2 awareness - wd_manager.update_dpi(msgwnd); - { - + { auto r = reinterpret_cast(lParam); - auto dpi_x = HIWORD(wParam); + auto dpi_x = HIWORD(wParam); /// \todo: always equals? we take it from native_interface::windows_dpi auto dpi_y = LOWORD(wParam); - + + if constexpr (dpi_debugging) + { + std::cout << "WM_DPICHANGED: dpi_x = " << dpi_x << ", dpi_y = " << dpi_y << '\n' + << "window_dpi= " << api::window_dpi(msgwnd); + std::cout << "SetWindowPos: " << r->left << ", r->top = " << r->top << + ", size = " << r->right - r->left << ", " << r->bottom - r->top << '\n'; + } + platform_abstraction::set_current_dpi(detail::native_interface::system_dpi()); + wd_manager.update_dpi(msgwnd); /// \todo: pass dpi = dpi_x to update_dpi ?? ::SetWindowPos(root_window, NULL, r->left, @@ -828,7 +880,9 @@ namespace detail r->right - r->left, r->bottom - r->top, SWP_NOZORDER | SWP_NOACTIVATE); - } + + wd_manager.refresh_tree(msgwnd); + } break; case WM_IME_STARTCOMPOSITION: break; @@ -892,15 +946,16 @@ namespace detail wd_manager.do_lazy_refresh(msgwnd, false); } break; - case WM_GETMINMAXINFO: + case WM_GETMINMAXINFO: ///\todo: reset MINMAXINFO pointed by lParam to the new values, system-side dpi ok? { bool take_over = false; - auto mmi = reinterpret_cast(lParam); + auto mmi = reinterpret_cast(lParam); ///\todo : system-side dpi ok? if (!msgwnd->min_track_size.empty()) { - mmi->ptMinTrackSize.x = static_cast(msgwnd->min_track_size.width + msgwnd->extra_width); - mmi->ptMinTrackSize.y = static_cast(msgwnd->min_track_size.height + msgwnd->extra_height); + ///\todo : user-side dpi to system-side ok? + mmi->ptMinTrackSize.x = static_cast(platform_abstraction::dpi_scale(msgwnd->min_track_size.width + msgwnd->extra_width , msgwnd->dpi)); + mmi->ptMinTrackSize.y = static_cast(platform_abstraction::dpi_scale(msgwnd->min_track_size.height + msgwnd->extra_height, msgwnd->dpi)); take_over = true; } @@ -908,12 +963,11 @@ namespace detail { if (msgwnd->max_track_size.width && msgwnd->max_track_size.height) { - mmi->ptMaxTrackSize.x = static_cast(msgwnd->max_track_size.width + msgwnd->extra_width); - mmi->ptMaxTrackSize.y = static_cast(msgwnd->max_track_size.height + msgwnd->extra_height); - if (mmi->ptMaxSize.x > mmi->ptMaxTrackSize.x) - mmi->ptMaxSize.x = mmi->ptMaxTrackSize.x; - if (mmi->ptMaxSize.y > mmi->ptMaxTrackSize.y) - mmi->ptMaxSize.y = mmi->ptMaxTrackSize.y; + mmi->ptMaxTrackSize.x = static_cast(platform_abstraction::dpi_scale(msgwnd->max_track_size.width + msgwnd->extra_width , msgwnd->dpi)); + mmi->ptMaxTrackSize.y = static_cast(platform_abstraction::dpi_scale(msgwnd->max_track_size.height + msgwnd->extra_height, msgwnd->dpi)); + + if (mmi->ptMaxSize.x > mmi->ptMaxTrackSize.x) mmi->ptMaxSize.x = mmi->ptMaxTrackSize.x; + if (mmi->ptMaxSize.y > mmi->ptMaxTrackSize.y) mmi->ptMaxSize.y = mmi->ptMaxTrackSize.y; take_over = true; } @@ -958,7 +1012,10 @@ namespace detail break; pressed_wd = nullptr; - msgwnd = wd_manager.find_window(native_window, { pmdec.mouse.x, pmdec.mouse.y }); + pos = point{ pmdec.mouse.x, pmdec.mouse.y }; /// client mouse position in native_window \todo: keep dpi in wd?? + platform_abstraction::untransform_dpi(pos, native_interface::window_dpi(native_window)); ///\todo: use root_wd->dpi here? + msgwnd = wd_manager.find_window(native_window, pos); + if (msgwnd && msgwnd->flags.enabled) { if (msgwnd->flags.take_active && !msgwnd->flags.ignore_mouse_focus) @@ -982,8 +1039,9 @@ namespace detail //Ignore mouse events when a window has been pressed by pressing spacebar if (pressed_wd_space) break; - - msgwnd = wd_manager.find_window(native_window, { pmdec.mouse.x, pmdec.mouse.y }); + pos = point{ pmdec.mouse.x, pmdec.mouse.y }; /// client mouse position in native_window \todo: keep dpi in wd?? + platform_abstraction::untransform_dpi(pos, native_interface::window_dpi(native_window)); ///\todo: use root_wd->dpi here? + msgwnd = wd_manager.find_window(native_window, pos); //Don't take care about whether msgwnd is equal to the pressed_wd. // @@ -1024,9 +1082,8 @@ namespace detail //If a root_window is created during the mouse_down event, Nana.GUI will ignore the mouse_up event. if (msgwnd->root != native_interface::get_focus_window()) { - auto pos = native_interface::cursor_position(); - auto rootwd = native_interface::find_window(pos.x, pos.y); - native_interface::calc_window_point(rootwd, pos); + nana::point pos; + auto rootwd = native_interface::find_cursor_window(pos); if (msgwnd != wd_manager.find_window(rootwd, pos)) { //call the drawer mouse up event for restoring the surface graphics @@ -1045,12 +1102,13 @@ namespace detail //mouse_click, mouse_up case WM_LBUTTONUP: case WM_MBUTTONUP: - case WM_RBUTTONUP: + case WM_RBUTTONUP: //Ignore mouse events when a window has been pressed by pressing spacebar if (pressed_wd_space) break; - - msgwnd = wd_manager.find_window(native_window, { pmdec.mouse.x, pmdec.mouse.y }); + pos = point{ pmdec.mouse.x, pmdec.mouse.y }; /// client mouse position in native_window \todo: keep dpi in wd?? + platform_abstraction::untransform_dpi(pos, native_interface::window_dpi(native_window));///\todo: use root_wd->dpi here? + msgwnd = wd_manager.find_window(native_window, pos); if (nullptr == msgwnd) break; @@ -1104,8 +1162,10 @@ namespace detail //Ignore mouse events when a window has been pressed by pressing spacebar if (pressed_wd_space) break; - - msgwnd = wd_manager.find_window(native_window, {pmdec.mouse.x, pmdec.mouse.y}); + pos = point{ pmdec.mouse.x, pmdec.mouse.y }; /// client mouse position in native_window \todo: keep dpi in wd?? + platform_abstraction::untransform_dpi(pos, native_interface::window_dpi(native_window));///\todo: use root_wd->dpi here? + msgwnd = wd_manager.find_window(native_window, pos); + //msgwnd = wd_manager.find_window(native_window, {pmdec.mouse.x, pmdec.mouse.y}); if (wd_manager.available(hovered_wd) && (msgwnd != hovered_wd)) { brock.event_msleave(hovered_wd); @@ -1122,7 +1182,7 @@ namespace detail else if(msgwnd) { bool prev_captured_inside; - if(wd_manager.capture_window_entered(pmdec.mouse.x, pmdec.mouse.y, prev_captured_inside)) + if(wd_manager.capture_window_entered(pos.x, pos.y, prev_captured_inside)) { event_code evt_code; if(prev_captured_inside) @@ -1276,9 +1336,10 @@ namespace detail break; case WM_SIZING: { - ::RECT* const r = reinterpret_cast(lParam); - unsigned width = static_cast(r->right - r->left) - msgwnd->extra_width; - unsigned height = static_cast(r->bottom - r->top) - msgwnd->extra_height; + ::RECT* r = reinterpret_cast(lParam); ///\todo: system-side dpi ok? + *r = unscale_dpi_(*r, msgwnd->dpi); ///\todo: to user-side dpi ok?) + unsigned width = static_cast(r->right - r->left) - msgwnd->extra_width; + unsigned height = static_cast(r->bottom - r->top ) - msgwnd->extra_height; if(msgwnd->max_track_size.width || msgwnd->min_track_size.width) { @@ -1286,6 +1347,7 @@ namespace detail { if(msgwnd->max_track_size.width && (width > msgwnd->max_track_size.width)) r->left = r->right - static_cast(msgwnd->max_track_size.width) - msgwnd->extra_width; + if(msgwnd->min_track_size.width && (width < msgwnd->min_track_size.width)) r->left = r->right - static_cast(msgwnd->min_track_size.width) - msgwnd->extra_width; } @@ -1349,8 +1411,10 @@ namespace detail if (arg.width != width || arg.height != height) { adjust_sizing(msgwnd, r, static_cast(wParam), arg.width, arg.height); + *r = scale_to_dpi_(*r, msgwnd->dpi); ///\todo: back to system-side dpi ok? return TRUE; } + *r = scale_to_dpi_(*r, msgwnd->dpi); ///\todo: back to system-side dpi ok? } break; case WM_SIZE: @@ -1358,7 +1422,11 @@ namespace detail wd_manager.size(msgwnd, size(pmdec.size.width, pmdec.size.height), true, true); break; case WM_MOVE: - brock.event_move(msgwnd, (int)(short) LOWORD(lParam), (int)(short) HIWORD(lParam)); + { + point p ( (int)(short) LOWORD(lParam), + (int)(short) HIWORD(lParam)); + brock.event_move(msgwnd, p.x, p.y); + } break; case WM_PAINT: { @@ -1728,7 +1796,7 @@ namespace detail void bedrock::map_through_widgets(basic_window* wd, native_drawable_type drawable) { - auto graph_context = reinterpret_cast(wd->root_graph->handle()->context); + auto graph_context = reinterpret_cast(wd->root_graph->handle()->context); // destination HDC for (auto child : wd->children) { @@ -1736,8 +1804,11 @@ namespace detail if (::nana::category::flags::widget == child->other.category) { - ::BitBlt(reinterpret_cast(drawable), child->pos_root.x, child->pos_root.y, static_cast(child->dimension.width), static_cast(child->dimension.height), - graph_context, child->pos_root.x, child->pos_root.y, SRCCOPY); + ///\todo: dpi scale + auto pos_root = platform_abstraction::dpi_scale(child->pos_root, wd->dpi); + auto dimension = platform_abstraction::dpi_scale(child->dimension, wd->dpi); + ::BitBlt(reinterpret_cast(drawable), pos_root.x, pos_root.y, static_cast(dimension.width), static_cast(dimension.height), + graph_context, pos_root.x, pos_root.y, SRCCOPY); } else if (::nana::category::flags::lite_widget == child->other.category) map_through_widgets(child, drawable); @@ -1844,8 +1915,8 @@ namespace detail wd->root_widget->other.attribute.root->state_cursor = nana::cursor::arrow; wd->root_widget->other.attribute.root->state_cursor_window = nullptr; - auto pos = native_interface::cursor_position(); - auto native_handle = native_interface::find_window(pos.x, pos.y); + nana::point pos; + auto native_handle = native_interface::find_cursor_window(pos); if (!native_handle) { @@ -1854,7 +1925,6 @@ namespace detail return; } - native_interface::calc_window_point(native_handle, pos); auto rev_wd = wd_manager().find_window(native_handle, pos); if (rev_wd) { diff --git a/source/gui/detail/drawer.cpp b/source/gui/detail/drawer.cpp index 799291f2b..ae6442e7c 100644 --- a/source/gui/detail/drawer.cpp +++ b/source/gui/detail/drawer.cpp @@ -15,6 +15,7 @@ #include #include #include +#include "../../detail/platform_abstraction.hpp" #if defined(NANA_X11) #include "../../detail/posix/platform_spec.hpp" @@ -235,8 +236,9 @@ namespace nana #endif }; - drawer::drawer() - : data_impl_{ new data_implement } + drawer::drawer(int dpi) + : graphics{ dpi }, + data_impl_{ new data_implement } {} drawer::~drawer() @@ -252,6 +254,7 @@ namespace nana void drawer::bind(basic_window* cw) { data_impl_->window_handle = cw; + graphics.set_dpi(cw->dpi); } void drawer::typeface_changed() @@ -636,7 +639,7 @@ namespace nana { wd->flags.action_before = wd->flags.action; - auto r = visual; + auto r = visual; /// \todo: dpi scale to SS r.pare_off(-static_cast(weight())); rectangle good_r; if (overlap(r, rectangle{ wd->root_graph->size() }, good_r)) @@ -645,6 +648,11 @@ namespace nana (good_r.right() > visual.right()) || (good_r.bottom() > visual.bottom())) { auto graph = wd->root_graph; + + // untransform r and good_r to the System-side dpi before creating a pixel buffer + platform_abstraction::untransform_dpi(r , graph->get_dpi()); + platform_abstraction::untransform_dpi(good_r, graph->get_dpi()); + nana::paint::pixel_buffer pixbuf(graph->handle(), r); pixel_argb_t px0, px1, px2, px3; diff --git a/source/gui/detail/inner_fwd_implement.hpp b/source/gui/detail/inner_fwd_implement.hpp index a6fee2a3f..06db82ac2 100644 --- a/source/gui/detail/inner_fwd_implement.hpp +++ b/source/gui/detail/inner_fwd_implement.hpp @@ -1,4 +1,4 @@ -/* +/** * Implementations of Inner Forward Declaration * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2018 Jinhao(cnjinhao@hotmail.com) @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/detail/inner_fwd_implement.hpp + * @file nana/gui/detail/inner_fwd_implement.hpp * */ @@ -77,7 +77,7 @@ namespace nana{ }condition; root_misc(root_misc&&); - root_misc(basic_window * wd, unsigned width, unsigned height); + root_misc(basic_window * wd, const size& sz); ~root_misc(); #ifdef NANA_X11 diff --git a/source/gui/detail/native_window_interface.cpp b/source/gui/detail/native_window_interface.cpp index 0e137c824..8dd141503 100644 --- a/source/gui/detail/native_window_interface.cpp +++ b/source/gui/detail/native_window_interface.cpp @@ -1,4 +1,4 @@ -/* +/** * Platform Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2022 Jinhao(cnjinhao@hotmail.com) @@ -7,10 +7,10 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/detail/native_window_interface.cpp + * @file nana/gui/detail/native_window_interface.cpp */ - +#include #include // for print_monitor_dpi() for debugging #include "../../detail/platform_spec_selector.hpp" @@ -21,6 +21,7 @@ #include #if defined(NANA_WINDOWS) +//# include # include # include #elif defined(NANA_X11) @@ -37,7 +38,138 @@ namespace nana namespace detail{ #if defined(NANA_WINDOWS) - + nana::point scale_to_dpi(int x, int y, int dpi) + { + auto scaled_p = nana::point(MulDiv(x, dpi, 96), + MulDiv(y, dpi, 96)); + if constexpr (dpi_debugging) + { + std::cout << " orig point= " << x << ", " << y << '\n'; + std::cout << " scaled point= " << scaled_p.x << ", " << scaled_p.y << '\n'; + } + return scaled_p; + } + nana::point scale_to_dpi(native_window_type wd, int x, int y) + { + int dpi = native_interface::window_dpi(wd); + return scale_to_dpi(x, y, dpi); + } + nana::point unscale_dpi(native_window_type wd, int x, int y) + { + int dpi = static_cast(native_interface::window_dpi(wd)); + auto scaled_p = nana::point(MulDiv(x, 96, dpi), + MulDiv(y, 96, dpi)); + if constexpr (dpi_debugging) + std::cout << " unscaled point= " << scaled_p.x << ", " << scaled_p.y << '\n'; + return scaled_p; + } + // create helper function to scale nana::rectangle to dpi + nana::rectangle scale_to_dpi(const nana::rectangle& r, int dpi) + { + auto scaled_r = nana::rectangle(MulDiv(r.x, dpi, 96), + MulDiv(r.y, dpi, 96), + MulDiv(r.width, dpi, 96), + MulDiv(r.height, dpi, 96)); + if constexpr (dpi_debugging) + { + std::cout << " orig rect= " << r.x << ", " << r.y << + " with size= " << r.width << ", " << r.height << '\n'; + std::cout << " scaled rect= " << scaled_r.x << ", " << scaled_r.y << + " with size= " << scaled_r.width << ", " << scaled_r.height << '\n'; + } + return scaled_r; + } + nana::rectangle scale_to_dpi(native_window_type wd, const nana::rectangle& r) + { + int dpi = static_cast(native_interface::window_dpi(wd)); + return scale_to_dpi(r, dpi); + } + nana::rectangle unscale_dpi(const nana::rectangle& r, int dpi) + { + auto scaled_r = nana::rectangle(MulDiv(r.x, 96, dpi), + MulDiv(r.y, 96, dpi), + MulDiv(r.width, 96, dpi), + MulDiv(r.height, 96, dpi)); + if constexpr (dpi_debugging) + { + std::cout << " unscaled rect= " << scaled_r.x << ", " << scaled_r.y << + " with size= " << scaled_r.width << ", " << scaled_r.height << '\n'; + } + return scaled_r; + } + + // create helper function to scale RECT to dpi + RECT scale_to_dpi(const RECT& r, int dpi) + { + RECT scaled_r {.left = MulDiv(r.left, dpi, 96), + .top = MulDiv(r.top, dpi, 96), + .right = MulDiv(r.right, dpi, 96), + .bottom= MulDiv(r.bottom, dpi, 96) } ; + + if constexpr (dpi_debugging) + { + std::cout << " orig rect= " << r.left << ", " << r.top << + " with size= " << r.right - r.left << ", " << r.bottom - r.top << '\n'; + std::cout << " scaled rect= " << scaled_r.left << ", " << scaled_r.top << + " with size= " << scaled_r.right - scaled_r.left << ", " << scaled_r.bottom - scaled_r.top << '\n'; + } + return scaled_r; + } + RECT scale_to_dpi(native_window_type wd, const RECT& r) + { + int dpi = static_cast(native_interface::window_dpi(wd)); + return scale_to_dpi(r, dpi); + } + + RECT unscale_dpi(const RECT& r, int dpi) + { + RECT scaled_r {.left = MulDiv(r.left, 96, dpi), + .top = MulDiv(r.top, 96, dpi), + .right = MulDiv(r.right, 96, dpi), + .bottom= MulDiv(r.bottom, 96, dpi) } ; + + if constexpr (dpi_debugging) + { + std::cout << " unscaled rect= " << scaled_r.left << ", " << scaled_r.top << + " with size= " << scaled_r.right - scaled_r.left << ", " << scaled_r.bottom - scaled_r.top << '\n'; + } + return scaled_r; + } + + nana::size scale_to_dpi(const nana::size& sz, int dpi) + { + auto scaled_sz = nana::size(MulDiv(sz.width, dpi, 96), + MulDiv(sz.height, dpi, 96)); + if constexpr (dpi_debugging) + { + std::cout << " orig size= " << sz.width << ", " << sz.height << '\n'; + std::cout << " scaled size= " << scaled_sz.width << ", " << scaled_sz.height << '\n'; + } + return scaled_sz; + } + nana::size scale_to_dpi(native_window_type wd, const nana::size& sz) + { + int dpi = static_cast(native_interface::window_dpi(wd)); + return scale_to_dpi(sz, dpi); + } + nana::size unscale_dpi(const nana::size& sz, int dpi) + { + auto scaled_sz = nana::size(MulDiv(sz.width, 96, dpi), + MulDiv(sz.height, 96, dpi)); + if constexpr (dpi_debugging) + { + std::cout << " unscaled size= " << scaled_sz.width << ", " << scaled_sz.height << '\n'; + } + return scaled_sz; + } + nana::size unscale_dpi(native_window_type wd, const nana::size& sz) + { + int dpi = static_cast(native_interface::window_dpi(wd)); + return unscale_dpi(sz, dpi); + } + + + struct DPI_AWARENESS_CONTEXT___ { int unused; }; ///< introduce named dummy type, avoid including windows.h typedef struct DPI_AWARENESS_CONTEXT___* DPI_AWARENESS_CONTEXT_; ///< introduce named dummy pointer type @@ -78,6 +210,7 @@ namespace detail{ using SetThreadDpiAwarenessContext_ftype = HRESULT(__stdcall*)(DPI_AWARENESS_CONTEXT_); using GetSystemMetrics_ftype = int (__stdcall*)(int ); using GetSystemMetricsForDpi_ftype = int (__stdcall*)(int, UINT ); + using MonitorFromPoint_ftype = HMONITOR(__stdcall*)(POINT, DWORD ); /// define function pointers members for each API SetProcessDPIAware_ftype SetProcessDPIAware { nullptr }; ///< https://learn.microsoft.com/en-us/windows/win32/api/winuser/nf-winuser-setprocessdpiaware @@ -91,6 +224,7 @@ namespace detail{ SetThreadDpiAwarenessContext_ftype SetThreadDpiAwarenessContext { nullptr }; GetSystemMetrics_ftype GetSystemMetrics { nullptr }; GetSystemMetricsForDpi_ftype GetSystemMetricsForDpi { nullptr }; + MonitorFromPoint_ftype MonitorFromPoint { nullptr }; dpi_function() { @@ -135,6 +269,9 @@ namespace detail{ this->GetSystemMetricsForDpi = reinterpret_cast (::GetProcAddress(user32, "GetSystemMetricsForDpi")); + + this->MonitorFromPoint = reinterpret_cast + (::GetProcAddress(user32, "MonitorFromPoint")); } /// Dynamically load Shcore.DLL to check these APIs are supported by the SDK and OS. @@ -226,6 +363,7 @@ namespace detail{ //This function is defined in bedrock_windows.cpp HINSTANCE windows_module_handle(); + /// A map to return the HICON associated with a window class tray_manager { struct window_extra_t @@ -476,6 +614,7 @@ namespace detail{ } #endif + /// Invokes a function in the thread of the specified window. void native_interface::affinity_execute(native_window_type native_handle, bool post, std::function&& fn) { if (!fn) @@ -543,10 +682,11 @@ namespace detail{ #endif } - /// generalized to Windows dpi awareness v2 to return already 'DPI' scaled size + /// generalized to Windows dpi awareness v2 to return already 'DPI' unscaled (user-side) size /// this result is used to calculate the area available to draw with may be smaller than the monitor size nana::size native_interface::primary_monitor_size() { + nana::size sz{0, 0}; #if defined(NANA_WINDOWS) if (wdpi_fns().GetDpiForMonitor && !wdpi_fns().GetDpiForWindow) // priorize possible x_dpi != y_dpi. Really?? @@ -554,7 +694,7 @@ namespace detail{ // get the main monitor HWND HWND primary_monitor = ::GetDesktopWindow(); HMONITOR pmonitor = ::MonitorFromWindow(primary_monitor, MONITOR_DEFAULTTOPRIMARY); - UINT x_dpi, y_dpi; + UINT x_dpi, y_dpi; // here x_dpi != y_dpi if (S_OK == wdpi_fns().GetDpiForMonitor(pmonitor, dpi_function::MDT_EFFECTIVE_DPI, &x_dpi, &y_dpi)) { if constexpr (dpi_debugging) @@ -564,36 +704,41 @@ namespace detail{ return nana::size(wdpi_fns().GetSystemMetricsForDpi(SM_CXSCREEN, x_dpi), wdpi_fns().GetSystemMetricsForDpi(SM_CYSCREEN, y_dpi)); // x_dpi != y_dpi ?? - else // fallback to GetSystemMetrics + else // fallback to GetSystemMetrics: here x_dpi != y_dpi return nana::size(MulDiv(::GetSystemMetrics(SM_CXSCREEN), 96, x_dpi), MulDiv(::GetSystemMetrics(SM_CYSCREEN), 96, y_dpi)); } } - std::size_t dpi = native_interface::system_dpi(); // originaly got from UINT or int: safe to get back to that + int dpi = native_interface::system_dpi(); // originaly got from UINT or int: safe to get back to that if constexpr (dpi_debugging) std::cout << "primary_monitor_size(): DPI= " << dpi << std::endl; if (false) //wdpi_fns().GetSystemMetricsForDpi) // do not scale ? { - nana::size sz = nana::size(MulDiv(::GetSystemMetrics(SM_CXSCREEN), 96, int(dpi)), - MulDiv(::GetSystemMetrics(SM_CYSCREEN), 96, int(dpi))); if constexpr (dpi_debugging) - std::cout << "primary_monitor_size() with GetSystemMetrics: size= " << sz.width << " x " << sz.height << std::endl; + std::cout << "primary_monitor_size() with GetSystemMetrics: \n" ; + + sz = nana::size(::GetSystemMetrics(SM_CXSCREEN), + ::GetSystemMetrics(SM_CYSCREEN)); + sz = unscale_dpi(sz, dpi); + sz = nana::size(wdpi_fns().GetSystemMetricsForDpi(SM_CXSCREEN, UINT(dpi)), wdpi_fns().GetSystemMetricsForDpi(SM_CYSCREEN, UINT(dpi))); if constexpr (dpi_debugging) - std::cout << "primary_monitor_size() with GetSystemMetricsForDpi: size= " << sz.width << " x " << sz.height << std::endl; + std::cout << "primary_monitor_size() with GetSystemMetricsForDpi: size= " + << sz.width << " x " << sz.height << std::endl; return sz; } - nana::size sz = nana::size(MulDiv(::GetSystemMetrics(SM_CXSCREEN), 96, int(dpi)), - MulDiv(::GetSystemMetrics(SM_CYSCREEN), 96, int(dpi))); + sz = nana::size(::GetSystemMetrics(SM_CXSCREEN), + ::GetSystemMetrics(SM_CYSCREEN)); + if constexpr (dpi_debugging) - std::cout << "primary_monitor_size() with GetSystemMetrics: size= " << sz.width << " x " << sz.height << std::endl; + std::cout << "primary_monitor_size() with GetSystemMetrics: \n" ; - return sz; + return unscale_dpi(sz, dpi); /// \todo: use platform_abstraction::unscale_dpi() instead, to include X11 ? #elif defined(NANA_X11) nana::detail::platform_scope_guard psg; @@ -602,30 +747,32 @@ namespace detail{ #endif } /// \todo: generalize dpi to v2 awareness - rectangle native_interface::screen_area_from_point(const point& pos) + rectangle native_interface::screen_area_from_system_point([[maybe_unused]] const point& system_point) ///< unused ? { #if defined(NANA_WINDOWS) - /// \todo: make DPI AWARE - typedef HMONITOR (__stdcall * MonitorFromPointT)(POINT,DWORD); - - MonitorFromPointT mfp = reinterpret_cast(::GetProcAddress(::GetModuleHandleA("User32.DLL"), "MonitorFromPoint")); - if(mfp) + // led assume somehow coordinates in the united global big and 'fake'-96 DPI sytem monitor are provided + // in pos (POINT structure that specifies the point of interest in virtual-screen coordinates.) + if(wdpi_fns().MonitorFromPoint) { - POINT native_pos = {pos.x, pos.y}; - HMONITOR monitor = mfp(native_pos, 2 /*MONITOR_DEFAULTTONEAREST*/); - - MONITORINFO mi; - mi.cbSize = sizeof mi; - - /// \todo: make DPI AWARE - if(::GetMonitorInfo(monitor, &mi)) + POINT native_pos = {system_point.x, system_point.y}; + HMONITOR monitor = wdpi_fns().MonitorFromPoint(native_pos, 2 /*MONITOR_DEFAULTTONEAREST*/); + UINT x_dpi, y_dpi; + if (S_OK == wdpi_fns().GetDpiForMonitor(monitor, dpi_function::MDT_EFFECTIVE_DPI, &x_dpi, &y_dpi)) { - return rectangle(mi.rcWork.left, mi.rcWork.top, - mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top); + if constexpr (dpi_debugging) + std::cout << "screen_area_from_system_point(): DPI= " << x_dpi << " x " << y_dpi << std::endl; + MONITORINFO mi; + mi.cbSize = sizeof mi; + + if(::GetMonitorInfo(monitor, &mi)) + { + return unscale_dpi(rectangle(mi.rcWork.left, mi.rcWork.top, + mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top), + x_dpi); + /// \todo: use platform_abstraction::unscale_dpi() instead, to include X11 ? + } } } -#else - static_cast(pos); //eliminate unused parameter compiler warning. #endif return rectangle{ primary_monitor_size() }; } @@ -633,6 +780,9 @@ namespace detail{ //platform-dependent native_interface::window_result native_interface::create_window(native_window_type owner, bool nested, const rectangle& r, const appearance& app) { + int dpi = native_interface::window_dpi(owner); + nana::rectangle scaled_r = platform_abstraction::dpi_scale(r, dpi); + #if defined(NANA_WINDOWS) DWORD style = WS_SYSMENU | WS_CLIPCHILDREN; DWORD style_ex= WS_EX_NOPARENTNOTIFY; @@ -650,12 +800,14 @@ namespace detail{ if(app.floating) style_ex |= WS_EX_TOPMOST; - POINT pt = {r.x, r.y}; + if constexpr (dpi_debugging) + std::wcout << " --- create_window():\n"; // on:" << window_caption(owner) << "\n"; + + POINT pt = {scaled_r.x, scaled_r.y}; if(owner && (nested == false)) ::ClientToScreen(reinterpret_cast(owner), &pt); - /// \todo: make DPI AWARE with AdjustWindowRectExForDpi ? HWND native_wd = ::CreateWindowEx(style_ex, L"NanaWindowInternal", L"Nana Window", style, pt.x, pt.y, 100, 100, @@ -668,13 +820,16 @@ namespace detail{ ::GetWindowRect(native_wd, &wd_area); if constexpr (dpi_debugging) { - // print for debuging the position of creation of the window pt - std::cout << "create_window(): pt= " << pt.x << ", " << pt.y << " with size= " << 100 << ", " << 100 << std::endl; - // with a client area of: - std::cout << "create_window(): client= " << client.right << ", " << client.top << " with size= " << client.right - client.left << ", "<< client.bottom - client.top << ", " << std::endl; - // and a window area of: - std::cout << "create_window(): wd_area= " << wd_area.right << ", " << wd_area.top << " with size= " << wd_area.right - wd_area.left << ", "<< wd_area.bottom - wd_area.top << ", " << std::endl; - } + // print for debuging the position of creation of the window pt + std::cout << " pt= " << pt.x << ", " << pt.y << + " with size= " << 100 << ", " << 100 << std::endl; + // with a client area of: + std::cout << " client= " << client.left << ", " << client.top << + " with size= " << client.right - client.left << ", " << client.bottom - client.top << std::endl; + // and a window area of: + std::cout << " wd_area= " << wd_area.left << ", " << wd_area.top << + " with size= " << wd_area.right - wd_area.left << ", " << wd_area.bottom - wd_area.top << std::endl; + } //a dimension with borders and caption title @@ -686,30 +841,35 @@ namespace detail{ wd_area.top = pt.y; } - int delta_w = static_cast(r.width) - client.right; - int delta_h = static_cast(r.height) - client.bottom; + int delta_w = static_cast(scaled_r.width ) - client.right; + int delta_h = static_cast(scaled_r.height) - client.bottom; ::MoveWindow(native_wd, wd_area.left, wd_area.top, wd_area.right + delta_w, wd_area.bottom + delta_h, true); // the window was moved to: if constexpr (dpi_debugging) - std::cout << "create_window(): moved to= " << wd_area.left << ", " << wd_area.top << " with size= " << wd_area.right + delta_w << ", "<< wd_area.bottom + delta_h << ", " << std::endl; + std::cout << " moved to= " << wd_area.left << ", " << wd_area.top << + " with size= " << wd_area.right + delta_w - wd_area.left << ", " << wd_area.bottom + delta_h -wd_area.top << std::endl; ::GetClientRect(native_wd, &client); ::GetWindowRect(native_wd, &wd_area); if constexpr (dpi_debugging) { // with a client area of: - std::cout << "create_window(): moved client= " << client.right << ", " << client.top << " with size= " << client.right - client.left << ", "<< client.bottom - client.top << ", " << std::endl; - // and a window area of: - std::cout << "create_window(): moved wd_area= " << wd_area.right << ", " << wd_area.top << " with size= " << wd_area.right - wd_area.left << ", "<< wd_area.bottom - wd_area.top << ", " << std::endl; + std::cout << " moved client= " << client.left << ", " << client.top << + " with size= " << client.right - client.left << ", " << client.bottom - client.top << std::endl; + // and a window area of: + std::cout << " moved wd_area= " << wd_area.left << ", " << wd_area.top << + " with size= " << wd_area.right - wd_area.left << ", " << wd_area.bottom - wd_area.top << std::endl; } wd_area.right -= wd_area.left; wd_area.bottom -= wd_area.top; + auto wd = reinterpret_cast(native_wd); + nana::size client_size{static_cast(client.right -client.left), + static_cast(client.bottom - client.top)}; + unsigned extra_width = static_cast(wd_area.right - client.right), + extra_height = static_cast(wd_area.bottom - client.bottom); - window_result result = { reinterpret_cast(native_wd), - static_cast(client.right), static_cast(client.bottom), - static_cast(wd_area.right - client.right), static_cast(wd_area.bottom - client.bottom)}; #elif defined(NANA_X11) nana::detail::platform_scope_guard psg; @@ -738,7 +898,7 @@ namespace detail{ Window parent = (owner ? reinterpret_cast(owner) : restrict::spec.root_window()); //The position passed to XCreateWindow is a screen coordinate. - auto pos = r.position(); + auto pos = scaled_r.position(); if((false == nested) && owner) { win_attr.save_under = True; @@ -753,7 +913,7 @@ namespace detail{ win_attr.event_mask = ButtonPressMask | ButtonReleaseMask | PointerMotionMask | KeyPressMask | KeyReleaseMask | ExposureMask | StructureNotifyMask | EnterWindowMask | LeaveWindowMask | FocusChangeMask; Window handle = ::XCreateWindow(disp, parent, - pos.x, pos.y, (r.width ? r.width : 1), (r.height ? r.height : 1), 0, + pos.x, pos.y, (scaled_r.width ? scaled_r.width : 1), (scaled_r.height ? scaled_r.height : 1), 0, restrict::spec.screen_depth(), InputOutput, restrict::spec.screen_visual(), attr_mask, &win_attr); if(handle) @@ -765,7 +925,7 @@ namespace detail{ restrict::spec.make_owner(origin_owner, reinterpret_cast(handle)); //The exposed_position is a relative position to its owner/parent. - exposed_positions[handle] = r.position(); + exposed_positions[handle] = scaled_r.position(); } XChangeWindowAttributes(disp, handle, attr_mask, &win_attr); @@ -806,8 +966,8 @@ namespace detail{ } else { - hints.min_width = hints.max_width = r.width; - hints.min_height = hints.max_height = r.height; + hints.min_width = hints.max_width = scaled_r.width; + hints.min_height = hints.max_height = scaled_r.height; hints.flags |= (PMinSize | PMaxSize); } ::XSetWMNormalHints(disp, handle, &hints); @@ -852,29 +1012,43 @@ namespace detail{ reinterpret_cast(const_cast(&ab.net_wm_state_skip_taskbar)), 1); } } - window_result result = {reinterpret_cast(handle), r.width, r.height, 0, 0}; - restrict::spec.msg_insert(reinterpret_cast(handle)); + auto wd = reinterpret_cast(handle); + nana::size client_size = nana::size(scaled_r.width, scaled_r.height); + unsigned extra_width = 0, + extra_height = 0; + restrict::spec.msg_insert(wd); #endif + int new_dpi = window_dpi(wd); + // unscale from system coordinates to App scale + window_result result = { .native_handle = wd, + .client_size = platform_abstraction::unscale_dpi(client_size, new_dpi), + .extra_width = platform_abstraction::unscale_dpi(extra_width, new_dpi), + .extra_height = platform_abstraction::unscale_dpi(extra_height, new_dpi), + .owner_dpi = dpi, + .dpi = new_dpi + }; return result; } - native_window_type native_interface::create_child_window(native_window_type parent, const rectangle& r) + native_window_type native_interface::create_child_window(native_window_type parent, const rectangle& r) ///< unused ? { if(nullptr == parent) return nullptr; -#if defined(NANA_WINDOWS) - /// \todo: make DPI AWARE with AdjustWindowRectExForDpi ? + /// \todo: use platform_abstraction::dpi_scale(r, dpi) instead, to include X11 ? + #if defined(NANA_WINDOWS) + + if constexpr (dpi_debugging) std::cout << " --- create_child_window():\n"; + + nana::rectangle scaled_r = scale_to_dpi(parent, r); + HWND handle = ::CreateWindowEx(WS_EX_CONTROLPARENT, // Extended possibilities for variation L"NanaWindowInternal", L"Nana Child Window", // Title Text WS_CHILD | WS_VISIBLE | WS_TABSTOP | WS_CLIPSIBLINGS, - r.x, r.y, r.width, r.height, + scaled_r.x, scaled_r.y, scaled_r.width, scaled_r.height, reinterpret_cast(parent), // The window is a child-window to desktop 0, windows_module_handle(), 0); - if constexpr (dpi_debugging) // print for debuging the position of creation of the window pt - std::cout << "create_child_window(): in " << r.x << ", " << r.y << " with size= " << r.width << ", " << r.height << std::endl; - -#elif defined(NANA_X11) + #elif defined(NANA_X11) nana::detail::platform_scope_guard psg; XSetWindowAttributes win_attr; @@ -944,7 +1118,7 @@ namespace detail{ ::XChangeProperty(disp, handle, ab.net_wm_state, XA_ATOM, 32, PropModeAppend, reinterpret_cast(const_cast(&ab.net_wm_state_skip_taskbar)), 1); } -#endif + #endif return reinterpret_cast(handle); } @@ -1059,8 +1233,7 @@ namespace detail{ #endif } - //close_window - //Destroy a window + /// close_window, Destroy a window void native_interface::close_window(native_window_type wd) { #if defined(NANA_WINDOWS) @@ -1302,7 +1475,11 @@ namespace detail{ nana::point native_interface::window_position(native_window_type wd) { + /// \todo: use platform_abstraction::unscale_dpi(p, dpi) instead, to include X11 ? #if defined(NANA_WINDOWS) + if constexpr (dpi_debugging) + std::wcout << " --- window_position() " << window_caption(wd) << ":\n"; + ::RECT r; ::GetWindowRect(reinterpret_cast(wd), & r); HWND coord_wd = ::GetWindow(reinterpret_cast(wd), GW_OWNER); @@ -1314,9 +1491,9 @@ namespace detail{ { ::POINT pos = {r.left, r.top}; ::ScreenToClient(coord_wd, &pos); - return nana::point(pos.x, pos.y); + return unscale_dpi(wd, pos.x, pos.y); } - return nana::point(r.left, r.top); + return unscale_dpi(wd, r.left, r.top); #elif defined(NANA_X11) point scr_pos; nana::detail::platform_scope_guard lock; @@ -1343,7 +1520,11 @@ namespace detail{ void native_interface::move_window(native_window_type wd, int x, int y) { + /// \todo: use platform_abstraction::dpi_scale(p, dpi) instead, to include X11 ? + /// \todo: no need to set wd->position, etc? #if defined(NANA_WINDOWS) + if constexpr (dpi_debugging) std::wcout << " --- move_window(x,y):" << window_caption(wd) << "\n"; + auto p = scale_to_dpi(wd, x, y); ::RECT r; ::GetWindowRect(reinterpret_cast(wd), &r); HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); @@ -1353,18 +1534,19 @@ namespace detail{ ::GetWindowRect(owner, &owner_rect); ::POINT pos = {owner_rect.left, owner_rect.top}; ::ScreenToClient(owner, &pos); - x += (owner_rect.left - pos.x); - y += (owner_rect.top - pos.y); + p.x += (owner_rect.left - pos.x); + p.y += (owner_rect.top - pos.y); } if (::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) { nana::internal_revert_guard irg; - ::MoveWindow(reinterpret_cast(wd), x, y, r.right - r.left, r.bottom - r.top, true); + ::MoveWindow(reinterpret_cast(wd), p.x, p.y, r.right - r.left, r.bottom - r.top, true); } else - ::MoveWindow(reinterpret_cast(wd), x, y, r.right - r.left, r.bottom - r.top, true); + ::MoveWindow(reinterpret_cast(wd), p.x, p.y, r.right - r.left, r.bottom - r.top, true); + #elif defined(NANA_X11) Display * disp = restrict::spec.open_display(); @@ -1414,10 +1596,12 @@ namespace detail{ bool native_interface::move_window(native_window_type wd, const rectangle& r) { + /// \todo: use platform_abstraction::dpi_scale(r, dpi) instead, to include X11 ? #if defined(NANA_WINDOWS) - int x = r.x; - int y = r.y; + if constexpr (dpi_debugging) std::cout << " --- move_window(rectangle):\n"; + auto scaled_r = scale_to_dpi(wd, r); + HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); if(owner) { @@ -1425,8 +1609,8 @@ namespace detail{ ::GetWindowRect(owner, &owner_rect); ::POINT pos = {owner_rect.left, owner_rect.top}; ::ScreenToClient(owner, &pos); - x += (owner_rect.left - pos.x); - y += (owner_rect.top - pos.y); + scaled_r.x += (owner_rect.left - pos.x); + scaled_r.y += (owner_rect.top - pos.y); } RECT client, wd_area; @@ -1438,10 +1622,12 @@ namespace detail{ if (::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) { nana::internal_revert_guard irg; - return (FALSE != ::MoveWindow(reinterpret_cast(wd), x, y, r.width + ext_w, r.height + ext_h, true)); + return (FALSE != ::MoveWindow(reinterpret_cast(wd), scaled_r.x, scaled_r.y, + scaled_r.width + ext_w, scaled_r.height + ext_h, true)); } - return (FALSE != ::MoveWindow(reinterpret_cast(wd), x, y, r.width + ext_w, r.height + ext_h, true)); + return (FALSE != ::MoveWindow(reinterpret_cast(wd), scaled_r.x, scaled_r.y, + scaled_r.width + ext_w, scaled_r.height + ext_h, true)); #elif defined(NANA_X11) Display * disp = restrict::spec.open_display(); long supplied; @@ -1545,14 +1731,13 @@ namespace detail{ { switch(action_if_no_wd_after) { - case z_order_action::bottom : wa = HWND_BOTTOM; break; - case z_order_action::top: wa = HWND_TOP; break; + case z_order_action::bottom : wa = HWND_BOTTOM; break; + case z_order_action::top: wa = HWND_TOP; break; case z_order_action::topmost: wa = HWND_TOPMOST; break; case z_order_action::foreground: ::SetForegroundWindow(reinterpret_cast(wd)); return; - default: - wa = HWND_NOTOPMOST; + default: wa = HWND_NOTOPMOST; } } if(::GetCurrentThreadId() != ::GetWindowThreadProcessId(reinterpret_cast(wd), 0)) @@ -1594,16 +1779,25 @@ namespace detail{ native_interface::frame_extents native_interface::window_frame_extents(native_window_type wd) { frame_extents fm_extents{0, 0, 0, 0}; + /// \todo: use platform_abstraction::unscale_dpi(fm, dpi) instead, to include X11 ? #if defined(NANA_WINDOWS) + if constexpr (dpi_debugging) + std::cout << " --- window_frame_extents():\n"; + int dpi = static_cast(native_interface::window_dpi(wd)); + ::RECT client; - ::GetClientRect(reinterpret_cast(wd), &client); //The right and bottom of client by GetClientRect indicate the width and height of the area + ::GetClientRect(reinterpret_cast(wd), &client); + //The right and bottom of client by GetClientRect indicate the width and height of the area ::RECT wd_area; ::GetWindowRect(reinterpret_cast(wd), &wd_area); - fm_extents.left = client.left - wd_area.left; + client = unscale_dpi(client, dpi); // first unscale to disminish rounding errors on small values + wd_area = unscale_dpi(wd_area, dpi); + + fm_extents.left = client.left - wd_area.left; fm_extents.right = wd_area.right - client.right; - fm_extents.top = client.top - wd_area.top; + fm_extents.top = client.top - wd_area.top; fm_extents.bottom = wd_area.bottom - client.bottom; #elif defined(NANA_X11) Atom type; @@ -1631,28 +1825,34 @@ namespace detail{ return fm_extents; } - bool native_interface::window_size(native_window_type wd, const size& sz) + bool native_interface::window_size(native_window_type wd, const size& sz) ///< change to new_size if possible { + /// \todo: use platform_abstraction::dpi_scale(sz, dpi) instead, to include X11 ? #if defined(NANA_WINDOWS) + if constexpr (dpi_debugging) std::cout << " --- window_size(sz):\n"; + auto p = scale_to_dpi(wd, static_cast(sz.width), static_cast(sz.height)); + ::RECT r; - ::GetWindowRect(reinterpret_cast(wd), &r); - HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); + ::GetWindowRect(reinterpret_cast(wd), &r); // original position + + HWND owner = ::GetWindow(reinterpret_cast(wd), GW_OWNER); HWND parent = ::GetParent(reinterpret_cast(wd)); - if(parent && (parent != owner)) + if(parent && (parent != owner)) // ? { - ::POINT pos = {r.left, r.top}; + ::POINT pos = {r.left, r.top}; // original system? position ::ScreenToClient(parent, &pos); - r.left = pos.x; - r.top = pos.y; + r.left = pos.x; // now, relative to parent + r.top = pos.y; } + // move to the original position but with the new size if (::GetWindowThreadProcessId(reinterpret_cast(wd), 0) != ::GetCurrentThreadId()) { nana::internal_revert_guard irg; - return (FALSE != ::MoveWindow(reinterpret_cast(wd), r.left, r.top, static_cast(sz.width), static_cast(sz.height), true)); + return (FALSE != ::MoveWindow(reinterpret_cast(wd), r.left, r.top, p.x, p.y, true)); } - return (FALSE != ::MoveWindow(reinterpret_cast(wd), r.left, r.top, static_cast(sz.width), static_cast(sz.height), true)); + return (FALSE != ::MoveWindow(reinterpret_cast(wd), r.left, r.top, p.x, p.y, true)); #elif defined(NANA_X11) auto disp = restrict::spec.open_display(); nana::detail::platform_scope_guard psg; @@ -1690,11 +1890,16 @@ namespace detail{ #endif } - void native_interface::get_window_rect(native_window_type wd, rectangle& r) + void native_interface::get_window_rect(native_window_type wd, rectangle& r) ///< unused ? { + /// \todo: use platform_abstraction::unscale_dpi(r, dpi) instead, to include X11 ? #if defined(NANA_WINDOWS) + if constexpr (dpi_debugging) + std::wcout << " --- get_window_rect() " << window_caption(wd) << ":\n"; ::RECT winr; ::GetWindowRect(reinterpret_cast(wd), &winr); + winr = unscale_dpi(winr, static_cast(native_interface::window_dpi(wd))); + r.x = winr.left; r.y = winr.top; r.width = winr.right - winr.left; @@ -1717,7 +1922,7 @@ namespace detail{ if(::GetCurrentThreadId() != ::GetWindowThreadProcessId(reinterpret_cast(wd), 0)) { wchar_t * wstr = new wchar_t[title.length() + 1]; - std::wcscpy(wstr, title.c_str()); + std::wcscpy(wstr, title.c_str()); ::PostMessage(reinterpret_cast(wd), nana::detail::messages::remote_thread_set_window_text, reinterpret_cast(wstr), 0); } else @@ -1754,7 +1959,7 @@ namespace detail{ ::GetWindowText(reinterpret_cast(wd), &(str[0]), static_cast(str.size())); - //Remove the null terminator writtien by GetWindowText + //"Remove" the null terminator writtien by GetWindowText str.resize(length); } @@ -1807,9 +2012,16 @@ namespace detail{ #endif } - nana::point native_interface::cursor_position() + nana::point native_interface::cursor_screen_position() + { + return platform_abstraction::unscale_dpi(cursor_sytem_position(), system_dpi()); + } + + nana::point native_interface::cursor_sytem_position() { #if defined(NANA_WINDOWS) + // return system point, unscaled + //if constexpr (dpi_debugging) std::wcout << " --- cursor_position():\n"; POINT point; ::GetCursorPos(&point); return nana::point(point.x, point.y); @@ -1892,7 +2104,14 @@ namespace detail{ void native_interface::caret_create(native_window_type wd, const ::nana::size& caret_sz) { #if defined(NANA_WINDOWS) - ::CreateCaret(reinterpret_cast(wd), 0, int(caret_sz.width), int(caret_sz.height)); + if constexpr + (dpi_debugging) std::wcout << " --- caret_create() " << window_caption(wd) << ":\n"; + + auto p = scale_to_dpi(wd, static_cast(caret_sz.width), + static_cast(caret_sz.height)); + + ::CreateCaret(reinterpret_cast(wd), 0, p.x, p.y); + #elif defined(NANA_X11) nana::detail::platform_scope_guard psg; restrict::spec.caret_open(wd, caret_sz); @@ -1912,9 +2131,13 @@ namespace detail{ #endif } - void native_interface::caret_pos(native_window_type wd, const point& pos) + void native_interface::caret_pos(native_window_type wd, const point& pos_ori) { + auto pos = platform_abstraction::dpi_scale(pos_ori, window_dpi(wd)); + #if defined(NANA_WINDOWS) + if constexpr (dpi_debugging) std::wcout << " --- caret_pos() " << window_caption(wd) << ":\n"; + if(::GetCurrentThreadId() != ::GetWindowThreadProcessId(reinterpret_cast(wd), 0)) { auto cp = new nana::detail::messages::caret; @@ -1982,22 +2205,36 @@ namespace detail{ #endif } + /// from window_point, all user-side bool native_interface::calc_screen_point(native_window_type wd, nana::point& pos) { + platform_abstraction::dpi_transform(pos, window_dpi(wd)); + bool sucess = transform_window_system_point_into_screen_sytem_point(wd, pos); + platform_abstraction::untransform_dpi(pos, system_dpi()); + return sucess; + } + + ///< from client, system-side + bool native_interface::transform_window_system_point_into_screen_sytem_point(native_window_type wd, nana::point& screen_system_point) + { #if defined(NANA_WINDOWS) - POINT point = {pos.x, pos.y}; - if(::ClientToScreen(reinterpret_cast(wd), &point)) + if constexpr (dpi_debugging) + std::wcout << " --- calc_screen_point() " << window_caption(wd) << ":\n"; + + POINT pt = {screen_system_point.x, screen_system_point.y}; + if(::ClientToScreen(reinterpret_cast(wd), &pt)) { - pos.x = point.x; - pos.y = point.y; + screen_system_point.x = pt.x; + screen_system_point.y = pt.y; return true; } #elif defined(NANA_X11) nana::detail::platform_scope_guard psg; - int x = pos.x, y = pos.y; + int x = screen_system_point.x, + y = screen_system_point.y; Window child; if(True == ::XTranslateCoordinates(restrict::spec.open_display(), - reinterpret_cast(wd), restrict::spec.root_window(), x, y, &pos.x, &pos.y, &child)) + reinterpret_cast(wd), restrict::spec.root_window(), x, y, &screen_system_point.x, &screen_system_point.y, &child)) { return true; } @@ -2005,12 +2242,33 @@ namespace detail{ return false; } + /// to client, user-side bool native_interface::calc_window_point(native_window_type wd, nana::point& pos) { + platform_abstraction::dpi_transform(pos, system_dpi()); + bool sucess = transform_screen_system_point_into_window_sytem_point(wd, pos); + platform_abstraction::untransform_dpi(pos, window_dpi(wd)); + return sucess; + } + + nana::point native_interface::cursor_window_position(native_window_type wd) + { + auto pos = cursor_sytem_position(); + transform_screen_system_point_into_window_sytem_point(wd, pos); + return platform_abstraction::untransform_dpi(pos, window_dpi(wd)); + } + + /// to client, system-side + bool native_interface::transform_screen_system_point_into_window_sytem_point(native_window_type wd, nana::point& pos) + { #if defined(NANA_WINDOWS) + if constexpr (dpi_debugging) + std::wcout << " --- transform_screen_system_point_into_window_sytem_point() " << window_caption(wd) << ":\n"; + POINT point = {pos.x, pos.y}; if(::ScreenToClient(reinterpret_cast(wd), &point)) { + //pos = unscale_dpi(wd, pos.x, pos.y); // work unscaled? wd_manager().find_window(native_handle, pos); pos.x = point.x; pos.y = point.y; return true; @@ -2027,10 +2285,10 @@ namespace detail{ return false; } - native_window_type native_interface::find_window(int x, int y) + native_window_type native_interface::find_window_from_system_screen_point(const nana::point& p) { #if defined(NANA_WINDOWS) - POINT pos = {x, y}; + POINT pos = {p.x, p.y}; return reinterpret_cast(::WindowFromPoint(pos)); #elif defined(NANA_X11) nana::detail::platform_scope_guard psg; @@ -2039,7 +2297,7 @@ namespace detail{ Window wd = root; Window child = 0; int dropx = 0, dropy = 0; - while(True == ::XTranslateCoordinates(restrict::spec.open_display(), root, wd, x, y, &dropx, &dropy, &child)) + while(True == ::XTranslateCoordinates(restrict::spec.open_display(), root, wd, p.x, p.y, &dropx, &dropy, &child)) { if(0 == child) break; wd = child; @@ -2047,6 +2305,15 @@ namespace detail{ return reinterpret_cast(wd); #endif } + native_window_type native_interface::find_cursor_window(nana::point& point) + { + auto pos = cursor_sytem_position(); + auto wd = find_window_from_system_screen_point(pos); + if (wd) + calc_window_point(wd, point); + platform_abstraction::untransform_dpi(point, window_dpi(wd)); + return wd; + } nana::size native_interface::check_track_size(nana::size sz, unsigned ext_width, unsigned ext_height, bool true_for_max) { @@ -2107,40 +2374,40 @@ namespace detail{ #endif } - std::size_t native_interface::window_dpi(native_window_type wd) /// \todo: add bool x_requested = true) + int native_interface::window_dpi(native_window_type wd, bool x_requested) { #ifdef NANA_WINDOWS HWND hwnd = reinterpret_cast(wd); if (!::IsWindow(hwnd)) - return system_dpi(); + return system_dpi(x_requested); if (wdpi_fns().GetDpiForWindow) // how to get x_dpi or y_dpi? - return wdpi_fns().GetDpiForWindow(hwnd); + return static_cast(wdpi_fns().GetDpiForWindow(hwnd)); if (wdpi_fns().GetDpiForMonitor) { HMONITOR pmonitor = ::MonitorFromWindow(hwnd, MONITOR_DEFAULTTOPRIMARY); UINT x_dpi, y_dpi; if (S_OK == wdpi_fns().GetDpiForMonitor(pmonitor, dpi_function::MDT_EFFECTIVE_DPI, &x_dpi, &y_dpi)) - return x_dpi; // x_requested ? x_dpi, y_dpi + return static_cast(x_requested ? x_dpi : y_dpi); } HDC hdc = ::GetDC(hwnd); // the old way. Works in any Windows version if (hdc) { - auto dpi = static_cast(::GetDeviceCaps(hdc, LOGPIXELSX)); // x_requested ? LOGPIXELSX : LOGPIXELSY + auto dpi = ::GetDeviceCaps(hdc, x_requested ? LOGPIXELSX : LOGPIXELSY); ::ReleaseDC(nullptr, hdc); return dpi; } #endif static_cast(wd); //eliminate the unused warning - return system_dpi(); + return system_dpi(x_requested); } - std::size_t native_interface::system_dpi() + int native_interface::system_dpi(bool x_requested) { #ifdef NANA_WINDOWS @@ -2152,23 +2419,40 @@ namespace detail{ HMONITOR pmonitor = ::MonitorFromWindow(primary_monitor, MONITOR_DEFAULTTOPRIMARY); UINT x_dpi, y_dpi; if (S_OK == wdpi_fns().GetDpiForMonitor(pmonitor, dpi_function::MDT_EFFECTIVE_DPI, &x_dpi, &y_dpi)) - return x_dpi; // x_dpi != y_dpi ?? + { + if constexpr ( dpi_debugging ) std::cout << "GetDpiForMonitor = " << (x_requested ? x_dpi : y_dpi) << std::endl; + return static_cast(x_requested ? x_dpi : y_dpi); + } } if (wdpi_fns().GetDpiForSystem) { if constexpr (dpi_debugging) std::cout << "GetDpiForSystem" << std::endl; - return wdpi_fns().GetDpiForSystem(); + return static_cast(wdpi_fns().GetDpiForSystem()); } - if constexpr (dpi_debugging) std::cout << "GetDeviceCaps" << std::endl; - //When DPI-aware APIs are not supported by the running Windows, it returns the system DPI auto hdc = ::GetDC(nullptr); - auto dpi = static_cast(::GetDeviceCaps(hdc, LOGPIXELSX)); + auto dpi = ::GetDeviceCaps(hdc, x_requested ? LOGPIXELSX : LOGPIXELSY); ::ReleaseDC(nullptr, hdc); + if constexpr (dpi_debugging) std::cout << "GetDeviceCaps = " << dpi << std::endl; return dpi; -#endif + #else + auto & spec = ::nana::detail::platform_spec::instance(); + auto disp = spec.open_display(); + auto screen = ::XDefaultScreen(disp); + + double dots = 0.5; + + if (x_requested) + dots += ((((double)DisplayWidth (disp, screen)) * 25.4) / + ((double)DisplayWidthMM(disp, screen))); + else + dots += ((((double)DisplayHeight (disp, screen)) * 25.4) / + ((double)DisplayHeightMM(disp, screen))); + + return static_cast(dots); + #endif return 96; } //end struct native_interface diff --git a/source/gui/detail/virtual_keyboard.cpp b/source/gui/detail/virtual_keyboard.cpp index 084a78223..19a817c19 100644 --- a/source/gui/detail/virtual_keyboard.cpp +++ b/source/gui/detail/virtual_keyboard.cpp @@ -309,7 +309,8 @@ namespace nana::detail langs_(langs), mode_(mode), behave_(behave), - im_(_m_default_im()) + im_(_m_default_im()), + cntpart_{.graph=paint::graphics(api::window_dpi(wd))} { cntpart_.lang = im_->lang(); @@ -781,7 +782,7 @@ namespace nana::detail if (pressed_key_ == key.value) r.pare_off(-2); - graph.rectangle(r, true, _m_key_color(key.value)); + graph.rectangle(r, true, _m_key_color(key.value)); // scaled ok by graphics if (key_types::character == key.type || key_types::digital == key.type || key_types::symbol == key.type) { diff --git a/source/gui/detail/window_layout.cpp b/source/gui/detail/window_layout.cpp index c742053b7..c105a9264 100644 --- a/source/gui/detail/window_layout.cpp +++ b/source/gui/detail/window_layout.cpp @@ -1,4 +1,4 @@ -/* +/** * Window Layout Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * -* @file: nana/gui/detail/window_layout.hpp +* @file nana/gui/detail/window_layout.hpp * */ @@ -85,9 +85,9 @@ namespace nana _m_paste_children(wd, false, false, rectangle{ wd->pos_root, wd->dimension }, graph, wd->pos_root); } - //read_visual_rectangle + /// read_visual_rectangle ///@brief Reads the visual rectangle of a window, the visual rectangle's reference frame is to root widget, - /// the visual rectangle is a rectangular block that a window should be displayed on screen. + /// the visual rectangle is a rectangular block that a window should display on screen. /// The result is a rectangle that is a visible area for its ancestors. bool window_layout::read_visual_rectangle(basic_window* wd, nana::rectangle& visual) { @@ -97,8 +97,8 @@ namespace nana if (category::flags::root != wd->other.category) { - //Test if the root widget is overlapped the specified widget - //the pos of root widget is (0, 0) + // Test if the root widget is overlapped the specified widget + // the pos of root widget is (0, 0) if (overlapped(visual, rectangle{ wd->root_widget->pos_owner, wd->root_widget->dimension }) == false) return false; @@ -218,16 +218,22 @@ namespace nana return true; } - //make_bground - // update the glass buffer of a glass window. - void window_layout::make_bground(basic_window* const wd) - { - nana::point rpos{ wd->pos_root }; - auto & glass_buffer = wd->other.glass_buffer; + /// make_bground + /// update the glass buffer of a glass window. + void window_layout::make_bground(basic_window* const wd) + { + + nana::point rpos{ wd->pos_root }; // root position of the widget + + auto & glass_buffer = wd->other.glass_buffer; // reference the glass graphic buffer of the widget + // The parent of the widget is a lite_widget (has no drawer graphic self)? if (category::flags::lite_widget == wd->parent->other.category) { - std::vector layers; + // store the layers of lite widgets up in the tree of widgets until a root widget with a drawer graphic is found + std::vector layers; + + // Traverse up the parent hierarchy until a non-lite widget is found auto beg = wd->parent; while (beg && (category::flags::lite_widget == beg->other.category)) { @@ -235,59 +241,82 @@ namespace nana beg = beg->parent; } - glass_buffer.bitblt(::nana::rectangle{ wd->dimension }, beg->drawer.graphics, wd->pos_root - beg->pos_root); + // Copy the corresponding part of the graphics of the parent widget to pos(0,0) of the the glass graphics buffer + glass_buffer.bitblt( ::nana::rectangle{ wd->dimension }, + beg->drawer.graphics, + wd->pos_root - beg->pos_root); - nana::rectangle r(wd->pos_owner, wd->dimension); - for (auto i = layers.rbegin(), layers_rend = layers.rend(); i != layers_rend; ++i) + nana::rectangle r(wd->pos_owner, wd->dimension); // represent the 'base' lite widget rectangle but in onwer coordinates + + // Traverse the layers of lite widgets in reverse order + for (auto i = layers.rbegin(), + layers_rend = layers.rend (); i != layers_rend; ++i) { auto pre = *i; - if (false == pre->visible) - continue; + if (false == pre->visible) continue; // Skip if the lite widget is not visible + r.position(wd->pos_root - pre->pos_root); // adjust the position current widget + // if this is the last lite_widget take wd, if not, take the next auto term = ((i + 1 != layers_rend) ? *(i + 1) : wd); - r.position(wd->pos_root - pre->pos_root); + // Traverse the children of the current lite widget for (auto child : pre->children) { - if (child->index >= term->index) - break; - - nana::rectangle ovlp; - if (child->visible && overlap(r, rectangle(child->pos_owner, child->dimension), ovlp)) + // Break the loop if the child's index is greater than or equal to the termination point's index + if (child->index >= term->index) break; + + nana::rectangle ovlp; // represent the overlap between the child and the current lite widget + // Check if the child is visible and overlaps with the current lite widget + if (child->visible && overlap(r, rectangle(child->pos_owner, child->dimension), ovlp)) { + // Copy the graphics of not lite_widget child to the glass buffer if (category::flags::lite_widget != child->other.category) - glass_buffer.bitblt(nana::rectangle(ovlp.x - pre->pos_owner.x, ovlp.y - pre->pos_owner.y, ovlp.width, ovlp.height), child->drawer.graphics, nana::point(ovlp.x - child->pos_owner.x, ovlp.y - child->pos_owner.y)); + glass_buffer.bitblt(nana::rectangle(ovlp.x - pre->pos_owner.x, ovlp.y - pre->pos_owner.y, ovlp.width, ovlp.height), + child->drawer.graphics, + nana::point(ovlp.x - child->pos_owner.x, ovlp.y - child->pos_owner.y)); ovlp.x += pre->pos_root.x; ovlp.y += pre->pos_root.y; + // Recursively paste the children of the child to the glass buffer _m_paste_children(child, false, false, ovlp, glass_buffer, rpos); } } } } else - glass_buffer.bitblt(::nana::rectangle{ wd->dimension }, wd->parent->drawer.graphics, wd->pos_owner); + // Copy the graphics of the parent widget to the glass buffer + glass_buffer.bitblt(::nana::rectangle{ wd->dimension }, + wd->parent->drawer.graphics, + wd->pos_owner); + // represent the current window but in client owner's coordinates: OC_US = WC_US of the owner const rectangle r_of_wd{ wd->pos_owner, wd->dimension }; + // Traverse the siblings of the current window for (auto child : wd->parent->children) { - if (child->index >= wd->index) - break; + // Break the loop if the child's index is greater than or equal to the current window's index: break on me or pass: process only previous to me + if (child->index >= wd->index) break; + // Create a rectangle to represent the overlap between the child and the current window nana::rectangle ovlp; + // Check if the child is visible and overlaps with the current window if (child->visible && overlap(r_of_wd, rectangle{ child->pos_owner, child->dimension }, ovlp)) { + // Copy the graphics of the not lite_widget child to the glass buffer if (category::flags::lite_widget != child->other.category) - glass_buffer.bitblt(nana::rectangle{ ovlp.x - wd->pos_owner.x, ovlp.y - wd->pos_owner.y, ovlp.width, ovlp.height }, child->drawer.graphics, {ovlp.position() - child->pos_owner}); + glass_buffer.bitblt(nana::rectangle{ ovlp.x - wd->pos_owner.x, ovlp.y - wd->pos_owner.y, ovlp.width, ovlp.height }, + child->drawer.graphics, + {ovlp.position() - child->pos_owner}); ovlp.x += wd->parent->pos_root.x; ovlp.y += wd->parent->pos_root.y; + // Recursively paste the children of the child to the glass buffer _m_paste_children(child, false, false, ovlp, glass_buffer, rpos); } } - if (wd->effect.bground) - wd->effect.bground->take_effect(wd, glass_buffer); - } + // Apply the background effect to the glass buffer if it exists + if (wd->effect.bground) wd->effect.bground->take_effect(wd, glass_buffer); + } void window_layout::_m_paste_children(basic_window* wd, bool have_refreshed, bool req_refresh_children, const nana::rectangle& parent_rect, nana::paint::graphics& graph, const nana::point& graph_rpos) { diff --git a/source/gui/detail/window_manager.cpp b/source/gui/detail/window_manager.cpp index dcc4ae1f5..697d84fdc 100644 --- a/source/gui/detail/window_manager.cpp +++ b/source/gui/detail/window_manager.cpp @@ -1,4 +1,4 @@ -/* +/** * Window Manager Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2022 Jinhao(cnjinhao@hotmail.com) @@ -7,12 +7,16 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/detail/window_manager.cpp + * @file nana/gui/detail/window_manager.cpp * @list of contributions: * Katsuhisa Yuasa, * wwriter, added a feature: disabling tabstop(#626) */ +#include +#include +#include + #include #include #include @@ -25,10 +29,6 @@ #include "window_register.hpp" #include "inner_fwd_implement.hpp" -#include -#include -#include - namespace nana { @@ -145,9 +145,9 @@ namespace nana other.wpassoc = nullptr; //moved-from } - root_misc::root_misc(basic_window * wd, unsigned width, unsigned height) + root_misc::root_misc(basic_window * wd, const size& sz) : window(wd), - root_graph({ width, height }) + root_graph(sz, wd->dpi) { condition.ignore_tab = false; condition.pressed = nullptr; @@ -366,7 +366,10 @@ namespace detail auto result = native_interface::create_window(native, nested, r, app); if (result.native_handle) { - auto wd = new basic_window(owner, widget_notifier_interface::get_notifier(wdg), (category::root_tag**)nullptr); + auto wd = new basic_window(owner, + widget_notifier_interface::get_notifier(wdg), + (category::root_tag**)nullptr, + result.dpi); if (nested) { wd->owner = nullptr; @@ -381,9 +384,10 @@ namespace detail internal_scope_guard lock; //create Root graphics Buffer and manage it - auto* value = impl_->misc_register.insert(result.native_handle, root_misc(wd, result.width, result.height)); + auto* value = impl_->misc_register.insert(result.native_handle, root_misc(wd, result.client_size)); - wd->bind_native_window(result.native_handle, result.width, result.height, result.extra_width, result.extra_height, value->root_graph); + wd->bind_native_window(result.native_handle, result.client_size.width, result.client_size.height, + result.extra_width, result.extra_height, value->root_graph); impl_->wd_register.insert(wd); bedrock::inc_window(wd->thread_id); @@ -400,15 +404,23 @@ namespace detail throw std::invalid_argument("invalid parent/owner handle"); if (parent->flags.destroying) - throw std::logic_error("the specified parent is destory"); + throw std::logic_error("the specified parent is destroying"); auto wdg_notifier = widget_notifier_interface::get_notifier(wdg); basic_window * wd; if (is_lite) - wd = new basic_window(parent, std::move(wdg_notifier), r, (category::lite_widget_tag**)nullptr); + wd = new basic_window(parent, + std::move(wdg_notifier), + r, + (category::lite_widget_tag**)nullptr, + parent->dpi); else - wd = new basic_window(parent, std::move(wdg_notifier), r, (category::widget_tag**)nullptr); + wd = new basic_window(parent, + std::move(wdg_notifier), + r, + (category::widget_tag**)nullptr, + parent->dpi); impl_->wd_register.insert(wd); return wd; @@ -460,7 +472,7 @@ namespace detail internal_scope_guard lock; if (impl_->wd_register.available(wd) == false) return; - rectangle update_area(wd->pos_owner, wd->dimension); + rectangle update_area(wd->pos_owner, wd->dimension); // user-side auto parent = wd->parent; if (parent) @@ -474,8 +486,8 @@ namespace detail update_area.y += parent->pos_owner.y; parent = parent->parent; } - - update(parent, false, false, &update_area); + // update_area = unscale_dpi(update_area, wd->dpi); + update(parent, false, false, &update_area); // user-side } void window_manager::destroy_handle(basic_window* wd) @@ -511,8 +523,7 @@ namespace detail } } - //show - //@brief: show or hide a window + /// show or hide a window bool window_manager::show(basic_window* wd, bool visible) { internal_scope_guard lock; @@ -573,7 +584,7 @@ namespace detail return attr_.capture.window; } - //move the wnd and its all children window, x and y is a relatively coordinate for wnd's parent window + /// move the wnd and all its children window, x and y are relative coordinate to wnd's parent window bool window_manager::move(basic_window* wd, int x, int y, bool passive) { internal_scope_guard lock; @@ -634,6 +645,7 @@ namespace detail const bool size_changed = (r.width != wd->dimension.width || r.height != wd->dimension.height); if(category::flags::root != wd->other.category) { + // wd is not a root window: move the window and its children (the system will not move any of then) //Move child widgets if(r.x != wd->pos_owner.x || r.y != wd->pos_owner.y) { @@ -750,8 +762,8 @@ namespace detail } //Before resizing the window, creates the new graphics - paint::graphics graph; - paint::graphics root_graph; + paint::graphics graph(wd->dpi); + paint::graphics root_graph(wd->dpi); if (category::flags::lite_widget != wd->other.category) { //If allocation fails, here throws std::bad_alloc. @@ -828,18 +840,19 @@ namespace detail return nullptr; } - //Copy the root buffer that wnd specified into DeviceContext + /// Copy the root buffer that wd specified into DeviceContext void window_manager::map(basic_window* wd, bool forced, const rectangle* update_area) { internal_scope_guard lock; if (impl_->wd_register.available(wd) && !wd->is_draw_through()) - bedrock::instance().flush_surface(wd, forced, update_area); + bedrock::instance().flush_surface(wd, forced, update_area); // used to PostMessage, no dpi scaling needed } - //update - //@brief: update is used for displaying the screen-off buffer. - // Because of a good efficiency, if it is called in an event procedure and the event procedure window is the - // same as update's, update would not map the screen-off buffer and just set the window for lazy refresh + + /// for displaying the screen-off buffer. + /// + /// for better efficiency, if it is called in an event procedure and the event procedure window is the + /// same as update's, update would not map the screen-off buffer and just set the window for lazy refresh bool window_manager::update(basic_window* wd, bool redraw, bool forced, const rectangle* update_area) { internal_scope_guard lock; @@ -1108,7 +1121,7 @@ namespace detail if (!this->available(wd)) return; - nana::point pos = native_interface::cursor_position(); + nana::point pos = native_interface::cursor_screen_position(); auto & attr_cap = attr_.capture.history; if (captured) @@ -1375,11 +1388,10 @@ namespace detail if (!available(wd)) return; - auto info = wd->drawer.graphics.typeface().info(); - - nana::paint::font ft{ info.value(), native_interface::window_dpi(wd->root) }; - - wd->drawer.graphics.typeface(ft); + wd->dpi = native_interface::window_dpi(wd->root); + wd->drawer.graphics.set_dpi(wd->dpi); + ///\todo: glass_buffer and root_graphics need to be updated too. + /// implement a wd->update_dpi(dpi) method to update all the window elements. for (auto child : wd->children) { @@ -1524,6 +1536,7 @@ namespace detail { wd->parent = for_new; wd->root = for_new->root; + wd->dpi = for_new->dpi; wd->root_graph = for_new->root_graph; wd->root_widget = for_new->root_widget; @@ -1547,6 +1560,7 @@ namespace detail else { child->root = wd->root; + child->dpi = wd->dpi; child->root_graph = wd->root_graph; child->root_widget = wd->root_widget; set_pos_root(child, delta_pos); diff --git a/source/gui/detail/window_register.hpp b/source/gui/detail/window_register.hpp index 965a1afac..6e78571d0 100644 --- a/source/gui/detail/window_register.hpp +++ b/source/gui/detail/window_register.hpp @@ -1,11 +1,24 @@ +/** + * window_register Implementation + * Nana C++ Library(http://www.nanapro.org) + * Copyright(C) 2003-2024 Jinhao(cnjinhao@hotmail.com) + * + * Distributed under the Boost Software License, Version 1.0. + * (See accompanying file LICENSE_1_0.txt or copy at + * http://www.boost.org/LICENSE_1_0.txt) + * + * @file nana/source/gui/detail/window_register.hpp + */ + #ifndef NANA_WINDOW_REGISTER_HEADER_INCLUDED #define NANA_WINDOW_REGISTER_HEADER_INCLUDED -#include "basic_window.hpp" #include #include #include //std::find +#include "basic_window.hpp" + namespace nana { namespace detail @@ -101,8 +114,8 @@ namespace nana return nana::npos; } private: - char bitmap_[CacheSize]; - size_type seq_[CacheSize]; + char bitmap_[CacheSize]; + size_type seq_[CacheSize]; pair_type * addr_; }; diff --git a/source/gui/dragdrop.cpp b/source/gui/dragdrop.cpp index 5852eb968..0bb195c42 100644 --- a/source/gui/dragdrop.cpp +++ b/source/gui/dragdrop.cpp @@ -250,7 +250,7 @@ namespace nana //bool found_data = false; if (simple_mode_) { - auto hovered_wd = api::find_window(point(pt.x, pt.y)); + auto hovered_wd = api::find_window_from_system_screen_point(point(pt.x, pt.y)); if ((hovered_wd && (hovered_wd == this->current_source())) || this->has(this->current_source(), hovered_wd)) *req_effect &= DROPEFFECT_COPY; @@ -770,7 +770,7 @@ using win32_dropdata = win32com_iunknown; if (MotionNotify == msg_pkt.u.xevent.type) { auto pos = api::cursor_position(); - auto native_cur_wd = reinterpret_cast(detail::native_interface::find_window(pos.x, pos.y)); + auto native_cur_wd = reinterpret_cast(detail::native_interface::find_window_from_system_screen_point(pos)); const char* icon = nullptr; if(hovered_.native_wd != native_cur_wd) @@ -786,7 +786,7 @@ using win32_dropdata = win32com_iunknown; } - auto cur_wd = api::find_window(api::cursor_position()); + auto cur_wd = api::find_window_from_system_screen_point(api::cursor_position()); if(hovered_.window_handle != cur_wd) { @@ -831,7 +831,7 @@ using win32_dropdata = win32com_iunknown; if (MotionNotify == msg_pkt.u.xevent.type) { auto pos = api::cursor_position(); - auto native_cur_wd = reinterpret_cast(detail::native_interface::find_window(pos.x, pos.y)); + auto native_cur_wd = reinterpret_cast(detail::native_interface::find_window_from_system_screen_point(pos)); xdnd_proto.mouse_move(native_cur_wd, pos, data.requested_action); } @@ -1029,7 +1029,7 @@ using win32_dropdata = win32com_iunknown; if (has_dropped) { - auto drop_wd = api::find_window(api::cursor_position()); + auto drop_wd = api::find_window_cursor(); auto i = impl_->targets.find(drop_wd); if ((impl_->targets.end() != i) && i->second) i->second(); diff --git a/source/gui/drawing.cpp b/source/gui/drawing.cpp index 836f31475..e884e1686 100644 --- a/source/gui/drawing.cpp +++ b/source/gui/drawing.cpp @@ -1,4 +1,4 @@ -/* +/** * A Drawing Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/drawing.cpp + * @file nana/gui/drawing.cpp */ #ifndef NANA_DRAWING_REMOVED diff --git a/source/gui/filebox.cpp b/source/gui/filebox.cpp index 230c965cd..401db0c94 100644 --- a/source/gui/filebox.cpp +++ b/source/gui/filebox.cpp @@ -494,7 +494,7 @@ namespace nana void _m_layout() { unsigned ascent, desent, ileading; - paint::graphics{nana::size{1, 1}}.text_metrics(ascent, desent, ileading); + paint::graphics{nana::size{1, 1}, api::window_dpi(this->handle())}.text_metrics(ascent, desent, ileading); auto text_height = ascent + desent + 16; place_.bind(*this); diff --git a/source/gui/layout_utility.cpp b/source/gui/layout_utility.cpp index 8af0cf8a9..a69073ab5 100644 --- a/source/gui/layout_utility.cpp +++ b/source/gui/layout_utility.cpp @@ -1,4 +1,4 @@ -/* +/** * Utility Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/layout_utility.hpp + * @file nana/gui/layout_utility.hpp * @contributors: Ryan Gonzalez * */ @@ -15,7 +15,7 @@ namespace nana { - //overlap test if overlapped between r1 and r2 + /// overlap test if overlapped between r1 and r2 bool overlapped(const rectangle& r1, const rectangle& r2) { if (r1.y + (long long)(r1.height) <= r2.y) return false; @@ -27,7 +27,7 @@ namespace nana return true; } - //overlap, compute the overlap area between r1 and r2. the rect is for root + /// overlap, compute the overlap area between r1 and r2. the rect is for root bool overlap(const rectangle& r1, const rectangle& r2, rectangle& r) { if(overlapped(r1, r2)) diff --git a/source/gui/msgbox.cpp b/source/gui/msgbox.cpp index 376cd86cd..3e734178d 100644 --- a/source/gui/msgbox.cpp +++ b/source/gui/msgbox.cpp @@ -704,7 +704,7 @@ namespace nana impl->dock.create(owner); - paint::graphics graph{ ::nana::size{ 10, 10 } }; + paint::graphics graph{ ::nana::size{ 10, 10 }, api::window_dpi(owner) }; auto value_px = graph.text_extent_size(impl->label_text).width + 20; impl->checkbox.create(impl->dock, rectangle{ (std::max)(static_cast(label_px) - 18, 0), 0, value_px, 0 }); @@ -726,7 +726,7 @@ namespace nana unsigned inputbox::boolean::fixed_pixels() const { - paint::graphics graph{ ::nana::size{ 10, 10 } }; + paint::graphics graph{ ::nana::size{ 10, 10 } , api::window_dpi(this->impl_->dock.handle())}; return graph.text_extent_size(impl_->label_text).width; } @@ -807,7 +807,7 @@ namespace nana { //get the longest value int longest = (std::abs(static_cast(impl_->begin < 0 ? impl_->begin * 10 : impl_->begin)) < std::abs(static_cast(impl_->last < 0 ? impl_->last * 10 : impl_->last)) ? impl_->last : impl_->begin); - paint::graphics graph{ ::nana::size{ 10, 10 } }; + paint::graphics graph{ ::nana::size{ 10, 10 }, api::window_dpi(this->impl_->dock.handle())}; return graph.text_extent_size(std::to_wstring(longest)).width + 34; } //end class integer @@ -890,7 +890,7 @@ namespace nana { //get the longest value auto longest = (std::abs(static_cast(impl_->begin < 0 ? impl_->begin * 10 : impl_->begin)) < std::abs(static_cast(impl_->last < 0 ? impl_->last * 10 : impl_->last)) ? impl_->last : impl_->begin); - paint::graphics graph{ ::nana::size{ 10, 10 } }; + paint::graphics graph{ ::nana::size{ 10, 10 } , api::window_dpi(this->impl_->dock.handle())}; return graph.text_extent_size(std::to_wstring(longest)).width + 34; } //end class real @@ -1015,7 +1015,7 @@ namespace nana if (impl_->options.empty()) return 0; - paint::graphics graph{ ::nana::size{ 10, 10 } }; + paint::graphics graph{ ::nana::size{ 10, 10 } , api::window_dpi(this->impl_->dock.handle())}; unsigned long_px = 0; //get the longest value for (auto & s : impl_->options) @@ -1309,7 +1309,7 @@ namespace nana { std::vector each_pixels; unsigned label_px = 0, fixed_px = 0; - paint::graphics graph({ 5, 5 }); + paint::graphics graph({ 5, 5 }, api::window_dpi(owner_)); bool has_0_fixed_px = false; for (auto p : contents) diff --git a/source/gui/place.cpp b/source/gui/place.cpp index 99f4c6034..b2efacf32 100644 --- a/source/gui/place.cpp +++ b/source/gui/place.cpp @@ -406,7 +406,7 @@ namespace nana return sp; } - //Parses unit. It returns unit string and modifies the sp to the next character of unit string if it parses successfully. + /// Parses unit, It returns unit string and modifies the sp to the next character of unit string if it parses successfully. std::string _m_unit(const char*& sp) noexcept { auto const start = sp; @@ -948,7 +948,7 @@ namespace nana else { double precise_px = 0; - fv += gap_value.get_value(100, 0, precise_px, dm, false); + fv += gap_value.get_value(100, 0, precise_px, dm, false); /// \todo: dpi to_system_px? } } @@ -1087,7 +1087,7 @@ namespace nana if (!div->min_px.empty()) { - auto v = div->min_px.get_value(static_cast(area_px), dm); + auto v = div->min_px.get_value(static_cast(area_px), dm); /// \todo: dpi to_system_px? if ((weight_floor > 0) && (v < weight_floor)) v = weight_floor; @@ -1100,7 +1100,7 @@ namespace nana if (!div->max_px.empty()) { - auto v = div->max_px.get_value(static_cast(area_px), dm); + auto v = div->max_px.get_value(static_cast(area_px), dm); /// \todo: dpi to_system_px? if (px > v) return v; } @@ -1205,9 +1205,9 @@ namespace nana rectangle_rotator area(vert, area_margined); auto area_px = area.w(); - auto fa = _m_fixed_and_adjustable(kind_of_division, area_px, dm); // fixed pixels and number of adjustable items + auto fa = _m_fixed_and_adjustable(kind_of_division, area_px, dm); // fixed pixels and number of adjustable items, /// \todo: dpi to_system_px? - double adjustable_px = _m_revise_adjustable(fa, area_px, dm); // amount of pixels for each adjustable item + double adjustable_px = _m_revise_adjustable(fa, area_px, dm); // amount of pixels for each adjustable item /// \todo: dpi to_system_px? double position = area.x(); std::vector delay_collocates; @@ -1232,7 +1232,7 @@ namespace nana else child_px = adjustable_px; - child_px = limit_px(child, child_px, area_px, dm); + child_px = limit_px(child, child_px, area_px, dm); /// \todo: dpi to_system_px? auto npx = static_cast(child_px); precise_px = child_px - npx; @@ -1241,7 +1241,7 @@ namespace nana else { // the child weight is a fixed value, therefore, the 1st parameter of get_value is useless. - child_px = static_cast(child->weight.get_value(0, dm)); + child_px = static_cast(child->weight.get_value(0, dm)); /// \todo: dpi to_system_px? } //Use 'endpos' to calc width is to avoid deviation @@ -1348,7 +1348,7 @@ namespace nana auto count = field->elements.size(); for (decltype(count) i = 0; i < count; ++i) { - auto fa = _m_calc_fa(arrange_.at(i), area_px, precise_px, dm); + auto fa = _m_calc_fa(arrange_.at(i), area_px, precise_px, dm); /// \todo: dpi to_system_px? //The fit-content element is like a fixed element if (fit_policy::none != this->fit) @@ -1366,7 +1366,7 @@ namespace nana if (i + 1 < count) { - fa = _m_calc_fa(gap.at(i), area_px, precise_px, dm); + fa = _m_calc_fa(gap.at(i), area_px, precise_px, dm); /// \todo: dpi to_system_px? result.first += fa.first; //fa.second is ignored for gap, because the it has not the adjustable gap. } @@ -1380,7 +1380,7 @@ namespace nana continue; if (!child->weight.empty()) - children_fixed_px += child->weight.get_value(area_px, dm); + children_fixed_px += child->weight.get_value(area_px, dm); /// \todo: dpi to_system_px? else ++result.second; } @@ -1454,7 +1454,7 @@ namespace nana max_px = std::numeric_limits::lowest(); if (!child->min_px.empty()) - min_px = child->min_px.get_value(static_cast(area_px), dm); + min_px = child->min_px.get_value(static_cast(area_px), dm); /// \todo: dpi to_system_px? auto weight_floor = (this->kind_of_division == kind::arrange ? child->run_.weight_floor.first : child->run_.weight_floor.second); if ((weight_floor > 0) && (min_px < weight_floor)) @@ -1467,7 +1467,7 @@ namespace nana } if (!child->max_px.empty()) - max_px = child->max_px.get_value(static_cast(area_px), dm); + max_px = child->max_px.get_value(static_cast(area_px), dm); /// \todo: dpi to_system_px? if (min_px >= 0 && max_px >= 0 && min_px > max_px) { @@ -1838,14 +1838,14 @@ namespace nana auto left_px = std::clamp(static_cast(left_pixels_) + delta, 0, total_pixels); - auto area_px = rectangle_rotator(vert, div_owner->margin_area(dm)).w(); + auto area_px = rectangle_rotator(vert, div_owner->margin_area(dm)).w(); /// \todo: dpi to_system_px? double imd_rate = 100.0 / area_px; - left_px = static_cast(limit_px(leaf_left, left_px, area_px, dm)); + left_px = static_cast(limit_px(leaf_left, left_px, area_px, dm)); /// \todo: dpi to_system_px? leaf_left->weight.assign_percent(imd_rate * left_px); auto right_px = std::clamp(static_cast(right_pixels_) - delta, 0, total_pixels); - right_px = static_cast(limit_px(leaf_right, right_px, area_px, dm)); + right_px = static_cast(limit_px(leaf_right, right_px, area_px, dm)); /// \todo: dpi to_system_px? leaf_right->weight.assign_percent(imd_rate * right_px); pause_move_collocate_ = true; @@ -1865,8 +1865,8 @@ namespace nana events.mouse_move.connect_unignorable(grab_fn); } - const place_parts::display_metrics dm{ wd }; - auto limited_range = _m_update_splitter_range(dm); + const place_parts::display_metrics dm{ wd }; /// \todo: dpi to_system_px? + auto limited_range = _m_update_splitter_range(dm); /// \todo: dpi to_system_px? if (!init_weight_.empty()) { @@ -1877,7 +1877,7 @@ namespace nana rectangle_rotator left(vert, leaf_left->field_area); rectangle_rotator right(vert, leaf_right->field_area); auto area_px = right.right() - left.x(); - auto right_px = static_cast(limit_px(leaf_right, init_weight_.get_value(area_px, dm), static_cast(area_px), dm)); + auto right_px = static_cast(limit_px(leaf_right, init_weight_.get_value(area_px, dm), static_cast(area_px), dm)); /// \todo: dpi to_system_px? //New position of splitter const auto pos = std::clamp(static_cast(area_px - right_px - splitter_px), limited_range.x(), limited_range.right()); @@ -2075,7 +2075,7 @@ namespace nana { const bool vert = (cursor::size_ns == splitter_cursor_); - rectangle_rotator area(vert, div_owner->margin_area(dm)); + rectangle_rotator area(vert, div_owner->margin_area(dm)); /// \todo: dpi to_system_px? auto leaf_left = _m_leaf(true); auto leaf_right = _m_leaf(false); @@ -2088,16 +2088,16 @@ namespace nana int endpos = right_base; if (!leaf_left->min_px.empty()) - pos += static_cast(leaf_left->min_px.get_value(area.w(), dm)); + pos += static_cast(leaf_left->min_px.get_value(area.w(), dm)); /// \todo: dpi to_system_px? if (!leaf_left->max_px.empty()) - endpos = left_base + static_cast(leaf_left->max_px.get_value(area.w(), dm)); + endpos = left_base + static_cast(leaf_left->max_px.get_value(area.w(), dm)); /// \todo: dpi to_system_px? if (!leaf_right->min_px.empty()) - endpos = (std::min)(right_base - static_cast(leaf_right->min_px.get_value(area.w(), dm)), endpos); + endpos = (std::min)(right_base - static_cast(leaf_right->min_px.get_value(area.w(), dm)), endpos); /// \todo: dpi to_system_px? if (!leaf_right->max_px.empty()) - pos = (std::max)(right_base - static_cast(leaf_right->max_px.get_value(area.w(), dm)), pos); + pos = (std::max)(right_base - static_cast(leaf_right->max_px.get_value(area.w(), dm)), pos); /// \todo: dpi to_system_px? area.x_ref() = pos; area.w_ref() = unsigned(endpos - pos + splitter_px); @@ -2514,7 +2514,7 @@ namespace nana double weight; if (!child->weight.empty()) { - weight = child->weight.get_value(is_vert ? room.height : room.width, dm); + weight = child->weight.get_value(is_vert ? room.height : room.width, dm); /// \todo: dpi to_system_px? if (weight > room_px) weight = room_px; } @@ -2652,7 +2652,7 @@ namespace nana if (child->display) { div = child.get(); - div->field_area = this->margin_area(dm); + div->field_area = this->margin_area(dm); div->collocate(wd); break; } @@ -3045,7 +3045,7 @@ namespace nana //2, max >= min if (min_px.is_negative()) min_px.reset(); if (max_px.is_negative()) max_px.reset(); - if ((!min_px.empty()) && (!max_px.empty()) && (min_px.get_value(100, dm) > max_px.get_value(100, dm))) //use a fixed dpi value for comparing two values. + if ((!min_px.empty()) && (!max_px.empty()) && (min_px.get_value(100, dm) > max_px.get_value(100, dm))) //use a fixed dpi value for comparing two values. /// \todo: dpi to_system_px? { min_px.reset(); max_px.reset(); @@ -3058,10 +3058,10 @@ namespace nana div->max_px = max_px; // use a fixed dpi for comparing values - if ((!min_px.empty()) && (!weight.empty()) && (weight.get_value(100, dm) < min_px.get_value(100, dm))) + if ((!min_px.empty()) && (!weight.empty()) && (weight.get_value(100, dm) < min_px.get_value(100, dm))) /// \todo: dpi to_system_px? weight.reset(); - if ((!max_px.empty()) && (!weight.empty()) && (weight.get_value(100, dm) > max_px.get_value(100, dm))) + if ((!max_px.empty()) && (!weight.empty()) && (weight.get_value(100, dm) > max_px.get_value(100, dm))) /// \todo: dpi to_system_px? weight.reset(); if (!weight.empty()) diff --git a/source/gui/place_parts.hpp b/source/gui/place_parts.hpp index 2b710ff29..10f20dd5c 100644 --- a/source/gui/place_parts.hpp +++ b/source/gui/place_parts.hpp @@ -12,12 +12,13 @@ #ifndef NANA_GUI_PLACE_PARTS_HPP #define NANA_GUI_PLACE_PARTS_HPP +#include +#include + #include #include #include #include -#include -#include namespace nana { @@ -475,28 +476,29 @@ namespace nana }moves_; };//class dockarea - /// \todo: generalize dpi to v2 awareness + /// \todo: eliminate this ?! struct display_metrics { - std::size_t dpi; + std::size_t dpi{96u}; double font_px{ 0 }; - display_metrics(window wd) : - dpi(api::window_dpi(wd)) + display_metrics(window wd) /// \todo: dpi to_system_px?: dpi(api::window_dpi(wd)) { - auto font_info = api::typeface(wd).info(); + auto font_info = api::typeface(wd).info(); // ask dinamicaly and not keee here? if (font_info) - font_px = font_info->size_pt * dpi / 72; + font_px = (font_info->size_pt * dpi) / 72.0; } }; - //number_t is used for storing a number type variable - //such as integer, real and percent. Essentially, percent is a typo of real. + /// storing a number type variable, such as integer, real and percent, where essentially, percent is a type of real. class number_t { public: enum class kind{ none, integer, real, percent }; - enum class units{medium, px, em}; + enum class units{ medium, ///< scalable? Copilot: The default unit, it is used for the value of margin, padding, and gap. + px, ///< fixed in px? Copilot: The pixel unit, it is used for the value of width, height, and size. + em ///< in font px? Copilot: The em unit, it is used for the value of font-size. + }; number_t() { @@ -543,12 +545,12 @@ namespace nana return 0; } - if (to_system_px) + if (to_system_px) /// \todo: eliminate ? { switch (unit_) { case units::medium: - return val * dm.dpi / 96; + return val; /// \todo: ? * dm.dpi / 96; case units::px: return val; case units::em: @@ -562,9 +564,9 @@ namespace nana case units::medium: return val; case units::px: - return val * 96 / dm.dpi; + return val; /// \todo: ? * 96 / dm.dpi; case units::em: - return val * dm.font_px * 96 / dm.dpi; + return val * dm.font_px; /// \todo: ? * 96 / dm.dpi; } } return 0; @@ -584,7 +586,7 @@ namespace nana return px; } - return get_value(0, dm, to_system_px); + return get_value(0, dm, to_system_px); /// \todo: to_system_px? } int integer() const noexcept @@ -766,27 +768,27 @@ namespace nana if (0 == it) //top { - auto px = static_cast(margins_[it].get_value(static_cast(field_area.height), dm, true)); + auto px = static_cast(margins_[it].get_value(static_cast(field_area.height), dm, true)); /// \todo: dpi to_system_px? r.y += px; r.height = differ(r.height, static_cast(px)); } if (-1 != ib) //bottom { - auto px = static_cast(margins_[ib].get_value(static_cast(field_area.height), dm, true)); + auto px = static_cast(margins_[ib].get_value(static_cast(field_area.height), dm, true)); /// \todo: dpi to_system_px? r.height = differ(r.height, static_cast(px)); } if (-1 != il) //left { - auto px = static_cast(margins_[il].get_value(static_cast(field_area.width), dm, true)); + auto px = static_cast(margins_[il].get_value(static_cast(field_area.width), dm, true)); /// \todo: dpi to_system_px? r.x += px; r.width = differ(r.width, static_cast(px)); } if (-1 != ir) //right { - auto px = static_cast(margins_[ir].get_value(static_cast(field_area.width), dm, true)); + auto px = static_cast(margins_[ir].get_value(static_cast(field_area.width), dm, true)); /// \todo: dpi to_system_px? r.width = differ(r.width, static_cast(px)); } } diff --git a/source/gui/programming_interface.cpp b/source/gui/programming_interface.cpp index 7330a2849..7c4a69435 100644 --- a/source/gui/programming_interface.cpp +++ b/source/gui/programming_interface.cpp @@ -262,6 +262,7 @@ namespace api internal_scope_guard lock; if(is_window(wd)) { + wd->drawer.graphics.set_dpi(wd->dpi); ///\todo: make(wd->dimension, wd->dpi) wd->drawer.graphics.make(wd->dimension); wd->drawer.graphics.rectangle(true, wd->annex.scheme->background.get_color()); wd->drawer.attached(wdg, dr); @@ -627,14 +628,15 @@ namespace api ::nana::point cursor_position() { - return interface_type::cursor_position(); + return interface_type::cursor_screen_position(); } + /// generalized to dpi awareness v2 ::nana::rectangle make_center(unsigned width, unsigned height) noexcept { auto screen = interface_type::primary_monitor_size(); if constexpr (dpi_debugging) - std::cout << "API::make_center() on screen: (" << screen.width << ", " << screen.height << ") " << std::endl; + std::cout << "API::make_center() on screen: (" << screen.width << ", " << screen.height << ")\n "; return{ static_cast(width > screen.width ? 0 : (screen.width - width ) >> 1), static_cast(height > screen.height ? 0 : (screen.height - height) >> 1), @@ -921,9 +923,10 @@ namespace api nana::size window_size(window wd) { - nana::rectangle r; - api::get_window_rectangle(wd, r); - return{ r.width, r.height }; + internal_scope_guard lock; + if(is_window(wd)) + return wd->dimension; + return {}; } void window_size(window wd, const size& sz) @@ -1562,9 +1565,21 @@ namespace api return restrict::wd_manager().calc_window_point(wd, pos); } - window find_window(const nana::point& pos) + window find_window_cursor() ///annex.content_measurer) { paint::graphics* graph = &wd->drawer.graphics; - paint::graphics temp_graph; + paint::graphics temp_graph(graph->get_dpi()); if (graph->empty()) { temp_graph.make({ 1, 1 }); @@ -1693,19 +1708,19 @@ namespace api return{}; } - /// \todo: generalize dpi to v2 awareness - unsigned screen_dpi(bool x_requested) + + int screen_dpi(bool x_requested) ///< unused ? { return ::nana::platform_abstraction::screen_dpi(x_requested); } - std::size_t window_dpi(window wd) + int window_dpi(window wd) { internal_scope_guard lock; if (is_window(wd)) return interface_type::window_dpi(wd->root); - return 0; + return 96; } dragdrop_status window_dragdrop_status(::nana::window wd) diff --git a/source/gui/screen.cpp b/source/gui/screen.cpp index e794f1cc8..fac9d1ace 100644 --- a/source/gui/screen.cpp +++ b/source/gui/screen.cpp @@ -1,4 +1,4 @@ -/* +/** * Screen Informations * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2015 Jinhao(cnjinhao@hotmail.com) @@ -7,17 +7,24 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/screen.cpp + * @file nana/gui/screen.cpp */ -#include + #include #include + #include #include +#include + +#include "../detail/platform_abstraction.hpp" + #if defined(NANA_WINDOWS) #include #endif +/// \todo: move all to nana::detail::native_interface in native_window_interface.hpp ??? + namespace nana { //class display @@ -25,14 +32,15 @@ namespace nana : public display { public: - real_display() = default; //For requirement of vector + real_display() = default; // requirement of vector #if defined(NANA_WINDOWS) - real_display(std::size_t number, const MONITORINFOEX& mi) + real_display(std::size_t number, const MONITORINFOEX& mi, int dpi) : index_(number), is_primary_(mi.dwFlags & /*MONITORINFOF_PRIMARY*/ 0x1), - area_(mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top), - workarea_(mi.rcWork.left, mi.rcWork.top, mi.rcWork.right - mi.rcWork.left, mi.rcWork.bottom - mi.rcWork.top) + area_ (mi.rcMonitor.left, mi.rcMonitor.top, mi.rcMonitor.right - mi.rcMonitor.left, mi.rcMonitor.bottom - mi.rcMonitor.top), + workarea_(mi.rcWork.left , mi.rcWork.top , mi.rcWork.right - mi.rcWork.left , mi.rcWork.bottom - mi.rcWork.top), + dpi_(dpi), scale_(dpi / 96.0) { } #else @@ -53,20 +61,33 @@ namespace nana return is_primary_; } - const ::nana::rectangle& area() const override + ::nana::rectangle area() const override { - return area_; + return platform_abstraction::unscale_dpi(area_, dpi_); } - const ::nana::rectangle& workarea() const override + ::nana::rectangle workarea() const override { - return workarea_; + return platform_abstraction::unscale_dpi(workarea_, dpi_); } + + int dpi() const override + { + return dpi_; + } + + double scaling() const override + { + return scale_; + } + private: - std::size_t index_; - bool is_primary_; + std::size_t index_; + bool is_primary_; ::nana::rectangle area_; ::nana::rectangle workarea_; + int dpi_; + double scale_{ 1.0 }; }; //class screen @@ -93,10 +114,31 @@ namespace nana { std::vector displays; + #if defined(NANA_WINDOWS) + + /// \todo: move all to nana::detail::native_interface in native_window_interface.hpp ??? + enum MONITOR_DPI_TYPE { + MDT_EFFECTIVE_DPI, + MDT_ANGULAR_DPI, + MDT_RAW_DPI, + MDT_DEFAULT + }; + using GetDpiForMonitor_ftype = HRESULT(__stdcall*)(HMONITOR, MONITOR_DPI_TYPE, UINT*, UINT*); + inline static GetDpiForMonitor_ftype GetDpiForMonitor { nullptr }; + void load_monitors() { std::vector tmp; + if (!GetDpiForMonitor) + { + HMODULE shcore = ::LoadLibraryA("SHCORE.DLL"); + if (shcore) + { + GetDpiForMonitor = reinterpret_cast(::GetProcAddress(shcore, "GetDpiForMonitor")); + ::FreeLibrary(shcore); + } + } ::EnumDisplayMonitors(nullptr, nullptr, implement::enum_proc, reinterpret_cast(&tmp)); tmp.swap(displays); } @@ -106,8 +148,14 @@ namespace nana auto disp_cont = reinterpret_cast*>(self_ptr); MONITORINFOEX mi; mi.cbSize = sizeof(MONITORINFOEX); - if (::GetMonitorInfo(handle, &mi)) - disp_cont->emplace_back(disp_cont->size(), mi); + if (! ::GetMonitorInfo(handle, &mi)) return TRUE; + int dpi = 96; + + UINT xdpi, ydpi; + LRESULT success = GetDpiForMonitor(handle, MDT_EFFECTIVE_DPI, &xdpi, &ydpi); + if (success == S_OK) dpi = xdpi; + + disp_cont->emplace_back(disp_cont->size(), mi, dpi); return TRUE; } @@ -159,7 +207,7 @@ namespace nana { for (auto & disp : impl_->displays) { - auto & r = disp.area(); + auto r = disp.area(); if (r.x == mi.rcMonitor.left && r.y == mi.rcMonitor.top && r.width == unsigned(mi.rcMonitor.right - mi.rcMonitor.left) && r.height == unsigned(mi.rcMonitor.bottom - mi.rcMonitor.top) diff --git a/source/gui/widgets/button.cpp b/source/gui/widgets/button.cpp index 390276df6..955225be0 100644 --- a/source/gui/widgets/button.cpp +++ b/source/gui/widgets/button.cpp @@ -120,7 +120,7 @@ namespace nana impl_->attr.pushed = pshd; if(false == pshd) { - if (api::find_window(api::cursor_position()) == impl_->wdg->handle()) + if (api::find_window_cursor() == impl_->wdg->handle()) impl_->attr.e_state = element_state::hovered; else impl_->attr.e_state = element_state::normal; diff --git a/source/gui/widgets/combox.cpp b/source/gui/widgets/combox.cpp index 783fbfcb1..a1aa34616 100644 --- a/source/gui/widgets/combox.cpp +++ b/source/gui/widgets/combox.cpp @@ -225,7 +225,7 @@ namespace nana if (api::is_transparent_background(this->widget_ptr()->handle())) { - paint::graphics trns_graph{ graph.size() }; + paint::graphics trns_graph{ graph.size(), graph.get_dpi() }; if (api::dev::copy_transparent_background(this->widget_ptr()->handle(), trns_graph)) { graph.blend(rectangle{ trns_graph.size() }, trns_graph, {}, 0.5); @@ -527,9 +527,9 @@ namespace nana size_t _m_button_size() { - double dpiScale = api::window_dpi(widget_->handle()) / 96.0; - - return static_cast(scheme_ptr_->button_size * dpiScale); + //double dpiScale = api::window_dpi(widget_->handle()) / 96.0; + /// \todo DPI ? + return scheme_ptr_->button_size; //static_cast(scheme_ptr_->button_size * dpiScale); } void _m_draw_push_button(bool enabled) diff --git a/source/gui/widgets/date_chooser.cpp b/source/gui/widgets/date_chooser.cpp index e06e5909e..722ea9d74 100644 --- a/source/gui/widgets/date_chooser.cpp +++ b/source/gui/widgets/date_chooser.cpp @@ -87,8 +87,8 @@ namespace nana } else if (tfid == transform_action::to_leave) { - nana::paint::graphics dzbuf(newbuf.size()); - nana::paint::graphics nzbuf(newbuf.size()); + nana::paint::graphics dzbuf(newbuf.size(), newbuf.get_dpi()); + nana::paint::graphics nzbuf(newbuf.size(), newbuf.get_dpi()); nana::rectangle r; for (std::size_t i = 1; i < duration.count; ++i) @@ -122,8 +122,8 @@ namespace nana } else if (tfid == transform_action::to_enter) { - nana::paint::graphics dzbuf(newbuf.size()); - nana::paint::graphics nzbuf(newbuf.size()); + nana::paint::graphics dzbuf(newbuf.size(), newbuf.get_dpi()); + nana::paint::graphics nzbuf(newbuf.size(), newbuf.get_dpi()); nana::rectangle r; for (std::size_t i = 1; i < duration.count; ++i) @@ -533,7 +533,7 @@ namespace nana _m_calc_basis(graph, refpos); - nana::paint::graphics gbuf({ width, graph.height() - 2 - topbar_height }); + nana::paint::graphics gbuf({ width, graph.height() - 2 - topbar_height }, graph.get_dpi()); gbuf.rectangle(true, { 0xf0, 0xf0, 0xf0 }); switch (page) @@ -555,13 +555,13 @@ namespace nana nana::point refpos(1, static_cast(topbar_height)+1); nana::rectangle r(0, 0, graph.width() - 2, graph.height() - 2 - topbar_height); - nana::paint::graphics dirtybuf({ r.width, r.height }); + nana::paint::graphics dirtybuf({ r.width, r.height }, graph.get_dpi()); dirtybuf.bitblt(r, graph, refpos); trace_.clear_logic_pos(); render(graph); - nana::paint::graphics gbuf({ r.width, r.height }); + nana::paint::graphics gbuf({ r.width, r.height }, graph.get_dpi()); gbuf.bitblt(r, graph, refpos); perf_transform_helper(window_handle, transf, graph, dirtybuf, gbuf, refpos, duration_); diff --git a/source/gui/widgets/label.cpp b/source/gui/widgets/label.cpp index 638e8cbd2..be97ce298 100644 --- a/source/gui/widgets/label.cpp +++ b/source/gui/widgets/label.cpp @@ -214,7 +214,7 @@ namespace nana void _m_set_default(const ::nana::paint::font& ft, const ::nana::color& fgcolor) { def_.font_name = ft.name(); - def_.font_size = ft.size(); + def_.font_size = ft.size(); /// \todo: set dpi ?? system dpi will be used. def_.font_bold = ft.bold(); def_.fgcolor = fgcolor; @@ -278,7 +278,7 @@ namespace nana { paint::font::font_style fs; fs.weight = (bold ? 800 : 400); - transient_.current_font = paint::font{ name, fontsize, fs }; + transient_.current_font = paint::font{ name, fontsize, fs, graph.get_dpi() }; /// \todo: set dpi ?? system dpi will be used. graph.typeface(transient_.current_font); } transient_.current_fblock = fp; @@ -959,7 +959,7 @@ namespace nana //First Check the graph of label //Then take a substitute for graph when the graph of label is zero-sized. nana::paint::graphics * graph_ptr = impl->graph; - nana::paint::graphics substitute; + nana::paint::graphics substitute(graph_ptr->get_dpi()); if(graph_ptr->empty()) { graph_ptr = &substitute; diff --git a/source/gui/widgets/listbox.cpp b/source/gui/widgets/listbox.cpp index 243f1eb0b..22b801d10 100644 --- a/source/gui/widgets/listbox.cpp +++ b/source/gui/widgets/listbox.cpp @@ -2465,7 +2465,7 @@ namespace nana { unsigned max_font_px = 0; - paint::graphics graph{ size{ 1, 1 } }; + paint::graphics graph{ size{ 1, 1 }, this->graph->get_dpi() }; for (auto & col : this->header.cont()) { if (!col.visible()) @@ -2850,7 +2850,7 @@ namespace nana if (graph->empty()) { //Creates a helper if widget graph is empty(when its size is 0). - graph_helper.reset(new paint::graphics{ nana::size{ 5, 5 } }); + graph_helper.reset(new paint::graphics( nana::size( 5, 5 ), api::window_dpi(this->widget_->handle() ))); graph_helper->typeface(ess_->graph->typeface()); graph = graph_helper.get(); } @@ -2893,7 +2893,7 @@ namespace nana if (graph->empty()) { //Creates a helper if widget graph is empty(when its size is 0). - graph_helper.reset(new paint::graphics{ nana::size{ 5, 5 } }); + graph_helper.reset(new paint::graphics( nana::size{ 5, 5 } , ess_->graph->get_dpi())); graph_helper->typeface(ess_->graph->typeface()); graph = graph_helper.get(); } @@ -3522,7 +3522,7 @@ namespace nana if(api::dev::copy_transparent_background(essence_->listbox_ptr->handle(), column_r, graph, column_r.position())) { - paint::graphics grad_graph{column_r.dimension()}; + paint::graphics grad_graph{column_r.dimension(), graph.get_dpi()}; grad_graph.gradual_rectangle(rectangle{column_r.dimension()}, bgcolor.blend(colors::white, 0.1), bgcolor.blend(colors::black, 0.1), true); graph.blend(column_r, grad_graph, {}, 0.8); @@ -3580,7 +3580,7 @@ namespace nana if (&essence_->header.at(0, true) == &col) crp.margin = essence_->header.margin(); - paint::graphics fl_graph({ col.width_px + crp.margin, crp.height }); + paint::graphics fl_graph({ col.width_px + crp.margin, crp.height }, this->essence_->graph->get_dpi() ); fl_graph.typeface(essence_->graph->typeface()); @@ -3765,7 +3765,7 @@ namespace nana static_cast(std::abs(essence_->mouse_selection.begin_position.y - essence_->mouse_selection.end_position.y)) }; - paint::graphics box_graph{ box_size }; + paint::graphics box_graph{ box_size, essence_->graph->get_dpi() }; box_graph.rectangle(true, essence_->scheme_ptr->selection_box.get_color().blend(colors::white, 0.6)); box_graph.rectangle(false, essence_->scheme_ptr->selection_box.get_color()); diff --git a/source/gui/widgets/menu.cpp b/source/gui/widgets/menu.cpp index 565f23207..b8fa1648f 100644 --- a/source/gui/widgets/menu.cpp +++ b/source/gui/widgets/menu.cpp @@ -1,4 +1,4 @@ -/* +/** * A Menu implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2009-2022 Jinhao(cnjinhao@hotmail.com) @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * -* @file: nana/gui/widgets/menu.cpp +* @file nana/gui/widgets/menu.cpp * @contributors: * kmribti(pr#102) * dankan1890(pr#158) @@ -87,9 +87,9 @@ namespace nana void background(graph_reference graph, window wd) override { nana::size sz = graph.size(); - unsigned int left_width = platform_abstraction::dpi_scale(wd, 30u); - unsigned int unit = platform_abstraction::dpi_scale(wd, 1u); - sz.width -= left_width; + unsigned int left_width = 30u; ///\todo: DPI? platform_abstraction::dpi_scale(wd, 30u); + unsigned int unit = 1u; ///\todo: DPI? platform_abstraction::dpi_scale(wd, 1u); + sz.width -= left_width; sz.height -= 2; graph.rectangle(false, colors::gray_border); graph.rectangle({ 1, 1, left_width - unit, sz.height }, true, static_cast(0xf6f6f6)); @@ -423,28 +423,29 @@ namespace nana return; _m_adjust_window_size(); - + ///\todo use scheme auto renderer = mbuilder_->renderer().get(); renderer->background(graph, *widget_); - auto two = platform_abstraction::dpi_scale(widget_->handle(), 2u); - auto splitter_h = _m_splitter_height(); + auto two = 2u; ///\todo use scheme + auto splitter_h= _m_splitter_height(); const unsigned item_h_px = _m_item_height(); - const unsigned image_px = item_h_px - platform_abstraction::dpi_scale(widget_->handle(), 2u); + const unsigned image_px = item_h_px - 2u; ///\todo use scheme nana::rectangle item_r(two, two, graph_->width() - two * 2, item_h_px); - unsigned strpixels = item_r.width - platform_abstraction::dpi_scale(widget_->handle(), 60u); + unsigned strpixels = item_r.width - 60u; ///\todo use scheme int text_top_off = static_cast(item_h_px - graph.text_extent_size(L"jh({[").height) / 2; - auto unit = platform_abstraction::dpi_scale(widget_->handle(), 1u); + auto unit = 1u; ///\todo use scheme std::size_t pos = 0; for (auto & m : menu_->items) { auto item_ptr = m.get(); if (item_ptr->flags.splitter) { - graph_->line({ item_r.x + platform_abstraction::dpi_scale(widget_->handle(), 40), item_r.y }, { static_cast(graph.width()) - 1, item_r.y }, colors::gray_border); + ///\todo use scheme + graph_->line({ item_r.x + 40, item_r.y }, { static_cast(graph.width()) - 1, item_r.y }, colors::gray_border); item_r.y += static_cast(splitter_h) + unit; ++pos; continue; @@ -460,16 +461,16 @@ namespace nana auto text = api::transform_shortkey_text(item_ptr->text, hotkey, &hotkey_pos); if (item_ptr->image.empty() == false) - renderer->item_image(graph, nana::point(item_r.x + platform_abstraction::dpi_scale(widget_->handle(), 5), item_r.y + static_cast(item_h_px - image_px) / 2 - platform_abstraction::dpi_scale(widget_->handle(), 2)), image_px, item_ptr->image); + renderer->item_image(graph, nana::point(item_r.x + 5 , item_r.y + static_cast(item_h_px - image_px) / 2 - 2 ), image_px, item_ptr->image); - renderer->item_text(graph, nana::point(item_r.x + platform_abstraction::dpi_scale(widget_->handle(), 40), item_r.y + text_top_off), text, strpixels, attr); + renderer->item_text(graph, nana::point(item_r.x + 40 , item_r.y + text_top_off), text, strpixels, attr); item_ptr->hotkey = hotkey; if (hotkey && item_ptr->flags.enabled) - api::dev::draw_shortkey_underline(*graph_, text, hotkey, hotkey_pos, { item_r.x + platform_abstraction::dpi_scale(widget_->handle(), 40), item_r.y + text_top_off }, colors::black); + api::dev::draw_shortkey_underline(*graph_, text, hotkey, hotkey_pos, { item_r.x + 40 , item_r.y + text_top_off }, colors::black); if (item_ptr->linked.menu_ptr) - renderer->sub_arrow(graph, nana::point(graph_->width() - platform_abstraction::dpi_scale(widget_->handle(), 20u), item_r.y), item_h_px, attr); + renderer->sub_arrow(graph, nana::point(graph_->width() - 20 , item_r.y), item_h_px, attr); item_r.y += item_r.height + unit; @@ -668,8 +669,8 @@ namespace nana std::size_t _m_get_index_by_pos(int x, int y) const { - int border_x = platform_abstraction::dpi_scale(widget_->handle(), detail_.border.x); - int border_y = platform_abstraction::dpi_scale(widget_->handle(), detail_.border.y); + int border_x = detail_.border.x; + int border_y = detail_.border.y; if( (x < border_x) || (x > static_cast(graph_->width()) - border_x) || (y < border_y) || @@ -678,7 +679,7 @@ namespace nana int pos = border_y; std::size_t index = 0; - int unit = platform_abstraction::dpi_scale(widget_->handle(), 1); + int unit = 1; ///\todo use scheme for (auto & m : menu_->items) { unsigned h = (m->flags.splitter ? _m_splitter_height() : _m_item_height()); @@ -688,14 +689,14 @@ namespace nana return npos; ++index; - pos += (h + unit); + pos += (h + unit); ///\todo use scheme } return npos; } unsigned _m_item_height() const { - return platform_abstraction::dpi_scale(widget_->handle(), menu_->item_pixels); + return menu_->item_pixels; } unsigned int _m_splitter_height() const @@ -706,7 +707,7 @@ namespace nana nana::size _m_client_size() const { nana::size size; - auto unit = platform_abstraction::dpi_scale(widget_->handle(), 1u); + auto unit = 1u; ///\todo use scheme if (menu_->items.size()) { for (auto & m : menu_->items) @@ -721,7 +722,7 @@ namespace nana ++size.height; } - size.width += platform_abstraction::dpi_scale(widget_->handle(), 35u + 40u); + size.width += 35u + 40u ; ///\todo use scheme size.height = static_cast(menu_->items.size() - size.height) * _m_item_height() + size.height * _m_splitter_height() + static_cast(menu_->items.size() - 1) * unit; } @@ -735,8 +736,9 @@ namespace nana { nana::size size = _m_client_size(); - size.width += platform_abstraction::dpi_scale(widget_->handle(), detail_.border.x) * 2u; - size.height += platform_abstraction::dpi_scale(widget_->handle(), detail_.border.y) * 2u; + constexpr unsigned int two = 2u; ///\todo use scheme + size.width += detail_.border.x * two; + size.height += detail_.border.y * two; widget_->size(size); diff --git a/source/gui/widgets/menubar.cpp b/source/gui/widgets/menubar.cpp index 2a1692a9b..876a5d6a8 100644 --- a/source/gui/widgets/menubar.cpp +++ b/source/gui/widgets/menubar.cpp @@ -1,4 +1,4 @@ -/* +/** * A Menubar implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2009-2020 Jinhao(cnjinhao@hotmail.com) @@ -7,7 +7,7 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * -* @file: nana/gui/widgets/menubar.cpp +* @file nana/gui/widgets/menubar.cpp */ #include @@ -35,8 +35,8 @@ namespace nana shortkey_pos(shortkey_pos) {} - std::string text; ///< Transformed text, the shortkey character has been processed. - wchar_t shortkey; + std::string text; ///< Transformed text, the shortkey character has been processed. + wchar_t shortkey; ///\todo: char ? std::size_t shortkey_pos; ::nana::menu menu_obj; ::nana::point pos; @@ -86,7 +86,7 @@ namespace nana api::register_shortkey(*widget_ptr, shortkey); - if (shortkey && shortkey < 0x61) + if (shortkey && shortkey < 0x61) ///\todo: to upper case? shortkey += (0x61 - 0x41); auto & last = items.emplace_back(new item_type{std::move(transformed_text), shortkey, shortkey_pos}); @@ -102,10 +102,11 @@ namespace nana this->close_menu(); state.behave = behavior::none; - auto pos = api::cursor_position(); - api::calc_window_point(widget_ptr->handle(), pos); - state.active = find(pos); - + ::nana::point pos; + if (api::find_window_cursor(pos)) + state.active = find(pos); + else + state.active = npos; return true; } @@ -187,7 +188,7 @@ namespace nana std::size_t find(const ::nana::point& pos) { auto menubar_size = widget_ptr->size(); - int offset = platform_abstraction::dpi_scale(widget_ptr->handle(), 2); + int offset = 2; if ((offset <= pos.x) && (offset <= pos.y) && (pos.y < static_cast(menubar_size.height))) { int item_x = offset; @@ -295,15 +296,15 @@ namespace nana item_renderer ird{ *ess_->widget_ptr, graph }; auto menubar_size = ess_->widget_ptr->size(); - nana::point item_pos = platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), nana::point{ 2, 2 }); - nana::size item_s(0, menubar_size.height - platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 2)); + nana::point item_pos = nana::point{ 2, 2 }; ///\todo DPI ? platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), nana::point{ 2, 2 }); + nana::size item_s(0, menubar_size.height - 2 ); ///\todo DPI ? platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 2) unsigned long index = 0; for (auto pm : ess_->items) { auto text_s = graph.text_extent_size(pm->text); - item_s.width = text_s.width + platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 16); + item_s.width = text_s.width + 16; ///\todo DPI ? platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 16); pm->pos = item_pos; pm->size = item_s; @@ -315,16 +316,18 @@ namespace nana if (state::selected == item_state) { int x = item_pos.x + item_s.width; - int y1 = item_pos.y + platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 2), y2 = item_pos.y + item_s.height - platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 1); - graph.line({ x, y1 }, { x, y2 }, bgcolor.blend(colors::gray_border, 0.6)); - graph.line({ x + platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 1), y1 }, { x + platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 1), y2 }, bgcolor.blend(colors::button_face_shadow_end, 0.5)); + int y1 = item_pos.y + 2, + y2 = item_pos.y + 1; ///\todo DPI ? item_s.height - platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 1); + + graph.line({ x , y1 }, { x , y2 }, bgcolor.blend(colors::gray_border , 0.6)); + graph.line({ x + 1, y1 }, { x + 1, y2 }, bgcolor.blend(colors::button_face_shadow_end, 0.5)); } //Draw text, the text is transformed from orignal for hotkey character int text_top_off = (item_s.height - text_s.height) / 2; - ird.caption({ item_pos.x + platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 8), item_pos.y + text_top_off }, nana::detail::to_nstring(pm->text)); + ird.caption({ item_pos.x + 8, item_pos.y + text_top_off }, nana::detail::to_nstring(pm->text)); - api::dev::draw_shortkey_underline(graph, pm->text, pm->shortkey, pm->shortkey_pos, { item_pos.x + platform_abstraction::dpi_scale(ess_->widget_ptr->handle(), 8), item_pos.y + text_top_off }, ird.scheme_ptr()->text_fgcolor); + api::dev::draw_shortkey_underline(graph, pm->text, pm->shortkey, pm->shortkey_pos, { item_pos.x + 8, item_pos.y + text_top_off }, ird.scheme_ptr()->text_fgcolor); item_pos.x += pm->size.width; ++index; @@ -669,7 +672,7 @@ namespace nana auto const native_handle = api::root(this->handle()); if (native_handle) { - auto wd = api::find_window(api::cursor_position()); + auto wd = api::find_window_cursor(); if (wd == this->handle()) return true; diff --git a/source/gui/widgets/skeletons/content_view.cpp b/source/gui/widgets/skeletons/content_view.cpp index a10f2a895..a045e0ed9 100644 --- a/source/gui/widgets/skeletons/content_view.cpp +++ b/source/gui/widgets/skeletons/content_view.cpp @@ -1,4 +1,4 @@ -/* +/** * A Content View Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2017-2020 Jinhao(cnjinhao@hotmail.com) @@ -7,13 +7,14 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * -* @file: nana/gui/widgets/skeletons/content_view.hpp -* @author: Jinhao +* @file nana/gui/widgets/skeletons/content_view.hpp +* @author Jinhao */ +#include + #include "content_view.hpp" #include -#include namespace nana { namespace widgets { diff --git a/source/gui/widgets/skeletons/text_editor.cpp b/source/gui/widgets/skeletons/text_editor.cpp index 855b2d6fd..2aa7bdea3 100644 --- a/source/gui/widgets/skeletons/text_editor.cpp +++ b/source/gui/widgets/skeletons/text_editor.cpp @@ -1,4 +1,4 @@ -/* +/** * A text editor implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2024 Jinhao(cnjinhao@hotmail.com) @@ -7,8 +7,8 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * -* @file: nana/gui/widgets/skeletons/text_editor.cpp -* @contributors: Ariel Vina-Rodriguez, Oleg Smolsky +* @file nana/gui/widgets/skeletons/text_editor.cpp +* @contributors Ariel Vina-Rodriguez, Oleg Smolsky */ #include #include @@ -2015,7 +2015,7 @@ namespace nana::widgets::skeletons //Draw background auto area = editor_area(); - paint::graphics canvas{graph_.size()}; + paint::graphics canvas{graph_.size(), graph_.get_dpi()}; if (!api::dev::copy_transparent_background(window_, canvas)) { @@ -3617,7 +3617,7 @@ namespace nana::widgets::skeletons //Draw as selected, and copy the selected part to the graph. - paint::graphics graph({ glyph_selected, line_px_ }); + paint::graphics graph(size( glyph_selected, line_px_ ), this->graph_.get_dpi()); graph.typeface(this->graph_.typeface()); graph.rectangle(true, selection_color(false, has_focused)); diff --git a/source/gui/widgets/slider.cpp b/source/gui/widgets/slider.cpp index d9945a7d3..a12a924a2 100644 --- a/source/gui/widgets/slider.cpp +++ b/source/gui/widgets/slider.cpp @@ -118,7 +118,7 @@ namespace nana const auto label_size = graph.text_extent_size(data.text) + size{ schm.vernier_text_margin * 2, 0 }; - paint::graphics graph_vern{ label_size }; + paint::graphics graph_vern{ label_size, graph.get_dpi() }; graph_vern.rectangle(true, schm.color_vernier); int arrow_pos; @@ -148,9 +148,9 @@ namespace nana if (label_pos.x > data.position) { - for (::nana::size::value_type l = 0; l < arrow_size.height; ++l) + for (::nana::size::value_type L = 0; L < arrow_size.height; ++L) { - auto ptr = arrow_pxbuf + l * arrow_size.width; + auto ptr = arrow_pxbuf + L * arrow_size.width; for (::nana::size::value_type x = 0; x < arrow_size.width / 2; ++x) std::swap(ptr[x], ptr[(arrow_size.width - 1) - x]); @@ -183,9 +183,9 @@ namespace nana const size label_size = (graph.text_extent_size(data.text) + size{ schm.vernier_text_margin * 2, 0 }).shift(); - paint::graphics graph_vern{ label_size }; + paint::graphics graph_vern{ label_size, graph.get_dpi() }; - paint::graphics graph_horz{ size(label_size).shift() }; + paint::graphics graph_horz{ size(label_size).shift(), graph.get_dpi() }; graph_horz.rectangle(true, schm.color_vernier); graph_horz.string({ static_cast(schm.vernier_text_margin), static_cast(graph_horz.height() - label_size.width) / 2 }, data.text, schm.color_vernier_text); @@ -431,7 +431,7 @@ namespace nana { api::release_capture(other_.wd); - if (other_.wd != api::find_window(api::cursor_position())) + if (other_.wd != api::find_window_cursor()) { slider_state_.mouse_state = ::nana::mouse_action::normal; attr_.is_draw_adorn = false; diff --git a/source/gui/widgets/toolbar.cpp b/source/gui/widgets/toolbar.cpp index da883c196..65ee9bdc1 100644 --- a/source/gui/widgets/toolbar.cpp +++ b/source/gui/widgets/toolbar.cpp @@ -331,7 +331,7 @@ namespace nana if(item.enable == false) { - nana::paint::graphics gh(imgsize); + nana::paint::graphics gh(imgsize, graph.get_dpi()); gh.bitblt(::nana::rectangle{ imgsize }, graph, pos); gh.rgb_to_wb(true); gh.paste(graph, pos.x, pos.y); diff --git a/source/gui/widgets/treebox.cpp b/source/gui/widgets/treebox.cpp index 9c2cb4ec9..c947b8305 100644 --- a/source/gui/widgets/treebox.cpp +++ b/source/gui/widgets/treebox.cpp @@ -120,7 +120,7 @@ namespace nana comp_attribute_t attr; if(comp_attribute(component::text, attr)) { - nana::paint::graphics item_graph({ item_r_.width, item_r_.height }); + nana::paint::graphics item_graph({ item_r_.width, item_r_.height }, graph_->get_dpi()); item_graph.typeface(graph_->typeface()); renderer_->begin_paint(*widget_); @@ -1735,7 +1735,7 @@ namespace nana { if (api::is_transparent_background(window_handle_)) { - paint::graphics item_graph{ attr.area.dimension() }; + paint::graphics item_graph{ attr.area.dimension(), graph.get_dpi() }; item_graph.rectangle(false, *fg_ptr); item_graph.rectangle(rectangle{ attr.area.dimension() }.pare_off(1), true, *bg_ptr); @@ -1912,25 +1912,6 @@ namespace nana //Treebox Implementation //class trigger - //struct treebox_node_type - - trigger::treebox_node_type::treebox_node_type(std::string text) - :text(std::move(text)) - {} - - trigger::treebox_node_type& trigger::treebox_node_type::operator=(const treebox_node_type& rhs) - { - if(this != &rhs) - { - text = rhs.text; - value = rhs.value; - checked = rhs.checked; - selected = rhs.selected; - img_idstr = rhs.img_idstr; - } - return *this; - } - //end struct treebox_node_type trigger::trigger() : impl_(new implementation) @@ -2092,7 +2073,7 @@ namespace nana if(p) p->value.second.text.swap(title); else - p = impl_->attr.tree_cont.insert(node, key, treebox_node_type(std::move(title))); + p = impl_->attr.tree_cont.insert(node, key, treebox_node_type{.text=std::move(title)}); if (p) impl_->draw(true); @@ -2102,7 +2083,7 @@ namespace nana trigger::node_type* trigger::insert(const std::string& path, std::string&& title) { - auto x = impl_->attr.tree_cont.insert(path, treebox_node_type(std::move(title))); + auto x = impl_->attr.tree_cont.insert(path, treebox_node_type{.text=std::move(title)}); if (x) impl_->draw(true); return x; diff --git a/source/gui/widgets/widget.cpp b/source/gui/widgets/widget.cpp index af8a523d1..51d33d415 100644 --- a/source/gui/widgets/widget.cpp +++ b/source/gui/widgets/widget.cpp @@ -1,12 +1,12 @@ -/* +/** * The fundamental widget class implementation - * Copyright(C) 2003-2020 Jinhao(cnjinhao@hotmail.com) + * Copyright(C) 2003-2024 Jinhao(cnjinhao@hotmail.com) * * Distributed under the Boost Software License, Version 1.0. * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/gui/widgets/widget.cpp + * @file nana/gui/widgets/widget.cpp */ #include @@ -20,8 +20,6 @@ namespace nana void set_eval(window, i18n_eval&&); } - //class widget - //@brief:The definition of class widget class widget::inner_widget_notifier : public detail::widget_notifier_interface { public: diff --git a/source/paint/detail/image_ico_resource.hpp b/source/paint/detail/image_ico_resource.hpp index 4b8a1302e..c64db1ac6 100644 --- a/source/paint/detail/image_ico_resource.hpp +++ b/source/paint/detail/image_ico_resource.hpp @@ -115,7 +115,7 @@ namespace nana{ namespace paint bool save(const std::filesystem::path& p) const override { - paint::graphics graph{size()}; + paint::graphics graph{size(), 96}; paste(rectangle{ size() }, graph, {}); @@ -154,7 +154,7 @@ namespace nana{ namespace paint if (!pxbuf_) pxbuf_.open(sz.width, sz.height); - paint::graphics graph{ size() }; + paint::graphics graph{ size(), 96 }; /// \todo: 96? it should be replaced by a DPI value.?? paste(rectangle{ size() }, graph, {}); @@ -168,7 +168,7 @@ namespace nana{ namespace paint if (!pxbuf_) pxbuf_.open(sz.width, sz.height); - paint::graphics graph{ size() }; + paint::graphics graph{ size() , 96 }; /// \todo: 96? it should be replaced by a DPI value.?? paste(rectangle{ size() }, graph, {}); diff --git a/source/paint/detail/native_paint_interface.cpp b/source/paint/detail/native_paint_interface.cpp index 9fe4a6de0..7312a1b83 100644 --- a/source/paint/detail/native_paint_interface.cpp +++ b/source/paint/detail/native_paint_interface.cpp @@ -1,4 +1,4 @@ -/* +/** * Platform Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2019 Jinhao(cnjinhao@hotmail.com) @@ -7,21 +7,21 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/paint/detail/native_paint_interface.cpp - * @contributors: dareg + * @file nana/paint/detail/native_paint_interface.cpp + * @contributors dareg */ -#include "../../detail/platform_spec_selector.hpp" -#include -#include -#include - #if defined(NANA_WINDOWS) #include #elif defined(NANA_X11) #include #endif +#include "../../detail/platform_spec_selector.hpp" +#include +#include +#include + namespace nana { #ifdef NANA_USE_XFT @@ -37,13 +37,13 @@ namespace paint namespace detail { - nana::size drawable_size(drawable_type dw) + nana::size drawable_size(drawable_type dw) ///< todo: dpi: system side { if(0 == dw) return nana::size(); #if defined(NANA_WINDOWS) BITMAP bmp; ::GetObject(dw->pixmap, sizeof bmp, &bmp); - return nana::size(bmp.bmWidth, bmp.bmHeight); + return nana::size(bmp.bmWidth, bmp.bmHeight); ///< dpi: system side #elif defined(NANA_X11) nana::detail::platform_spec & spec = nana::detail::platform_spec::instance(); Window root; @@ -106,7 +106,7 @@ namespace detail return bgcolor; } - void blend(drawable_type dw, const rectangle& area, pixel_color_t color, double fade_rate) + void blend(drawable_type dw, const rectangle& area, pixel_color_t color, double fade_rate) ///< todo: dpi: user or system side? { if (fade_rate <= 0) return; @@ -139,10 +139,10 @@ namespace detail i->value = (px_r | px_g | px_b); } } - pixbuf.paste(nana::rectangle(r.x, 0, r.width, r.height), dw, point{r.x, r.y}); + pixbuf.paste(nana::rectangle(r.x, 0, r.width, r.height), dw, point{r.x, r.y}); ///< todo: dpi: system side? } - nana::size real_text_extent_size(drawable_type dw, const wchar_t* text, std::size_t len) + nana::size real_text_extent_size(drawable_type dw, const wchar_t* text, std::size_t len) ///< todo: take string_view? dpi: system side { if (dw && text && len) { @@ -166,7 +166,7 @@ namespace detail return {}; } - nana::size real_text_extent_size(drawable_type dw, const char* text, std::size_t len) + nana::size real_text_extent_size(drawable_type dw, const char* text, std::size_t len) ///< todo: take string_view? dpi: return user or system side? Now SS. { if (dw && text && len) { @@ -193,7 +193,7 @@ namespace detail } - nana::size text_extent_size(drawable_type dw, const char * text, std::size_t len) + nana::size text_extent_size(drawable_type dw, const char * text, std::size_t len) ///< todo: take string_view? dpi: return user or system side? Now SS. { if (nullptr == dw || nullptr == text || 0 == len) return{}; @@ -202,7 +202,7 @@ namespace detail auto const end = text + len; int tabs = 0; - for (; text != end; ++text) + for (; text != end; ++text) ///< todo: is this UNICODE 'safe'? { if (*text == '\t') ++tabs; @@ -212,7 +212,7 @@ namespace detail return extents; } - nana::size text_extent_size(drawable_type dw, const wchar_t * text, std::size_t len) + nana::size text_extent_size(drawable_type dw, const wchar_t * text, std::size_t len) ///< todo: take string_view? dpi: return user or system side? Now SS. { if (nullptr == dw || nullptr == text || 0 == len) return{}; @@ -231,7 +231,7 @@ namespace detail return extents; } - void draw_string(drawable_type dw, const nana::point& pos, const wchar_t * str, std::size_t len) + void draw_string(drawable_type dw, const nana::point& pos, const wchar_t * str, std::size_t len) ///< todo: take string_view? dpi: return user or system side? Now SS. { #if defined(NANA_WINDOWS) ::TextOut(dw->context, pos.x, pos.y, str, static_cast(len)); diff --git a/source/paint/graphics.cpp b/source/paint/graphics.cpp index 59f4f68cd..98170b7a5 100644 --- a/source/paint/graphics.cpp +++ b/source/paint/graphics.cpp @@ -1,4 +1,4 @@ -/* +/** * Paint Graphics Implementation * Nana C++ Library(https://nana.acemind.cn) * Copyright(C) 2003-2022 Jinhao(cnjinhao@hotmail.com) @@ -7,8 +7,15 @@ * (See accompanying file LICENSE_1_0.txt or copy at * http://www.boost.org/LICENSE_1_0.txt) * - * @file: nana/paint/graphics.cpp + * @file nana/paint/graphics.cpp */ +#include + +#if defined(NANA_WINDOWS) + #include +#elif defined(NANA_X11) + #include +#endif #include "../detail/platform_spec_selector.hpp" #include @@ -18,12 +25,7 @@ #include #include #include -#include -#if defined(NANA_WINDOWS) - #include -#elif defined(NANA_X11) - #include -#endif +#include #include "../detail/platform_abstraction.hpp" @@ -35,12 +37,6 @@ namespace nana namespace detail { - font_style::font_style(unsigned weight, bool italic, bool underline, bool strike_out) : - weight(weight), - italic(italic), - underline(underline), - strike_out(strike_out) - {} font_style& font_style::change_weight(unsigned w) { @@ -125,13 +121,14 @@ namespace paint } /// \todo: generalize dpi to v2 awareness - font::font(const font_info& fi, std::size_t dpi): + font::font(const font_info& fi, int dpi): impl_(new impl_type) { impl_->real_font = platform_abstraction::open_font(fi, (dpi ? dpi : platform_abstraction::current_dpi()), {}); } + /// \todo: generalize dpi to v2 awareness - font::font(const std::string& font_family, double size_pt, const font_style& fs, std::size_t dpi): + font::font(const std::string& font_family, double size_pt, const font_style& fs, int dpi): impl_(new impl_type) { font_info fi; @@ -142,7 +139,7 @@ namespace paint } /// \todo: generalize dpi to v2 awareness - font::font(double size_pt, const path_type& ttf, const font_style& fs, std::size_t dpi) : + font::font(double size_pt, const path_type& ttf, const font_style& fs, int dpi) : impl_(new impl_type) { font_info fi; @@ -176,13 +173,16 @@ namespace paint return impl_->real_font->font_info().family; } - double font::size(bool fixed) const + double font::size(bool fixed, int dpi) const { double size_pt = (empty() ? 0.0 : impl_->real_font->font_info().size_pt); if (fixed && (0.0 == size_pt)) return platform_abstraction::font_default_pt(); + if (!dpi) dpi = platform_abstraction::current_dpi(); + size_pt = size_pt * 96.0 / dpi; + return size_pt; } @@ -259,24 +259,49 @@ namespace paint } //end class font - //class graphics + //class graphics. /// \todo add dpi, scale, and/or wd/widget? to the graphics constructor struct graphics::implementation { - std::shared_ptr<::nana::detail::drawable_impl_type> platform_drawable; + int dpi { 97 }; + float scale{ dpi / 96.0f }; /// \todo: font font_shadow; - drawable_type handle{ nullptr }; - ::nana::size size; + std::shared_ptr<::nana::detail::drawable_impl_type> platform_drawable; + drawable_type handle{ nullptr }; ///< just refers to the platform-specific drawable_impl_type object above + ::nana::size size; ///< system-side size, dpi-scaled pixel_buffer pxbuf; - bool changed{ false }; + bool changed{ false }; }; - graphics::graphics() - : impl_(new implementation) - {} - - graphics::graphics(const nana::size& sz) - : impl_(new implementation) - { + void graphics::set_dpi(int dpi) + { + if (dpi == impl_->dpi) return; + auto sz = this->size(); + auto info = typeface().info(); + graphics duplicate(std::move(*this)); + impl_->dpi = dpi; + nana::paint::font ft{ info.value(), dpi }; + typeface(ft); + make(sz); // this will scale the size to the dpi + //bitblt(0, 0, duplicate); + } + int graphics::get_dpi() const + { + return impl_->dpi; + } + graphics::graphics(int dpi) + : impl_(new implementation{.dpi {dpi?dpi: api::screen_dpi()}}) + { + auto info = typeface().info(); + nana::paint::font ft{ info.value(), impl_->dpi }; + typeface(ft); + } + + graphics::graphics(const nana::size& sz, int dpi) + : impl_(new implementation{.dpi{dpi}, .scale{dpi/96.0f}}) + { + auto info = typeface().info(); + nana::paint::font ft{ info.value(), dpi }; + typeface(ft); make(sz); } @@ -294,7 +319,6 @@ namespace paint return *this; } - graphics::graphics(graphics&& other) : impl_(std::move(other.impl_)) { @@ -355,8 +379,9 @@ namespace paint impl_.swap(other.impl_); } - void graphics::make(const ::nana::size& sz) + void graphics::make(const ::nana::size& sz_) { + auto sz = platform_abstraction::dpi_scale(sz_, impl_->dpi); if (impl_->handle == nullptr || impl_->size != sz) { if (sz.empty()) @@ -365,14 +390,14 @@ namespace paint return; } - //The object will be deleted while dwptr_ is performing a release. + // The object will be deleted while dwptr_ is performing a release. + // Real constructor of drawable_impl_type. \todo: why not use make_unique? std::shared_ptr dw{ new nana::detail::drawable_impl_type, detail::drawable_deleter{} }; - //Reuse the old font if (impl_->platform_drawable) { drawable_type reuse = impl_->platform_drawable.get(); - dw->font = reuse->font; + dw->font = reuse->font; // the correct 'dpi' size of font was set before for reuse by set_dpi dw->string.tab_length = reuse->string.tab_length; } else @@ -466,8 +491,8 @@ namespace paint impl_->handle = dw.get(); impl_->size = sz; - impl_->handle->string.tab_pixels = detail::real_text_extent_size(impl_->handle, L"\t", 1).width; - impl_->handle->string.whitespace_pixels = detail::real_text_extent_size(impl_->handle, L" ", 1).width; + impl_->handle->string.tab_pixels = detail::real_text_extent_size(impl_->handle, L"\t", 1).width; // dpi unscaled to SS + impl_->handle->string.whitespace_pixels = detail::real_text_extent_size(impl_->handle, L" " , 1).width; // dpi unscaled to SS } } @@ -478,7 +503,7 @@ namespace paint void graphics::resize(const ::nana::size& sz) { graphics duplicate(std::move(*this)); - make(sz); + make(sz); // this will scale the size to the dpi bitblt(0, 0, duplicate); } @@ -489,13 +514,13 @@ namespace paint impl_->font_shadow = f; if(impl_->handle && (false == f.empty())) { - impl_->handle->font = f.impl_->real_font; + impl_->handle->font = f.impl_->real_font; /// \todo: scale_dpi before? no, the font don't know the target dpi. Set it before! #if defined(NANA_WINDOWS) ::SelectObject(impl_->handle->context, reinterpret_cast(f.impl_->real_font->native_handle())); #endif - - impl_->handle->string.tab_pixels = detail::real_text_extent_size(impl_->handle, L"\t", 1).width; - impl_->handle->string.whitespace_pixels = detail::real_text_extent_size(impl_->handle, L" ", 1).width; + /// scaled, system-side size + impl_->handle->string.tab_pixels = detail::real_text_extent_size(impl_->handle, L"\t", 1).width; + impl_->handle->string.whitespace_pixels = detail::real_text_extent_size(impl_->handle, L" " , 1).width; if (impl_->changed == false) impl_->changed = true; @@ -512,12 +537,12 @@ namespace paint size graphics::text_extent_size(std::string_view text) const { throw_not_utf8(text); - return detail::text_extent_size(impl_->handle, text.data(), text.length()); + return platform_abstraction::unscale_dpi(detail::text_extent_size(impl_->handle, text.data(), text.length()), impl_->dpi) ; } size graphics::text_extent_size(std::wstring_view text) const { - return detail::text_extent_size(impl_->handle, text.data(), text.length()); + return platform_abstraction::unscale_dpi(detail::text_extent_size(impl_->handle, text.data(), text.length()), impl_->dpi) ; } #ifdef __cpp_char8_t @@ -527,7 +552,7 @@ namespace paint } #endif - nana::size graphics::glyph_extent_size(std::wstring_view text, std::size_t begin, std::size_t end) const + nana::size graphics::glyph_extent_size(std::wstring_view text, std::size_t begin, std::size_t end) const /// \todo: not used? { end = std::clamp(end, static_cast(0), static_cast(text.size())); @@ -552,14 +577,14 @@ namespace paint #elif defined(NANA_X11) sz = text_extent_size(text.substr(begin, end - begin)); #endif - return sz; + return platform_abstraction::unscale_dpi(sz, impl_->dpi) ; } - std::unique_ptr graphics::glyph_pixels(std::wstring_view text) const + std::unique_ptr graphics::glyph_pixels(std::wstring_view text) const ///\todo: return vector? { if (nullptr == impl_->handle || nullptr == impl_->handle->context) return {}; - auto pxbuf = std::unique_ptr{ new unsigned[text.size() ? text.size() : 1] }; + auto pxbuf = std::unique_ptr{ new unsigned[text.size() ? text.size() : 1] }; ///\todo: vector? if (!text.empty()) { @@ -570,10 +595,14 @@ namespace paint ::GetTextExtentExPoint(impl_->handle->context, text.data(), static_cast(text.size()), 0, 0, dx, &extents); pxbuf[0] = (text[0] == '\t' ? tab_pixels : dx[0]); + // unscale_dpi + pxbuf[0] = platform_abstraction::unscale_dpi(pxbuf[0], impl_->dpi); for (std::size_t i = 1; i < text.size(); ++i) { pxbuf[i] = (text[i] == '\t' ? tab_pixels : dx[i] - dx[i - 1]); + // unscale_dpi + pxbuf[i] = platform_abstraction::unscale_dpi(pxbuf[i], impl_->dpi); } delete[] dx; #elif defined(NANA_X11) && defined(NANA_USE_XFT) @@ -583,7 +612,7 @@ namespace paint return pxbuf; } - ::nana::size graphics::bidi_extent_size(std::string_view utf8str) const + nana::size graphics::bidi_extent_size(std::string_view utf8str) const { return bidi_extent_size(to_wstring(utf8str)); } @@ -596,14 +625,14 @@ namespace paint auto const reordered = unicode_reorder(text.data(), text.size()); for (auto & i : reordered) { - nana::size t = text_extent_size(std::wstring_view(i.begin, i.end - i.begin)); + nana::size t = text_extent_size(std::wstring_view(i.begin, i.end - i.begin)); /// user-side sz.width += t.width; if (sz.height < t.height) sz.height = t.height; } } - return sz; + return sz ; } #ifdef __cpp_char8_t ::nana::size graphics::bidi_extent_size(std::u8string_view text) const @@ -619,9 +648,13 @@ namespace paint #if defined(NANA_WINDOWS) ::TEXTMETRIC tm; ::GetTextMetrics(impl_->handle->context, &tm); - ascent = static_cast(tm.tmAscent); - descent = static_cast(tm.tmDescent); - internal_leading = static_cast(tm.tmInternalLeading); + // uscale_dpi before + ascent = static_cast(tm.tmAscent); + ascent = platform_abstraction::unscale_dpi(ascent, impl_->dpi) ; + descent = static_cast(tm.tmDescent); + descent = platform_abstraction::unscale_dpi(descent, impl_->dpi) ; + internal_leading = static_cast(tm.tmInternalLeading); + internal_leading = platform_abstraction::unscale_dpi(internal_leading, impl_->dpi) ; return true; #elif defined(NANA_X11) if(impl_->handle->font) @@ -658,30 +691,34 @@ namespace paint void graphics::line_begin(int x, int y) { if(!impl_->handle) return; + auto p = platform_abstraction::dpi_scale(point(x,y), impl_->dpi); + #if defined(NANA_WINDOWS) - ::MoveToEx(impl_->handle->context, x, y, 0); + ::MoveToEx(impl_->handle->context, p.x, p.y, 0); #elif defined(NANA_X11) - impl_->handle->line_begin_pos.x = x; - impl_->handle->line_begin_pos.y = y; + impl_->handle->line_begin_pos = p; #endif } void graphics::bitblt(int x, int y, const graphics& src) { - nana::rectangle r(src.size()); + nana::rectangle r(src.size()); r.x = x; r.y = y; bitblt(r, src); } - void graphics::bitblt(const nana::rectangle& r_dst, native_window_type src) + void graphics::bitblt(const nana::rectangle& r_dst_, native_window_type src) { if(impl_->handle) { + auto r_dst = platform_abstraction::dpi_scale(r_dst_, impl_->dpi); + #if defined(NANA_WINDOWS) HDC dc = ::GetDC(reinterpret_cast(src)); - ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, dc, 0, 0, SRCCOPY); + ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, + dc, 0, 0, SRCCOPY); ::ReleaseDC(reinterpret_cast(src), dc); #elif defined(NANA_X11) ::XCopyArea(nana::detail::platform_spec::instance().open_display(), @@ -692,13 +729,18 @@ namespace paint } } - void graphics::bitblt(const nana::rectangle& r_dst, native_window_type src, const nana::point& p_src) + void graphics::bitblt(const nana::rectangle& r_dst_, native_window_type src, const nana::point& p_src_) /// \todo: unused? { if(impl_->handle) { + auto r_dst = platform_abstraction::dpi_scale(r_dst_, impl_->dpi); + auto p_src = platform_abstraction::dpi_scale(p_src_, nana::detail::native_interface::window_dpi(src)); + #if defined(NANA_WINDOWS) + HDC dc = ::GetDC(reinterpret_cast(src)); - ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, dc, p_src.x, p_src.y, SRCCOPY); + ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, + dc, p_src.x, p_src.y, SRCCOPY); ::ReleaseDC(reinterpret_cast(src), dc); #elif defined(NANA_X11) ::XCopyArea(nana::detail::platform_spec::instance().open_display(), @@ -709,12 +751,14 @@ namespace paint } } - void graphics::bitblt(const nana::rectangle& r_dst, const graphics& src) + void graphics::bitblt(const nana::rectangle& r_dst_, const graphics& src) { if(impl_->handle && src.impl_->handle) { + auto r_dst = platform_abstraction::dpi_scale(r_dst_, impl_->dpi); #if defined(NANA_WINDOWS) - ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, src.impl_->handle->context, 0, 0, SRCCOPY); + ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, + src.impl_->handle->context, 0, 0, SRCCOPY); #elif defined(NANA_X11) ::XCopyArea(nana::detail::platform_spec::instance().open_display(), src.impl_->handle->pixmap, impl_->handle->pixmap, impl_->handle->context, @@ -724,12 +768,15 @@ namespace paint } } - void graphics::bitblt(const nana::rectangle& r_dst, const graphics& src, const nana::point& p_src) + void graphics::bitblt(const nana::rectangle& r_dst_, const graphics& src, const nana::point& p_src_) { if(impl_->handle && src.impl_->handle) { + auto r_dst = platform_abstraction::dpi_scale(r_dst_, impl_->dpi); + auto p_src = platform_abstraction::dpi_scale(p_src_, src.impl_->dpi); ///\todo: use dpi src? #if defined(NANA_WINDOWS) - ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, src.impl_->handle->context, p_src.x, p_src.y, SRCCOPY); + ::BitBlt(impl_->handle->context, r_dst.x, r_dst.y, r_dst.width, r_dst.height, + src.impl_->handle->context, p_src.x, p_src.y, SRCCOPY); #elif defined(NANA_X11) ::XCopyArea(nana::detail::platform_spec::instance().open_display(), src.impl_->handle->pixmap, impl_->handle->pixmap, impl_->handle->context, @@ -739,8 +786,9 @@ namespace paint } } - void graphics::blend(const nana::rectangle& r, const ::nana::color& clr, double fade_rate) + void graphics::blend(const nana::rectangle& r_, const ::nana::color& clr, double fade_rate) { + auto r = platform_abstraction::dpi_scale(r_, impl_->dpi); ///\todo : scale dpi? for blend(drawable_type dw, ?? if (impl_->handle) { nana::paint::detail::blend(impl_->handle, r, clr.px_color(), fade_rate); @@ -748,27 +796,31 @@ namespace paint } } - void graphics::blend(const ::nana::rectangle& blend_r, const graphics& graph, const point& blend_graph_point, double fade_rate)///< blends with the blend_graph. + void graphics::blend(const ::nana::rectangle& blend_r_, const graphics& graph, const point& blend_graph_point_, double fade_rate)///< blends with the blend_graph. { if (graph.impl_->handle && impl_->handle && (graph.impl_->handle != impl_->handle)) { pixel_buffer graph_px; + auto blend_r = platform_abstraction::dpi_scale(blend_r_, impl_->dpi); + auto blend_graph_point = platform_abstraction::dpi_scale(blend_graph_point_, graph.impl_->dpi); nana::rectangle r{ blend_graph_point, blend_r.dimension() }; - graph_px.attach(graph.impl_->handle, r); - graph_px.blend(r, impl_->handle, blend_r.position(), 1 - fade_rate); + graph_px.attach(graph.impl_->handle, r); + graph_px.blend(r, impl_->handle, blend_r.position(), 1 - fade_rate); if (graph.impl_->changed == false) graph.impl_->changed = true; } } - void graphics::blur(const nana::rectangle& r, std::size_t radius) + void graphics::blur(const nana::rectangle& r, std::size_t radius_) /// \todo: scale dpi ? { if(impl_->handle) { + // convert to unsigned int and back to size_t + auto radius = static_cast(platform_abstraction::dpi_scale(static_cast(radius_), impl_->dpi)); pixel_buffer pixbuf(impl_->handle, 0, 0); - pixbuf.blur(r, radius); + pixbuf.blur(r, radius); /// \todo: scale dpi ? pixbuf.paste(impl_->handle, point{}); } } @@ -778,16 +830,16 @@ namespace paint if(impl_->handle) { //Create the color table for performance - float* tablebuf = new float[0x100 * 3]; - float* table_red = tablebuf; + float* tablebuf = new float[0x100 * 3]; + float* table_red = tablebuf; float* table_green = tablebuf + 0x100; - float* table_blue = tablebuf + 0x200; + float* table_blue = tablebuf + 0x200; for(int i = 0; i < 0x100; ++i) { - table_red[i] = (i * 0.3f); + table_red [i] = (i * 0.3f); table_green[i] = (i * 0.59f); - table_blue[i] = (i * 0.11f); + table_blue [i] = (i * 0.11f); } pixel_buffer pixbuf(impl_->handle, 0, 0); @@ -851,13 +903,16 @@ namespace paint { if(impl_->handle && dst.impl_->handle && impl_->handle != dst.impl_->handle) { + auto p = platform_abstraction::dpi_scale(point(x, y), dst.impl_->dpi); + auto sz = platform_abstraction::dpi_scale(size(), dst.impl_->dpi); #if defined(NANA_WINDOWS) - ::BitBlt(dst.impl_->handle->context, x, y, impl_->size.width, impl_->size.height, impl_->handle->context, 0, 0, SRCCOPY); + ::BitBlt(dst.impl_->handle->context, p.x, p.y, sz.width, sz.height, + impl_->handle->context, 0, 0, SRCCOPY); #elif defined(NANA_X11) Display* display = nana::detail::platform_spec::instance().open_display(); ::XCopyArea(display, impl_->handle->pixmap, dst.impl_->handle->pixmap, impl_->handle->context, - 0, 0, impl_->size.width, impl_->size.height, x, y); + 0, 0, sz.width, sz.height, p.x, p.y); ::XFlush(display); #endif @@ -874,11 +929,14 @@ namespace paint { if(impl_->handle) { + auto p = platform_abstraction::dpi_scale(nana::rectangle(dx, dy, width, height), nana::detail::native_interface::window_dpi(dst)); + point s = platform_abstraction::dpi_scale(point(sx, sy), impl_->dpi); #if defined(NANA_WINDOWS) HDC dc = ::GetDC(reinterpret_cast(dst)); if(dc) { - ::BitBlt(dc, dx, dy, width, height, impl_->handle->context, sx, sy, SRCCOPY); + ::BitBlt(dc, p.x, p.y, p.width, p.height, + impl_->handle->context, s.x, s.y, SRCCOPY); ::ReleaseDC(reinterpret_cast(dst), dc); } #elif defined(NANA_X11) @@ -890,7 +948,7 @@ namespace paint ::XCopyArea(display, impl_->handle->pixmap, reinterpret_cast(dst), impl_->handle->context, - sx, sy, width, height, dx, dy); + s.x, s.y, width, height, p.x, p.y); XWindowAttributes attr; spec.set_error_handler(); @@ -907,42 +965,49 @@ namespace paint { if(impl_->handle && dst && impl_->handle != dst) { + auto p = platform_abstraction::dpi_scale(point(x, y), impl_->dpi); ///\todo: how to get dpi of dst? #if defined (NANA_WINDOWS) - ::BitBlt(dst->context, x, y, impl_->size.width, impl_->size.height, impl_->handle->context, 0, 0, SRCCOPY); + + ::BitBlt(dst->context, p.x, p.y, impl_->size.width, impl_->size.height, + impl_->handle->context, 0, 0, SRCCOPY); #elif defined(NANA_X11) Display * display = nana::detail::platform_spec::instance().open_display(); ::XCopyArea(display, impl_->handle->pixmap, dst->pixmap, impl_->handle->context, - 0, 0, impl_->size.width, impl_->size.height, x, y); + 0, 0, impl_->size.width, impl_->size.height, p.x, p.y); ::XFlush(display); #endif } } - - void graphics::paste(const nana::rectangle& r_src, graphics& dst, int x, int y) const + void graphics::paste(const nana::rectangle& r_src_, graphics& dst, int x_, int y_) const { if(impl_->handle && dst.impl_->handle && impl_->handle != dst.impl_->handle) { + auto r_src = platform_abstraction::dpi_scale(r_src_, impl_->dpi); + auto p = platform_abstraction::dpi_scale(point(x_, y_), dst.impl_->dpi); ///\todo: how to get dpi of dst? #if defined(NANA_WINDOWS) - ::BitBlt(dst.impl_->handle->context, x, y, r_src.width, r_src.height, impl_->handle->context, r_src.x, r_src.y, SRCCOPY); + ::BitBlt(dst.impl_->handle->context, p.x, p.y, r_src.width, r_src.height, + impl_->handle->context, r_src.x, r_src.y, SRCCOPY); #elif defined(NANA_X11) Display* display = nana::detail::platform_spec::instance().open_display(); ::XCopyArea(display, impl_->handle->pixmap, dst.impl_->handle->pixmap, impl_->handle->context, - r_src.x, r_src.y, r_src.width, r_src.height, x, y); + r_src.x, r_src.y, r_src.width, r_src.height, p.x, p.y); ::XFlush(display); #endif } } - void graphics::stretch(const nana::rectangle& src_r, graphics& dst, const nana::rectangle& r) const + void graphics::stretch(const nana::rectangle& src_r_, graphics& dst, const nana::rectangle& dst_r_) const { if(impl_->handle && dst.impl_->handle && (impl_->handle != dst.impl_->handle)) { + auto src_r = platform_abstraction::dpi_scale(src_r_, impl_->dpi); + auto dst_r = platform_abstraction::dpi_scale(dst_r_, dst.impl_->dpi); pixel_buffer pixbuf(impl_->handle, 0, 0); - pixbuf.stretch(src_r, dst.impl_->handle, r); + pixbuf.stretch(src_r, dst.impl_->handle, dst_r); } } @@ -959,15 +1024,16 @@ namespace paint } unsigned graphics::width() const{ - return impl_->size.width; + return platform_abstraction::unscale_dpi(impl_->size.width, impl_->dpi); } unsigned graphics::height() const{ - return impl_->size.height; + return platform_abstraction::unscale_dpi(impl_->size.height, impl_->dpi); } - nana::size graphics::size() const{ - return this->impl_->size; + nana::size graphics::size() const + { + return platform_abstraction::unscale_dpi(impl_->size, impl_->dpi); } void graphics::setsta() @@ -1067,12 +1133,13 @@ namespace paint { if (impl_->handle) { + auto p = platform_abstraction::dpi_scale(point(x, y), impl_->dpi); #if defined(NANA_WINDOWS) - ::SetPixel(impl_->handle->context, x, y, impl_->handle->bgcolor_native); + ::SetPixel(impl_->handle->context, p.x, p.y, impl_->handle->bgcolor_native); #elif defined(NANA_X11) Display* disp = nana::detail::platform_spec::instance().open_display(); impl_->handle->update_color(); - ::XDrawPoint(disp, impl_->handle->pixmap, impl_->handle->context, x, y); + ::XDrawPoint(disp, impl_->handle->pixmap, impl_->handle->context, p.x, p.y); #endif if (impl_->changed == false) impl_->changed = true; } @@ -1107,10 +1174,11 @@ namespace paint string(pos, utf8str); } - void graphics::string(const nana::point& text_pos, std::wstring_view str) + void graphics::string(const nana::point& text_pos_, std::wstring_view str) { if (impl_->handle && !str.empty()) { + auto text_pos = platform_abstraction::dpi_scale(text_pos_, impl_->dpi); #if defined(NANA_POSIX) impl_->handle->update_text_color(); #endif @@ -1121,7 +1189,7 @@ namespace paint if (i != end) { auto pos = text_pos; - std::size_t tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.tab_pixels; + std::size_t tab_pixels = impl_->handle->string.tab_length * impl_->handle->string.tab_pixels; /// system-side ? while (true) { auto len = i - begin; @@ -1171,9 +1239,11 @@ namespace paint } #endif - void graphics::line(const nana::point& pos1, const nana::point& pos2) + void graphics::line(const nana::point& pos1_, const nana::point& pos2_) { if (!impl_->handle) return; + auto pos1 = platform_abstraction::dpi_scale(pos1_, impl_->dpi); + auto pos2 = platform_abstraction::dpi_scale(pos2_, impl_->dpi); #if defined(NANA_WINDOWS) if (pos1 != pos2) { @@ -1206,9 +1276,10 @@ namespace paint line_to(pos); } - void graphics::line_to(const point& pos) + void graphics::line_to(const point& pos_) { if (!impl_->handle) return; + auto pos = platform_abstraction::dpi_scale(pos_, impl_->dpi); #if defined(NANA_WINDOWS) auto prv_pen = ::SelectObject(impl_->handle->context, ::CreatePen(PS_SOLID, 1, impl_->handle->bgcolor_native)); @@ -1237,10 +1308,11 @@ namespace paint rectangle(::nana::rectangle{ size() }, solid); } - void graphics::rectangle(const ::nana::rectangle& r, bool solid) + void graphics::rectangle(const ::nana::rectangle& r_, bool solid) { - if (r.width && r.height && impl_->handle && r.right() > 0 && r.bottom() > 0) + if (r_.width && r_.height && impl_->handle && r_.right() > 0 && r_.bottom() > 0) { + auto r = platform_abstraction::dpi_scale(r_, impl_->dpi); #if defined(NANA_WINDOWS) auto brush = ::CreateSolidBrush(impl_->handle->bgcolor_native); @@ -1302,8 +1374,9 @@ namespace paint } } - void graphics::gradual_rectangle(const ::nana::rectangle& rct, const ::nana::color& from, const ::nana::color& to, bool vertical) + void graphics::gradual_rectangle(const ::nana::rectangle& rct_, const ::nana::color& from, const ::nana::color& to, bool vertical) { + auto rct = platform_abstraction::dpi_scale(rct_, impl_->dpi); #if defined(NANA_WINDOWS) if (impl_->pxbuf.open(impl_->handle)) { @@ -1369,10 +1442,15 @@ namespace paint } #define NANA_WINDOWS_RGB(a) (((DWORD)(a) & 0xFF)<<16) | ((DWORD)(a) & 0xFF00) | (((DWORD)(a) & 0xFF0000) >> 16 ) - void graphics::round_rectangle(const ::nana::rectangle& r, unsigned radius_x, unsigned radius_y, const color& clr, bool solid, const color& solid_clr) + + void graphics::round_rectangle(const ::nana::rectangle& r_, unsigned radius_x_, unsigned radius_y_, const color& clr, bool solid, const color& solid_clr) { if (impl_->handle) { + auto r = platform_abstraction::dpi_scale( r_, impl_->dpi); + auto radius_x = platform_abstraction::dpi_scale(radius_x_, impl_->dpi); + auto radius_y = platform_abstraction::dpi_scale(radius_y_, impl_->dpi); + #if defined(NANA_WINDOWS) impl_->handle->set_color(clr); diff --git a/source/paint/pixel_buffer.cpp b/source/paint/pixel_buffer.cpp index 87f478b39..4d625b257 100644 --- a/source/paint/pixel_buffer.cpp +++ b/source/paint/pixel_buffer.cpp @@ -79,12 +79,12 @@ namespace nana{ namespace paint return true; } public: - const drawable_type drawable; //Attached handle + const drawable_type drawable; //Attached handle const nana::rectangle valid_r; - const nana::size pixel_size; - pixel_color_t * raw_pixel_buffer{ nullptr }; - const std::size_t bytes_per_line; - bool alpha_channel{false}; + const nana::size pixel_size; + pixel_color_t * raw_pixel_buffer{ nullptr }; + const std::size_t bytes_per_line; + bool alpha_channel{false}; #if defined(NANA_X11) struct x11_members { @@ -95,32 +95,33 @@ namespace nana{ namespace paint struct image_processor_tag { - paint::image_process::stretch_interface * stretch_receptacle{nullptr}; - paint::image_process::stretch_interface * const * stretch; - paint::image_process::alpha_blend_interface * alpha_blend_receptacle{nullptr}; + paint::image_process::stretch_interface * stretch_receptacle {nullptr}; + paint::image_process::stretch_interface * const * stretch; + paint::image_process::alpha_blend_interface * alpha_blend_receptacle{nullptr}; paint::image_process::alpha_blend_interface * const * alpha_blend; - paint::image_process::blend_interface * blend_receptacle{nullptr}; - paint::image_process::blend_interface * const * blend; - paint::image_process::line_interface * line_receptacle{nullptr}; - paint::image_process::line_interface * const * line; - paint::image_process::blur_interface * blur_receptacle{nullptr}; - paint::image_process::blur_interface * const * blur; + paint::image_process::blend_interface * blend_receptacle {nullptr}; + paint::image_process::blend_interface * const * blend; + paint::image_process::line_interface * line_receptacle {nullptr}; + paint::image_process::line_interface * const * line; + paint::image_process::blur_interface * blur_receptacle {nullptr}; + paint::image_process::blur_interface * const * blur; image_processor_tag() { auto & provider = detail::image_process_provider::instance(); - stretch = provider.stretch(); + stretch = provider.stretch(); alpha_blend = provider.alpha_blend(); - blend = provider.blend(); - line = provider.line(); - blur = provider.blur(); + blend = provider.blend(); + line = provider.line(); + blur = provider.blur(); } + }img_pro; pixel_buffer_storage(std::size_t width, std::size_t height) : drawable(nullptr), valid_r(0, 0, static_cast(width), static_cast(height)), - pixel_size(static_cast(width), static_cast(height)), + pixel_size (static_cast(width), static_cast(height)), bytes_per_line(width * sizeof(pixel_color_t)) { _m_alloc(); @@ -559,24 +560,25 @@ namespace nana{ namespace paint bool pixel_buffer::open(drawable_type drawable, const nana::rectangle & want_rectangle) { - auto sz = nana::paint::detail::drawable_size(drawable); + auto sz = nana::paint::detail::drawable_size(drawable); if(want_rectangle.x >= static_cast(sz.width) || want_rectangle.y >= static_cast(sz.height)) return false; auto want_r = want_rectangle; - if(want_r.width == 0) want_r.width = sz.width - want_r.x; + if(want_r.width == 0) want_r.width = sz.width - want_r.x; if(want_r.height == 0) want_r.height = sz.height - want_r.y; ::nana::rectangle r; if (false == overlap(::nana::rectangle{ sz }, want_r, r)) return false; + #if defined(NANA_WINDOWS) BITMAPINFO bmpinfo; assign_windows_bitmapinfo({want_r.width, want_r.height}, bmpinfo); bool need_dup = (r.width != sz.width || r.height != sz.height); - HDC context = drawable->context; + HDC context = drawable->context; HBITMAP pixmap = drawable->pixmap; HBITMAP orig_bmp = nullptr; @@ -845,7 +847,8 @@ namespace nana{ namespace paint pixel_color_t pixel_buffer::pixel(int x, int y) const { auto sp = storage_.get(); - if(sp && 0 <= x && x < static_cast(sp->pixel_size.width) && 0 <= y && y < static_cast(sp->pixel_size.height)) + if(sp && 0 <= x && x < static_cast(sp->pixel_size.width ) + && 0 <= y && y < static_cast(sp->pixel_size.height)) return *reinterpret_cast(reinterpret_cast(sp->raw_pixel_buffer + x) + y * sp->bytes_per_line); return pixel_color_t(); diff --git a/source/paint/text_renderer.cpp b/source/paint/text_renderer.cpp index 3d9f878e4..d7e512986 100644 --- a/source/paint/text_renderer.cpp +++ b/source/paint/text_renderer.cpp @@ -44,7 +44,7 @@ namespace nana unsigned operator()(const int top, const wchar_t * buf, std::size_t bufsize) { - auto const drawable = graph_.handle(); + //auto const drawable = graph_.handle(); std::vector auto const reordered = unicode_reorder(buf, bufsize); unsigned return_max_height = 0; @@ -52,7 +52,8 @@ namespace nana std::vector word_metrics; for (auto & ent : reordered) { - auto word_sz = detail::text_extent_size(drawable, ent.begin, ent.end - ent.begin); + /// \todo: dpi scale ?? + auto word_sz = graph_.text_extent_size({ent.begin, static_cast(ent.end - ent.begin) }); word_metrics.push_back(word_sz); string_px += word_sz.width; @@ -81,7 +82,7 @@ namespace nana if (pos.x + static_cast(wdm->width) <= right_ - static_cast(ellipsis_px_)) { //This word can be fully painted. - detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin); + graph_.string(pos, {ent.begin, static_cast(ent.end - ent.begin) }); } else { @@ -89,7 +90,7 @@ namespace nana nana::rectangle r{ nana::size{ static_cast(right_ - ellipsis_px_) - pos.x, wdm->height } }; - nana::paint::graphics dummy({ r.width, r.height }); + nana::paint::graphics dummy({ r.width, r.height }, graph_.get_dpi()); dummy.typeface(graph_.typeface()); dummy.bitblt(r, graph_, pos); @@ -98,7 +99,7 @@ namespace nana r.y = top; graph_.bitblt(r, dummy); if (ellipsis_px_) - detail::draw_string(drawable, point{ right_ - static_cast(ellipsis_px_), top }, L"...", 3); + graph_.string(point{ right_ - static_cast(ellipsis_px_), top }, L"..."); break; } } @@ -114,7 +115,7 @@ namespace nana pos.x = (right_ - left_ - string_px) / 2; for (auto & ent : reordered) { - detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin); + graph_.string(pos, {ent.begin, static_cast(ent.end - ent.begin) }); pos.x += (wdm++)->width; } break; @@ -124,7 +125,7 @@ namespace nana for (auto i = reordered.crbegin(); i != reordered.crend(); ++i) { pos.x -= (wdm--)->width; - detail::draw_string(drawable, pos, i->begin, i->end - i->begin); + graph_.string(pos, {i->begin, static_cast(i->end - i->begin) }); } break; } @@ -155,7 +156,7 @@ namespace nana { unsigned return_max_height = 0; - auto const drawable = graph.handle(); + //auto const drawable = graph.handle(); unsigned string_px = 0; std::vector word_metrics; @@ -164,7 +165,8 @@ namespace nana for(auto & i : reordered) { - auto word_sz = detail::text_extent_size(drawable, i.begin, i.end - i.begin); + /// \todo: dpi scale ?? + auto word_sz = graph.text_extent_size({i.begin, static_cast(i.end - i.begin) }); word_metrics.emplace_back(word_sz); string_px += word_sz.width; @@ -206,7 +208,7 @@ namespace nana idx_splitted = find_splitted(idx_head, len, pos.x, right, pxbuf); if(idx_splitted == len) { - detail::draw_string(drawable, pos, i.begin + idx_head, idx_splitted - idx_head); + graph.string(pos, {i.begin + idx_head, idx_splitted - idx_head}); // bidi_string ?? for(std::size_t i = idx_head; i < len; ++i) pos.x += static_cast(pxbuf[i]); @@ -216,7 +218,7 @@ namespace nana //Check the word whether it is splittable. if(splittable(i.begin, idx_splitted)) { - detail::draw_string(drawable, pos, i.begin + idx_head, idx_splitted - idx_head); + graph.string(pos, {i.begin + idx_head, idx_splitted - idx_head}); // bidi_string ?? idx_head = idx_splitted; pos.x = left; pos.y += static_cast(max_height); @@ -235,8 +237,9 @@ namespace nana if(u != head) { - detail::draw_string(drawable, pos, head, u - head); - idx_head += u - head; + const std::size_t ln = u - head; + graph.string(pos, {head, ln }); + idx_head += ln; pos.x = left; pos.y += static_cast(max_height); } @@ -251,7 +254,7 @@ namespace nana std::size_t splen = u - head; pos.y += static_cast(max_height); pos.x = left; - detail::draw_string(drawable, pos, head, splen); + graph.string(pos, {head, splen}); // bidi_string ?? for(std::size_t k = idx_head; k < idx_head + splen; ++k) pos.x += static_cast(pxbuf[k]); @@ -271,14 +274,14 @@ namespace nana { pos.x = left; pos.y += static_cast(max_height); - detail::draw_string(drawable, pos, i.begin, 1); + graph.string(pos, {i.begin, 1}); // bidi_string ?? pos.x += static_cast(wdm->width); } max_height = 0; } else { - detail::draw_string(drawable, pos, i.begin, i.end - i.begin); + graph.string(pos, {i.begin, static_cast(i.end - i.begin) }); // bidi_string ?? pos.x += static_cast(wdm->width); } @@ -299,7 +302,7 @@ namespace nana for(auto & ent : reordered) { if (pos.x + static_cast(wdm->width) > 0) - detail::draw_string(drawable, pos, ent.begin, ent.end - ent.begin); + graph.string(pos, {ent.begin, static_cast(ent.end - ent.begin) }); // bidi_string ?? pos.x += static_cast(wdm->width); ++wdm; @@ -317,7 +320,7 @@ namespace nana std::size_t len = ent.end - ent.begin; pos.x -= static_cast(wdm->width); - detail::draw_string(drawable, pos, ent.begin, len); + graph.string(pos, {ent.begin, len}); // bidi_string ?? ++wdm; } } @@ -373,7 +376,7 @@ namespace nana { unsigned return_max_height = 0; - auto drawable = graph.handle(); + //auto drawable = graph.handle(); std::vector word_metrics; @@ -382,7 +385,8 @@ namespace nana for(auto & i : reordered) { - auto word_sz = detail::text_extent_size(drawable, i.begin, i.end - i.begin); + /// \todo: dpi scale ?? + auto word_sz = graph.text_extent_size({i.begin, static_cast(i.end - i.begin) }); word_metrics.emplace_back(word_sz); string_px += word_sz.width; diff --git a/source/system/platform.cpp b/source/system/platform.cpp index 52b30d79c..466e8db55 100644 --- a/source/system/platform.cpp +++ b/source/system/platform.cpp @@ -104,7 +104,6 @@ namespace system bool get_async_mouse_state(int button) { #if defined(NANA_WINDOWS) - /// \todo: add to dpi_function GetSystemMetricsForDpi and replace this bool swap = (::GetSystemMetrics(SM_SWAPBUTTON) != 0); switch(button) {