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 @@ - + true SysprofTracksView @@ -155,5 +155,14 @@ + + + timecode + false + + +