#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include "../common/context.h"
#include "../common/object.h"
#include "container.h"
#include "tree.h"
void* ui_strmodel_getvalue(
void *elm,
int column) {
return column ==
0 ? elm :
NULL;
}
UIWIDGET ui_listview_str(UiObject *obj, UiList *list, ui_callback f,
void *udata) {
return ui_listview(obj, list, ui_strmodel_getvalue, f, udata);
}
UIWIDGET ui_listview_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f,
void *udata) {
GtkWidget *view = gtk_tree_view_new();
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
GtkTreeViewColumn *column = gtk_tree_view_column_new_with_attributes(
NULL, renderer,
"text",
0,
NULL);
gtk_tree_view_append_column(
GTK_TREE_VIEW(view), column);
gtk_tree_view_set_headers_visible(
GTK_TREE_VIEW(view),
FALSE);
#ifdef UI_GTK3
#if GTK_MINOR_VERSION >=
8
gtk_tree_view_set_activate_on_single_click(
GTK_TREE_VIEW(view),
TRUE);
#else
#endif
#else
#endif
UiModel *model = ui_model(obj->ctx,
UI_STRING,
"", -
1);
model->getvalue = getvalue;
UiList *list = var->value;
UiListModel *listmodel = ui_list_model_new(obj, var, model);
gtk_tree_view_set_model(
GTK_TREE_VIEW(view),
GTK_TREE_MODEL(listmodel));
UiListView *listview = malloc(
sizeof(UiListView));
listview->obj = obj;
listview->widget = view;
listview->var = var;
listview->model = model;
g_signal_connect(
view,
"destroy",
G_CALLBACK(ui_listview_destroy),
listview);
list->update = ui_listview_update;
list->obj = listview;
if(f) {
UiTreeEventData *event = ui_malloc(obj->ctx,
sizeof(UiTreeEventData));
event->obj = obj;
event->userdata = udata;
event->activate = f;
event->selection =
NULL;
g_signal_connect(
view,
"row-activated",
G_CALLBACK(ui_listview_activate_event),
event);
}
GtkWidget *scroll_area = gtk_scrolled_window_new(
NULL,
NULL);
gtk_scrolled_window_set_policy(
GTK_SCROLLED_WINDOW(scroll_area),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add(
GTK_CONTAINER(scroll_area), view);
UiContainer *ct = uic_get_current_container(obj);
ct->add(ct, scroll_area,
TRUE);
ct->current = view;
return scroll_area;
}
UIWIDGET ui_listview(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f,
void *udata) {
UiVar *var = malloc(
sizeof(UiVar));
var->value = list;
var->type =
UI_VAR_SPECIAL;
return ui_listview_var(obj, var, getvalue, f, udata);
}
UIWIDGET ui_listview_nv(UiObject *obj,
char *varname, ui_getvaluefunc getvalue, ui_callback f,
void *udata) {
UiVar *var = uic_create_var(obj->ctx, varname,
UI_VAR_LIST);
if(var) {
return ui_listview_var(obj, var, getvalue, f, udata);
}
else {
}
return NULL;
}
static void drag_begin(GtkWidget *widget, GdkDragContext *context, gpointer udata) {
printf(
"drag begin\n");
}
static void drag_end(
GtkWidget *widget,
GdkDragContext *context,
guint time,
gpointer udata)
{
printf(
"drag end\n");
}
static GtkTargetEntry targetentries[] =
{
{
"STRING",
0,
0 },
{
"text/plain",
0,
1 },
{
"text/uri-list",
0,
2 },
};
UIWIDGET ui_table_var(UiObject *obj, UiVar *var, UiModel *model, UiListCallbacks cb) {
GtkWidget *view = gtk_tree_view_new();
int addi =
0;
for(
int i=
0;i<model->columns;i++) {
GtkTreeViewColumn *column =
NULL;
if(model->types[i] ==
UI_ICON_TEXT) {
column = gtk_tree_view_column_new();
gtk_tree_view_column_set_title(column, model->titles[i]);
GtkCellRenderer *iconrenderer = gtk_cell_renderer_pixbuf_new();
GtkCellRenderer *textrenderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_end(column, textrenderer,
TRUE);
gtk_tree_view_column_pack_start(column, iconrenderer,
FALSE);
gtk_tree_view_column_add_attribute(column, iconrenderer,
"pixbuf", i);
gtk_tree_view_column_add_attribute(column, textrenderer,
"text", i+
1);
addi++;
}
else {
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
column = gtk_tree_view_column_new_with_attributes(
model->titles[i],
renderer,
"text",
i + addi,
NULL);
}
gtk_tree_view_column_set_resizable(column,
TRUE);
gtk_tree_view_append_column(
GTK_TREE_VIEW(view), column);
}
#ifdef UI_GTK3
#else
#endif
UiList *list = var->value;
UiListModel *listmodel = ui_list_model_new(obj, var, model);
gtk_tree_view_set_model(
GTK_TREE_VIEW(view),
GTK_TREE_MODEL(listmodel));
UiListView *tableview = malloc(
sizeof(UiListView));
tableview->obj = obj;
tableview->widget = view;
tableview->var = var;
tableview->model = model;
g_signal_connect(
view,
"destroy",
G_CALLBACK(ui_listview_destroy),
tableview);
list->update = ui_listview_update;
list->obj = tableview;
UiTreeEventData *event = ui_malloc(obj->ctx,
sizeof(UiTreeEventData));
event->obj = obj;
event->activate = cb.activate;
event->selection = cb.selection;
event->userdata = cb.userdata;
if(cb.activate) {
g_signal_connect(
view,
"row-activated",
G_CALLBACK(ui_listview_activate_event),
event);
}
if(cb.selection) {
GtkTreeSelection *selection = gtk_tree_view_get_selection(
GTK_TREE_VIEW(view));
g_signal_connect(
selection,
"changed",
G_CALLBACK(ui_listview_selection_event),
event);
}
GtkTreeSelection *selection = gtk_tree_view_get_selection (
GTK_TREE_VIEW(view));
gtk_tree_selection_set_mode(selection,
GTK_SELECTION_MULTIPLE);
GtkWidget *scroll_area = gtk_scrolled_window_new(
NULL,
NULL);
gtk_scrolled_window_set_policy(
GTK_SCROLLED_WINDOW(scroll_area),
GTK_POLICY_AUTOMATIC,
GTK_POLICY_AUTOMATIC);
gtk_container_add(
GTK_CONTAINER(scroll_area), view);
UiContainer *ct = uic_get_current_container(obj);
ct->add(ct, scroll_area,
TRUE);
ct->current = view;
return scroll_area;
}
UIWIDGET ui_table(UiObject *obj, UiList *list, UiModel *model, UiListCallbacks cb) {
UiVar *var = malloc(
sizeof(UiVar));
var->value = list;
var->type =
UI_VAR_SPECIAL;
return ui_table_var(obj, var, model, cb);
}
UIWIDGET ui_table_nv(UiObject *obj,
char *varname, UiModel *model, UiListCallbacks cb) {
UiVar *var = uic_create_var(obj->ctx, varname,
UI_VAR_LIST);
if(var) {
return ui_table_var(obj, var, model, cb);
}
else {
}
return NULL;
}
GtkWidget* ui_get_tree_widget(
UIWIDGET widget) {
GList *c = gtk_container_get_children(
GTK_CONTAINER(widget));
if(c) {
return c->data;
}
return NULL;
}
static char** targets2array(
char *target0, va_list ap,
int *nelm) {
int al =
16;
char **targets = calloc(
16,
sizeof(
char*));
targets[
0] = target0;
int i =
1;
char *target;
while((target = va_arg(ap,
char*)) !=
NULL) {
if(i >= al) {
al *=
2;
targets = realloc(targets, al*
sizeof(
char*));
}
targets[i] = target;
i++;
}
*nelm = i;
return targets;
}
static GtkTargetEntry* targetstr2gtktargets(
char **str,
int nelm) {
GtkTargetEntry *targets = calloc(nelm,
sizeof(GtkTargetEntry));
for(
int i=
0;i<nelm;i++) {
targets[i].target = str[i];
}
return targets;
}
void ui_table_dragsource(
UIWIDGET tablewidget,
int actions,
char *target0, ...) {
va_list ap;
va_start(ap, target0);
int nelm;
char **targets = targets2array(target0, ap, &nelm);
va_end(ap);
ui_table_dragsource_a(tablewidget, actions, targets, nelm);
free(targets);
}
void ui_table_dragsource_a(
UIWIDGET tablewidget,
int actions,
char **targets,
int nelm) {
GtkTargetEntry* t = targetstr2gtktargets(targets, nelm);
gtk_tree_view_enable_model_drag_source(
GTK_TREE_VIEW(ui_get_tree_widget(tablewidget)),
GDK_BUTTON1_MASK,
t,
nelm,
GDK_ACTION_COPY|
GDK_ACTION_MOVE|
GDK_ACTION_LINK);
free(t);
}
void ui_table_dragdest(
UIWIDGET tablewidget,
int actions,
char *target0, ...) {
va_list ap;
va_start(ap, target0);
int nelm;
char **targets = targets2array(target0, ap, &nelm);
va_end(ap);
ui_table_dragdest_a(tablewidget, actions, targets, nelm);
free(targets);
}
void ui_table_dragdest_a(
UIWIDGET tablewidget,
int actions,
char **targets,
int nelm) {
GtkTargetEntry* t = targetstr2gtktargets(targets, nelm);
gtk_tree_view_enable_model_drag_dest(
GTK_TREE_VIEW(ui_get_tree_widget(tablewidget)),
t,
nelm,
GDK_ACTION_COPY|
GDK_ACTION_MOVE|
GDK_ACTION_LINK);
free(t);
}
void ui_listview_update(UiList *list,
int i) {
UiListView *view = list->obj;
UiListModel *model = ui_list_model_new(view->obj, view->var, view->model);
gtk_tree_view_set_model(
GTK_TREE_VIEW(view->widget),
GTK_TREE_MODEL(model));
g_object_unref(
G_OBJECT(model));
}
void ui_listview_destroy(GtkWidget *w, UiListView *v) {
gtk_tree_view_set_model(
GTK_TREE_VIEW(w),
NULL);
ui_destroy_boundvar(v->obj->ctx, v->var);
free(v);
}
void ui_combobox_destroy(GtkWidget *w, UiListView *v) {
gtk_combo_box_set_model(
GTK_COMBO_BOX(w),
NULL);
ui_destroy_boundvar(v->obj->ctx, v->var);
free(v);
}
void ui_listview_activate_event(
GtkTreeView *treeview,
GtkTreePath *path,
GtkTreeViewColumn *column,
UiTreeEventData *event)
{
UiListSelection *selection = ui_listview_selection(
gtk_tree_view_get_selection(treeview),
event);
UiEvent e;
e.obj = event->obj;
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = selection;
e.intval = selection->count >
0 ? selection->rows[
0] : -
1;
event->activate(&e, event->userdata);
if(selection->count >
0) {
free(selection->rows);
}
free(selection);
}
void ui_listview_selection_event(
GtkTreeSelection *treeselection,
UiTreeEventData *event)
{
UiListSelection *selection = ui_listview_selection(treeselection, event);
UiEvent e;
e.obj = event->obj;
e.window = event->obj->window;
e.document = event->obj->ctx->document;
e.eventdata = selection;
e.intval = selection->count >
0 ? selection->rows[
0] : -
1;
event->selection(&e, event->userdata);
if(selection->count >
0) {
free(selection->rows);
}
free(selection);
}
UiListSelection* ui_listview_selection(
GtkTreeSelection *selection,
UiTreeEventData *event)
{
GList *rows = gtk_tree_selection_get_selected_rows(selection,
NULL);
UiListSelection *ls = malloc(
sizeof(UiListSelection));
ls->count = g_list_length(rows);
ls->rows = calloc(ls->count,
sizeof(
int));
GList *r = rows;
int i =
0;
while(r) {
GtkTreePath *path = r->data;
ls->rows[i] = ui_tree_path_list_index(path);
r = r->next;
i++;
}
return ls;
}
int ui_tree_path_list_index(GtkTreePath *path) {
int depth = gtk_tree_path_get_depth(path);
if(depth ==
0) {
fprintf(stderr,
"UiError: treeview selection: depth == 0\n");
return -
1;
}
int *indices = gtk_tree_path_get_indices(path);
return indices[depth -
1];
}
UIWIDGET ui_combobox_str(UiObject *obj, UiList *list, ui_callback f,
void *udata) {
return ui_combobox(obj, list, ui_strmodel_getvalue, f, udata);
}
UIWIDGET ui_combobox(UiObject *obj, UiList *list, ui_getvaluefunc getvalue, ui_callback f,
void *udata) {
UiVar *var = malloc(
sizeof(UiVar));
var->value = list;
var->type =
UI_VAR_SPECIAL;
return ui_combobox_var(obj, var, getvalue, f, udata);
}
UIWIDGET ui_combobox_nv(UiObject *obj,
char *varname, ui_getvaluefunc getvalue, ui_callback f,
void *udata) {
UiVar *var = uic_create_var(obj->ctx, varname,
UI_VAR_LIST);
if(var) {
return ui_combobox_var(obj, var, getvalue, f, udata);
}
else {
}
return NULL;
}
UIWIDGET ui_combobox_var(UiObject *obj, UiVar *var, ui_getvaluefunc getvalue, ui_callback f,
void *udata) {
UiModel *model = ui_model(obj->ctx,
UI_STRING,
"", -
1);
model->getvalue = getvalue;
UiListModel *listmodel = ui_list_model_new(obj, var, model);
GtkWidget *combobox = ui_create_combobox(obj, listmodel, f, udata);
UiContainer *ct = uic_get_current_container(obj);
ct->add(ct, combobox,
FALSE);
return combobox;
}
GtkWidget* ui_create_combobox(UiObject *obj, UiListModel *model, ui_callback f,
void *udata) {
GtkWidget *combobox = gtk_combo_box_new_with_model(
GTK_TREE_MODEL(model));
UiListView *uicbox = malloc(
sizeof(UiListView));
uicbox->obj = obj;
uicbox->widget = combobox;
uicbox->var = model->var;
uicbox->model = model->model;
g_signal_connect(
combobox,
"destroy",
G_CALLBACK(ui_combobox_destroy),
uicbox);
UiList *list = model->var->value;
list->update = ui_combobox_modelupdate;
list->obj = uicbox;
GtkCellRenderer *renderer = gtk_cell_renderer_text_new();
gtk_cell_layout_pack_start(
GTK_CELL_LAYOUT(combobox), renderer,
TRUE);
gtk_cell_layout_set_attributes(
GTK_CELL_LAYOUT(combobox),
renderer,
"text",
0,
NULL);
gtk_combo_box_set_active(
GTK_COMBO_BOX(combobox),
0);
if(f) {
UiEventData *event = ui_malloc(obj->ctx,
sizeof(UiEventData));
event->obj = obj;
event->userdata = udata;
event->callback = f;
event->value =
0;
g_signal_connect(
combobox,
"changed",
G_CALLBACK(ui_combobox_change_event),
event);
}
return combobox;
}
void ui_combobox_change_event(GtkComboBox *widget, UiEventData *e) {
UiEvent event;
event.obj = e->obj;
event.window = event.obj->window;
event.document = event.obj->ctx->document;
event.eventdata =
NULL;
event.intval = gtk_combo_box_get_active(widget);
e->callback(&event, e->userdata);
}
void ui_combobox_modelupdate(UiList *list,
int i) {
UiListView *view = list->obj;
UiListModel *model = ui_list_model_new(view->obj, view->var, view->model);
gtk_combo_box_set_model(
GTK_COMBO_BOX(view->widget),
GTK_TREE_MODEL(model));
}