1 /*
2 This file is part of Warzone 2100.
3 Copyright (C) 1999-2004 Eidos Interactive
4 Copyright (C) 2005-2020 Warzone 2100 Project
5
6 Warzone 2100 is free software; you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation; either version 2 of the License, or
9 (at your option) any later version.
10
11 Warzone 2100 is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 GNU General Public License for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with Warzone 2100; if not, write to the Free Software
18 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20 /** @file
21 * Functions for the MultibuttonWidget widget
22 */
23
24 #include "lib/framework/frame.h"
25 #include "widget.h"
26 #include "widgint.h"
27 #include "multibutform.h"
28 #include "button.h"
29 #include "tip.h"
30 #include "lib/ivis_opengl/pieblitfunc.h"
31
MultibuttonWidget(int value)32 MultibuttonWidget::MultibuttonWidget(int value)
33 : W_FORM()
34 , label(nullptr)
35 , currentValue_(value)
36 , disabled(false)
37 , gap_(3)
38 , lockCurrent(false)
39 {
40 }
41
display(int xOffset,int yOffset)42 void MultibuttonWidget::display(int xOffset, int yOffset)
43 {
44 iV_ShadowBox(xOffset + x(), yOffset + y(), xOffset + x() + width() - 1, yOffset + y() + height() - 1, 0, WZCOL_MENU_BORDER, WZCOL_MENU_BORDER, WZCOL_MENU_BACKGROUND);
45 }
46
geometryChanged()47 void MultibuttonWidget::geometryChanged()
48 {
49 int s = width() - gap_;
50 switch (butAlign)
51 {
52 case ButtonAlignment::CENTER_ALIGN:
53 {
54 int width_of_all_buttons = 0;
55 for (size_t i = 0; i < buttons.size(); ++i)
56 {
57 if (i > 0)
58 {
59 width_of_all_buttons += gap_;
60 }
61 width_of_all_buttons += buttons[i].first->width();
62 }
63 if (width_of_all_buttons < width())
64 {
65 s = width() - gap_ - ((width() - width_of_all_buttons) / 2);
66 }
67 }
68 // fall-through
69 case ButtonAlignment::RIGHT_ALIGN:
70 for (auto i = buttons.crbegin(); i != buttons.crend(); ++i)
71 {
72 i->first->move(s - i->first->width(), (height() - i->first->height()) / 2);
73 s -= i->first->width() + gap_;
74 }
75 break;
76 }
77 if (label != nullptr)
78 {
79 label->setGeometry(gap_, 0, s - gap_, height());
80 }
81 }
82
setLabel(char const * text)83 void MultibuttonWidget::setLabel(char const *text)
84 {
85 attach(label = std::make_shared<W_LABEL>());
86 label->setString(text);
87 label->setCacheNeverExpires(true);
88
89 geometryChanged();
90 }
91
addButton(int value,const std::shared_ptr<W_BUTTON> & button)92 void MultibuttonWidget::addButton(int value, const std::shared_ptr<W_BUTTON>& button)
93 {
94 this->attach(button);
95 button->setState(value == currentValue_ && lockCurrent ? WBUT_LOCK : disabled ? WBUT_DISABLE : 0);
96 buttons.push_back(std::make_pair(button, value));
97
98 button->addOnClickHandler([value](W_BUTTON& button) {
99 auto pParent = std::static_pointer_cast<MultibuttonWidget>(button.parent());
100 assert(pParent != nullptr);
101 pParent->choose(value);
102 });
103
104 geometryChanged();
105 }
106
setButtonMinClickInterval(UDWORD interval)107 void MultibuttonWidget::setButtonMinClickInterval(UDWORD interval)
108 {
109 for (auto& button_pair : buttons)
110 {
111 if (button_pair.first)
112 {
113 button_pair.first->minClickInterval = interval;
114 }
115 }
116 }
117
setButtonAlignment(MultibuttonWidget::ButtonAlignment newAlignment)118 void MultibuttonWidget::setButtonAlignment(MultibuttonWidget::ButtonAlignment newAlignment)
119 {
120 if (newAlignment == butAlign)
121 {
122 return;
123 }
124 butAlign = newAlignment;
125 geometryChanged();
126 }
127
enable(bool enabled)128 void MultibuttonWidget::enable(bool enabled)
129 {
130 if (!enabled == disabled)
131 {
132 return;
133 }
134
135 disabled = !enabled;
136 stateChanged();
137 }
138
setGap(int gap)139 void MultibuttonWidget::setGap(int gap)
140 {
141 if (gap == gap_)
142 {
143 return;
144 }
145
146 gap_ = gap;
147 geometryChanged();
148 }
149
addOnChooseHandler(const W_ON_CHOOSE_FUNC & onChooseFunc)150 void MultibuttonWidget::addOnChooseHandler(const W_ON_CHOOSE_FUNC& onChooseFunc)
151 {
152 onChooseHandlers.push_back(onChooseFunc);
153 }
154
choose(int value)155 void MultibuttonWidget::choose(int value)
156 {
157 if (value == currentValue_ && lockCurrent)
158 {
159 return;
160 }
161
162 currentValue_ = value;
163 stateChanged();
164
165 /* Call all onChoose event handlers */
166 for (auto it = onChooseHandlers.begin(); it != onChooseHandlers.end(); it++)
167 {
168 auto onChoose = *it;
169 if (onChoose)
170 {
171 onChoose(*this, currentValue_);
172 }
173 }
174
175 if (auto lockedScreen = screenPointer.lock())
176 {
177 lockedScreen->setReturn(shared_from_this());
178 }
179 }
180
stateChanged()181 void MultibuttonWidget::stateChanged()
182 {
183 for (auto i = buttons.cbegin(); i != buttons.cend(); ++i)
184 {
185 i->first->setState(i->second == currentValue_ && lockCurrent ? WBUT_LOCK : disabled ? WBUT_DISABLE : 0);
186 }
187 }
188
MultichoiceWidget(int value)189 MultichoiceWidget::MultichoiceWidget(int value)
190 : MultibuttonWidget(value)
191 {
192 lockCurrent = true;
193 }
194
195