diff options
author | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2025-03-29 20:34:14 +0100 |
---|---|---|
committer | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2025-03-31 12:49:57 +0200 |
commit | 80f76c3aae438f7b9a7c1359c3f37aac460f934b (patch) | |
tree | c5786337049f701db3a22c432d773eaac4525012 /src | |
parent | 2739d3cface75a5477918ce03bd2f85b3244fe1a (diff) | |
download | mana-80f76c3aae438f7b9a7c1359c3f37aac460f934b.tar.gz mana-80f76c3aae438f7b9a7c1359c3f37aac460f934b.tar.bz2 mana-80f76c3aae438f7b9a7c1359c3f37aac460f934b.tar.xz mana-80f76c3aae438f7b9a7c1359c3f37aac460f934b.zip |
GUI: Apply clipping only where necessary
Clipping has been disabled globally by taking it out of
Graphics::pushClipArea. Now its name is a little confusing, but it can't
just be changed since it is part of Guichan.
Widgets that do need to clip their children use the new
Graphics::pushClipRect, which pushes a clipping rectangle without
affecting the local coordinates. These are:
* ScrollArea
* TextField
* TabbedArea (scrolling tabs)
* MiniMap
While it might count as a small optimization, I'm actually disabling
clipping because it is not always desired. For example it gets in the
way of rendering the complete ResizeGrip in the Jewelry theme because
that's a child widget.
Diffstat (limited to 'src')
-rw-r--r-- | src/graphics.cpp | 17 | ||||
-rw-r--r-- | src/graphics.h | 8 | ||||
-rw-r--r-- | src/gui/itempopup.cpp | 3 | ||||
-rw-r--r-- | src/gui/minimap.cpp | 51 | ||||
-rw-r--r-- | src/gui/widgets/scrollarea.cpp | 10 | ||||
-rw-r--r-- | src/gui/widgets/scrollarea.h | 5 | ||||
-rw-r--r-- | src/gui/widgets/tabbedarea.cpp | 49 | ||||
-rw-r--r-- | src/gui/widgets/tabbedarea.h | 2 | ||||
-rw-r--r-- | src/gui/widgets/textfield.cpp | 5 | ||||
-rw-r--r-- | src/openglgraphics.cpp | 38 | ||||
-rw-r--r-- | src/openglgraphics.h | 2 | ||||
-rw-r--r-- | src/sdlgraphics.cpp | 30 | ||||
-rw-r--r-- | src/sdlgraphics.h | 9 |
13 files changed, 123 insertions, 106 deletions
diff --git a/src/graphics.cpp b/src/graphics.cpp index 72101069..9b8cce83 100644 --- a/src/graphics.cpp +++ b/src/graphics.cpp @@ -237,3 +237,20 @@ void Graphics::_endDraw() { popClipArea(); } + +void Graphics::pushClipRect(const gcn::Rectangle &rect) +{ + const gcn::ClipRectangle &carea = mClipStack.top(); + mClipRects.emplace(rect.x + carea.xOffset, + rect.y + carea.yOffset, + rect.width, + rect.height); + + updateClipRect(); +} + +void Graphics::popClipRect() +{ + mClipRects.pop(); + updateClipRect(); +} diff --git a/src/graphics.h b/src/graphics.h index 4df63932..4b03023d 100644 --- a/src/graphics.h +++ b/src/graphics.h @@ -261,11 +261,19 @@ class Graphics : public gcn::Graphics return mColor; } + void pushClipRect(const gcn::Rectangle &rect); + void popClipRect(); + protected: + virtual void updateClipRect() = 0; + int mWidth = 0; int mHeight = 0; float mScale = 1.0f; gcn::Color mColor; + + // Actual clipping rects. Clipping by gcn::Graphics::mClipStack is disabled. + std::stack<gcn::Rectangle> mClipRects; }; extern Graphics *graphics; diff --git a/src/gui/itempopup.cpp b/src/gui/itempopup.cpp index c21f4003..35951331 100644 --- a/src/gui/itempopup.cpp +++ b/src/gui/itempopup.cpp @@ -23,7 +23,6 @@ #include "gui/itempopup.h" #include "configuration.h" -#include "graphics.h" #include "units.h" #include "gui/gui.h" @@ -35,7 +34,6 @@ #include "utils/gettext.h" #include "utils/stringutils.h" -#include "resources/image.h" #include "resources/resourcemanager.h" #include "resources/theme.h" @@ -139,6 +137,7 @@ void ItemPopup::setNoItem() mItemDesc->setText(std::string()); mItemEffect->setText(std::string()); + mItemWeight->setText(std::string()); setContentSize(mItemName->getWidth(), mItemName->getHeight()); } diff --git a/src/gui/minimap.cpp b/src/gui/minimap.cpp index fc7fddd0..8924bc26 100644 --- a/src/gui/minimap.cpp +++ b/src/gui/minimap.cpp @@ -37,6 +37,7 @@ #include "utils/filesystem.h" #include "utils/gettext.h" +#include <algorithm> #include <guichan/font.hpp> Minimap::Minimap(): @@ -136,40 +137,38 @@ void Minimap::draw(gcn::Graphics *graphics) { Window::draw(graphics); + if (!mMap) + return; + + auto g = static_cast<Graphics*>(graphics); const gcn::Rectangle a = getChildrenArea(); - graphics->pushClipArea(a); + g->pushClipRect(a); // does actual clipping + g->pushClipArea(a); // only applies an offset + + const int tileWidth = mMap->getTileWidth(); + const int tileHeight = mMap->getTileHeight(); int mapOriginX = 0; int mapOriginY = 0; - if (mMapImage && mMap) + if (mMapImage) { if (mMapImage->getWidth() > a.width || mMapImage->getHeight() > a.height) { const Vector &p = local_player->getPosition(); - mapOriginX = (int) (((a.width) / 2) - (int) (p.x * mWidthProportion) - / mMap->getTileWidth()); - mapOriginY = (int) (((a.height) / 2) - - (int) (p.y * mHeightProportion) - / mMap->getTileHeight()); + mapOriginX = (a.width / 2) - (int) (p.x * mWidthProportion) / tileWidth; + mapOriginY = (a.height / 2) - (int) (p.y * mHeightProportion) / tileHeight; const int minOriginX = a.width - mMapImage->getWidth(); const int minOriginY = a.height - mMapImage->getHeight(); - if (mapOriginX < minOriginX) - mapOriginX = minOriginX; - if (mapOriginY < minOriginY) - mapOriginY = minOriginY; - if (mapOriginX > 0) - mapOriginX = 0; - if (mapOriginY > 0) - mapOriginY = 0; + mapOriginX = std::clamp(mapOriginX, minOriginX, 0); + mapOriginY = std::clamp(mapOriginY, minOriginY, 0); } - static_cast<Graphics*>(graphics)-> - drawImage(mMapImage, mapOriginX, mapOriginY); + g->drawImage(mMapImage, mapOriginX, mapOriginY); } for (auto actor : actorSpriteManager->getAll()) @@ -218,16 +217,14 @@ void Minimap::draw(gcn::Graphics *graphics) const int offsetWidth = (int) ((dotSize - 1) * mWidthProportion); const Vector &pos = being->getPosition(); - if (mMap) - { - graphics->fillRectangle(gcn::Rectangle( - (int) (pos.x * mWidthProportion) / mMap->getTileWidth() - + mapOriginX - offsetWidth, - (int) (pos.y * mHeightProportion) / mMap->getTileHeight() - + mapOriginY - offsetHeight, - dotSize, dotSize)); - } + g->fillRectangle( + gcn::Rectangle((int) (pos.x * mWidthProportion) / tileWidth + mapOriginX - offsetWidth, + (int) (pos.y * mHeightProportion) / tileHeight + mapOriginY + - offsetHeight, + dotSize, + dotSize)); } - graphics->popClipArea(); + g->popClipArea(); + g->popClipRect(); } diff --git a/src/gui/widgets/scrollarea.cpp b/src/gui/widgets/scrollarea.cpp index 8ee6692f..c4d55072 100644 --- a/src/gui/widgets/scrollarea.cpp +++ b/src/gui/widgets/scrollarea.cpp @@ -134,6 +134,16 @@ void ScrollArea::drawFrame(gcn::Graphics *graphics) gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollArea, state); } +void ScrollArea::drawChildren(gcn::Graphics *graphics) +{ + auto g = static_cast<Graphics*>(graphics); + g->pushClipRect(getChildrenArea()); + + gcn::ScrollArea::drawChildren(graphics); + + g->popClipRect(); +} + void ScrollArea::setOpaque(bool opaque) { mOpaque = opaque; diff --git a/src/gui/widgets/scrollarea.h b/src/gui/widgets/scrollarea.h index 314711bf..40f1adc1 100644 --- a/src/gui/widgets/scrollarea.h +++ b/src/gui/widgets/scrollarea.h @@ -72,6 +72,11 @@ class ScrollArea : public gcn::ScrollArea void drawFrame(gcn::Graphics *graphics) override; /** + * Applies clipping to the contents. + */ + void drawChildren(gcn::Graphics* graphics) override; + + /** * Sets whether the widget should draw its background or not. */ void setOpaque(bool opaque); diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp index d9ff9566..fb5436e0 100644 --- a/src/gui/widgets/tabbedarea.cpp +++ b/src/gui/widgets/tabbedarea.cpp @@ -21,6 +21,8 @@ #include "gui/widgets/tabbedarea.h" +#include "graphics.h" + #include "gui/widgets/tab.h" #include <guichan/widgets/container.hpp> @@ -61,7 +63,12 @@ void TabbedArea::draw(gcn::Graphics *graphics) if (mTabs.empty()) return; + auto g = static_cast<Graphics*>(graphics); + g->pushClipRect(getChildrenArea()); + drawChildren(graphics); + + g->popClipRect(); } gcn::Widget *TabbedArea::getWidget(const std::string &name) const @@ -206,9 +213,8 @@ void TabbedArea::updateTabsWidth() { mTabsWidth = 0; for (const auto &[tab, _] : mTabs) - { mTabsWidth += tab->getWidth(); - } + updateVisibleTabsWidth(); } @@ -216,9 +222,7 @@ void TabbedArea::updateVisibleTabsWidth() { mVisibleTabsWidth = 0; for (unsigned int i = mTabScrollIndex; i < mTabs.size(); ++i) - { mVisibleTabsWidth += mTabs[i].first->getWidth(); - } } void TabbedArea::adjustTabPositions() @@ -265,7 +269,7 @@ void TabbedArea::action(const gcn::ActionEvent& actionEvent) { if (actionEvent.getId() == "shift_left") { - if (mTabScrollIndex) + if (mTabScrollIndex > 0) --mTabScrollIndex; } else if (actionEvent.getId() == "shift_right") @@ -282,33 +286,18 @@ void TabbedArea::action(const gcn::ActionEvent& actionEvent) void TabbedArea::updateArrowEnableState() { updateTabsWidth(); - if (mTabsWidth > getWidth() - 2) - { - mArrowButton[0]->setVisible(true); - mArrowButton[1]->setVisible(true); - } - else - { - mArrowButton[0]->setVisible(false); - mArrowButton[1]->setVisible(false); + + const bool arrowButtonsVisible = mTabsWidth > getWidth() - 2; + mArrowButton[0]->setVisible(arrowButtonsVisible); + mArrowButton[1]->setVisible(arrowButtonsVisible); + + if (!arrowButtonsVisible) mTabScrollIndex = 0; - } - // Left arrow consistency check - if (!mTabScrollIndex) - mArrowButton[0]->setEnabled(false); - else - mArrowButton[0]->setEnabled(true); + mArrowButton[0]->setEnabled(mTabScrollIndex > 0); // Right arrow consistency check - if (mVisibleTabsWidth < getWidth() - 2 - - mArrowButton[0]->getWidth() - - mArrowButton[1]->getWidth()) - { - mArrowButton[1]->setEnabled(false); - } - else - { - mArrowButton[1]->setEnabled(true); - } + const int availableWidth = getWidth() - 2 - mArrowButton[0]->getWidth() + - mArrowButton[1]->getWidth(); + mArrowButton[1]->setEnabled(mVisibleTabsWidth >= availableWidth); } diff --git a/src/gui/widgets/tabbedarea.h b/src/gui/widgets/tabbedarea.h index c0566faa..558b2696 100644 --- a/src/gui/widgets/tabbedarea.h +++ b/src/gui/widgets/tabbedarea.h @@ -36,7 +36,7 @@ class Tab; /** * A tabbed area, the same as the guichan tabbed area in 0.8, but extended */ -class TabbedArea : public gcn::TabbedArea, public gcn::WidgetListener +class TabbedArea final : public gcn::TabbedArea, public gcn::WidgetListener { public: TabbedArea(); diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp index 04955ec8..9f35a5dd 100644 --- a/src/gui/widgets/textfield.cpp +++ b/src/gui/widgets/textfield.cpp @@ -53,6 +53,9 @@ void TextField::draw(gcn::Graphics *graphics) if (getFrameSize() == 0) drawFrame(graphics); + auto g = static_cast<Graphics *>(graphics); + g->pushClipRect(gcn::Rectangle(0, 0, getWidth(), getHeight())); + if (isFocused()) { drawCaret(graphics, @@ -62,6 +65,8 @@ void TextField::draw(gcn::Graphics *graphics) graphics->setColor(Theme::getThemeColor(Theme::TEXT)); graphics->setFont(getFont()); graphics->drawText(mText, mPadding - mXScroll, mPadding); + + g->popClipRect(); } void TextField::drawFrame(gcn::Graphics *graphics) diff --git a/src/openglgraphics.cpp b/src/openglgraphics.cpp index 253cc1d2..51d8cde3 100644 --- a/src/openglgraphics.cpp +++ b/src/openglgraphics.cpp @@ -626,14 +626,6 @@ bool OpenGLGraphics::pushClipArea(gcn::Rectangle area) glPushMatrix(); glTranslatef(transX, transY, 0); - int x = (int) (mClipStack.top().x * mScaleX); - int y = (int) ((mHeight - mClipStack.top().y - - mClipStack.top().height) * mScaleY); - int width = (int) (mClipStack.top().width * mScaleX); - int height = (int) (mClipStack.top().height * mScaleY); - - glScissor(x, y, width, height); - return result; } @@ -642,17 +634,6 @@ void OpenGLGraphics::popClipArea() Graphics::popClipArea(); glPopMatrix(); - - if (mClipStack.empty()) - return; - - int x = (int) (mClipStack.top().x * mScaleX); - int y = (int) ((mHeight - mClipStack.top().y - - mClipStack.top().height) * mScaleY); - int width = (int) (mClipStack.top().width * mScaleX); - int height = (int) (mClipStack.top().height * mScaleY); - - glScissor(x, y, width, height); } void OpenGLGraphics::setColor(const gcn::Color &color) @@ -663,6 +644,25 @@ void OpenGLGraphics::setColor(const gcn::Color &color) mColorAlpha = (color.a != 255); } +void OpenGLGraphics::updateClipRect() +{ + if (mClipRects.empty()) + { + glDisable(GL_SCISSOR_TEST); + return; + } + + const gcn::Rectangle &clipRect = mClipRects.top(); + + const int x = (int) (clipRect.x * mScaleX); + const int y = (int) ((mHeight - clipRect.y - clipRect.height) * mScaleY); + const int width = (int) (clipRect.width * mScaleX); + const int height = (int) (clipRect.height * mScaleY); + + glEnable(GL_SCISSOR_TEST); + glScissor(x, y, width, height); +} + void OpenGLGraphics::drawPoint(int x, int y) { setTexturingAndBlending(false); diff --git a/src/openglgraphics.h b/src/openglgraphics.h index 2245938a..b342d9e5 100644 --- a/src/openglgraphics.h +++ b/src/openglgraphics.h @@ -115,6 +115,8 @@ class OpenGLGraphics final : public Graphics protected: void setTexturingAndBlending(bool enable); + void updateClipRect() override; + private: void drawQuadArrayfi(int size); diff --git a/src/sdlgraphics.cpp b/src/sdlgraphics.cpp index 28907b1e..23336313 100644 --- a/src/sdlgraphics.cpp +++ b/src/sdlgraphics.cpp @@ -258,33 +258,21 @@ SDL_Surface *SDLGraphics::getScreenshot() return screenshot; } -bool SDLGraphics::pushClipArea(gcn::Rectangle area) +void SDLGraphics::updateClipRect() { - bool result = Graphics::pushClipArea(area); - updateSDLClipRect(); - return result; -} - -void SDLGraphics::popClipArea() -{ - Graphics::popClipArea(); - updateSDLClipRect(); -} - -void SDLGraphics::updateSDLClipRect() -{ - if (mClipStack.empty()) + if (mClipRects.empty()) { SDL_RenderSetClipRect(mRenderer, nullptr); return; } - const gcn::ClipRectangle &carea = mClipStack.top(); - SDL_Rect rect; - rect.x = carea.x; - rect.y = carea.y; - rect.w = carea.width; - rect.h = carea.height; + const gcn::Rectangle &clipRect = mClipRects.top(); + const SDL_Rect rect = { + clipRect.x, + clipRect.y, + clipRect.width, + clipRect.height + }; SDL_RenderSetClipRect(mRenderer, &rect); } diff --git a/src/sdlgraphics.h b/src/sdlgraphics.h index 806e86f4..2b7635a5 100644 --- a/src/sdlgraphics.h +++ b/src/sdlgraphics.h @@ -69,10 +69,6 @@ public: SDL_Surface *getScreenshot() override; - bool pushClipArea(gcn::Rectangle area) override; - - void popClipArea() override; - void drawPoint(int x, int y) override; void drawLine(int x1, int y1, int x2, int y2) override; @@ -81,8 +77,9 @@ public: void fillRectangle(const gcn::Rectangle &rectangle) override; -private: - void updateSDLClipRect(); +protected: + void updateClipRect() override; +private: SDL_Renderer *mRenderer = nullptr; }; |