summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThorbjørn Lindeijer <bjorn@lindeijer.nl>2024-10-23 13:56:55 +0200
committerThorbjørn Lindeijer <bjorn@lindeijer.nl>2025-03-14 13:53:08 +0100
commit2a8355942f7e4127ac911588c9893b4d6c5a82f8 (patch)
tree3255906c9f91e267f8758e6742bc65b843210889 /src
parent79e4325192f3260ed4ded264e43da8429650bf72 (diff)
downloadmana-2a8355942f7e4127ac911588c9893b4d6c5a82f8.tar.gz
mana-2a8355942f7e4127ac911588c9893b4d6c5a82f8.tar.bz2
mana-2a8355942f7e4127ac911588c9893b4d6c5a82f8.tar.xz
mana-2a8355942f7e4127ac911588c9893b4d6c5a82f8.zip
Moved widget drawing code into Theme
This is cleaner overall since now each widget type no longer needs to keep track of its own instances and updating of the GUI alpha. It also introduces a single point from where the GUI theme support can be enhanced. Theme is no longer a singleton, though for now there is a single instance owned by the Gui singleton. Widgets adjusted to delegate their painting to the Theme: * Button * Tab * TextField * CheckBox * RadioButton * Slider * DropDown * ProgressBar * ScrollArea * ResizeGrip * PlayerBox (by subclassing ScrollArea) The Window and Popup widgets already use the theme through the Skin class. They can actually use a different skin per instance, though this feature is only used by the SpeechBubble.
Diffstat (limited to 'src')
-rw-r--r--src/client.cpp12
-rw-r--r--src/graphics.cpp2
-rw-r--r--src/gui/abilitieswindow.cpp2
-rw-r--r--src/gui/abilitieswindow.h1
-rw-r--r--src/gui/gui.cpp9
-rw-r--r--src/gui/gui.h11
-rw-r--r--src/gui/serverdialog.cpp10
-rw-r--r--src/gui/skilldialog.cpp22
-rw-r--r--src/gui/widgets/avatarlistbox.cpp10
-rw-r--r--src/gui/widgets/button.cpp92
-rw-r--r--src/gui/widgets/button.h9
-rw-r--r--src/gui/widgets/checkbox.cpp98
-rw-r--r--src/gui/widgets/checkbox.h25
-rw-r--r--src/gui/widgets/dropdown.cpp116
-rw-r--r--src/gui/widgets/dropdown.h15
-rw-r--r--src/gui/widgets/emoteshortcutcontainer.cpp1
-rw-r--r--src/gui/widgets/listbox.cpp19
-rw-r--r--src/gui/widgets/listbox.h8
-rw-r--r--src/gui/widgets/playerbox.cpp69
-rw-r--r--src/gui/widgets/playerbox.h18
-rw-r--r--src/gui/widgets/popup.cpp4
-rw-r--r--src/gui/widgets/progressbar.cpp98
-rw-r--r--src/gui/widgets/progressbar.h23
-rw-r--r--src/gui/widgets/progressindicator.cpp3
-rw-r--r--src/gui/widgets/radiobutton.cpp89
-rw-r--r--src/gui/widgets/radiobutton.h19
-rw-r--r--src/gui/widgets/resizegrip.cpp37
-rw-r--r--src/gui/widgets/resizegrip.h12
-rw-r--r--src/gui/widgets/scrollarea.cpp224
-rw-r--r--src/gui/widgets/scrollarea.h27
-rw-r--r--src/gui/widgets/slider.cpp154
-rw-r--r--src/gui/widgets/slider.h15
-rw-r--r--src/gui/widgets/tab.cpp130
-rw-r--r--src/gui/widgets/tab.h13
-rw-r--r--src/gui/widgets/textfield.cpp73
-rw-r--r--src/gui/widgets/textfield.h11
-rw-r--r--src/gui/widgets/window.cpp4
-rw-r--r--src/resources/theme.cpp643
-rw-r--r--src/resources/theme.h139
39 files changed, 839 insertions, 1428 deletions
diff --git a/src/client.cpp b/src/client.cpp
index 2743a8b2..df8f1e23 100644
--- a/src/client.cpp
+++ b/src/client.cpp
@@ -310,13 +310,11 @@ Client::Client(const Options &options):
}
#endif
- Theme::prepareThemePath();
-
// Initialize the item and emote shortcuts.
itemShortcut = new ItemShortcut;
emoteShortcut = new EmoteShortcut;
- gui = new Gui(graphics);
+ gui = new Gui(graphics, Theme::prepareThemePath());
// Initialize sound engine
try
@@ -577,7 +575,7 @@ int Client::exec()
// Don't allow an alpha opacity
// lower than the default value
- Theme::instance()->setMinimumOpacity(0.8f);
+ gui->getTheme()->setMinimumOpacity(0.8f);
mCurrentDialog = new ServerDialog(&mCurrentServer,
mConfigDir);
@@ -596,7 +594,7 @@ int Client::exec()
logger->log("State: LOGIN");
// Don't allow an alpha opacity
// lower than the default value
- Theme::instance()->setMinimumOpacity(0.8f);
+ gui->getTheme()->setMinimumOpacity(0.8f);
if (mOptions.username.empty() || mOptions.password.empty())
{
@@ -720,7 +718,7 @@ int Client::exec()
logger->log("State: CHAR SELECT");
// Don't allow an alpha opacity
// lower than the default value
- Theme::instance()->setMinimumOpacity(0.8f);
+ gui->getTheme()->setMinimumOpacity(0.8f);
mCurrentDialog = new CharSelectDialog(&loginData);
@@ -770,7 +768,7 @@ int Client::exec()
sound.fadeOutMusic(1000);
// Allow any alpha opacity
- Theme::instance()->setMinimumOpacity(-1.0f);
+ gui->getTheme()->setMinimumOpacity(0.0f);
delete mSetupButton;
delete mDesktop;
diff --git a/src/graphics.cpp b/src/graphics.cpp
index afdac4f6..92f291c8 100644
--- a/src/graphics.cpp
+++ b/src/graphics.cpp
@@ -28,9 +28,7 @@
void ImageRect::setAlpha(float alpha)
{
for (auto img : grid)
- {
img->setAlpha(alpha);
- }
}
void Graphics::updateSize(int width, int height, float /*scale*/)
diff --git a/src/gui/abilitieswindow.cpp b/src/gui/abilitieswindow.cpp
index 10fed4ba..700fa7ff 100644
--- a/src/gui/abilitieswindow.cpp
+++ b/src/gui/abilitieswindow.cpp
@@ -180,7 +180,7 @@ AbilityEntry::AbilityEntry(AbilityInfo *info) :
if (!info->icon.empty())
mIcon = new Icon(info->icon);
else
- mIcon = new Icon(Theme::resolveThemePath("unknown-item.png"));
+ mIcon = new Icon(Theme::getImageFromTheme("unknown-item.png"));
mIcon->setPosition(1, 0);
add(mIcon);
diff --git a/src/gui/abilitieswindow.h b/src/gui/abilitieswindow.h
index aa84ed79..ddc5a9e4 100644
--- a/src/gui/abilitieswindow.h
+++ b/src/gui/abilitieswindow.h
@@ -55,4 +55,3 @@ class AbilitiesWindow : public Window, public gcn::ActionListener
};
extern AbilitiesWindow *abilitiesWindow;
-
diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp
index e6eed8f2..90f12672 100644
--- a/src/gui/gui.cpp
+++ b/src/gui/gui.cpp
@@ -56,8 +56,9 @@ gcn::Font *monoFont = nullptr;
bool Gui::debugDraw;
-Gui::Gui(Graphics *graphics)
- : mCustomCursorScale(Client::getVideo().settings().scale())
+Gui::Gui(Graphics *graphics, const std::string &themePath)
+ : mTheme(new Theme(themePath))
+ , mCustomCursorScale(Client::getVideo().settings().scale())
{
logger->log("Initializing GUI...");
// Set graphics
@@ -152,8 +153,6 @@ Gui::~Gui()
delete getTop();
delete guiInput;
-
- Theme::deleteInstance();
}
void Gui::logic()
@@ -271,7 +270,7 @@ void Gui::loadCustomCursors()
mCustomMouseCursors.clear();
- const std::string cursorPath = Theme::resolveThemePath("mouse.png");
+ const std::string cursorPath = mTheme->resolvePath("mouse.png");
SDL_Surface *mouseSurface = loadSurface(cursorPath);
if (!mouseSurface)
{
diff --git a/src/gui/gui.h b/src/gui/gui.h
index da8023b3..0441d18e 100644
--- a/src/gui/gui.h
+++ b/src/gui/gui.h
@@ -30,8 +30,10 @@
#include <SDL.h>
+#include <memory>
#include <vector>
+class Theme;
class TextInput;
class Graphics;
class SDLInput;
@@ -75,7 +77,7 @@ enum class Cursor {
class Gui final : public gcn::Gui, public EventListener
{
public:
- Gui(Graphics *screen);
+ Gui(Graphics *screen, const std::string &themePath);
~Gui() override;
@@ -120,6 +122,12 @@ class Gui final : public gcn::Gui, public EventListener
*/
void setCursorType(Cursor cursor);
+ /**
+ * The global GUI theme.
+ */
+ Theme *getTheme() const
+ { return mTheme.get(); }
+
static bool debugDraw;
protected:
@@ -132,6 +140,7 @@ class Gui final : public gcn::Gui, public EventListener
void loadCustomCursors();
void loadSystemCursors();
+ std::unique_ptr<Theme> mTheme; /**< The global GUI theme */
gcn::Font *mGuiFont; /**< The global GUI font */
gcn::Font *mInfoParticleFont; /**< Font for Info Particles*/
bool mCustomCursor = false; /**< Show custom cursor */
diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp
index 941bef82..6bf5a9d5 100644
--- a/src/gui/serverdialog.cpp
+++ b/src/gui/serverdialog.cpp
@@ -32,7 +32,6 @@
#include "gui/sdlinput.h"
#include "gui/widgets/button.h"
-#include "gui/widgets/dropdown.h"
#include "gui/widgets/label.h"
#include "gui/widgets/layout.h"
#include "gui/widgets/listbox.h"
@@ -97,16 +96,15 @@ public:
auto *model = static_cast<ServersListModel*>(mListModel);
- updateAlpha();
+ const int alpha = gui->getTheme()->getGuiAlpha();
- graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT,
- (int) (mAlpha * 255.0f)));
+ graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT, alpha));
graphics->setFont(getFont());
const int height = getRowHeight();
const gcn::Color unsupported =
Theme::getThemeColor(Theme::SERVER_VERSION_NOT_SUPPORTED,
- (int) (mAlpha * 255.0f));
+ alpha);
// Draw filled rectangle around the selected list element
if (mSelected >= 0)
@@ -117,7 +115,7 @@ public:
for (int i = 0, y = 0; i < model->getNumberOfElements();
++i, y += height)
{
- ServerInfo info = model->getServer(i);
+ const ServerInfo &info = model->getServer(i);
graphics->setColor(Theme::getThemeColor(Theme::TEXT));
diff --git a/src/gui/skilldialog.cpp b/src/gui/skilldialog.cpp
index 217c3800..7f45ae9d 100644
--- a/src/gui/skilldialog.cpp
+++ b/src/gui/skilldialog.cpp
@@ -30,7 +30,6 @@
#include "gui/widgets/button.h"
#include "gui/widgets/label.h"
#include "gui/widgets/listbox.h"
-#include "gui/widgets/progressbar.h"
#include "gui/widgets/scrollarea.h"
#include "gui/widgets/tab.h"
#include "gui/widgets/tabbedarea.h"
@@ -132,14 +131,12 @@ public:
if (!mListModel)
return;
- auto* model = static_cast<SkillModel*>(mListModel);
+ auto *model = static_cast<SkillModel *>(mListModel);
+ auto *graphics = static_cast<Graphics *>(gcnGraphics);
- updateAlpha();
+ const int alpha = gui->getTheme()->getGuiAlpha();
- auto *graphics = static_cast<Graphics*>(gcnGraphics);
-
- graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT,
- (int) (mAlpha * 255.0f)));
+ graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT, alpha));
graphics->setFont(getFont());
// Draw filled rectangle around the selected list element
@@ -155,12 +152,8 @@ public:
i < model->getNumberOfElements();
++i, y += getRowHeight())
{
- SkillInfo *e = model->getSkillAt(i);
-
- if (e)
- {
+ if (SkillInfo *e = model->getSkillAt(i))
e->draw(graphics, y, getWidth());
- }
}
}
@@ -482,8 +475,7 @@ void SkillInfo::draw(Graphics *graphics, int y, int width)
if (!skillExp.empty())
{
- gcn::Rectangle rect(33, y + 15, width - 33, 17);
-
- ProgressBar::render(graphics, rect, color, progress, skillExp);
+ const gcn::Rectangle rect(33, y + 15, width - 33, 17);
+ gui->getTheme()->drawProgressBar(graphics, rect, color, progress, skillExp);
}
}
diff --git a/src/gui/widgets/avatarlistbox.cpp b/src/gui/widgets/avatarlistbox.cpp
index 47e29ed0..f7d6e801 100644
--- a/src/gui/widgets/avatarlistbox.cpp
+++ b/src/gui/widgets/avatarlistbox.cpp
@@ -66,14 +66,12 @@ 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();
+ const int alpha = gui->getTheme()->getGuiAlpha();
- auto *graphics = static_cast<Graphics*>(gcnGraphics);
-
- graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT,
- (int) (mAlpha * 255.0f)));
+ graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT, alpha));
graphics->setFont(getFont());
const int fontHeight = getFont()->getHeight();
diff --git a/src/gui/widgets/button.cpp b/src/gui/widgets/button.cpp
index 58630ee8..eb2722e5 100644
--- a/src/gui/widgets/button.cpp
+++ b/src/gui/widgets/button.cpp
@@ -21,22 +21,18 @@
#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 <guichan/exception.hpp>
#include <guichan/font.hpp>
int Button::mInstances = 0;
-float Button::mAlpha = 1.0;
-ImageRect *Button::mButton;
TextPopup *Button::mTextPopup = nullptr;
enum {
@@ -47,20 +43,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,6 +62,8 @@ Button::Button(const std::string &caption, const std::string &actionEventId,
adjustSize();
}
+Button::~Button() = default;
+
bool Button::setButtonIcon(const std::string &iconFile)
{
// We clean up possible older references.
@@ -129,27 +113,6 @@ void Button::init()
if (mInstances == 0)
{
- // Load the skin
- mButton = new ImageRect[BUTTON_COUNT];
-
- for (int mode = 0; mode < BUTTON_COUNT; ++mode)
- {
- auto 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++;
- }
- }
- }
- updateAlpha();
-
// Create the tooltip popup. It is shared by all buttons and will get
// deleted by the WindowContainer.
if (!mTextPopup)
@@ -158,54 +121,29 @@ void Button::init()
mInstances++;
}
-Button::~Button()
-{
- 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;
- }
-}
-
-void Button::updateAlpha()
+void Button::draw(gcn::Graphics *graphics)
{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
+ Theme::WidgetState state;
+ state.width = getWidth();
+ state.height = getHeight();
+ state.enabled = isEnabled();
+ state.hovered = mHasMouse;
+ state.selected = isPressed();
+ state.focused = isFocused();
- if (mAlpha != alpha)
- {
- mAlpha = alpha;
- for (int mode = 0; mode < BUTTON_COUNT; ++mode)
- {
- mButton[mode].setAlpha(mAlpha);
- }
- }
-}
+ gui->getTheme()->drawButton(static_cast<Graphics*>(graphics), state);
-void Button::draw(gcn::Graphics *graphics)
-{
int mode;
- if (!isEnabled())
+ if (!state.enabled)
mode = BUTTON_DISABLED;
- else if (isPressed())
+ else if (state.selected)
mode = BUTTON_PRESSED;
- else if (mHasMouse || isFocused())
+ else if (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
diff --git a/src/gui/widgets/button.h b/src/gui/widgets/button.h
index bac3f914..32f7cb77 100644
--- a/src/gui/widgets/button.h
+++ b/src/gui/widgets/button.h
@@ -57,11 +57,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);
@@ -92,9 +87,7 @@ class Button : public gcn::Button
void removeButtonIcon();
- static ImageRect* mButton; /**< Button state graphics */
static int mInstances; /**< Number of button instances */
- static float mAlpha;
std::vector<std::unique_ptr<Image>> mButtonIcon; /**< Button Icons graphics */
@@ -102,6 +95,6 @@ class Button : public gcn::Button
* 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 */
};
diff --git a/src/gui/widgets/checkbox.cpp b/src/gui/widgets/checkbox.cpp
index 399ffeb4..e2d13ab2 100644
--- a/src/gui/widgets/checkbox.cpp
+++ b/src/gui/widgets/checkbox.cpp
@@ -21,57 +21,12 @@
#include "gui/widgets/checkbox.h"
-#include "configuration.h"
-#include "graphics.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;
-
CheckBox::CheckBox(const std::string &caption, bool selected):
gcn::CheckBox(caption, selected)
{
- if (instances == 0)
- {
- auto 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);
- }
-
- instances++;
-}
-
-CheckBox::~CheckBox()
-{
- instances--;
-
- if (instances == 0)
- {
- delete checkBoxNormal;
- delete checkBoxChecked;
- delete checkBoxDisabled;
- delete checkBoxDisabledChecked;
- delete checkBoxNormalHi;
- delete checkBoxCheckedHi;
- }
}
void CheckBox::draw(gcn::Graphics* graphics)
@@ -86,55 +41,14 @@ void CheckBox::draw(gcn::Graphics* graphics)
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);
- }
-}
-
void CheckBox::drawBox(gcn::Graphics* graphics)
{
- Image *box;
-
- if (isEnabled())
- {
- if (isSelected())
- {
- if (mHasMouse)
- box = checkBoxCheckedHi;
- else
- box = checkBoxChecked;
- }
- else
- {
- if (mHasMouse)
- box = checkBoxNormalHi;
- else
- box = checkBoxNormal;
- }
- }
- else
- {
- if (isSelected())
- box = checkBoxDisabledChecked;
- else
- box = checkBoxDisabled;
- }
-
- updateAlpha();
+ Theme::WidgetState state;
+ state.enabled = isEnabled();
+ state.hovered = mHasMouse;
+ state.selected = isSelected();
- static_cast<Graphics*>(graphics)->drawImage(box, 2, 2);
+ gui->getTheme()->drawCheckBox(graphics, state);
}
void CheckBox::mouseEntered(gcn::MouseEvent& event)
diff --git a/src/gui/widgets/checkbox.h b/src/gui/widgets/checkbox.h
index 8b5a4986..b72213a9 100644
--- a/src/gui/widgets/checkbox.h
+++ b/src/gui/widgets/checkbox.h
@@ -23,8 +23,6 @@
#include <guichan/widgets/checkbox.hpp>
-class Image;
-
/**
* Check box widget. Same as the Guichan check box but with custom look.
*
@@ -35,41 +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.
*/
- 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;
};
diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp
index 2c78a3d7..7202827b 100644
--- a/src/gui/widgets/dropdown.cpp
+++ b/src/gui/widgets/dropdown.cpp
@@ -21,125 +21,37 @@
#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;
-ResourceRef<Image> DropDown::buttons[2][2];
-ImageRect DropDown::skin;
-float DropDown::mAlpha = 1.0;
-
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
- auto 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++;
- }
- }
-
- skin.setAlpha(mAlpha);
- }
-
- instances++;
}
DropDown::~DropDown()
{
- instances--;
- // Free images memory
- if (instances == 0)
- {
- buttons[0][0] = nullptr;
- buttons[0][1] = nullptr;
- buttons[1][0] = nullptr;
- buttons[1][1] = nullptr;
-
- 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);
+ const gcn::Color *highlightColor = &Theme::getThemeColor(Theme::HIGHLIGHT, alpha);
gcn::Color shadowColor = faceColor - 0x303030;
shadowColor.a = alpha;
@@ -174,18 +86,24 @@ 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);
+ Theme::WidgetState state;
+ state.width = getWidth() + bs * 2;
+ state.height = getHeight() + bs * 2;
+
+ gui->getTheme()->drawDropDownFrame(static_cast<Graphics*>(graphics), state);
}
void DropDown::drawButton(gcn::Graphics *graphics)
{
- int height = mDroppedDown ? mFoldedUpHeight : getHeight();
-
- static_cast<Graphics*>(graphics)->
- drawImage(buttons[mDroppedDown][mPushed], getWidth() - height + 2, 1);
+ Theme::WidgetState state;
+ state.width = getWidth();
+ state.height = mDroppedDown ? mFoldedUpHeight : getHeight();
+ state.enabled = isEnabled();
+ state.selected = mDroppedDown;
+ state.hovered = mPushed;
+
+ gui->getTheme()->drawDropDownButton(static_cast<Graphics*>(graphics), state);
}
// -- KeyListener notifications
diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h
index 7c4e6d1d..53bfd0e2 100644
--- a/src/gui/widgets/dropdown.h
+++ b/src/gui/widgets/dropdown.h
@@ -21,12 +21,8 @@
#pragma once
-#include "resources/resource.h"
#include <guichan/widgets/dropdown.hpp>
-class Image;
-class ImageRect;
-
/**
* A drop down box from which you can select different values.
*
@@ -47,11 +43,6 @@ 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;
@@ -79,10 +70,4 @@ class DropDown : public gcn::DropDown
* @param graphics a Graphics object to draw with.
*/
void drawButton(gcn::Graphics *graphics) override;
-
- // Add own Images.
- static int instances;
- static ResourceRef<Image> buttons[2][2];
- static ImageRect skin;
- static float mAlpha;
};
diff --git a/src/gui/widgets/emoteshortcutcontainer.cpp b/src/gui/widgets/emoteshortcutcontainer.cpp
index 7f33538f..1aef6323 100644
--- a/src/gui/widgets/emoteshortcutcontainer.cpp
+++ b/src/gui/widgets/emoteshortcutcontainer.cpp
@@ -24,7 +24,6 @@
#include "configuration.h"
#include "emoteshortcut.h"
#include "graphics.h"
-#include "item.h"
#include "keyboardconfig.h"
#include "resources/emotedb.h"
diff --git a/src/gui/widgets/listbox.cpp b/src/gui/widgets/listbox.cpp
index 55f0f422..f1fcfd53 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,31 +31,19 @@
#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();
+ const int alpha = gui->getTheme()->getGuiAlpha();
- graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT,
- (int) (mAlpha * 255.0f)));
+ graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT, alpha));
graphics->setFont(getFont());
const int height = getRowHeight();
diff --git a/src/gui/widgets/listbox.h b/src/gui/widgets/listbox.h
index bd95cc39..d5b4e759 100644
--- a/src/gui/widgets/listbox.h
+++ b/src/gui/widgets/listbox.h
@@ -42,11 +42,6 @@ class ListBox : public gcn::ListBox
*/
void draw(gcn::Graphics *graphics) override;
- /**
- * Update the alpha value to the graphic components.
- */
- static void updateAlpha();
-
// Inherited from KeyListener
void keyPressed(gcn::KeyEvent& keyEvent) override;
@@ -60,7 +55,4 @@ class ListBox : public gcn::ListBox
void mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) override;
void mouseDragged(gcn::MouseEvent &event) override;
-
- protected:
- static float mAlpha;
};
diff --git a/src/gui/widgets/playerbox.cpp b/src/gui/widgets/playerbox.cpp
index dff87114..f251035d 100644
--- a/src/gui/widgets/playerbox.cpp
+++ b/src/gui/widgets/playerbox.cpp
@@ -22,63 +22,17 @@
#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)
-{
- setFrameSize(2);
-
- if (instances == 0)
- {
- // Load the background skin
- auto 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);
- }
-
- instances++;
-}
-
-PlayerBox::~PlayerBox()
+PlayerBox::PlayerBox(const Being *being)
+ : mBeing(being)
{
- 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
@@ -86,19 +40,4 @@ void PlayerBox::draw(gcn::Graphics *graphics)
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 bd94a71f..39392c63 100644
--- a/src/gui/widgets/playerbox.h
+++ b/src/gui/widgets/playerbox.h
@@ -21,17 +21,16 @@
#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:
/**
@@ -40,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
@@ -51,19 +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;
};
diff --git a/src/gui/widgets/popup.cpp b/src/gui/widgets/popup.cpp
index 94d8cf85..b12acf31 100644
--- a/src/gui/widgets/popup.cpp
+++ b/src/gui/widgets/popup.cpp
@@ -25,8 +25,8 @@
#include "graphics.h"
#include "log.h"
+#include "gui/gui.h"
#include "gui/viewport.h"
-
#include "gui/widgets/windowcontainer.h"
#include "resources/theme.h"
@@ -46,7 +46,7 @@ Popup::Popup(const std::string &name, const std::string &skin):
setPadding(6);
// Loads the skin
- mSkin = Theme::instance()->load(skin);
+ mSkin = gui->getTheme()->load(skin);
// Add this window to the window container
windowContainer->add(this);
diff --git a/src/gui/widgets/progressbar.cpp b/src/gui/widgets/progressbar.cpp
index ec9690ab..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,34 +44,6 @@ ProgressBar::ProgressBar(float progress,
mProgress);
setSize(width, height);
-
- if (mInstances == 0)
- {
- auto 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);
- }
-
- mInstances++;
-}
-
-ProgressBar::~ProgressBar()
-{
- mInstances--;
-
- if (mInstances == 0)
- {
- std::for_each(mBorder.grid, mBorder.grid + 9, dtor<Image*>());
- }
}
void ProgressBar::logic()
@@ -112,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)
@@ -147,9 +99,7 @@ void ProgressBar::setProgress(float progress)
mProgress = p;
if (mProgressPalette >= 0)
- {
mColorToGo = Theme::getProgressColor(mProgressPalette, progress);
- }
}
void ProgressBar::setProgressPalette(int progressPalette)
@@ -158,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)
@@ -170,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 9f1f6e58..52904f5a 100644
--- a/src/gui/widgets/progressbar.h
+++ b/src/gui/widgets/progressbar.h
@@ -25,9 +25,6 @@
#include <string>
-class Graphics;
-class ImageRect;
-
/**
* A progress bar.
*
@@ -43,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;
@@ -110,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;
@@ -127,10 +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;
};
diff --git a/src/gui/widgets/progressindicator.cpp b/src/gui/widgets/progressindicator.cpp
index a103c8b4..ccd4fd54 100644
--- a/src/gui/widgets/progressindicator.cpp
+++ b/src/gui/widgets/progressindicator.cpp
@@ -21,6 +21,7 @@
#include "progressindicator.h"
#include "graphics.h"
+#include "gui/gui.h"
#include "simpleanimation.h"
#include "resources/animation.h"
@@ -31,7 +32,7 @@
ProgressIndicator::ProgressIndicator()
{
- const std::string path = Theme::resolveThemePath("progress-indicator.png");
+ const std::string path = gui->getTheme()->resolvePath("progress-indicator.png");
mImageSet = ResourceManager::getInstance()->getImageSet(path, 32, 32);
Animation anim;
diff --git a/src/gui/widgets/radiobutton.cpp b/src/gui/widgets/radiobutton.cpp
index 9fcc34fa..ee2f4983 100644
--- a/src/gui/widgets/radiobutton.cpp
+++ b/src/gui/widgets/radiobutton.cpp
@@ -21,93 +21,24 @@
#include "gui/widgets/radiobutton.h"
-#include "configuration.h"
-#include "graphics.h"
-
-#include "resources/image.h"
+#include "gui/gui.h"
#include "resources/theme.h"
-int RadioButton::instances = 0;
-float RadioButton::mAlpha = 1.0;
-ResourceRef<Image> RadioButton::radioNormal;
-ResourceRef<Image> RadioButton::radioChecked;
-ResourceRef<Image> RadioButton::radioDisabled;
-ResourceRef<Image> RadioButton::radioDisabledChecked;
-ResourceRef<Image> RadioButton::radioNormalHi;
-ResourceRef<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++;
-}
-
-RadioButton::~RadioButton()
-{
- instances--;
-
- if (instances == 0)
- {
- radioNormal = nullptr;
- radioChecked = nullptr;
- radioDisabled = nullptr;
- radioDisabledChecked = nullptr;
- radioNormalHi = nullptr;
- radioCheckedHi = nullptr;
- }
}
void RadioButton::drawBox(gcn::Graphics* graphics)
{
- if (config.guiAlpha != mAlpha)
- {
- mAlpha = config.guiAlpha;
- radioNormal->setAlpha(mAlpha);
- radioChecked->setAlpha(mAlpha);
- radioDisabled->setAlpha(mAlpha);
- radioDisabledChecked->setAlpha(mAlpha);
- radioNormalHi->setAlpha(mAlpha);
- radioCheckedHi->setAlpha(mAlpha);
- }
-
- 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;
+ Theme::WidgetState state;
+ state.enabled = isEnabled();
+ state.hovered = mHasMouse;
+ state.selected = isSelected();
- if (box)
- static_cast<Graphics*>(graphics)->drawImage(box, 2, 2);
+ gui->getTheme()->drawRadioButton(graphics, state);
}
void RadioButton::draw(gcn::Graphics* graphics)
diff --git a/src/gui/widgets/radiobutton.h b/src/gui/widgets/radiobutton.h
index 4f6b5a49..192e5d34 100644
--- a/src/gui/widgets/radiobutton.h
+++ b/src/gui/widgets/radiobutton.h
@@ -21,22 +21,17 @@
#pragma once
-#include "resources/resource.h"
-
#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.
@@ -60,13 +55,5 @@ class RadioButton : public gcn::RadioButton
void mouseExited(gcn::MouseEvent& event) override;
private:
- static int instances;
- static float mAlpha;
bool mHasMouse = false;
- static ResourceRef<Image> radioNormal;
- static ResourceRef<Image> radioChecked;
- static ResourceRef<Image> radioDisabled;
- static ResourceRef<Image> radioDisabledChecked;
- static ResourceRef<Image> radioNormalHi;
- static ResourceRef<Image> radioCheckedHi;
};
diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp
index b7d2ec16..bda0b386 100644
--- a/src/gui/widgets/resizegrip.cpp
+++ b/src/gui/widgets/resizegrip.cpp
@@ -21,48 +21,23 @@
#include "gui/widgets/resizegrip.h"
-#include "configuration.h"
#include "graphics.h"
+#include "gui/gui.h"
#include "resources/image.h"
#include "resources/theme.h"
#include <guichan/graphics.hpp>
-ResourceRef<Image> ResizeGrip::gripImage;
-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 = nullptr;
+ const auto gripImage = gui->getTheme()->getResizeGripImage();
+ setSize(gripImage->getWidth() + 2,
+ gripImage->getHeight() + 2);
}
void ResizeGrip::draw(gcn::Graphics *graphics)
{
- if (config.guiAlpha != mAlpha)
- {
- mAlpha = config.guiAlpha;
- gripImage->setAlpha(mAlpha);
- }
-
+ const auto gripImage = gui->getTheme()->getResizeGripImage();
static_cast<Graphics*>(graphics)->drawImage(gripImage, 0, 0);
}
diff --git a/src/gui/widgets/resizegrip.h b/src/gui/widgets/resizegrip.h
index 5638eff4..9b4e0611 100644
--- a/src/gui/widgets/resizegrip.h
+++ b/src/gui/widgets/resizegrip.h
@@ -21,12 +21,8 @@
#pragma once
-#include "resources/resource.h"
-
#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
@@ -37,16 +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 ResourceRef<Image> gripImage; /**< Resize grip image */
- static int mInstances; /**< Number of resize grip instances */
- static float mAlpha;
};
diff --git a/src/gui/widgets/scrollarea.cpp b/src/gui/widgets/scrollarea.cpp
index e99e19e5..6a2cb7e4 100644
--- a/src/gui/widgets/scrollarea.cpp
+++ b/src/gui/widgets/scrollarea.cpp
@@ -21,21 +21,11 @@
#include "gui/widgets/scrollarea.h"
-#include "configuration.h"
#include "graphics.h"
-#include "resources/image.h"
+#include "gui/gui.h"
#include "resources/theme.h"
-#include "utils/dtor.h"
-
-int ScrollArea::instances = 0;
-float ScrollArea::mAlpha = 1.0;
-ImageRect ScrollArea::background;
-ImageRect ScrollArea::vMarker;
-ImageRect ScrollArea::vMarkerHi;
-ResourceRef<Image> ScrollArea::buttons[4][2];
-
ScrollArea::ScrollArea()
{
addWidgetListener(this);
@@ -51,24 +41,6 @@ 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] = nullptr;
- buttons[UP][1] = nullptr;
- buttons[DOWN][0] = nullptr;
- buttons[DOWN][1] = nullptr;
- buttons[LEFT][0] = nullptr;
- buttons[LEFT][1] = nullptr;
- buttons[RIGHT][0] = nullptr;
- buttons[RIGHT][1] = nullptr;
- }
}
void ScrollArea::init()
@@ -80,74 +52,6 @@ void ScrollArea::init()
setDownButtonScrollAmount(2);
setLeftButtonScrollAmount(2);
setRightButtonScrollAmount(2);
-
- if (instances == 0)
- {
- // Load the background skin
- auto 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);
-
- // Load vertical scrollbar skin
- auto vscroll = Theme::getImageFromTheme("vscroll_grey.png");
- auto vscrollHi = Theme::getImageFromTheme("vscroll_highlight.png");
-
- 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++;
- }
- }
-
- vMarker.setAlpha(config.guiAlpha);
- vMarkerHi.setAlpha(config.guiAlpha);
-
- 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");
- }
-
- instances++;
}
void ScrollArea::logic()
@@ -196,38 +100,18 @@ void ScrollArea::logic()
}
}
-void ScrollArea::updateAlpha()
+void ScrollArea::drawFrame(gcn::Graphics *graphics)
{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
-
- if (alpha != mAlpha)
- {
- mAlpha = alpha;
+ if (!mOpaque)
+ return;
- background.setAlpha(mAlpha);
- vMarker.setAlpha(mAlpha);
- vMarkerHi.setAlpha(mAlpha);
- }
-}
+ const int bs = getFrameSize();
-void ScrollArea::draw(gcn::Graphics *graphics)
-{
- updateAlpha();
- gcn::ScrollArea::draw(graphics);
-}
+ Theme::WidgetState state;
+ state.width = getWidth() + bs * 2;
+ state.height = getHeight() + bs * 2;
-void ScrollArea::drawFrame(gcn::Graphics *graphics)
-{
- if (mOpaque)
- {
- 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);
- }
+ gui->getTheme()->drawScrollAreaFrame(static_cast<Graphics *>(graphics), state);
}
void ScrollArea::setOpaque(bool opaque)
@@ -236,35 +120,6 @@ void ScrollArea::setOpaque(bool opaque)
setFrameSize(mOpaque ? 2 : 0);
}
-void ScrollArea::drawButton(gcn::Graphics *graphics, BUTTON_DIR dir)
-{
- int state = 0;
- gcn::Rectangle dim;
-
- 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_cast<Graphics*>(graphics)->
- drawImage(buttons[dir][state], dim.x, dim.y);
-}
-
void ScrollArea::drawBackground(gcn::Graphics *graphics)
{
// background is drawn as part of the frame instead
@@ -272,62 +127,68 @@ void ScrollArea::drawBackground(gcn::Graphics *graphics)
void ScrollArea::drawUpButton(gcn::Graphics *graphics)
{
- drawButton(graphics, UP);
+ auto theme = gui->getTheme();
+ theme->drawScrollAreaButton(static_cast<Graphics *>(graphics),
+ Theme::ARROW_UP,
+ mUpButtonPressed,
+ getUpButtonDimension());
}
void ScrollArea::drawDownButton(gcn::Graphics *graphics)
{
- drawButton(graphics, DOWN);
+ auto theme = gui->getTheme();
+ theme->drawScrollAreaButton(static_cast<Graphics *>(graphics),
+ Theme::ARROW_DOWN,
+ mDownButtonPressed,
+ getDownButtonDimension());
}
void ScrollArea::drawLeftButton(gcn::Graphics *graphics)
{
- drawButton(graphics, LEFT);
+ auto theme = gui->getTheme();
+ theme->drawScrollAreaButton(static_cast<Graphics *>(graphics),
+ Theme::ARROW_LEFT,
+ mLeftButtonPressed,
+ getLeftButtonDimension());
}
void ScrollArea::drawRightButton(gcn::Graphics *graphics)
{
- drawButton(graphics, RIGHT);
+ auto theme = gui->getTheme();
+ theme->drawScrollAreaButton(static_cast<Graphics *>(graphics),
+ Theme::ARROW_RIGHT,
+ 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->fillRectangle(getVerticalBarDimension());
graphics->setColor(gcn::Color(255, 255, 255));
}
void ScrollArea::drawHBar(gcn::Graphics *graphics)
{
- const gcn::Rectangle dim = getHorizontalBarDimension();
graphics->setColor(gcn::Color(0, 0, 0, 32));
- graphics->fillRectangle(dim);
+ graphics->fillRectangle(getHorizontalBarDimension());
graphics->setColor(gcn::Color(255, 255, 255));
}
void ScrollArea::drawVMarker(gcn::Graphics *graphics)
{
- gcn::Rectangle dim = getVerticalMarkerDimension();
-
- 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);
+ auto theme = gui->getTheme();
+ theme->drawScrollAreaMarker(static_cast<Graphics *>(graphics),
+ mHasMouse && (mX > (getWidth() - getScrollbarWidth())),
+ getVerticalMarkerDimension());
}
void ScrollArea::drawHMarker(gcn::Graphics *graphics)
{
- gcn::Rectangle dim = getHorizontalMarkerDimension();
-
- 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);
+ auto theme = gui->getTheme();
+ theme->drawScrollAreaMarker(static_cast<Graphics *>(graphics),
+ mHasMouse && (mY > (getHeight() - getScrollbarWidth())),
+ getHorizontalMarkerDimension());
}
void ScrollArea::mouseMoved(gcn::MouseEvent& event)
@@ -348,6 +209,9 @@ void ScrollArea::mouseExited(gcn::MouseEvent& event)
void ScrollArea::widgetResized(const gcn::Event &event)
{
- getContent()->setSize(getWidth() - 2 * getFrameSize(),
- getHeight() - 2 * getFrameSize());
+ if (auto content = getContent())
+ {
+ content->setSize(getWidth() - 2 * getFrameSize(),
+ getHeight() - 2 * getFrameSize());
+ }
}
diff --git a/src/gui/widgets/scrollarea.h b/src/gui/widgets/scrollarea.h
index ac45e4c8..18b1f17d 100644
--- a/src/gui/widgets/scrollarea.h
+++ b/src/gui/widgets/scrollarea.h
@@ -21,8 +21,6 @@
#pragma once
-#include "resources/resource.h"
-
#include <guichan/widgetlistener.hpp>
#include <guichan/widgets/scrollarea.hpp>
@@ -66,16 +64,6 @@ class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener
void logic() override;
/**
- * Update the alpha value to the graphic components.
- */
- static void updateAlpha();
-
- /**
- * Draws the scroll area.
- */
- void draw(gcn::Graphics *graphics) override;
-
- /**
* Draws the background and border of the scroll area.
*/
void drawFrame(gcn::Graphics *graphics) override;
@@ -108,19 +96,11 @@ class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener
void widgetResized(const gcn::Event &event) 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;
@@ -131,13 +111,6 @@ 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 ResourceRef<Image> buttons[4][2];
-
int mX = 0;
int mY = 0;
bool mHasMouse = false;
diff --git a/src/gui/widgets/slider.cpp b/src/gui/widgets/slider.cpp
index f0b61667..20a843f3 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,151 +38,27 @@ 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)
- {
- auto slider = Theme::getImageFromTheme("slider.png");
- auto 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);
- }
-
- 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);
- }
-
+ setMarkerLength(gui->getTheme()->getSliderMarkerLength());
}
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());
-
- x += w;
- static_cast<Graphics*>(graphics)->drawImage(hEnd, x, y);
- }
- else
- {
- static_cast<Graphics*>(graphics)->drawImage(hStartHi, x, y);
-
- 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);
+ Theme::WidgetState state;
+ state.width = getWidth();
+ state.height = getHeight();
+ state.enabled = isEnabled();
+ state.hovered = mHasMouse;
+
+ auto theme = gui->getTheme();
+ theme->drawSlider(static_cast<Graphics*>(graphics), state, getMarkerPosition());
}
void Slider::drawMarker(gcn::Graphics *graphics)
{
- static_cast<Graphics*>(graphics)->
- drawImage(mHasMouse?hGripHi:hGrip, getMarkerPosition(),
- (getHeight() - (mHasMouse?hGripHi:hGrip)->getHeight()) / 2);
+ // Marker is drawn in Slider::draw
}
void Slider::mouseEntered(gcn::MouseEvent& event)
diff --git a/src/gui/widgets/slider.h b/src/gui/widgets/slider.h
index edbbcd4d..142d3f6a 100644
--- a/src/gui/widgets/slider.h
+++ b/src/gui/widgets/slider.h
@@ -23,8 +23,6 @@
#include <guichan/widgets/slider.hpp>
-class Image;
-
/**
* Slider widget. Same as the Guichan slider but with custom look.
*
@@ -46,13 +44,6 @@ 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.
*/
@@ -79,11 +70,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;
};
diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp
index d20e7993..1a857e55 100644
--- a/src/gui/widgets/tab.cpp
+++ b/src/gui/widgets/tab.cpp
@@ -21,141 +21,47 @@
#include "gui/widgets/tab.h"
-#include "configuration.h"
#include "graphics.h"
+#include "gui/gui.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()
{
setFocusable(false);
setFrameSize(0);
- mFlash = false;
-
- if (mInstances == 0)
- {
- // Load the skin
- for (int mode = 0; mode < TAB_COUNT; mode++)
- {
- auto tabImage = 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] = tabImage->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);
- }
- }
- mInstances++;
-}
-
-void Tab::updateAlpha()
-{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
-
- // 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;
-
- for (auto &t : tabImg)
- {
- t.setAlpha(mAlpha);
- }
- }
}
void Tab::draw(gcn::Graphics *graphics)
{
- int mode = TAB_STANDARD;
-
- // check which type of tab to draw
- if (mTabbedArea)
- {
+ Theme::WidgetState state;
+ state.width = getWidth();
+ state.height = getHeight();
+ state.enabled = isEnabled();
+ state.hovered = mHasMouse;
+ state.selected = mTabbedArea && mTabbedArea->isTabSelected(this);
+ state.focused = isFocused();
+
+ gui->getTheme()->drawTab(static_cast<Graphics*>(graphics), state);
+
+ // if tab is selected, it doesnt need to highlight activity
+ if (state.selected)
+ mFlash = false;
+
+ if (mFlash)
+ mLabel->setForegroundColor(Theme::getThemeColor(Theme::TAB_FLASH));
+ else
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;
- }
- if (mFlash)
- {
- mLabel->setForegroundColor(Theme::getThemeColor(Theme::TAB_FLASH));
- }
- }
-
- updateAlpha();
-
- // draw tab
- static_cast<Graphics*>(graphics)->
- drawImageRect(0, 0, getWidth(), getHeight(), tabImg[mode]);
// draw label
drawChildren(graphics);
diff --git a/src/gui/widgets/tab.h b/src/gui/widgets/tab.h
index 37d5f0c5..7d1365fd 100644
--- a/src/gui/widgets/tab.h
+++ b/src/gui/widgets/tab.h
@@ -23,7 +23,6 @@
#include <guichan/widgets/tab.hpp>
-class ImageRect;
class TabbedArea;
/**
@@ -34,12 +33,6 @@ class Tab : public gcn::Tab
{
public:
Tab();
- ~Tab() override;
-
- /**
- * Update the alpha value to the graphic components.
- */
- static void updateAlpha();
/**
* Draw the tabbed area.
@@ -64,10 +57,6 @@ class Tab : public gcn::Tab
/** 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;
+ bool mFlash = false;
};
diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp
index be75a96f..a1a20e90 100644
--- a/src/gui/widgets/textfield.cpp
+++ b/src/gui/widgets/textfield.cpp
@@ -21,84 +21,29 @@
#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)
+TextField::TextField(const std::string &text, bool loseFocusOnTab)
+ : gcn::TextField(text)
+ , mLoseFocusOnTab(loseFocusOnTab)
{
setFrameSize(2);
-
- mLoseFocusOnTab = loseFocusOnTab;
-
- if (instances == 0)
- {
- // Load the skin
- auto 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);
- }
-
- instances++;
-}
-
-TextField::~TextField()
-{
- instances--;
-
- if (instances == 0)
- std::for_each(skin.grid, skin.grid + 9, dtor<Image*>());
-}
-
-void TextField::updateAlpha()
-{
- float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
-
- if (alpha != mAlpha)
- {
- mAlpha = alpha;
- skin.setAlpha(mAlpha);
- }
}
void TextField::draw(gcn::Graphics *graphics)
{
- updateAlpha();
-
if (isFocused())
{
drawCaret(graphics,
@@ -113,13 +58,13 @@ void TextField::draw(gcn::Graphics *graphics)
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;
+ Theme::WidgetState state;
+ state.width = getWidth() + bs * 2;
+ state.height = getHeight() + bs * 2;
- static_cast<Graphics*>(graphics)->drawImageRect(0, 0, w, h, skin);
+ gui->getTheme()->drawTextFieldFrame(static_cast<Graphics*>(graphics), state);
}
void TextField::setNumeric(bool numeric)
diff --git a/src/gui/widgets/textfield.h b/src/gui/widgets/textfield.h
index f91b9e8c..8ea8ec30 100644
--- a/src/gui/widgets/textfield.h
+++ b/src/gui/widgets/textfield.h
@@ -26,8 +26,6 @@
#include <vector>
class TextInput;
-class ImageRect;
-class TextField;
struct TextHistory
{
@@ -78,7 +76,6 @@ class TextField : public gcn::TextField
*/
TextField(const std::string &text = std::string(),
bool loseFocusOnTab = true);
- ~TextField() override;
/**
* Draws the text field.
@@ -86,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;
@@ -163,9 +155,6 @@ class TextField : public gcn::TextField
void autoComplete();
void handlePaste();
- static int instances;
- static float mAlpha;
- static ImageRect skin;
bool mNumeric = false;
int mMinimum;
int mMaximum;
diff --git a/src/gui/widgets/window.cpp b/src/gui/widgets/window.cpp
index 8bf9d081..52ee917e 100644
--- a/src/gui/widgets/window.cpp
+++ b/src/gui/widgets/window.cpp
@@ -63,7 +63,7 @@ Window::Window(const std::string &caption, bool modal, Window *parent,
setTitleBarHeight(20);
// Loads the skin
- mSkin = Theme::instance()->load(skin);
+ mSkin = gui->getTheme()->load(skin);
// Add this window to the window container
windowContainer->add(this);
@@ -695,7 +695,7 @@ int Window::getResizeHandles(gcn::MouseEvent &event)
int Window::getGuiAlpha()
{
float alpha = std::max(config.guiAlpha,
- Theme::instance()->getMinimumOpacity());
+ gui->getTheme()->getMinimumOpacity());
return (int) (alpha * 255.0f);
}
diff --git a/src/resources/theme.cpp b/src/resources/theme.cpp
index b1b099ff..bdb5ce31 100644
--- a/src/resources/theme.cpp
+++ b/src/resources/theme.cpp
@@ -25,6 +25,7 @@
#include "configuration.h"
#include "log.h"
+#include "textrenderer.h"
#include "resources/dye.h"
#include "resources/image.h"
@@ -36,13 +37,18 @@
#include "utils/stringutils.h"
#include "utils/xml.h"
+#include <guichan/font.hpp>
+
#include <algorithm>
+#include <optional>
+/**
+ * Initializes the directory in which the client looks for GUI themes, which at
+ * the same time functions as a fallback directory when looking up files
+ * relevant for the GUI theme.
+ */
static std::string defaultThemePath;
-std::string Theme::mThemePath;
-Theme *Theme::mInstance = nullptr;
-// Set the theme path...
static void initDefaultThemePath()
{
defaultThemePath = branding.getStringValue("guiThemePath");
@@ -51,6 +57,21 @@ static void initDefaultThemePath()
defaultThemePath = "graphics/gui/";
}
+static std::optional<std::string> findThemePath(const std::string &theme)
+{
+ if (theme.empty())
+ return {};
+
+ std::string themePath = defaultThemePath;
+ themePath += theme;
+
+ if (FS::isDirectory(themePath))
+ return themePath;
+
+ return {};
+}
+
+
Skin::Skin(ImageRect skin, Image *close, Image *stickyUp, Image *stickyDown):
mBorder(skin),
mCloseImage(close),
@@ -63,16 +84,10 @@ Skin::~Skin()
// Clean up static resources
for (auto img : mBorder.grid)
delete img;
-
- delete mStickyImageUp;
- delete mStickyImageDown;
}
-void Skin::updateAlpha(float minimumOpacityAllowed)
+void Skin::updateAlpha(float alpha)
{
- const float alpha = std::max(minimumOpacityAllowed,
- config.guiAlpha);
-
mBorder.setAlpha(alpha);
mCloseImage->setAlpha(alpha);
@@ -92,13 +107,28 @@ int Skin::getMinHeight() const
mBorder.grid[ImageRect::LOWER_LEFT]->getHeight();
}
-Theme::Theme():
- Palette(THEME_COLORS_END),
- mMinimumOpacity(-1.0f),
- mProgressColors(THEME_PROG_END)
-{
- initDefaultThemePath();
+enum {
+ BUTTON_MODE_STANDARD, // 0
+ BUTTON_MODE_HIGHLIGHTED, // 1
+ BUTTON_MODE_PRESSED, // 2
+ BUTTON_MODE_DISABLED, // 3
+ BUTTON_MODE_COUNT // 4 - Must be last.
+};
+
+enum {
+ TAB_STANDARD, // 0
+ TAB_HIGHLIGHTED, // 1
+ TAB_SELECTED, // 2
+ TAB_UNUSED, // 3
+ TAB_COUNT // 4 - Must be last.
+};
+
+Theme::Theme(const std::string &path)
+ : Palette(THEME_COLORS_END)
+ , mThemePath(path)
+ , mProgressColors(THEME_PROG_END)
+{
listen(Event::ConfigChannel);
loadColors();
@@ -113,31 +143,214 @@ Theme::Theme():
mColors[SERVER].ch = 'S';
mColors[LOGGER].ch = 'L';
mColors[HYPERLINK].ch = '<';
+
+ // Button skin
+ struct ButtonData
+ {
+ char const *file;
+ int gridX;
+ int gridY;
+ };
+
+ constexpr ButtonData data[BUTTON_MODE_COUNT] = {
+ { "button.png", 0, 0 },
+ { "buttonhi.png", 9, 4 },
+ { "buttonpress.png", 16, 19 },
+ { "button_disabled.png", 25, 23 }
+ };
+
+ mButton = new ImageRect[BUTTON_MODE_COUNT];
+
+ for (int mode = 0; mode < BUTTON_MODE_COUNT; ++mode)
+ {
+ auto modeImage = getImage(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++;
+ }
+ }
+ }
+
+ // Tab skin
+ struct TabData
+ {
+ char const *file;
+ int gridX[4];
+ int gridY[4];
+ };
+
+ constexpr TabData tabData[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} }
+ };
+
+ for (int mode = 0; mode < TAB_COUNT; mode++)
+ {
+ auto tabImage = getImage(tabData[mode].file);
+ int a = 0;
+ for (int y = 0; y < 3; y++)
+ {
+ for (int x = 0; x < 3; x++)
+ {
+ mTabImg[mode].grid[a] = tabImage->getSubImage(
+ tabData[mode].gridX[x], tabData[mode].gridY[y],
+ tabData[mode].gridX[x + 1] - tabData[mode].gridX[x] + 1,
+ tabData[mode].gridY[y + 1] - tabData[mode].gridY[y] + 1);
+ a++;
+ }
+ }
+ mTabImg[mode].setAlpha(mAlpha);
+ }
+
+ // TextField images
+ auto deepBox = getImage("deepbox.png");
+ constexpr int gridx[4] = {0, 3, 28, 31};
+ constexpr int gridy[4] = {0, 3, 28, 31};
+ int a = 0;
+
+ for (int y = 0; y < 3; y++)
+ {
+ for (int x = 0; x < 3; x++)
+ {
+ mDeepBoxImageRect.grid[a] = deepBox->getSubImage(gridx[x],
+ gridy[y],
+ gridx[x + 1] - gridx[x] + 1,
+ gridy[y + 1] - gridy[y] + 1);
+ a++;
+ }
+ }
+
+ // CheckBox images
+ auto checkBox = getImage("checkbox.png");
+ mCheckBoxNormal.reset(checkBox->getSubImage(0, 0, 9, 10));
+ mCheckBoxChecked.reset(checkBox->getSubImage(9, 0, 9, 10));
+ mCheckBoxDisabled.reset(checkBox->getSubImage(18, 0, 9, 10));
+ mCheckBoxDisabledChecked.reset(checkBox->getSubImage(27, 0, 9, 10));
+ mCheckBoxNormalHi.reset(checkBox->getSubImage(36, 0, 9, 10));
+ mCheckBoxCheckedHi.reset(checkBox->getSubImage(45, 0, 9, 10));
+
+ // RadioButton images
+ mRadioNormal = getImage("radioout.png");
+ mRadioChecked = getImage("radioin.png");
+ mRadioDisabled = getImage("radioout.png");
+ mRadioDisabledChecked = getImage("radioin.png");
+ mRadioNormalHi = getImage("radioout_highlight.png");
+ mRadioCheckedHi = getImage("radioin_highlight.png");
+
+ // Slider images
+ int x, y, w, h, o1, o2;
+ auto slider = getImage("slider.png");
+ auto sliderHi = getImage("slider_hilight.png");
+
+ x = 0; y = 0;
+ w = 15; h = 6;
+ o1 = 4; o2 = 11;
+ hStart.reset(slider->getSubImage(x, y, o1 - x, h));
+ hMid.reset(slider->getSubImage(o1, y, o2 - o1, h));
+ hEnd.reset(slider->getSubImage(o2, y, w - o2 + x, h));
+ hStartHi.reset(sliderHi->getSubImage(x, y, o1 - x, h));
+ hMidHi.reset(sliderHi->getSubImage(o1, y, o2 - o1, h));
+ hEndHi.reset(sliderHi->getSubImage(o2, y, w - o2 + x, h));
+
+ x = 6; y = 8;
+ w = 9; h = 10;
+ hGrip.reset(slider->getSubImage(x, y, w, h));
+ hGripHi.reset(sliderHi->getSubImage(x, y, w, h));
+
+ x = 0; y = 6;
+ w = 6; h = 21;
+ o1 = 10; o2 = 18;
+ vStart.reset(slider->getSubImage(x, y, w, o1 - y));
+ vMid.reset(slider->getSubImage(x, o1, w, o2 - o1));
+ vEnd.reset(slider->getSubImage(x, o2, w, h - o2 + y));
+ vStartHi.reset(sliderHi->getSubImage(x, y, w, o1 - y));
+ vMidHi.reset(sliderHi->getSubImage(x, o1, w, o2 - o1));
+ vEndHi.reset(sliderHi->getSubImage(x, o2, w, h - o2 + y));
+
+ x = 6; y = 8;
+ w = 9; h = 10;
+ vGrip.reset(slider->getSubImage(x, y, w, h));
+ vGripHi.reset(sliderHi->getSubImage(x, y, w, h));
+
+ // ProgressBar and ScrollArea images
+ auto vscroll = getImage("vscroll_grey.png");
+ auto vscrollHi = getImage("vscroll_highlight.png");
+
+ constexpr int vsgridx[4] = {0, 4, 7, 11};
+ constexpr int vsgridy[4] = {0, 4, 15, 19};
+ a = 0;
+
+ for (int y = 0; y < 3; y++)
+ {
+ for (int x = 0; x < 3; x++)
+ {
+ mScrollBarMarker.grid[a] = vscroll->getSubImage(
+ vsgridx[x], vsgridy[y],
+ vsgridx[x + 1] - vsgridx[x],
+ vsgridy[y + 1] - vsgridy[y]);
+ mScrollBarMarkerHi.grid[a] = vscrollHi->getSubImage(
+ vsgridx[x], vsgridy[y],
+ vsgridx[x + 1] - vsgridx[x],
+ vsgridy[y + 1] - vsgridy[y]);
+ a++;
+ }
+ }
+
+ mScrollBarMarker.setAlpha(config.guiAlpha);
+ mScrollBarMarkerHi.setAlpha(config.guiAlpha);
+
+ // DropDown and ScrollArea buttons
+ mArrowButtons[ARROW_UP][0] = getImage("vscroll_up_default.png");
+ mArrowButtons[ARROW_DOWN][0] = getImage("vscroll_down_default.png");
+ mArrowButtons[ARROW_LEFT][0] = getImage("hscroll_left_default.png");
+ mArrowButtons[ARROW_RIGHT][0] = getImage("hscroll_right_default.png");
+ mArrowButtons[ARROW_UP][1] = getImage("vscroll_up_pressed.png");
+ mArrowButtons[ARROW_DOWN][1] = getImage("vscroll_down_pressed.png");
+ mArrowButtons[ARROW_LEFT][1] = getImage("hscroll_left_pressed.png");
+ mArrowButtons[ARROW_RIGHT][1] = getImage("hscroll_right_pressed.png");
+
+ mResizeGripImage = getImage("resize.png");
}
Theme::~Theme()
{
- delete_all(mSkins);
- delete_all(mProgressColors);
+ for (int mode = 0; mode < BUTTON_MODE_COUNT; ++mode)
+ {
+ std::for_each(mButton[mode].grid, mButton[mode].grid + 9,
+ dtor<Image*>());
+ }
+ delete[] mButton;
+
+ for (auto &imgRect : mTabImg)
+ std::for_each(imgRect.grid, imgRect.grid + 9, dtor<Image*>());
+
+ std::for_each(mDeepBoxImageRect.grid, mDeepBoxImageRect.grid + 9, dtor<Image*>());
+ std::for_each(mScrollBarMarker.grid, mScrollBarMarker.grid + 9, dtor<Image*>());
+ std::for_each(mScrollBarMarkerHi.grid, mScrollBarMarkerHi.grid + 9, dtor<Image*>());
}
-Theme *Theme::instance()
+const gcn::Color &Theme::getThemeColor(int type, int alpha)
{
- if (!mInstance)
- mInstance = new Theme;
-
- return mInstance;
+ return gui->getTheme()->getColor(type, alpha);
}
-void Theme::deleteInstance()
+const gcn::Color &Theme::getThemeColor(char c, bool &valid)
{
- delete mInstance;
- mInstance = nullptr;
+ return gui->getTheme()->getColor(c, valid);
}
gcn::Color Theme::getProgressColor(int type, float progress)
{
- DyePalette *dye = mInstance->mProgressColors[type];
+ const auto &dye = gui->getTheme()->mProgressColors[type];
int color[3] = {0, 0, 0};
dye->getColor(progress, color);
@@ -145,42 +358,226 @@ gcn::Color Theme::getProgressColor(int type, float progress)
return gcn::Color(color[0], color[1], color[2]);
}
-Skin *Theme::load(const std::string &filename, const std::string &defaultPath)
+Skin *Theme::load(const std::string &filename)
{
// Check if this skin was already loaded
auto skinIterator = mSkins.find(filename);
if (skinIterator != mSkins.end())
{
- Skin *skin = skinIterator->second;
+ auto &skin = skinIterator->second;
skin->instances++;
- return skin;
+ return skin.get();
}
- Skin *skin = readSkin(filename);
-
+ auto skin = readSkin(filename);
if (!skin)
{
- // Try falling back on the defaultPath if this makes sense
- if (filename != defaultPath)
- {
- logger->log("Error loading skin '%s', falling back on default.",
- filename.c_str());
+ logger->error(strprintf("Error: Loading default skin '%s' failed. "
+ "Make sure the skin file is valid.",
+ mThemePath.c_str()));
+ }
- skin = readSkin(defaultPath);
+ // Add the skin to the loaded skins
+ return (mSkins[filename] = std::move(skin)).get();
+}
+
+void Theme::drawButton(Graphics *graphics, const WidgetState &state) const
+{
+ int mode;
+
+ if (!state.enabled)
+ mode = BUTTON_MODE_DISABLED;
+ else if (state.selected)
+ mode = BUTTON_MODE_PRESSED;
+ else if (state.hovered || state.focused)
+ mode = BUTTON_MODE_HIGHLIGHTED;
+ else
+ mode = BUTTON_MODE_STANDARD;
+
+ graphics->drawImageRect(0, 0, state.width, state.height, mButton[mode]);
+}
+
+void Theme::drawTextFieldFrame(Graphics *graphics, const WidgetState &state) const
+{
+ graphics->drawImageRect(0, 0, state.width, state.height, mDeepBoxImageRect);
+}
+
+void Theme::drawTab(Graphics *graphics, const WidgetState &state) const
+{
+ int mode = TAB_STANDARD;
+
+ if (state.selected)
+ mode = TAB_SELECTED;
+ else if (state.hovered)
+ mode = TAB_HIGHLIGHTED;
+
+ graphics->drawImageRect(0, 0, state.width, state.height, mTabImg[mode]);
+}
+
+void Theme::drawCheckBox(gcn::Graphics *graphics, const WidgetState &state) const
+{
+ Image *box;
+
+ if (state.enabled)
+ {
+ if (state.selected)
+ {
+ if (state.hovered)
+ box = mCheckBoxCheckedHi.get();
+ else
+ box = mCheckBoxChecked.get();
}
+ else
+ {
+ if (state.hovered)
+ box = mCheckBoxNormalHi.get();
+ else
+ box = mCheckBoxNormal.get();
+ }
+ }
+ else
+ {
+ if (state.selected)
+ box = mCheckBoxDisabledChecked.get();
+ else
+ box = mCheckBoxDisabled.get();
+ }
- if (!skin)
+ static_cast<Graphics*>(graphics)->drawImage(box, 2, 2);
+}
+
+void Theme::drawRadioButton(gcn::Graphics *graphics, const WidgetState &state) const
+{
+ Image *box = nullptr;
+
+ if (state.enabled)
+ {
+ if (state.selected)
+ {
+ if (state.hovered)
+ box = mRadioCheckedHi;
+ else
+ box = mRadioChecked;
+ }
+ else
{
- logger->error(strprintf("Error: Loading default skin '%s' failed. "
- "Make sure the skin file is valid.",
- defaultPath.c_str()));
+ if (state.hovered)
+ box = mRadioNormalHi;
+ else
+ box = mRadioNormal;
}
}
+ else
+ {
+ if (state.selected)
+ box = mRadioDisabledChecked;
+ else
+ box = mRadioDisabled;
+ }
- // Add the skin to the loaded skins
- mSkins[filename] = skin;
+ static_cast<Graphics*>(graphics)->drawImage(box, 2, 2);
+}
- return skin;
+void Theme::drawSlider(Graphics *graphics, const WidgetState &state, int markerPosition) const
+{
+ auto start = state.hovered ? hStartHi.get() : hStart.get();
+ auto mid = state.hovered ? hMidHi.get() : hMid.get();
+ auto end = state.hovered ? hEndHi.get() : hEnd.get();
+ auto grip = state.hovered ? hGripHi.get() : hGrip.get();
+
+ int w = state.width;
+ int h = state.height;
+ int x = 0;
+ int y = (h - start->getHeight()) / 2;
+
+ graphics->drawImage(start, x, y);
+
+ w -= start->getWidth() + end->getWidth();
+ x += start->getWidth();
+
+ graphics->drawImagePattern(mid, x, y, w, mid->getHeight());
+
+ x += w;
+ graphics->drawImage(end, x, y);
+
+ graphics->drawImage(grip, markerPosition, (state.height - grip->getHeight()) / 2);
+}
+
+void Theme::drawDropDownFrame(Graphics *graphics, const WidgetState &state) const
+{
+ graphics->drawImageRect(0, 0, state.width, state.height, mDeepBoxImageRect);
+}
+
+void Theme::drawDropDownButton(Graphics *graphics, const WidgetState &state) const
+{
+ const auto buttonDir = state.selected ? ARROW_UP : ARROW_DOWN;
+ const Image *img = mArrowButtons[buttonDir][state.hovered];
+ graphics->drawImage(img, state.width - img->getHeight() - 2, 2);
+}
+
+void Theme::drawProgressBar(Graphics *graphics, const gcn::Rectangle &area,
+ const gcn::Color &color, float progress,
+ const std::string &text) const
+{
+ gcn::Font *oldFont = graphics->getFont();
+ gcn::Color oldColor = graphics->getColor();
+
+ graphics->drawImageRect(area, mScrollBarMarker);
+
+ // 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);
+}
+
+void Theme::drawScrollAreaFrame(Graphics *graphics, const WidgetState &state) const
+{
+ graphics->drawImageRect(0, 0, state.width, state.height, mDeepBoxImageRect);
+}
+
+void Theme::drawScrollAreaButton(Graphics *graphics,
+ ArrowButtonDirection dir,
+ bool pressed,
+ const gcn::Rectangle &dim) const
+{
+ const int state = pressed ? 1 : 0;
+ graphics->drawImage(mArrowButtons[dir][state], dim.x, dim.y);
+}
+
+void Theme::drawScrollAreaMarker(Graphics *graphics, bool hovered, const gcn::Rectangle &dim) const
+{
+ const auto &imageRect = hovered ? mScrollBarMarkerHi : mScrollBarMarker;
+ graphics->drawImageRect(dim.x, dim.y, dim.width, dim.height, imageRect);
+}
+
+int Theme::getSliderMarkerLength() const
+{
+ return hGrip->getWidth();
}
void Theme::setMinimumOpacity(float minimumOpacity)
@@ -194,8 +591,68 @@ void Theme::setMinimumOpacity(float minimumOpacity)
void Theme::updateAlpha()
{
+ const float alpha = std::max(config.guiAlpha, mMinimumOpacity);
+ if (mAlpha == alpha)
+ return;
+
+ mAlpha = alpha;
+
for (auto &skin : mSkins)
- skin.second->updateAlpha(mMinimumOpacity);
+ skin.second->updateAlpha(mAlpha);
+
+ for (int mode = 0; mode < BUTTON_MODE_COUNT; ++mode)
+ mButton[mode].setAlpha(mAlpha);
+
+ for (auto &t : mTabImg)
+ t.setAlpha(mAlpha);
+
+ mDeepBoxImageRect.setAlpha(mAlpha);
+
+ mCheckBoxNormal->setAlpha(mAlpha);
+ mCheckBoxChecked->setAlpha(mAlpha);
+ mCheckBoxDisabled->setAlpha(mAlpha);
+ mCheckBoxDisabledChecked->setAlpha(mAlpha);
+ mCheckBoxNormalHi->setAlpha(mAlpha);
+ mCheckBoxCheckedHi->setAlpha(mAlpha);
+
+ mRadioNormal->setAlpha(mAlpha);
+ mRadioChecked->setAlpha(mAlpha);
+ mRadioDisabled->setAlpha(mAlpha);
+ mRadioDisabledChecked->setAlpha(mAlpha);
+ mRadioNormalHi->setAlpha(mAlpha);
+ mRadioCheckedHi->setAlpha(mAlpha);
+
+ 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);
+
+ mScrollBarMarker.setAlpha(mAlpha);
+ mScrollBarMarkerHi.setAlpha(mAlpha);
+
+ mArrowButtons[ARROW_UP][0]->setAlpha(mAlpha);
+ mArrowButtons[ARROW_DOWN][0]->setAlpha(mAlpha);
+ mArrowButtons[ARROW_LEFT][0]->setAlpha(mAlpha);
+ mArrowButtons[ARROW_RIGHT][0]->setAlpha(mAlpha);
+ mArrowButtons[ARROW_UP][1]->setAlpha(mAlpha);
+ mArrowButtons[ARROW_DOWN][1]->setAlpha(mAlpha);
+ mArrowButtons[ARROW_LEFT][1]->setAlpha(mAlpha);
+ mArrowButtons[ARROW_RIGHT][1]->setAlpha(mAlpha);
+
+ mResizeGripImage->setAlpha(mAlpha);
}
void Theme::event(Event::Channel channel, const Event &event)
@@ -208,14 +665,14 @@ void Theme::event(Event::Channel channel, const Event &event)
}
}
-Skin *Theme::readSkin(const std::string &filename)
+std::unique_ptr<Skin> Theme::readSkin(const std::string &filename) const
{
if (filename.empty())
return nullptr;
logger->log("Loading skin '%s'.", filename.c_str());
- XML::Document doc(resolveThemePath(filename));
+ XML::Document doc(resolvePath(filename));
XML::Node rootNode = doc.rootNode();
if (!rootNode || rootNode.name() != "skinset")
@@ -232,7 +689,7 @@ Skin *Theme::readSkin(const std::string &filename)
logger->log("Theme::load(): <skinset> defines '%s' as a skin image.",
skinSetImage.c_str());
- auto dBorders = Theme::getImageFromTheme(skinSetImage);
+ auto dBorders = getImage(skinSetImage);
ImageRect border;
memset(&border, 0, sizeof(ImageRect));
@@ -301,48 +758,31 @@ Skin *Theme::readSkin(const std::string &filename)
logger->log("Finished loading skin.");
// Hard-coded for now until we update the above code to look for window buttons
- auto closeImage = Theme::getImageFromTheme("close_button.png");
- auto sticky = Theme::getImageFromTheme("sticky_button.png");
+ auto closeImage = getImage("close_button.png");
+ auto sticky = getImage("sticky_button.png");
Image *stickyImageUp = sticky->getSubImage(0, 0, 15, 15);
Image *stickyImageDown = sticky->getSubImage(15, 0, 15, 15);
- Skin *skin = new Skin(border, closeImage, stickyImageUp, stickyImageDown);
- skin->updateAlpha(mMinimumOpacity);
+ auto skin = std::make_unique<Skin>(border, closeImage, stickyImageUp, stickyImageDown);
+ skin->updateAlpha(mAlpha);
return skin;
}
-bool Theme::tryThemePath(std::string themePath)
-{
- if (!themePath.empty())
- {
- themePath = defaultThemePath + themePath;
-
- if (FS::exists(themePath))
- {
- mThemePath = themePath;
- return true;
- }
- }
-
- return false;
-}
-
-void Theme::prepareThemePath()
+std::string Theme::prepareThemePath()
{
- // Ensure the Theme object has been created
- instance();
+ initDefaultThemePath();
// Try theme from settings
- if (!tryThemePath(config.theme))
- // Try theme from branding
- if (!tryThemePath(branding.getStringValue("theme")))
- // Use default
- mThemePath = defaultThemePath;
+ auto themePath = findThemePath(config.theme);
+
+ // Try theme from branding
+ if (!themePath)
+ themePath = findThemePath(branding.getStringValue("theme"));
- instance()->loadColors(mThemePath);
+ return themePath.value_or(defaultThemePath);
}
-std::string Theme::resolveThemePath(const std::string &path)
+std::string Theme::resolvePath(const std::string &path) const
{
// Need to strip off any dye info for the existence tests
int pos = path.find('|');
@@ -352,23 +792,23 @@ std::string Theme::resolveThemePath(const std::string &path)
else
file = path;
- // Might be a valid path already
- if (FS::exists(file))
- return path;
-
// Try the theme
- file = getThemePath() + "/" + file;
+ file = mThemePath + "/" + file;
if (FS::exists(file))
- return getThemePath() + "/" + path;
+ return mThemePath + "/" + path;
// Backup
- return std::string(defaultThemePath) + "/" + path;
+ return defaultThemePath + "/" + path;
+}
+
+ResourceRef<Image> Theme::getImage(const std::string &path) const
+{
+ return ResourceManager::getInstance()->getImage(resolvePath(path));
}
ResourceRef<Image> Theme::getImageFromTheme(const std::string &path)
{
- ResourceManager *resman = ResourceManager::getInstance();
- return resman->getImage(resolveThemePath(path));
+ return gui->getTheme()->getImage(path);
}
static int readColorType(const std::string &type)
@@ -499,15 +939,9 @@ static int readProgressType(const std::string &type)
return -1;
}
-void Theme::loadColors(std::string file)
+void Theme::loadColors()
{
- if (file == defaultThemePath)
- return; // No need to reload
-
- if (file.empty())
- file = defaultThemePath;
-
- file += "/colors.xml";
+ std::string file = resolvePath("colors.xml");
XML::Document doc(file);
XML::Node root = doc.rootNode();
@@ -518,35 +952,30 @@ void Theme::loadColors(std::string file)
return;
}
- int type;
- std::string temp;
- gcn::Color color;
- GradientType grad;
-
for (auto node : root.children())
{
if (node.name() == "color")
{
- type = readColorType(node.getProperty("id", ""));
+ const int type = readColorType(node.getProperty("id", std::string()));
if (type < 0) // invalid or no type given
continue;
- temp = node.getProperty("color", "");
+ const std::string temp = node.getProperty("color", std::string());
if (temp.empty()) // no color set, so move on
continue;
- color = readColor(temp);
- grad = readColorGradient(node.getProperty("effect", ""));
+ const gcn::Color color = readColor(temp);
+ const GradientType grad = readColorGradient(node.getProperty("effect", std::string()));
mColors[type].set(type, color, grad, 10);
}
else if (node.name() == "progressbar")
{
- type = readProgressType(node.getProperty("id", ""));
+ const int type = readProgressType(node.getProperty("id", std::string()));
if (type < 0) // invalid or no type given
continue;
- mProgressColors[type] = new DyePalette(node.getProperty("color", ""));
+ mProgressColors[type] = std::make_unique<DyePalette>(node.getProperty("color", std::string()));
}
}
}
diff --git a/src/resources/theme.h b/src/resources/theme.h
index d914fb7f..6a55e6dd 100644
--- a/src/resources/theme.h
+++ b/src/resources/theme.h
@@ -27,9 +27,10 @@
#include "eventlistener.h"
#include "gui/palette.h"
-#include "resources/resource.h"
+#include "resources/image.h"
#include <map>
+#include <memory>
#include <string>
class DyePalette;
@@ -58,7 +59,7 @@ class Skin
* Returns the image used by a sticky button for this skin.
*/
Image *getStickyImage(bool state) const
- { return state ? mStickyImageDown : mStickyImageUp; }
+ { return state ? mStickyImageDown.get() : mStickyImageUp.get(); }
/**
* Returns the minimum width which can be used with this skin.
@@ -73,34 +74,39 @@ class Skin
/**
* Updates the alpha value of the skin
*/
- void updateAlpha(float minimumOpacityAllowed = 0.0f);
+ void updateAlpha(float alpha);
int instances = 0;
private:
ImageRect mBorder; /**< The window border and background */
ResourceRef<Image> mCloseImage; /**< Close Button Image */
- Image *mStickyImageUp; /**< Sticky Button Image */
- Image *mStickyImageDown; /**< Sticky Button Image */
+ std::unique_ptr<Image> mStickyImageUp; /**< Sticky Button Image */
+ std::unique_ptr<Image> mStickyImageDown; /**< Sticky Button Image */
};
class Theme : public Palette, public EventListener
{
public:
- static Theme *instance();
- static void deleteInstance();
+ static std::string prepareThemePath();
- static void prepareThemePath();
- static const std::string &getThemePath() { return mThemePath; }
+ Theme(const std::string &path);
+ ~Theme() override;
/**
- * Returns the patch to the given gui resource relative to the theme
+ * Returns the patch to the given GUI resource relative to the theme
* or, if it isn't in the theme, relative to 'graphics/gui'.
*/
- static std::string resolveThemePath(const std::string &path);
-
+ std::string resolvePath(const std::string &path) const;
static ResourceRef<Image> getImageFromTheme(const std::string &path);
+ enum ArrowButtonDirection {
+ ARROW_UP,
+ ARROW_DOWN,
+ ARROW_LEFT,
+ ARROW_RIGHT
+ };
+
enum ThemePalette {
TEXT,
SHADOW,
@@ -165,34 +171,58 @@ class Theme : public Palette, public EventListener
*
* @return the requested color
*/
- static const gcn::Color &getThemeColor(int type, int alpha = 255)
- {
- return mInstance->getColor(type, alpha);
- }
-
- static const gcn::Color &getThemeColor(char c, bool &valid)
- {
- return mInstance->getColor(c, valid);
- }
+ static const gcn::Color &getThemeColor(int type, int alpha = 255);
+ static const gcn::Color &getThemeColor(char c, bool &valid);
static gcn::Color getProgressColor(int type, float progress);
/**
* Loads a skin.
*/
- Skin *load(const std::string &filename,
- const std::string &defaultPath = getThemePath());
+ Skin *load(const std::string &filename);
+
+ struct WidgetState
+ {
+ int width = 0;
+ int height = 0;
+ bool enabled = true;
+ bool hovered = false;
+ bool selected = false;
+ bool focused = false;
+ };
+
+ void drawButton(Graphics *graphics, const WidgetState &state) const;
+ void drawTextFieldFrame(Graphics *graphics, const WidgetState &state) const;
+ void drawTab(Graphics *graphics, const WidgetState &state) const;
+ void drawCheckBox(gcn::Graphics *graphics, const WidgetState &state) const;
+ void drawRadioButton(gcn::Graphics *graphics, const WidgetState &state) const;
+ void drawSlider(Graphics *graphics, const WidgetState &state, int markerPosition) const;
+ void drawDropDownFrame(Graphics *graphics, const WidgetState &state) const;
+ void drawDropDownButton(Graphics *graphics, const WidgetState &state) const;
+ void drawProgressBar(Graphics *graphics,
+ const gcn::Rectangle &area,
+ const gcn::Color &color,
+ float progress,
+ const std::string &text = std::string()) const;
+ void drawScrollAreaFrame(Graphics *graphics, const WidgetState &state) const;
+ void drawScrollAreaButton(Graphics *graphics,
+ ArrowButtonDirection dir,
+ bool pressed,
+ const gcn::Rectangle &dim) const;
+ void drawScrollAreaMarker(Graphics *graphics, bool hovered, const gcn::Rectangle &dim) const;
+
+ int getSliderMarkerLength() const;
+ const Image *getResizeGripImage() const { return mResizeGripImage; }
/**
- * Updates the alpha values of all of the skins.
+ * Get the current GUI alpha value.
*/
- void updateAlpha();
+ int getGuiAlpha() const { return static_cast<int>(mAlpha * 255.0f); }
/**
* Get the minimum opacity allowed to skins.
*/
- float getMinimumOpacity() const
- { return mMinimumOpacity; }
+ float getMinimumOpacity() const { return mMinimumOpacity; }
/**
* Set the minimum opacity allowed to skins.
@@ -203,26 +233,57 @@ class Theme : public Palette, public EventListener
void event(Event::Channel channel, const Event &event) override;
private:
- Theme();
- ~Theme() override;
+ /**
+ * Updates the alpha values of all of the skins and images.
+ */
+ void updateAlpha();
- Skin *readSkin(const std::string &filename);
+ std::unique_ptr<Skin> readSkin(const std::string &filename) const;
- // Map containing all window skins
- std::map<std::string, Skin *> mSkins;
+ ResourceRef<Image> getImage(const std::string &path) const;
- static std::string mThemePath;
- static Theme *mInstance;
+ // Map containing all window skins
+ std::map<std::string, std::unique_ptr<Skin>> mSkins;
- static bool tryThemePath(std::string themePath);
+ std::string mThemePath;
- void loadColors(std::string file = std::string());
+ void loadColors();
/**
* Tells if the current skins opacity
* should not get less than the given value
*/
- float mMinimumOpacity;
-
- std::vector<DyePalette *> mProgressColors;
+ float mMinimumOpacity = 0.0f;
+ float mAlpha = 1.0;
+
+ std::vector<std::unique_ptr<DyePalette>> mProgressColors;
+
+ ImageRect *mButton; /**< Button state graphics */
+ ImageRect mTabImg[4]; /**< Tab state graphics */
+ ImageRect mDeepBoxImageRect;
+
+ std::unique_ptr<Image> mCheckBoxNormal;
+ std::unique_ptr<Image> mCheckBoxChecked;
+ std::unique_ptr<Image> mCheckBoxDisabled;
+ std::unique_ptr<Image> mCheckBoxDisabledChecked;
+ std::unique_ptr<Image> mCheckBoxNormalHi;
+ std::unique_ptr<Image> mCheckBoxCheckedHi;
+
+ ResourceRef<Image> mRadioNormal;
+ ResourceRef<Image> mRadioChecked;
+ ResourceRef<Image> mRadioDisabled;
+ ResourceRef<Image> mRadioDisabledChecked;
+ ResourceRef<Image> mRadioNormalHi;
+ ResourceRef<Image> mRadioCheckedHi;
+
+ std::unique_ptr<Image> hStart, hMid, hEnd, hGrip;
+ std::unique_ptr<Image> vStart, vMid, vEnd, vGrip;
+ std::unique_ptr<Image> hStartHi, hMidHi, hEndHi, hGripHi;
+ std::unique_ptr<Image> vStartHi, vMidHi, vEndHi, vGripHi;
+
+ ImageRect mScrollBarMarker;
+ ImageRect mScrollBarMarkerHi;
+ ResourceRef<Image> mArrowButtons[4][2];
+
+ ResourceRef<Image> mResizeGripImage;
};