JSON protocol: fix field_addr memory leak.
[freeciv.git] / client / gui-qt / canvas.cpp
blob78ee79c2a1140f71ce5769f5c8bf0146535b5c40
1 /**********************************************************************
2 Freeciv - Copyright (C) 1996-2005 - Freeciv Development Team
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.
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 ***********************************************************************/
14 #ifdef HAVE_CONFIG_H
15 #include <fc_config.h>
16 #endif
18 // Qt
19 #include <QFontMetrics>
20 #include <QPainter>
22 // qt-client
23 #include "canvas.h"
24 #include "colors.h"
25 #include "fc_client.h"
26 #include "fonts.h"
27 #include "qtg_cxxside.h"
28 #include "sprite.h"
30 static QFont *get_font(enum client_font font);
31 /****************************************************************************
32 Create a canvas of the given size.
33 ****************************************************************************/
34 struct canvas *qtg_canvas_create(int width, int height)
36 struct canvas *store = new canvas;
38 store->map_pixmap = QPixmap(width, height);
39 return store;
42 /****************************************************************************
43 Free any resources associated with this canvas and the canvas struct
44 itself.
45 ****************************************************************************/
46 void qtg_canvas_free(struct canvas *store)
48 delete store;
51 /****************************************************************************
52 Set canvas zoom for future drawing operations.
53 ****************************************************************************/
54 void qtg_canvas_set_zoom(struct canvas *store, float zoom)
56 /* Qt-client has no zoom support */
59 /****************************************************************************
60 This gui has zoom support.
61 ****************************************************************************/
62 bool qtg_has_zoom_support()
64 return FALSE;
67 /****************************************************************************
68 Copies an area from the source canvas to the destination canvas.
69 ****************************************************************************/
70 void qtg_canvas_copy(struct canvas *dest, struct canvas *src,
71 int src_x, int src_y, int dest_x, int dest_y, int width,
72 int height)
75 QRectF source_rect(src_x, src_y, width, height);
76 QRectF dest_rect(dest_x, dest_y, width, height);
77 QPainter p;
79 if (!width || !height) {
80 return;
83 p.begin(&dest->map_pixmap);
84 p.drawPixmap(dest_rect, src->map_pixmap, source_rect);
85 p.end();
89 /****************************************************************************
90 Copies an area from the source pixmap to the destination pixmap.
91 ****************************************************************************/
92 void pixmap_copy(QPixmap *dest, QPixmap *src, int src_x, int src_y,
93 int dest_x, int dest_y, int width, int height)
95 QRectF source_rect(src_x, src_y, width, height);
96 QRectF dest_rect(dest_x, dest_y, width, height);
97 QPainter p;
99 if (!width || !height) {
100 return;
103 p.begin(dest);
104 p.drawPixmap(dest_rect, *src, source_rect);
105 p.end();
108 /****************************************************************************
109 Copies an area from the source image to the destination image.
110 ****************************************************************************/
111 void image_copy(QImage *dest, QImage *src, int src_x, int src_y,
112 int dest_x, int dest_y, int width, int height)
114 QRectF source_rect(src_x, src_y, width, height);
115 QRectF dest_rect(dest_x, dest_y, width, height);
116 QPainter p;
118 if (!width || !height) {
119 return;
122 p.begin(dest);
123 p.drawImage(dest_rect, *src, source_rect);
124 p.end();
127 /****************************************************************************
128 Draw some or all of a sprite onto the canvas.
129 ****************************************************************************/
130 void qtg_canvas_put_sprite(struct canvas *pcanvas,
131 int canvas_x, int canvas_y,
132 struct sprite *sprite,
133 int offset_x, int offset_y, int width, int height)
135 QPainter p;
137 p.begin(&pcanvas->map_pixmap);
138 p.drawPixmap(canvas_x, canvas_y, *sprite->pm, offset_x, offset_y, width, height);
139 p.end();
142 /****************************************************************************
143 Draw a full sprite onto the canvas.
144 ****************************************************************************/
145 void qtg_canvas_put_sprite_full(struct canvas *pcanvas,
146 int canvas_x, int canvas_y,
147 struct sprite *sprite)
149 int width, height;
151 get_sprite_dimensions(sprite, &width, &height);
152 canvas_put_sprite(pcanvas, canvas_x, canvas_y, sprite,
153 0, 0, width, height);
156 /****************************************************************************
157 Draw a full sprite onto the canvas. If "fog" is specified draw it with
158 fog.
159 ****************************************************************************/
160 void qtg_canvas_put_sprite_fogged(struct canvas *pcanvas,
161 int canvas_x, int canvas_y,
162 struct sprite *psprite,
163 bool fog, int fog_x, int fog_y)
165 QPainter p;
167 p.begin(&pcanvas->map_pixmap);
168 p.setCompositionMode(QPainter::CompositionMode_Difference);
169 p.setOpacity(0.5);
170 p.drawPixmap(canvas_x, canvas_y, *psprite->pm);
171 p.end();
174 /****************************************************************************
175 Draw a filled-in colored rectangle onto canvas.
176 ****************************************************************************/
177 void qtg_canvas_put_rectangle(struct canvas *pcanvas,
178 struct color *pcolor,
179 int canvas_x, int canvas_y,
180 int width, int height)
183 QBrush brush(pcolor->qcolor);
184 QPen pen(pcolor->qcolor);
185 QPainter p;
187 p.begin(&pcanvas->map_pixmap);
188 p.setPen(pen);
189 p.setBrush(brush);
190 if (width == 1 && height == 1) {
191 p.drawPoint(canvas_x, canvas_y);
192 } else if (width == 1) {
193 p.drawLine(canvas_x, canvas_y, canvas_x, canvas_y + height -1);
194 } else if (height == 1) {
195 p.drawLine(canvas_x, canvas_y, canvas_x + width - 1, canvas_y);
196 } else {
197 p.drawRect(canvas_x, canvas_y, width, height);
200 p.end();
203 /****************************************************************************
204 Fill the area covered by the sprite with the given color.
205 ****************************************************************************/
206 void qtg_canvas_fill_sprite_area(struct canvas *pcanvas,
207 struct sprite *psprite, struct color *pcolor,
208 int canvas_x, int canvas_y)
210 int width, height;
212 get_sprite_dimensions(psprite, &width, &height);
213 qtg_canvas_put_rectangle(pcanvas, pcolor, canvas_x, canvas_y, width, height);
216 /****************************************************************************
217 Draw a 1-pixel-width colored line onto the canvas.
218 ****************************************************************************/
219 void qtg_canvas_put_line(struct canvas *pcanvas, struct color *pcolor,
220 enum line_type ltype, int start_x, int start_y,
221 int dx, int dy)
223 QPen pen;
224 QPainter p;
226 pen.setColor(pcolor->qcolor);
228 switch (ltype) {
229 case LINE_NORMAL:
230 pen.setWidth(1);
231 break;
232 case LINE_BORDER:
233 pen.setStyle(Qt::DashLine);
234 pen.setDashOffset(4);
235 pen.setWidth(1);
236 break;
237 case LINE_TILE_FRAME:
238 pen.setWidth(2);
239 break;
240 case LINE_GOTO:
241 pen.setWidth(2);
242 break;
243 default:
244 pen.setWidth(1);
245 break;
248 p.begin(&pcanvas->map_pixmap);
249 p.setPen(pen);
250 p.setRenderHint(QPainter::Antialiasing);
251 p.drawLine(start_x, start_y, start_x + dx, start_y + dy);
252 p.end();
255 /****************************************************************************
256 Draw a 1-pixel-width colored curved line onto the canvas.
257 ****************************************************************************/
258 void qtg_canvas_put_curved_line(struct canvas *pcanvas, struct color *pcolor,
259 enum line_type ltype, int start_x, int start_y,
260 int dx, int dy)
262 QPen pen;
263 pen.setColor(pcolor->qcolor);
264 QPainter p;
265 QPainterPath path;
267 switch (ltype) {
268 case LINE_NORMAL:
269 pen.setWidth(1);
270 break;
271 case LINE_BORDER:
272 pen.setStyle(Qt::DashLine);
273 pen.setDashOffset(4);
274 pen.setWidth(2);
275 break;
276 case LINE_TILE_FRAME:
277 pen.setWidth(2);
278 break;
279 case LINE_GOTO:
280 pen.setWidth(2);
281 break;
282 default:
283 pen.setWidth(1);
284 break;
287 p.begin(&pcanvas->map_pixmap);
288 p.setRenderHints(QPainter::Antialiasing);
289 p.setPen(pen);
291 path.moveTo(start_x, start_y);
292 path.cubicTo(start_x + dx / 2, start_y, start_x, start_y + dy / 2,
293 start_x + dx, start_y + dy);
294 p.drawPath(path);
295 p.end();
298 /****************************************************************************
299 Return the size of the given text in the given font. This size should
300 include the ascent and descent of the text. Either of width or height
301 may be NULL in which case those values simply shouldn't be filled out.
302 ****************************************************************************/
303 void qtg_get_text_size(int *width, int *height,
304 enum client_font font, const char *text)
306 QFont *afont;
307 QFontMetrics *fm;
309 afont = get_font(font);
310 fm = new QFontMetrics(*afont);
311 if (width) {
312 *width = fm->width(QString::fromUtf8(text));
315 if (height) {
316 *height = fm->height();
318 delete fm;
321 /****************************************************************************
322 Draw the text onto the canvas in the given color and font. The canvas
323 position does not account for the ascent of the text; this function must
324 take care of this manually. The text will not be NULL but may be empty.
325 ****************************************************************************/
326 void qtg_canvas_put_text(struct canvas *pcanvas, int canvas_x, int canvas_y,
327 enum client_font font, struct color *pcolor,
328 const char *text)
330 QPainter p;
331 QPen pen;
332 QFont *afont;
333 QColor color(pcolor->qcolor);
334 QFontMetrics *fm;
336 afont = get_font(font);
337 pen.setColor(color);
338 fm = new QFontMetrics(*afont);
340 p.begin(&pcanvas->map_pixmap);
341 p.setPen(pen);
342 p.setFont(*afont);
343 p.drawText(canvas_x, canvas_y + fm->ascent(), QString::fromUtf8(text));
344 p.end();
345 delete fm;
348 /****************************************************************************
349 Returns given font
350 ****************************************************************************/
351 QFont *get_font(client_font font)
353 QFont *qf;
354 int ssize;
356 switch (font) {
357 case FONT_CITY_NAME:
358 qf = fc_font::instance()->get_font(fonts::city_names);
359 if (gui()->map_scale != 1.0f) {
360 ssize = ceil(gui()->map_scale * fc_font::instance()->city_fontsize);
361 if (qf->pointSize() != ssize) {
362 qf->setPointSize(ssize);
365 break;
366 case FONT_CITY_PROD:
367 qf = fc_font::instance()->get_font(fonts::city_productions);
368 if (gui()->map_scale != 1.0f) {
369 ssize = ceil(gui()->map_scale * fc_font::instance()->prod_fontsize);
370 if (qf->pointSize() != ssize) {
371 qf->setPointSize(ssize);
374 break;
375 case FONT_REQTREE_TEXT:
376 qf = fc_font::instance()->get_font(fonts::reqtree_text);
377 break;
378 case FONT_COUNT:
379 qf = NULL;
380 break;
381 default:
382 qf = NULL;
383 break;
385 return qf;
388 /****************************************************************************
389 Return rectangle containing pure image (crops transparency)
390 ****************************************************************************/
391 QRect zealous_crop_rect(QImage &p)
393 int r, t, b, l;
394 int oh, ow;
396 ow = p.width();
397 l = ow;
398 r = 0;
399 oh = p.height();
400 t = oh;
401 b = 0;
402 for (int y = 0; y < oh; y++) {
403 QRgb row[ow];
404 bool row_filled = false;
405 int x;
407 /* Copy to a location with guaranteed QRgb suitable alignment.
408 * That fixes clang compiler warning. */
409 memcpy(row, p.scanLine(y), ow * sizeof(QRgb));
411 for (x = 0; x < ow; ++x) {
412 if (qAlpha(row[x])) {
413 row_filled = true;
414 r = qMax(r, x);
415 if (l > x) {
416 l = x;
417 x = r;
421 if (row_filled) {
422 t = qMin(t, y);
423 b = y;
426 return QRect(l, t, r - l, b - t);