From: Michael Tremer Date: Wed, 31 Mar 2021 21:37:34 +0000 (+0000) Subject: progressbar: Add a simple string widget X-Git-Tag: 0.9.28~1285^2~447 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8ff80562b6b127dc78e0285ad27c327f58ec368b;p=pakfire.git progressbar: Add a simple string widget Signed-off-by: Michael Tremer --- diff --git a/src/libpakfire/include/pakfire/progressbar.h b/src/libpakfire/include/pakfire/progressbar.h index b55f0f259..41d71dd63 100644 --- a/src/libpakfire/include/pakfire/progressbar.h +++ b/src/libpakfire/include/pakfire/progressbar.h @@ -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 */ diff --git a/src/libpakfire/progressbar.c b/src/libpakfire/progressbar.c index c6f321b00..6df0d47e7 100644 --- a/src/libpakfire/progressbar.c +++ b/src/libpakfire/progressbar.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -33,6 +34,18 @@ #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); +} diff --git a/tests/libpakfire/progressbar.c b/tests/libpakfire/progressbar.c index b82d954d0..28af34ede 100644 --- a/tests/libpakfire/progressbar.c +++ b/tests/libpakfire/progressbar.c @@ -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++) {