Fresh IDE . Artifact [b49a40c420]
Not logged in

This repository is a mirror!

The original is located on: https://fresh.flatassembler.net/fossil/repo/fresh
If you want to follow the project, please update your remote-url

Artifact b49a40c4207b0922e8ae28732f22404de50d25cc:


; _______________________________________________________________________________________
;|                                                                                       |
;| ..::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