CLuxSubMenuクラス
CLuxSubMenuクラスはサブメニューを管理するためのクラスです。ほとんどはCLuxMenuクラスと同等の処理を行いますが、親メニューのようにメニューバーを描画するわけではないので、専用のメソッドをオーバーライドしていきたいと思います。
CLuxSubMenuとCLuxMenuは異なるクラスのため、QueryInterfaceメソッドをオーバーライドして専用のGUIDを識別させる必要があります。判別用のGUIDを変更するだけなので、コードの詳細は省略します。
GetItemSizeメソッド
CLuxMenuのGetItemSizeメソッドと異なる点は、文字列描画に必要な幅に加え、アイコン用の幅と文字列の右側に位置するある程度のブランクを考慮し、50ピクセルだけ多めにサイズ指定している点です。他はCLuxMenu.GetItemSizeと同じような処理になります。
'------------------------------------------------------- ' メニューアイテムの表示領域を取得 '------------------------------------------------------- Virtual Sub GetItemSize(item_index As Long, ByRef size As SIZE) If ppobj_MenuItemData[item_index]->str Then Dim hdc As HDC hdc=GetDC(GetDesktopWindow()) Dim hOldFont As HFONT hOldFont=SelectObject(hdc,m_hMenuFont) GetTextExtentPoint32(hdc, ppobj_MenuItemData[item_index]->str, lstrlen(ppobj_MenuItemData[item_index]->str), size) SelectObject(hdc,hOldFont) DeleteDC(hdc) size.cx+=50 If size.cy<22 Then size.cy=22 Else 'セパレータのとき size.cx=50 size.cy=10 End If End Sub
OwnerDrawメソッド
このメソッドは、メニューバー描画とポップアップメニューの見た目が違うのと同じくらい、CLuxMenuのOwnerDrawメソッドとは大きく異なります。
まずCLuxCtrlBase.CreateGradationBitmapメソッドを利用して左端に表示するグラデーションビットマップを生成し、描画を行います。セパレータの場合は境界線を引いて完了です。
bSelectを使って選択状態を識別し、必要に応じてホットイメージで背景を描画します。この際に、メニューアイテムの状態が無効になっていないか(MFS_DISABLEDが指定されていないか)も考慮しておきましょう。
メニューアイテムがチェック状態の場合は、アイコンを描画せずにチェックマークを描画しています。チェック状態でない場合は、アイコンが指定されていればアイコンを描画します。チェック状態でなく、アイコンも指定されていない場合は左側のグラデーションバーには何も表示する必要はありません。また、アイコンの描画にはDrawIconEx関数を使用し、透過処理などもその関数に任せます。
最後に、文字列を描画して完了ですが、ショートカット文字列の存在を忘れずに行います。szMainにメニュー文字列を、szShortcutにショートカット文字列を分別して格納し、szShortcutは右端に描画します。
'------------------------------------------------------- ' サブメニューのオーナー描画 '------------------------------------------------------- Virtual Sub OwnerDraw(hdc As HDC, ByRef ref_rc As RECT, bSelect As BOOL, item_index As Long) Dim rc As RECT Dim BackColor As COLORREF, TextColor As COLORREF Dim i As Long Dim hPen As HPEN,hOldPen As HPEN Dim hBrush As HBRUSH, hOldBrush As HBRUSH '----------------------------- ' 左側のグラデーションを描画 '----------------------------- Dim size As SIZE size.cx=22 size.cy=ref_rc.bottom-ref_rc.top Dim hBmp As HBITMAP hBmp=CreateGradationBitmap(size,RGB(254,254,251), _ RGB(196,196,173),DIRECTION_HORZ) Dim memdc As HDC memdc=CreateCompatibleDC(hdc) SelectObject(memdc,hBmp) BitBlt(hdc,ref_rc.left,ref_rc.top,size.cx,size.cy,memdc,0,0,SRCCOPY) DeleteDC(memdc) DeleteObject(hBmp) If ppobj_MenuItemData[item_index]->str=0 Then 'セパレータのとき hPen=CreatePen(PS_SOLID,0,MenuColor_Default_Line) hOldPen=SelectObject(hdc,hPen) MoveToEx(hdc,ref_rc.left+24, ref_rc.top+(ref_rc.bottom-ref_rc.top)\2,ByVal NULL) LineTo(hdc,ref_rc.right,ref_rc.top+(ref_rc.bottom-ref_rc.top)\2) SelectObject(hdc,hOldPen) DeleteObject(hPen) Exit Sub End If 'アイテムの状態を取得 Dim mii As MENUITEMINFO mii.cbSize=SizeOf(MENUITEMINFO) mii.fMask=MIIM_STATE GetMenuItemInfo(m_hMenu,item_index,1,mii) If bSelect<>0 and (mii.fState and MFS_DISABLED)=0 Then 'ホットイメージで表示 BackColor=MenuColor_Hot_Back hPen=CreatePen(PS_SOLID,0,MenuColor_Hot_Line) hOldPen=SelectObject(hdc,hPen) hBrush=CreateSolidBrush(BackColor) hOldBrush=SelectObject(hdc,hBrush) Rectangle(hdc,ref_rc.left,ref_rc.top,ref_rc.right,ref_rc.bottom) SelectObject(hdc,hOldPen) SelectObject(hdc,hOldBrush) DeleteObject(hPen) DeleteObject(hBrush) Else BackColor=GetSysColor(COLOR_MENU) rc=ref_rc rc.left=ref_rc.left+22 rc.right=ref_rc.right '背景を塗りつぶす hBrush=CreateSolidBrush(BackColor) FillRect(hdc,rc,hBrush) DeleteObject(hBrush) End If If mii.fState and MFS_CHECKED Then 'チェックマークの外枠を描画 rc=ref_rc rc.top++ rc.right=rc.left+20 rc.bottom-- hPen=CreatePen(PS_SOLID,0,MenuColor_Hot_Line) hOldPen=SelectObject(hdc,hPen) hBrush=CreateSolidBrush(BackColor) hOldBrush=SelectObject(hdc,hBrush) Rectangle(hdc,rc.left,rc.top,rc.right,rc.bottom) SelectObject(hdc,hOldPen) SelectObject(hdc,hOldBrush) DeleteObject(hPen) DeleteObject(hBrush) 'チェックマークを描画 Dim BaseX As Long : BaseX=rc.left Dim BaseY As Long : BaseY=rc.top For i=0 To ELM(3) SetPixel(hdc,BaseX+6+i,BaseY+9+i,MenuColor_Text) SetPixel(hdc,BaseX+6+i,BaseY+10+i,MenuColor_Text) Next For i=0 To ELM(4) SetPixel(hdc,BaseX+9+i,BaseY+10-i,MenuColor_Text) SetPixel(hdc,BaseX+9+i,BaseY+11-i,MenuColor_Text) Next Else If ppobj_MenuItemData[item_index]->hIcon Then 'アイコンを描画 Dim hIcon As HICON If mii.fState and MFS_DISABLED Then hIcon=ppobj_MenuItemData[item_index]->hGrayIcon Else hIcon=ppobj_MenuItemData[item_index]->hIcon End If DrawIconEx(hdc,ref_rc.left+1, ref_rc.top+3,hIcon,16,16,0,NULL,DI_NORMAL) End If End If 'メイン文字列とショートカットキー文字列を分別 Dim szMain[255] As Byte,szShortcut[255] As Byte i=0 Do If ppobj_MenuItemData[item_index]->str[i]=Asc(Ex"\t") Then szMain[i]=0 lstrcpy(szShortcut,ppobj_MenuItemData[item_index]->str+i+1) Exit Do End If szMain[i]=ppobj_MenuItemData[item_index]->str[i] If ppobj_MenuItemData[item_index]->str[i]=0 Then szShortcut[0]=0 Exit Do End If i++ Loop rc=ref_rc rc.left=ref_rc.left+26 rc.right=ref_rc.right Dim hOldFont As HFONT hOldFont=SelectObject(hdc,m_hMenuFont) If mii.fState and MFS_DISABLED Then '淡色カラー TextColor=MenuColor_Gray_Text Else '通常カラー TextColor=MenuColor_Text End If SetBkMode(hdc, TRANSPARENT) SetTextColor(hdc, TextColor) DrawText(hdc,szMain,-1,rc,DT_VCENTER or DT_LEFT or DT_SINGLELINE) If szShortcut[0] Then rc.left=rc.right-45 DrawText(hdc,szShortcut,-1,rc, DT_VCENTER or DT_LEFT or DT_SINGLELINE) End If SelectObject(hdc,hOldFont) End Sub
