Code

moving trunk for module inkscape
[inkscape.git] / src / display / canvas-grid.cpp
1 #define SP_CANVAS_GRID_C
3 /*
4  * SPCGrid
5  *
6  * Copyright (C) Lauris Kaplinski 2000
7  *
8  */
11 #include "sp-canvas-util.h"
12 #include "canvas-grid.h"
13 #include "display-forward.h"
14 #include <libnr/nr-pixops.h>
16 enum {
17     ARG_0,
18     ARG_ORIGINX,
19     ARG_ORIGINY,
20     ARG_SPACINGX,
21     ARG_SPACINGY,
22     ARG_COLOR,
23     ARG_EMPCOLOR,
24     ARG_EMPSPACING
25 };
28 static void sp_cgrid_class_init (SPCGridClass *klass);
29 static void sp_cgrid_init (SPCGrid *grid);
30 static void sp_cgrid_destroy (GtkObject *object);
31 static void sp_cgrid_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
33 static void sp_cgrid_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags);
34 static void sp_cgrid_render (SPCanvasItem *item, SPCanvasBuf *buf);
36 static SPCanvasItemClass * parent_class;
38 GtkType
39 sp_cgrid_get_type (void)
40 {
41     static GtkType cgrid_type = 0;
43     if (!cgrid_type) {
44         GtkTypeInfo cgrid_info = {
45             "SPCGrid",
46             sizeof (SPCGrid),
47             sizeof (SPCGridClass),
48             (GtkClassInitFunc) sp_cgrid_class_init,
49             (GtkObjectInitFunc) sp_cgrid_init,
50             NULL, NULL,
51             (GtkClassInitFunc) NULL
52         };
53         cgrid_type = gtk_type_unique (sp_canvas_item_get_type (), &cgrid_info);
54     }
55     return cgrid_type;
56 }
58 static void
59 sp_cgrid_class_init (SPCGridClass *klass)
60 {
61     GtkObjectClass *object_class;
62     SPCanvasItemClass *item_class;
64     object_class = (GtkObjectClass *) klass;
65     item_class = (SPCanvasItemClass *) klass;
67     parent_class = (SPCanvasItemClass*)gtk_type_class (sp_canvas_item_get_type ());
69     gtk_object_add_arg_type ("SPCGrid::originx", GTK_TYPE_DOUBLE, GTK_ARG_WRITABLE, ARG_ORIGINX);
70     gtk_object_add_arg_type ("SPCGrid::originy", GTK_TYPE_DOUBLE, GTK_ARG_WRITABLE, ARG_ORIGINY);
71     gtk_object_add_arg_type ("SPCGrid::spacingx", GTK_TYPE_DOUBLE, GTK_ARG_WRITABLE, ARG_SPACINGX);
72     gtk_object_add_arg_type ("SPCGrid::spacingy", GTK_TYPE_DOUBLE, GTK_ARG_WRITABLE, ARG_SPACINGY);
73     gtk_object_add_arg_type ("SPCGrid::color", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_COLOR);
74     gtk_object_add_arg_type ("SPCGrid::empcolor", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_EMPCOLOR);
75     gtk_object_add_arg_type ("SPCGrid::empspacing", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_EMPSPACING);
77     object_class->destroy = sp_cgrid_destroy;
78     object_class->set_arg = sp_cgrid_set_arg;
80     item_class->update = sp_cgrid_update;
81     item_class->render = sp_cgrid_render;
82 }
84 static void
85 sp_cgrid_init (SPCGrid *grid)
86 {
87     grid->origin[NR::X] = grid->origin[NR::Y] = 0.0;
88     grid->spacing[NR::X] = grid->spacing[NR::Y] = 8.0;
89     grid->color = 0x0000ff7f;
90     grid->empcolor = 0x3F3FFF40;
91     grid->empspacing = 5;
92 }
94 static void
95 sp_cgrid_destroy (GtkObject *object)
96 {
97     g_return_if_fail (object != NULL);
98     g_return_if_fail (SP_IS_CGRID (object));
100     if (GTK_OBJECT_CLASS (parent_class)->destroy)
101         (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
104 static void
105 sp_cgrid_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
107     SPCanvasItem *item = SP_CANVAS_ITEM (object);
108     SPCGrid *grid = SP_CGRID (object);
110     switch (arg_id) {
111     case ARG_ORIGINX:
112         grid->origin[NR::X] = GTK_VALUE_DOUBLE (* arg);
113         sp_canvas_item_request_update (item);
114         break;
115     case ARG_ORIGINY:
116         grid->origin[NR::Y] = GTK_VALUE_DOUBLE (* arg);
117         sp_canvas_item_request_update (item);
118         break;
119     case ARG_SPACINGX:
120         grid->spacing[NR::X] = GTK_VALUE_DOUBLE (* arg);
121         if (grid->spacing[NR::X] < 0.01) grid->spacing[NR::X] = 0.01;
122         sp_canvas_item_request_update (item);
123         break;
124     case ARG_SPACINGY:
125         grid->spacing[NR::Y] = GTK_VALUE_DOUBLE (* arg);
126         if (grid->spacing[NR::Y] < 0.01) grid->spacing[NR::Y] = 0.01;
127         sp_canvas_item_request_update (item);
128         break;
129     case ARG_COLOR:
130         grid->color = GTK_VALUE_INT (* arg);
131         sp_canvas_item_request_update (item);
132         break;
133     case ARG_EMPCOLOR:
134         grid->empcolor = GTK_VALUE_INT (* arg);
135         sp_canvas_item_request_update (item);
136         break;
137     case ARG_EMPSPACING:
138         grid->empspacing = GTK_VALUE_INT (* arg);
139         // std::cout << "Emphasis Spacing: " << grid->empspacing << std::endl;
140         sp_canvas_item_request_update (item);
141         break;
142     default:
143         break;
144     }
147 static void
148 sp_grid_hline (SPCanvasBuf *buf, gint y, gint xs, gint xe, guint32 rgba)
150     if ((y >= buf->rect.y0) && (y < buf->rect.y1)) {
151         guint r, g, b, a;
152         gint x0, x1, x;
153         guchar *p;
154         r = NR_RGBA32_R (rgba);
155         g = NR_RGBA32_G (rgba);
156         b = NR_RGBA32_B (rgba);
157         a = NR_RGBA32_A (rgba);
158         x0 = MAX (buf->rect.x0, xs);
159         x1 = MIN (buf->rect.x1, xe + 1);
160         p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 3;
161         for (x = x0; x < x1; x++) {
162             p[0] = NR_COMPOSEN11 (r, a, p[0]);
163             p[1] = NR_COMPOSEN11 (g, a, p[1]);
164             p[2] = NR_COMPOSEN11 (b, a, p[2]);
165             p += 3;
166         }
167     }
170 static void
171 sp_grid_vline (SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba)
173     if ((x >= buf->rect.x0) && (x < buf->rect.x1)) {
174         guint r, g, b, a;
175         gint y0, y1, y;
176         guchar *p;
177         r = NR_RGBA32_R(rgba);
178         g = NR_RGBA32_G (rgba);
179         b = NR_RGBA32_B (rgba);
180         a = NR_RGBA32_A (rgba);
181         y0 = MAX (buf->rect.y0, ys);
182         y1 = MIN (buf->rect.y1, ye + 1);
183         p = buf->buf + (y0 - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 3;
184         for (y = y0; y < y1; y++) {
185             p[0] = NR_COMPOSEN11 (r, a, p[0]);
186             p[1] = NR_COMPOSEN11 (g, a, p[1]);
187             p[2] = NR_COMPOSEN11 (b, a, p[2]);
188             p += buf->buf_rowstride;
189         }
190     }
193 /**
194     \brief  This function renders the grid on a particular canvas buffer
195     \param  item  The grid to render on the buffer
196     \param  buf   The buffer to render the grid on
197     
198     This function gets called a touch more than you might believe,
199     about once per tile.  This means that it could probably be optimized
200     and help things out.
202     Basically this function has to determine where in the canvas it is,
203     and how that associates with the grid.  It does this first by looking
204     at the bounding box of the buffer, and then calculates where the grid
205     starts in that buffer.  It will then step through grid lines until
206     it is outside of the buffer.
208     For each grid line it is drawn using the function \c sp_grid_hline
209     or \c sp_grid_vline.  These are convience functions for the sake
210     of making the function easier to read.
212     Also, there are emphisized lines on the grid.  While the \c syg and
213     \c sxg variable track grid positioning, the \c xlinestart and \c
214     ylinestart variables track the 'count' of what lines they are.  If
215     that count is a multiple of the line seperation between emphisis
216     lines, then that line is drawn in the emphisis color.
217 */
218 static void
219 sp_cgrid_render (SPCanvasItem * item, SPCanvasBuf * buf)
221     SPCGrid *grid = SP_CGRID (item);
223     sp_canvas_prepare_buffer (buf);
225     const gdouble sxg = floor ((buf->rect.x0 - grid->ow[NR::X]) / grid->sw[NR::X]) * grid->sw[NR::X] + grid->ow[NR::X];
226     const gint  xlinestart = (gint) Inkscape::round((sxg - grid->ow[NR::X]) / grid->sw[NR::X]);
227     const gdouble syg = floor ((buf->rect.y0 - grid->ow[NR::Y]) / grid->sw[NR::Y]) * grid->sw[NR::Y] + grid->ow[NR::Y];
228     const gint  ylinestart = (gint) Inkscape::round((syg - grid->ow[NR::Y]) / grid->sw[NR::Y]);
230     gint ylinenum;
231     gdouble y;
232     for (y = syg, ylinenum = ylinestart; y < buf->rect.y1; y += grid->sw[NR::Y], ylinenum++) {
233         const gint y0 = (gint) Inkscape::round(y);
234         const gint y1 = (gint) Inkscape::round(y + grid->sw[NR::Y]);
236         if (!grid->scaled[NR::Y] &&
237                 (ylinenum % grid->empspacing) == 0) {
238             sp_grid_hline (buf, y0, buf->rect.x0, buf->rect.x1 - 1, grid->empcolor);
239         } else {
240             sp_grid_hline (buf, y0, buf->rect.x0, buf->rect.x1 - 1, grid->color);
241         }
243         gint xlinenum;
244         gdouble x;
245         for (x = sxg, xlinenum = xlinestart; x < buf->rect.x1; x += grid->sw[NR::X], xlinenum++) {
246             const gint ix = (gint) Inkscape::round(x);
247             if (!grid->scaled[NR::X] &&
248                     (xlinenum % grid->empspacing) == 0) {
249                 sp_grid_vline (buf, ix, y0 + 1, y1 - 1, grid->empcolor);
250             } else {
251                 sp_grid_vline (buf, ix, y0 + 1, y1 - 1, grid->color);
252             }
253         }
254     }
257 static void
258 sp_cgrid_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags)
260     SPCGrid *grid = SP_CGRID (item);
262     if (parent_class->update)
263         (* parent_class->update) (item, affine, flags);
265     grid->ow = grid->origin * affine;
266     grid->sw = grid->spacing * affine;
267     grid->sw -= NR::Point(affine[4], affine[5]);
269     for(int dim = 0; dim < 2; dim++) {
270         gint scaling_factor = grid->empspacing;
272         if (scaling_factor <= 1)
273             scaling_factor = 5;
275         grid->scaled[dim] = FALSE;
276         grid->sw[dim] = fabs (grid->sw[dim]);
277         while (grid->sw[dim] < 8.0) {
278             grid->scaled[dim] = TRUE;
279             grid->sw[dim] *= scaling_factor;
280             /* First pass, go up to the major line spacing, then
281                keep increasing by two. */
282             scaling_factor = 2;
283         }
284     }
286     if (grid->empspacing == 0) {
287         grid->scaled[NR::Y] = TRUE;
288         grid->scaled[NR::X] = TRUE;
289     }
291     sp_canvas_request_redraw (item->canvas,
292                      -1000000, -1000000,
293                      1000000, 1000000);
294                      
295     item->x1 = item->y1 = -1000000;
296     item->x2 = item->y2 = 1000000;
299 /*
300   Local Variables:
301   mode:c++
302   c-file-style:"stroustrup"
303   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
304   indent-tabs-mode:nil
305   fill-column:99
306   End:
307 */
308 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :