Progress bar widget example

This application is a thorough example of the progress bar widget, consisting of a window with various progress bars, each with a given look/style one can give to those widgets.

With two auxiliary buttons, one can start or stop a timer which will fill in the bars in synchrony, simulating an underlying task being completed.

We create seven progress bars, being three of them horizontal, three vertical and a final one under the "wheel" alternate style.

For the first one, we add a progress bar on total pristine state, with no other call than the elm_progressbar_add() one:

/* pb with no label, default unit label and no icon */
evas_object_size_hint_weight_set(pb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(pb, EVAS_HINT_FILL, 0.5);
evas_object_show(pb);
example_data.pb1 = pb;
See, than, that the defaults of a progress bar are:

The second progress bar is given a primary label, "Infinite bounce", and, besides, it's set to pulse. See how, after one starts the progress timer, with the "Start" button, it animates differently than the previous one. It won't account for the progress, itself, and just dumbly animate a small bar within its bar region.

/* pb with label, and set to pulse */
evas_object_size_hint_align_set(pb, EVAS_HINT_FILL, 0.5);
evas_object_size_hint_weight_set(pb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_object_text_set(pb, "Infinite bounce");
elm_progressbar_pulse_set(pb, EINA_TRUE);
evas_object_show(pb);
example_data.pb2 = pb;

Next, comes a progress bar with an icon, a primary label and a unit label function set. It's also made to grow its bar in an inverted manner, so check that out during the timer's progression:

ic1 = elm_icon_add(win);
snprintf(buf, sizeof(buf), "%s/images/logo_small.png", elm_app_data_dir_get());
elm_image_file_set(ic1, buf, NULL);
evas_object_size_hint_aspect_set(ic1, EVAS_ASPECT_CONTROL_VERTICAL, 1, 1);
/* pb with label, icon, custom unit label function and span size set */
elm_object_text_set(pb, "Label");
elm_object_part_content_set(pb, "icon", ic1);
_progress_format_free);
evas_object_size_hint_align_set(pb, EVAS_HINT_FILL, 0.5);
evas_object_size_hint_weight_set(pb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show(ic1);
evas_object_show(pb);
example_data.pb3 = pb;
Another important thing in this one is the call to elm_progressbar_span_size_set() – this is how we forcefully set a minimum horizontal size to our whole window! We're not resizing it manually, as you can see in the complete code.

The format callback is a simple function that gets passed the progress value and returns a string. A free function should be provided as well, if the format callback allocates memory.

/* Format callback */
static char *
_progress_format_cb(double val)
{
static char buf[30];
int files = (1-val)*14000;
if (snprintf(buf, 30, "%i files left", files) > 0)
return strdup(buf);
return NULL;
}
static void
_progress_format_free(char *str)
{
free(str);
}

The last horizontal progress bar has a callback that gets called when its value is changed. This callback updates a label to provide an estimate when the operation finishes.

/* pb with label and changed trigger */
elm_object_text_set(pb, "Label");
evas_object_size_hint_align_set(pb, EVAS_HINT_FILL, 0.5);
evas_object_size_hint_weight_set(pb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show(pb);
label = elm_label_add(win);
elm_object_text_set(label, "ETA: N/A");
evas_object_size_hint_align_set(label, 0.5, 0.5);
evas_object_size_hint_weight_set(label, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_box_pack_end(bx, label);
evas_object_show(label);
evas_object_smart_callback_add(pb, "changed", _on_changed, label);
example_data.pb4 = pb;

The "changed" signal is emitted every time the progressbar value is updated through elm_progressbar_value_set(). This callback calculates and displays the ETA based on the progress and time that has passed.

/* Callback for "changed" signal */
static void
_on_changed(void *data,
Evas_Object *obj,
void *event_info)
{
static char buf[30];
static time_t tstart = 0;
static double eta = 0;
time_t tdiff;
double val;
Evas_Object *label = (Evas_Object *)data;
if (val == 0)
{
tstart = 0;
elm_object_text_set(label, "ETA: N/A");
return;
}
/* First invocation */
if (tstart == 0)
{
tstart = time(NULL);
}
/* Calculate ETA and update */
tdiff = time(NULL) - tstart;
eta = 0.3*eta + 0.7*(tdiff/val)*(1-val);
snprintf(buf, 30, "ETA: %.0fs", eta);
elm_object_text_set(label, buf);
}

The next three progress bars are just variants on the ones already shown, but now all being vertical. Another time we use one of than to give the window a minimum vertical size, with elm_progressbar_span_size_set(). To demonstrate this trick once more, the fifth one, which is also set to pulse, has a smaller hardcoded span size:

/* vertical pb, with pulse and custom (small) span size */
evas_object_size_hint_align_set(pb, EVAS_HINT_FILL, 0.5);
evas_object_size_hint_weight_set(pb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
elm_progressbar_pulse_set(pb, EINA_TRUE);
elm_object_text_set(pb, "Infinite bounce");
elm_box_pack_end(hbx, pb);
evas_object_show(pb);
example_data.pb6 = pb;

We end the widget demonstration by showing a progress bar with the special "wheel" progress bar style. One does not need to set it to pulse, with elm_progressbar_pulse_set(), explicitly, because its theme does not take it in account:

/* "wheel" style progress bar */
elm_object_style_set(pb, "wheel");
elm_object_text_set(pb, "Style: wheel");
elm_progressbar_pulse_set(pb, EINA_TRUE);
evas_object_size_hint_align_set(pb, EVAS_HINT_FILL, 0.5);
evas_object_size_hint_weight_set(pb, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_show(pb);
example_data.pb8 = pb;

The two buttons exercising the bars, the facto, follow:

bt = elm_button_add(win);
elm_object_text_set(bt, "Start");
evas_object_smart_callback_add(bt, "clicked", _progressbar_example_start,
NULL);
elm_box_pack_end(bt_bx, bt);
evas_object_show(bt);
bt = elm_button_add(win);
elm_object_text_set(bt, "Stop");
evas_object_smart_callback_add(bt, "clicked", _progressbar_example_stop,
NULL);
elm_box_pack_end(bt_bx, bt);
evas_object_show(bt);

The first of the callbacks will, for the progress bars set to pulse, start the pulsing animation at that time. For the others, a timer callback will take care of updating the values:

static Eina_Bool
_progressbar_example_value_set(void *data)
{
double progress;
progress = elm_progressbar_value_get(example_data.pb1);
if (progress < 1.0) progress += 0.0123;
else progress = 0.0;
/* just the non-pulsing ones need an update */
elm_progressbar_value_set(example_data.pb1, progress);
elm_progressbar_value_set(example_data.pb3, progress);
elm_progressbar_value_set(example_data.pb4, progress);
elm_progressbar_value_set(example_data.pb5, progress);
elm_progressbar_value_set(example_data.pb7, progress);
if (progress < 1.0) return ECORE_CALLBACK_RENEW;
example_data.run = 0;
return ECORE_CALLBACK_CANCEL;
}
static void
_progressbar_example_start(void *data,
Evas_Object *obj,
void *event_info)
{
elm_progressbar_pulse(example_data.pb2, EINA_TRUE);
elm_progressbar_pulse(example_data.pb6, EINA_TRUE);
elm_progressbar_pulse(example_data.pb8, EINA_TRUE);
if (!example_data.run)
{
example_data.timer = ecore_timer_add(
0.1, _progressbar_example_value_set, NULL);
example_data.run = EINA_TRUE;
}
}

Finally, the callback to stop the progress timer will stop the pulsing on the pulsing progress bars and, for the others, to delete the timer which was acting on their values:

/* end of show */
static void
_progressbar_example_stop(void *data,
Evas_Object *obj,
void *event_info)
{
elm_progressbar_pulse(example_data.pb2, EINA_FALSE);
elm_progressbar_pulse(example_data.pb6, EINA_FALSE);
elm_progressbar_pulse(example_data.pb8, EINA_FALSE);
if (example_data.run)
{
ecore_timer_del(example_data.timer);
example_data.run = EINA_FALSE;
}
}

This is how the example program's window looks like:

progressbar_example.png

See the full source code for this example.