openclonk/src/editor/C4ObjectListDlg.cpp

860 lines
23 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2007-2009, RedWolf Design GmbH, http://www.clonk.de/
* Copyright (c) 2009-2016, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
/* A window listing all objects in the game */
#include "C4Include.h"
#include "editor/C4ObjectListDlg.h"
#include "editor/C4Console.h"
#include "object/C4Object.h"
#include "object/C4GameObjects.h"
#ifdef USE_GTK
#include <gtk/gtk.h>
/* Some boilerplate GObject defines. 'klass' is used instead of 'class', because 'class' is a C++ keyword */
#define C4_TYPE_LIST (c4_list_get_type ())
#define C4_LIST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), C4_TYPE_LIST, C4List))
#define C4_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), C4_TYPE_LIST, C4ListClass))
#define C4_IS_LIST(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), C4_TYPE_LIST))
#define C4_IS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), C4_TYPE_LIST))
#define C4_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), C4_TYPE_LIST, C4ListClass))
/* The data columns that we export via the tree model interface */
enum
{
C4_LIST_COL_OBJECT,
C4_LIST_N_COLUMNS
};
typedef struct _C4List C4List;
typedef struct _C4ListClass C4ListClass;
struct _C4List
{
GObject parent; /* this MUST be the first member */
C4ObjectList * data;
gint stamp; /* A random integer to check if an iter belongs to this model */
};
/* more boilerplate GObject stuff */
struct _C4ListClass
{
GObjectClass parent_class;
};
static GObjectClass *parent_class = NULL;
GType c4_list_get_type (void);
// Initialise an instance
static void
c4_list_init (C4List *c4_list)
{
c4_list->data = &::Objects;
c4_list->stamp = g_random_int(); /* Random int to check whether iters belong to this model */
}
// destructor
static void
c4_list_finalize (GObject *object)
{
/* must chain up - finalize parent */
(* parent_class->finalize) (object);
}
static GtkTreeModelFlags
c4_list_get_flags (GtkTreeModel *tree_model)
{
g_return_val_if_fail (C4_IS_LIST(tree_model), (GtkTreeModelFlags)0);
// neither is this a flat list nor do the iters persist changes in the model
//return GtkTreeModelFlags(GTK_TREE_MODEL_ITERS_PERSIST);
return GtkTreeModelFlags(0);
}
// converts 'path' into an iterator and stores that in 'iter'
static gboolean
c4_list_get_iter (GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreePath * path)
{
gint *indices, depth;
g_assert(C4_IS_LIST(tree_model));
g_assert(path!=NULL);
C4List * c4_list = C4_LIST(tree_model);
indices = gtk_tree_path_get_indices(path);
depth = gtk_tree_path_get_depth(path);
iter->stamp = c4_list->stamp;
C4ObjectLink * pLnk = C4_LIST(tree_model)->data->First;
// Skip Contained Objects in the main list
while (pLnk && pLnk->Obj->Contained) pLnk = pLnk->Next;
for (int i = 0; i < depth; ++i)
{
if (!pLnk)
return false;
if (indices[i] < 0)
return false;
for (int j = 0; j < indices[i]; ++j)
{
pLnk = pLnk->Next;
// Skip Contained Objects in the main list
while (i == 0 && pLnk && pLnk->Obj->Contained) pLnk = pLnk->Next;
if (!pLnk)
return false;
}
iter->user_data = pLnk;
iter->user_data2 = pLnk->Obj->Contained;
pLnk = pLnk->Obj->Contents.First;
}
return true;
}
// converts 'iter' into a new tree path and returns that.
// Note: This is called by OnObjectRemove with an iter which is not in the
// list anymore, but with the object and prev still usable.
static GtkTreePath *
c4_list_get_path (GtkTreeModel * tree_model, GtkTreeIter * iter)
{
g_return_val_if_fail (C4_IS_LIST(tree_model), NULL);
g_return_val_if_fail (iter != NULL, NULL);
g_return_val_if_fail (iter->user_data != NULL, NULL);
GtkTreePath *path = gtk_tree_path_new();
C4List * c4_list = C4_LIST(tree_model);
C4Object * pObj = ((C4ObjectLink *) iter->user_data)->Obj;
int i = 0;
for (C4ObjectLink * pLnk = ((C4ObjectLink *) iter->user_data)->Prev; pLnk; pLnk = pLnk->Prev)
{
// Skip Contained Objects in the main list
if (pObj->Contained != pLnk->Obj->Contained) continue;
++i;
}
gtk_tree_path_prepend_index(path, i);
pObj = (C4Object *) iter->user_data2;
while (pObj)
{
i = 0;
C4ObjectList * pList = c4_list->data;
if (pObj->Contained)
pList = &pObj->Contained->Contents;
for (C4ObjectLink * pLnk = pList->First; pLnk && pLnk->Obj != pObj; pLnk = pLnk->Next)
{
// Skip Contained Objects in the main list
if (pObj->Contained != pLnk->Obj->Contained) continue;
++i;
}
gtk_tree_path_prepend_index(path, i);
pObj = pObj->Contained;
}
return path;
}
// ++iter
static gboolean
c4_list_iter_next (GtkTreeModel * tree_model, GtkTreeIter * iter)
{
g_return_val_if_fail (C4_IS_LIST (tree_model), false);
if (iter == NULL || iter->user_data == NULL)
return false;
C4ObjectLink * pLnk = (C4ObjectLink *) iter->user_data;
pLnk = pLnk->Next;
// Skip Contained Objects in the main list
if (!(C4Object *)iter->user_data2)
while (pLnk && pLnk->Obj->Contained)
pLnk = pLnk->Next;
if (!pLnk)
return false;
iter->user_data = pLnk;
iter->user_data2 = pLnk->Obj->Contained;
return true;
}
// Set 'iter' to the first child of 'parent', or the first top-level row if
// 'parent' is 0, or return false if there aren't any children.
static gboolean
c4_list_iter_children (GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent)
{
g_return_val_if_fail (parent == NULL || parent->user_data != NULL, false);
g_return_val_if_fail (C4_IS_LIST (tree_model), false);
C4List *c4_list = C4_LIST(tree_model);
C4ObjectLink * pLnk;
if (parent)
{
C4ObjectList * pList = &((C4ObjectLink *)parent->user_data)->Obj->Contents;
pLnk = pList->First;
}
else
{
pLnk = c4_list->data->First;
// Skip...
while (pLnk && pLnk->Obj->Contained) pLnk = pLnk->Next;
}
if (!pLnk)
return false;
/* Set iter to first item in list */
iter->stamp = c4_list->stamp;
iter->user_data = pLnk;
iter->user_data2 = pLnk->Obj->Contained;
return true;
}
// Return true if 'parent' has children.
static gboolean
c4_list_iter_has_child (GtkTreeModel *tree_model,
GtkTreeIter *parent)
{
g_return_val_if_fail (parent == NULL || parent->user_data != NULL, false);
g_return_val_if_fail (C4_IS_LIST (tree_model), false);
C4List *c4_list = C4_LIST(tree_model);
C4ObjectList * pList = c4_list->data;
if (parent)
pList = &((C4ObjectLink *)parent->user_data)->Obj->Contents;
return pList->First != 0;
}
// Counts the children 'parent' has.
static gint
c4_list_iter_n_children (GtkTreeModel *tree_model, GtkTreeIter *parent)
{
g_return_val_if_fail (C4_IS_LIST (tree_model), -1);
g_return_val_if_fail (parent == NULL || parent->user_data != NULL, -1);
C4List *c4_list = C4_LIST(tree_model);
int i = 0;
if (parent)
{
C4ObjectList * pList = &((C4ObjectLink *)parent->user_data)->Obj->Contents;
C4ObjectLink * pLnk = pList->First;
while (pLnk)
{
++i;
pLnk = pLnk->Next;
}
}
else
{
C4ObjectLink * pLnk = c4_list->data->First;
while (pLnk)
{
if (!pLnk->Obj->Contained)
++i;
pLnk = pLnk->Next;
}
}
return i;
}
// Sets 'iter' to the 'n'-th child of 'parent'.
static gboolean
c4_list_iter_nth_child (GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * parent, gint n)
{
g_return_val_if_fail (C4_IS_LIST (tree_model), false);
g_return_val_if_fail (parent == NULL || parent->user_data != NULL, false);
C4List *c4_list = C4_LIST(tree_model);
C4ObjectLink * pLnk;
if (parent)
{
C4ObjectList * pList = &((C4ObjectLink *)parent->user_data)->Obj->Contents;
pLnk = pList->First;
for (int i = 0; i < n; ++i)
{
if (!pLnk)
return false;
pLnk = pLnk->Next;
}
}
else
{
pLnk = c4_list->data->First;
for (int i = 0; i < n; ++i)
{
if (!pLnk)
return false;
pLnk = pLnk->Next;
// Skip...
while (pLnk && pLnk->Obj->Contained) pLnk = pLnk->Next;
}
}
if (!pLnk)
return false;
iter->stamp = c4_list->stamp;
iter->user_data = pLnk;
iter->user_data2 = pLnk->Obj->Contained;
return true;
}
// Helper function.
static gboolean c4_list_iter_for_C4Object (GtkTreeModel * tree_model, GtkTreeIter * iter, C4ObjectList * pList, C4Object * pObj)
{
if (!pObj)
return false;
C4List * c4_list = C4_LIST(tree_model);
for (C4ObjectLink * pLnk = pList->First; pLnk; pLnk = pLnk->Next)
{
if (pLnk->Obj == pObj)
{
iter->stamp = c4_list->stamp;
iter->user_data = pLnk;
iter->user_data2 = pLnk->Obj->Contained;
return true;
}
}
g_return_val_if_reached(false);
}
// Sets 'iter' to the parent row of 'child'.
static gboolean
c4_list_iter_parent (GtkTreeModel * tree_model, GtkTreeIter * iter, GtkTreeIter * child)
{
g_return_val_if_fail (C4_IS_LIST (tree_model), false);
g_return_val_if_fail (child == NULL || child->user_data != NULL, false);
C4List * c4_list = C4_LIST(tree_model);
C4Object * pObj = (C4Object *) child->user_data2;
C4ObjectList * pList = c4_list->data;
if (pObj->Contained)
pList = &pObj->Contained->Contents;
return c4_list_iter_for_C4Object(tree_model, iter, pList, pObj);
}
static C4Object *
c4_list_iter_get_C4Object(GtkTreeModel * tree_model, GtkTreeIter * iter)
{
g_return_val_if_fail (C4_IS_LIST (tree_model), NULL);
g_return_val_if_fail (iter != NULL && iter->user_data != NULL, NULL);
return ((C4ObjectLink *) iter->user_data)->Obj;
}
// How many columns does this model have?
static gint
c4_list_get_n_columns (GtkTreeModel * tree_model)
{
g_return_val_if_fail (C4_IS_LIST(tree_model), 0);
return 1;
}
// What sort of data is in the column?
static GType
c4_list_get_column_type (GtkTreeModel * tree_model, gint index)
{
g_return_val_if_fail (C4_IS_LIST(tree_model), G_TYPE_INVALID);
g_return_val_if_fail (index < 1 && index >= 0, G_TYPE_INVALID);
return G_TYPE_POINTER;
}
// gets the data for the 'column' in the row at 'iter' and stores that in 'value'.
static void
c4_list_get_value (GtkTreeModel * tree_model, GtkTreeIter * iter, gint column, GValue * value)
{
g_return_if_fail (C4_IS_LIST (tree_model));
g_return_if_fail (iter != NULL);
g_return_if_fail (column == 0);
C4Object * pObj = ((C4ObjectLink *) iter->user_data)->Obj;
g_return_if_fail (pObj != NULL);
g_value_init (value, G_TYPE_POINTER);
g_value_set_pointer(value, pObj);
// g_value_set_string(value, pObj->GetName());
}
// Wrapper around g_object_new.
static C4List *
c4_list_new (void)
{
C4List * list;
list = (C4List *) g_object_new (C4_TYPE_LIST, NULL);
g_assert(list != NULL);
return list;
}
// Called once for the class.
static void
c4_list_class_init (C4ListClass * klass)
{
GObjectClass * object_class;
parent_class = (GObjectClass*) g_type_class_peek_parent (klass);
object_class = (GObjectClass*) klass;
object_class->finalize = c4_list_finalize;
}
// fill in the GtkTreeModel interface with the functions above.
static void
c4_list_tree_model_init (GtkTreeModelIface *iface)
{
iface->get_flags = c4_list_get_flags;
iface->get_n_columns = c4_list_get_n_columns;
iface->get_column_type = c4_list_get_column_type;
iface->get_iter = c4_list_get_iter;
iface->get_path = c4_list_get_path;
iface->get_value = c4_list_get_value;
iface->iter_next = c4_list_iter_next;
iface->iter_children = c4_list_iter_children;
iface->iter_has_child = c4_list_iter_has_child;
iface->iter_n_children = c4_list_iter_n_children;
iface->iter_nth_child = c4_list_iter_nth_child;
iface->iter_parent = c4_list_iter_parent;
}
// Return the type, registering it on first call.
GType
c4_list_get_type (void)
{
static GType c4_list_type = 0;
if (c4_list_type == 0)
{
// Some boilerplate type registration stuff
static const GTypeInfo c4_list_info =
{
sizeof (C4ListClass), /* class_size */
NULL, /* base_init */
NULL, /* base_finalize */
(GClassInitFunc) c4_list_class_init, /* class_init */
NULL, /* class finalize */
NULL, /* class_data */
sizeof (C4List), /* instance_size */
0, /* n_preallocs */
(GInstanceInitFunc) c4_list_init, /* instance_init */
NULL /* value_table */
};
c4_list_type = g_type_register_static (G_TYPE_OBJECT, "C4List",
&c4_list_info, (GTypeFlags)0);
/* register the GtkTreeModel interface with the type system */
static const GInterfaceInfo tree_model_info =
{
(GInterfaceInitFunc) c4_list_tree_model_init,
NULL,
NULL
};
g_type_add_interface_static (c4_list_type, GTK_TYPE_TREE_MODEL, &tree_model_info);
}
return c4_list_type;
}
void C4ObjectListDlg::OnObjectRemove(C4ObjectList * pList, C4ObjectLink * pLnk)
{
if (!model) return;
C4List * c4_list = C4_LIST(model);
C4Object * Contained = pLnk->Obj->Contained;
GtkTreeIter iter;
iter.stamp = c4_list->stamp;
iter.user_data = pLnk;
iter.user_data2 = Contained;
// While pLnk is not in the list anymore, with pLnk->Prev and Contained a path can still be made
GtkTreePath * path = c4_list_get_path(GTK_TREE_MODEL(model), &iter);
gtk_tree_model_row_deleted(GTK_TREE_MODEL(model), path);
gtk_tree_path_free(path);
// Removed from a now empty container?
if (Contained && !Contained->Contents.First)
{
printf("Removed from a now empty container\n");
GtkTreeIter parent;
C4ObjectList * pList = c4_list->data;
if (Contained->Contained)
pList = &Contained->Contained->Contents;
c4_list_iter_for_C4Object(GTK_TREE_MODEL(model), &parent, pList, Contained);
GtkTreePath * path = c4_list_get_path(GTK_TREE_MODEL(model), &parent);
gtk_tree_model_row_has_child_toggled(GTK_TREE_MODEL(model), path, &parent);
gtk_tree_path_free(path);
}
// Cheat: For the signals it must look as if the object had it's parent removed already
pLnk->Obj->Contained = 0;
// if removed from contents, it get's added to main list
if (pList != c4_list->data)
{
printf("Removed from a container\n");
GtkTreeIter iter;
C4ObjectList * pList = c4_list->data;
c4_list_iter_for_C4Object(GTK_TREE_MODEL(model), &iter, pList, pLnk->Obj);
GtkTreePath * path = c4_list_get_path(GTK_TREE_MODEL(model), &iter);
gtk_tree_model_row_inserted(GTK_TREE_MODEL(model), path, &iter);
gtk_tree_path_free(path);
}
// End-of-cheat
pLnk->Obj->Contained = Contained;
}
void C4ObjectListDlg::OnObjectAdded(C4ObjectList * pList, C4ObjectLink * pLnk)
{
if (!model) return;
C4List * c4_list = C4_LIST(model);
// Inserted into a container? Remove from main list
if (pList != c4_list->data)
{
printf("Inserted into a container\n");
GtkTreePath *path = gtk_tree_path_new();
int i = 0;
C4ObjectList * pList = c4_list->data;
C4Object * pObj = pLnk->Obj;
for (C4ObjectLink * pLnk2 = pList->First; pLnk2 && pLnk2->Obj != pObj; pLnk2 = pLnk2->Next)
{
// Skip Contained Objects in the main list
if (pLnk2->Obj->Contained) continue;
++i;
}
gtk_tree_path_prepend_index(path, i);
gtk_tree_model_row_deleted(GTK_TREE_MODEL(model), path);
gtk_tree_path_free(path);
}
GtkTreeIter iter;
iter.stamp = c4_list->stamp;
iter.user_data = pLnk;
iter.user_data2 = pLnk->Obj->Contained;
GtkTreePath * path = c4_list_get_path(GTK_TREE_MODEL(model), &iter);
gtk_tree_model_row_inserted(GTK_TREE_MODEL(model), path, &iter);
gtk_tree_path_free(path);
// Inserted into a previously empty container?
if (pLnk->Obj->Contained &&
pLnk->Obj->Contained->Contents.First == pLnk->Obj->Contained->Contents.Last)
{
printf("Inserted into a previously empty container\n");
GtkTreeIter parent;
c4_list_iter_parent(GTK_TREE_MODEL(model), &parent, &iter);
GtkTreePath * path = c4_list_get_path(GTK_TREE_MODEL(model), &parent);
gtk_tree_model_row_has_child_toggled(GTK_TREE_MODEL(model), path, &parent);
gtk_tree_path_free(path);
}
}
void C4ObjectListDlg::OnObjectRename(C4ObjectList * pList, C4ObjectLink * pLnk)
{
}
void C4ObjectListDlg::OnDestroy(GtkWidget* widget, C4ObjectListDlg* dlg)
{
dlg->window = 0;
dlg->model = 0;
dlg->treeview = 0;
}
void C4ObjectListDlg::OnRowActivated(GtkTreeView * tree_view, GtkTreePath * path, GtkTreeViewColumn * column, C4ObjectListDlg * dlg)
{
Console.EditCursor.SetMode(C4CNS_ModeEdit);
Console.EditCursor.OpenPropTools();
}
void C4ObjectListDlg::OnSelectionChanged(GtkTreeSelection* selection, C4ObjectListDlg* dlg)
{
if (dlg->updating_selection) return;
dlg->updating_selection = true;
GList* list = gtk_tree_selection_get_selected_rows(selection, NULL);
Console.EditCursor.GetSelection().Clear();
for (GList * i = list; i; i = i->next)
{
GtkTreePath * path = (GtkTreePath *)i->data;
GtkTreeIter iter;
c4_list_get_iter(GTK_TREE_MODEL(dlg->model), &iter, path);
Console.EditCursor.GetSelection().Add(((C4ObjectLink *)iter.user_data)->Obj, C4ObjectList::stNone);
}
g_list_foreach (list, (GFunc)gtk_tree_path_free, NULL);
g_list_free (list);
Console.EditCursor.OnSelectionChanged();
dlg->updating_selection = false;
}
void C4ObjectListDlg::Update(C4ObjectList &rSelection)
{
if (updating_selection) return;
if (!window) return;
updating_selection = true;
GtkTreeSelection *selection;
selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
gtk_tree_selection_unselect_all(selection);
for (C4ObjectLink * pLnk = rSelection.First; pLnk; pLnk = pLnk->Next)
{
GtkTreeIter iter;
C4List * c4_list = C4_LIST(model);
C4ObjectList * pList = c4_list->data;
if (pLnk->Obj->Contained)
pList = &pLnk->Obj->Contained->Contents;
c4_list_iter_for_C4Object(GTK_TREE_MODEL(model), &iter, pList, pLnk->Obj);
gtk_tree_selection_select_iter(selection, &iter);
}
updating_selection = false;
}
C4ObjectListDlg::C4ObjectListDlg():
window(0),
treeview(0),
model(0),
updating_selection(false)
{
}
C4ObjectListDlg::~C4ObjectListDlg()
{
}
void C4ObjectListDlg::Execute()
{
}
static void name_cell_data_func(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, gpointer data)
{
C4Object* object = c4_list_iter_get_C4Object(model, iter);
g_object_set(G_OBJECT(renderer), "text", object->GetName(), (gpointer)NULL);
}
enum { ICON_SIZE = 24 };
#ifdef _UNUSED_
static void icon_cell_data_func(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, gpointer data)
{
C4Object* object = c4_list_iter_get_C4Object(model, iter);
// Icons for objects with ColorByOwner are cached by object, others by Def
// FIXME: Invalidate cache when objects change color, and redraw.
gpointer key = object->Def;
if (object->Def->ColorByOwner) key = object;
GHashTable* table = static_cast<GHashTable*>(data);
GdkPixbuf* pixbuf = GDK_PIXBUF(g_hash_table_lookup(table, key));
if (pixbuf == NULL)
{
/* Not yet cached, create from Graphics */
C4Surface* surface = object->Def->Graphics.Bmp.Bitmap;
if (object->Def->Graphics.Bmp.BitmapClr) surface = object->Def->Graphics.Bmp.BitmapClr;
const C4Rect& picture = object->Def->PictureRect;
pixbuf = gdk_pixbuf_new(GDK_COLORSPACE_RGB, true, 8, picture.Wdt, picture.Hgt);
guchar* pixels = gdk_pixbuf_get_pixels(pixbuf);
surface->Lock();
for (int y = 0; y < picture.Hgt; ++ y) for (int x = 0; x < picture.Wdt; ++ x)
{
DWORD dw = surface->GetPixDw(picture.x + x, picture.y + y, true);
*pixels = (dw >> 16) & 0xff; ++ pixels;
*pixels = (dw >> 8 ) & 0xff; ++ pixels;
*pixels = (dw ) & 0xff; ++ pixels;
*pixels = 0xff - ((dw >> 24) & 0xff); ++ pixels;
}
surface->Unlock();
// Scale down to ICON_SIZE, keeping aspect ratio
guint dest_width, dest_height;
if (picture.Wdt >= picture.Hgt)
{
double factor = static_cast<double>(picture.Hgt) / static_cast<double>(picture.Wdt);
dest_width = ICON_SIZE;
dest_height = dest_width * factor;
}
else
{
double factor = static_cast<double>(picture.Wdt) / static_cast<double>(picture.Hgt);
dest_height = ICON_SIZE;
dest_width = dest_height * factor;
}
GdkPixbuf* scaled = gdk_pixbuf_scale_simple(pixbuf, dest_width, dest_height, GDK_INTERP_HYPER);
g_object_unref(G_OBJECT(pixbuf));
pixbuf = scaled;
g_hash_table_insert(table, key, pixbuf);
}
g_object_set(G_OBJECT(renderer), "pixbuf", pixbuf, NULL);
}
#endif // _UNUSED_
void C4ObjectListDlg::Open()
{
// Create Window if necessary
if (window == NULL)
{
// The Windows
window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
gtk_window_set_resizable(GTK_WINDOW(window), true);
gtk_window_set_type_hint(GTK_WINDOW(window), GDK_WINDOW_TYPE_HINT_UTILITY);
gtk_window_set_role(GTK_WINDOW(window), "objectlist");
gtk_window_set_title(GTK_WINDOW(window), "Objects");
gtk_window_set_default_size(GTK_WINDOW(window), 180, 300);
gtk_window_set_transient_for(GTK_WINDOW(window), GTK_WINDOW(Console.window));
g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(OnDestroy), this);
// The Tree
GtkWidget* scrolled_wnd = gtk_scrolled_window_new(NULL, NULL);
gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scrolled_wnd), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
gtk_scrolled_window_set_shadow_type(GTK_SCROLLED_WINDOW(scrolled_wnd), GTK_SHADOW_IN);
model = G_OBJECT(c4_list_new());
treeview = gtk_tree_view_new_with_model(GTK_TREE_MODEL(model));
g_object_unref(model); /* destroy store automatically with view */
g_signal_connect(G_OBJECT(treeview), "row-activated", G_CALLBACK(OnRowActivated), this);
GtkTreeViewColumn * col = gtk_tree_view_column_new();
GtkCellRenderer * renderer = gtk_cell_renderer_text_new();
gtk_tree_view_column_pack_start(col, renderer, true);
gtk_tree_view_column_set_cell_data_func(col, renderer, name_cell_data_func, NULL, NULL);
gtk_tree_view_column_set_title(col, "Name");
gtk_tree_view_column_set_sizing(col, GTK_TREE_VIEW_COLUMN_FIXED);
gtk_tree_view_append_column(GTK_TREE_VIEW(treeview),col);
gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(treeview), false);
gtk_tree_view_set_fixed_height_mode(GTK_TREE_VIEW(treeview), true);
GtkTreeSelection * selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(treeview));
gtk_tree_selection_set_mode(selection, GTK_SELECTION_MULTIPLE);
g_signal_connect(G_OBJECT(selection), "changed", G_CALLBACK(OnSelectionChanged), this);
gtk_container_add(GTK_CONTAINER(scrolled_wnd), treeview);
gtk_widget_set_vexpand(scrolled_wnd, true);
gtk_widget_set_hexpand(scrolled_wnd, true);
gtk_container_add(GTK_CONTAINER(window), scrolled_wnd);
gtk_widget_show_all(window);
}
else
{
gtk_window_present_with_time(GTK_WINDOW(window), gtk_get_current_event_time());
}
}
#else
C4ObjectListDlg::C4ObjectListDlg()
{
}
C4ObjectListDlg::~C4ObjectListDlg()
{
}
void C4ObjectListDlg::Execute()
{
}
void C4ObjectListDlg::Open()
{
}
void C4ObjectListDlg::Update(C4ObjectList &rSelection)
{
}
void C4ObjectListDlg::OnObjectRemove(C4ObjectList * pList, C4ObjectLink * pLnk)
{
}
void C4ObjectListDlg::OnObjectAdded(C4ObjectList * pList, C4ObjectLink * pLnk)
{
}
void C4ObjectListDlg::OnObjectRename(C4ObjectList * pList, C4ObjectLink * pLnk)
{
}
#endif
C4ObjectListChangeListener & ObjectListChangeListener = Console.ObjectListDlg;