;*************************************************************
;* coolmenu.asm
;*
;* This file contains coolmenu/toolbars/accelerators engine code.
;* You must include in executable section of the program.
;*
;* You can use this work for any purpos, only don't forget to
;* write somewhere in docs: "Based on work of John Found" or
;* something similar. :)
;*
;* '2003 John Found
;*************************************************************
iglobal
cToolbarClassName du TOOLBAR_CLASS, 0
endg
CoolCode:
;************************************************************
; Function DrawMenuIcon
; Parameters:
; DC - device context
; x,y - coordinates of upper left corner of the item
; height - height of the menu item
; State - state of the menu item
;************************************************************
proc DrawMenuIcon, .DC, .x, .y, .height, .Image, .State
.v dd 0
.Brush1 LOGBRUSH
.Brush2 LOGBRUSH
begin
mov [.Brush1.lbStyle], BS_SOLID
mov [.Brush2.lbStyle], BS_SOLID
; invoke GetSysColor, COLOR_BTNHIGHLIGHT
; test [.State], ODS_CHECKED
; jnz @f
; invoke GetSysColor, COLOR_MENU
;@@:
; invoke ImageList_SetBkColor, [hImlMenu], eax
; Compute coordinates
mov eax, [.y]
shl eax, 1
add eax, [.height]
sub eax, [MenuIconHeight]
sub eax, 2 ; 2 more pixels???
sar eax, 1
mov [.v],eax
mov ecx,[.x]
inc eax
inc ecx
; Select image list
mov ebx,[hImlMenu]
test [.State],ODS_GRAYED
jz @f
mov ebx,[hImlMenuGray]
@@:
cmp [.Image],-1
jne @f
test [.State],ODS_CHECKED
jz .qfalse ; if the item is not checked and there is no Image (Image = -1) then return false
mov [.Image], ImageChecked
@@:
invoke ImageList_Draw, ebx, [.Image], [.DC], ecx, eax, ILD_NORMAL
invoke GetSysColor, COLOR_MENU
invoke ImageList_SetBkColor, ebx, eax
; Draw border
mov [.Brush1.lbColor],$ffffff
mov [.Brush2.lbColor],$808080
test [.State], ODS_GRAYED
jz @f
invoke GetSysColor,COLOR_GRAYTEXT
mov [.Brush1.lbColor],eax
mov [.Brush2.lbColor],eax
@@:
test [.State],ODS_SELECTED or ODS_CHECKED
jnz @f
invoke GetSysColor,COLOR_MENU
mov [.Brush1.lbColor],eax
mov [.Brush2.lbColor],eax
@@:
test [.State],ODS_CHECKED
jz @f
mov [.Brush1.lbColor], $808080
mov [.Brush2.lbColor], $ffffff
@@:
lea eax, [.Brush1]
invoke ExtCreatePen,PS_COSMETIC,1,eax,0,NULL
invoke SelectObject,[.DC],eax
push eax
mov esi,[.v]
mov ebx,[.x]
add esi, [MenuIconHeight]
add ebx, [MenuIconWidth]
add esi, 2
add ebx, 2
invoke MoveToEx,[.DC],[.x],esi,NULL
invoke LineTo,[.DC],[.x],[.v]
invoke LineTo,[.DC],ebx,[.v]
; pop eax
invoke SelectObject,[.DC] ;,eax The eax is in stack, don't pop/push again
invoke DeleteObject,eax
lea eax, [.Brush2]
invoke ExtCreatePen, PS_COSMETIC, 1, eax, 0, NULL
invoke SelectObject,[.DC],eax
push eax
dec [.x]
invoke LineTo,[.DC],ebx,esi
invoke LineTo,[.DC],[.x],esi
; pop eax
invoke SelectObject,[.DC] ;,eax
invoke DeleteObject,eax
xor eax,eax
dec eax
jmp .finish
.qfalse:
xor eax,eax
.finish:
return
endp
;************************************************************
; Function DrawMenuText *
; Parameters: *
; DC - device context *
; x1,y1,x2,y2 - rectangle to draw text *
; xOfs - offset of text in rectangle *
; Caption - pointer to the caption string *
; CapLen - length of the caption string *
; State - state of the menu item *
; ID - ID of the menu function. *
;************************************************************
proc DrawMenuText, .DC, .x1, .y1, .x2, .y2, .xOfs, .Caption, .CapLen, .State, .ID, .ptrAccel
.str rb 64
begin
; Draw background rectangle
mov esi,COLOR_HIGHLIGHT
mov edi,COLOR_HIGHLIGHTTEXT
test [.State],ODS_SELECTED
jnz @f
mov esi,COLOR_MENU
mov edi,COLOR_MENUTEXT
@@:
test [.State],ODS_GRAYED
jz @f
mov edi,COLOR_GRAYTEXT
@@:
invoke GetSysColor,esi
invoke SetBkColor,[.DC],eax
invoke GetSysColor,edi
invoke SetTextColor,[.DC],eax
inc esi
lea ebx,[.x1]
invoke FillRect,[.DC],ebx,esi
sub [.x2],12
; Draw text
mov ecx,[.xOfs]
add [.x1],ecx
stdcall utf8ToWideChar, [.Caption]
push eax
invoke DrawTextW, [.DC], eax, [.CapLen], ebx, \
DT_LEFT or DT_SINGLELINE or DT_VCENTER
stdcall FreeMem ; from the stack
lea esi,[.str]
stdcall AccelToStr, [.ptrAccel], esi
mov dword [esi+eax], 0
stdcall utf8ToWideChar, esi
push eax
invoke DrawTextW, [.DC], eax, -1, ebx, DT_RIGHT or DT_SINGLELINE or DT_VCENTER
stdcall FreeMem ; from the stack
pop eax
invoke SelectObject, [.DC], eax
return
endp
;*************************************************************
; Draws the entire menu item (icon and text)
;*************************************************************
proc DoDrawItem, .DC, .x1, .y1, .x2, .y2, .Caption, .CapLen, .State, .Image, .ID, .ptrAccel
begin
mov eax, [.y2]
sub eax, [.y1]
stdcall DrawMenuIcon, [.DC], [.x1], [.y1], eax, [.Image], [.State]
mov ebx, [MenuIconWidth]
add ebx, 4
test eax, eax
jz @f ; if no image, don't move the left side of the rectangle.
add [.x1], ebx
xor ebx, ebx
@@:
inc ebx
; Print the text.
stdcall DrawMenuText, [.DC], [.x1], [.y1], [.x2], [.y2], ebx, \
[.Caption], [.CapLen], [.State], [.ID], [.ptrAccel]
return
endp
;************************************************************
; On draw item.
;************************************************************
proc OnDrawItem, .lparam
begin
mov esi, [.lparam] ; address of TDrawItemStruct
cmp [esi+DRAWITEMSTRUCT.CtlType], ODT_MENU
jne .qfalse
mov edi,[esi+DRAWITEMSTRUCT.itemData]
test edi,edi
jz .qfalse
movzx eax, [edi+TAction.TextLen]
movsx ecx, [edi+TAction.Image]
stdcall DoDrawItem, [esi+DRAWITEMSTRUCT.hDC], \
[esi+DRAWITEMSTRUCT.rcItem.left], \
[esi+DRAWITEMSTRUCT.rcItem.top], \
[esi+DRAWITEMSTRUCT.rcItem.right], \
[esi+DRAWITEMSTRUCT.rcItem.bottom], \
[edi+TAction.ptrText], \
eax, \
[esi+DRAWITEMSTRUCT.itemState], \
ecx, \
[esi+DRAWITEMSTRUCT.CtlID], \
[edi+TAction.ptrAccel]
xor eax,eax
inc eax
jmp .finish
.qfalse:
xor eax,eax
.finish:
return
endp
;************************************************************
; On measure item.
;************************************************************
proc OnMeasureItem, .hwnd, .lparam
.ARect RECT
.DC dd ?
.str rb 64
.sz SIZE
begin
mov esi,[.lparam] ; address of MEASUREITEMSTRUCT
cmp [esi+MEASUREITEMSTRUCT.CtlType], ODT_MENU
jne .qfalse
mov edi,[esi+MEASUREITEMSTRUCT.itemData]
test edi,edi
jz .qfalse
stdcall GetDefaultFont, gdfMenu
push eax
invoke GetDC,[.hwnd] ; try with current window DC
mov [.DC],eax
invoke SelectObject, eax ; the font is already in the stack.
push eax
xor eax,eax
mov [.ARect.left],eax
mov [.ARect.right],eax
mov [.ARect.top],eax
mov [.ARect.bottom],eax
lea ebx,[.ARect]
movzx eax, [edi+TAction.TextLen]
lea ebx, [esi+MEASUREITEMSTRUCT.itemWidth]
stdcall utf8ToWideChar, [edi+TAction.ptrText]
push eax
dec ecx
invoke GetTextExtentPoint32W, [.DC], eax, ecx, ebx
stdcall FreeMem ; from the stack
mov eax, [MenuIconHeight]
add eax, 3
cmp [esi+MEASUREITEMSTRUCT.itemHeight], eax ; this is height of the icon image
jae @f
mov [esi+MEASUREITEMSTRUCT.itemHeight], eax
@@:
lea ebx,[.str]
stdcall AccelToStr, [edi+TAction.ptrAccel], ebx
test eax, eax
jz .NoAccel
mov dword [ebx+eax], 0
stdcall utf8ToWideChar, ebx
push eax
lea edx,[.sz]
dec ecx
invoke GetTextExtentPoint32W, [.DC], eax, ecx, edx
stdcall FreeMem ; from the stack
mov ebx, [.sz.cx]
add [esi+MEASUREITEMSTRUCT.itemWidth], ebx
cmp [edi+TAction.Image], -1
jne .NoAccel
add [esi+MEASUREITEMSTRUCT.itemWidth], 12
.NoAccel:
add [esi+MEASUREITEMSTRUCT.itemWidth], 24 ; the distance between the label and the accelerator.
invoke SelectObject,[.DC] ; the last arg is in stack.
invoke DeleteObject, eax
invoke ReleaseDC, [.hwnd], [.DC]
xor eax, eax
inc eax
return
.qfalse:
xor eax,eax
return
endp
uglobal
buffMenuitem MENUITEMINFO
endg
;*********************************************************
; On Menu char WM_MENUCHAR message
;*********************************************************
proc OnMenuChar, .wparam, .hmenu
.count dd ?
.widechar rw 512
begin
test word [.wparam+2], MF_SYSMENU
jnz .default
invoke GetMenuItemCount, [.hmenu]
cmp eax,0
jle .default
mov [.count],eax
xor ebx,ebx
mov [buffMenuitem.cbSize],sizeof.MENUITEMINFO
mov [buffMenuitem.fMask], MIIM_DATA or MIIM_TYPE or MIIM_SUBMENU
.searchloop:
invoke GetMenuItemInfoW, [.hmenu], ebx, TRUE, buffMenuitem
test eax, eax
jz .notthis
cmp [buffMenuitem.hSubMenu], 0
jne .notthis ; windows will handle this
test [buffMenuitem.fType], MFT_OWNERDRAW
jz .nod
mov edi, [buffMenuitem.dwItemData]
stdcall StrPtr, [edi+TAction.ptrText]
lea ecx, [.widechar]
invoke MultiByteToWideChar, CP_UTF8, 0, eax, -1, ecx, 512
mov ecx, eax
lea edi, [.widechar]
jmp .OK
.nod:
cmp [buffMenuitem.fType], MFT_STRING
jne .notthis
mov edi, [buffMenuitem.dwTypeData]
mov ecx, [buffMenuitem.cch]
; test edi, edi
; jz .notthis
.OK:
jecxz .notthis
mov dx, word [.wparam]
cmp dx, $61
jb .search
cmp dx, $7a
ja .search
sub dx, 20h
.search:
mov eax, [edi]
cmp ax, '&'
jne .next
shr eax, 16
cmp ax, $61
jb @f
cmp ax, $7a
ja @f
sub ax, 20h
@@:
cmp ax, dx
je .this
.next:
add edi, 2
loop .search
.notthis:
inc ebx
cmp ebx, [.count]
jne .searchloop
;not found
.default:
stc
return
.this:
mov ax, 2
shl eax, 16
mov ax, bx
.finish:
clc
return
endp
;****************************************************************
; Creates menu from CoolMenu structure (See CoolMenu macro).
; Returns handle to the menu.
;
; ptrMenuItems: pointer to the CoolMenu array
; fPopup: if <>0, creates popup menu instead of main menu
;****************************************************************
proc CreateCoolMenu, .ptrMenuItems, .fPopup
.item MENUITEMINFO
.level dd ?
begin
push esi edi ebx
mov esi, [.ptrMenuItems]
mov [.level], 0
mov eax, [.fPopup]
test eax, eax
jnz .popup
invoke CreateMenu
jmp .cont
.popup:
invoke CreatePopupMenu
.cont:
mov ebx,eax
mov [.item.cbSize],sizeof.MENUITEMINFO
mov [.item.fMask], MIIM_ID or MIIM_STATE or MIIM_SUBMENU or MIIM_TYPE or MIIM_DATA
mov [.item.fState],MFS_ENABLED
mov [.item.hbmpChecked],0
mov [.item.hbmpUnchecked],0
.loopitems:
xor eax,eax
mov [.item.hSubMenu],eax
mov [.item.wID],eax
mov [.item.dwItemData],eax
test [esi+TCoolMenuItem.Flags], mfEnd
jnz .leveldn
test [esi+TCoolMenuItem.Flags], mfSeparator
jnz .separator
test [esi+TCoolMenuItem.Flags], mfSubmenu
jnz .submenu
mov [.item.fState],MFS_ENABLED
test [esi+TCoolMenuItem.Flags], mfChecked
jz @f
or [.item.fState], MFS_CHECKED
@@:
mov [.item.fType],MFT_OWNERDRAW
movzx edi, [esi+TCoolMenuItem.Action]
imul edi, sizeof.TAction
add edi, MainActionList
movzx eax,[edi+TAction.ID]
mov [.item.wID],eax
mov [.item.dwItemData], edi
jmp .ready
.separator:
mov [.item.fType], MFT_SEPARATOR
jmp .ready
.submenu:
invoke CreatePopupMenu
mov [.item.hSubMenu],eax
mov [.item.fType], MFT_STRING
movzx edi, [esi+TCoolMenuItem.Action] ; Action is the offset to the string
add edi, esi
stdcall utf8ToWideChar, edi
mov [.item.dwTypeData], eax
lea eax,[.item]
invoke InsertMenuItemW, ebx, -1, TRUE, eax
stdcall FreeMem, [.item.dwTypeData]
inc [.level]
push ebx
mov ebx,[.item.hSubMenu]
jmp .next
.leveldn:
cmp [.level],0
je .next
pop ebx
dec [.level]
jmp .next
.ready:
lea eax, [.item]
invoke InsertMenuItemW, ebx, -1, TRUE, eax
.next:
add esi,sizeof.TCoolMenuItem
cmp word [esi],-2 ; end of structure
jne .loopitems
mov eax,ebx
pop ebx edi esi
return
endp
proc GetHintText, .ActList, .action
begin
mov eax, [.action]
imul eax, sizeof.TAction
add eax, [.ActList]
mov eax, [eax+TAction.ptrHint]
return
endp
;***********************************************************************
; Creates toolbar from CoolToolbar structure (See CoolToolbar macro).
; Returns handle to the toolbar.
;***********************************************************************
proc CreateCoolToolbar, .ptrActionList, .ptrToolbarItems, .ParentWindow, .ToolbarID
.item TToolbarButton
.win WINDOWPOS
begin
; Create toolbar
xor esi,esi
invoke GetModuleHandleW, esi
mov edi, eax
invoke CreateWindowExW, esi, cToolbarClassName, NULL, \
WS_CHILD or \
WS_VISIBLE or WS_CLIPSIBLINGS or \
TBSTYLE_TRANSPARENT or \
TBSTYLE_FLAT or \
TBSTYLE_TOOLTIPS or \
TBSTYLE_WRAPABLE or \
CCS_NOPARENTALIGN or CCS_NORESIZE or CCS_NODIVIDER, \
esi, esi, esi, esi, \
[.ParentWindow], [.ToolbarID], \
edi, NULL
mov ebx,eax
stdcall SubclassWindow, ebx, CoolToolbarProc
invoke SendMessageW, ebx, TB_BUTTONSTRUCTSIZE, TToolbarButton.size, esi
; make arrows for dropdown buttons
invoke SendMessageW, ebx, TB_GETEXTENDEDSTYLE, esi, esi
or eax,TBSTYLE_EX_DRAWDDARROWS
invoke SendMessageW, ebx, TB_SETEXTENDEDSTYLE, esi, eax
; make tooltip to appear on not active main window.
invoke SendMessageW, ebx, TB_GETTOOLTIPS, 0, 0
mov esi, eax
invoke GetWindowLongW, esi, GWL_STYLE
or eax, TTS_ALWAYSTIP or TTS_NOPREFIX
invoke SetWindowLongW, esi, GWL_STYLE, eax
; Set tooltip delay time.
invoke SendMessageW, esi, TTM_SETDELAYTIME, TTDT_AUTOMATIC, 600
; Create buttons
mov esi, [.ptrToolbarItems]
xor eax, eax
mov [.item.dwData], eax
mov [.item.iString], -1
.itemloop:
cmp [esi+TCoolButton.Action],-2 ; end of structure
je .finish
test [esi+TCoolButton.Flags],bfSeparator
jnz .separator
movzx edi,[esi+TCoolButton.Action]
imul edi,sizeof.TAction
add edi,[.ptrActionList]
movsx eax,[edi+TAction.Image]
movzx ecx,[edi+TAction.ID]
mov [.item.iBitmap],eax
mov [.item.idCommand],ecx
mov al,[esi+TCoolButton.Flags]
mov [.item.fsStyle],al
and [.item.fsStyle], $1f
mov [.item.fsState],TBSTATE_ENABLED
test al, bfDisabled
jz @f
mov [.item.fsState],0
@@:
test al, bfChecked
jz @f
or [.item.fsState], TBSTATE_CHECKED
@@:
test al, bfWrap
jz .ready
or [.item.fsState], TBSTATE_WRAP or TBSTATE_ENABLED
jmp .ready
.separator:
xor eax,eax
mov [.item.iBitmap],eax
mov [.item.idCommand],eax
mov [.item.fsState],al
mov [.item.fsStyle],TBSTYLE_SEP
.ready:
lea edi,[.item]
invoke SendMessageW, ebx, TB_ADDBUTTONS, 1, edi
add esi, sizeof.TCoolButton
jmp .itemloop
.finish:
mov eax,ebx
return
endp
proc CoolToolbarProc, .hwnd, .wmsg, .wparam, .lparam
begin
dispatch [.wmsg]
.ondefault:
stc
return
oncase SGM_AUTOSIZE
invoke SendMessageW, [.hwnd], TB_AUTOSIZE, 0, 0
stdcall __ComputeToolbarSize, [.hwnd]
OutputValue "Toolbar width: ", eax, 10, -1
OutputValue "Toolbar height: ", edx, 10, -1
push eax edx
; invoke SetWindowPos, [.hwnd], 0, 0, 0, eax, edx, SWP_NOZORDER
pop edx eax
and eax, $ffff
shl edx, 16
or eax, edx
clc
return
enddispatch
endp
proc GetNCSize, .hwnd
.winrect RECT
.client RECT
begin
lea eax, [.winrect]
invoke GetWindowRect, [.hwnd], eax
lea eax, [.client]
invoke GetClientRect, [.hwnd], eax
mov eax, [.winrect.right]
mov edx, [.winrect.bottom]
sub eax, [.winrect.left]
sub edx, [.winrect.top]
sub eax, [.client.right]
sub edx, [.client.bottom]
return
endp
proc __ComputeToolbarSize, .hToolbar
.winbounds TBounds
.winrect RECT
begin
pushad
mov [.winbounds.width], $4
mov [.winbounds.height], $4
xor esi,esi
lea ebx, [.winrect]
.whiletoolbar:
invoke SendMessageW, [.hToolbar], TB_GETITEMRECT, esi, ebx
test eax,eax
jz .endauto
; [.winbounds.width] = max ([.winbounds.width], [.winrect.right])
; [.winbounds.height] = max ([.winbounds.height], [.winrect.bottom])
mov eax, [.winbounds.width]
mov ecx, [.winbounds.height]
cmp eax, [.winrect.right]
cmovl eax, [.winrect.right]
cmp ecx, [.winrect.bottom]
cmovl ecx, [.winrect.bottom]
mov [.winbounds.width], eax
mov [.winbounds.height], ecx
inc esi
jmp .whiletoolbar
.endauto:
stdcall GetNCSize, [.hToolbar]
add eax, [.winbounds.width]
add edx, [.winbounds.height]
mov [esp+4*regEAX], eax
mov [esp+4*regEDX], edx
popad
return
endp
struct TKeyName
.VirtKey dw ?
.NextOfs db ?
.Text db ?
ends
struc dk [code,txt] {
forward
local .TheEnd
dw code
db .TheEnd-$+2
db txt,0
.TheEnd = $
common
dw -1
}
iglobal
VKeyArray dk \
VK_BACK, 'BkSp', \
VK_TAB, 'Tab', \
VK_CLEAR, 'Clear', \
VK_RETURN, 'Enter', \
VK_SHIFT, 'Shift', \
VK_CONTROL, 'Ctrl', \
VK_MENU, 'Alt', \
VK_PAUSE, 'Pause', \
VK_CAPITAL, 'CapsLock', \
VK_ESCAPE, 'Esc', \
VK_SPACE, 'Space', \
VK_PGUP, 'PgUp', \
VK_PGDN, 'PgDn', \
VK_END, 'End', \
VK_HOME, 'Home', \
VK_LEFT, 'Left', \
VK_UP, 'Up', \
VK_RIGHT, 'Right', \
VK_DOWN, 'Down', \
VK_SELECT, 'Select', \
VK_EXECUTE, 'Execute', \
VK_SNAPSHOT, 'PrtScr', \
VK_INSERT, 'Ins', \
VK_DELETE, 'Del', \
VK_HELP, 'Help', \
VK_LWIN, 'LeftWin', \
VK_RWIN, 'RightWin', \
VK_APPS, 'Apps', \
VK_NUMPAD0, 'Num0', \
VK_NUMPAD1, 'Num1', \
VK_NUMPAD2, 'Num2', \
VK_NUMPAD3, 'Num3', \
VK_NUMPAD4, 'Num4', \
VK_NUMPAD5, 'Num5', \
VK_NUMPAD6, 'Num6', \
VK_NUMPAD7, 'Num7', \
VK_NUMPAD8, 'Num8', \
VK_NUMPAD9, 'Num9', \
VK_MULTIPLY, 'Num*', \
VK_ADD, 'Num+', \
VK_SUBTRACT, 'Num-', \
VK_DECIMAL, 'Num.', \
VK_DIVIDE, 'Num/', \
VK_F1, 'F1', \
VK_F2, 'F2', \
VK_F3, 'F3', \
VK_F4, 'F4', \
VK_F5, 'F5', \
VK_F6, 'F6', \
VK_F7, 'F7', \
VK_F8, 'F8', \
VK_F9, 'F9', \
VK_F10, 'F10', \
VK_F11, 'F11', \
VK_F12, 'F12', \
VK_F13, 'F13', \
VK_F14, 'F14', \
VK_F15, 'F15', \
VK_F16, 'F16', \
VK_F17, 'F17', \
VK_F18, 'F18', \
VK_F19, 'F19', \
VK_F20, 'F20', \
VK_F21, 'F21', \
VK_F22, 'F22', \
VK_F23, 'F23', \
VK_F24, 'F24', \
VK_NUMLOCK, 'NumLock', \
VK_SCROLL, 'ScrLock', \
VK_LSHIFT, 'LShift', \
VK_RSHIFT, 'RShift'
endg
;************************************************************************
; Returns string with text name of the virtual key in
; given accelerator.
;
; ptrAccel: Pointer to the ACCEL structure of the accelerator.
; ptrStr: Pointer to the buffer for the string.
;
; Returns: eax - length of the string (only ASCII chars)
;
; Note: IMHO this is not the best method to convert virtual
; key to string, but windows don't provide any other way.
; using MapVirtualKey and then GetKeyNameText don't works
; good, because of bad convertion VK -> scancode
; WARNING:
; NO ERROR CHECK.
; If you set some strange accelerator key /VK_LBUTTON for example/
; the result string will be strange.
;************************************************************************
proc AccelToStr, .ptrAccel, .ptrStr
.Prefix rb 32
.str rb 32
begin
push esi edi ebx
mov edx, [.ptrAccel]
test edx, edx
jz .noaccel
movzx eax, [edx+TAccel.Key]
mov esi, VKeyArray
.search:
cmp [esi+TKeyName.VirtKey],-1
je .notfound
cmp [esi+TKeyName.VirtKey], ax
je .found
movzx ebx, [esi+TKeyName.NextOfs]
add esi, ebx
jmp .search
.notfound:
and ax, $00ff
mov word [.str], ax
jmp .prefix
.found:
add esi, 3
lea edi, [.str]
.copy:
mov al, [esi]
inc esi
mov [edi], al
inc edi
test al, al
jnz .copy
.prefix:
lea esi, [.str]
test [edx+TAccel.Flags], Alt
jz @f
sub esi, 4
mov dword [esi], 'Alt+'
@@:
test [edx+TAccel.Flags], Ctrl
jz @f
sub esi, 5
mov dword [esi], 'Ctrl'
mov byte [esi+4], '+'
@@:
test [edx+TAccel.Flags], Shift
jz @f
sub esi, 6
mov dword [esi], 'Shif'
mov word [esi+4],'t+'
@@:
mov edi, [.ptrStr]
xor eax, eax
dec eax
.copy2:
mov bl, [esi]
inc esi
mov [edi], bl
inc edi
inc eax ; eax is counter of string length
test bl, bl
jnz .copy2
jz .exit
.noaccel:
mov edi,[.ptrStr]
xor eax,eax
mov [edi],eax
.exit:
pop ebx edi esi
return
endp
proc DisableBitmap, .hBmp, .IconWidth, .clrTransparent, .clrGrayBlend, .clrBack
.bmp BITMAPINFOHEADER
.b BITMAP
.ptrBits dd ?
.hBmpRes dd ?
.dc dd ?
.dc2 dd ?
.clr dd ?
begin
push esi edi ebx
mov eax, [.clrGrayBlend]
bswap eax
shr eax, 8
mov [.clrGrayBlend], eax
mov al, byte [.clrBack]
xchg al, byte [.clrBack+2]
mov byte [.clrBack], al
xor ebx, ebx
dec [.IconWidth]
invoke CreateCompatibleDC, ebx
mov [.dc], eax
invoke CreateCompatibleDC, ebx
mov [.dc2], eax
lea esi, [.b]
invoke GetObjectW, [.hBmp], sizeof.BITMAP, esi
mov [.bmp.biSize], sizeof.BITMAPINFOHEADER
mov ecx, [.b.bmWidth]
mov edx, [.b.bmHeight]
mov [.bmp.biWidth], ecx
mov [.bmp.biHeight], edx
mov [.bmp.biPlanes], 1
mov [.bmp.biBitCount], 32
mov [.bmp.biCompression], BI_RGB
mov [.bmp.biSizeImage], ebx
mov [.bmp.biClrUsed],ebx
mov [.bmp.biClrImportant], ebx
lea ecx, [.ptrBits]
lea esi, [.bmp]
invoke CreateDIBSection, ebx, esi, ebx, ecx, ebx, ebx
mov [.hBmpRes], eax
invoke SelectObject, [.dc2], [.hBmpRes]
push eax
invoke SelectObject, [.dc], [.hBmp]
push eax
lea eax, [.bmp]
invoke GetDIBits, [.dc], [.hBmp], ebx, [.bmp.biHeight], [.ptrBits], eax, ebx
invoke SelectObject, [.dc]
invoke SelectObject, [.dc2]
invoke DeleteDC, [.dc]
invoke DeleteDC, [.dc2]
mov edi, [.ptrBits]
mov ecx, [.bmp.biHeight]
shl ecx, 16
.outloop:
xor esi, esi ; Counter from 0 to IconWidth-1
mov cx, word [.bmp.biWidth]
.inloop:
xor ebx, ebx
xor eax, eax
xor ebx, ebx
and dword [edi], $ffffff
mov edx, [edi]
cmp edx, [.clrTransparent]
jne .gray
mov eax, [.clrBack]
jmp .next
.gray:
movzx eax, dl
movzx ebx, dh
add eax, eax ; 2* Blue
add eax, ebx ; + Green
shr edx, 16
movzx ebx, dl
add eax, ebx ; + Red
shr eax, 2 ; div 4 -> Grayscale pixel.
; This formula gives more realistic view.
push eax eax
; -----byte 0
movzx ebx, byte [.clrGrayBlend]
imul ebx, esi ; clrBlend * xi
mov edx, eax
imul edx, esi ; clrGray * xi
imul eax, [.IconWidth] ; clrGray * xmax
add eax, ebx ;
sub eax, edx ; eax := clrBlend * xi + clrGray * xmax - clrGray * xi
xor edx, edx
div [.IconWidth]
mov byte [.clr], al
; -----byte 1
pop eax
movzx ebx, byte [.clrGrayBlend+1]
imul ebx, esi ; clrBlend * xi
mov edx, eax
imul edx, esi ; clrGray * xi
imul eax, [.IconWidth] ; clrGray * xmax
add eax, ebx ;
sub eax, edx ; eax := clrBlend * xi + clrGray * xmax - clrGray * xi
xor edx, edx
div [.IconWidth]
mov byte [.clr+1], al
; -----byte 2
pop eax
movzx ebx, byte [.clrGrayBlend+2]
imul ebx, esi ; clrBlend * xi
mov edx, eax
imul edx, esi ; clrGray * xi
imul eax, [.IconWidth] ; clrGray * xmax
add eax, ebx ;
sub eax, edx ; eax := clrBlend * xi + clrGray * xmax - clrGray * xi
xor edx, edx
div [.IconWidth]
mov byte [.clr+2], al
; combine it all
mov eax, [.clr]
and eax, $ffffff
.next:
mov [edi], eax
lea edi, [edi+4]
inc esi
cmp esi, [.IconWidth]
jbe .doloop
xor esi, esi
.doloop:
dec cx
jnz .inloop
sub ecx, $10000
jnz .outloop
.finish:
mov eax, [.hBmpRes]
pop ebx edi esi
return
endp
proc ExecAction, .actionlist, .number, .wparam, .lparam
begin
mov ebx, [.actionlist]
movzx esi, word [.wparam]
cmp esi, FirstID
jl .ondefault
sub esi, FirstID
cmp esi, [.number]
jge .ondefault
imul esi,sizeof.TAction
add esi, [.actionlist]
cmp [esi+TAction.OnExecute], 0
je @f
stdcall [esi+TAction.OnExecute], [.wparam], [.lparam]
@@:
xor eax, eax
clc
return
.ondefault:
stc
return
endp
gdfCaption = 0
gdfSmallCaption = 1
gdfMenu = 2
gdfStatus = 3
gdfMessage = 4
gdfMAX = 4
proc GetDefaultFont, .index
.ncm NONCLIENTMETRICSW
begin
push ecx edx
mov [.ncm.cbSize], sizeof.NONCLIENTMETRICSW
lea eax, [.ncm]
invoke SystemParametersInfoW, SPI_GETNONCLIENTMETRICS, sizeof.NONCLIENTMETRICSW, eax, 0
test eax, eax
jz .default
mov eax, [.index]
cmp eax, gdfMAX
ja .default
movzx eax, [.offsets+eax]
lea eax, [.ncm+4*eax]
invoke CreateFontIndirectW, eax
test eax, eax
jnz .finish
.default:
int3
invoke GetStockObject, DEFAULT_GUI_FONT
.finish:
pop edx ecx
return
.offsets db NONCLIENTMETRICSW.lfCaptionFont/4
db NONCLIENTMETRICSW.lfSmCaptionFont/4
db NONCLIENTMETRICSW.lfMenuFont/4
db NONCLIENTMETRICSW.lfStatusFont/4
db NONCLIENTMETRICSW.lfMessageFont/4
endp
DispSize 'actions engine', ($ - CoolCode)