diff options
author | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2025-03-24 14:28:55 +0100 |
---|---|---|
committer | Thorbjørn Lindeijer <bjorn@lindeijer.nl> | 2025-03-24 21:14:28 +0100 |
commit | c600e0fae271ed25d066b01149fbc148295edde8 (patch) | |
tree | 6b57ba0988d9d38f3bf760ccc208ec8298bfbdde /src/gui | |
parent | 5274cc92c1055a3209dfae7e5346bfe52c35e4a8 (diff) | |
download | mana-c600e0fae271ed25d066b01149fbc148295edde8.tar.gz mana-c600e0fae271ed25d066b01149fbc148295edde8.tar.bz2 mana-c600e0fae271ed25d066b01149fbc148295edde8.tar.xz mana-c600e0fae271ed25d066b01149fbc148295edde8.zip |
Expanded GUI theming capabilities
* Moved previously hardcoded values for frame size, padding and title bar
height to the Skin.
* Added support for rendering colored rectangles (used for scroll bar
background).
* Scroll bar width is now determined by its skin.
* Added separate skins for horizontal and vertical scroll bars and horizontal
and vertical scroll markers and added a skin for the shortcut box.
* Added support for hovered state on window close button.
Diffstat (limited to 'src/gui')
34 files changed, 451 insertions, 305 deletions
diff --git a/src/gui/equipmentwindow.cpp b/src/gui/equipmentwindow.cpp index 569bcf8b..ff3c6630 100644 --- a/src/gui/equipmentwindow.cpp +++ b/src/gui/equipmentwindow.cpp @@ -65,13 +65,14 @@ EquipmentWindow::EquipmentWindow(Equipment *equipment): setWindowName("Equipment"); setCloseButton(true); setSaveVisible(true); - setDefaultSize(180, 300, ImageRect::CENTER); + setContentSize(175, 290); + setDefaultSize(getWidth(), getHeight(), ImageRect::CENTER); loadWindowState(); mUnequip = new Button(_("Unequip"), "unequip", this); const gcn::Rectangle &area = getChildrenArea(); - mUnequip->setPosition(area.width - mUnequip->getWidth() - 5, - area.height - mUnequip->getHeight() - 5); + mUnequip->setPosition(area.width - mUnequip->getWidth() - getPadding(), + area.height - mUnequip->getHeight() - getPadding()); mUnequip->setEnabled(false); add(playerBox); @@ -108,7 +109,6 @@ EquipmentWindow::~EquipmentWindow() void EquipmentWindow::draw(gcn::Graphics *graphics) { Window::draw(graphics); - Window::drawChildren(graphics); // Draw equipment boxes auto *g = static_cast<Graphics*>(graphics); @@ -237,6 +237,8 @@ void EquipmentWindow::mousePressed(gcn::MouseEvent& mouseEvent) void EquipmentWindow::mouseMoved(gcn::MouseEvent &event) { + Window::mouseMoved(event); + const int x = event.getX(); const int y = event.getY(); @@ -261,6 +263,8 @@ void EquipmentWindow::mouseMoved(gcn::MouseEvent &event) void EquipmentWindow::mouseExited(gcn::MouseEvent &event) { + Window::mouseExited(event); + mItemPopup->setVisible(false); } diff --git a/src/gui/equipmentwindow.h b/src/gui/equipmentwindow.h index a5cda4e3..f46d1175 100644 --- a/src/gui/equipmentwindow.h +++ b/src/gui/equipmentwindow.h @@ -54,6 +54,8 @@ class EquipmentWindow : public Window, public gcn::ActionListener void action(const gcn::ActionEvent &event) override; void mousePressed(gcn::MouseEvent& mouseEvent) override; + void mouseMoved(gcn::MouseEvent &event) override; + void mouseExited(gcn::MouseEvent &event) override; /** * Loads the correct amount of displayed equip boxes. @@ -83,9 +85,6 @@ class EquipmentWindow : public Window, public gcn::ActionListener Equipment *mEquipment; private: - void mouseExited(gcn::MouseEvent &event) override; - void mouseMoved(gcn::MouseEvent &event) override; - int getBoxIndex(int x, int y) const; Item *getItem(int x, int y) const; std::string getSlotName(int x, int y) const; diff --git a/src/gui/helpwindow.cpp b/src/gui/helpwindow.cpp index e687e817..e0e21610 100644 --- a/src/gui/helpwindow.cpp +++ b/src/gui/helpwindow.cpp @@ -48,7 +48,6 @@ HelpWindow::HelpWindow(): setDefaultSize(500, 400, ImageRect::CENTER); mBrowserBox = new BrowserBox; - mBrowserBox->setFrameSize(4); mScrollArea = new ScrollArea(mBrowserBox); auto *okButton = new Button(_("Close"), "close", this); diff --git a/src/gui/npcdialog.cpp b/src/gui/npcdialog.cpp index 1df40d4f..e2e7b040 100644 --- a/src/gui/npcdialog.cpp +++ b/src/gui/npcdialog.cpp @@ -87,7 +87,6 @@ NpcDialog::NpcDialog(int npcId) // Setup output text box mTextBox = new BrowserBox(BrowserBox::AUTO_WRAP); mTextBox->setWrapIndent(15); - mTextBox->setFrameSize(2); mTextBox->setLinkHandler(mItemLinkHandler.get()); mTextBox->setEnableKeys(true); diff --git a/src/gui/setup_video.cpp b/src/gui/setup_video.cpp index 38602a5c..68fb6767 100644 --- a/src/gui/setup_video.cpp +++ b/src/gui/setup_video.cpp @@ -557,6 +557,6 @@ void Setup_Video::refreshScaleList() } mScaleListModel->setVideoSettings(mVideoSettings); - mScaleDropDown->setListModel(mScaleListModel.get()); + mScaleDropDown->adjustHeight(); mScaleDropDown->setSelected(mVideoSettings.userScale); } diff --git a/src/gui/setup_video.h b/src/gui/setup_video.h index 17b82e00..969d8e8f 100644 --- a/src/gui/setup_video.h +++ b/src/gui/setup_video.h @@ -29,6 +29,7 @@ #include <guichan/actionlistener.hpp> #include <guichan/keylistener.hpp> +class DropDown; class ResolutionListModel; class ScaleListModel; @@ -59,7 +60,7 @@ class Setup_Video : public SetupTab, public gcn::ActionListener, gcn::DropDown *mWindowModeDropDown; gcn::DropDown *mResolutionDropDown; - gcn::DropDown *mScaleDropDown; + DropDown *mScaleDropDown; gcn::CheckBox *mVSyncCheckBox; gcn::CheckBox *mOpenGLCheckBox; gcn::CheckBox *mCustomCursorCheckBox; diff --git a/src/gui/shortcutwindow.cpp b/src/gui/shortcutwindow.cpp index 7d299d2c..82c7678e 100644 --- a/src/gui/shortcutwindow.cpp +++ b/src/gui/shortcutwindow.cpp @@ -41,7 +41,11 @@ ShortcutWindow::ShortcutWindow(const std::string &title, setSaveVisible(true); setupWindow->registerWindowForReset(this); - const int border = getPadding() * 2; + auto scrollArea = new ScrollArea(content); + scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + scrollArea->setOpaque(false); + + const int border = (getPadding() + content->getFrameSize()) * 2; setMinWidth(content->getBoxWidth() + border); setMinHeight(content->getBoxHeight() + border + GRAB_MARGIN); setMaxWidth(content->getBoxWidth() * content->getMaxItems() + border); @@ -49,10 +53,6 @@ ShortcutWindow::ShortcutWindow(const std::string &title, setDefaultSize(getMinWidth(), getMaxHeight(), ImageRect::LOWER_RIGHT); - auto scrollArea = new ScrollArea(content); - scrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); - scrollArea->setOpaque(false); - place(0, 0, scrollArea, 5, 5).setPadding(0); Layout &layout = getLayout(); diff --git a/src/gui/updaterwindow.cpp b/src/gui/updaterwindow.cpp index 34169195..d05a9299 100644 --- a/src/gui/updaterwindow.cpp +++ b/src/gui/updaterwindow.cpp @@ -140,7 +140,6 @@ UpdaterWindow::UpdaterWindow(const std::string &updateHost, mPlayButton = new Button(_("Play"), "play", this); mBrowserBox->setLinkHandler(mLinkHandler.get()); - mBrowserBox->setFrameSize(4); mProgressBar->setSmoothProgress(false); mScrollArea->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); mPlayButton->setEnabled(false); diff --git a/src/gui/widgets/button.cpp b/src/gui/widgets/button.cpp index 215cb5a0..31fab2c4 100644 --- a/src/gui/widgets/button.cpp +++ b/src/gui/widgets/button.cpp @@ -109,7 +109,9 @@ void Button::removeButtonIcon() void Button::init() { - setFrameSize(0); + auto &skin = gui->getTheme()->getSkin(SkinType::Button); + setFrameSize(skin.frameSize); + setSpacing(skin.padding); if (mInstances == 0) { diff --git a/src/gui/widgets/container.h b/src/gui/widgets/container.h index 9ef805ad..fbdaa1d4 100644 --- a/src/gui/widgets/container.h +++ b/src/gui/widgets/container.h @@ -43,6 +43,9 @@ class Container : public gcn::Container Container(); ~Container() override; + // Overridden to disable drawing of the frame + void drawFrame(gcn::Graphics *graphics) override {} + protected: /** * Gets the layout handler for this container. diff --git a/src/gui/widgets/dropdown.cpp b/src/gui/widgets/dropdown.cpp index 1d54efd7..45c8e53f 100644 --- a/src/gui/widgets/dropdown.cpp +++ b/src/gui/widgets/dropdown.cpp @@ -31,12 +31,18 @@ #include "resources/theme.h" +#include <guichan/font.hpp> + DropDown::DropDown(gcn::ListModel *listModel): gcn::DropDown::DropDown(listModel, new ScrollArea, new ListBox(listModel)) { - setFrameSize(2); + auto &skin = gui->getTheme()->getSkin(SkinType::DropDownFrame); + setFrameSize(skin.frameSize); + mPadding = skin.padding; + + setHeight(getFont()->getHeight() + 2 * mPadding); } DropDown::~DropDown() @@ -59,13 +65,16 @@ void DropDown::draw(gcn::Graphics* graphics) { graphics->setFont(getFont()); graphics->setColor(Theme::getThemeColor(Theme::TEXT)); - graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()), 1, 0); + graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()), + mPadding, + mPadding); } if (isFocused()) { graphics->setColor(*highlightColor); - graphics->drawRectangle(gcn::Rectangle(0, 0, getWidth() - h, h)); + graphics->drawRectangle( + gcn::Rectangle(mPadding, mPadding, getWidth() - h - mPadding * 2, h - 2 * mPadding)); } drawButton(graphics); @@ -94,6 +103,39 @@ void DropDown::drawFrame(gcn::Graphics *graphics) gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::DropDownFrame, state); } +// Overridden so that we can take mPadding into account +void DropDown::adjustHeight() +{ + const int listBoxHeight = mListBox->getHeight(); + int height = getFont()->getHeight() + 2 * mPadding; + + // The addition/subtraction of 2 compensates for the seperation lines + // seperating the selected element view and the scroll area. + + if (mDroppedDown && getParent()) + { + int availableHeight = getParent()->getChildrenArea().height - getY(); + + if (listBoxHeight > availableHeight - height - 2) + { + mScrollArea->setHeight(availableHeight - height - 2); + height = availableHeight; + } + else + { + height += listBoxHeight + 2; + mScrollArea->setHeight(listBoxHeight); + } + } + + setHeight(height); + + mScrollArea->setWidth(getWidth()); + // Resize the ListBox to exactly fit the ScrollArea. + mListBox->setWidth(mScrollArea->getChildrenArea().width); + mScrollArea->setPosition(0, 0); +} + void DropDown::drawButton(gcn::Graphics *graphics) { WidgetState state(this); @@ -177,3 +219,32 @@ void DropDown::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent) mouseEvent.consume(); distributeActionEvent(); } + +// Overridden to call our version of adjustHeight +void DropDown::dropDown() +{ + if (!mDroppedDown) + { + mDroppedDown = true; + mFoldedUpHeight = getHeight(); + adjustHeight(); + + if (getParent()) + { + getParent()->moveToTop(this); + } + } + + mListBox->requestFocus(); +} + +// Overridden to call our version of adjustHeight +void DropDown::foldUp() +{ + if (mDroppedDown) + { + mDroppedDown = false; + adjustHeight(); + mInternalFocusHandler.focusNone(); + } +} diff --git a/src/gui/widgets/dropdown.h b/src/gui/widgets/dropdown.h index 53bfd0e2..a5e2e2f7 100644 --- a/src/gui/widgets/dropdown.h +++ b/src/gui/widgets/dropdown.h @@ -47,6 +47,8 @@ class DropDown : public gcn::DropDown void drawFrame(gcn::Graphics *graphics) override; + void adjustHeight(); + // Inherited from FocusListener void focusLost(const gcn::Event& event) override; @@ -70,4 +72,9 @@ class DropDown : public gcn::DropDown * @param graphics a Graphics object to draw with. */ void drawButton(gcn::Graphics *graphics) override; + + void dropDown() override; + void foldUp() override; + + int mPadding = 1; }; diff --git a/src/gui/widgets/emoteshortcutcontainer.cpp b/src/gui/widgets/emoteshortcutcontainer.cpp index 1aef6323..06d80ec2 100644 --- a/src/gui/widgets/emoteshortcutcontainer.cpp +++ b/src/gui/widgets/emoteshortcutcontainer.cpp @@ -21,11 +21,12 @@ #include "gui/widgets/emoteshortcutcontainer.h" -#include "configuration.h" #include "emoteshortcut.h" #include "graphics.h" #include "keyboardconfig.h" +#include "gui/gui.h" + #include "resources/emotedb.h" #include "resources/image.h" #include "resources/theme.h" @@ -34,40 +35,28 @@ static const int MAX_ITEMS = 12; EmoteShortcutContainer::EmoteShortcutContainer() { - addMouseListener(this); - addWidgetListener(this); - - mBackgroundImg = Theme::getImageFromTheme("item_shortcut_bgr.png"); - mMaxItems = std::min(EmoteDB::getEmoteCount(), MAX_ITEMS); - - if (mBackgroundImg) - { - mBoxHeight = mBackgroundImg->getHeight(); - mBoxWidth = mBackgroundImg->getWidth(); - } } void EmoteShortcutContainer::draw(gcn::Graphics *graphics) { - mBackgroundImg->setAlpha(config.guiAlpha); - auto *g = static_cast<Graphics*>(graphics); + auto theme = gui->getTheme(); graphics->setFont(getFont()); for (int i = 0; i < mMaxItems; i++) { - const int emoteX = (i % mGridWidth) * mBoxWidth; - const int emoteY = (i / mGridWidth) * mBoxHeight; - - g->drawImage(mBackgroundImg, emoteX, emoteY); + WidgetState state; + state.x = (i % mGridWidth) * mBoxWidth; + state.y = (i / mGridWidth) * mBoxHeight; + theme->drawSkin(g, SkinType::ShortcutBox, state); // Draw emote keyboard shortcut. const char *key = SDL_GetKeyName( keyboard.getKeyValue(KeyboardConfig::KEY_EMOTE_1 + i)); graphics->setColor(Theme::getThemeColor(Theme::TEXT)); - g->drawText(key, emoteX + 2, emoteY + 2, gcn::Graphics::LEFT); + g->drawText(key, state.x + 2, state.y + 2, gcn::Graphics::LEFT); int emoteId = emoteShortcut->getEmote(i); if (emoteId != -1) @@ -75,7 +64,7 @@ void EmoteShortcutContainer::draw(gcn::Graphics *graphics) if (auto image = EmoteDB::get(emoteId).image) { image->setAlpha(1.0f); - g->drawImage(image, emoteX + 2, emoteY + 10); + g->drawImage(image, state.x + 2, state.y + 10); } } } @@ -112,6 +101,7 @@ void EmoteShortcutContainer::mouseDragged(gcn::MouseEvent &event) emoteShortcut->removeEmote(index); } } + if (mEmoteMoved != -1) { mCursorPosX = event.getX(); @@ -123,7 +113,6 @@ void EmoteShortcutContainer::mouseDragged(gcn::MouseEvent &event) void EmoteShortcutContainer::mousePressed(gcn::MouseEvent &event) { const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) return; diff --git a/src/gui/widgets/itemcontainer.h b/src/gui/widgets/itemcontainer.h index 7c972347..0a8ac1e2 100644 --- a/src/gui/widgets/itemcontainer.h +++ b/src/gui/widgets/itemcontainer.h @@ -72,6 +72,9 @@ class ItemContainer : public gcn::Widget, */ void draw(gcn::Graphics *graphics) override; + // Overridden to disable drawing of the frame + void drawFrame(gcn::Graphics *graphics) override {} + // KeyListener void keyPressed(gcn::KeyEvent &event) override; void keyReleased(gcn::KeyEvent &event) override; diff --git a/src/gui/widgets/itemshortcutcontainer.cpp b/src/gui/widgets/itemshortcutcontainer.cpp index 594ad1ce..4d0641b1 100644 --- a/src/gui/widgets/itemshortcutcontainer.cpp +++ b/src/gui/widgets/itemshortcutcontainer.cpp @@ -21,7 +21,6 @@ #include "gui/widgets/itemshortcutcontainer.h" -#include "configuration.h" #include "graphics.h" #include "inventory.h" #include "item.h" @@ -39,47 +38,32 @@ #include "utils/stringutils.h" ItemShortcutContainer::ItemShortcutContainer() + : mItemPopup(new ItemPopup) { - addMouseListener(this); - addWidgetListener(this); - - mItemPopup = new ItemPopup; - - mBackgroundImg = Theme::getImageFromTheme("item_shortcut_bgr.png"); mMaxItems = itemShortcut->getItemCount(); - - if (mBackgroundImg) - { - mBoxHeight = mBackgroundImg->getHeight(); - mBoxWidth = mBackgroundImg->getWidth(); - } } -ItemShortcutContainer::~ItemShortcutContainer() -{ - delete mItemPopup; -} +ItemShortcutContainer::~ItemShortcutContainer() = default; void ItemShortcutContainer::draw(gcn::Graphics *graphics) { - mBackgroundImg->setAlpha(config.guiAlpha); - auto *g = static_cast<Graphics*>(graphics); + auto theme = gui->getTheme(); graphics->setFont(getFont()); for (int i = 0; i < mMaxItems; i++) { - const int itemX = (i % mGridWidth) * mBoxWidth; - const int itemY = (i / mGridWidth) * mBoxHeight; - - g->drawImage(mBackgroundImg, itemX, itemY); + WidgetState state; + state.x = (i % mGridWidth) * mBoxWidth; + state.y = (i / mGridWidth) * mBoxHeight; + theme->drawSkin(g, SkinType::ShortcutBox, state); // Draw item keyboard shortcut. const char *key = SDL_GetKeyName( keyboard.getKeyValue(KeyboardConfig::KEY_SHORTCUT_1 + i)); graphics->setColor(Theme::getThemeColor(Theme::TEXT)); - g->drawText(key, itemX + 2, itemY + 2, gcn::Graphics::LEFT); + g->drawText(key, state.x + 2, state.y + 2, gcn::Graphics::LEFT); if (itemShortcut->getItem(i) < 0) continue; @@ -101,11 +85,11 @@ void ItemShortcutContainer::draw(gcn::Graphics *graphics) caption = "Eq."; image->setAlpha(1.0f); - g->drawImage(image, itemX, itemY); + g->drawImage(image, state.x, state.y); if (item->isEquipped()) g->setColor(Theme::getThemeColor(Theme::ITEM_EQUIPPED)); - g->drawText(caption, itemX + mBoxWidth / 2, - itemY + mBoxHeight - 14, gcn::Graphics::CENTER); + g->drawText(caption, state.x + mBoxWidth / 2, + state.y + mBoxHeight - 14, gcn::Graphics::CENTER); } } } @@ -133,23 +117,20 @@ void ItemShortcutContainer::mouseDragged(gcn::MouseEvent &event) if (!mItemMoved && mItemClicked) { const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) return; const int itemId = itemShortcut->getItem(index); - if (itemId < 0) return; - Item *item = PlayerInfo::getInventory()->findItem(itemId); - - if (item) + if (Item *item = PlayerInfo::getInventory()->findItem(itemId)) { mItemMoved = item; itemShortcut->removeItem(index); } } + if (mItemMoved) { mCursorPosX = event.getX(); @@ -222,18 +203,14 @@ void ItemShortcutContainer::mouseReleased(gcn::MouseEvent &event) void ItemShortcutContainer::mouseMoved(gcn::MouseEvent &event) { const int index = getIndexFromGrid(event.getX(), event.getY()); - if (index == -1) return; const int itemId = itemShortcut->getItem(index); - if (itemId < 0) return; - Item *item = PlayerInfo::getInventory()->findItem(itemId); - - if (item) + if (Item *item = PlayerInfo::getInventory()->findItem(itemId)) { mItemPopup->setItem(item->getInfo()); mItemPopup->position(viewport->getMouseX(), viewport->getMouseY()); diff --git a/src/gui/widgets/itemshortcutcontainer.h b/src/gui/widgets/itemshortcutcontainer.h index e346b1b6..63d9e0ef 100644 --- a/src/gui/widgets/itemshortcutcontainer.h +++ b/src/gui/widgets/itemshortcutcontainer.h @@ -25,6 +25,8 @@ #include <guichan/mouselistener.hpp> +#include <memory> + class Image; class Item; class ItemPopup; @@ -68,5 +70,5 @@ class ItemShortcutContainer : public ShortcutContainer bool mItemClicked = false; Item *mItemMoved = nullptr; - ItemPopup *mItemPopup; + std::unique_ptr<ItemPopup> mItemPopup; }; diff --git a/src/gui/widgets/listbox.h b/src/gui/widgets/listbox.h index d5b4e759..40bc2fbc 100644 --- a/src/gui/widgets/listbox.h +++ b/src/gui/widgets/listbox.h @@ -42,6 +42,9 @@ class ListBox : public gcn::ListBox */ void draw(gcn::Graphics *graphics) override; + // Overridden to disable drawing of the frame + void drawFrame(gcn::Graphics *graphics) override {} + // Inherited from KeyListener void keyPressed(gcn::KeyEvent& keyEvent) override; diff --git a/src/gui/widgets/popup.cpp b/src/gui/widgets/popup.cpp index 8bbab948..b7c70fe5 100644 --- a/src/gui/widgets/popup.cpp +++ b/src/gui/widgets/popup.cpp @@ -42,7 +42,9 @@ Popup::Popup(const std::string &name, SkinType skinType) if (!windowContainer) throw GCN_EXCEPTION("Popup::Popup(): no windowContainer set"); - setPadding(6); + auto &skin = gui->getTheme()->getSkin(skinType); + setFrameSize(skin.frameSize); + setPadding(skin.padding); // Add this window to the window container windowContainer->add(this); @@ -63,10 +65,20 @@ void Popup::setWindowContainer(WindowContainer *wc) void Popup::draw(gcn::Graphics *graphics) { - gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), mSkinType, WidgetState(this)); + if (getFrameSize() == 0) + drawFrame(graphics); + drawChildren(graphics); } +void Popup::drawFrame(gcn::Graphics *graphics) +{ + WidgetState state(this); + state.width += getFrameSize() * 2; + state.height += getFrameSize() * 2; + gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), mSkinType, state); +} + gcn::Rectangle Popup::getChildrenArea() { return gcn::Rectangle(getPadding(), getPadding(), diff --git a/src/gui/widgets/popup.h b/src/gui/widgets/popup.h index 6a206672..012b55de 100644 --- a/src/gui/widgets/popup.h +++ b/src/gui/widgets/popup.h @@ -74,6 +74,11 @@ class Popup : public Container, public gcn::MouseListener void draw(gcn::Graphics *graphics) override; /** + * Draws the popup frame. + */ + void drawFrame(gcn::Graphics *graphics) override; + + /** * Sets the size of this popup. */ void setContentSize(int width, int height); diff --git a/src/gui/widgets/resizegrip.cpp b/src/gui/widgets/resizegrip.cpp index 69803d07..c802a405 100644 --- a/src/gui/widgets/resizegrip.cpp +++ b/src/gui/widgets/resizegrip.cpp @@ -30,10 +30,8 @@ ResizeGrip::ResizeGrip() { - const auto theme = gui->getTheme(); - const auto minWidth = theme->getMinWidth(SkinType::ResizeGrip); - const auto minHeight = theme->getMinHeight(SkinType::ResizeGrip); - setSize(minWidth + 2, minHeight + 2); + auto &skin = gui->getTheme()->getSkin(SkinType::ResizeGrip); + setSize(skin.getMinWidth() + skin.padding, skin.getMinHeight() + skin.padding); } void ResizeGrip::draw(gcn::Graphics *graphics) diff --git a/src/gui/widgets/scrollarea.cpp b/src/gui/widgets/scrollarea.cpp index 62c37c64..8ee6692f 100644 --- a/src/gui/widgets/scrollarea.cpp +++ b/src/gui/widgets/scrollarea.cpp @@ -27,7 +27,6 @@ ScrollArea::ScrollArea() { - addWidgetListener(this); init(); } @@ -47,10 +46,24 @@ void ScrollArea::init() // Draw background by default setOpaque(true); - setUpButtonScrollAmount(2); - setDownButtonScrollAmount(2); - setLeftButtonScrollAmount(2); - setRightButtonScrollAmount(2); + auto theme = gui->getTheme(); + + int minWidth = theme->getSkin(SkinType::ScrollAreaVBar).getMinWidth(); + if (minWidth > 0) + setScrollbarWidth(minWidth); + + if (auto content = getContent()) + content->setFrameSize(theme->getSkin(SkinType::ScrollArea).padding); + + // The base color is only used when rendering a square in the corner where + // the scrollbars meet. We disable rendering of this square by setting the + // base color to transparent. + setBaseColor(gcn::Color(0, 0, 0, 0)); + + setUpButtonScrollAmount(5); + setDownButtonScrollAmount(5); + setLeftButtonScrollAmount(5); + setRightButtonScrollAmount(5); } void ScrollArea::logic() @@ -99,6 +112,14 @@ void ScrollArea::logic() } } +void ScrollArea::draw(gcn::Graphics *graphics) +{ + if (getFrameSize() == 0) + drawFrame(graphics); + + gcn::ScrollArea::draw(graphics); +} + void ScrollArea::drawFrame(gcn::Graphics *graphics) { if (!mOpaque) @@ -116,7 +137,9 @@ void ScrollArea::drawFrame(gcn::Graphics *graphics) void ScrollArea::setOpaque(bool opaque) { mOpaque = opaque; - setFrameSize(mOpaque ? 2 : 0); + + auto &skin = gui->getTheme()->getSkin(SkinType::ScrollArea); + setFrameSize(mOpaque ? skin.frameSize : 0); } void ScrollArea::drawBackground(gcn::Graphics *graphics) @@ -146,30 +169,38 @@ void ScrollArea::drawRightButton(gcn::Graphics *graphics) void ScrollArea::drawVBar(gcn::Graphics *graphics) { - graphics->setColor(gcn::Color(0, 0, 0, 32)); - graphics->fillRectangle(getVerticalBarDimension()); - graphics->setColor(gcn::Color(255, 255, 255)); + WidgetState state(getVerticalBarDimension()); + if (mHasMouse && (mX > (getWidth() - getScrollbarWidth()))) + state.flags |= STATE_HOVERED; + + gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollAreaVBar, state); } void ScrollArea::drawHBar(gcn::Graphics *graphics) { - graphics->setColor(gcn::Color(0, 0, 0, 32)); - graphics->fillRectangle(getHorizontalBarDimension()); - graphics->setColor(gcn::Color(255, 255, 255)); + WidgetState state(getHorizontalBarDimension()); + if (mHasMouse && (mY > (getHeight() - getScrollbarWidth()))) + state.flags |= STATE_HOVERED; + + gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollAreaHBar, state); } void ScrollArea::drawVMarker(gcn::Graphics *graphics) { - drawMarker(static_cast<Graphics *>(graphics), - mHasMouse && (mX > (getWidth() - getScrollbarWidth())), - getVerticalMarkerDimension()); + WidgetState state(getVerticalMarkerDimension()); + if (mHasMouse && (mX > (getWidth() - getScrollbarWidth()))) + state.flags |= STATE_HOVERED; + + gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollAreaVMarker, state); } void ScrollArea::drawHMarker(gcn::Graphics *graphics) { - drawMarker(static_cast<Graphics *>(graphics), - mHasMouse && (mY > (getHeight() - getScrollbarWidth())), - getHorizontalMarkerDimension()); + WidgetState state(getHorizontalMarkerDimension()); + if (mHasMouse && (mY > (getHeight() - getScrollbarWidth()))) + state.flags |= STATE_HOVERED; + + gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollAreaHMarker, state); } void ScrollArea::drawButton(gcn::Graphics *graphics, @@ -177,30 +208,13 @@ void ScrollArea::drawButton(gcn::Graphics *graphics, bool pressed, const gcn::Rectangle &dim) { - WidgetState state; - state.x = dim.x; - state.y = dim.y; - state.width = dim.width; - state.height = dim.height; + WidgetState state(dim); if (pressed) state.flags |= STATE_SELECTED; gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), skinType, state); } -void ScrollArea::drawMarker(gcn::Graphics *graphics, bool hovered, const gcn::Rectangle &dim) -{ - WidgetState state; - state.x = dim.x; - state.y = dim.y; - state.width = dim.width; - state.height = dim.height; - if (hovered) - state.flags |= STATE_HOVERED; - - gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::ScrollBar, state); -} - void ScrollArea::mouseMoved(gcn::MouseEvent& event) { mX = event.getX(); @@ -216,12 +230,3 @@ void ScrollArea::mouseExited(gcn::MouseEvent& event) { mHasMouse = false; } - -void ScrollArea::widgetResized(const gcn::Event &event) -{ - 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 17f69548..314711bf 100644 --- a/src/gui/widgets/scrollarea.h +++ b/src/gui/widgets/scrollarea.h @@ -23,7 +23,6 @@ #include "resources/theme.h" -#include <guichan/widgetlistener.hpp> #include <guichan/widgets/scrollarea.hpp> /** @@ -35,7 +34,7 @@ * * \ingroup GUI */ -class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener +class ScrollArea : public gcn::ScrollArea { public: /** @@ -63,6 +62,11 @@ class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener void logic() override; /** + * Overridden to draw the frame if its size is 0. + */ + void draw(gcn::Graphics *graphics) override; + + /** * Draws the background and border of the scroll area. */ void drawFrame(gcn::Graphics *graphics) override; @@ -92,8 +96,6 @@ class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener */ void mouseExited(gcn::MouseEvent& event) override; - void widgetResized(const gcn::Event &event) override; - protected: /** * Initializes the scroll area. @@ -114,7 +116,6 @@ class ScrollArea : public gcn::ScrollArea, public gcn::WidgetListener SkinType skinType, bool pressed, const gcn::Rectangle &dim); - static void drawMarker(gcn::Graphics *graphics, bool hovered, const gcn::Rectangle &dim); int mX = 0; int mY = 0; diff --git a/src/gui/widgets/shortcutcontainer.cpp b/src/gui/widgets/shortcutcontainer.cpp index 4bcf3860..ccf4b082 100644 --- a/src/gui/widgets/shortcutcontainer.cpp +++ b/src/gui/widgets/shortcutcontainer.cpp @@ -21,7 +21,19 @@ #include "gui/widgets/shortcutcontainer.h" -ShortcutContainer::~ShortcutContainer() = default; +#include "gui/gui.h" + +#include "resources/theme.h" + +ShortcutContainer::ShortcutContainer() +{ + addMouseListener(this); + addWidgetListener(this); + + auto &skin = gui->getTheme()->getSkin(SkinType::ShortcutBox); + mBoxWidth = skin.getMinWidth(); + mBoxHeight = skin.getMinHeight(); +} void ShortcutContainer::widgetResized(const gcn::Event &event) { diff --git a/src/gui/widgets/shortcutcontainer.h b/src/gui/widgets/shortcutcontainer.h index 9998e188..35a88d7f 100644 --- a/src/gui/widgets/shortcutcontainer.h +++ b/src/gui/widgets/shortcutcontainer.h @@ -21,8 +21,6 @@ #pragma once -#include "resources/image.h" - #include <guichan/mouselistener.hpp> #include <guichan/widget.hpp> #include <guichan/widgetlistener.hpp> @@ -37,28 +35,25 @@ class ShortcutContainer : public gcn::Widget, public gcn::MouseListener { public: - ShortcutContainer() = default; - ~ShortcutContainer(); + ShortcutContainer(); /** * Draws the shortcuts */ void draw(gcn::Graphics *graphics) override = 0; + // Overridden to disable drawing of the frame + void drawFrame(gcn::Graphics *graphics) override {} + /** * Invoked when a widget changes its size. This is used to determine * the new height of the container. */ void widgetResized(const gcn::Event &event) override; - int getMaxItems() const - { return mMaxItems; } - - int getBoxWidth() const - { return mBoxWidth; } - - int getBoxHeight() const - { return mBoxHeight; } + int getMaxItems() const { return mMaxItems; } + int getBoxWidth() const { return mBoxWidth; } + int getBoxHeight() const { return mBoxHeight; } protected: /** @@ -70,8 +65,6 @@ class ShortcutContainer : public gcn::Widget, */ int getIndexFromGrid(int pointX, int pointY) const; - ResourceRef<Image> mBackgroundImg; - int mMaxItems = 0; int mBoxWidth = 0; int mBoxHeight = 0; diff --git a/src/gui/widgets/slider.cpp b/src/gui/widgets/slider.cpp index 7ad5aa60..dd476eb9 100644 --- a/src/gui/widgets/slider.cpp +++ b/src/gui/widgets/slider.cpp @@ -40,8 +40,9 @@ Slider::Slider(double scaleStart, double scaleEnd): void Slider::init() { - setFrameSize(0); - setMarkerLength(gui->getTheme()->getMinWidth(SkinType::SliderHandle)); + auto theme = gui->getTheme(); + setFrameSize(theme->getSkin(SkinType::Slider).frameSize); + setMarkerLength(theme->getMinWidth(SkinType::SliderHandle)); } void Slider::draw(gcn::Graphics *graphics) @@ -58,11 +59,6 @@ void Slider::draw(gcn::Graphics *graphics) theme->drawSkin(static_cast<Graphics*>(graphics), SkinType::SliderHandle, handleState); } -void Slider::drawMarker(gcn::Graphics *graphics) -{ - // Marker is drawn in Slider::draw -} - void Slider::mouseEntered(gcn::MouseEvent& event) { mHasMouse = true; diff --git a/src/gui/widgets/slider.h b/src/gui/widgets/slider.h index 142d3f6a..52b3b3af 100644 --- a/src/gui/widgets/slider.h +++ b/src/gui/widgets/slider.h @@ -49,10 +49,11 @@ class Slider : public gcn::Slider */ void draw(gcn::Graphics *graphics) override; - /** - * Draws the marker. - */ - void drawMarker(gcn::Graphics *graphics) override; + // Overridden to disable drawing of the frame + void drawFrame(gcn::Graphics *graphics) override {} + + // Marker is drawn in Slider::draw + void drawMarker(gcn::Graphics *graphics) override {} /** * Called when the mouse enteres the widget area. diff --git a/src/gui/widgets/tab.cpp b/src/gui/widgets/tab.cpp index 5779b561..3bfa405f 100644 --- a/src/gui/widgets/tab.cpp +++ b/src/gui/widgets/tab.cpp @@ -33,27 +33,33 @@ Tab::Tab() : mTabColor(&Theme::getThemeColor(Theme::TAB)) { - init(); + setFocusable(false); + + auto &skin = gui->getTheme()->getSkin(SkinType::Tab); + setFrameSize(skin.frameSize); + mPadding = skin.padding; + mLabel->setPosition(mPadding, mPadding); } -void Tab::init() +void Tab::setCaption(const std::string &caption) { - setFocusable(false); - setFrameSize(0); + mLabel->setCaption(caption); + mLabel->adjustSize(); + + setSize(mLabel->getWidth() + mPadding * 2, + mLabel->getHeight() + mPadding * 2); + + if (mTabbedArea) + static_cast<TabbedArea*>(mTabbedArea)->adjustTabPositions(); } void Tab::draw(gcn::Graphics *graphics) { - WidgetState state(this); - if (mHasMouse) - state.flags |= STATE_HOVERED; - if (mTabbedArea && mTabbedArea->isTabSelected(this)) - state.flags |= STATE_SELECTED; - - gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::Tab, state); + if (getFrameSize() == 0) + drawFrame(graphics); // if tab is selected, it doesnt need to highlight activity - if (state.flags & STATE_SELECTED) + if (mTabbedArea && mTabbedArea->isTabSelected(this)) mFlash = false; if (mFlash) @@ -65,6 +71,19 @@ void Tab::draw(gcn::Graphics *graphics) drawChildren(graphics); } +void Tab::drawFrame(gcn::Graphics *graphics) +{ + WidgetState state(this); + state.width += getFrameSize() * 2; + state.height += getFrameSize() * 2; + if (mHasMouse) + state.flags |= STATE_HOVERED; + if (mTabbedArea && mTabbedArea->isTabSelected(this)) + state.flags |= STATE_SELECTED; + + gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::Tab, state); +} + void Tab::setTabColor(const gcn::Color *color) { mTabColor = color; diff --git a/src/gui/widgets/tab.h b/src/gui/widgets/tab.h index 7d1365fd..d67321c6 100644 --- a/src/gui/widgets/tab.h +++ b/src/gui/widgets/tab.h @@ -35,11 +35,23 @@ class Tab : public gcn::Tab Tab(); /** - * Draw the tabbed area. + * Sets the caption of the tab. Shadowing gcn::Tab::setCaption, which + * shouldn't be used because it calls gcn::Tab::adjustSize, which does + * not take into account the padding. + */ + void setCaption(const std::string& caption); + + /** + * Draw the tab. */ void draw(gcn::Graphics *graphics) override; /** + * Draw the tab frame. + */ + void drawFrame(gcn::Graphics *graphics) override; + + /** * Set the normal color fo the tab's text. */ void setTabColor(const gcn::Color *color); @@ -54,9 +66,7 @@ class Tab : public gcn::Tab virtual void setCurrent() {} private: - /** Load images if no other instances exist yet */ - void init(); - const gcn::Color *mTabColor; bool mFlash = false; + int mPadding = 8; }; diff --git a/src/gui/widgets/table.cpp b/src/gui/widgets/table.cpp index 905bb166..7cddc1fa 100644 --- a/src/gui/widgets/table.cpp +++ b/src/gui/widgets/table.cpp @@ -21,8 +21,7 @@ #include "gui/widgets/table.h" -#include "configuration.h" - +#include "gui/gui.h" #include "gui/sdlinput.h" #include "resources/theme.h" @@ -33,13 +32,10 @@ #include <guichan/graphics.hpp> #include <guichan/key.hpp> -float GuiTable::mAlpha = 1.0; - class GuiTableActionListener : public gcn::ActionListener { public: - GuiTableActionListener(GuiTable *_table, gcn::Widget *_widget, int _row, int _column); - + GuiTableActionListener(GuiTable *table, gcn::Widget *widget, int row, int column); ~GuiTableActionListener() override; void action(const gcn::ActionEvent& actionEvent) override; @@ -269,13 +265,11 @@ void GuiTable::draw(gcn::Graphics* graphics) if (!mModel) return; - if (config.guiAlpha != mAlpha) - mAlpha = config.guiAlpha; + const auto guiAlpha = gui->getTheme()->getGuiAlpha(); if (mOpaque) { - graphics->setColor(Theme::getThemeColor(Theme::BACKGROUND, - (int)(mAlpha * 255.0f))); + graphics->setColor(Theme::getThemeColor(Theme::BACKGROUND, guiAlpha)); graphics->fillRectangle(gcn::Rectangle(0, 0, getWidth(), getHeight())); } @@ -320,8 +314,7 @@ void GuiTable::draw(gcn::Graphics* graphics) widget->setDimension(bounds); - graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT, - (int)(mAlpha * 255.0f))); + graphics->setColor(Theme::getThemeColor(Theme::HIGHLIGHT, guiAlpha)); if (mLinewiseMode && r == mSelectedRow && c == 0) { @@ -497,14 +490,12 @@ gcn::Widget *GuiTable::getWidgetAt(int x, int y) const if (row > -1 && column > -1) { - gcn::Widget *w = mModel->getElementAt(row, column); - if (w && w->isFocusable()) - return w; - else - return nullptr; // Grab the event locally + if (gcn::Widget *w = mModel->getElementAt(row, column)) + if (w->isFocusable()) + return w; } - else - return nullptr; + + return nullptr; // Grab the event locally } int GuiTable::getRowForY(int y) const @@ -516,8 +507,8 @@ int GuiTable::getRowForY(int y) const if (row < 0 || row >= mModel->getRows()) return -1; - else - return row; + + return row; } int GuiTable::getColumnForX(int x) const @@ -534,24 +525,23 @@ int GuiTable::getColumnForX(int x) const if (column < 0 || column >= mModel->getColumns()) return -1; - else - return column; + + return column; } void GuiTable::_setFocusHandler(gcn::FocusHandler* focusHandler) { gcn::Widget::_setFocusHandler(focusHandler); - if (mModel) + if (!mModel) + return; + + for (int r = 0; r < mModel->getRows(); ++r) { - for (int r = 0; r < mModel->getRows(); ++r) + for (int c = 0; c < mModel->getColumns(); ++c) { - for (int c = 0; c < mModel->getColumns(); ++c) - { - gcn::Widget *w = mModel->getElementAt(r, c); - if (w) - w->_setFocusHandler(focusHandler); - } + if (gcn::Widget *w = mModel->getElementAt(r, c)) + w->_setFocusHandler(focusHandler); } } } diff --git a/src/gui/widgets/table.h b/src/gui/widgets/table.h index 3fc2745b..81071267 100644 --- a/src/gui/widgets/table.h +++ b/src/gui/widgets/table.h @@ -40,10 +40,10 @@ class GuiTableActionListener; * * \ingroup GUI */ -class GuiTable : public gcn::Widget, - public gcn::MouseListener, - public gcn::KeyListener, - public TableModelListener +class GuiTable final : public gcn::Widget, + public gcn::MouseListener, + public gcn::KeyListener, + public TableModelListener { // so that the action listener can call distributeActionEvent friend class GuiTableActionListener; @@ -102,6 +102,9 @@ public: // Inherited from Widget void draw(gcn::Graphics* graphics) override; + // Overridden to disable drawing of the frame + void drawFrame(gcn::Graphics* graphics) override {} + virtual gcn::Widget *getWidgetAt(int x, int y) const; void moveToTop(gcn::Widget *child) override; @@ -158,8 +161,6 @@ private: bool mWrappingEnabled; bool mOpaque; - static float mAlpha; - /** * Holds the background color of the table. */ diff --git a/src/gui/widgets/textfield.cpp b/src/gui/widgets/textfield.cpp index 46fa18ae..04955ec8 100644 --- a/src/gui/widgets/textfield.cpp +++ b/src/gui/widgets/textfield.cpp @@ -39,21 +39,29 @@ TextField::TextField(const std::string &text, bool loseFocusOnTab) : gcn::TextField(text) , mLoseFocusOnTab(loseFocusOnTab) { - setFrameSize(2); + auto &skin = gui->getTheme()->getSkin(SkinType::TextField); + setFrameSize(skin.frameSize); + mPadding = skin.padding; + + setWidth(getFont()->getWidth(mText) + 2 * mPadding); + setHeight(getFont()->getHeight() + 2 * mPadding); + fixScroll(); } void TextField::draw(gcn::Graphics *graphics) { + if (getFrameSize() == 0) + drawFrame(graphics); + if (isFocused()) { drawCaret(graphics, - getFont()->getWidth(mText.substr(0, mCaretPosition)) - - mXScroll); + getFont()->getWidth(mText.substr(0, mCaretPosition)) - mXScroll); } graphics->setColor(Theme::getThemeColor(Theme::TEXT)); graphics->setFont(getFont()); - graphics->drawText(mText, 1 - mXScroll, 1); + graphics->drawText(mText, mPadding - mXScroll, mPadding); } void TextField::drawFrame(gcn::Graphics *graphics) @@ -99,6 +107,12 @@ int TextField::getValue() const return value; } +void TextField::drawCaret(gcn::Graphics *graphics, int x) +{ + graphics->setColor(getForegroundColor()); + graphics->drawLine(mPadding + x, mPadding, mPadding + x, getHeight() - mPadding); +} + void TextField::keyPressed(gcn::KeyEvent &keyEvent) { switch (keyEvent.getKey().getValue()) diff --git a/src/gui/widgets/textfield.h b/src/gui/widgets/textfield.h index 8ea8ec30..b84dd723 100644 --- a/src/gui/widgets/textfield.h +++ b/src/gui/widgets/textfield.h @@ -130,35 +130,39 @@ class TextField : public gcn::TextField * Sets the TextField's source of autocomplete. Passing null will * disable autocomplete. */ - void setAutoComplete(AutoCompleteLister *lister) - { mAutoComplete = lister; } + void setAutoComplete(AutoCompleteLister *lister) + { mAutoComplete = lister; } - /** + /** * Returns the TextField's source of autocomplete. */ - AutoCompleteLister *getAutoComplete() const - { return mAutoComplete; } + AutoCompleteLister *getAutoComplete() const + { return mAutoComplete; } - /** + /** * Sets the TextField's source of input history. */ - void setHistory(TextHistory *history) - { mHistory = history; } + void setHistory(TextHistory *history) + { mHistory = history; } - /** + /** * Returns the TextField's source of input history. */ - TextHistory *getHistory() const - { return mHistory; } + TextHistory *getHistory() const + { return mHistory; } + + protected: + void drawCaret(gcn::Graphics *graphics, int x) override; private: void autoComplete(); void handlePaste(); bool mNumeric = false; - int mMinimum; - int mMaximum; + int mMinimum = 0; + int mMaximum = 0; bool mLoseFocusOnTab; + int mPadding = 1; AutoCompleteLister *mAutoComplete = nullptr; diff --git a/src/gui/widgets/window.cpp b/src/gui/widgets/window.cpp index d47e1a29..fe31c4b0 100644 --- a/src/gui/widgets/window.cpp +++ b/src/gui/widgets/window.cpp @@ -56,9 +56,10 @@ Window::Window(const std::string &caption, bool modal, Window *parent) instances++; - setFrameSize(0); - setPadding(3); - setTitleBarHeight(20); + auto &skin = gui->getTheme()->getSkin(SkinType::Window); + setFrameSize(skin.frameSize); + setPadding(skin.padding); + setTitleBarHeight(skin.titleBarHeight); // Add this window to the window container windowContainer->add(this); @@ -98,45 +99,44 @@ void Window::setWindowContainer(WindowContainer *wc) void Window::draw(gcn::Graphics *graphics) { - auto g = static_cast<Graphics*>(graphics); - auto theme = gui->getTheme(); - - WidgetState state(this); - theme->drawSkin(g, SkinType::Window, state); + if (getFrameSize() == 0) + drawFrame(graphics); - // Draw title - if (mShowTitle) - { - g->setColor(Theme::getThemeColor(Theme::TEXT)); - g->setFont(getFont()); - g->drawText(getCaption(), 7, 5, gcn::Graphics::LEFT); - } - - const int closeButtonWidth = theme->getMinWidth(SkinType::ButtonClose); - const int stickyButtonWidth = theme->getMinWidth(SkinType::ButtonSticky); + auto g = static_cast<Graphics*>(graphics); - // Draw Close Button if (mCloseButton) { - state.x = state.width - closeButtonWidth - getPadding(); - state.y = getPadding(); - theme->drawSkin(g, SkinType::ButtonClose, state); + WidgetState state(getCloseButtonRect(), mCloseButtonHovered ? STATE_HOVERED : 0); + gui->getTheme()->drawSkin(g, SkinType::ButtonClose, state); } - // Draw Sticky Button if (mStickyButton) { - state.flags = mSticky ? STATE_SELECTED : 0; - state.x = state.width - stickyButtonWidth - getPadding(); - state.y = getPadding(); - if (mCloseButton) - state.x -= closeButtonWidth; - theme->drawSkin(g, SkinType::ButtonSticky, state); + WidgetState state(getStickyButtonRect(), mSticky ? STATE_SELECTED : 0); + gui->getTheme()->drawSkin(g, SkinType::ButtonSticky, state); } drawChildren(graphics); } +void Window::drawFrame(gcn::Graphics *graphics) +{ + auto g = static_cast<Graphics*>(graphics); + auto theme = gui->getTheme(); + + WidgetState state(this); + state.width += getFrameSize() * 2; + state.height += getFrameSize() * 2; + theme->drawSkin(g, SkinType::Window, state); + + if (mShowTitle) + { + g->setColor(Theme::getThemeColor(Theme::TEXT)); + g->setFont(getFont()); + g->drawText(getCaption(), 7 + getFrameSize(), 5 + getFrameSize(), gcn::Graphics::LEFT); + } +} + void Window::setContentSize(int width, int height) { width = width + 2 * getPadding(); @@ -273,9 +273,7 @@ void Window::widgetResized(const gcn::Event &event) void Window::widgetHidden(const gcn::Event &event) { if (gui) - { gui->setCursorType(Cursor::POINTER); - } WidgetListIterator it; @@ -335,45 +333,16 @@ void Window::mousePressed(gcn::MouseEvent &event) if (event.getButton() == gcn::MouseEvent::LEFT) { - auto theme = gui->getTheme(); - const int x = event.getX(); const int y = event.getY(); - const int closeButtonWidth = theme->getMinWidth(SkinType::ButtonClose); - const int closeButtonHeight = theme->getMinHeight(SkinType::ButtonClose); - const int stickyButtonWidth = theme->getMinWidth(SkinType::ButtonSticky); - const int stickyButtonHeight = theme->getMinHeight(SkinType::ButtonSticky); + if (mCloseButton && getCloseButtonRect().isPointInRect(x, y)) + close(); - // Handle close button - if (mCloseButton) - { - gcn::Rectangle closeButtonRect(getWidth() - closeButtonWidth - getPadding(), - getPadding(), - closeButtonWidth, - closeButtonHeight); - - if (closeButtonRect.isPointInRect(x, y)) - close(); - } - - // Handle sticky button - if (mStickyButton) - { - int stickyButtonX = getWidth() - stickyButtonWidth - getPadding(); - if (mCloseButton) - stickyButtonX -= closeButtonWidth; - - gcn::Rectangle stickyButtonRect(stickyButtonX, - getPadding(), - stickyButtonWidth, - stickyButtonHeight); - - if (stickyButtonRect.isPointInRect(x, y)) - setSticky(!isSticky()); - } + if (mStickyButton && getStickyButtonRect().isPointInRect(x, y)) + setSticky(!isSticky()); - // Handle window resizing + // Update resizing state and disable moving if we're resizing the window mouseResize = getResizeHandles(event); if (mouseResize) mMoved = false; @@ -396,10 +365,14 @@ void Window::mouseExited(gcn::MouseEvent &event) { if (mGrip && !mouseResize) gui->setCursorType(Cursor::POINTER); + + mCloseButtonHovered = false; } void Window::mouseMoved(gcn::MouseEvent &event) { + mCloseButtonHovered = false; + // Make sure BeingPopup is hidden (Viewport does not receive mouseExited) if (viewport) viewport->hideBeingPopup(); @@ -409,30 +382,36 @@ void Window::mouseMoved(gcn::MouseEvent &event) if (event.isConsumed()) return; - int resizeHandles = getResizeHandles(event); + mCloseButtonHovered = getCloseButtonRect().isPointInRect(event.getX(), event.getY()); + Cursor cursor = Cursor::POINTER; // Changes the custom mouse cursor based on its current position. - switch (resizeHandles) + if (!mCloseButtonHovered) { + switch (getResizeHandles(event)) + { case BOTTOM | RIGHT: case TOP | LEFT: - gui->setCursorType(Cursor::RESIZE_DOWN_RIGHT); + cursor = Cursor::RESIZE_DOWN_RIGHT; break; case BOTTOM | LEFT: case TOP | RIGHT: - gui->setCursorType(Cursor::RESIZE_DOWN_LEFT); + cursor = Cursor::RESIZE_DOWN_LEFT; break; case BOTTOM: case TOP: - gui->setCursorType(Cursor::RESIZE_DOWN); + cursor = Cursor::RESIZE_DOWN; break; case RIGHT: case LEFT: - gui->setCursorType(Cursor::RESIZE_ACROSS); + cursor = Cursor::RESIZE_ACROSS; break; default: - gui->setCursorType(Cursor::POINTER); + break; + } } + + gui->setCursorType(cursor); } void Window::mouseDragged(gcn::MouseEvent &event) @@ -693,6 +672,45 @@ int Window::getResizeHandles(gcn::MouseEvent &event) return resizeHandles; } +gcn::Rectangle Window::getCloseButtonRect() const +{ + auto theme = gui->getTheme(); + + auto &closeButtonSkin = theme->getSkin(SkinType::ButtonClose); + const int closeButtonWidth = closeButtonSkin.getMinWidth(); + const int closeButtonHeight = closeButtonSkin.getMinHeight(); + + return { + getWidth() - closeButtonWidth - closeButtonSkin.padding, + closeButtonSkin.padding, + closeButtonWidth, + closeButtonHeight + }; +} + +gcn::Rectangle Window::getStickyButtonRect() const +{ + auto theme = gui->getTheme(); + + auto &closeButtonSkin = theme->getSkin(SkinType::ButtonClose); + const int closeButtonWidth = closeButtonSkin.getMinWidth(); + + auto &stickyButtonSkin = theme->getSkin(SkinType::ButtonSticky); + const int stickyButtonWidth = stickyButtonSkin.getMinWidth(); + const int stickyButtonHeight = stickyButtonSkin.getMinHeight(); + + int stickyButtonX = getWidth() - stickyButtonWidth - stickyButtonSkin.padding; + if (mCloseButton) + stickyButtonX -= closeButtonWidth + closeButtonSkin.padding; + + return { + stickyButtonX, + stickyButtonSkin.padding, + stickyButtonWidth, + stickyButtonHeight + }; +} + int Window::getGuiAlpha() { float alpha = std::max(config.guiAlpha, diff --git a/src/gui/widgets/window.h b/src/gui/widgets/window.h index 916d767b..0e84bcb9 100644 --- a/src/gui/widgets/window.h +++ b/src/gui/widgets/window.h @@ -68,11 +68,16 @@ class Window : public gcn::Window, gcn::WidgetListener static void setWindowContainer(WindowContainer *windowContainer); /** - * Draws the window. + * Draws the window contents. */ void draw(gcn::Graphics *graphics) override; /** + * Draws the window frame. + */ + void drawFrame(gcn::Graphics *graphics) override; + + /** * Sets the size of this window. */ void setContentSize(int width, int height); @@ -375,6 +380,9 @@ class Window : public gcn::Window, gcn::WidgetListener */ int getResizeHandles(gcn::MouseEvent &event); + gcn::Rectangle getCloseButtonRect() const; + gcn::Rectangle getStickyButtonRect() const; + ResizeGrip *mGrip = nullptr; /**< Resize grip */ Window *mParent; /**< The parent window */ Layout *mLayout = nullptr; /**< Layout handler */ @@ -382,6 +390,7 @@ class Window : public gcn::Window, gcn::WidgetListener bool mShowTitle = true; /**< Window has a title bar */ bool mModal; /**< Window is modal */ bool mCloseButton = false; /**< Window has a close button */ + bool mCloseButtonHovered = false; bool mDefaultVisible = false; /**< Window's default visibility */ bool mSaveVisible = false; /**< Window will save visibility */ bool mStickyButton = false; /**< Window has a sticky button */ |