Mana
Loading...
Searching...
No Matches
dropdown.cpp
Go to the documentation of this file.
1/*
2 * The Mana Client
3 * Copyright (C) 2006-2009 The Mana World Development Team
4 * Copyright (C) 2009-2012 The Mana Developers
5 *
6 * This file is part of The Mana Client.
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License
19 * along with this program. If not, see <http://www.gnu.org/licenses/>.
20 */
21
23
24#include "graphics.h"
25
26#include "gui/gui.h"
27#include "gui/sdlinput.h"
28
29#include "gui/widgets/listbox.h"
31
32#include "resources/theme.h"
33
34#include <guichan/font.hpp>
35
36DropDown::DropDown(gcn::ListModel *listModel):
37 gcn::DropDown::DropDown(listModel,
38 new ScrollArea,
39 new ListBox(listModel))
40{
42 setFrameSize(skin.frameSize);
43 mPadding = skin.padding;
44
45 // Make sure to call the right setOpaque function
46 static_cast<ScrollArea*>(mScrollArea)->setOpaque(false);
47
48 setHeight(getFont()->getHeight() + 2 * mPadding);
49}
50
52{
53 delete mScrollArea;
54}
55
56void DropDown::draw(gcn::Graphics* graphics)
57{
58 const int h = mDroppedDown ? mFoldedUpHeight : getHeight();
59
60 const int alpha = gui->getTheme()->getGuiAlpha();
61 gcn::Color faceColor = getBaseColor();
62 faceColor.a = alpha;
63 auto highlightColor = Theme::getThemeColor(Theme::HIGHLIGHT);
64 highlightColor.a = alpha;
65 gcn::Color shadowColor = faceColor - 0x303030;
66 shadowColor.a = alpha;
67
68 if (mListBox->getListModel() && mListBox->getSelected() >= 0)
69 {
70 graphics->setFont(getFont());
72 graphics->drawText(mListBox->getListModel()->getElementAt(mListBox->getSelected()),
74 mPadding);
75 }
76
77 if (isFocused())
78 {
79 graphics->setColor(highlightColor);
80 graphics->drawRectangle(
81 gcn::Rectangle(mPadding, mPadding, getWidth() - h - mPadding * 2, h - 2 * mPadding));
82 }
83
85
86 if (mDroppedDown)
87 {
88 drawChildren(graphics);
89
90 // Draw two lines separating the ListBox with selected
91 // element view.
92 graphics->setColor(highlightColor);
93 graphics->drawLine(0, h, getWidth() - 1, h);
94 graphics->setColor(shadowColor);
95 graphics->drawLine(0, h + 1, getWidth() - 1, h + 1);
96 }
97}
98
99void DropDown::drawFrame(gcn::Graphics *graphics)
100{
101 const int bs = getFrameSize();
102
103 WidgetState state(this);
104 state.width += bs * 2;
105 state.height += bs * 2;
106
107 gui->getTheme()->drawSkin(static_cast<Graphics *>(graphics), SkinType::DropDownFrame, state);
108}
109
110// Overridden so that we can take mPadding into account
112{
113 const int listBoxHeight = mListBox->getHeight();
114 int height = getFont()->getHeight() + 2 * mPadding;
115
116 // The addition/subtraction of 4 compensates for the seperation lines
117 // seperating the selected element view and the scroll area.
118 const int extraHeight = 4;
119
120 if (mDroppedDown && getParent())
121 {
122 int availableHeight = getParent()->getChildrenArea().height - getY() - getFrameSize();
123
124 if (listBoxHeight > availableHeight - height - extraHeight)
125 {
126 mScrollArea->setHeight(availableHeight - height - extraHeight);
127 height = availableHeight;
128 }
129 else
130 {
131 height += listBoxHeight + extraHeight;
132 mScrollArea->setHeight(listBoxHeight);
133 }
134 }
135
136 setHeight(height);
137
138 mScrollArea->setWidth(getWidth());
139 // Resize the ListBox to exactly fit the ScrollArea, minus the one pixel padding.
140 mListBox->setWidth(mScrollArea->getChildrenArea().width - 2);
141 mScrollArea->setPosition(0, 0);
142}
143
144// Overridden to add more space for the separator
146{
147 if (mDroppedDown)
148 {
149 // Calculate the children area (with the two pixel border in mind)
150 return gcn::Rectangle(1,
151 mFoldedUpHeight + 3,
152 getWidth() - 2,
153 getHeight() - mFoldedUpHeight - 4);
154 }
155
156 return gcn::Rectangle();
157}
158
159void DropDown::drawButton(gcn::Graphics *graphics)
160{
161 WidgetState state(this);
162 if (mDroppedDown)
163 {
164 state.height = mFoldedUpHeight;
165 state.flags |= STATE_SELECTED;
166 }
167 if (mPushed)
168 state.flags |= STATE_HOVERED;
169
171
172 // FIXME: Needs support for setting alignment in the theme.
173 state.x = state.width - skin.getMinWidth();
174
175 skin.draw(static_cast<Graphics *>(graphics), state);
176}
177
178// -- KeyListener notifications
179void DropDown::keyPressed(gcn::KeyEvent& keyEvent)
180{
181 if (keyEvent.isConsumed())
182 return;
183
184 const gcn::Key key = keyEvent.getKey();
185 const int selectedIndex = getSelected();
186
187 if (key.getValue() == Key::ENTER || key.getValue() == Key::SPACE)
188 dropDown();
189 else if (key.getValue() == Key::UP)
190 setSelected(getSelected() - 1);
191 else if (key.getValue() == Key::DOWN)
192 setSelected(getSelected() + 1);
193 else if (key.getValue() == Key::HOME)
194 setSelected(0);
195 else if (key.getValue() == Key::END)
196 setSelected(mListBox->getListModel()->getNumberOfElements() - 1);
197 else
198 return;
199
200 keyEvent.consume();
201
202 if (getSelected() != selectedIndex)
203 distributeActionEvent();
204}
205
206void DropDown::focusLost(const gcn::Event& event)
207{
208 gcn::DropDown::focusLost(event);
209 releaseModalMouseInputFocus();
210}
211
212void DropDown::mousePressed(gcn::MouseEvent& mouseEvent)
213{
214 gcn::DropDown::mousePressed(mouseEvent);
215
216 if (0 <= mouseEvent.getY() && mouseEvent.getY() < getHeight() &&
217 mouseEvent.getX() >= 0 && mouseEvent.getX() < getWidth() &&
218 mouseEvent.getButton() == gcn::MouseEvent::LEFT && mDroppedDown &&
219 mouseEvent.getSource() == mListBox)
220 {
221 mPushed = false;
222 foldUp();
223 releaseModalMouseInputFocus();
224 distributeActionEvent();
225 }
226}
227
228void DropDown::mouseWheelMovedUp(gcn::MouseEvent& mouseEvent)
229{
230 setSelected(getSelected() - 1);
231 mouseEvent.consume();
232 distributeActionEvent();
233}
234
235void DropDown::mouseWheelMovedDown(gcn::MouseEvent& mouseEvent)
236{
237 setSelected(getSelected() + 1);
238 mouseEvent.consume();
239 distributeActionEvent();
240}
241
242// Overridden to call our version of adjustHeight
244{
245 if (!mDroppedDown)
246 {
247 mDroppedDown = true;
248 mFoldedUpHeight = getHeight();
249 adjustHeight();
250
251 if (getParent())
252 {
253 getParent()->moveToTop(this);
254 }
255 }
256
257 mListBox->requestFocus();
258}
259
260// Overridden to call our version of adjustHeight
262{
263 if (mDroppedDown)
264 {
265 mDroppedDown = false;
266 adjustHeight();
267 mInternalFocusHandler.focusNone();
268 }
269}
A drop down box from which you can select different values.
Definition dropdown.h:34
void mouseWheelMovedDown(gcn::MouseEvent &mouseEvent) override
Definition dropdown.cpp:235
void mouseWheelMovedUp(gcn::MouseEvent &mouseEvent) override
Definition dropdown.cpp:228
void mousePressed(gcn::MouseEvent &mouseEvent) override
Definition dropdown.cpp:212
~DropDown() override
Definition dropdown.cpp:51
void dropDown() override
Definition dropdown.cpp:243
void adjustHeight()
Definition dropdown.cpp:111
void focusLost(const gcn::Event &event) override
Definition dropdown.cpp:206
void drawButton(gcn::Graphics *graphics) override
Draws the button with the little down arrow.
Definition dropdown.cpp:159
DropDown(gcn::ListModel *listModel=nullptr)
Contructor.
Definition dropdown.cpp:36
void drawFrame(gcn::Graphics *graphics) override
Definition dropdown.cpp:99
void keyPressed(gcn::KeyEvent &keyEvent) override
Definition dropdown.cpp:179
gcn::Rectangle getChildrenArea() override
Definition dropdown.cpp:145
int mPadding
Definition dropdown.h:83
void foldUp() override
Definition dropdown.cpp:261
void draw(gcn::Graphics *graphics) override
Definition dropdown.cpp:56
A central point of control for graphics.
Definition graphics.h:78
void drawText(const std::string &text, int x, int y, gcn::Graphics::Alignment alignment, const gcn::Color &color, gcn::Font *font, bool outline=false, bool shadow=false, const std::optional< gcn::Color > &outlineColor={}, const std::optional< gcn::Color > &shadowColor={})
Definition graphics.cpp:176
void setColor(const gcn::Color &color) override
Definition graphics.h:255
Theme * getTheme() const
The global GUI theme.
Definition gui.h:138
A list box, meant to be used inside a scroll area.
Definition listbox.h:36
A scroll area.
Definition scrollarea.h:38
int getGuiAlpha() const
Get the current GUI alpha value.
Definition theme.h:321
const Skin & getSkin(SkinType skinType) const
Definition theme.cpp:434
static const gcn::Color & getThemeColor(int type)
Gets the color associated with the type in the default palette (0).
Definition theme.cpp:313
@ HIGHLIGHT
Definition theme.h:231
@ TEXT
Definition theme.h:214
void drawSkin(Graphics *graphics, SkinType type, const WidgetState &state) const
Definition theme.cpp:373
Graphics * graphics
Definition client.cpp:104
Gui * gui
The GUI system.
Definition gui.cpp:50
@ ENTER
Definition sdlinput.h:78
@ SPACE
Definition sdlinput.h:76
@ HOME
Definition sdlinput.h:91
@ UP
Definition sdlinput.h:121
@ DOWN
Definition sdlinput.h:122
@ END
Definition sdlinput.h:94
uint8_t flags
Definition theme.h:150
int width
Definition theme.h:148
int height
Definition theme.h:149
@ STATE_HOVERED
Definition theme.h:105
@ STATE_SELECTED
Definition theme.h:106
@ DropDownButton