2 Copyright (C) 2001-2006, William Joseph.
5 This file is part of GtkRadiant.
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
22 #include "entitylist.h"
24 #include "iselection.h"
26 #include <gtk/gtktreemodel.h>
27 #include <gtk/gtktreeview.h>
28 #include <gtk/gtktreeselection.h>
29 #include <gtk/gtkcellrenderertext.h>
31 #include "string/string.h"
34 #include "signal/isignal.h"
35 #include "generic/object.h"
37 #include "gtkutil/widget.h"
38 #include "gtkutil/window.h"
39 #include "gtkutil/idledraw.h"
40 #include "gtkutil/accelerator.h"
41 #include "gtkutil/closure.h"
43 #include "treemodel.h"
45 void RedrawEntityList();
46 typedef FreeCaller<RedrawEntityList> RedrawEntityListCaller;
48 typedef struct _GtkTreeView GtkTreeView;
63 WindowPositionTracker m_positionTracker;
66 GtkTreeView* m_tree_view;
67 GraphTreeModel* m_tree_model;
68 bool m_selection_disabled;
71 m_dirty(EntityList::eDefault),
72 m_idleDraw(RedrawEntityListCaller()),
74 m_selection_disabled(false)
80 return GTK_WIDGET_VISIBLE(GTK_WIDGET(m_window));
86 EntityList* g_EntityList;
88 inline EntityList& getEntityList()
90 ASSERT_NOTNULL(g_EntityList);
96 inline Nameable* Node_getNameable(scene::Node& node)
98 return NodeTypeCast<Nameable>::cast(node);
101 const char* node_get_name(scene::Node& node)
103 Nameable* nameable = Node_getNameable(node);
104 return (nameable != 0)
109 template<typename value_type>
110 inline void gtk_tree_model_get_pointer(GtkTreeModel* model, GtkTreeIter* iter, gint column, value_type** pointer)
112 GValue value = GValue_default();
113 gtk_tree_model_get_value(model, iter, column, &value);
114 *pointer = (value_type*)g_value_get_pointer(&value);
119 void entitylist_treeviewcolumn_celldatafunc(GtkTreeViewColumn* column, GtkCellRenderer* renderer, GtkTreeModel* model, GtkTreeIter* iter, gpointer data)
122 gtk_tree_model_get_pointer(model, iter, 0, &node);
123 scene::Instance* instance;
124 gtk_tree_model_get_pointer(model, iter, 1, &instance);
127 gtk_cell_renderer_set_fixed_size(renderer, -1, -1);
128 char* name = const_cast<char*>(node_get_name(*node));
129 g_object_set(G_OBJECT(renderer), "text", name, "visible", TRUE, 0);
131 //globalOutputStream() << "rendering cell " << makeQuoted(name) << "\n";
132 GtkStyle* style = gtk_widget_get_style(GTK_WIDGET(getEntityList().m_tree_view));
133 if(instance->childSelected())
135 g_object_set(G_OBJECT(renderer), "cell-background-gdk", &style->base[GTK_STATE_ACTIVE], 0);
139 g_object_set(G_OBJECT(renderer), "cell-background-gdk", &style->base[GTK_STATE_NORMAL], 0);
144 gtk_cell_renderer_set_fixed_size(renderer, -1, 0);
145 g_object_set(G_OBJECT(renderer), "text", "", "visible", FALSE, 0);
149 static gboolean entitylist_tree_select(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer data)
152 gtk_tree_model_get_iter(model, &iter, path);
154 gtk_tree_model_get_pointer(model, &iter, 0, &node);
155 scene::Instance* instance;
156 gtk_tree_model_get_pointer(model, &iter, 1, &instance);
157 Selectable* selectable = Instance_getSelectable(*instance);
161 if(path_currently_selected != FALSE)
163 getEntityList().m_selection_disabled = true;
164 GlobalSelectionSystem().setSelectedAll(false);
165 getEntityList().m_selection_disabled = false;
168 else if(selectable != 0)
170 getEntityList().m_selection_disabled = true;
171 selectable->setSelected(path_currently_selected == FALSE);
172 getEntityList().m_selection_disabled = false;
179 static gboolean entitylist_tree_select_null(GtkTreeSelection *selection, GtkTreeModel *model, GtkTreePath *path, gboolean path_currently_selected, gpointer data)
184 void EntityList_ConnectSignals(GtkTreeView* view)
186 GtkTreeSelection* select = gtk_tree_view_get_selection(view);
187 gtk_tree_selection_set_select_function(select, entitylist_tree_select, NULL, 0);
190 void EntityList_DisconnectSignals(GtkTreeView* view)
192 GtkTreeSelection* select = gtk_tree_view_get_selection(view);
193 gtk_tree_selection_set_select_function(select, entitylist_tree_select_null, 0, 0);
198 gboolean treemodel_update_selection(GtkTreeModel* model, GtkTreePath* path, GtkTreeIter* iter, gpointer data)
200 GtkTreeView* view = reinterpret_cast<GtkTreeView*>(data);
202 scene::Instance* instance;
203 gtk_tree_model_get_pointer(model, iter, 1, &instance);
204 Selectable* selectable = Instance_getSelectable(*instance);
208 GtkTreeSelection* selection = gtk_tree_view_get_selection(view);
209 if(selectable->isSelected())
211 gtk_tree_selection_select_path(selection, path);
215 gtk_tree_selection_unselect_path(selection, path);
222 void EntityList_UpdateSelection(GtkTreeModel* model, GtkTreeView* view)
224 EntityList_DisconnectSignals(view);
225 gtk_tree_model_foreach(model, treemodel_update_selection, view);
226 EntityList_ConnectSignals(view);
230 void RedrawEntityList()
232 switch(getEntityList().m_dirty)
234 case EntityList::eInsertRemove:
235 case EntityList::eSelection:
236 EntityList_UpdateSelection(GTK_TREE_MODEL(getEntityList().m_tree_model), getEntityList().m_tree_view);
240 getEntityList().m_dirty = EntityList::eDefault;
243 void entitylist_queue_draw()
245 getEntityList().m_idleDraw.queueDraw();
248 void EntityList_SelectionUpdate()
250 if(getEntityList().m_selection_disabled)
253 if(getEntityList().m_dirty < EntityList::eSelection)
254 getEntityList().m_dirty = EntityList::eSelection;
255 entitylist_queue_draw();
258 void EntityList_SelectionChanged(const Selectable& selectable)
260 EntityList_SelectionUpdate();
263 void entitylist_treeview_rowcollapsed(GtkTreeView* view, GtkTreeIter* iter, GtkTreePath* path, gpointer user_data)
267 void entitylist_treeview_row_expanded(GtkTreeView* view, GtkTreeIter* iter, GtkTreePath* path, gpointer user_data)
269 EntityList_SelectionUpdate();
273 void EntityList_SetShown(bool shown)
275 widget_set_visible(GTK_WIDGET(getEntityList().m_window), shown);
278 void EntityList_toggleShown()
280 EntityList_SetShown(!getEntityList().visible());
283 gint graph_tree_model_compare_name(GtkTreeModel *model, GtkTreeIter *a, GtkTreeIter *b, gpointer user_data)
286 gtk_tree_model_get(model, a, 0, (gpointer*)&first, -1);
288 gtk_tree_model_get(model, b, 0, (gpointer*)&second, -1);
290 if(first != 0 && second != 0)
292 result = string_compare(node_get_name(*first), node_get_name(*second));
296 return (first < second) ? -1 : (second < first) ? 1 : 0;
301 extern GraphTreeModel* scene_graph_get_tree_model();
302 void AttachEntityTreeModel()
304 getEntityList().m_tree_model = scene_graph_get_tree_model();
306 gtk_tree_view_set_model(getEntityList().m_tree_view, GTK_TREE_MODEL(getEntityList().m_tree_model));
309 void DetachEntityTreeModel()
311 getEntityList().m_tree_model = 0;
313 gtk_tree_view_set_model(getEntityList().m_tree_view, 0);
316 void EntityList_constructWindow(GtkWindow* main_window)
318 ASSERT_MESSAGE(getEntityList().m_window == 0, "error");
320 GtkWindow* window = create_persistent_floating_window("Entity List", main_window);
322 gtk_window_add_accel_group(window, global_accel);
324 getEntityList().m_positionTracker.connect(window);
327 getEntityList().m_window = window;
330 GtkScrolledWindow* scr = create_scrolled_window(GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC);
331 gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(scr));
334 GtkWidget* view = gtk_tree_view_new();
335 gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(view), FALSE);
337 GtkCellRenderer* renderer = gtk_cell_renderer_text_new();
338 GtkTreeViewColumn* column = gtk_tree_view_column_new();
339 gtk_tree_view_column_pack_start(column, renderer, TRUE);
340 gtk_tree_view_column_set_cell_data_func(column, renderer, entitylist_treeviewcolumn_celldatafunc, 0, 0);
342 GtkTreeSelection* select = gtk_tree_view_get_selection (GTK_TREE_VIEW(view));
343 gtk_tree_selection_set_mode(select, GTK_SELECTION_MULTIPLE);
345 g_signal_connect(G_OBJECT(view), "row_expanded", G_CALLBACK(entitylist_treeview_row_expanded), 0);
346 g_signal_connect(G_OBJECT(view), "row_collapsed", G_CALLBACK(entitylist_treeview_rowcollapsed), 0);
348 gtk_tree_view_append_column (GTK_TREE_VIEW (view), column);
350 gtk_widget_show(view);
351 gtk_container_add (GTK_CONTAINER(scr), view);
352 getEntityList().m_tree_view = GTK_TREE_VIEW(view);
356 EntityList_ConnectSignals(getEntityList().m_tree_view);
357 AttachEntityTreeModel();
360 void EntityList_destroyWindow()
362 DetachEntityTreeModel();
363 EntityList_DisconnectSignals(getEntityList().m_tree_view);
364 destroy_floating_window(getEntityList().m_window);
367 #include "preferencesystem.h"
369 #include "iselection.h"
373 scene::Node* nullNode = 0;
376 class NullSelectedInstance : public scene::Instance, public Selectable
380 InstanceTypeCastTable m_casts;
384 InstanceStaticCast<NullSelectedInstance, Selectable>::install(m_casts);
386 InstanceTypeCastTable& get()
393 typedef LazyStatic<TypeCasts> StaticTypeCasts;
395 NullSelectedInstance() : Instance(scene::Path(makeReference(*nullNode)), 0, this, StaticTypeCasts::instance().get())
399 void setSelected(bool select)
401 ERROR_MESSAGE("error");
403 bool isSelected() const
409 typedef LazyStatic<NullSelectedInstance> StaticNullSelectedInstance;
412 void EntityList_Construct()
414 graph_tree_model_insert(scene_graph_get_tree_model(), StaticNullSelectedInstance::instance());
416 g_EntityList = new EntityList;
418 getEntityList().m_positionTracker.setPosition(c_default_window_pos);
420 GlobalPreferenceSystem().registerPreference("EntityInfoDlg", WindowPositionTrackerImportStringCaller(getEntityList().m_positionTracker), WindowPositionTrackerExportStringCaller(getEntityList().m_positionTracker));
422 typedef FreeCaller1<const Selectable&, EntityList_SelectionChanged> EntityListSelectionChangedCaller;
423 GlobalSelectionSystem().addSelectionChangeCallback(EntityListSelectionChangedCaller());
425 void EntityList_Destroy()
429 graph_tree_model_erase(scene_graph_get_tree_model(), StaticNullSelectedInstance::instance());