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)
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 ***********************************************************************/
15 #include <fc_config.h>
29 #include "mapctrl_common.h"
30 #include "overview_common.h"
35 #include "qtg_cxxside.h"
38 const char*get_timeout_label_text();
39 static int mapview_frozen_level
= 0;
40 extern void destroy_city_dialog();
41 extern struct canvas
*canvas
;
42 extern QApplication
*qapp
;
44 #define MAX_DIRTY_RECTS 20
45 static int num_dirty_rects
= 0;
46 static QRect dirty_rects
[MAX_DIRTY_RECTS
];
48 /**************************************************************************
49 Check if point x, y is in area (px -> pxe, py - pye)
50 **************************************************************************/
51 bool is_point_in_area(int x
, int y
, int px
, int py
, int pxe
, int pye
)
53 if (x
>= px
&& y
>= py
&& x
<= pxe
&& y
<= pye
) {
60 /**************************************************************************
61 Constructor for idle callbacks
62 **************************************************************************/
65 connect(&timer
, SIGNAL(timeout()), this, SLOT(idling()));
66 /*if there would be messages in
67 *that queue is big we may want to decrease it*/
71 /**************************************************************************
72 slot used to execute 1 callback from callabcks stored in idle list
73 **************************************************************************/
74 void mr_idle::idling()
76 call_me_back
* cb
= new call_me_back
;
78 while (!callback_list
.isEmpty()) {
79 cb
= callback_list
.dequeue();
80 (cb
->callback
) (cb
->data
);
85 /**************************************************************************
86 Adds one callback to execute later
87 **************************************************************************/
88 void mr_idle::add_callback(call_me_back
* cb
)
90 callback_list
.enqueue(cb
);
93 /**************************************************************************
95 **************************************************************************/
96 map_view::map_view() : QWidget()
98 setMouseTracking(true);
101 /**************************************************************************
102 slot inherited from QPixamp
103 **************************************************************************/
104 void map_view::paintEvent(QPaintEvent
*event
)
109 paint(&painter
, event
);
113 /**************************************************************************
115 **************************************************************************/
116 void map_view::paint(QPainter
*painter
, QPaintEvent
*event
)
118 int width
= mapview
.store
->map_pixmap
.width();
119 int height
= mapview
.store
->map_pixmap
.height();
121 painter
->drawPixmap(0, 0, width
, height
, mapview
.store
->map_pixmap
);
124 /**************************************************************************
125 Sets new point for new search
126 **************************************************************************/
127 void map_view::resume_searching(int pos_x
,int pos_y
,int &w
, int &h
,
128 int wdth
, int hght
, int recursive_nr
)
130 int new_pos_x
, new_pos_y
;
136 if (pos_y
+ hght
+ 4 < height() && pos_x
> width() / 2) {
137 new_pos_y
= pos_y
+ 5;
138 } else if (pos_x
> 0 && pos_y
> 10) {
139 new_pos_x
= pos_x
- 5;
140 } else if (pos_y
> 0) {
141 new_pos_y
= pos_y
- 5;
142 } else if (pos_x
+ wdth
+ 4 < this->width()) {
143 new_pos_x
= pos_x
+ 5;
145 find_place(new_pos_x
, new_pos_y
, w
, h
, wdth
, hght
, recursive_nr
);
148 /**************************************************************************
149 Searches place for widget with size w and height h
150 Starts looking from position pos_x, pos_y, going clockwork
151 Returns position as (w,h)
152 Along with resume_searching its recursive function.
153 **************************************************************************/
154 void map_view::find_place(int pos_x
, int pos_y
, int &w
, int &h
, int wdth
,
155 int hght
, int recursive_nr
)
159 QList
<fcwidget
*>widgets
= this->findChildren
<fcwidget
*>();
160 bool cont_searching
= false;
162 if (recursive_nr
>= 1000) {
164 * give up searching position
169 * try position pos_x, pos_y,
170 * check middle and borders if aren't above other widget
172 for (i
= 0; i
< widgets
.count(); i
++) {
173 if (widgets
[i
]->was_destroyed
== true) {
176 x
= widgets
[i
]->pos().x();
177 y
= widgets
[i
]->pos().y();
178 if (x
== 0 && y
==0) {
181 xe
= widgets
[i
]->pos().x() + widgets
[i
]->width();
182 ye
= widgets
[i
]->pos().y() + widgets
[i
]->height();
184 if (is_point_in_area(pos_x
, pos_y
, x
, y
, xe
, ye
)) {
185 cont_searching
= true;
187 if (is_point_in_area(pos_x
+ wdth
, pos_y
, x
, y
, xe
, ye
)) {
188 cont_searching
= true;
190 if (is_point_in_area(pos_x
+ wdth
, pos_y
+ hght
, x
, y
, xe
, ye
)) {
191 cont_searching
= true;
193 if (is_point_in_area(pos_x
, pos_y
+ hght
, x
, y
, xe
, ye
)) {
194 cont_searching
= true;
196 if (is_point_in_area(pos_x
+ wdth
/ 2, pos_y
+ hght
/ 2, x
, y
, xe
, ye
)) {
197 cont_searching
= true;
202 if (cont_searching
) {
203 resume_searching(pos_x
, pos_y
, w
, h
, wdth
, hght
, recursive_nr
);
208 /****************************************************************************
209 Called when map view has been resized
210 ****************************************************************************/
211 void map_view::resizeEvent(QResizeEvent
* event
)
215 size
= event
->size();
217 if (C_S_RUNNING
== client_state()) {
218 map_canvas_resized(size
.width(), size
.height());
219 gui()->unitinfo_wdg
->move(0,size
.height()-gui()->unitinfo_wdg
->height());
220 gui()->game_info_label
->move(size
.width()
221 -gui()->game_info_label
->width(),
223 -gui()->game_info_label
->height());
227 /****************************************************************************
228 Constructor for resize widget
229 ****************************************************************************/
230 resize_widget::resize_widget(QWidget
*parent
) : QLabel()
233 setCursor(Qt::SizeFDiagCursor
);
234 setPixmap(QPixmap(resize_button
));
237 /****************************************************************************
238 Puts resize widget to right bottom corner
239 ****************************************************************************/
240 void resize_widget::put_to_corner()
242 move(parentWidget()->width() - width(),
243 parentWidget()->height() - height());
246 /****************************************************************************
247 Mouse handler for resize widget (resizes parent widget)
248 ****************************************************************************/
249 void resize_widget::mouseMoveEvent(QMouseEvent
* event
)
253 qp
= event
->globalPos();
254 np
.setX(qp
.x() - point
.x());
255 np
.setY(qp
.y() - point
.y());
256 np
.setX(qMax(np
.x(), 32));
257 np
.setY(qMax(np
.y(), 32));
258 parentWidget()->resize(np
.x(), np
.y());
261 /****************************************************************************
262 Sets moving point for resize widget;
263 ****************************************************************************/
264 void resize_widget::mousePressEvent(QMouseEvent
* event
)
268 qp
= event
->globalPos();
269 point
.setX(qp
.x() - parentWidget()->width());
270 point
.setY(qp
.y() - parentWidget()->height());
274 /****************************************************************************
275 Constructor for close widget
276 ****************************************************************************/
277 close_widget::close_widget(QWidget
*parent
) : QLabel()
280 setCursor(Qt::ArrowCursor
);
281 setPixmap(QPixmap(close_button
));
284 /****************************************************************************
285 Puts close widget to right top corner
286 ****************************************************************************/
287 void close_widget::put_to_corner()
289 move(parentWidget()->width()-width(), 0);
292 /****************************************************************************
293 Mouse handler for close widget, hides parent widget
294 ****************************************************************************/
295 void close_widget::mousePressEvent(QMouseEvent
* event
)
297 if (event
->button() == Qt::LeftButton
) {
298 parentWidget()->hide();
302 /****************************************************************************
303 Notifies parent to do custom action, parent is already hidden.
304 ****************************************************************************/
305 void close_widget::notify_parent()
309 fcw
= reinterpret_cast<fcwidget
*>(parentWidget());
314 /**************************************************************************
315 Constructor for minimap
316 **************************************************************************/
317 minimap_view::minimap_view(QWidget
*parent
) : fcwidget()
320 setScaledContents(true);
324 background
= QBrush(QColor (0, 0, 0));
325 setCursor(Qt::CrossCursor
);
326 rw
= new resize_widget(this);
328 cw
= new close_widget(this);
334 /**************************************************************************
335 Paint event for minimap
336 **************************************************************************/
337 void minimap_view::paintEvent(QPaintEvent
*event
)
342 paint(&painter
, event
);
346 /**************************************************************************
347 Sets scaling factor for minimap
348 **************************************************************************/
349 void minimap_view::scale(double factor
)
351 scale_factor
*= factor
;
352 if (scale_factor
< 1) {
358 /**************************************************************************
359 Converts gui to overview position.
360 **************************************************************************/
361 static void gui_to_overview(int *map_x
, int *map_y
, int gui_x
, int gui_y
)
363 const int W
= tileset_tile_width(tileset
);
364 const int H
= tileset_tile_height(tileset
);
365 const int HH
= tileset_hex_height(tileset
);
366 const int HW
= tileset_hex_width(tileset
);
369 if (HH
> 0 || HW
> 0) {
371 int xmult
, ymult
, mod
, compar
;
372 x
= DIVIDE(gui_x
, W
);
373 y
= DIVIDE(gui_y
, H
);
376 xmult
= (dx
>= W
/ 2) ? -1 : 1;
377 ymult
= (dy
>= H
/ 2) ? -1 : 1;
378 dx
= (dx
>= W
/ 2) ? (W
- 1 - dx
) : dx
;
379 dy
= (dy
>= H
/ 2) ? (H
- 1 - dy
) : dy
;
381 compar
= (dx
- HW
/ 2) * (H
/ 2) - (H
/ 2 - 1 - dy
) * (W
/ 2 - HW
);
383 compar
= (dy
- HH
/ 2) * (W
/ 2) - (W
/ 2 - 1 - dx
) * (H
/ 2 - HH
);
385 mod
= (compar
< 0) ? -1 : 0;
386 *map_x
= (x
+ y
) + mod
* (xmult
+ ymult
) / 2;
387 *map_y
= (y
- x
) + mod
* (ymult
- xmult
) / 2;
388 } else if (tileset_is_isometric(tileset
)) {
390 *map_x
= DIVIDE(gui_x
* H
+ gui_y
* W
, W
* H
);
391 *map_y
= DIVIDE(gui_y
* W
- gui_x
* H
, W
* H
);
393 *map_x
= DIVIDE(gui_x
, W
);
394 *map_y
= DIVIDE(gui_y
, H
);
398 map_to_overview_pos(map_x
, map_y
, a
, b
);
403 /**************************************************************************
404 Called by close widget, cause widget has been hidden. Updates menu.
405 **************************************************************************/
406 void minimap_view::update_menu()
408 ::gui()->menu_bar
->minimap_status
->setChecked(false);
411 /**************************************************************************
412 Minimap is being moved, position is being remebered
413 **************************************************************************/
414 void minimap_view::moveEvent(QMoveEvent
* event
)
416 position
= event
->pos();
419 /**************************************************************************
420 Minimap is just unhidden, old position is restored
421 **************************************************************************/
422 void minimap_view::showEvent(QShowEvent
* event
)
425 event
->setAccepted(true);
428 /**************************************************************************
429 Draws viewport on minimap
430 **************************************************************************/
431 void minimap_view::draw_viewport(QPainter
*painter
)
434 int src_x
, src_y
, dst_x
, dst_y
;
439 gui_to_overview(&x
[0], &y
[0], mapview
.gui_x0
, mapview
.gui_y0
);
440 gui_to_overview(&x
[1], &y
[1], mapview
.gui_x0
+ mapview
.width
,
442 gui_to_overview(&x
[2], &y
[2], mapview
.gui_x0
+ mapview
.width
,
443 mapview
.gui_y0
+ mapview
.height
);
444 gui_to_overview(&x
[3], &y
[3], mapview
.gui_x0
,
445 mapview
.gui_y0
+ mapview
.height
);
446 painter
->setPen(QColor(Qt::white
));
448 if (scale_factor
> 1) {
449 for (i
= 0; i
< 4; i
++) {
450 scale_point(x
[i
], y
[i
]);
454 for (i
= 0; i
< 4; i
++) {
455 src_x
= x
[i
] * w_ratio
;
456 src_y
= y
[i
] * h_ratio
;
457 dst_x
= x
[(i
+ 1) % 4] * w_ratio
;
458 dst_y
= y
[(i
+ 1) % 4] * h_ratio
;
459 painter
->drawLine(src_x
, src_y
, dst_x
, dst_y
);
463 /**************************************************************************
464 Scales point from real overview coords to scaled overview coords.
465 **************************************************************************/
466 void minimap_view::scale_point(int &x
, int &y
)
471 gui_to_overview(&ax
, &bx
, mapview
.gui_x0
+ mapview
.width
/ 2,
472 mapview
.gui_y0
+ mapview
.height
/ 2);
473 x
= qRound(x
* scale_factor
);
474 y
= qRound(y
* scale_factor
);
475 dx
= qRound(ax
* scale_factor
- overview
.width
/ 2);
476 dy
= qRound(bx
* scale_factor
- overview
.height
/ 2);
482 /**************************************************************************
483 Scales point from scaled overview coords to real overview coords.
484 **************************************************************************/
485 void minimap_view::unscale_point(int &x
, int &y
)
490 gui_to_overview(&ax
, &bx
, mapview
.gui_x0
+ mapview
.width
/ 2,
491 mapview
.gui_y0
+ mapview
.height
/ 2);
492 dx
= qRound(ax
* scale_factor
- overview
.width
/ 2);
493 dy
= qRound(bx
* scale_factor
- overview
.height
/ 2);
496 x
= qRound(x
/ scale_factor
);
497 y
= qRound(y
/ scale_factor
);
502 /**************************************************************************
503 Updates minimap's pixmap
504 **************************************************************************/
505 void minimap_view::update_image()
509 QPixmap
bigger_pix(overview
.width
* 2, overview
.height
* 2);
510 int delta_x
, delta_y
;
515 if (isHidden() == true ){
518 if (overview
.map
!= NULL
) {
519 if (scale_factor
> 1) {
521 scale later and draw without looking for origin */
522 src
= &overview
.map
->map_pixmap
;
523 dst
= &overview
.window
->map_pixmap
;
526 ix
= overview
.width
- x
;
527 iy
= overview
.height
- y
;
528 pixmap_copy(dst
, src
, 0, 0, ix
, iy
, x
, y
);
529 pixmap_copy(dst
, src
, 0, y
, ix
, 0, x
, iy
);
530 pixmap_copy(dst
, src
, x
, 0, 0, iy
, ix
, y
);
531 pixmap_copy(dst
, src
, x
, y
, 0, 0, ix
, iy
);
532 tpix
= &overview
.window
->map_pixmap
;
533 wf
= static_cast <float>(overview
.width
) / scale_factor
;
534 hf
= static_cast <float>(overview
.height
) / scale_factor
;
538 /* qt 4.8 is going to copy pixmap badly if coords x+size, y+size
539 will go over image so we create extra black bigger image */
540 bigger_pix
.fill(Qt::black
);
541 delta_x
= overview
.width
/ 2;
542 delta_y
= overview
.height
/ 2;
543 pixmap_copy(&bigger_pix
, tpix
, 0, 0, delta_x
, delta_y
, overview
.width
,
545 gpix
= bigger_pix
.copy(delta_x
+ x
, delta_y
+ y
, wf
, hf
);
546 *pix
= gpix
.scaled(width(), height(),
547 Qt::IgnoreAspectRatio
, Qt::FastTransformation
);
549 tpix
= &overview
.map
->map_pixmap
;
550 *pix
= tpix
->scaled(width(), height(),
551 Qt::IgnoreAspectRatio
, Qt::FastTransformation
);
557 /**************************************************************************
558 Redraws visible map using stored pixmap
559 **************************************************************************/
560 void minimap_view::paint(QPainter
* painter
, QPaintEvent
* event
)
564 x
= overview
.map_x0
* w_ratio
;
565 y
= overview
.map_y0
* h_ratio
;
566 ix
= pix
->width() - x
;
567 iy
= pix
->height() - y
;
569 if (scale_factor
> 1) {
570 painter
->drawPixmap(0, 0, *pix
, 0, 0, pix
->width(), pix
->height());
572 painter
->drawPixmap(ix
, iy
, *pix
, 0, 0, x
, y
);
573 painter
->drawPixmap(ix
, 0, *pix
, 0, y
, x
, iy
);
574 painter
->drawPixmap(0, iy
, *pix
, x
, 0, ix
, y
);
575 painter
->drawPixmap(0, 0, *pix
, x
, y
, ix
, iy
);
577 painter
->setPen(QColor(Qt::yellow
));
578 painter
->setRenderHint(QPainter::Antialiasing
);
579 painter
->drawRect(0, 0, width() - 1, height() - 1);
580 draw_viewport(painter
);
585 /****************************************************************************
586 Called when minimap has been resized
587 ****************************************************************************/
588 void minimap_view::resizeEvent(QResizeEvent
* event
)
591 size
= event
->size();
593 if (C_S_RUNNING
== client_state()) {
594 w_ratio
= static_cast<float>(width()) / overview
.width
;
595 h_ratio
= static_cast<float>(height()) / overview
.height
;
600 /****************************************************************************
601 Wheel event for minimap - zooms it in or out
602 ****************************************************************************/
603 void minimap_view::wheelEvent(QWheelEvent
* event
)
605 if (event
->delta() > 0) {
613 /****************************************************************************
614 Sets scale factor to scale minimap 20% up
615 ****************************************************************************/
616 void minimap_view::zoom_in()
618 if (scale_factor
< overview
.width
/ 8) {
623 /****************************************************************************
624 Sets scale factor to scale minimap 20% down
625 ****************************************************************************/
626 void minimap_view::zoom_out()
631 /**************************************************************************
632 Mouse Handler for minimap_view
633 Left button - moves minimap
634 Right button - recenters on some point
635 For wheel look mouseWheelEvent
636 **************************************************************************/
637 void minimap_view::mousePressEvent(QMouseEvent
* event
)
642 if (event
->button() == Qt::LeftButton
) {
643 cursor
= event
->globalPos() - geometry().topLeft();
645 if (event
->button() == Qt::RightButton
) {
646 cursor
= event
->pos();
647 fx
= event
->pos().x();
648 fy
= event
->pos().y();
649 fx
= qRound(fx
/ w_ratio
);
650 fy
= qRound(fy
/ h_ratio
);
651 if (scale_factor
> 1) {
652 unscale_point(fx
, fy
);
656 fx
= qMin(fx
, overview
.width
- 1);
657 fy
= qMin(fy
, overview
.height
- 1);
658 overview_to_map_pos(&x
, &y
, fx
, fy
);
659 center_tile_mapcanvas(map_pos_to_tile(x
, y
));
662 event
->setAccepted(true);
665 /**************************************************************************
666 Called when mouse button was pressed. Used to moving minimap.
667 **************************************************************************/
668 void minimap_view::mouseMoveEvent(QMouseEvent
* event
)
670 if (event
->buttons() & Qt::LeftButton
) {
671 move(event
->globalPos() - cursor
);
672 setCursor(Qt::SizeAllCursor
);
676 /**************************************************************************
677 Called when mouse button unpressed. Restores cursor.
678 **************************************************************************/
679 void minimap_view::mouseReleaseEvent(QMouseEvent
* event
)
681 setCursor(Qt::CrossCursor
);
685 /**************************************************************************
686 Constructor for information label
687 **************************************************************************/
688 info_label::info_label(QWidget
*parent
) : fcwidget()
691 indicator_icons
= NULL
;
693 setMouseTracking(true);
695 create_end_turn_pixmap();
696 highlight_end_button
= true;
697 end_button_area
.setWidth(0);
698 rates_area
.setWidth(0);
699 indicator_area
.setWidth(0);
702 /**************************************************************************
703 Sets information about current turn
704 **************************************************************************/
705 void info_label::set_turn_info(QString str
)
710 /**************************************************************************
711 Sets information about current time
712 **************************************************************************/
713 void info_label::set_time_info(QString str
)
719 /**************************************************************************
720 Sets information about current economy
721 **************************************************************************/
722 void info_label::set_eco_info(QString str
)
727 /**************************************************************************
729 **************************************************************************/
730 void info_label::update_menu()
732 /** Function inherited from abstract parent
733 * PORTME , if needed */
736 /**************************************************************************
737 Creates end turn pixmap, to use at painting.
738 It searches for optimal pixel size for font to get optimal size.
739 Pixmap size is 80% width of rates pixmap
740 **************************************************************************/
741 void info_label::create_end_turn_pixmap()
744 QString
str(_("End Turn"));
745 QFontMetrics
fm(*ufont
);
748 struct sprite
*sprite
= get_tax_sprite(tileset
, O_LUXURY
);
750 w
= 8 * sprite
->pm
->width();
752 for (s
= 8; s
< 30; s
++) {
753 ufont
->setPixelSize(s
);
754 if (fm
.width(str
) < w
) {
758 ufont
->setPixelSize(r
);
759 pen
.setColor(QColor(30, 175, 30));
760 end_turn_pix
= new QPixmap(w
, fm
.height() + 4);
761 end_turn_pix
->fill(Qt::transparent
);
762 p
.begin(end_turn_pix
);
765 p
.drawText(0, fm
.height() + 3, str
);
769 /**************************************************************************
770 Sets pixmap about current rates
771 **************************************************************************/
772 void info_label::set_rates_pixmap()
777 struct sprite
*sprite
= get_tax_sprite(tileset
, O_LUXURY
);
778 int w
= sprite
->pm
->width();
779 int h
= sprite
->pm
->height();
783 if (rates_label
== NULL
) {
784 rates_label
= new QPixmap(10 * w
, h
);
787 source_rect
= QRect(0, 0, w
, h
);
788 dest_rect
= QRect(0, 0, w
, h
);
789 rates_label
->fill(Qt::transparent
);
792 if (client_is_global_observer()){
796 for (; d
< client
.conn
.playing
->economic
.luxury
/ 10; d
++) {
797 dest_rect
.moveTo(d
* w
, 0);
798 p
.begin(rates_label
);
799 p
.drawPixmap(dest_rect
, *sprite
->pm
, source_rect
);
802 sprite
= get_tax_sprite(tileset
, O_SCIENCE
);
804 for (; d
< (client
.conn
.playing
->economic
.science
805 + client
.conn
.playing
->economic
.luxury
) / 10; d
++) {
806 dest_rect
.moveTo(d
* w
, 0);
807 p
.begin(rates_label
);
808 p
.drawPixmap(dest_rect
, *sprite
->pm
, source_rect
);
811 sprite
= get_tax_sprite(tileset
, O_GOLD
);
813 for (; d
< 10; d
++) {
814 dest_rect
.moveTo(d
* w
, 0);
815 p
.begin(rates_label
);
816 p
.drawPixmap(dest_rect
, *sprite
->pm
, source_rect
);
822 /**************************************************************************
823 Highligts end turn button and shows tooltips
824 **************************************************************************/
825 void info_label::mouseMoveEvent(QMouseEvent
*event
)
827 QPoint
p(event
->x(), event
->y());
828 p
= this->mapToGlobal(p
);
830 struct sprite
*sprite
;
833 if (client_is_global_observer()){
837 if (end_button_area
.contains(event
->x(), event
->y())) {
838 if (highlight_end_button
== false) {
841 highlight_end_button
= true;
843 if (highlight_end_button
== true) {
846 highlight_end_button
= false;
849 if (indicator_area
.contains(event
->x(), event
->y())) {
850 sprite
= get_tax_sprite(tileset
, O_LUXURY
);
851 w
= sprite
->pm
->width();
852 switch (event
->x() / w
) {
854 QToolTip::showText(p
, QString(get_bulb_tooltip()));
857 QToolTip::showText(p
, QString(get_global_warming_tooltip()));
860 QToolTip::showText(p
, QString(get_nuclear_winter_tooltip()));
863 QToolTip::showText(p
, QString(get_government_tooltip()));
866 QToolTip::hideText();
871 if (rates_area
.contains(event
->x(), event
->y())) {
872 QToolTip::showText(p
,
873 QString(_("Shows your current luxury/science/tax "
874 "rates. Use mouse wheel to change them")));
875 } else if (!indicator_area
.contains(event
->x(), event
->y())) {
876 QToolTip::hideText();
884 /**************************************************************************
885 Mouse wheel event, used for changing tax rates
886 **************************************************************************/
887 void info_label::wheelEvent(QWheelEvent
*event
)
890 QPoint
p(event
->x(), event
->y());
891 int delta
= event
->delta();
895 p
= this->mapToGlobal(p
);
896 pos
= rates_label
->width() / 10;
897 p2
= event
->x() - rates_area
.left();
898 if (client_is_global_observer()){
901 a
= client
.conn
.playing
->economic
.luxury
/ 10;
902 b
= client
.conn
.playing
->economic
.science
/ 10;
904 if (rates_area
.contains(event
->x(), event
->y())) {
920 } else if ((a
+ b
) * pos
> p2
) {
952 if (a
+ b
+ c
== 10) {
953 dsend_packet_player_rates(&client
.conn
, qMax(c
, 0) * 10,
954 qMax(a
, 0) * 10, qMax(b
, 0) * 10);
959 /**************************************************************************
960 Mouse press event for information label.
961 Checks if end turn has been clicked or rates dialog
962 (in rates dialog raises luxury only, rest can be easily changed by wheel)
963 **************************************************************************/
964 void info_label::mousePressEvent(QMouseEvent
*event
)
967 QPoint
p(event
->x(), event
->y());
968 int pos
= rates_label
->width() / 10;
969 int p2
= event
->x() - rates_area
.left();
974 p
= this->mapToGlobal(p
);
975 if (client_is_global_observer()){
979 b
= client
.conn
.playing
->economic
.science
/ 10;
980 if (event
->button() == Qt::LeftButton
) {
981 if (end_button_area
.contains(event
->x(), event
->y())) {
983 end_turn_button
= true;
985 if (rates_area
.contains(event
->x(), event
->y())) {
992 dsend_packet_player_rates(&client
.conn
, (10 - a
- b
) * 10,
998 /**************************************************************************
999 Paint event for information label
1000 **************************************************************************/
1001 void info_label::paint(QPainter
*painter
, QPaintEvent
*event
)
1006 ufont
->setPixelSize(14);
1008 fm
= new QFontMetrics(*ufont
);
1009 QPainter::CompositionMode comp_mode
= painter
->compositionMode();
1013 pen
.setColor(QColor(232, 255, 0));
1014 painter
->setBrush(QColor(0, 0, 0, 135));
1015 painter
->drawRect(0, 0, width(), height());
1016 painter
->setPen(pen
);
1017 painter
->setFont(*ufont
);
1018 h
= h
+ fm
->height() + 5;
1019 w
= fm
->width(turn_info
);
1020 w
= (width() - w
) / 2;
1021 painter
->drawText(w
, h
, turn_info
);
1022 h
= h
+ fm
->height() + 5;
1023 w
= fm
->width(time_label
);
1024 w
= (width() - w
) / 2;
1025 painter
->drawText(w
, h
, time_label
);
1026 w
= fm
->width(eco_info
);
1027 w
= (width() - w
) / 2;
1028 h
= h
+ fm
->height() + 5;
1029 painter
->drawText(w
, h
, eco_info
);
1030 h
= h
+ indicator_icons
->height();
1031 w
= rates_label
->width();
1032 w
= (width() - w
) / 2;
1033 indicator_area
.setRect(w
, h
, indicator_icons
->width(),
1034 indicator_icons
->height());
1035 painter
->drawPixmap(w
, h
, *indicator_icons
);
1036 h
= h
+ rates_label
->height() + 6;
1037 rates_area
.setRect(w
, h
, rates_label
->width(), rates_label
->height());
1038 painter
->drawPixmap(w
, h
, *rates_label
);
1039 h
= h
+ end_turn_pix
->height() + 6;
1040 w
= end_turn_pix
->width();
1041 w
= (width() - w
) / 2;
1042 end_button_area
.setRect(w
, h
, end_turn_pix
->width(),
1043 end_turn_pix
->height() - 10);
1044 if (highlight_end_button
== true) {
1045 painter
->setCompositionMode(QPainter::CompositionMode_HardLight
);
1047 if (end_turn_button
== false) {
1048 painter
->setCompositionMode(QPainter::CompositionMode_DestinationOver
);
1050 painter
->drawPixmap(w
, h
, *end_turn_pix
);
1051 painter
->setCompositionMode(comp_mode
);
1055 /**************************************************************************
1056 Paint event for information label, redirects event to paint(...)
1057 **************************************************************************/
1058 void info_label::paintEvent(QPaintEvent
*event
)
1062 painter
.begin(this);
1063 paint(&painter
, event
);
1067 /**************************************************************************
1068 Updates size and size of objects
1069 **************************************************************************/
1070 void info_label::info_update()
1075 ufont
->setPixelSize(14);
1076 fm
= new QFontMetrics(*ufont
);
1077 w
= qMax(w
, fm
->width(eco_info
));
1078 w
= qMax(w
, fm
->width(turn_info
));
1079 w
= qMax(w
, fm
->width(time_label
));
1080 if (rates_label
!= NULL
&& indicator_icons
!= NULL
) {
1081 h
= 3 * (fm
->height() + 5) + rates_label
->height() +
1082 indicator_icons
->height();
1083 w
= qMax(w
, rates_label
->width());
1084 w
= qMax(w
, indicator_icons
->width());
1086 ufont
->setPixelSize(20);
1087 h
= h
+ fm
->height() + 20;
1088 setFixedWidth(h
+ 20);
1089 setFixedHeight(w
+ 20);
1094 /****************************************************************************
1095 Typically an info box is provided to tell the player about the state
1096 of their civilization. This function is called when the label is
1098 ****************************************************************************/
1099 void update_info_label(void)
1102 QString s
= QString::fromLatin1(textyear(game
.info
.year
)) + " ("
1103 + _("Turn") + ":" + QString::number(game
.info
.turn
) + ")";
1104 gui()->game_info_label
->set_turn_info(s
);
1105 set_indicator_icons(client_research_sprite(),
1106 client_warming_sprite(),
1107 client_cooling_sprite(), client_government_sprite());
1108 if (client
.conn
.playing
!= NULL
) {
1109 eco_info
= QString(_("Gold")) + ": "
1110 + QString::number(client
.conn
.playing
->economic
.gold
);
1111 gui()->game_info_label
->set_eco_info(eco_info
);
1113 gui()->game_info_label
->set_rates_pixmap();
1114 gui()->game_info_label
->info_update();
1117 /****************************************************************************
1118 Update the information label which gives info on the current unit
1119 and the tile under the current unit, for specified unit. Note that
1120 in practice punit is always the focus unit.
1122 Clears label if punit is NULL.
1124 Typically also updates the cursor for the map_canvas (this is
1125 related because the info label may includes "select destination"
1126 prompt etc). And it may call update_unit_pix_label() to update the
1127 icons for units on this tile.
1128 ****************************************************************************/
1129 void update_unit_info_label(struct unit_list
*punitlist
)
1131 gui()->unitinfo_wdg
->uupdate(punitlist
);
1134 /****************************************************************************
1135 Update the mouse cursor. Cursor type depends on what user is doing and
1137 ****************************************************************************/
1138 void update_mouse_cursor(enum cursor_type new_cursor_type
)
1143 /****************************************************************************
1144 Update the timeout display. The timeout is the time until the turn
1146 ****************************************************************************/
1147 void qtg_update_timeout_label(void)
1149 gui()->game_info_label
->set_time_info (
1150 QString::fromLatin1(get_timeout_label_text()));
1153 /****************************************************************************
1154 If do_restore is false it should change the turn button style (to
1155 draw the user's attention to it). If called regularly from a timer
1156 this will give a blinking turn done button. If do_restore is true
1157 this should reset the turn done button to the default style.
1158 ****************************************************************************/
1159 void update_turn_done_button(bool do_restore
)
1161 if (!get_turn_done_button_state()) {
1166 gui()->game_info_label
->end_turn_button
= true;
1171 /**************************************************************************
1172 Sets indicator icons in information label
1173 It assumes all icons have the same size
1174 **************************************************************************/
1175 void info_label::set_indicator_icons(QPixmap
* bulb
, QPixmap
* sol
,
1176 QPixmap
* flake
, QPixmap
* gov
)
1179 QRect
source_rect(0, 0, bulb
->width(), bulb
->height());
1180 QRect
dest_rect(0, 0, bulb
->width(), bulb
->height());
1182 if (indicator_icons
== NULL
) {
1183 indicator_icons
= new QPixmap(7 * bulb
->width(), bulb
->height());
1185 indicator_icons
->fill(Qt::transparent
);
1187 p
.begin(indicator_icons
);
1188 dest_rect
.setLeft(3 * bulb
->width());
1189 p
.drawPixmap(dest_rect
, *bulb
, source_rect
);
1190 dest_rect
.setLeft(4 * bulb
->width());
1191 p
.drawPixmap(dest_rect
, *sol
, source_rect
);
1192 dest_rect
.setLeft(5 * bulb
->width());
1193 p
.drawPixmap(dest_rect
, *flake
, source_rect
);
1194 dest_rect
.setLeft(6 * bulb
->width());
1195 p
.drawPixmap(dest_rect
, *gov
, source_rect
);
1199 /****************************************************************************
1200 Set information for the indicator icons typically shown in the main
1201 client window. The parameters tell which sprite to use for the
1203 ****************************************************************************/
1204 void set_indicator_icons(struct sprite
*bulb
, struct sprite
*sol
,
1205 struct sprite
*flake
, struct sprite
*gov
)
1207 gui()->game_info_label
->set_indicator_icons(bulb
->pm
, sol
->pm
, flake
->pm
,
1211 /****************************************************************************
1212 Return a canvas that is the overview window.
1213 ****************************************************************************/
1214 struct canvas
*get_overview_window(void)
1219 /****************************************************************************
1220 Flush the given part of the canvas buffer (if there is one) to the
1222 ****************************************************************************/
1223 void flush_mapcanvas(int canvas_x
, int canvas_y
,
1224 int pixel_width
, int pixel_height
)
1226 gui()->mapview_wdg
->repaint(canvas_x
, canvas_y
, pixel_width
, pixel_height
);
1229 /****************************************************************************
1230 Mark the rectangular region as "dirty" so that we know to flush it
1232 ****************************************************************************/
1233 void dirty_rect(int canvas_x
, int canvas_y
,
1234 int pixel_width
, int pixel_height
)
1236 if (mapview_is_frozen()) {
1239 if (num_dirty_rects
< MAX_DIRTY_RECTS
) {
1240 dirty_rects
[num_dirty_rects
].setX(canvas_x
);
1241 dirty_rects
[num_dirty_rects
].setY(canvas_y
);
1242 dirty_rects
[num_dirty_rects
].setWidth(pixel_width
);
1243 dirty_rects
[num_dirty_rects
].setHeight(pixel_height
);
1248 /****************************************************************************
1249 Mark the entire screen area as "dirty" so that we can flush it later.
1250 ****************************************************************************/
1251 void dirty_all(void)
1253 if (mapview_is_frozen()) {
1256 num_dirty_rects
= MAX_DIRTY_RECTS
;
1259 /****************************************************************************
1260 Flush all regions that have been previously marked as dirty. See
1261 dirty_rect and dirty_all. This function is generally called after we've
1262 processed a batch of drawing operations.
1263 ****************************************************************************/
1264 void flush_dirty(void)
1266 if (mapview_is_frozen()) {
1269 if (num_dirty_rects
== MAX_DIRTY_RECTS
) {
1270 flush_mapcanvas(0, 0, gui()->mapview_wdg
->width(),
1271 gui()->mapview_wdg
->height());
1274 for (i
= 0; i
< num_dirty_rects
; i
++) {
1275 flush_mapcanvas(dirty_rects
[i
].x(), dirty_rects
[i
].y(),
1276 dirty_rects
[i
].width(), dirty_rects
[i
].height());
1279 num_dirty_rects
= 0;
1282 /****************************************************************************
1283 Do any necessary synchronization to make sure the screen is up-to-date.
1284 The canvas should have already been flushed to screen via flush_dirty -
1285 all this function does is make sure the hardware has caught up.
1286 ****************************************************************************/
1287 void gui_flush(void)
1289 gui()->mapview_wdg
->update();
1292 /****************************************************************************
1293 Update (refresh) the locations of the mapview scrollbars (if it uses
1295 ****************************************************************************/
1296 void update_map_canvas_scrollbars(void)
1298 gui()->mapview_wdg
->update();
1301 /****************************************************************************
1302 Update the size of the sliders on the scrollbars.
1303 ****************************************************************************/
1304 void update_map_canvas_scrollbars_size(void)
1309 /****************************************************************************
1310 Update (refresh) all city descriptions on the mapview.
1311 ****************************************************************************/
1312 void update_city_descriptions(void)
1314 update_map_canvas_visible();
1317 /**************************************************************************
1318 Put overlay tile to pixmap
1319 **************************************************************************/
1320 void pixmap_put_overlay_tile(int canvas_x
, int canvas_y
,
1321 struct sprite
*ssprite
)
1330 /****************************************************************************
1331 Draw a cross-hair overlay on a tile.
1332 ****************************************************************************/
1333 void put_cross_overlay_tile(struct tile
*ptile
)
1335 int canvas_x
, canvas_y
;
1337 if (tile_to_canvas_pos(&canvas_x
, &canvas_y
, ptile
)) {
1338 pixmap_put_overlay_tile(canvas_x
, canvas_y
,
1339 get_attention_crosshair_sprite(tileset
));
1344 /****************************************************************************
1346 ****************************************************************************/
1347 void draw_selection_rectangle(int canvas_x
, int canvas_y
, int w
, int h
)
1352 /****************************************************************************
1353 This function is called when the tileset is changed.
1354 ****************************************************************************/
1355 void tileset_changed(void)
1357 gui()->unitinfo_wdg
->update_arrow_pix();
1358 destroy_city_dialog();
1361 /****************************************************************************
1362 Return the dimensions of the area (container widget; maximum size) for
1364 ****************************************************************************/
1365 void get_overview_area_dimensions(int *width
, int *height
)
1367 *width
= ::gui()->minimapview_wdg
->width();
1368 *height
= ::gui()->minimapview_wdg
->height();
1371 /****************************************************************************
1372 Called when the map size changes. This may be used to change the
1373 size of the GUI element holding the overview canvas. The
1374 overview.width and overview.height are updated if this function is
1376 It's used for first creation of overview only, later overview stays the
1377 same size, scaled by qt-specific function.
1378 ****************************************************************************/
1379 void overview_size_changed(void)
1381 int map_width
, map_height
, over_width
, over_height
, ow
, oh
;
1383 map_width
= gui()->mapview_wdg
->width();
1384 map_height
= gui()->mapview_wdg
->height();
1385 over_width
= overview
.width
;
1386 over_height
= overview
.height
;
1388 /* lower overview width size to max 20% of map width, keep aspect ratio*/
1389 if (map_width
/over_width
< 5){
1390 ratio
= static_cast<float>(map_width
)/over_width
;
1391 ow
= static_cast<float>(map_width
)/5.0;
1392 ratio
= static_cast<float>(over_width
)/ow
;
1393 over_height
=static_cast<float>(over_height
)/ratio
;
1396 /* if height still too high lower again */
1397 if (map_height
/over_height
< 5){
1398 ratio
= static_cast<float>(map_height
)/over_height
;
1399 oh
= static_cast<float>(map_height
)/5.0;
1400 ratio
= static_cast<float>(over_height
)/oh
;
1401 over_width
=static_cast<float>(over_width
)/ratio
;
1404 /* make minimap not less than 48x48 */
1405 if (over_width
< 48) {
1408 if (over_height
< 48) {
1411 gui()->minimapview_wdg
->resize(over_width
, over_height
);
1414 /**************************************************************************
1415 Constructor for unit_label (shows information about unit) and
1416 might call for unit_selection_dialog
1417 It uses default font for display text with modified size to fit on screen
1418 **************************************************************************/
1419 unit_label::unit_label(QWidget
*parent
)
1426 selection_area
.setWidth(0);
1427 highlight_pix
= false;
1428 setMouseTracking(true);
1433 /**************************************************************************
1434 Updates units label (pixmap and text) and calls update() to redraw
1435 Font size is fixed to match widget size.
1436 **************************************************************************/
1437 void unit_label::uupdate(unit_list
*punits
)
1440 struct unit
*punit
= unit_list_get(punits
, 0);
1441 struct player
*owner
;
1442 struct canvas
*unit_pixmap
;
1446 if (unit_list_size(punits
) == 0) {
1455 } else if (unit_list_size(punits
) == 1) {
1456 if (unit_list_size(unit_tile(punit
)->units
) > 1) {
1461 ufont
->setPixelSize(height() / 3);
1463 unit_label1
= get_unit_info_label_text1(punits
);
1464 owner
= unit_owner(punit
);
1465 pcity
= player_city_by_number(owner
, punit
->homecity
);
1466 if (pcity
!= NULL
&& unit_list_size(punits
) == 1) {
1467 unit_label1
= unit_label1
+ " " + _("from") + " ";
1468 unit_label1
+= QString(city_name(pcity
));
1470 unit_label2
= QString(unit_activity_text(unit_list_get(punits
, 0)))
1471 + QString(" ") + QString(_("HP")) + QString(": ")
1472 + QString::number(punit
->hp
) + QString("/")
1473 + QString::number(unit_type(punit
)->hp
);
1479 punit
= head_of_units_in_focus();
1481 unit_pixmap
= qtg_canvas_create(tileset_full_tile_width(tileset
),
1482 tileset_tile_height(tileset
) * 3 / 2);
1483 unit_pixmap
->map_pixmap
.fill(Qt::transparent
);
1484 put_unit(punit
, unit_pixmap
, 0, 0);
1485 pix
= &unit_pixmap
->map_pixmap
;
1486 *pix
= pix
->scaledToHeight(height());
1487 w_width
= pix
->width() + 1;
1489 QFontMetrics
fm(*ufont
);
1490 if (arrow_pix
== NULL
) {
1491 arrow_pix
= get_arrow_sprite(tileset
, ARROW_PLUS
)->pm
;
1492 *arrow_pix
= arrow_pix
->scaledToHeight(height());
1494 w_width
+= qMax(fm
.width(unit_label1
), fm
.width(unit_label2
));
1495 if (one_unit
== false) {
1496 w_width
+= arrow_pix
->width() + 1;
1499 setFixedWidth(w_width
);
1500 move(0, parentWidget()->height() - height());
1504 /**************************************************************************
1505 Mouse press event for unit label, it calls unit selector
1506 **************************************************************************/
1507 void unit_label::mousePressEvent(QMouseEvent
*event
)
1509 struct unit
*punit
= unit_list_get(ul_units
, 0);
1511 if (event
->button() == Qt::LeftButton
) {
1512 if (selection_area
.contains(event
->x(), event
->y())) {
1513 if (punit
!= NULL
&& selection_area
.width() > 0) {
1514 unit_select_dialog_popup(unit_tile(punit
));
1520 /**************************************************************************
1521 Mouse move event for unit label, used for highlighting pixmap of
1523 **************************************************************************/
1524 void unit_label::mouseMoveEvent(QMouseEvent
*event
)
1526 bool redraw
= false;
1528 if (selection_area
.contains(event
->x(), event
->y())) {
1529 if (highlight_pix
== false) {
1532 highlight_pix
= true;
1534 if (highlight_pix
== true) {
1537 highlight_pix
= false;
1544 /**************************************************************************
1545 Paint event for unit label
1546 **************************************************************************/
1547 void unit_label::paint(QPainter
*painter
, QPaintEvent
*event
)
1550 QPainter::CompositionMode comp_mode
= painter
->compositionMode();
1553 selection_area
.setWidth(0);
1555 pen
.setColor(QColor(232, 255, 0));
1556 painter
->setBrush(QColor(0, 0, 0, 135));
1557 painter
->drawRect(0, 0, w_width
, height());
1558 painter
->setFont(*ufont
);
1559 painter
->setPen(pen
);
1561 painter
->drawPixmap(0, (height() - pix
->height()) / 2, *pix
);
1562 w
= pix
->width() + 1;
1563 if (one_unit
== false) {
1564 if (highlight_pix
) {
1565 painter
->setCompositionMode(QPainter::CompositionMode_HardLight
);
1567 painter
->drawPixmap(w
, 0, *arrow_pix
);
1568 selection_area
.setRect(w
, 5, arrow_pix
->width(),
1569 arrow_pix
->height() - 10);
1570 w
= w
+ arrow_pix
->width() + 1;
1572 painter
->setCompositionMode(comp_mode
);
1573 painter
->drawText(w
, height() / 2.5, unit_label1
);
1574 painter
->drawText(w
, height() - 8, unit_label2
);
1576 painter
->drawText(5, height() / 3 + 5, _("No units selected."));
1580 /**************************************************************************
1581 Updates unit selector pixmap, necessary when changing tileset
1582 **************************************************************************/
1583 void unit_label::update_arrow_pix()
1585 arrow_pix
= get_arrow_sprite(tileset
, ARROW_PLUS
)->pm
;
1586 *arrow_pix
= arrow_pix
->scaledToHeight(height());
1589 /**************************************************************************
1590 Paint event for unit label, it calls paint(...)
1591 **************************************************************************/
1592 void unit_label::paintEvent(QPaintEvent
*event
)
1596 painter
.begin(this);
1597 paint(&painter
, event
);
1601 /**************************************************************************
1602 Updates menu for unit label
1603 **************************************************************************/
1604 void unit_label::update_menu()
1606 /* PORTME, if needed */
1608 /**************************************************************************
1609 Sets the position of the overview scroll window based on mapview position.
1610 **************************************************************************/
1611 void update_overview_scroll_window_pos(int x
, int y
)
1617 /****************************************************************************
1618 Return whether the map should be drawn or not.
1619 ****************************************************************************/
1620 bool mapview_is_frozen(void)
1622 return (0 < mapview_frozen_level
);
1626 /****************************************************************************
1627 Freeze the drawing of the map.
1628 ****************************************************************************/
1629 void mapview_freeze(void)
1631 mapview_frozen_level
++;
1634 /****************************************************************************
1635 Thaw the drawing of the map.
1636 ****************************************************************************/
1637 void mapview_thaw(void)
1639 if (1 < mapview_frozen_level
) {
1640 mapview_frozen_level
--;
1642 fc_assert(0 < mapview_frozen_level
);
1643 mapview_frozen_level
= 0;
1648 /**************************************************************************
1649 Constructor for info_tile
1650 **************************************************************************/
1651 info_tile::info_tile(struct tile
*ptile
, QWidget
*parent
): QLabel(parent
)
1654 info_font
= gui()->fc_fonts
.get_font("gui_qt_font_comment_label");
1659 /**************************************************************************
1660 Calculates size of info_tile and moves it to be fully visible
1661 **************************************************************************/
1662 void info_tile::calc_size()
1664 QFontMetrics
fm(*info_font
);
1666 int hh
= tileset_tile_height(tileset
);
1672 str
= popup_info_text(itile
);
1673 str_list
= str
.split("\n");
1675 foreach(str
, str_list
) {
1676 w
= qMax(w
, fm
.width(str
));
1678 setFixedHeight(str_list
.count() * (fm
.height() + 5));
1679 setFixedWidth(w
+ 10);
1680 if (tile_to_canvas_pos(&x
, &y
, itile
)) {
1683 if (y
- height() > 0) {
1684 fin_y
= y
- height();
1688 if (x
+ width() > parentWidget()->width()) {
1689 fin_x
= parentWidget()->width() - width();
1695 /**************************************************************************
1696 Redirected paint event for info_tile
1697 **************************************************************************/
1698 void info_tile::paint(QPainter
*painter
, QPaintEvent
*event
)
1701 QFontMetrics
fm(*info_font
);
1707 pen
.setColor(QColor(232, 255, 0));
1708 painter
->setBrush(QColor(0, 0, 0, 205));
1709 painter
->drawRect(0, 0, width(), height());
1710 painter
->setPen(pen
);
1711 painter
->setFont(*info_font
);
1712 for (int i
= 0; i
< str_list
.count(); i
++) {
1713 painter
->drawText(5, pos
, str_list
.at(i
));
1718 /**************************************************************************
1719 Paint event for info_tile
1720 **************************************************************************/
1721 void info_tile::paintEvent(QPaintEvent
*event
)
1725 painter
.begin(this);
1726 paint(&painter
, event
);