diff --git a/src/libsysprof-gtk/style.css b/src/libsysprof-gtk/style.css
index ce16809b..672858a3 100644
--- a/src/libsysprof-gtk/style.css
+++ b/src/libsysprof-gtk/style.css
@@ -69,6 +69,18 @@ timeruler {
color: alpha(currentColor, .8);
}
+tracks timecode {
+ border-radius: 7px;
+ background: @accent_bg_color;
+ color: @accent_fg_color;
+ padding: 1px 3px;
+ margin: 2px 6px;
+ box-shadow: 0 2px 8px 2px alpha(black, .27);
+ border: 1px solid shade(@accent_bg_color, .9);
+ font-feature-settings: "tnum";
+ font-size: .9em;
+}
+
tracks track chart {
margin-top: 1px;
}
diff --git a/src/libsysprof-gtk/sysprof-time-ruler.c b/src/libsysprof-gtk/sysprof-time-ruler.c
index f4673b1f..c64691c7 100644
--- a/src/libsysprof-gtk/sysprof-time-ruler.c
+++ b/src/libsysprof-gtk/sysprof-time-ruler.c
@@ -279,3 +279,41 @@ sysprof_time_ruler_set_session (SysprofTimeRuler *self,
g_object_notify_by_pspec (G_OBJECT (self), properties[PROP_SESSION]);
}
}
+
+char *
+sysprof_time_ruler_get_label_at_point (SysprofTimeRuler *self,
+ double x)
+{
+ char str[32];
+ const SysprofTimeSpan *visible;
+ gint64 duration;
+ gint64 o;
+
+ g_return_val_if_fail (SYSPROF_IS_TIME_RULER (self), NULL);
+
+ if (x < 0)
+ return NULL;
+
+ if (x > gtk_widget_get_width (GTK_WIDGET (self)))
+ return NULL;
+
+ if (self->session == NULL)
+ return NULL;
+
+ if (!(visible = sysprof_session_get_visible_time (self->session)) ||
+ !(duration = sysprof_time_span_duration (*visible)))
+ return NULL;
+
+ o = (x / (double)gtk_widget_get_width (GTK_WIDGET (self))) * duration;
+
+ if (o == 0)
+ g_snprintf (str, sizeof str, "%.3lfs", .0);
+ else if (o < 1000000)
+ g_snprintf (str, sizeof str, "%.3lfμs", o/1000.);
+ else if (o < SYSPROF_NSEC_PER_SEC)
+ g_snprintf (str, sizeof str, "%.3lfms", o/1000000.);
+ else
+ g_snprintf (str, sizeof str, "%.3lfs", o/(double)SYSPROF_NSEC_PER_SEC);
+
+ return g_strdup (str);
+}
diff --git a/src/libsysprof-gtk/sysprof-time-ruler.h b/src/libsysprof-gtk/sysprof-time-ruler.h
index 900070c4..a80fd0e7 100644
--- a/src/libsysprof-gtk/sysprof-time-ruler.h
+++ b/src/libsysprof-gtk/sysprof-time-ruler.h
@@ -30,11 +30,14 @@ SYSPROF_AVAILABLE_IN_ALL
G_DECLARE_FINAL_TYPE (SysprofTimeRuler, sysprof_time_ruler, SYSPROF, TIME_RULER, GtkWidget)
SYSPROF_AVAILABLE_IN_ALL
-GtkWidget *sysprof_time_ruler_new (void);
+GtkWidget *sysprof_time_ruler_new (void);
SYSPROF_AVAILABLE_IN_ALL
-SysprofSession *sysprof_time_ruler_get_session (SysprofTimeRuler *self);
+SysprofSession *sysprof_time_ruler_get_session (SysprofTimeRuler *self);
SYSPROF_AVAILABLE_IN_ALL
-void sysprof_time_ruler_set_session (SysprofTimeRuler *self,
- SysprofSession *session);
+void sysprof_time_ruler_set_session (SysprofTimeRuler *self,
+ SysprofSession *session);
+SYSPROF_AVAILABLE_IN_ALL
+char *sysprof_time_ruler_get_label_at_point (SysprofTimeRuler *self,
+ double x);
G_END_DECLS
diff --git a/src/libsysprof-gtk/sysprof-tracks-view.c b/src/libsysprof-gtk/sysprof-tracks-view.c
index 67a6ed43..73d358ce 100644
--- a/src/libsysprof-gtk/sysprof-tracks-view.c
+++ b/src/libsysprof-gtk/sysprof-tracks-view.c
@@ -27,24 +27,26 @@
struct _SysprofTracksView
{
- GtkWidget parent_instance;
+ GtkWidget parent_instance;
- SysprofSession *session;
+ SysprofSession *session;
- GtkBox *box;
- GtkWidget *top_left;
- GtkListView *list_view;
- GtkButton *zoom;
+ GtkBox *box;
+ GtkWidget *top_left;
+ GtkListView *list_view;
+ SysprofTimeRuler *ruler;
+ GtkLabel *timecode;
+ GtkButton *zoom;
- double motion_x;
- double motion_y;
+ double motion_x;
+ double motion_y;
- double drag_start_x;
- double drag_start_y;
- double drag_offset_x;
- double drag_offset_y;
+ double drag_start_x;
+ double drag_start_y;
+ double drag_offset_x;
+ double drag_offset_y;
- guint in_drag_selection : 1;
+ guint in_drag_selection : 1;
};
enum {
@@ -57,6 +59,36 @@ G_DEFINE_FINAL_TYPE (SysprofTracksView, sysprof_tracks_view, GTK_TYPE_WIDGET)
static GParamSpec *properties [N_PROPS];
+static void
+set_motion (SysprofTracksView *self,
+ double x,
+ double y)
+{
+ gboolean timecode_visible = FALSE;
+ int ruler_start;
+
+ g_assert (SYSPROF_IS_TRACKS_VIEW (self));
+
+ if (self->motion_x == x && self->motion_y == y)
+ return;
+
+ self->motion_x = x;
+ self->motion_y = y;
+
+ ruler_start = gtk_widget_get_width (self->top_left);
+
+ if (x >= ruler_start)
+ {
+ g_autofree char *str = sysprof_time_ruler_get_label_at_point (self->ruler, x - ruler_start);
+ gtk_label_set_label (self->timecode, str);
+ timecode_visible = TRUE;
+ }
+
+ gtk_widget_set_visible (GTK_WIDGET (self->timecode), timecode_visible);
+
+ gtk_widget_queue_draw (GTK_WIDGET (self));
+}
+
static void
sysprof_tracks_view_motion_enter_cb (SysprofTracksView *self,
double x,
@@ -66,10 +98,7 @@ sysprof_tracks_view_motion_enter_cb (SysprofTracksView *self,
g_assert (SYSPROF_IS_TRACKS_VIEW (self));
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
- self->motion_x = x;
- self->motion_y = y;
-
- gtk_widget_queue_draw (GTK_WIDGET (self));
+ set_motion (self, x, y);
}
static void
@@ -79,11 +108,7 @@ sysprof_tracks_view_motion_leave_cb (SysprofTracksView *self,
g_assert (SYSPROF_IS_TRACKS_VIEW (self));
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
- self->motion_x = -1;
- self->motion_y = -1;
-
- gtk_widget_queue_draw (GTK_WIDGET (self));
-
+ set_motion (self, -1, -1);
}
static void
@@ -95,10 +120,7 @@ sysprof_tracks_view_motion_cb (SysprofTracksView *self,
g_assert (SYSPROF_IS_TRACKS_VIEW (self));
g_assert (GTK_IS_EVENT_CONTROLLER_MOTION (motion));
- self->motion_x = x;
- self->motion_y = y;
-
- gtk_widget_queue_draw (GTK_WIDGET (self));
+ set_motion (self, x, y);
}
static void
@@ -332,6 +354,9 @@ G_GNUC_END_IGNORE_DEPRECATIONS
if (gtk_widget_get_visible (GTK_WIDGET (self->zoom)))
gtk_widget_snapshot_child (GTK_WIDGET (self), GTK_WIDGET (self->zoom), snapshot);
+
+ if (gtk_widget_get_visible (GTK_WIDGET (self->timecode)))
+ gtk_widget_snapshot_child (GTK_WIDGET (self), GTK_WIDGET (self->timecode), snapshot);
}
static void
@@ -391,9 +416,9 @@ sysprof_tracks_view_size_allocate (GtkWidget *widget,
GtkRequisition min_req;
GtkRequisition nat_req;
+ /* Position the zoom button in the center of the selected area */
gtk_widget_get_preferred_size (GTK_WIDGET (self->zoom), &min_req, &nat_req);
graphene_rect_get_center (&selection, &middle);
-
gtk_widget_size_allocate (GTK_WIDGET (self->zoom),
&(GtkAllocation) {
middle.x - (min_req.width/2),
@@ -402,6 +427,27 @@ sysprof_tracks_view_size_allocate (GtkWidget *widget,
min_req.height
}, -1);
}
+
+ if (gtk_widget_get_visible (GTK_WIDGET (self->timecode)))
+ {
+ GtkRequisition min_req;
+ GtkRequisition nat_req;
+
+ gtk_widget_get_preferred_size (GTK_WIDGET (self->timecode), &min_req, &nat_req);
+
+ if (self->motion_x + min_req.width < gtk_widget_get_width (GTK_WIDGET (self)))
+ gtk_widget_size_allocate (GTK_WIDGET (self->timecode),
+ &(GtkAllocation) {
+ self->motion_x, 0,
+ min_req.width, min_req.height
+ }, -1);
+ else
+ gtk_widget_size_allocate (GTK_WIDGET (self->timecode),
+ &(GtkAllocation) {
+ self->motion_x - min_req.width, 0,
+ min_req.width, min_req.height
+ }, -1);
+ }
}
static void
@@ -484,6 +530,8 @@ sysprof_tracks_view_class_init (SysprofTracksViewClass *klass)
gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, box);
gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, list_view);
+ gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, ruler);
+ gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, timecode);
gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, top_left);
gtk_widget_class_bind_template_child (widget_class, SysprofTracksView, zoom);
diff --git a/src/libsysprof-gtk/sysprof-tracks-view.ui b/src/libsysprof-gtk/sysprof-tracks-view.ui
index f04f35cf..6d90f5b3 100644
--- a/src/libsysprof-gtk/sysprof-tracks-view.ui
+++ b/src/libsysprof-gtk/sysprof-tracks-view.ui
@@ -29,7 +29,7 @@
-
+
+
+ timecode
+ false
+
+
+