diff --git a/inc/widget_builder.h b/inc/widget_builder.h
new file mode 100644
index 0000000..60c0857
--- /dev/null
+++ b/inc/widget_builder.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2020 Scoopta
+ * This file is part of Wofi
+ * Wofi is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Wofi is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Wofi. If not, see .
+ */
+
+#ifndef WIDGET_BUILDER_H
+#define WIDGET_BUILDER_H
+
+#include
+
+#include
+
+struct widget_builder {
+ WofiPropertyBox* box;
+ struct widget* widget;
+ struct mode* mode;
+ size_t actions;
+};
+
+void wofi_free_widget_builder(struct widget_builder* builder);
+
+#endif
diff --git a/inc/widget_builder_api.h b/inc/widget_builder_api.h
new file mode 100644
index 0000000..d839c3e
--- /dev/null
+++ b/inc/widget_builder_api.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 Scoopta
+ * This file is part of Wofi
+ * Wofi is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Wofi is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Wofi. If not, see .
+ */
+
+#ifndef WIDGET_BUILDER_API_H
+#define WIDGET_BUILDER_API_H
+
+#include
+
+#include
+
+#include
+
+struct widget_builder* wofi_create_widget_builder(struct mode* mode, size_t actions);
+
+void wofi_widget_builder_set_search_text(struct widget_builder* builder, char* search_text);
+
+void wofi_widget_builder_set_action(struct widget_builder* builder, char* action);
+
+void wofi_widget_builder_insert_text(struct widget_builder* builder, char* text, char* css_name);
+
+void wofi_widget_builder_insert_image(struct widget_builder* builder, GdkPixbuf* pixbuf, char* css_name);
+
+struct widget_builder* wofi_widget_builder_get_idx(struct widget_builder* builder, size_t idx);
+
+struct widget* wofi_widget_builder_get_widget(struct widget_builder* builder);
+
+#endif
diff --git a/inc/wofi.h b/inc/wofi.h
index dc9247a..531891e 100644
--- a/inc/wofi.h
+++ b/inc/wofi.h
@@ -24,6 +24,21 @@
#include
+#include
+
+struct widget {
+ size_t action_count;
+ char* mode, **text, *search_text, **actions;
+ struct widget_builder* builder;
+};
+
+struct mode {
+ void (*mode_exec)(const gchar* cmd);
+ struct widget* (*mode_get_widget)(void);
+ char* name, *dso;
+ struct wl_list link;
+};
+
void wofi_init(struct map* config);
void wofi_load_css(bool nyan);
diff --git a/man/wofi-widget-builder.3 b/man/wofi-widget-builder.3
new file mode 100644
index 0000000..3b8bc41
--- /dev/null
+++ b/man/wofi-widget-builder.3
@@ -0,0 +1,79 @@
+.TH wofi\-widget\-builder 3
+.SH NAME
+wofi \- Widget builder API functions
+
+.SH DESCRIPTION
+The functions documented here are used for building custom widgets with more power and flexibility than previously allowed. They are defined in wofi_widget_builder_api.h
+
+.TP
+.B struct widget_builder* wofi_create_widget_builder(struct mode* mode, size_t actions)
+Creates multiple widget builders. The number of builders created is specified by actions and is returned as an array.
+
+.B struct mode* mode
+\- The \fBstruct mode*\fR given to your mode's \fBinit()\fR function.
+
+.B size_t actions
+\- The number of builders to create
+
+.TP
+.B void wofi_widget_builder_set_search_text(struct widget_builder* builder, char* search_text)
+Sets the search text for the widget specified by the builder
+
+.B struct widget_builder* builder
+\- The builder that contains the widget to set the search text for
+
+.B char* search_text
+\- The text to set as the search text
+
+.TP
+.B void wofi_widget_builder_set_action(struct widget_builder* builder, char* action)
+Sets the action for the widget specified by the builder
+
+.B struct widget_builder* builder
+\- The builder that contains the widget to set the action for
+
+.B char* action
+\- The text to set as the action
+
+.TP
+.B void wofi_widget_builder_insert_text(struct widget_builder* builder, char* text, char* css_name)
+Inserts text into the widget specified by the builder
+
+.B struct widget_builder* builder
+\- The builder that contains the widget to add the text to
+
+.B char* text
+\- The text to add to the widget
+
+.B char* css_name
+\- The name of the CSS node for this text. The name that will be assigned is #mode_name-css_name where mode_name is the name of the mode, i.e. drun etc.
+
+.TP
+.B void wofi_widget_builder_insert_image(struct widget_builder* builder, GdkPixbuf* pixbuf, char* css_name)
+Inserts an image into the widget specified by the builder
+
+.B struct widget_builder* builder
+\- The builder that contains the widget to add the image to
+
+.B GdkPixbuf* pixbuf
+\- The image to add to the widget
+
+.B char* css_name
+\- The name of the CSS node for this image. The name that will be assigned is #mode_name-css_name where mode_name is the name of the mode, i.e. drun etc.
+
+.TP
+.B struct widget_builder* wofi_widget_builder_get_idx(struct widget_builder* builder, size_t idx)
+Gets the widget_builder at the provided index in the array
+
+.B struct widget_builder* builder
+\- The array of builders to get the builder from
+
+.B size_t idx
+\- The index in the array to get
+
+.TP
+.B struct widget* wofi_widget_builder_get_widget(struct widget_builder* builder)
+Constructs a new widget from the specified builder, the widget can be returned by \fBstruct widget* get_widget(void)\fR
+
+.B struct widget_builder* builder
+\- The builder to construct a widget for
diff --git a/meson.build b/meson.build
index 13b2bc2..0f84ae8 100644
--- a/meson.build
+++ b/meson.build
@@ -24,6 +24,7 @@ sources = ['src/config.c',
'src/map.c',
'src/property_box.c',
'src/utils.c',
+ 'src/widget_builder.c',
'src/wofi.c',
'proto/wlr-layer-shell-unstable-v1-protocol.c',
'proto/xdg-output-unstable-v1-protocol.c',
diff --git a/src/widget_builder.c b/src/widget_builder.c
new file mode 100644
index 0000000..d7c572f
--- /dev/null
+++ b/src/widget_builder.c
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2020 Scoopta
+ * This file is part of Wofi
+ * Wofi is free software: you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Wofi is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with Wofi. If not, see .
+ */
+
+#include
+
+#include
+#include
+
+struct widget_builder* wofi_create_widget_builder(struct mode* mode, size_t actions) {
+ struct widget_builder* builder = calloc(actions, sizeof(struct widget_builder));
+
+ for(size_t count = 0; count < actions; ++count) {
+ builder[count].mode = mode;
+ builder[count].box = WOFI_PROPERTY_BOX(wofi_property_box_new(GTK_ORIENTATION_HORIZONTAL, 0));
+
+ if(count == 0) {
+ builder->actions = actions;
+ }
+ }
+ return builder;
+}
+
+void wofi_widget_builder_set_search_text(struct widget_builder* builder, char* search_text) {
+ wofi_property_box_add_property(builder->box, "filter", search_text);
+}
+
+void wofi_widget_builder_set_action(struct widget_builder* builder, char* action) {
+ wofi_property_box_add_property(builder->box, "action", action);
+}
+
+void wofi_widget_builder_insert_text(struct widget_builder* builder, char* text, char* css_name) {
+ GtkWidget* label = gtk_label_new(text);
+ gtk_container_add(GTK_CONTAINER(builder->box), label);
+ if(css_name != NULL) {
+ char* tmp = utils_concat(3, builder->mode->name, "-", css_name);
+ gtk_widget_set_name(label, tmp);
+ free(tmp);
+ }
+}
+
+void wofi_widget_builder_insert_image(struct widget_builder* builder, GdkPixbuf* pixbuf, char* css_name) {
+ GtkWidget* img = gtk_image_new_from_pixbuf(pixbuf);
+ gtk_container_add(GTK_CONTAINER(builder->box), img);
+ if(css_name != NULL) {
+ char* tmp = utils_concat(3, builder->mode->name, "-", css_name);
+ gtk_widget_set_name(img, tmp);
+ free(tmp);
+ }
+}
+
+struct widget_builder* wofi_widget_builder_get_idx(struct widget_builder* builder, size_t idx) {
+ return builder + idx;
+}
+
+struct widget* wofi_widget_builder_get_widget(struct widget_builder* builder) {
+ if(builder->actions == 0) {
+ fprintf(stderr, "%s: This is not the 0 index of the widget_builder array\n", builder->mode->name);
+ return NULL;
+ }
+
+ if(builder->widget == NULL) {
+ builder->widget = malloc(sizeof(struct widget));
+ builder->widget->builder = builder;
+ builder->widget->action_count = builder->actions;
+ }
+
+ for(size_t count = 0; count < builder->actions; ++count) {
+ }
+
+ return builder->widget;
+}
+
+void wofi_free_widget_builder(struct widget_builder* builder) {
+ if(builder->widget != NULL) {
+ free(builder->widget);
+ }
+ free(builder);
+}
diff --git a/src/wofi.c b/src/wofi.c
index cbe5577..562c3cd 100644
--- a/src/wofi.c
+++ b/src/wofi.c
@@ -30,11 +30,11 @@
#include
#include
#include
+#include
#include
#include
-#include
#include
#include
@@ -109,18 +109,6 @@ static struct wl_list outputs;
static struct zxdg_output_manager_v1* output_manager;
static struct zwlr_layer_surface_v1* wlr_surface;
-struct mode {
- void (*mode_exec)(const gchar* cmd);
- struct widget* (*mode_get_widget)(void);
- char* name, *dso;
- struct wl_list link;
-};
-
-struct widget {
- size_t action_count;
- char* mode, **text, *search_text, **actions;
-};
-
struct output_node {
char* name;
struct wl_output* output;
@@ -502,11 +490,17 @@ static gboolean _insert_widget(gpointer data) {
if(node == NULL) {
return FALSE;
}
+
GtkWidget* parent;
if(node->action_count > 1 && !no_actions) {
parent = gtk_expander_new("");
g_signal_connect(parent, "activate", G_CALLBACK(expand), NULL);
- GtkWidget* box = create_label(node->mode, node->text[0], node->search_text, node->actions[0]);
+ GtkWidget* box;
+ if(node->builder == NULL) {
+ box = create_label(node->mode, node->text[0], node->search_text, node->actions[0]);
+ } else {
+ box = GTK_WIDGET(node->builder->box);
+ }
gtk_expander_set_label_widget(GTK_EXPANDER(parent), box);
GtkWidget* exp_box = gtk_list_box_new();
@@ -514,7 +508,11 @@ static gboolean _insert_widget(gpointer data) {
g_signal_connect(exp_box, "row-activated", G_CALLBACK(activate_item), NULL);
gtk_container_add(GTK_CONTAINER(parent), exp_box);
for(size_t count = 1; count < node->action_count; ++count) {
- box = create_label(node->mode, node->text[count], node->search_text, node->actions[count]);
+ if(node->builder == NULL) {
+ box = create_label(node->mode, node->text[count], node->search_text, node->actions[count]);
+ } else {
+ box = GTK_WIDGET(node->builder[count].box);
+ }
GtkWidget* row = gtk_list_box_row_new();
gtk_widget_set_name(row, "entry");
@@ -523,8 +521,13 @@ static gboolean _insert_widget(gpointer data) {
gtk_container_add(GTK_CONTAINER(exp_box), row);
}
} else {
- parent = create_label(node->mode, node->text[0], node->search_text, node->actions[0]);
+ if(node->builder == NULL) {
+ parent = create_label(node->mode, node->text[0], node->search_text, node->actions[0]);
+ } else {
+ parent = GTK_WIDGET(node->builder->box);
+ }
}
+
gtk_widget_set_halign(parent, content_halign);
GtkWidget* child = gtk_flow_box_child_new();
gtk_widget_set_name(child, "entry");
@@ -546,17 +549,21 @@ static gboolean _insert_widget(gpointer data) {
gtk_widget_set_visible(box, FALSE);
}
- free(node->mode);
- for(size_t count = 0; count < node->action_count; ++count) {
- free(node->text[count]);
+ if(node->builder != NULL) {
+ wofi_free_widget_builder(node->builder);
+ } else {
+ free(node->mode);
+ for(size_t count = 0; count < node->action_count; ++count) {
+ free(node->text[count]);
+ }
+ free(node->text);
+ free(node->search_text);
+ for(size_t count = 0; count < node->action_count; ++count) {
+ free(node->actions[count]);
+ }
+ free(node->actions);
+ free(node);
}
- free(node->text);
- free(node->search_text);
- for(size_t count = 0; count < node->action_count; ++count) {
- free(node->actions[count]);
- }
- free(node->actions);
- free(node);
return TRUE;
}
@@ -774,7 +781,7 @@ struct wl_list* wofi_read_cache(struct mode* mode) {
}
struct widget* wofi_create_widget(struct mode* mode, char* text[], char* search_text, char* actions[], size_t action_count) {
- struct widget* widget = malloc(sizeof(struct widget));
+ struct widget* widget = calloc(1, sizeof(struct widget));
widget->mode = strdup(mode->name);
widget->text = malloc(action_count * sizeof(char*));
for(size_t count = 0; count < action_count; ++count) {