1 /***********************************************************************
2 Freeciv - Copyright (C) 1996 - A Kjeldberg, L Gregersen, P Unold
3 This program is free software; you can redistribute it and/or modify
4 it under the terms of the GNU General Public License as published by
5 the Free Software Foundation; either version 2, or (at your option)
6 any later version.
7
8 This program is distributed in the hope that it will be useful,
9 but WITHOUT ANY WARRANTY; without even the implied warranty of
10 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 GNU General Public License for more details.
12 ***********************************************************************/
13
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
17
18 // Qt
19 #include <QApplication>
20 #include <QGroupBox>
21 #include <QMouseEvent>
22 #include <QPainter>
23 #include <QScreen>
24 #include <QVBoxLayout>
25
26 // common
27 #include "multipliers.h"
28
29 // gui-qt
30 #include "fc_client.h"
31 #include "dialogs.h"
32 #include "qtg_cxxside.h"
33 #include "sprite.h"
34
35 #include "ratesdlg.h"
36
37 static int scale_to_mult(const struct multiplier *pmul, int scale);
38 static int mult_to_scale(const struct multiplier *pmul, int val);
39
40 /**************************************************************************
41 Dialog constructor for changing rates with sliders.
42 Automatic destructor will clean qobjects, so there is no one
43 **************************************************************************/
tax_rates_dialog(QWidget * parent)44 tax_rates_dialog::tax_rates_dialog(QWidget *parent)
45 : qfc_dialog(parent)
46 {
47 QHBoxLayout *some_layout;
48 QVBoxLayout *main_layout;
49 QPushButton *cancel_button;
50 QPushButton *ok_button;
51 QPushButton *apply_button;
52 QLabel *l1, *l2;
53 QString str;
54 int max;
55
56 setWindowTitle(_("Tax rates"));
57 main_layout = new QVBoxLayout;
58
59 if (client.conn.playing != nullptr) {
60 max = get_player_bonus(client.conn.playing, EFT_MAX_RATES);
61 } else {
62 max = 100;
63 }
64
65 /* Trans: Government - max rate (of taxes) x% */
66 str = QString(_("%1 - max rate: %2%")).
67 arg(government_name_for_player(client.conn.playing),
68 QString::number(max));
69
70 l2 = new QLabel(_("Select tax, luxury and science rates"));
71 l1 = new QLabel(str);
72 l1->setAlignment(Qt::AlignHCenter);
73 l2->setAlignment(Qt::AlignHCenter);
74 main_layout->addWidget(l2);
75 main_layout->addWidget(l1);
76 main_layout->addSpacing(20);
77
78 cancel_button = new QPushButton(_("Cancel"));
79 ok_button = new QPushButton(_("Ok"));
80 apply_button = new QPushButton(_("Apply"));
81 some_layout = new QHBoxLayout;
82 connect(cancel_button, &QAbstractButton::pressed,
83 this, &tax_rates_dialog::slot_cancel_button_pressed);
84 connect(apply_button, &QAbstractButton::pressed,
85 this, &tax_rates_dialog::slot_apply_button_pressed);
86 connect(ok_button, &QAbstractButton::pressed,
87 this, &tax_rates_dialog::slot_ok_button_pressed);
88 some_layout->addWidget(cancel_button);
89 some_layout->addWidget(apply_button);
90 some_layout->addWidget(ok_button);
91 fcde = new fc_double_edge(this);
92 main_layout->addWidget(fcde);
93 main_layout->addSpacing(20);
94 main_layout->addLayout(some_layout);
95 setLayout(main_layout);
96 }
97
98 /***************************************************************************
99 When cancel in qtpushbutton pressed selfdestruction :D.
100 ***************************************************************************/
slot_cancel_button_pressed()101 void tax_rates_dialog::slot_cancel_button_pressed()
102 {
103 delete this;
104 }
105
106 /***************************************************************************
107 When ok in qpushbutton pressed send info to server and selfdestroy :D.
108 ***************************************************************************/
slot_ok_button_pressed()109 void tax_rates_dialog::slot_ok_button_pressed()
110 {
111 dsend_packet_player_rates(&client.conn, 10 * fcde->current_min,
112 10 * (10 - fcde->current_max),
113 10 * (fcde->current_max - fcde->current_min));
114 delete this;
115 }
116
117 /***************************************************************************
118 Pressed "apply" in tax rates dialog.
119 ***************************************************************************/
slot_apply_button_pressed()120 void tax_rates_dialog::slot_apply_button_pressed()
121 {
122 dsend_packet_player_rates(&client.conn, 10 * fcde->current_min,
123 10 * (10 - fcde->current_max),
124 10 * (fcde->current_max - fcde->current_min));
125 }
126
127 /**************************************************************************
128 Multipler rates dialog constructor
129 Inheriting from qfc_dialog will cause crash in Qt5.2
130 **************************************************************************/
multipler_rates_dialog(QWidget * parent)131 multipler_rates_dialog::multipler_rates_dialog(QWidget *parent)
132 : QDialog(parent)
133 {
134 QGroupBox *group_box;
135 QHBoxLayout *some_layout;
136 QLabel *label;
137 QSlider *slider;
138 QVBoxLayout *main_layout;
139 struct player *pplayer = client_player();
140
141 cancel_button = new QPushButton;
142 ok_button = new QPushButton;
143 setWindowTitle(_("Change policies"));
144 main_layout = new QVBoxLayout;
145
146 multipliers_iterate(pmul) {
147 QHBoxLayout *hb = new QHBoxLayout;
148 int val = player_multiplier_target_value(pplayer, pmul);
149
150 group_box = new QGroupBox(multiplier_name_translation(pmul));
151 slider = new QSlider(Qt::Horizontal, this);
152 slider->setMinimum(mult_to_scale(pmul, pmul->start));
153 slider->setMaximum(mult_to_scale(pmul, pmul->stop));
154 slider->setValue(mult_to_scale(pmul, val));
155 connect(slider, &QAbstractSlider::valueChanged,
156 this, &multipler_rates_dialog::slot_set_value);
157 slider_list.append(slider);
158 label = new QLabel(QString::number(mult_to_scale(pmul, val)));
159 hb->addWidget(slider);
160 hb->addWidget(label);
161 group_box->setLayout(hb);
162 slider->setProperty("lab", QVariant::fromValue((void *) label));
163 main_layout->addWidget(group_box);
164
165 } multipliers_iterate_end;
166 some_layout = new QHBoxLayout;
167 cancel_button->setText(_("Cancel"));
168 ok_button->setText(_("Ok"));
169 connect(cancel_button, &QAbstractButton::pressed,
170 this, &multipler_rates_dialog::slot_cancel_button_pressed);
171 connect(ok_button, &QAbstractButton::pressed,
172 this, &multipler_rates_dialog::slot_ok_button_pressed);
173 some_layout->addWidget(cancel_button);
174 some_layout->addWidget(ok_button);
175 main_layout->addSpacing(20);
176 main_layout->addLayout(some_layout);
177 setLayout(main_layout);
178 }
179
180 /**************************************************************************
181 Slider value changed
182 **************************************************************************/
slot_set_value(int i)183 void multipler_rates_dialog::slot_set_value(int i)
184 {
185 QSlider *qo;
186 qo = (QSlider *) QObject::sender();
187 QVariant qvar;
188 QLabel *lab;
189
190 qvar = qo->property("lab");
191 lab = reinterpret_cast<QLabel *>(qvar.value<void *>());
192 lab->setText(QString::number(qo->value()));
193 }
194
195
196 /***************************************************************************
197 Cancel pressed
198 ***************************************************************************/
slot_cancel_button_pressed()199 void multipler_rates_dialog::slot_cancel_button_pressed()
200 {
201 close();
202 deleteLater();
203 }
204
205 /***************************************************************************
206 Ok pressed - send mulipliers value.
207 ***************************************************************************/
slot_ok_button_pressed()208 void multipler_rates_dialog::slot_ok_button_pressed()
209 {
210 int j = 0;
211 int value;
212 struct packet_player_multiplier mul;
213
214 multipliers_iterate(pmul) {
215 Multiplier_type_id i = multiplier_index(pmul);
216 value = slider_list.at(j)->value();
217 mul.multipliers[i] = scale_to_mult(pmul, value);
218 j++;
219 } multipliers_iterate_end;
220 mul.count = multiplier_count();
221 send_packet_player_multiplier(&client.conn, &mul);
222 close();
223 deleteLater();
224 }
225
226
227 /**************************************************************************
228 Convert real multiplier display value to scale value
229 **************************************************************************/
mult_to_scale(const struct multiplier * pmul,int val)230 int mult_to_scale(const struct multiplier *pmul, int val)
231 {
232 return (val - pmul->start) / pmul->step;
233 }
234
235 /**************************************************************************
236 Convert scale units to real multiplier display value
237 **************************************************************************/
scale_to_mult(const struct multiplier * pmul,int scale)238 int scale_to_mult(const struct multiplier *pmul, int scale)
239 {
240 return scale * pmul->step + pmul->start;
241 }
242
243 /**************************************************************************
244 Popup (or raise) the (tax/science/luxury) rates selection dialog.
245 **************************************************************************/
popup_rates_dialog(void)246 void popup_rates_dialog(void)
247 {
248 QPoint p;
249 QRect rect;
250
251 p = QCursor::pos();
252 rect = QApplication::primaryScreen()->availableGeometry();
253 tax_rates_dialog *trd = new tax_rates_dialog(gui()->central_wdg);
254 p.setY(p.y() - trd->height() / 2);
255 if (p.y() < 50) {
256 p.setY(50);
257 }
258 if (p.y() + trd->height() > rect.bottom()) {
259 p.setY(rect.bottom() - trd->height());
260 }
261 if (p.x() + trd->width() > rect.right()) {
262 p.setX(rect.right() - trd->width());
263 }
264 trd->move(p);
265 trd->show();
266 }
267
268 /**************************************************************************
269 Update multipliers (policies) dialog.
270 **************************************************************************/
real_multipliers_dialog_update(void * unused)271 void real_multipliers_dialog_update(void *unused)
272 {
273 /* PORTME */
274 }
275
276 /**************************************************************************
277 Popups multiplier dialog
278 **************************************************************************/
popup_multiplier_dialog(void)279 void popup_multiplier_dialog(void)
280 {
281 multipler_rates_dialog *mrd;
282 if (!can_client_issue_orders()) {
283 return;
284 }
285 mrd = new multipler_rates_dialog(gui()->central_wdg);
286 mrd->show();
287 }
288
289 /**************************************************************************
290 Double edged slider constructor
291 **************************************************************************/
fc_double_edge(QWidget * parent)292 fc_double_edge::fc_double_edge(QWidget *parent)
293 : QWidget(parent)
294 {
295
296 current_min = client.conn.playing->economic.tax / 10;
297 current_max = 10 - (client.conn.playing->economic.luxury / 10);
298 mouse_x = 0.;
299 moved = 0;
300 on_min = false;
301 on_max = false;
302
303 if (client.conn.playing != nullptr) {
304 max_rates = get_player_bonus(client.conn.playing, EFT_MAX_RATES) / 10;
305 } else {
306 max_rates = 10;
307 }
308 cursor_pix = *fc_icons::instance()->get_pixmap("control");
309 setMouseTracking(true);
310 }
311
312 /**************************************************************************
313 Double edged slider destructor
314 **************************************************************************/
~fc_double_edge()315 fc_double_edge::~fc_double_edge()
316 {
317 }
318
319 /**************************************************************************
320 Default size for double edge slider
321 **************************************************************************/
sizeHint() const322 QSize fc_double_edge::sizeHint() const
323 {
324 return QSize(30 * get_tax_sprite(tileset, O_LUXURY)->pm->width(),
325 3 * get_tax_sprite(tileset, O_LUXURY)->pm->height());
326 }
327
328 /**************************************************************************
329 Double edge paint event
330 **************************************************************************/
paintEvent(QPaintEvent * event)331 void fc_double_edge::paintEvent(QPaintEvent *event)
332 {
333 QPainter p;
334 int i, j, pos;
335 QPixmap *pix;
336 QPixmap pix_scaled;
337 QSize s;
338 double x_min, x_max;
339
340 cursor_pix = cursor_pix.scaled(width() / 20, height());
341 cursor_size = cursor_pix.width();
342 p.begin(this);
343 p.setRenderHint(QPainter::TextAntialiasing);
344 p.setBrush(Qt::SolidPattern);
345 p.setPen(Qt::SolidLine);
346
347 x_min = static_cast<double>(current_min) / 10 *
348 ((width() - 1) - 2 * cursor_size) + cursor_size;
349 x_max = static_cast<double>(current_max) / 10 *
350 ((width() - 1) - 2 * cursor_size) + cursor_size;
351
352 pos = cursor_size;
353 pix = get_tax_sprite(tileset, O_GOLD)->pm;
354 s.setWidth((width() - 2 * cursor_size) / 10);
355 s.setHeight(height());
356 pix_scaled = pix->scaled(s, Qt::IgnoreAspectRatio,
357 Qt::SmoothTransformation);
358 for (i = 0; i < current_min; i++) {
359 p.drawPixmap(pos, 0, pix_scaled);
360 pos = pos + pix_scaled.width();
361 }
362 j = i;
363 pix = get_tax_sprite(tileset, O_SCIENCE)->pm;
364 pix_scaled = pix->scaled(s, Qt::IgnoreAspectRatio,
365 Qt::SmoothTransformation);
366 for (i = j; i < current_max; i++) {
367 p.drawPixmap(pos, 0, pix_scaled);
368 pos = pos + pix_scaled.width();
369 }
370 j = i;
371 pix = get_tax_sprite(tileset, O_LUXURY)->pm;
372 pix_scaled = pix->scaled(s, Qt::IgnoreAspectRatio,
373 Qt::SmoothTransformation);
374 for (i = j; i < 10; i++) {
375 p.drawPixmap(pos, 0, pix_scaled);
376 pos = pos + pix_scaled.width();
377 }
378 p.drawPixmap(x_max - cursor_size / 2, 0, cursor_pix);
379 p.drawPixmap(x_min - cursor_size / 2, 0, cursor_pix);
380 p.end();
381 }
382
383 /**************************************************************************
384 Double edged slider mouse press event
385 **************************************************************************/
mousePressEvent(QMouseEvent * event)386 void fc_double_edge::mousePressEvent(QMouseEvent *event)
387 {
388 if (event->buttons() & Qt::LeftButton) {
389 mouse_x = static_cast<double>(event->x());
390
391 if (mouse_x <= current_max * width() / 10 - 2 * cursor_size) {
392 moved = 1;
393 } else {
394 moved = 2;
395 }
396 } else {
397 moved = 0;
398 }
399 mouseMoveEvent(event);
400 update();
401 }
402
403 /**************************************************************************
404 Double edged slider mouse move event
405 **************************************************************************/
mouseMoveEvent(QMouseEvent * event)406 void fc_double_edge::mouseMoveEvent(QMouseEvent *event)
407 {
408 float x_min, x_max, x_mouse;
409 if (on_max || on_min) {
410 setCursor(Qt::SizeHorCursor);
411 } else {
412 setCursor(Qt::ArrowCursor);
413 }
414
415 x_mouse = static_cast<float>(event->x());
416 x_min = static_cast<float>(current_min) / 10 *
417 ((width() - 1) - 2 * cursor_size) + cursor_size;
418 x_max = static_cast<float>(current_max) / 10 *
419 ((width() - 1) - 2 * cursor_size) + cursor_size;
420
421 on_min = (((x_mouse > (x_min - cursor_size * 1.1)) &&
422 (x_mouse < (x_min + cursor_size * 1.1)))
423 && (!on_max))
424 || (moved == 1);
425 on_max = (((x_mouse > (x_max - cursor_size * 1.1)) &&
426 (x_mouse < (x_max + cursor_size * 1.1)))
427 && !on_min)
428 || (moved == 2);
429 if (event->buttons() & Qt::LeftButton) {
430 if ((moved != 2) && on_min) {
431 x_min = x_mouse * width() /
432 ((width() - 1) - 2 * cursor_size) - cursor_size;
433 if (x_min < 0) x_min = 0;
434 if (x_min > width()) x_min = width();
435 current_min = (x_min * 10 / (width() - 1));
436 if (current_min > max_rates) {
437 current_min = max_rates;
438 }
439 if (current_max < current_min) {
440 current_max = current_min;
441 }
442 if (current_max - current_min > max_rates) {
443 current_min = current_max - max_rates;
444 }
445 moved = 1;
446 } else if ((moved != 1) && on_max) {
447 x_max = x_mouse * width() /
448 ((width() - 1) - 2 * cursor_size) - cursor_size;
449 if (x_max < 0) x_max = 0;
450 if (x_max > width()) x_max = width();
451 current_max = (x_max * 10 / (width() - 1));
452 if (current_max > max_rates + current_min) {
453 current_max = max_rates + current_min;
454 }
455 if (current_max < 10 - max_rates) {
456 current_max = 10 - max_rates;
457 }
458 if (current_min > current_max)
459 current_min = current_max;
460 moved = 2;
461 }
462 update();
463 } else {
464 moved = 0;
465 }
466
467 mouse_x = x_mouse;
468 }
469
470