#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;
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) {
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);
}
if (r)
goto ERROR;
+ // Setup widgets
+ STAILQ_INIT(&p->widgets);
+
// Done
*progressbar = p;
return 0;
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.
}
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);
+}