Skip to content

Commit 69a17a8

Browse files
committed
st-entry: Add progress/busy bar.
This works similarly to Gtk's, a thin bar under the text in an entry box.
1 parent c264274 commit 69a17a8

3 files changed

Lines changed: 250 additions & 0 deletions

File tree

data/theme/cinnamon-sass/_common.scss

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ stage {
6262
icon-size: 16px;
6363
color: $fg_color;
6464
}
65+
66+
-st-progress-color: $accent_bg_color;
6567
}
6668

6769
// buttons in dialogs

src/st/st-entry.c

Lines changed: 242 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,7 @@ enum
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+
117132
static guint entry_signals[LAST_SIGNAL] = { 0, };
118133

119134
G_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
/******************************************************************************/

src/st/st-entry.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,12 @@ void st_entry_set_hint_actor (StEntry *entry,
8686
ClutterActor *hint_actor);
8787
ClutterActor * st_entry_get_hint_actor (StEntry *entry);
8888

89+
void st_entry_set_progress (StEntry *entry,
90+
gdouble fraction);
91+
gdouble st_entry_get_progress (StEntry *entry);
92+
void st_entry_start_busy (StEntry *entry);
93+
void st_entry_end_busy (StEntry *entry);
94+
8995
G_END_DECLS
9096

9197
#endif /* __ST_ENTRY_H__ */

0 commit comments

Comments
 (0)