From 4c001bd24854b56f6e09372c4ac6870770053f98 Mon Sep 17 00:00:00 2001 From: grorp Date: Wed, 26 Jun 2024 15:25:27 +0200 Subject: [PATCH 1/3] Make button sprites (scrollbar arrows) DPI-aware (#14772) --- irr/include/IGUIButton.h | 5 +--- irr/include/IGUISkin.h | 6 +++++ irr/src/CGUIButton.cpp | 40 +++++++++++++++---------------- irr/src/CGUIButton.h | 10 +++----- irr/src/CGUISkin.h | 7 ++++++ src/client/clientlauncher.cpp | 1 + src/gui/guiButton.cpp | 44 ++++++++++++++++------------------- src/gui/guiButton.h | 8 ++----- src/gui/guiSkin.h | 7 ++++++ 9 files changed, 67 insertions(+), 61 deletions(-) diff --git a/irr/include/IGUIButton.h b/irr/include/IGUIButton.h index 0fbf866ac..8870f8b1c 100644 --- a/irr/include/IGUIButton.h +++ b/irr/include/IGUIButton.h @@ -200,7 +200,7 @@ class IGUIButton : public IGUIElement \param loop: True if the animation should loop, false if not \param scale: True if the sprite should scale to button size, false if not */ virtual void setSprite(EGUI_BUTTON_STATE state, s32 index, - video::SColor color = video::SColor(255, 255, 255, 255), bool loop = false, bool scale = false) = 0; + video::SColor color = video::SColor(255, 255, 255, 255), bool loop = false) = 0; //! Get the sprite-index for the given state or -1 when no sprite is set virtual s32 getSpriteIndex(EGUI_BUTTON_STATE state) const = 0; @@ -211,9 +211,6 @@ class IGUIButton : public IGUIElement //! Returns if the sprite in the given state does loop virtual bool getSpriteLoop(EGUI_BUTTON_STATE state) const = 0; - //! Returns if the sprite in the given state is scaled - virtual bool getSpriteScale(EGUI_BUTTON_STATE state) const = 0; - //! Sets if the button should behave like a push button. /** Which means it can be in two states: Normal or Pressed. With a click on the button, the user can change the state of the button. */ diff --git a/irr/include/IGUISkin.h b/irr/include/IGUISkin.h index 6ec456472..36b510606 100644 --- a/irr/include/IGUISkin.h +++ b/irr/include/IGUISkin.h @@ -374,6 +374,12 @@ const c8 *const GUISkinFontNames[EGDF_COUNT + 1] = { class IGUISkin : virtual public IReferenceCounted { public: + //! returns display density scaling factor + virtual float getScale() const = 0; + + //! sets display density scaling factor + virtual void setScale(float scale) = 0; + //! returns default color virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const = 0; diff --git a/irr/src/CGUIButton.cpp b/irr/src/CGUIButton.cpp index f023024f9..60bab5f83 100644 --- a/irr/src/CGUIButton.cpp +++ b/irr/src/CGUIButton.cpp @@ -75,12 +75,11 @@ void CGUIButton::setSpriteBank(IGUISpriteBank *sprites) SpriteBank = sprites; } -void CGUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale) +void CGUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop) { ButtonSprites[(u32)state].Index = index; ButtonSprites[(u32)state].Color = color; ButtonSprites[(u32)state].Loop = loop; - ButtonSprites[(u32)state].Scale = scale; } //! Get the sprite-index for the given state or -1 when no sprite is set @@ -101,12 +100,6 @@ bool CGUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const return ButtonSprites[(u32)state].Loop; } -//! Returns if the sprite in the given state is scaled -bool CGUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const -{ - return ButtonSprites[(u32)state].Scale; -} - //! called if an event happened. bool CGUIButton::OnEvent(const SEvent &event) { @@ -294,19 +287,26 @@ void CGUIButton::draw() void CGUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di ¢er) { u32 stateIdx = (u32)state; + s32 spriteIdx = ButtonSprites[stateIdx].Index; + if (spriteIdx == -1) + return; - if (ButtonSprites[stateIdx].Index != -1) { - if (ButtonSprites[stateIdx].Scale) { - const video::SColor colors[] = {ButtonSprites[stateIdx].Color, ButtonSprites[stateIdx].Color, ButtonSprites[stateIdx].Color, ButtonSprites[stateIdx].Color}; - SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect, - &AbsoluteClippingRect, colors, - os::Timer::getTime() - startTime, ButtonSprites[stateIdx].Loop); - } else { - SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center, - &AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, os::Timer::getTime(), - ButtonSprites[stateIdx].Loop, true); - } - } + u32 rectIdx = SpriteBank->getSprites()[spriteIdx].Frames[0].rectNumber; + core::rect srcRect = SpriteBank->getPositions()[rectIdx]; + + IGUISkin *skin = Environment->getSkin(); + s32 scale = std::max(std::floor(skin->getScale()), 1.0f); + core::rect rect(center, srcRect.getSize() * scale); + rect -= rect.getSize() / 2; + + const video::SColor colors[] = { + ButtonSprites[stateIdx].Color, + ButtonSprites[stateIdx].Color, + ButtonSprites[stateIdx].Color, + ButtonSprites[stateIdx].Color, + }; + SpriteBank->draw2DSprite(spriteIdx, rect, &AbsoluteClippingRect, colors, + os::Timer::getTime() - startTime, ButtonSprites[stateIdx].Loop); } EGUI_BUTTON_IMAGE_STATE CGUIButton::getImageState(bool pressed) const diff --git a/irr/src/CGUIButton.h b/irr/src/CGUIButton.h index 8ff36c9a7..8a1434025 100644 --- a/irr/src/CGUIButton.h +++ b/irr/src/CGUIButton.h @@ -92,7 +92,7 @@ class CGUIButton : public IGUIButton */ virtual void setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color = video::SColor(255, 255, 255, 255), - bool loop = false, bool scale = false) override; + bool loop = false) override; //! Get the sprite-index for the given state or -1 when no sprite is set s32 getSpriteIndex(EGUI_BUTTON_STATE state) const override; @@ -103,9 +103,6 @@ class CGUIButton : public IGUIButton //! Returns if the sprite in the given state does loop bool getSpriteLoop(EGUI_BUTTON_STATE state) const override; - //! Returns if the sprite in the given state is scaled - bool getSpriteScale(EGUI_BUTTON_STATE state) const override; - //! Sets if the button should behave like a push button. Which means it //! can be in two states: Normal or Pressed. With a click on the button, //! the user can change the state of the button. @@ -158,19 +155,18 @@ class CGUIButton : public IGUIButton struct ButtonSprite { ButtonSprite() : - Index(-1), Loop(false), Scale(false) + Index(-1), Loop(false) { } bool operator==(const ButtonSprite &other) const { - return Index == other.Index && Color == other.Color && Loop == other.Loop && Scale == other.Scale; + return Index == other.Index && Color == other.Color && Loop == other.Loop; } s32 Index; video::SColor Color; bool Loop; - bool Scale; }; ButtonSprite ButtonSprites[EGBS_COUNT]; diff --git a/irr/src/CGUISkin.h b/irr/src/CGUISkin.h index 130e5fada..68eae1c73 100644 --- a/irr/src/CGUISkin.h +++ b/irr/src/CGUISkin.h @@ -24,6 +24,12 @@ class CGUISkin : public IGUISkin //! destructor virtual ~CGUISkin(); + //! returns display density scaling factor + virtual float getScale() const override { return Scale; } + + //! sets display density scaling factor + virtual void setScale(float scale) override { Scale = scale; } + //! returns default color video::SColor getColor(EGUI_DEFAULT_COLOR color) const override; @@ -210,6 +216,7 @@ class CGUISkin : public IGUISkin EGUI_SKIN_TYPE getType() const override; private: + float Scale = 1.0f; video::SColor Colors[EGDC_COUNT]; s32 Sizes[EGDS_COUNT]; u32 Icons[EGDI_COUNT]; diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index f64d02844..5365d70f9 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -352,6 +352,7 @@ void ClientLauncher::config_guienv() float density = rangelim(g_settings->getFloat("gui_scaling"), 0.5f, 20) * RenderingEngine::getDisplayDensity(); + skin->setScale(density); skin->setSize(gui::EGDS_CHECK_BOX_WIDTH, (s32)(17.0f * density)); skin->setSize(gui::EGDS_SCROLLBAR_SIZE, (s32)(21.0f * density)); skin->setSize(gui::EGDS_WINDOW_BUTTON_WIDTH, (s32)(15.0f * density)); diff --git a/src/gui/guiButton.cpp b/src/gui/guiButton.cpp index 4e47e7425..d78433edd 100644 --- a/src/gui/guiButton.cpp +++ b/src/gui/guiButton.cpp @@ -89,12 +89,11 @@ void GUIButton::setSpriteBank(IGUISpriteBank* sprites) SpriteBank = sprites; } -void GUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop, bool scale) +void GUIButton::setSprite(EGUI_BUTTON_STATE state, s32 index, video::SColor color, bool loop) { ButtonSprites[(u32)state].Index = index; ButtonSprites[(u32)state].Color = color; ButtonSprites[(u32)state].Loop = loop; - ButtonSprites[(u32)state].Scale = scale; } //! Get the sprite-index for the given state or -1 when no sprite is set @@ -115,12 +114,6 @@ bool GUIButton::getSpriteLoop(EGUI_BUTTON_STATE state) const return ButtonSprites[(u32)state].Loop; } -//! Returns if the sprite in the given state is scaled -bool GUIButton::getSpriteScale(EGUI_BUTTON_STATE state) const -{ - return ButtonSprites[(u32)state].Scale; -} - //! called if an event happened. bool GUIButton::OnEvent(const SEvent& event) { @@ -354,23 +347,26 @@ void GUIButton::draw() void GUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center) { u32 stateIdx = (u32)state; + s32 spriteIdx = ButtonSprites[stateIdx].Index; + if (spriteIdx == -1) + return; - if (ButtonSprites[stateIdx].Index != -1) - { - if ( ButtonSprites[stateIdx].Scale ) - { - const video::SColor colors[] = {ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color}; - SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect.UpperLeftCorner, - &AbsoluteClippingRect, colors[0], // FIXME: remove [0] - porting::getTimeMs()-startTime, ButtonSprites[stateIdx].Loop); - } - else - { - SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center, - &AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, porting::getTimeMs(), - ButtonSprites[stateIdx].Loop, true); - } - } + u32 rectIdx = SpriteBank->getSprites()[spriteIdx].Frames[0].rectNumber; + core::rect srcRect = SpriteBank->getPositions()[rectIdx]; + + IGUISkin *skin = Environment->getSkin(); + s32 scale = std::max(std::floor(skin->getScale()), 1.0f); + core::rect rect(center, srcRect.getSize() * scale); + rect -= rect.getSize() / 2; + + const video::SColor colors[] = { + ButtonSprites[stateIdx].Color, + ButtonSprites[stateIdx].Color, + ButtonSprites[stateIdx].Color, + ButtonSprites[stateIdx].Color, + }; + SpriteBank->draw2DSprite(spriteIdx, rect, &AbsoluteClippingRect, colors, + porting::getTimeMs() - startTime, ButtonSprites[stateIdx].Loop); } EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const diff --git a/src/gui/guiButton.h b/src/gui/guiButton.h index c96f1ca4e..4fad8747c 100644 --- a/src/gui/guiButton.h +++ b/src/gui/guiButton.h @@ -92,7 +92,7 @@ class GUIButton : public gui::IGUIButton */ virtual void setSprite(gui::EGUI_BUTTON_STATE state, s32 index, video::SColor color=video::SColor(255,255,255,255), - bool loop=false, bool scale=false) override; + bool loop=false) override; //! Get the sprite-index for the given state or -1 when no sprite is set virtual s32 getSpriteIndex(gui::EGUI_BUTTON_STATE state) const override; @@ -103,9 +103,6 @@ class GUIButton : public gui::IGUIButton //! Returns if the sprite in the given state does loop virtual bool getSpriteLoop(gui::EGUI_BUTTON_STATE state) const override; - //! Returns if the sprite in the given state is scaled - virtual bool getSpriteScale(gui::EGUI_BUTTON_STATE state) const override; - //! Sets if the button should behave like a push button. Which means it //! can be in two states: Normal or Pressed. With a click on the button, //! the user can change the state of the button. @@ -230,13 +227,12 @@ class GUIButton : public gui::IGUIButton { bool operator==(const ButtonSprite &other) const { - return Index == other.Index && Color == other.Color && Loop == other.Loop && Scale == other.Scale; + return Index == other.Index && Color == other.Color && Loop == other.Loop; } s32 Index = -1; video::SColor Color; bool Loop = false; - bool Scale = false; }; ButtonSprite ButtonSprites[gui::EGBS_COUNT]; diff --git a/src/gui/guiSkin.h b/src/gui/guiSkin.h index 623a9c30a..33df7a933 100644 --- a/src/gui/guiSkin.h +++ b/src/gui/guiSkin.h @@ -27,6 +27,12 @@ namespace gui //! destructor virtual ~GUISkin(); + //! returns display density scaling factor + virtual float getScale() const { return Scale; } + + //! sets display density scaling factor + virtual void setScale(float scale) { Scale = scale; } + //! returns default color virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const; @@ -292,6 +298,7 @@ namespace gui private: + float Scale = 1.0f; video::SColor Colors[EGDC_COUNT]; s32 Sizes[EGDS_COUNT]; u32 Icons[EGDI_COUNT]; From 514e106414961784cfc9d55e375916747160e58d Mon Sep 17 00:00:00 2001 From: Erich Schubert Date: Wed, 26 Jun 2024 22:21:18 +0200 Subject: [PATCH 2/3] Fix missing newline before Markdown list (#14783) Renders incorrectly e.g. on https://api.minetest.net/spatial-vectors/ --- doc/lua_api.md | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/lua_api.md b/doc/lua_api.md index 3952062e8..ee1f4060b 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -3902,6 +3902,7 @@ Operators --------- Operators can be used if all of the involved vectors have metatables: + * `v1 == v2`: * Returns whether `v1` and `v2` are identical. * `-v`: From 9a1501ae89ffe79c38dbd6756c9e7ed647dd7dc1 Mon Sep 17 00:00:00 2001 From: grorp Date: Thu, 27 Jun 2024 14:44:44 +0200 Subject: [PATCH 3/3] CIrrDeviceSDL: Fix numpad key events not having correct KeyInput.Char (#14780) Allows you to change viewing range using numpad +/- again. This fix also works with the current unreleased version of SDL 3. The keycodes for numpad keys (both SDL keycodes and Irrlicht keycodes) are not the same as the keycodes for the equivalent non-numpad keys and don't correspond to chars, so I mapped them to chars manually. Since I think the resolution of https://github.com/minetest/minetest/issues/13770 was "just disable numlock", I made sure to only do this for the numpad number keys if numlock is enabled. --- irr/src/CIrrDeviceSDL.cpp | 63 +++++++++++++++++++++++++++++++++------ irr/src/CIrrDeviceSDL.h | 4 +-- 2 files changed, 56 insertions(+), 11 deletions(-) diff --git a/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index f8fb66da3..a930bec39 100644 --- a/irr/src/CIrrDeviceSDL.cpp +++ b/irr/src/CIrrDeviceSDL.cpp @@ -129,9 +129,9 @@ EM_BOOL CIrrDeviceSDL::MouseLeaveCallback(int eventType, const EmscriptenMouseEv } #endif -bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE key) +bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE irrlichtKey) { - switch (key) { + switch (irrlichtKey) { // keys which are known to have safe special character interpretation // could need changes over time (removals and additions!) case KEY_RETURN: @@ -189,24 +189,68 @@ bool CIrrDeviceSDL::keyIsKnownSpecial(EKEY_CODE key) } } -int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key) +int CIrrDeviceSDL::findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock) { + switch (irrlichtKey) { // special cases that always return a char regardless of how the SDL keycode // looks - switch (key) { case KEY_RETURN: case KEY_ESCAPE: - return (int)key; + return (int)irrlichtKey; + + // This is necessary for keys on the numpad because they don't use the same + // keycodes as their non-numpad versions (whose keycodes correspond to chars), + // but have their own SDL keycodes and their own Irrlicht keycodes (which + // don't correspond to chars). + case KEY_MULTIPLY: + return '*'; + case KEY_ADD: + return '+'; + case KEY_SUBTRACT: + return '-'; + case KEY_DIVIDE: + return '/'; + default: break; } + if (numlock) { + // Number keys on the numpad are also affected, but we only want them + // to produce number chars when numlock is enabled. + switch (irrlichtKey) { + case KEY_NUMPAD0: + return '0'; + case KEY_NUMPAD1: + return '1'; + case KEY_NUMPAD2: + return '2'; + case KEY_NUMPAD3: + return '3'; + case KEY_NUMPAD4: + return '4'; + case KEY_NUMPAD5: + return '5'; + case KEY_NUMPAD6: + return '6'; + case KEY_NUMPAD7: + return '7'; + case KEY_NUMPAD8: + return '8'; + case KEY_NUMPAD9: + return '9'; + default: + break; + } + } + // SDL in-place ORs values with no character representation with 1<<30 // https://wiki.libsdl.org/SDL2/SDLKeycodeLookup - if (assumedChar & (1 << 30)) + // This also affects the numpad keys btw. + if (sdlKey & (1 << 30)) return 0; - switch (key) { + switch (irrlichtKey) { case KEY_PRIOR: case KEY_NEXT: case KEY_HOME: @@ -218,7 +262,7 @@ int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key) case KEY_NUMLOCK: return 0; default: - return assumedChar; + return sdlKey; } } @@ -825,7 +869,8 @@ bool CIrrDeviceSDL::run() irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN); irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0; irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL) != 0; - irrevent.KeyInput.Char = findCharToPassToIrrlicht(mp.SDLKey, key); + irrevent.KeyInput.Char = findCharToPassToIrrlicht(mp.SDLKey, key, + (SDL_event.key.keysym.mod & KMOD_NUM) != 0); postEventFromUser(irrevent); } break; diff --git a/irr/src/CIrrDeviceSDL.h b/irr/src/CIrrDeviceSDL.h index 8c7c7c3e1..1f91cbceb 100644 --- a/irr/src/CIrrDeviceSDL.h +++ b/irr/src/CIrrDeviceSDL.h @@ -273,10 +273,10 @@ class CIrrDeviceSDL : public CIrrDeviceStub #endif // Check if a key is a known special character with no side effects on text boxes. - static bool keyIsKnownSpecial(EKEY_CODE key); + static bool keyIsKnownSpecial(EKEY_CODE irrlichtKey); // Return the Char that should be sent to Irrlicht for the given key (either the one passed in or 0). - static int findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key); + static int findCharToPassToIrrlicht(uint32_t sdlKey, EKEY_CODE irrlichtKey, bool numlock); // Check if a text box is in focus. Enable or disable SDL_TEXTINPUT events only if in focus. void resetReceiveTextInputEvents();