; _______________________________________________________________________________________
;|                                                                                       |
;| ..::FreshLib::..  Free, open source. Licensed under "BSD 2-clause" license."          |
;|_______________________________________________________________________________________|
;
;  Description: This file contains procedures and data, that form the appearance of the
;               FreshLib GUI application. Colors, control borders, backgrownd drawing etc.
;
;  Target OS: Any
;
;  Dependencies:
;
;  Notes: The user should be able to change these settings and if he uses external
;         procedures, then the code from this library should not be compiled.
;_________________________________________________________________________________________

module "Runtime GUI themes support"

match =ThemeGUI, ThemeGUI {
  ThemeGUI equ flat_gui
}

; Box border type
bxNone   = 0
bxRaised = 1
bxSunken = 2
bxFlat   = 3
bxFocused = 4
bxNoFill = $80000000
bxDisabled = $40000000




struct TMetaHeader
  .pData dd ?           ; pointer to the NamedArray data fields.
  .length dd ?          ; total length of the NamedArray structure: fields+static data+meta data.
  .count dd ?           ; count of the TMetaFields following.
ends

struct TMetaField
  .pName  dd  ?
  .type   dw  ?
  .len    dw  ?         ; length of the field in dwords
  .offset dd  ?         ; offset of the field, relative to the start of the array.
ends


;
; The NamedArray is a type of structure that contains
; the fields names together with the field values.
; This way, the values of the array can be write to
; text files and then restored in runtime, based not
; on the fields offsets (that can differ) but based on
; field names.
;


___natNUM     = 0          ; NUM,  Stored as decimal, signed.
___natHEX     = 1          ; HEX,  Stored as hex, unsigned.
___natTXT     = 2          ; TXT,  Stored as string. Needs postprocessing.
___natFONT    = 3          ; FONT, Stored as multivalue: face, size, flags, etc.
___natPNG     = 4          ; PNG,  Stored as a hex array. Need postprocessing.
___natFILE    = 5          ; FILE, Stored as a hex array.


macro NamedArray lbl, [name, type, value] {
common
  local ..fake_lbl

  label ..fake_lbl dword
  label lbl dword

; data fields

forward
  local ..len, ..fake_name

    ..len = 0

    label ..fake_name dword

    if used lbl#.#name | (defined options.WholeTheme & options.WholeTheme)
      label lbl#.#name dword
      irp val, value \{

        ..len = ..len + 1

        if (type eq NUM)|(type eq HEX)
          dd val
        else
          if type eq TXT
            if val eqtype 1
              dd val
            else
              dd 0        ; will be changed later in the macro
            end if
          else
            if (type eq FONT) | (type eq PNG)
              dd 0        ; will be changed later in the macro.
              dd 0
            else
              if type eq FILE
                dd 0          ; pointer to data
              else
                Error! Unknown `type type.
              end if
            end if
          end if
        end if
      \}
    end if

; data for the strings, images, files, etc.
forward
local ..index

    ..index = 0

    irp val, value \{
    \local ..dta, ..len

      if used lbl\#.\#name | (defined options.WholeTheme & options.WholeTheme)
        if type eq TXT
          if ~ val eqtype 1
              ..dta db val
                    db 0
          end if
        end if

        if type eq FONT
          match face : size : weight : flags, val \\{         ; For the Linux port, this structure is enough and not need FontCreate call.
            \\local ..font_face

            ..dta dd  ..font_face   ; font face string
                  dd  size          ; NUM
                  dd  weight        ; NUM
                  dd  flags         ; HEX

            ..font_face db face, 0
          \\}

          ..index = ..index + 4
        end if

        if type eq PNG
                dd ..len
          ..dta file val
          ..len = $ - ..dta

          ..index = ..index + 4
        end if

        if type eq FILE
                dd ..len
          ..dta file val
          ..len = $ - ..dta
        end if

        if defined ..dta
          store dword ..dta at ..fake_name + ..index
        end if
      end if

      ..index = ..index + 4
    \}

; Header of the meta data.
common
  local ..cnt, ..total, ..fake_meta
  ..cnt = 0

  if used lbl#.#meta | (defined options.WholeTheme & options.WholeTheme)

    label lbl#.#meta dword
    label ..fake_meta  dword

    dd ..fake_lbl
    dd lbl#.#size
    dd ..total

; metadata
forward
  local ..namestr

; array with the fields names and offsets.
    if defined lbl#.#name

      dd  ..namestr
      dw  ___nat#type
      dw  ..len     ; dwords
      dd  ..fake_name - ..fake_lbl

      ..cnt = ..cnt + 1

    end if

; field names
forward

    if used ..namestr | (defined options.WholeTheme & options.WholeTheme)
      ..namestr db `name, 0
    end if

; Initialization code
common
  end if

    if used lbl#.#Init | (defined options.WholeTheme & options.WholeTheme)
      lbl#.#Init:

forward

local ..index

      ..index = 0

      irp val, value \{
        if used lbl\#.\#name | (defined options.WholeTheme & options.WholeTheme)
          if type eq FONT
            mov     eax, [..fake_name+..index+4]
            stdcall  FontCreate, [eax+__TFont.hFontFace], [eax+__TFont.height], [eax+__TFont.weight], [eax+__TFont.flags]
            mov      [..fake_name+..index], eax

            ..index = ..index + 4
          end if

          if (type eq PNG)
            mov     eax, [..fake_name+..index+4]
            stdcall  CreateImagePNG, eax, [eax-4]
            mov      [..fake_name+..index], eax

            ..index = ..index + 4
          end if
        end if

        ..index = ..index + 4
      \}

common
          retn
    end if
common
  lbl#.#size = $ - ..fake_lbl

  ..total = ..cnt
}



; Serializes the NamedArray to a string.
; .pMeta - poitner to the meta data of the named array structure.

proc NamedArrayToString, .pMeta
.array dd ?
.data2string dd ?
.datalen     dd ?
begin
        pushad

        mov     esi, [.pMeta]
        stdcall StrNew
        mov     edi, eax

        lodsd
        mov     [.array], eax

        lodsd   ; TMetaHeader.length

        lodsd
        mov     ecx, eax        ; count of the meta records.

.loop:
        dec     ecx
        js      .end_loop

        lodsd                   ; pointer to the field name.

        stdcall StrCat, edi, eax
        stdcall StrCharCat, edi, " = "

        lodsw                   ; data type
        movzx   eax, ax
        push    [.data_handlers+4*eax]
        push    [.data_len+4*eax]

        pop     [.datalen]
        pop     [.data2string]

        lodsw
        movzx   edx, ax         ; number of sub values

        lodsd                   ; offset, relative to [.array]
        mov     ebx, eax
        add     ebx, [.array]   ; pointer to the values

.loop2:
        dec     edx
        js      .end_loop2

        stdcall [.data2string], ebx
        push    eax

        stdcall StrCat, edi, eax
        stdcall StrDel ; from the stack

        add     ebx, [.datalen]

        test    edx, edx
        jz      .loop2

        stdcall StrCharCat, edi, ", "
        jmp     .loop2

.end_loop2:
        stdcall StrCharCat, edi, $0a0d
        jmp     .loop

.end_loop:
        mov     [esp+regEAX*4], edi
        popad
        return


.data_handlers dd __DataToNum, __DataToHex, __DataToTxt, __DataToFont, __DataToPng, __DataToFile
.data_len      dd 4,           4,           4,           8,            8,            4

endp


proc __DataToNum, .pData
begin
        mov     eax, [.pData]
        stdcall NumToStr, [eax], ntsDec or ntsSigned
        return
endp



proc __DataToHex, .pData
begin
        mov     eax, [.pData]
        stdcall NumToStr, [eax], ntsHex or ntsUnsigned
        stdcall StrCharInsert, eax, '$', 0
        return
endp



proc __DataToTxt, .pData
begin
        mov     eax, [.pData]
        stdcall StrDupMem, [eax]
        stdcall StrSetQuotes, eax, 0
        return
endp



proc __DataToFont, .pData
begin
        push    esi ebx

        mov     esi, [.pData]
        mov     esi, [esi+4]

        stdcall StrDup, [esi+__TFont.hFontFace]    ; face name
        stdcall StrSetQuotes, eax, 0
        mov     ebx, eax

        stdcall StrCharCat, ebx, " : "

        stdcall NumToStr, [esi+__TFont.height], ntsDec or ntsUnsigned    ; size
        stdcall StrCat, ebx, eax
        stdcall StrDel, eax

        stdcall StrCharCat, ebx, " : "

        stdcall NumToStr, [esi+__TFont.weight], ntsDec or ntsUnsigned    ; weight
        stdcall StrCat, ebx, eax
        stdcall StrDel, eax

        stdcall StrCharCat, ebx, " : $"

        stdcall NumToStr, [esi+__TFont.flags], ntsHex or ntsUnsigned    ; flags
        stdcall StrCat, ebx, eax
        stdcall StrDel, eax

        mov     eax, ebx

        pop     ebx esi
        return
endp



proc __DataToPng, .pData
begin
        pushad

        mov     esi, [.pData]
        mov     esi, [esi+4]            ; pointer to the compressed file.
        mov     ecx, [esi-4]            ; length
        jmp     __DataToFile.convert_file
endp



proc __DataToFile, .pData
begin
        pushad

        mov     esi, [.pData]
        mov     esi, [esi]              ; pointer to the compressed file.
        mov     ecx, [esi-4]            ; length

.convert_file:
        stdcall NumToStr, ecx, ntsDec or ntsUnsigned
        mov     ebx, eax

        stdcall StrCharCat, ebx, ":"

        stdcall EncodeBase64, esi, ecx
        push    eax

        stdcall StrCat, ebx, eax
        stdcall StrDel ; from the stack

        mov     [esp+regEAX*4], ebx
        popad
        return
endp




proc StringToNamedArray, .pMeta, .hString
.string2data dd ?
.free_data   dd ?
.data_start  dd ?
.data_end    dd ?
begin
        pushad

        mov     esi, [.pMeta]
        mov     eax, [esi+TMetaHeader.pData]
        mov     [.data_start], eax
        add     eax, [esi+TMetaHeader.length]
        mov     [.data_end], eax

        stdcall StrSplitList, [.hString], $0a, FALSE
        mov     esi, eax

        xor     ecx, ecx

.loop:
        cmp     ecx, [esi+TArray.count]
        jae     .end_loop

        stdcall StrSplitList, [esi+TArray.array+4*ecx], "=", FALSE
        mov     edi, eax

        cmp     [edi+TArray.count], 2
        jne     .next_line

        stdcall __SearchName, [.pMeta], [edi+TArray.array]
        test    eax, eax
        jz      .free1

        push    esi ecx

        mov     ebx, eax

        stdcall StrSplitList, [edi+TArray.array+4], ',', FALSE
        mov     edx, eax

        movzx   ecx, [ebx+TMetaField.len]
        cmp     ecx, [edx+TArray.count]
        jb      .free2                          ; there is no place to restore this parameter.

        movzx   eax, [ebx+TMetaField.type]
        push    [.data_handlers+4*eax]
        push    [.free_handlers+4*eax]

        pop     [.free_data]
        pop     [.string2data]

        mov     esi, [ebx+TMetaField.offset]
        add     esi, [.data_start]      ; pointer to the data field.

        xor     ecx, ecx

.loop2:
        cmp     ecx, [edx+TArray.count]
        jae     .free2

        call    [.free_data]
        stdcall [.string2data], [edx+TArray.array+4*ecx]

        inc     ecx
        jmp     .loop2


.free2:
        stdcall ListFree, edx, StrDel

        pop     ecx esi

.free1:
        stdcall ListFree, edi, StrDel

.next_line:
        inc     ecx
        jmp     .loop

.end_loop:
        stdcall ListFree, esi, StrDel
        popad
        return

.data_handlers dd __NumToData, __NumToData, __TxtToData, __FontToData, __PngToData, __FileToData
.free_handlers dd .end_free,   .end_free,   .free_txt,   .free_font,   .free_png,   .free_file


.check_ptr:
        test    eax, eax
        jz      .out

        cmp     eax, [.data_start]
        jb      .out
        cmp     eax, [.data_end]
        ja      .out
;in
        stc
        retn

.out:
        clc
        retn

.free_txt:
        stdcall StrDel, [esi]
        retn

.free_font:
        stdcall FontDestroy, [esi]
        mov     eax, [esi+4]
        call    .check_ptr
        jc      .end_free

        stdcall StrDel, [eax+__TFont.hFontFace]
        retn

.free_png:
        stdcall DestroyImage, [esi]
        mov     eax, [esi+4]

.free_ptr:
        sub     eax, 4
        call    .check_ptr
        jc      .end_free

        stdcall FreeMem, eax

.end_free:
        retn


.free_file:
        mov     eax, [esi]
        jmp     .free_ptr

endp



proc __NumToData, .hString
begin
        stdcall StrToNumEx, [.hString]
        mov     [esi], eax
        add     esi, 4
        return
endp


proc __TxtToData, .hString
begin
        stdcall StrDup, [.hString]
        stdcall StrClipQuotes, eax
        mov     [esi], eax
        add     esi, 4
        return
endp



proc __FontToData, .hString
begin
        push    ebx ecx edx edi

        xor     eax, eax
        mov     [esi], eax

        mov     edi, [esi+4]    ; pointer to the font parameters.

        stdcall StrSplitList, [.hString], ":", FALSE
        mov     edx, eax

        cmp     [edx+TArray.count], 4
        jne     .finish

        stdcall StrClipQuotes, [edx+TArray.array]
        stdcall StrDup, [edx+TArray.array]
        mov     [edi+__TFont.hFontFace], eax

        stdcall StrToNumEx, [edx+TArray.array+4]        ; size
        mov     [edi+__TFont.height], eax
        mov     ebx, eax

        stdcall StrToNumEx, [edx+TArray.array+8]        ; weight
        mov     [edi+__TFont.weight], eax
        mov     ecx, eax

        stdcall StrToNumEx, [edx+TArray.array+12]       ; flags
        mov     [edi+__TFont.flags], eax
        mov     edi, eax

        stdcall StrPtr, [edx+TArray.array]
        stdcall FontCreate, eax, ebx, ecx, edi

        stdcall ListFree, edx, StrDel

        mov     [esi], eax
        add     esi, 8

.finish:
        pop     edi edx ecx ebx
        return
endp



proc __PngToData, .hString
begin
        push    edx

        stdcall StrSplitList, [.hString], ":", FALSE
        mov     edx, eax

        cmp     [edx+TArray.count], 2
        jne     .finish

        stdcall DecodeBase64, [edx+TArray.array+4]

        mov     [esi+4], eax

        stdcall CreateImagePNG, eax, [eax-4]
        mov     [esi], eax

.finish:
        add     esi, 8
        pop     edx
        return
endp



proc __FileToData, .hString
begin
        push    edx

        stdcall StrSplitList, [.hString], ":", FALSE
        mov     edx, eax

        cmp     [edx+TArray.count], 2
        jne     .finish

        stdcall DecodeBase64, [edx+TArray.array+4]

        mov     [esi], eax

.finish:
        add     esi, 4
        pop     edx
        return
endp



; returns a pointer to the parameter description block: name, count, offset.

proc __SearchName, .pMeta, .hName
begin
        push    esi ecx

        mov     esi, [.pMeta]

        mov     ecx, [esi+TMetaHeader.count]
        add     esi, sizeof.TMetaHeader

.search:
        dec     ecx
        js      .not_found

        stdcall StrCompCase, [esi+TMetaField.pName], [.hName]
        jc      .found

        add     esi, sizeof.TMetaField
        jmp     .search

.not_found:
        xor     esi, esi

.found:
        mov     eax, esi
        pop     ecx esi
        return
endp




iglobal
; drawing functions.

  var DrawBox = DrawBoxDefault
  var DrawSlider = DrawSliderDefault

  var DrawSplitter = DrawSplitterDefault
endg



proc DrawBoxDefault, .pImage, .pBounds, .bkground, .border, .brd_width
begin
        pushad

        mov     esi, [.pBounds]

        mov     edx, [.border]
        and     edx, $ff
        jz      .borderok

        mov     eax, [GUI.clBorderLight]
        mov     ecx, [GUI.clBorderDark]

        test    [.border], bxDisabled
        jz      .enabled_ok

        mov     eax, [GUI.clBorderLightGray]
        mov     ecx, [GUI.clBorderDarkGray]

.enabled_ok:
        cmp     edx, bxRaised
        je      .colorok

        xchg    eax, ecx

        cmp     edx, bxSunken
        je      .colorok

        mov     eax, [GUI.clBorderNeutralGray]

        test    [.border], bxDisabled
        jnz     .flat_ok

        mov     eax, [GUI.clBorderNeutral]

.flat_ok:
        mov     ecx, eax
        cmp     edx, bxFlat
        je      .colorok

        mov     eax, [GUI.clBorderFocused]
        mov     ecx, eax

.colorok:
        mov     ebx, [.brd_width]

; left border line
        stdcall DrawSolidRect, [.pImage], [esi+TBounds.x],[esi+TBounds.y], ebx, [esi+TBounds.height], eax

; top
        add     [esi+TBounds.x], ebx
        sub     [esi+TBounds.width], ebx

        stdcall DrawSolidRect, [.pImage], [esi+TBounds.x], [esi+TBounds.y], [esi+TBounds.width], ebx, eax

; right
        sub     [esi+TBounds.width], ebx
        add     [esi+TBounds.y], ebx
        sub     [esi+TBounds.height], ebx

        mov     edx, [esi+TBounds.width]
        add     edx, [esi+TBounds.x]
        stdcall DrawSolidRect, [.pImage], edx, [esi+TBounds.y], ebx, [esi+TBounds.height], ecx

; bottom
        sub     [esi+TBounds.height], ebx

        mov     edx, [esi+TBounds.y]
        add     edx, [esi+TBounds.height]
        stdcall DrawSolidRect, [.pImage], [esi+TBounds.x], edx, [esi+TBounds.width], ebx, ecx

.borderok:
        bt      [.border], 31
        jc      .fillok

        stdcall DrawSolidRect, [.pImage], [esi+TBounds.x], [esi+TBounds.y], [esi+TBounds.width], [esi+TBounds.height], [.bkground]

.fillok:

        popad
        return
endp



sliderHorizontal = 0
sliderVertical   = 1

proc DrawSliderDefault, .pImage, .pBounds, .bkground, .type
begin
        stdcall DrawBoxDefault, [.pImage], [.pBounds], [.bkground], [scrollBorder], 2
        return
endp





proc DrawSplitterDefault, .pImage, .pRect, .type
begin
        pushad

        mov     esi, [.pRect]
        mov     eax, [esi+RECT.right]
        mov     ecx, [esi+RECT.bottom]
        sub     eax, [esi+RECT.left]
        sub     ecx, [esi+RECT.top]

        stdcall DrawSolidRect, [.pImage], [esi+RECT.left], [esi+RECT.top], eax, ecx, [GUI.clSplitter]
        popad
        return
endp


proc DrawSplitterDefault2, .pImage, .pRect, .type
.bounds TBounds
begin
        pushad

        mov     esi, [.pRect]
        mov     eax, [esi+RECT.left]
        mov     ecx, [esi+RECT.top]
        mov     edx, [esi+RECT.right]
        mov     ebx, [esi+RECT.bottom]
        sub     edx, eax
        sub     ebx, ecx
        mov     [.bounds.x], eax
        mov     [.bounds.y], ecx
        mov     [.bounds.width], edx
        mov     [.bounds.height], ebx
        lea     eax, [.bounds]

        stdcall DrawBoxDefault, [.pImage], eax, [GUI.clDialogBk], bxSunken, [GUI.boxBorderWidth]

        popad
        return
endp






endmodule





