/* csgtree.c * Giram - A GPLed Modelling Program. * Copyright (C) 1999-2002 DindinX * * This program 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 2 of the License, or * (at your option) any later version. * * This program 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 this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include #include #include "giram.h" #include "tools/tool_select.h" #include "widgets/girammultihpan.h" #include "csgtree.h" #include "csg.h" #include "view.h" #include "giramobjecteditor.h" #include "giramintl.h" /*#include "pixmaps/eye.xpm" #include "pixmaps/noeye.xpm"*/ enum { SELECTED_COLUMN = 0, VISIBLE_COLUMN, NAME_COLUMN, EDITABLE_COLUMN, TYPE_COLUMN, POINTER_COLUMN, NUM_COLUMNS }; enum { TYPE_TITLE = 0, TYPE_LIGHT = 1, TYPE_OBJECT = 2, TYPE_BACKGROUND = 3, TYPE_TRANSFORM = 4 }; GtkTreeModel *csg_tree_model = NULL; GiramObjectEditor *csgtree_object_editor = NULL; /************************************************************************ * csg_tree_model_select *************************************************************************/ static gboolean csg_tree_model_select(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, ObjectStruct *object) { ObjectStruct *pointer; gtk_tree_model_get(csg_tree_model, iter, POINTER_COLUMN, &pointer, -1); if (pointer == object) { gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), iter, SELECTED_COLUMN, TRUE, -1); return TRUE; } else return FALSE; } /***************************************************************************** * CSGTreeSelect - Marks an object as selected in the CSG Tree * May be called if the CSG Tree dialog is not opened. ******************************************************************************/ void CSGTreeSelect(ObjectStruct *Object) { if (csg_tree_model) gtk_tree_model_foreach(csg_tree_model, (GtkTreeModelForeachFunc)csg_tree_model_select, Object); } /************************************************************************ * csg_tree_model_unselect *************************************************************************/ static gboolean csg_tree_model_unselect(GtkTreeModel *model, GtkTreePath *path, GtkTreeIter *iter, ObjectStruct *object) { ObjectStruct *pointer; gtk_tree_model_get(csg_tree_model, iter, POINTER_COLUMN, &pointer, -1); if (pointer == object) { gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), iter, SELECTED_COLUMN, FALSE, -1); return TRUE; } else return FALSE; } /***************************************************************************** * CSGTreeUnselect - Marks an object as not selected in the CSG Tree * May be called if the CSG Tree dialog is not opened. ******************************************************************************/ void CSGTreeUnselect(ObjectStruct *Object) { if (csg_tree_model) gtk_tree_model_foreach(csg_tree_model, (GtkTreeModelForeachFunc)csg_tree_model_unselect, Object); } /************************************************************************ * selected_toggled *************************************************************************/ static void selected_toggled(GtkCellRendererToggle *cell, gchar *path_str, gpointer data) { GtkTreeIter iter; GtkTreePath *path = gtk_tree_path_new_from_string(path_str); gboolean selected; gint type; gtk_tree_model_get_iter(csg_tree_model, &iter, path); gtk_tree_model_get(csg_tree_model, &iter, SELECTED_COLUMN, &selected, TYPE_COLUMN, &type, -1); selected = !selected; gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), &iter, SELECTED_COLUMN, selected, -1); gtk_tree_path_free(path); if (type == TYPE_OBJECT) { /* only objects can be "selected" for now. */ ObjectStruct *object; GSList *tmp_list; gtk_tree_model_get(csg_tree_model, &iter, POINTER_COLUMN, &object, -1); object->selected = selected; if (object->selected) object->frame->selection = g_list_append(object->frame->selection, object); else object->frame->selection = g_list_remove(object->frame->selection, object); for (tmp_list = object->frame->all_views ; tmp_list ; tmp_list = tmp_list->next) { ViewStruct *TmpView = tmp_list->data; gtk_widget_queue_draw(TmpView->canvas); } } } /************************************************************************ * visible_toggled *************************************************************************/ static void visible_toggled(GtkCellRendererToggle *cell, gchar *path_str, gpointer data) { GtkTreeIter iter; GtkTreePath *path = gtk_tree_path_new_from_string(path_str); gboolean visible; gint type; gtk_tree_model_get_iter(csg_tree_model, &iter, path); gtk_tree_path_free(path); gtk_tree_model_get(csg_tree_model, &iter, VISIBLE_COLUMN, &visible, TYPE_COLUMN, &type, -1); visible = !visible; gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), &iter, VISIBLE_COLUMN, visible, -1); if (type == TYPE_OBJECT) { /* only objects can be set visible/unvisible, FIXME: this should change in a near future */ ObjectStruct *object; GSList *tmp_list; gtk_tree_model_get(csg_tree_model, &iter, POINTER_COLUMN, &object, -1); object->visible = visible; for (tmp_list = object->frame->all_views ; tmp_list ; tmp_list = tmp_list->next) { ViewStruct *TmpView = tmp_list->data; gtk_widget_queue_draw(TmpView->canvas); } } } /************************************************************************ * create_recusive_csg_tree_objects *************************************************************************/ static void create_recusive_csg_tree_objects(ObjectStruct *csg_object, GtkTreeIter *iter) { GtkTreeIter child_iter; GSList *tmp_list; for (tmp_list = ((CSGStruct *)csg_object)->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) { gchar buf1[100]; ObjectStruct *TmpObject = tmp_list->data; if (TmpObject->name) strcpy(buf1, TmpObject->name); else strcpy(buf1, "unnamed"); gtk_tree_store_append(GTK_TREE_STORE(csg_tree_model), &child_iter, iter); gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), &child_iter, SELECTED_COLUMN, TmpObject->selected, VISIBLE_COLUMN, TmpObject->visible, NAME_COLUMN, buf1, EDITABLE_COLUMN, TRUE, TYPE_COLUMN, TYPE_OBJECT, POINTER_COLUMN, TmpObject, -1); if (TmpObject->Type == CSG_OBJECT) create_recusive_csg_tree_objects(TmpObject, &child_iter); } } /************************************************************************ * giram_create_tree_model *************************************************************************/ void giram_create_tree_model(FrameStruct *frame) { GtkTreeIter iter, child_iter, child_child_iter; GSList *tmp_list, *tmp_list2; /* model */ if (csg_tree_model) gtk_tree_store_clear(GTK_TREE_STORE(csg_tree_model)); else csg_tree_model = (GtkTreeModel *)gtk_tree_store_new(NUM_COLUMNS, G_TYPE_BOOLEAN, G_TYPE_BOOLEAN, G_TYPE_STRING, G_TYPE_BOOLEAN, G_TYPE_INT, G_TYPE_POINTER); /* the atmospheric (background color, skyphere, fog, etc.) */ gtk_tree_store_append(GTK_TREE_STORE(csg_tree_model), &iter, NULL); gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), &iter, SELECTED_COLUMN, FALSE, VISIBLE_COLUMN, FALSE, NAME_COLUMN, _("Atmospherics"), EDITABLE_COLUMN, FALSE, TYPE_COLUMN, TYPE_TITLE, POINTER_COLUMN, NULL, -1); /* the background color */ gtk_tree_store_append(GTK_TREE_STORE(csg_tree_model), &child_iter, &iter); gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), &child_iter, SELECTED_COLUMN, FALSE, VISIBLE_COLUMN, FALSE, NAME_COLUMN, _("background color"), EDITABLE_COLUMN, FALSE, TYPE_COLUMN, TYPE_BACKGROUND, POINTER_COLUMN, frame, -1); /* the lights */ gtk_tree_store_append(GTK_TREE_STORE(csg_tree_model), &iter, NULL); gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), &iter, SELECTED_COLUMN, FALSE, VISIBLE_COLUMN, FALSE, NAME_COLUMN, _("Lights"), EDITABLE_COLUMN, FALSE, TYPE_COLUMN, TYPE_TITLE, POINTER_COLUMN, NULL, -1); for (tmp_list = frame->all_light_sources ; tmp_list ; tmp_list = g_slist_next(tmp_list)) { gchar buf1[100]; LightSourceStruct *TmpLight = tmp_list->data; if (TmpLight->name) strcpy(buf1, TmpLight->name); else strcpy(buf1, "unnamed"); gtk_tree_store_append(GTK_TREE_STORE(csg_tree_model), &child_iter, &iter); gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), &child_iter, SELECTED_COLUMN, FALSE, VISIBLE_COLUMN, FALSE, NAME_COLUMN, buf1, EDITABLE_COLUMN, TRUE, TYPE_COLUMN, TYPE_LIGHT, POINTER_COLUMN, TmpLight, -1); } /* then, the objects */ gtk_tree_store_append(GTK_TREE_STORE(csg_tree_model), &iter, NULL); gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), &iter, SELECTED_COLUMN, FALSE, VISIBLE_COLUMN, FALSE, NAME_COLUMN, _("Objects"), EDITABLE_COLUMN, FALSE, TYPE_COLUMN, TYPE_TITLE, POINTER_COLUMN, NULL, -1); for (tmp_list = frame->all_objects ; tmp_list ; tmp_list = g_slist_next(tmp_list)) { gchar buf1[100]; ObjectStruct *TmpObject = tmp_list->data; if (TmpObject->name) strcpy(buf1, TmpObject->name); else strcpy(buf1, "unnamed"); gtk_tree_store_append(GTK_TREE_STORE(csg_tree_model), &child_iter, &iter); gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), &child_iter, SELECTED_COLUMN, TmpObject->selected, VISIBLE_COLUMN, TmpObject->visible, NAME_COLUMN, buf1, EDITABLE_COLUMN, TRUE, TYPE_COLUMN, TYPE_OBJECT, POINTER_COLUMN, TmpObject, -1); if (TmpObject->Type == CSG_OBJECT) create_recusive_csg_tree_objects(TmpObject, &child_iter); for (tmp_list2 = TmpObject->all_transforms ; tmp_list2 ; tmp_list2 = g_slist_next(tmp_list2)) { TransformationStruct *transform = tmp_list2->data; gtk_tree_store_append(GTK_TREE_STORE(csg_tree_model), &child_child_iter, &child_iter); gtk_tree_store_set(GTK_TREE_STORE(csg_tree_model), &child_child_iter, SELECTED_COLUMN, FALSE, VISIBLE_COLUMN, transform->active, NAME_COLUMN, transform->name, EDITABLE_COLUMN, FALSE, TYPE_COLUMN, TYPE_TRANSFORM, POINTER_COLUMN, transform, -1); } } } /************************************************************************ * giram_tree_view_edited_changed *************************************************************************/ static void giram_tree_view_edited_changed(GtkTreeSelection *sel) { GtkTreeModel *model; GtkTreeIter iter; gint type; ObjectStruct *pointer; if (! gtk_tree_selection_get_selected(sel, &model, &iter)) return; gtk_tree_model_get(model, &iter, POINTER_COLUMN, &pointer, TYPE_COLUMN, &type, -1); switch (type) { case TYPE_OBJECT: /* an actual object */ { ObjectStruct *object = (ObjectStruct *)pointer; giram_object_editor_set_object(csgtree_object_editor, object); } break; case TYPE_BACKGROUND: /* the background color */ { FrameStruct *frame = (FrameStruct *)pointer; giram_object_editor_set_background(csgtree_object_editor, frame->background_color); } break; case TYPE_LIGHT: /* a light source */ { LightSourceStruct *light = (LightSourceStruct *)pointer; giram_object_editor_set_lightsource(csgtree_object_editor, light); } break; case TYPE_TRANSFORM: /* a transformation */ { TransformationStruct *transformation = (TransformationStruct *)pointer; giram_object_editor_set_transformation(csgtree_object_editor, transformation); } break; default: giram_object_editor_set_object(csgtree_object_editor, NULL); } } /***************************************************************************** * giram_show_csgtree_model ******************************************************************************/ static void giram_show_csgtree_model(FrameStruct *frame) { GtkWidget *window, *scr, *tree_view, *button, *hpaned; GtkCellRenderer *renderer; gint col_offset; GtkTreeViewColumn *column; GtkTreeSelection *sel; giram_create_tree_model(frame); window = gtk_dialog_new(); button = gtk_dialog_add_button(GTK_DIALOG(window), GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE); g_signal_connect_swapped(G_OBJECT(button), "clicked", G_CALLBACK(gtk_widget_destroy), window); hpaned = giram_multihpan_new(); gtk_container_add(GTK_CONTAINER(GTK_DIALOG(window)->vbox), hpaned); scr = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scr), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); giram_multipan_add1(GIRAM_MULTIPAN(hpaned), scr); /* The view */ tree_view = gtk_tree_view_new_with_model((GtkTreeModel*)csg_tree_model); gtk_widget_set_size_request(tree_view, 200, 220); gtk_tree_view_set_rules_hint(GTK_TREE_VIEW(tree_view), TRUE); gtk_tree_view_set_headers_visible(GTK_TREE_VIEW(tree_view), FALSE); gtk_container_add(GTK_CONTAINER(scr), tree_view); /* selected column */ renderer = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(selected_toggled), csg_tree_model); col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree_view), -1, "Edited", renderer, "active", SELECTED_COLUMN, "visible", EDITABLE_COLUMN, NULL); /* visible column */ renderer = gtk_cell_renderer_toggle_new(); g_signal_connect(G_OBJECT(renderer), "toggled", G_CALLBACK(visible_toggled), csg_tree_model); col_offset = gtk_tree_view_insert_column_with_attributes(GTK_TREE_VIEW(tree_view), -1, "Visible", renderer, "active", VISIBLE_COLUMN, "visible", EDITABLE_COLUMN, NULL); /* name column */ renderer = gtk_cell_renderer_text_new (); col_offset = gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (tree_view), -1, "Names", renderer, "text", NAME_COLUMN, NULL); column = gtk_tree_view_get_column(GTK_TREE_VIEW(tree_view), col_offset - 1); gtk_tree_view_set_expander_column(GTK_TREE_VIEW(tree_view), column); gtk_tree_view_column_set_clickable(GTK_TREE_VIEW_COLUMN(column), TRUE); /* The object editor part */ csgtree_object_editor = GIRAM_OBJECT_EDITOR(giram_object_editor_new(NULL)); giram_multipan_add2(GIRAM_MULTIPAN(hpaned), GTK_WIDGET(csgtree_object_editor)); /* handle the selection */ sel = gtk_tree_view_get_selection(GTK_TREE_VIEW(tree_view)); g_signal_connect(G_OBJECT(sel), "changed", G_CALLBACK(giram_tree_view_edited_changed), NULL); gtk_widget_show_all(window); } /***************************************************************************** * ShowCSGTree ******************************************************************************/ void ShowCSGTree(GtkWidget *DrawingArea) { FrameStruct *TmpFrame; ViewStruct *view_data = NULL; if (DrawingArea) { view_data = g_object_get_data(G_OBJECT(DrawingArea), "ViewData"); } if (DrawingArea) TmpFrame = view_data->frame; else if (all_frames) TmpFrame = all_frames->data; else TmpFrame = NULL; if (TmpFrame) { giram_show_csgtree_model(TmpFrame); if (TmpFrame->all_objects) { /* by default, select the first object (if any) in the object editor */ /* ObjectStruct *object; object = TmpFrame->all_objects->data; giram_object_editor_set_object(GIRAM_OBJECT_EDITOR(goe), object); gtk_ctree_node_set_pixmap(GTK_CTREE(CSGTreeCTree), object->CSGTreeNode, 0, RightTrianglePixmap, RightTriangleMask);*/ } } }