Go to the documentation of this file.00001
00002
00003 #include "vgui_win32_utils.h"
00004 #include <vcl_iostream.h>
00005 #include <vcl_cassert.h>
00006 #include <vcl_cstddef.h>
00007
00008
00009 vgui_win32_utils* vgui_win32_utils::instance()
00010 {
00011 static vgui_win32_utils instance_;
00012 return &instance_;
00013 }
00014
00015
00016
00017
00018 HMENU vgui_win32_utils::vgui_menu_to_win32(vgui_menu const &vguimenu,
00019 vcl_vector<vgui_command_sptr> &callbacks_, HACCEL *hAccel, bool isPopup)
00020 {
00021 HMENU hMenu;
00022 MENUITEMTEMPLATEHEADER *pMenuHeader;
00023 MENUITEMTEMPLATE *pMenuItem;
00024
00025
00026
00027 menu_capacity = 1024;
00028 item_count = 0;
00029 callbacks.clear();
00030
00031 pAccel = 0;
00032 accel_capacity = 16;
00033 accel_count = 0;
00034
00035 pMenu = (unsigned char *)malloc(sizeof(MENUITEMTEMPLATEHEADER) + menu_capacity);
00036 if ( pMenu == NULL ) {
00037 vcl_cerr << "Memory allocation error\n";
00038 return NULL;
00039 }
00040
00041 pAccel = (ACCEL *)malloc(sizeof(ACCEL)*accel_capacity);
00042 if ( pAccel == NULL )
00043 vcl_cerr << "Memory allocation error\n";
00044
00045
00046 pMenuHeader = (MENUITEMTEMPLATEHEADER *)pMenu;
00047 pMenuHeader->versionNumber = 0;
00048 pMenuHeader->offset = 0;
00049 int offset = sizeof(MENUITEMTEMPLATEHEADER);
00050
00051 if ( isPopup ) {
00052
00053 pMenuItem = (MENUITEMTEMPLATE*)(pMenu + offset);
00054 pMenuItem->mtOption = MF_END | MF_POPUP;
00055 offset += sizeof(pMenuItem->mtOption);
00056 pMenuItem->mtID = 0;
00057 offset += sizeof(WCHAR);
00058 }
00059
00060 addMenuItems(vguimenu, offset, isPopup);
00061
00062 hMenu = LoadMenuIndirect(pMenu);
00063 if ( !hMenu )
00064 ShowErrorMessage(GetLastError());
00065
00066 if ( !isPopup )
00067 *hAccel = CreateAcceleratorTable(pAccel, accel_count);
00068
00069 free(pMenu);
00070 free(pAccel);
00071
00072 callbacks_ = callbacks;
00073 return hMenu;
00074 }
00075
00076
00077 int vgui_win32_utils::addMenuItems(vgui_menu const &vguimenu, int offset_in, bool is_popup)
00078 {
00079 static unsigned int max_menuitem_size = 256;
00080
00081 MENUITEMTEMPLATE *pMenuItem;
00082 WCHAR *pMenuItemText;
00083 vcl_string menuItemText;
00084 int stride, offset;
00085
00086
00087
00088
00089 offset = offset_in;
00090 for ( unsigned int i=0; i < vguimenu.size(); ++i ) {
00091 pMenuItem = (MENUITEMTEMPLATE*)(pMenu + offset);
00092
00093
00094 if (vguimenu[i].is_separator() ||
00095 vguimenu[i].is_toggle_button())
00096 continue;
00097
00098 stride = 0;
00099 pMenuItem->mtOption = 0;
00100 stride += sizeof(pMenuItem->mtOption);
00101 if ( i == vguimenu.size()-1 )
00102 pMenuItem->mtOption |= MF_END;
00103
00104 if (vguimenu[i].is_command()) {
00105 int menuItemID = is_popup ? POPUPMENU_ID_START+item_count++ : MENU_ID_START+item_count++;
00106 pMenuItem->mtID = menuItemID;
00107 stride += sizeof(pMenuItem->mtID);
00108
00109 menuItemText = vguimenu[i].name;
00110 addAccelerator(menuItemText, vguimenu[i], menuItemID);
00111
00112
00113 vcl_size_t j;
00114 pMenuItemText = pMenuItem->mtString;
00115 for ( j = 0; j < menuItemText.size(); j++ )
00116 *(pMenuItemText+j) = (WCHAR)menuItemText.c_str()[j];
00117 *(pMenuItemText+j) = 0;
00118 stride += sizeof(WCHAR) * (wcslen(pMenuItemText)+1);
00119
00120
00121 callbacks.push_back(vguimenu[i].cmnd);
00122 }
00123 else if (vguimenu[i].is_submenu()) {
00124 pMenuItem->mtOption |= MF_POPUP;
00125
00126 menuItemText = vguimenu[i].name;
00127 vcl_size_t j;
00128
00129
00130 pMenuItemText = (WCHAR *)&pMenuItem->mtID;
00131 for ( j = 0; j < menuItemText.size(); j++ )
00132 *(pMenuItemText+j) = menuItemText.c_str()[j];
00133 *(pMenuItemText+j) = 0;
00134 stride += sizeof(WCHAR) * (wcslen(pMenuItemText)+1);
00135
00136
00137 stride += addMenuItems(*vguimenu[i].menu, offset+stride, is_popup);
00138 }
00139
00140 offset += stride;
00141
00142
00143
00144 assert(offset < menu_capacity);
00145
00146
00147 if ( offset > menu_capacity-(int)max_menuitem_size ) {
00148 menu_capacity <<= 1;
00149 pMenu = (unsigned char *)realloc(pMenu, sizeof(MENUITEMTEMPLATEHEADER)+menu_capacity);
00150 if ( pMenu == NULL ) {
00151 vcl_cerr << "Memory allocation error\n";
00152 return 0;
00153 }
00154 }
00155 }
00156
00157 return offset - offset_in;
00158 }
00159
00160
00161
00162 HMENU vgui_win32_utils::vgui_menu_to_win32ex(vgui_menu const &vguimenu,
00163 vcl_vector<vgui_command_sptr> &callbacks_, HACCEL *hAccel, bool isPopup)
00164 {
00165 HMENU hMenu;
00166 MENUEX_TEMPLATE_HEADER *pMenuHeader;
00167 MENUEX_TEMPLATE_ITEM *pMenuItem;
00168
00169
00170
00171
00172 menu_capacity = 1024;
00173 item_count = 0;
00174 callbacks.clear();
00175
00176 pAccel = 0;
00177 accel_capacity = 16;
00178 accel_count = 0;
00179
00180 pMenu = (unsigned char *)malloc(sizeof(MENUEX_TEMPLATE_HEADER) + menu_capacity);
00181 if ( pMenu == NULL ) {
00182 vcl_cerr << "Memory allocation error\n";
00183 return NULL;
00184 }
00185
00186 pAccel = (ACCEL *)malloc(sizeof(ACCEL)*accel_capacity);
00187 if ( pAccel == NULL )
00188 vcl_cerr << "Memory allocation error\n";
00189
00190
00191 pMenuHeader = (MENUEX_TEMPLATE_HEADER *)pMenu;
00192 pMenuHeader->wVersion = 1;
00193 pMenuHeader->wOffset = 4;
00194 pMenuHeader->dwHelpId = 0;
00195 int offset = sizeof(MENUEX_TEMPLATE_HEADER);
00196
00197 if ( isPopup ) {
00198
00199 pMenuItem = (MENUEX_TEMPLATE_ITEM*)(pMenu+offset);
00200 pMenuItem->dwType = MFT_STRING;
00201 offset += sizeof(pMenuItem->dwType);
00202 pMenuItem->dwState = MFS_ENABLED;
00203 offset += sizeof(pMenuItem->dwState);
00204 pMenuItem->menuId = 0;
00205 offset += sizeof(pMenuItem->menuId);
00206 pMenuItem->bResInfo = 0x01 | 0x80;
00207 offset += sizeof(pMenuItem->bResInfo);
00208 pMenuItem->szText = 0;
00209 offset += sizeof(pMenuItem->szText);
00210 pMenuItem->dwHelpId = 0;
00211 offset += sizeof(pMenuItem->dwHelpId);
00212 }
00213
00214 addMenuItemsEx(vguimenu, offset, isPopup);
00215
00216 hMenu = LoadMenuIndirect(pMenu);
00217 if ( !hMenu )
00218 ShowErrorMessage(GetLastError());
00219
00220 if ( !isPopup )
00221 *hAccel = CreateAcceleratorTable(pAccel, accel_count);
00222
00223 free(pMenu);
00224 free(pAccel);
00225
00226 callbacks_ = callbacks;
00227 return hMenu;
00228 }
00229
00230 int vgui_win32_utils::addMenuItemsEx(vgui_menu const &vguimenu, int offset_in, bool is_popup)
00231 {
00232 static unsigned int max_menuitem_size = 256;
00233
00234 MENUEX_TEMPLATE_ITEM *pMenuItem;
00235 WCHAR *pMenuItemText;
00236 vcl_string menuItemText;
00237 int stride, offset;
00238 bool last_item;
00239
00240
00241
00242
00243 offset = offset_in;
00244 for ( unsigned int i=0; i < vguimenu.size(); ++i ) {
00245 pMenuItem = (MENUEX_TEMPLATE_ITEM*)(pMenu + offset);
00246 stride = 0;
00247
00248
00249 last_item = (i == vguimenu.size()-1) ? true : false;
00250
00251 pMenuItem->dwType = MFT_STRING;
00252 stride += sizeof(pMenuItem->dwType);
00253 pMenuItem->dwState = MFS_ENABLED;
00254 stride += sizeof(pMenuItem->dwState);
00255 pMenuItem->menuId = 0;
00256 stride += sizeof(pMenuItem->menuId);
00257
00258 if (vguimenu[i].is_separator()) {
00259 pMenuItem->dwType = MFT_SEPARATOR;
00260 pMenuItem->bResInfo = last_item ? 0x80 : 0;
00261 stride += sizeof(pMenuItem->bResInfo);
00262 pMenuItem->szText = 0;
00263 stride += sizeof(pMenuItem->szText);
00264 if ( stride % 4 ) {
00265 stride += 4;
00266 stride &= ~3;
00267 }
00268 }
00269 else if (vguimenu[i].is_command()) {
00270 int menuItemID = is_popup ? POPUPMENU_ID_START+item_count++ : MENU_ID_START+item_count++;
00271 pMenuItem->menuId = menuItemID;
00272
00273 pMenuItem->bResInfo = last_item ? 0x80 : 0;
00274 stride += sizeof(pMenuItem->bResInfo);
00275
00276 menuItemText = vguimenu[i].name;
00277 addAccelerator(menuItemText, vguimenu[i], menuItemID);
00278
00279
00280 pMenuItemText = (WCHAR *)&pMenuItem->szText;
00281 vcl_size_t j;
00282 for ( j = 0; j < menuItemText.size(); j++ )
00283 *(pMenuItemText+j) = menuItemText.c_str()[j];
00284 *(pMenuItemText+j) = 0;
00285
00286 stride += sizeof(WCHAR) * (wcslen(pMenuItemText)+1);
00287
00288 if ( stride % 4 ) {
00289 stride += 4;
00290 stride &= ~3;
00291 }
00292
00293
00294 callbacks.push_back(vguimenu[i].cmnd);
00295 }
00296 else if (vguimenu[i].is_submenu()) {
00297 pMenuItem->bResInfo = last_item ? 0x80 | 0x01 : 0x01;
00298 stride += sizeof(pMenuItem->bResInfo);
00299
00300 menuItemText = vguimenu[i].name;
00301 pMenuItemText = (WCHAR *)&pMenuItem->szText;
00302 vcl_size_t j;
00303 for ( j = 0; j < menuItemText.size(); j++ )
00304 *(pMenuItemText+j) = menuItemText.c_str()[j];
00305 *(pMenuItemText+j) = 0;
00306 stride += sizeof(WCHAR) * (wcslen(pMenuItemText)+1);
00307
00308 if ( stride % 4 ) {
00309 stride += 4;
00310 stride &= ~3;
00311 }
00312
00313 DWORD* dwHelpId = (DWORD *)(pMenu+offset+stride);
00314 *dwHelpId = 0;
00315 stride += sizeof(pMenuItem->dwHelpId);
00316
00317
00318 stride += addMenuItemsEx(*vguimenu[i].menu, offset+stride, is_popup);
00319 }
00320 else if (vguimenu[i].is_toggle_button()) {
00321 vcl_cerr << "vgui_win32_utils: toggle button is not converted\n";
00322 }
00323
00324 offset += stride;
00325
00326
00327
00328 assert(offset < menu_capacity);
00329
00330
00331 if ( offset > menu_capacity-(int)max_menuitem_size ) {
00332 menu_capacity <<= 1;
00333 pMenu = (unsigned char *)realloc(pMenu, sizeof(MENUEX_TEMPLATE_HEADER) + menu_capacity);
00334 if ( pMenu == NULL ) {
00335 vcl_cerr << "Memory allocation error\n";
00336 return NULL;
00337 }
00338 }
00339 }
00340
00341 return offset-offset_in;
00342 }
00343
00344 inline void vgui_win32_utils::addAccelerator(vcl_string &menuItemText,
00345 vgui_menu_item const &vguimenu, int menuItemId)
00346 {
00347 ACCEL *pa = pAccel+accel_count;
00348 pa->cmd = menuItemId;
00349
00350 pa->fVirt = FVIRTKEY;
00351
00352 if ( vguimenu.short_cut.mod != vgui_MODIFIER_NULL ||
00353 vguimenu.short_cut.key != vgui_KEY_NULL )
00354 menuItemText += "\t";
00355
00356 if ( vguimenu.short_cut.mod & vgui_CTRL ) {
00357 menuItemText += "Ctrl+";
00358 pa->fVirt |= FCONTROL;
00359 }
00360 if ( vguimenu.short_cut.mod & vgui_SHIFT ) {
00361 menuItemText += "Shift+";
00362 pa->fVirt |= FSHIFT;
00363 }
00364 if ( vguimenu.short_cut.mod & vgui_ALT ) {
00365 menuItemText += "Alt+";
00366 pa->fVirt |= FALT;
00367 }
00368
00369 vgui_key key = vguimenu.short_cut.key;
00370 if ( key != vgui_KEY_NULL ) {
00371 if ( key >= 'A' && key <= 'Z'|| key >= 'a' && key <= 'z') {
00372 if ( key >= 'a' && key <= 'z')
00373 key = vgui_key(key + 'A' - 'a');
00374 menuItemText += key;
00375 pa->key = key;
00376 }
00377 else {
00378 menuItemText += vgui_key_to_string(key);
00379 pa->key = vgui_key_to_virt_key(key);
00380 }
00381
00382 if (++accel_count >= accel_capacity) {
00383 accel_capacity <<= 1;
00384 pAccel = (ACCEL *)realloc(pAccel, sizeof(ACCEL)*accel_capacity);
00385 if ( pAccel == NULL )
00386 vcl_cerr << "Memory allocation error\n";
00387 }
00388 }
00389 }
00390
00391
00392 inline vcl_string vgui_win32_utils::vgui_key_to_string(vgui_key key)
00393 {
00394 vcl_string str;
00395
00396 switch ( key ) {
00397
00398 case vgui_F1:
00399 str = "F1"; break;
00400 case vgui_F2:
00401 str = "F2"; break;
00402 case vgui_F3:
00403 str = "F3"; break;
00404 case vgui_F4:
00405 str = "F4"; break;
00406 case vgui_F5:
00407 str = "F5"; break;
00408 case vgui_F6:
00409 str = "F6"; break;
00410 case vgui_F7:
00411 str = "F7"; break;
00412 case vgui_F8:
00413 str = "F8"; break;
00414 case vgui_F9:
00415 str = "F9"; break;
00416 case vgui_F10:
00417 str = "F10"; break;
00418 case vgui_F11:
00419 str = "F11"; break;
00420 case vgui_F12:
00421 str = "F12"; break;
00422 case vgui_CURSOR_LEFT:
00423 str = "Left"; break;
00424 case vgui_CURSOR_UP:
00425 str = "Up"; break;
00426 case vgui_CURSOR_RIGHT:
00427 str = "Right"; break;
00428 case vgui_CURSOR_DOWN:
00429 str = "Down"; break;
00430 case vgui_PAGE_UP:
00431 str = "PageUp"; break;
00432 case vgui_PAGE_DOWN:
00433 str = "PageDown"; break;
00434 case vgui_HOME:
00435 str = "Home"; break;
00436 case vgui_END:
00437 str = "End"; break;
00438 case vgui_DELETE:
00439 str = "Del"; break;
00440 case vgui_INSERT:
00441 str = "Ins"; break;
00442 default:
00443 str = ""; break;
00444 }
00445
00446 return str;
00447 }
00448
00449 UINT vgui_win32_utils::vgui_key_to_virt_key(vgui_key key)
00450 {
00451 UINT virt_key;
00452
00453 switch ( key ) {
00454
00455 case vgui_F1:
00456 case vgui_F2:
00457 case vgui_F3:
00458 case vgui_F4:
00459 case vgui_F5:
00460 case vgui_F6:
00461 case vgui_F7:
00462 case vgui_F8:
00463 case vgui_F9:
00464 case vgui_F10:
00465 case vgui_F11:
00466 case vgui_F12:
00467 virt_key = VK_F1 + key - vgui_F1;
00468 break;
00469 case vgui_CURSOR_LEFT:
00470 virt_key = VK_LEFT; break;
00471 case vgui_CURSOR_UP:
00472 virt_key = VK_UP; break;
00473 case vgui_CURSOR_RIGHT:
00474 virt_key = VK_RIGHT; break;
00475 case vgui_CURSOR_DOWN:
00476 virt_key = VK_DOWN; break;
00477 case vgui_PAGE_UP:
00478 virt_key = VK_PRIOR; break;
00479 case vgui_PAGE_DOWN:
00480 virt_key = VK_NEXT; break;
00481 case vgui_HOME:
00482 virt_key = VK_HOME; break;
00483 case vgui_END:
00484 virt_key = VK_END; break;
00485 case vgui_DELETE:
00486 virt_key = VK_DELETE; break;
00487 case vgui_INSERT:
00488 virt_key = VK_INSERT; break;
00489 default:
00490 virt_key = 0x07; break;
00491 }
00492
00493 return virt_key;
00494 }
00495
00496 void vgui_win32_utils::ShowErrorMessage(DWORD dwErrorNo)
00497 {
00498 LPSTR lpBuffer;
00499 FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
00500 FORMAT_MESSAGE_IGNORE_INSERTS |
00501 FORMAT_MESSAGE_FROM_SYSTEM,
00502 NULL,
00503 dwErrorNo,
00504 LANG_NEUTRAL,
00505 (LPTSTR) & lpBuffer,
00506 0 ,
00507 NULL);
00508 vcl_cerr << lpBuffer;
00509 }