Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

glwidget.cpp

Go to the documentation of this file.
00001 /*
00002  *  Celestia GTK+ Front-End
00003  *  Copyright (C) 2005 Pat Suwalski <pat@suwalski.net>
00004  *
00005  *  This program is free software; you can redistribute it and/or modify
00006  *  it under the terms of the GNU General Public License as published by
00007  *  the Free Software Foundation; either version 2 of the License, or
00008  *  (at your option) any later version.
00009  *
00010  *  $Id: glwidget.cpp,v 1.1 2005/12/06 03:19:35 suwalski Exp $
00011  */
00012 
00013 #include <gdk/gdkkeysyms.h>
00014 #include <gtk/gtk.h>
00015 #include <gtk/gtkgl.h>
00016 
00017 #include <celestia/celestiacore.h>
00018 
00019 #include "glwidget.h"
00020 #include "actions.h"
00021 #include "common.h"
00022 
00023 
00024 /* Declarations: Callbacks */
00025 static gint glarea_idle(AppData* app);
00026 static gint glarea_configure(GtkWidget* widget, GdkEventConfigure*, AppData* app);
00027 static gint glarea_expose(GtkWidget* widget, GdkEventExpose* event, AppData* app);
00028 static gint glarea_motion_notify(GtkWidget*, GdkEventMotion* event, AppData* app);
00029 static gint glarea_mouse_scroll(GtkWidget*, GdkEventScroll* event, AppData* app);
00030 static gint glarea_button_press(GtkWidget*, GdkEventButton* event, AppData* app);
00031 static gint glarea_button_release(GtkWidget*, GdkEventButton* event, AppData* app);
00032 static gint glarea_key_press(GtkWidget* widget, GdkEventKey* event, AppData* app);
00033 static gint glarea_key_release(GtkWidget* widget, GdkEventKey* event, AppData* app);
00034 
00035 /* Declarations: Helpers */
00036 static gint glDrawFrame(AppData* app);
00037 static bool handleSpecialKey(int key, int state, bool down, AppData* app);
00038 
00039 
00040 /* ENTRY: Initialize/Bind all glArea Callbacks */
00041 void initGLCallbacks(AppData* app)
00042 {
00043         g_signal_connect(GTK_OBJECT(app->glArea), "expose_event",
00044                          G_CALLBACK(glarea_expose), app);
00045         g_signal_connect(GTK_OBJECT(app->glArea), "configure_event",
00046                          G_CALLBACK(glarea_configure), app);
00047         g_signal_connect(GTK_OBJECT(app->glArea), "button_press_event",
00048                          G_CALLBACK(glarea_button_press), app);
00049         g_signal_connect(GTK_OBJECT(app->glArea), "button_release_event",
00050                          G_CALLBACK(glarea_button_release), app);
00051         g_signal_connect(GTK_OBJECT(app->glArea), "scroll_event",
00052                          G_CALLBACK(glarea_mouse_scroll), app);
00053         g_signal_connect(GTK_OBJECT(app->glArea), "motion_notify_event",
00054                          G_CALLBACK(glarea_motion_notify), app);
00055         g_signal_connect(GTK_OBJECT(app->glArea), "key_press_event",
00056                          G_CALLBACK(glarea_key_press), app);
00057         g_signal_connect(GTK_OBJECT(app->glArea), "key_release_event",
00058                          G_CALLBACK(glarea_key_release), app);
00059         
00060         /* Main call to execute redraw during GTK main loop */
00061         g_idle_add((GSourceFunc)glarea_idle, app);
00062 
00063 }
00064 
00065 
00066 /* CALLBACK: GL Function for main update (in GTK idle loop) */
00067 static gint glarea_idle(AppData* app)
00068 {
00069         app->core->tick();
00070         return glDrawFrame(app);
00071 }
00072 
00073 
00074 /* CALLBACK: GL Function for event "configure_event" */
00075 static gint glarea_configure(GtkWidget* widget, GdkEventConfigure*, AppData* app)
00076 {
00077         GdkGLContext *glcontext = gtk_widget_get_gl_context (widget);
00078         GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable (widget);
00079 
00080         if (!gdk_gl_drawable_gl_begin (gldrawable, glcontext))
00081                 return FALSE;
00082 
00083         app->core->resize(widget->allocation.width, widget->allocation.height);
00084 
00085         /* GConf changes only saved upon exit, since caused a lot of CPU activity
00086          * while saving intermediate steps. */
00087 
00088         gdk_gl_drawable_gl_end (gldrawable);
00089         return TRUE;
00090 }
00091 
00092 
00093 /* CALLBACK: GL Function for event "expose_event" */
00094 static gint glarea_expose(GtkWidget*, GdkEventExpose* event, AppData* app)
00095 {
00096         /* Draw only the last expose */
00097         if (event->count > 0)
00098                 return TRUE;
00099 
00100         /* Redraw -- draw checks are made in function */
00101         return glDrawFrame(app);
00102 }
00103 
00104 
00105 /* CALLBACK: GL Function for event "motion_notify_event" */
00106 static gint glarea_motion_notify(GtkWidget*, GdkEventMotion* event, AppData* app)
00107 {
00108         int x = (int) event->x;
00109         int y = (int) event->y;
00110 
00111         int buttons = 0;
00112         if ((event->state & GDK_BUTTON1_MASK) != 0)
00113                 buttons |= CelestiaCore::LeftButton;
00114         if ((event->state & GDK_BUTTON2_MASK) != 0)
00115                 buttons |= CelestiaCore::MiddleButton;
00116         if ((event->state & GDK_BUTTON3_MASK) != 0)
00117                 buttons |= CelestiaCore::RightButton;
00118         if ((event->state & GDK_SHIFT_MASK) != 0)
00119                 buttons |= CelestiaCore::ShiftKey;
00120         if ((event->state & GDK_CONTROL_MASK) != 0)
00121                 buttons |= CelestiaCore::ControlKey;
00122 
00123         app->core->mouseMove(x - app->lastX, y - app->lastY, buttons);
00124 
00125         app->lastX = x;
00126         app->lastY = y;
00127 
00128         return TRUE;
00129 }
00130 
00131 
00132 /* CALLBACK: GL Function for event "scroll_event" */
00133 static gint glarea_mouse_scroll(GtkWidget*, GdkEventScroll* event, AppData* app)
00134 {
00135         if (event->direction == GDK_SCROLL_UP)
00136                 app->core->mouseWheel(-1.0f, 0);
00137         else 
00138                 app->core->mouseWheel(1.0f, 0);
00139 
00140         return TRUE;
00141 }
00142 
00143 
00144 /* CALLBACK: GL Function for event "button_press_event" */
00145 static gint glarea_button_press(GtkWidget*, GdkEventButton* event, AppData* app)
00146 {
00147         app->lastX = (int) event->x;
00148         app->lastY = (int) event->y;
00149 
00150         if (event->button == 1)
00151                 app->core->mouseButtonDown(event->x, event->y, CelestiaCore::LeftButton);
00152         else if (event->button == 2)
00153                 app->core->mouseButtonDown(event->x, event->y, CelestiaCore::MiddleButton);
00154         else if (event->button == 3)
00155                 app->core->mouseButtonDown(event->x, event->y, CelestiaCore::RightButton);
00156 
00157         return TRUE;
00158 }
00159 
00160 
00161 /* CALLBACK: GL Function for event "button_release_event" */
00162 static gint glarea_button_release(GtkWidget*, GdkEventButton* event, AppData* app)
00163 {
00164         app->lastX = (int) event->x;
00165         app->lastY = (int) event->y;
00166 
00167         if (event->button == 1)
00168                 app->core->mouseButtonUp(event->x, event->y, CelestiaCore::LeftButton);
00169         else if (event->button == 2)
00170                 app->core->mouseButtonUp(event->x, event->y, CelestiaCore::MiddleButton);
00171         else if (event->button == 3)
00172                 app->core->mouseButtonUp(event->x, event->y, CelestiaCore::RightButton);
00173 
00174         return TRUE;
00175 }
00176 
00177 
00178 /* CALLBACK: GL Function for event "key_press_event" */
00179 static gint glarea_key_press(GtkWidget* widget, GdkEventKey* event, AppData* app)
00180 {
00181         gtk_signal_emit_stop_by_name(GTK_OBJECT(widget),"key_press_event");
00182 
00183         switch (event->keyval)
00184         {
00185                 case GDK_Escape:
00186                         app->core->charEntered('\033');
00187                         break;
00188                 case GDK_BackSpace:
00189                         app->core->charEntered('\b');
00190                         break;
00191                 case GDK_Tab:
00192                         /* Tab has to be handled specially because keyDown and keyUp
00193                          * do not trigger auto-completion. */
00194                         app->core->charEntered(event->keyval);
00195                         break;
00196                 case GDK_ISO_Left_Tab:
00197                         /* This is what Celestia calls BackTab */
00198                         app->core->charEntered(CelestiaCore::Key_BackTab);
00199                         break;
00200                 /* Temporary until galaxy brightness added as GtkAction */
00201                 case GDK_bracketleft:
00202                         app->core->charEntered('(');
00203                         break;
00204                 case GDK_bracketright:
00205                         app->core->charEntered(')');
00206                         break;
00207                 default:
00208                         if (!handleSpecialKey(event->keyval, event->state, true, app))
00209                         {
00210                                 if ((event->string != NULL) && (*(event->string)))
00211                                 {
00212                                         /* See if our key accelerators will handle this event. */
00213                                         if((!app->core->getTextEnterMode()) && gtk_accel_groups_activate (G_OBJECT (app->mainWindow), event->keyval, GDK_SHIFT_MASK))
00214                                                 return TRUE;
00215 
00216                                         char* s = event->string;
00217 
00218                                         while (*s != '\0')
00219                                         {
00220                                                 char c = *s++;
00221                                                 app->core->charEntered(c);
00222                                         }
00223                                 }
00224                         }
00225                         if (event->state & GDK_MOD1_MASK)
00226                                 return FALSE;
00227         }
00228 
00229         return TRUE;
00230 }
00231 
00232 
00233 /* CALLBACK: GL Function for event "key_release_event" */
00234 static gint glarea_key_release(GtkWidget* widget, GdkEventKey* event, AppData* app)
00235 {
00236         gtk_signal_emit_stop_by_name(GTK_OBJECT(widget),"key_release_event");
00237         return handleSpecialKey(event->keyval, event->state, false, app);
00238 }
00239 
00240 
00241 /* HELPER: GL Common Draw function.
00242  *         If everything checks out, call appCore->draw() */
00243 static gint glDrawFrame(AppData* app)
00244 {
00245         GdkGLContext *glcontext = gtk_widget_get_gl_context(app->glArea);
00246         GdkGLDrawable *gldrawable = gtk_widget_get_gl_drawable(app->glArea);
00247 
00248         if (!gdk_gl_drawable_gl_begin(gldrawable, glcontext))
00249                 return FALSE;
00250 
00251         if (app->bReady)
00252         {
00253                 app->core->draw();
00254                 gdk_gl_drawable_swap_buffers(GDK_GL_DRAWABLE(gldrawable));
00255         }
00256 
00257         gdk_gl_drawable_gl_end(gldrawable);
00258         return TRUE;
00259 }
00260 
00261 
00262 /* HELPER: Lookup function for keypress-action. Any key that is not part of
00263  *         the menu system must be listed here. */
00264 static bool handleSpecialKey(int key, int state, bool down, AppData* app)
00265 {
00266         int k = -1;
00267 
00268         switch (key)
00269         {
00270                 case GDK_Up:
00271                         k = CelestiaCore::Key_Up;
00272                         break;
00273                 case GDK_Down:
00274                         k = CelestiaCore::Key_Down;
00275                         break;
00276                 case GDK_Left:
00277                         k = CelestiaCore::Key_Left;
00278                         break;
00279                 case GDK_Right:
00280                         k = CelestiaCore::Key_Right;
00281                         break;
00282                 case GDK_Home:
00283                         k = CelestiaCore::Key_Home;
00284                         break;
00285                 case GDK_End:
00286                         k = CelestiaCore::Key_End;
00287                         break;
00288                 case GDK_F1:
00289                         k = CelestiaCore::Key_F1;
00290                         break;
00291                 case GDK_F2:
00292                         k = CelestiaCore::Key_F2;
00293                         break;
00294                 case GDK_F3:
00295                         k = CelestiaCore::Key_F3;
00296                         break;
00297                 case GDK_F4:
00298                         k = CelestiaCore::Key_F4;
00299                         break;
00300                 case GDK_F5:
00301                         k = CelestiaCore::Key_F5;
00302                         break;
00303                 case GDK_F6:
00304                         k = CelestiaCore::Key_F6;
00305                         break;
00306                 case GDK_F7:
00307                         k = CelestiaCore::Key_F7;
00308                         break;
00309                 case GDK_F10:
00310                         if (down) actionCaptureImage(NULL, app);
00311                         break;
00312                 case GDK_KP_Insert:
00313                 case GDK_KP_0:
00314                         k = CelestiaCore::Key_NumPad0;
00315                         break;
00316                 case GDK_KP_End:
00317                 case GDK_KP_1:
00318                         k = CelestiaCore::Key_NumPad1;
00319                         break;
00320                 case  GDK_KP_Down:
00321                 case GDK_KP_2:
00322                         k = CelestiaCore::Key_NumPad2;
00323                         break;
00324                 case GDK_KP_Next:
00325                 case GDK_KP_3:
00326                         k = CelestiaCore::Key_NumPad3;
00327                         break;
00328                 case GDK_KP_Left:
00329                 case GDK_KP_4:
00330                         k = CelestiaCore::Key_NumPad4;
00331                         break;
00332                 case GDK_KP_Begin:
00333                 case GDK_KP_5:
00334                         k = CelestiaCore::Key_NumPad5;
00335                         break;
00336                 case GDK_KP_Right:
00337                 case GDK_KP_6:
00338                         k = CelestiaCore::Key_NumPad6;
00339                         break;
00340                 case GDK_KP_Home:
00341                 case GDK_KP_7:
00342                         k = CelestiaCore::Key_NumPad7;
00343                         break;
00344                 case GDK_KP_Up:
00345                 case GDK_KP_8:
00346                         k = CelestiaCore::Key_NumPad8;
00347                         break;
00348                 case GDK_KP_Prior:
00349                 case GDK_KP_9:
00350                         k = CelestiaCore::Key_NumPad9;
00351                         break;
00352                 case GDK_A:
00353                 case GDK_a:
00354                         k = 'A';
00355                         break;
00356                 case GDK_Z:
00357                 case GDK_z:
00358                         k = 'Z';
00359                         break;
00360         }
00361 
00362         if (k >= 0)
00363         {
00364                 if (down)
00365                         app->core->keyDown(k, (state & GDK_SHIFT_MASK) 
00366                                            ? CelestiaCore::ShiftKey 
00367                                            : 0);
00368                 else
00369                         app->core->keyUp(k);
00370                 return (k < 'A' || k > 'Z');
00371         }
00372         else
00373         {
00374                 return false;
00375         }
00376 }

Generated on Sat Jan 14 22:30:30 2006 for Celestia by  doxygen 1.4.1