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