This commit is contained in:
DustyBagel 2024-06-27 17:53:40 -05:00
commit eff77e1f7f
12 changed files with 124 additions and 72 deletions

@ -3902,6 +3902,7 @@ Operators
--------- ---------
Operators can be used if all of the involved vectors have metatables: Operators can be used if all of the involved vectors have metatables:
* `v1 == v2`: * `v1 == v2`:
* Returns whether `v1` and `v2` are identical. * Returns whether `v1` and `v2` are identical.
* `-v`: * `-v`:

@ -200,7 +200,7 @@ class IGUIButton : public IGUIElement
\param loop: True if the animation should loop, false if not \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 */ \param scale: True if the sprite should scale to button size, false if not */
virtual void setSprite(EGUI_BUTTON_STATE state, s32 index, 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 //! Get the sprite-index for the given state or -1 when no sprite is set
virtual s32 getSpriteIndex(EGUI_BUTTON_STATE state) const = 0; 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 //! Returns if the sprite in the given state does loop
virtual bool getSpriteLoop(EGUI_BUTTON_STATE state) const = 0; 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. //! 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, /** 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. */ the user can change the state of the button. */

@ -374,6 +374,12 @@ const c8 *const GUISkinFontNames[EGDF_COUNT + 1] = {
class IGUISkin : virtual public IReferenceCounted class IGUISkin : virtual public IReferenceCounted
{ {
public: 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 //! returns default color
virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const = 0; virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const = 0;

@ -75,12 +75,11 @@ void CGUIButton::setSpriteBank(IGUISpriteBank *sprites)
SpriteBank = 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].Index = index;
ButtonSprites[(u32)state].Color = color; ButtonSprites[(u32)state].Color = color;
ButtonSprites[(u32)state].Loop = loop; 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 //! 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; 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. //! called if an event happened.
bool CGUIButton::OnEvent(const SEvent &event) 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 &center) void CGUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di &center)
{ {
u32 stateIdx = (u32)state; u32 stateIdx = (u32)state;
s32 spriteIdx = ButtonSprites[stateIdx].Index;
if (spriteIdx == -1)
return;
if (ButtonSprites[stateIdx].Index != -1) { u32 rectIdx = SpriteBank->getSprites()[spriteIdx].Frames[0].rectNumber;
if (ButtonSprites[stateIdx].Scale) { core::rect<s32> srcRect = SpriteBank->getPositions()[rectIdx];
const video::SColor colors[] = {ButtonSprites[stateIdx].Color, ButtonSprites[stateIdx].Color, ButtonSprites[stateIdx].Color, ButtonSprites[stateIdx].Color};
SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect, IGUISkin *skin = Environment->getSkin();
&AbsoluteClippingRect, colors, s32 scale = std::max(std::floor(skin->getScale()), 1.0f);
os::Timer::getTime() - startTime, ButtonSprites[stateIdx].Loop); core::rect<s32> rect(center, srcRect.getSize() * scale);
} else { rect -= rect.getSize() / 2;
SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center,
&AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, os::Timer::getTime(), const video::SColor colors[] = {
ButtonSprites[stateIdx].Loop, true); 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 EGUI_BUTTON_IMAGE_STATE CGUIButton::getImageState(bool pressed) const

@ -92,7 +92,7 @@ class CGUIButton : public IGUIButton
*/ */
virtual void setSprite(EGUI_BUTTON_STATE state, s32 index, virtual void setSprite(EGUI_BUTTON_STATE state, s32 index,
video::SColor color = video::SColor(255, 255, 255, 255), 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 //! Get the sprite-index for the given state or -1 when no sprite is set
s32 getSpriteIndex(EGUI_BUTTON_STATE state) const override; 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 //! Returns if the sprite in the given state does loop
bool getSpriteLoop(EGUI_BUTTON_STATE state) const override; 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 //! 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, //! can be in two states: Normal or Pressed. With a click on the button,
//! the user can change the state of the button. //! the user can change the state of the button.
@ -158,19 +155,18 @@ class CGUIButton : public IGUIButton
struct ButtonSprite struct ButtonSprite
{ {
ButtonSprite() : ButtonSprite() :
Index(-1), Loop(false), Scale(false) Index(-1), Loop(false)
{ {
} }
bool operator==(const ButtonSprite &other) const 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; s32 Index;
video::SColor Color; video::SColor Color;
bool Loop; bool Loop;
bool Scale;
}; };
ButtonSprite ButtonSprites[EGBS_COUNT]; ButtonSprite ButtonSprites[EGBS_COUNT];

@ -24,6 +24,12 @@ class CGUISkin : public IGUISkin
//! destructor //! destructor
virtual ~CGUISkin(); 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 //! returns default color
video::SColor getColor(EGUI_DEFAULT_COLOR color) const override; video::SColor getColor(EGUI_DEFAULT_COLOR color) const override;
@ -210,6 +216,7 @@ class CGUISkin : public IGUISkin
EGUI_SKIN_TYPE getType() const override; EGUI_SKIN_TYPE getType() const override;
private: private:
float Scale = 1.0f;
video::SColor Colors[EGDC_COUNT]; video::SColor Colors[EGDC_COUNT];
s32 Sizes[EGDS_COUNT]; s32 Sizes[EGDS_COUNT];
u32 Icons[EGDI_COUNT]; u32 Icons[EGDI_COUNT];

@ -129,9 +129,9 @@ EM_BOOL CIrrDeviceSDL::MouseLeaveCallback(int eventType, const EmscriptenMouseEv
} }
#endif #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 // keys which are known to have safe special character interpretation
// could need changes over time (removals and additions!) // could need changes over time (removals and additions!)
case KEY_RETURN: 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 // special cases that always return a char regardless of how the SDL keycode
// looks // looks
switch (key) {
case KEY_RETURN: case KEY_RETURN:
case KEY_ESCAPE: 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: default:
break; 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 // SDL in-place ORs values with no character representation with 1<<30
// https://wiki.libsdl.org/SDL2/SDLKeycodeLookup // https://wiki.libsdl.org/SDL2/SDLKeycodeLookup
if (assumedChar & (1 << 30)) // This also affects the numpad keys btw.
if (sdlKey & (1 << 30))
return 0; return 0;
switch (key) { switch (irrlichtKey) {
case KEY_PRIOR: case KEY_PRIOR:
case KEY_NEXT: case KEY_NEXT:
case KEY_HOME: case KEY_HOME:
@ -218,7 +262,7 @@ int CIrrDeviceSDL::findCharToPassToIrrlicht(int assumedChar, EKEY_CODE key)
case KEY_NUMLOCK: case KEY_NUMLOCK:
return 0; return 0;
default: default:
return assumedChar; return sdlKey;
} }
} }
@ -825,7 +869,8 @@ bool CIrrDeviceSDL::run()
irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN); irrevent.KeyInput.PressedDown = (SDL_event.type == SDL_KEYDOWN);
irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0; irrevent.KeyInput.Shift = (SDL_event.key.keysym.mod & KMOD_SHIFT) != 0;
irrevent.KeyInput.Control = (SDL_event.key.keysym.mod & KMOD_CTRL) != 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); postEventFromUser(irrevent);
} break; } break;

@ -273,10 +273,10 @@ class CIrrDeviceSDL : public CIrrDeviceStub
#endif #endif
// Check if a key is a known special character with no side effects on text boxes. // 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). // 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. // Check if a text box is in focus. Enable or disable SDL_TEXTINPUT events only if in focus.
void resetReceiveTextInputEvents(); void resetReceiveTextInputEvents();

@ -353,6 +353,7 @@ void ClientLauncher::config_guienv()
float density = rangelim(g_settings->getFloat("gui_scaling"), 0.5f, 20) * float density = rangelim(g_settings->getFloat("gui_scaling"), 0.5f, 20) *
RenderingEngine::getDisplayDensity(); RenderingEngine::getDisplayDensity();
skin->setScale(density);
skin->setSize(gui::EGDS_CHECK_BOX_WIDTH, (s32)(17.0f * 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_SCROLLBAR_SIZE, (s32)(21.0f * density));
skin->setSize(gui::EGDS_WINDOW_BUTTON_WIDTH, (s32)(15.0f * density)); skin->setSize(gui::EGDS_WINDOW_BUTTON_WIDTH, (s32)(15.0f * density));

@ -89,12 +89,11 @@ void GUIButton::setSpriteBank(IGUISpriteBank* sprites)
SpriteBank = 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].Index = index;
ButtonSprites[(u32)state].Color = color; ButtonSprites[(u32)state].Color = color;
ButtonSprites[(u32)state].Loop = loop; 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 //! 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; 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. //! called if an event happened.
bool GUIButton::OnEvent(const SEvent& event) 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) void GUIButton::drawSprite(EGUI_BUTTON_STATE state, u32 startTime, const core::position2di& center)
{ {
u32 stateIdx = (u32)state; u32 stateIdx = (u32)state;
s32 spriteIdx = ButtonSprites[stateIdx].Index;
if (spriteIdx == -1)
return;
if (ButtonSprites[stateIdx].Index != -1) u32 rectIdx = SpriteBank->getSprites()[spriteIdx].Frames[0].rectNumber;
{ core::rect<s32> srcRect = SpriteBank->getPositions()[rectIdx];
if ( ButtonSprites[stateIdx].Scale )
{ IGUISkin *skin = Environment->getSkin();
const video::SColor colors[] = {ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color,ButtonSprites[stateIdx].Color}; s32 scale = std::max(std::floor(skin->getScale()), 1.0f);
SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, AbsoluteRect.UpperLeftCorner, core::rect<s32> rect(center, srcRect.getSize() * scale);
&AbsoluteClippingRect, colors[0], // FIXME: remove [0] rect -= rect.getSize() / 2;
porting::getTimeMs()-startTime, ButtonSprites[stateIdx].Loop);
} const video::SColor colors[] = {
else ButtonSprites[stateIdx].Color,
{ ButtonSprites[stateIdx].Color,
SpriteBank->draw2DSprite(ButtonSprites[stateIdx].Index, center, ButtonSprites[stateIdx].Color,
&AbsoluteClippingRect, ButtonSprites[stateIdx].Color, startTime, porting::getTimeMs(), ButtonSprites[stateIdx].Color,
ButtonSprites[stateIdx].Loop, true); };
} SpriteBank->draw2DSprite(spriteIdx, rect, &AbsoluteClippingRect, colors,
} porting::getTimeMs() - startTime, ButtonSprites[stateIdx].Loop);
} }
EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const EGUI_BUTTON_IMAGE_STATE GUIButton::getImageState(bool pressed) const

@ -92,7 +92,7 @@ class GUIButton : public gui::IGUIButton
*/ */
virtual void setSprite(gui::EGUI_BUTTON_STATE state, s32 index, virtual void setSprite(gui::EGUI_BUTTON_STATE state, s32 index,
video::SColor color=video::SColor(255,255,255,255), 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 //! 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; 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 //! Returns if the sprite in the given state does loop
virtual bool getSpriteLoop(gui::EGUI_BUTTON_STATE state) const override; 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 //! 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, //! can be in two states: Normal or Pressed. With a click on the button,
//! the user can change the state of 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 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; s32 Index = -1;
video::SColor Color; video::SColor Color;
bool Loop = false; bool Loop = false;
bool Scale = false;
}; };
ButtonSprite ButtonSprites[gui::EGBS_COUNT]; ButtonSprite ButtonSprites[gui::EGBS_COUNT];

@ -27,6 +27,12 @@ namespace gui
//! destructor //! destructor
virtual ~GUISkin(); 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 //! returns default color
virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const; virtual video::SColor getColor(EGUI_DEFAULT_COLOR color) const;
@ -292,6 +298,7 @@ namespace gui
private: private:
float Scale = 1.0f;
video::SColor Colors[EGDC_COUNT]; video::SColor Colors[EGDC_COUNT];
s32 Sizes[EGDS_COUNT]; s32 Sizes[EGDS_COUNT];
u32 Icons[EGDI_COUNT]; u32 Icons[EGDI_COUNT];