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`: 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 @@ public: \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 @@ public: //! 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 @@ public: */ 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 @@ public: //! 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 @@ private: 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 @@ public: //! 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 @@ public: 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/irr/src/CIrrDeviceSDL.cpp b/irr/src/CIrrDeviceSDL.cpp index cc7505c72..6dfa84d09 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 @@ private: #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(); diff --git a/src/client/clientlauncher.cpp b/src/client/clientlauncher.cpp index 9d07a7528..cdadd5ce2 100644 --- a/src/client/clientlauncher.cpp +++ b/src/client/clientlauncher.cpp @@ -353,6 +353,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 @@ public: */ 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 @@ public: //! 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 @@ private: { 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];