]> git.ipfire.org Git - pakfire.git/commitdiff
progressbar: Add a simple string widget
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 31 Mar 2021 21:37:34 +0000 (21:37 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 31 Mar 2021 21:37:34 +0000 (21:37 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/libpakfire/include/pakfire/progressbar.h
src/libpakfire/progressbar.c
tests/libpakfire/progressbar.c

index b55f0f259fa4acd2f234b45ba8a421f205ebfd0d..41d71dd6349289ada3226a42b4eae51c5abded7c 100644 (file)
@@ -40,6 +40,8 @@ int pakfire_progressbar_update(struct pakfire_progressbar* p, unsigned long valu
 int pakfire_progressbar_increment(struct pakfire_progressbar* p);
 int pakfire_progressbar_finish(struct pakfire_progressbar* p);
 
+int pakfire_progressbar_add_string(struct pakfire_progressbar* p, const char* string);
+
 #endif
 
 #endif /* PAKFIRE_PROGRESSBAR_H */
index c6f321b008059724071a864c663f9ccd80af63d9..6df0d47e78d6cfff8caf5e1f73eef6ecdf1ddc0f 100644 (file)
@@ -23,6 +23,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <sys/ioctl.h>
+#include <sys/queue.h>
 #include <time.h>
 
 #include <pakfire/logging.h>
 
 #define REDRAW_TIMEOUT 100
 
+struct pakfire_progressbar_widget {
+       STAILQ_ENTRY(pakfire_progressbar_widget) nodes;
+
+       int expandable;
+       void* data;
+
+       const char* (*print)(struct pakfire_progressbar* p, int width, void* data);
+       void (*free)(void* data);
+
+       char buffer[1024];
+};
+
 struct pakfire_progressbar {
        Pakfire pakfire;
        int nrefs;
@@ -58,6 +71,10 @@ struct pakfire_progressbar {
 
        struct timespec time_start;
        struct timespec time_redraw;
+
+       // Widgets
+       STAILQ_HEAD(widgets, pakfire_progressbar_widget) widgets;
+       unsigned int num_widgets;
 };
 
 static int pakfire_progressbar_update_terminal_size(struct pakfire_progressbar* p) {
@@ -75,7 +92,25 @@ static int pakfire_progressbar_update_terminal_size(struct pakfire_progressbar*
        return 0;
 }
 
+static void pakfire_progressbar_widget_free(struct pakfire_progressbar_widget* widget) {
+       // Call own free method
+       if (widget->free && widget->data)
+               widget->free(widget->data);
+
+       free(widget);
+}
+
 static void pakfire_progressbar_free(struct pakfire_progressbar* p) {
+       struct pakfire_progressbar_widget* widget;
+
+       // Free widgets
+       while (!STAILQ_EMPTY(&p->widgets)) {
+               widget = STAILQ_FIRST(&p->widgets);
+               STAILQ_REMOVE_HEAD(&p->widgets, nodes);
+
+               pakfire_progressbar_widget_free(widget);
+       }
+
        pakfire_unref(p->pakfire);
        free(p);
 }
@@ -100,6 +135,9 @@ int pakfire_progressbar_create(struct pakfire_progressbar** progressbar,
        if (r)
                goto ERROR;
 
+       // Setup widgets
+       STAILQ_INIT(&p->widgets);
+
        // Done
        *progressbar = p;
        return 0;
@@ -185,6 +223,27 @@ int pakfire_progressbar_finish(struct pakfire_progressbar* p) {
        return 0;
 }
 
+static int pakfire_progressbar_add_widget(struct pakfire_progressbar* p,
+               const char* (*print)(struct pakfire_progressbar* p, int width, void* data),
+               void (*free)(void* data), int expandable, void* data) {
+       // Allocate the widget
+       struct pakfire_progressbar_widget* widget = calloc(1, sizeof(*widget));
+       if (!widget)
+               return ENOMEM;
+
+       // Assign everything
+       widget->print = print;
+       widget->free = free;
+       widget->expandable = expandable;
+       widget->data = data;
+
+       // Append it to the list
+       STAILQ_INSERT_TAIL(&p->widgets, widget, nodes);
+       p->num_widgets++;
+
+       return 0;
+}
+
 /*
        This functions determines whether this progressbar needs to be redrawn
        and sets any markers to determine the next redraw.
@@ -223,11 +282,70 @@ REDRAW:
 }
 
 static int pakfire_progressbar_redraw(struct pakfire_progressbar* p) {
+       struct pakfire_progressbar_widget* widget;
+
        // Return when we should not be redrawing
        if (!pakfire_progressbar_needs_redraw(p))
                return 0;
 
-       fprintf(p->terminal.f, "\r%lu/%lu", p->value, p->value_max);
+       unsigned int cols_left = p->terminal.cols - p->num_widgets - 2;
+       int i = 0;
+
+       // Create an array with the result of all print functions
+       const char* elements[p->num_widgets];
+
+       // Process all non-expandable widgets in the first pass
+       STAILQ_FOREACH(widget, &p->widgets, nodes) {
+               const char* element = NULL;
+
+               if (!widget->expandable) {
+                       element = widget->print(p, 0, widget->data);
+                       cols_left -= strlen(element);
+               }
+
+               elements[i++] = element;
+       }
+
+       // How many expandable widgets are left?
+       int num_expandables = p->num_widgets - i;
+
+       // How much space do we allocate to each of them?
+       int width = cols_left - num_expandables;
+
+       i = 0;
+
+       // Process all expandable widgets
+       STAILQ_FOREACH(widget, &p->widgets, nodes) {
+               const char* element = elements[i];
+
+               if (!widget->expandable) {
+                       element = widget->print(p, width, widget->data);
+               }
+
+               elements[i++] = element;
+       }
+
+       // Reset the line
+       fputs("\r ", p->terminal.f);
+
+       // Print all elements
+       for (unsigned int i = 0; i < p->num_widgets; i++)
+               fputs(elements[i], p->terminal.f);
 
        return 0;
 }
+
+// String widget
+
+const char* pakfire_progressbar_string_print(
+               struct pakfire_progressbar* p, int width, void* data) {
+       return (const char*)data;
+}
+
+int pakfire_progressbar_add_string(struct pakfire_progressbar* p, const char* string) {
+       char* s = strdup(string);
+       if (!s)
+               return ENOMEM;
+
+       return pakfire_progressbar_add_widget(p, pakfire_progressbar_string_print, free, 0, s);
+}
index b82d954d0a8c4294b9730b1e7ebda5c7b606a88e..28af34ede3a5cbd8e4949d5a8927bd89977c0864 100644 (file)
@@ -33,6 +33,9 @@ static int test_run(const struct test* t) {
 
        ASSERT(pakfire_progressbar_finish(p) == EINVAL);
 
+       // Add a string
+       ASSERT_SUCCESS(pakfire_progressbar_add_string(p, "STRING"));
+
        ASSERT_SUCCESS(pakfire_progressbar_start(p, 1000));
 
        for (unsigned int i = 0; i < 1000; i++) {