/* ダイアログデータの取得 Toolbar */ int CPropToolbar::GetData( HWND hwndDlg ) { HWND hwndResList; int i; int j; int k; hwndResList = ::GetDlgItem( hwndDlg, IDC_LIST_RES ); /* ツールバーボタンの数 */ m_Common.m_sToolBar.m_nToolBarButtonNum = List_GetCount( hwndResList ); /* ツールバーボタンの情報を取得 */ k = 0; for( i = 0; i < m_Common.m_sToolBar.m_nToolBarButtonNum; ++i ){ j = List_GetItemData( hwndResList, i ); if( LB_ERR != j ){ m_Common.m_sToolBar.m_nToolBarButtonIdxArr[k] = j; k++; } } m_Common.m_sToolBar.m_nToolBarButtonNum = k; /* フラットツールバーにする/しない */ m_Common.m_sToolBar.m_bToolBarIsFlat = ::IsDlgButtonChecked( hwndDlg, IDC_CHECK_TOOLBARISFLAT ); return TRUE; }
HMENUITEM GetDefaultMenuItem(HPOPUP popup) { for (int i = 0; i < List_GetCount(popup->menu_items); ++i) { HMENUITEM item = (HMENUITEM)List_Get(popup->menu_items, i); if (item->item_style & CPM_ITEM_DEFAULT) return item; } return NULL; }
static void SetDlgItemsEnableState( HWND hwndDlg, HWND hwndResList, HWND hwndFuncList ) { int nIndex1 = List_GetCurSel( hwndResList ); int nIndex2 = List_GetCurSel( hwndFuncList ); int i = List_GetCount( hwndResList ); if( LB_ERR == nIndex1 ){ ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_DELETE ), FALSE ); ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_UP ), FALSE ); ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_DOWN ), FALSE ); }else{ ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_DELETE ), TRUE ); if( nIndex1 <= 0 ){ ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_UP ), FALSE ); }else{ ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_UP ), TRUE ); } if( nIndex1 + 1 >= i ){ ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_DOWN ), FALSE ); }else{ ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_DOWN ), TRUE ); } } if( LB_ERR == nIndex1 || LB_ERR == nIndex2 ){ ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_INSERT ), FALSE ); }else{ ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_INSERT ), TRUE ); } if( LB_ERR == nIndex2 ){ ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_ADD ), FALSE ); }else{ ::EnableWindow( ::GetDlgItem( hwndDlg, IDC_BUTTON_ADD ), TRUE ); } }
/* Toolbar メッセージ処理 */ INT_PTR CPropToolbar::DispatchEvent( HWND hwndDlg, // handle to dialog box UINT uMsg, // message WPARAM wParam, // first message parameter LPARAM lParam // second message parameter ) { WORD wNotifyCode; WORD wID; HWND hwndCtl; NMHDR* pNMHDR; int idCtrl; static HWND hwndCombo; static HWND hwndFuncList; static HWND hwndResList; LPDRAWITEMSTRUCT pDis; int nIndex1; int nIndex2; // int nIndex3; int nNum; int i; int j; static int nListItemHeight; LRESULT lResult; switch( uMsg ){ case WM_INITDIALOG: /* コントロールのハンドルを取得 */ hwndCombo = ::GetDlgItem( hwndDlg, IDC_COMBO_FUNCKIND ); hwndFuncList = ::GetDlgItem( hwndDlg, IDC_LIST_FUNC ); hwndResList = ::GetDlgItem( hwndDlg, IDC_LIST_RES ); { // 2014.11.25 フォントの高さが正しくなかったバグを修正 CTextWidthCalc calc(hwndResList); int nFontHeight = calc.GetTextHeight(); nListItemHeight = std::max(nFontHeight, GetSystemMetrics(SM_CYSMICON)) + DpiScaleY(2); nToolBarListBoxTopMargin = (nListItemHeight - (nFontHeight + 1)) / 2; } /* ダイアログデータの設定 Toolbar */ SetData( hwndDlg ); // Modified by KEITA for WIN64 2003.9.6 ::SetWindowLongPtr( hwndDlg, DWLP_USER, lParam ); // From Here Oct.14, 2000 JEPRO added (Ref. CPropComCustmenu.cpp 内のWM_INITDIALOGを参考にした) /* キー選択時の処理 */ ::SendMessageCmd( hwndDlg, WM_COMMAND, MAKELONG( IDC_COMBO_FUNCKIND, CBN_SELCHANGE ), (LPARAM)hwndCombo ); // To Here Oct. 14, 2000 ::SetTimer( hwndDlg, 1, 300, NULL ); SetDlgItemsEnableState( hwndDlg, hwndResList, hwndFuncList ); return TRUE; case WM_DRAWITEM: idCtrl = (UINT) wParam; /* コントロールのID */ pDis = (LPDRAWITEMSTRUCT) lParam; /* 項目描画情報 */ switch( idCtrl ){ case IDC_LIST_RES: /* ツールバーボタン結果リスト */ case IDC_LIST_FUNC: /* ボタン一覧リスト */ DrawToolBarItemList( pDis ); /* ツールバーボタンリストのアイテム描画 */ return TRUE; } return TRUE; case WM_NOTIFY: idCtrl = (int)wParam; pNMHDR = (NMHDR*)lParam; switch( pNMHDR->code ){ case PSN_HELP: OnHelp( hwndDlg, IDD_PROP_TOOLBAR ); return TRUE; case PSN_KILLACTIVE: // MYTRACE( _T("PROP_TOOLBAR PSN_KILLACTIVE\n") ); /* ダイアログデータの取得 Toolbar */ GetData( hwndDlg ); return TRUE; //@@@ 2002.01.03 YAZAKI 最後に表示していたシートを正しく覚えていないバグ修正 case PSN_SETACTIVE: m_nPageNum = ID_PROPCOM_PAGENUM_TOOLBAR; return TRUE; } break; case WM_COMMAND: wNotifyCode = HIWORD( wParam ); /* 通知コード */ wID = LOWORD( wParam ); /* 項目ID、 コントロールID、 またはアクセラレータID */ hwndCtl = (HWND) lParam; /* コントロールのハンドル */ if( hwndResList == hwndCtl ){ switch( wNotifyCode ){ case LBN_SELCHANGE: return TRUE; } }else if( hwndCombo == hwndCtl ){ switch( wNotifyCode ){ case CBN_SELCHANGE: nIndex2 = Combo_GetCurSel( hwndCombo ); List_ResetContent( hwndFuncList ); /* 機能一覧に文字列をセット (リストボックス) */ // From Here Oct. 15, 2001 genta Lookupを使うように変更 nNum = m_cLookup.GetItemCount( nIndex2 ); for( i = 0; i < nNum; ++i ){ nIndex1 = m_cLookup.Pos2FuncCode( nIndex2, i ); int nbarNo = m_pcMenuDrawer->FindToolbarNoFromCommandId( nIndex1 ); if( nbarNo >= 0 ){ /* ツールバーボタンの情報をセット (リストボックス) */ lResult = ::Listbox_ADDDATA( hwndFuncList, (LPARAM)nbarNo ); if( lResult == LB_ERR || lResult == LB_ERRSPACE ){ break; } lResult = List_SetItemHeight( hwndFuncList, lResult, nListItemHeight ); } } return TRUE; } }else{ switch( wNotifyCode ){ /* ボタン/チェックボックスがクリックされた */ case BN_CLICKED: switch( wID ){ case IDC_BUTTON_INSERTSEPARATOR: nIndex1 = List_GetCurSel( hwndResList ); if( LB_ERR == nIndex1 ){ // break; nIndex1 = 0; } // From Here Apr. 13, 2002 genta nIndex1 = ::Listbox_INSERTDATA( hwndResList, nIndex1, 0 ); if( nIndex1 == LB_ERR || nIndex1 == LB_ERRSPACE ){ break; } // To Here Apr. 13, 2002 genta List_SetCurSel( hwndResList, nIndex1 ); break; // 2005/8/9 aroka 折返ボタンが押されたら、右のリストに「ツールバー折返」を追加する。 case IDC_BUTTON_INSERTWRAP: nIndex1 = List_GetCurSel( hwndResList ); if( LB_ERR == nIndex1 ){ // break; nIndex1 = 0; } // From Here Apr. 13, 2002 genta // 2010.06.25 Moca 折り返しのツールバーのボタン番号定数名を変更。最後ではなく固定値にする nIndex1 = ::Listbox_INSERTDATA( hwndResList, nIndex1, CMenuDrawer::TOOLBAR_BUTTON_F_TOOLBARWRAP ); if( nIndex1 == LB_ERR || nIndex1 == LB_ERRSPACE ){ break; } // To Here Apr. 13, 2002 genta List_SetCurSel( hwndResList, nIndex1 ); break; case IDC_BUTTON_DELETE: nIndex1 = List_GetCurSel( hwndResList ); if( LB_ERR == nIndex1 ){ break; } i = List_DeleteString( hwndResList, nIndex1 ); if( i == LB_ERR ){ break; } if( nIndex1 >= i ){ if( i == 0 ){ i = List_SetCurSel( hwndResList, 0 ); }else{ i = List_SetCurSel( hwndResList, i - 1 ); } }else{ i = List_SetCurSel( hwndResList, nIndex1 ); } break; case IDC_BUTTON_INSERT: nIndex1 = List_GetCurSel( hwndResList ); if( LB_ERR == nIndex1 ){ // break; nIndex1 = 0; } nIndex2 = List_GetCurSel( hwndFuncList ); if( LB_ERR == nIndex2 ){ break; } i = List_GetItemData( hwndFuncList, nIndex2 ); // From Here Apr. 13, 2002 genta nIndex1 = ::Listbox_INSERTDATA( hwndResList, nIndex1, i ); if( nIndex1 == LB_ERR || nIndex1 == LB_ERRSPACE ){ break; } // To Here Apr. 13, 2002 genta List_SetCurSel( hwndResList, nIndex1 + 1 ); break; case IDC_BUTTON_ADD: nIndex1 = List_GetCount( hwndResList ); nIndex2 = List_GetCurSel( hwndFuncList ); if( LB_ERR == nIndex2 ){ break; } i = List_GetItemData( hwndFuncList, nIndex2 ); // From Here Apr. 13, 2002 genta // ここでは i != 0 だとは思うけど、一応保険です。 nIndex1 = ::Listbox_INSERTDATA( hwndResList, nIndex1, i ); if( nIndex1 == LB_ERR || nIndex1 == LB_ERRSPACE ){ TopErrorMessage( NULL, LS(STR_PROPCOMTOOL_ERR05), nIndex1 ); break; } // To Here Apr. 13, 2002 genta List_SetCurSel( hwndResList, nIndex1 ); break; case IDC_BUTTON_UP: nIndex1 = List_GetCurSel( hwndResList ); if( LB_ERR == nIndex1 || 0 >= nIndex1 ){ break; } i = List_GetItemData( hwndResList, nIndex1 ); j = List_DeleteString( hwndResList, nIndex1 ); if( j == LB_ERR ){ break; } // From Here Apr. 13, 2002 genta nIndex1 = ::Listbox_INSERTDATA( hwndResList, nIndex1 - 1, i ); if( nIndex1 == LB_ERR || nIndex1 == LB_ERRSPACE ){ TopErrorMessage( NULL, LS(STR_PROPCOMTOOL_ERR05), nIndex1 ); break; } // To Here Apr. 13, 2002 genta List_SetCurSel( hwndResList, nIndex1 ); break; case IDC_BUTTON_DOWN: i = List_GetCount( hwndResList ); nIndex1 = List_GetCurSel( hwndResList ); if( LB_ERR == nIndex1 || nIndex1 + 1 >= i ){ break; } i = List_GetItemData( hwndResList, nIndex1 ); j = List_DeleteString( hwndResList, nIndex1 ); if( j == LB_ERR ){ break; } // From Here Apr. 13, 2002 genta nIndex1 = ::Listbox_INSERTDATA( hwndResList, nIndex1 + 1, i ); if( nIndex1 == LB_ERR || nIndex1 == LB_ERRSPACE ){ TopErrorMessage( NULL, LS(STR_PROPCOMTOOL_ERR05), nIndex1 ); break; } List_SetCurSel( hwndResList, nIndex1 ); // To Here Apr. 13, 2002 genta break; } break; } } break; case WM_TIMER: SetDlgItemsEnableState( hwndDlg, hwndResList, hwndFuncList ); break; case WM_DESTROY: ::KillTimer( hwndDlg, 1 ); break; //@@@ 2001.02.04 Start by MIK: Popup Help case WM_HELP: { HELPINFO *p = (HELPINFO *)lParam; MyWinHelp( (HWND)p->hItemHandle, HELP_WM_HELP, (ULONG_PTR)(LPVOID)p_helpids ); // 2006.10.10 ryoji MyWinHelpに変更に変更 } return TRUE; /*NOTREACHED*/ //break; //@@@ 2001.02.04 End //@@@ 2001.12.22 Start by MIK: Context Menu Help //Context Menu case WM_CONTEXTMENU: MyWinHelp( hwndDlg, HELP_CONTEXTMENU, (ULONG_PTR)(LPVOID)p_helpids ); // 2006.10.10 ryoji MyWinHelpに変更に変更 return TRUE; //@@@ 2001.12.22 End } return FALSE; }
LRESULT CALLBACK Internal_WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { HPOPUP popup = (HPOPUP)GetWindowLong(hWnd, GWLP_USERDATA); switch (message) { case WM_PAINT: { HDC hdc; PAINTSTRUCT paintstruct; hdc = BeginPaint(hWnd, &paintstruct); DRAWCONTEXT context; context.paintstruct = paintstruct; context.fill_color = CLASSIC_DEFAULT_BASECOLOR; context.draw_color = 0x000000; // NOTE(toni): We can just straight up use the "right" and "bottom" // variables because the x and y position are always gonna be zero anyways. CDrawUtils::FillRectangle3D( &context, 0, 0, popup->menu_size.cx, popup->menu_size.cy, RECT_RAISED ); // Item positions int xPos = 3, yPos = 3; for (int i = 0; i < List_GetCount(popup->menu_items); ++i) { HMENUITEM item = (HMENUITEM)List_Get(popup->menu_items, i); switch (item->item_style & CPM_ITEM_TYPEMASK) { case CPM_ITEM_ICONTEXT: { // TODO(toni): Implement! } case CPM_ITEM_TEXT: { LPCPM_ITEM_EXTRADATA_TEXT text_data = (LPCPM_ITEM_EXTRADATA_TEXT)item->item_extradata; if (!text_data->item_text) break; int text_x = xPos + 16, text_y = yPos + 3; // Selecting the correct font to draw SelectObject( hdc, (item->item_style & CPM_ITEM_DEFAULT) ? popup->menu_item_font_default : popup->menu_item_font ); if ((item->item_style & CPM_ITEM_STATEMASK) == CPM_ITEM_STATE_SELECTED) { context.fill_color = 0x800000; context.draw_color = 0xFFFFFF; CDrawUtils::FillSolidRectangle( &context, xPos, yPos, popup->menu_size.cx - 6, item->item_size.cy ); } else if ((item->item_style & CPM_ITEM_STATEMASK) == CPM_ITEM_STATE_DISABLED) { context.fill_color = CLASSIC_DEFAULT_BASECOLOR; context.draw_color = 0xFFFFFF; CDrawUtils::DrawString( &context, text_data->item_text, text_x + 1, text_y + 1 ); context.draw_color = 0x848284; } else { context.fill_color = CLASSIC_DEFAULT_BASECOLOR; context.draw_color = 0x000000; } SetBkMode(hdc, TRANSPARENT); CDrawUtils::DrawString( &context, text_data->item_text, text_x, text_y ); SetBkMode(hdc, OPAQUE); } break; case CPM_ITEM_SEPARATOR: { context.fill_color = 0x848284; CDrawUtils::FillSolidRectangle(&context, xPos + 1, yPos + 3, popup->menu_size.cx - 8, 1); context.fill_color = 0xFFFFFF; CDrawUtils::FillSolidRectangle(&context, xPos + 1, yPos + 4, popup->menu_size.cx - 8, 1); } break; default: break; // We should never even get here } yPos += item->item_size.cy; } EndPaint(hWnd, &paintstruct); } break; case WM_MOUSEMOVE: { int mx = (int)((short)LOWORD(lParam)), my = (int)((short)HIWORD(lParam)); // Initial item positions int xPos = 3, yPos = 3; bool flags_changed = false; RECT rect_deselected = { 0, 0, 0, 0 }, rect_selected = { 0, 0, 0, 0 }; for (int i = 0; i < List_GetCount(popup->menu_items); ++i) { HMENUITEM item = (HMENUITEM)List_Get(popup->menu_items, i); // Skipping Separators and disabled items... if (((item->item_style & CPM_ITEM_TYPEMASK) == CPM_ITEM_SEPARATOR) || ((item->item_style & CPM_ITEM_STATEMASK) == CPM_ITEM_STATE_DISABLED)) { yPos += item->item_size.cy; continue; } if ((item->item_style & CPM_ITEM_STATEMASK) == CPM_ITEM_STATE_SELECTED) { // Remember: Border is 3 pixels, and width always means "double the value dude!" if (!IsPointInArea(mx, my, xPos, yPos, popup->menu_size.cx - 6, item->item_size.cy)) { // If previous items are still selected, // even though the mouse isn't over it anymore, // just deselect them item->item_style &= ~CPM_ITEM_STATE_SELECTED; // Marking the area that has to be redrawn // // NOTE(toni): There only should ever be exactly // 1 menu item selected at the same time. // So we only have to care about this one area. rect_deselected.left = xPos; rect_deselected.top = yPos; rect_deselected.right = MAKECOORDINATE(xPos, popup->menu_size.cx - 6); rect_deselected.bottom = MAKECOORDINATE(yPos, item->item_size.cy); flags_changed = true; } } else { if (IsPointInArea(mx, my, xPos, yPos, popup->menu_size.cx - 6, item->item_size.cy)) { // Select the current item item->item_style |= CPM_ITEM_STATE_SELECTED; // Marking the area that has to be redrawn rect_selected.left = xPos; rect_selected.top = yPos; rect_selected.right = MAKECOORDINATE(xPos, popup->menu_size.cx - 6); rect_selected.bottom = MAKECOORDINATE(yPos, item->item_size.cy); flags_changed = true; } } yPos += item->item_size.cy; } if (flags_changed) { if ((rect_deselected.left > 0) && (rect_deselected.top > 0) && (rect_deselected.right > 0) && (rect_deselected.bottom > 0)) RedrawWindow(hWnd, &rect_deselected, NULL, RDW_INVALIDATE); if ((rect_selected.left > 0) && (rect_selected.top > 0) && (rect_selected.right > 0) && (rect_selected.bottom > 0)) RedrawWindow(hWnd, &rect_selected, NULL, RDW_INVALIDATE); } } break; case WM_LBUTTONUP: case WM_RBUTTONUP: { for (int i = 0; i < List_GetCount(popup->menu_items); ++i) { HMENUITEM item = (HMENUITEM)List_Get(popup->menu_items, i); if ((item->item_style & CPM_ITEM_STATEMASK) == CPM_ITEM_STATE_SELECTED) { // Notify the menu procedure (if there is one) // that the user clicked on a menu item! if (popup->menu_proc) { CPM_ITEMINFO info = { item, i }; popup->menu_proc(popup, CPM_ITEMSELECTED, &info); } DestroyWindow(hWnd); break; } } } break; case WM_ACTIVATE: { // If our little popup menu gets thrown into the background // just destroy it... if (!wParam) DestroyWindow(hWnd); } break; case WM_DESTROY: { // Before we deallocate, we have to notify the Menu Procedure. // Because maybe the user wants to access the Menu items // before they're gone. // (if there even is one) if (popup->menu_proc) popup->menu_proc(popup, CPM_DESTROY, NULL); // Destroying all the Menu items // we don't need them anymore after this popup menu has been closed. for (int i = 0; i < List_GetCount(popup->menu_items); ++i) { HMENUITEM item = (HMENUITEM)List_Get(popup->menu_items, i); DestroyMenuItem(item); } PostQuitMessage(0); } break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; }
DWORD WINAPI PopupWorker(LPVOID param) { HPOPUP popup = (HPOPUP)param; if (!List_GetCount(popup->menu_items)) { // If there have no menu items been inserted yet // just fail the call and close everything immediately DBG_ErrorExit("Popup Menu creation - No menu items!"); return 1; } popup->menu_wndclass.style = (CS_HREDRAW | CS_VREDRAW); popup->menu_wndclass.lpfnWndProc = Internal_WndProc; popup->menu_wndclass.hCursor = LoadCursor(NULL, IDC_ARROW); popup->menu_wndclass.lpszClassName = GenerateNewClassName(TEXT("Classic_Popup")); if (!RegisterClass(&popup->menu_wndclass)) { DBG_ErrorExit("Popup Menu creation (In Worker thread)"); return 1; } POINT mpos; if (!GetCursorPos(&mpos)) { DBG_ErrorExit("Popup Menu creation - Unable to retrieve cursor positon!"); return 1; } int popup_w = 0, popup_h = 0; for (int i = 0; i < List_GetCount(popup->menu_items); ++i) { HMENUITEM item = (HMENUITEM)List_Get(popup->menu_items, i); // Compute the absolute size of our popup menu if (popup_w < item->item_size.cx) popup_w = item->item_size.cx; popup_h += item->item_size.cy; } // Adding some extra pixels // Think about the border too! popup_w += 19; // Suffix Icon Size (16 x 16) + Border Width (3) popup_h += 7; // Menu Item Extra pixels from bottom + 3 pixels for border popup->menu_wnd = CreateWindowEx( WS_EX_TOOLWINDOW, popup->menu_wndclass.lpszClassName, NULL, WS_POPUP, mpos.x, mpos.y, popup_w, popup_h, NULL, NULL, popup->menu_wndclass.hInstance, NULL ); popup->menu_size.cx = popup_w; popup->menu_size.cy = popup_h; if (!popup->menu_wnd) { DBG_ErrorExit("Popup Menu HWND creation (In Worker thread)"); return 1; } // Gotta give the WndProc access to our popup struct SetWindowLong(popup->menu_wnd, GWLP_USERDATA, (long)popup); if (popup->menu_proc) popup->menu_proc(popup, CPM_CREATE, NULL); ShowWindow(popup->menu_wnd, SW_SHOW); UpdateWindow(popup->menu_wnd); if (popup->menu_proc) popup->menu_proc(popup, CPM_SHOW, NULL); MSG msg; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } DeleteObject(popup->menu_item_font); DeleteObject(popup->menu_item_font_default); // Unregister our Window class since we won't ever use it anymore UnregisterClass( popup->menu_wndclass.lpszClassName, popup->menu_wndclass.hInstance ); CloseHandle(popup->worker_thread_handle); free(popup); // Freeing the Popup handle return 0; }