/* Copyright (C) 2003 by Sean David Fleming sean@ivec.org 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. The GNU GPL can also be found at http://www.gnu.org */ #include #include #include #ifdef __APPLE__ #include #else #include #endif #include "gdis.h" #include "opengl.h" #include "interface.h" extern struct sysenv_pak sysenv; /***************************/ /* free a canvas structure */ /***************************/ void canvas_free(gpointer data) { struct canvas_pak *canvas = data; g_free(canvas); } /****************************/ /* schedule redraw requests */ /****************************/ void redraw_canvas(gint action) { GSList *list; struct model_pak *model; switch (action) { case SINGLE: /* data = sysenv.active_model; if (data) data->redraw = TRUE; break; */ case ALL: for (list=sysenv.mal ; list ; list=g_slist_next(list)) { model = list->data; model->redraw = TRUE; } break; } sysenv.refresh_canvas = TRUE; } /*******************/ /* configure event */ /*******************/ #define DEBUG_GL_CONFIG_EVENT 0 gint canvas_configure(GtkWidget *w, GdkEventConfigure *event, gpointer data) { gint size; GSList *list; struct model_pak *model; g_assert(w != NULL); /* store new drawing area size */ if (w->allocation.width > w->allocation.height) size = w->allocation.height; else size = w->allocation.width; sysenv.x = 0; sysenv.y = 0; sysenv.width = w->allocation.width; sysenv.height = w->allocation.height; sysenv.size = size; /* update canvases */ canvas_resize(); #if DEBUG_GL_CONFIG_EVENT printf("Relative canvas origin: (%d,%d)\n",sysenv.x,sysenv.y); printf(" Canvas dimensions: %dx%d\n",sysenv.width,sysenv.height); #endif /* update coords */ for (list=sysenv.mal ; list ; list=g_slist_next(list)) { model = list->data; model->redraw = TRUE; } /* new screen size to be saved as default */ sysenv.write_gdisrc = TRUE; return(TRUE); } /*****************/ /* expose event */ /****************/ #define DEBUG_GL_EXPOSE 0 gint canvas_expose(GtkWidget *w, GdkEventExpose *event, gpointer data) { /* gl_clear_canvas(); for (list=sysenv.mal ; list ; list=g_slist_next(list)) { model = list->data; model->redraw = TRUE; canvas = model->canvas; if (canvas->active) gl_draw(canvas, model); } */ redraw_canvas(ALL); return(TRUE); } /**********************************/ /* update the model/canvas layout */ /**********************************/ void canvas_shuffle(void) { gint c, m; GSList *clist, *mlist; struct canvas_pak *canvas; /* find active model in canvas list */ c = 0; mlist = NULL; for (clist=sysenv.canvas_list ; clist ; clist=g_slist_next(clist)) { canvas = clist->data; if (sysenv.active_model) { if (!canvas->model &&!mlist) { canvas->model = sysenv.active_model; } if (canvas->model == sysenv.active_model) { m = g_slist_index(sysenv.mal, canvas->model); if (m < c) { /* not enough prior models to display active model at current canvas poisiton */ /* start at active model */ /* TODO - start at low enough model number so that active model is displayed */ mlist = g_slist_find(sysenv.mal, sysenv.active_model); } else { /* we have enough prior models to display active model at current canvas poisiton */ mlist = g_slist_nth(sysenv.mal, m-c); } } } c++; } /* active model not in the canvas list */ if (sysenv.active_model && !mlist) { /* start at active model */ mlist = g_slist_find(sysenv.mal, sysenv.active_model); } /* fill the canvas list */ if (mlist) { for (clist=sysenv.canvas_list ; clist ; clist=g_slist_next(clist)) { canvas = clist->data; if (mlist) { canvas->model = mlist->data; mlist = g_slist_next(mlist); } else canvas->model = NULL; } } } /*****************************************************/ /* create a new canvas and place in the canvas table */ /*****************************************************/ void canvas_new(gint x, gint y, gint w, gint h) { struct canvas_pak *canvas; /* create an OpenGL capable drawing area */ canvas = g_malloc(sizeof(struct canvas_pak)); /* printf("creating canvas: %p (%d,%d) [%d x %d] \n", canvas, x, y, w, h); */ canvas->x = x; canvas->y = y; canvas->width = w; canvas->height = h; if (w > h) canvas->size = h; else canvas->size = w; canvas->active = FALSE; canvas->resize = TRUE; /* canvas->model = sysenv.active_model; */ canvas->model = NULL; sysenv.canvas_list = g_slist_prepend(sysenv.canvas_list, canvas); } /**************************************/ /* initialize the OpenGL drawing area */ /**************************************/ void canvas_init(GtkWidget *box) { /* create the drawing area */ sysenv.glarea = gtk_drawing_area_new(); gtk_widget_set_gl_capability(sysenv.glarea, sysenv.glconfig, NULL, TRUE, GDK_GL_RGBA_TYPE); gtk_widget_set_size_request(sysenv.glarea, sysenv.width, sysenv.height); gtk_box_pack_start(GTK_BOX(box), sysenv.glarea, TRUE, TRUE, 0); /* init signals */ g_signal_connect(GTK_OBJECT(sysenv.glarea), "expose_event", GTK_SIGNAL_FUNC(canvas_expose), NULL); g_signal_connect(GTK_OBJECT(sysenv.glarea), "configure_event", GTK_SIGNAL_FUNC(canvas_configure), NULL); /* TODO - what about the "realize" event??? */ g_signal_connect(GTK_OBJECT(sysenv.glarea), "motion_notify_event", GTK_SIGNAL_FUNC(gui_motion_event), NULL); g_signal_connect(GTK_OBJECT(sysenv.glarea), "button_press_event", GTK_SIGNAL_FUNC(gui_press_event), NULL); g_signal_connect(GTK_OBJECT(sysenv.glarea), "button_release_event", GTK_SIGNAL_FUNC(gui_release_event), NULL); g_signal_connect(GTK_OBJECT(sysenv.glarea), "scroll_event", GTK_SIGNAL_FUNC(gui_scroll_event), NULL); gtk_widget_set_events(GTK_WIDGET(sysenv.glarea), GDK_EXPOSURE_MASK | GDK_LEAVE_NOTIFY_MASK | GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK | GDK_SCROLL_MASK | GDK_POINTER_MOTION_MASK | GDK_POINTER_MOTION_HINT_MASK); gtk_widget_show(sysenv.glarea); } /**************************/ /* table resize primitive */ /**************************/ #define DEBUG_CANVAS_RESIZE 0 void canvas_resize(void) { gint i, j, n, rows, cols, width, height; GSList *list; struct canvas_pak *canvas; n = g_slist_length(sysenv.canvas_list); rows = cols = 1; switch (n) { case 2: rows = 1; cols = 2; break; case 3: case 4: rows = 2; cols = 2; break; } width = sysenv.width / cols; height = sysenv.height / rows; #if DEBUG_CANVAS_RESIZE printf("Splitting (%d, %d) : %d x %d\n", rows, cols, width, height); #endif list = sysenv.canvas_list; for (i=rows ; i-- ; ) { for (j=0 ; jdata; canvas->x = j*width; canvas->y = i*height; canvas->width = width; canvas->height = height; canvas->resize = TRUE; #if DEBUG_CANVAS_RESIZE printf(" - canvas (%d, %d) : [%d, %d]\n", i, j, canvas->x, canvas->y); #endif list = g_slist_next(list); } } } canvas_shuffle(); } /*******************************/ /* revert to a single viewport */ /*******************************/ void canvas_single(void) { gint i, n; struct canvas_pak *canvas; n = g_slist_length(sysenv.canvas_list); if (n > 1) { for (i=n-1 ; i-- ; ) { canvas = g_slist_nth_data(sysenv.canvas_list, i); sysenv.canvas_list = g_slist_remove(sysenv.canvas_list, canvas); } } canvas_resize(); redraw_canvas(SINGLE); } /************************************/ /* increase the number of viewports */ /************************************/ void canvas_create(void) { gint n; n = g_slist_length(sysenv.canvas_list); switch (n) { case 2: canvas_new(0, 0, 0, 0); case 1: case 0: canvas_new(0, 0, 0, 0); canvas_resize(); redraw_canvas(ALL); break; } } /************************************/ /* decrease the number of viewports */ /************************************/ void canvas_delete(void) { gint n; gpointer canvas; n = g_slist_length(sysenv.canvas_list); switch (n) { case 4: canvas = sysenv.canvas_list->data; sysenv.canvas_list = g_slist_remove(sysenv.canvas_list, canvas); canvas_free(canvas); case 2: canvas = sysenv.canvas_list->data; sysenv.canvas_list = g_slist_remove(sysenv.canvas_list, canvas); canvas_free(canvas); /* resize & redraw */ canvas_resize(); redraw_canvas(ALL); break; } } /*********************************************/ /* select model at the given canvas position */ /*********************************************/ void canvas_select(gint x, gint y) { gint ry; GSList *list; struct canvas_pak *canvas; /* height invert correction */ ry = sysenv.height - y - 1; for (list=sysenv.canvas_list ; list ; list=g_slist_next(list)) { canvas = list->data; if (x >= canvas->x && x < canvas->x+canvas->width) { if (ry >= canvas->y && ry < canvas->y+canvas->height) { if (canvas->model) { /* only select if not already active -avoid's deselecting graphs */ if (canvas->model != sysenv.active_model) tree_select_model(canvas->model); } } } } } /***********************************************/ /* get the canvas a model is drawn in (if any) */ /***********************************************/ gpointer canvas_find(struct model_pak *model) { GSList *list; struct canvas_pak *canvas; for (list=sysenv.canvas_list ; list ; list=g_slist_next(list)) { canvas = list->data; if (canvas->model == model) return(canvas); } return(NULL); }