home *** CD-ROM | disk | FTP | other *** search
- (*******************************************************************)
- (* *)
- (* Microworks ObjectMate 2.6 *)
- (* *)
- (* Windows Interface Develpment Kit the Borland Languages. *)
- (* *)
- (* ODMENU.PAS : Ownerdraw menu unit *)
- (* *)
- (* Copyright 1992-94 Microworks Sydney, Australia. *)
- (* *)
- (*******************************************************************)
-
- (* This unit contains the functions necessary to draw ownerdraw menus. The main
- * functions are 'DrawMenuItem' and 'MeasureMenuItem' and should be called from
- * your WM_DRAWITEM and WM_MEASUREITEM methods respecitively. You can specify the
- * menu text font, highlight color and highlight text color as arguments in a call
- * to DrawMenuItem. Zero values specify a fine system font and the standard
- * Windows' highlight and highlight-text colors. The font handle passed as an
- * argument to DrawMenuItem should also be passed to MeasureMenuItem so that each
- * item is measured and drawn using the same font.
- *
- * The other functions 'StripStrLen', 'GetMenuItemPos', 'ProcessSystemChar' and
- * 'Set3DSystemMenu' are accessory functions. GetMenuItemPos returns the zero based
- * position of a menu item. It's used to determine if the next or previous menu
- * item is a separator and if it is, draw its the adjacent part along with the current
- * item. Set3DSystemMenu sets up an ownerdraw system menu and ProcessSystemChar
- * processes its mnemonics. You should call Set3DSystemMenu from somewhere like
- * SetupWindow. It takes a window handle and application name as arguments.
- * ProcessSystemChar must be called from EvMenuChar if the active menu is the system
- * menu. StripStrLen calculates the length of the menu text minus any 'single' or
- * 'first of a pair' ampersands.
- *
- * Since the system menu rarely gets modified the Set3DSystemMenu and
- * ProcessSystemChar functions are provided for convenience.
-
- * You can enhance your ownerdraw menu's by adding a bitmap or icon glyph to each
- * item. If you do, you will need to pass a pointer to a record that specifies
- * the menu item text and bitmap or icon handle as its members. This pointer is
- * passed as the itemData member of the DRAWITEMSTRUCT and MEASUREITEMSTRUCT
- * structures. You will need to retrieve the text string and bitmap or icon handle
- * in MeasureMenuItem to calculate the itemWidth and itemHeight, and in DrawMenuItem
- * to draw each item.
- *)
-
- unit ODMenu;
-
- interface
-
- uses WinTypes, WinProcs, Win31, Strings, SFX200;
-
- procedure DrawMenuItem (DIS: PDrawItemStruct; Font: HFont; Color, TextColor: TColorRef);
-
- function GetMenuItemPos(Menu: HMenu; ItemID: LongInt): Word;
-
- function GetMenuTextExtent (DC: HDC; Str: PChar; Count: Integer; var Size: TSize): BOOL;
-
- procedure MeasureMenuItem (Wnd: HWnd; MIS: PMeasureItemStruct; Font: HFont);
-
- function ProcessSystemChar (Key: Word): LongInt;
-
- procedure Set3DSystemMenu (Wnd: HWnd; Name: PChar);
-
- implementation
-
- const
-
- LTGRAY = $00C0C0C0;
- BLACK = $00000000;
-
- { StripStrLen - returns the length of string "str" minus any 'underline' or
- 'first of a pair' ampersands. }
-
- function StripStrLen (Str: PChar): Integer;
- var
- i : Integer;
- P : PChar;
- begin
- i := lstrlen(Str);
- P := StrScan(Str, '&');
- while P <> nil do
- begin
- Dec(i);
- P := StrScan(@P[2], '&');
- end;
- StripStrLen := i;
- end;
-
- { DrawMenuItem - draws the ownerdraw menu items. Font, Color and TextColor can be zero. }
-
- procedure DrawMenuItem (DIS: PDrawItemStruct; Font: HFont; Color, TextColor: TColorRef);
- var
- IsNext, IsPrev : Boolean;
- GrayBrush : HBrush;
- WhiteBrush : HBrush;
- Brush, OldBrush : HBrush;
- OldFont : HFont;
- OldPen, Pen : HPen;
- a, b, c : Integer;
- Count, Pos : Word;
- MenuText : array[0..144] of Char;
- begin
- with DIS^ do
- case CtlType of
- ODT_MENU:
- begin
- IsNext := FALSE;
- IsPrev := FALSE;
- if GetSystemMetrics(SM_CYSIZE) = 26 then
- begin
- a := 5; b := 5;
- end
- else
- begin
- if GetSystemMetrics(SM_CXSCREEN) = 640 then
- a := 3
- else
- a := 4;
- b := 3;
- end;
- WhiteBrush := GetStockObject(WHITE_BRUSH);
- GrayBrush := GetStockObject(GRAY_BRUSH);
- if itemState and ODS_SELECTED <> 0 then
- begin
- if Color = 0 then
- Color := GetSysColor(COLOR_HIGHLIGHT);
- if TextColor = 0 then
- TextColor := GetSysColor(COLOR_HIGHLIGHTTEXT);
- end
- else
- begin
- Color := LTGRAY;
- TextColor := BLACK;
- end;
- Brush := CreateSolidBrush(Color);
- SetBkColor(hDC, Color);
- SetBkMode(hDC, TRANSPARENT);
- if (itemState and ODS_DISABLED <> 0) or (itemState and ODS_GRAYED <> 0) then
- begin
- if (itemState and ODS_SELECTED <> 0) then
- begin
- if (Color = LTGRAY) then
- SetTextColor(hDC, RGB(221, 221, 221))
- else
- SetTextColor(hDC, LTGRAY);
- end
- else
- SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
- end
- else
- SetTextColor(hDC, TextColor);
- Count := GetMenuItemCount(hwndItem) - 1;
- Pos := GetMenuItemPos(hwndItem, itemId);
- if (Pos <= Count) and (GetMenuItemID(hwndItem, Pos + 1) = 0) then
- begin
- Inc(rcItem.bottom, a);
- IsNext := TRUE;
- end;
- if (Pos > 0) and (GetMenuItemID(hwndItem, Pos - 1) = 0) then
- begin
- Dec(rcItem.top, b);
- IsPrev := TRUE;
- end;
- OldBrush := SelectObject(hDC, WhiteBrush);
- PatBlt(hDC, rcItem.left, rcItem.top, 2, rcItem.bottom- rcItem.top, PatCopy);
- SelectObject(hDC, GrayBrush);
- PatBlt(hDC, rcItem.right-2, rcItem.top, 2, rcItem.bottom- rcItem.top, PatCopy);
- if (Pos = 0) or IsPrev then
- begin
- SelectObject(hDC, WhiteBrush);
- PatBlt(hDC, rcItem.left+2, rcItem.top, rcItem.right- rcItem.left-2, 1, PatCopy);
- PatBlt(hDC, rcItem.left+2, rcItem.top+1, rcItem.right- rcItem.left-3, 1, PatCopy);
- Inc(rcItem.top, 2);
- end;
- if (Pos = Count) or IsNext then
- begin
- SelectObject(hDC, GrayBrush);
- PatBlt(hDC, rcItem.left+1, rcItem.bottom-1, rcItem.right- rcItem.left-2, 1, PatCopy);
- PatBlt(hDC, rcItem.left+2, rcItem.bottom-2, rcItem.right- rcItem.left-4, 1, PatCopy);
- Dec(rcItem.bottom, 2);
- end;
- InflateRect(rcItem, -2, 0);
- if itemState and ODS_SELECTED <> 0 then
- begin
- if IsNext then
- begin
- Dec(rcItem.bottom, a);
- if itemState and ODS_SELECTED <> 0 then
- begin
- SelectObject(hDC, GetStockObject(LtGray_Brush));
- PatBlt(hDC, rcItem.left, rcItem.bottom, rcItem.right- rcItem.left, a, PatCopy);
- end;
- end;
- if IsPrev then
- begin
- Inc(rcItem.top, b);
- if itemState and ODS_SELECTED <> 0 then
- begin
- SelectObject(hDC, GetStockObject(LtGray_Brush));
- PatBlt(hDC, rcItem.left, rcItem.top -3, rcItem.right- rcItem.left, b, PatCopy);
- end;
- end;
- end;
- FillRect(hDC, rcItem, Brush);
- SelectObject(hDC, OldBrush);
- if itemState and ODS_CHECKED <> 0 then
- begin
- Pen := CreatePen(PS_SOLID, 1, TextColor);
- OldPen := SelectObject(hDC, Pen);
- c := rcItem.top + (((rcItem.bottom - rcItem.top) - 10) div 2);
- MoveTo(hDC, rcItem.Left + 3, c + 5);
- LineTo(hDC, rcItem.Left + 3, c + 10);
- MoveTo(hDC, rcItem.Left + 4, c + 4);
- LineTo(hDC, rcItem.Left + 4, c + 10);
- MoveTo(hDC, rcItem.Left + 5, c + 7);
- LineTo(hDC, rcItem.Left + 12, c + 0);
- MoveTo(hDC, rcItem.Left + 5, c + 8);
- LineTo(hDC, rcItem.Left + 13, c + 0);
- SelectObject(hDC, OldPen);
- DeleteObject(Pen);
- end;
- lstrcpy(MenuText, PChar(itemData));
- if Font <> 0 then
- OldFont := SelectObject(hDC, Font)
- else
- OldFont := SelectObject(hDC, GetSFXObject(SYSTEM_FINE_FONT));
- rcItem.left := 7 + 12;
- if (itemState and ODS_SELECTED = 0) then
- begin
- if IsNext then
- Dec(rcItem.bottom, a)
- else
- if IsPrev then
- Inc(rcItem.top, b);
- end;
- DrawText(hDC, MenuText, -1, rcItem, DT_SINGLELINE + DT_VCENTER + DT_EXPANDTABS);
- if (itemState and ODS_SELECTED <> 0) and not (Color = LTGRAY) then
- begin
- OffsetRect(rcItem, 1, 0);
- DrawText(hDC, MenuText, -1, rcItem, DT_SINGLELINE + DT_VCENTER + DT_EXPANDTABS);
- end;
- SelectObject(hDC, OldFont);
- DeleteObject(Brush);
- end;
- end;
- end;
-
- { GetMenuItemPos -> returns the zero based position of a menu item }
-
- function GetMenuItemPos(Menu: HMenu; ItemID: LongInt): Word;
- var
- Count : Integer;
- Item : LongInt;
- begin
- (* To properly sort through a menu items, if a menu has more than one sub menu
- * each sub menu must have different menu handle.
- *)
- Count := GetMenuItemCount(Menu);
- if Count > -1 then
- begin
- if IsMenu(ItemID) then
- repeat
- Dec(Count);
- Item := LongInt(GetSubMenu(Menu, Count));
- until (Item = ItemID) or (Count = 0)
- else
- repeat
- Dec(Count);
- Item := GetMenuItemID(Menu, Count);
- until (Item = ItemID) or (Count = 0);
- end;
- GetMenuItemPos := Count;
- end;
-
- { GetMenuTextExtent -> imports the WIN31 GetTextExtentPoint function correctly }
-
- function GetMenuTextExtent; external 'GDI' index 471;
-
- { MeasureMenuItem -> sets the width and height of the ownerdraw menu items. Font can be zero }
-
- procedure MeasureMenuItem (Wnd: HWnd; MIS: PMeasureItemStruct; Font: HFont);
- var
- DC : HDC;
- MenuFont : HFont;
- OldFont : HFont;
- Size : TSize;
- MenuText : array[0..144] of Char;
- begin
- with MIS^ do
- case CtlType of
- ODT_MENU:
- begin
- DC := GetDC(Wnd);
- if Font = 0 then
- MenuFont := GetSFXObject(SYSTEM_FINE_FONT)
- else
- MenuFont := Font;
- OldFont := SelectObject(DC, MenuFont);
- lstrcpy(MenuText, PChar(itemData));
- GetMenuTextExtent(DC, MenuText, StripStrLen(MenuText), Size);
- ItemWidth := Size.cX + 20;
- ItemHeight := Size.cY + ((Size.cY div 5) * 2);
- SelectObject(DC, OldFont);
- ReleaseDC(Wnd, DC);
- end;
- end;
- end;
-
- { ProcessSystemChar -> call from WM_MENUCHAR to process the system menu mnemonics }
-
- function ProcessSystemChar (Key: Word): LongInt;
- begin
- case Key of
- 82, 114 : ProcessSystemChar := MakeLong(0, 2);
- 77, 109 : ProcessSystemChar := MakeLong(1, 2);
- 83, 115 : ProcessSystemChar := MakeLong(2, 2);
- 78, 110 : ProcessSystemChar := MakeLong(3, 2);
- 88, 120 : ProcessSystemChar := MakeLong(4, 2);
- 67, 99 : ProcessSystemChar := MakeLong(6, 2);
- else
- ProcessSystemChar := 0;
- end;
- end;
-
- { Set3DSystemMenu-> sets up a basic 3D system menu, minus the 'Switch To' item. }
-
- procedure Set3DSystemMenu (Wnd: HWnd; Name: PChar);
- const
- TextStr : array[0..50] of Char = '';
- var
- SysMenu : HMenu;
- begin
- SysMenu := GetSystemMenu(Wnd, False);
- RemoveMenu(SysMenu, 7, mf_ByPosition);
- RemoveMenu(SysMenu, 7, mf_ByPosition);
- ModifyMenu(SysMenu, 0, mf_ByPosition or mf_OwnerDraw, sc_Restore, '&Restore');
- ModifyMenu(SysMenu, 1, mf_ByPosition or mf_OwnerDraw, sc_Move, '&Move');
- ModifyMenu(SysMenu, 2, mf_ByPosition or mf_OwnerDraw, sc_Size, '&Size');
- ModifyMenu(SysMenu, 3, mf_ByPosition or mf_OwnerDraw, sc_Minimize, 'Mi&nimize');
- ModifyMenu(SysMenu, 4, mf_ByPosition or mf_OwnerDraw, sc_Maximize, 'Ma&ximize');
- wvsprintf(TextStr, '&Close %s Alt+F4', Name);
- ModifyMenu(SysMenu, 6, mf_ByPosition or mf_OwnerDraw, sc_Close, TextStr);
- end;
-
- begin
- end.