00001
00002 #include "vgui_mfc_adaptor.h"
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016 #include <vcl_iostream.h>
00017 #include <vcl_cstring.h>
00018
00019 #include <vgui/vgui_gl.h>
00020 #include <vgui/vgui_event.h>
00021 #include <vgui/vgui_popup_params.h>
00022 #include <vgui/vgui_macro.h>
00023 #include <vgui/impl/mfc/vgui_mfc_utils.h>
00024 #include <vgui/impl/mfc/vgui_mfc_mainfrm.h>
00025
00026 static bool debug = false;
00027 extern bool vgui_mfc_use_bitmap;
00028
00029
00030
00031 vgui_menu vgui_mfc_adaptor::last_popup;
00032 IMPLEMENT_DYNCREATE(vgui_mfc_adaptor, CView)
00033
00034
00035
00036 vgui_mfc_adaptor::vgui_mfc_adaptor( )
00037 : m_pDC(0), m_pDC_default_bitmap(0),
00038 m_pDC_aux(0), m_pDC_aux_default_bitmap(0),
00039 win_(0),
00040 redraw_posted_(true),
00041 overlay_redraw_posted_(true),
00042 idle_request_posted_(false)
00043 {
00044 if (vgui_mfc_use_bitmap)
00045
00046
00047 set_double_buffering(false);
00048
00049
00050 m_pCWnd = 0;
00051 hOldDC = 0;
00052 hOldRC = 0;
00053 }
00054
00055
00056
00057
00058 vgui_mfc_adaptor::~vgui_mfc_adaptor()
00059 {
00060 CView::OnDestroy();
00061
00062
00063 if (FALSE == ::wglMakeCurrent(hOldDC, hOldRC))
00064 ::AfxMessageBox("wglMakeCurrent failed" );
00065
00066
00067 if ( m_hRC && (FALSE == ::wglDeleteContext( m_hRC )) )
00068 {
00069 ::AfxMessageBox("wglDeleteContext failed.");
00070 }
00071
00072
00073 HDC m_hgldc = ::GetDC(m_hWnd);
00074 ::ReleaseDC(m_hWnd, m_hgldc);
00075
00076
00077 if ( m_pDC )
00078 {
00079 if ( m_pDC_default_bitmap )
00080 {
00081 HBITMAP hBmp = (HBITMAP)::SelectObject( m_pDC->GetSafeHdc(), m_pDC_default_bitmap );
00082 if (hBmp == 0)
00083 ::AfxMessageBox("SelectObject with old HBITMAP failed.");
00084 else
00085 ::DeleteObject(hBmp);
00086 }
00087 delete m_pDC;
00088 }
00089 if ( m_pDC_aux )
00090 {
00091 if ( m_pDC_aux_default_bitmap )
00092 {
00093 HBITMAP hBmp = (HBITMAP)::SelectObject( m_pDC_aux->GetSafeHdc(), m_pDC_aux_default_bitmap );
00094 if (hBmp == 0)
00095 ::AfxMessageBox("SelectObject with old HBITMAP failed.");
00096 else
00097 ::DeleteObject(hBmp);
00098 }
00099 delete m_pDC_aux;
00100 }
00101 }
00102
00103 BEGIN_MESSAGE_MAP(vgui_mfc_adaptor, CView)
00104 ON_WM_CREATE()
00105 ON_WM_DESTROY()
00106 ON_WM_ERASEBKGND()
00107 ON_WM_SIZE()
00108 ON_WM_KEYDOWN()
00109 ON_WM_KEYUP()
00110 ON_WM_LBUTTONDOWN()
00111 ON_WM_LBUTTONUP()
00112 ON_WM_MOUSEMOVE()
00113 ON_WM_RBUTTONDOWN()
00114 ON_WM_RBUTTONUP()
00115 ON_WM_MOUSEWHEEL()
00116 ON_WM_MBUTTONDOWN()
00117 ON_WM_MBUTTONUP()
00118 ON_WM_PAINT()
00119 END_MESSAGE_MAP()
00120
00121
00122
00123
00124
00125
00126 void vgui_mfc_adaptor::post_overlay_redraw()
00127 {
00128 if (!overlay_redraw_posted_)
00129 {
00130 CWnd* wnd;
00131 if (m_pCWnd != 0)
00132 wnd = m_pCWnd;
00133 else
00134 wnd = AfxGetApp()->GetMainWnd();
00135 if (wnd)
00136 wnd->Invalidate(FALSE);
00137 }
00138 overlay_redraw_posted_ = true;
00139 }
00140
00141
00142 void vgui_mfc_adaptor::post_redraw()
00143 {
00144 if (!redraw_posted_)
00145 {
00146
00147 CWnd* wnd;
00148 if (m_pCWnd != 0)
00149 wnd = m_pCWnd;
00150 else
00151 wnd = AfxGetApp()->GetMainWnd();
00152 if (wnd)
00153 wnd->Invalidate(FALSE);
00154 }
00155 redraw_posted_ = true;
00156 }
00157
00158
00159 void vgui_mfc_adaptor::make_current()
00160 {
00161 ::wglMakeCurrent( m_pDC->GetSafeHdc(), m_hRC );
00162 }
00163
00164
00165 void vgui_mfc_adaptor::swap_buffers()
00166 {
00167 if ( !vgui_mfc_use_bitmap )
00168 SwapBuffers(m_pDC->m_hDC);
00169 }
00170
00171
00172 void vgui_mfc_adaptor::set_default_popup(vgui_menu)
00173 {
00174 vcl_cerr << "vgui_mfc_adaptor::set_default_popup\n";
00175 }
00176
00177
00178 vgui_menu vgui_mfc_adaptor::get_popup()
00179 {
00180 vcl_cerr<< "vgui_mfc_adaptor::get_popup\n";
00181 return vgui_menu();
00182 }
00183
00184
00185
00186
00187 void vgui_mfc_adaptor::setup_adaptor(CWnd* this_cwnd, HDC oldDC, HGLRC oldContext)
00188 {
00189 m_pCWnd = this_cwnd;
00190 hOldDC = oldDC;
00191 hOldRC = oldContext;
00192 }
00193
00194 #ifdef _DEBUG
00195 void vgui_mfc_adaptor::AssertValid() const
00196 {
00197 CView::AssertValid();
00198 }
00199
00200 void vgui_mfc_adaptor::Dump(CDumpContext& dc) const
00201 {
00202 CView::Dump(dc);
00203 }
00204 #endif //_DEBUG
00205
00206
00207 BOOL vgui_mfc_adaptor::PreCreateWindow(CREATESTRUCT& cs)
00208 {
00209
00210
00211
00212
00213
00214 cs.style |= WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
00215
00216 return CView::PreCreateWindow(cs);
00217 }
00218
00219
00220
00221
00222 int vgui_mfc_adaptor::OnCreate(LPCREATESTRUCT lpCreateStruct)
00223 {
00224 if (CView::OnCreate(lpCreateStruct) == -1)
00225 return -1;
00226
00227
00228
00229 if (vgui_mfc_use_bitmap) {
00230 create_bitmap( 1, 1, m_pDC, m_pDC_default_bitmap );
00231 create_bitmap( 1, 1, m_pDC_aux, m_pDC_aux_default_bitmap );
00232 set_double_buffering(false);
00233 } else {
00234 m_pDC = new CClientDC(this);
00235 }
00236
00237 if ( NULL == m_pDC )
00238 {
00239 ::AfxMessageBox("Couldn't get a valid DC.");
00240 return FALSE;
00241 }
00242
00243 if ( vgui_mfc_use_bitmap )
00244 m_hRC = setup_for_gl( m_pDC,
00245 PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL );
00246 else
00247 m_hRC = setup_for_gl( m_pDC,
00248 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER );
00249
00250 post_redraw();
00251
00252 return 0;
00253 }
00254
00255
00256 HGLRC vgui_mfc_adaptor::setup_for_gl( CDC* pDC, DWORD dwFlags )
00257 {
00258 PIXELFORMATDESCRIPTOR pfd;
00259 ZeroMemory( &pfd, sizeof( pfd ) );
00260 pfd.nSize = sizeof( pfd );
00261 pfd.nVersion = 1;
00262 pfd.dwFlags = dwFlags;
00263 pfd.iPixelType = PFD_TYPE_RGBA;
00264 pfd.cColorBits = 24;
00265 pfd.cDepthBits = 16;
00266 pfd.iLayerType = PFD_MAIN_PLANE;
00267
00268 int pixelformat = ChoosePixelFormat( pDC->GetSafeHdc(), &pfd );
00269
00270 if (0 == pixelformat) {
00271 ::AfxMessageBox("ChoosePixelFormat failed.");
00272 vcl_cerr<<"Error code:"<<GetLastError();
00273 return 0;
00274 }
00275 if ( FALSE == SetPixelFormat( pDC->GetSafeHdc(), pixelformat, &pfd ) )
00276 {
00277 AfxMessageBox("SetPixelFormat failed.");
00278 vcl_cerr<<"Error code:"<<GetLastError();
00279 return 0;
00280 }
00281
00282 HGLRC glrc = wglCreateContext( pDC->GetSafeHdc() );
00283 if ( 0 == glrc )
00284 {
00285 AfxMessageBox("wglCreateContext failed.");
00286 return 0;
00287 }
00288
00289 if ( FALSE == wglMakeCurrent( pDC->GetSafeHdc(), glrc ) )
00290 {
00291 AfxMessageBox("wglMakeCurrent failed.");
00292 return 0;
00293 }
00294
00295
00296 glClearColor( 0.0f, 0.0f, 0.0f, 0.0f );
00297
00298 glClearDepth( 1.0f );
00299
00300 glEnable( GL_DEPTH_TEST );
00301
00302 vgui_macro_report_errors;
00303
00304 return glrc;
00305 }
00306
00307
00308 void vgui_mfc_adaptor::create_bitmap( int cx, int cy,
00309 CDC*& pDC,
00310 HBITMAP& defaultBitmapForDC )
00311 {
00312 BITMAPINFOHEADER bih;
00313 ZeroMemory( &bih, sizeof(bih) );
00314
00315 bih.biSize = sizeof(bih);
00316 bih.biWidth = cx;
00317 bih.biHeight = cy;
00318 bih.biPlanes = 1;
00319 bih.biBitCount = 24;
00320 bih.biCompression = BI_RGB;
00321
00322 if ( !pDC ){
00323 pDC = new CDC();
00324 pDC->CreateCompatibleDC(NULL);
00325 }
00326
00327 void *buffer;
00328 HBITMAP hbmp = CreateDIBSection( pDC->GetSafeHdc(),
00329 (BITMAPINFO *)&bih,
00330 DIB_RGB_COLORS,
00331 &buffer,
00332 NULL,
00333 0 );
00334 if ( !hbmp ) {
00335 AfxMessageBox( "Failed to create bitmap" );
00336 return;
00337 }
00338 pDC->SetStretchBltMode(COLORONCOLOR);
00339 HBITMAP old_hbmp = (HBITMAP)SelectObject( pDC->GetSafeHdc(), hbmp );
00340 if (old_hbmp == 0)
00341 {
00342 ::AfxMessageBox( "Failed to select bitmap into DC" );
00343 return;
00344 }
00345
00346 if (defaultBitmapForDC == 0)
00347 defaultBitmapForDC = old_hbmp;
00348 else
00349 if ( !DeleteObject(old_hbmp) )
00350 {
00351 ::AfxMessageBox( "Failed to delete old bitmap" );
00352 return;
00353 }
00354 }
00355
00356
00357
00358 void vgui_mfc_adaptor::OnDestroy()
00359 {
00360
00361
00362 }
00363
00364
00365
00366 BOOL vgui_mfc_adaptor::OnEraseBkgnd(CDC* pDC)
00367 {
00368
00369 return TRUE;
00370 }
00371
00372
00373 void vgui_mfc_adaptor::service_redraws()
00374 {
00375 if ( redraw_posted_ )
00376 {
00377 vgui_macro_report_errors;
00378 this->make_current();
00379 dispatch_to_tableau(vgui_event(vgui_DRAW));
00380 vgui_macro_report_errors;
00381 redraw_posted_ = false;
00382 aux_dc_valid_ = false;
00383 }
00384
00385 if ( overlay_redraw_posted_ )
00386 {
00387 this->make_current();
00388
00389 if ( vgui_mfc_use_bitmap )
00390 {
00391 if ( aux_dc_valid_ ) {
00392
00393 m_pDC->BitBlt( 0, 0, m_width, m_height, m_pDC_aux, 0, 0, SRCCOPY );
00394 } else {
00395
00396 m_pDC_aux->BitBlt( 0, 0, m_width, m_height, m_pDC, 0, 0, SRCCOPY );
00397 aux_dc_valid_ = true;
00398 }
00399 }
00400 else
00401 {
00402
00403
00404
00405 if ( aux_dc_valid_ ) {
00406
00407 dispatch_to_tableau( vgui_event(vgui_DRAW) );
00408 } else {
00409
00410 aux_dc_valid_ = true;
00411 }
00412 }
00413
00414 vgui_macro_report_errors;
00415 dispatch_to_tableau(vgui_event(vgui_DRAW_OVERLAY));
00416 vgui_macro_report_errors;
00417
00418 overlay_redraw_posted_ = false;
00419 }
00420
00421 if ( vgui_mfc_use_bitmap )
00422 {
00423 CWnd* wnd;
00424 if (m_pCWnd)
00425 wnd = m_pCWnd;
00426 else {
00427 CWinApp* ap = AfxGetApp();
00428 if (ap)
00429 wnd = ap->GetMainWnd();
00430 else return;
00431 }
00432 CDC *win_dc = wnd->GetDC();
00433 RECT r;
00434 wnd->GetClientRect(&r);
00435 win_dc->BitBlt(0,0,r.right,r.bottom,m_pDC,0,0,SRCCOPY);
00436 wnd->ReleaseDC(win_dc);
00437 }
00438
00439 swap_buffers();
00440 }
00441
00442
00443 void vgui_mfc_adaptor::post_timer(float tm,int id)
00444 {
00445 CWnd* wnd;
00446 if (m_pCWnd)
00447 wnd = m_pCWnd;
00448 else
00449 wnd = AfxGetApp()->GetMainWnd();
00450 wnd->SetTimer(id,tm,NULL);
00451 }
00452
00453
00454 void vgui_mfc_adaptor::kill_timer(int id)
00455 {
00456 CWnd* wnd;
00457 if (m_pCWnd)
00458 wnd = m_pCWnd;
00459 else
00460 wnd = AfxGetApp()->GetMainWnd();
00461 wnd->KillTimer(id);
00462 }
00463
00464
00465 void vgui_mfc_adaptor::OnDraw(CDC* pDC)
00466 {
00467 if (debug)
00468 vcl_cerr << "OnDraw\n";
00469
00470
00471 service_redraws();
00472
00473 }
00474
00475
00476 void vgui_mfc_adaptor::draw()
00477 {
00478 post_redraw();
00479 service_redraws();
00480 }
00481
00482 bool vgui_mfc_adaptor::do_idle()
00483 {
00484 if ( idle_request_posted_ )
00485 idle_request_posted_ = dispatch_to_tableau( vgui_event( vgui_IDLE ) );
00486 return idle_request_posted_;
00487 }
00488
00489
00490
00491 void vgui_mfc_adaptor::OnPaint()
00492 {
00493 CView::OnPaint();
00494 }
00495
00496
00497 void vgui_mfc_adaptor::OnSize(UINT nType, int cx, int cy)
00498 {
00499 CView::OnSize(nType, cx, cy);
00500
00501 m_width = cx;
00502 m_height = cy;
00503
00504 if ( cx != 0 && cy != 0 && vgui_mfc_use_bitmap )
00505 {
00506
00507
00508 create_bitmap( cx, cy, m_pDC, m_pDC_default_bitmap );
00509 m_hRC = setup_for_gl( m_pDC,
00510 PFD_DRAW_TO_BITMAP | PFD_SUPPORT_OPENGL );
00511 create_bitmap( cx, cy, m_pDC_aux, m_pDC_aux_default_bitmap );
00512 }
00513 dispatch_to_tableau(vgui_RESHAPE);
00514 post_redraw();
00515 }
00516
00517
00518 void mfc_key(UINT nChar, UINT nFlags, int *the_key, int *the_ascii_char)
00519 {
00520 if (nFlags & 256)
00521 {
00522
00523 switch (nChar)
00524 {
00525 case VK_NEXT:
00526 *the_key = vgui_PAGE_DOWN;
00527 *the_ascii_char = vgui_PAGE_DOWN;
00528 return;
00529 case VK_PRIOR:
00530 *the_key = vgui_PAGE_UP;
00531 *the_ascii_char = vgui_PAGE_UP;
00532 return;
00533 case VK_HOME:
00534 *the_key = vgui_HOME;
00535 *the_ascii_char = vgui_HOME;
00536 return;
00537 case VK_END:
00538 *the_key = vgui_END;
00539 *the_ascii_char = vgui_END;
00540 return;
00541 case VK_LEFT:
00542 *the_key = vgui_CURSOR_LEFT;
00543 *the_ascii_char = vgui_CURSOR_LEFT;
00544 return;
00545 case VK_UP:
00546 *the_key = vgui_CURSOR_UP;
00547 *the_ascii_char = vgui_CURSOR_UP;
00548 return;
00549 case VK_RIGHT:
00550 *the_key = vgui_CURSOR_RIGHT;
00551 *the_ascii_char = vgui_CURSOR_RIGHT;
00552 return;
00553 case VK_DOWN:
00554 *the_key = vgui_CURSOR_DOWN;
00555 *the_ascii_char = vgui_CURSOR_DOWN;
00556 return;
00557 default:
00558 *the_key = vgui_key(0);
00559 *the_ascii_char = vgui_key(0);
00560 return;
00561 }
00562 }
00563 else if (nChar >= VK_F1 && nChar <= VK_F12)
00564 {
00565 *the_key = *the_ascii_char = vgui_F1 + (nChar - VK_F1);
00566 }
00567 else
00568 {
00569 unsigned short buf[1024];
00570 unsigned char lpKeyState[256];
00571 vcl_memset(lpKeyState, 0, 256);
00572 vcl_memset(buf, 0, 256);
00573
00574 int is_ok = ToAscii(nChar, nFlags & 0xff, lpKeyState, buf, 0);
00575 if (is_ok == 1)
00576 *the_key = buf[0];
00577 else
00578 *the_key = nChar;
00579
00580
00581 lpKeyState[VK_SHIFT] = GetKeyState(VK_SHIFT);
00582 lpKeyState[VK_CONTROL] = GetKeyState(VK_CONTROL);
00583
00584 is_ok = ToAscii(nChar, nFlags & 0xff, lpKeyState, buf, 0);
00585 if (is_ok == 1)
00586 *the_ascii_char = buf[0];
00587 else
00588 *the_ascii_char = nChar;
00589 }
00590 }
00591
00592
00593 vgui_event vgui_mfc_adaptor::generate_vgui_event(UINT nChar, UINT nRepCnt, UINT nFlags, vgui_event_type evttype)
00594 {
00595 vgui_event evt(evttype);
00596 if (GetKeyState(VK_SHIFT) & 0x8000)
00597 evt.modifier = vgui_SHIFT;
00598 if (GetKeyState(VK_CONTROL) & 0x8000)
00599 evt.modifier = vgui_CTRL;
00600 if (GetKeyState(VK_MENU) & 0x8000)
00601 evt.modifier = vgui_ALT;
00602
00603
00604
00605 int the_key, the_ascii_char;
00606 mfc_key(nChar, nFlags, &the_key, &the_ascii_char);
00607 evt.set_key( vgui_key(the_key) );
00608 evt.ascii_char = vgui_key(the_ascii_char);
00609 return evt;
00610 }
00611
00612
00613 void vgui_mfc_adaptor::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
00614 {
00615
00616 if (nChar == VK_SHIFT || nChar == VK_CONTROL)
00617 return;
00618
00619 dispatch_to_tableau(generate_vgui_event(nChar, nRepCnt, nFlags, vgui_KEY_PRESS));
00620 service_redraws();
00621 }
00622
00623
00624 void vgui_mfc_adaptor::OnKeyUp(UINT nChar, UINT nRepCnt, UINT nFlags)
00625 {
00626
00627 if (nChar == VK_SHIFT || nChar == VK_CONTROL)
00628 return;
00629
00630 dispatch_to_tableau(generate_vgui_event(nChar, nRepCnt, nFlags, vgui_KEY_RELEASE));
00631 service_redraws();
00632 }
00633
00634
00635 void vgui_mfc_adaptor::domouse(vgui_event_type et, UINT nFlags, CPoint point, vgui_button b)
00636 {
00637 #if 0
00638 vcl_cerr <<"vgui_mfc_adaptor::domouse: wo = "<< point.x<<", "<< point.y<<'\n';
00639 #endif
00640
00641
00642 point.x += 2;
00643 point.y += 2;
00644
00645
00646 vgui_event e(et);
00647
00648 e.button = b;
00649 if (nFlags & MK_LBUTTON) e.button = vgui_LEFT;
00650 if (nFlags & MK_MBUTTON) e.button = vgui_MIDDLE;
00651 if (nFlags & MK_RBUTTON) e.button = vgui_RIGHT;
00652 if (nFlags & MK_SHIFT) e.modifier = vgui_modifier((int)e.modifier | vgui_SHIFT);
00653 if (nFlags & MK_CONTROL) e.modifier = vgui_modifier((int)e.modifier | vgui_CTRL);
00654 e.wx = point.x;
00655 e.wy = m_height - point.y;
00656
00657 if (e.modifier == mixin::popup_modifier && e.button == mixin::popup_button)
00658 {
00659 vgui_popup_params params;
00660 params.x = point.x;
00661 params.y = point.y;
00662 last_popup = get_total_popup(params);
00663 CMenu *popup = vgui_mfc_utils::instance()->set_popup_menu(last_popup);
00664
00665 CWnd* wnd;
00666 if (m_pCWnd)
00667 wnd = m_pCWnd;
00668 else
00669 wnd = AfxGetApp()->GetMainWnd();
00670
00671
00672 ClientToScreen(&point);
00673 popup->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,point.x,point.y,wnd);
00674 delete popup;
00675 }
00676 else
00677 dispatch_to_tableau(e);
00678
00679
00680
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00694
00695
00696
00697 }
00698
00699
00700 void vgui_mfc_adaptor::OnLButtonDown(UINT nFlags, CPoint point)
00701 {
00702 domouse(vgui_BUTTON_DOWN, nFlags, point, vgui_LEFT);
00703 }
00704
00705
00706 void vgui_mfc_adaptor::OnLButtonUp(UINT nFlags, CPoint point)
00707 {
00708 domouse(vgui_BUTTON_UP, nFlags, point, vgui_LEFT);
00709 }
00710
00711
00712 void vgui_mfc_adaptor::OnMButtonDown(UINT nFlags, CPoint point)
00713 {
00714 domouse(vgui_BUTTON_DOWN, nFlags, point, vgui_MIDDLE);
00715 }
00716
00717
00718 void vgui_mfc_adaptor::OnMButtonUp(UINT nFlags, CPoint point)
00719 {
00720 domouse(vgui_BUTTON_UP, nFlags, point, vgui_MIDDLE);
00721 }
00722
00723
00724 void vgui_mfc_adaptor::OnRButtonDown(UINT nFlags, CPoint point)
00725 {
00726 domouse(vgui_BUTTON_DOWN, nFlags, point, vgui_RIGHT);
00727 }
00728
00729
00730 void vgui_mfc_adaptor::OnRButtonUp(UINT nFlags, CPoint point)
00731 {
00732 domouse(vgui_BUTTON_UP, nFlags, point, vgui_RIGHT);
00733 }
00734
00735
00736 void vgui_mfc_adaptor::OnMouseMove(UINT nFlags, CPoint point)
00737 {
00738 domouse(vgui_MOTION, nFlags, point, vgui_BUTTON_NULL);
00739 }
00740
00741
00742 BOOL vgui_mfc_adaptor::OnMouseWheel(UINT nFlags, short zDelta, CPoint pt)
00743 {
00744 #ifdef DEBUG
00745 vcl_cerr << "Mouse wheel events are not handled\n";
00746 #endif
00747 return FALSE;
00748 }
00749