; _______________________________________________________________________________________
;| |
;| ..::FreshLib::.. Free, open source. Licensed under "BSD 2-clause" license." |
;|_______________________________________________________________________________________|
;
; Description: TWindow object class
;
; Target OS: Any
;
; Dependencies:
;
; Notes: TWindow is the common ancestor of all visible on the screen controls.
; This file contains only OS independent part of the library and includes
; the OS dependent files.
;_________________________________________________________________________________________
module "TWindow library"
ObjectClass Window, \
Object, \
TWindow.Create, \
TWindow.Destroy, \
TWindow.Get, \
TWindow.Set, \
TWindow.ExecCmd, \
TWindow.SysEventHandler
; The elements of the array returned by .GetSiblings param
; if handle<>0 and pWindow=0 - it is a native window, not added by FreshLib
struct TWinArrayItem
.handle dd ? ; The native OS handle of the window.
.pWindow dd ? ; pointer to TWindow descendent structure.
ends
; Border kind of window.
borderNone = 0
borderFull = 1
borderModal = 2
borderToolbox = 3
struct __TInternalAlign
.client TBounds
.pClientWindow dd ?
ends
; assign X = 01
; assign Y = 10
; adjheight = 01
; topleft = 00
; bottomright = 10
; 00 - adjwidht + bottomright
; Window align values.
waNone = 0
waLeft = 1
waRight = 2
waTop = 3
waBottom = 4
waClient = 5
object TWindow, TObject
.handle dd ? ; it is handle to the system provided window.
._x dd ?
._y dd ?
._width dd ?
._height dd ?
._visible dd ?
._bounds_changed dd ?
._border dd ?
._align dd ? ; window horizontal alignment
._FreeArea TBounds ; the window area that remains free after all children aligned. [1]
._caption dd ? ; string handle with window caption.
._cursor dd ? ; it is a handle to the mouse cursor.
.OnKeyPress dd ? ; key press user handler.
; parameters
param .x
param .y
param .width
param .height
param .Align
param .FreeArea ; read only.
param .borderKind
param .Zorder
param .Visible
param .Caption
param .Parent
param .Cursor
param .Children ; read only. returns array with all children; See the notes [2] below.
method .Refresh
method .Focus
method .AlignChildren
method .ToBack
method .ToFront
method ._ComputeFreeArea
endobj
; NOTES:
; [1] FreeArea field
;
; [2] The param .children returns an array of TWinArrayItem filled with information about
; all children of the given window.
; This array is allocated with CreateArray and needs to be free with FreeMem after use.
; TArray.lparam of the array contains a pointer to the element containing current window
; OS dependend code
include '%TargetOS%/windows.asm'
; OS independent code.
;_________________________________________________________________________________________
proc TWindow.Create, .obj
begin
push eax ecx edx
mov ebx, [.obj]
stdcall _CreateNullWindow
mov [ebx+TWindow.handle], eax
stdcall _SetWindowStruct, eax, ebx
pop edx ecx eax
clc
return
endp
;_________________________________________________________________________________________
proc TWindow.Destroy, .obj
begin
push eax
mov eax, [.obj]
cmp [eax+TWindow.handle], 0
je @f
stdcall _DestroyWindow, [eax+TWindow.handle]
@@:
pop eax
return
endp
;_________________________________________________________________________________________
proc TWindow.Get, .obj, .paramID
.rect RECT
begin
push edx esi
stdcall IsObject, [.obj], CWindow
jc .not_processed
mov esi, [.obj]
mov eax, [.paramID]
test eax, maskParameter
jz .field
cmp eax, TWindow.x
je .getrect
cmp eax, TWindow.y
je .getrect
cmp eax, TWindow.width
je .getrect
cmp eax, TWindow.height
je .getrect
cmp eax, TWindow.FreeArea
je .getfreearea
cmp eax, TWindow.Visible
je .getvisible
cmp eax, TWindow.Caption
je .getcaption
cmp eax, TWindow.borderKind
je .getborder
cmp eax, TWindow.Children
je .getchildren
cmp eax, TWindow.Parent
je .getparent
.not_processed:
stc
pop esi edx
return
.field:
mov eax, [esi+eax]
.finish:
clc
pop esi edx
return
;.........................................................................................
.getparent:
stdcall _GetParent, [esi+TWindow.handle]
test eax, eax
jz .finish
stdcall _GetWindowStruct, eax
jmp .finish
;.........................................................................................
.getchildren:
stdcall _GetChildren, [esi+TWindow.handle]
test eax, eax
jz .finish
push ebx edi
mov ebx, eax
mov ecx, [ebx+TArray.count]
.loop:
jecxz .endloop
dec ecx
stdcall _GetWindowStruct, [ebx+TArray.array+8*ecx+TWinArrayItem.handle]
mov [ebx+TArray.array+8*ecx+TWinArrayItem.pWindow], eax
jmp .loop
.endloop:
mov eax, ebx
pop edi ebx
jmp .finish
;.........................................................................................
.getfreearea:
mov [esi+TWindow._FreeArea.x], 0
mov [esi+TWindow._FreeArea.y], 0
mov eax, [esi+TWindow._width]
mov ecx, [esi+TWindow._height]
mov [esi+TWindow._FreeArea.width], eax
mov [esi+TWindow._FreeArea.height], ecx
execute esi, TWindow._ComputeFreeArea
lea eax, [esi+TWindow._FreeArea]
jmp .finish
;.........................................................................................
.getborder:
mov eax, [esi+TWindow._border]
jmp .finish
;.........................................................................................
.getcaption:
mov eax, [esi+TWindow._caption]
test eax, eax
jz .finish
stdcall StrDup, eax
jmp .finish
;.........................................................................................
.getvisible:
mov eax, [esi+TWindow._visible]
; stdcall _GetVisible, [esi+TWindow.handle]
jmp .finish
;.........................................................................................
.getrect:
mov eax, [.paramID]
sub eax, TWindow.x
mov eax, [esi+TWindow._x+4*eax]
jmp .finish
endp
;_________________________________________________________________________________________
proc TWindow.Set, .obj, .paramID, .value
begin
stdcall IsObject, [.obj], CWindow
jc .fault
push eax esi
mov esi, [.obj]
mov eax, [.paramID]
test eax, maskParameter
jz .field
cmp eax, TWindow.x
je .setrect
cmp eax, TWindow.y
je .setrect
cmp eax, TWindow.width
je .setrect
cmp eax, TWindow.height
je .setrect
cmp eax, TWindow.Visible
je .setvisible
cmp eax, TWindow.Caption
je .setcaption
cmp eax, TWindow.borderKind
je .setborder
cmp eax, TWindow.Align
je .setalign
pop esi eax
.fault:
stc
return
.field:
pushd [.value]
popd [esi+eax]
.finish:
clc
pop esi eax
return
;.........................................................................................
.setalign:
locals
.bounds TBounds
endl
mov eax, [.value]
cmp eax, [esi+TWindow._align]
je .finish
mov [esi+TWindow._align], eax
stdcall Get, esi, TWindow.Parent
test eax, eax
jz .finish
execute eax, TWindow.AlignChildren
jmp .finish
;.........................................................................................
.setborder:
mov eax, [.value]
xchg eax, [esi+TWindow._border]
cmp eax, [esi+TWindow._border]
je .finish
stdcall _SetWindowBorder, [esi+TWindow.handle], [esi+TWindow._border]
jmp .finish
;.........................................................................................
.setcaption:
lea eax, [esi+TWindow._caption]
stdcall SetString, eax, [.value]
stdcall StrPtr, [eax]
stdcall _SetWindowTextUtf8, [esi+TWindow.handle], eax
jmp .finish
;.........................................................................................
.setvisible:
mov eax, [.value]
xchg [esi+TWindow._visible], eax
cmp [esi+TWindow._visible], eax
je .finish
stdcall _ShowWindow, [esi+TWindow.handle], [.value]
cmp [.value], 0
je .finish
cmp [esi+TWindow._align], waNone
je .finish
stdcall Get, esi, TWindow.Parent
test eax, eax
jz .finish
execute eax, TWindow.AlignChildren
jmp .finish
;.........................................................................................
.setrect:
mov eax, [.paramID]
sub eax, TWindow.x
mov ecx, [.value]
cmp ecx, [esi+TWindow._x+4*eax]
je .finish
mov [esi+TWindow._x+4*eax], ecx
lea eax, [esi+TWindow._x]
stdcall _SetWindowBounds, [esi+TWindow.handle], eax
mov [esi+TWindow._bounds_changed], 0
jmp .finish
endp
;_________________________________________________________________________________________
proc TWindow.ExecCmd, .self, .method
begin
push eax edx
cmp [.method], TWindow.Refresh
je .refresh
cmp [.method], TWindow._ComputeFreeArea
je .computefreearea
cmp [.method], TWindow.AlignChildren
je .alignchildren
cmp [.method], TWindow.Focus
je .focus
cmp [.method], TWindow.AddChild
je .addchild
.error:
stc
pop edx eax
return
;.........................................................................................
.refresh:
mov eax, [.self]
cmp [eax+TWindow._visible], 0
je .finish
stdcall _RefreshWindow, [eax+TWindow.handle]
.finish:
clc
pop edx eax
return
;.........................................................................................
.computefreearea:
jmp .finish
;.........................................................................................
.alignchildren:
locals
.winalign __TInternalAlign
endl
; THIS METHOD is not written very good. It should be revised some day in order to make
; alignment fast and smooth for all OS supported!
push esi edi
stdcall Get, [.self], TWindow.Children
test eax, eax
jz .endalign
mov edi, eax
lea esi, [.winalign]
mov ecx, [.self]
push [ecx+TWindow._width] [ecx+TWindow._height]
pop [esi+__TInternalAlign.client.height] [esi+__TInternalAlign.client.width]
xor ecx,ecx
mov [esi+__TInternalAlign.client.y], ecx
mov [esi+__TInternalAlign.client.x], ecx
mov [esi+__TInternalAlign.pClientWindow], ecx
.loop:
cmp ecx, [edi+TArray.count]
je .endloop
stdcall __DoAlignOne, [edi+TArray.array+8*ecx+TWinArrayItem.pWindow]
inc ecx
jmp .loop
.endloop:
mov ecx, [.winalign.pClientWindow]
jecxz .updatewindows
mov eax, [esi+__TInternalAlign.client.x]
mov edx, [esi+__TInternalAlign.client.y]
sub eax, [ecx+TWindow._x]
sub edx, [ecx+TWindow._y]
mov ebx, eax
or ebx, edx
mov eax, [esi+__TInternalAlign.client.width]
mov edx, [esi+__TInternalAlign.client.height]
sub eax, [ecx+TWindow._width]
sub edx, [ecx+TWindow._height]
or ebx, eax
or ebx, edx
mov [ecx+TWindow._bounds_changed], ebx
push [esi+__TInternalAlign.client.height] [esi+__TInternalAlign.client.width] [esi+__TInternalAlign.client.y] [esi+__TInternalAlign.client.x]
pop [ecx+TWindow._x] [ecx+TWindow._y] [ecx+TWindow._width] [ecx+TWindow._height]
.updatewindows:
mov ecx, [edi+TArray.count]
.updateloop:
dec ecx
js .endupdate
mov eax, [edi+8*ecx+TArray.array+TWinArrayItem.pWindow]
cmp [eax+TWindow._bounds_changed], 0
je .refresh_only
lea edx, [eax+TWindow._x]
; mov [eax+TWindow._bounds_changed], 0 - it will be zeroed in the seMoveResize event handler.
stdcall _SetWindowBounds, [eax+TWindow.handle], edx
.refresh_only:
stdcall _RefreshWindow, [eax+TWindow.handle]
jmp .updateloop
.endupdate:
stdcall FreeMem, edi
mov eax, [.self]
stdcall _RefreshWindow, [eax+TWindow.handle]
.endalign:
pop edi esi
jmp .finish
;.........................................................................................
.focus:
mov eax, [.self]
stdcall _SetFocus, [eax+TWindow.handle]
jmp .finish
;.........................................................................................
.addchild:
; method parameter.
virtual at ebx
.child dd ?
end virtual
stdcall IsObject, [.child], CWindow
jne .add_non_window
mov ebx, [.child]
mov eax, [.self]
stdcall _AddChild, [eax+TWindow.handle], [ebx+TWindow.handle]
jmp .finish
.add_non_window: ; this is possible, but not implemented for now.
jmp .error
endp
;_________________________________________________________________________________________
proc TWindow.SysEventHandler, .pObj, .pEvent
begin
push eax ecx edx esi edi
mov esi, [.pObj]
mov ebx, [.pEvent]
mov eax, [ebx+TSysEvent.event]
cmp eax, seMouseEnter
je .mouseenter
cmp eax, seMouseLeave
je .mouseleave
cmp eax, seMouseBtnPress
je .btnpress
cmp eax, seMoveResize
je .moveresize
cmp eax, seKbdKeyPress
je .keypress
stc
.finish:
pop edi esi edx ecx eax
return
;.........................................................................................
.moveresize:
mov eax, [ebx+TMoveResizeEvent.newX]
mov ecx, [ebx+TMoveResizeEvent.newY]
mov [esi+TWindow._x], eax
mov [esi+TWindow._y], ecx
mov eax, [ebx+TMoveResizeEvent.newWidth]
mov ecx, [ebx+TMoveResizeEvent.newHeight]
xchg [esi+TWindow._width], eax
xchg [esi+TWindow._height], ecx
sub eax, [esi+TWindow._width]
sub ecx, [esi+TWindow._height]
or eax, ecx
jnz .alignchildren ; when the resize is as a result of internal windows align, the _width and _height fields are already set.
; it must be this way, because the resize should be fast, but in Linux there is no DeferWindowPos function like in Win32
cmp [esi+TWindow._bounds_changed], 0
je .endresize
.alignchildren:
execute esi, TWindow.AlignChildren
mov [esi+TWindow._bounds_changed], 0
.endresize:
clc
jmp .finish
;.........................................................................................
.btnpress:
execute esi, TWindow.Focus
clc
jmp .finish
;.........................................................................................
.mouseenter:
mov eax, [esi+TWindow._cursor]
test eax, $ffffff00
jnz @f
stdcall GetStockCursor, eax
@@:
stdcall SetMouseCursor, eax
clc
jmp .finish
;.........................................................................................
.mouseleave:
stdcall GetStockCursor, mcArrow
stdcall SetMouseCursor, eax
clc
jmp .finish
;.........................................................................................
.keypress:
cmp [esi+TWindow.OnKeyPress], 0
je @f
stdcall [esi+TWindow.OnKeyPress], esi, ebx
@@:
clc
jmp .finish
endp
proc __DoAlignOne, .pWindow
.bounds TBounds
.align dd ?
begin
pushad
mov ebx, [.pWindow]
cmp [ebx+TWindow._align], waNone
je .exit
cmp [ebx+TWindow._align], waClient
ja .exit
stdcall Get, ebx, TWindow.Visible
test eax, eax
jz .exit
cmp [ebx+TWindow._align], waClient
jne .doalign
; only one window with waClient may exists.
cmp [esi+__TInternalAlign.pClientWindow], 0
jne .exit
mov [esi+__TInternalAlign.pClientWindow], ebx
jmp .exit
.doalign:
mov eax, [ebx+TWindow._align]
dec eax
mov [.align], eax
; save the old bounds in order to detect change.
mov eax, [ebx+TWindow._x]
mov ecx, [ebx+TWindow._y]
mov [.bounds.x], eax
mov [.bounds.y], ecx
mov eax, [ebx+TWindow._width]
mov ecx, [ebx+TWindow._height]
mov [.bounds.width], eax
mov [.bounds.height], ecx
mov ecx, TBounds.width
mov edx, [ebx+TWindow._height]
mov edi, TBounds.y
bt [.align], 1 ; 0 - width; 1 - height
jc @f
mov ecx, TBounds.height
mov edx, [ebx+TWindow._width]
mov edi, TBounds.x
@@:
mov eax, [esi+__TInternalAlign.client+ecx]
mov [ebx+TWindow._x+ecx], eax
mov eax, [esi+__TInternalAlign.client.x]
mov ecx, [esi+__TInternalAlign.client.y]
bt [.align], 0 ; 0 - left/top; 1-right/bottom
jnc @f
add eax, [esi+__TInternalAlign.client.width]
add ecx, [esi+__TInternalAlign.client.height]
sub eax, [ebx+TWindow._width]
sub ecx, [ebx+TWindow._height]
neg edx
add edi, 8
@@:
mov [ebx+TWindow._x], eax
mov [ebx+TWindow._y], ecx
add [esi+__TInternalAlign.client+edi], edx
test edx, edx
js @f
sub [esi+__TInternalAlign.client+edi+8], edx
@@:
mov eax, [ebx+TWindow._x]
mov ecx, [ebx+TWindow._y]
mov edx, [ebx+TWindow._width]
mov edi, [ebx+TWindow._height]
sub eax, [.bounds.x]
sub ecx, [.bounds.y]
sub edx, [.bounds.width]
sub edi, [.bounds.height]
or ecx, eax
or edx, edi
or ecx, edx
mov [ebx+TWindow._bounds_changed], ecx
.exit:
popad
return
endp
endmodule