core/vgui/impl/wx/vgui_wx_adaptor.cxx
Go to the documentation of this file.
00001 // This is core/vgui/impl/wx/vgui_wx_adaptor.cxx
00002 #include "vgui_wx_adaptor.h"
00003 //=========================================================================
00004 //:
00005 // \file
00006 // \brief  wxWidgets implementation of vgui_adaptor.
00007 //
00008 // See vgui_wx_adaptor.h for details.
00009 //=========================================================================
00010 
00011 #include "vgui_wx_menu.h"
00012 #include <vgui/vgui_macro.h>
00013 #include <vgui/vgui_popup_params.h>
00014 
00015 #include <wx/log.h>
00016 
00017 #include <wx/menu.h>
00018 #include <wx/timer.h>
00019 #include <wx/dcclient.h>
00020 
00021 #ifndef wxEventHandler               // wxWidgets-2.5.3 doesn't define this
00022 #define wxEventHandler(func) \
00023     (wxObjectEventFunction)wxStaticCastEvent(wxEventFunction, &func)
00024 #endif
00025 
00026 #include <vcl_cassert.h>
00027 #include <vcl_iostream.h>
00028 // not used? #include <vcl_map.h>
00029 
00030 //-------------------------------------------------------------------------
00031 // Private helpers - declarations.
00032 //-------------------------------------------------------------------------
00033 namespace
00034 {
00035   //: Event type for dynamic timer events.
00036   const wxEventType wxEVT_VGUI_TIMER = wxNewEventType();
00037 
00038   inline bool is_modifier(int key_code);
00039   inline vgui_modifier get_modifiers(const wxMouseEvent& e);
00040   inline vgui_modifier get_modifiers(const wxKeyEvent& e);
00041   inline vgui_event_type translate_mouse_event_type(const wxMouseEvent& e);
00042   inline vgui_button translate_mouse_button(int button);
00043   inline vgui_key translate_key(int key_code);
00044 }
00045 
00046 //-------------------------------------------------------------------------
00047 // vgui_wx_adaptor implementation - construction & destruction.
00048 //-------------------------------------------------------------------------
00049 IMPLEMENT_CLASS(vgui_wx_adaptor, wxGLCanvas)
00050 
00051 //: ***** To ensure the commands stay in scope for the lifetime of the popup.
00052 vgui_menu vgui_wx_adaptor::last_popup_;
00053 
00054 //: Constructor.
00055 vgui_wx_adaptor::vgui_wx_adaptor(wxWindow* parent,
00056                                  wxWindowID id,
00057                                  const wxPoint& pos,
00058                                  const wxSize& size,
00059                                  long style,
00060                                  const wxString& name,
00061                                  int* attributes)
00062   : wxGLCanvas(parent, id, pos, size,
00063                style|wxFULL_REPAINT_ON_RESIZE|wxBORDER_SUNKEN, name, attributes)
00064   , view_(0)
00065   , redraw_posted_(true)
00066   , overlay_redraw_posted_(true)
00067   , idle_request_posted_(false)
00068   , destroy_posted_(false)
00069 {
00070   wxLogTrace(wxTRACE_RefCount, wxT("vgui_wx_adaptor::vgui_wx_adaptor"));
00071 }
00072 
00073 //: Destructor.
00074 vgui_wx_adaptor::~vgui_wx_adaptor()
00075 {
00076   wxLogTrace(wxTRACE_RefCount, wxT("vgui_wx_adaptor::~vgui_wx_adaptor"));
00077 }
00078 
00079 //-------------------------------------------------------------------------
00080 // vgui_wx_adaptor implementation - virtual functions from vgui_adaptor.
00081 //-------------------------------------------------------------------------
00082 //: Redraw the rendering area.
00083 void vgui_wx_adaptor::post_redraw(void)
00084 {
00085   if (!redraw_posted_)
00086   {
00087     redraw_posted_ = true;
00088     invalidate_canvas();
00089   }
00090 }
00091 
00092 //: Redraws overlay buffer.
00093 void vgui_wx_adaptor::post_overlay_redraw(void)
00094 {
00095   if (!overlay_redraw_posted_)
00096   {
00097     overlay_redraw_posted_ = true;
00098     invalidate_canvas();
00099   }
00100 }
00101 
00102 //: Flags that a child requests idle processing.
00103 void vgui_wx_adaptor::post_idle_request(void)
00104 {
00105   if (!idle_request_posted_)
00106   {
00107     idle_request_posted_ = true;
00108     wxWakeUpIdle();
00109   }
00110 }
00111 
00112 
00113 //: ***** What is this for???
00114 void vgui_wx_adaptor::post_message(char const *, void const *)
00115 {
00116   assert(false);
00117 }
00118 
00119 //: Schedules destruction of parent vgui_window.
00120 void vgui_wx_adaptor::post_destroy(void)
00121 {
00122   // ***** forget about any posted redraws
00123   redraw_posted_ = false;
00124   overlay_redraw_posted_ = false;
00125 
00126   vgui_macro_report_errors;
00127 
00128   if (!destroy_posted_)
00129   {
00130     destroy_posted_ = true;
00131     Close();
00132   }
00133 
00134   //if (view_)
00135   //{
00136   //  view_->GetDocument()->DeleteAllViews();
00137   //}
00138   //else
00139   //{
00140   //  // ***** or should I call Destroy() ???
00141   //  GetParent()->Close();
00142   //}
00143   //destroy_posted_ = true;
00144 
00145   vgui_macro_report_errors;
00146 }
00147 
00148 //: Sets timer 'id' to dispatch a vgui_TIMER event every 'timeout' ms.
00149 void vgui_wx_adaptor::post_timer(float timeout, int id)
00150 {
00151   Connect(id, wxEVT_VGUI_TIMER, wxEventHandler(vgui_wx_adaptor::on_timer));
00152 }
00153 
00154 //: Stop timer 'id'.
00155 void vgui_wx_adaptor::kill_timer(int id)
00156 {
00157   Disconnect(id, wxEVT_VGUI_TIMER);
00158 }
00159 
00160 //: Swap buffers if using double buffering.
00161 void vgui_wx_adaptor::swap_buffers()
00162 {
00163   SwapBuffers();
00164 }
00165 
00166 //: Make this the current GL rendering context.
00167 void vgui_wx_adaptor::make_current()
00168 {
00169   SetCurrent();
00170 }
00171 
00172 //-------------------------------------------------------------------------
00173 // vgui_wx_adaptor implementation - event handling.
00174 //-------------------------------------------------------------------------
00175 BEGIN_EVENT_TABLE(vgui_wx_adaptor, wxGLCanvas)
00176   EVT_SIZE(vgui_wx_adaptor::on_size)
00177   EVT_PAINT(vgui_wx_adaptor::on_paint)
00178   EVT_ERASE_BACKGROUND(vgui_wx_adaptor::on_erase_background)
00179   EVT_KEY_DOWN(vgui_wx_adaptor::on_key_down)
00180   EVT_KEY_UP(vgui_wx_adaptor::on_key_up)
00181   EVT_CHAR(vgui_wx_adaptor::on_char)
00182   EVT_MOUSE_EVENTS(vgui_wx_adaptor::on_mouse_event)
00183   EVT_IDLE(vgui_wx_adaptor::on_idle)
00184   EVT_CLOSE(vgui_wx_adaptor::on_close)
00185 END_EVENT_TABLE()
00186 
00187 //: Called when canvas is resized.
00188 void vgui_wx_adaptor::on_size(wxSizeEvent& event)
00189 {
00190   wxGLCanvas::OnSize(event);
00191   dispatch_to_tableau(vgui_RESHAPE);
00192   post_redraw();
00193   Update();
00194 }
00195 
00196 //: Called when a window needs to be repainted.
00197 void vgui_wx_adaptor::on_paint(wxPaintEvent& WXUNUSED(event))
00198 {
00199   vgui_macro_report_errors;
00200   // must always be here
00201   wxPaintDC dc(this);
00202 
00203 #ifndef __WXMOTIF__
00204   if (!GetContext()) { return; }
00205 #endif
00206 
00207   SetCurrent();
00208 
00209   if (redraw_posted_ || overlay_redraw_posted_)
00210   {
00211     dispatch_to_tableau(vgui_DRAW);
00212     redraw_posted_ = false;
00213   }
00214 
00215   if (overlay_redraw_posted_)
00216   {
00217     dispatch_to_tableau(vgui_DRAW_OVERLAY);
00218     overlay_redraw_posted_ = false;
00219   }
00220 
00221   SwapBuffers();
00222   vgui_macro_report_errors;
00223 }
00224 
00225 //: Called when the background needs erasing (i.e., before repainting).
00226 void vgui_wx_adaptor::on_erase_background(wxEraseEvent& WXUNUSED(event))
00227 {
00228   vgui_macro_report_errors;
00229   // do nothing (avoids flickering in wxMSW)
00230 }
00231 
00232 //: Helper used by on_key_up/down to reduce code duplication.
00233 void vgui_wx_adaptor::on_key(vgui_event& ve, wxKeyEvent& event)
00234 {
00235   ve.origin   = this;
00236 
00237   ve.ascii_char = translate_key(event.GetKeyCode());
00238   ve.modifier = get_modifiers(event);
00239   // ***** this should be handled in vgui_event::set_key(ascii,bool)
00240   //       ve.set_key(ve.ascii_char, ve.modifier != vgui_MODIFIER_NULL)
00241   // or    ve.set_key(ve.ascii_char, ve.modifier)
00242   if (0 < ve.ascii_char && ve.ascii_char < 27 && ve.modifier_is_down(vgui_CTRL))
00243   {
00244     ve.key = static_cast<vgui_key>(ve.ascii_char + 'a' - 1);
00245   }
00246   else { ve.set_key(ve.ascii_char); }
00247 
00248 #if 0
00249   if (ve.type == vgui_KEY_PRESS)
00250   {
00251     vcl_cout << "key (wx, vgui): " << ve.key << '\t' << ve.ascii_char
00252              << '\t' << ve.modifier << vcl_endl;
00253   }
00254 #endif
00255 
00256   // ***** what should I return here?? What about if scrolled window??
00257   ve.wx = event.GetX();
00258   ve.wy = get_height() - event.GetY();
00259 
00260   // ***** what exactly goes here??
00261   ve.timestamp = 0;
00262 
00263   if (!dispatch_to_tableau(ve)) { event.Skip(); }
00264   //invalidate_canvas();
00265 }
00266 
00267 //: Called when a key is pressed.
00268 void vgui_wx_adaptor::on_key_down(wxKeyEvent& event)
00269 {
00270   // if it's a modifier event let it propagate
00271   if (is_modifier(event.GetKeyCode()))
00272   {
00273     event.Skip();
00274     return;
00275   }
00276 
00277 #if 0
00278   vcl_cout << "EVT_KEY_DOWN: " << event.GetKeyCode() << vcl_endl;
00279 #endif
00280 
00281   // save the code and let the event propagate to the on_char handler
00282   last_key_down_ = event.GetKeyCode();
00283   event.Skip();
00284 
00285   //vgui_event e(vgui_KEY_PRESS);
00286   //on_key(e, event);
00287 }
00288 
00289 //: Called when a key is released.
00290 void vgui_wx_adaptor::on_key_up(wxKeyEvent& event)
00291 {
00292   if (is_modifier(event.GetKeyCode()))
00293   {
00294     event.Skip();
00295     return;
00296   }
00297 
00298 #if 0
00299   vcl_cout << "EVT_KEY_UP  : " << event.GetKeyCode()
00300            << " (" << ascii_code_[event.GetKeyCode()] << ')' << vcl_endl;
00301 #endif
00302 
00303   // get the ascii char of the last key down with same code
00304   event.m_keyCode = ascii_code_[event.GetKeyCode()];
00305 
00306   vgui_event e(vgui_KEY_RELEASE);
00307   on_key(e, event);
00308 }
00309 
00310 //: Called when a key is pressed, but carries a translated ascii code.
00311 //
00312 // To catch this event after a key_down has been caught, call
00313 // event.skip() from the on_key_down handler. Note that the char event
00314 // is always generated after the key_down event in wxWidgets.
00315 void vgui_wx_adaptor::on_char(wxKeyEvent& event)
00316 {
00317   if (is_modifier(event.GetKeyCode()))
00318   {
00319     event.Skip();
00320     return;
00321   }
00322 
00323 #if 0
00324   vcl_cout << "EVT_CHAR    : " << last_key_down_
00325            << " (" << event.GetKeyCode() << ')' << vcl_endl;
00326 #endif
00327 
00328   // save ascii code of last on_key_down event for on_key_up to use
00329   ascii_code_[last_key_down_] = event.GetKeyCode();
00330 
00331   vgui_event e(vgui_KEY_PRESS);
00332   on_key(e, event);
00333 }
00334 
00335 //: Called for all types of mouse events (e.g., button-up, motion, etc.).
00336 void vgui_wx_adaptor::on_mouse_event(wxMouseEvent& event)
00337 {
00338   vgui_macro_report_errors;
00339   vgui_event e;
00340 
00341   e.origin   = this;
00342   e.modifier = get_modifiers(event);
00343   e.button   = translate_mouse_button(event.GetButton());
00344   e.type     = translate_mouse_event_type(event);
00345 
00346   // ***** what should I return here?? What about if scrolled window??
00347   e.wx = event.GetX();
00348   e.wy = get_height() - event.GetY();
00349 
00350   // ***** what exactly goes here??
00351   e.timestamp = 0;
00352 
00353   if ( e.modifier == mixin::popup_modifier &&
00354        e.button   == mixin::popup_button )
00355   {
00356   vgui_macro_report_errors;
00357     vgui_popup_params params;
00358     params.x = e.wx;
00359     params.y = e.wy;
00360 
00361   vgui_macro_report_errors;
00362     // ***** why can't last_popup be local??
00363     last_popup_ = get_total_popup(params);
00364 
00365   vgui_macro_report_errors;
00366     // present the popup menu
00367     vgui_wx_menu popup;
00368     wxMenu* menu = popup.create_wx_menu(last_popup_);
00369   vgui_macro_report_errors;
00370     PushEventHandler(&popup);
00371     PopupMenu(menu);
00372     PopEventHandler();
00373   vgui_macro_report_errors;
00374     delete menu;
00375 
00376   vgui_macro_report_errors;
00377     invalidate_canvas();
00378   vgui_macro_report_errors;
00379     return;
00380   }
00381 
00382   // ***** Grab Mouse (ENTER/LEAVE)
00383   if (e.button == vgui_LEFT)
00384   {
00385     if (e.type == vgui_BUTTON_DOWN)
00386     {
00387       CaptureMouse();
00388     }
00389     else if (e.type == vgui_BUTTON_UP)
00390     {
00391       ReleaseMouse();
00392     }
00393   }
00394 
00395   if (!dispatch_to_tableau(e)) { event.Skip(); }
00396   //invalidate_canvas();
00397   vgui_macro_report_errors;
00398 }
00399 
00400 //: Called when the system becomes idle.
00401 void vgui_wx_adaptor::on_idle(wxIdleEvent& event)
00402 {
00403   if (idle_request_posted_)
00404   {
00405     idle_request_posted_ = dispatch_to_tableau(vgui_IDLE);
00406     event.RequestMore(idle_request_posted_);
00407     //post_redraw();
00408     //invalidate_canvas();
00409   }
00410 
00411   event.Skip();
00412 }
00413 
00414 //: Called when the user tries to close a frame or dialog box.
00415 // The event can be generated programmatically or when the user tries to
00416 // close using the window manager (X) or system menu (Windows).
00417 void vgui_wx_adaptor::on_close(wxCloseEvent& event)
00418 {
00419   // ***** can't find error with inline_tableaus
00420   vgui_macro_report_errors;
00421   dispatch_to_tableau(vgui_DESTROY);
00422   vgui_macro_report_errors;
00423   Destroy();
00424   //GetParent()->Destroy();
00425   vgui_macro_report_errors;
00426 }
00427 
00428 //: Called at fixed intervals when using a timer.
00429 void vgui_wx_adaptor::on_timer(wxEvent& event)
00430 {
00431   vgui_event e(vgui_TIMER);
00432   e.origin = this;
00433   e.timer_id = event.GetId();
00434   dispatch_to_tableau(e);
00435 }
00436 
00437 //: Generates a wxPaintEvent for the window to be repainted.
00438 void vgui_wx_adaptor::invalidate_canvas(void)
00439 {
00440   Refresh();
00441 
00442 #if 0
00443   if (view_)
00444   {
00445     view_->GetDocument()->UpdateAllViews();
00446   }
00447   else { Refresh(); }
00448 #endif
00449 }
00450 
00451 //-------------------------------------------------------------------------
00452 // Private helpers - definitions.
00453 //-------------------------------------------------------------------------
00454 namespace
00455 {
00456   inline bool is_modifier(int key_code)
00457   {
00458     switch (key_code)
00459     {
00460     case WXK_SHIFT:
00461     case WXK_ALT:
00462     case WXK_CONTROL:
00463     //case WXK_META: // ***** which one is the meta key??
00464       return true;
00465     default:
00466       return false;
00467     }
00468   }
00469 
00470   // ***** check if design allows for multiple modifiers... if so, this needs to change
00471   inline vgui_modifier get_modifiers(const wxMouseEvent& e)
00472   {
00473     int mod = 0;
00474     if (e.ShiftDown())   { mod |= vgui_SHIFT; }
00475     if (e.AltDown())     { mod |= vgui_ALT;   }
00476 #ifdef __WXMAC__
00477     // Swap META(CMD) and CTRL on Mac because this is closer to native behavior
00478     // and CTRL-Left-Click triggers a Right-Click which interferes with some
00479     // built-in vgui controls
00480     if (e.MetaDown())     { mod |= vgui_CTRL;  }
00481     if (e.ControlDown()) { mod |= vgui_META;  }
00482 #else
00483     if (e.ControlDown()) { mod |= vgui_CTRL;  }
00484     if (e.MetaDown())    { mod |= vgui_META;  }
00485 #endif
00486     return static_cast<vgui_modifier>(mod);
00487   }
00488 
00489   // ***** check if design allows for multiple modifiers... if so, this needs to change
00490   inline vgui_modifier get_modifiers(const wxKeyEvent& e)
00491   {
00492     int mod = 0;
00493     if (e.ShiftDown())   { mod |= vgui_SHIFT; }
00494     if (e.AltDown())     { mod |= vgui_ALT;   }
00495 #ifdef __WXMAC__
00496     // Swap META(CMD) and CTRL on Mac because this is closer to native behavior
00497     // and CTRL-Left-Click triggers a Right-Click which interferes with some
00498     // built-in vgui controls
00499     if (e.MetaDown())     { mod |= vgui_CTRL;  }
00500     if (e.ControlDown()) { mod |= vgui_META;  }
00501 #else
00502     if (e.ControlDown()) { mod |= vgui_CTRL;  }
00503     if (e.MetaDown())    { mod |= vgui_META;  }
00504 #endif
00505     return static_cast<vgui_modifier>(mod);
00506   }
00507 
00508   inline vgui_event_type translate_mouse_event_type(const wxMouseEvent& e)
00509   {
00510     if (e.Moving() || e.Dragging()) { return vgui_MOTION; }
00511     else if (e.ButtonDown() || e.ButtonDClick())
00512     {
00513       return vgui_BUTTON_DOWN;
00514     }
00515     else if (e.ButtonUp()) { return vgui_BUTTON_UP; }
00516     else if (e.Entering()) { return vgui_ENTER;     }
00517     else if (e.Leaving ()) { return vgui_LEAVE;     }
00518     else if (e.GetEventType() == wxEVT_MOUSEWHEEL)
00519     {
00520       if (e.GetWheelRotation() > 0) { return vgui_WHEEL_UP; }
00521       else { return vgui_WHEEL_DOWN; }
00522     }
00523     else { return vgui_OTHER; }
00524   }
00525 
00526   inline vgui_button translate_mouse_button(int button)
00527   {
00528     switch (button)
00529     {
00530     case wxMOUSE_BTN_NONE   : return vgui_BUTTON_NULL;
00531     case wxMOUSE_BTN_LEFT   : return vgui_LEFT;
00532     case wxMOUSE_BTN_MIDDLE : return vgui_MIDDLE;
00533     case wxMOUSE_BTN_RIGHT  : return vgui_RIGHT;
00534     default:
00535       vcl_cerr << "VGUI wx Error: Unknown button identifier.\n";
00536       return vgui_BUTTON_NULL;
00537     }
00538   }
00539 
00540   inline vgui_key translate_key(int key_code)
00541   {
00542     switch (key_code)
00543     {
00544     case WXK_ESCAPE    : return vgui_ESC;
00545     case WXK_TAB       : return vgui_TAB;
00546     case WXK_RETURN    : return vgui_RETURN;
00547     case '\n'          : return vgui_NEWLINE;
00548 
00549     case WXK_F1        : return vgui_F1;
00550     case WXK_F2        : return vgui_F2;
00551     case WXK_F3        : return vgui_F3;
00552     case WXK_F4        : return vgui_F4;
00553     case WXK_F5        : return vgui_F5;
00554     case WXK_F6        : return vgui_F6;
00555     case WXK_F7        : return vgui_F7;
00556     case WXK_F8        : return vgui_F8;
00557     case WXK_F9        : return vgui_F9;
00558     case WXK_F10       : return vgui_F10;
00559     case WXK_F11       : return vgui_F11;
00560     case WXK_F12       : return vgui_F12;
00561     case WXK_LEFT      : return vgui_CURSOR_LEFT;
00562     case WXK_UP        : return vgui_CURSOR_UP;
00563     case WXK_RIGHT     : return vgui_CURSOR_RIGHT;
00564     case WXK_DOWN      : return vgui_CURSOR_DOWN;
00565     case WXK_PRIOR     : return vgui_PAGE_UP;
00566     case WXK_NEXT      : return vgui_PAGE_DOWN;
00567     //case WXK_PAGEUP    : return vgui_PAGE_UP;   // ***** ??
00568     //case WXK_PAGEDOWN  : return vgui_PAGE_DOWN; // ***** ??
00569     case WXK_HOME      : return vgui_HOME;
00570     case WXK_END       : return vgui_END;
00571     case WXK_DELETE    : return vgui_DELETE;
00572     case WXK_INSERT    : return vgui_INSERT;
00573     default:
00574       if (0 < key_code && key_code < 256) // it's an ascii code
00575       {
00576         return static_cast<vgui_key>(key_code);
00577       }
00578       else
00579       {
00580 #ifdef __WXDEBUG__
00581         vcl_cerr << "VGUI wx Error: Unknown key code.\n";
00582 #endif
00583         return vgui_KEY_NULL;
00584       }
00585     }
00586   }
00587 } // unnamed namespace