summaryrefslogtreecommitdiff
path: root/src/gui/widgets
diff options
context:
space:
mode:
Diffstat (limited to 'src/gui/widgets')
-rw-r--r--src/gui/widgets/avatarlistbox.cpp64
-rw-r--r--src/gui/widgets/avatarlistbox.h12
-rw-r--r--src/gui/widgets/browserbox.cpp259
-rw-r--r--src/gui/widgets/browserbox.h45
-rw-r--r--src/gui/widgets/button.cpp205
-rw-r--r--src/gui/widgets/button.h23
-rw-r--r--src/gui/widgets/channeltab.h5
-rw-r--r--src/gui/widgets/chattab.cpp2
-rw-r--r--src/gui/widgets/chattab.h5
-rw-r--r--src/gui/widgets/checkbox.cpp126
-rw-r--r--src/gui/widgets/checkbox.h32
-rw-r--r--src/gui/widgets/container.h10
-rw-r--r--src/gui/widgets/desktop.cpp2
-rw-r--r--src/gui/widgets/desktop.h5
-rw-r--r--src/gui/widgets/dropdown.cpp201
-rw-r--r--src/gui/widgets/dropdown.h25
-rw-r--r--src/gui/widgets/emoteshortcutcontainer.cpp57
-rw-r--r--src/gui/widgets/emoteshortcutcontainer.h7
-rw-r--r--src/gui/widgets/flowcontainer.h5
-rw-r--r--src/gui/widgets/icon.cpp2
-rw-r--r--src/gui/widgets/icon.h5
-rw-r--r--src/gui/widgets/inttextfield.h5
-rw-r--r--src/gui/widgets/itemcontainer.cpp97
-rw-r--r--src/gui/widgets/itemcontainer.h9
-rw-r--r--src/gui/widgets/itemlinkhandler.h5
-rw-r--r--src/gui/widgets/itemshortcutcontainer.cpp96
-rw-r--r--src/gui/widgets/itemshortcutcontainer.h11
-rw-r--r--src/gui/widgets/label.cpp35
-rw-r--r--src/gui/widgets/label.h30
-rw-r--r--src/gui/widgets/layout.h14
-rw-r--r--src/gui/widgets/layouthelper.h5
-rw-r--r--src/gui/widgets/linkhandler.h5
-rw-r--r--src/gui/widgets/listbox.cpp23
-rw-r--r--src/gui/widgets/listbox.h14
-rw-r--r--src/gui/widgets/passwordfield.h5
-rw-r--r--src/gui/widgets/playerbox.cpp76
-rw-r--r--src/gui/widgets/playerbox.h23
-rw-r--r--src/gui/widgets/popup.cpp82
-rw-r--r--src/gui/widgets/popup.h44
-rw-r--r--src/gui/widgets/progressbar.cpp100
-rw-r--r--src/gui/widgets/progressbar.h28
-rw-r--r--src/gui/widgets/progressindicator.cpp10
-rw-r--r--src/gui/widgets/progressindicator.h8
-rw-r--r--src/gui/widgets/radiobutton.cpp118
-rw-r--r--src/gui/widgets/radiobutton.h35
-rw-r--r--src/gui/widgets/resizegrip.cpp40
-rw-r--r--src/gui/widgets/resizegrip.h16
-rw-r--r--src/gui/widgets/scrollarea.cpp692
-rw-r--r--src/gui/widgets/scrollarea.h76
-rw-r--r--src/gui/widgets/setuptab.h5
-rw-r--r--src/gui/widgets/shopitems.h5
-rw-r--r--src/gui/widgets/shoplistbox.cpp18
-rw-r--r--src/gui/widgets/shoplistbox.h5
-rw-r--r--src/gui/widgets/shortcutcontainer.cpp10
-rw-r--r--src/gui/widgets/shortcutcontainer.h25
-rw-r--r--src/gui/widgets/slider.cpp167
-rw-r--r--src/gui/widgets/slider.h29
-rw-r--r--src/gui/widgets/spacer.h5
-rw-r--r--src/gui/widgets/tab.cpp169
-rw-r--r--src/gui/widgets/tab.h32
-rw-r--r--src/gui/widgets/tabbedarea.cpp59
-rw-r--r--src/gui/widgets/tabbedarea.h16
-rw-r--r--src/gui/widgets/table.cpp73
-rw-r--r--src/gui/widgets/table.h53
-rw-r--r--src/gui/widgets/tablemodel.h5
-rw-r--r--src/gui/widgets/textbox.cpp48
-rw-r--r--src/gui/widgets/textbox.h17
-rw-r--r--src/gui/widgets/textfield.cpp98
-rw-r--r--src/gui/widgets/textfield.h46
-rw-r--r--src/gui/widgets/textpreview.cpp42
-rw-r--r--src/gui/widgets/textpreview.h55
-rw-r--r--src/gui/widgets/vertcontainer.h5
-rw-r--r--src/gui/widgets/whispertab.cpp2
-rw-r--r--src/gui/widgets/whispertab.h5
-rw-r--r--src/gui/widgets/window.cpp234
-rw-r--r--src/gui/widgets/window.h53
-rw-r--r--src/gui/widgets/windowcontainer.cpp9
-rw-r--r--src/gui/widgets/windowcontainer.h11
78 files changed, 1820 insertions, 2280 deletions
diff --git a/src/gui/widgets/avatarlistbox.cpp b/src/gui/widgets/avatarlistbox.cpp
index ec3327b2..4a806d04 100644
--- a/src/gui/widgets/avatarlistbox.cpp
+++ b/src/gui/widgets/avatarlistbox.cpp
@@ -32,33 +32,21 @@
#include <guichan/font.hpp>
-int AvatarListBox::instances = 0;
-Image *AvatarListBox::onlineIcon = nullptr;
-Image *AvatarListBox::offlineIcon = nullptr;
-
AvatarListBox::AvatarListBox(AvatarListModel *model):
ListBox(model)
{
- instances++;
-
- if (instances == 1)
- {
- onlineIcon = Theme::getImageFromTheme("circle-green.png");
- offlineIcon = Theme::getImageFromTheme("circle-gray.png");
- }
-
setWidth(200);
}
-AvatarListBox::~AvatarListBox()
+unsigned int AvatarListBox::getRowHeight() const
{
- instances--;
+ auto rowHeight = ListBox::getRowHeight();
- if (instances == 0)
- {
- onlineIcon->decRef();
- offlineIcon->decRef();
- }
+ auto theme = gui->getTheme();
+ if (auto onlineIcon = theme->getIcon("online"))
+ rowHeight = std::max<unsigned>(rowHeight, onlineIcon->getHeight() + 2);
+
+ return rowHeight;
}
void AvatarListBox::draw(gcn::Graphics *gcnGraphics)
@@ -66,34 +54,42 @@ void AvatarListBox::draw(gcn::Graphics *gcnGraphics)
if (!mListModel)
return;
- auto* model = static_cast<AvatarListModel*>(mListModel);
+ auto *model = static_cast<AvatarListModel *>(mListModel);
+ auto *graphics = static_cast<Graphics *>(gcnGraphics);
- updateAlpha();
-
- auto *graphics = static_cast<Graphics*>(gcnGraphics);
-
- graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT,
- (int) (mAlpha * 255.0f)));
graphics->setFont(getFont());
- const int fontHeight = getFont()->getHeight();
+ const int rowHeight = getRowHeight();
// Draw filled rectangle around the selected list element
if (mSelected >= 0)
- graphics->fillRectangle(gcn::Rectangle(0, fontHeight * mSelected,
- getWidth(), fontHeight));
+ {
+ auto highlightColor = Theme::getThemeColor(Theme::HIGHLIGHT);
+ highlightColor.a = gui->getTheme()->getGuiAlpha();
+ graphics->setColor(highlightColor);
+ graphics->fillRectangle(gcn::Rectangle(0, rowHeight * mSelected,
+ getWidth(), rowHeight));
+ }
+
+ auto theme = gui->getTheme();
+ auto onlineIcon = theme->getIcon("online");
+ auto offlineIcon = theme->getIcon("offline");
// Draw the list elements
graphics->setColor(Theme::getThemeColor(Theme::TEXT));
for (int i = 0, y = 0;
i < model->getNumberOfElements();
- ++i, y += fontHeight)
+ ++i, y += rowHeight)
{
Avatar *a = model->getAvatarAt(i);
+ int x = 1;
+
// Draw online status
- Image *icon = a->getOnline() ? onlineIcon : offlineIcon;
- if (icon)
- graphics->drawImage(icon, 2, y + 1);
+ if (const Image *icon = a->getOnline() ? onlineIcon : offlineIcon)
+ {
+ graphics->drawImage(icon, x, y + (rowHeight - icon->getHeight()) / 2);
+ x += icon->getWidth() + 4;
+ }
if (a->getDisplayBold())
graphics->setFont(boldFont);
@@ -111,7 +107,7 @@ void AvatarListBox::draw(gcn::Graphics *gcnGraphics)
}
// Draw Name
- graphics->drawText(text, 15, y);
+ graphics->drawText(text, x, y);
if (a->getDisplayBold())
graphics->setFont(getFont());
diff --git a/src/gui/widgets/avatarlistbox.h b/src/gui/widgets/avatarlistbox.h
index 7ee36d1e..1f51935f 100644
--- a/src/gui/widgets/avatarlistbox.h
+++ b/src/gui/widgets/avatarlistbox.h
@@ -18,8 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GUI_GUILDLISTBOX_H
-#define GUI_GUILDLISTBOX_H
+#pragma once
#include "avatar.h"
@@ -43,7 +42,7 @@ class AvatarListBox : public ListBox
public:
AvatarListBox(AvatarListModel *model);
- ~AvatarListBox() override;
+ unsigned int getRowHeight() const override;
/**
* Draws the list box.
@@ -51,11 +50,4 @@ public:
void draw(gcn::Graphics *gcnGraphics) override;
void mousePressed(gcn::MouseEvent &event) override;
-
-private:
- static int instances;
- static Image *onlineIcon;
- static Image *offlineIcon;
};
-
-#endif
diff --git a/src/gui/widgets/browserbox.cpp b/src/gui/widgets/browserbox.cpp
index 9eee9448..4fe85ae5 100644
--- a/src/gui/widgets/browserbox.cpp
+++ b/src/gui/widgets/browserbox.cpp
@@ -22,6 +22,9 @@
#include "gui/widgets/browserbox.h"
+#include "keyboardconfig.h"
+#include "textrenderer.h"
+
#include "gui/gui.h"
#include "gui/truetypefont.h"
#include "gui/widgets/linkhandler.h"
@@ -38,9 +41,44 @@
#include <algorithm>
+/**
+ * Check for key replacements in format "###key;"
+ */
+static void replaceKeys(std::string &text)
+{
+ auto keyStart = text.find("###");
+
+ while (keyStart != std::string::npos)
+ {
+ const auto keyEnd = text.find(";", keyStart + 3);
+ if (keyEnd == std::string::npos)
+ break;
+
+ std::string_view key(text.data() + keyStart + 3, keyEnd - keyStart - 3);
+
+ // Remove "key" prefix
+ if (key.size() > 3 && key.substr(0, 3) == "key")
+ key.remove_prefix(3);
+
+ const auto keyName = keyboard.getKeyName(key);
+ if (!keyName.empty())
+ {
+ text.replace(keyStart, keyEnd - keyStart + 1, keyName);
+ keyStart = text.find("###", keyStart + keyName.size());
+ }
+ else
+ {
+ keyStart = text.find("###", keyEnd + 1);
+ }
+ }
+}
+
+
struct LayoutContext
{
- LayoutContext(gcn::Font *font);
+ LayoutContext(gcn::Font *font, const Palette &palette);
+
+ LinePart linePart(int x, std::string text);
int y = 0;
gcn::Font *font;
@@ -48,23 +86,39 @@ struct LayoutContext
const int minusWidth;
const int tildeWidth;
int lineHeight;
- gcn::Color selColor;
const gcn::Color textColor;
+ const std::optional<gcn::Color> textOutlineColor;
+ gcn::Color color;
+ std::optional<gcn::Color> outlineColor;
};
-LayoutContext::LayoutContext(gcn::Font *font)
+inline LayoutContext::LayoutContext(gcn::Font *font, const Palette &palette)
: font(font)
, fontHeight(font->getHeight())
, minusWidth(font->getWidth("-"))
, tildeWidth(font->getWidth("~"))
, lineHeight(fontHeight)
- , selColor(Theme::getThemeColor(Theme::TEXT))
- , textColor(Theme::getThemeColor(Theme::TEXT))
+ , textColor(palette.getColor(Theme::TEXT))
+ , textOutlineColor(palette.getOutlineColor(Theme::TEXT))
+ , color(textColor)
+ , outlineColor(textOutlineColor)
{
if (auto *trueTypeFont = dynamic_cast<const TrueTypeFont*>(font))
lineHeight = trueTypeFont->getLineHeight();
}
+inline LinePart LayoutContext::linePart(int x, std::string text)
+{
+ return {
+ x,
+ y,
+ color,
+ outlineColor,
+ std::move(text),
+ font
+ };
+}
+
BrowserBox::BrowserBox(Mode mode):
mMode(mode)
@@ -75,28 +129,38 @@ BrowserBox::BrowserBox(Mode mode):
BrowserBox::~BrowserBox() = default;
-void BrowserBox::addRow(const std::string &row)
+void BrowserBox::addRows(std::string_view rows)
+{
+ std::string_view::size_type start = 0;
+ std::string_view::size_type end = 0;
+ while (end != std::string::npos)
+ {
+ end = rows.find('\n', start);
+ addRow(rows.substr(start, end - start));
+ start = end + 1;
+ }
+}
+
+void BrowserBox::addRow(std::string_view row)
{
TextRow &newRow = mTextRows.emplace_back();
// Use links and user defined colors
if (mUseLinksAndUserColors)
{
- std::string tmp = row;
-
// Check for links in format "@@link|Caption@@"
- auto idx1 = tmp.find("@@");
- while (idx1 != std::string::npos)
+ auto linkStart = row.find("@@");
+ while (linkStart != std::string::npos)
{
- const auto idx2 = tmp.find("|", idx1);
- const auto idx3 = tmp.find("@@", idx2);
+ const auto linkSep = row.find("|", linkStart);
+ const auto linkEnd = row.find("@@", linkSep);
- if (idx2 == std::string::npos || idx3 == std::string::npos)
+ if (linkSep == std::string::npos || linkEnd == std::string::npos)
break;
BrowserLink &link = newRow.links.emplace_back();
- link.link = tmp.substr(idx1 + 2, idx2 - (idx1 + 2));
- link.caption = tmp.substr(idx2 + 1, idx3 - (idx2 + 1));
+ link.link = row.substr(linkStart + 2, linkSep - (linkStart + 2));
+ link.caption = row.substr(linkSep + 1, linkEnd - (linkSep + 1));
if (link.caption.empty())
{
@@ -107,18 +171,18 @@ void BrowserBox::addRow(const std::string &row)
link.caption = link.link;
}
- newRow.text += tmp.substr(0, idx1);
+ newRow.text += row.substr(0, linkStart);
newRow.text += "##<" + link.caption;
- tmp.erase(0, idx3 + 2);
- if (!tmp.empty())
+ row = row.substr(linkEnd + 2);
+ if (!row.empty())
{
newRow.text += "##>";
}
- idx1 = tmp.find("@@");
+ linkStart = row.find("@@");
}
- newRow.text += tmp;
+ newRow.text += row;
}
// Don't use links and user defined colors
else
@@ -126,8 +190,11 @@ void BrowserBox::addRow(const std::string &row)
newRow.text = row;
}
+ if (mEnableKeys)
+ replaceKeys(newRow.text);
+
// Layout the newly added row
- LayoutContext context(getFont());
+ LayoutContext context(getFont(), gui->getTheme()->getPalette(mPalette));
context.y = getHeight();
layoutTextRow(newRow, context);
@@ -175,14 +242,14 @@ void BrowserBox::mousePressed(gcn::MouseEvent &event)
if (mHoveredLink) {
mLinkHandler->handleLink(mHoveredLink->link);
- gui->setCursorType(Cursor::POINTER);
+ gui->setCursorType(Cursor::Pointer);
}
}
void BrowserBox::mouseMoved(gcn::MouseEvent &event)
{
updateHoveredLink(event.getX(), event.getY());
- gui->setCursorType(mHoveredLink ? Cursor::HAND : Cursor::POINTER);
+ gui->setCursorType(mHoveredLink ? Cursor::Hand : Cursor::Pointer);
event.consume(); // Suppress mouse cursor change by parent
}
@@ -204,19 +271,20 @@ void BrowserBox::draw(gcn::Graphics *graphics)
if (mHoveredLink)
{
+ auto &palette = gui->getTheme()->getPalette(mPalette);
auto &link = *mHoveredLink;
const gcn::Rectangle &rect = link.rect;
if (mHighlightMode & BACKGROUND)
{
- graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT));
+ graphics->setColor(palette.getColor(Theme::HIGHLIGHT));
graphics->fillRectangle(rect);
}
if (mHighlightMode & UNDERLINE)
{
- graphics->setColor(Theme::getThemeColor(Theme::HYPERLINK));
+ graphics->setColor(palette.getColor(Theme::HYPERLINK));
graphics->drawLine(rect.x,
rect.y + rect.height,
rect.x + rect.width,
@@ -233,34 +301,16 @@ void BrowserBox::draw(gcn::Graphics *graphics)
if (part.y > yEnd)
return;
- auto font = part.font;
-
- // Handle text shadows
- if (mShadows)
- {
- graphics->setColor(Theme::getThemeColor(Theme::SHADOW,
- part.color.a / 2));
-
- if (mOutline)
- font->drawString(graphics, part.text, part.x + 2, part.y + 2);
- else
- font->drawString(graphics, part.text, part.x + 1, part.y + 1);
- }
-
- if (mOutline)
- {
- // Text outline
- graphics->setColor(Theme::getThemeColor(Theme::OUTLINE,
- part.color.a / 4));
- font->drawString(graphics, part.text, part.x + 1, part.y);
- font->drawString(graphics, part.text, part.x - 1, part.y);
- font->drawString(graphics, part.text, part.x, part.y + 1);
- font->drawString(graphics, part.text, part.x, part.y - 1);
- }
-
- // the main text
- graphics->setColor(part.color);
- font->drawString(graphics, part.text, part.x, part.y);
+ TextRenderer::renderText(graphics,
+ part.text,
+ part.x,
+ part.y,
+ Graphics::LEFT,
+ part.color,
+ part.font,
+ part.outlineColor.has_value() || mOutline,
+ mShadows,
+ part.outlineColor);
}
}
}
@@ -270,13 +320,13 @@ void BrowserBox::draw(gcn::Graphics *graphics)
*/
void BrowserBox::relayoutText()
{
- LayoutContext context(getFont());
+ LayoutContext context(getFont(), gui->getTheme()->getPalette(mPalette));
for (auto &row : mTextRows)
layoutTextRow(row, context);
mLastLayoutWidth = getWidth();
- mLayoutTimer.set(100);
+ mLayoutTimer.set(33);
setHeight(context.y);
}
@@ -288,7 +338,8 @@ void BrowserBox::layoutTextRow(TextRow &row, LayoutContext &context)
{
// each line starts with normal font in default color
context.font = getFont();
- context.selColor = context.textColor;
+ context.color = context.textColor;
+ context.outlineColor = context.textOutlineColor;
const int startY = context.y;
row.parts.clear();
@@ -301,15 +352,7 @@ void BrowserBox::layoutTextRow(TextRow &row, LayoutContext &context)
if (startsWith(row.text, "---"))
{
for (x = 0; x < getWidth(); x += context.minusWidth - 1)
- {
- row.parts.push_back(LinePart {
- x,
- context.y,
- context.selColor,
- "-",
- context.font
- });
- }
+ row.parts.push_back(context.linePart(x, "-"));
context.y += row.height;
@@ -318,7 +361,9 @@ void BrowserBox::layoutTextRow(TextRow &row, LayoutContext &context)
return;
}
- gcn::Color prevColor = context.selColor;
+ auto &palette = gui->getTheme()->getPalette(mPalette);
+ auto prevColor = context.color;
+ auto prevOutlineColor = context.outlineColor;
// TODO: Check if we must take texture size limits into account here
// TODO: Check if some of the O(n) calls can be removed
@@ -342,44 +387,38 @@ void BrowserBox::layoutTextRow(TextRow &row, LayoutContext &context)
const char c = row.text.at(start + 2);
start += 3;
- bool valid;
- const gcn::Color &col = Theme::getThemeColor(c, valid);
-
- if (c == '>')
- {
- context.selColor = prevColor;
- }
- else if (c == '<')
+ switch (c)
{
- prevColor = context.selColor;
- context.selColor = col;
- }
- else if (c == 'B')
- {
- context.font = boldFont;
- }
- else if (c == 'b')
- {
- context.font = getFont();
- }
- else if (valid)
- {
- context.selColor = col;
- }
- else switch (c)
- {
- case '1': context.selColor = RED; break;
- case '2': context.selColor = GREEN; break;
- case '3': context.selColor = BLUE; break;
- case '4': context.selColor = ORANGE; break;
- case '5': context.selColor = YELLOW; break;
- case '6': context.selColor = PINK; break;
- case '7': context.selColor = PURPLE; break;
- case '8': context.selColor = GRAY; break;
- case '9': context.selColor = BROWN; break;
- case '0':
- default:
- context.selColor = context.textColor;
+ case '>':
+ context.color = prevColor;
+ context.outlineColor = prevOutlineColor;
+ break;
+ case '<':
+ prevColor = context.color;
+ prevOutlineColor = context.outlineColor;
+ context.color = palette.getColor(Theme::HYPERLINK);
+ context.outlineColor = palette.getOutlineColor(Theme::HYPERLINK);
+ break;
+ case 'B':
+ context.font = boldFont;
+ break;
+ case 'b':
+ context.font = getFont();
+ break;
+ default: {
+ const auto colorId = Theme::getColorIdForChar(c);
+ if (colorId)
+ {
+ context.color = palette.getColor(*colorId);
+ context.outlineColor = palette.getOutlineColor(*colorId);
+ }
+ else
+ {
+ context.color = context.textColor;
+ context.outlineColor = context.textOutlineColor;
+ }
+ break;
+ }
}
// Update the position of the links
@@ -452,7 +491,8 @@ void BrowserBox::layoutTextRow(TextRow &row, LayoutContext &context)
row.parts.push_back(LinePart {
getWidth() - context.tildeWidth,
context.y,
- context.selColor,
+ context.color,
+ context.outlineColor,
"~",
getFont()
});
@@ -466,14 +506,7 @@ void BrowserBox::layoutTextRow(TextRow &row, LayoutContext &context)
wrapped = true;
}
- row.parts.push_back(LinePart {
- x,
- context.y,
- context.selColor,
- std::move(part),
- context.font
- });
-
+ row.parts.push_back(context.linePart(x, std::move(part)));
row.width = std::max(row.width, x + partWidth);
if (mMode == AUTO_WRAP && partWidth == 0)
@@ -506,7 +539,7 @@ void BrowserBox::updateHoveredLink(int x, int y)
void BrowserBox::maybeRelayoutText()
{
// Reduce relayouting frequency when there is a lot of text
- if (mTextRows.size() > 100)
+ if (mTextRows.size() > 1000)
if (!mLayoutTimer.passed())
return;
diff --git a/src/gui/widgets/browserbox.h b/src/gui/widgets/browserbox.h
index 7278bb59..142bba63 100644
--- a/src/gui/widgets/browserbox.h
+++ b/src/gui/widgets/browserbox.h
@@ -20,8 +20,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef BROWSERBOX_H
-#define BROWSERBOX_H
+#pragma once
#include "utils/time.h"
@@ -52,6 +51,7 @@ struct LinePart
int x;
int y;
gcn::Color color;
+ std::optional<gcn::Color> outlineColor;
std::string text;
gcn::Font *font;
};
@@ -87,6 +87,8 @@ class BrowserBox : public gcn::Widget,
*/
void setLinkHandler(LinkHandler *handler) { mLinkHandler = handler; }
+ void setPalette(int palette) { mPalette = palette; }
+
/**
* Sets the Highlight mode for links.
*/
@@ -118,9 +120,19 @@ class BrowserBox : public gcn::Widget,
void disableLinksAndUserColors() { mUseLinksAndUserColors = false; }
/**
+ * Enable or disable the replacement of keys.
+ */
+ void setEnableKeys(bool enable) { mEnableKeys = enable; }
+
+ /**
+ * Adds one or more text rows to the browser, separated by '\n'.
+ */
+ void addRows(std::string_view rows);
+
+ /**
* Adds a text row to the browser.
*/
- void addRow(const std::string &row);
+ void addRow(std::string_view row);
/**
* Remove all rows.
@@ -145,29 +157,6 @@ class BrowserBox : public gcn::Widget,
void drawFrame(gcn::Graphics *) override {}
/**
- * BrowserBox colors.
- *
- * NOTES (by Javila):
- * - color values is "0x" prefix followed by HTML color style.
- * - we can add up to 10 different colors: [0..9].
- * - not all colors will be fine with all backgrounds due transparent
- * windows and widgets. So, I think it's better keep BrowserBox
- * opaque (white background) by default.
- */
- enum
- {
- RED = 0xff0000, /**< Color 1 */
- GREEN = 0x009000, /**< Color 2 */
- BLUE = 0x0000ff, /**< Color 3 */
- ORANGE = 0xe0980e, /**< Color 4 */
- YELLOW = 0xf1dc27, /**< Color 5 */
- PINK = 0xff00d8, /**< Color 6 */
- PURPLE = 0x8415e2, /**< Color 7 */
- GRAY = 0x919191, /**< Color 8 */
- BROWN = 0x8e4c17 /**< Color 9 */
- };
-
- /**
* Highlight modes for links.
* This can be used for a bitmask.
*/
@@ -186,16 +175,16 @@ class BrowserBox : public gcn::Widget,
std::deque<TextRow> mTextRows;
LinkHandler *mLinkHandler = nullptr;
+ int mPalette = 0;
Mode mMode;
unsigned int mHighlightMode = UNDERLINE | BACKGROUND;
int mWrapIndent = 0;
bool mShadows = false;
bool mOutline = false;
bool mUseLinksAndUserColors = true;
+ bool mEnableKeys = false;
std::optional<BrowserLink> mHoveredLink;
unsigned int mMaxRows = 0;
int mLastLayoutWidth = 0;
Timer mLayoutTimer;
};
-
-#endif
diff --git a/src/gui/widgets/button.cpp b/src/gui/widgets/button.cpp
index 274f329b..31c3a677 100644
--- a/src/gui/widgets/button.cpp
+++ b/src/gui/widgets/button.cpp
@@ -21,25 +21,22 @@
#include "gui/widgets/button.h"
-#include "configuration.h"
#include "graphics.h"
+#include "gui/gui.h"
#include "gui/textpopup.h"
#include "resources/image.h"
#include "resources/theme.h"
-
-#include "utils/dtor.h"
+#include "textrenderer.h"
#include <guichan/exception.hpp>
#include <guichan/font.hpp>
int Button::mInstances = 0;
-float Button::mAlpha = 1.0;
-ImageRect *Button::mButton;
TextPopup *Button::mTextPopup = nullptr;
-enum{
+enum {
BUTTON_STANDARD, // 0
BUTTON_HIGHLIGHTED, // 1
BUTTON_PRESSED, // 2
@@ -47,20 +44,6 @@ enum{
BUTTON_COUNT // 4 - Must be last.
};
-struct ButtonData
-{
- char const *file;
- int gridX;
- int gridY;
-};
-
-static ButtonData const data[BUTTON_COUNT] = {
- { "button.png", 0, 0 },
- { "buttonhi.png", 9, 4 },
- { "buttonpress.png", 16, 19 },
- { "button_disabled.png", 25, 23 }
-};
-
Button::Button()
{
init();
@@ -80,18 +63,19 @@ Button::Button(const std::string &caption, const std::string &actionEventId,
adjustSize();
}
-bool Button::setButtonIcon(const std::string& iconFile)
+Button::~Button() = default;
+
+bool Button::setButtonIcon(const std::string &iconFile)
{
// We clean up possible older references.
- if (mButtonIcon)
- removeButtonIcon();
+ removeButtonIcon();
// If nothing relevant was set, we can quit now.
if (iconFile.empty())
return false;
// Load the icon frames.
- Image *btnIcons = Theme::getImageFromTheme(iconFile);
+ auto btnIcons = Theme::getImageFromTheme(iconFile);
if (!btnIcons)
return false;
@@ -101,141 +85,76 @@ bool Button::setButtonIcon(const std::string& iconFile)
if (frameWidth > 0 && frameHeight > 0)
{
- mButtonIcon = new Image*[BUTTON_COUNT];
+ mButtonIcon.resize(BUTTON_COUNT);
+
for (int mode = 0; mode < BUTTON_COUNT; ++mode)
{
- mButtonIcon[mode] = btnIcons->getSubImage(mode * frameWidth, 0,
- frameWidth, frameHeight);
+ mButtonIcon[mode].reset(
+ btnIcons->getSubImage(mode * frameWidth, 0, frameWidth, frameHeight));
}
adjustSize();
}
- btnIcons->decRef();
- return (mButtonIcon);
+ return !mButtonIcon.empty();
}
-void Button::removeButtonIcon(bool adjustButtonSize)
+void Button::removeButtonIcon()
{
- if (!mButtonIcon)
+ if (mButtonIcon.empty())
return;
- // Delete potential button icons
- for (int mode = 0; mode < BUTTON_COUNT; ++mode)
- {
- delete mButtonIcon[mode];
- mButtonIcon[mode] = nullptr;
- }
- delete[] mButtonIcon;
- mButtonIcon = nullptr;
-
- if (adjustButtonSize)
- adjustSize();
+ mButtonIcon.clear();
+ adjustSize();
}
void Button::init()
{
- setFrameSize(0);
+ auto &skin = gui->getTheme()->getSkin(SkinType::Button);
+ setFrameSize(skin.frameSize);
+ setSpacing(skin.padding);
if (mInstances == 0)
{
- // Load the skin
- mButton = new ImageRect[BUTTON_COUNT];
-
- for (int mode = 0; mode < BUTTON_COUNT; ++mode)
- {
- Image *modeImage = Theme::getImageFromTheme(data[mode].file);
- int a = 0;
- for (int y = 0; y < 3; y++)
- {
- for (int x = 0; x < 3; x++)
- {
- mButton[mode].grid[a] = modeImage->getSubImage(
- data[x].gridX, data[y].gridY,
- data[x + 1].gridX - data[x].gridX + 1,
- data[y + 1].gridY - data[y].gridY + 1);
- a++;
- }
- }
- modeImage->decRef();
- }
- updateAlpha();
-
- // Load the popup
+ // Create the tooltip popup. It is shared by all buttons and will get
+ // deleted by the WindowContainer.
if (!mTextPopup)
- mTextPopup = new TextPopup();
+ mTextPopup = new TextPopup;
}
mInstances++;
}
-Button::~Button()
+void Button::draw(gcn::Graphics *graphics)
{
- mInstances--;
-
- if (mInstances == 0)
- {
- for (int mode = 0; mode < BUTTON_COUNT; ++mode)
- {
- std::for_each(mButton[mode].grid, mButton[mode].grid + 9,
- dtor<Image*>());
- }
- delete[] mButton;
+ WidgetState widgetState(this);
+ if (mHasMouse)
+ widgetState.flags |= STATE_HOVERED;
+ if (isPressed())
+ widgetState.flags |= STATE_SELECTED;
- // Remove the popup
- delete mTextPopup;
- mTextPopup = nullptr;
- }
- // Don' try to readjust the size when it's about to be deleted.
- removeButtonIcon(false);
-}
+ auto &skin = gui->getTheme()->getSkin(SkinType::Button);
+ skin.draw(static_cast<Graphics *>(graphics), widgetState);
-void Button::updateAlpha()
-{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
+ auto skinState = skin.getState(widgetState.flags);
+ auto font = (skinState && skinState->textFormat.bold) ? boldFont : getFont();
- if (mAlpha != alpha)
- {
- mAlpha = alpha;
- for (int mode = 0; mode < BUTTON_COUNT; ++mode)
- {
- mButton[mode].setAlpha(mAlpha);
- }
- }
-}
-
-void Button::draw(gcn::Graphics *graphics)
-{
int mode;
- if (!isEnabled())
+ if (widgetState.flags & STATE_DISABLED)
mode = BUTTON_DISABLED;
- else if (isPressed())
+ else if (widgetState.flags & STATE_SELECTED)
mode = BUTTON_PRESSED;
- else if (mHasMouse || isFocused())
+ else if (widgetState.flags & (STATE_HOVERED | STATE_FOCUSED))
mode = BUTTON_HIGHLIGHTED;
else
mode = BUTTON_STANDARD;
- updateAlpha();
-
- static_cast<Graphics*>(graphics)->
- drawImageRect(0, 0, getWidth(), getHeight(), mButton[mode]);
-
- if (mode == BUTTON_DISABLED)
- graphics->setColor(Theme::getThemeColor(Theme::BUTTON_DISABLED));
- else
- graphics->setColor(Theme::getThemeColor(Theme::BUTTON));
-
+ Image *icon = mButtonIcon.empty() ? nullptr : mButtonIcon[mode].get();
int textX = 0;
- int textY = getHeight() / 2 - getFont()->getHeight() / 2;
+ int textY = getHeight() / 2 - font->getHeight() / 2;
int btnIconX = 0;
- int btnIconY = getHeight() / 2
- - ((mButtonIcon && mButtonIcon[mode]) ?
- mButtonIcon[mode]->getHeight() / 2 : 0);
-
- int btnIconWidth = (mButtonIcon && mButtonIcon[mode]) ?
- mButtonIcon[mode]->getWidth() : 0;
+ int btnIconY = getHeight() / 2 - (icon ? icon->getHeight() / 2 : 0);
+ int btnIconWidth = icon ? icon->getWidth() : 0;
switch (getAlignment())
{
@@ -243,7 +162,7 @@ void Button::draw(gcn::Graphics *graphics)
if (btnIconWidth)
{
btnIconX = 4;
- textX = btnIconX + mButtonIcon[mode]->getWidth() + 2;
+ textX = btnIconX + icon->getWidth() + 2;
}
else
{
@@ -253,9 +172,8 @@ void Button::draw(gcn::Graphics *graphics)
case gcn::Graphics::CENTER:
if (btnIconWidth)
{
- btnIconX = getWidth() / 2 - (getFont()->getWidth(mCaption)
- + mButtonIcon[mode]->getWidth() + 2) / 2;
- textX = getWidth() / 2 + mButtonIcon[mode]->getWidth() / 2 + 2;
+ btnIconX = (getWidth() - font->getWidth(mCaption) - icon->getWidth() - 2) / 2;
+ textX = (getWidth() + icon->getWidth()) / 2 + 2;
}
else
{
@@ -264,15 +182,13 @@ void Button::draw(gcn::Graphics *graphics)
break;
case gcn::Graphics::RIGHT:
if (btnIconWidth)
- btnIconX = getWidth() - 4 - getFont()->getWidth(mCaption) - 2;
+ btnIconX = getWidth() - 4 - font->getWidth(mCaption) - 2;
textX = getWidth() - 4;
break;
default:
throw GCN_EXCEPTION("Button::draw(). Unknown alignment.");
}
- graphics->setFont(getFont());
-
if (isPressed())
{
textX++; textY++;
@@ -280,23 +196,32 @@ void Button::draw(gcn::Graphics *graphics)
}
if (btnIconWidth)
- static_cast<Graphics*>(graphics)->drawImage(mButtonIcon[mode],
- btnIconX, btnIconY);
- graphics->drawText(getCaption(), textX, textY, getAlignment());
+ static_cast<Graphics *>(graphics)->drawImage(icon, btnIconX, btnIconY);
+
+ if (auto skinState = skin.getState(widgetState.flags))
+ {
+ auto &textFormat = skinState->textFormat;
+ TextRenderer::renderText(static_cast<Graphics *>(graphics),
+ getCaption(),
+ textX,
+ textY,
+ getAlignment(),
+ font,
+ textFormat);
+ }
}
void Button::adjustSize()
{
// Size of the image button.
int iconWidth = 0, iconHeight = 0;
- if (mButtonIcon)
+ if (!mButtonIcon.empty())
{
for (int mode = 0; mode < BUTTON_COUNT; ++mode)
{
- iconWidth = std::max(iconWidth, mButtonIcon[mode] ?
- mButtonIcon[mode]->getWidth() + 2 : 0);
- iconHeight = std::max(iconHeight, mButtonIcon[mode] ?
- mButtonIcon[mode]->getHeight() : 0);
+ const Image *icon = mButtonIcon[mode].get();
+ iconWidth = std::max(iconWidth, icon->getWidth() + 2);
+ iconHeight = std::max(iconHeight, icon->getHeight());
}
}
@@ -311,16 +236,9 @@ void Button::setCaption(const std::string& caption)
adjustSize();
}
-void Button::logic()
-{
- gcn::Button::logic();
- mTextPopup->logic();
-}
-
void Button::mouseMoved(gcn::MouseEvent &event)
{
gcn::Button::mouseMoved(event);
- mTextPopup->mouseMoved(event);
int x = event.getX();
int y = event.getY();
@@ -344,7 +262,6 @@ void Button::mouseMoved(gcn::MouseEvent &event)
void Button::mouseExited(gcn::MouseEvent &event)
{
gcn::Button::mouseExited(event);
- mTextPopup->mouseExited(event);
mTextPopup->setVisible(false);
}
diff --git a/src/gui/widgets/button.h b/src/gui/widgets/button.h
index a09b4445..97f7307b 100644
--- a/src/gui/widgets/button.h
+++ b/src/gui/widgets/button.h
@@ -19,12 +19,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef BUTTON_H
-#define BUTTON_H
+#pragma once
#include <guichan/widgets/button.hpp>
-class ImageRect;
+#include <memory>
+#include <vector>
+
class Image;
class TextPopup;
@@ -55,11 +56,6 @@ class Button : public gcn::Button
*/
void draw(gcn::Graphics *graphics) override;
- /**
- * Update the alpha value to the button components.
- */
- void updateAlpha();
-
void adjustSize();
void setCaption(const std::string &caption);
@@ -82,27 +78,22 @@ class Button : public gcn::Button
void setButtonPopupText(const std::string &text)
{ mPopupText = text; }
- void logic() override;
void mouseMoved(gcn::MouseEvent &event) override;
void mouseExited(gcn::MouseEvent &event) override;
private:
void init();
- void removeButtonIcon(bool adjustButtonSize = true);
+ void removeButtonIcon();
- static ImageRect* mButton; /**< Button state graphics */
static int mInstances; /**< Number of button instances */
- static float mAlpha;
- Image** mButtonIcon = nullptr; /**< Button Icons graphics */
+ std::vector<std::unique_ptr<Image>> mButtonIcon; /**< Button Icons graphics */
/**
* The buttons popup
* @note: This is a global object. One for all the buttons.
*/
- static TextPopup* mTextPopup;
+ static TextPopup *mTextPopup;
std::string mPopupText; /**< the current button text */
};
-
-#endif
diff --git a/src/gui/widgets/channeltab.h b/src/gui/widgets/channeltab.h
index 2894dacd..d6dc1268 100644
--- a/src/gui/widgets/channeltab.h
+++ b/src/gui/widgets/channeltab.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef CHANNELTAB_H
-#define CHANNELTAB_H
+#pragma once
#include "chattab.h"
@@ -51,5 +50,3 @@ class ChannelTab : public ChatTab
private:
Channel *mChannel;
};
-
-#endif // CHANNELTAB_H
diff --git a/src/gui/widgets/chattab.cpp b/src/gui/widgets/chattab.cpp
index 485de566..03c3270a 100644
--- a/src/gui/widgets/chattab.cpp
+++ b/src/gui/widgets/chattab.cpp
@@ -160,7 +160,7 @@ void ChatTab::chatLog(std::string line, Own own, bool ignoreRecord)
tmp.nick = strprintf(_("Global announcement from %s:"),
tmp.nick.c_str());
tmp.nick += " ";
- lineColor = "##1"; // Equiv. to BrowserBox::RED
+ lineColor = "##g";
}
break;
case BY_PLAYER:
diff --git a/src/gui/widgets/chattab.h b/src/gui/widgets/chattab.h
index 3e770fe1..dfc07638 100644
--- a/src/gui/widgets/chattab.h
+++ b/src/gui/widgets/chattab.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef CHATTAB_H
-#define CHATTAB_H
+#pragma once
#include "gui/chatwindow.h"
@@ -135,5 +134,3 @@ class ChatTab : public Tab, public AutoCompleteLister, public EventListener
};
extern ChatTab *localChatTab;
-
-#endif // CHATTAB_H
diff --git a/src/gui/widgets/checkbox.cpp b/src/gui/widgets/checkbox.cpp
index 274855fd..e6079f2f 100644
--- a/src/gui/widgets/checkbox.cpp
+++ b/src/gui/widgets/checkbox.cpp
@@ -21,121 +21,43 @@
#include "gui/widgets/checkbox.h"
-#include "configuration.h"
-#include "graphics.h"
+#include "textrenderer.h"
-#include "resources/image.h"
+#include "gui/gui.h"
#include "resources/theme.h"
-int CheckBox::instances = 0;
-float CheckBox::mAlpha = 1.0;
-Image *CheckBox::checkBoxNormal;
-Image *CheckBox::checkBoxChecked;
-Image *CheckBox::checkBoxDisabled;
-Image *CheckBox::checkBoxDisabledChecked;
-Image *CheckBox::checkBoxNormalHi;
-Image *CheckBox::checkBoxCheckedHi;
+#include <guichan/font.hpp>
-CheckBox::CheckBox(const std::string &caption, bool selected):
- gcn::CheckBox(caption, selected)
+CheckBox::CheckBox(const std::string &caption, bool selected)
+ : gcn::CheckBox(caption, selected)
{
- if (instances == 0)
- {
- Image *checkBox = Theme::getImageFromTheme("checkbox.png");
- checkBoxNormal = checkBox->getSubImage(0, 0, 9, 10);
- checkBoxChecked = checkBox->getSubImage(9, 0, 9, 10);
- checkBoxDisabled = checkBox->getSubImage(18, 0, 9, 10);
- checkBoxDisabledChecked = checkBox->getSubImage(27, 0, 9, 10);
- checkBoxNormalHi = checkBox->getSubImage(36, 0, 9, 10);
- checkBoxCheckedHi = checkBox->getSubImage(45, 0, 9, 10);
- checkBoxNormal->setAlpha(mAlpha);
- checkBoxChecked->setAlpha(mAlpha);
- checkBoxDisabled->setAlpha(mAlpha);
- checkBoxDisabledChecked->setAlpha(mAlpha);
- checkBoxNormalHi->setAlpha(mAlpha);
- checkBoxCheckedHi->setAlpha(mAlpha);
- checkBox->decRef();
- }
-
- instances++;
-}
-
-CheckBox::~CheckBox()
-{
- instances--;
-
- if (instances == 0)
- {
- delete checkBoxNormal;
- delete checkBoxChecked;
- delete checkBoxDisabled;
- delete checkBoxDisabledChecked;
- delete checkBoxNormalHi;
- delete checkBoxCheckedHi;
- }
+ auto &skin = gui->getTheme()->getSkin(SkinType::CheckBox);
+ setWidth(skin.getMinWidth() + 2 * skin.padding + skin.spacing + getFont()->getWidth(caption));
+ setHeight(skin.getMinHeight() + 2 * skin.padding);
}
void CheckBox::draw(gcn::Graphics* graphics)
{
- drawBox(graphics);
-
- graphics->setFont(getFont());
- graphics->setColor(Theme::getThemeColor(Theme::TEXT));
-
- const int h = getHeight() + getHeight() / 2;
-
- graphics->drawText(getCaption(), h - 2, 0);
-}
-
-void CheckBox::updateAlpha()
-{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
-
- if (mAlpha != alpha)
- {
- mAlpha = alpha;
- checkBoxNormal->setAlpha(mAlpha);
- checkBoxChecked->setAlpha(mAlpha);
- checkBoxDisabled->setAlpha(mAlpha);
- checkBoxDisabledChecked->setAlpha(mAlpha);
- checkBoxNormal->setAlpha(mAlpha);
- checkBoxCheckedHi->setAlpha(mAlpha);
- }
-}
+ WidgetState widgetState(this);
+ if (mHasMouse)
+ widgetState.flags |= STATE_HOVERED;
+ if (isSelected())
+ widgetState.flags |= STATE_SELECTED;
-void CheckBox::drawBox(gcn::Graphics* graphics)
-{
- Image *box;
+ auto &skin = gui->getTheme()->getSkin(SkinType::CheckBox);
+ skin.draw(static_cast<Graphics *>(graphics), widgetState);
- if (isEnabled())
- {
- if (isSelected())
- {
- if (mHasMouse)
- box = checkBoxCheckedHi;
- else
- box = checkBoxChecked;
- }
- else
- {
- if (mHasMouse)
- box = checkBoxNormalHi;
- else
- box = checkBoxNormal;
- }
- }
- else
+ if (auto skinState = skin.getState(widgetState.flags))
{
- if (isSelected())
- box = checkBoxDisabledChecked;
- else
- box = checkBoxDisabled;
+ auto &textFormat = skinState->textFormat;
+ TextRenderer::renderText(static_cast<Graphics *>(graphics),
+ getCaption(),
+ skin.getMinWidth() + skin.padding + skin.spacing,
+ skin.padding,
+ Graphics::LEFT,
+ textFormat.bold ? boldFont : getFont(),
+ textFormat);
}
-
- updateAlpha();
-
- static_cast<Graphics*>(graphics)->drawImage(box, 2, 2);
}
void CheckBox::mouseEntered(gcn::MouseEvent& event)
diff --git a/src/gui/widgets/checkbox.h b/src/gui/widgets/checkbox.h
index f77b1761..ea1a20e7 100644
--- a/src/gui/widgets/checkbox.h
+++ b/src/gui/widgets/checkbox.h
@@ -19,13 +19,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef CHECKBOX_H
-#define CHECKBOX_H
+#pragma once
#include <guichan/widgets/checkbox.hpp>
-class Image;
-
/**
* Check box widget. Same as the Guichan check box but with custom look.
*
@@ -36,43 +33,26 @@ class CheckBox : public gcn::CheckBox
public:
CheckBox(const std::string &caption, bool selected = false);
- ~CheckBox() override;
-
/**
* Draws the caption, then calls drawBox to draw the check box.
*/
- void draw(gcn::Graphics* graphics) override;
-
- /**
- * Update the alpha value to the checkbox components.
- */
- void updateAlpha();
+ void draw(gcn::Graphics *graphics) override;
/**
- * Draws the check box, not the caption.
+ * Overridden because box is drawn in CheckBox::draw.
*/
- void drawBox(gcn::Graphics* graphics) override;
+ void drawBox(gcn::Graphics *graphics) override {}
/**
* Called when the mouse enteres the widget area.
*/
- void mouseEntered(gcn::MouseEvent& event) override;
+ void mouseEntered(gcn::MouseEvent &event) override;
/**
* Called when the mouse leaves the widget area.
*/
- void mouseExited(gcn::MouseEvent& event) override;
+ void mouseExited(gcn::MouseEvent &event) override;
private:
- static int instances;
- static float mAlpha;
bool mHasMouse = false;
- static Image *checkBoxNormal;
- static Image *checkBoxChecked;
- static Image *checkBoxDisabled;
- static Image *checkBoxDisabledChecked;
- static Image *checkBoxNormalHi;
- static Image *checkBoxCheckedHi;
};
-
-#endif
diff --git a/src/gui/widgets/container.h b/src/gui/widgets/container.h
index ef44c8cd..54b7950b 100644
--- a/src/gui/widgets/container.h
+++ b/src/gui/widgets/container.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GUI_CONTAINER_H
-#define GUI_CONTAINER_H
+#pragma once
#include <guichan/widgets/container.hpp>
@@ -33,7 +32,7 @@ class LayoutHelper;
* A widget container.
*
* The main difference between the standard Guichan container and this one is
- * that childs added to this container are automatically deleted when the
+ * that children added to this container are automatically deleted when the
* container is deleted.
*
* This container is also non-opaque by default.
@@ -44,6 +43,9 @@ class Container : public gcn::Container
Container();
~Container() override;
+ // Overridden to disable drawing of the frame
+ void drawFrame(gcn::Graphics *graphics) override {}
+
protected:
/**
* Gets the layout handler for this container.
@@ -63,5 +65,3 @@ class Container : public gcn::Container
private:
LayoutHelper *mLayoutHelper = nullptr;
};
-
-#endif
diff --git a/src/gui/widgets/desktop.cpp b/src/gui/widgets/desktop.cpp
index c8ded9f5..e424beec 100644
--- a/src/gui/widgets/desktop.cpp
+++ b/src/gui/widgets/desktop.cpp
@@ -105,7 +105,7 @@ void Desktop::setBestFittingWallpaper()
return;
ResourceManager *resman = ResourceManager::getInstance();
- auto wallpaper = resman->getImageRef(wallpaperName);
+ auto wallpaper = resman->getImage(wallpaperName);
if (wallpaper)
{
diff --git a/src/gui/widgets/desktop.h b/src/gui/widgets/desktop.h
index 5909ac72..a7aa4a1e 100644
--- a/src/gui/widgets/desktop.h
+++ b/src/gui/widgets/desktop.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef DESKTOP_H
-#define DESKTOP_H
+#pragma once
#include "guichanfwd.h"
@@ -66,5 +65,3 @@ class Desktop : public Container, gcn::WidgetListener
ResourceRef<Image> mWallpaper;
gcn::Label *mVersionLabel;
};
-
-#endif // DESKTOP_H
diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp
index 8811eb8d..7d8ad0e5 100644
--- a/src/gui/widgets/dropdown.cpp
+++ b/src/gui/widgets/dropdown.cpp
@@ -21,127 +21,44 @@
#include "gui/widgets/dropdown.h"
-#include "configuration.h"
#include "graphics.h"
+#include "gui/gui.h"
#include "gui/sdlinput.h"
#include "gui/widgets/listbox.h"
#include "gui/widgets/scrollarea.h"
-#include "resources/image.h"
#include "resources/theme.h"
-#include "utils/dtor.h"
-
-#include <algorithm>
-
-int DropDown::instances = 0;
-Image *DropDown::buttons[2][2];
-ImageRect DropDown::skin;
-float DropDown::mAlpha = 1.0;
+#include <guichan/font.hpp>
DropDown::DropDown(gcn::ListModel *listModel):
gcn::DropDown::DropDown(listModel,
new ScrollArea,
new ListBox(listModel))
{
- setFrameSize(2);
-
- // Initialize graphics
- if (instances == 0)
- {
- // Load the background skin
-
- // Get the button skin
- buttons[1][0] = Theme::getImageFromTheme("vscroll_up_default.png");
- buttons[0][0] = Theme::getImageFromTheme("vscroll_down_default.png");
- buttons[1][1] = Theme::getImageFromTheme("vscroll_up_pressed.png");
- buttons[0][1] = Theme::getImageFromTheme("vscroll_down_pressed.png");
-
- buttons[0][0]->setAlpha(mAlpha);
- buttons[0][1]->setAlpha(mAlpha);
- buttons[1][0]->setAlpha(mAlpha);
- buttons[1][1]->setAlpha(mAlpha);
-
- // get the border skin
- Image *boxBorder = Theme::getImageFromTheme("deepbox.png");
- int gridx[4] = {0, 3, 28, 31};
- int gridy[4] = {0, 3, 28, 31};
- int a = 0;
-
- for (int y = 0; y < 3; y++)
- {
- for (int x = 0; x < 3; x++)
- {
- skin.grid[a] = boxBorder->getSubImage(gridx[x], gridy[y],
- gridx[x + 1] -
- gridx[x] + 1,
- gridy[y + 1] -
- gridy[y] + 1);
- a++;
- }
- }
+ auto &skin = gui->getTheme()->getSkin(SkinType::DropDownFrame);
+ setFrameSize(skin.frameSize);
+ mPadding = skin.padding;
- skin.setAlpha(mAlpha);
-
- boxBorder->decRef();
- }
-
- instances++;
+ setHeight(getFont()->getHeight() + 2 * mPadding);
}
DropDown::~DropDown()
{
- instances--;
- // Free images memory
- if (instances == 0)
- {
- buttons[0][0]->decRef();
- buttons[0][1]->decRef();
- buttons[1][0]->decRef();
- buttons[1][1]->decRef();
-
- std::for_each(skin.grid, skin.grid + 9, dtor<Image*>());
- }
-
delete mScrollArea;
}
-void DropDown::updateAlpha()
-{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
-
- if (mAlpha != alpha)
- {
- mAlpha = alpha;
-
- buttons[0][0]->setAlpha(mAlpha);
- buttons[0][1]->setAlpha(mAlpha);
- buttons[1][0]->setAlpha(mAlpha);
- buttons[1][1]->setAlpha(mAlpha);
-
- skin.setAlpha(mAlpha);
- }
-}
-
void DropDown::draw(gcn::Graphics* graphics)
{
- int h;
+ const int h = mDroppedDown ? mFoldedUpHeight : getHeight();
- if (mDroppedDown)
- h = mFoldedUpHeight;
- else
- h = getHeight();
-
- updateAlpha();
-
- const int alpha = (int) (mAlpha * 255.0f);
+ const int alpha = gui->getTheme()->getGuiAlpha();
gcn::Color faceColor = getBaseColor();
faceColor.a = alpha;
- const gcn::Color *highlightColor = &Theme::getThemeColor(Theme::HIGHLIGHT,
- alpha);
+ auto highlightColor = Theme::getThemeColor(Theme::HIGHLIGHT);
+ highlightColor.a = alpha;
gcn::Color shadowColor = faceColor - 0x303030;
shadowColor.a = alpha;
@@ -149,13 +66,16 @@ void DropDown::draw(gcn::Graphics* graphics)
{
graphics->setFont(getFont());
graphics->setColor(Theme::getThemeColor(Theme::TEXT));
- graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()), 1, 0);
+ graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()),
+ mPadding,
+ mPadding);
}
if (isFocused())
{
- graphics->setColor(*highlightColor);
- graphics->drawRectangle(gcn::Rectangle(0, 0, getWidth() - h, h));
+ graphics->setColor(highlightColor);
+ graphics->drawRectangle(
+ gcn::Rectangle(mPadding, mPadding, getWidth() - h - mPadding * 2, h - 2 * mPadding));
}
drawButton(graphics);
@@ -166,7 +86,7 @@ void DropDown::draw(gcn::Graphics* graphics)
// Draw two lines separating the ListBox with selected
// element view.
- graphics->setColor(*highlightColor);
+ graphics->setColor(highlightColor);
graphics->drawLine(0, h, getWidth(), h);
graphics->setColor(shadowColor);
graphics->drawLine(0, h + 1, getWidth(), h + 1);
@@ -176,18 +96,64 @@ void DropDown::draw(gcn::Graphics* graphics)
void DropDown::drawFrame(gcn::Graphics *graphics)
{
const int bs = getFrameSize();
- const int w = getWidth() + bs * 2;
- const int h = getHeight() + bs * 2;
- static_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, skin);
+ WidgetState state(this);
+ state.width += bs * 2;
+ state.height += bs * 2;
+
+ gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::DropDownFrame, state);
+}
+
+// Overridden so that we can take mPadding into account
+void DropDown::adjustHeight()
+{
+ const int listBoxHeight = mListBox->getHeight();
+ int height = getFont()->getHeight() + 2 * mPadding;
+
+ // The addition/subtraction of 2 compensates for the seperation lines
+ // seperating the selected element view and the scroll area.
+
+ if (mDroppedDown && getParent())
+ {
+ int availableHeight = getParent()->getChildrenArea().height - getY();
+
+ if (listBoxHeight > availableHeight - height - 2)
+ {
+ mScrollArea->setHeight(availableHeight - height - 2);
+ height = availableHeight;
+ }
+ else
+ {
+ height += listBoxHeight + 2;
+ mScrollArea->setHeight(listBoxHeight);
+ }
+ }
+
+ setHeight(height);
+
+ mScrollArea->setWidth(getWidth());
+ // Resize the ListBox to exactly fit the ScrollArea.
+ mListBox->setWidth(mScrollArea->getChildrenArea().width);
+ mScrollArea->setPosition(0, 0);
}
void DropDown::drawButton(gcn::Graphics *graphics)
{
- int height = mDroppedDown ? mFoldedUpHeight : getHeight();
+ WidgetState state(this);
+ if (mDroppedDown)
+ {
+ state.height = mFoldedUpHeight;
+ state.flags |= STATE_SELECTED;
+ }
+ if (mPushed)
+ state.flags |= STATE_HOVERED;
+
+ auto &skin = gui->getTheme()->getSkin(SkinType::DropDownButton);
+
+ // FIXME: Needs support for setting alignment in the theme.
+ state.x = state.width - skin.getMinWidth();
- static_cast<Graphics*>(graphics)->
- drawImage(buttons[mDroppedDown][mPushed], getWidth() - height + 2, 1);
+ skin.draw(static_cast<Graphics *>(graphics), state);
}
// -- KeyListener notifications
@@ -253,3 +219,32 @@ void DropDown::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent)
mouseEvent.consume();
distributeActionEvent();
}
+
+// Overridden to call our version of adjustHeight
+void DropDown::dropDown()
+{
+ if (!mDroppedDown)
+ {
+ mDroppedDown = true;
+ mFoldedUpHeight = getHeight();
+ adjustHeight();
+
+ if (getParent())
+ {
+ getParent()->moveToTop(this);
+ }
+ }
+
+ mListBox->requestFocus();
+}
+
+// Overridden to call our version of adjustHeight
+void DropDown::foldUp()
+{
+ if (mDroppedDown)
+ {
+ mDroppedDown = false;
+ adjustHeight();
+ mInternalFocusHandler.focusNone();
+ }
+}
diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h
index f92c7dd5..a5e2e2f7 100644
--- a/src/gui/widgets/dropdown.h
+++ b/src/gui/widgets/dropdown.h
@@ -19,14 +19,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef DROPDOWN_H
-#define DROPDOWN_H
+#pragma once
#include <guichan/widgets/dropdown.hpp>
-class Image;
-class ImageRect;
-
/**
* A drop down box from which you can select different values.
*
@@ -47,15 +43,12 @@ class DropDown : public gcn::DropDown
~DropDown() override;
- /**
- * Update the alpha value to the graphic components.
- */
- static void updateAlpha();
-
void draw(gcn::Graphics *graphics) override;
void drawFrame(gcn::Graphics *graphics) override;
+ void adjustHeight();
+
// Inherited from FocusListener
void focusLost(const gcn::Event& event) override;
@@ -80,12 +73,8 @@ class DropDown : public gcn::DropDown
*/
void drawButton(gcn::Graphics *graphics) override;
- // Add own Images.
- static int instances;
- static Image *buttons[2][2];
- static ImageRect skin;
- static float mAlpha;
-};
-
-#endif // end DROPDOWN_H
+ void dropDown() override;
+ void foldUp() override;
+ int mPadding = 1;
+};
diff --git a/src/gui/widgets/emoteshortcutcontainer.cpp b/src/gui/widgets/emoteshortcutcontainer.cpp
index 8ecbc9bf..06d80ec2 100644
--- a/src/gui/widgets/emoteshortcutcontainer.cpp
+++ b/src/gui/widgets/emoteshortcutcontainer.cpp
@@ -21,13 +21,12 @@
#include "gui/widgets/emoteshortcutcontainer.h"
-#include "configuration.h"
#include "emoteshortcut.h"
#include "graphics.h"
-#include "imagesprite.h"
-#include "item.h"
#include "keyboardconfig.h"
+#include "gui/gui.h"
+
#include "resources/emotedb.h"
#include "resources/image.h"
#include "resources/theme.h"
@@ -36,65 +35,52 @@ static const int MAX_ITEMS = 12;
EmoteShortcutContainer::EmoteShortcutContainer()
{
- addMouseListener(this);
- addWidgetListener(this);
-
- mBackgroundImg = Theme::getImageFromTheme("item_shortcut_bgr.png");
-
- mBackgroundImg->setAlpha(config.guiAlpha);
-
mMaxItems = std::min(EmoteDB::getEmoteCount(), MAX_ITEMS);
-
- mBoxHeight = mBackgroundImg->getHeight();
- mBoxWidth = mBackgroundImg->getWidth();
-}
-
-EmoteShortcutContainer::~EmoteShortcutContainer()
-{
- mBackgroundImg->decRef();
}
void EmoteShortcutContainer::draw(gcn::Graphics *graphics)
{
- if (config.guiAlpha != mAlpha)
- {
- mAlpha = config.guiAlpha;
- mBackgroundImg->setAlpha(mAlpha);
- }
-
auto *g = static_cast<Graphics*>(graphics);
+ auto theme = gui->getTheme();
graphics->setFont(getFont());
for (int i = 0; i < mMaxItems; i++)
{
- const int emoteX = (i % mGridWidth) * mBoxWidth;
- const int emoteY = (i / mGridWidth) * mBoxHeight;
-
- g->drawImage(mBackgroundImg, emoteX, emoteY);
+ WidgetState state;
+ state.x = (i % mGridWidth) * mBoxWidth;
+ state.y = (i / mGridWidth) * mBoxHeight;
+ theme->drawSkin(g, SkinType::ShortcutBox, state);
// Draw emote keyboard shortcut.
const char *key = SDL_GetKeyName(
keyboard.getKeyValue(KeyboardConfig::KEY_EMOTE_1 + i));
graphics->setColor(Theme::getThemeColor(Theme::TEXT));
- g->drawText(key, emoteX + 2, emoteY + 2, gcn::Graphics::LEFT);
+ g->drawText(key, state.x + 2, state.y + 2, gcn::Graphics::LEFT);
int emoteId = emoteShortcut->getEmote(i);
if (emoteId != -1)
{
- EmoteDB::get(emoteId).sprite->draw(g, emoteX + 2, emoteY + 10);
+ if (auto image = EmoteDB::get(emoteId).image)
+ {
+ image->setAlpha(1.0f);
+ g->drawImage(image, state.x + 2, state.y + 10);
+ }
}
}
if (mEmoteMoved != -1)
{
// Draw the emote image being dragged by the cursor.
- const ImageSprite *sprite = EmoteDB::get(mEmoteMoved).sprite.get();
+ if (auto image = EmoteDB::get(mEmoteMoved).image)
+ {
+ image->setAlpha(1.0f);
- const int tPosX = mCursorPosX - (sprite->getWidth() / 2);
- const int tPosY = mCursorPosY - (sprite->getHeight() / 2);
+ const int tPosX = mCursorPosX - (image->getWidth() / 2);
+ const int tPosY = mCursorPosY - (image->getHeight() / 2);
- sprite->draw(g, tPosX, tPosY);
+ g->drawImage(image, tPosX, tPosY);
+ }
}
}
@@ -115,6 +101,7 @@ void EmoteShortcutContainer::mouseDragged(gcn::MouseEvent &event)
emoteShortcut->removeEmote(index);
}
}
+
if (mEmoteMoved != -1)
{
mCursorPosX = event.getX();
@@ -126,7 +113,6 @@ void EmoteShortcutContainer::mouseDragged(gcn::MouseEvent &event)
void EmoteShortcutContainer::mousePressed(gcn::MouseEvent &event)
{
const int index = getIndexFromGrid(event.getX(), event.getY());
-
if (index == -1)
return;
@@ -170,4 +156,3 @@ void EmoteShortcutContainer::mouseReleased(gcn::MouseEvent &event)
mEmoteClicked = false;
}
}
-
diff --git a/src/gui/widgets/emoteshortcutcontainer.h b/src/gui/widgets/emoteshortcutcontainer.h
index ecd41736..57d5efd2 100644
--- a/src/gui/widgets/emoteshortcutcontainer.h
+++ b/src/gui/widgets/emoteshortcutcontainer.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef EMOTESHORTCUTCONTAINER_H
-#define EMOTESHORTCUTCONTAINER_H
+#pragma once
#include "gui/widgets/shortcutcontainer.h"
@@ -34,8 +33,6 @@ class EmoteShortcutContainer : public ShortcutContainer
public:
EmoteShortcutContainer();
- ~EmoteShortcutContainer() override;
-
/**
* Draws the items.
*/
@@ -60,5 +57,3 @@ class EmoteShortcutContainer : public ShortcutContainer
bool mEmoteClicked = false;
int mEmoteMoved = -1;
};
-
-#endif
diff --git a/src/gui/widgets/flowcontainer.h b/src/gui/widgets/flowcontainer.h
index 21daae16..46be0919 100644
--- a/src/gui/widgets/flowcontainer.h
+++ b/src/gui/widgets/flowcontainer.h
@@ -18,8 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef FLOWCONTAINER_H
-#define FLOWCONTAINER_H
+#pragma once
#include "container.h"
@@ -56,5 +55,3 @@ class FlowContainer : public Container,
int mGridWidth = 1;
int mGridHeight = 1;
};
-
-#endif
diff --git a/src/gui/widgets/icon.cpp b/src/gui/widgets/icon.cpp
index 67fd8384..61506a6b 100644
--- a/src/gui/widgets/icon.cpp
+++ b/src/gui/widgets/icon.cpp
@@ -27,7 +27,7 @@
#include "resources/resourcemanager.h"
Icon::Icon(const std::string &file)
- : Icon(ResourceManager::getInstance()->getImageRef(file))
+ : Icon(ResourceManager::getInstance()->getImage(file))
{
}
diff --git a/src/gui/widgets/icon.h b/src/gui/widgets/icon.h
index 3ebc2c16..5e61520c 100644
--- a/src/gui/widgets/icon.h
+++ b/src/gui/widgets/icon.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef ICON_H
-#define ICON_H
+#pragma once
#include "resources/resource.h"
@@ -68,5 +67,3 @@ class Icon : public gcn::Widget
private:
ResourceRef<Image> mImage;
};
-
-#endif // ICON_H
diff --git a/src/gui/widgets/inttextfield.h b/src/gui/widgets/inttextfield.h
index d5829404..bebad71d 100644
--- a/src/gui/widgets/inttextfield.h
+++ b/src/gui/widgets/inttextfield.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef INTTEXTFIELD_H
-#define INTTEXTFIELD_H
+#pragma once
#include "textfield.h"
@@ -71,5 +70,3 @@ class IntTextField : public TextField
int mDefault; /**< Default value */
int mValue; /**< Current value */
};
-
-#endif
diff --git a/src/gui/widgets/itemcontainer.cpp b/src/gui/widgets/itemcontainer.cpp
index 940c69f4..d0d24c51 100644
--- a/src/gui/widgets/itemcontainer.cpp
+++ b/src/gui/widgets/itemcontainer.cpp
@@ -25,7 +25,6 @@
#include "inventory.h"
#include "item.h"
#include "itemshortcut.h"
-#include "log.h"
#include "gui/chatwindow.h"
#include "gui/itempopup.h"
@@ -44,19 +43,12 @@
// TODO: Add support for adding items to the item shortcut window (global
// itemShortcut).
-static const int BOX_WIDTH = 35;
-static const int BOX_HEIGHT = 43;
-
ItemContainer::ItemContainer(Inventory *inventory):
mInventory(inventory)
{
mItemPopup = new ItemPopup;
setFocusable(true);
- mSelImg = Theme::getImageFromTheme("selection.png");
- if (!mSelImg)
- logger->error("Unable to load selection.png");
-
addKeyListener(this);
addMouseListener(this);
addWidgetListener(this);
@@ -64,7 +56,6 @@ ItemContainer::ItemContainer(Inventory *inventory):
ItemContainer::~ItemContainer()
{
- mSelImg->decRef();
delete mItemPopup;
}
@@ -113,39 +104,47 @@ void ItemContainer::draw(gcn::Graphics *graphics)
}
}
+ auto theme = gui->getTheme();
+ auto &slotSkin = theme->getSkin(SkinType::ItemSlot);
+ WidgetState slotState;
+
for (int i = 0; i < mGridColumns; i++)
{
for (int j = 0; j < mGridRows; j++)
{
- int itemX = i * BOX_WIDTH;
- int itemY = j * BOX_HEIGHT;
+ int itemX = i * slotSkin.width;
+ int itemY = j * slotSkin.height;
int itemIndex = j * mGridColumns + i;
+ slotState.x = itemX;
+ slotState.y = itemY;
+ slotState.flags = 0;
+
+ if (itemIndex == mSelectedIndex)
+ {
+ slotState.flags |= STATE_SELECTED;
+
+ if (mSelectionStatus == SEL_DRAGGING)
+ {
+ // Reposition the coords to that of the cursor.
+ itemX = mDragPosX - (slotSkin.width / 2);
+ itemY = mDragPosY - (slotSkin.height / 2);
+ }
+ }
+
+ slotSkin.draw(g, slotState);
+
Item *item = getItemAt(itemIndex);
if (!item || item->getId() == 0)
continue;
- Image *image = item->getImage();
- if (image)
+ if (Image *image = item->getImage())
{
- if (itemIndex == mSelectedIndex)
- {
- if (mSelectionStatus == SEL_DRAGGING)
- {
- // Reposition the coords to that of the cursor.
- itemX = mDragPosX - (BOX_WIDTH / 2);
- itemY = mDragPosY - (BOX_HEIGHT / 2);
- }
- else
- {
- // Draw selection border image.
- g->drawImage(mSelImg, itemX, itemY);
- }
- }
- image->setAlpha(1.0f); // ensure the image if fully drawn...
- g->drawImage(image, itemX, itemY);
+ image->setAlpha(1.0f);
+ g->drawImage(image, itemX + slotSkin.padding, itemY + slotSkin.padding);
}
+
// Draw item caption
std::string caption;
if (item->getQuantity() > 1)
@@ -154,22 +153,22 @@ void ItemContainer::draw(gcn::Graphics *graphics)
caption = "Eq.";
if (item->isEquipped())
- g->setColor(Theme::getThemeColor(Theme::ITEM_EQUIPPED));
+ g->setColor(theme->getColor(Theme::ITEM_EQUIPPED));
else
g->setColor(gcn::Color(0, 0, 0));
- g->drawText(caption, itemX + BOX_WIDTH / 2,
- itemY + BOX_HEIGHT - 14, gcn::Graphics::CENTER);
+ g->drawText(caption, itemX + slotSkin.width / 2,
+ itemY + slotSkin.height - 14, gcn::Graphics::CENTER);
}
}
// Draw an orange box around the selected item
if (isFocused() && mHighlightedIndex != -1)
{
- const int itemX = (mHighlightedIndex % mGridColumns) * BOX_WIDTH;
- const int itemY = (mHighlightedIndex / mGridColumns) * BOX_HEIGHT;
+ const int itemX = (mHighlightedIndex % mGridColumns) * slotSkin.width;
+ const int itemY = (mHighlightedIndex / mGridColumns) * slotSkin.height;
g->setColor(gcn::Color(255, 128, 0));
- g->drawRectangle(gcn::Rectangle(itemX, itemY, BOX_WIDTH, BOX_HEIGHT));
+ g->drawRectangle(gcn::Rectangle(itemX, itemY, slotSkin.width, slotSkin.height));
}
}
@@ -355,9 +354,7 @@ void ItemContainer::mouseReleased(gcn::MouseEvent &event)
// Show ItemTooltip
void ItemContainer::mouseMoved(gcn::MouseEvent &event)
{
- Item *item = getItemAt(getSlotIndex(event.getX(), event.getY()));
-
- if (item)
+ if (Item *item = getItemAt(getSlotIndex(event.getX(), event.getY())))
{
mItemPopup->setItem(item->getInfo());
mItemPopup->position(viewport->getMouseX(), viewport->getMouseY());
@@ -376,26 +373,36 @@ void ItemContainer::mouseExited(gcn::MouseEvent &event)
void ItemContainer::widgetResized(const gcn::Event &event)
{
- mGridColumns = std::max(1, getWidth() / BOX_WIDTH);
+ auto &slotSkin = gui->getTheme()->getSkin(SkinType::ItemSlot);
+
+ mGridColumns = std::max(1, getWidth() / slotSkin.width);
adjustHeight();
}
void ItemContainer::adjustHeight()
{
+ auto &slotSkin = gui->getTheme()->getSkin(SkinType::ItemSlot);
+
mGridRows = (mLastUsedSlot + 1) / mGridColumns;
if (mGridRows == 0 || (mLastUsedSlot + 1) % mGridColumns > 0)
++mGridRows;
- setHeight(mGridRows * BOX_HEIGHT);
+ setHeight(mGridRows * slotSkin.height);
}
int ItemContainer::getSlotIndex(int x, int y) const
{
- if (x < getWidth() && y < getHeight())
- {
- return (y / BOX_HEIGHT) * mGridColumns + (x / BOX_WIDTH);
- }
- return Inventory::NO_SLOT_INDEX;
+ if (x >= getWidth() || y >= getHeight())
+ return Inventory::NO_SLOT_INDEX;
+
+ auto &slotSkin = gui->getTheme()->getSkin(SkinType::ItemSlot);
+ const auto row = y / slotSkin.height;
+ const auto column = x / slotSkin.width;
+
+ if (row < 0 || row >= mGridRows || column < 0 || column >= mGridColumns)
+ return Inventory::NO_SLOT_INDEX;
+
+ return (row * mGridColumns) + column;
}
void ItemContainer::keyAction()
diff --git a/src/gui/widgets/itemcontainer.h b/src/gui/widgets/itemcontainer.h
index 51807aba..c1d611b9 100644
--- a/src/gui/widgets/itemcontainer.h
+++ b/src/gui/widgets/itemcontainer.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef ITEMCONTAINER_H
-#define ITEMCONTAINER_H
+#pragma once
#include <guichan/keylistener.hpp>
#include <guichan/mouselistener.hpp>
@@ -71,6 +70,9 @@ class ItemContainer : public gcn::Widget,
*/
void draw(gcn::Graphics *graphics) override;
+ // Overridden to disable drawing of the frame
+ void drawFrame(gcn::Graphics *graphics) override {}
+
// KeyListener
void keyPressed(gcn::KeyEvent &event) override;
void keyReleased(gcn::KeyEvent &event) override;
@@ -178,7 +180,6 @@ class ItemContainer : public gcn::Widget,
Inventory *mInventory;
int mGridColumns = 1;
int mGridRows = 1;
- Image *mSelImg;
int mSelectedIndex = -1;
int mHighlightedIndex = -1;
int mLastUsedSlot = -1;
@@ -196,5 +197,3 @@ class ItemContainer : public gcn::Widget,
std::list<gcn::SelectionListener *> mSelectionListeners;
};
-
-#endif // ITEMCONTAINER_H
diff --git a/src/gui/widgets/itemlinkhandler.h b/src/gui/widgets/itemlinkhandler.h
index 28e9c11c..58202d33 100644
--- a/src/gui/widgets/itemlinkhandler.h
+++ b/src/gui/widgets/itemlinkhandler.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef ITEM_LINK_HANDLER_H
-#define ITEM_LINK_HANDLER_H
+#pragma once
#include "gui/widgets/linkhandler.h"
@@ -49,5 +48,3 @@ class ItemLinkHandler : public LinkHandler, gcn::ActionListener
Window *mParent = nullptr;
std::string mLink;
};
-
-#endif
diff --git a/src/gui/widgets/itemshortcutcontainer.cpp b/src/gui/widgets/itemshortcutcontainer.cpp
index 0b8f0c8c..b47fa29d 100644
--- a/src/gui/widgets/itemshortcutcontainer.cpp
+++ b/src/gui/widgets/itemshortcutcontainer.cpp
@@ -21,7 +21,6 @@
#include "gui/widgets/itemshortcutcontainer.h"
-#include "configuration.h"
#include "graphics.h"
#include "inventory.h"
#include "item.h"
@@ -39,64 +38,45 @@
#include "utils/stringutils.h"
ItemShortcutContainer::ItemShortcutContainer()
+ : mItemPopup(new ItemPopup)
{
- addMouseListener(this);
- addWidgetListener(this);
-
- mItemPopup = new ItemPopup;
-
- mBackgroundImg = Theme::getImageFromTheme("item_shortcut_bgr.png");
mMaxItems = itemShortcut->getItemCount();
-
- mBackgroundImg->setAlpha(config.guiAlpha);
-
- mBoxHeight = mBackgroundImg->getHeight();
- mBoxWidth = mBackgroundImg->getWidth();
}
-ItemShortcutContainer::~ItemShortcutContainer()
-{
- mBackgroundImg->decRef();
- delete mItemPopup;
-}
+ItemShortcutContainer::~ItemShortcutContainer() = default;
void ItemShortcutContainer::draw(gcn::Graphics *graphics)
{
- if (config.guiAlpha != mAlpha)
- {
- mAlpha = config.guiAlpha;
- mBackgroundImg->setAlpha(mAlpha);
- }
-
auto *g = static_cast<Graphics*>(graphics);
+ auto theme = gui->getTheme();
+ auto &skin = theme->getSkin(SkinType::ShortcutBox);
graphics->setFont(getFont());
for (int i = 0; i < mMaxItems; i++)
{
- const int itemX = (i % mGridWidth) * mBoxWidth;
- const int itemY = (i / mGridWidth) * mBoxHeight;
-
- g->drawImage(mBackgroundImg, itemX, itemY);
+ WidgetState state;
+ state.x = (i % mGridWidth) * mBoxWidth;
+ state.y = (i / mGridWidth) * mBoxHeight;
+ skin.draw(g, state);
// Draw item keyboard shortcut.
const char *key = SDL_GetKeyName(
keyboard.getKeyValue(KeyboardConfig::KEY_SHORTCUT_1 + i));
graphics->setColor(Theme::getThemeColor(Theme::TEXT));
- g->drawText(key, itemX + 2, itemY + 2, gcn::Graphics::LEFT);
+ g->drawText(key,
+ state.x + skin.padding + 2,
+ state.y + skin.padding + 2,
+ gcn::Graphics::LEFT);
- if (itemShortcut->getItem(i) < 0)
+ const int itemId = itemShortcut->getItem(i);
+ if (itemId < 0)
continue;
- Item *item =
- PlayerInfo::getInventory()->findItem(itemShortcut->getItem(i));
-
- if (item)
+ if (Item *item = PlayerInfo::getInventory()->findItem(itemId))
{
// Draw item icon.
- Image* image = item->getImage();
-
- if (image)
+ if (Image *image = item->getImage())
{
std::string caption;
if (item->getQuantity() > 1)
@@ -105,11 +85,13 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics)
caption = "Eq.";
image->setAlpha(1.0f);
- g->drawImage(image, itemX, itemY);
+ g->drawImage(image, state.x + skin.padding, state.y + skin.padding);
if (item->isEquipped())
g->setColor(Theme::getThemeColor(Theme::ITEM_EQUIPPED));
- g->drawText(caption, itemX + mBoxWidth / 2,
- itemY + mBoxHeight - 14, gcn::Graphics::CENTER);
+ g->drawText(caption,
+ state.x + mBoxWidth / 2,
+ state.y + mBoxHeight - 14,
+ gcn::Graphics::CENTER);
}
}
}
@@ -117,7 +99,7 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics)
if (mItemMoved)
{
// Draw the item image being dragged by the cursor.
- if (Image* image = mItemMoved->getImage())
+ if (Image *image = mItemMoved->getImage())
{
const int tPosX = mCursorPosX - (image->getWidth() / 2);
const int tPosY = mCursorPosY - (image->getHeight() / 2);
@@ -137,23 +119,20 @@ void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event)
if (!mItemMoved && mItemClicked)
{
const int index = getIndexFromGrid(event.getX(), event.getY());
-
if (index == -1)
return;
const int itemId = itemShortcut->getItem(index);
-
if (itemId < 0)
return;
- Item *item = PlayerInfo::getInventory()->findItem(itemId);
-
- if (item)
+ if (Item *item = PlayerInfo::getInventory()->findItem(itemId))
{
mItemMoved = item;
itemShortcut->removeItem(index);
}
}
+
if (mItemMoved)
{
mCursorPosX = event.getX();
@@ -225,19 +204,7 @@ void ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event)
// Show ItemTooltip
void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event)
{
- const int index = getIndexFromGrid(event.getX(), event.getY());
-
- if (index == -1)
- return;
-
- const int itemId = itemShortcut->getItem(index);
-
- if (itemId < 0)
- return;
-
- Item *item = PlayerInfo::getInventory()->findItem(itemId);
-
- if (item)
+ if (Item *item = getItemAt(event.getX(), event.getY()))
{
mItemPopup->setItem(item->getInfo());
mItemPopup->position(viewport->getMouseX(), viewport->getMouseY());
@@ -248,6 +215,19 @@ void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event)
}
}
+Item *ItemShortcutContainer::getItemAt(int x, int y) const
+{
+ const int index = getIndexFromGrid(x, y);
+ if (index == -1)
+ return nullptr;
+
+ const int itemId = itemShortcut->getItem(index);
+ if (itemId < 0)
+ return nullptr;
+
+ return PlayerInfo::getInventory()->findItem(itemId);
+}
+
// Hide ItemTooltip
void ItemShortcutContainer::mouseExited(gcn::MouseEvent &event)
{
diff --git a/src/gui/widgets/itemshortcutcontainer.h b/src/gui/widgets/itemshortcutcontainer.h
index 243920a0..a01857db 100644
--- a/src/gui/widgets/itemshortcutcontainer.h
+++ b/src/gui/widgets/itemshortcutcontainer.h
@@ -19,13 +19,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef ITEMSHORTCUTCONTAINER_H
-#define ITEMSHORTCUTCONTAINER_H
+#pragma once
#include "gui/widgets/shortcutcontainer.h"
#include <guichan/mouselistener.hpp>
+#include <memory>
+
class Image;
class Item;
class ItemPopup;
@@ -66,10 +67,10 @@ class ItemShortcutContainer : public ShortcutContainer
void mouseExited(gcn::MouseEvent &event) override;
void mouseMoved(gcn::MouseEvent &event) override;
+ Item *getItemAt(int x, int y) const;
+
bool mItemClicked = false;
Item *mItemMoved = nullptr;
- ItemPopup *mItemPopup;
+ std::unique_ptr<ItemPopup> mItemPopup;
};
-
-#endif
diff --git a/src/gui/widgets/label.cpp b/src/gui/widgets/label.cpp
index af5220ef..a2ed8820 100644
--- a/src/gui/widgets/label.cpp
+++ b/src/gui/widgets/label.cpp
@@ -21,8 +21,13 @@
#include "gui/widgets/label.h"
+#include "textrenderer.h"
+
#include "resources/theme.h"
+#include <guichan/exception.hpp>
+#include <guichan/font.hpp>
+
Label::Label()
{
setForegroundColor(Theme::getThemeColor(Theme::TEXT));
@@ -36,5 +41,33 @@ Label::Label(const std::string &caption) :
void Label::draw(gcn::Graphics *graphics)
{
- gcn::Label::draw(static_cast<gcn::Graphics*>(graphics));
+ int textX;
+ int textY = (getHeight() - getFont()->getHeight()) / 2;
+
+ switch (getAlignment())
+ {
+ case Graphics::LEFT:
+ textX = 0;
+ break;
+ case Graphics::CENTER:
+ textX = getWidth() / 2;
+ break;
+ case Graphics::RIGHT:
+ textX = getWidth();
+ break;
+ default:
+ throw GCN_EXCEPTION("Unknown alignment.");
+ }
+
+ TextRenderer::renderText(static_cast<Graphics *>(graphics),
+ getCaption(),
+ textX,
+ textY,
+ getAlignment(),
+ getForegroundColor(),
+ getFont(),
+ mOutlineColor.has_value(),
+ mShadowColor.has_value(),
+ mOutlineColor,
+ mShadowColor);
}
diff --git a/src/gui/widgets/label.h b/src/gui/widgets/label.h
index cb7a8b1c..85bcbe23 100644
--- a/src/gui/widgets/label.h
+++ b/src/gui/widgets/label.h
@@ -19,14 +19,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef LABEL_H
-#define LABEL_H
+#pragma once
#include <guichan/widgets/label.hpp>
+#include <optional>
/**
* Label widget. Same as the Guichan label but modified to use the palette
- * system.
+ * system and support outlines and shadows.
*
* \ingroup GUI
*/
@@ -42,9 +42,31 @@ class Label : public gcn::Label
Label(const std::string &caption);
/**
+ * Sets the color of the outline.
+ */
+ void setOutlineColor(std::optional<gcn::Color> color);
+
+ /**
+ * Sets the color of the shadow.
+ */
+ void setShadowColor(std::optional<gcn::Color> color);
+
+ /**
* Draws the label.
*/
void draw(gcn::Graphics *graphics) override;
+
+ private:
+ std::optional<gcn::Color> mOutlineColor;
+ std::optional<gcn::Color> mShadowColor;
};
-#endif
+inline void Label::setOutlineColor(std::optional<gcn::Color> color)
+{
+ mOutlineColor = color;
+}
+
+inline void Label::setShadowColor(std::optional<gcn::Color> color)
+{
+ mShadowColor = color;
+}
diff --git a/src/gui/widgets/layout.h b/src/gui/widgets/layout.h
index 4e4b28c5..42f08758 100644
--- a/src/gui/widgets/layout.h
+++ b/src/gui/widgets/layout.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef WIDGET_LAYOUT_H
-#define WIDGET_LAYOUT_H
+#pragma once
#include <guichan/widgets/container.hpp>
@@ -168,9 +167,12 @@ class LayoutCell
};
LayoutCell() = default;
-
~LayoutCell();
+ // Copy not allowed, as the cell may own an array.
+ LayoutCell(LayoutCell const &) = delete;
+ LayoutCell &operator=(LayoutCell const &) = delete;
+
/**
* Sets the padding around the cell content.
*/
@@ -232,10 +234,6 @@ class LayoutCell
void computeSizes();
private:
- // Copy not allowed, as the cell may own an array.
- LayoutCell(LayoutCell const &);
- LayoutCell &operator=(LayoutCell const &);
-
union
{
gcn::Widget *mWidget;
@@ -310,5 +308,3 @@ class Layout : public LayoutCell
private:
bool mComputed;
};
-
-#endif // WIDGET_LAYOUT_H
diff --git a/src/gui/widgets/layouthelper.h b/src/gui/widgets/layouthelper.h
index 26360a9a..ad01c565 100644
--- a/src/gui/widgets/layouthelper.h
+++ b/src/gui/widgets/layouthelper.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef LAYOUTHELPER_H
-#define LAYOUTHELPER_H
+#pragma once
#include "gui/widgets/layout.h"
@@ -74,5 +73,3 @@ class LayoutHelper : public gcn::WidgetListener
Layout mLayout; /**< Layout handler */
gcn::Container *mContainer; /**< Managed container */
};
-
-#endif // LAYOUTHELPER_H
diff --git a/src/gui/widgets/linkhandler.h b/src/gui/widgets/linkhandler.h
index 33263a25..48b182a1 100644
--- a/src/gui/widgets/linkhandler.h
+++ b/src/gui/widgets/linkhandler.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef LINK_HANDLER_H
-#define LINK_HANDLER_H
+#pragma once
#include <string>
@@ -35,5 +34,3 @@ class LinkHandler
virtual void handleLink(const std::string &link) = 0;
};
-
-#endif
diff --git a/src/gui/widgets/listbox.cpp b/src/gui/widgets/listbox.cpp
index 55f0f422..112de232 100644
--- a/src/gui/widgets/listbox.cpp
+++ b/src/gui/widgets/listbox.cpp
@@ -21,8 +21,7 @@
#include "gui/widgets/listbox.h"
-#include "configuration.h"
-
+#include "gui/gui.h"
#include "gui/sdlinput.h"
#include "resources/theme.h"
@@ -32,39 +31,29 @@
#include <guichan/key.hpp>
#include <guichan/listmodel.hpp>
-float ListBox::mAlpha = 1.0;
-
ListBox::ListBox(gcn::ListModel *listModel):
gcn::ListBox(listModel)
{
}
-void ListBox::updateAlpha()
-{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
-
- if (mAlpha != alpha)
- mAlpha = alpha;
-}
-
void ListBox::draw(gcn::Graphics *graphics)
{
if (!mListModel)
return;
- updateAlpha();
-
- graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT,
- (int) (mAlpha * 255.0f)));
graphics->setFont(getFont());
const int height = getRowHeight();
// Draw filled rectangle around the selected list element
if (mSelected >= 0)
+ {
+ auto highlightColor = Theme::getThemeColor(Theme::HIGHLIGHT);
+ highlightColor.a = gui->getTheme()->getGuiAlpha();
+ graphics->setColor(highlightColor);
graphics->fillRectangle(gcn::Rectangle(0, height * mSelected,
getWidth(), height));
+ }
// Draw the list elements
graphics->setColor(Theme::getThemeColor(Theme::TEXT));
diff --git a/src/gui/widgets/listbox.h b/src/gui/widgets/listbox.h
index d16256b1..40bc2fbc 100644
--- a/src/gui/widgets/listbox.h
+++ b/src/gui/widgets/listbox.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef LISTBOX_H
-#define LISTBOX_H
+#pragma once
#include <guichan/widgets/listbox.hpp>
@@ -43,10 +42,8 @@ class ListBox : public gcn::ListBox
*/
void draw(gcn::Graphics *graphics) override;
- /**
- * Update the alpha value to the graphic components.
- */
- static void updateAlpha();
+ // Overridden to disable drawing of the frame
+ void drawFrame(gcn::Graphics *graphics) override {}
// Inherited from KeyListener
@@ -61,9 +58,4 @@ class ListBox : public gcn::ListBox
void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) override;
void mouseDragged(gcn::MouseEvent &event) override;
-
- protected:
- static float mAlpha;
};
-
-#endif
diff --git a/src/gui/widgets/passwordfield.h b/src/gui/widgets/passwordfield.h
index 4bed0e05..36964843 100644
--- a/src/gui/widgets/passwordfield.h
+++ b/src/gui/widgets/passwordfield.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef PASSWORDFIELD_H
-#define PASSWORDFIELD_H
+#pragma once
#include "textfield.h"
@@ -42,5 +41,3 @@ class PasswordField : public TextField
*/
void draw(gcn::Graphics *graphics) override;
};
-
-#endif
diff --git a/src/gui/widgets/playerbox.cpp b/src/gui/widgets/playerbox.cpp
index 3bdd6bd1..f251035d 100644
--- a/src/gui/widgets/playerbox.cpp
+++ b/src/gui/widgets/playerbox.cpp
@@ -22,86 +22,22 @@
#include "gui/widgets/playerbox.h"
#include "being.h"
-#include "configuration.h"
#include "graphics.h"
-#include "resources/image.h"
-#include "resources/theme.h"
-
-#include "utils/dtor.h"
-
-int PlayerBox::instances = 0;
-float PlayerBox::mAlpha = 1.0;
-ImageRect PlayerBox::background;
-
-PlayerBox::PlayerBox(const Being *being):
- mBeing(being)
+PlayerBox::PlayerBox(const Being *being)
+ : mBeing(being)
{
- setFrameSize(2);
-
- if (instances == 0)
- {
- // Load the background skin
- Image *textbox = Theme::getImageFromTheme("deepbox.png");
- int bggridx[4] = {0, 3, 28, 31};
- int bggridy[4] = {0, 3, 28, 31};
- int a = 0;
-
- for (int y = 0; y < 3; y++)
- {
- for (int x = 0; x < 3; x++)
- {
- background.grid[a] = textbox->getSubImage(
- bggridx[x], bggridy[y],
- bggridx[x + 1] - bggridx[x] + 1,
- bggridy[y + 1] - bggridy[y] + 1);
- a++;
- }
- }
-
- background.setAlpha(config.guiAlpha);
-
- textbox->decRef();
- }
-
- instances++;
-}
-
-PlayerBox::~PlayerBox()
-{
- instances--;
-
- mBeing = nullptr;
-
- if (instances == 0)
- {
- std::for_each(background.grid, background.grid + 9, dtor<Image*>());
- }
}
void PlayerBox::draw(gcn::Graphics *graphics)
{
+ ScrollArea::draw(graphics);
+
if (mBeing)
{
// Draw character
- const int bs = getFrameSize();
- const int x = getWidth() / 2 + bs;
- const int y = getHeight() - bs;
+ const int x = getWidth() / 2;
+ const int y = (getHeight() + mBeing->getHeight()) / 2 - 12;
mBeing->drawSpriteAt(static_cast<Graphics*>(graphics), x, y);
}
-
- if (config.guiAlpha != mAlpha)
- {
- mAlpha = config.guiAlpha;
- background.setAlpha(config.guiAlpha);
- }
-}
-
-void PlayerBox::drawFrame(gcn::Graphics *graphics)
-{
- const int bs = getFrameSize();
- const int w = getWidth() + bs * 2;
- const int h = getHeight() + bs * 2;
-
- static_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, background);
}
diff --git a/src/gui/widgets/playerbox.h b/src/gui/widgets/playerbox.h
index 68dd670e..39392c63 100644
--- a/src/gui/widgets/playerbox.h
+++ b/src/gui/widgets/playerbox.h
@@ -19,20 +19,18 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef PLAYERBOX_H
-#define PLAYERBOX_H
+#pragma once
-#include <guichan/widgets/scrollarea.hpp>
+#include "scrollarea.h"
class Being;
-class ImageRect;
/**
* A box showing a player character.
*
* \ingroup GUI
*/
-class PlayerBox : public gcn::ScrollArea
+class PlayerBox : public ScrollArea
{
public:
/**
@@ -41,8 +39,6 @@ class PlayerBox : public gcn::ScrollArea
*/
PlayerBox(const Being *being = nullptr);
- ~PlayerBox() override;
-
/**
* Sets a new player character to be displayed by this box. Setting the
* player to <code>NULL</code> causes the box not to draw any
@@ -52,21 +48,10 @@ class PlayerBox : public gcn::ScrollArea
{ mBeing = being; }
/**
- * Draws the scroll area.
+ * Draws the scroll area and the player.
*/
void draw(gcn::Graphics *graphics) override;
- /**
- * Draws the background and border of the scroll area.
- */
- void drawFrame(gcn::Graphics *graphics) override;
-
private:
const Being *mBeing; /**< The character used for display */
-
- static float mAlpha;
- static int instances;
- static ImageRect background;
};
-
-#endif
diff --git a/src/gui/widgets/popup.cpp b/src/gui/widgets/popup.cpp
index 94d8cf85..b245b9e6 100644
--- a/src/gui/widgets/popup.cpp
+++ b/src/gui/widgets/popup.cpp
@@ -22,31 +22,32 @@
#include "gui/widgets/popup.h"
+#include "browserbox.h"
#include "graphics.h"
#include "log.h"
+#include "textbox.h"
+#include "gui/gui.h"
#include "gui/viewport.h"
-
+#include "gui/widgets/label.h"
#include "gui/widgets/windowcontainer.h"
-#include "resources/theme.h"
-
#include <guichan/exception.hpp>
-Popup::Popup(const std::string &name, const std::string &skin):
- mPopupName(name),
- mMaxWidth(graphics->getWidth()),
- mMaxHeight(graphics->getHeight())
+Popup::Popup(const std::string &name, SkinType skinType)
+ : mPopupName(name)
+ , mMaxWidth(graphics->getWidth())
+ , mMaxHeight(graphics->getHeight())
+ , mSkinType(skinType)
{
logger->log("Popup::Popup(\"%s\")", name.c_str());
if (!windowContainer)
throw GCN_EXCEPTION("Popup::Popup(): no windowContainer set");
- setPadding(6);
-
- // Loads the skin
- mSkin = Theme::instance()->load(skin);
+ auto &skin = getSkin();
+ setFrameSize(skin.frameSize);
+ setPadding(skin.padding);
// Add this window to the window container
windowContainer->add(this);
@@ -58,8 +59,6 @@ Popup::Popup(const std::string &name, const std::string &skin):
Popup::~Popup()
{
logger->log("Popup::~Popup(\"%s\")", mPopupName.c_str());
-
- mSkin->instances--;
}
void Popup::setWindowContainer(WindowContainer *wc)
@@ -67,15 +66,57 @@ void Popup::setWindowContainer(WindowContainer *wc)
windowContainer = wc;
}
-void Popup::draw(gcn::Graphics *graphics)
+void Popup::add(gcn::Widget *widget)
+{
+ Container::add(widget);
+ widgetAdded(widget);
+}
+
+void Popup::add(gcn::Widget *widget, int x, int y)
+{
+ Container::add(widget, x, y);
+ widgetAdded(widget);
+}
+
+void Popup::widgetAdded(gcn::Widget *widget) const
{
- auto *g = static_cast<Graphics*>(graphics);
+ if (const int paletteId = getSkin().palette)
+ {
+ if (auto browserBox = dynamic_cast<BrowserBox*>(widget))
+ {
+ browserBox->setPalette(paletteId);
+ }
+ else if (auto label = dynamic_cast<Label*>(widget))
+ {
+ auto &palette = gui->getTheme()->getPalette(paletteId);
+ label->setForegroundColor(palette.getColor(Theme::TEXT));
+ label->setOutlineColor(palette.getOutlineColor(Theme::TEXT));
+ }
+ else if (auto textBox = dynamic_cast<TextBox*>(widget))
+ {
+ auto &palette = gui->getTheme()->getPalette(paletteId);
+ textBox->setTextColor(&palette.getColor(Theme::TEXT));
+ textBox->setOutlineColor(palette.getOutlineColor(Theme::TEXT));
+ }
+ }
+}
- g->drawImageRect(0, 0, getWidth(), getHeight(), mSkin->getBorder());
+void Popup::draw(gcn::Graphics *graphics)
+{
+ if (getFrameSize() == 0)
+ drawFrame(graphics);
drawChildren(graphics);
}
+void Popup::drawFrame(gcn::Graphics *graphics)
+{
+ WidgetState state(this);
+ state.width += getFrameSize() * 2;
+ state.height += getFrameSize() * 2;
+ getSkin().draw(static_cast<Graphics *>(graphics), state);
+}
+
gcn::Rectangle Popup::getChildrenArea()
{
return gcn::Rectangle(getPadding(), getPadding(),
@@ -116,12 +157,12 @@ void Popup::setLocationRelativeTo(gcn::Widget *widget)
void Popup::setMinWidth(int width)
{
- mMinWidth = std::max(width, mSkin->getMinWidth());
+ mMinWidth = std::max(getSkin().getMinWidth(), width);
}
void Popup::setMinHeight(int height)
{
- mMinHeight = std::max(height, mSkin->getMinHeight());
+ mMinHeight = std::max(getSkin().getMinHeight(), height);
}
void Popup::setMaxWidth(int width)
@@ -156,6 +197,11 @@ void Popup::position(int x, int y)
requestMoveToTop();
}
+const Skin &Popup::getSkin() const
+{
+ return gui->getTheme()->getSkin(mSkinType);
+}
+
void Popup::mouseMoved(gcn::MouseEvent &event)
{
if (viewport)
diff --git a/src/gui/widgets/popup.h b/src/gui/widgets/popup.h
index c77bf814..b88cafc9 100644
--- a/src/gui/widgets/popup.h
+++ b/src/gui/widgets/popup.h
@@ -20,12 +20,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef POPUP_H
-#define POPUP_H
+#pragma once
#include "guichanfwd.h"
#include "gui/widgets/container.h"
+#include "resources/theme.h"
#include <guichan/mouselistener.hpp>
@@ -53,10 +53,10 @@ class Popup : public Container, public gcn::MouseListener
*
* @param name A human readable name for the popup. Only useful for
* debugging purposes.
- * @param skin The location where the Popup's skin XML can be found.
+ * @param skinType The skin type used when drawing the popup.
*/
- Popup(const std::string &name = std::string(),
- const std::string &skin = "window.xml");
+ explicit Popup(const std::string &name = std::string(),
+ SkinType skinType = SkinType::Popup);
/**
* Destructor. Deletes all the added widgets.
@@ -68,12 +68,21 @@ class Popup : public Container, public gcn::MouseListener
*/
static void setWindowContainer(WindowContainer *windowContainer);
+ // Container interface
+ void add(gcn::Widget *widget) override;
+ void add(gcn::Widget *widget, int x, int y) override;
+
/**
* Draws the popup.
*/
void draw(gcn::Graphics *graphics) override;
/**
+ * Draws the popup frame.
+ */
+ void drawFrame(gcn::Graphics *graphics) override;
+
+ /**
* Sets the size of this popup.
*/
void setContentSize(int width, int height);
@@ -151,15 +160,20 @@ class Popup : public Container, public gcn::MouseListener
*/
void position(int x, int y);
+ /**
+ * Returns the Skin used by this popup.
+ */
+ const Skin &getSkin() const;
+
private:
- std::string mPopupName; /**< Name of the popup */
- int mMinWidth = 100; /**< Minimum popup width */
- int mMinHeight = 40; /**< Minimum popup height */
- int mMaxWidth; /**< Maximum popup width */
- int mMaxHeight; /**< Maximum popup height */
- int mPadding; /**< Holds the padding of the popup. */
-
- Skin *mSkin; /**< Skin in use by this popup */
-};
+ void widgetAdded(gcn::Widget *widget) const;
-#endif
+ std::string mPopupName; /**< Name of the popup */
+ int mMinWidth = 100; /**< Minimum popup width */
+ int mMinHeight = 40; /**< Minimum popup height */
+ int mMaxWidth; /**< Maximum popup width */
+ int mMaxHeight; /**< Maximum popup height */
+ int mPadding; /**< Holds the padding of the popup. */
+
+ SkinType mSkinType; /**< The skin type used when drawing the popup widget. */
+};
diff --git a/src/gui/widgets/progressbar.cpp b/src/gui/widgets/progressbar.cpp
index 9d41d1af..5cf1b05a 100644
--- a/src/gui/widgets/progressbar.cpp
+++ b/src/gui/widgets/progressbar.cpp
@@ -21,23 +21,14 @@
#include "gui/widgets/progressbar.h"
-#include "configuration.h"
#include "graphics.h"
-#include "textrenderer.h"
#include "gui/gui.h"
-#include "resources/image.h"
#include "resources/theme.h"
-#include "utils/dtor.h"
-
#include <guichan/font.hpp>
-ImageRect ProgressBar::mBorder;
-int ProgressBar::mInstances = 0;
-float ProgressBar::mAlpha = 1.0;
-
ProgressBar::ProgressBar(float progress,
int width, int height,
int color):
@@ -53,36 +44,6 @@ ProgressBar::ProgressBar(float progress,
mProgress);
setSize(width, height);
-
- if (mInstances == 0)
- {
- Image *dBorders = Theme::getImageFromTheme("vscroll_grey.png");
- mBorder.grid[0] = dBorders->getSubImage(0, 0, 4, 4);
- mBorder.grid[1] = dBorders->getSubImage(4, 0, 3, 4);
- mBorder.grid[2] = dBorders->getSubImage(7, 0, 4, 4);
- mBorder.grid[3] = dBorders->getSubImage(0, 4, 4, 10);
- mBorder.grid[4] = dBorders->getSubImage(4, 4, 3, 10);
- mBorder.grid[5] = dBorders->getSubImage(7, 4, 4, 10);
- mBorder.grid[6] = dBorders->getSubImage(0, 15, 4, 4);
- mBorder.grid[7] = dBorders->getSubImage(4, 15, 3, 4);
- mBorder.grid[8] = dBorders->getSubImage(7, 15, 4, 4);
-
- mBorder.setAlpha(mAlpha);
-
- dBorders->decRef();
- }
-
- mInstances++;
-}
-
-ProgressBar::~ProgressBar()
-{
- mInstances--;
-
- if (mInstances == 0)
- {
- std::for_each(mBorder.grid, mBorder.grid + 9, dtor<Image*>());
- }
}
void ProgressBar::logic()
@@ -114,30 +75,19 @@ void ProgressBar::logic()
}
}
-void ProgressBar::updateAlpha()
-{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
-
- if (mAlpha != alpha)
- {
- mAlpha = alpha;
- mBorder.setAlpha(mAlpha);
- }
-}
-
void ProgressBar::draw(gcn::Graphics *graphics)
{
- updateAlpha();
-
- mColor.a = (int) (mAlpha * 255);
+ mColor.a = gui->getTheme()->getGuiAlpha();
gcn::Rectangle rect = getDimension();
rect.x = 0;
rect.y = 0;
- render(static_cast<Graphics*>(graphics), rect, mColor,
- mProgress, mText);
+ gui->getTheme()->drawProgressBar(static_cast<Graphics *>(graphics),
+ rect,
+ mColor,
+ mProgress,
+ mText);
}
void ProgressBar::setProgress(float progress)
@@ -149,9 +99,7 @@ void ProgressBar::setProgress(float progress)
mProgress = p;
if (mProgressPalette >= 0)
- {
mColorToGo = Theme::getProgressColor(mProgressPalette, progress);
- }
}
void ProgressBar::setProgressPalette(int progressPalette)
@@ -160,9 +108,7 @@ void ProgressBar::setProgressPalette(int progressPalette)
mProgressPalette = progressPalette;
if (mProgressPalette != oldPalette && mProgressPalette >= 0)
- {
mColorToGo = Theme::getProgressColor(mProgressPalette, mProgressToGo);
- }
}
void ProgressBar::setColor(const gcn::Color &color)
@@ -172,37 +118,3 @@ void ProgressBar::setColor(const gcn::Color &color)
if (!mSmoothColorChange)
mColor = color;
}
-
-void ProgressBar::render(Graphics *graphics, const gcn::Rectangle &area,
- const gcn::Color &color, float progress,
- const std::string &text)
-{
- gcn::Font *oldFont = graphics->getFont();
- gcn::Color oldColor = graphics->getColor();
-
- graphics->drawImageRect(area, mBorder);
-
- // The bar
- if (progress > 0)
- {
- graphics->setColor(color);
- graphics->fillRectangle(gcn::Rectangle(area.x + 4, area.y + 4,
- (int) (progress * (area.width - 8)),
- area.height - 8));
- }
-
- // The label
- if (!text.empty())
- {
- const int textX = area.x + area.width / 2;
- const int textY = area.y + (area.height - boldFont->getHeight()) / 2;
-
- TextRenderer::renderText(graphics, text, textX, textY,
- gcn::Graphics::CENTER,
- Theme::getThemeColor(Theme::PROGRESS_BAR),
- gui->getFont(), true, false);
- }
-
- graphics->setFont(oldFont);
- graphics->setColor(oldColor);
-}
diff --git a/src/gui/widgets/progressbar.h b/src/gui/widgets/progressbar.h
index 2f9e665f..52904f5a 100644
--- a/src/gui/widgets/progressbar.h
+++ b/src/gui/widgets/progressbar.h
@@ -19,16 +19,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef PROGRESSBAR_H
-#define PROGRESSBAR_H
+#pragma once
#include <guichan/widget.hpp>
#include <string>
-class Graphics;
-class ImageRect;
-
/**
* A progress bar.
*
@@ -44,19 +40,12 @@ class ProgressBar : public gcn::Widget
int width = 40, int height = 7,
int color = -1);
- ~ProgressBar() override;
-
/**
* Performs progress bar logic (fading colors)
*/
void logic() override;
/**
- * Update the alpha value to the graphic components.
- */
- static void updateAlpha();
-
- /**
* Draws the progress bar.
*/
void draw(gcn::Graphics *graphics) override;
@@ -111,13 +100,6 @@ class ProgressBar : public gcn::Widget
void setSmoothColorChange(bool smoothColorChange)
{ mSmoothColorChange = smoothColorChange; }
- /**
- * Renders a progressbar with the given properties.
- */
- static void render(Graphics *graphics, const gcn::Rectangle &area,
- const gcn::Color &color, float progress,
- const std::string &text = std::string());
-
private:
float mProgress, mProgressToGo;
bool mSmoothProgress = true;
@@ -128,12 +110,4 @@ class ProgressBar : public gcn::Widget
bool mSmoothColorChange = true;
std::string mText;
-
- static ImageRect mBorder;
- static int mInstances;
- static float mAlpha;
-
- static const gcn::Color TEXT_COLOR;
};
-
-#endif
diff --git a/src/gui/widgets/progressindicator.cpp b/src/gui/widgets/progressindicator.cpp
index 496bd8a1..ccd4fd54 100644
--- a/src/gui/widgets/progressindicator.cpp
+++ b/src/gui/widgets/progressindicator.cpp
@@ -21,10 +21,10 @@
#include "progressindicator.h"
#include "graphics.h"
+#include "gui/gui.h"
#include "simpleanimation.h"
#include "resources/animation.h"
-#include "resources/imageset.h"
#include "resources/resourcemanager.h"
#include "resources/theme.h"
@@ -32,12 +32,12 @@
ProgressIndicator::ProgressIndicator()
{
- ImageSet *images = Theme::getImageSetFromTheme("progress-indicator.png",
- 32, 32);
+ const std::string path = gui->getTheme()->resolvePath("progress-indicator.png");
+ mImageSet = ResourceManager::getInstance()->getImageSet(path, 32, 32);
Animation anim;
- for (size_t i = 0; i < images->size(); ++i)
- anim.addFrame(images->get(i), 100, 0, 0);
+ for (size_t i = 0; i < mImageSet->size(); ++i)
+ anim.addFrame(mImageSet->get(i), 100, 0, 0);
mIndicator = std::make_unique<SimpleAnimation>(std::move(anim));
diff --git a/src/gui/widgets/progressindicator.h b/src/gui/widgets/progressindicator.h
index 428bbd02..4a6ea339 100644
--- a/src/gui/widgets/progressindicator.h
+++ b/src/gui/widgets/progressindicator.h
@@ -18,8 +18,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef PROGRESSINDICATOR_H
-#define PROGRESSINDICATOR_H
+#pragma once
+
+#include "resources/imageset.h"
#include <guichan/widget.hpp>
@@ -42,6 +43,5 @@ public:
private:
std::unique_ptr<SimpleAnimation> mIndicator;
+ ResourceRef<ImageSet> mImageSet;
};
-
-#endif // PROGRESSINDICATOR_H
diff --git a/src/gui/widgets/radiobutton.cpp b/src/gui/widgets/radiobutton.cpp
index 92cdacd1..ceba78eb 100644
--- a/src/gui/widgets/radiobutton.cpp
+++ b/src/gui/widgets/radiobutton.cpp
@@ -21,109 +21,43 @@
#include "gui/widgets/radiobutton.h"
-#include "configuration.h"
-#include "graphics.h"
+#include "textrenderer.h"
-#include "resources/image.h"
+#include "gui/gui.h"
#include "resources/theme.h"
-int RadioButton::instances = 0;
-float RadioButton::mAlpha = 1.0;
-Image *RadioButton::radioNormal;
-Image *RadioButton::radioChecked;
-Image *RadioButton::radioDisabled;
-Image *RadioButton::radioDisabledChecked;
-Image *RadioButton::radioNormalHi;
-Image *RadioButton::radioCheckedHi;
-
-RadioButton::RadioButton(const std::string &caption, const std::string &group,
- bool marked):
- gcn::RadioButton(caption, group, marked)
+RadioButton::RadioButton(const std::string &caption,
+ const std::string &group,
+ bool marked)
+ : gcn::RadioButton(caption, group, marked)
{
- if (instances == 0)
- {
- radioNormal = Theme::getImageFromTheme("radioout.png");
- radioChecked = Theme::getImageFromTheme("radioin.png");
- radioDisabled = Theme::getImageFromTheme("radioout.png");
- radioDisabledChecked = Theme::getImageFromTheme("radioin.png");
- radioNormalHi = Theme::getImageFromTheme("radioout_highlight.png");
- radioCheckedHi = Theme::getImageFromTheme("radioin_highlight.png");
- radioNormal->setAlpha(mAlpha);
- radioChecked->setAlpha(mAlpha);
- radioDisabled->setAlpha(mAlpha);
- radioDisabledChecked->setAlpha(mAlpha);
- radioNormalHi->setAlpha(mAlpha);
- radioCheckedHi->setAlpha(mAlpha);
- }
-
- instances++;
+ auto &skin = gui->getTheme()->getSkin(SkinType::RadioButton);
+ setWidth(skin.getMinWidth() + 2 * skin.padding + skin.spacing + getFont()->getWidth(caption));
+ setHeight(skin.getMinHeight() + 2 * skin.padding);
}
-RadioButton::~RadioButton()
+void RadioButton::draw(gcn::Graphics* graphics)
{
- instances--;
+ WidgetState widgetState(this);
+ if (mHasMouse)
+ widgetState.flags |= STATE_HOVERED;
+ if (isSelected())
+ widgetState.flags |= STATE_SELECTED;
- if (instances == 0)
- {
- radioNormal->decRef();
- radioChecked->decRef();
- radioDisabled->decRef();
- radioDisabledChecked->decRef();
- radioNormalHi->decRef();
- radioCheckedHi->decRef();
- }
-}
+ auto &skin = gui->getTheme()->getSkin(SkinType::RadioButton);
+ skin.draw(static_cast<Graphics *>(graphics), widgetState);
-void RadioButton::drawBox(gcn::Graphics* graphics)
-{
- if (config.guiAlpha != mAlpha)
+ if (auto skinState = skin.getState(widgetState.flags))
{
- mAlpha = config.guiAlpha;
- radioNormal->setAlpha(mAlpha);
- radioChecked->setAlpha(mAlpha);
- radioDisabled->setAlpha(mAlpha);
- radioDisabledChecked->setAlpha(mAlpha);
- radioNormalHi->setAlpha(mAlpha);
- radioCheckedHi->setAlpha(mAlpha);
+ auto &textFormat = skinState->textFormat;
+ TextRenderer::renderText(static_cast<Graphics *>(graphics),
+ getCaption(),
+ skin.getMinWidth() + skin.padding + skin.spacing,
+ skin.padding,
+ Graphics::LEFT,
+ textFormat.bold ? boldFont : getFont(),
+ textFormat);
}
-
- Image *box = nullptr;
-
- if (isEnabled())
- if (isSelected())
- if (mHasMouse)
- box = radioCheckedHi;
- else
- box = radioChecked;
- else
- if (mHasMouse)
- box = radioNormalHi;
- else
- box = radioNormal;
- else
- if (isSelected())
- box = radioDisabledChecked;
- else
- box = radioDisabled;
-
- if (box)
- static_cast<Graphics*>(graphics)->drawImage(box, 2, 2);
-}
-
-void RadioButton::draw(gcn::Graphics* graphics)
-{
- graphics->pushClipArea(gcn::Rectangle(1, 1, getWidth() - 1,
- getHeight() - 1));
-
- drawBox(graphics);
-
- graphics->popClipArea();
-
- graphics->setFont(getFont());
- graphics->setColor(getForegroundColor());
-
- int h = getHeight() + getHeight() / 2;
- graphics->drawText(getCaption(), h - 2, 0);
}
void RadioButton::mouseEntered(gcn::MouseEvent& event)
diff --git a/src/gui/widgets/radiobutton.h b/src/gui/widgets/radiobutton.h
index 2a96ff6e..fda43d01 100644
--- a/src/gui/widgets/radiobutton.h
+++ b/src/gui/widgets/radiobutton.h
@@ -19,55 +19,40 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef RADIOBUTTON_H
-#define RADIOBUTTON_H
+#pragma once
#include <guichan/widgets/radiobutton.hpp>
-class Image;
-
/**
* Guichan based RadioButton with custom look
*/
class RadioButton : public gcn::RadioButton
{
public:
- RadioButton(const std::string &caption,const std::string &group,
- bool marked = false);
-
- ~RadioButton() override;
+ RadioButton(const std::string &caption,
+ const std::string &group,
+ bool marked = false);
/**
- * Draws the radiobutton, not the caption.
+ * Implementation of the draw method.
*/
- void drawBox(gcn::Graphics* graphics) override;
+ void draw(gcn::Graphics *graphics) override;
/**
- * Implementation of the draw methods.
- * Thus, avoiding the rhomb around the radio button.
+ * Overridden because box is drawn in RadioButton::draw.
*/
- void draw(gcn::Graphics* graphics) override;
+ void drawBox(gcn::Graphics *graphics) override {}
/**
* Called when the mouse enteres the widget area.
*/
- void mouseEntered(gcn::MouseEvent& event) override;
+ void mouseEntered(gcn::MouseEvent &event) override;
/**
* Called when the mouse leaves the widget area.
*/
- void mouseExited(gcn::MouseEvent& event) override;
+ void mouseExited(gcn::MouseEvent &event) override;
private:
- static int instances;
- static float mAlpha;
bool mHasMouse = false;
- static Image *radioNormal;
- static Image *radioChecked;
- static Image *radioDisabled;
- static Image *radioDisabledChecked;
- static Image *radioNormalHi;
- static Image *radioCheckedHi;
};
-
-#endif // RADIOBUTTON_H
diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp
index dd29a977..0c5a7fb5 100644
--- a/src/gui/widgets/resizegrip.cpp
+++ b/src/gui/widgets/resizegrip.cpp
@@ -21,48 +21,22 @@
#include "gui/widgets/resizegrip.h"
-#include "configuration.h"
#include "graphics.h"
-#include "resources/image.h"
+#include "gui/gui.h"
#include "resources/theme.h"
#include <guichan/graphics.hpp>
-Image *ResizeGrip::gripImage = nullptr;
-int ResizeGrip::mInstances = 0;
-float ResizeGrip::mAlpha = 1.0;
-
-ResizeGrip::ResizeGrip(const std::string &image)
-{
- if (mInstances == 0)
- {
- // Load the grip image
- gripImage = Theme::getImageFromTheme(image);
- gripImage->setAlpha(mAlpha);
- }
-
- mInstances++;
-
- setWidth(gripImage->getWidth() + 2);
- setHeight(gripImage->getHeight() + 2);
-}
-
-ResizeGrip::~ResizeGrip()
+ResizeGrip::ResizeGrip()
{
- mInstances--;
-
- if (mInstances == 0)
- gripImage->decRef();
+ auto &skin = gui->getTheme()->getSkin(SkinType::ResizeGrip);
+ setSize(skin.width, skin.height);
}
void ResizeGrip::draw(gcn::Graphics *graphics)
{
- if (config.guiAlpha != mAlpha)
- {
- mAlpha = config.guiAlpha;
- gripImage->setAlpha(mAlpha);
- }
-
- static_cast<Graphics*>(graphics)->drawImage(gripImage, 0, 0);
+ gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics),
+ SkinType::ResizeGrip,
+ WidgetState(this));
}
diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h
index d2f8ca4d..9b4e0611 100644
--- a/src/gui/widgets/resizegrip.h
+++ b/src/gui/widgets/resizegrip.h
@@ -19,13 +19,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef RESIZEGRIP_H
-#define RESIZEGRIP_H
+#pragma once
#include <guichan/widget.hpp>
-class Image;
-
/**
* Resize grip. The resize grip is part of a resizable Window. It relies on the
* fact that uncaught mouse events are automatically routed to the parent
@@ -36,19 +33,10 @@ class Image;
class ResizeGrip : public gcn::Widget
{
public:
- ResizeGrip(const std::string &image = "resize.png");
-
- ~ResizeGrip() override;
+ ResizeGrip();
/**
* Draws the resize grip.
*/
void draw(gcn::Graphics *graphics) override;
-
- private:
- static Image *gripImage; /**< Resize grip image */
- static int mInstances; /**< Number of resize grip instances */
- static float mAlpha;
};
-
-#endif
diff --git a/src/gui/widgets/scrollarea.cpp b/src/gui/widgets/scrollarea.cpp
index 225a231d..1dec34be 100644
--- a/src/gui/widgets/scrollarea.cpp
+++ b/src/gui/widgets/scrollarea.cpp
@@ -21,24 +21,14 @@
#include "gui/widgets/scrollarea.h"
-#include "configuration.h"
#include "graphics.h"
-#include "resources/image.h"
-#include "resources/theme.h"
+#include "gui/gui.h"
-#include "utils/dtor.h"
-
-int ScrollArea::instances = 0;
-float ScrollArea::mAlpha = 1.0;
-ImageRect ScrollArea::background;
-ImageRect ScrollArea::vMarker;
-ImageRect ScrollArea::vMarkerHi;
-Image *ScrollArea::buttons[4][2];
+#include <guichan/exception.hpp>
ScrollArea::ScrollArea()
{
- addWidgetListener(this);
init();
}
@@ -51,24 +41,11 @@ ScrollArea::ScrollArea(gcn::Widget *widget):
ScrollArea::~ScrollArea()
{
delete getContent();
+}
- instances--;
-
- if (instances == 0)
- {
- std::for_each(background.grid, background.grid + 9, dtor<Image*>());
- std::for_each(vMarker.grid, vMarker.grid + 9, dtor<Image*>());
- std::for_each(vMarkerHi.grid, vMarkerHi.grid + 9, dtor<Image*>());
-
- buttons[UP][0]->decRef();
- buttons[UP][1]->decRef();
- buttons[DOWN][0]->decRef();
- buttons[DOWN][1]->decRef();
- buttons[LEFT][0]->decRef();
- buttons[LEFT][1]->decRef();
- buttons[RIGHT][0]->decRef();
- buttons[RIGHT][1]->decRef();
- }
+void ScrollArea::setShowButtons(bool showButtons)
+{
+ mShowButtons = showButtons;
}
void ScrollArea::init()
@@ -76,83 +53,27 @@ void ScrollArea::init()
// Draw background by default
setOpaque(true);
- setUpButtonScrollAmount(2);
- setDownButtonScrollAmount(2);
- setLeftButtonScrollAmount(2);
- setRightButtonScrollAmount(2);
-
- if (instances == 0)
- {
- // Load the background skin
- Image *textbox = Theme::getImageFromTheme("deepbox.png");
- const int bggridx[4] = {0, 3, 28, 31};
- const int bggridy[4] = {0, 3, 28, 31};
- int a = 0;
-
- for (int y = 0; y < 3; y++)
- {
- for (int x = 0; x < 3; x++)
- {
- background.grid[a] = textbox->getSubImage(
- bggridx[x], bggridy[y],
- bggridx[x + 1] - bggridx[x] + 1,
- bggridy[y + 1] - bggridy[y] + 1);
- a++;
- }
- }
- background.setAlpha(config.guiAlpha);
+ auto theme = gui->getTheme();
- textbox->decRef();
+ int scrollBarWidth = theme->getSkin(SkinType::ScrollAreaVBar).width;
+ if (scrollBarWidth > 0)
+ setScrollbarWidth(scrollBarWidth);
- // Load vertical scrollbar skin
- Image *vscroll = Theme::getImageFromTheme("vscroll_grey.png");
- Image *vscrollHi = Theme::getImageFromTheme("vscroll_highlight.png");
+ auto &scrollAreaSkin = theme->getSkin(SkinType::ScrollArea);
+ setShowButtons(scrollAreaSkin.showButtons);
- int vsgridx[4] = {0, 4, 7, 11};
- int vsgridy[4] = {0, 4, 15, 19};
- a = 0;
-
- for (int y = 0; y < 3; y++)
- {
- for (int x = 0; x < 3; x++)
- {
- vMarker.grid[a] = vscroll->getSubImage(
- vsgridx[x], vsgridy[y],
- vsgridx[x + 1] - vsgridx[x],
- vsgridy[y + 1] - vsgridy[y]);
- vMarkerHi.grid[a] = vscrollHi->getSubImage(
- vsgridx[x], vsgridy[y],
- vsgridx[x + 1] - vsgridx[x],
- vsgridy[y + 1] - vsgridy[y]);
- a++;
- }
- }
+ if (auto content = getContent())
+ content->setFrameSize(scrollAreaSkin.padding);
- vMarker.setAlpha(config.guiAlpha);
- vMarkerHi.setAlpha(config.guiAlpha);
-
- vscroll->decRef();
- vscrollHi->decRef();
-
- buttons[UP][0] =
- Theme::getImageFromTheme("vscroll_up_default.png");
- buttons[DOWN][0] =
- Theme::getImageFromTheme("vscroll_down_default.png");
- buttons[LEFT][0] =
- Theme::getImageFromTheme("hscroll_left_default.png");
- buttons[RIGHT][0] =
- Theme::getImageFromTheme("hscroll_right_default.png");
- buttons[UP][1] =
- Theme::getImageFromTheme("vscroll_up_pressed.png");
- buttons[DOWN][1] =
- Theme::getImageFromTheme("vscroll_down_pressed.png");
- buttons[LEFT][1] =
- Theme::getImageFromTheme("hscroll_left_pressed.png");
- buttons[RIGHT][1] =
- Theme::getImageFromTheme("hscroll_right_pressed.png");
- }
+ // The base color is only used when rendering a square in the corner where
+ // the scrollbars meet. We disable rendering of this square by setting the
+ // base color to transparent.
+ setBaseColor(gcn::Color(0, 0, 0, 0));
- instances++;
+ setUpButtonScrollAmount(5);
+ setDownButtonScrollAmount(5);
+ setLeftButtonScrollAmount(5);
+ setRightButtonScrollAmount(5);
}
void ScrollArea::logic()
@@ -201,159 +122,237 @@ void ScrollArea::logic()
}
}
-void ScrollArea::updateAlpha()
+void ScrollArea::draw(gcn::Graphics *graphics)
{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
-
- if (alpha != mAlpha)
- {
- mAlpha = alpha;
+ if (getFrameSize() == 0)
+ drawFrame(graphics);
- background.setAlpha(mAlpha);
- vMarker.setAlpha(mAlpha);
- vMarkerHi.setAlpha(mAlpha);
- }
+ gcn::ScrollArea::draw(graphics);
}
-void ScrollArea::draw(gcn::Graphics *graphics)
+void ScrollArea::drawFrame(gcn::Graphics *graphics)
{
- if (mVBarVisible)
- {
- drawUpButton(graphics);
- drawDownButton(graphics);
- drawVBar(graphics);
- drawVMarker(graphics);
- }
-
- if (mHBarVisible)
- {
- drawLeftButton(graphics);
- drawRightButton(graphics);
- drawHBar(graphics);
- drawHMarker(graphics);
- }
+ if (!mOpaque)
+ return;
- if (mHBarVisible && mVBarVisible)
- {
- graphics->setColor(getBaseColor());
- graphics->fillRectangle(gcn::Rectangle(getWidth() - mScrollbarWidth,
- getHeight() - mScrollbarWidth,
- mScrollbarWidth,
- mScrollbarWidth));
- }
+ const int bs = getFrameSize();
- updateAlpha();
+ WidgetState state(this);
+ state.width += bs * 2;
+ state.height += + bs * 2;
- drawChildren(graphics);
+ gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollArea, state);
}
-void ScrollArea::drawFrame(gcn::Graphics *graphics)
+void ScrollArea::drawChildren(gcn::Graphics *graphics)
{
- if (mOpaque)
- {
- const int bs = getFrameSize();
- const int w = getWidth() + bs * 2;
- const int h = getHeight() + bs * 2;
+ auto g = static_cast<Graphics*>(graphics);
+ g->pushClipRect(getChildrenArea());
- static_cast<Graphics*>(graphics)->
- drawImageRect(0, 0, w, h, background);
- }
+ gcn::ScrollArea::drawChildren(graphics);
+
+ g->popClipRect();
}
void ScrollArea::setOpaque(bool opaque)
{
mOpaque = opaque;
- setFrameSize(mOpaque ? 2 : 0);
+
+ auto &skin = gui->getTheme()->getSkin(SkinType::ScrollArea);
+ setFrameSize(mOpaque ? skin.frameSize : 0);
}
-void ScrollArea::drawButton(gcn::Graphics *graphics, BUTTON_DIR dir)
+void ScrollArea::drawBackground(gcn::Graphics *graphics)
{
- int state = 0;
- gcn::Rectangle dim;
+ // background is drawn as part of the frame instead
+}
- switch (dir)
- {
- case UP:
- state = mUpButtonPressed ? 1 : 0;
- dim = getUpButtonDimension();
- break;
- case DOWN:
- state = mDownButtonPressed ? 1 : 0;
- dim = getDownButtonDimension();
- break;
- case LEFT:
- state = mLeftButtonPressed ? 1 : 0;
- dim = getLeftButtonDimension();
- break;
- case RIGHT:
- state = mRightButtonPressed ? 1 : 0;
- dim = getRightButtonDimension();
- break;
- }
+static void drawButton(gcn::Graphics *graphics,
+ SkinType skinType,
+ bool pressed,
+ const gcn::Rectangle &dim)
+{
+ WidgetState state(dim);
+ if (pressed)
+ state.flags |= STATE_SELECTED;
- static_cast<Graphics*>(graphics)->
- drawImage(buttons[dir][state], dim.x, dim.y);
+ gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), skinType, state);
}
void ScrollArea::drawUpButton(gcn::Graphics *graphics)
{
- drawButton(graphics, UP);
+ if (!mShowButtons)
+ return;
+
+ drawButton(graphics, SkinType::ButtonUp, mUpButtonPressed, getUpButtonDimension());
}
void ScrollArea::drawDownButton(gcn::Graphics *graphics)
{
- drawButton(graphics, DOWN);
+ if (!mShowButtons)
+ return;
+
+ drawButton(graphics, SkinType::ButtonDown, mDownButtonPressed, getDownButtonDimension());
}
void ScrollArea::drawLeftButton(gcn::Graphics *graphics)
{
- drawButton(graphics, LEFT);
+ if (!mShowButtons)
+ return;
+
+ drawButton(graphics, SkinType::ButtonLeft, mLeftButtonPressed, getLeftButtonDimension());
}
void ScrollArea::drawRightButton(gcn::Graphics *graphics)
{
- drawButton(graphics, RIGHT);
+ if (!mShowButtons)
+ return;
+
+ drawButton(graphics, SkinType::ButtonRight, mRightButtonPressed, getRightButtonDimension());
}
void ScrollArea::drawVBar(gcn::Graphics *graphics)
{
- const gcn::Rectangle dim = getVerticalBarDimension();
- graphics->setColor(gcn::Color(0, 0, 0, 32));
- graphics->fillRectangle(dim);
- graphics->setColor(gcn::Color(255, 255, 255));
+ WidgetState state(getVerticalBarDimension());
+ if (mHasMouse && (mX > (getWidth() - getScrollbarWidth())))
+ state.flags |= STATE_HOVERED;
+
+ gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollAreaVBar, state);
}
void ScrollArea::drawHBar(gcn::Graphics *graphics)
{
- const gcn::Rectangle dim = getHorizontalBarDimension();
- graphics->setColor(gcn::Color(0, 0, 0, 32));
- graphics->fillRectangle(dim);
- graphics->setColor(gcn::Color(255, 255, 255));
+ WidgetState state(getHorizontalBarDimension());
+ if (mHasMouse && (mY > (getHeight() - getScrollbarWidth())))
+ state.flags |= STATE_HOVERED;
+
+ gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollAreaHBar, state);
}
void ScrollArea::drawVMarker(gcn::Graphics *graphics)
{
- gcn::Rectangle dim = getVerticalMarkerDimension();
+ WidgetState state(getVerticalMarkerDimension());
+ if (state.height == 0)
+ return;
- if ((mHasMouse) && (mX > (getWidth() - getScrollbarWidth())))
- static_cast<Graphics*>(graphics)->
- drawImageRect(dim.x, dim.y, dim.width, dim.height, vMarkerHi);
- else
- static_cast<Graphics*>(graphics)->
- drawImageRect(dim.x, dim.y, dim.width, dim.height,vMarker);
+ if (mHasMouse && (mX > (getWidth() - getScrollbarWidth())))
+ state.flags |= STATE_HOVERED;
+
+ gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollAreaVMarker, state);
}
void ScrollArea::drawHMarker(gcn::Graphics *graphics)
{
- gcn::Rectangle dim = getHorizontalMarkerDimension();
+ WidgetState state(getHorizontalMarkerDimension());
+ if (state.width == 0)
+ return;
+
+ if (mHasMouse && (mY > (getHeight() - getScrollbarWidth())))
+ state.flags |= STATE_HOVERED;
+
+ gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollAreaHMarker, state);
+}
+
+/**
+ * Code copied from gcn::ScrollArea::checkPolicies to make sure it takes the
+ * frame size of the content into account.
+ */
+void ScrollArea::checkPolicies()
+{
+ int w = getWidth();
+ int h = getHeight();
- if ((mHasMouse) && (mY > (getHeight() - getScrollbarWidth())))
- static_cast<Graphics*>(graphics)->
- drawImageRect(dim.x, dim.y, dim.width, dim.height, vMarkerHi);
- else
- static_cast<Graphics*>(graphics)->
- drawImageRect(dim.x, dim.y, dim.width, dim.height, vMarker);
+ mHBarVisible = false;
+ mVBarVisible = false;
+
+ if (!getContent())
+ {
+ mHBarVisible = (mHPolicy == SHOW_ALWAYS);
+ mVBarVisible = (mVPolicy == SHOW_ALWAYS);
+ return;
+ }
+
+ const int contentFrameSize = getContent()->getFrameSize();
+ w -= 2 * contentFrameSize;
+ h -= 2 * contentFrameSize;
+
+ if (mHPolicy == SHOW_AUTO &&
+ mVPolicy == SHOW_AUTO)
+ {
+ if (getContent()->getWidth() <= w
+ && getContent()->getHeight() <= h)
+ {
+ mHBarVisible = false;
+ mVBarVisible = false;
+ }
+
+ if (getContent()->getWidth() > w)
+ {
+ mHBarVisible = true;
+ }
+
+ if ((getContent()->getHeight() > h)
+ || (mHBarVisible && getContent()->getHeight() > h - mScrollbarWidth))
+ {
+ mVBarVisible = true;
+ }
+
+ if (mVBarVisible && getContent()->getWidth() > w - mScrollbarWidth)
+ {
+ mHBarVisible = true;
+ }
+
+ return;
+ }
+
+ switch (mHPolicy)
+ {
+ case SHOW_NEVER:
+ mHBarVisible = false;
+ break;
+
+ case SHOW_ALWAYS:
+ mHBarVisible = true;
+ break;
+
+ case SHOW_AUTO:
+ if (mVPolicy == SHOW_NEVER)
+ {
+ mHBarVisible = getContent()->getWidth() > w;
+ }
+ else // (mVPolicy == SHOW_ALWAYS)
+ {
+ mHBarVisible = getContent()->getWidth() > w - mScrollbarWidth;
+ }
+ break;
+
+ default:
+ throw GCN_EXCEPTION("Horizontal scroll policy invalid.");
+ }
+
+ switch (mVPolicy)
+ {
+ case SHOW_NEVER:
+ mVBarVisible = false;
+ break;
+
+ case SHOW_ALWAYS:
+ mVBarVisible = true;
+ break;
+
+ case SHOW_AUTO:
+ if (mHPolicy == SHOW_NEVER)
+ {
+ mVBarVisible = getContent()->getHeight() > h;
+ }
+ else // (mHPolicy == SHOW_ALWAYS)
+ {
+ mVBarVisible = getContent()->getHeight() > h - mScrollbarWidth;
+ }
+ break;
+ default:
+ throw GCN_EXCEPTION("Vertical scroll policy invalid.");
+ }
}
void ScrollArea::mouseMoved(gcn::MouseEvent& event)
@@ -372,8 +371,299 @@ void ScrollArea::mouseExited(gcn::MouseEvent& event)
mHasMouse = false;
}
-void ScrollArea::widgetResized(const gcn::Event &event)
+/**
+ * Code copied from gcn::ScrollArea::mousePressed to make it call our custom
+ * getVerticalMarkerDimension and getHorizontalMarkerDimension functions.
+ */
+void ScrollArea::mousePressed(gcn::MouseEvent &mouseEvent)
{
- getContent()->setSize(getWidth() - 2 * getFrameSize(),
- getHeight() - 2 * getFrameSize());
+ int x = mouseEvent.getX();
+ int y = mouseEvent.getY();
+
+ if (getUpButtonDimension().isPointInRect(x, y))
+ {
+ setVerticalScrollAmount(getVerticalScrollAmount()
+ - mUpButtonScrollAmount);
+ mUpButtonPressed = true;
+ }
+ else if (getDownButtonDimension().isPointInRect(x, y))
+ {
+ setVerticalScrollAmount(getVerticalScrollAmount()
+ + mDownButtonScrollAmount);
+ mDownButtonPressed = true;
+ }
+ else if (getLeftButtonDimension().isPointInRect(x, y))
+ {
+ setHorizontalScrollAmount(getHorizontalScrollAmount()
+ - mLeftButtonScrollAmount);
+ mLeftButtonPressed = true;
+ }
+ else if (getRightButtonDimension().isPointInRect(x, y))
+ {
+ setHorizontalScrollAmount(getHorizontalScrollAmount()
+ + mRightButtonScrollAmount);
+ mRightButtonPressed = true;
+ }
+ else if (getVerticalMarkerDimension().isPointInRect(x, y))
+ {
+ mIsHorizontalMarkerDragged = false;
+ mIsVerticalMarkerDragged = true;
+
+ mVerticalMarkerDragOffset = y - getVerticalMarkerDimension().y;
+ }
+ else if (getVerticalBarDimension().isPointInRect(x,y))
+ {
+ if (y < getVerticalMarkerDimension().y)
+ {
+ setVerticalScrollAmount(getVerticalScrollAmount()
+ - (int)(getChildrenArea().height * 0.95));
+ }
+ else
+ {
+ setVerticalScrollAmount(getVerticalScrollAmount()
+ + (int)(getChildrenArea().height * 0.95));
+ }
+ }
+ else if (getHorizontalMarkerDimension().isPointInRect(x, y))
+ {
+ mIsHorizontalMarkerDragged = true;
+ mIsVerticalMarkerDragged = false;
+
+ mHorizontalMarkerDragOffset = x - getHorizontalMarkerDimension().x;
+ }
+ else if (getHorizontalBarDimension().isPointInRect(x,y))
+ {
+ if (x < getHorizontalMarkerDimension().x)
+ {
+ setHorizontalScrollAmount(getHorizontalScrollAmount()
+ - (int)(getChildrenArea().width * 0.95));
+ }
+ else
+ {
+ setHorizontalScrollAmount(getHorizontalScrollAmount()
+ + (int)(getChildrenArea().width * 0.95));
+ }
+ }
+}
+
+/**
+ * Code copied from gcn::ScrollArea::mouseDragged to make it call our custom
+ * getVerticalMarkerDimension and getHorizontalMarkerDimension functions.
+ */
+void ScrollArea::mouseDragged(gcn::MouseEvent &mouseEvent)
+{
+ if (mIsVerticalMarkerDragged)
+ {
+ int pos = mouseEvent.getY() - getVerticalBarDimension().y - mVerticalMarkerDragOffset;
+ int length = getVerticalMarkerDimension().height;
+
+ gcn::Rectangle barDim = getVerticalBarDimension();
+
+ if ((barDim.height - length) > 0)
+ {
+ setVerticalScrollAmount((getVerticalMaxScroll() * pos)
+ / (barDim.height - length));
+ }
+ else
+ {
+ setVerticalScrollAmount(0);
+ }
+ }
+
+ if (mIsHorizontalMarkerDragged)
+ {
+ int pos = mouseEvent.getX() - getHorizontalBarDimension().x - mHorizontalMarkerDragOffset;
+ int length = getHorizontalMarkerDimension().width;
+
+ gcn::Rectangle barDim = getHorizontalBarDimension();
+
+ if ((barDim.width - length) > 0)
+ {
+ setHorizontalScrollAmount((getHorizontalMaxScroll() * pos)
+ / (barDim.width - length));
+ }
+ else
+ {
+ setHorizontalScrollAmount(0);
+ }
+ }
+
+ mouseEvent.consume();
+}
+
+gcn::Rectangle ScrollArea::getUpButtonDimension()
+{
+ if (!mVBarVisible || !mShowButtons)
+ return gcn::Rectangle();
+
+ return gcn::Rectangle(getWidth() - mScrollbarWidth, 0, mScrollbarWidth, mScrollbarWidth);
+}
+
+gcn::Rectangle ScrollArea::getDownButtonDimension()
+{
+ if (!mVBarVisible || !mShowButtons)
+ return gcn::Rectangle();
+
+ gcn::Rectangle dim(getWidth() - mScrollbarWidth,
+ getHeight() - mScrollbarWidth,
+ mScrollbarWidth,
+ mScrollbarWidth);
+
+ if (mHBarVisible)
+ dim.y -= mScrollbarWidth;
+
+ return dim;
+}
+
+gcn::Rectangle ScrollArea::getLeftButtonDimension()
+{
+ if (!mHBarVisible || !mShowButtons)
+ return gcn::Rectangle();
+
+ return gcn::Rectangle(0, getHeight() - mScrollbarWidth, mScrollbarWidth, mScrollbarWidth);
+}
+
+gcn::Rectangle ScrollArea::getRightButtonDimension()
+{
+ if (!mHBarVisible || !mShowButtons)
+ return gcn::Rectangle();
+
+ gcn::Rectangle dim(getWidth() - mScrollbarWidth,
+ getHeight() - mScrollbarWidth,
+ mScrollbarWidth,
+ mScrollbarWidth);
+
+ if (mVBarVisible)
+ dim.x -= mScrollbarWidth;
+
+ return dim;
+}
+
+gcn::Rectangle ScrollArea::getVerticalBarDimension()
+{
+ if (!mVBarVisible)
+ return gcn::Rectangle();
+
+ gcn::Rectangle dim(getWidth() - mScrollbarWidth,
+ getUpButtonDimension().height,
+ mScrollbarWidth,
+ getHeight()
+ - getUpButtonDimension().height
+ - getDownButtonDimension().height);
+
+ if (mHBarVisible)
+ dim.height -= mScrollbarWidth;
+
+ if (dim.height < 0)
+ dim.height = 0;
+
+ return dim;
+}
+
+gcn::Rectangle ScrollArea::getHorizontalBarDimension()
+{
+ if (!mHBarVisible)
+ return gcn::Rectangle();
+
+ gcn::Rectangle dim(getLeftButtonDimension().width,
+ getHeight() - mScrollbarWidth,
+ getWidth()
+ - getLeftButtonDimension().width
+ - getRightButtonDimension().width,
+ mScrollbarWidth);
+
+ if (mVBarVisible)
+ dim.width -= mScrollbarWidth;
+
+ if (dim.width < 0)
+ dim.width = 0;
+
+ return dim;
+}
+
+static void getMarkerValues(int barSize,
+ int maxScroll, int scrollAmount,
+ int contentHeight, int viewHeight,
+ int fixedMarkerSize, int minMarkerSize,
+ int &markerSize, int &markerPos)
+{
+ if (fixedMarkerSize == 0)
+ {
+ if (contentHeight != 0 && contentHeight > viewHeight)
+ markerSize = std::max((barSize * viewHeight) / contentHeight, minMarkerSize);
+ else
+ markerSize = barSize;
+ }
+ else
+ {
+ if (contentHeight > viewHeight)
+ markerSize = fixedMarkerSize;
+ else
+ markerSize = 0;
+ }
+
+ // Hide the marker when it doesn't fit
+ if (markerSize > barSize)
+ markerSize = 0;
+
+ if (maxScroll != 0)
+ markerPos = ((barSize - markerSize) * scrollAmount + maxScroll / 2) / maxScroll;
+ else
+ markerPos = 0;
+}
+
+gcn::Rectangle ScrollArea::getVerticalMarkerDimension()
+{
+ if (!mVBarVisible)
+ return gcn::Rectangle();
+
+ auto &markerSkin = gui->getTheme()->getSkin(SkinType::ScrollAreaVMarker);
+ const gcn::Rectangle barDim = getVerticalBarDimension();
+
+ int contentHeight = 0;
+ if (auto content = getContent())
+ contentHeight = content->getHeight() + content->getFrameSize() * 2;
+
+ int length;
+ int pos;
+
+ getMarkerValues(barDim.height,
+ getVerticalMaxScroll(),
+ getVerticalScrollAmount(),
+ contentHeight,
+ getChildrenArea().height,
+ markerSkin.height,
+ mScrollbarWidth,
+ length,
+ pos);
+
+ return gcn::Rectangle(barDim.x, barDim.y + pos, mScrollbarWidth, length);
+}
+
+gcn::Rectangle ScrollArea::getHorizontalMarkerDimension()
+{
+ if (!mHBarVisible)
+ return gcn::Rectangle();
+
+ auto &markerSkin = gui->getTheme()->getSkin(SkinType::ScrollAreaHMarker);
+ const gcn::Rectangle barDim = getHorizontalBarDimension();
+
+ int contentWidth = 0;
+ if (auto content = getContent())
+ contentWidth = content->getWidth() + content->getFrameSize() * 2;
+
+ int length;
+ int pos;
+
+ getMarkerValues(barDim.width,
+ getHorizontalMaxScroll(),
+ getHorizontalScrollAmount(),
+ contentWidth,
+ getChildrenArea().width,
+ markerSkin.width,
+ mScrollbarWidth,
+ length,
+ pos);
+
+ return gcn::Rectangle(barDim.x + pos, barDim.y, length, mScrollbarWidth);
}
diff --git a/src/gui/widgets/scrollarea.h b/src/gui/widgets/scrollarea.h
index 2fae2d4b..0ba10578 100644
--- a/src/gui/widgets/scrollarea.h
+++ b/src/gui/widgets/scrollarea.h
@@ -19,14 +19,9 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef SCROLLAREA_H
-#define SCROLLAREA_H
+#pragma once
#include <guichan/widgets/scrollarea.hpp>
-#include <guichan/widgetlistener.hpp>
-
-class Image;
-class ImageRect;
/**
* A scroll area.
@@ -35,9 +30,11 @@ class ImageRect;
* content. However, it won't delete a previously set content widget when
* setContent is called!
*
+ * Also overrides several functions to support fixed-size scroll bar markers.
+ *
* \ingroup GUI
*/
-class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener
+class ScrollArea : public gcn::ScrollArea
{
public:
/**
@@ -59,18 +56,18 @@ class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener
~ScrollArea() override;
/**
- * Logic function optionally adapts width or height of contents. This
- * depends on the scrollbar settings.
+ * Sets whether the scroll bar buttons are shown.
*/
- void logic() override;
+ void setShowButtons(bool showButtons);
/**
- * Update the alpha value to the graphic components.
+ * Logic function optionally adapts width or height of contents. This
+ * depends on the scrollbar settings.
*/
- static void updateAlpha();
+ void logic() override;
/**
- * Draws the scroll area.
+ * Overridden to draw the frame if its size is 0.
*/
void draw(gcn::Graphics *graphics) override;
@@ -80,6 +77,11 @@ class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener
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);
@@ -92,34 +94,28 @@ class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener
/**
* Called when the mouse moves in the widget area.
*/
- void mouseMoved(gcn::MouseEvent& event) override;
+ void mouseMoved(gcn::MouseEvent &event) override;
/**
* Called when the mouse enteres the widget area.
*/
- void mouseEntered(gcn::MouseEvent& event) override;
+ void mouseEntered(gcn::MouseEvent &event) override;
/**
* Called when the mouse leaves the widget area.
*/
- void mouseExited(gcn::MouseEvent& event) override;
+ void mouseExited(gcn::MouseEvent &event) override;
- void widgetResized(const gcn::Event &event) override;
+ void mousePressed(gcn::MouseEvent &mouseEvent) override;
+ void mouseDragged(gcn::MouseEvent &mouseEvent) override;
protected:
- enum BUTTON_DIR {
- UP,
- DOWN,
- LEFT,
- RIGHT
- };
-
/**
* Initializes the scroll area.
*/
void init();
- void drawButton(gcn::Graphics *graphics, BUTTON_DIR dir);
+ void drawBackground(gcn::Graphics *graphics) override;
void drawUpButton(gcn::Graphics *graphics) override;
void drawDownButton(gcn::Graphics *graphics) override;
void drawLeftButton(gcn::Graphics *graphics) override;
@@ -129,17 +125,31 @@ class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener
void drawVMarker(gcn::Graphics *graphics) override;
void drawHMarker(gcn::Graphics *graphics) override;
- static int instances;
- static float mAlpha;
- static ImageRect background;
- static ImageRect vMarker;
- static ImageRect vMarkerHi;
- static Image *buttons[4][2];
+ void checkPolicies() override;
+
+ /**
+ * Shadowing these functions from gcn::ScrollArea with versions that
+ * support hiding the buttons. We need to make sure we always use these
+ * versions.
+ */
+ gcn::Rectangle getUpButtonDimension();
+ gcn::Rectangle getDownButtonDimension();
+ gcn::Rectangle getLeftButtonDimension();
+ gcn::Rectangle getRightButtonDimension();
+ gcn::Rectangle getVerticalBarDimension();
+ gcn::Rectangle getHorizontalBarDimension();
+
+ /**
+ * Shadowing these functions from gcn::ScrollArea with versions that
+ * supports fixed-size scroll bar markers. We need to make sure we
+ * always use these versions.
+ */
+ gcn::Rectangle getVerticalMarkerDimension();
+ gcn::Rectangle getHorizontalMarkerDimension();
int mX = 0;
int mY = 0;
bool mHasMouse = false;
bool mOpaque = true;
+ bool mShowButtons = true;
};
-
-#endif
diff --git a/src/gui/widgets/setuptab.h b/src/gui/widgets/setuptab.h
index 0cc35a98..78cef5b2 100644
--- a/src/gui/widgets/setuptab.h
+++ b/src/gui/widgets/setuptab.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GUI_SETUPTAB_H
-#define GUI_SETUPTAB_H
+#pragma once
#include "gui/widgets/container.h"
@@ -58,5 +57,3 @@ protected:
private:
std::string mName;
};
-
-#endif
diff --git a/src/gui/widgets/shopitems.h b/src/gui/widgets/shopitems.h
index e213f67c..1b6e1727 100644
--- a/src/gui/widgets/shopitems.h
+++ b/src/gui/widgets/shopitems.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef SHOP_H
-#define SHOP_H
+#pragma once
#include <guichan/listmodel.hpp>
@@ -111,5 +110,3 @@ class ShopItems : public gcn::ListModel
/** Look for duplicate entries on addition. */
bool mMergeDuplicates;
};
-
-#endif // SHOP_H
diff --git a/src/gui/widgets/shoplistbox.cpp b/src/gui/widgets/shoplistbox.cpp
index 31c733a6..e2313c85 100644
--- a/src/gui/widgets/shoplistbox.cpp
+++ b/src/gui/widgets/shoplistbox.cpp
@@ -71,14 +71,13 @@ void ShopListBox::draw(gcn::Graphics *gcnGraphics)
return;
const int alpha = (int)(config.guiAlpha * 255.0f);
- const gcn::Color &highlightColor =
- Theme::getThemeColor(Theme::HIGHLIGHT, alpha);
- const gcn::Color &backgroundColor =
- Theme::getThemeColor(Theme::BACKGROUND, alpha);
- const gcn::Color &warningColor =
- Theme::getThemeColor(Theme::SHOP_WARNING, alpha);
- const gcn::Color &textColor =
- Theme::getThemeColor(Theme::TEXT);
+ auto highlightColor = Theme::getThemeColor(Theme::HIGHLIGHT);
+ auto backgroundColor = Theme::getThemeColor(Theme::BACKGROUND);
+ auto warningColor = Theme::getThemeColor(Theme::SHOP_WARNING);
+ auto textColor = Theme::getThemeColor(Theme::TEXT);
+ highlightColor.a = alpha;
+ backgroundColor.a = alpha;
+ warningColor.a = alpha;
auto *graphics = static_cast<Graphics*>(gcnGraphics);
@@ -168,8 +167,7 @@ void ShopListBox::mouseMoved(gcn::MouseEvent &event)
}
else
{
- Item *item = mShopItems->at(index);
- if (item)
+ if (Item *item = mShopItems->at(index))
{
mItemPopup->setItem(item->getInfo());
mItemPopup->position(viewport->getMouseX(), viewport->getMouseY());
diff --git a/src/gui/widgets/shoplistbox.h b/src/gui/widgets/shoplistbox.h
index 4dbd756b..f6a1b12a 100644
--- a/src/gui/widgets/shoplistbox.h
+++ b/src/gui/widgets/shoplistbox.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef SHOPLISTBOX_H
-#define SHOPLISTBOX_H
+#pragma once
#include "gui/widgets/listbox.h"
@@ -97,5 +96,3 @@ class ShopListBox : public ListBox
bool mPriceCheck;
};
-
-#endif // SHOPLISTBOX_H
diff --git a/src/gui/widgets/shortcutcontainer.cpp b/src/gui/widgets/shortcutcontainer.cpp
index 5925752e..9271b1f4 100644
--- a/src/gui/widgets/shortcutcontainer.cpp
+++ b/src/gui/widgets/shortcutcontainer.cpp
@@ -21,10 +21,18 @@
#include "gui/widgets/shortcutcontainer.h"
-float ShortcutContainer::mAlpha = 1.0;
+#include "gui/gui.h"
+
+#include "resources/theme.h"
ShortcutContainer::ShortcutContainer()
{
+ addMouseListener(this);
+ addWidgetListener(this);
+
+ auto &skin = gui->getTheme()->getSkin(SkinType::ShortcutBox);
+ mBoxWidth = skin.width;
+ mBoxHeight = skin.height;
}
void ShortcutContainer::widgetResized(const gcn::Event &event)
diff --git a/src/gui/widgets/shortcutcontainer.h b/src/gui/widgets/shortcutcontainer.h
index cab20f27..35a88d7f 100644
--- a/src/gui/widgets/shortcutcontainer.h
+++ b/src/gui/widgets/shortcutcontainer.h
@@ -19,15 +19,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef SHORTCUTCONTAINER_H
-#define SHORTCUTCONTAINER_H
+#pragma once
#include <guichan/mouselistener.hpp>
#include <guichan/widget.hpp>
#include <guichan/widgetlistener.hpp>
-class Image;
-
/**
* A generic shortcut container.
*
@@ -45,20 +42,18 @@ class ShortcutContainer : public gcn::Widget,
*/
void draw(gcn::Graphics *graphics) override = 0;
+ // Overridden to disable drawing of the frame
+ void drawFrame(gcn::Graphics *graphics) override {}
+
/**
* Invoked when a widget changes its size. This is used to determine
* the new height of the container.
*/
void widgetResized(const gcn::Event &event) override;
- int getMaxItems() const
- { return mMaxItems; }
-
- int getBoxWidth() const
- { return mBoxWidth; }
-
- int getBoxHeight() const
- { return mBoxHeight; }
+ int getMaxItems() const { return mMaxItems; }
+ int getBoxWidth() const { return mBoxWidth; }
+ int getBoxHeight() const { return mBoxHeight; }
protected:
/**
@@ -70,10 +65,6 @@ class ShortcutContainer : public gcn::Widget,
*/
int getIndexFromGrid(int pointX, int pointY) const;
- Image *mBackgroundImg;
-
- static float mAlpha;
-
int mMaxItems = 0;
int mBoxWidth = 0;
int mBoxHeight = 0;
@@ -82,5 +73,3 @@ class ShortcutContainer : public gcn::Widget,
int mGridWidth = 1;
int mGridHeight = 1;
};
-
-#endif
diff --git a/src/gui/widgets/slider.cpp b/src/gui/widgets/slider.cpp
index a7ba37e8..bad10c15 100644
--- a/src/gui/widgets/slider.cpp
+++ b/src/gui/widgets/slider.cpp
@@ -21,19 +21,11 @@
#include "gui/widgets/slider.h"
-#include "configuration.h"
#include "graphics.h"
-#include "resources/image.h"
+#include "gui/gui.h"
#include "resources/theme.h"
-Image *Slider::hStart, *Slider::hMid, *Slider::hEnd, *Slider::hGrip;
-Image *Slider::vStart, *Slider::vMid, *Slider::vEnd, *Slider::vGrip;
-Image *Slider::hStartHi, *Slider::hMidHi, *Slider::hEndHi, *Slider::hGripHi;
-Image *Slider::vStartHi, *Slider::vMidHi, *Slider::vEndHi, *Slider::vGripHi;
-float Slider::mAlpha = 1.0;
-int Slider::mInstances = 0;
-
Slider::Slider(double scaleEnd):
gcn::Slider(scaleEnd)
{
@@ -46,154 +38,30 @@ Slider::Slider(double scaleStart, double scaleEnd):
init();
}
-Slider::~Slider()
-{
- mInstances--;
-
- if (mInstances == 0)
- {
- delete hStart;
- delete hMid;
- delete hEnd;
- delete hGrip;
- delete vStart;
- delete vMid;
- delete vEnd;
- delete vGrip;
- delete hStartHi;
- delete hMidHi;
- delete hEndHi;
- delete hGripHi;
- delete vStartHi;
- delete vMidHi;
- delete vEndHi;
- delete vGripHi;
- }
-}
-
void Slider::init()
{
- int x, y, w, h,o1,o2;
- setFrameSize(0);
-
- // Load resources
- if (mInstances == 0)
- {
- Image *slider = Theme::getImageFromTheme("slider.png");
- Image *sliderHi = Theme::getImageFromTheme("slider_hilight.png");
-
- x = 0; y = 0;
- w = 15; h = 6;
- o1 = 4; o2 = 11;
- hStart = slider->getSubImage(x, y, o1 - x, h);
- hMid = slider->getSubImage(o1, y, o2 - o1, h);
- hEnd = slider->getSubImage(o2, y, w - o2 + x, h);
- hStartHi = sliderHi->getSubImage(x, y, o1 - x, h);
- hMidHi = sliderHi->getSubImage(o1, y, o2 - o1, h);
- hEndHi = sliderHi->getSubImage(o2, y, w - o2 + x, h);
-
- x = 6; y = 8;
- w = 9; h = 10;
- hGrip = slider->getSubImage(x, y, w, h);
- hGripHi = sliderHi->getSubImage(x, y, w, h);
-
- x = 0; y = 6;
- w = 6; h = 21;
- o1 = 10; o2 = 18;
- vStart = slider->getSubImage(x, y, w, o1 - y);
- vMid = slider->getSubImage(x, o1, w, o2 - o1);
- vEnd = slider->getSubImage(x, o2, w, h - o2 + y);
- vStartHi = sliderHi->getSubImage(x, y, w, o1 - y);
- vMidHi = sliderHi->getSubImage(x, o1, w, o2 - o1);
- vEndHi = sliderHi->getSubImage(x, o2, w, h - o2 + y);
-
- x = 6; y = 8;
- w = 9; h = 10;
- vGrip = slider->getSubImage(x, y, w, h);
- vGripHi = sliderHi->getSubImage(x, y, w, h);
-
- slider->decRef();
- sliderHi->decRef();
- }
-
- mInstances++;
-
- setMarkerLength(hGrip->getWidth());
-}
-
-void Slider::updateAlpha()
-{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
-
- if (alpha != mAlpha)
- {
- mAlpha = alpha;
- hStart->setAlpha(mAlpha);
- hMid->setAlpha(mAlpha);
- hEnd->setAlpha(mAlpha);
- hGrip->setAlpha(mAlpha);
- hStartHi->setAlpha(mAlpha);
- hMidHi->setAlpha(mAlpha);
- hEndHi->setAlpha(mAlpha);
- hGripHi->setAlpha(mAlpha);
-
- vStart->setAlpha(mAlpha);
- vMid->setAlpha(mAlpha);
- vEnd->setAlpha(mAlpha);
- vGrip->setAlpha(mAlpha);
- vStartHi->setAlpha(mAlpha);
- vMidHi->setAlpha(mAlpha);
- vEndHi->setAlpha(mAlpha);
- vGripHi->setAlpha(mAlpha);
- }
-
+ auto theme = gui->getTheme();
+ auto &sliderSkin = theme->getSkin(SkinType::Slider);
+ auto &sliderHandleSkin = theme->getSkin(SkinType::SliderHandle);
+ setFrameSize(sliderSkin.frameSize);
+ setMarkerLength(sliderHandleSkin.getMinWidth());
+
+ setWidth(100);
+ setHeight(sliderSkin.getMinHeight() + 2 * sliderSkin.padding);
}
void Slider::draw(gcn::Graphics *graphics)
{
- int w = getWidth();
- int h = getHeight();
- int x = 0;
- int y = mHasMouse?(h - hStartHi->getHeight()) / 2:(h - hStart->getHeight()) / 2;
-
- updateAlpha();
-
- if (!mHasMouse)
- {
- static_cast<Graphics*>(graphics)->drawImage(hStart, x, y);
-
- w -= hStart->getWidth() + hEnd->getWidth();
- x += hStart->getWidth();
-
- static_cast<Graphics*>(graphics)->
- drawImagePattern(hMid, x, y, w, hMid->getHeight());
+ WidgetState state(this);
+ if (mHasMouse)
+ state.flags |= STATE_HOVERED;
- x += w;
- static_cast<Graphics*>(graphics)->drawImage(hEnd, x, y);
- }
- else
- {
- static_cast<Graphics*>(graphics)->drawImage(hStartHi, x, y);
+ auto theme = gui->getTheme();
+ theme->drawSkin(static_cast<Graphics*>(graphics), SkinType::Slider, state);
- w -= hStartHi->getWidth() + hEndHi->getWidth();
- x += hStartHi->getWidth();
-
- static_cast<Graphics*>(graphics)->
- drawImagePattern(hMidHi, x, y, w, hMidHi->getHeight());
-
- x += w;
- static_cast<Graphics*>(graphics)->drawImage(hEndHi, x, y);
- }
-
- drawMarker(graphics);
-}
-
-void Slider::drawMarker(gcn::Graphics *graphics)
-{
- static_cast<Graphics*>(graphics)->
- drawImage(mHasMouse?hGripHi:hGrip, getMarkerPosition(),
- (getHeight() - (mHasMouse?hGripHi:hGrip)->getHeight()) / 2);
+ WidgetState handleState(state);
+ handleState.x += getMarkerPosition();
+ theme->drawSkin(static_cast<Graphics*>(graphics), SkinType::SliderHandle, handleState);
}
void Slider::mouseEntered(gcn::MouseEvent& event)
@@ -205,4 +73,3 @@ void Slider::mouseExited(gcn::MouseEvent& event)
{
mHasMouse = false;
}
-
diff --git a/src/gui/widgets/slider.h b/src/gui/widgets/slider.h
index 3896cb52..52b3b3af 100644
--- a/src/gui/widgets/slider.h
+++ b/src/gui/widgets/slider.h
@@ -19,13 +19,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef SLIDER_H
-#define SLIDER_H
+#pragma once
#include <guichan/widgets/slider.hpp>
-class Image;
-
/**
* Slider widget. Same as the Guichan slider but with custom look.
*
@@ -47,22 +44,16 @@ class Slider : public gcn::Slider
*/
Slider(double scaleStart, double scaleEnd);
- ~Slider() override;
-
- /**
- * Update the alpha value to the graphic components.
- */
- static void updateAlpha();
-
/**
* Draws the slider.
*/
void draw(gcn::Graphics *graphics) override;
- /**
- * Draws the marker.
- */
- void drawMarker(gcn::Graphics *graphics) override;
+ // Overridden to disable drawing of the frame
+ void drawFrame(gcn::Graphics *graphics) override {}
+
+ // Marker is drawn in Slider::draw
+ void drawMarker(gcn::Graphics *graphics) override {}
/**
* Called when the mouse enteres the widget area.
@@ -80,13 +71,5 @@ class Slider : public gcn::Slider
*/
void init();
- static Image *hStart, *hMid, *hEnd, *hGrip;
- static Image *vStart, *vMid, *vEnd, *vGrip;
- static Image *hStartHi, *hMidHi, *hEndHi, *hGripHi;
- static Image *vStartHi, *vMidHi, *vEndHi, *vGripHi;
bool mHasMouse = false;
- static float mAlpha;
- static int mInstances;
};
-
-#endif
diff --git a/src/gui/widgets/spacer.h b/src/gui/widgets/spacer.h
index f6a210dc..2fda6e8c 100644
--- a/src/gui/widgets/spacer.h
+++ b/src/gui/widgets/spacer.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef SPACER_H
-#define SPACER_H
+#pragma once
#include "guichan/graphics.hpp"
#include "guichan/widget.hpp"
@@ -48,5 +47,3 @@ class Spacer : public gcn::Widget
*/
void draw(gcn::Graphics *g) override {}
};
-
-#endif // SPACER_H
diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp
index 64f49eac..b2779c4f 100644
--- a/src/gui/widgets/tab.cpp
+++ b/src/gui/widgets/tab.cpp
@@ -21,149 +21,90 @@
#include "gui/widgets/tab.h"
-#include "configuration.h"
#include "graphics.h"
+#include "gui/gui.h"
+#include "gui/widgets/label.h"
#include "gui/widgets/tabbedarea.h"
-#include "resources/image.h"
#include "resources/theme.h"
-#include "utils/dtor.h"
-
#include <guichan/widgets/label.hpp>
-int Tab::mInstances = 0;
-float Tab::mAlpha = 1.0;
-
-enum {
- TAB_STANDARD, // 0
- TAB_HIGHLIGHTED, // 1
- TAB_SELECTED, // 2
- TAB_UNUSED, // 3
- TAB_COUNT // 4 - Must be last.
-};
-
-struct TabData
-{
- char const *file;
- int gridX[4];
- int gridY[4];
-};
-
-static TabData const data[TAB_COUNT] = {
- { "tab.png", {0, 9, 16, 25}, {0, 13, 19, 20} },
- { "tab_hilight.png", {0, 9, 16, 25}, {0, 13, 19, 20} },
- { "tabselected.png", {0, 9, 16, 25}, {0, 4, 12, 20} },
- { "tab.png", {0, 9, 16, 25}, {0, 13, 19, 20} }
-};
-
-ImageRect Tab::tabImg[TAB_COUNT];
-
-Tab::Tab() :
- mTabColor(&Theme::getThemeColor(Theme::TAB))
-{
- init();
-}
-
-Tab::~Tab()
-{
- mInstances--;
-
- if (mInstances == 0)
- {
- for (auto &imgRect : tabImg)
- {
- std::for_each(imgRect.grid, imgRect.grid + 9, dtor<Image*>());
- }
- }
-}
-
-void Tab::init()
+Tab::Tab()
{
setFocusable(false);
- setFrameSize(0);
- mFlash = false;
- if (mInstances == 0)
- {
- // Load the skin
- Image *tab[TAB_COUNT];
-
- for (int mode = 0; mode < TAB_COUNT; mode++)
- {
- tab[mode] = Theme::getImageFromTheme(data[mode].file);
- int a = 0;
- for (int y = 0; y < 3; y++)
- {
- for (int x = 0; x < 3; x++)
- {
- tabImg[mode].grid[a] = tab[mode]->getSubImage(
- data[mode].gridX[x], data[mode].gridY[y],
- data[mode].gridX[x + 1] - data[mode].gridX[x] + 1,
- data[mode].gridY[y + 1] - data[mode].gridY[y] + 1);
- a++;
- }
- }
- tabImg[mode].setAlpha(mAlpha);
- tab[mode]->decRef();
- }
- }
- mInstances++;
+ // Replace the label with customized version
+ delete mLabel;
+ mLabel = new Label();
+ add(mLabel);
+
+ auto &skin = gui->getTheme()->getSkin(SkinType::Tab);
+ setFrameSize(skin.frameSize);
+ mPadding = skin.padding;
+ mLabel->setPosition(mPadding, mPadding);
}
-void Tab::updateAlpha()
+void Tab::setCaption(const std::string &caption)
{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
+ mLabel->setCaption(caption);
+ mLabel->adjustSize();
- // TODO We don't need to do this for every tab on every draw
- // Maybe use a config listener to do it as the value changes.
- if (alpha != mAlpha)
- {
- mAlpha = alpha;
+ setSize(mLabel->getWidth() + mPadding * 2,
+ mLabel->getHeight() + mPadding * 2);
- for (auto &t : tabImg)
- {
- t.setAlpha(mAlpha);
- }
- }
+ if (mTabbedArea)
+ static_cast<TabbedArea*>(mTabbedArea)->adjustTabPositions();
}
void Tab::draw(gcn::Graphics *graphics)
{
- int mode = TAB_STANDARD;
+ if (getFrameSize() == 0)
+ drawFrame(graphics);
- // check which type of tab to draw
- if (mTabbedArea)
+ // if tab is selected, it doesnt need to highlight activity
+ if (mTabbedArea && mTabbedArea->isTabSelected(this))
+ mFlash = false;
+
+ uint8_t flags = 0;
+ if (mHasMouse)
+ flags |= STATE_HOVERED;
+ if (mTabbedArea && mTabbedArea->isTabSelected(this))
+ flags |= STATE_SELECTED;
+
+ auto &skin = gui->getTheme()->getSkin(SkinType::Tab);
+ if (auto state = skin.getState(flags))
{
- mLabel->setForegroundColor(*mTabColor);
- if (mTabbedArea->isTabSelected(this))
- {
- mode = TAB_SELECTED;
- // if tab is selected, it doesnt need to highlight activity
- mFlash = false;
- }
- else if (mHasMouse)
- {
- mode = TAB_HIGHLIGHTED;
- }
+ gcn::Color foregroundColor = state->textFormat.color;
if (mFlash)
- {
- mLabel->setForegroundColor(Theme::getThemeColor(Theme::TAB_FLASH));
- }
+ foregroundColor = Theme::getThemeColor(Theme::TAB_FLASH);
+ else if (mTabColor)
+ foregroundColor = *mTabColor;
+
+ auto label = static_cast<Label*>(mLabel);
+ label->setForegroundColor(foregroundColor);
+ label->setOutlineColor(state->textFormat.outlineColor);
+ label->setShadowColor(state->textFormat.shadowColor);
}
- updateAlpha();
-
- // draw tab
- static_cast<Graphics*>(graphics)->
- drawImageRect(0, 0, getWidth(), getHeight(), tabImg[mode]);
-
// draw label
drawChildren(graphics);
}
+void Tab::drawFrame(gcn::Graphics *graphics)
+{
+ WidgetState state(this);
+ state.width += getFrameSize() * 2;
+ state.height += getFrameSize() * 2;
+ if (mHasMouse)
+ state.flags |= STATE_HOVERED;
+ if (mTabbedArea && mTabbedArea->isTabSelected(this))
+ state.flags |= STATE_SELECTED;
+
+ gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::Tab, state);
+}
+
void Tab::setTabColor(const gcn::Color *color)
{
mTabColor = color;
diff --git a/src/gui/widgets/tab.h b/src/gui/widgets/tab.h
index 86650257..534abaff 100644
--- a/src/gui/widgets/tab.h
+++ b/src/gui/widgets/tab.h
@@ -19,12 +19,10 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef TAB_H
-#define TAB_H
+#pragma once
#include <guichan/widgets/tab.hpp>
-class ImageRect;
class TabbedArea;
/**
@@ -35,19 +33,25 @@ class Tab : public gcn::Tab
{
public:
Tab();
- ~Tab() override;
/**
- * Update the alpha value to the graphic components.
+ * Sets the caption of the tab. Shadowing gcn::Tab::setCaption, which
+ * shouldn't be used because it calls gcn::Tab::adjustSize, which does
+ * not take into account the padding.
*/
- static void updateAlpha();
+ void setCaption(const std::string& caption);
/**
- * Draw the tabbed area.
+ * Draw the tab.
*/
void draw(gcn::Graphics *graphics) override;
/**
+ * Draw the tab frame.
+ */
+ void drawFrame(gcn::Graphics *graphics) override;
+
+ /**
* Set the normal color fo the tab's text.
*/
void setTabColor(const gcn::Color *color);
@@ -62,15 +66,7 @@ class Tab : public gcn::Tab
virtual void setCurrent() {}
private:
- /** Load images if no other instances exist yet */
- void init();
-
- static ImageRect tabImg[4]; /**< Tab state graphics */
- static int mInstances; /**< Number of tab instances */
- static float mAlpha;
-
- const gcn::Color *mTabColor;
- bool mFlash;
+ const gcn::Color *mTabColor = nullptr;
+ bool mFlash = false;
+ int mPadding = 8;
};
-
-#endif
diff --git a/src/gui/widgets/tabbedarea.cpp b/src/gui/widgets/tabbedarea.cpp
index af0c11cb..3609791a 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>
@@ -30,13 +32,13 @@ TabbedArea::TabbedArea()
mWidgetContainer->setOpaque(false);
addWidgetListener(this);
- mArrowButton[0] = new Button(std::string(), "shift_left", this);
- mArrowButton[1] = new Button(std::string(), "shift_right", this);
+ mArrowButton[0] = std::make_unique<Button>(std::string(), "shift_left", this);
+ mArrowButton[1] = std::make_unique<Button>(std::string(), "shift_right", this);
mArrowButton[0]->setButtonIcon("tab_arrows_left.png");
mArrowButton[1]->setButtonIcon("tab_arrows_right.png");
- add(mArrowButton[0]);
- add(mArrowButton[1]);
+ add(mArrowButton[0].get());
+ add(mArrowButton[1].get());
widgetResized(nullptr);
}
@@ -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
@@ -105,7 +112,7 @@ void TabbedArea::addTab(const std::string &caption, gcn::Widget *widget)
addTab(tab, widget);
}
-void TabbedArea::removeTab(Tab *tab)
+void TabbedArea::removeTab(gcn::Tab *tab)
{
if (tab == mSelectedTab)
{
@@ -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 8e6dcb5f..5d0ccfcc 100644
--- a/src/gui/widgets/tabbedarea.h
+++ b/src/gui/widgets/tabbedarea.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef TABBEDAREA_H
-#define TABBEDAREA_H
+#pragma once
#include <guichan/widget.hpp>
#include <guichan/widgetlistener.hpp>
@@ -29,6 +28,7 @@
#include "gui/widgets/button.h"
+#include <memory>
#include <string>
class Tab;
@@ -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();
@@ -86,12 +86,12 @@ class TabbedArea : public gcn::TabbedArea, public gcn::WidgetListener
void addTab(const std::string &caption, gcn::Widget *widget) override;
/**
- * Overload the remove tab function as it's broken in guichan 0.8.
+ * Override the remove tab function as it's broken in guichan 0.8.
*/
- void removeTab(Tab *tab);
+ void removeTab(gcn::Tab *tab) override;
/**
- * Overload the logic function since it's broken in guichan 0.8.
+ * Override the logic function since it's broken in guichan 0.8.
*/
void logic() override;
@@ -115,7 +115,7 @@ class TabbedArea : public gcn::TabbedArea, public gcn::WidgetListener
private:
/** The tab arrows */
- Button *mArrowButton[2];
+ std::unique_ptr<Button> mArrowButton[2];
/** Check whether the arrow should be clickable */
void updateArrowEnableState();
@@ -151,5 +151,3 @@ class TabbedArea : public gcn::TabbedArea, public gcn::WidgetListener
*/
unsigned mTabScrollIndex = 0;
};
-
-#endif
diff --git a/src/gui/widgets/table.cpp b/src/gui/widgets/table.cpp
index 905bb166..909617a0 100644
--- a/src/gui/widgets/table.cpp
+++ b/src/gui/widgets/table.cpp
@@ -21,8 +21,7 @@
#include "gui/widgets/table.h"
-#include "configuration.h"
-
+#include "gui/gui.h"
#include "gui/sdlinput.h"
#include "resources/theme.h"
@@ -33,13 +32,10 @@
#include <guichan/graphics.hpp>
#include <guichan/key.hpp>
-float GuiTable::mAlpha = 1.0;
-
class GuiTableActionListener : public gcn::ActionListener
{
public:
- GuiTableActionListener(GuiTable *_table, gcn::Widget *_widget, int _row, int _column);
-
+ GuiTableActionListener(GuiTable *table, gcn::Widget *widget, int row, int column);
~GuiTableActionListener() override;
void action(const gcn::ActionEvent& actionEvent) override;
@@ -81,18 +77,12 @@ void GuiTableActionListener::action(const gcn::ActionEvent& actionEvent)
}
-GuiTable::GuiTable(TableModel *initial_model, gcn::Color background,
+GuiTable::GuiTable(TableModel *initialModel, gcn::Color background,
bool opacity) :
- mLinewiseMode(false),
- mWrappingEnabled(false),
mOpaque(opacity),
- mBackgroundColor(background),
- mModel(nullptr),
- mSelectedRow(0),
- mSelectedColumn(0),
- mTopWidget(nullptr)
+ mBackgroundColor(background)
{
- setModel(initial_model);
+ setModel(initialModel);
setFocusable(true);
addMouseListener(this);
@@ -269,16 +259,19 @@ void GuiTable::draw(gcn::Graphics* graphics)
if (!mModel)
return;
- if (config.guiAlpha != mAlpha)
- mAlpha = config.guiAlpha;
+ const auto guiAlpha = gui->getTheme()->getGuiAlpha();
if (mOpaque)
{
- graphics->setColor(Theme::getThemeColor(Theme::BACKGROUND,
- (int)(mAlpha * 255.0f)));
+ auto backgroundColor = Theme::getThemeColor(Theme::BACKGROUND);
+ backgroundColor.a = guiAlpha;
+ graphics->setColor(backgroundColor);
graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
}
+ auto highlightColor = Theme::getThemeColor(Theme::HIGHLIGHT);
+ highlightColor.a = guiAlpha;
+
// First, determine how many rows we need to draw, and where we should start.
int first_row = -(getY() / getRowHeight());
@@ -320,8 +313,7 @@ void GuiTable::draw(gcn::Graphics* graphics)
widget->setDimension(bounds);
- graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT,
- (int)(mAlpha * 255.0f)));
+ graphics->setColor(highlightColor);
if (mLinewiseMode && r == mSelectedRow && c == 0)
{
@@ -368,7 +360,7 @@ void GuiTable::moveToBottom(gcn::Widget *widget)
mTopWidget = nullptr;
}
-gcn::Rectangle GuiTable::getChildrenArea() const
+gcn::Rectangle GuiTable::getChildrenArea()
{
return gcn::Rectangle(0, 0, getWidth(), getHeight());
}
@@ -487,7 +479,7 @@ void GuiTable::modelUpdated(bool completed)
}
}
-gcn::Widget *GuiTable::getWidgetAt(int x, int y) const
+gcn::Widget *GuiTable::getWidgetAt(int x, int y)
{
int row = getRowForY(y);
int column = getColumnForX(x);
@@ -497,14 +489,12 @@ gcn::Widget *GuiTable::getWidgetAt(int x, int y) const
if (row > -1 && column > -1)
{
- gcn::Widget *w = mModel->getElementAt(row, column);
- if (w && w->isFocusable())
- return w;
- else
- return nullptr; // Grab the event locally
+ if (gcn::Widget *w = mModel->getElementAt(row, column))
+ if (w->isFocusable())
+ return w;
}
- else
- return nullptr;
+
+ return nullptr; // Grab the event locally
}
int GuiTable::getRowForY(int y) const
@@ -516,8 +506,8 @@ int GuiTable::getRowForY(int y) const
if (row < 0 || row >= mModel->getRows())
return -1;
- else
- return row;
+
+ return row;
}
int GuiTable::getColumnForX(int x) const
@@ -534,24 +524,23 @@ int GuiTable::getColumnForX(int x) const
if (column < 0 || column >= mModel->getColumns())
return -1;
- else
- return column;
+
+ return column;
}
void GuiTable::_setFocusHandler(gcn::FocusHandler* focusHandler)
{
gcn::Widget::_setFocusHandler(focusHandler);
- if (mModel)
+ if (!mModel)
+ return;
+
+ for (int r = 0; r < mModel->getRows(); ++r)
{
- for (int r = 0; r < mModel->getRows(); ++r)
+ for (int c = 0; c < mModel->getColumns(); ++c)
{
- for (int c = 0; c < mModel->getColumns(); ++c)
- {
- gcn::Widget *w = mModel->getElementAt(r, c);
- if (w)
- w->_setFocusHandler(focusHandler);
- }
+ if (gcn::Widget *w = mModel->getElementAt(r, c))
+ w->_setFocusHandler(focusHandler);
}
}
}
diff --git a/src/gui/widgets/table.h b/src/gui/widgets/table.h
index a9202022..88350928 100644
--- a/src/gui/widgets/table.h
+++ b/src/gui/widgets/table.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef TABLE_H
-#define TABLE_H
+#pragma once
#include "tablemodel.h"
@@ -41,16 +40,16 @@ class GuiTableActionListener;
*
* \ingroup GUI
*/
-class GuiTable : public gcn::Widget,
- public gcn::MouseListener,
- public gcn::KeyListener,
- public TableModelListener
+class GuiTable final : public gcn::Widget,
+ public gcn::MouseListener,
+ public gcn::KeyListener,
+ public TableModelListener
{
// so that the action listener can call distributeActionEvent
friend class GuiTableActionListener;
public:
- GuiTable(TableModel * initial_model = nullptr, gcn::Color background = 0xffffff,
+ GuiTable(TableModel *initialModel = nullptr, gcn::Color background = 0xffffff,
bool opacity = true);
~GuiTable() override;
@@ -85,7 +84,7 @@ public:
void setWrappingEnabled(bool wrappingEnabled)
{mWrappingEnabled = wrappingEnabled;}
- gcn::Rectangle getChildrenArea() const;
+ gcn::Rectangle getChildrenArea() override;
/**
* Toggle whether to use linewise selection mode, in which the table selects
@@ -103,7 +102,10 @@ public:
// Inherited from Widget
void draw(gcn::Graphics* graphics) override;
- virtual gcn::Widget *getWidgetAt(int x, int y) const;
+ // Overridden to disable drawing of the frame
+ void drawFrame(gcn::Graphics* graphics) override {}
+
+ gcn::Widget *getWidgetAt(int x, int y) override;
void moveToTop(gcn::Widget *child) override;
@@ -120,7 +122,7 @@ public:
*
* @param opaque True if the table should be opaque, false otherwise.
*/
- virtual void setOpaque(bool opaque) {mOpaque = opaque;}
+ void setOpaque(bool opaque) {mOpaque = opaque;}
/**
* Checks if the table is opaque, that is if the table area displays its
@@ -128,7 +130,7 @@ public:
*
* @return True if the table is opaque, false otherwise.
*/
- virtual bool isOpaque() const {return mOpaque;}
+ bool isOpaque() const {return mOpaque;}
// Inherited from MouseListener
void mousePressed(gcn::MouseEvent& mouseEvent) override;
@@ -144,42 +146,35 @@ public:
protected:
/** Frees all action listeners on inner widgets. */
- virtual void uninstallActionListeners();
+ void uninstallActionListeners();
/** Installs all action listeners on inner widgets. */
- virtual void installActionListeners();
+ void installActionListeners();
- virtual int getRowHeight() const;
- virtual int getColumnWidth(int i) const;
+ int getRowHeight() const;
+ int getColumnWidth(int i) const;
private:
int getRowForY(int y) const; // -1 on error
int getColumnForX(int x) const; // -1 on error
void recomputeDimensions();
- bool mLinewiseMode;
- bool mWrappingEnabled;
- bool mOpaque;
- static float mAlpha;
+ bool mLinewiseMode = false;
+ bool mWrappingEnabled = false;
+ bool mOpaque;
/**
* Holds the background color of the table.
*/
gcn::Color mBackgroundColor;
- TableModel *mModel;
+ TableModel *mModel = nullptr;
- int mSelectedRow;
- int mSelectedColumn;
-
- /** Number of frames to skip upwards when drawing the selected widget. */
- int mPopFramesNr;
+ int mSelectedRow = 0;
+ int mSelectedColumn = 0;
/** If someone moves a fresh widget to the top, we must display it. */
- gcn::Widget *mTopWidget;
+ gcn::Widget *mTopWidget = nullptr;
/** Vector for compactness; used as a list in practice. */
std::vector<GuiTableActionListener *> mActionListeners;
};
-
-
-#endif // TABLE_H
diff --git a/src/gui/widgets/tablemodel.h b/src/gui/widgets/tablemodel.h
index d4274e39..2ba36556 100644
--- a/src/gui/widgets/tablemodel.h
+++ b/src/gui/widgets/tablemodel.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef TABLE_MODEL_H
-#define TABLE_MODEL_H
+#pragma once
#include <guichanfwd.h>
@@ -143,5 +142,3 @@ protected:
std::vector<gcn::Widget *> mTableModel;
std::vector<int> mWidths;
};
-
-#endif // TABLE_MODEL_H
diff --git a/src/gui/widgets/textbox.cpp b/src/gui/widgets/textbox.cpp
index 419fa16e..6cc514fe 100644
--- a/src/gui/widgets/textbox.cpp
+++ b/src/gui/widgets/textbox.cpp
@@ -21,15 +21,20 @@
#include "gui/widgets/textbox.h"
+#include "gui/gui.h"
#include "resources/theme.h"
+#include "textrenderer.h"
#include <guichan/font.hpp>
#include <sstream>
-TextBox::TextBox() :
- mTextColor(&Theme::getThemeColor(Theme::TEXT))
+TextBox::TextBox()
{
+ auto &palette = gui->getTheme()->getPalette(0);
+ mTextColor = &palette.getColor(Theme::TEXT);
+ mOutlineColor = palette.getOutlineColor(Theme::TEXT);
+
setOpaque(false);
setFrameSize(0);
mMinWidth = getWidth();
@@ -147,3 +152,42 @@ void TextBox::setTextWrapped(const std::string &text, int minDimension)
gcn::TextBox::setText(wrappedStream.str());
}
+
+/**
+ * Overridden so we can customize the color and outline of the text.
+ */
+void TextBox::draw(gcn::Graphics *graphics)
+{
+ unsigned int i;
+
+ if (mOpaque)
+ {
+ graphics->setColor(getBackgroundColor());
+ graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
+ }
+
+ if (isFocused() && isEditable())
+ {
+ drawCaret(graphics,
+ getFont()->getWidth(mTextRows[mCaretRow].substr(0, mCaretColumn)),
+ mCaretRow * getFont()->getHeight());
+ }
+
+ graphics->setColor(*mTextColor);
+ graphics->setFont(getFont());
+
+ for (i = 0; i < mTextRows.size(); i++)
+ {
+ // Move the text one pixel so we can have a caret before a letter.
+ TextRenderer::renderText(graphics,
+ mTextRows[i],
+ 1,
+ i * getFont()->getHeight(),
+ gcn::Graphics::LEFT,
+ *mTextColor,
+ getFont(),
+ mOutlineColor.has_value(),
+ false,
+ mOutlineColor);
+ }
+}
diff --git a/src/gui/widgets/textbox.h b/src/gui/widgets/textbox.h
index bcf09ee2..49a5a2ad 100644
--- a/src/gui/widgets/textbox.h
+++ b/src/gui/widgets/textbox.h
@@ -19,11 +19,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef TEXTBOX_H
-#define TEXTBOX_H
+#pragma once
#include <guichan/widgets/textbox.hpp>
+#include <optional>
+
/**
* A text box, meant to be used inside a scroll area. Same as the Guichan text
* box except this one doesn't have a background or border, instead completely
@@ -39,6 +40,9 @@ class TextBox : public gcn::TextBox
void setTextColor(const gcn::Color *color)
{ mTextColor = color; }
+ void setOutlineColor(const std::optional<gcn::Color> &color)
+ { mOutlineColor = color; }
+
/**
* Sets the text after wrapping it to the current width of the widget.
*/
@@ -52,15 +56,10 @@ class TextBox : public gcn::TextBox
/**
* Draws the text.
*/
- void draw(gcn::Graphics *graphics) override
- {
- setForegroundColor(*mTextColor);
- gcn::TextBox::draw(graphics);
- }
+ void draw(gcn::Graphics *graphics) override;
private:
int mMinWidth;
const gcn::Color *mTextColor;
+ std::optional<gcn::Color> mOutlineColor;
};
-
-#endif
diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp
index dd0adecd..6c866477 100644
--- a/src/gui/widgets/textfield.cpp
+++ b/src/gui/widgets/textfield.cpp
@@ -21,107 +21,63 @@
#include "gui/widgets/textfield.h"
-#include "configuration.h"
#include "graphics.h"
+#include "gui/gui.h"
#include "gui/sdlinput.h"
-#include "resources/image.h"
#include "resources/theme.h"
#include "utils/copynpaste.h"
-#include "utils/dtor.h"
#include "utils/stringutils.h"
#include <guichan/font.hpp>
#include <SDL.h>
-#undef DELETE //Win32 compatibility hack
-
-int TextField::instances = 0;
-float TextField::mAlpha = 1.0;
-ImageRect TextField::skin;
-
-TextField::TextField(const std::string &text, bool loseFocusOnTab):
- gcn::TextField(text)
-{
- setFrameSize(2);
-
- mLoseFocusOnTab = loseFocusOnTab;
-
- if (instances == 0)
- {
- // Load the skin
- Image *textbox = Theme::getImageFromTheme("deepbox.png");
- int gridx[4] = {0, 3, 28, 31};
- int gridy[4] = {0, 3, 28, 31};
- int a = 0;
-
- for (int y = 0; y < 3; y++)
- {
- for (int x = 0; x < 3; x++)
- {
- skin.grid[a] = textbox->getSubImage(
- gridx[x], gridy[y],
- gridx[x + 1] - gridx[x] + 1,
- gridy[y + 1] - gridy[y] + 1);
- a++;
- }
- }
- skin.setAlpha(config.guiAlpha);
-
- textbox->decRef();
- }
-
- instances++;
-}
-
-TextField::~TextField()
+TextField::TextField(const std::string &text, bool loseFocusOnTab)
+ : gcn::TextField(text)
+ , mLoseFocusOnTab(loseFocusOnTab)
{
- instances--;
-
- if (instances == 0)
- std::for_each(skin.grid, skin.grid + 9, dtor<Image*>());
-}
+ auto &skin = gui->getTheme()->getSkin(SkinType::TextField);
+ setFrameSize(skin.frameSize);
+ mPadding = skin.padding;
-void TextField::updateAlpha()
-{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
-
- if (alpha != mAlpha)
- {
- mAlpha = alpha;
- skin.setAlpha(mAlpha);
- }
+ setWidth(getFont()->getWidth(mText) + 2 * mPadding);
+ setHeight(getFont()->getHeight() + 2 * mPadding);
+ fixScroll();
}
void TextField::draw(gcn::Graphics *graphics)
{
- updateAlpha();
+ if (getFrameSize() == 0)
+ drawFrame(graphics);
+
+ auto g = static_cast<Graphics *>(graphics);
+ g->pushClipRect(gcn::Rectangle(0, 0, getWidth(), getHeight()));
if (isFocused())
{
drawCaret(graphics,
- getFont()->getWidth(mText.substr(0, mCaretPosition)) -
- mXScroll);
+ getFont()->getWidth(mText.substr(0, mCaretPosition)) - mXScroll);
}
graphics->setColor(Theme::getThemeColor(Theme::TEXT));
graphics->setFont(getFont());
- graphics->drawText(mText, 1 - mXScroll, 1);
+ graphics->drawText(mText, mPadding - mXScroll, mPadding);
+
+ g->popClipRect();
}
void TextField::drawFrame(gcn::Graphics *graphics)
{
- //updateAlpha(); -> Not useful...
+ const int bs = getFrameSize();
- int bs = getFrameSize();
- int w = getWidth() + bs * 2;
- int h = getHeight() + bs * 2;
+ WidgetState state(this);
+ state.width += bs * 2;
+ state.height += bs * 2;
- static_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, skin);
+ gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::TextField, state);
}
void TextField::setNumeric(bool numeric)
@@ -156,6 +112,12 @@ int TextField::getValue() const
return value;
}
+void TextField::drawCaret(gcn::Graphics *graphics, int x)
+{
+ graphics->setColor(Theme::getThemeColor(Theme::CARET));
+ graphics->drawLine(mPadding + x, mPadding, mPadding + x, getHeight() - mPadding);
+}
+
void TextField::keyPressed(gcn::KeyEvent &keyEvent)
{
switch (keyEvent.getKey().getValue())
diff --git a/src/gui/widgets/textfield.h b/src/gui/widgets/textfield.h
index 9235f4b8..b84dd723 100644
--- a/src/gui/widgets/textfield.h
+++ b/src/gui/widgets/textfield.h
@@ -19,16 +19,13 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef TEXTFIELD_H
-#define TEXTFIELD_H
+#pragma once
#include <guichan/widgets/textfield.hpp>
#include <vector>
class TextInput;
-class ImageRect;
-class TextField;
struct TextHistory
{
@@ -79,7 +76,6 @@ class TextField : public gcn::TextField
*/
TextField(const std::string &text = std::string(),
bool loseFocusOnTab = true);
- ~TextField() override;
/**
* Draws the text field.
@@ -87,11 +83,6 @@ class TextField : public gcn::TextField
void draw(gcn::Graphics *graphics) override;
/**
- * Update the alpha value to the graphic components.
- */
- static void updateAlpha();
-
- /**
* Draws the background and border.
*/
void drawFrame(gcn::Graphics *graphics) override;
@@ -139,42 +130,41 @@ class TextField : public gcn::TextField
* Sets the TextField's source of autocomplete. Passing null will
* disable autocomplete.
*/
- void setAutoComplete(AutoCompleteLister *lister)
- { mAutoComplete = lister; }
+ void setAutoComplete(AutoCompleteLister *lister)
+ { mAutoComplete = lister; }
- /**
+ /**
* Returns the TextField's source of autocomplete.
*/
- AutoCompleteLister *getAutoComplete() const
- { return mAutoComplete; }
+ AutoCompleteLister *getAutoComplete() const
+ { return mAutoComplete; }
- /**
+ /**
* Sets the TextField's source of input history.
*/
- void setHistory(TextHistory *history)
- { mHistory = history; }
+ void setHistory(TextHistory *history)
+ { mHistory = history; }
- /**
+ /**
* Returns the TextField's source of input history.
*/
- TextHistory *getHistory() const
- { return mHistory; }
+ TextHistory *getHistory() const
+ { return mHistory; }
+
+ protected:
+ void drawCaret(gcn::Graphics *graphics, int x) override;
private:
void autoComplete();
void handlePaste();
- static int instances;
- static float mAlpha;
- static ImageRect skin;
bool mNumeric = false;
- int mMinimum;
- int mMaximum;
+ int mMinimum = 0;
+ int mMaximum = 0;
bool mLoseFocusOnTab;
+ int mPadding = 1;
AutoCompleteLister *mAutoComplete = nullptr;
TextHistory *mHistory = nullptr; /**< Text history. */
};
-
-#endif
diff --git a/src/gui/widgets/textpreview.cpp b/src/gui/widgets/textpreview.cpp
index f9e85052..2f80bd23 100644
--- a/src/gui/widgets/textpreview.cpp
+++ b/src/gui/widgets/textpreview.cpp
@@ -29,49 +29,19 @@
#include <typeinfo>
-float TextPreview::mAlpha = 1.0;
-
-TextPreview::TextPreview(const std::string &text):
- mText(text)
+TextPreview::TextPreview(const std::string &text)
+ : mText(text)
{
mFont = gui->getFont();
mTextColor = &Theme::getThemeColor(Theme::TEXT);
- mBGColor = &Theme::getThemeColor(Theme::BACKGROUND);
}
void TextPreview::draw(gcn::Graphics* graphics)
{
- if (config.guiAlpha != mAlpha)
- mAlpha = config.guiAlpha;
-
- int alpha = (int) (mAlpha * 255.0f);
-
- if (!mTextAlpha)
- alpha = 255;
-
- if (mOpaque)
- {
- graphics->setColor(gcn::Color((int) mBGColor->r,
- (int) mBGColor->g,
- (int) mBGColor->b,
- (int)(mAlpha * 255.0f)));
- graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight()));
- }
-
- if (mTextBGColor && typeid(*mFont) == typeid(TrueTypeFont))
- {
- auto *font = static_cast<TrueTypeFont*>(mFont);
- int x = font->getWidth(mText) + 1 + 2 * ((mOutline || mShadow) ? 1 :0);
- int y = font->getHeight() + 1 + 2 * ((mOutline || mShadow) ? 1 : 0);
- graphics->setColor(gcn::Color((int) mTextBGColor->r,
- (int) mTextBGColor->g,
- (int) mTextBGColor->b,
- (int)(mAlpha * 255.0f)));
- graphics->fillRectangle(gcn::Rectangle(1, 1, x, y));
- }
-
TextRenderer::renderText(graphics, mText, 2, 2, gcn::Graphics::LEFT,
- gcn::Color(mTextColor->r, mTextColor->g,
- mTextColor->b, alpha),
+ gcn::Color(mTextColor->r,
+ mTextColor->g,
+ mTextColor->b,
+ 255),
mFont, mOutline, mShadow);
}
diff --git a/src/gui/widgets/textpreview.h b/src/gui/widgets/textpreview.h
index 7e88248f..8246a200 100644
--- a/src/gui/widgets/textpreview.h
+++ b/src/gui/widgets/textpreview.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef TEXTPREVIEW_H
-#define TEXTPREVIEW_H
+#pragma once
#include <guichan/color.hpp>
#include <guichan/font.hpp>
@@ -45,37 +44,6 @@ class TextPreview : public gcn::Widget
}
/**
- * Sets the text to use the set alpha value.
- *
- * @param alpha whether to use alpha values for the text or not
- */
- void useTextAlpha(bool alpha)
- {
- mTextAlpha = alpha;
- }
-
- /**
- * Sets the color the text background is drawn in. This is only the
- * rectangle directly behind the text, not to full widget.
- *
- * @param color the color to set
- */
- void setTextBGColor(const gcn::Color *color)
- {
- mTextBGColor = color;
- }
-
- /**
- * Sets the background color of the widget.
- *
- * @param color the color to set
- */
- void setBGColor(const gcn::Color *color)
- {
- mBGColor = color;
- }
-
- /**
* Sets the font to render the text in.
*
* @param font the font to use.
@@ -112,31 +80,10 @@ class TextPreview : public gcn::Widget
*/
void draw(gcn::Graphics *graphics) override;
- /**
- * Set opacity for this widget (whether or not to show the background
- * color)
- *
- * @param opaque Whether the widget should be opaque or not
- */
- void setOpaque(bool opaque) { mOpaque = opaque; }
-
- /**
- * Gets opacity for this widget (whether or not the background color
- * is shown below the widget)
- */
- bool isOpaque() const { return mOpaque; }
-
private:
gcn::Font *mFont;
std::string mText;
const gcn::Color *mTextColor;
- const gcn::Color *mBGColor;
- const gcn::Color *mTextBGColor = nullptr;
- static float mAlpha;
- bool mTextAlpha = false;
- bool mOpaque = false;
bool mShadow = false;
bool mOutline = false;
};
-
-#endif
diff --git a/src/gui/widgets/vertcontainer.h b/src/gui/widgets/vertcontainer.h
index b66957d3..a684453f 100644
--- a/src/gui/widgets/vertcontainer.h
+++ b/src/gui/widgets/vertcontainer.h
@@ -18,8 +18,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef GUI_VERTCONTAINER_H
-#define GUI_VERTCONTAINER_H
+#pragma once
#include "gui/widgets/container.h"
@@ -42,5 +41,3 @@ class VertContainer : public Container, public gcn::WidgetListener
int mSpacing;
int mCount = 0;
};
-
-#endif
diff --git a/src/gui/widgets/whispertab.cpp b/src/gui/widgets/whispertab.cpp
index 636f48dd..28181971 100644
--- a/src/gui/widgets/whispertab.cpp
+++ b/src/gui/widgets/whispertab.cpp
@@ -36,7 +36,7 @@ WhisperTab::WhisperTab(const std::string &nick) :
ChatTab(nick),
mNick(nick)
{
- setTabColor(&Theme::getThemeColor(Theme::WHISPER));
+ setTabColor(&Theme::getThemeColor(Theme::WHISPER_TAB));
}
WhisperTab::~WhisperTab()
diff --git a/src/gui/widgets/whispertab.h b/src/gui/widgets/whispertab.h
index 0f01bacc..1a0a4a0f 100644
--- a/src/gui/widgets/whispertab.h
+++ b/src/gui/widgets/whispertab.h
@@ -19,8 +19,7 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef WHISPERTAB_H
-#define WHISPERTAB_H
+#pragma once
#include "chattab.h"
@@ -63,5 +62,3 @@ class WhisperTab : public ChatTab
private:
std::string mNick;
};
-
-#endif // CHANNELTAB_H
diff --git a/src/gui/widgets/window.cpp b/src/gui/widgets/window.cpp
index 8bf9d081..e57918b7 100644
--- a/src/gui/widgets/window.cpp
+++ b/src/gui/widgets/window.cpp
@@ -23,6 +23,7 @@
#include "configuration.h"
#include "log.h"
+#include "textrenderer.h"
#include "gui/gui.h"
#include "gui/viewport.h"
@@ -31,9 +32,6 @@
#include "gui/widgets/resizegrip.h"
#include "gui/widgets/windowcontainer.h"
-#include "resources/image.h"
-#include "resources/theme.h"
-
#include <guichan/exception.hpp>
#include <guichan/focushandler.hpp>
@@ -43,13 +41,17 @@
int Window::instances = 0;
int Window::mouseResize = 0;
-Window::Window(const std::string &caption, bool modal, Window *parent,
- const std::string &skin):
- gcn::Window(caption),
- mParent(parent),
- mModal(modal),
- mMaxWinWidth(graphics->getWidth()),
- mMaxWinHeight(graphics->getHeight())
+Window::Window(const std::string &caption, bool modal, Window *parent)
+ : Window(SkinType::Window, caption, modal, parent)
+{}
+
+Window::Window(SkinType skinType, const std::string &caption, bool modal, Window *parent)
+ : gcn::Window(caption)
+ , mParent(parent)
+ , mModal(modal)
+ , mSkinType(skinType)
+ , mMaxWinWidth(graphics->getWidth())
+ , mMaxWinHeight(graphics->getHeight())
{
logger->log("Window::Window(\"%s\")", caption.c_str());
@@ -58,19 +60,17 @@ Window::Window(const std::string &caption, bool modal, Window *parent,
instances++;
- setFrameSize(0);
- setPadding(3);
- setTitleBarHeight(20);
-
- // Loads the skin
- mSkin = Theme::instance()->load(skin);
+ auto &skin = getSkin();
+ setFrameSize(skin.frameSize);
+ setPadding(skin.padding);
+ setTitleBarHeight(skin.titleBarHeight);
// Add this window to the window container
windowContainer->add(this);
if (mModal)
{
- gui->setCursorType(Cursor::POINTER);
+ gui->setCursorType(Cursor::Pointer);
requestModalFocus();
}
@@ -94,8 +94,6 @@ Window::~Window()
removeWidgetListener(this);
instances--;
-
- mSkin->instances--;
}
void Window::setWindowContainer(WindowContainer *wc)
@@ -105,44 +103,57 @@ void Window::setWindowContainer(WindowContainer *wc)
void Window::draw(gcn::Graphics *graphics)
{
- auto *g = static_cast<Graphics*>(graphics);
+ if (getFrameSize() == 0)
+ drawFrame(graphics);
- g->drawImageRect(0, 0, getWidth(), getHeight(), mSkin->getBorder());
-
- // Draw title
- if (mShowTitle)
- {
- g->setColor(Theme::getThemeColor(Theme::TEXT));
- g->setFont(getFont());
- g->drawText(getCaption(), 7, 5, gcn::Graphics::LEFT);
- }
+ auto g = static_cast<Graphics*>(graphics);
- // Draw Close Button
if (mCloseButton)
{
- g->drawImage(mSkin->getCloseImage(),
- getWidth() - mSkin->getCloseImage()->getWidth() - getPadding(),
- getPadding());
+ WidgetState state(getCloseButtonRect(), mCloseButtonHovered ? STATE_HOVERED : 0);
+ gui->getTheme()->drawSkin(g, SkinType::ButtonClose, state);
}
- // Draw Sticky Button
if (mStickyButton)
{
- Image *button = mSkin->getStickyImage(mSticky);
- int x = getWidth() - button->getWidth() - getPadding();
- if (mCloseButton)
- x -= mSkin->getCloseImage()->getWidth();
-
- g->drawImage(button, x, getPadding());
+ WidgetState state(getStickyButtonRect(), mSticky ? STATE_SELECTED : 0);
+ gui->getTheme()->drawSkin(g, SkinType::ButtonSticky, state);
}
drawChildren(graphics);
}
+void Window::drawFrame(gcn::Graphics *graphics)
+{
+ auto g = static_cast<Graphics*>(graphics);
+
+ WidgetState widgetState(this);
+ widgetState.width += getFrameSize() * 2;
+ widgetState.height += getFrameSize() * 2;
+
+ auto &skin = getSkin();
+ skin.draw(g, widgetState);
+
+ if (mShowTitle)
+ {
+ if (auto skinState = skin.getState(widgetState.flags))
+ {
+ auto &textFormat = skinState->textFormat;
+ TextRenderer::renderText(g,
+ getCaption(),
+ getFrameSize() + skin.titleOffsetX,
+ getFrameSize() + skin.titleOffsetY,
+ gcn::Graphics::LEFT,
+ textFormat.bold ? boldFont : getFont(),
+ textFormat);
+ }
+ }
+}
+
void Window::setContentSize(int width, int height)
{
- width = width + 2 * getPadding();
- height = height + getPadding() + getTitleBarHeight();
+ width += 2 * getPadding();
+ height += getPadding() + getTitleBarHeight();
if (getMinWidth() > width)
width = getMinWidth();
@@ -156,6 +167,16 @@ void Window::setContentSize(int width, int height)
setSize(width, height);
}
+void Window::setMinimumContentSize(int width, int height)
+{
+ const int padding = getPadding();
+ const int titleBarHeight = getTitleBarHeight();
+ auto &skin = getSkin();
+
+ setMinWidth(std::max(skin.getMinWidth(), width + 2 * padding));
+ setMinHeight(std::max(skin.getMinHeight(), height + padding + titleBarHeight));
+}
+
void Window::setLocationRelativeTo(gcn::Widget *widget)
{
int wx;
@@ -218,13 +239,12 @@ void Window::setLocationRelativeTo(ImageRect::ImagePosition position,
void Window::setMinWidth(int width)
{
- mMinWinWidth = width > mSkin->getMinWidth() ? width : mSkin->getMinWidth();
+ mMinWinWidth = std::max(getSkin().getMinWidth(), width);
}
void Window::setMinHeight(int height)
{
- mMinWinHeight = height > mSkin->getMinHeight() ?
- height : mSkin->getMinHeight();
+ mMinWinHeight = std::max(getSkin().getMinHeight(), height);
}
void Window::setMaxWidth(int width)
@@ -276,9 +296,7 @@ void Window::widgetResized(const gcn::Event &event)
void Window::widgetHidden(const gcn::Event &event)
{
if (gui)
- {
- gui->setCursorType(Cursor::POINTER);
- }
+ gui->setCursorType(Cursor::Pointer);
WidgetListIterator it;
@@ -341,38 +359,13 @@ void Window::mousePressed(gcn::MouseEvent &event)
const int x = event.getX();
const int y = event.getY();
- // Handle close button
- if (mCloseButton)
- {
- gcn::Rectangle closeButtonRect(
- getWidth() - mSkin->getCloseImage()->getWidth() - getPadding(),
- getPadding(),
- mSkin->getCloseImage()->getWidth(),
- mSkin->getCloseImage()->getHeight());
-
- if (closeButtonRect.isPointInRect(x, y))
- {
- close();
- }
- }
+ if (mCloseButton && getCloseButtonRect().isPointInRect(x, y))
+ close();
- // Handle sticky button
- if (mStickyButton)
- {
- Image *button = mSkin->getStickyImage(mSticky);
- int rx = getWidth() - button->getWidth() - getPadding();
- if (mCloseButton)
- rx -= mSkin->getCloseImage()->getWidth();
- gcn::Rectangle stickyButtonRect(rx, getPadding(),
- button->getWidth(), button->getHeight());
-
- if (stickyButtonRect.isPointInRect(x, y))
- {
- setSticky(!isSticky());
- }
- }
+ if (mStickyButton && getStickyButtonRect().isPointInRect(x, y))
+ setSticky(!isSticky());
- // Handle window resizing
+ // Update resizing state and disable moving if we're resizing the window
mouseResize = getResizeHandles(event);
if (mouseResize)
mMoved = false;
@@ -384,6 +377,11 @@ void Window::close()
setVisible(false);
}
+const Skin &Window::getSkin() const
+{
+ return gui->getTheme()->getSkin(mSkinType);
+}
+
void Window::mouseReleased(gcn::MouseEvent &event)
{
mouseResize = 0;
@@ -394,11 +392,15 @@ void Window::mouseReleased(gcn::MouseEvent &event)
void Window::mouseExited(gcn::MouseEvent &event)
{
if (mGrip && !mouseResize)
- gui->setCursorType(Cursor::POINTER);
+ gui->setCursorType(Cursor::Pointer);
+
+ mCloseButtonHovered = false;
}
void Window::mouseMoved(gcn::MouseEvent &event)
{
+ mCloseButtonHovered = false;
+
// Make sure BeingPopup is hidden (Viewport does not receive mouseExited)
if (viewport)
viewport->hideBeingPopup();
@@ -408,30 +410,36 @@ void Window::mouseMoved(gcn::MouseEvent &event)
if (event.isConsumed())
return;
- int resizeHandles = getResizeHandles(event);
+ mCloseButtonHovered = getCloseButtonRect().isPointInRect(event.getX(), event.getY());
+ Cursor cursor = Cursor::Pointer;
// Changes the custom mouse cursor based on its current position.
- switch (resizeHandles)
+ if (!mCloseButtonHovered)
{
+ switch (getResizeHandles(event))
+ {
case BOTTOM | RIGHT:
case TOP | LEFT:
- gui->setCursorType(Cursor::RESIZE_DOWN_RIGHT);
+ cursor = Cursor::ResizeDownRight;
break;
case BOTTOM | LEFT:
case TOP | RIGHT:
- gui->setCursorType(Cursor::RESIZE_DOWN_LEFT);
+ cursor = Cursor::ResizeDownLeft;
break;
case BOTTOM:
case TOP:
- gui->setCursorType(Cursor::RESIZE_DOWN);
+ cursor = Cursor::ResizeDown;
break;
case RIGHT:
case LEFT:
- gui->setCursorType(Cursor::RESIZE_ACROSS);
+ cursor = Cursor::ResizeAcross;
break;
default:
- gui->setCursorType(Cursor::POINTER);
+ break;
+ }
}
+
+ gui->setCursorType(cursor);
}
void Window::mouseDragged(gcn::MouseEvent &event)
@@ -675,6 +683,13 @@ int Window::getResizeHandles(gcn::MouseEvent &event)
if (inPadding && event.getSource() == this)
{
+ /**
+ * The width of the resize border. Is independent of the actual window
+ * border width, and determines mostly the size of the corner area
+ * where two borders are moved at the same time.
+ */
+ const int resizeBorderWidth = std::max(mGrip->getWidth(), 10);
+
resizeHandles |= (x >= getWidth() - resizeBorderWidth) ? RIGHT :
(x < resizeBorderWidth) ? LEFT : 0;
resizeHandles |= (y >= getHeight() - resizeBorderWidth) ? BOTTOM :
@@ -692,10 +707,55 @@ int Window::getResizeHandles(gcn::MouseEvent &event)
return resizeHandles;
}
+gcn::Rectangle Window::getCloseButtonRect() const
+{
+ if (!mCloseButton)
+ return {};
+
+ auto theme = gui->getTheme();
+
+ auto &closeSkin = theme->getSkin(SkinType::ButtonClose);
+ const int closeWidth = closeSkin.getMinWidth();
+ const int closeHeight = closeSkin.getMinHeight();
+
+ return {
+ getWidth() - closeWidth - closeSkin.padding,
+ closeSkin.padding,
+ closeWidth,
+ closeHeight
+ };
+}
+
+gcn::Rectangle Window::getStickyButtonRect() const
+{
+ if (!mStickyButton)
+ return {};
+
+ auto theme = gui->getTheme();
+
+ auto &closeSkin = theme->getSkin(SkinType::ButtonClose);
+ const int closeWidth = closeSkin.getMinWidth();
+
+ auto &stickySkin = theme->getSkin(SkinType::ButtonSticky);
+ const int stickyWidth = stickySkin.getMinWidth();
+ const int stickyHeight = stickySkin.getMinHeight();
+
+ int stickyX = getWidth() - stickyWidth - stickySkin.padding - stickySkin.spacing;
+ if (mCloseButton)
+ stickyX -= closeWidth + closeSkin.padding;
+
+ return {
+ stickyX,
+ stickySkin.padding,
+ stickyWidth,
+ stickyHeight
+ };
+}
+
int Window::getGuiAlpha()
{
float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
+ gui->getTheme()->getMinimumOpacity());
return (int) (alpha * 255.0f);
}
diff --git a/src/gui/widgets/window.h b/src/gui/widgets/window.h
index bf6f363c..6331a715 100644
--- a/src/gui/widgets/window.h
+++ b/src/gui/widgets/window.h
@@ -19,14 +19,14 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef WINDOW_H
-#define WINDOW_H
+#pragma once
#include "graphics.h"
#include "guichanfwd.h"
-#include <guichan/widgetlistener.hpp>
+#include "resources/theme.h"
+#include <guichan/widgetlistener.hpp>
#include <guichan/widgets/window.hpp>
class ContainerPlacer;
@@ -54,10 +54,18 @@ class Window : public gcn::Window, gcn::WidgetListener
* @param parent The parent window. This is the window standing above
* this one in the window hiearchy. When reordering,
* a window will never go below its parent window.
- * @param skin The location where the window's skin XML can be found.
*/
- Window(const std::string &caption = "Window", bool modal = false,
- Window *parent = nullptr, const std::string &skin = "window.xml");
+ Window(const std::string &caption = "Window",
+ bool modal = false,
+ Window *parent = nullptr);
+
+ /**
+ * Constructor that allows customizing the SkinType used by the window.
+ */
+ Window(SkinType skinType,
+ const std::string &caption = "Window",
+ bool modal = false,
+ Window *parent = nullptr);
/**
* Destructor. Deletes all the added widgets.
@@ -70,16 +78,26 @@ class Window : public gcn::Window, gcn::WidgetListener
static void setWindowContainer(WindowContainer *windowContainer);
/**
- * Draws the window.
+ * Draws the window contents.
*/
void draw(gcn::Graphics *graphics) override;
/**
+ * Draws the window frame.
+ */
+ void drawFrame(gcn::Graphics *graphics) override;
+
+ /**
* Sets the size of this window.
*/
void setContentSize(int width, int height);
/**
+ * Sets the minimum size of the window content.
+ */
+ void setMinimumContentSize(int width, int height);
+
+ /**
* Sets the location relative to the given widget.
*/
void setLocationRelativeTo(gcn::Widget *widget);
@@ -345,6 +363,11 @@ class Window : public gcn::Window, gcn::WidgetListener
virtual void close();
/**
+ * Returns the Skin used by this window.
+ */
+ const Skin &getSkin() const;
+
+ /**
* Gets the alpha value used by the window, in a Guichan usable format.
*/
static int getGuiAlpha();
@@ -377,6 +400,9 @@ class Window : public gcn::Window, gcn::WidgetListener
*/
int getResizeHandles(gcn::MouseEvent &event);
+ gcn::Rectangle getCloseButtonRect() const;
+ gcn::Rectangle getStickyButtonRect() const;
+
ResizeGrip *mGrip = nullptr; /**< Resize grip */
Window *mParent; /**< The parent window */
Layout *mLayout = nullptr; /**< Layout handler */
@@ -384,10 +410,12 @@ class Window : public gcn::Window, gcn::WidgetListener
bool mShowTitle = true; /**< Window has a title bar */
bool mModal; /**< Window is modal */
bool mCloseButton = false; /**< Window has a close button */
+ bool mCloseButtonHovered = false;
bool mDefaultVisible = false; /**< Window's default visibility */
bool mSaveVisible = false; /**< Window will save visibility */
bool mStickyButton = false; /**< Window has a sticky button */
bool mSticky = false; /**< Window resists hiding*/
+ SkinType mSkinType; /**< The skin type used when drawing the window. */
int mMinWinWidth = 100; /**< Minimum window width */
int mMinWinHeight = 40; /**< Minimum window height */
int mMaxWinWidth; /**< Maximum window width */
@@ -398,15 +426,4 @@ class Window : public gcn::Window, gcn::WidgetListener
int mDefaultHeight; /**< Default window height */
static int instances; /**< Number of Window instances */
-
- Skin *mSkin; /**< Skin in use by this window */
-
- /**
- * The width of the resize border. Is independent of the actual window
- * border width, and determines mostly the size of the corner area
- * where two borders are moved at the same time.
- */
- static const int resizeBorderWidth = 10;
};
-
-#endif
diff --git a/src/gui/widgets/windowcontainer.cpp b/src/gui/widgets/windowcontainer.cpp
index 36f0998f..4e350a9e 100644
--- a/src/gui/widgets/windowcontainer.cpp
+++ b/src/gui/widgets/windowcontainer.cpp
@@ -24,16 +24,15 @@
#include "gui/gui.h"
#include "gui/widgets/window.h"
-#include "utils/dtor.h"
-
#include <guichan/focushandler.hpp>
WindowContainer *windowContainer = nullptr;
void WindowContainer::logic()
{
- delete_all(mDeathList);
- mDeathList.clear();
+ for (auto widget : mScheduledDeletions)
+ delete widget;
+ mScheduledDeletions.clear();
gcn::Container::logic();
}
@@ -48,7 +47,7 @@ void WindowContainer::draw(gcn::Graphics *graphics)
void WindowContainer::scheduleDelete(gcn::Widget *widget)
{
- mDeathList.push_back(widget);
+ mScheduledDeletions.insert(widget);
}
void WindowContainer::adjustAfterResize(int oldScreenWidth,
diff --git a/src/gui/widgets/windowcontainer.h b/src/gui/widgets/windowcontainer.h
index 861839c9..ff03a903 100644
--- a/src/gui/widgets/windowcontainer.h
+++ b/src/gui/widgets/windowcontainer.h
@@ -19,11 +19,12 @@
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
-#ifndef WINDOWCONTAINER_H
-#define WINDOWCONTAINER_H
+#pragma once
#include "gui/widgets/container.h"
+#include <set>
+
/**
* A window container. This container adds functionality for more convenient
* widget (windows in particular) destruction.
@@ -65,11 +66,9 @@ class WindowContainer : public Container
bool widgetIsVisible(gcn::Widget *widget);
/**
- * List of widgets that are scheduled to be deleted.
+ * Set of widgets that are scheduled to be deleted.
*/
- std::list<gcn::Widget *> mDeathList;
+ std::set<gcn::Widget *> mScheduledDeletions;
};
extern WindowContainer *windowContainer;
-
-#endif