How customdrawed content could make treeitems draw rectangle to fit them
I tried to reproduce in assembly one of MS official examples related to custom draw technology. from page About Custom Draw from sample SAMPLE: CustDTv Illustrates Custom Draw in a TreeView (Q248496) for now aloowed at github so here is code(language: assembler fasm with patched core to exetnd syntax to more convinient for me):
format PE GUI 4.0
entry start
include 'win32a.inc'
PE_IMAGE_BASE = $-rva $
IDD_DIALOG = 101
IDC_TREE = 1000
FONTSINFO_SIZE_THAT_FIT_MY_OS_FONT_COUNT = $4000
macro HANDLE value:? { dd value }
struc HANDLE value:? { . dd value }
sizeof.HANDLE=4
ITEM_COLORS = 1
ITEM_FONTS = 2
;ITEM_UNKNOWN = 3;
MAX_COLORS = 99
ClrTagsize equ 21
sizeof.MyColorINFO = ClrTagsize+8+4
struc MyColorINFO [COLORREF,name] {
dd COLORREF
TCHAR[8] `COLORREF,0
TCHAR[ClrTagsize] name,0 }
section '.text' code readable executable
start: RTL_C
invoke DialogBoxParam,PE_IMAGE_BASE,101,HWND_DESKTOP,DialogProc,0
invoke ExitProcess,0
flush_locals
handleCustomDraw: RTL_C pNMTVCD
;frame esp
mov eax,[pNMTVCD]
mov eax,[eax+NMCUSTOMDRAWINFO.dwDrawStage]
cmp eax,CDDS_PREPAINT
jz .onprepaint
cmp eax,CDDS_ITEMPREPAINT
jz .onitemprepaint
cmp eax,CDDS_ITEMPOSTPAINT
jz .itempostpaint
jmp .default
.onprepaint:
mov eax,CDRF_NOTIFYPOSTPAINT or CDRF_NOTIFYITEMDRAW
jmp .finish
.onitemprepaint:
mov [TVinserter.item.mask],TVIF_HANDLE or TVIF_PARAM
mov eax,[pNMTVCD]
mov eax,[eax+NMCUSTOMDRAWINFO.dwItemSpec]
mov [TVinserter.item.hItem],eax
invoke SendMessage,[hwndTV],TVM_GETITEM,0,TVinserter.item
mov eax,[TVinserter.item.lParam]
test eax,eax
jz .retpostpaintnewfont
test dword[eax],-1
js .onfontsprepaint
.oncolorsprepaint:
mov eax,[pNMTVCD]
test [eax+NMCUSTOMDRAWINFO.uItemState],CDIS_FOCUS
jz .prepaintunfocus
.prepaintfocus:
invoke SendMessage,[hwndTV],WM_GETFONT,0,0
invoke GetObject,eax,sizeof.LOGFONT,logFontTEMP
or [logFontTEMP.lfWeight],FW_BOLD
invoke CreateFontIndirect,logFontTEMP
push eax
mov eax,[pNMTVCD]
invoke SelectObject,[eax+NMCUSTOMDRAWINFO.hdc],?
sub esp,4
invoke DeleteObject,?
jmp .retpostpaintnewfont
.prepaintunfocus:
mov edx,[TVinserter.item.lParam]
mov edx,[edx]
mov [eax+NMCUSTOMDRAW.clrText],edx
jmp .retpostpaintnewfont
.onfontsprepaint:
push dword[eax+4]
mov eax,[pNMTVCD]
invoke SelectObject,[eax+NMCUSTOMDRAWINFO.hdc],?
.retpostpaintnewfont:
mov eax,CDRF_NOTIFYPOSTPAINT or CDRF_NEWFONT
jmp .finish
.itempostpaint:
mov eax,[pNMTVCD]
mov eax,[eax+NMCUSTOMDRAWINFO.dwItemSpec]
mov [TVinserter.item.hItem],eax
mov [rc.left],eax
invoke SendMessage,[hwndTV],TVM_GETITEMRECT,1,rc
mov eax,[rc.left]
xchg eax,[rc.right]
add eax,5
mov [rc.left],eax
add [rc.right],eax
mov [TVinserter.item.mask],TVIF_HANDLE + TVIF_PARAM + TVIF_TEXT
mov [TVinserter.item.pszText],szFace
mov [TVinserter.item.cchTextMax],64
invoke SendMessage,[hwndTV],TVM_GETITEM,0,TVinserter.item
mov eax,[TVinserter.item.lParam]
test eax,eax
jz .finish
test dword[eax],-1
js .onfontspostpaint
.oncolorspostpaint:
mov eax,[pNMTVCD]
test [eax+NMCUSTOMDRAWINFO.uItemState],CDIS_FOCUS
jz .postpaintunfocus
.postpaintfocus:
invoke SetTextColor,[eax+NMCUSTOMDRAWINFO.hdc],$FF0000
push eax
sub esp,4
mov eax,[TVinserter.item.lParam]
add eax,12
invoke DrawText,[esp+16],eax,-1,rc,DT_LEFT
invoke SetTextColor,?,?
jmp .default
.postpaintunfocus:
invoke FillRect,[eax+NMCUSTOMDRAWINFO.hdc],rc,COLOR_WINDOW+1
jmp .default
.onfontspostpaint:
jmp .default
.default:
xor eax,eax ; CDRF_DODEFAULT
.finish:
;exitf
stack_cleanup callee
flush_locals
DialogProc: RTL_C hwnddlg,msg,wparam,lparam
;frame esp
mov eax,[msg]
cmp eax,WM_COMMAND
je .wmcommand
cmp eax,WM_NOTIFY
je .wmnotify
cmp eax,WM_INITDIALOG
je .wminitdialog
cmp eax,WM_DESTROY
je .wmdestroy
.unprocessed:
xor eax,eax
jmp .finish
.wmcommand:
mov eax,[wparam]
sub eax,BN_CLICKED shl 16
jz .finish
cmp eax,IDCANCEL
ja .unprocessed
invoke EndDialog,[hwnddlg],eax
jmp .unprocessed
.wminitdialog:
invoke GetDlgItem,[hwnddlg],IDC_TREE
mov [hwndTV],eax
invoke SetFocus,eax
invoke SendMessage,[hwndTV],WM_GETFONT,0,0
mov [hFontTV],eax
invoke GetObject,eax,sizeof.LOGFONT,logFontTV
stdcall insertItems
jmp .unprocessed
.wmdestroy:
push edi
mov edi,FontsINFO
@@:
cmp dword[edi],-1
jnz @F
invoke DeleteObject,[edi+4]
add edi,8
jmp @B
@@:
pop edi
jmp .unprocessed
.wmnotify:
cmp [wparam],IDC_TREE
jnz .unprocessed
mov eax,[lparam]
test eax,eax
jz .finish
cmp [eax+NMHDR.code],NM_CUSTOMDRAW
jnz .unprocessed
stdcall handleCustomDraw,[lparam]
.handled:
invoke SetWindowLong,[hwnddlg],DWL_MSGRESULT,eax
.processed:
mov eax,1
.finish:
;exitf
stack_cleanup callee
flush_locals
insertItems: RTL_C
;frame esp
mov [TVinserter.item.mask],TVIF_TEXT
mov [TVinserter.item.pszText],szColors
mov [TVinserter.item.cchTextMax],szColors.length
invoke SendMessage,[hwndTV],TVM_INSERTITEM,0,TVinserter
mov [TVinserter.hParent],eax
invoke SendMessage,[hwndTV],TVM_SELECTITEM,TVGN_CARET,eax
mov [TVinserter.item.mask],TVIF_TEXT or TVIF_PARAM
mov [TVinserter.item.lParam],ColorsINFO-sizeof.MyColorINFO
mov [TVinserter.item.pszText],ColorsINFO+4-sizeof.MyColorINFO
mov [TVinserter.item.cchTextMax],8
push edi
mov edi,MAX_COLORS
@@:
add [TVinserter.item.lParam],sizeof.MyColorINFO
add [TVinserter.item.pszText],sizeof.MyColorINFO
invoke SendMessage,[hwndTV],TVM_INSERTITEM,0,TVinserter
dec edi
jne @B
mov [TVinserter.hParent],TVI_ROOT
mov [TVinserter.item.mask],TVIF_TEXT
mov [TVinserter.item.pszText],szFonts
mov [TVinserter.item.cchTextMax],szFonts.length
invoke SendMessage,[hwndTV],TVM_INSERTITEM,0,TVinserter
push eax
mov [TVinserter.item.lParam],FontsINFO
@@:
mov [TVinserter.hParent],eax
mov [TVinserter.item.mask],TVIF_TEXT
mov eax,20
mul edi
add eax,szCharSets
mov [TVinserter.item.pszText],eax
mov [TVinserter.item.cchTextMax],20
invoke SendMessage,[hwndTV],TVM_INSERTITEM,0,TVinserter
mov [TVinserter.hParent],eax
mov al,[edi+baCharSets]
mov [logFontTEMP.lfCharSet],al
stdcall enumFonts
mov eax,[esp]
inc edi
cmp edi,14
jb @B
pop eax
pop edi
.finish:
;exitf
stack_cleanup callee
flush_locals
enumFonts: RTL_C
;frame esp
invoke GetDC,NULL
push eax
invoke EnumFontFamiliesEx,eax,logFontTEMP,enumFontFamilyProc,0,0
invoke ReleaseDC,0,?
.finish:
;exitf
stack_cleanup callee
flush_locals
enumFontFamilyProc: RTL_C lpelfe, lpntme, FontType, lParam
;frame esp
mov eax,[lpelfe]
mov al,[eax+LOGFONT.lfCharSet]
cmp al,[logFontTEMP.lfCharSet]
jnz .retContinueEnumeration
mov [TVinserter.item.mask],TVIF_TEXT or TVIF_PARAM
mov eax,[lpelfe]
mov edx,[logFontTV.lfHeight]
mov [eax+LOGFONT.lfHeight],edx
mov edx,[logFontTV.lfWidth]
mov [eax+LOGFONT.lfWidth],edx
invoke CreateFontIndirect,eax
add [TVinserter.item.lParam],8
mov edx,[TVinserter.item.lParam]
or dword[edx],-1
mov dword[edx+4],eax
mov eax,[lpelfe]
add eax,ENUMLOGFONTEX.elfFullName
mov [TVinserter.item.pszText],eax
mov [TVinserter.item.cchTextMax],64
invoke SendMessage,[hwndTV],TVM_INSERTITEM,0,TVinserter
.retContinueEnumeration:
or al,TRUE
.finish:
;exitf
stack_cleanup callee
flush_locals
section '.data' data readable writeable
ColorsINFO MyColorINFO\
$FFFFFF,'White',\
$0000FF,'Red',\
$00FF00,'Green',\
$FF0000,'Blue',\
$FF00FF,'Magenta',\
$FFFF00,'Cyan',\
$00FFFF,'Yellow',\
$000000,'Black',\
$93DB70,'Aquamarine',\
$17335C,'Baker''s Chocolate',\
$9F5F9F,'Blue Violet',\
$42A6B5,'Brass',\
$19D9D9,'Bright Gold',\
$2A2AA6,'Brown',\
$53788C,'Bronze',\
$3D7DA6,'Bronze II',\
$9F9F5F,'Cadet Blue',\
$1987D9,'Cool Copper',\
$3373B8,'Copper',\
$007FFF,'Coral',\
$6F4242,'Corn Flower Blue',\
$33405C,'Dark Brown',\
$2F4F2F,'Dark Green',\
$6E764A,'Dark Green Copper',\
$2F4F4F,'Dark Olive Green',\
$CD3299,'Dark Orchid',\
$781F87,'Dark Purple',\
$8E236B,'Dark Slate Blue',\
$4F4F2F,'Dark Slate Grey',\
$4F6997,'Dark Tan',\
$DB9370,'Dark Turquoise',\
$425E85,'Dark Wood',\
$545454,'Dim Grey',\
$636385,'Dusty Rose',\
$7592D1,'Feldspar',\
$23238E,'Firebrick',\
$238E23,'Forest Green',\
$327FCD,'Gold',\
$70DBDB,'Goldenrod',\
$C0C0C0,'Grey',\
$767F52,'Green Copper',\
$70DB93,'Green Yellow',\
$215E21,'Hunter Green',\
$2F2F4E,'Indian Red',\
$5F9F9F,'Khaki',\
$D9D9C0,'Light Blue',\
$A8A8A8,'Light Grey',\
$BD8F8F,'Light Steel Blue',\
$A6C2E9,'Light Wood',\
$32CD32,'Lime Green',\
$3378E4,'Mandarian Orange',\
$6B238E,'Maroon',\
$99CD32,'Medium Aquamarine',\
$CD3232,'Medium Blue',\
$238E6B,'Medium Forest Green',\
$AEEAEA,'Medium Goldenrod',\
$DB7093,'Medium Orchid',\
$426F42,'Medium Sea Green',\
$FF007F,'Medium Slate Blue',\
$00FF7F,'Medium Spring Green',\
$DBDB70,'Medium Turquoise',\
$9370DB,'Medium Violet Red',\
$6480A6,'Medium Wood',\
$4F2F2F,'Midnight Blue',\
$8E2323,'Navy Blue',\
$FF4D4D,'Neon Blue',\
$C76EFF,'Neon Pink',\
$9C0000,'New Midnight Blue',\
$9EC7EB,'New Tan',\
$3BB5CF,'Old Gold',\
$007FFF,'Orange',\
$0024FF,'Orange Red',\
$DB70DB,'Orchid',\
$8FBC8F,'Pale Green',\
$8F8FBC,'Pink',\
$EAADEA,'Plum',\
$F3D9D9,'Quartz',\
$AB5959,'Rich Blue',\
$42426F,'Salmon',\
$17178C,'Scarlet',\
$688E23,'Sea Green',\
$26426B,'Semi-Sweet Chocolate',\
$236B8E,'Sienna',\
$FAE8E6,'Silver',\
$CC9932,'Sky Blue',\
$FF7F00,'Slate Blue',\
$AE1CFF,'Spicy Pink',\
$7FFF00,'Spring Green',\
$8E6B23,'Steel Blue',\
$DEB038,'Summer Sky',\
$7093DB,'Tan',\
$D8BFD8,'Thistle',\
$EAEAAD,'Turquoise',\
$33405C,'Very Dark Brown',\
$CDCDCD,'Very Light Grey',\
$4F2F4F,'Violet',\
$9932CC,'Violet Red',\
$BFD8D8,'Wheat',\
$32CC99,'Yellow Green'
szColors db 'Some Colors and their (HTML) names',0
.length = $-szColors-1
szFonts db 'Fonts installed in the system',0
.length = $-szFonts-1
szCharSets TCHAR[20] 'ANSI_CHARSET',0
TCHAR[20] 'BALTIC_CHARSET',0
TCHAR[20] 'CHINESEBIG5_CHARSET',0
TCHAR[20] 'DEFAULT_CHARSET',0
TCHAR[20] 'EASTEUROPE_CHARSET',0
TCHAR[20] 'GB2312_CHARSET',0
TCHAR[20] 'GREEK_CHARSET',0
TCHAR[20] 'HANGUL_CHARSET',0
TCHAR[20] 'MAC_CHARSET',0
TCHAR[20] 'OEM_CHARSET',0
TCHAR[20] 'RUSSIAN_CHARSET',0
TCHAR[20] 'SHIFTJIS_CHARSET',0
TCHAR[20] 'SYMBOL_CHARSET',0
TCHAR[20] 'TURKISH_CHARSET',0
szFace TCHAR[64]
baCharSets db ANSI_CHARSET,\
BALTIC_CHARSET,\
CHINESEBIG5_CHARSET,\
DEFAULT_CHARSET,\
EASTEUROPE_CHARSET,\
GB2312_CHARSET,\
GREEK_CHARSET,\
HANGEUL_CHARSET,\
MAC_CHARSET,\
OEM_CHARSET,\
RUSSIAN_CHARSET,\
SHIFTJIS_CHARSET,\
SYMBOL_CHARSET,\
TURKISH_CHARSET,\
$FF
TVinserter TV_INSERTSTRUCT TVI_ROOT,0
hwndTV HANDLE
hFontTV HANDLE
logFontTV LOGFONT
logFontTEMP LOGFONT
rc RECT
FontsINFO rb FONTSINFO_SIZE_THAT_FIT_MY_OS_FONT_COUNT
section '.idata' import data readable writeable
library kernel,'KERNEL32.DLL',\
user,'USER32.DLL',\
gdi,'GDI32.DLL',\
comctl,'COMCTL32.DLL'
import kernel,\
GetModuleHandle,'GetModuleHandleA',\
ExitProcess,'ExitProcess'
import user,\
DialogBoxParam,'DialogBoxParamA',\
DrawText,'DrawTextA',\
CreateWindowEx,'CreateWindowExA',\
CallWindowProc,'CallWindowProcA',\
CheckRadioButton,'CheckRadioButton',\
FillRect,'FillRect',\
GetClientRect,'GetClientRect',\
GetDC,'GetDC',\
GetDlgItem,'GetDlgItem',\
GetDlgItemText,'GetDlgItemTextA',\
IsDlgButtonChecked,'IsDlgButtonChecked',\
MessageBox,'MessageBoxA',\
ReleaseDC,'ReleaseDC',\
SetFocus,'SetFocus',\
SetWindowLong,'SetWindowLongA',\
SetWindowText,'SetWindowTextA',\
SetProp,'SetPropA',\
SendMessage,'SendMessageA',\
EndDialog,'EndDialog'
import gdi,\
CreateFontIndirect,'CreateFontIndirectA',\
DeleteObject,'DeleteObject',\
GetObject,'GetObjectA',\
EnumFontFamiliesEx,'EnumFontFamiliesExA',\
SelectObject,'SelectObject',\
SetTextColor,'SetTextColor'
import comctl,\
InitCommonControls,'InitCommonControls'
virtual
dd InitCommonControls
end virtual
section '.rsrc' resource data readable
directory RT_DIALOG,dialogs
resource dialogs,\
IDD_DIALOG,LANG_ENGLISH+SUBLANG_DEFAULT,demonstration
dialog demonstration,'Custom Draw TreeView',0, 0, 318, 262,DS_SETFONT or DS_MODALFRAME or DS_CENTER or WS_POPUPWINDOW or WS_CAPTION
dialogitem 'SysTreeView32','Tree1',IDC_TREE, 22, 19, 200, 224,WS_VISIBLE+TVS_HASBUTTONS + TVS_HASLINES + TVS_LINESATROOT + WS_BORDER + WS_TABSTOP
dialogitem 'BUTTON','OK',IDOK,261, 7, 50, 14,WS_VISIBLE+WS_TABSTOP+BS_DEFPUSHBUTTON
dialogitem 'BUTTON','C&ancel',IDCANCEL,261, 24, 50, 14,WS_VISIBLE+WS_TABSTOP+BS_PUSHBUTTON
dialogitem 'BUTTON',' Colors && Fonts ',-1,7,7,230,248,WS_VISIBLE+BS_GROUPBOX
enddialog
I made much of simplification: in original each tree item lParam pointed to runtime created in heap structure which fields used differently for items that represent colors and items that represent fonts. My tree items lParam for non custom drawed items pointed to nowhere, while for color & for fonts they points to different(and by size too) structures. For colors such structures staticaly initialized in design time. For fonts I left enought place to fit all needed structures in my OS.
My reproduction looks similar to original one:
- colorized tree view items are colorized when they not selected, and their font become bold when they selected and textual description of color is added i that time;
- font tree view items are made in font that they describe
- But...
As seen on images when used bold font for selection text from my representation don`t fit to tree item rectangle, blue color textual color comment do not fit drawing rectangle too. Same thing for font tree items they limited with rectangle enought to fit font description in tree view font and not always enought to fit font description in tree item own font. (I research original code, disassemble compiled executable, but I found only things I already reproduced) and there is no code that makes content to fit in drawing rectangles. Is there way to recalculate tree item rectangle in custom drawing process. On which state it could be done (prepaint, itemprepaint, itempostpaint)? And one more: when font tree item is howered(in original) appear something tooltip like in treeview font with tree item font description.(I did not find styles or runtime code that do that).
(bytes order of colors shown in reverse order in my variant - that difference I do not want to resolve, I like mine).
lets summary my request: how to make text that bold or font altered in custom draw process to fit tree view item rectangle, or on which state of custom draw extend this rectangle. And how to do that? Thanks in advance.