1 /* batteryviewer: Display battery metrics
2 * Copyright (C) 2023 Scott Worley <scottworley@scottworley.com>
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, version 3.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <https://www.gnu.org/licenses/>.
18 * h/t https://ptomato.name/advanced-gtk-techniques/html/custom-container.html
19 * for examples of how to make GTK widgets
26 #define BV_CHART_PRIVATE(obj) \
27 (G_TYPE_INSTANCE_GET_PRIVATE((obj), BV_CHART_TYPE, BVChartPrivate))
29 typedef struct _BVChartPrivate BVChartPrivate
;
31 struct _BVChartPrivate
{
33 float minx
, miny
, maxx
, maxy
;
44 G_DEFINE_TYPE_WITH_CODE(BVChart
, bv_chart
, GTK_TYPE_DRAWING_AREA
,
45 G_ADD_PRIVATE(BVChart
))
47 typedef void (*cairo_draw_func
)(cairo_t
*cr
, double x
, double y
);
49 static struct ScreenPoint
to_screen(BVChartPrivate
*priv
,
50 GtkAllocation
*allocation
,
51 struct BVChartPoint
*p
) {
53 float xscale
= (allocation
->width
- 2 * margin
) / (priv
->maxx
- priv
->minx
);
54 float yscale
= (allocation
->height
- 2 * margin
) / (priv
->miny
- priv
->maxy
);
55 struct ScreenPoint screen_p
= {
56 .x
= xscale
* (p
->x
- priv
->minx
) + margin
,
57 .y
= yscale
* (p
->y
- priv
->maxy
) + margin
,
62 static void draw_data(BVChartPrivate
*priv
, cairo_t
*cr
,
63 GtkAllocation
*allocation
) {
64 cairo_set_source_rgb(cr
, 0.0, 0.0, 1.0);
65 float gap_threshold
= 3.0;
67 for (guint i
= 0; i
< priv
->points
->len
; i
++) {
68 struct BVChartPoint
*p
=
69 &g_array_index(priv
->points
, struct BVChartPoint
, i
);
70 gboolean is_gap
= p
->x
- prevx
> gap_threshold
;
71 cairo_draw_func f
= is_gap
? cairo_move_to
: cairo_line_to
;
72 struct ScreenPoint screen_p
= to_screen(priv
, allocation
, p
);
73 f(cr
, screen_p
.x
, screen_p
.y
);
79 static void draw_axis(BVChartPrivate
*priv
, cairo_t
*cr
,
80 GtkAllocation
*allocation
) {
81 if (priv
->miny
< 0.0 && priv
->maxy
> 0.0) {
82 cairo_set_source_rgb(cr
, 0.0, 0.0, 0.0);
83 struct BVChartPoint p
= {.x
= priv
->minx
, .y
= 0.0};
84 struct ScreenPoint screen_p
= to_screen(priv
, allocation
, &p
);
85 cairo_move_to(cr
, screen_p
.x
, screen_p
.y
);
87 screen_p
= to_screen(priv
, allocation
, &p
);
88 cairo_line_to(cr
, screen_p
.x
, screen_p
.y
);
93 static gboolean
bv_chart_draw(GtkWidget
*widget
, cairo_t
*cr
) {
94 BVChart
*chart
= BV_CHART(widget
);
95 BVChartPrivate
*priv
= bv_chart_get_instance_private(chart
);
97 cairo_set_source_rgb(cr
, 1.0, 1.0, 1.0);
100 if (priv
->points
->len
< 2)
103 GtkAllocation allocation
;
104 gtk_widget_get_allocation(widget
, &allocation
);
106 draw_data(priv
, cr
, &allocation
);
107 draw_axis(priv
, cr
, &allocation
);
112 static void bv_chart_class_init(BVChartClass
*klass
) {
113 GtkWidgetClass
*widget_class
= GTK_WIDGET_CLASS(klass
);
114 widget_class
->draw
= bv_chart_draw
;
117 static void bv_chart_init(BVChart
*chart
) {
118 gtk_widget_set_has_window(GTK_WIDGET(chart
), FALSE
);
119 BVChartPrivate
*priv
= bv_chart_get_instance_private(chart
);
120 gboolean zero_terminated
= FALSE
;
121 gboolean clear_
= FALSE
;
123 g_array_new(zero_terminated
, clear_
, sizeof(struct BVChartPoint
));
124 priv
->minx
= FLT_MAX
;
125 priv
->miny
= FLT_MAX
;
126 priv
->maxx
= FLT_MIN
;
127 priv
->maxy
= FLT_MIN
;
130 GtkWidget
*bv_chart_new() {
131 return GTK_WIDGET(g_object_new(bv_chart_get_type(), NULL
));
134 void bv_chart_add_point(BVChart
*chart
, float x
, float y
) {
135 BVChartPrivate
*priv
= bv_chart_get_instance_private(chart
);
144 struct BVChartPoint p
= {.x
= x
, .y
= y
};
145 g_array_append_val(priv
->points
, p
);