00001
00002 #include "vgui_win32_adaptor.h"
00003 #include "vgui_win32_utils.h"
00004
00005 #include <vcl_iostream.h>
00006 #include <vcl_cstring.h>
00007 #include <vcl_utility.h>
00008 #include <vgui/vgui_gl.h>
00009 #include <vgui/vgui_event.h>
00010 #include <vgui/vgui_macro.h>
00011 #include <vgui/vgui_find.h>
00012 #include <vgui/vgui_image_tableau.h>
00013 #include <vgui/vgui_viewer2D_tableau.h>
00014 #include <vgui/vgui_popup_params.h>
00015 #include <vgui/vgui_command.h>
00016
00017 vgui_menu vgui_win32_adaptor::last_popup;
00018
00019 BEGIN_MESSAGE_MAP(vgui_win32_adaptor, vgui_win32_cmdtarget)
00020 END_MESSAGE_MAP()
00021
00022 vgui_win32_adaptor::vgui_win32_adaptor(HWND hwnd, vgui_window *win)
00023 : hwnd_(hwnd), win_(win), tid_(0),
00024 redraw_posted_(true),
00025 overlay_redraw_posted_(true),
00026 idle_request_posted_(false)
00027 {
00028
00029 hdc_ = GetDC(hwnd);
00030
00031
00032 hglrc_ = setup_for_gl(hdc_);
00033 }
00034
00035 vgui_win32_adaptor::~vgui_win32_adaptor()
00036 {
00037
00038
00039
00040
00041
00042
00043 dispatch_to_tableau(vgui_DESTROY);
00044
00045 if ( hglrc_ ) {
00046
00047 wglMakeCurrent( NULL, NULL );
00048
00049 wglDeleteContext(hglrc_);
00050 }
00051 ReleaseDC(hwnd_, hdc_);
00052
00053
00054 popup_callbacks.clear();
00055
00056
00057 if ( tid_ )
00058 kill_timer(tid_);
00059 }
00060
00061 void vgui_win32_adaptor::post_timer(float timeout, int name)
00062 {
00063 vcl_map<unsigned int, vgui_win32_internal_timer>::iterator it = timers_.find(name);
00064 if ( it == timers_.end() ) {
00065 unsigned int tid = SetTimer(hwnd_, name, (unsigned int)timeout, NULL);
00066 if ( tid ) {
00067 vgui_win32_internal_timer it(tid, NULL);
00068 timers_.insert(vcl_pair<unsigned int, vgui_win32_internal_timer>(name, it));
00069 }
00070 }
00071 }
00072
00073
00074
00075 void vgui_win32_adaptor::post_redraw()
00076 {
00077 if ( !redraw_posted_ ) {
00078 RECT rect;
00079 if ( GetUpdateRect(hwnd_, &rect, FALSE) )
00080 InvalidateRect(hwnd_, &rect, FALSE);
00081 else
00082 InvalidateRect(hwnd_, NULL, FALSE);
00083
00084
00085 PostMessage(hwnd_, WM_SIZE, 0, MAKELPARAM(width, height));
00086 }
00087 redraw_posted_ = true;
00088 }
00089
00090
00091 void vgui_win32_adaptor::post_overlay_redraw()
00092 {
00093 if ( !overlay_redraw_posted_ ) {
00094 RECT rect;
00095 if ( GetUpdateRect(hwnd_, &rect, FALSE) )
00096 InvalidateRect(hwnd_, &rect, FALSE);
00097 else
00098 InvalidateRect(hwnd_, NULL, FALSE);
00099 }
00100 overlay_redraw_posted_ = true;
00101 }
00102
00103
00104 void vgui_win32_adaptor::post_idle_request()
00105 {
00106 idle_request_posted_ = true;
00107 }
00108
00109
00110
00111
00112 void vgui_win32_adaptor::post_destroy()
00113 {
00114
00115
00116
00117 PostMessage(hwnd_, WM_CLOSE, 0, 0);
00118 }
00119
00120
00121 void vgui_win32_adaptor::kill_timer(int name)
00122 {
00123 vcl_map<unsigned int, vgui_win32_internal_timer>::iterator it = timers_.find(name);
00124 if ( it == timers_.end() )
00125 return;
00126
00127 KillTimer(hwnd_, it->second.timer_id);
00128 timers_.erase(it);
00129 }
00130
00131
00132 HGLRC vgui_win32_adaptor::setup_for_gl(HDC hdc)
00133 {
00134
00135 PIXELFORMATDESCRIPTOR pfd =
00136 {
00137 sizeof(PIXELFORMATDESCRIPTOR),
00138 1,
00139 PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER,
00140 PFD_TYPE_RGBA,
00141 24,
00142 0, 0, 0, 0, 0, 0,
00143 0, 0,
00144 0, 0, 0, 0, 0,
00145 16,
00146 0,
00147 0,
00148 PFD_MAIN_PLANE,
00149 0,
00150 0, 0, 0
00151 };
00152
00153 int selected_pf = ChoosePixelFormat(hdc, &pfd);
00154 if ( selected_pf == 0 ) {
00155 MessageBox(NULL, TEXT("Failed to ChoosePixelFormat"), TEXT("Error"),
00156 MB_ICONERROR | MB_OK);
00157 vcl_cerr << "Failed to ChoosePixelFormat (error code:" << GetLastError() << ")\n";
00158 return 0;
00159 }
00160
00161 if ( !SetPixelFormat(hdc, selected_pf, &pfd) ) {
00162 MessageBox(NULL, TEXT("Failed to SetPixelFormat"), TEXT("Error"),
00163 MB_ICONERROR | MB_OK);
00164 vcl_cerr << "Failed to SetPixelFormat (error code:" << GetLastError() << ")\n";
00165 return 0;
00166 }
00167
00168
00169
00170 HGLRC hglrc = wglCreateContext(hdc);
00171 if ( !hglrc ) {
00172 MessageBox(NULL, TEXT("wglCreateContext failed"), TEXT("Error"),
00173 MB_ICONERROR | MB_OK);
00174 vcl_cerr << "wglCreateContext failed (error code:" << GetLastError() << ")\n";
00175 return 0;
00176 }
00177
00178
00179 if ( !wglMakeCurrent(hdc, hglrc) ) {
00180 MessageBox(NULL, TEXT("wglMakeCurrent failed"), TEXT("Error"),
00181 MB_ICONERROR | MB_OK);
00182 vcl_cerr << "wglMakeCurrent failed (error code:" << GetLastError() << ")\n";
00183 return 0;
00184 }
00185
00186
00187 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
00188
00189 glClearDepth(1.0f);
00190
00191 glEnable(GL_DEPTH_TEST);
00192
00193
00194
00195 return hglrc;
00196 }
00197
00198
00199 BOOL vgui_win32_adaptor::OnCmdMsg(UINT message, WPARAM wParam, LPARAM lParam)
00200 {
00201 switch ( message )
00202 {
00203 case WM_SIZE:
00204 OnSize(wParam, lParam);
00205 break;
00206 case WM_PAINT:
00207 OnPaint();
00208 break;
00209 case WM_TIMER:
00210 OnTimer(wParam, lParam);
00211 break;
00212 case WM_HSCROLL:
00213 OnHScroll(message, wParam, lParam);
00214 break;
00215 case WM_VSCROLL:
00216 OnVScroll(message, wParam, lParam);
00217 break;
00218 case WM_KEYDOWN:
00219 OnKeyDown(wParam, lParam);
00220
00221 return TRUE;
00222 case WM_KEYUP:
00223 OnKeyUp(wParam, lParam);
00224
00225 return TRUE;
00226 case WM_LBUTTONDOWN:
00227 OnLButtonDown(wParam, lParam);
00228 return TRUE;
00229 case WM_MBUTTONDOWN:
00230 OnMButtonDown(wParam, lParam);
00231 return TRUE;
00232 case WM_RBUTTONDOWN:
00233 OnRButtonDown(wParam, lParam);
00234 return TRUE;
00235 case WM_LBUTTONUP:
00236 OnLButtonUp(wParam, lParam);
00237 return TRUE;
00238 case WM_MBUTTONUP:
00239 OnMButtonUp(wParam, lParam);
00240 return TRUE;
00241 case WM_RBUTTONUP:
00242 OnRButtonUp(wParam, lParam);
00243 return TRUE;
00244 case WM_MOUSEMOVE:
00245 OnMouseMove(wParam, lParam);
00246 break;
00247 #ifdef WM_MOUSEWHEEL
00248 case WM_MOUSEWHEEL:
00249 OnMouseWheel(wParam, lParam);
00250
00251 return TRUE;
00252 #endif
00253 case WM_COMMAND:
00254 menu_dispatcher(LOWORD(wParam));
00255 return TRUE;
00256 default:
00257 break;
00258 }
00259
00260 return FALSE;
00261 }
00262
00263 void vgui_win32_adaptor::menu_dispatcher(int menuId)
00264 {
00265 int item_count = popup_callbacks.size();
00266
00267
00268 if ( menuId >= POPUPMENU_ID_START && menuId < POPUPMENU_ID_START+item_count )
00269
00270 popup_callbacks[menuId-POPUPMENU_ID_START]->execute();
00271 }
00272
00273 void vgui_win32_adaptor::OnSize(WPARAM wParam, LPARAM lParam)
00274 {
00275
00276 width = LOWORD(lParam);
00277 height = HIWORD(lParam);
00278
00279
00280
00281 vgui_tableau_sptr imtab = vgui_find_below_by_type_name(
00282 this->get_tableau(), "vgui_image_tableau");
00283 vgui_tableau_sptr vrtab = vgui_find_below_by_type_name(
00284 this->get_tableau(), "vgui_viewer2D_tableau");
00285 if ( imtab && vrtab ) {
00286 int im_width, im_height;
00287
00288 vgui_image_tableau_sptr im;
00289 im.vertical_cast(imtab);
00290 vgui_viewer2D_tableau_sptr vr;
00291 vr.vertical_cast(vrtab);
00292
00293 im_width = im->width() *vr->token.scaleX;
00294 im_height = im->height()*vr->token.scaleY;
00295
00296 SCROLLINFO si;
00297
00298 si.cbSize = sizeof(si);
00299 si.fMask = SIF_RANGE | SIF_PAGE;
00300 si.nMin = 0;
00301 si.nMax = 100;
00302 si.nPage = 100.*width/im_width;
00303 si.nPos = -100.*vr->token.offsetX/width;
00304 SetScrollInfo(hwnd_, SB_HORZ, &si, TRUE);
00305
00306
00307 si.nPage = 100.*height/im_height;
00308 si.nPos = -100.*vr->token.offsetY/height;
00309 SetScrollInfo(hwnd_, SB_VERT, &si, TRUE);
00310 }
00311
00312 dispatch_to_tableau(vgui_RESHAPE);
00313 post_redraw();
00314 }
00315
00316 void vgui_win32_adaptor::OnPaint()
00317 {
00318 if ( redraw_posted_ ) {
00319 this->make_current();
00320 vgui_macro_report_errors;
00321 dispatch_to_tableau(vgui_event(vgui_DRAW));
00322 vgui_macro_report_errors;
00323 redraw_posted_ = false;
00324 }
00325
00326 if ( overlay_redraw_posted_ ) {
00327 this->make_current();
00328 vgui_macro_report_errors;
00329
00330 dispatch_to_tableau(vgui_event(vgui_DRAW));
00331 dispatch_to_tableau(vgui_event(vgui_DRAW_OVERLAY));
00332 vgui_macro_report_errors;
00333 overlay_redraw_posted_ = false;
00334 }
00335
00336 swap_buffers();
00337 }
00338
00339 void vgui_win32_adaptor::OnTimer(WPARAM wParam, LPARAM lParam)
00340 {
00341 vgui_event e(vgui_TIMER);
00342 e.timer_id = wParam;
00343 dispatch_to_tableau(e);
00344 }
00345
00346 void vgui_win32_adaptor::OnHScroll(UINT message, WPARAM wParam, LPARAM lParam)
00347 {
00348 static SCROLLINFO si;
00349 int iHorzPos;
00350 vgui_event e;
00351
00352
00353 si.cbSize = sizeof(si);
00354 si.fMask = SIF_ALL;
00355 GetScrollInfo(hwnd_, SB_HORZ, &si);
00356
00357
00358 iHorzPos = si.nPos;
00359 switch (LOWORD(wParam)) {
00360 case SB_LINELEFT:
00361 si.nPos -= 1;
00362 break;
00363 case SB_LINERIGHT:
00364 si.nPos += 1;
00365 break;
00366 case SB_PAGELEFT:
00367 si.nPos -= si.nPage;
00368 break;
00369 case SB_PAGERIGHT:
00370 si.nPos += si.nPage;
00371 break;
00372 case SB_THUMBPOSITION:
00373 si.nPos = si.nTrackPos;
00374 break;
00375 default:
00376 break;
00377 }
00378
00379
00380
00381 si.fMask = SIF_POS;
00382 SetScrollInfo(hwnd_, SB_HORZ, &si, TRUE);
00383 GetScrollInfo(hwnd_, SB_HORZ, &si);
00384
00385
00386 if ( si.nPos != iHorzPos ) {
00387 e.type = vgui_HSCROLL;
00388 e.data = &si.nPos;
00389 dispatch_to_tableau(e);
00390
00391 ScrollWindow(hwnd_, 0, (iHorzPos-si.nPos), NULL, NULL);
00392 UpdateWindow(hwnd_);
00393 }
00394 }
00395
00396 void vgui_win32_adaptor::OnVScroll(UINT message, WPARAM wParam, LPARAM lParam)
00397 {
00398 static SCROLLINFO si;
00399 int iVertPos;
00400 vgui_event e;
00401
00402
00403 si.cbSize = sizeof(si);
00404 si.fMask = SIF_ALL;
00405 GetScrollInfo(hwnd_, SB_VERT, &si);
00406
00407
00408 iVertPos = si.nPos;
00409 switch (LOWORD(wParam)) {
00410 case SB_TOP:
00411 si.nPos = si.nMin;
00412 break;
00413 case SB_BOTTOM:
00414 si.nPos = si.nMax;
00415 break;
00416 case SB_LINEUP:
00417 si.nPos -= 1;
00418 break;
00419 case SB_LINEDOWN:
00420 si.nPos += 1;
00421 break;
00422 case SB_PAGEUP:
00423 si.nPos -= si.nPage;
00424 break;
00425 case SB_PAGEDOWN:
00426 si.nPos += si.nPage;
00427 break;
00428 case SB_THUMBTRACK:
00429 si.nPos = si.nTrackPos;
00430 break;
00431 default:
00432 break;
00433 }
00434
00435
00436
00437 si.fMask = SIF_POS;
00438 SetScrollInfo(hwnd_, SB_VERT, &si, TRUE);
00439 GetScrollInfo(hwnd_, SB_VERT, &si);
00440
00441
00442 if ( si.nPos != iVertPos ) {
00443 e.type = vgui_VSCROLL;
00444 e.data = &si.nPos;
00445 dispatch_to_tableau(e);
00446
00447 ScrollWindow(hwnd_, 0, (iVertPos-si.nPos), NULL, NULL);
00448 UpdateWindow(hwnd_);
00449 }
00450 }
00451
00452 void vgui_win32_adaptor::OnKeyDown(WPARAM wParam, LPARAM lParam)
00453 {
00454
00455 if ( wParam == VK_SHIFT || wParam == VK_CONTROL )
00456 return;
00457
00458 vgui_event ev = translate_message(wParam, lParam, vgui_KEY_PRESS);
00459 dispatch_to_tableau(ev);
00460 }
00461
00462 void vgui_win32_adaptor::OnKeyUp(WPARAM wParam, LPARAM lParam)
00463 {
00464
00465 if ( wParam == VK_SHIFT || wParam == VK_CONTROL )
00466 return;
00467
00468 vgui_event ev = translate_message(wParam, lParam, vgui_KEY_UP);
00469 dispatch_to_tableau(ev);
00470 }
00471
00472 void vgui_win32_adaptor::OnLButtonDown(WPARAM wParam, LPARAM lParam)
00473 {
00474 domouse(vgui_BUTTON_DOWN, vgui_LEFT, wParam, LOWORD(lParam), HIWORD(lParam));
00475 }
00476
00477 void vgui_win32_adaptor::OnLButtonUp(WPARAM wParam, LPARAM lParam)
00478 {
00479 domouse(vgui_BUTTON_UP, vgui_LEFT, wParam, LOWORD(lParam), HIWORD(lParam));
00480 }
00481
00482 void vgui_win32_adaptor::OnMButtonDown(WPARAM wParam, LPARAM lParam)
00483 {
00484 domouse(vgui_BUTTON_DOWN, vgui_MIDDLE, wParam, LOWORD(lParam), HIWORD(lParam));
00485 }
00486
00487 void vgui_win32_adaptor::OnMButtonUp(WPARAM wParam, LPARAM lParam)
00488 {
00489 domouse(vgui_BUTTON_UP, vgui_MIDDLE, wParam, LOWORD(lParam), HIWORD(lParam));
00490 }
00491
00492 void vgui_win32_adaptor::OnRButtonDown(WPARAM wParam, LPARAM lParam)
00493 {
00494 domouse(vgui_BUTTON_DOWN, vgui_RIGHT, wParam, LOWORD(lParam), HIWORD(lParam));
00495 }
00496
00497 void vgui_win32_adaptor::OnRButtonUp(WPARAM wParam, LPARAM lParam)
00498 {
00499 domouse(vgui_BUTTON_UP, vgui_RIGHT, wParam, LOWORD(lParam), HIWORD(lParam));
00500 }
00501
00502
00503 void vgui_win32_adaptor::OnMouseMove(WPARAM wParam, LPARAM lParam)
00504 {
00505 domouse(vgui_MOTION, vgui_BUTTON_NULL, wParam, LOWORD(lParam), HIWORD(lParam));
00506 }
00507
00508 void vgui_win32_adaptor::OnMouseWheel(WPARAM wParam, LPARAM lParam)
00509 {
00510 short delta = HIWORD(wParam);
00511 domouse( delta > 0 ? vgui_WHEEL_UP : vgui_WHEEL_DOWN,
00512 vgui_BUTTON_NULL, LOWORD(wParam), LOWORD(lParam), HIWORD(lParam));
00513 }
00514
00515
00516 void vgui_win32_adaptor::translate_key(UINT nChar, UINT nFlags,
00517 int *the_key, int *the_ascii_char)
00518 {
00519 if (nFlags & 256) {
00520
00521 switch (nChar) {
00522 case VK_NEXT:
00523 *the_key = vgui_PAGE_DOWN;
00524 *the_ascii_char = vgui_PAGE_DOWN;
00525 return;
00526 case VK_PRIOR:
00527 *the_key = vgui_PAGE_UP;
00528 *the_ascii_char = vgui_PAGE_UP;
00529 return;
00530 case VK_HOME:
00531 *the_key = vgui_HOME;
00532 *the_ascii_char = vgui_HOME;
00533 return;
00534 case VK_END:
00535 *the_key = vgui_END;
00536 *the_ascii_char = vgui_END;
00537 return;
00538 case VK_LEFT:
00539 *the_key = vgui_CURSOR_LEFT;
00540 *the_ascii_char = vgui_CURSOR_LEFT;
00541 return;
00542 case VK_UP:
00543 *the_key = vgui_CURSOR_UP;
00544 *the_ascii_char = vgui_CURSOR_UP;
00545 return;
00546 case VK_RIGHT:
00547 *the_key = vgui_CURSOR_RIGHT;
00548 *the_ascii_char = vgui_CURSOR_RIGHT;
00549 return;
00550 case VK_DOWN:
00551 *the_key = vgui_CURSOR_DOWN;
00552 *the_ascii_char = vgui_CURSOR_DOWN;
00553 return;
00554 case VK_DELETE:
00555 *the_key = vgui_DELETE;
00556 *the_ascii_char = vgui_DELETE;
00557 return;
00558 case VK_INSERT:
00559 *the_key = vgui_INSERT;
00560 *the_ascii_char = vgui_INSERT;
00561 return;
00562
00563 default:
00564 *the_key = vgui_key(0);
00565 *the_ascii_char = vgui_key(0);
00566 return;
00567 }
00568 }
00569 else if (nChar >= VK_F1 && nChar <= VK_F12)
00570 {
00571 *the_key = *the_ascii_char = vgui_F1 + (nChar - VK_F1);
00572 }
00573 else if (nChar == VK_ESCAPE )
00574 *the_key = *the_ascii_char = vgui_ESC;
00575 else if (nChar == VK_TAB )
00576 *the_key = *the_ascii_char = vgui_TAB;
00577 else if (nChar == VK_RETURN )
00578 *the_key = *the_ascii_char = vgui_RETURN;
00579 else
00580 {
00581 unsigned short buf[1024];
00582 unsigned char lpKeyState[256];
00583 vcl_memset(lpKeyState, 0, 256);
00584 vcl_memset(buf, 0, 256);
00585
00586 int is_ok = ToAscii(nChar, nFlags & 0xff, lpKeyState, buf, 0);
00587 if (is_ok == 1)
00588 *the_key = buf[0];
00589 else
00590 *the_key = nChar;
00591
00592
00593 lpKeyState[VK_SHIFT] = GetKeyState(VK_SHIFT);
00594 lpKeyState[VK_CONTROL] = GetKeyState(VK_CONTROL);
00595
00596 is_ok = ToAscii(nChar, nFlags & 0xff, lpKeyState, buf, 0);
00597 if (is_ok == 1)
00598 *the_ascii_char = buf[0];
00599 else
00600 *the_ascii_char = nChar;
00601 }
00602 }
00603
00604
00605 vgui_event vgui_win32_adaptor::translate_message(WPARAM wParam,
00606 LPARAM lParam, vgui_event_type evtype)
00607 {
00608 vgui_event ev(evtype);
00609
00610
00611 if ( GetKeyState(VK_SHIFT) & 0x8000 )
00612 ev.modifier = vgui_SHIFT;
00613 if ( GetKeyState(VK_CONTROL) & 0x8000 )
00614 ev.modifier = vgui_CTRL;
00615 if ( GetKeyState(VK_MENU) & 0x8000 )
00616 ev.modifier = vgui_ALT;
00617
00618
00619 int nChar, nFlags, key, ascii_char;
00620 nChar = wParam;
00621 nFlags = HIWORD(lParam);
00622 translate_key(nChar, nFlags, &key, &ascii_char);
00623 ev.set_key(vgui_key(key));
00624 ev.ascii_char = vgui_key(ascii_char);
00625
00626 return ev;
00627 }
00628
00629 void vgui_win32_adaptor::domouse(vgui_event_type et, vgui_button b, UINT nFlags, int x, int y)
00630 {
00631
00632
00633 x += 2;
00634 y += 2;
00635
00636
00637 vgui_event e(et);
00638
00639 e.button = b;
00640
00641
00642 if (nFlags & MK_LBUTTON)
00643 e.button = vgui_LEFT;
00644 if (nFlags & MK_MBUTTON)
00645 e.button = vgui_MIDDLE;
00646 if (nFlags & MK_RBUTTON)
00647 e.button = vgui_RIGHT;
00648
00649 if (nFlags & MK_SHIFT)
00650 e.modifier = vgui_modifier((int)e.modifier | vgui_SHIFT);
00651 if (nFlags & MK_CONTROL)
00652 e.modifier = vgui_modifier((int)e.modifier | vgui_CTRL);
00653
00654 e.wx = x;
00655 e.wy = height - y;
00656
00657 if (e.modifier == mixin::popup_modifier && e.button == mixin::popup_button
00658 && e.type == vgui_BUTTON_UP)
00659 {
00660 vgui_popup_params params;
00661 params.x = x;
00662 params.y = y;
00663 last_popup = get_total_popup(params);
00664
00665
00666 HMENU hMenu = vgui_win32_utils::instance()->vgui_menu_to_win32ex(
00667 last_popup, popup_callbacks, 0, true);
00668
00669 POINT point;
00670 point.x = x; point.y = y;
00671
00672
00673 ClientToScreen(hwnd_, &point);
00674 HMENU hPopupMenu = GetSubMenu(hMenu, 0);
00675 TrackPopupMenu(hPopupMenu, TPM_RIGHTBUTTON, point.x, point.y, 0, hwnd_, NULL);
00676 }
00677 else
00678 dispatch_to_tableau(e);
00679
00680 # if 0 // explained below:
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692 {
00693 if (et == vgui_BUTTON_DOWN) {
00694 SetCapture(hwnd_);
00695 }
00696 else if (et != vgui_MOTION) {
00697 ReleaseCapture();
00698 }
00699 }
00700 #endif // 0
00701 }
00702