; int __stdcall GenericBox(DLGTEMPLATE* dlg, void* DlgProc);
;       int __stdcall DlgProc(DLGTEMPLATE* dlg, int msg, int param1, int param2);

virtual at 0
dlgtemplate:
; ”« £¨:
; ¡¨â 0: ¨á¯®«ì§®¢ âì áâ ­¤ àâ­ë¥ æ¢¥â  ¤¨ «®£ 
; ¡¨â 1: ¨á¯®«ì§®¢ âì áâ ­¤ àâ­ë¥ æ¢¥â  ¯à¥¤ã¯à¥¦¤¥­¨ï/®è¨¡ª¨
; (¥á«¨ «î¡®© ¨§ íâ¨å ¡¨â®¢ ãáâ ­®¢«¥­, ¯®«ï main_color,border_color,header_color
;  ¨£­®à¨àãîâáï)
; ¡¨â 2: ­¥ à¨á®¢ âì ⥭ì
.flags          dd      ?
.x              dd      ?
.y              dd      ?
.width          dd      ?
.height         dd      ?
.border_size_x  dd      ?
.border_size_y  dd      ?
.title          dd      ?
.main_color     db      ?
.border_color   db      ?
.header_color   db      ?
                db      ?       ; align
.dataptr        dd      ?       ; used internally, ignored on input
.size = $
end virtual

GenericBox:
        push    [cursor_x]
        push    [cursor_y]
        push    dword [esp+8+8]
        push    dword [esp+8+8]
        call    ShowGenericBox
        test    eax, eax
        jz      @f
        pop     [cursor_y]
        pop     [cursor_x]
        ret
@@:
        pushad
; message loop
.event:
;        call    get_event
        push    10
        pop     eax
        int     40h
        dec     eax
        jz      .redraw
        dec     eax
        jz      .key
        jmp     exit
.redraw:
        call    draw_window
        jmp     .event
.key:
        mov     al, 2
        int     40h
        shr     eax, 8
        cmp     al, 0xE0
        jnz     @f
        mov     [bWasE0], 1
        jmp     .event
@@:
        xchg    ah, [bWasE0]
        cmp     al, 0x1D
        jz      .ctrl_down
        cmp     al, 0x9D
        jz      .ctrl_up
        cmp     al, 0x2A
        jz      .lshift_down
        cmp     al, 0xAA
        jz      .lshift_up
        cmp     al, 0x36
        jz      .rshift_down
        cmp     al, 0xB6
        jz      .rshift_up
        cmp     al, 0x38
        jz      .alt_down
        cmp     al, 0xB8
        jz      .alt_up
        mov     ebx, [esp+24h+8]
        mov     ecx, [esp+28h+8]
        push    0
        push    eax
        push    2
        push    ebx
        call    ecx
        test    eax, eax
        jz      .event
        mov     [esp+28], eax
        jmp     .exit
.ctrl_down:
        test    ah, ah
        jnz     .rctrl_down
        or      [ctrlstate], 4
        jmp     .event
.rctrl_down:
        or      [ctrlstate], 8
        jmp     .event
.ctrl_up:
        test    ah, ah
        jnz     .rctrl_up
        and     [ctrlstate], not 4
        jmp     .event
.rctrl_up:
        and     [ctrlstate], not 8
        jmp     .event
.lshift_down:
        test    ah, ah
        jnz     @f
        or      [ctrlstate], 1
@@:     jmp     .event
.lshift_up:
        test    ah, ah
        jnz     @b
        and     [ctrlstate], not 1
        jmp     @b
.rshift_down:
        or      [ctrlstate], 2
        jmp     .event
.rshift_up:
        and     [ctrlstate], not 2
        jmp     .event
.alt_down:
        test    ah, ah
        jnz     .ralt_down
        or      [ctrlstate], 0x10
        jmp     .event
.ralt_down:
        or      [ctrlstate], 0x20
        jmp     .event
.alt_up:
        test    ah, ah
        jnz     .ralt_up
        and     [ctrlstate], not 0x10
        jmp     .event
.ralt_up:
        and     [ctrlstate], not 0x20
        jmp     .event
.exit:
        popad
        push    eax
        push    0
        push    dword [esp+12+8]
        call    HideGenericBox
        pop     eax
        pop     [cursor_y]
        pop     [cursor_x]
        pushad
        call    draw_image
        popad
        ret     8

; int __stdcall ShowGenericBox(DLGTEMPLATE* dlg, void* DlgProc);
ShowGenericBox:
        pushad
        mov     ebx, [esp+20h+4]
; center window if required
        push    [ebx+dlgtemplate.x]
        push    [ebx+dlgtemplate.y]
        cmp     [ebx+dlgtemplate.x], -1
        jnz     @f
        mov     eax, [cur_width]
        sub     eax, [ebx+dlgtemplate.width]
        shr     eax, 1
        mov     [ebx+dlgtemplate.x], eax
@@:
        cmp     [ebx+dlgtemplate.y], -1
        jnz     @f
        mov     eax, [cur_height]
        sub     eax, [ebx+dlgtemplate.height]
        shr     eax, 1
        mov     [ebx+dlgtemplate.y], eax
@@:
; some checks
        mov     eax, [ebx+dlgtemplate.x]
        cmp     eax, 1
        jl      .sizeerr
        add     eax, [ebx+dlgtemplate.width]
        cmp     eax, [cur_width]
        jge     .sizeerr
        mov     eax, [ebx+dlgtemplate.y]
        cmp     eax, 1
        jl      .sizeerr
        add     eax, [ebx+dlgtemplate.height]
        cmp     eax, [cur_height]
        jge     .sizeerr
        cmp     [ebx+dlgtemplate.border_size_x], 1
        jl      .sizeerr
        cmp     [ebx+dlgtemplate.border_size_y], 1
        jge     .sizeok
.sizeerr:
        pop     [ebx+dlgtemplate.y]
        pop     [ebx+dlgtemplate.x]
        popad
        or      eax, -1
        ret     8
.sizeok:
; set color if required
        test    byte [ebx+dlgtemplate.flags], 1
        jz      @f
        mov     edi, dialog_colors
        jmp     .setcolor
@@:
        test    byte [ebx+dlgtemplate.flags], 2
        jz      @f
        mov     edi, warning_colors
.setcolor:
        mov     al, [edi + dialog_main_color-dialog_colors]
        mov     [ebx+dlgtemplate.main_color], al
        mov     al, [edi + dialog_border_color-dialog_colors]
        mov     [ebx+dlgtemplate.border_color], al
        mov     al, [edi + dialog_header_color-dialog_colors]
        mov     [ebx+dlgtemplate.header_color], al
@@:
; allocate memory for data under dialog
; for 'No memory' dialog use static data area
        mov     eax, nomem_dlgsavearea
        cmp     ebx, nomem_dlgdata
        jz      .allocated
        mov     eax, [ebx+dlgtemplate.width]
        add     eax, [ebx+dlgtemplate.border_size_x]
        add     eax, [ebx+dlgtemplate.border_size_x]
        inc     eax
        inc     eax
        mov     edx, [ebx+dlgtemplate.height]
        add     edx, [ebx+dlgtemplate.border_size_y]
        add     edx, [ebx+dlgtemplate.border_size_y]
        inc     edx
        mul     edx
        lea     ecx, [eax*2+8]
        call    xpgalloc
        test    eax, eax
        jnz     @f
        pop     [ebx+dlgtemplate.y]
        pop     [ebx+dlgtemplate.x]
        popad
        or      eax, -1
        ret     8
@@:
.allocated:
        mov     [ebx+dlgtemplate.dataptr], eax
        pop     dword [eax+4]
        pop     dword [eax]
        lea     ebp, [eax+8]
; save data
        mov     eax, [ebx+dlgtemplate.y]
        add     eax, [ebx+dlgtemplate.height]
        add     eax, [ebx+dlgtemplate.border_size_y]
        inc     eax
        push    eax
        mov     eax, [ebx+dlgtemplate.x]
        add     eax, [ebx+dlgtemplate.width]
        add     eax, [ebx+dlgtemplate.border_size_x]
        inc     eax
        inc     eax
        push    eax
        mov     eax, [ebx+dlgtemplate.y]
        sub     eax, [ebx+dlgtemplate.border_size_y]
        push    eax
        mov     eax, [ebx+dlgtemplate.x]
        sub     eax, [ebx+dlgtemplate.border_size_x]
        push    eax
        call    save_console_data
; draw shadow
        test    byte [ebx+dlgtemplate.flags], 4
        jnz     .noshadow
        call    draw_dialog_shadow
.noshadow:
        popad
        push    dword [esp+8]
        push    dword [esp+8]
        call    DrawGenericBox
        xor     eax, eax
        ret     8

draw_dialog_shadow:
        mov     eax, [ebx+dlgtemplate.x]
        sub     eax, [ebx+dlgtemplate.border_size_x]
        ja      @f
        xor     eax, eax
@@:
        inc     eax
        inc     eax
        mov     edx, [ebx+dlgtemplate.y]
        sub     edx, [ebx+dlgtemplate.border_size_y]
        ja      @f
        xor     edx, edx
@@:
        inc     edx
        call    get_console_ptr
        mov     ecx, [ebx+dlgtemplate.y]
        add     ecx, [ebx+dlgtemplate.height]
        add     ecx, [ebx+dlgtemplate.border_size_y]
        inc     ecx
        cmp     ecx, [cur_height]
        jb      @f
        mov     ecx, [cur_height]
@@:
        sub     ecx, edx
        mov     edx, ecx
        mov     ecx, [ebx+dlgtemplate.x]
        add     ecx, [ebx+dlgtemplate.width]
        add     ecx, [ebx+dlgtemplate.border_size_x]
        inc     ecx
        inc     ecx
        cmp     ecx, [cur_width]
        jb      @f
        mov     ecx, [cur_width]
@@:
        sub     ecx, eax
        mov     eax, ecx
.shadow_loop:
        mov     ecx, eax
        push    edi
.sl1:
        inc     edi
        test    byte [edi], 0x0F
        jnz     @f
        or      byte [edi], 8
@@:
        and     byte [edi], 0x0F
        inc     edi
        loop    .sl1
        pop     edi
        add     edi, [cur_width]
        add     edi, [cur_width]
        dec     edx
        jnz     .shadow_loop
        ret

; void __stdcall DrawGenericBox(DLGDATA* dlg, void* DlgProc)
DrawGenericBox:
        pushad
        mov     ebx, [esp+24h]
; draw area background
        mov     eax, [ebx+dlgtemplate.x]
        sub     eax, [ebx+dlgtemplate.border_size_x]
        ja      @f
        xor     eax, eax
@@:
        mov     edx, [ebx+dlgtemplate.y]
        sub     edx, [ebx+dlgtemplate.border_size_y]
        ja      @f
        xor     edx, edx
@@:
        call    get_console_ptr
        mov     ecx, [ebx+dlgtemplate.x]
        add     ecx, [ebx+dlgtemplate.width]
        add     ecx, [ebx+dlgtemplate.border_size_x]
        cmp     ecx, [cur_width]
        jb      @f
        mov     ecx, [cur_width]
@@:
        sub     ecx, eax
        mov     esi, ecx
        mov     ecx, [ebx+dlgtemplate.y]
        add     ecx, [ebx+dlgtemplate.height]
        add     ecx, [ebx+dlgtemplate.border_size_y]
        cmp     ecx, [cur_height]
        jb      @f
        mov     ecx, [cur_height]
@@:
        sub     ecx, edx
        mov     edx, ecx
        mov     al, ' '
        mov     ah, [ebx+dlgtemplate.border_color]
.1:
        mov     ecx, esi
        push    edi
        rep     stosw
        pop     edi
        add     edi, [cur_width]
        add     edi, [cur_width]
        dec     edx
        jnz     .1
; draw border
        mov     eax, [ebx+dlgtemplate.x]
        dec     eax
        mov     edx, [ebx+dlgtemplate.y]
        dec     edx
        call    get_console_ptr
        mov     edx, [ebx+dlgtemplate.height]
        inc     edx
        inc     edx
        mov     ah, [ebx+dlgtemplate.border_color]
        push    ebx
        mov     ebx, [ebx+dlgtemplate.width]
        inc     ebx
        inc     ebx
        call    draw_border
        pop     ebx
; draw header
        mov     esi, [ebx+dlgtemplate.title]
        test    esi, esi
        jz      .noheader
        cmp     byte [esi], 0
        jz      .noheader
        push    esi
@@:     lodsb
        test    al, al
        jnz     @b
        mov     eax, esi
        pop     esi
        sub     eax, esi
        inc     eax     ; eax = ¤«¨­  § £®«®¢ª  + 2
        mov     ecx, [ebx+dlgtemplate.width]
        cmp     eax, ecx
        jbe     .fullhea
        sub     ecx, 5
        jb      .noheader
        xor     edx, edx
        jmp     .drawhea
.fullhea:
        mov     edx, ecx
        sub     edx, eax
        shr     edx, 1
.drawhea:
        mov     eax, [ebx+dlgtemplate.x]
        add     eax, edx
        mov     edx, [ebx+dlgtemplate.y]
        dec     edx
        call    get_console_ptr
        mov     ah, [ebx+dlgtemplate.header_color]
        mov     al, ' '
        stosw
.2:
        dec     ecx
        jz	.3
        lodsb
        test    al, al
        jz      .4
        stosw
        jmp     .2
.3:
        mov     al, '.'
        stosw
        stosw
        stosw
.4:
        mov     al, ' '
        stosw
.noheader:
; draw window background
        mov     eax, [ebx+dlgtemplate.x]
        mov     edx, [ebx+dlgtemplate.y]
        call    get_console_ptr
        mov     ah, [ebx+dlgtemplate.main_color]
        mov     al, ' '
        mov     edx, [ebx+dlgtemplate.height]
@@:
        mov     ecx, [ebx+dlgtemplate.width]
        push    edi
        rep     stosw
        pop     edi
        add     edi, [cur_width]
        add     edi, [cur_width]
        dec     edx
        jnz     @b
; send redraw message
        mov     eax, [esp+28h]
        push    0
        push    0
        push    1
        push    ebx
        call    eax
        call    draw_image
        popad
        ret     8

; void __stdcall HideGenericBox(DLGTEMPLATE* dlg, int bRedrawWindow);
HideGenericBox:
; void __stdcall HideDialogBox(DLGDATA* dlg, int bRedrawWindow);
HideDialogBox:
        pushad
        mov     ebx, [esp+24h]
        mov     ebp, [ebx+dlgtemplate.dataptr]
        add     ebp, 8
; restore data
        mov     eax, [ebx+dlgtemplate.y]
        add     eax, [ebx+dlgtemplate.height]
        add     eax, [ebx+dlgtemplate.border_size_y]
        inc     eax
        push    eax
        mov     eax, [ebx+dlgtemplate.x]
        add     eax, [ebx+dlgtemplate.width]
        add     eax, [ebx+dlgtemplate.border_size_x]
        inc     eax
        inc     eax
        push    eax
        mov     eax, [ebx+dlgtemplate.y]
        sub     eax, [ebx+dlgtemplate.border_size_y]
        push    eax
        mov     eax, [ebx+dlgtemplate.x]
        sub     eax, [ebx+dlgtemplate.border_size_x]
        push    eax
        call    restore_console_data
        call    draw_keybar
        lea     ecx, [ebp-8]
        push    dword [ecx]
        push    dword [ecx+4]
        pop     [ebx+dlgtemplate.y]
        pop     [ebx+dlgtemplate.x]
        cmp     ebx, nomem_dlgdata
        jz      @f
        call    pgfree
@@:
        or      [cursor_x], -1
        or      [cursor_y], -1
        cmp     dword [esp+28h], 0
        jz      @f
        call    draw_image
@@:
        popad
        ret     8

save_console_data:
        cmp     dword [esp+4], 0
        jge     @f
        and     dword [esp+4], 0
@@:
        cmp     dword [esp+8], 0
        jge     @f
        and     dword [esp+8], 0
@@:
        mov     eax, [esp+12]
        cmp     eax, [cur_width]
        jbe     @f
        mov     eax, [cur_width]
@@:
        sub     eax, [esp+4]
        ja      @f
        ret     16
@@:
        mov     [esp+12], eax
        mov     eax, [esp+16]
        cmp     eax, [cur_height]
        jbe     @f
        mov     eax, [cur_height]
@@:
        sub     eax, [esp+8]
        ja      @f
        ret     16
@@:
        mov     [esp+16], eax
        mov     eax, [esp+4]
        mov     edx, [esp+8]
        call    get_console_ptr
        mov     esi, edi
        mov     edi, ebp
.l:
        mov     ecx, [esp+12]
        push    esi
        shr     ecx, 1
        rep     movsd
        adc     ecx, ecx
        rep     movsw
        pop     esi
        add     esi, [cur_width]
        add     esi, [cur_width]
        dec     dword [esp+16]
        jnz     .l
        ret     16

restore_console_data:
        cmp     dword [esp+4], 0
        jge     @f
        and     dword [esp+4], 0
@@:
        cmp     dword [esp+8], 0
        jge     @f
        and     dword [esp+8], 0
@@:
        mov     eax, [esp+12]
        cmp     eax, [cur_width]
        jbe     @f
        mov     eax, [cur_width]
@@:
        sub     eax, [esp+4]
        ja      @f
        ret     16
@@:
        mov     [esp+12], eax
        mov     eax, [esp+16]
        cmp     eax, [cur_height]
        jbe     @f
        mov     eax, [cur_height]
@@:
        sub     eax, [esp+8]
        ja      @f
        ret     16
@@:
        mov     [esp+16], eax
        mov     eax, [esp+4]
        mov     edx, [esp+8]
        call    get_console_ptr
        mov     esi, ebp
.l:
        mov     ecx, [esp+12]
        push    edi
        shr     ecx, 1
        rep     movsd
        adc     ecx, ecx
        rep     movsw
        pop     edi
        add     edi, [cur_width]
        add     edi, [cur_width]
        dec     dword [esp+16]
        jnz     .l
        ret     16

; int __stdcall menu(void* variants, const char* title, unsigned flags);
; variants 㪠§ë¢ ¥â ­  ⥪ã騩 í«¥¬¥­â ¢ ¤¢ãá¢ï§­®¬ «¨­¥©­®¬ ᯨ᪥
menu:
        pop     eax
        push    [cur_height]
        push    [cur_width]
        push    0
        push    0
        push    eax

; int __stdcall menu_centered_in(unsigned left, unsigned top, unsigned width, unsigned height,
;       void* variants, const char* title, unsigned flags);
menu_centered_in:
        pushad
        mov     ecx, 60
; 40 bytes for dlgtemplate + additional:
; +40: dd cur_variant
; +44: dd num_variants
; +48: dd begin_variant
; +52: dd end_variant
; +56: dd cur_variant_idx
        call    xpgalloc
        test    eax, eax
        jnz     @f
.ret_bad:
        popad
        or      eax, -1
        ret     28
@@:
        mov     ebx, eax
        mov     eax, 1
        test    byte [esp+20h+28], 1
        jz      @f
        mov     al, 3
@@:
        mov     [ebx+dlgtemplate.border_size_x], eax
        inc     eax
        shr     eax, 1
        mov     [ebx+dlgtemplate.border_size_y], eax
;  å®¤¨¬ è¨à¨­ã ¨ ¢ëá®âã ®ª­ 
        xor     eax, eax
        xor     ecx, ecx
        mov     esi, [esp+20h+20]
        mov     [ebx+40], esi
        mov     dword [ebx+56], eax
@@:
        cmp     dword [esi+4], eax
        jz      .find_width
        mov     esi, [esi+4]
        inc     dword [ebx+56]
        jmp     @b
.find_width:
        mov     [ebx+48], esi
        add     esi, 8
        push    esi
        xor     edx, edx
.fw1:
        cmp     byte [esi], '&'
        jnz     @f
        mov     dl, 1
@@:
        inc     esi
        cmp     byte [esi-1], 0
        jnz     .fw1
        sub     esi, [esp]
        sub     esi, edx
        dec     esi
        cmp     eax, esi
        ja      @f
        mov     eax, esi
@@:
        inc     ecx
        pop     esi
        mov     esi, [esi-8]
        test    esi, esi
        jnz     .find_width
        add     eax, 3
        add     eax, [ebx+dlgtemplate.border_size_x]
        add     eax, [ebx+dlgtemplate.border_size_x]
        cmp     eax, [cur_width]
        jb      @f
        mov     eax, [cur_width]
@@:
        sub     eax, [ebx+dlgtemplate.border_size_x]
        sub     eax, [ebx+dlgtemplate.border_size_x]
        mov     [ebx+dlgtemplate.width], eax
        mov     [ebx+dlgtemplate.height], ecx
        mov     [ebx+44], ecx
        sub     eax, [esp+20h+12]
        neg     eax
        sar     eax, 1
        add     eax, [esp+20h+4]
        cmp     eax, [ebx+dlgtemplate.border_size_x]
        jge     @f
        mov     eax, [ebx+dlgtemplate.border_size_x]
@@:
        push    eax
        add     eax, [ebx+dlgtemplate.width]
        add     eax, [ebx+dlgtemplate.border_size_x]
        cmp     eax, [cur_width]
        jbe     @f
        pop     eax
        mov     eax, [cur_width]
        sub     eax, [ebx+dlgtemplate.width]
        sub     eax, [ebx+dlgtemplate.border_size_x]
        push    eax
@@:
        pop     [ebx+dlgtemplate.x]
        sub     ecx, [esp+20h+16]
        neg     ecx
        sar     ecx, 1
        add     ecx, [esp+20h+8]
        cmp     ecx, [ebx+dlgtemplate.border_size_y]
        jge     @f
        mov     ecx, [ebx+dlgtemplate.border_size_y]
@@:
        push    ecx
        add     ecx, [ebx+dlgtemplate.height]
        add     ecx, [ebx+dlgtemplate.border_size_y]
        cmp     ecx, [cur_height]
        jbe     @f
        pop     ecx
        mov     ecx, [cur_height]
        sub     ecx, [ebx+dlgtemplate.height]
        sub     ecx, [ebx+dlgtemplate.border_size_y]
        push    ecx
@@:
        pop     [ebx+dlgtemplate.y]
        mov     eax, [cur_height]
        sub     eax, 6
        cmp     [ebx+dlgtemplate.height], eax
        jbe     .small_height
        mov     [ebx+dlgtemplate.height], eax
        mov     [ebx+dlgtemplate.y], 3
.small_height:
        mov     ecx, [ebx+dlgtemplate.height]
        mov     eax, [ebx+40]
        mov     [ebx+48], eax
        dec     ecx
        jz      .skip
        push    ecx
@@:
        cmp     dword [eax+4], 0
        jz      @f
        mov     eax, [eax+4]
        loop    @b
@@:
        mov     [ebx+48], eax
        pop     ecx
.loop:
        mov     eax, [eax]
        loop    .loop
.skip:
        mov     [ebx+52], eax
        mov     eax, [esp+20h+24]
        mov     [ebx+dlgtemplate.title], eax
        mov     al, [menu_normal_color]
        mov     [ebx+dlgtemplate.main_color], al
        mov     al, [menu_border_color]
        mov     [ebx+dlgtemplate.border_color], al
        mov     al, [menu_header_color]
        mov     [ebx+dlgtemplate.header_color], al
        push    MenuDlgProc
        push    ebx
        call    GenericBox
        mov     [esp+28], eax
        mov     ecx, ebx
        call    pgfree
        popad
        ret     28

MenuDlgProc:
        mov     eax, [esp+8]
        cmp     al, 1
        jz      .draw
        cmp     al, 2
        jz      .key
        ret     16
.draw:
        call    .dodraw
        ret     16
.prev:
        mov     eax, [ebx+40]
        cmp     dword [eax+4], 0
        jz      .end
        call    .line_prev
.posret:
        mov     [ebx+40], eax
.redraw:
        call    .dodraw
        call    draw_image
        xor     eax, eax
        ret     16
.next:
        mov     eax, [ebx+40]
        cmp     dword [eax], 0
        jz      .home
        call    .line_next
        jmp     .posret
.pgdn:
        mov     eax, [ebx+40]
        mov     ecx, [ebx+dlgtemplate.height]
.pgdnl:
        cmp     dword [eax], 0
        jz      .posret
        call    .line_next
        loop    .pgdnl
        jmp     .posret
.key:
        mov     al, [esp+12]
        cmp     al, 0x48
        jz      .prev
        cmp     al, 0x4B
        jz      .prev
        cmp     al, 0x4D
        jz      .next
        cmp     al, 0x50
        jz      .next
        cmp     al, 0x1C
        jz      .enter
        cmp     al, 1
        jz      .esc
        cmp     al, 0x47
        jz      .home
        cmp     al, 0x4F
        jz      .end
        cmp     al, 0x51
        jz      .pgdn
        cmp     al, 0x49
        jz      .pgup
        cmp     al, 0x52
        jz      .ins
        cmp     al, 0x53
        jz      .del
        mov     edx, [ebx+40]
@@:
        cmp     dword [edx+4], 0
        jz      @f
        mov     edx, [edx+4]
        jmp     @b
@@:
.l:
        lea     esi, [edx+7]
@@:
        inc     esi
        cmp     byte [esi], 0
        jz      .n
        cmp     byte [esi], '&'
        jnz     @b
        movzx   ecx, byte [esi+1]
        cmp     [ascii2scan+ecx], al
        jnz     .n
        mov     eax, edx
        ret     16
.n:
        mov     edx, [edx]
        test    edx, edx
        jnz     .l
.ret:
        xor     eax, eax
        ret     16
.pgup:
        mov     eax, [ebx+40]
        mov     ecx, [ebx+dlgtemplate.height]
.pgupl:
        cmp     dword [eax+4], 0
        jz      .posret
        call    .line_prev
        loop    .pgupl
        jmp     .posret
.home:
        mov     eax, [ebx+40]
@@:
        cmp     dword [eax+4], 0
        jz      @f
        mov     eax, [eax+4]
        jmp     @b
@@:
        mov     [ebx+48], eax
        push    eax
        mov     ecx, [ebx+dlgtemplate.height]
        dec     ecx
        jz      .h1
.h2:
        mov     eax, [eax]
        loop    .h2
.h1:
        mov     [ebx+52], eax
        pop     eax
        and     dword [ebx+56], 0
        jmp     .posret
.end:
        mov     eax, [ebx+40]
@@:
        cmp     dword [eax], 0
        jz      @f
        mov     eax, [eax]
        jmp     @b
@@:
        mov     [ebx+52], eax
        push    eax
        mov     ecx, [ebx+dlgtemplate.height]
        dec     ecx
        jz      .e1
.e2:
        mov     eax, [eax+4]
        loop    .e2
.e1:
        mov     [ebx+48], eax
        mov     eax, [ebx+44]
        dec     eax
        mov     [ebx+56], eax
        pop     eax
        jmp     .posret
.esc:
        or      eax, -1
        ret     16
.enter:
        mov     eax, [ebx+40]
        ret     16
.ins:
        push    5
        pop     edx
        jmp     @f
.del:
        push    4
        pop     edx
@@:
        mov     eax, [ebx+40]
        cmp     byte [eax+8], '/'
        jnz     @f
        cmp     word [eax+9], 'cd'
        jnz     @f
        movzx   ecx, byte [eax+11]
        sub     ecx, '0'
        push    24
        pop     eax
        mov     ebx, edx
        int     40h
@@:
        xor     eax, eax
        ret     16

.line_prev:
        cmp     eax, [ebx+48]
        jnz     @f
        mov     edx, [ebx+48]
        mov     edx, [edx+4]
        mov     [ebx+48], edx
        mov     edx, [ebx+52]
        mov     edx, [edx+4]
        mov     [ebx+52], edx
@@:
        mov     eax, [eax+4]
        dec     dword [ebx+56]
        ret
.line_next:
        cmp     eax, [ebx+52]
        jnz     @f
        mov     edx, [ebx+48]
        mov     edx, [edx]
        mov     [ebx+48], edx
        mov     edx, [ebx+52]
        mov     edx, [edx]
        mov     [ebx+52], edx
@@:
        mov     eax, [eax]
        inc     dword [ebx+56]
        ret

.dodraw:
        mov     eax, [ebx+dlgtemplate.x]
        mov     edx, [ebx+dlgtemplate.y]
        call    get_console_ptr
        mov     esi, [ebx+48]
.0:
        xor     edx, edx
        mov     ah, [menu_selected_color]
        cmp     esi, [ebx+40]
        jz      @f
        mov     ah, [menu_normal_color]
@@:
        push    edi
        mov     ecx, [ebx+dlgtemplate.width]
        mov     al, ' '
        stosw
        dec     ecx
        stosw
        dec     ecx
        dec     ecx
        push    esi
        add     esi, 8
@@:
        lodsb
        test    al, al
        jz      @f
        cmp     al, '&'
        jnz     .noamp
        test    dl, dl
        jnz     .noamp
        mov     dl, 1
        lodsb
        push    eax
        mov     ah, [menu_selected_highlight_color]
        push    ecx
        mov     ecx, [esp+8]
        cmp     ecx, [ebx+40]
        pop     ecx
        jz      .amp1
        mov     ah, [menu_highlight_color]
.amp1:
        stosw
        pop     eax
        jmp     .amp2
.noamp:
        stosw
.amp2:
        loop    @b
        mov     al, ' '
        cmp     byte [esi], 0
        jnz     .1
        lodsb
        jmp     .1
@@:
        mov     al, ' '
.1:
        stosw
        mov     al, ' '
        rep     stosw
        pop     esi edi
        add     edi, [cur_width]
        add     edi, [cur_width]
        cmp     esi, [ebx+52]
        jz      @f
        mov     esi, [esi]
        test    esi, esi
        jnz     .0
@@:
; ‹¨­¥©ª  ¯à®ªàã⪨
        mov     ecx, [ebx+dlgtemplate.height]
        cmp     ecx, [ebx+44]
        jz      .noscrollbar
        sub     ecx, 2
        jbe     .noscrollbar
        mov     eax, [ebx+56]
        mul     ecx
        div     dword [ebx+44]
        push    eax
        mov     eax, [ebx+dlgtemplate.x]
        add     eax, [ebx+dlgtemplate.width]
        mov     edx, [ebx+dlgtemplate.y]
        call    get_console_ptr
        pop     edx
        inc     edx
        mov     al, 0x1E
        mov     ah, [menu_scrollbar_color]
        mov     [edi], ax
        add     edi, [cur_width]
        add     edi, [cur_width]
.2:
        mov     al, 0xB2
        dec     edx
        jz      @f
        mov     al, 0xB0
@@:
        mov     [edi], ax
        add     edi, [cur_width]
        add     edi, [cur_width]
        loop    .2
        mov     al, 0x1F
        stosw
.noscrollbar:
        ret

get_ascii_char:
; query keyboard layout
        pushad
        mov     al, [ctrlstate]
        and     al, 3
        xor     ecx, ecx
        cmp     al, 1
        sbb     ecx, -2
        push    26
        pop     eax
        push    2
        pop     ebx
        mov     edx, layout
        int     0x40
        popad
; translate scancode to ASCII
        movzx   eax, byte [layout+eax]
        ret

virtual at 0
dlgitemtemplate:
; «¥¬¥­âë:
;       1 = áâ â¨ç¥áª¨© ⥪áâ
;       2 = ª­®¯ª 
;       3 = ¯®«¥ । ªâ¨à®¢ ­¨ï
;       4 = £®à¨§®­â «ì­ë© à §¤¥«¨â¥«ì
;       5 = ä« ¦®ª
;       6 = ᯨ᮪
.type           dd      ?
.x1             dd      ?
.y1             dd      ?
.x2             dd      ?
.y2             dd      ?
; „ ­­ë¥:
; ¤«ï ⥪áâ : const char* data - ASCIIZ-áâப 
; ¤«ï ª­®¯ª¨ ¨ ä« ¦ª : const char* data - § £®«®¢®ª
; ¤«ï । ªâ®à : struct {unsigned maxlength; unsigned pos; unsigned start;
;                        char data[maxlength+1];}* data;
; ¤«ï ᯨ᪠: struct {listitem* curitemptr; unsigned numitems;
;               listitem *head; unsigned curitem;}* data;
; head = 㪠§ â¥«ì ­  ¯¥à¢ë© ®â®¡à ¦ ¥¬ë© í«¥¬¥­â,
; curitemptr = 㪠§ â¥«ì ­  ¢ë¤¥«¥­­ë© í«¥¬¥­â, curitem = ¥£® ¨­¤¥ªá ¢ ᯨ᪥ (®â 0)
; (£¤¥ struct listitem {listitem* next; listitem* prev; char text[];};)
.data           dd      ?
.flags          dd      ?
; ”« £¨:
;       0 = ¢ëà ¢­¨¢ ­¨¥ ¢«¥¢®
;       1 = ¢ëà ¢­¨¢ ­¨¥ ¯® 業âàã
;       2 = ¢ëà ¢­¨¢ ­¨¥ ¢¯à ¢®
;       4 = í«¥¬¥­â ¨¬¥¥â 䮪ãá ¢¢®¤ 
;       8 = í«¥¬¥­â ¬®¦¥â ¨¬¥âì 䮪ãá ¢¢®¤ 
;       10h: ¤«ï ª­®¯ª¨ = ª­®¯ª  ¯® 㬮«ç ­¨î (Enter ­  ­¥-ª­®¯ª¥)
;            ¤«ï ¯®«ï ¢¢®¤  = ¤ ­­ë¥ ¡ë«¨ ¬®¤¨ä¨æ¨à®¢ ­ë
;            ¤«ï ä« ¦ª  = ä« ¦®ª ãáâ ­®¢«¥­
;       20h: ¤«ï ¯®«ï ¢¢®¤  = ­¥ ®â®¡à ¦ âì ¢¢®¤¨¬ë¥ ¤ ­­ë¥ (¯®ª §ë¢ âì '*')
.size = $
end virtual
;       struct DLGDATA
;       {
;               DLGTEMPLATE dialog;     /* window description */
;               void* DlgProc;          /* dialog procedure */
; /* int __stdcall DlgProc(DLGDATA* dlg, int msg, int param1, int param2); */
;               void* user_data;        /* arbitrary user data */
;               unsigned num_items;     /* number of items in the following array */
;               DLGITEMTEMPLATE items[]; /* array of dialog items */
;       }
; int __stdcall DialogBox(DLGDATA* dlg);
DialogBox:
        push    ManagerDlgProc
        push    dword [esp+8]
        call    GenericBox
        ret     4

; int __stdcall ShowDialogBox(DLGDATA* dlg);
ShowDialogBox:
        push    ManagerDlgProc
        push    dword [esp+8]
        call    ShowGenericBox
        ret     4

; void __stdcall DrawDialogBox(DLGDATA* dlg);
DrawDialogBox:
        push    ManagerDlgProc
        push    dword [esp+8]
        call    DrawGenericBox
        ret     4

ManagerDlgProc:
        mov     ebp, ebx
        mov     eax, [esp+8]
        dec     eax
        jz      .draw
        dec     eax
        jz      .key
        xor     eax, eax
        ret     16
.draw:
        call    .dodraw
        ret     16
.key:
; find item with focus
        add     ebx, dlgtemplate.size+12
        mov     ecx, [ebx-4]
        jecxz   .nobtns
@@:
        test    [ebx+dlgitemtemplate.flags], 4
        jnz     @f
        add     ebx, dlgitemtemplate.size
        loop    @b
@@:
.nobtns:
        mov     al, [esp+12]
        cmp     al, 1
        jz      .esc
        cmp     al, 0x1C
        jz      .enter
        cmp     al, 0xF
        jz      .tab
        cmp     al, 0x48
        jz      .up
        cmp     al, 0x50
        jz      .down
        jecxz   .nobtns2
        cmp     [ebx+dlgitemtemplate.type], 3
        jz      .key_edit
        cmp     [ebx+dlgitemtemplate.type], 5
        jnz     @f
        cmp     al, 0x39
        jnz     @f
        xor     [ebx+dlgitemtemplate.flags], 10h
        jmp     .ret_draw
@@:
.nobtns2:
        cmp     al, 0x4B
        jz      .left
        cmp     al, 0x4D
        jz      .right
.ret0:
        xor     eax, eax
        ret     16
.esc:
        or      eax, -1
        ret     16
.enter:
        cmp     [ebx+dlgitemtemplate.type], 2
        jnz     @f
.enter_found:
        mov     eax, ebx
        ret     16
@@:
        lea     ebx, [ebp+dlgtemplate.size+12]
        mov     ecx, [ebx-4]
.enter_find:
        cmp     [ebx+dlgitemtemplate.type], 2
        jnz     @f
        test    [ebx+dlgitemtemplate.flags], 0x10
        jnz     .enter_found
@@:
        add     ebx, dlgitemtemplate.size
        loop    .enter_find
        jmp     .enter_found
.tab:
        test    [ctrlstate], 3
        jnz     .shift_tab
.right:
.down:
        jecxz   .ret0
        and     byte [ebx+dlgitemtemplate.flags], not 4
        dec     ecx
        jz      .find_first_btn
@@:
        add     ebx, dlgitemtemplate.size
        test    [ebx+dlgitemtemplate.flags], 8
        jnz     .btn_found
        loop    @b
.find_first_btn:
        lea     ebx, [ebp+dlgtemplate.size+12]
@@:
        test    [ebx+dlgitemtemplate.flags], 8
        jnz     .btn_found
        add     ebx, dlgitemtemplate.size
        jmp     @b
.btn_found:
        or      byte [ebx+dlgitemtemplate.flags], 4
.ret_draw:
        mov     ebx, ebp
        call    .dodraw
        call    draw_image
        xor     eax, eax
        ret     16
.shift_tab:
.left:
.up:
        jecxz   .ret0
        and     byte [ebx+dlgitemtemplate.flags], not 4
        sub     ecx, [ebp+dlgtemplate.size+8]
        neg     ecx
        jz      .find_last_btn
@@:
        sub     ebx, dlgitemtemplate.size
        test    [ebx+dlgitemtemplate.flags], 8
        loopz   @b
        jnz     .btn_found
.find_last_btn:
        mov     ebx, [ebp+dlgtemplate.size+8]
        imul    ebx, dlgitemtemplate.size
        lea     ebx, [ebx+ebp+dlgtemplate.size+12]
@@:
        sub     ebx, dlgitemtemplate.size
        test    [ebx+dlgitemtemplate.flags], 8
        jz      @b
        jmp     .btn_found
.key_edit:
; ®¡à ¡®âª  ª« ¢¨è ¢ ¯®«¥ ¢¢®¤ 
        test    al, 0x80
        jnz     .ret0
        or      [ebx+dlgitemtemplate.flags], 0x10
        mov     edx, [ebx+dlgitemtemplate.data]
        cmp     al, 0x4B
        jz      .editor_left
        cmp     al, 0x4D
        jz      .editor_right
        cmp     al, 0x47
        jz      .editor_home
        cmp     al, 0x4F
        jz      .editor_end
        cmp     al, 0x0E
        jz      .editor_backspace
        cmp     al, 0x53
        jnz     .editor_char
.editor_del:
        mov     ecx, [edx+4]
        lea     edi, [ecx+edx+12]
        lea     esi, [edi+1]
        cmp     byte [edi], 0
        jz      .ret_test
        jmp     .copy_and_ret_test
.editor_left:
        mov     ecx, [edx+4]
        jecxz   @f
        dec     dword [edx+4]
@@:     jmp     .ret_test
.editor_right:
        mov     ecx, [edx+4]
        cmp     byte [edx+ecx+12], 0
        jz      @b
        inc     dword [edx+4]
        jmp     @b
.editor_home:
        and     dword [edx+4], 0
        jmp     @b
.editor_end:
        lea     edi, [edx+12]
        xor     eax, eax
        or      ecx, -1
        repnz   scasb
        not     ecx
        dec     ecx
        mov     [edx+4], ecx
.ret_test:
        mov     eax, [edx+4]
        cmp     [edx+8], eax
        jl      .ret_test.l1
        mov     [edx+8], eax
        jmp     .ret_test.l2
.ret_test.l1:
        add     eax, [ebx+dlgitemtemplate.x1]
        sub     eax, [ebx+dlgitemtemplate.x2]
        cmp     [edx+8], eax
        jge     .ret_test.l2
        mov     [edx+8], eax
.ret_test.l2:
        jmp     .ret_draw
.editor_backspace:
        mov     ecx, [edx+4]
        jecxz   .ret_test
        dec     dword [edx+4]
        lea     esi, [edx+ecx+12]
        lea     edi, [esi-1]
.copy_and_ret_test:
@@:
        lodsb
        stosb
        test    al, al
        jnz     @b
        jmp     .ret_test
.editor_char:
        test    [ctrlstate], 0x3C
        jnz     .ret_draw
        movzx   eax, al
        call    get_ascii_char
        push    eax
; insert entered symbol
        xor     eax, eax
        lea     edi, [edx+12]
        or      ecx, -1
        repnz   scasb
        not     ecx
        pop     eax
        cmp     ecx, [edx]
        ja      .ret_test       ; buffer capacity exceeded
        lea     edi, [edx+ecx+12-1]
        mov     esi, [edx+4]
        lea     esi, [edx+esi+12]
@@:
        mov     cl, [edi]
        mov     [edi+1], cl
        dec     edi
        cmp     edi, esi
        jae     @b
        mov     [esi], al
        inc     dword [edx+4]
@@:     jmp     .ret_test

.dodraw:
        or      [cursor_x], -1
        or      [cursor_y], -1
        add     ebx, dlgtemplate.size+8
        mov     ecx, [ebx]
        add     ebx, 4
        jecxz   .done_draw
.draw_loop:
        push    ecx
        mov     eax, [ebx+dlgitemtemplate.type]
        cmp     eax, draw_functions_num
        jae     .draw_loop_continue
        call    [draw_functions + eax*4]
.draw_loop_continue:
        pop     ecx
        add     ebx, dlgitemtemplate.size
        loop    .draw_loop
.done_draw:
        ret

iglobal
align 4
label draw_functions dword
        dd      ManagerDlgProc.done_draw
        dd      draw_static_text
        dd      draw_button
        dd      draw_editbox
        dd      draw_h_separator
        dd      draw_checkbox
        dd      draw_listbox
draw_functions_num = ($ - draw_functions) / 4
endg

draw_static_text:
; à¨á㥬 áâ â¨ç¥áª¨© ⥪áâ
        mov     ah, [dialog_main_color]
        test    byte [ebp+dlgtemplate.flags], 2
        jz      draw_text
        mov     ah, [warning_main_color]
draw_text:
; ®¯à¥¤¥«ï¥¬ ¤«¨­ã áâப¨
        mov     esi, [ebx+dlgitemtemplate.data]
draw_text_esi:
        test    esi, esi
        jz      .ret2
        push    eax
        push    -1
        pop     ecx
@@:
        inc     ecx
        cmp     byte [ecx+esi], 0
        jnz     @b
; ¢ ecx ¤«¨­  áâப¨
        xor     eax, eax
        mov     edx, [ebx+dlgitemtemplate.x2]
        sub     edx, [ebx+dlgitemtemplate.x1]
        inc     edx
        cmp     ecx, edx
        jae     .text_draw
        mov     al, byte [ebx+dlgitemtemplate.flags]
        and     al, 3
        jz      .text_align_left
        cmp     al, 1
        jz      .text_align_center
; ⥪áâ ¢ë஢­¥­ ¢¯à ¢®
        mov     eax, edx
        sub     eax, ecx
        jmp     .text_draw
.text_align_center:
        mov     eax, edx
        sub     eax, ecx
        shr     eax, 1
        jmp     .text_draw
.text_align_left:
        xor     eax, eax
.text_draw:
        push    ecx
        push    eax
        push    edx
        call    dlgitem_get_console_ptr
        pop     edx
        pop     ecx
        mov     ah, [esp+5]
        mov     al, ' '
        rep     stosw
        pop     ecx
        cmp     ecx, edx
        jbe     .text_copy
        cmp     [ebx+dlgitemtemplate.type], 3
        jnz     @f
        mov     ecx, edx
        jmp     .text_copy
@@:
        cmp     edx, 3
        jb      .ret
        mov     al, '.'
        stosw
        stosw
        stosw
        add     esi, ecx
        mov     ecx, edx
        sub     ecx, 3
        sub     esi, ecx
.text_copy:
        jecxz   .ret
; check for password editboxes
        cmp     [ebx+dlgitemtemplate.type], 3
        jnz     @f
        test    [ebx+dlgitemtemplate.flags], 20h
        jz      @f
        mov     al, '*'
        rep     stosw
        jmp     .ret
@@:
        lodsb
        stosw
        loop    @b
.ret:
        mov     eax, [ebp+dlgtemplate.x]
        mov     edx, [ebp+dlgtemplate.y]
        add     eax, [ebx+dlgitemtemplate.x2]
        inc     eax
        add     edx, [ebx+dlgitemtemplate.y1]
        mov     ecx, edi
        call    get_console_ptr
        xchg    ecx, edi
        sub     ecx, edi
        shr     ecx, 1
        pop     eax
        mov     al, ' '
        rep     stosw
.ret2:
        ret

draw_button:
        mov     ecx, dialog_colors
        test    byte [ebp+dlgtemplate.flags], 2
        jz      @f
        mov     ecx, warning_colors
@@:
        mov     ah, [dialog_normal_btn_color-dialog_colors+ecx]
        test    [ebx+dlgitemtemplate.flags], 4
        jz      @f
        mov     ah, [dialog_selected_btn_color-dialog_colors+ecx]
@@:
        jmp     draw_text

draw_editbox:
        mov     edx, [ebx+dlgitemtemplate.data]
        test    [ebx+dlgitemtemplate.flags], 4
        jz      @f
        mov     eax, [ebx+dlgitemtemplate.x1]
        add     eax, [edx+4]
        sub     eax, [edx+8]
        add     eax, [ebp+dlgtemplate.x]
        mov     [cursor_x], eax
        mov     eax, [ebx+dlgitemtemplate.y1]
        add     eax, [ebp+dlgtemplate.y]
        mov     [cursor_y], eax
@@:
        mov     ecx, dialog_colors
        test    byte [ebp+dlgtemplate.flags], 2
        jz      @f
        mov     ecx, warning_colors
@@:
        mov     ah, [dialog_edit_color-dialog_colors+ecx]
        test    [ebx+dlgitemtemplate.flags], 10h
        jnz     @f
        mov     ah, [dialog_unmodified_edit_color-dialog_colors+ecx]
@@:
        mov     esi, [ebx+dlgitemtemplate.data]
        add     esi, [edx+8]
        add     esi, 12
        jmp     draw_text_esi

dlgitem_get_console_ptr:
        mov     eax, [ebx+dlgitemtemplate.x1]
        mov     edx, [ebx+dlgitemtemplate.y1]
        mov     ecx, eax
        add     eax, [ebp+dlgtemplate.x]
        add     edx, [ebp+dlgtemplate.y]
        jmp     get_console_ptr

draw_h_separator:
; à¨á㥬 £®à¨§®­â «ì­ë© à §¤¥«¨â¥«ì
        call    dlgitem_get_console_ptr
.scan:
        mov     al, 0xC7
        test    ecx, ecx
        js      @f
        mov     al, 0xB6
        cmp     ecx, [ebp+dlgtemplate.width]
        jz      @f
        mov     al, 0xC4
@@:
        stosb
        jz      .done
        inc     ecx
        inc     edi
        cmp     ecx, [ebx+dlgitemtemplate.x2]
        jb      .scan
.done:
        ret

draw_checkbox:
; à¨á㥬 ä« ¦®ª
        call    dlgitem_get_console_ptr
        test    byte [ebx+dlgitemtemplate.flags], 4
        jz      @f
        inc     eax
        mov     [cursor_x], eax
        mov     [cursor_y], edx
@@:
        mov     ah, [dialog_main_color]
        test    byte [ebp+dlgtemplate.flags], 2
        jz      @f
        mov     ah, [warning_main_color]
@@:
        mov     al, '['
        stosw
        mov     al, 'x'
        test    byte [ebx+dlgitemtemplate.flags], 10h
        jnz     @f
        mov     al, ' '
@@:
        stosw
        mov     al, ']'
        stosw
        mov     al, ' '
        stosw
        mov     ecx, [ebx+dlgitemtemplate.x2]
        sub     ecx, [ebx+dlgitemtemplate.x1]
        jb      .ret
        sub     ecx, 3
        jbe     .ret
        mov     esi, [ebx+dlgitemtemplate.data]
@@:
        lodsb
        test    al, al
        jz      .ret
        stosw
        loop    @b
.ret:
        ret

draw_listbox:
; à¨á㥬 ᯨ᮪
        call    dlgitem_get_console_ptr
        mov     edx, [ebx+dlgitemtemplate.data]
        mov     esi, [edx+8]
        mov     eax, [ebx+dlgitemtemplate.y2]
        sub     eax, [ebx+dlgitemtemplate.y1]
        push    eax
        push    eax
.0:
        test    esi, esi
        jz      .listdone
        push    esi edi
        push    edx
        or      edx, -1
        mov     ecx, [ebx+dlgitemtemplate.x2]
        sub     ecx, [ebx+dlgitemtemplate.x1]
        inc     ecx
        xor     eax, eax
@@:
        inc     edx
        cmp     byte [esi+8+edx], al
        jnz     @b
@@:
        cmp     ecx, edx
        jae     .text_draw
        mov     al, byte [ebx+dlgitemtemplate.flags]
        and     al, 3
        jz      .text_align_left
        cmp     al, 1
        jz      .text_align_center
; ⥪áâ ¢ë஢­¥­ ¢¯à ¢®
        mov     eax, edx
        sub     eax, ecx
        jmp     .text_draw
.text_align_center:
        mov     eax, edx
        sub     eax, ecx
        shr     eax, 1
        jmp     .text_draw
.text_align_left:
;        xor     eax, eax
.text_draw:
        pop     edx
        cmp     esi, [edx]
        lea     esi, [esi+8+eax]
        mov     ah, [dialog_selected_list_color]
        jz      @f
        mov     ah, [dialog_list_color]
@@:
        jecxz   .next
@@:
        lodsb
        test    al, al
        jz      @f
        stosw
        loop    @b
@@:
        mov     al, ' '
        rep     stosw
.next:
        pop     edi esi
        add     edi, [cur_width]
        add     edi, [cur_width]
        mov     esi, [esi]
        dec     dword [esp]
        jns     .0
.listdone:
        pop     eax
; ‹¨­¥©ª  ¯à®ªàã⪨
        pop     ecx
        inc     ecx
        mov     esi, [edx+4]
        cmp     ecx, esi
        jae     .noscrollbar
        sub     ecx, 2
        jbe     .noscrollbar
        mov     eax, [edx+12]
        mul     ecx
        div     esi
        push    eax
        mov     eax, [ebx+dlgitemtemplate.x2]
        add     eax, [ebp+dlgtemplate.x]
        mov     edx, [ebx+dlgitemtemplate.y1]
        add     edx, [ebp+dlgtemplate.y]
        call    get_console_ptr
        pop     edx
        inc     edx
        mov     al, 0x1E
        mov     ah, [dialog_scroll_list_color]
        mov     [edi], ax
        add     edi, [cur_width]
        add     edi, [cur_width]
.2:
        mov     al, 0xB1
        dec     edx
        jz      @f
        mov     al, 0xB0
@@:
        mov     [edi], ax
        add     edi, [cur_width]
        add     edi, [cur_width]
        loop    .2
        mov     al, 0x1F
        stosw
.noscrollbar:
        ret

listbox_key:
        mov     edx, [ebx+dlgitemtemplate.data]
        cmp     al, 0x48
        jz      .prev
        cmp     al, 0x50
        jz      .next
        cmp     al, 0x47
        jz      .home
        cmp     al, 0x4F
        jz      .end
        cmp     al, 0x51
        jz      .pgdn
        cmp     al, 0x49
        jz      .pgup
        ret
.next:
        call    .calc_last_line
        mov     eax, [edx]
        cmp     dword [eax], 0
        jz      @f
        call    .line_next
@@:
        mov     [edx], eax
        ret
.pgdn:
        call    .calc_last_line
        mov     eax, [edx]
        mov     ecx, [ebx+dlgitemtemplate.y2]
        sub     ecx, [ebx+dlgitemtemplate.y1]
.pgdnl:
        cmp     dword [eax], 0
        jz      @f
        call    .line_next
        loop    .pgdnl
@@:
        mov     [edx], eax
        ret
.prev:
        mov     eax, [edx]
        cmp     dword [eax+4], 0
        jz      @f
        call    .line_prev
@@:
        mov     [edx], eax
        ret
.pgup:
        mov     eax, [edx]
        mov     ecx, [ebx+dlgitemtemplate.y2]
        sub     ecx, [ebx+dlgitemtemplate.y1]
;        inc     ecx
.pgupl:
        cmp     dword [eax+4], 0
        jz      @f
        call    .line_prev
        loop    .pgupl
@@:
        mov     [edx], eax
        ret
.home:
        mov     eax, [edx]
@@:
        cmp     dword [eax+4], 0
        jz      @f
        mov     eax, [eax+4]
        jmp     @b
@@:
        mov     [edx], eax
        mov     [edx+8], eax
        and     dword [edx+12], 0
        ret
.end:
        mov     eax, [edx]
@@:
        cmp     dword [eax], 0
        jz      @f
        mov     eax, [eax]
        jmp     @b
@@:
        mov     [edx], eax
        mov     ecx, [ebx+dlgitemtemplate.y2]
        sub     ecx, [ebx+dlgitemtemplate.y1]
        jz      .e1
.e2:
        mov     eax, [eax+4]
        loop    .e2
.e1:
        mov     [edx+8], eax
        mov     eax, [edx+4]
        dec     eax
        mov     [edx+12], eax
        ret

.line_prev:
        cmp     eax, [edx+8]
        mov     eax, [eax+4]
        jnz     @f
        mov     [edx+8], eax
@@:
        dec     dword [edx+12]
        ret
.calc_last_line:
        mov     esi, [edx+8]
        mov     ecx, [ebx+dlgitemtemplate.y2]
        sub     ecx, [ebx+dlgitemtemplate.y1]
        jz      .clldone
@@:
        mov     esi, [esi]
        test    esi, esi
        jz      @f
        loop    @b
.clldone:
        ret
.line_next:
        cmp     eax, esi
        mov     eax, [eax]
        jnz     @f
        push    eax
        mov     eax, [edx+8]
        mov     eax, [eax]
        mov     [edx+8], eax
        pop     eax
        mov     esi, eax
@@:
        inc     dword [edx+12]
        ret

; void __stdcall SayNoMem(void);
SayNoMem:
        or      dword [nomem_dlgdata+4], -1
        or      dword [nomem_dlgdata+8], -1
        push    nomem_dlgdata
        call    DialogBox
        ret

; int __stdcall ConfirmCancel(void);
; return value: 0 = the user is sure, nonzero = the user wants to continue
ConfirmCancel:
        push    YesOrNoBtn
        push    2
        push    ConfirmCancelMsg
        push    1
        push    aCancelled
        call    SayErrTitle
        test    eax, eax
        ret

; int __stdcall SayErr(int num_strings, const char* strings[],
;                      int num_buttons, const char* buttons[]);
SayErr:
        pop     eax
        push    aError
        push    eax
; int __stdcall SayErrTitle(const char* title,
;                       int num_strings, const char* strings[],
;                       int num_buttons, const char* buttons[]);
SayErrTitle:
        push    2
        jmp     @f

; int __stdcall Message(const char* title,
;                       int num_strings, const char* strings[],
;                       int num_buttons, const char* buttons[]);
Message:
        push    1
@@:
        pop     eax
; [esp+4] = title
; [esp+8] = num_strings
; [esp+12] = strings
; [esp+16] = num_buttons
; [esp+20] = buttons
        pushad
        mov     ecx, [esp+32+8]
        add     ecx, [esp+32+16]
        imul    ecx, dlgitemtemplate.size
        add     ecx, dlgtemplate.size+12
        call    xpgalloc
        test    eax, eax
        jnz     @f
        popad
        or      eax, -1
        ret     28
@@:
        mov     ebx, eax
        mov     edi, eax
        mov     eax, [esp+28]
        stosd                           ; dlgtemplate.flags
        or      eax, -1
        stosd                           ; dlgtemplate.x
        stosd                           ; dlgtemplate.y
; calculate width
        mov     ecx, [esp+32+8]
        mov     esi, [esp+32+12]
        xor     edx, edx
.calcwidth:
        lodsd
@@:
        inc     eax
        cmp     byte [eax-1], 0
        jnz     @b
        sub     eax, [esi-4]
        inc     eax
        cmp     edx, eax
        ja      @f
        mov     edx, eax
@@:
        loop    .calcwidth
        mov     ecx, [esp+32+16]
        mov     esi, [esp+32+20]
        xor     ebp, ebp
.calcwidth2:
        lodsd
@@:
        inc     eax
        cmp     byte [eax-1], 0
        jnz     @b
        sub     eax, [esi-4]
        inc     eax
        add     ebp, eax
        loop    .calcwidth2
        inc     ebp
        inc     ebp
        cmp     edx, ebp
        ja      @f
        mov     edx, ebp
@@:
        mov     eax, [cur_width]
        sub     eax, 8
        cmp     edx, eax
        jb      @f
        mov     edx, eax
@@:
        mov     eax, edx
        stosd                           ; dlgtemplate.width
        mov     eax, [esp+32+8]
        inc     eax
        stosd                           ; dlgtemplate.height
        mov     eax, 3
        stosd                           ; dlgtemplate.border_size_x
        mov     al, 2
        stosd                           ; dlgtemplate.border_size_y
        mov     eax, [esp+32+4]
        stosd                           ; dlgtemplate.title
        xor     eax, eax
        stosd                           ; (ignored)
        stosd                           ; (ignored)
        stosd                           ; DlgProc
        stosd                           ; userdata
        mov     eax, [esp+32+8]
        add     eax, [esp+32+16]
        stosd                           ; num_items
; fill strings
        xor     ecx, ecx
        mov     esi, [esp+32+12]
@@:
        mov     eax, 1
        stosd                           ; dlgitemtemplate.type
        dec     eax
        stosd                           ; dlgitemtemplate.x1
        mov     eax, ecx
        stosd                           ; dlgitemtemplate.y1
        lea     eax, [edx-1]
        stosd                           ; dlgitemtemplate.x2
        mov     eax, ecx
        stosd                           ; dlgitemtemplate.y2
        movsd                           ; dlgitemtemplate.data
        mov     eax, 1
        stosd                           ; dlgitemtemplate.flags
        inc     ecx
        cmp     ecx, [esp+32+8]
        jb      @b
; fill buttons
        mov     ecx, [esp+32+16]
        mov     esi, [esp+32+20]
        sub     edx, ebp
        jc      .big
        shr     edx, 1
        inc     edx
        jmp     .fillbtns
.big:
        xor     edx, edx
.fillbtns:
        mov     eax, 2
        stosd                           ; dlgitemtemplate.type
        mov     eax, edx
        stosd                           ; dlgitemtemplate.x1
        mov     eax, [ebx+dlgtemplate.height]
        dec     eax
        stosd                           ; dlgitemtemplate.y1
        push    eax
        lodsd
        sub     eax, edx
@@:
        inc     edx
        cmp     byte [eax+edx-1], 0
        jnz     @b
        mov     eax, edx
        inc     edx
        stosd                           ; dlgitemtemplate.x2
        pop     eax
        stosd                           ; dlgitemtemplate.y2
        mov     eax, [esi-4]
        stosd                           ; dlgitemtemplate.data
        mov     eax, 9
        cmp     ecx, [esp+32+16]
        jnz     @f
        or      al, 4
@@:
        stosd                           ; dlgitemtemplate.flags
        loop    .fillbtns
        push    ebx
        call    DialogBox
        cmp     eax, -1
        jz      @f
        sub     eax, ebx
        sub     eax, dlgtemplate.size+12
        xor     edx, edx
        mov     ecx, dlgitemtemplate.size
        div     ecx
        sub     eax, [esp+32+8]
@@:
        mov     [esp+28], eax
        mov     ecx, ebx
        call    pgfree
        popad
        ret     20