Code

Renaming from SP_CGRID to INKSCAPE_CXYGRID. SPCGrid to Inkscape::CXYGrid
[inkscape.git] / src / display / canvas-grid.cpp
1 #define INKSCAPE_CANVAS_GRID_C
3 /*
4  * CXYGrid
5  *
6  * Copyright (C) Johan Engelen 2006 <johan@shouraizou.nl>
7  * Copyright (C) Lauris Kaplinski 2000
8  *
9  */
12 #include "sp-canvas-util.h"
13 #include "canvas-grid.h"
14 #include "display-forward.h"
15 #include <libnr/nr-pixops.h>
17 namespace Inkscape {
19 enum {
20     ARG_0,
21     ARG_ORIGINX,
22     ARG_ORIGINY,
23     ARG_SPACINGX,
24     ARG_SPACINGY,
25     ARG_COLOR,
26     ARG_EMPCOLOR,
27     ARG_EMPSPACING
28 };
31 static void cxygrid_class_init (CXYGridClass *klass);
32 static void cxygrid_init (CXYGrid *grid);
33 static void cxygrid_destroy (GtkObject *object);
34 static void cxygrid_set_arg (GtkObject *object, GtkArg *arg, guint arg_id);
36 static void cxygrid_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags);
37 static void cxygrid_render (SPCanvasItem *item, SPCanvasBuf *buf);
39 static SPCanvasItemClass * parent_class;
41 GtkType
42 cxygrid_get_type (void)
43 {
44     static GtkType cxygrid_type = 0;
46     if (!cxygrid_type) {
47         GtkTypeInfo cxygrid_info = {
48             "CXYGrid",
49             sizeof (CXYGrid),
50             sizeof (CXYGridClass),
51             (GtkClassInitFunc) cxygrid_class_init,
52             (GtkObjectInitFunc) cxygrid_init,
53             NULL, NULL,
54             (GtkClassInitFunc) NULL
55         };
56         cxygrid_type = gtk_type_unique (sp_canvas_item_get_type (), &cxygrid_info);
57     }
58     return cxygrid_type;
59 }
61 static void
62 cxygrid_class_init (CXYGridClass *klass)
63 {
64     GtkObjectClass *object_class;
65     SPCanvasItemClass *item_class;
67     object_class = (GtkObjectClass *) klass;
68     item_class = (SPCanvasItemClass *) klass;
70     parent_class = (SPCanvasItemClass*)gtk_type_class (sp_canvas_item_get_type ());
72     gtk_object_add_arg_type ("CXYGrid::originx", GTK_TYPE_DOUBLE, GTK_ARG_WRITABLE, ARG_ORIGINX);
73     gtk_object_add_arg_type ("CXYGrid::originy", GTK_TYPE_DOUBLE, GTK_ARG_WRITABLE, ARG_ORIGINY);
74     gtk_object_add_arg_type ("CXYGrid::spacingx", GTK_TYPE_DOUBLE, GTK_ARG_WRITABLE, ARG_SPACINGX);
75     gtk_object_add_arg_type ("CXYGrid::spacingy", GTK_TYPE_DOUBLE, GTK_ARG_WRITABLE, ARG_SPACINGY);
76     gtk_object_add_arg_type ("CXYGrid::color", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_COLOR);
77     gtk_object_add_arg_type ("CXYGrid::empcolor", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_EMPCOLOR);
78     gtk_object_add_arg_type ("CXYGrid::empspacing", GTK_TYPE_INT, GTK_ARG_WRITABLE, ARG_EMPSPACING);
80     object_class->destroy = cxygrid_destroy;
81     object_class->set_arg = cxygrid_set_arg;
83     item_class->update = cxygrid_update;
84     item_class->render = cxygrid_render;
85 }
87 static void
88 cxygrid_init (CXYGrid *grid)
89 {
90     grid->origin[NR::X] = grid->origin[NR::Y] = 0.0;
91     grid->spacing[NR::X] = grid->spacing[NR::Y] = 8.0;
92     grid->color = 0x0000ff7f;
93     grid->empcolor = 0x3F3FFF40;
94     grid->empspacing = 5;
95 }
97 static void
98 cxygrid_destroy (GtkObject *object)
99 {
100     g_return_if_fail (object != NULL);
101     g_return_if_fail (INKSCAPE_IS_CXYGRID (object));
103     if (GTK_OBJECT_CLASS (parent_class)->destroy)
104         (* GTK_OBJECT_CLASS (parent_class)->destroy) (object);
107 static void
108 cxygrid_set_arg (GtkObject *object, GtkArg *arg, guint arg_id)
110     SPCanvasItem *item = SP_CANVAS_ITEM (object);
111     CXYGrid *grid = INKSCAPE_CXYGRID (object);
113     switch (arg_id) {
114     case ARG_ORIGINX:
115         grid->origin[NR::X] = GTK_VALUE_DOUBLE (* arg);
116         sp_canvas_item_request_update (item);
117         break;
118     case ARG_ORIGINY:
119         grid->origin[NR::Y] = GTK_VALUE_DOUBLE (* arg);
120         sp_canvas_item_request_update (item);
121         break;
122     case ARG_SPACINGX:
123         grid->spacing[NR::X] = GTK_VALUE_DOUBLE (* arg);
124         if (grid->spacing[NR::X] < 0.01) grid->spacing[NR::X] = 0.01;
125         sp_canvas_item_request_update (item);
126         break;
127     case ARG_SPACINGY:
128         grid->spacing[NR::Y] = GTK_VALUE_DOUBLE (* arg);
129         if (grid->spacing[NR::Y] < 0.01) grid->spacing[NR::Y] = 0.01;
130         sp_canvas_item_request_update (item);
131         break;
132     case ARG_COLOR:
133         grid->color = GTK_VALUE_INT (* arg);
134         sp_canvas_item_request_update (item);
135         break;
136     case ARG_EMPCOLOR:
137         grid->empcolor = GTK_VALUE_INT (* arg);
138         sp_canvas_item_request_update (item);
139         break;
140     case ARG_EMPSPACING:
141         grid->empspacing = GTK_VALUE_INT (* arg);
142         // std::cout << "Emphasis Spacing: " << grid->empspacing << std::endl;
143         sp_canvas_item_request_update (item);
144         break;
145     default:
146         break;
147     }
150 static void
151 grid_hline (SPCanvasBuf *buf, gint y, gint xs, gint xe, guint32 rgba)
153     if ((y >= buf->rect.y0) && (y < buf->rect.y1)) {
154         guint r, g, b, a;
155         gint x0, x1, x;
156         guchar *p;
157         r = NR_RGBA32_R (rgba);
158         g = NR_RGBA32_G (rgba);
159         b = NR_RGBA32_B (rgba);
160         a = NR_RGBA32_A (rgba);
161         x0 = MAX (buf->rect.x0, xs);
162         x1 = MIN (buf->rect.x1, xe + 1);
163         p = buf->buf + (y - buf->rect.y0) * buf->buf_rowstride + (x0 - buf->rect.x0) * 3;
164         for (x = x0; x < x1; x++) {
165             p[0] = NR_COMPOSEN11_1111 (r, a, p[0]);
166             p[1] = NR_COMPOSEN11_1111 (g, a, p[1]);
167             p[2] = NR_COMPOSEN11_1111 (b, a, p[2]);
168             p += 3;
169         }
170     }
173 static void
174 grid_vline (SPCanvasBuf *buf, gint x, gint ys, gint ye, guint32 rgba)
176     if ((x >= buf->rect.x0) && (x < buf->rect.x1)) {
177         guint r, g, b, a;
178         gint y0, y1, y;
179         guchar *p;
180         r = NR_RGBA32_R(rgba);
181         g = NR_RGBA32_G (rgba);
182         b = NR_RGBA32_B (rgba);
183         a = NR_RGBA32_A (rgba);
184         y0 = MAX (buf->rect.y0, ys);
185         y1 = MIN (buf->rect.y1, ye + 1);
186         p = buf->buf + (y0 - buf->rect.y0) * buf->buf_rowstride + (x - buf->rect.x0) * 3;
187         for (y = y0; y < y1; y++) {
188             p[0] = NR_COMPOSEN11_1111 (r, a, p[0]);
189             p[1] = NR_COMPOSEN11_1111 (g, a, p[1]);
190             p[2] = NR_COMPOSEN11_1111 (b, a, p[2]);
191             p += buf->buf_rowstride;
192         }
193     }
196 /**
197     \brief  This function renders the grid on a particular canvas buffer
198     \param  item  The grid to render on the buffer
199     \param  buf   The buffer to render the grid on
200     
201     This function gets called a touch more than you might believe,
202     about once per tile.  This means that it could probably be optimized
203     and help things out.
205     Basically this function has to determine where in the canvas it is,
206     and how that associates with the grid.  It does this first by looking
207     at the bounding box of the buffer, and then calculates where the grid
208     starts in that buffer.  It will then step through grid lines until
209     it is outside of the buffer.
211     For each grid line it is drawn using the function \c sp_grid_hline
212     or \c sp_grid_vline.  These are convience functions for the sake
213     of making the function easier to read.
215     Also, there are emphisized lines on the grid.  While the \c syg and
216     \c sxg variable track grid positioning, the \c xlinestart and \c
217     ylinestart variables track the 'count' of what lines they are.  If
218     that count is a multiple of the line seperation between emphisis
219     lines, then that line is drawn in the emphisis color.
220 */
221 static void
222 cxygrid_render (SPCanvasItem * item, SPCanvasBuf * buf)
224     CXYGrid *grid = INKSCAPE_CXYGRID (item);
226     sp_canvas_prepare_buffer (buf);
228     const gdouble sxg = floor ((buf->rect.x0 - grid->ow[NR::X]) / grid->sw[NR::X]) * grid->sw[NR::X] + grid->ow[NR::X];
229     const gint  xlinestart = (gint) Inkscape::round((sxg - grid->ow[NR::X]) / grid->sw[NR::X]);
230     const gdouble syg = floor ((buf->rect.y0 - grid->ow[NR::Y]) / grid->sw[NR::Y]) * grid->sw[NR::Y] + grid->ow[NR::Y];
231     const gint  ylinestart = (gint) Inkscape::round((syg - grid->ow[NR::Y]) / grid->sw[NR::Y]);
233     gint ylinenum;
234     gdouble y;
235     for (y = syg, ylinenum = ylinestart; y < buf->rect.y1; y += grid->sw[NR::Y], ylinenum++) {
236         const gint y0 = (gint) Inkscape::round(y);
238         if (!grid->scaled[NR::Y] && (ylinenum % grid->empspacing) == 0) {
239             grid_hline (buf, y0, buf->rect.x0, buf->rect.x1 - 1, grid->empcolor);
240         } else {
241             grid_hline (buf, y0, buf->rect.x0, buf->rect.x1 - 1, grid->color);
242         }
243     }     
245     gint xlinenum;
246     gdouble x;
247     for (x = sxg, xlinenum = xlinestart; x < buf->rect.x1; x += grid->sw[NR::X], xlinenum++) {
248         const gint ix = (gint) Inkscape::round(x);
249         if (!grid->scaled[NR::X] && (xlinenum % grid->empspacing) == 0) {
250             grid_vline (buf, ix, buf->rect.y0, buf->rect.y1, grid->empcolor);
251         } else {
252             grid_vline (buf, ix, buf->rect.y0, buf->rect.y1, grid->color);
253         }
254     }
257 static void
258 cxygrid_update (SPCanvasItem *item, NR::Matrix const &affine, unsigned int flags)
260     CXYGrid *grid = INKSCAPE_CXYGRID (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;
297 }        
300 }; /* namespace Inkscape */
302 /*
303   Local Variables:
304   mode:c++
305   c-file-style:"stroustrup"
306   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
307   indent-tabs-mode:nil
308   fill-column:99
309   End:
310 */
311 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :