8181 PROP_HINT_TEXT ,
8282 PROP_HINT_ACTOR ,
8383 PROP_TEXT ,
84+ PROP_PROGRESS ,
8485};
8586
8687/* signals */
@@ -112,8 +113,22 @@ struct _StEntryPrivate
112113 CoglPipeline * text_shadow_material ;
113114 gfloat shadow_width ;
114115 gfloat shadow_height ;
116+
117+ gdouble progress_fraction ;
118+ gdouble progress_pulse_position ;
119+ guint progress_timeout ;
120+ gboolean progress_visible ;
121+ gboolean progress_pulse_way_back ;
122+ ClutterColor progress_color ;
123+ gfloat progress_height ;
124+ CoglPipeline * progress_pipeline ;
115125};
116126
127+ #define PROGRESS_PULSE_FRACTION 0.2
128+ #define PROGRESS_PULSE_STEP 0.02
129+ #define PROGRESS_PULSE_INTERVAL_MS 30
130+ #define PROGRESS_DEFAULT_HEIGHT 2.0
131+
117132static guint entry_signals [LAST_SIGNAL ] = { 0 , };
118133
119134G_DEFINE_TYPE_WITH_PRIVATE (StEntry , st_entry , ST_TYPE_WIDGET );
@@ -142,6 +157,10 @@ st_entry_set_property (GObject *gobject,
142157 st_entry_set_text (entry , g_value_get_string (value ));
143158 break ;
144159
160+ case PROP_PROGRESS :
161+ st_entry_set_progress (entry , g_value_get_double (value ));
162+ break ;
163+
145164 default :
146165 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject , prop_id , pspec );
147166 break ;
@@ -174,6 +193,10 @@ st_entry_get_property (GObject *gobject,
174193 g_value_set_string (value , clutter_text_get_text (CLUTTER_TEXT (priv -> entry )));
175194 break ;
176195
196+ case PROP_PROGRESS :
197+ g_value_set_double (value , priv -> progress_fraction );
198+ break ;
199+
177200 default :
178201 G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject , prop_id , pspec );
179202 break ;
@@ -230,6 +253,13 @@ st_entry_dispose (GObject *object)
230253 ClutterSeat * seat ;
231254
232255 cogl_clear_object (& priv -> text_shadow_material );
256+ cogl_clear_object (& priv -> progress_pipeline );
257+
258+ if (priv -> progress_timeout )
259+ {
260+ g_source_remove (priv -> progress_timeout );
261+ priv -> progress_timeout = 0 ;
262+ }
233263
234264 seat = clutter_backend_get_default_seat (clutter_get_default_backend ());
235265 keymap = clutter_seat_get_keymap (seat );
@@ -264,6 +294,7 @@ st_entry_style_changed (StWidget *self)
264294 gdouble size ;
265295
266296 cogl_clear_object (& priv -> text_shadow_material );
297+ cogl_clear_object (& priv -> progress_pipeline );
267298
268299 theme_node = st_widget_get_theme_node (self );
269300
@@ -279,6 +310,14 @@ st_entry_style_changed (StWidget *self)
279310 if (st_theme_node_lookup_color (theme_node , "selected-color" , TRUE, & color ))
280311 clutter_text_set_selected_text_color (CLUTTER_TEXT (priv -> entry ), & color );
281312
313+ if (st_theme_node_lookup_color (theme_node , "-st-progress-color" , TRUE, & color ))
314+ priv -> progress_color = color ;
315+ else if (st_theme_node_lookup_color (theme_node , "caret-color" , TRUE, & color ))
316+ priv -> progress_color = color ;
317+
318+ if (st_theme_node_lookup_length (theme_node , "-st-progress-height" , TRUE, & size ))
319+ priv -> progress_height = size ;
320+
282321 _st_set_text_from_style ((ClutterText * )priv -> entry , theme_node );
283322
284323 ST_WIDGET_CLASS (st_entry_parent_class )-> style_changed (self );
@@ -784,6 +823,53 @@ st_entry_paint (ClutterActor *actor,
784823 }
785824 }
786825
826+ if (priv -> progress_visible )
827+ {
828+ CoglFramebuffer * framebuffer =
829+ clutter_paint_context_get_framebuffer (paint_context );
830+ ClutterActorBox content_box , actor_box ;
831+ gfloat bar_x , bar_y , bar_width , bar_height ;
832+ gfloat total_width ;
833+
834+ clutter_actor_get_allocation_box (actor , & actor_box );
835+ st_theme_node_get_content_box (theme_node , & actor_box , & content_box );
836+ total_width = content_box .x2 - content_box .x1 ;
837+ bar_height = priv -> progress_height ;
838+ bar_y = content_box .y2 - bar_height ;
839+
840+ if (priv -> progress_timeout )
841+ {
842+ bar_width = PROGRESS_PULSE_FRACTION * total_width ;
843+ bar_x = content_box .x1 + priv -> progress_pulse_position * (total_width - bar_width );
844+ }
845+ else
846+ {
847+ bar_x = content_box .x1 ;
848+ bar_width = priv -> progress_fraction * total_width ;
849+ }
850+
851+ if (bar_width > 0 )
852+ {
853+ if (priv -> progress_pipeline == NULL )
854+ {
855+ CoglContext * ctx =
856+ clutter_backend_get_cogl_context (clutter_get_default_backend ());
857+ priv -> progress_pipeline = cogl_pipeline_new (ctx );
858+ }
859+
860+ cogl_pipeline_set_color4ub (priv -> progress_pipeline ,
861+ priv -> progress_color .red ,
862+ priv -> progress_color .green ,
863+ priv -> progress_color .blue ,
864+ priv -> progress_color .alpha );
865+ cogl_framebuffer_draw_rectangle (framebuffer ,
866+ priv -> progress_pipeline ,
867+ bar_x , bar_y ,
868+ bar_x + bar_width ,
869+ bar_y + bar_height );
870+ }
871+ }
872+
787873 /* Since we paint the background ourselves, chain to the parent class
788874 * of StWidget, to avoid painting it twice.
789875 * This is needed as we still want to paint children.
@@ -845,6 +931,20 @@ st_entry_class_init (StEntryClass *klass)
845931 NULL , G_PARAM_READWRITE );
846932 g_object_class_install_property (gobject_class , PROP_TEXT , pspec );
847933
934+ /**
935+ * StEntry:progress:
936+ *
937+ * A value between 0.0 and 1.0 indicating the fraction of work completed.
938+ * Setting this to a value greater than 0.0 will display a progress bar
939+ * inside the entry. Setting it to 0.0 hides the progress bar.
940+ */
941+ pspec = g_param_spec_double ("progress" ,
942+ "Progress" ,
943+ "Progress fraction" ,
944+ 0.0 , 1.0 , 0.0 ,
945+ G_PARAM_READWRITE );
946+ g_object_class_install_property (gobject_class , PROP_PROGRESS , pspec );
947+
848948 /* signals */
849949 /**
850950 * StEntry::primary-icon-clicked:
@@ -907,6 +1007,9 @@ st_entry_init (StEntry *entry)
9071007 priv -> shadow_width = -1. ;
9081008 priv -> shadow_height = -1. ;
9091009
1010+ priv -> progress_height = PROGRESS_DEFAULT_HEIGHT ;
1011+ priv -> progress_color = (ClutterColor ) { 0x4a , 0x90 , 0xd9 , 0xff };
1012+
9101013 clutter_actor_add_child (CLUTTER_ACTOR (entry ), priv -> entry );
9111014 clutter_actor_set_reactive ((ClutterActor * ) entry , TRUE);
9121015
@@ -1239,6 +1342,145 @@ st_entry_get_hint_actor (StEntry *entry)
12391342 return priv -> hint_actor ;
12401343}
12411344
1345+ static gboolean
1346+ progress_pulse_cb (gpointer data )
1347+ {
1348+ StEntry * entry = ST_ENTRY (data );
1349+ StEntryPrivate * priv = entry -> priv ;
1350+
1351+ if (priv -> progress_pulse_way_back )
1352+ {
1353+ priv -> progress_pulse_position -= PROGRESS_PULSE_STEP ;
1354+
1355+ if (priv -> progress_pulse_position < 0.0 )
1356+ {
1357+ priv -> progress_pulse_position = 0.0 ;
1358+ priv -> progress_pulse_way_back = FALSE;
1359+ }
1360+ }
1361+ else
1362+ {
1363+ priv -> progress_pulse_position += PROGRESS_PULSE_STEP ;
1364+
1365+ if (priv -> progress_pulse_position > 1.0 )
1366+ {
1367+ priv -> progress_pulse_position = 1.0 ;
1368+ priv -> progress_pulse_way_back = TRUE;
1369+ }
1370+ }
1371+
1372+ clutter_actor_queue_redraw (CLUTTER_ACTOR (entry ));
1373+ return G_SOURCE_CONTINUE ;
1374+ }
1375+
1376+ /**
1377+ * st_entry_set_progress:
1378+ * @entry: a #StEntry
1379+ * @fraction: value between 0.0 and 1.0
1380+ *
1381+ * Sets the progress fraction to display in a bar inside the entry.
1382+ * A value greater than 0.0 will display a proportional progress bar.
1383+ * Setting this to 0.0 will hide the progress bar. This also stops
1384+ * any active busy pulse animation.
1385+ */
1386+ void
1387+ st_entry_set_progress (StEntry * entry ,
1388+ gdouble fraction )
1389+ {
1390+ StEntryPrivate * priv ;
1391+
1392+ g_return_if_fail (ST_IS_ENTRY (entry ));
1393+
1394+ priv = entry -> priv ;
1395+ fraction = CLAMP (fraction , 0.0 , 1.0 );
1396+
1397+ if (priv -> progress_timeout )
1398+ {
1399+ g_source_remove (priv -> progress_timeout );
1400+ priv -> progress_timeout = 0 ;
1401+ }
1402+
1403+ priv -> progress_fraction = fraction ;
1404+ priv -> progress_visible = (fraction > 0.0 );
1405+
1406+ clutter_actor_queue_redraw (CLUTTER_ACTOR (entry ));
1407+ g_object_notify (G_OBJECT (entry ), "progress" );
1408+ }
1409+
1410+ /**
1411+ * st_entry_get_progress:
1412+ * @entry: a #StEntry
1413+ *
1414+ * Gets the current progress fraction.
1415+ *
1416+ * Returns: the progress fraction between 0.0 and 1.0
1417+ */
1418+ gdouble
1419+ st_entry_get_progress (StEntry * entry )
1420+ {
1421+ g_return_val_if_fail (ST_IS_ENTRY (entry ), 0.0 );
1422+
1423+ return entry -> priv -> progress_fraction ;
1424+ }
1425+
1426+ /**
1427+ * st_entry_start_busy:
1428+ * @entry: a #StEntry
1429+ *
1430+ * Starts a pulsing progress bar animation inside the entry.
1431+ * The bar bounces back and forth to indicate ongoing activity.
1432+ * Call st_entry_end_busy() to stop the animation.
1433+ */
1434+ void
1435+ st_entry_start_busy (StEntry * entry )
1436+ {
1437+ StEntryPrivate * priv ;
1438+
1439+ g_return_if_fail (ST_IS_ENTRY (entry ));
1440+
1441+ priv = entry -> priv ;
1442+
1443+ if (priv -> progress_timeout )
1444+ return ;
1445+
1446+ priv -> progress_visible = TRUE;
1447+ priv -> progress_pulse_position = 0.0 ;
1448+ priv -> progress_pulse_way_back = FALSE;
1449+ priv -> progress_fraction = 0.0 ;
1450+
1451+ priv -> progress_timeout =
1452+ clutter_threads_add_timeout (PROGRESS_PULSE_INTERVAL_MS ,
1453+ progress_pulse_cb ,
1454+ entry );
1455+ clutter_actor_queue_redraw (CLUTTER_ACTOR (entry ));
1456+ }
1457+
1458+ /**
1459+ * st_entry_end_busy:
1460+ * @entry: a #StEntry
1461+ *
1462+ * Stops the pulsing progress bar animation started by
1463+ * st_entry_start_busy().
1464+ */
1465+ void
1466+ st_entry_end_busy (StEntry * entry )
1467+ {
1468+ StEntryPrivate * priv ;
1469+
1470+ g_return_if_fail (ST_IS_ENTRY (entry ));
1471+
1472+ priv = entry -> priv ;
1473+
1474+ if (priv -> progress_timeout )
1475+ {
1476+ g_source_remove (priv -> progress_timeout );
1477+ priv -> progress_timeout = 0 ;
1478+ }
1479+
1480+ priv -> progress_visible = FALSE;
1481+ clutter_actor_queue_redraw (CLUTTER_ACTOR (entry ));
1482+ }
1483+
12421484/******************************************************************************/
12431485/*************************** ACCESSIBILITY SUPPORT ****************************/
12441486/******************************************************************************/
0 commit comments