

struct TLvItem
  .captions dd ?         ; pointer to TArray of dword with strings for the item and subitems.
  .icon     dd ?         ; index into ._img_icons
  .data     dd ?         ; user data, attached to the item.
            dd ?         ;

  .shift = 4
ends


lvsTiles   = 0
lvsList    = 1
lvsDetails = 2


object TListView, TGrid

  ._img_icons     dd      ?
  ._items         dd      ?     ; TArray of TLvItem elements.
  ._style         dd      ?
  ._headers       dd      ?     ; TArray of dword with strings, captions of the header.

  param .Icons, ._img_icons, .SetIcons
  param .Style, ._style, .SetStyle
  param .Items, ._items, NONE

  method .Destroy

  method .GetItem, .index       ; returns pointer to TLvItem

  method .SetIcons, .value
  method .SetStyle, .value
  method .SetVisible, .value

  method .DrawCell, .canvas, .ptrRect, .Col, .Row

  method .InsertItem, .index, .caption, .icon, .data
  method .AddSubItem, .iItem, .strSubitem
  method .Clear

  method .AddHeader, .hString
  method .ClearHeaders

  method .ArangeItems

endobj


interface TListView.OnFocusChange, .pListView, .x, .y, .fFocused


method TListView.Destroy
begin
        push    eax
        get     eax, [.self], TListView:Icons
        stdcall DestroyImage, eax
        pop     eax
        inherited
        return
endp




method TListView.AddHeader      ; .hString
begin
        pushad
        mov     esi, [.self]
        mov     edx, [esi+TListView._headers]
        test    edx, edx
        jnz     .array_ok

        stdcall CreateArray, 4
        mov     edx, eax

.array_ok:
        stdcall AddArrayItems, edx, 1
        mov     [esi+TListView._headers], edx
        mov     edx, eax

        stdcall StrDup, [.hString]
        mov     [edx], eax

        popad
        return
endp



method TListView.ClearHeaders
begin
        push    eax edx
        mov     edx, [.self]
        xor     eax, eax
        xchg    eax, [edx+TListView._headers]

        stdcall ListFree, eax, StrDel
        pop     edx eax
        return
endp



method TListView.GetItem  ; .index
begin
        pushad
        mov     esi, [.self]
        get     ebx, esi, TListView:Items
        test    ebx, ebx
        jz      .notfound

        mov     ecx, [.index]

        cmp     ecx, [ebx+TArray.count]
        jae     .notfound

        shl     ecx, TLvItem.shift
        lea     eax, [ebx+TArray.array+ecx]
        mov     [esp+4*regEAX], eax

        clc
        popad
        return

.notfound:
        stc
        popad
        return
endp



method TListView.SetIcons       ; .value
begin
        push    esi eax
        mov     esi, [.self]

        stdcall CreateImagePNG, [.value], -1
        jc      .finish

        xchg    eax, [esi+TListView._img_icons]
        stdcall DestroyImage, eax

        xor     eax, eax
        and     [esi+TListView._canvas_valid], eax
        exec    esi, TListView:RectChanged2, eax

.finish:
        pop     eax esi
        return
endp




method TListView.SetStyle       ; .value
begin
        pushad
        mov     esi, [.self]

        mov     eax, [.value]
        xchg    eax, [esi+TListView._style]
        cmp     eax, [esi+TListView._style]
        je      .finish

        exec    [.self], TListView:ArangeItems
        exec    [.self], TListView:ForceRefresh

.finish:
        popad
        return
endp


method TListView.SetVisible
begin
        inherited [.value]

        cmp       [.value], 0
        je        .finish

        push    eax esi
        mov     esi, [.self]

        exec    esi, TListView:ArangeItems

        xor     eax, eax
        mov     [esi+TListView._canvas_valid], eax
        exec    esi, TListView:RectChanged2, eax
        pop     esi eax

.finish:
        return
endp



method  TListView.DrawCell      ; .canvas, .ptrRect, .Col, .Row
.sel RECT
begin
        pushad

        mov     edx, [.self]

        mov     ecx, cellFixed
        mov     esi, [.Col]
        mov     edi, [.Row]
        cmp     esi, [edx+TListView.FixedCols]
        jl      .status_ok
        cmp     edi, [edx+TListView.FixedRows]
        jl      .status_ok

        cmp     edi, [edx+TListView._focused.y]
        jne     .is_selected

        test    [edx+TListView._flags], gfRowFocus
        jnz     .focused

        cmp     esi, [edx+TListView._focused.x]
        jne     .is_selected

.focused:
        mov     ecx, cellFocused
        cmp     edx, [__FocusedWindow]
        je      .status_ok

        mov     ecx, cellFocused2
        jmp     .status_ok

.is_selected:
        lea     ecx, [edx+TListView.selection]
        lea     eax, [.sel]
        stdcall RectCopy, eax, ecx
        stdcall RectSort, eax
        inc     [eax+RECT.right]
        inc     [eax+RECT.bottom]

        mov     ecx, cellSelected
        stdcall PointInRect, eax, esi, edi
        jc      .status_ok

        mov     ecx, cellRegular

.status_ok:
        mov     eax, [edx+TListView._style]
        and     eax, 3 ;(0..3)

        mov     ebx, [.Row]
        sub     ebx, [edx+TListView.FixedRows]
        cmovl   ebx, [edx+TListView._headers]
        jl      .drawit

        mov     edx, [edx+TListView._items]
        test    edx, edx
        jz      .finish

        cmp     ebx, [edx+TArray.count]
        jae     .finish

        imul    ebx, sizeof.TLvItem
        lea     ebx, [edx+ebx+TArray.array]

.drawit:
        stdcall [__lv_draw_proc+4*eax], [.canvas], [.ptrRect], ebx, [.Col], ecx         ; ebx can be pointer to TLvItem or string handle.

.finish:
        popad
        return
endp



method TListView.Clear
begin
        pushad
        mov     esi, [.self]
        mov     edx, [esi+TListView._items]
        test    edx, edx
        jz      .finish

        mov     ecx, [edx+TArray.count]
        lea     edi, [edx+TArray.array]

.loop:
        dec     ecx
        js      .free_array

        stdcall ListFree, [edi+TLvItem.captions], StrDel
        add     edi, sizeof.TLvItem
        jmp     .loop

.free_array:
        stdcall FreeMem, edx

        or      eax, -1
        mov     [esi+TListView._focused.x], eax
        mov     [esi+TListView._focused.y], eax
        mov     [esi+TListView.selection.left], eax
        mov     [esi+TListView.selection.top], eax
        mov     [esi+TListView.selection.right], eax
        mov     [esi+TListView.selection.bottom], eax

        xor     eax, eax
        mov     [esi+TListView._items], eax
        mov     [esi+TListView._canvas_valid], eax
        exec    esi, TListView:RectChanged2, eax

.finish:
        popad
        return
endp




method TListView.InsertItem     ; .index, .caption, .icon, .data
begin
        pushad
        mov     esi, [.self]
        mov     edx, [esi+TListView._items]
        test    edx, edx
        jnz     @f
        stdcall CreateArray, sizeof.TLvItem
        jc      .finish
        mov     edx, eax
@@:

        stdcall InsertArrayItems, edx, [.index], 1
        jc      .finish
        mov     [esi+TListView._items], edx

        mov     edi, eax

        stdcall CreateArray, 4
        stdcall AddArrayItems, eax, 1
        mov     [edi+TLvItem.captions], edx
        mov     edx, eax

        stdcall StrDup, [.caption]
        mov     [edx], eax

        mov     eax, [.icon]
        mov     ecx, [.data]
        mov     [edi+TLvItem.icon], eax
        mov     [edi+TLvItem.data], ecx

        cmp     [esi+TListView._visible], FALSE
        je      .finish

        exec    esi, TListView:ArangeItems

        xor     eax, eax
        mov     [esi+TListView._canvas_valid], eax
        exec    esi, TListView:RectChanged2, eax

.finish:
        popad
        return
endp



method TListView.AddSubItem     ; .iItem, .strSubitem
begin
        pushad

        mov     esi, [.self]
        mov     edi, [esi+TListView._items]
        mov     ecx, [.iItem]
        cmp     ecx, [edi+TArray.count]
        jae     .error

        shl     ecx, TLvItem.shift
        lea     edi, [edi + TArray.array + ecx]

        mov     edx, [edi+TLvItem.captions]
        stdcall AddArrayItems, edx, 1
        jc      .error

        mov     [edi+TLvItem.captions], edx
        mov     edx, eax

        stdcall StrDup, [.strSubitem]
        mov     [edx], eax

        clc
        popad
        return

.error:
        stc
        popad
        return
endp




method TListView.ArangeItems
begin
        push    eax
        mov     eax, [.self]

        mov     eax, [eax+TListView._style]
        and     eax, 3 ;(0..3)

        stdcall [__lv_count_proc+4*eax], [.self]

        pop     eax
        return
endp


iglobal
  if used __lv_count_proc
    __lv_count_proc dd __LVTileCount, __LVListCount, __LVDetailsCount, 0
  end if

  if used __lv_draw_proc
    __lv_draw_proc dd  __LVTileDraw, __LVListDraw, __LVDetailsDraw, 0
  end if
endg


proc __LVTileCount, .self
begin

        return
endp



proc __LVListCount, .self
begin
        pushad

        stdcall GetFontMetrics, [GUI.DefaultFont]
        mov     ebx, eax

        mov     esi, [.self]

        xor     ecx, ecx
        mov     edx, [esi+TListView._items]
        test    edx, edx
        jz      .set_count

        mov     ecx, [edx+TArray.count]

.set_count:
        exec    esi, TListView:SetCounts, 1, ecx
        exec    esi, TListView:SetColWidth, 0, [esi+TListView._width]

        test    ecx, ecx
        jz      .finish

; height:
        lea     edi, [edx+TArray.array]

.loop:
        dec     ecx
        js      .end_loop

        mov     eax, [edi+TLvItem.icon]
        test    eax, eax
        jz      .next

        cmp     ebx, [eax+TImage.height]
        cmovb   ebx, [eax+TImage.height]

.next:
        add     edi, sizeof.TLvItem
        jmp     .loop

.end_loop:
        add     ebx, [GUI.lvIconMargin]
        add     ebx, [GUI.lvIconMargin]

        mov     [esi+TListView.RowHeight], ebx

        mov     eax, [edx+TArray.count]
        dec     eax
        exec    esi,  TListView:SetRowsHeight, 0, eax, ebx

.finish:
        popad
        return
endp




proc __LVDetailsCount, .self
begin
        pushad

        stdcall GetFontMetrics, [GUI.DefaultFont]
        mov     ebx, eax

        mov     esi, [.self]

        xor     edi, edi        ; columns count
        inc     edi
        mov     edx, [esi+TListView._headers]
        test    edx, edx
        jz      .columns_ok

        mov     edi, [edx+TArray.count]
        test    edi, edi
        jnz     .columns_ok

        inc     edi

.columns_ok:
        xor     ecx, ecx
        mov     edx, [esi+TListView._items]
        test    edx, edx
        jz      .set_count

        mov     ecx, [edx+TArray.count]

.set_count:
        push    edx

        mov     eax, [esi+TListView._width]
        sar     eax, 1
        xor     edx, edx
        dec     edi
        jz      @f
        idiv    edi
@@:
        inc     edi

        pop     edx

        mov     [esi+TListView.ColWidth], eax

        inc     ecx
        exec    esi, TListView:SetCounts, edi, ecx

        exec    esi, TListView:SetColumnsWidth, 0, edi, [esi+TListView.ColWidth]

        mov     eax, [esi+TListView._width]
        sar     eax, 1
        exec    esi, TListView:SetColWidth, 0, eax

        cmp     ecx, 1
        jbe     .finish

;.height:
        lea     edi, [edx+TArray.array]

.loop:
        dec     ecx
        jz      .end_loop

        mov     eax, [edi+TLvItem.icon]
        test    eax, eax
        jz      .next

        cmp     ebx, [eax+TImage.height]
        cmovb   ebx, [eax+TImage.height]

.next:
        add     edi, sizeof.TLvItem
        jmp     .loop

.end_loop:
        add     ebx, [GUI.lvIconMargin]
        add     ebx, [GUI.lvIconMargin]

        mov     [esi+TListView.RowHeight], ebx

        mov     eax, [edx+TArray.count]
        dec     eax
        exec    esi,  TListView:SetRowsHeight, 0, eax, ebx

.finish:
        popad
        return
endp




proc __LVTileDraw, .canvas, .ptrRect, .pItem, .iSubitem, .sel
begin
        return
endp



proc __LVListDraw, .canvas, .ptrRect, .pItem, .iSubitem, .sel
begin

        pushad

        mov     esi, [.pItem]
        mov     edi, [.ptrRect]
        mov     ecx, [edi+RECT.left]
        mov     edx, [edi+RECT.top]
        mov     ebx, [esi+TLvItem.icon]
        test    ebx, ebx
        jz      .icon_ok

        mov     eax, [edi+RECT.bottom]
        sub     eax, [edi+RECT.top]
        stdcall DrawSolidRect, [.canvas], ecx, edx, [ebx+TImage.wrapW], eax, [GUI.clGridCellBk]

        mov     eax, ecx
        add     eax, [GUI.lvIconMargin]
        add     edx, [GUI.lvIconMargin]

        stdcall BlendImage, [.canvas], eax, edx, ebx, 0, 0, [ebx+TImage.wrapW], [ebx+TImage.wrapH]

        add     ecx, [ebx+TImage.wrapW]
        add     ecx, [GUI.lvIconMargin]
        add     ecx, [GUI.lvIconMargin]

.icon_ok:
        mov     eax, [edi+RECT.right]
        mov     edx, [edi+RECT.bottom]

        sub     eax, ecx
        sub     edx, [edi+RECT.top]

        mov     ebx, [.sel]
        mov     esi, [esi+TLvItem.captions]
        stdcall DrawTextBox, [.canvas], [esi+TArray.array], ecx, [edi+RECT.top], eax, edx, 0, dtfAlignLeft or dtfSingleLine or dtfAlignMiddle, [GUI.DefaultFont], [GUI.clGridCellTxt + 4*ebx]
        popad
        return
endp



proc __LVDetailsDraw, .canvas, .ptrRect, .pItem, .iSubitem, .sel
.draw_flags dd ?
begin
        pushad

        mov     esi, [.pItem]
        mov     edi, [.ptrRect]

        mov     [.draw_flags], dtfAlignCenter or dtfSingleLine or dtfAlignMiddle

        mov     eax, [edi+RECT.left]
        mov     ecx, eax

        cmp     [.sel], cellFixed
        je      .draw_text_from_array   ; in this case, pItem is an array with the header strings.

        mov     [.draw_flags], dtfAlignLeft or dtfSingleLine or dtfAlignMiddle

        cmp     [.iSubitem], 0
        je      .draw_icon

        mov     [.draw_flags], dtfAlignLeft or dtfSingleLine or dtfAlignMiddle
        jmp     .icon_ok

.draw_icon:
        mov     edx, [edi+RECT.top]
        mov     ebx, [esi+TLvItem.icon]
        test    ebx, ebx
        jz      .icon_ok

        add     eax, [GUI.lvIconMargin]
        add     edx, [GUI.lvIconMargin]

        stdcall BlendSolidRect, [.canvas], eax, edx, [ebx+TImage.wrapW], [ebx+TImage.wrapH], $c0ffffff;[GUI.clGridCellBk]
        stdcall BlendImage, [.canvas], eax, edx, ebx, 0, 0, [ebx+TImage.wrapW], [ebx+TImage.wrapH]

        add     ecx, [ebx+TImage.wrapW]
        add     ecx, [GUI.lvIconMargin]
        add     ecx, [GUI.lvIconMargin]

.icon_ok:
        mov     esi, [esi+TLvItem.captions]

.draw_text_from_array:
        test    esi, esi
        jz      .finish

        mov     eax, [.iSubitem]
        cmp     eax, [esi+TArray.count]
        jae     .finish

        mov     esi, [esi+TArray.array+4*eax]         ; string handle of the cell content.

        mov     eax, [edi+RECT.right]
        mov     edx, [edi+RECT.bottom]

        sub     eax, ecx
        sub     eax, [GUI.lvIconMargin]
        sub     eax, [GUI.lvIconMargin]
        sub     edx, [edi+RECT.top]

        mov     ebx, [.sel]
        stdcall DrawTextBox, [.canvas], esi, ecx, [edi+RECT.top], eax, edx, 0, [.draw_flags], [GUI.DefaultFont], [GUI.clGridCellTxt + 4*ebx]

.finish:
        popad
        return
endp

