You are not logged in.
Pages: 1
A little progress bar with ToZ.
Depends: gcc libgtk-3-dev (3.24+)
Save images in a folder:
toz.gif
toz.png
save toz-bar.c in the same dir
toz-bar.c
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <glib.h>
#define IMAGE "toz.png"
#define ANIMATION "toz.gif"
/* ToZ animated progressbar
gcc -Wall -Wextra -o toz-bar toz-bar.c `pkg-config --cflags --libs gtk+-3.0`
Code: Misko 2021
depends: gcc libgtk-3-dev (3.24)
*/
guint threadID = 0;
typedef struct {
GtkWidget *progress_bar;
GtkWidget *button1;
GdkPixbufAnimation *animation;
GtkWidget *progress_animation;
GtkWidget *progress_label;
GtkStyleProvider *progressbar_style_provider;
} app_widgets;
void destroy_handler (GtkApplication* app, gpointer data)
{
(void) app;
g_application_quit(G_APPLICATION (data));
}
void
stop_progress_cb (gpointer user_data)
{
app_widgets *widgets = (app_widgets *) user_data;
gdouble fraction;
fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR(widgets->progress_bar));
gtk_image_set_from_file(GTK_IMAGE(widgets->progress_animation),
IMAGE);
g_print("ToZ progress: %.0f %%\n", fraction*100);
}
static gboolean
fill (gpointer user_data)
{
app_widgets *widgets = (app_widgets *) user_data;
GtkAllocation *alloc = g_new(GtkAllocation, 1);
gdouble fraction;
/*Get the current progress*/
fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR(widgets->progress_bar));
if (fraction > 0.999) {
fraction = 0;
}
/*Increase the bar by 1% each time this function is called*/
if (fraction < 0.999)
fraction += 0.01;
gtk_widget_get_allocation (widgets->progress_bar, alloc);
gtk_widget_set_margin_start(widgets->progress_animation,
alloc->width*fraction);
/*Fill in the bar with the new fraction*/
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(widgets->progress_bar),
fraction);
gchar temp[256];
memset(&temp, 0x0, 256);
if (fraction > 0.999) {
snprintf(temp, 255, "Complete: %.0f %%", fraction*100);
gtk_button_set_label (GTK_BUTTON(widgets->button1),
"Repeat");
threadID = 0;
}
else {
snprintf(temp, 255, "Solving: %.0f %%", fraction*100);
}
gtk_label_set_text (GTK_LABEL(widgets->progress_label), temp);
g_free(alloc);
/*Ensures that the fraction stays below 1.0*/
if (fraction < 0.999)
return TRUE;
return FALSE;
}
void
button1_clicked_cb (GtkButton *button,
app_widgets *widgets)
{
if (threadID == 0)
{
threadID = g_timeout_add_full (0, 100, fill,
widgets, stop_progress_cb);
gtk_button_set_label (button,
"Pause");
gtk_image_set_from_animation(GTK_IMAGE(widgets->progress_animation),
widgets->animation);
}
else
{
GSource *source = g_main_context_find_source_by_id(NULL,
threadID);
if (source)
{
g_source_destroy (source);
}
threadID = 0;
gtk_button_set_label (button,
"Continue");
}
}
static void
progress_bar_size_allocate (GtkWidget *progress_bar,
GdkRectangle *allocation,
gpointer user_data)
{
(void) progress_bar;
app_widgets *widgets = (app_widgets *) user_data;
gdouble fraction;
/*Get the current progress*/
fraction = gtk_progress_bar_get_fraction
(GTK_PROGRESS_BAR(widgets->progress_bar));
if (fraction == 0)
{
fraction = 0.01;
}
/*Set the margin of animation when the window width changes*/
gtk_widget_set_margin_start(widgets->progress_animation,
allocation->width*fraction);
if (fraction > 0.999)
gtk_widget_set_margin_start(widgets->progress_animation, 1);
}
static void
progress_animation_size_allocate (GtkWidget *animation,
GdkRectangle *allocation,
gpointer user_data)
{
(void) animation;
app_widgets *widgets = (app_widgets *) user_data;
GtkAllocation *progress_bar_allocation = g_new(GtkAllocation, 1);
char *css_text;
gtk_widget_get_allocation (widgets->progress_bar,
progress_bar_allocation);
progress_bar_allocation->height = allocation->height;
css_text = g_strdup_printf ("progressbar trough,\n"
"progressbar progress\n"
"{\n"
" min-height: %dpx;\n"
"}\n",
allocation->height);
gtk_css_provider_load_from_data (GTK_CSS_PROVIDER
(widgets->progressbar_style_provider),
css_text, -1, NULL);
g_free(progress_bar_allocation);
g_free (css_text);
}
static void
activate (GtkApplication *app,
app_widgets *widgets,
gpointer user_data)
{
(void) user_data;
GtkSizeGroup *size_group;
GtkWidget *window;
GtkWidget *grid;
GtkWidget *button2;
GtkWidget *progress_overlay;
GError *error = NULL;
GtkWidget *box;
gdouble fraction = 0.0;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window),
"ToZ's Progress Bar");
gtk_window_set_default_size (GTK_WINDOW (window),
420, 60);
/*Create a grid container to store the widgets*/
grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE);
gtk_grid_set_row_homogeneous (GTK_GRID (grid), FALSE);
widgets->progress_bar = gtk_progress_bar_new();
gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR(widgets->progress_bar),
FALSE);
gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR(widgets->progress_bar),
FALSE);
/* Fill in the given fraction of the bar.
It has to be between 0.0-1.0 inclusive */
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (widgets->progress_bar),
fraction);
widgets->progress_label = gtk_label_new ("ToZ is ready");
widgets->button1 = gtk_button_new_with_label ("Begin");
button2 = gtk_button_new_with_label ("Cancel");
progress_overlay = gtk_overlay_new ();
gtk_widget_set_hexpand (progress_overlay, TRUE);
gtk_widget_set_vexpand (progress_overlay, FALSE);
gtk_container_add (GTK_CONTAINER (progress_overlay),
widgets->progress_bar);
widgets->animation = gdk_pixbuf_animation_new_from_file(ANIMATION, &error);
if (error) {
g_warning("No image found\n*ERROR %s\n", error->message);
destroy_handler(NULL, app);
}
/* gtk_window_set_icon (GTK_WINDOW(window),
gdk_pixbuf_new_from_file(IMAGE, NULL)); */
widgets->progress_animation = gtk_image_new_from_file (IMAGE);
gtk_widget_set_vexpand(widgets->progress_bar, FALSE);
gtk_widget_set_name (widgets->progress_animation,
"progress-animation");
/*create a box container for the image*/
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start (GTK_BOX(box), widgets->progress_animation,
FALSE, FALSE, 2);
gtk_widget_set_halign (widgets->progress_animation,
GTK_ALIGN_START);
gtk_overlay_add_overlay (GTK_OVERLAY (progress_overlay),
box);
gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (progress_overlay),
box, TRUE);
size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
gtk_size_group_add_widget (size_group, widgets->progress_bar);
gtk_size_group_add_widget (size_group, box);
widgets->progressbar_style_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
gtk_style_context_add_provider (gtk_widget_get_style_context (widgets->progress_bar),
widgets->progressbar_style_provider,
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
gtk_grid_attach (GTK_GRID (grid), progress_overlay, 0, 0, 4, 1);
gtk_grid_attach (GTK_GRID (grid), widgets->progress_label, 0, 1, 2, 1);
gtk_grid_attach (GTK_GRID (grid), widgets->button1, 2, 1, 1, 1);
gtk_grid_attach_next_to (GTK_GRID (grid), button2, widgets->button1,
GTK_POS_RIGHT, 1, 1);
gtk_container_add (GTK_CONTAINER (window), grid);
gtk_container_set_border_width(GTK_CONTAINER(grid),12);
gtk_container_set_border_width(GTK_CONTAINER(window),5);
g_signal_connect (widgets->progress_animation, "size-allocate",
G_CALLBACK (progress_animation_size_allocate),
widgets);
g_signal_connect (widgets->progress_bar, "size-allocate",
G_CALLBACK (progress_bar_size_allocate),
widgets);
g_signal_connect (widgets->button1, "clicked",
G_CALLBACK (button1_clicked_cb), widgets);
g_signal_connect (button2, "clicked",
G_CALLBACK (destroy_handler), app);
g_signal_connect (G_OBJECT(window), "destroy",
G_CALLBACK (destroy_handler), app);
gtk_widget_show_all (window);
}
int
main (int argc, char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.toz_bar", G_APPLICATION_FLAGS_NONE);
app_widgets *widgets = g_slice_new(app_widgets);
g_signal_connect (app, "activate", G_CALLBACK (activate), widgets);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
g_slice_free(app_widgets, widgets);
return status;
}
Compile with:
gcc -Wall -Wextra -o toz-bar toz-bar.c `pkg-config --cflags --libs gtk+-3.0`
run:
./toz-bar
----------
Bonus: the same method with the gtk spinner
spin-bar.c
#include <stdio.h>
#include <string.h>
#include <gtk/gtk.h>
#include <gdk/gdk.h>
#include <glib.h>
/* Spinner in a progressbar
gcc -Wall -Wextra -o spin-bar spin-bar.c `pkg-config --cflags --libs gtk+-3.0`
Code: Misko 2021
depends: gcc libgtk-3-dev (3.24)
*/
guint threadID = 0;
typedef struct {
GtkWidget *progress_bar;
GtkWidget *button1;
GtkWidget *progress_spinner;
GtkWidget *progress_label;
GtkStyleProvider *progressbar_style_provider;
} app_widgets;
void destroy_handler (GtkApplication* app, gpointer data)
{
(void) app;
g_application_quit(G_APPLICATION (data));
}
void
stop_progress_cb (gpointer user_data)
{
app_widgets *widgets = (app_widgets *) user_data;
gdouble fraction;
fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR(widgets->progress_bar));
gtk_spinner_stop(GTK_SPINNER(widgets->progress_spinner));
g_print("progress: %.0f %%\n", fraction*100);
}
static gboolean
fill (gpointer user_data)
{
app_widgets *widgets = (app_widgets *) user_data;
GtkAllocation *alloc = g_new(GtkAllocation, 1);
gdouble fraction;
/*Get the current progress*/
fraction = gtk_progress_bar_get_fraction (GTK_PROGRESS_BAR(widgets->progress_bar));
if (fraction > 0.999) {
fraction = 0;
}
/*Increase the bar by 1% each time this function is called*/
if (fraction < 0.999)
fraction += 0.01;
gtk_widget_get_allocation (widgets->progress_bar, alloc);
gtk_widget_set_margin_start(widgets->progress_spinner,
alloc->width*fraction);
/*Fill in the bar with the new fraction*/
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR(widgets->progress_bar),
fraction);
gchar temp[256];
memset(&temp, 0x0, 256);
if (fraction > 0.999) {
snprintf(temp, 255, "Complete: %.0f %%", fraction*100);
gtk_button_set_label (GTK_BUTTON(widgets->button1),
"Repeat");
threadID = 0;
}
else {
snprintf(temp, 255, "Rolling: %.0f %%", fraction*100);
}
gtk_label_set_text (GTK_LABEL(widgets->progress_label), temp);
g_free(alloc);
/*Ensures that the fraction stays below 1.0*/
if (fraction < 0.999)
return TRUE;
return FALSE;
}
void
button1_clicked_cb (GtkButton *button,
app_widgets *widgets)
{
if (threadID == 0)
{
threadID = g_timeout_add_full (0, 100, fill,
widgets, stop_progress_cb);
gtk_button_set_label (button,
"Pause");
gtk_spinner_start(GTK_SPINNER(widgets->progress_spinner));
}
else
{
GSource *source = g_main_context_find_source_by_id(NULL,
threadID);
if (source)
{
g_source_destroy (source);
}
threadID = 0;
gtk_button_set_label (button,
"Continue");
}
}
static void
progress_bar_size_allocate (GtkWidget *progress_bar,
GdkRectangle *allocation,
gpointer user_data)
{
(void) progress_bar;
app_widgets *widgets = (app_widgets *) user_data;
gdouble fraction;
/*Get the current progress*/
fraction = gtk_progress_bar_get_fraction
(GTK_PROGRESS_BAR(widgets->progress_bar));
if (fraction == 0)
{
fraction = 0.01;
}
/*Set the margin of animation when the window width changes*/
gtk_widget_set_margin_start(widgets->progress_spinner,
allocation->width*fraction);
if (fraction > 0.999)
gtk_widget_set_margin_start(widgets->progress_spinner, 1);
}
static void
progress_spinner_size_allocate (GtkWidget *animation,
GdkRectangle *allocation,
gpointer user_data)
{
(void) animation;
app_widgets *widgets = (app_widgets *) user_data;
GtkAllocation *progress_bar_allocation = g_new(GtkAllocation, 1);
char *css_text;
gtk_widget_get_allocation (widgets->progress_bar,
progress_bar_allocation);
progress_bar_allocation->height = allocation->height;
css_text = g_strdup_printf ("progressbar trough,\n"
"progressbar progress\n"
"{\n"
" min-height: %dpx;\n"
"}\n",
allocation->height);
gtk_css_provider_load_from_data (GTK_CSS_PROVIDER
(widgets->progressbar_style_provider),
css_text, -1, NULL);
g_free(progress_bar_allocation);
g_free (css_text);
}
static void
activate (GtkApplication *app,
app_widgets *widgets,
gpointer user_data)
{
(void) user_data;
GtkSizeGroup *size_group;
GtkWidget *window;
GtkWidget *grid;
GtkWidget *button2;
GtkWidget *progress_overlay;
GtkWidget *box;
gdouble fraction = 0.0;
window = gtk_application_window_new (app);
gtk_window_set_title (GTK_WINDOW (window),
"Progress Bar Spin");
gtk_window_set_default_size (GTK_WINDOW (window),
420, 60);
/*Create a grid container to store the widgets*/
grid = gtk_grid_new ();
gtk_grid_set_row_spacing (GTK_GRID (grid), 10);
gtk_grid_set_column_spacing (GTK_GRID (grid), 10);
gtk_grid_set_column_homogeneous (GTK_GRID (grid), TRUE);
gtk_grid_set_row_homogeneous (GTK_GRID (grid), FALSE);
widgets->progress_bar = gtk_progress_bar_new();
gtk_progress_bar_set_inverted (GTK_PROGRESS_BAR(widgets->progress_bar),
FALSE);
gtk_progress_bar_set_show_text (GTK_PROGRESS_BAR(widgets->progress_bar),
FALSE);
/* Fill in the given fraction of the bar.
It has to be between 0.0-1.0 inclusive */
gtk_progress_bar_set_fraction (GTK_PROGRESS_BAR (widgets->progress_bar),
fraction);
widgets->progress_label = gtk_label_new ("Ready");
widgets->button1 = gtk_button_new_with_label ("Begin");
button2 = gtk_button_new_with_label ("Cancel");
progress_overlay = gtk_overlay_new ();
gtk_widget_set_hexpand (progress_overlay, TRUE);
gtk_widget_set_vexpand (progress_overlay, FALSE);
gtk_container_add (GTK_CONTAINER (progress_overlay),
widgets->progress_bar);
widgets->progress_spinner = gtk_spinner_new();
gtk_widget_set_vexpand(widgets->progress_bar, FALSE);
gtk_widget_set_name (widgets->progress_spinner,
"progress-spinner");
box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
gtk_box_pack_start (GTK_BOX(box), widgets->progress_spinner,
FALSE, FALSE, 2);
gtk_widget_set_halign (widgets->progress_spinner,
GTK_ALIGN_START);
gtk_overlay_add_overlay (GTK_OVERLAY (progress_overlay),
box);
gtk_overlay_set_overlay_pass_through (GTK_OVERLAY (progress_overlay),
box, TRUE);
size_group = gtk_size_group_new (GTK_SIZE_GROUP_VERTICAL);
gtk_size_group_add_widget (size_group, widgets->progress_bar);
gtk_size_group_add_widget (size_group, box);
widgets->progressbar_style_provider = GTK_STYLE_PROVIDER (gtk_css_provider_new ());
gtk_style_context_add_provider (gtk_widget_get_style_context (widgets->progress_bar),
widgets->progressbar_style_provider,
GTK_STYLE_PROVIDER_PRIORITY_APPLICATION);
gtk_grid_attach (GTK_GRID (grid), progress_overlay, 0, 0, 4, 1);
gtk_grid_attach (GTK_GRID (grid), widgets->progress_label, 0, 1, 2, 1);
gtk_grid_attach (GTK_GRID (grid), widgets->button1, 2, 1, 1, 1);
gtk_grid_attach_next_to (GTK_GRID (grid), button2, widgets->button1,
GTK_POS_RIGHT, 1, 1);
gtk_container_add (GTK_CONTAINER (window), grid);
gtk_container_set_border_width(GTK_CONTAINER(grid),12);
gtk_container_set_border_width(GTK_CONTAINER(window),5);
g_signal_connect (widgets->progress_spinner, "size-allocate",
G_CALLBACK (progress_spinner_size_allocate),
widgets);
g_signal_connect (widgets->progress_bar, "size-allocate",
G_CALLBACK (progress_bar_size_allocate),
widgets);
g_signal_connect (widgets->button1, "clicked",
G_CALLBACK (button1_clicked_cb), widgets);
g_signal_connect (button2, "clicked",
G_CALLBACK (destroy_handler), app);
g_signal_connect (G_OBJECT(window), "destroy",
G_CALLBACK (destroy_handler), app);
gtk_widget_show_all (window);
}
int
main (int argc, char **argv)
{
GtkApplication *app;
int status;
app = gtk_application_new ("org.gtk.spin_bar", G_APPLICATION_FLAGS_NONE);
app_widgets *widgets = g_slice_new(app_widgets);
g_signal_connect (app, "activate", G_CALLBACK (activate), widgets);
status = g_application_run (G_APPLICATION (app), argc, argv);
g_object_unref (app);
g_slice_free(app_widgets, widgets);
return status;
}
Compile & run
gcc -Wall -Wextra -o spin-bar spin-bar.c `pkg-config --cflags --libs gtk+-3.0` && ./spin-bar
----
So which one is better?
Do you want to exit the Circus?
https://www.youtube.com/watch?v=ZJwQicZHp_c
Offline
Pages: 1
[ Generated in 0.008 seconds, 7 queries executed - Memory usage: 612.5 KiB (Peak: 657.16 KiB) ]