[gnome-disk-utility/ata-smart-ui-rework] More work in progress for new ATA smart graphs
- From: David Zeuthen <davidz src gnome org>
- To: svn-commits-list gnome org
- Subject: [gnome-disk-utility/ata-smart-ui-rework] More work in progress for new ATA smart graphs
- Date: Fri, 10 Jul 2009 21:55:25 +0000 (UTC)
commit 06d3d26bc57565e30b0fde28514149e0f3d1ba92
Author: David Zeuthen <davidz redhat com>
Date: Fri Jul 10 17:52:25 2009 -0400
More work in progress for new ATA smart graphs
src/gdu-gtk/gdu-ata-smart-dialog.c | 181 ++++--
src/gdu-gtk/gdu-curve.c | 98 ++-
src/gdu-gtk/gdu-curve.h | 23 +-
src/gdu-gtk/gdu-graph.c | 1205 +++++++++++++++++++++++++-----------
src/gdu-gtk/gdu-graph.h | 16 +-
src/gdu-gtk/gdu-gtk-enums.h | 18 +-
src/gdu-gtk/gdu-gtk-types.h | 2 +-
7 files changed, 1048 insertions(+), 495 deletions(-)
---
diff --git a/src/gdu-gtk/gdu-ata-smart-dialog.c b/src/gdu-gtk/gdu-ata-smart-dialog.c
index 50339cb..853618c 100644
--- a/src/gdu-gtk/gdu-ata-smart-dialog.c
+++ b/src/gdu-gtk/gdu-ata-smart-dialog.c
@@ -165,18 +165,18 @@ selection_changed (GtkTreeSelection *tree_selection,
g_debug ("selected %s", attr_name);
- GArray *cur_points;
- GArray *worst_points;
- GArray *threshold_points;
- GArray *raw_points;
- GArray *band_points;
+ GArray *cur_samples;
+ GArray *worst_samples;
+ GArray *threshold_samples;
+ GArray *raw_samples;
+ GArray *band_samples;
GList *l;
guint64 now;
- cur_points = g_array_new (FALSE, FALSE, sizeof (GduPoint));
- worst_points = g_array_new (FALSE, FALSE, sizeof (GduPoint));
- threshold_points = g_array_new (FALSE, FALSE, sizeof (GduPoint));
- raw_points = g_array_new (FALSE, FALSE, sizeof (GduPoint));
- band_points = g_array_new (FALSE, FALSE, sizeof (GduPoint));
+ cur_samples = g_array_new (FALSE, FALSE, sizeof (GduSample));
+ worst_samples = g_array_new (FALSE, FALSE, sizeof (GduSample));
+ threshold_samples = g_array_new (FALSE, FALSE, sizeof (GduSample));
+ raw_samples = g_array_new (FALSE, FALSE, sizeof (GduSample));
+ band_samples = g_array_new (FALSE, FALSE, sizeof (GduSample));
guint64 raw_min;
guint64 raw_max;
@@ -236,7 +236,7 @@ selection_changed (GtkTreeSelection *tree_selection,
break;
}
-
+#if 0
gchar **y_axis_left;
y_axis_left = g_new0 (gchar *, 6);
for (n = 0; n < 5; n++) {
@@ -251,6 +251,7 @@ selection_changed (GtkTreeSelection *tree_selection,
y_axis_left[n] = NULL;
gdu_graph_set_y_markers_left (GDU_GRAPH (dialog->priv->graph), (const gchar* const *) y_axis_left);
g_strfreev (y_axis_left);
+#endif
guint64 tolerance;
guint64 timespan;
@@ -262,38 +263,38 @@ selection_changed (GtkTreeSelection *tree_selection,
now = (guint64) time (NULL);
last_age = timespan;
- /* oldest points first */
+ /* oldest samples first */
for (l = dialog->priv->historical_data; l != NULL; l = l->next) {
GduAtaSmartHistoricalData *data = GDU_ATA_SMART_HISTORICAL_DATA (l->data);
GduAtaSmartAttribute *attr;
guint64 time_collected;
- GduPoint point;
+ GduSample sample;
guint64 age;
- gboolean use_point;
+ gboolean use_sample;
- memset (&point, '\0', sizeof (GduPoint));
+ memset (&sample, '\0', sizeof (GduSample));
time_collected = gdu_ata_smart_historical_data_get_time_collected (data);
age = now - time_collected;
- /* skip old points, except if the following point is not too old */
- use_point = FALSE;
+ /* skip old samples, except if the following sample is not too old */
+ use_sample = FALSE;
if (age < timespan) {
- use_point = TRUE;
+ use_sample = TRUE;
} else {
if (l->next != NULL) {
GduAtaSmartHistoricalData *next_data = GDU_ATA_SMART_HISTORICAL_DATA (l->next->data);
guint64 next_age;
next_age = now - gdu_ata_smart_historical_data_get_time_collected (next_data);
if (next_age < timespan) {
- use_point = TRUE;
+ use_sample = TRUE;
}
}
}
- if (use_point) {
+ if (use_sample) {
- point.x = 1.0 - ((gdouble) age) / ((gdouble) timespan);
+ sample.time_usec = time_collected * 1000L * 1000L;
attr = gdu_ata_smart_historical_data_get_attribute (data, attr_name);
if (attr != NULL) {
@@ -307,41 +308,35 @@ selection_changed (GtkTreeSelection *tree_selection,
threshold = gdu_ata_smart_attribute_get_threshold (attr);
raw = gdu_ata_smart_attribute_get_pretty_value (attr);
- point.y = current / 255.0f;
- g_array_append_val (cur_points, point);
+ sample.value = current / 255.0f;
+ g_array_append_val (cur_samples, sample);
- point.y = worst / 255.0f;
- g_array_append_val (worst_points, point);
+ sample.value = worst / 255.0f;
+ g_array_append_val (worst_samples, sample);
- point.y = threshold / 255.0f;
- g_array_append_val (threshold_points, point);
+ sample.value = threshold / 255.0f;
+ g_array_append_val (threshold_samples, sample);
- point.y = ((gdouble) (raw - raw_min)) / ((gdouble) (raw_max - raw_min));
- g_array_append_val (raw_points, point);
+ sample.value = ((gdouble) (raw - raw_min)) / ((gdouble) (raw_max - raw_min));
+ g_array_append_val (raw_samples, sample);
g_object_unref (attr);
}
/* draw a band if there's a discontinuity; e.g. no samples for an hour or more */
if (last_age - age >= tolerance) {
- guint64 band_start;
- guint64 band_end;
-
- band_start = last_age - tolerance;
- band_end = age + tolerance;
-
- point.x = 1.0 - band_start / ((gdouble) timespan);
- point.y = 1.0;
- g_array_append_val (band_points, point);
+ sample.time_usec = (now - last_age + tolerance) * 1000 * 1000;
+ sample.value = 1.0;
+ g_array_append_val (band_samples, sample);
- point.x = 1.0 - band_end / ((gdouble) timespan);
- point.y = 1.0;
- g_array_append_val (band_points, point);
+ sample.time_usec = (now - age - tolerance) * 1000 * 1000;
+ sample.value = 1.0;
+ g_array_append_val (band_samples, sample);
/* close the segment */
- point.x = G_MAXDOUBLE;
- point.y = G_MAXDOUBLE;
- g_array_append_val (band_points, point);
+ sample.time_usec = G_MAXINT64;
+ sample.value = G_MAXDOUBLE;
+ g_array_append_val (band_samples, sample);
}
}
@@ -353,12 +348,13 @@ selection_changed (GtkTreeSelection *tree_selection,
(((argb_hex) >> 16)&0xff) / 255.0, \
(((argb_hex) >> 8)&0xff) / 255.0, \
(((argb_hex) >> 0)&0xff) / 255.0, \
- alpha \
+ alpha / 255.0 \
}
/* see http://tango.freedesktop.org/Tango_Icon_Theme_Guidelines for colors
*/
GduColor raw_color = GDU_COLOR_FROM_HEX (0xfcaf3e, 255.0); /* orange */
+ GduColor raw_fill_color = GDU_COLOR_FROM_HEX (0xfcaf3e, 128.0); /* orange */
GduColor cur_color = GDU_COLOR_FROM_HEX (0x729fcf, 255.0); /* sky blue */
GduColor worst_color = GDU_COLOR_FROM_HEX (0xad7fa8, 255.0); /* plum */
GduColor threshold_color = GDU_COLOR_FROM_HEX (0xef2929, 255.0); /* scarlet red */
@@ -369,11 +365,11 @@ selection_changed (GtkTreeSelection *tree_selection,
/* add graphs in order */
gint z_order = 0;
- /* first the bands representing no data */
+ /* bands representing no data */
c = gdu_curve_new ();
gdu_curve_set_legend (c, _("No data"));
gdu_curve_set_z_order (c, z_order++);
- gdu_curve_set_points (c, band_points);
+ gdu_curve_set_samples (c, band_samples);
gdu_curve_set_color (c, &band_color);
gdu_curve_set_fill_color (c, &band_fill_color);
gdu_curve_set_flags (c, GDU_CURVE_FLAGS_FILLED | GDU_CURVE_FLAGS_FADE_EDGES);
@@ -382,11 +378,11 @@ selection_changed (GtkTreeSelection *tree_selection,
c);
g_object_unref (c);
- /* then worst */
+ /* worst */
c = gdu_curve_new ();
gdu_curve_set_legend (c, _("Worst"));
gdu_curve_set_z_order (c, z_order++);
- gdu_curve_set_points (c, worst_points);
+ gdu_curve_set_samples (c, worst_samples);
gdu_curve_set_color (c, &worst_color);
gdu_curve_set_width (c, 1.0);
gdu_graph_add_curve (GDU_GRAPH (dialog->priv->graph),
@@ -394,11 +390,11 @@ selection_changed (GtkTreeSelection *tree_selection,
c);
g_object_unref (c);
- /* then threshold */
+ /* threshold */
c = gdu_curve_new ();
gdu_curve_set_legend (c, _("Treshold"));
gdu_curve_set_z_order (c, z_order++);
- gdu_curve_set_points (c, threshold_points);
+ gdu_curve_set_samples (c, threshold_samples);
gdu_curve_set_color (c, &threshold_color);
gdu_curve_set_width (c, 1.0);
gdu_graph_add_curve (GDU_GRAPH (dialog->priv->graph),
@@ -406,11 +402,11 @@ selection_changed (GtkTreeSelection *tree_selection,
c);
g_object_unref (c);
- /* then current */
+ /* current */
c = gdu_curve_new ();
gdu_curve_set_legend (c, _("Current"));
gdu_curve_set_z_order (c, z_order++);
- gdu_curve_set_points (c, cur_points);
+ gdu_curve_set_samples (c, cur_samples);
gdu_curve_set_color (c, &cur_color);
gdu_curve_set_width (c, 2.0);
gdu_graph_add_curve (GDU_GRAPH (dialog->priv->graph),
@@ -419,29 +415,67 @@ selection_changed (GtkTreeSelection *tree_selection,
g_object_unref (c);
- /* then raw */
+ /* raw */
c = gdu_curve_new ();
gdu_curve_set_legend (c, _("Raw")); /* TODO: units? */
gdu_curve_set_z_order (c, z_order++);
- gdu_curve_set_points (c, raw_points);
+ gdu_curve_set_samples (c, raw_samples);
gdu_curve_set_color (c, &raw_color);
+ gdu_curve_set_fill_color (c, &raw_fill_color);
gdu_curve_set_width (c, 2.0);
+ gdu_curve_set_flags (c,
+ GDU_CURVE_FLAGS_AXIS_MARKERS_LEFT |
+ GDU_CURVE_FLAGS_FILLED |
+ GDU_CURVE_FLAGS_NORMALIZE);
gdu_graph_add_curve (GDU_GRAPH (dialog->priv->graph),
"raw",
c);
g_object_unref (c);
- g_array_unref (cur_points);
- g_array_unref (worst_points);
- g_array_unref (threshold_points);
- g_array_unref (raw_points);
- g_array_unref (band_points);
+ g_array_unref (cur_samples);
+ g_array_unref (worst_samples);
+ g_array_unref (threshold_samples);
+ g_array_unref (raw_samples);
+ g_array_unref (band_samples);
out:
g_free (attr_name);
}
static void
+on_period_scale_changed (GtkRange *range,
+ gpointer user_data)
+{
+ gdouble value;
+ GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
+
+ value = gtk_range_get_value (range);
+
+ gdu_graph_set_window_size_usec (GDU_GRAPH (dialog->priv->graph),
+ value * 60 * 60 * G_USEC_PER_SEC);
+}
+
+static void
+on_end_scale_changed (GtkRange *range,
+ gpointer user_data)
+{
+ gdouble value;
+ GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (user_data);
+ gint64 now_usec;
+
+ now_usec = time (NULL) * G_USEC_PER_SEC;
+
+ value = gtk_range_get_value (range);
+ if (value < 1.0) {
+ gdu_graph_set_window_end_usec (GDU_GRAPH (dialog->priv->graph),
+ G_MAXINT64);
+ } else {
+ gdu_graph_set_window_end_usec (GDU_GRAPH (dialog->priv->graph),
+ now_usec - value * 60 * 60 * G_USEC_PER_SEC);
+ }
+}
+
+static void
gdu_ata_smart_dialog_constructed (GObject *object)
{
GduAtaSmartDialog *dialog = GDU_ATA_SMART_DIALOG (object);
@@ -498,9 +532,10 @@ gdu_ata_smart_dialog_constructed (GObject *object)
graph = gdu_graph_new ();
dialog->priv->graph = graph;
- gtk_widget_set_size_request (graph, 480, 250);
+ gtk_widget_set_size_request (graph, 480, 350);
gtk_box_pack_start (GTK_BOX (hbox), graph, TRUE, TRUE, 0);
+#if 0
const gchar *time_axis[7];
time_axis[0] = C_("ATA SMART graph label", "five days ago");
time_axis[1] = C_("ATA SMART graph label", "four days ago");
@@ -519,6 +554,7 @@ gdu_ata_smart_dialog_constructed (GObject *object)
y_axis_right[4] = C_("ATA SMART graph label", "255");
y_axis_right[5] = NULL;
gdu_graph_set_y_markers_right (GDU_GRAPH (graph), y_axis_right);
+#endif
row = 0;
@@ -778,6 +814,29 @@ gdu_ata_smart_dialog_constructed (GObject *object)
G_CALLBACK (device_changed),
dialog);
+ GtkWidget *scale;
+ scale = gtk_hscale_new_with_range (2.0,
+ 365 * 24.0,
+ 1.0);
+ gtk_scale_set_digits (GTK_SCALE (scale), 0);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
+ g_signal_connect (scale,
+ "value-changed",
+ G_CALLBACK (on_period_scale_changed),
+ dialog);
+
+ scale = gtk_hscale_new_with_range (0.0,
+ 365 * 24.0,
+ 1.0);
+ gtk_scale_set_digits (GTK_SCALE (scale), 0);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), TRUE);
+ gtk_box_pack_start (GTK_BOX (vbox), scale, FALSE, FALSE, 0);
+ g_signal_connect (scale,
+ "value-changed",
+ G_CALLBACK (on_end_scale_changed),
+ dialog);
+
if (G_OBJECT_CLASS (gdu_ata_smart_dialog_parent_class)->constructed != NULL)
G_OBJECT_CLASS (gdu_ata_smart_dialog_parent_class)->constructed (object);
}
diff --git a/src/gdu-gtk/gdu-curve.c b/src/gdu-gtk/gdu-curve.c
index cc7a5a0..545c789 100644
--- a/src/gdu-gtk/gdu-curve.c
+++ b/src/gdu-gtk/gdu-curve.c
@@ -31,7 +31,8 @@
struct GduCurvePrivate
{
GduCurveFlags flags;
- GArray *points;
+ GduCurveUnit unit;
+ GArray *samples;
gint z_order;
GduColor *color;
GduColor *fill_color;
@@ -45,7 +46,8 @@ enum
{
PROP_0,
PROP_FLAGS,
- PROP_POINTS,
+ PROP_UNIT,
+ PROP_SAMPLES,
PROP_Z_ORDER,
PROP_COLOR,
PROP_FILL_COLOR,
@@ -66,8 +68,12 @@ gdu_curve_set_property (GObject *object,
gdu_curve_set_flags (curve, g_value_get_flags (value));
break;
- case PROP_POINTS:
- gdu_curve_set_points (curve, g_value_get_boxed (value));
+ case PROP_UNIT:
+ gdu_curve_set_unit (curve, g_value_get_enum (value));
+ break;
+
+ case PROP_SAMPLES:
+ gdu_curve_set_samples (curve, g_value_get_boxed (value));
break;
case PROP_Z_ORDER:
@@ -109,8 +115,12 @@ gdu_curve_get_property (GObject *object,
g_value_set_flags (value, gdu_curve_get_flags (curve));
break;
- case PROP_POINTS:
- g_value_set_boxed (value, gdu_curve_get_points (curve));
+ case PROP_UNIT:
+ g_value_set_enum (value, gdu_curve_get_unit (curve));
+ break;
+
+ case PROP_SAMPLES:
+ g_value_set_boxed (value, gdu_curve_get_samples (curve));
break;
case PROP_Z_ORDER:
@@ -148,8 +158,8 @@ gdu_curve_finalize (GObject *object)
gdu_color_free (curve->priv->color);
if (curve->priv->fill_color != NULL)
gdu_color_free (curve->priv->fill_color);
- if (curve->priv->points != NULL)
- g_array_unref (curve->priv->points);
+ if (curve->priv->samples != NULL)
+ g_array_unref (curve->priv->samples);
g_free (curve->priv->legend);
@@ -196,10 +206,21 @@ gdu_curve_class_init (GduCurveClass *klass)
G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
- PROP_POINTS,
- g_param_spec_boxed ("points",
- _("Points"),
- _("The points of the curve"),
+ PROP_UNIT,
+ g_param_spec_enum ("unit",
+ _("Unit"),
+ _("The unit used for the curve"),
+ GDU_TYPE_CURVE_UNIT,
+ GDU_CURVE_UNIT_NUMBER,
+ G_PARAM_READABLE |
+ G_PARAM_WRITABLE |
+ G_PARAM_CONSTRUCT));
+
+ g_object_class_install_property (gobject_class,
+ PROP_SAMPLES,
+ g_param_spec_boxed ("samples",
+ _("Samples"),
+ _("The samples of the curve"),
G_TYPE_ARRAY,
G_PARAM_READABLE |
G_PARAM_WRITABLE));
@@ -279,11 +300,18 @@ gdu_curve_get_flags (GduCurve *curve)
return curve->priv->flags;
}
+GduCurveUnit
+gdu_curve_get_unit (GduCurve *curve)
+{
+ g_return_val_if_fail (GDU_IS_CURVE (curve), G_MAXINT);
+ return curve->priv->unit;
+}
+
GArray *
-gdu_curve_get_points (GduCurve *curve)
+gdu_curve_get_samples (GduCurve *curve)
{
g_return_val_if_fail (GDU_IS_CURVE (curve), NULL);
- return curve->priv->points;
+ return curve->priv->samples;
}
gint
@@ -324,22 +352,30 @@ gdu_curve_get_legend (GduCurve *curve)
/* ---------------------------------------------------------------------------------------------------- */
void
-gdu_curve_set_flags (GduCurve *curve,
- GduCurveFlags flags)
+gdu_curve_set_flags (GduCurve *curve,
+ GduCurveFlags flags)
{
g_return_if_fail (GDU_IS_CURVE (curve));
curve->priv->flags = flags;
}
void
-gdu_curve_set_points (GduCurve *curve,
- GArray *points)
+gdu_curve_set_unit (GduCurve *curve,
+ GduCurveUnit unit)
+{
+ g_return_if_fail (GDU_IS_CURVE (curve));
+ curve->priv->unit = unit;
+}
+
+void
+gdu_curve_set_samples (GduCurve *curve,
+ GArray *samples)
{
g_return_if_fail (GDU_IS_CURVE (curve));
- if (curve->priv->points != NULL)
- g_array_unref (curve->priv->points);
- curve->priv->points = points != NULL ? g_array_ref (points) : NULL;
+ if (curve->priv->samples != NULL)
+ g_array_unref (curve->priv->samples);
+ curve->priv->samples = samples != NULL ? g_array_ref (samples) : NULL;
}
void
@@ -430,31 +466,31 @@ gdu_color_get_type (void)
return g_define_type_id__volatile;
}
-GduPoint *
-gdu_point_dup (GduPoint *point)
+GduSample *
+gdu_sample_dup (GduSample *sample)
{
- GduPoint *p;
- p = g_memdup (point, sizeof (GduPoint));
+ GduSample *p;
+ p = g_memdup (sample, sizeof (GduSample));
return p;
}
void
-gdu_point_free (GduPoint *point)
+gdu_sample_free (GduSample *sample)
{
- g_free (point);
+ g_free (sample);
}
GType
-gdu_point_get_type (void)
+gdu_sample_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
GType g_define_type_id =
- g_boxed_type_register_static ("GduPoint",
- (GBoxedCopyFunc) gdu_point_dup,
- (GBoxedFreeFunc) gdu_point_free);
+ g_boxed_type_register_static ("GduSample",
+ (GBoxedCopyFunc) gdu_sample_dup,
+ (GBoxedFreeFunc) gdu_sample_free);
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
diff --git a/src/gdu-gtk/gdu-curve.h b/src/gdu-gtk/gdu-curve.h
index 294695d..fc52017 100644
--- a/src/gdu-gtk/gdu-curve.h
+++ b/src/gdu-gtk/gdu-curve.h
@@ -55,7 +55,8 @@ GType gdu_curve_get_type (void) G_GNUC_CONST;
GduCurve *gdu_curve_new (void);
GduCurveFlags gdu_curve_get_flags (GduCurve *curve);
-GArray *gdu_curve_get_points (GduCurve *curve);
+GduCurveUnit gdu_curve_get_unit (GduCurve *curve);
+GArray *gdu_curve_get_samples (GduCurve *curve);
gint gdu_curve_get_z_order (GduCurve *curve);
GduColor *gdu_curve_get_color (GduCurve *curve);
GduColor *gdu_curve_get_fill_color (GduCurve *curve);
@@ -64,8 +65,10 @@ const gchar *gdu_curve_get_legend (GduCurve *curve);
void gdu_curve_set_flags (GduCurve *curve,
GduCurveFlags flags);
-void gdu_curve_set_points (GduCurve *curve,
- GArray *points);
+void gdu_curve_set_unit (GduCurve *curve,
+ GduCurveUnit unit);
+void gdu_curve_set_samples (GduCurve *curve,
+ GArray *samples);
void gdu_curve_set_z_order (GduCurve *curve,
gint z_order);
void gdu_curve_set_color (GduCurve *curve,
@@ -79,16 +82,16 @@ void gdu_curve_set_legend (GduCurve *curve,
/* ---------------------------------------------------------------------------------------------------- */
-struct GduPoint
+struct GduSample
{
- gdouble x;
- gdouble y;
+ gint64 time_usec;
+ gdouble value;
};
-#define GDU_TYPE_POINT (gdu_point_get_type ())
-GType gdu_point_get_type (void) G_GNUC_CONST;
-GduPoint *gdu_point_dup (GduPoint *point);
-void gdu_point_free (GduPoint *point);
+#define GDU_TYPE_SAMPLE (gdu_sample_get_type ())
+GType gdu_sample_get_type (void) G_GNUC_CONST;
+GduSample *gdu_sample_dup (GduSample *sample);
+void gdu_sample_free (GduSample *sample);
struct GduColor
{
diff --git a/src/gdu-gtk/gdu-graph.c b/src/gdu-gtk/gdu-graph.c
index d04f969..3a16097 100644
--- a/src/gdu-gtk/gdu-graph.c
+++ b/src/gdu-gtk/gdu-graph.c
@@ -31,13 +31,10 @@
struct GduGraphPrivate
{
- guint foo;
-
- gchar **x_markers;
- gchar **y_markers_left;
- gchar **y_markers_right;
-
GHashTable *curves;
+
+ gint64 window_end_usec;
+ gint64 window_size_usec;
};
G_DEFINE_TYPE (GduGraph, gdu_graph, GTK_TYPE_DRAWING_AREA)
@@ -48,9 +45,8 @@ static gboolean gdu_graph_expose_event (GtkWidget *widget,
enum
{
PROP_0,
- PROP_X_MARKERS,
- PROP_Y_MARKERS_LEFT,
- PROP_Y_MARKERS_RIGHT,
+ PROP_WINDOW_END_USEC,
+ PROP_WINDOW_SIZE_USEC,
};
static void
@@ -62,16 +58,12 @@ gdu_graph_set_property (GObject *object,
GduGraph *graph = GDU_GRAPH (object);
switch (prop_id) {
- case PROP_X_MARKERS:
- gdu_graph_set_x_markers (graph, g_value_get_boxed (value));
+ case PROP_WINDOW_END_USEC:
+ gdu_graph_set_window_end_usec (graph, g_value_get_int64 (value));
break;
- case PROP_Y_MARKERS_LEFT:
- gdu_graph_set_y_markers_left (graph, g_value_get_boxed (value));
- break;
-
- case PROP_Y_MARKERS_RIGHT:
- gdu_graph_set_y_markers_right (graph, g_value_get_boxed (value));
+ case PROP_WINDOW_SIZE_USEC:
+ gdu_graph_set_window_size_usec (graph, g_value_get_int64 (value));
break;
default:
@@ -89,16 +81,12 @@ gdu_graph_get_property (GObject *object,
GduGraph *graph = GDU_GRAPH (object);
switch (prop_id) {
- case PROP_X_MARKERS:
- g_value_set_boxed (value, graph->priv->x_markers);
+ case PROP_WINDOW_END_USEC:
+ g_value_set_int64 (value, graph->priv->window_end_usec);
break;
- case PROP_Y_MARKERS_LEFT:
- g_value_set_boxed (value, graph->priv->y_markers_left);
- break;
-
- case PROP_Y_MARKERS_RIGHT:
- g_value_set_boxed (value, graph->priv->y_markers_right);
+ case PROP_WINDOW_SIZE_USEC:
+ g_value_set_int64 (value, graph->priv->window_size_usec);
break;
default:
@@ -112,10 +100,6 @@ gdu_graph_finalize (GObject *object)
{
GduGraph *graph = GDU_GRAPH (object);
- g_strfreev (graph->priv->x_markers);
- g_strfreev (graph->priv->y_markers_left);
- g_strfreev (graph->priv->y_markers_right);
-
g_hash_table_unref (graph->priv->curves);
if (G_OBJECT_CLASS (gdu_graph_parent_class)->finalize != NULL)
@@ -132,36 +116,31 @@ gdu_graph_class_init (GduGraphClass *klass)
gobject_class->set_property = gdu_graph_set_property;
gobject_class->get_property = gdu_graph_get_property;
- widget_class->expose_event = gdu_graph_expose_event;
+ widget_class->expose_event = gdu_graph_expose_event;
g_type_class_add_private (klass, sizeof (GduGraphPrivate));
g_object_class_install_property (gobject_class,
- PROP_X_MARKERS,
- g_param_spec_boxed ("x-markers",
- _("X Markers"),
- _("Markers to print on the X axis"),
- G_TYPE_STRV,
+ PROP_WINDOW_END_USEC,
+ g_param_spec_int64 ("window-end-usec",
+ _("Window End Microseconds"),
+ _("The end of the graph window, in micro-seconds since epoch"),
+ G_MININT64,
+ G_MAXINT64,
+ G_MAXINT64,
G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT));
- g_object_class_install_property (gobject_class,
- PROP_Y_MARKERS_LEFT,
- g_param_spec_boxed ("y-markers-left",
- _("Left Y Markers"),
- _("Markers to print on the left Y axis"),
- G_TYPE_STRV,
- G_PARAM_READABLE |
- G_PARAM_WRITABLE |
- G_PARAM_CONSTRUCT));
g_object_class_install_property (gobject_class,
- PROP_Y_MARKERS_RIGHT,
- g_param_spec_boxed ("y-markers-right",
- _("Right Y Markers"),
- _("Markers to print on the right Y axis"),
- G_TYPE_STRV,
+ PROP_WINDOW_SIZE_USEC,
+ g_param_spec_int64 ("window-size-usec",
+ _("Window Size Microseconds"),
+ _("Size of graph window, in microseconds"),
+ G_MININT64,
+ G_MAXINT64,
+ 12L * 60 * 60 * G_USEC_PER_SEC,
G_PARAM_READABLE |
G_PARAM_WRITABLE |
G_PARAM_CONSTRUCT));
@@ -180,56 +159,40 @@ gdu_graph_new (void)
return GTK_WIDGET (g_object_new (GDU_TYPE_GRAPH, NULL));
}
-gchar **
-gdu_graph_get_x_markers (GduGraph *graph)
+gint64
+gdu_graph_get_window_end_usec (GduGraph *graph)
{
- g_return_val_if_fail (GDU_IS_GRAPH (graph), NULL);
- return g_strdupv (graph->priv->x_markers);
+ g_return_val_if_fail (GDU_IS_GRAPH (graph), 0);
+ return graph->priv->window_end_usec;
}
-gchar **
-gdu_graph_get_y_markers_left (GduGraph *graph)
+gint64
+gdu_graph_get_window_size_usec (GduGraph *graph)
{
- g_return_val_if_fail (GDU_IS_GRAPH (graph), NULL);
- return g_strdupv (graph->priv->y_markers_left);
-}
-
-gchar **
-gdu_graph_get_y_markers_right (GduGraph *graph)
-{
- g_return_val_if_fail (GDU_IS_GRAPH (graph), NULL);
- return g_strdupv (graph->priv->y_markers_right);
+ g_return_val_if_fail (GDU_IS_GRAPH (graph), 0);
+ return graph->priv->window_size_usec;
}
void
-gdu_graph_set_x_markers (GduGraph *graph,
- const gchar* const *markers)
+gdu_graph_set_window_end_usec (GduGraph *graph,
+ gint64 time_usec)
{
g_return_if_fail (GDU_IS_GRAPH (graph));
- g_strfreev (graph->priv->x_markers);
- graph->priv->x_markers = g_strdupv ((gchar **) markers);
- if (GTK_WIDGET (graph)->window != NULL)
- gdk_window_invalidate_rect (GTK_WIDGET (graph)->window, NULL, TRUE);
-}
-void
-gdu_graph_set_y_markers_left (GduGraph *graph,
- const gchar* const *markers)
-{
- g_return_if_fail (GDU_IS_GRAPH (graph));
- g_strfreev (graph->priv->y_markers_left);
- graph->priv->y_markers_left = g_strdupv ((gchar **) markers);
+ graph->priv->window_end_usec = time_usec;
+
if (GTK_WIDGET (graph)->window != NULL)
gdk_window_invalidate_rect (GTK_WIDGET (graph)->window, NULL, TRUE);
}
void
-gdu_graph_set_y_markers_right (GduGraph *graph,
- const gchar* const *markers)
+gdu_graph_set_window_size_usec (GduGraph *graph,
+ gint64 period_usec)
{
g_return_if_fail (GDU_IS_GRAPH (graph));
- g_strfreev (graph->priv->y_markers_right);
- graph->priv->y_markers_right = g_strdupv ((gchar **) markers);
+
+ graph->priv->window_size_usec = period_usec;
+
if (GTK_WIDGET (graph)->window != NULL)
gdk_window_invalidate_rect (GTK_WIDGET (graph)->window, NULL, TRUE);
}
@@ -248,6 +211,18 @@ measure_width (cairo_t *cr,
return te.width;
}
+static gboolean
+str_fits_width (cairo_t *cr,
+ gdouble width_pixels,
+ const gchar *str)
+{
+ if (measure_width (cr, str) < width_pixels)
+ return TRUE;
+ return FALSE;
+}
+
+
+#if 0
static gdouble
measure_height (cairo_t *cr,
const gchar *s)
@@ -261,6 +236,7 @@ measure_height (cairo_t *cr,
cairo_text_extents (cr, s, &te);
return te.height;
}
+#endif
static void
set_fade_edges_pattern (cairo_t *cr,
@@ -297,339 +273,610 @@ set_fade_edges_pattern (cairo_t *cr,
}
static gint
-compute_all_legends_width (cairo_t *cr,
- gdouble lb_width,
- GList *curve_list)
+curve_z_order_sort (GduCurve *a,
+ GduCurve *b)
{
- GList *l;
- gint width;
+ return gdu_curve_get_z_order (a) - gdu_curve_get_z_order (b);
+}
- width = 0;
- for (l = curve_list; l != NULL; l = l->next) {
- GduCurve *c = GDU_CURVE (l->data);
- cairo_text_extents_t te;
- const gchar *text;
+typedef enum
+{
+ TIME_MARKER_TEXT_ALIGN_CENTER,
+ TIME_MARKER_TEXT_ALIGN_LEFT
+} TimeMarkerTextAlign;
- text = gdu_curve_get_legend (c);
+typedef enum
+{
+ TEXT_MARKER_GRANULARITY_1_HOUR,
+ TEXT_MARKER_GRANULARITY_3_HOUR,
+ TEXT_MARKER_GRANULARITY_1_DAY,
+ TEXT_MARKER_GRANULARITY_1_WEEK,
+ TEXT_MARKER_GRANULARITY_1_MONTH,
+ TEXT_MARKER_GRANULARITY_1_YEAR,
+} TextMarkerGranularity;
+
+typedef enum
+{
+ TIME_MARKER_FLAGS_NONE = 0, /* No flags set */
+ TIME_MARKER_FLAGS_TEXT_AREA = (1<<0), /* Make the line cut through the text area */
+ TIME_MARKER_FLAGS_EMPHASIS = (1<<1), /* Emphasize the line */
+} TimeMarkerFlags;
- if (text == NULL)
- continue;
+typedef struct
+{
+ gint64 time_usec; /* position in time, in localtime, usec since Epoch */
- cairo_select_font_face (cr, "sans",
- CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
- cairo_set_font_size (cr, 8.0);
- cairo_text_extents (cr, text, &te);
+ TimeMarkerFlags flags; /* Flags affecting presentation */
- width += lb_width + 3 + ceil (te.width) + 12;
- }
+ gchar *text; /* Text to print, NULL for no text */
+ TimeMarkerTextAlign text_align; /* How to align the text */
+ gdouble text_width_pixels; /* width of the area for text, in pixels */
+} TimeMarker;
- return width;
+static void
+time_marker_free (TimeMarker *marker)
+{
+ g_free (marker->text);
+ g_free (marker);
}
-static gint
-curve_z_order_sort (GduCurve *a,
- GduCurve *b)
+static gchar *
+time_marker_format_time_hour (cairo_t *cr,
+ gdouble width_pixels,
+ struct tm *t,
+ struct tm *now)
{
- return gdu_curve_get_z_order (a) - gdu_curve_get_z_order (b);
+ gchar buf[512];
+
+ if (now->tm_year == t->tm_year &&
+ now->tm_yday == t->tm_yday) {
+ /* today */
+ strftime (buf, sizeof buf, _("%l %P"), t);
+ } else if (now->tm_year == t->tm_year &&
+ now->tm_mon == t->tm_mon &&
+ (now->tm_mday - t->tm_mday) < 7) {
+ /* this week */
+
+ strftime (buf, sizeof buf, _("%A %l %P"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
+
+ strftime (buf, sizeof buf, _("%a %l %P"), t);
+
+ } else if (now->tm_year == t->tm_year) {
+ /* this year */
+
+ strftime (buf, sizeof buf, _("%B %e, %l %P"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
+
+ strftime (buf, sizeof buf, _("%b %e, %l %P"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
+
+ strftime (buf, sizeof buf, _("%b %e, %l %P"), t);
+ } else {
+ /* other year */
+
+ strftime (buf, sizeof buf, _("%B %e, %l %P, %Y"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
+
+ strftime (buf, sizeof buf, _("%b %e, %l %P, %Y"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
+
+ strftime (buf, sizeof buf, _("%b %e, %l %P, %y"), t);
+ }
+
+ out:
+ return g_strdup (buf);
}
-static gboolean
-gdu_graph_expose_event (GtkWidget *widget,
- GdkEventExpose *event)
+static gchar *
+time_marker_format_time_day (cairo_t *cr,
+ gdouble width_pixels,
+ struct tm *t,
+ struct tm *now)
{
- GduGraph *graph = GDU_GRAPH (widget);
- guint n_x_markers;
- guint n_y_markers_left;
- guint n_y_markers_right;
- cairo_t *cr;
- gdouble width, height;
- guint n;
- gdouble x, y;
- guint twidth;
- guint theight;
- guint left_margin;
- guint right_margin;
- guint top_margin;
- guint bottom_margin;
- guint x_markers_height;
- double gx, gy, gw, gh;
- guint64 t_left;
- guint64 t_right;
- GTimeVal now;
- GList *curve_list;
- GList *l;
- gdouble lb_width;
- gdouble lb_height;
- gdouble lb_padding;
- gdouble lb_xpos;
- gdouble lb_ypos;
+ gchar buf[512];
- curve_list = g_hash_table_get_values (graph->priv->curves);
- curve_list = g_list_sort (curve_list,
- (GCompareFunc) curve_z_order_sort);
+ if (now->tm_year == t->tm_year) {
+ strftime (buf, sizeof buf, _("%A %B %e"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
- n_x_markers = graph->priv->x_markers != NULL ? g_strv_length (graph->priv->x_markers) : 0;
- n_y_markers_left = graph->priv->y_markers_left != NULL ? g_strv_length (graph->priv->y_markers_left) : 0;
- n_y_markers_right = graph->priv->y_markers_right != NULL ? g_strv_length (graph->priv->y_markers_right) : 0;
+ strftime (buf, sizeof buf, _("%a %B %e"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
- width = widget->allocation.width;
- height = widget->allocation.height;
+ strftime (buf, sizeof buf, _("%b %e"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
- cr = gdk_cairo_create (widget->window);
- cairo_rectangle (cr,
- event->area.x, event->area.y,
- event->area.width, event->area.height);
- cairo_clip (cr);
+ if (now->tm_mon == t->tm_mon) {
+ strftime (buf, sizeof buf, _("%e"), t);
+ }
- gx = 0;
- gy = 0;
- gw = width;
- gh = height;
+ } else {
+ strftime (buf, sizeof buf, _("%A %B %e, %Y"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
- top_margin = 10;
+ strftime (buf, sizeof buf, _("%a %B %e, %Y"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
- /* measure text of all x markers */
- bottom_margin = 0;
- for (n = 0; n < n_x_markers; n++) {
- theight = ceil (measure_height (cr, graph->priv->x_markers[n]));
- if (theight > bottom_margin)
- bottom_margin = theight;
+ strftime (buf, sizeof buf, _("%b %e, %y"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
}
- bottom_margin += 12; /* padding */
- x_markers_height = bottom_margin;
- /* compute how much size we need for legends */
- bottom_margin += 6; /* padding */
- lb_height = 14;
- lb_width = 23; /* golden ratio */
- lb_padding = 6;
- bottom_margin += lb_height + lb_padding;
+ out:
+ return g_strdup (buf);
+}
- /* adjust drawing area */
- gy += top_margin;
- gh -= top_margin;
- gh -= bottom_margin;
+static gchar *
+time_marker_format_time_week (cairo_t *cr,
+ gdouble width_pixels,
+ struct tm *t,
+ struct tm *now)
+{
+ /* for now, just use the day format - we could do week numbers but... */
+ return time_marker_format_time_day (cr, width_pixels, t, now);
+}
- gint all_legends_width;
- all_legends_width = compute_all_legends_width (cr,
- lb_width,
- curve_list);
+static gchar *
+time_marker_format_time_month (cairo_t *cr,
+ gdouble width_pixels,
+ struct tm *t,
+ struct tm *now)
+{
+ gchar buf[512];
- /* draw legends */
- lb_ypos = gy + gh + x_markers_height + 6; /* padding */
- lb_xpos = 10 + ceil (((width - 20) - all_legends_width) / 2);
- for (l = curve_list; l != NULL; l = l->next) {
- GduCurve *c = GDU_CURVE (l->data);
- GduColor *color;
- GduColor *fill_color;
- gdouble width;
- GduCurveFlags flags;
- const gchar *text;
- gdouble x, y;
- cairo_text_extents_t te;
+ strftime (buf, sizeof buf, _("%B %Y"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
- color = gdu_curve_get_color (c);
- fill_color = gdu_curve_get_fill_color (c);
- if (fill_color == NULL)
- fill_color = color;
- width = gdu_curve_get_width (c);
- flags = gdu_curve_get_flags (c);
- text = gdu_curve_get_legend (c);
+ strftime (buf, sizeof buf, _("%b %y"), t);
+ if (str_fits_width (cr, width_pixels, buf))
+ goto out;
- if (text == NULL)
- continue;
+ if (now->tm_year == t->tm_year) {
+ strftime (buf, sizeof buf, _("%b"), t);
+ }
- x = lb_xpos + 0.5;
- y = lb_ypos + 0.5;
+ out:
+ return g_strdup (buf);
+}
- cairo_new_path (cr);
- cairo_set_dash (cr, NULL, 0, 0.0);
- cairo_set_line_width (cr, 1.0);
- cairo_rectangle (cr, x, y, lb_width, lb_height);
- cairo_close_path (cr);
- cairo_set_source_rgba (cr, 1, 1, 1, 1);
- cairo_fill_preserve (cr);
- cairo_set_source_rgba (cr, 0, 0, 0, 1);
- cairo_stroke (cr);
+static gchar *
+time_marker_format_time_year (cairo_t *cr,
+ gdouble width_pixels,
+ struct tm *t,
+ struct tm *now)
+{
+ gchar buf[512];
+ strftime (buf, sizeof buf, _("%Y"), t);
+ return g_strdup (buf);
+}
- cairo_new_path (cr);
+/* returns a list of time markers to draw */
+static GPtrArray *
+time_markers_get (cairo_t *cr,
+ gint64 since_usec,
+ gint64 until_usec,
+ gdouble width_pixels)
+{
+ GPtrArray *markers;
+ gint64 size_usec;
+ gdouble secs_per_pixel;
+ gdouble minimum_distance_pixels;
+ gdouble secs_per_minimum_distance;
+ guint64 distance_usec;
+ gdouble distance_pixels;
+ guint64 t_usec;
+ gint64 timezone_offset_usec;
+ TextMarkerGranularity granularity;
+ gdouble margin_pixels;
+ guint n;
- if (flags * GDU_CURVE_FLAGS_FILLED) {
- if (flags & GDU_CURVE_FLAGS_FADE_EDGES) {
- set_fade_edges_pattern (cr, x, x + lb_width, fill_color);
+ /* minimum distance between markers */
+ minimum_distance_pixels = 70;
+
+ /* margin on left/right of marker text */
+ margin_pixels = 3;
+
+ size_usec = until_usec - since_usec;
+
+ secs_per_pixel = size_usec / ((gdouble) G_USEC_PER_SEC) / width_pixels;
+ secs_per_minimum_distance = minimum_distance_pixels * secs_per_pixel;
+
+ markers = g_ptr_array_new_with_free_func ((GDestroyNotify) time_marker_free);
+
+ if (secs_per_minimum_distance < 60*60) {
+ /* 1 hour granularity */
+ distance_usec = 60*60L * G_USEC_PER_SEC;
+ granularity = TEXT_MARKER_GRANULARITY_1_HOUR;
+ } else if (secs_per_minimum_distance < 3*60*60) {
+ /* 3 hour granularity */
+ distance_usec = 3*60*60L * G_USEC_PER_SEC;
+ granularity = TEXT_MARKER_GRANULARITY_3_HOUR;
+ } else if (secs_per_minimum_distance < 24*60*60) {
+ /* day granularity */
+ distance_usec = 24*60*60L * G_USEC_PER_SEC;
+ granularity = TEXT_MARKER_GRANULARITY_1_DAY;
+ } else if (secs_per_minimum_distance < 7*24*60*60) {
+ /* week granularity */
+ distance_usec = 7*24*60*60L * G_USEC_PER_SEC;
+ granularity = TEXT_MARKER_GRANULARITY_1_WEEK;
+ } else if (secs_per_minimum_distance < 30*24*60*60) {
+ /* month granularity */
+ distance_usec = 30*24*60*60L * G_USEC_PER_SEC;
+ granularity = TEXT_MARKER_GRANULARITY_1_MONTH;
+ } else /* if (secs_per_minimum_distance < 365*24*60*60)*/ {
+ /* year granularity */
+ distance_usec = 365*24*60*60L * G_USEC_PER_SEC;
+ granularity = TEXT_MARKER_GRANULARITY_1_YEAR;
+ }
+ distance_pixels = distance_usec / secs_per_pixel / G_USEC_PER_SEC;
+
+ /* TODO: figure this out from somewhere */
+ timezone_offset_usec = - 4 * 60 * 60 * 1L * G_USEC_PER_SEC;
+
+ struct tm tm_now;
+ time_t time_now_utc;
+
+ time_now_utc = time (NULL);
+ localtime_r (&time_now_utc, &tm_now);
+
+ /* we use different loops according to the granularity used */
+ if (granularity < TEXT_MARKER_GRANULARITY_1_DAY) {
+ /* Now, for the distance D, we sweep over the interval [since - 2*D; until + 2*D] and
+ * create a marker for each point T in said interval where T is divisible by D.
+ *
+ * We also adjust for the local timezone to get the markers to land correctly, e.g.
+ * at 12am when using a 3-hour granularity.
+ */
+ for (t_usec = since_usec - 2 * distance_usec - (since_usec % distance_usec) -
+ timezone_offset_usec - 24*60*60*1L*G_USEC_PER_SEC;
+ t_usec < until_usec + 2 * distance_usec;
+ t_usec += distance_usec) {
+ TimeMarker *marker;
+ time_t time_utc_sec;
+ struct tm tm;
+ gchar *s;
+
+ time_utc_sec = t_usec / G_USEC_PER_SEC;
+ localtime_r (&time_utc_sec, &tm);
+
+ if (tm.tm_hour == 0) {
+ s = time_marker_format_time_day (cr, distance_pixels - 2*margin_pixels, &tm, &tm_now);
} else {
- cairo_set_source_rgba (cr,
- fill_color->red,
- fill_color->green,
- fill_color->blue,
- fill_color->alpha);
+ s = time_marker_format_time_hour (cr, distance_pixels - 2*margin_pixels, &tm, &tm_now);
}
- cairo_rectangle (cr, x + 1, y + 1, lb_width - 2, lb_height - 2);
- cairo_fill (cr);
- } else {
- cairo_move_to (cr, x, y + lb_height/2.0);
- cairo_line_to (cr, x + lb_width / 2.0, y + lb_height/3.0);
- cairo_line_to (cr, x + lb_width, y + 2.0 * lb_height/3.0);
- cairo_set_line_width (cr, width);
- cairo_set_source_rgba (cr,
- color->red,
- color->green,
- color->blue,
- color->alpha);
- cairo_stroke (cr);
+ marker = g_new0 (TimeMarker, 1);
+ marker->text = s;
+ marker->time_usec = t_usec;
+ marker->flags = TIME_MARKER_FLAGS_TEXT_AREA | TIME_MARKER_FLAGS_EMPHASIS;
+ marker->text_align = TIME_MARKER_TEXT_ALIGN_LEFT;
+ marker->text_width_pixels = distance_pixels;
+ g_ptr_array_add (markers, marker);
+
+ /* add extra markers */
+ switch (granularity) {
+ case TEXT_MARKER_GRANULARITY_1_HOUR:
+ /* four extra markers => every 15 minutes */
+ for (n = 0; n < 4; n++) {
+ marker = g_new0 (TimeMarker, 1);
+ marker->time_usec = t_usec + n * distance_usec / 4;
+ marker->flags = TIME_MARKER_FLAGS_NONE;
+ g_ptr_array_add (markers, marker);
+ }
+ break;
+ case TEXT_MARKER_GRANULARITY_3_HOUR:
+ /* three extra markers => every hour */
+ for (n = 0; n < 3; n++) {
+ marker = g_new0 (TimeMarker, 1);
+ marker->time_usec = t_usec + n * distance_usec / 3;
+ marker->flags = TIME_MARKER_FLAGS_NONE;
+ g_ptr_array_add (markers, marker);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ }
+ } else {
+ GDate date_iter;
+ GDate date_until;
+ GDate date_next;
+
+ g_date_clear (&date_iter, 1);
+ g_date_clear (&date_until, 1);
+ g_date_clear (&date_next, 1);
+
+ g_date_set_time_t (&date_iter, (time_t) ((since_usec - timezone_offset_usec) / G_USEC_PER_SEC));
+ g_date_set_time_t (&date_until, (time_t) ((until_usec - timezone_offset_usec) / G_USEC_PER_SEC));
+
+ /* adjust so we start from beginning of the specified period */
+ switch (granularity) {
+ case TEXT_MARKER_GRANULARITY_1_DAY:
+ g_date_subtract_days (&date_iter, 1);
+ g_date_add_days (&date_until, 1);
+ break;
+ case TEXT_MARKER_GRANULARITY_1_WEEK:
+ g_date_add_days (&date_iter, -g_date_get_weekday (&date_iter));
+ g_date_subtract_days (&date_iter, 7);
+ g_date_add_days (&date_until, 7);
+ break;
+ case TEXT_MARKER_GRANULARITY_1_MONTH:
+ g_date_set_day (&date_iter, 1);
+ g_date_subtract_months (&date_iter, 1);
+ g_date_add_months (&date_until, 1);
+ break;
+ case TEXT_MARKER_GRANULARITY_1_YEAR:
+ g_date_set_day (&date_iter, 1);
+ g_date_set_month (&date_iter, 1);
+ g_date_subtract_years (&date_iter, 1);
+ g_date_add_years (&date_until, 1);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
}
- /* and now show the text */
+ while (g_date_compare (&date_iter, &date_until) < 0) {
+ TimeMarker *marker;
+ gint64 t_usec;
+ struct tm tm;
+ gchar *s;
+
+ g_date_to_struct_tm (&date_iter, &tm);
+ tm.tm_sec = tm.tm_min = tm.tm_hour = 0;
+
+ date_next = date_iter;
+ switch (granularity) {
+ case TEXT_MARKER_GRANULARITY_1_DAY:
+ g_date_add_days (&date_next, 1);
+ break;
+ case TEXT_MARKER_GRANULARITY_1_WEEK:
+ g_date_add_days (&date_next, 7);
+ break;
+ case TEXT_MARKER_GRANULARITY_1_MONTH:
+ g_date_add_months (&date_next, 1);
+ break;
+ case TEXT_MARKER_GRANULARITY_1_YEAR:
+ g_date_add_years (&date_next, 1);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_select_font_face (cr, "sans",
- CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
- cairo_set_font_size (cr, 8.0);
- cairo_text_extents (cr, text, &te);
- cairo_move_to (cr,
- x + lb_width + 3 - te.x_bearing,
- y + lb_height/2.0 - te.height/2 - te.y_bearing);
+ /* distance in pixels varies since each month/year isn't the same */
+ distance_usec = g_date_days_between (&date_iter, &date_next) * 24*60*60*1L*G_USEC_PER_SEC;
+ distance_pixels = distance_usec / secs_per_pixel / G_USEC_PER_SEC;
+
+ switch (granularity) {
+ case TEXT_MARKER_GRANULARITY_1_DAY:
+ s = time_marker_format_time_day (cr, distance_pixels - 2*margin_pixels, &tm, &tm_now);
+ break;
+ case TEXT_MARKER_GRANULARITY_1_WEEK:
+ s = time_marker_format_time_week (cr, distance_pixels - 2*margin_pixels, &tm, &tm_now);
+ break;
+ case TEXT_MARKER_GRANULARITY_1_MONTH:
+ s = time_marker_format_time_month (cr, distance_pixels - 2*margin_pixels, &tm, &tm_now);
+ break;
+ case TEXT_MARKER_GRANULARITY_1_YEAR:
+ s = time_marker_format_time_year (cr, distance_pixels - 2*margin_pixels, &tm, &tm_now);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
- cairo_show_text (cr, text);
+#if 0
+ g_debug ("Using `%s' for sec=%d min=%d hour=%d mday=%d mon=%d year=%d wday=%d yday=%d isdst=%d",
+ s,
+ tm.tm_sec,
+ tm.tm_min,
+ tm.tm_hour,
+ tm.tm_mday,
+ tm.tm_mon,
+ tm.tm_year,
+ tm.tm_wday,
+ tm.tm_yday,
+ tm.tm_isdst);
+#endif
+
+ t_usec = timelocal (&tm) * 1L * G_USEC_PER_SEC;
+
+ /* TODO: Maybe want to center some markers, like months */
+ marker = g_new0 (TimeMarker, 1);
+ marker->text = s;
+ marker->time_usec = t_usec;
+ marker->flags = TIME_MARKER_FLAGS_TEXT_AREA | TIME_MARKER_FLAGS_EMPHASIS;
+ marker->text_align = TIME_MARKER_TEXT_ALIGN_LEFT;
+ marker->text_width_pixels = distance_pixels;
+ g_ptr_array_add (markers, marker);
+
+ /* add extra markers */
+ switch (granularity) {
+ case TEXT_MARKER_GRANULARITY_1_DAY:
+ /* four extra markers => every 6 hours */
+ for (n = 0; n < 4; n++) {
+ marker = g_new0 (TimeMarker, 1);
+ marker->time_usec = t_usec + n * distance_usec / 4;
+ marker->flags = TIME_MARKER_FLAGS_NONE;
+ g_ptr_array_add (markers, marker);
+ }
+ break;
+ case TEXT_MARKER_GRANULARITY_1_WEEK:
+ /* seven extra markers => every day */
+ for (n = 0; n < 7; n++) {
+ marker = g_new0 (TimeMarker, 1);
+ marker->time_usec = t_usec + n * distance_usec / 7;
+ marker->flags = TIME_MARKER_FLAGS_NONE;
+ g_ptr_array_add (markers, marker);
+ }
+ break;
+ case TEXT_MARKER_GRANULARITY_1_MONTH:
+ /* four extra markers => every week */
+ for (n = 0; n < 4; n++) {
+ marker = g_new0 (TimeMarker, 1);
+ marker->time_usec = t_usec + n * distance_usec / 4;
+ marker->flags = TIME_MARKER_FLAGS_NONE;
+ g_ptr_array_add (markers, marker);
+ }
+ break;
+ case TEXT_MARKER_GRANULARITY_1_YEAR:
+ /* twelve extra markers => every month */
+ for (n = 0; n < 12; n++) {
+ marker = g_new0 (TimeMarker, 1);
+ marker->time_usec = t_usec + n * distance_usec / 12;
+ marker->flags = TIME_MARKER_FLAGS_NONE;
+ g_ptr_array_add (markers, marker);
+ }
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
- lb_xpos += lb_width + 3 + ceil (te.width) + 12;
+ date_iter = date_next;
+ }
}
- /* measure text on the left y-axis */
- left_margin = 0;
- for (n = 0; n < n_y_markers_left; n++) {
- twidth = ceil (measure_width (cr, graph->priv->y_markers_left[n]));
- if (twidth > left_margin)
- left_margin = twidth;
- }
- /* include half width of first xmarker label */
- if (n_x_markers > 0) {
- twidth = ceil (measure_width (cr, graph->priv->x_markers[0]));
- if (twidth/2 > left_margin)
- left_margin = twidth/2;
- }
- left_margin += 6; /* padding */
- gx += left_margin;
- gw -= left_margin;
+ return markers;
+}
- /* measure text on the right y-axis */
- right_margin = 0;
- for (n = 0; n < n_y_markers_right; n++) {
- twidth = ceil (measure_width (cr, graph->priv->y_markers_right[n]));
- if (twidth/2 > right_margin)
- right_margin = twidth/2;
- }
- /* include half width of last xmarker label */
- if (n_x_markers > 0) {
- twidth = ceil (measure_width (cr, graph->priv->x_markers[n_x_markers - 1]));
- right_margin += twidth/2;
- }
- right_margin += 6; /* padding */
- gw -= right_margin;
+typedef enum {
+ TIMEBAR_STYLE_SEPARATE,
+ TIMEBAR_STYLE_EMBEDDED
+} TimeBarStyle;
- /* draw the box to draw in */
- cairo_set_source_rgb (cr, 1, 1, 1);
- cairo_rectangle (cr, gx, gy, gw, gh);
- cairo_set_line_width (cr, 0.0);
- cairo_fill (cr);
-
- /* draw markers on the left y-axis */
- for (n = 0; n < n_y_markers_left; n++) {
- gdouble pos;
- gdouble dashes[1] = {2.0};
- const gchar *s;
- cairo_text_extents_t te;
+static void
+draw_curves (cairo_t *cr,
+ gdouble gx, gdouble gy, gdouble gw, gdouble gh,
+ TimeBarStyle timebar_style,
+ GList *curve_list,
+ gint64 window_since_usec, gint64 window_until_usec)
+{
+ GTimeVal now;
+ GList *l;
+ gint64 window_size_usec;
+ guint n;
+ gdouble x, y;
+ guint64 t_left;
+ guint64 t_right;
+ guint timebar_height;
- pos = ceil (gy + gh / (n_y_markers_left - 1) * n);
+ if (timebar_style == TIMEBAR_STYLE_SEPARATE)
+ timebar_height = 12;
+ else
+ timebar_height = 0;
- s = graph->priv->y_markers_left[n_y_markers_left - 1 - n];
+ window_size_usec = window_until_usec - window_since_usec;
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_select_font_face (cr, "sans",
- CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
- cairo_set_font_size (cr, 8.0);
- cairo_text_extents (cr, s, &te);
- cairo_move_to (cr,
- gx/2.0 - 3 - te.width/2 - te.x_bearing,
- pos - te.height/2 - te.y_bearing);
+ cairo_reset_clip (cr);
- cairo_show_text (cr, s);
+ /* draw the box to draw in */
+ cairo_set_source_rgb (cr, 1, 1, 1);
+ cairo_rectangle (cr, gx, gy, gw, gh - timebar_height);
+ cairo_fill_preserve (cr);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
+ cairo_set_line_width (cr, 1.0);
+ cairo_set_dash (cr, NULL, 0, 0.0);
+ cairo_stroke (cr);
+ g_get_current_time (&now);
+ t_left = now.tv_sec - 6 * 24 * 60 * 60;
+ t_right = now.tv_sec;
+
+ /* draw time bar */
+ if (timebar_height > 0) {
+ cairo_new_path (cr);
+ cairo_rectangle (cr, gx, gy + gh - timebar_height, gw, timebar_height);
+ cairo_set_source_rgb (cr, 0x72 / 255.0, 0x9f / 255.0, 0xcf / 255.0);
+ cairo_fill_preserve (cr);
+ cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_set_line_width (cr, 1.0);
- cairo_set_dash (cr, dashes, 1, 0.0);
- cairo_move_to (cr,
- gx - 0.5,
- pos - 0.5);
- cairo_line_to (cr,
- gx - 0.5 + gw,
- pos - 0.5);
+ cairo_set_dash (cr, NULL, 0, 0.0);
cairo_stroke (cr);
}
- /* draw markers on the right y-axis */
- for (n = 0; n < n_y_markers_right; n++) {
- gdouble pos;
- const gchar *s;
+ /* clip to the graph + timebar area */
+ cairo_rectangle (cr, gx, gy, gw, gh);
+ cairo_clip (cr);
+
+ /* ---------------------------------------------------------------------------------------------------- */
+
+ GPtrArray *time_markers;
+ time_markers = time_markers_get (cr,
+ window_since_usec,
+ window_until_usec,
+ gw);
+ for (n = 0; n < time_markers->len; n++) {
+ TimeMarker *marker;
cairo_text_extents_t te;
- pos = ceil (gy + gh / (n_y_markers_right - 1) * n);
+ marker = time_markers->pdata[n];
- s = graph->priv->y_markers_right[n_y_markers_right - 1 - n];
+ x = ceil (gx + gw * (marker->time_usec- window_since_usec) / window_size_usec) + 0.5;
+
+ /* draw the vertical line */
+ cairo_new_path (cr);
+ cairo_move_to (cr, x, gy);
+ if (marker->flags & TIME_MARKER_FLAGS_TEXT_AREA) {
+ cairo_line_to (cr, x, gy + gh);
+ } else {
+ cairo_line_to (cr, x, gy + gh - timebar_height);
+ }
+ if (marker->flags & TIME_MARKER_FLAGS_EMPHASIS) {
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 1.0);
+ cairo_set_line_width (cr, 1.0);
+ } else {
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.75);
+ cairo_set_line_width (cr, 0.5);
+ }
+ cairo_set_dash (cr, NULL, 0, 0.0);
+ cairo_stroke (cr);
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
cairo_select_font_face (cr, "sans",
CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
cairo_set_font_size (cr, 8.0);
- cairo_text_extents (cr, s, &te);
- cairo_move_to (cr,
- gx + gw + right_margin/2.0 + 3 - te.width/2 - te.x_bearing,
- pos - te.height/2 - te.y_bearing);
+ cairo_text_extents (cr, marker->text, &te);
- cairo_show_text (cr, s);
- }
-
- g_get_current_time (&now);
- t_left = now.tv_sec - 6 * 24 * 60 * 60;
- t_right = now.tv_sec;
-
- /* draw time markers on x-axis */
- for (n = 0; n < n_x_markers; n++) {
- double pos;
- guint64 val;
- const gchar *s;
- cairo_text_extents_t te;
- double dashes[1] = {2.0};
+ if (timebar_style == TIMEBAR_STYLE_SEPARATE) {
+ y = gy + gh - timebar_height/2 - 8.0/2 - te.y_bearing;
+ } else {
+ y = gy + gh - 8.0 - 2.0 - te.y_bearing;
+ }
- s = graph->priv->x_markers[n];
+ if (marker->text_align == TIME_MARKER_TEXT_ALIGN_CENTER) {
- pos = ceil (gx + gw / (n_x_markers - 1) * n);
- val = t_left + (t_right - t_left) * n / (n_x_markers - 1);
+ cairo_move_to (cr,
+ x + te.x_bearing + 3 + marker->text_width_pixels/2 - te.width/2,
+ y);
- cairo_set_source_rgb (cr, 0.0, 0.0, 0.0);
- cairo_select_font_face (cr, "sans",
- CAIRO_FONT_SLANT_NORMAL, CAIRO_FONT_WEIGHT_NORMAL);
- cairo_set_font_size (cr, 8.0);
- cairo_text_extents (cr, s, &te);
- cairo_move_to (cr,
- pos - te.width/2 - te.x_bearing,
- gy + gh + x_markers_height/2.0 - te.y_bearing);
+ } else if (marker->text_align == TIME_MARKER_TEXT_ALIGN_LEFT) {
- cairo_show_text (cr, s);
+ cairo_move_to (cr,
+ x + te.x_bearing + 3,
+ y);
+ }
- cairo_set_line_width (cr, 1.0);
- cairo_set_dash (cr, dashes, 1, 0.0);
- cairo_move_to (cr,
- pos - 0.5,
- gy - 0.5);
- cairo_line_to (cr,
- pos - 0.5,
- gy - 0.5 + gh);
- cairo_stroke (cr);
+ cairo_show_text (cr, marker->text);
}
+ g_ptr_array_unref (time_markers);
/* clip to the graph area */
- cairo_rectangle (cr, gx, gy, gw, gh);
+ cairo_rectangle (cr, gx, gy, gw, gh - timebar_height);
+ cairo_reset_clip (cr);
cairo_clip (cr);
for (l = curve_list; l != NULL; l = l->next) {
@@ -638,8 +885,10 @@ gdu_graph_expose_event (GtkWidget *widget,
GduColor *fill_color;
gdouble width;
GduCurveFlags flags;
- GArray *points;
+ GArray *samples;
guint m;
+ gdouble sample_value_min;
+ gdouble sample_value_max;
color = gdu_curve_get_color (c);
fill_color = gdu_curve_get_fill_color (c);
@@ -647,48 +896,117 @@ gdu_graph_expose_event (GtkWidget *widget,
fill_color = color;
width = gdu_curve_get_width (c);
flags = gdu_curve_get_flags (c);
- points = gdu_curve_get_points (c);
+ samples = gdu_curve_get_samples (c);
+
+ /* if normalization is requested, find min/max for sample values in curve on window */
+ if (flags & GDU_CURVE_FLAGS_NORMALIZE) {
+ sample_value_min = G_MAXDOUBLE;
+ sample_value_max = -G_MAXDOUBLE;
+
+ for (m = 0; m < samples->len; m++) {
+ GduSample *sample;
+
+ sample = &g_array_index (samples, GduSample, m);
+ /* ignore break points */
+ if (sample->time_usec == G_MAXINT64 && sample->value == G_MAXDOUBLE)
+ continue;
+
+ /* ignore samples outside window */
+ x = gx + gw * (sample->time_usec - window_since_usec) / window_size_usec;
+ if (x < gx)
+ continue;
+ if (x > gx + gw)
+ continue;
+
+ if (sample->value < sample_value_min)
+ sample_value_min = sample->value;
+ if (sample->value > sample_value_max)
+ sample_value_max = sample->value;
+ }
+
+ if (sample_value_max - sample_value_min < 0.001) {
+ sample_value_min -= 1.0;
+ sample_value_max += 1.0;
+ }
+ } else {
+ sample_value_min = 0.0;
+ sample_value_max = 1.0;
+ }
+
+ /* draw the curve */
m = 0;
- while (m < points->len) {
- guint first_point_index;
+ while (m < samples->len) {
+ gint first_sample_index;
cairo_new_path (cr);
- first_point_index = m;
- for (; m < points->len; m++) {
- GduPoint *point;
+ first_sample_index = -1;
+ for (; m < samples->len; m++) {
+ GduSample *sample;
+ gdouble sample_value_normalized;
- point = &g_array_index (points, GduPoint, m);
+ sample = &g_array_index (samples, GduSample, m);
- if (point->x == G_MAXDOUBLE &&
- point->y == G_MAXDOUBLE) {
+ if (sample->time_usec == G_MAXINT64 && sample->value == G_MAXDOUBLE) {
m++;
break;
}
- x = gx + gw * point->x;
- y = gy + gh * (1.0f - point->y);
+ x = gx + gw * (sample->time_usec - window_since_usec) / window_size_usec;
+
+ if (x < gx) {
+ if (m + 1 < samples->len) {
+ GduSample *next_sample;
+ gdouble next_x;
+
+ next_sample = &g_array_index (samples, GduSample, m + 1);
+ next_x = gx + gw * (next_sample->time_usec - window_since_usec) / window_size_usec;
+ if (next_x < gx)
+ continue;
+ } else {
+ continue;
+ }
+ }
+
+ sample_value_normalized = (sample->value - sample_value_min) /
+ (sample_value_max - sample_value_min);
+
+ y = gy + (gh - timebar_height) * (1.0f - sample_value_normalized);
if (y < gy + 1.0)
y = gy;
- if (y > gy + gh - 1.0)
- y = gy + gh - 1.0;
+ if (y > gy + (gh - timebar_height) - 1.0)
+ y = gy + (gh - timebar_height) - 1.0;
cairo_line_to (cr, x, y);
+
+ if (first_sample_index == -1)
+ first_sample_index = m;
}
+ /* then draw the curve */
+ cairo_set_dash (cr, NULL, 0, 0.0);
+ cairo_set_line_width (cr, width);
+ cairo_set_source_rgba (cr,
+ color->red,
+ color->green,
+ color->blue,
+ color->alpha);
+
+ cairo_stroke_preserve (cr);
+
/* fill if requested */
- if (flags & GDU_CURVE_FLAGS_FILLED) {
- GduPoint *point;
+ if (flags & GDU_CURVE_FLAGS_FILLED && first_sample_index != -1) {
+ GduSample *sample;
gdouble first_x;
/* first, close the path */
- cairo_line_to (cr, x, gy + gh);
- point = &g_array_index (points, GduPoint, first_point_index);
- first_x = gx + gw * point->x;
- cairo_line_to (cr, first_x, gy + gh);
+ cairo_line_to (cr, x, gy + (gh - timebar_height));
+ sample = &g_array_index (samples, GduSample, first_sample_index);
+ first_x = gx + gw * (sample->time_usec - window_since_usec) / window_size_usec;
+ cairo_line_to (cr, first_x, gy + (gh - timebar_height));
cairo_close_path (cr);
if (flags & GDU_CURVE_FLAGS_FADE_EDGES) {
@@ -700,25 +1018,156 @@ gdu_graph_expose_event (GtkWidget *widget,
fill_color->blue,
fill_color->alpha);
}
- cairo_fill_preserve (cr);
+ cairo_fill (cr);
}
- /* then draw the curve */
- cairo_set_dash (cr, NULL, 0, 0.0);
- cairo_set_line_width (cr, width);
- cairo_set_source_rgba (cr,
- color->red,
- color->green,
- color->blue,
- color->alpha);
+ } /* process more samples */
+ }
+}
+
+static gboolean
+gdu_graph_expose_event (GtkWidget *widget,
+ GdkEventExpose *event)
+{
+ GduGraph *graph = GDU_GRAPH (widget);
+ cairo_t *cr;
+ gdouble width, height;
+ guint left_margin;
+ guint right_margin;
+ guint top_margin;
+ guint bottom_margin;
+ gdouble gx, gy, gw, gh;
+ gint64 window_since_usec;
+ gint64 window_until_usec;
+ gint64 small_graph_window_since_usec;
+ gint64 small_graph_window_until_usec;
+ GList *curve_list;
+ GList *l;
+ gint64 now_usec;
+
+ curve_list = g_hash_table_get_values (graph->priv->curves);
+ curve_list = g_list_sort (curve_list,
+ (GCompareFunc) curve_z_order_sort);
+
+ width = widget->allocation.width;
+ height = widget->allocation.height;
+
+ cr = gdk_cairo_create (widget->window);
+
+ cairo_rectangle (cr,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+ cairo_clip (cr);
+
+ gx = 0.5;
+ gy = 0.5;
+ gw = width;
+ gh = height;
+
+ top_margin = 10;
+ bottom_margin = 10;
+ left_margin = 10;
+ right_margin = 10;
+
+ guint small_graph_height;
+ small_graph_height = 60;
+ bottom_margin += small_graph_height;
+
+ /* adjust drawing area */
+ gy += top_margin;
+ gh -= top_margin;
+ gh -= bottom_margin;
+ gx += left_margin;
+ gw -= left_margin;
+ gw -= right_margin;
+
+ now_usec = time (NULL) * G_USEC_PER_SEC;
+ window_until_usec = graph->priv->window_end_usec;
+ if (graph->priv->window_end_usec > now_usec)
+ window_until_usec = now_usec;
+ window_since_usec = window_until_usec - graph->priv->window_size_usec;
+
+ draw_curves (cr,
+ gx, gy, gw, gh,
+ TIMEBAR_STYLE_SEPARATE,
+ curve_list,
+ window_since_usec, window_until_usec);
+
+
+ small_graph_window_since_usec = G_MAXINT64;
+ small_graph_window_until_usec = G_MININT64;
+ for (l = curve_list; l != NULL; l = l->next) {
+ GduCurve *curve;
+ GArray *samples;
+ GduSample *sample;
+ gint64 first, last;
+
+ curve = GDU_CURVE (l->data);
+ samples = gdu_curve_get_samples (curve);
+
+ if (samples == NULL || samples->len == 0)
+ continue;
+
+ sample = &g_array_index (samples, GduSample, 0);
+ first = sample->time_usec;
+
+ sample = &g_array_index (samples, GduSample, samples->len - 1);
+ last = sample->time_usec;
+
+ if (first != G_MAXINT64) {
+ if (first < small_graph_window_since_usec)
+ small_graph_window_since_usec = first;
+ }
+
+ if (last != G_MAXINT64) {
+ if (last > small_graph_window_until_usec)
+ small_graph_window_until_usec = last;
+ }
+ }
+ if (small_graph_window_since_usec != G_MAXINT64 && small_graph_window_until_usec != G_MININT64) {
+
+ if (small_graph_window_until_usec - small_graph_window_since_usec < 21 * 24 * 3600 * 1L * G_USEC_PER_SEC)
+ small_graph_window_since_usec = small_graph_window_until_usec - 21 * 24 * 3600 * 1L * G_USEC_PER_SEC;
+
+ draw_curves (cr,
+ gx, gy + gh, gw, small_graph_height,
+ TIMEBAR_STYLE_EMBEDDED,
+ curve_list,
+ small_graph_window_since_usec, small_graph_window_until_usec);
+
+ gdouble zm_x0;
+ gdouble zm_x1;
+ gint64 small_window_size_usec;
+
+ small_window_size_usec = small_graph_window_until_usec - small_graph_window_since_usec;
- cairo_stroke (cr);
+ zm_x0 = gx + gw * (window_since_usec - small_graph_window_since_usec) / small_window_size_usec;
+ zm_x1 = gx + gw * (window_until_usec - small_graph_window_since_usec) / small_window_size_usec;
+
+ cairo_reset_clip (cr);
+ cairo_set_source_rgba (cr, 0.0, 0.0, 0.0, 0.5);
+
+#if 1
+ cairo_rectangle (cr,
+ gx, gy + gh,
+ zm_x0 - gx, small_graph_height);
+ cairo_fill (cr);
+#endif
+
+#if 1
+ cairo_rectangle (cr,
+ zm_x1, gy + gh,
+ gx + gw - zm_x1, small_graph_height);
+ cairo_fill (cr);
+#endif
- } /* process more points */
}
+
g_list_free (curve_list);
+ cairo_destroy (cr);
+
/* propagate event further */
return FALSE;
}
diff --git a/src/gdu-gtk/gdu-graph.h b/src/gdu-gtk/gdu-graph.h
index 5db40e7..b238dd5 100644
--- a/src/gdu-gtk/gdu-graph.h
+++ b/src/gdu-gtk/gdu-graph.h
@@ -54,15 +54,13 @@ struct GduGraphClass
GType gdu_graph_get_type (void);
GtkWidget *gdu_graph_new (void);
-gchar **gdu_graph_get_x_markers (GduGraph *graph);
-gchar **gdu_graph_get_y_markers_left (GduGraph *graph);
-gchar **gdu_graph_get_y_markers_right (GduGraph *graph);
-void gdu_graph_set_x_markers (GduGraph *graph,
- const gchar* const *markers);
-void gdu_graph_set_y_markers_left (GduGraph *graph,
- const gchar* const *markers);
-void gdu_graph_set_y_markers_right (GduGraph *graph,
- const gchar* const *markers);
+
+gint64 gdu_graph_get_window_end_usec (GduGraph *graph);
+gint64 gdu_graph_get_window_size_usec (GduGraph *graph);
+void gdu_graph_set_window_end_usec (GduGraph *graph,
+ gint64 time_usec);
+void gdu_graph_set_window_size_usec (GduGraph *graph,
+ gint64 period_usec);
GduCurve *gdu_graph_lookup_curve (GduGraph *graph,
const gchar *curve_id);
diff --git a/src/gdu-gtk/gdu-gtk-enums.h b/src/gdu-gtk/gdu-gtk-enums.h
index 9c1b49c..c9b5ad5 100644
--- a/src/gdu-gtk/gdu-gtk-enums.h
+++ b/src/gdu-gtk/gdu-gtk-enums.h
@@ -28,11 +28,19 @@
#include <glib-object.h>
-typedef enum
-{
- GDU_CURVE_FLAGS_NONE = 0,
- GDU_CURVE_FLAGS_FILLED = (1 << 0),
- GDU_CURVE_FLAGS_FADE_EDGES = (1 << 1),
+typedef enum {
+ GDU_CURVE_FLAGS_NONE = 0,
+ GDU_CURVE_FLAGS_FILLED = (1 << 0),
+ GDU_CURVE_FLAGS_FADE_EDGES = (1 << 1),
+ GDU_CURVE_FLAGS_AXIS_MARKERS_LEFT = (1 << 2),
+ GDU_CURVE_FLAGS_AXIS_MARKERS_RIGHT = (1 << 3),
+ GDU_CURVE_FLAGS_NORMALIZE = (1 << 4),
} GduCurveFlags;
+typedef enum {
+ GDU_CURVE_UNIT_NUMBER = 0,
+ GDU_CURVE_UNIT_TIME = 1,
+ GDU_CURVE_UNIT_TEMPERATURE = 2
+} GduCurveUnit;
+
#endif /* GDU_GTK_ENUMS_H */
diff --git a/src/gdu-gtk/gdu-gtk-types.h b/src/gdu-gtk/gdu-gtk-types.h
index 2be3ac0..afa97b2 100644
--- a/src/gdu-gtk/gdu-gtk-types.h
+++ b/src/gdu-gtk/gdu-gtk-types.h
@@ -33,7 +33,7 @@
G_BEGIN_DECLS
-typedef struct GduPoint GduPoint;
+typedef struct GduSample GduSample;
typedef struct GduColor GduColor;
typedef struct GduCurve GduCurve;
typedef struct GduGraph GduGraph;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]