#include <stdio.h>
#include <stdlib.h>
#include "model.h"
#include "image.h"
#include "toolkit.h"
#define IS_UI_LIST_MODEL(obj) \
(
G_TYPE_CHECK_INSTANCE_TYPE((obj), list_model_type))
#define UI_LIST_MODEL(obj) \
(
G_TYPE_CHECK_INSTANCE_CAST((obj), list_model_type, UiListModel))
static void list_model_class_init(GObjectClass *cl, gpointer data);
static void list_model_interface_init(GtkTreeModelIface *i, gpointer data);
static void list_model_init(UiListModel *instance, GObjectClass *cl);
static void list_model_dnd_dest_interface_init(GtkTreeDragDestIface *i, gpointer data);
static void list_model_dnd_src_interface_init(GtkTreeDragSourceIface *i, gpointer data);
static GObjectClass list_model_class;
static const GTypeInfo list_model_info = {
sizeof(GObjectClass),
NULL,
NULL,
(GClassInitFunc)list_model_class_init,
NULL,
NULL,
sizeof(UiListModel),
0,
(GInstanceInitFunc)list_model_init
};
static const GInterfaceInfo list_model_interface_info = {
(GInterfaceInitFunc)list_model_interface_init,
NULL,
NULL
};
static GType list_model_type;
static const GInterfaceInfo list_model_dnd_dest_interface_info = {
(GInterfaceInitFunc)list_model_dnd_dest_interface_init,
NULL,
NULL
};
static const GInterfaceInfo list_model_dnd_src_interface_info = {
(GInterfaceInitFunc)list_model_dnd_src_interface_init,
NULL,
NULL
};
void ui_list_init() {
list_model_type = g_type_register_static(
G_TYPE_OBJECT,
"UiListModel",
&list_model_info,
(GTypeFlags)
0);
g_type_add_interface_static(
list_model_type,
GTK_TYPE_TREE_MODEL,
&list_model_interface_info);
g_type_add_interface_static(
list_model_type,
GTK_TYPE_TREE_DRAG_DEST,
&list_model_dnd_dest_interface_info);
g_type_add_interface_static(
list_model_type,
GTK_TYPE_TREE_DRAG_SOURCE,
&list_model_dnd_src_interface_info);
}
static void list_model_class_init(GObjectClass *cl, gpointer data) {
cl->dispose = ui_list_model_dispose;
cl->finalize = ui_list_model_finalize;
}
static void list_model_interface_init(GtkTreeModelIface *i, gpointer data) {
i->get_flags = ui_list_model_get_flags;
i->get_n_columns = ui_list_model_get_n_columns;
i->get_column_type = ui_list_model_get_column_type;
i->get_iter = ui_list_model_get_iter;
i->get_path = ui_list_model_get_path;
i->get_value = ui_list_model_get_value;
i->iter_next = ui_list_model_iter_next;
i->iter_children = ui_list_model_iter_children;
i->iter_has_child = ui_list_model_iter_has_child;
i->iter_n_children = ui_list_model_iter_n_children;
i->iter_nth_child = ui_list_model_iter_nth_child;
i->iter_parent = ui_list_model_iter_parent;
}
static void list_model_dnd_dest_interface_init(GtkTreeDragDestIface *i, gpointer data) {
i->drag_data_received = ui_list_model_drag_data_received;
i->row_drop_possible = ui_list_model_row_drop_possible;
}
static void list_model_dnd_src_interface_init(GtkTreeDragSourceIface *i, gpointer data) {
i->drag_data_delete = ui_list_model_drag_data_delete;
i->drag_data_get = ui_list_model_drag_data_get;
i->row_draggable = ui_list_model_row_draggable;
}
static void list_model_init(UiListModel *instance, GObjectClass *cl) {
instance->columntypes =
NULL;
instance->var =
NULL;
instance->numcolumns =
0;
instance->stamp = g_random_int();
}
static GType ui_gtk_type(UiModelType type) {
switch(type) {
default:
break;
case UI_STRING:
return G_TYPE_STRING;
case UI_INTEGER:
return G_TYPE_INT;
}
return G_TYPE_INVALID;
}
static void ui_model_set_value(GType type,
void *data, GValue *value) {
switch(type) {
default:
break;
case G_TYPE_OBJECT: {
value->g_type =
G_TYPE_OBJECT;
g_value_set_object(value, data);
return;
}
case G_TYPE_STRING: {
value->g_type =
G_TYPE_STRING;
g_value_set_string(value, data);
return;
}
case G_TYPE_INT: {
value->g_type =
G_TYPE_INT;
int *i = data;
g_value_set_int(value, *i);
return;
}
}
value->g_type =
G_TYPE_INVALID;
}
UiListModel* ui_list_model_new(UiObject *obj, UiVar *var, UiModel *info) {
UiListModel *model = g_object_new(list_model_type,
NULL);
model->obj = obj;
model->model = info;
model->var = var;
model->columntypes = calloc(
sizeof(GType),
2 * info->columns);
int ncol =
0;
for(
int i=
0;i<info->columns;i++) {
UiModelType type = info->types[i];
if(type ==
UI_ICON_TEXT) {
model->columntypes[ncol] =
G_TYPE_OBJECT;
ncol++;
model->columntypes[ncol] =
G_TYPE_STRING;
}
else {
model->columntypes[ncol] = ui_gtk_type(info->types[i]);
}
ncol++;
}
model->numcolumns = ncol;
return model;
}
void ui_list_model_dispose(GObject *obj) {
}
void ui_list_model_finalize(GObject *obj) {
}
GtkTreeModelFlags ui_list_model_get_flags(GtkTreeModel *tree_model) {
return (
GTK_TREE_MODEL_LIST_ONLY |
GTK_TREE_MODEL_ITERS_PERSIST);
}
gint ui_list_model_get_n_columns(GtkTreeModel *tree_model) {
g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
0);
UiListModel *model =
UI_LIST_MODEL(tree_model);
return model->numcolumns;
}
GType ui_list_model_get_column_type(GtkTreeModel *tree_model, gint index) {
g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
G_TYPE_INVALID);
UiListModel *model =
UI_LIST_MODEL(tree_model);
g_return_val_if_fail(index < model->numcolumns,
G_TYPE_INVALID);
return model->columntypes[index];
}
gboolean ui_list_model_get_iter(
GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreePath *path)
{
g_assert(
IS_UI_LIST_MODEL(tree_model));
UiListModel *model =
UI_LIST_MODEL(tree_model);
UiList *list = model->var->value;
gint depth = gtk_tree_path_get_depth(path);
g_assert(depth ==
1);
gint *indices = gtk_tree_path_get_indices(path);
gint row = indices[
0];
if(row ==
0) {
if(list->first(list) ==
NULL) {
return FALSE;
}
}
else if(row >= list->count(list)) {
return FALSE;
}
void *val =
NULL;
if(row ==
0) {
val = list->first(list);
}
else {
val = list->get(list, row);
}
iter->stamp = model->stamp;
iter->user_data = list->iter;
iter->user_data2 = (gpointer)(
intptr_t)row;
iter->user_data3 = val;
return val ?
TRUE :
FALSE;
}
GtkTreePath* ui_list_model_get_path(
GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
NULL);
g_return_val_if_fail(iter !=
NULL,
NULL);
g_return_val_if_fail(iter->user_data !=
NULL,
NULL);
UiListModel *model =
UI_LIST_MODEL(tree_model);
GtkTreePath *path = gtk_tree_path_new();
gtk_tree_path_append_index(path, (
int)(
intptr_t)iter->user_data2);
return path;
}
void ui_list_model_get_value(
GtkTreeModel *tree_model,
GtkTreeIter *iter,
gint column,
GValue *value)
{
g_return_if_fail(
IS_UI_LIST_MODEL(tree_model));
g_return_if_fail(iter !=
NULL);
g_return_if_fail(iter->user_data !=
NULL);
UiListModel *model =
UI_LIST_MODEL(tree_model);
UiList *list = model->var->value;
g_return_if_fail(column < model->numcolumns);
list->iter = iter->user_data;
if(model->model->getvalue) {
void *data = model->model->getvalue(iter->user_data3, column);
if(model->columntypes[column] ==
G_TYPE_OBJECT) {
UiImage *img = data;
ui_model_set_value(model->columntypes[column], img->pixbuf, value);
}
else {
ui_model_set_value(model->columntypes[column], data, value);
}
}
else {
value->g_type =
G_TYPE_INVALID;
}
}
gboolean ui_list_model_iter_next(
GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
FALSE);
g_return_val_if_fail(iter !=
NULL,
FALSE);
if(!iter->user_data) {
return FALSE;
}
UiListModel *model =
UI_LIST_MODEL(tree_model);
UiList *list = model->var->value;
list->iter = iter->user_data;
void *val = list->next(list);
iter->user_data = list->iter;
intptr_t index = (
intptr_t)iter->user_data2;
index++;
iter->user_data2 = (gpointer)index;
iter->user_data3 = val;
return val ?
TRUE :
FALSE;
}
gboolean ui_list_model_iter_children(
GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent)
{
g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
FALSE);
UiListModel *model =
UI_LIST_MODEL(tree_model);
UiList *list = model->var->value;
if(parent) {
return FALSE;
}
void *val = list->first(list);
iter->stamp = model->stamp;
iter->user_data = list->iter;
iter->user_data2 = (gpointer)
0;
iter->user_data3 = val;
return val ?
TRUE :
FALSE;
}
gboolean ui_list_model_iter_has_child(
GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
return FALSE;
}
gint ui_list_model_iter_n_children(
GtkTreeModel *tree_model,
GtkTreeIter *iter)
{
g_assert(
IS_UI_LIST_MODEL(tree_model));
if(!iter) {
UiListModel *model =
UI_LIST_MODEL(tree_model);
UiList *list = model->var->value;
return list->count(list);
}
return 0;
}
gboolean ui_list_model_iter_nth_child(
GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *parent,
gint n)
{
g_return_val_if_fail(
IS_UI_LIST_MODEL(tree_model),
FALSE);
if(parent) {
return FALSE;
}
UiListModel *model =
UI_LIST_MODEL(tree_model);
UiList *list = model->var->value;
if(n ==
0) {
if(list->first(list) ==
NULL) {
return FALSE;
}
}
else if(n >= list->count(list)) {
return FALSE;
}
void *val = list->get(list, n);
iter->stamp = model->stamp;
iter->user_data = list->iter;
iter->user_data2 = (gpointer)(
intptr_t)n;
iter->user_data3 = val;
return val ?
TRUE :
FALSE;
}
gboolean ui_list_model_iter_parent(
GtkTreeModel *tree_model,
GtkTreeIter *iter,
GtkTreeIter *child)
{
return FALSE;
}
gboolean ui_list_model_drag_data_received(
GtkTreeDragDest *drag_dest,
GtkTreePath *dest_path,
GtkSelectionData *selection_data)
{
UiListModel *model =
UI_LIST_MODEL(drag_dest);
if(model->model->drop) {
gint *indices = gtk_tree_path_get_indices(dest_path);
gint row = indices[
0];
UiEvent e;
e.obj = model->obj;
e.window = e.obj->window;
e.document = e.obj->ctx->document;
e.eventdata =
NULL;
e.intval =
0;
UiSelection s;
s.data = selection_data;
model->model->drop(&e, &s, model->var->value, row);
}
return TRUE;
}
gboolean ui_list_model_row_drop_possible(
GtkTreeDragDest *drag_dest,
GtkTreePath *dest_path,
GtkSelectionData *selection_data)
{
UiListModel *model =
UI_LIST_MODEL(drag_dest);
if(model->model->candrop) {
gint *indices = gtk_tree_path_get_indices(dest_path);
gint row = indices[
0];
UiEvent e;
e.obj = model->obj;
e.window = e.obj->window;
e.document = e.obj->ctx->document;
e.eventdata =
NULL;
e.intval =
0;
UiSelection s;
s.data = selection_data;
return model->model->candrop(&e, &s, model->var->value, row);
}
return TRUE;
}
gboolean ui_list_model_row_draggable(
GtkTreeDragSource *drag_source,
GtkTreePath *path)
{
UiListModel *model =
UI_LIST_MODEL(drag_source);
if(model->model->candrag) {
gint *indices = gtk_tree_path_get_indices(path);
gint row = indices[
0];
UiEvent e;
e.obj = model->obj;
e.window = e.obj->window;
e.document = e.obj->ctx->document;
e.eventdata =
NULL;
e.intval =
0;
return model->model->candrag(&e, model->var->value, row);
}
return TRUE;
}
gboolean ui_list_model_drag_data_get(
GtkTreeDragSource *drag_source,
GtkTreePath *path,
GtkSelectionData *selection_data)
{
UiListModel *model =
UI_LIST_MODEL(drag_source);
if(model->model->data_get) {
gint *indices = gtk_tree_path_get_indices(path);
gint row = indices[
0];
UiEvent e;
e.obj = model->obj;
e.window = e.obj->window;
e.document = e.obj->ctx->document;
e.eventdata =
NULL;
e.intval =
0;
UiSelection s;
s.data = selection_data;
model->model->data_get(&e, &s, model->var->value, row);
}
return TRUE;
}
gboolean ui_list_model_drag_data_delete(
GtkTreeDragSource *drag_source,
GtkTreePath *path)
{
UiListModel *model =
UI_LIST_MODEL(drag_source);
if(model->model->data_get) {
gint *indices = gtk_tree_path_get_indices(path);
gint row = indices[
0];
UiEvent e;
e.obj = model->obj;
e.window = e.obj->window;
e.document = e.obj->ctx->document;
e.eventdata =
NULL;
e.intval =
0;
model->model->data_delete(&e, model->var->value, row);
}
return TRUE;
}