1 /*
2 Copyright (C) 2011 Tom Szilagyi
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 */
18
19 #include <gtk/gtk.h>
20 #include <math.h>
21 #include <stdlib.h>
22
23 #include "ir_meter.h"
24 #include "ir_utils.h"
25
26 G_DEFINE_TYPE(IRMeter, ir_meter, GTK_TYPE_DRAWING_AREA);
27
28 typedef struct _IRMeterPrivate IRMeterPrivate;
29
30 #define IR_METER_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE((obj), IR_METER_TYPE, IRMeterPrivate))
31
32 struct _IRMeterPrivate {
33 GdkPixmap * pixmap;
34 float level;
35 };
36
37
38 static gboolean ir_meter_expose(GtkWidget * widget, GdkEventExpose * event);
39 static gboolean ir_meter_configure(GtkWidget * widget, GdkEventConfigure * event);
40 static void ir_meter_destroy(GtkObject * object);
41
ir_meter_class_init(IRMeterClass * cls)42 static void ir_meter_class_init(IRMeterClass * cls) {
43 GtkObjectClass * obj_class = GTK_OBJECT_CLASS(cls); /* changed G_ to GTK_ */
44 GtkWidgetClass * widget_class = GTK_WIDGET_CLASS(cls);
45 widget_class->expose_event = ir_meter_expose;
46 widget_class->configure_event = ir_meter_configure;
47 obj_class->destroy = ir_meter_destroy;
48 g_type_class_add_private(obj_class, sizeof(IRMeterPrivate));
49 }
50
ir_meter_init(IRMeter * w)51 static void ir_meter_init(IRMeter * w) {
52 IRMeterPrivate * p = IR_METER_GET_PRIVATE(w);
53 p->pixmap = NULL;
54 p->level = 0.0;
55 }
56
ir_meter_destroy(GtkObject * object)57 static void ir_meter_destroy(GtkObject * object) {
58 IRMeter * w = IR_METER(object);
59 IRMeterPrivate * p = IR_METER_GET_PRIVATE(w);
60 if (p->pixmap) {
61 gdk_pixmap_unref(p->pixmap);
62 p->pixmap = NULL;
63 }
64 }
65
draw_fullscale(GtkWidget * widget)66 static void draw_fullscale(GtkWidget * widget) {
67 IRMeterPrivate * p = IR_METER_GET_PRIVATE(widget);
68 int w = widget->allocation.width;
69 int h = widget->allocation.height;
70
71 cairo_t * cr = gdk_cairo_create(p->pixmap);
72
73 float fzero = 1.0f + 90.0f/96.0f; /* result of convert_real_to_scale(ADJ_*_GAIN, 0) */
74 fzero = exp10(fzero);
75 fzero = (fzero - 10.0f) / 90.0f;
76 int zero = h * (1.0 - fzero);
77
78 cairo_rectangle(cr, 0, 0, w, zero);
79 cairo_set_source_rgb(cr, 1, 0, 0);
80 cairo_fill_preserve(cr);
81 cairo_set_source_rgb(cr, 1, 0, 0);
82 cairo_stroke(cr);
83
84 int n = h - zero - 1;
85 int i;
86 for (i = 0; i < n/2; i++) {
87 cairo_set_source_rgb(cr, 0, 1.0, 2.0*(float)i/n);
88 cairo_move_to(cr, 0, zero + i + 1);
89 cairo_line_to(cr, w, zero + i + 1);
90 cairo_stroke(cr);
91 }
92 for (; i < n; i++) {
93 cairo_set_source_rgb(cr, 0, 1.0 - 2.0*(float)(i-n/2)/n, 1.0);
94 cairo_move_to(cr, 0, zero + i + 1);
95 cairo_line_to(cr, w, zero + i + 1);
96 cairo_stroke(cr);
97 }
98 cairo_destroy(cr);
99 }
100
draw(GtkWidget * widget)101 static void draw(GtkWidget * widget) {
102 IRMeterPrivate * p = IR_METER_GET_PRIVATE(widget);
103 int w = widget->allocation.width;
104 int h = widget->allocation.height;
105 int pos = h * (1.0f - (p->level - 10.0f) / 90.0f);
106
107 cairo_t * cr = gdk_cairo_create(widget->window);
108 gdk_cairo_set_source_pixmap(cr, p->pixmap, 0, 0);
109
110 cairo_rectangle(cr, 0, 0, w, pos);
111 cairo_set_source_rgb(cr, 0, 0, 0);
112 cairo_fill_preserve(cr);
113 cairo_set_source_rgb(cr, 0, 0, 0);
114 cairo_stroke(cr);
115
116 cairo_destroy(cr);
117 }
118
ir_meter_configure(GtkWidget * widget,GdkEventConfigure * event)119 static gboolean ir_meter_configure(GtkWidget * widget, GdkEventConfigure * event) {
120 IRMeterPrivate * p = IR_METER_GET_PRIVATE(widget);
121 int w = widget->allocation.width;
122 int h = widget->allocation.height;
123 if (p->pixmap) {
124 gdk_pixmap_unref(p->pixmap);
125 }
126 p->pixmap = gdk_pixmap_new(widget->window, w, h, -1);
127 draw_fullscale(widget);
128 draw(widget);
129 return TRUE;
130 }
131
ir_meter_expose(GtkWidget * widget,GdkEventExpose * event)132 static gboolean ir_meter_expose(GtkWidget * widget, GdkEventExpose * event) {
133 IRMeterPrivate * p = IR_METER_GET_PRIVATE(widget);
134 gdk_draw_drawable(widget->window,
135 widget->style->fg_gc[GTK_WIDGET_STATE(widget)],
136 p->pixmap,
137 event->area.x, event->area.y,
138 event->area.x, event->area.y,
139 event->area.width, event->area.height);
140 draw(widget);
141 return FALSE;
142 }
143
ir_meter_redraw(IRMeter * w)144 void ir_meter_redraw(IRMeter * w) {
145 GtkWidget * widget;
146 GdkRegion * region;
147 widget = GTK_WIDGET(w);
148 if (!widget->window) {
149 return;
150 }
151 region = gdk_drawable_get_clip_region(widget->window);
152 gdk_window_invalidate_region(widget->window, region, TRUE);
153 gdk_window_process_updates(widget->window, TRUE);
154 gdk_region_destroy(region);
155 }
156
ir_meter_redraw_all(IRMeter * w)157 void ir_meter_redraw_all(IRMeter * w) {
158 GtkWidget * widget = GTK_WIDGET(w);
159 if (!widget->window) {
160 return;
161 }
162 draw_fullscale(widget);
163 ir_meter_redraw(w);
164 }
165
ir_meter_set_level(IRMeter * w,float level)166 void ir_meter_set_level(IRMeter * w, float level) {
167 if (!w || !GTK_IS_WIDGET(w)) {
168 return;
169 }
170 IRMeterPrivate * p = IR_METER_GET_PRIVATE(w);
171 p->level = level;
172 ir_meter_redraw(w);
173 }
174
ir_meter_new(void)175 GtkWidget * ir_meter_new(void) {
176 return (GtkWidget *)g_object_new(IR_METER_TYPE, NULL);
177 }
178