1 /*
2 * The ManaPlus Client
3 * Copyright (C) 2008 Douglas Boffey <dougaboffey@netscape.net>
4 * Copyright (C) 2011-2019 The ManaPlus Developers
5 * Copyright (C) 2019-2021 Andrei Karas
6 *
7 * This file is part of The ManaPlus Client.
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program. If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "gui/widgets/tabs/setup_colors.h"
24
25 #include "gui/gui.h"
26 #include "gui/userpalette.h"
27
28 #include "gui/fonts/font.h"
29
30 #include "gui/widgets/browserbox.h"
31 #include "gui/widgets/containerplacer.h"
32 #include "gui/widgets/createwidget.h"
33 #include "gui/widgets/label.h"
34 #include "gui/widgets/layouthelper.h"
35 #include "gui/widgets/listbox.h"
36 #include "gui/widgets/scrollarea.h"
37 #include "gui/widgets/slider.h"
38 #include "gui/widgets/textfield.h"
39 #include "gui/widgets/textpreview.h"
40
41 #include "utils/delete2.h"
42 #include "utils/gettext.h"
43 #include "utils/stringutils.h"
44
45 #include <cmath>
46
47 #include "debug.h"
48
49 const char *const Setup_Colors::rawmsg =
50 // TRANSLATORS: color selection preview message
51 N_("This is what the color looks like");
52
Setup_Colors(const Widget2 * const widget)53 Setup_Colors::Setup_Colors(const Widget2 *const widget) :
54 SetupTab(widget),
55 SelectionListener(),
56 mColorBox(CREATEWIDGETR(ListBox, this, userPalette, "")),
57 mScroll(new ScrollArea(this, mColorBox,
58 Opaque_true, "setup_colors_background.xml")),
59 mPreview(new BrowserBox(this, Opaque_true,
60 "browserbox.xml")),
61 mTextPreview(new TextPreview(this, gettext(rawmsg))),
62 mPreviewBox(new ScrollArea(this, mPreview, Opaque_true,
63 "setup_colors_preview_background.xml")),
64 mSelected(-1),
65 // TRANSLATORS: colors tab. label.
66 mGradTypeLabel(new Label(this, _("Type:"))),
67 mGradTypeSlider(new Slider(this, 0.0, 3.0, 1.0)),
68 mGradTypeText(new Label(this)),
69 // TRANSLATORS: colors tab. label.
70 mGradDelayLabel(new Label(this, _("Delay:"))),
71 mGradDelaySlider(new Slider(this, 20.0, 100.0, 1.0)),
72 mGradDelayText(new TextField(this, std::string(), LoseFocusOnTab_true,
73 nullptr, std::string(), false)),
74 // TRANSLATORS: colors tab. label.
75 mRedLabel(new Label(this, _("Red:"))),
76 mRedSlider(new Slider(this, 0.0, 255.0, 1.0)),
77 mRedText(new TextField(this, std::string(), LoseFocusOnTab_true,
78 nullptr, std::string(), false)),
79 // TRANSLATORS: colors tab. label.
80 mGreenLabel(new Label(this, _("Green:"))),
81 mGreenSlider(new Slider(this, 0.0, 255.0, 1.0)),
82 mGreenText(new TextField(this, std::string(), LoseFocusOnTab_true,
83 nullptr, std::string(), false)),
84 // TRANSLATORS: colors tab. label.
85 mBlueLabel(new Label(this, _("Blue:"))),
86 mBlueSlider(new Slider(this, 0.0, 255.0, 1.0)),
87 mBlueText(new TextField(this, std::string(), LoseFocusOnTab_true,
88 nullptr, std::string(), false))
89 {
90 // TRANSLATORS: settings colors tab name
91 setName(_("Colors"));
92 mColorBox->addSelectionListener(this);
93 mScroll->setHorizontalScrollPolicy(ScrollArea::SHOW_NEVER);
94 mPreview->setOpaque(Opaque_false);
95
96 // don't do anything with links
97 mPreview->setLinkHandler(nullptr);
98
99 mPreviewBox->setHeight(20);
100 mPreviewBox->setScrollPolicy(ScrollArea::SHOW_NEVER,
101 ScrollArea::SHOW_NEVER);
102
103 mGradTypeSlider->setWidth(180);
104 mGradTypeSlider->setActionEventId("slider_grad");
105 mGradTypeSlider->setValue(0);
106 mGradTypeSlider->addActionListener(this);
107 mGradTypeSlider->setEnabled(false);
108
109 // TRANSLATORS: color type
110 std::string longText = _("Static");
111
112 const Font *const font = getFont();
113 // TRANSLATORS: color type
114 if (getFont()->getWidth(_("Pulse")) > font->getWidth(longText))
115 {
116 // TRANSLATORS: color type
117 longText = _("Pulse");
118 }
119 // TRANSLATORS: color type
120 if (getFont()->getWidth(_("Rainbow")) > font->getWidth(longText))
121 {
122 // TRANSLATORS: color type
123 longText = _("Rainbow");
124 }
125 // TRANSLATORS: color type
126 if (getFont()->getWidth(_("Spectrum")) > font->getWidth(longText))
127 {
128 // TRANSLATORS: color type
129 longText = _("Spectrum");
130 }
131
132 mGradTypeText->setCaption(longText);
133
134 mGradDelayText->setWidth(40);
135 mGradDelayText->setRange(20, 100);
136 mGradDelayText->setNumeric(true);
137 mGradDelayText->setEnabled(false);
138
139 mGradDelaySlider->setWidth(180);
140 mGradDelaySlider->setValue(mGradDelayText->getValue());
141 mGradDelaySlider->setActionEventId("slider_graddelay");
142 mGradDelaySlider->addActionListener(this);
143 mGradDelaySlider->setEnabled(false);
144
145 mRedText->setWidth(40);
146 mRedText->setRange(0, 255);
147 mRedText->setNumeric(true);
148 mRedText->setEnabled(false);
149
150 mRedSlider->setWidth(180);
151 mRedSlider->setValue(mRedText->getValue());
152 mRedSlider->setActionEventId("slider_red");
153 mRedSlider->addActionListener(this);
154 mRedSlider->setEnabled(false);
155
156 mGreenText->setWidth(40);
157 mGreenText->setRange(0, 255);
158 mGreenText->setNumeric(true);
159 mGreenText->setEnabled(false);
160
161 mGreenSlider->setWidth(180);
162 mGreenSlider->setValue(mGreenText->getValue());
163 mGreenSlider->setActionEventId("slider_green");
164 mGreenSlider->addActionListener(this);
165 mGreenSlider->setEnabled(false);
166
167 mBlueText->setWidth(40);
168 mBlueText->setRange(0, 255);
169 mBlueText->setNumeric(true);
170 mBlueText->setEnabled(false);
171
172 mBlueSlider->setWidth(180);
173 mBlueSlider->setValue(mBlueText->getValue());
174 mBlueSlider->setActionEventId("slider_blue");
175 mBlueSlider->addActionListener(this);
176 mBlueSlider->setEnabled(false);
177
178 setOpaque(Opaque_false);
179
180 // Do the layout
181 LayoutHelper h(this);
182 ContainerPlacer place = h.getPlacer(0, 0);
183
184 place(0, 0, mScroll, 6, 6).setPadding(2);
185 place(0, 6, mPreviewBox, 6, 1).setPadding(2);
186 place(0, 7, mGradTypeLabel, 3, 1);
187 place(3, 7, mGradTypeSlider, 1, 1);
188 place(4, 7, mGradTypeText, 2, 1).setPadding(1);
189 place(0, 8, mRedLabel, 3, 1);
190 place(3, 8, mRedSlider, 1, 1);
191 place(5, 8, mRedText, 1, 1).setPadding(1);
192 place(0, 9, mGreenLabel, 3, 1);
193 place(3, 9, mGreenSlider, 1, 1);
194 place(5, 9, mGreenText, 1, 1).setPadding(1);
195 place(0, 10, mBlueLabel, 3, 1);
196 place(3, 10, mBlueSlider, 1, 1);
197 place(5, 10, mBlueText, 1, 1).setPadding(1);
198 place(0, 11, mGradDelayLabel, 3, 1);
199 place(3, 11, mGradDelaySlider, 1, 1);
200 place(5, 11, mGradDelayText, 1, 1).setPadding(1);
201
202 mGradTypeText->setCaption("");
203
204 setDimension(Rect(0, 0, 365, 350));
205 }
206
~Setup_Colors()207 Setup_Colors::~Setup_Colors()
208 {
209 if ((mPreviewBox != nullptr) && mPreviewBox->getContent() == mPreview)
210 delete2(mTextPreview)
211 else
212 delete2(mPreview)
213 }
214
action(const ActionEvent & event)215 void Setup_Colors::action(const ActionEvent &event)
216 {
217 const std::string &eventId = event.getId();
218 if (eventId == "slider_grad")
219 {
220 updateGradType();
221 updateColor();
222 return;
223 }
224
225 if (eventId == "slider_graddelay")
226 {
227 mGradDelayText->setText(toString(
228 std::floor(mGradDelaySlider->getValue())));
229 updateColor();
230 return;
231 }
232 if (eventId == "slider_red")
233 {
234 mRedText->setText(toString(std::floor(mRedSlider->getValue())));
235 updateColor();
236 return;
237 }
238 if (eventId == "slider_green")
239 {
240 mGreenText->setText(toString(std::floor(mGreenSlider->getValue())));
241 updateColor();
242 return;
243 }
244 if (eventId == "slider_blue")
245 {
246 mBlueText->setText(toString(std::floor(mBlueSlider->getValue())));
247 updateColor();
248 return;
249 }
250 }
251
valueChanged(const SelectionEvent & event A_UNUSED)252 void Setup_Colors::valueChanged(const SelectionEvent &event A_UNUSED)
253 {
254 if (userPalette == nullptr)
255 return;
256
257 mSelected = mColorBox->getSelected();
258 const UserColorIdT type = static_cast<UserColorIdT>(
259 userPalette->getColorTypeAt(mSelected));
260 const Color *col = &userPalette->getColor(type, 255U);
261 const GradientTypeT grad = userPalette->getGradientType(type);
262 const int delay = userPalette->getGradientDelay(type);
263 const Visible showControls = fromBool(grad != GradientType::LABEL,
264 Visible);
265 mPreview->setVisible(showControls);
266 mPreviewBox->setVisible(showControls);
267 mTextPreview->setVisible(showControls);
268 mGradTypeLabel->setVisible(showControls);
269 mGradTypeSlider->setVisible(showControls);
270 mGradTypeText->setVisible(showControls);
271 mGradDelayLabel->setVisible(showControls);
272 mGradDelaySlider->setVisible(showControls);
273 mGradDelayText->setVisible(showControls);
274 mRedLabel->setVisible(showControls);
275 mRedSlider->setVisible(showControls);
276 mRedText->setVisible(showControls);
277 mGreenLabel->setVisible(showControls);
278 mGreenSlider->setVisible(showControls);
279 mGreenText->setVisible(showControls);
280 mBlueLabel->setVisible(showControls);
281 mBlueSlider->setVisible(showControls);
282 mBlueText->setVisible(showControls);
283
284 mPreview->clearRows();
285 mPreviewBox->setContent(mTextPreview);
286 mTextPreview->setFont(boldFont);
287 mTextPreview->setTextColor(col);
288 mTextPreview->setTextBGColor(nullptr);
289 mTextPreview->setOpaque(Opaque_false);
290 mTextPreview->setShadow(true);
291 mTextPreview->setOutline(true);
292 mTextPreview->useTextAlpha(false);
293
294 // probably need combite both switches and add all mssing color ids.
295
296 PRAGMA45(GCC diagnostic push)
297 PRAGMA45(GCC diagnostic ignored "-Wswitch-enum")
298 switch (type)
299 {
300 case UserColorId::AIR_COLLISION_HIGHLIGHT:
301 case UserColorId::WATER_COLLISION_HIGHLIGHT:
302 case UserColorId::MONSTER_COLLISION_HIGHLIGHT:
303 case UserColorId::GROUNDTOP_COLLISION_HIGHLIGHT:
304 case UserColorId::COLLISION_HIGHLIGHT:
305 case UserColorId::PORTAL_HIGHLIGHT:
306 case UserColorId::HOME_PLACE:
307 case UserColorId::ROAD_POINT:
308 case UserColorId::NET:
309 mTextPreview->setBGColor(col);
310 mTextPreview->setOpaque(Opaque_true);
311 mTextPreview->setOutline(false);
312 mTextPreview->setShadow(false);
313 break;
314 case UserColorId::ATTACK_RANGE_BORDER:
315 case UserColorId::HOME_PLACE_BORDER:
316 if (gui != nullptr)
317 mTextPreview->setFont(gui->getFont());
318 mTextPreview->setTextColor(col);
319 mTextPreview->setOutline(false);
320 mTextPreview->setShadow(false);
321 break;
322 case UserColorId::PARTICLE:
323 case UserColorId::EXP_INFO:
324 case UserColorId::PICKUP_INFO:
325 case UserColorId::HIT_PLAYER_MONSTER:
326 case UserColorId::HIT_MONSTER_PLAYER:
327 case UserColorId::HIT_CRITICAL:
328 case UserColorId::MISS:
329 case UserColorId::HIT_LOCAL_PLAYER_MONSTER:
330 case UserColorId::HIT_LOCAL_PLAYER_CRITICAL:
331 case UserColorId::HIT_LOCAL_PLAYER_MISS:
332 case UserColorId::ATTACK_RANGE:
333 case UserColorId::MONSTER_ATTACK_RANGE:
334 case UserColorId::FLOOR_ITEM_TEXT:
335 case UserColorId::SKILL_ATTACK_RANGE:
336 mTextPreview->setShadow(false);
337 break;
338 default:
339 break;
340 }
341
342 switch (type)
343 {
344 case UserColorId::PORTAL_HIGHLIGHT:
345 case UserColorId::ATTACK_RANGE:
346 case UserColorId::ATTACK_RANGE_BORDER:
347 case UserColorId::MONSTER_ATTACK_RANGE:
348 case UserColorId::SKILL_ATTACK_RANGE:
349 case UserColorId::HOME_PLACE:
350 case UserColorId::HOME_PLACE_BORDER:
351 case UserColorId::AIR_COLLISION_HIGHLIGHT:
352 case UserColorId::WATER_COLLISION_HIGHLIGHT:
353 case UserColorId::MONSTER_COLLISION_HIGHLIGHT:
354 case UserColorId::GROUNDTOP_COLLISION_HIGHLIGHT:
355 case UserColorId::COLLISION_HIGHLIGHT:
356 case UserColorId::WALKABLE_HIGHLIGHT:
357 case UserColorId::ROAD_POINT:
358 case UserColorId::MONSTER_HP:
359 case UserColorId::MONSTER_HP2:
360 case UserColorId::HOMUN_HP:
361 case UserColorId::HOMUN_HP2:
362 case UserColorId::MERC_HP:
363 case UserColorId::MERC_HP2:
364 case UserColorId::ELEMENTAL_HP:
365 case UserColorId::ELEMENTAL_HP2:
366 case UserColorId::PLAYER_HP:
367 case UserColorId::PLAYER_HP2:
368 case UserColorId::FLOOR_ITEM_TEXT:
369 case UserColorId::NET:
370 // TRANSLATORS: colors tab. label.
371 mGradDelayLabel->setCaption(_("Alpha:"));
372 mGradDelayText->setRange(0, 255);
373 mGradDelaySlider->setScale(0, 255);
374 break;
375 default:
376 // TRANSLATORS: colors tab. label.
377 mGradDelayLabel->setCaption(_("Delay:"));
378 mGradDelayText->setRange(20, 100);
379 mGradDelaySlider->setScale(20, 100);
380 break;
381 }
382 PRAGMA45(GCC diagnostic pop)
383 if (grad != GradientType::STATIC && grad != GradientType::PULSE)
384 { // If nonstatic color, don't display the current, but the committed
385 // color at the sliders
386 col = &userPalette->getCommittedColor(type);
387 }
388 else if (grad == GradientType::PULSE)
389 {
390 col = &userPalette->getTestColor(type);
391 }
392
393 setEntry(mGradDelaySlider, mGradDelayText, delay);
394 setEntry(mRedSlider, mRedText, col->r);
395 setEntry(mGreenSlider, mGreenText, col->g);
396 setEntry(mBlueSlider, mBlueText, col->b);
397
398 mGradTypeSlider->setValue(CAST_S32(grad));
399 updateGradType();
400 mGradTypeSlider->setEnabled(true);
401 }
402
setEntry(Slider * const s,TextField * const t,const int value)403 void Setup_Colors::setEntry(Slider *const s, TextField *const t,
404 const int value)
405 {
406 if (s != nullptr)
407 s->setValue(value);
408 if (t != nullptr)
409 t->setText(toString(value));
410 }
411
apply()412 void Setup_Colors::apply()
413 {
414 if (userPalette != nullptr)
415 userPalette->commit();
416 }
417
cancel()418 void Setup_Colors::cancel()
419 {
420 if (userPalette == nullptr)
421 return;
422
423 userPalette->rollback();
424 const UserColorIdT type = static_cast<UserColorIdT>(
425 userPalette->getColorTypeAt(mSelected));
426 const Color *const col = &userPalette->getColor(type, 255U);
427 mGradTypeSlider->setValue(CAST_S32(
428 userPalette->getGradientType(type)));
429 const int delay = userPalette->getGradientDelay(type);
430 setEntry(mGradDelaySlider, mGradDelayText, delay);
431 setEntry(mRedSlider, mRedText, col->r);
432 setEntry(mGreenSlider, mGreenText, col->g);
433 setEntry(mBlueSlider, mBlueText, col->b);
434 }
435
updateGradType()436 void Setup_Colors::updateGradType()
437 {
438 if (mSelected == -1 || (userPalette == nullptr))
439 return;
440
441 mSelected = mColorBox->getSelected();
442 const UserColorIdT type = static_cast<UserColorIdT>(
443 userPalette->getColorTypeAt(mSelected));
444 const GradientTypeT grad = userPalette->getGradientType(type);
445
446 mGradTypeText->setCaption(
447 // TRANSLATORS: color type
448 (grad == GradientType::STATIC) ? _("Static") :
449 // TRANSLATORS: color type
450 (grad == GradientType::PULSE) ? _("Pulse") :
451 // TRANSLATORS: color type
452 (grad == GradientType::RAINBOW) ? _("Rainbow") : _("Spectrum"));
453
454 const bool enable = (grad == GradientType::STATIC ||
455 grad == GradientType::PULSE);
456 const bool delayEnable = true;
457
458 mGradDelayText->setEnabled(delayEnable);
459 mGradDelaySlider->setEnabled(delayEnable);
460
461 mRedText->setEnabled(enable);
462 mRedSlider->setEnabled(enable);
463 mGreenText->setEnabled(enable);
464 mGreenSlider->setEnabled(enable);
465 mBlueText->setEnabled(enable);
466 mBlueSlider->setEnabled(enable);
467 }
468
updateColor() const469 void Setup_Colors::updateColor() const
470 {
471 if (mSelected == -1 || (userPalette == nullptr))
472 return;
473
474 const UserColorIdT type = static_cast<UserColorIdT>(
475 userPalette->getColorTypeAt(mSelected));
476 const GradientTypeT grad = static_cast<GradientTypeT>(
477 CAST_S32(mGradTypeSlider->getValue()));
478 const int delay = CAST_S32(mGradDelaySlider->getValue());
479 userPalette->setGradient(type, grad);
480 userPalette->setGradientDelay(type, delay);
481
482 if (grad == GradientType::STATIC)
483 {
484 userPalette->setColor(type,
485 CAST_S32(mRedSlider->getValue()),
486 CAST_S32(mGreenSlider->getValue()),
487 CAST_S32(mBlueSlider->getValue()));
488 }
489 else if (grad == GradientType::PULSE)
490 {
491 userPalette->setTestColor(type, Color(
492 CAST_S32(mRedSlider->getValue()),
493 CAST_S32(mGreenSlider->getValue()),
494 CAST_S32(mBlueSlider->getValue()),
495 255U));
496 }
497 }
498