1 /* Dia -- an diagram creation/manipulation program
2  * Copyright (C) 1998 Alexander Larsson
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #include <config.h>
20 
21 #include <math.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <gdk/gdk.h>
25 
26 #include "message.h"
27 #include "render_gdk.h"
28 #include "diagdkrenderer.h"
29 
30 static void clip_region_clear(DiaRenderer *renderer);
31 static void clip_region_add_rect(DiaRenderer *renderer,
32                                  Rectangle *rect);
33 
34 static void draw_pixel_line(DiaRenderer *renderer,
35                             int x1, int y1,
36                             int x2, int y2,
37                             Color *color);
38 static void draw_pixel_rect(DiaRenderer *renderer,
39                             int x, int y,
40                             int width, int height,
41                             Color *color);
42 static void fill_pixel_rect(DiaRenderer *renderer,
43                             int x, int y,
44                             int width, int height,
45                             Color *color);
46 static void set_size (DiaRenderer *renderer,
47                       gpointer window,
48                       int width, int height);
49 static void copy_to_window (DiaRenderer *renderer,
50                 gpointer window,
51                 int x, int y, int width, int height);
52 
53 typedef struct _DiaGdkInteractiveRenderer DiaGdkInteractiveRenderer;
54 struct _DiaGdkInteractiveRenderer
55 {
56   DiaGdkRenderer parent_instance; /*!< inheritance in object oriented C */
57 };
58 typedef struct _DiaGdkInteractiveRendererClass DiaGdkInteractiveRendererClass;
59 struct _DiaGdkInteractiveRendererClass
60 {
61   DiaGdkRendererClass parent_class; /*!< the base class */
62 };
63 #define DIA_TYPE_GDK_INTERACTIVE_RENDERER           (dia_gdk_interactive_renderer_get_type ())
64 #define DIA_GDK_INTERACTIVE_RENDERER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), DIA_TYPE_GDK_INTERACTIVE_RENDERER, DiaGdkInteractiveRenderer))
65 
66 static void
dia_gdk_renderer_iface_init(DiaInteractiveRendererInterface * iface)67 dia_gdk_renderer_iface_init (DiaInteractiveRendererInterface* iface)
68 {
69   iface->clip_region_clear = clip_region_clear;
70   iface->clip_region_add_rect = clip_region_add_rect;
71   iface->draw_pixel_line = draw_pixel_line;
72   iface->draw_pixel_rect = draw_pixel_rect;
73   iface->fill_pixel_rect = fill_pixel_rect;
74   iface->copy_to_window = copy_to_window;
75   iface->set_size = set_size;
76 }
77 
78 G_DEFINE_TYPE_WITH_CODE (DiaGdkInteractiveRenderer, dia_gdk_interactive_renderer, DIA_TYPE_GDK_RENDERER,
79 			 G_IMPLEMENT_INTERFACE (DIA_TYPE_INTERACTIVE_RENDERER_INTERFACE, dia_gdk_renderer_iface_init));
80 
81 static void
dia_gdk_interactive_renderer_class_init(DiaGdkInteractiveRendererClass * klass)82 dia_gdk_interactive_renderer_class_init(DiaGdkInteractiveRendererClass *klass)
83 {
84 }
85 static void
dia_gdk_interactive_renderer_init(DiaGdkInteractiveRenderer * object)86 dia_gdk_interactive_renderer_init(DiaGdkInteractiveRenderer *object)
87 {
88   DiaGdkInteractiveRenderer *ia_renderer = DIA_GDK_INTERACTIVE_RENDERER (object);
89   DiaGdkRenderer *renderer = DIA_GDK_RENDERER(object);
90   DiaRenderer *dia_renderer = DIA_RENDERER(object);
91 
92   dia_renderer->is_interactive = 1;
93 
94   renderer->gc = NULL;
95   renderer->pixmap = NULL;
96   renderer->clip_region = NULL;
97 }
98 
99 DiaRenderer *
new_gdk_renderer(DDisplay * ddisp)100 new_gdk_renderer(DDisplay *ddisp)
101 {
102   DiaGdkRenderer *renderer;
103   GType renderer_type = 0;
104 
105   renderer = g_object_new (DIA_TYPE_GDK_INTERACTIVE_RENDERER, NULL);
106   renderer->transform = dia_transform_new (&ddisp->visible, &ddisp->zoom_factor);
107 
108   return DIA_RENDERER(renderer);
109 }
110 
111 static void
set_size(DiaRenderer * object,gpointer window,int width,int height)112 set_size(DiaRenderer *object, gpointer window,
113 		      int width, int height)
114 {
115   DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
116 
117   if (renderer->pixmap != NULL)
118     gdk_drawable_unref(renderer->pixmap);
119 
120   if (window)
121     renderer->pixmap = gdk_pixmap_new(GDK_WINDOW(window),  width, height, -1);
122   else /* the integrated UI insist to call us too early */
123     renderer->pixmap = gdk_pixmap_new(NULL,  width, height, 24);
124 
125   if (renderer->gc == NULL) {
126     renderer->gc = gdk_gc_new(renderer->pixmap);
127 
128     gdk_gc_set_line_attributes(renderer->gc,
129 			       renderer->line_width,
130 			       renderer->line_style,
131 			       renderer->cap_style,
132 			       renderer->join_style);
133   }
134 }
135 
136 static void
copy_to_window(DiaRenderer * object,gpointer window,int x,int y,int width,int height)137 copy_to_window (DiaRenderer *object, gpointer window,
138                 int x, int y, int width, int height)
139 {
140   DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
141   static GdkGC *copy_gc = NULL;
142 
143   if (!copy_gc)
144     copy_gc = gdk_gc_new(window);
145 
146   gdk_draw_pixmap (GDK_WINDOW(window),
147                    copy_gc,
148                    renderer->pixmap,
149                    x, y,
150                    x, y,
151                    width, height);
152 }
153 
154 static void
clip_region_clear(DiaRenderer * object)155 clip_region_clear(DiaRenderer *object)
156 {
157   DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
158 
159   if (renderer->clip_region != NULL)
160     gdk_region_destroy(renderer->clip_region);
161 
162   renderer->clip_region =  gdk_region_new();
163 
164   gdk_gc_set_clip_region(renderer->gc, renderer->clip_region);
165 }
166 
167 static void
clip_region_add_rect(DiaRenderer * object,Rectangle * rect)168 clip_region_add_rect(DiaRenderer *object,
169 		 Rectangle *rect)
170 {
171   DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
172   GdkRectangle clip_rect;
173   int x1,y1;
174   int x2,y2;
175 
176   dia_transform_coords(renderer->transform, rect->left, rect->top,  &x1, &y1);
177   dia_transform_coords(renderer->transform, rect->right, rect->bottom,  &x2, &y2);
178 
179   clip_rect.x = x1;
180   clip_rect.y = y1;
181   clip_rect.width = x2 - x1 + 1;
182   clip_rect.height = y2 - y1 + 1;
183 
184   gdk_region_union_with_rect( renderer->clip_region, &clip_rect );
185 
186   gdk_gc_set_clip_region(renderer->gc, renderer->clip_region);
187 }
188 
189 static void
draw_pixel_line(DiaRenderer * object,int x1,int y1,int x2,int y2,Color * color)190 draw_pixel_line(DiaRenderer *object,
191 		int x1, int y1,
192 		int x2, int y2,
193 		Color *color)
194 {
195   DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
196   GdkGC *gc = renderer->gc;
197   GdkColor gdkcolor;
198   int target_width, target_height;
199 
200   dia_gdk_renderer_set_dashes(renderer, x1+y1);
201 
202   gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), &target_width, &target_height);
203 
204   if (   (x1 < 0 && x2 < 0)
205       || (y1 < 0 && y2 < 0)
206       || (x1 > target_width && x2 > target_width)
207       || (y1 > target_height && y2 > target_height))
208     return; /* clip early rather than failing in Gdk */
209 
210   color_convert(color, &gdkcolor);
211   gdk_gc_set_foreground(gc, &gdkcolor);
212 
213   gdk_draw_line(renderer->pixmap, gc, x1, y1, x2, y2);
214 }
215 
216 static void
draw_pixel_rect(DiaRenderer * object,int x,int y,int width,int height,Color * color)217 draw_pixel_rect(DiaRenderer *object,
218 		int x, int y,
219 		int width, int height,
220 		Color *color)
221 {
222   DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
223   GdkGC *gc = renderer->gc;
224   GdkColor gdkcolor;
225   int target_width, target_height;
226 
227   dia_gdk_renderer_set_dashes(renderer, x+y);
228 
229   gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), &target_width, &target_height);
230 
231   if (x + width < 0 || y + height < 0 || x > target_width || y > target_height)
232     return; /* clip early rather than failing in Gdk */
233 
234   color_convert(color, &gdkcolor);
235   gdk_gc_set_foreground(gc, &gdkcolor);
236 
237   gdk_draw_rectangle (renderer->pixmap, gc, FALSE,
238 		      x, y,  width, height);
239 }
240 
241 static void
fill_pixel_rect(DiaRenderer * object,int x,int y,int width,int height,Color * color)242 fill_pixel_rect(DiaRenderer *object,
243 		int x, int y,
244 		int width, int height,
245 		Color *color)
246 {
247   DiaGdkRenderer *renderer = DIA_GDK_RENDERER (object);
248   GdkGC *gc = renderer->gc;
249   GdkColor gdkcolor;
250   int target_width, target_height;
251 
252   gdk_drawable_get_size (GDK_DRAWABLE (renderer->pixmap), &target_width, &target_height);
253 
254   if (x + width < 0 || y + height < 0 || x > target_width || y > target_height)
255     return; /* clip early rather than failing in Gdk */
256 
257   color_convert(color, &gdkcolor);
258   gdk_gc_set_foreground(gc, &gdkcolor);
259 
260   gdk_draw_rectangle (renderer->pixmap, gc, TRUE,
261 		      x, y,  width, height);
262 }
263