Update Spanish translation
[gnumeric.git] / src / preview-grid.c
blobcc2e268c96364319dca817a82c20e67f1c20e9a7
1 /*
2 * preview-grid.c : Preview Grid Canvas Item
4 * Based upon "The Grid Gnome Canvas Item" a.k.a. Item-Grid
5 * (item-grid.c) Created by Miguel de Icaza (miguel@kernel.org)
7 * Author : Almer S. Tigelaar <almer@gnome.org>
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, see <https://www.gnu.org/licenses/>.
23 #include <gnumeric-config.h>
24 #include <gnumeric.h>
25 #include <preview-grid-impl.h>
27 #include <cell.h>
28 #include <sheet.h>
29 #include <cell-draw.h>
30 #include <colrow.h>
31 #include <pattern.h>
32 #include <mstyle.h>
33 #include <rendered-value.h>
34 #include <sheet-style.h>
35 #include <style-border.h>
36 #include <style-color.h>
37 #include <value.h>
38 #include <gnm-marshalers.h>
40 #include <gsf/gsf-impl-utils.h>
42 static GocItemClass *parent_klass;
43 enum {
44 PREVIEW_GRID_PROP_0,
45 PREVIEW_GRID_PROP_RENDER_GRIDLINES,
46 PREVIEW_GRID_PROP_DEFAULT_COL_WIDTH,
47 PREVIEW_GRID_PROP_DEFAULT_ROW_HEIGHT,
48 PREVIEW_GRID_PROP_DEFAULT_STYLE,
49 PREVIEW_GRID_PROP_DEFAULT_VALUE
52 /*****************************************************************************/
54 static GnmStyle *
55 pg_get_style (GnmPreviewGrid *pg, int col, int row)
57 GnmPreviewGridClass *klass = GNM_PREVIEW_GRID_GET_CLASS (pg);
58 GnmStyle *style;
60 g_return_val_if_fail (col >= 0 && col < gnm_sheet_get_max_cols (pg->sheet), NULL);
61 g_return_val_if_fail (row >= 0 && row < gnm_sheet_get_max_rows (pg->sheet), NULL);
62 g_return_val_if_fail (klass != NULL, NULL);
64 if (klass->get_cell_style) {
65 style = klass->get_cell_style (pg, col, row);
66 if (style != NULL)
67 return style;
70 return pg->defaults.style;
73 static GnmCell *
74 pg_fetch_cell (GnmPreviewGrid *pg, int col, int row)
76 GnmPreviewGridClass *klass = GNM_PREVIEW_GRID_GET_CLASS (pg);
77 GnmCell *cell;
78 GnmValue *v = NULL;
80 g_return_val_if_fail (klass != NULL, NULL);
81 g_return_val_if_fail (pg != NULL, NULL);
82 g_return_val_if_fail (col >= 0 && col < gnm_sheet_get_max_cols (pg->sheet), NULL);
83 g_return_val_if_fail (row >= 0 && row < gnm_sheet_get_max_rows (pg->sheet), NULL);
85 if (NULL != klass->get_cell_value)
86 v = (klass->get_cell_value) (pg, col, row);
87 if (NULL == v)
88 v = value_dup (pg->defaults.value);
90 cell = sheet_cell_fetch (pg->sheet, col, row);
91 gnm_cell_set_value (cell, v);
93 gnm_cell_render_value (cell, TRUE);
95 return cell;
98 /**
99 * pg_get_row_offset:
100 * pg:
101 * @y: offset
102 * @row_origin: if not null the origin of the row containing pixel @y is put here
104 * Return value: Row containing pixel y (and origin in @row_origin)
106 static int
107 pg_get_row_offset (GnmPreviewGrid *pg, int const y, int *row_origin)
109 int row = 0;
110 int pixel = 1;
111 int const h = pg->defaults.row_height;
113 g_return_val_if_fail (pg != NULL, 0);
115 do {
116 if (y <= (pixel + h) || h == 0) {
117 if (row_origin)
118 *row_origin = pixel;
119 return row;
121 pixel += h;
122 } while (++row < gnm_sheet_get_max_rows (pg->sheet));
124 if (row_origin)
125 *row_origin = pixel;
127 return gnm_sheet_get_last_row (pg->sheet);
131 * pg_get_col_offset:
132 * @x: offset
133 * @col_origin: if not null the origin of the column containing pixel @x is put here
135 * Return value: Column containing pixel x (and origin in @col_origin)
137 static int
138 pg_get_col_offset (GnmPreviewGrid *pg, int const x, int *col_origin)
140 int col = 0;
141 int pixel = 1;
142 int w;
144 g_return_val_if_fail (pg != NULL, 0);
146 do {
147 w = pg->defaults.col_width;
148 if (x <= (pixel + w) || w == 0) {
149 if (col_origin)
150 *col_origin = pixel;
151 return col;
153 pixel += w;
154 } while (++col < gnm_sheet_get_max_cols (pg->sheet));
156 if (col_origin)
157 *col_origin = pixel;
159 return gnm_sheet_get_last_col (pg->sheet);
162 static void
163 preview_grid_update_bounds (GocItem *item)
165 item->x0 = -2;
166 item->y0 = -2;
167 item->x1 = INT_MAX/2; /* FIXME add some num cols/rows abilities */
168 item->y1 = INT_MAX/2; /* FIXME and some flags to decide how to adapt */
171 static void
172 preview_grid_draw_background (cairo_t *cr, GnmPreviewGrid const *pg, GnmStyle const *mstyle,
173 int col, int row, int x, int y, int w, int h)
175 if (gnm_pattern_background_set (mstyle, cr, FALSE, NULL)) {
176 cairo_rectangle (cr, x, y, w+1, h+1);
177 cairo_fill (cr);
179 gnm_style_border_draw_diag (mstyle, cr, x, y, x+w, y+h);
182 static void
183 pg_style_get_row (GnmPreviewGrid *pg, GnmStyleRow *sr)
185 int const row = sr->row;
186 int col;
188 for (col = sr->start_col; col <= sr->end_col; col++) {
189 GnmStyle const *style = pg_get_style (pg, col, row);
190 sheet_style_set_pos (pg->sheet, col, row,
191 gnm_style_dup (style));
194 sheet_style_get_row (pg->sheet, sr);
197 /* no spans or merges */
198 static gboolean
199 preview_grid_draw_region (GocItem const *item, cairo_t *cr,
200 double x0, double y0, double x1, double y1)
202 GnmPreviewGrid *pg = GNM_PREVIEW_GRID (item);
204 /* To ensure that far and near borders get drawn we pretend to draw +-2
205 * pixels around the target area which would include the surrounding
206 * borders if necessary */
207 /* TODO : there is an opportunity to speed up the redraw loop by only
208 * painting the borders of the edges and not the content.
209 * However, that feels like more hassle that it is worth. Look into this someday.
211 int x, y, col, row, n;
212 int const start_col = pg_get_col_offset (pg, x0 - 2, &x);
213 int end_col = pg_get_col_offset (pg, x1 + 2, NULL);
214 int diff_x = x;
215 int start_row = pg_get_row_offset (pg, y0 - 2, &y);
216 int end_row = pg_get_row_offset (pg, y1 + 2, NULL);
217 int diff_y = y;
218 int row_height = pg->defaults.row_height;
220 GnmStyleRow sr, next_sr;
221 GnmStyle const **styles;
222 GnmBorder const **borders, **prev_vert;
223 GnmBorder const *none = pg->gridlines ? gnm_style_border_none () : NULL;
224 gpointer *sr_array_data;
226 int *colwidths = NULL;
228 gnm_style_border_none_set_color (style_color_grid ());
231 * allocate a single blob of memory for all 8 arrays of pointers.
232 * - 6 arrays of n GnmBorder const *
233 * - 2 arrays of n GnmStyle const *
235 n = end_col - start_col + 3; /* 1 before, 1 after, 1 fencepost */
236 sr_array_data = g_new (gpointer, n * 8);
237 style_row_init (&prev_vert, &sr, &next_sr, start_col, end_col,
238 sr_array_data, !pg->gridlines);
240 /* load up the styles for the first row */
241 next_sr.row = sr.row = row = start_row;
242 pg_style_get_row (pg, &sr);
244 /* Collect the column widths */
245 colwidths = g_new (int, n);
246 colwidths -= start_col;
247 for (col = start_col; col <= end_col; col++)
248 colwidths[col] = pg->defaults.col_width;
250 /* Fill entire region with default background (even past far edge) */
251 gtk_render_background (goc_item_get_style_context (item),
252 cr, diff_x, diff_y, x1 - x0, y1 - y0);
254 for (y = diff_y; row <= end_row; row = sr.row = next_sr.row) {
255 if (++next_sr.row > end_row) {
256 for (col = start_col ; col <= end_col; ++col)
257 next_sr.vertical[col] =
258 next_sr.bottom[col] = none;
259 } else
260 pg_style_get_row (pg, &next_sr);
262 for (col = start_col, x = diff_x; col <= end_col; col++) {
263 GnmStyle const *style = sr.styles[col];
264 GnmCell const *cell = pg_fetch_cell (pg, col, row);
266 preview_grid_draw_background (cr, pg,
267 style, col, row, x, y,
268 colwidths[col], row_height);
270 if (!gnm_cell_is_empty (cell))
271 cell_draw (cell, cr,
272 x, y, colwidths[col], row_height,
273 -1, FALSE);
275 x += colwidths[col];
278 gnm_style_borders_row_draw
279 (prev_vert, &sr, cr,
280 diff_x, y, y + row_height,
281 colwidths, TRUE, 1 /* cheat dir == 1 for now */);
283 /* roll the pointers */
284 borders = prev_vert; prev_vert = sr.vertical;
285 sr.vertical = next_sr.vertical; next_sr.vertical = borders;
286 borders = sr.top; sr.top = sr.bottom;
287 sr.bottom = next_sr.top = next_sr.bottom; next_sr.bottom = borders;
288 styles = sr.styles; sr.styles = next_sr.styles; next_sr.styles = styles;
290 y += row_height;
293 g_free (sr_array_data);
294 g_free (colwidths + start_col); // Offset reverts -= from above
295 return TRUE;
298 static double
299 preview_grid_distance (GocItem *item, double cx, double cy,
300 GocItem **actual_item)
302 *actual_item = item;
303 return 0.0;
306 static void
307 preview_grid_set_property (GObject *obj, guint param_id,
308 GValue const *value, GParamSpec *pspec)
310 GnmPreviewGrid *pg = GNM_PREVIEW_GRID (obj);
312 switch (param_id){
313 case PREVIEW_GRID_PROP_RENDER_GRIDLINES:
314 pg->gridlines = g_value_get_boolean (value);
315 break;
316 case PREVIEW_GRID_PROP_DEFAULT_COL_WIDTH:
317 pg->defaults.col_width = g_value_get_uint (value);
318 break;
319 case PREVIEW_GRID_PROP_DEFAULT_ROW_HEIGHT:
320 pg->defaults.row_height = g_value_get_uint (value);
321 break;
322 case PREVIEW_GRID_PROP_DEFAULT_STYLE : {
323 GnmStyle *style = g_value_dup_boxed (value);
324 g_return_if_fail (style != NULL);
325 gnm_style_unref (pg->defaults.style);
326 pg->defaults.style = style;
327 break;
329 case PREVIEW_GRID_PROP_DEFAULT_VALUE: {
330 GnmValue *val = g_value_dup_boxed (value);
331 g_return_if_fail (val != NULL);
332 value_release (pg->defaults.value);
333 pg->defaults.value = val;
334 break;
336 default: G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, param_id, pspec);
337 return; /* NOTE : RETURN */
340 goc_item_invalidate (GOC_ITEM (obj));
343 static void
344 preview_grid_dispose (GObject *obj)
346 GnmPreviewGrid *pg = GNM_PREVIEW_GRID (obj);
348 if (pg->defaults.style != NULL) {
349 gnm_style_unref (pg->defaults.style);
350 pg->defaults.style = NULL;
352 value_release (pg->defaults.value);
353 pg->defaults.value = NULL;
355 g_clear_object (&pg->sheet);
357 G_OBJECT_CLASS (parent_klass)->dispose (obj);
360 static void
361 gnm_preview_grid_init (GnmPreviewGrid *pg)
363 pg->sheet = g_object_new (GNM_SHEET_TYPE,
364 "rows", 256,
365 "columns", 256,
366 NULL);
367 pg->gridlines = FALSE;
368 pg->defaults.col_width = 64;
369 pg->defaults.row_height = 17;
370 pg->defaults.style = gnm_style_new_default ();
371 pg->defaults.value = value_new_empty ();
374 static void
375 gnm_preview_grid_class_init (GObjectClass *gobject_klass)
377 GocItemClass *item_klass = (GocItemClass *)gobject_klass;
379 parent_klass = g_type_class_peek_parent (gobject_klass);
381 gobject_klass->set_property = preview_grid_set_property;
382 gobject_klass->dispose = preview_grid_dispose;
383 g_object_class_install_property
384 (gobject_klass, PREVIEW_GRID_PROP_RENDER_GRIDLINES,
385 g_param_spec_boolean ("render-gridlines", NULL, NULL,
386 FALSE,
387 GSF_PARAM_STATIC | G_PARAM_WRITABLE));
388 g_object_class_install_property
389 (gobject_klass, PREVIEW_GRID_PROP_DEFAULT_COL_WIDTH,
390 g_param_spec_uint ("default-col-width", NULL, NULL,
391 0, G_MAXUINT, 0,
392 GSF_PARAM_STATIC | G_PARAM_WRITABLE));
393 g_object_class_install_property
394 (gobject_klass, PREVIEW_GRID_PROP_DEFAULT_ROW_HEIGHT,
395 g_param_spec_uint ("default-row-height", NULL, NULL,
396 0, G_MAXUINT, 0,
397 GSF_PARAM_STATIC | G_PARAM_WRITABLE));
398 g_object_class_install_property
399 (gobject_klass, PREVIEW_GRID_PROP_DEFAULT_STYLE,
400 g_param_spec_boxed ("default-style", NULL, NULL,
401 gnm_style_get_type (),
402 GSF_PARAM_STATIC | G_PARAM_WRITABLE));
403 g_object_class_install_property
404 (gobject_klass, PREVIEW_GRID_PROP_DEFAULT_VALUE,
405 g_param_spec_boxed ("default-value", NULL, NULL,
406 gnm_value_get_type (),
407 GSF_PARAM_STATIC | G_PARAM_WRITABLE));
409 item_klass->update_bounds = preview_grid_update_bounds;
410 item_klass->draw_region = preview_grid_draw_region;
411 item_klass->distance = preview_grid_distance;
414 GSF_CLASS (GnmPreviewGrid, gnm_preview_grid,
415 gnm_preview_grid_class_init, gnm_preview_grid_init,
416 GOC_TYPE_GROUP)