Qt client - remove right click menu from end turn sidebar
[freeciv.git] / client / gui-gtk-2.0 / canvas.c
blobfe1bc679a24a4c38e77a5f26e016050b23bc3107
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 #include "canvas.h"
19 #include "colors.h"
20 #include "gui_main.h"
21 #include "mapview.h"
23 /****************************************************************************
24 Create a canvas of the given size.
25 ****************************************************************************/
26 struct canvas *canvas_create(int width, int height)
28 struct canvas *result = fc_malloc(sizeof(*result));
30 result->type = CANVAS_PIXMAP;
31 result->v.pixmap = gdk_pixmap_new(root_window, width, height, -1);
32 return result;
35 /****************************************************************************
36 Free any resources associated with this canvas and the canvas struct
37 itself.
38 ****************************************************************************/
39 void canvas_free(struct canvas *store)
41 if (store->type == CANVAS_PIXMAP) {
42 g_object_unref(store->v.pixmap);
44 free(store);
47 /****************************************************************************
48 Set canvas zoom for future drawing operations.
49 ****************************************************************************/
50 void canvas_set_zoom(struct canvas *store, float zoom)
52 /* gtk2-client has no zoom support */
55 /****************************************************************************
56 This gui has zoom support.
57 ****************************************************************************/
58 bool has_zoom_support(void)
60 return FALSE;
63 /****************************************************************************
64 Copies an area from the source canvas to the destination canvas.
65 ****************************************************************************/
66 void canvas_copy(struct canvas *dest, struct canvas *src,
67 int src_x, int src_y, int dest_x, int dest_y,
68 int width, int height)
70 if (dest->type == src->type) {
71 if (src->type == CANVAS_PIXMAP) {
72 gdk_draw_drawable(dest->v.pixmap, fill_bg_gc, src->v.pixmap,
73 src_x, src_y, dest_x, dest_y, width, height);
78 /****************************************************************************
79 Place part of a (possibly masked) sprite on a pixmap.
80 ****************************************************************************/
81 static void pixmap_put_sprite(GdkDrawable *pixmap,
82 int pixmap_x, int pixmap_y,
83 struct sprite *ssprite,
84 int offset_x, int offset_y,
85 int width, int height)
87 if (ssprite->pixmap) {
88 if (ssprite->mask) {
89 gdk_gc_set_clip_origin(civ_gc, pixmap_x, pixmap_y);
90 gdk_gc_set_clip_mask(civ_gc, ssprite->mask);
93 gdk_draw_drawable(pixmap, civ_gc, ssprite->pixmap,
94 offset_x, offset_y,
95 pixmap_x + offset_x, pixmap_y + offset_y,
96 MIN(width, MAX(0, ssprite->width - offset_x)),
97 MIN(height, MAX(0, ssprite->height - offset_y)));
99 gdk_gc_set_clip_mask(civ_gc, NULL);
100 } else {
101 gdk_draw_pixbuf(pixmap, civ_gc, ssprite->pixbuf,
102 offset_x, offset_y,
103 pixmap_x + offset_x, pixmap_y + offset_y,
104 MIN(width, MAX(0, ssprite->width - offset_x)),
105 MIN(height, MAX(0, ssprite->height - offset_y)),
106 GDK_RGB_DITHER_NONE, 0, 0);
110 /****************************************************************************
111 Draw some or all of a sprite onto the mapview or citydialog canvas.
112 ****************************************************************************/
113 void canvas_put_sprite(struct canvas *pcanvas,
114 int canvas_x, int canvas_y,
115 struct sprite *sprite,
116 int offset_x, int offset_y, int width, int height)
118 switch (pcanvas->type) {
119 case CANVAS_PIXMAP:
120 pixmap_put_sprite(pcanvas->v.pixmap, canvas_x, canvas_y,
121 sprite, offset_x, offset_y, width, height);
122 break;
123 case CANVAS_PIXCOMM:
124 gtk_pixcomm_copyto(pcanvas->v.pixcomm, sprite, canvas_x, canvas_y);
125 break;
126 case CANVAS_PIXBUF:
128 GdkPixbuf *src, *dst;
130 /* FIXME: is this right??? */
131 if (canvas_x < 0) {
132 offset_x -= canvas_x;
133 canvas_x = 0;
135 if (canvas_y < 0) {
136 offset_y -= canvas_y;
137 canvas_y = 0;
141 src = sprite_get_pixbuf(sprite);
142 dst = pcanvas->v.pixbuf;
143 gdk_pixbuf_composite(src, dst, canvas_x, canvas_y,
144 MIN(width,
145 MIN(gdk_pixbuf_get_width(dst), gdk_pixbuf_get_width(src))),
146 MIN(height,
147 MIN(gdk_pixbuf_get_height(dst), gdk_pixbuf_get_height(src))),
148 canvas_x - offset_x, canvas_y - offset_y,
149 1.0, 1.0, GDK_INTERP_NEAREST, 255);
151 break;
152 default:
153 break;
157 /****************************************************************************
158 Draw a full sprite onto the mapview or citydialog canvas.
159 ****************************************************************************/
160 void canvas_put_sprite_full(struct canvas *pcanvas,
161 int canvas_x, int canvas_y,
162 struct sprite *sprite)
164 canvas_put_sprite(pcanvas, canvas_x, canvas_y, sprite,
165 0, 0, sprite->width, sprite->height);
168 /****************************************************************************
169 Draw a full sprite onto the canvas. If "fog" is specified draw it with
170 fog.
171 ****************************************************************************/
172 void canvas_put_sprite_fogged(struct canvas *pcanvas,
173 int canvas_x, int canvas_y,
174 struct sprite *psprite,
175 bool fog, int fog_x, int fog_y)
177 if (pcanvas->type == CANVAS_PIXMAP) {
178 pixmap_put_overlay_tile_draw(pcanvas->v.pixmap, canvas_x, canvas_y,
179 psprite, fog);
183 /****************************************************************************
184 Draw a filled-in colored rectangle onto the mapview or citydialog canvas.
185 ****************************************************************************/
186 void canvas_put_rectangle(struct canvas *pcanvas,
187 struct color *pcolor,
188 int canvas_x, int canvas_y, int width, int height)
190 GdkColor *col = &pcolor->color;
192 switch (pcanvas->type) {
193 case CANVAS_PIXMAP:
194 gdk_gc_set_foreground(fill_bg_gc, col);
195 gdk_draw_rectangle(pcanvas->v.pixmap, fill_bg_gc, TRUE,
196 canvas_x, canvas_y, width, height);
197 break;
198 case CANVAS_PIXCOMM:
199 gtk_pixcomm_fill(pcanvas->v.pixcomm, col);
200 break;
201 case CANVAS_PIXBUF:
202 gdk_pixbuf_fill(pcanvas->v.pixbuf,
203 ((guint32)(col->red & 0xff00) << 16)
204 | ((col->green & 0xff00) << 8) | (col->blue & 0xff00) | 0xff);
205 break;
206 default:
207 break;
211 /****************************************************************************
212 Fill the area covered by the sprite with the given color.
213 ****************************************************************************/
214 void canvas_fill_sprite_area(struct canvas *pcanvas,
215 struct sprite *psprite,
216 struct color *pcolor,
217 int canvas_x, int canvas_y)
219 if (pcanvas->type == CANVAS_PIXMAP) {
220 gdk_gc_set_clip_origin(fill_bg_gc, canvas_x, canvas_y);
221 gdk_gc_set_clip_mask(fill_bg_gc, sprite_get_mask(psprite));
222 gdk_gc_set_foreground(fill_bg_gc, &pcolor->color);
224 gdk_draw_rectangle(pcanvas->v.pixmap, fill_bg_gc, TRUE,
225 canvas_x, canvas_y, psprite->width, psprite->height);
227 gdk_gc_set_clip_mask(fill_bg_gc, NULL);
231 /****************************************************************************
232 Draw a colored line onto the mapview or citydialog canvas.
233 ****************************************************************************/
234 void canvas_put_line(struct canvas *pcanvas,
235 struct color *pcolor,
236 enum line_type ltype, int start_x, int start_y,
237 int dx, int dy)
239 if (pcanvas->type == CANVAS_PIXMAP) {
240 GdkGC *gc = NULL;
242 switch (ltype) {
243 case LINE_NORMAL:
244 gc = thin_line_gc;
245 break;
246 case LINE_BORDER:
247 gc = border_line_gc;
248 break;
249 case LINE_TILE_FRAME:
250 gc = thick_line_gc;
251 break;
252 case LINE_GOTO:
253 gc = thick_line_gc;
254 break;
257 gdk_gc_set_foreground(gc, &pcolor->color);
258 gdk_draw_line(pcanvas->v.pixmap, gc,
259 start_x, start_y, start_x + dx, start_y + dy);
263 /****************************************************************************
264 Draw a colored curved line for the Technology Tree connectors
265 A curved line is: 1 horizontal line, 2 arcs, 1 horizontal line
266 ****************************************************************************/
267 void canvas_put_curved_line(struct canvas *pcanvas,
268 struct color *pcolor,
269 enum line_type ltype, int start_x, int start_y,
270 int dx, int dy)
272 if (pcanvas->type == CANVAS_PIXMAP) {
273 GdkGC *gc = NULL;
275 switch (ltype) {
276 case LINE_NORMAL:
277 gc = thin_line_gc;
278 break;
279 case LINE_BORDER:
280 gc = border_line_gc;
281 break;
282 case LINE_TILE_FRAME:
283 gc = thick_line_gc;
284 break;
285 case LINE_GOTO:
286 gc = thick_line_gc;
287 break;
290 gdk_gc_set_foreground(gc, &pcolor->color);
292 /* To begin, work out the endpoints of the curve */
293 /* and initial horizontal stroke */
294 int line1end_x = start_x + 10;
295 int end_x = start_x + dx;
296 int end_y = start_y + dy;
298 int arcwidth = dx - 10;
299 /* draw a short horizontal line */
300 gdk_draw_line(pcanvas->v.pixmap, gc,
301 start_x, start_y, line1end_x, start_y);
303 if (end_y < start_y) {
304 /* if end_y is above start_y then the first curve is rising */
305 int archeight = -dy + 1;
307 /* position the BB of the arc */
308 int arcstart_x = line1end_x-arcwidth/2 -1;
309 int arcstart_y = end_y-1;
311 /* Draw arc curving up */
312 gdk_draw_arc(pcanvas->v.pixmap, gc, FALSE,
313 arcstart_x, arcstart_y,
314 arcwidth, archeight, 0, -90*64);
316 /* Shift BB to the right */
317 arcstart_x = arcstart_x + arcwidth;
319 /* draw arc curving across */
320 gdk_draw_arc(pcanvas->v.pixmap, gc, FALSE,
321 arcstart_x, arcstart_y,
322 arcwidth, archeight, 180*64, -90*64);
324 } else { /* end_y is below start_y */
326 int archeight = dy + 1;
328 /* position BB */
329 int arcstart_x = line1end_x - arcwidth/2 -1;
330 int arcstart_y = start_y-1;
332 /* Draw arc curving down */
333 gdk_draw_arc(pcanvas->v.pixmap, gc, FALSE,
334 arcstart_x, arcstart_y,
335 arcwidth, archeight, 0, 90*64);
337 /* shift BB right */
338 arcstart_x = arcstart_x + arcwidth;
340 /* Draw arc curving across */
341 gdk_draw_arc(pcanvas->v.pixmap, gc, FALSE,
342 arcstart_x, arcstart_y,
343 arcwidth, archeight, 270*64, -90*64);
346 /* Draw short horizontal line */
347 gdk_draw_line(pcanvas->v.pixmap, gc,
348 end_x - 10, start_y + dy, end_x, end_y);
352 static PangoLayout *layout;
353 static struct {
354 GtkStyle **styles;
355 bool shadowed;
356 } fonts[FONT_COUNT] = {
357 {&city_names_style, TRUE},
358 {&city_productions_style, TRUE},
359 {&reqtree_text_style, FALSE}
361 #define FONT(font) ((*fonts[font].styles)->font_desc)
363 /****************************************************************************
364 Return the size of the given text in the given font. This size should
365 include the ascent and descent of the text. Either of width or height
366 may be NULL in which case those values simply shouldn't be filled out.
367 ****************************************************************************/
368 void get_text_size(int *width, int *height,
369 enum client_font font, const char *text)
371 PangoRectangle rect;
373 if (!layout) {
374 layout = pango_layout_new(gdk_pango_context_get());
377 pango_layout_set_font_description(layout, FONT(font));
378 pango_layout_set_text(layout, text, -1);
380 pango_layout_get_pixel_extents(layout, &rect, NULL);
381 if (width) {
382 *width = rect.width;
384 if (height) {
385 *height = rect.height;
389 /****************************************************************************
390 Draw the text onto the canvas in the given color and font. The canvas
391 position does not account for the ascent of the text; this function must
392 take care of this manually. The text will not be NULL but may be empty.
393 ****************************************************************************/
394 void canvas_put_text(struct canvas *pcanvas, int canvas_x, int canvas_y,
395 enum client_font font,
396 struct color *pcolor,
397 const char *text)
399 PangoRectangle rect;
401 if (pcanvas->type != CANVAS_PIXMAP) {
402 return;
404 if (!layout) {
405 layout = pango_layout_new(gdk_pango_context_get());
408 gdk_gc_set_foreground(civ_gc, &pcolor->color);
409 pango_layout_set_font_description(layout, FONT(font));
410 pango_layout_set_text(layout, text, -1);
412 pango_layout_get_pixel_extents(layout, &rect, NULL);
414 /* Suppress drop shadow for black text */
415 if (fonts[font].shadowed
416 && !gdk_color_equal(&pcolor->color, &toplevel->style->black)) {
417 gtk_draw_shadowed_string(pcanvas->v.pixmap,
418 toplevel->style->black_gc, civ_gc,
419 canvas_x,
420 canvas_y + PANGO_ASCENT(rect), layout);
421 } else {
422 gdk_draw_layout(pcanvas->v.pixmap, civ_gc,
423 canvas_x, canvas_y + PANGO_ASCENT(rect),
424 layout);