summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <bjorn@lindeijer.nl>2025-03-29 20:34:14 +0100
committerThorbjørn Lindeijer <bjorn@lindeijer.nl>2025-03-31 12:49:57 +0200
commit80f76c3aae438f7b9a7c1359c3f37aac460f934b (patch)
treec5786337049f701db3a22c432d773eaac4525012 /src
parent2739d3cface75a5477918ce03bd2f85b3244fe1a (diff)
downloadmana-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.cpp17
-rw-r--r--src/graphics.h8
-rw-r--r--src/gui/itempopup.cpp3
-rw-r--r--src/gui/minimap.cpp51
-rw-r--r--src/gui/widgets/scrollarea.cpp10
-rw-r--r--src/gui/widgets/scrollarea.h5
-rw-r--r--src/gui/widgets/tabbedarea.cpp49
-rw-r--r--src/gui/widgets/tabbedarea.h2
-rw-r--r--src/gui/widgets/textfield.cpp5
-rw-r--r--src/openglgraphics.cpp38
-rw-r--r--src/openglgraphics.h2
-rw-r--r--src/sdlgraphics.cpp30
-rw-r--r--src/sdlgraphics.h9
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;
};