]> sigrok.org Git - sigrok-gtk.git/blame - gtkcellrenderersignal.c
sr/srd/cli: require glib version >= 2.28
[sigrok-gtk.git] / gtkcellrenderersignal.c
CommitLineData
3f63165c
UH
1/*
2 * This file is part of the sigrok project.
3 *
4 * Copyright (C) 2011 Gareth McMullin <gareth@blacksphere.co.nz>
5 *
6 * This program is free software: you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation, either version 3 of the License, or
9 * (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20#include <gtk/gtk.h>
21
22#include "gtkcellrenderersignal.h"
23
24enum
25{
26 PROP_0,
27 PROP_DATA,
28 PROP_PROBE,
29 PROP_FOREGROUND,
30 PROP_SCALE,
31 PROP_OFFSET,
32};
33
34struct _GtkCellRendererSignalPrivate
35{
36 GArray *data;
37 guint32 probe;
38 GdkColor foreground;
39 gdouble scale;
40 gint offset;
41};
42
43static void gtk_cell_renderer_signal_finalize(GObject *object);
44static void gtk_cell_renderer_signal_get_property(GObject *object,
45 guint param_id, GValue *value,
46 GParamSpec *pspec);
47static void gtk_cell_renderer_signal_set_property(GObject *object,
48 guint param_id, const GValue *value,
49 GParamSpec *pspec);
50static void gtk_cell_renderer_signal_get_size(GtkCellRenderer *cell,
51 GtkWidget *widget,
52 GdkRectangle *cell_area,
53 gint *x_offset,
54 gint *y_offset,
55 gint *width,
56 gint *height);
57static void gtk_cell_renderer_signal_render(GtkCellRenderer *cell,
58 GdkWindow *window,
59 GtkWidget *widget,
60 GdkRectangle *background_area,
61 GdkRectangle *cell_area,
62 GdkRectangle *expose_area,
63 GtkCellRendererState flags);
64
65
66G_DEFINE_TYPE(GtkCellRendererSignal, gtk_cell_renderer_signal, GTK_TYPE_CELL_RENDERER);
67
68static void
69gtk_cell_renderer_signal_class_init (GtkCellRendererSignalClass *klass)
70{
71 GObjectClass *object_class = G_OBJECT_CLASS (klass);
72 GtkCellRendererClass *cell_class = GTK_CELL_RENDERER_CLASS (klass);
73
74 object_class->finalize = gtk_cell_renderer_signal_finalize;
75 object_class->get_property = gtk_cell_renderer_signal_get_property;
76 object_class->set_property = gtk_cell_renderer_signal_set_property;
77
78 cell_class->get_size = gtk_cell_renderer_signal_get_size;
79 cell_class->render = gtk_cell_renderer_signal_render;
80
81 g_object_class_install_property(object_class,
82 PROP_DATA,
83 g_param_spec_pointer("data",
84 "Data",
85 "Binary samples data",
86 G_PARAM_READWRITE));
87
88 g_object_class_install_property (object_class,
89 PROP_PROBE,
90 g_param_spec_int("probe",
91 "Probe",
92 "Bit in Data to display",
93 -1, G_MAXINT, -1,
94 G_PARAM_READWRITE));
95
96 g_object_class_install_property (object_class,
97 PROP_FOREGROUND,
98 g_param_spec_string("foreground",
99 "Foreground",
100 "Foreground Colour",
101 NULL,
102 G_PARAM_WRITABLE));
103
104 g_object_class_install_property (object_class,
105 PROP_SCALE,
106 g_param_spec_double("scale",
107 "Scale",
108 "Pixels per sample",
109 0, 100, 1,
110 G_PARAM_READWRITE));
111
112 g_object_class_install_property (object_class,
113 PROP_OFFSET,
114 g_param_spec_int("offset",
115 "Offset",
116 "Offset...",
117 0, G_MAXINT, 0,
118 G_PARAM_READWRITE));
119
120 g_type_class_add_private (object_class,
121 sizeof (GtkCellRendererSignalPrivate));
122}
123
124static void gtk_cell_renderer_signal_init(GtkCellRendererSignal *cel)
125{
126 GtkCellRendererSignalPrivate *priv;
127
128 cel->priv = G_TYPE_INSTANCE_GET_PRIVATE(cel,
129 GTK_TYPE_CELL_RENDERER_SIGNAL,
130 GtkCellRendererSignalPrivate);
131 priv = cel->priv;
132
133 priv->data = NULL;
134 priv->probe = -1;
135 priv->scale = 1;
136 priv->offset = 0;
137}
138
139GtkCellRenderer *gtk_cell_renderer_signal_new(void)
140{
141 return g_object_new(GTK_TYPE_CELL_RENDERER_SIGNAL, NULL);
142}
143
144static void gtk_cell_renderer_signal_finalize(GObject *object)
145{
146 GtkCellRendererSignal *cel = GTK_CELL_RENDERER_SIGNAL(object);
147 GtkCellRendererSignalPrivate *priv = cel->priv;
148 /* Keep this around, because it'll be useful in future */
149 (void)priv;
150 G_OBJECT_CLASS(gtk_cell_renderer_signal_parent_class)->finalize(object);
151}
152
153static void
154gtk_cell_renderer_signal_get_property(GObject *object,
155 guint param_id,
156 GValue *value,
157 GParamSpec *pspec)
158{
159 GtkCellRendererSignal *cel = GTK_CELL_RENDERER_SIGNAL(object);
160 GtkCellRendererSignalPrivate *priv = cel->priv;
161
162 switch (param_id) {
163 case PROP_DATA:
164 g_value_set_pointer(value, priv->data);
165 break;
166 case PROP_PROBE:
167 g_value_set_int(value, priv->probe);
168 break;
169 case PROP_SCALE:
170 g_value_set_double(value, priv->scale);
171 break;
172 case PROP_OFFSET:
173 g_value_set_int(value, priv->offset);
174 break;
175 default:
176 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
177 }
178}
179
180static void
181gtk_cell_renderer_signal_set_property(GObject *object,
182 guint param_id,
183 const GValue *value,
184 GParamSpec *pspec)
185{
186 GtkCellRendererSignal *cel = GTK_CELL_RENDERER_SIGNAL(object);
187 GtkCellRendererSignalPrivate *priv = cel->priv;
188
189 switch (param_id) {
190 case PROP_DATA:
191 priv->data = g_value_get_pointer(value);
192 break;
193 case PROP_PROBE:
194 priv->probe = g_value_get_int(value);
195 break;
196 case PROP_FOREGROUND:
197 gdk_color_parse(g_value_get_string(value), &priv->foreground);
198 break;
199 case PROP_SCALE:
200 priv->scale = g_value_get_double(value);
201 break;
202 case PROP_OFFSET:
203 priv->offset = g_value_get_int(value);
204 break;
205 default:
206 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, param_id, pspec);
207 }
208}
209
210static void
211gtk_cell_renderer_signal_get_size(GtkCellRenderer *cell,
212 GtkWidget *widget,
213 GdkRectangle *cell_area,
214 gint *x_offset,
215 gint *y_offset,
216 gint *width,
217 gint *height)
218{
219 (void)cell;
220 (void)widget;
221 (void)cell_area;
222
223 /* FIXME: What about cell_area? */
224 if (width) *width = 0;
225 if (height) *height = 30;
226
227 if (x_offset) *x_offset = 0;
228 if (y_offset) *y_offset = 0;
229}
230
231
232static gboolean sample(GArray *data, gint probe, guint i)
233{
234 int unitsize = g_array_get_element_size(data);
235 g_return_val_if_fail(i < data->len, FALSE);
236 g_return_val_if_fail(probe < unitsize * 8, FALSE);
237
238 return data->data[(i*unitsize) + probe/8] & (1 << (probe & 7));
239}
240
241static void
242gtk_cell_renderer_signal_render(GtkCellRenderer *cell,
243 GdkWindow *window,
244 GtkWidget *widget,
245 GdkRectangle *background_area,
246 GdkRectangle *cell_area,
247 GdkRectangle *expose_area,
248 GtkCellRendererState flags)
249{
250 GtkCellRendererSignal *cel = GTK_CELL_RENDERER_SIGNAL(cell);
251 GtkCellRendererSignalPrivate *priv= cel->priv;
252 guint nsamples = priv->data->len;
253 gint xpad, ypad;
254 int x, y, w, h;
255 guint si;
256 gdouble o;
257
258 (void)widget;
259 (void)expose_area;
260 (void)flags;
261
262 gtk_cell_renderer_get_padding (cell, &xpad, &ypad);
263 x = cell_area->x + xpad;
264 y = cell_area->y + ypad;
265 w = cell_area->width - xpad * 2;
266 h = cell_area->height - ypad * 2;
267
268 cairo_t *cr = gdk_cairo_create(GDK_DRAWABLE(window));
269
270 /* Set clipping region to background rectangle.
271 * This prevents us drawing over other cells.
272 */
273 cairo_new_path(cr);
274 gdk_cairo_rectangle(cr, background_area);
275 cairo_clip(cr);
276
277 cairo_set_line_join(cr, CAIRO_LINE_JOIN_ROUND);
278 gdk_cairo_set_source_color(cr, &priv->foreground);
279 /*cairo_set_line_width(cr, 1);*/
280 cairo_new_path(cr);
281
282 si = priv->offset / priv->scale;
283 if (si >= nsamples)
284 return;
285 o = x - (priv->offset - si * priv->scale);
286
287 guint32 oldsample = sample(priv->data, priv->probe, si++);
288 cairo_move_to(cr, o, y +
289 (oldsample ? 0 : h));
290 o += priv->scale;
291
292 while ((si < nsamples) && (o - priv->scale < x+w)) {
293 guint32 cursample = sample(priv->data, priv->probe, si);
294 if (cursample != oldsample) {
295 cairo_line_to(cr, o - priv->scale/8, y +
296 (oldsample ? 0 : h));
297 cairo_line_to(cr, o + priv->scale/8, y +
298 (cursample ? 0 : h));
299 oldsample = cursample;
300 }
301 o += priv->scale;
302 si++;
303 }
304 cairo_line_to(cr, o - priv->scale/8, y +
305 (oldsample ? 0 : h));
306
307 cairo_stroke(cr);
308 cairo_destroy(cr);
309}