Xfce Forum

Sub domains
 

You are not logged in.

#1 2021-04-16 14:39:47

Misko_2083
Member
Registered: 2015-10-13
Posts: 156
Website

ToZ bar

A little progress bar with ToZ.
Depends: gcc libgtk-3-dev (3.24+)

Save images in a folder:
toz.gif
Wy5TUKC.gif
toz.png
wJgnk9e.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? big_smile

Offline

Board footer

Powered by FluxBB