; макрос для системной библиотеки box_lib.obj
; элемент TreeList для Kolibri OS
; файл последний раз изменялся 8.12.2009 IgorA
; на код применена GPL2 лицензия


sizeof.TreeList equ 20
;struct TreeList
;  type dw ? ;+ 0 тип элемента, или индекс иконки для узла
;  lev db ?  ;+ 2 уровень элемента
;  clo db ?  ;+ 3 флаг закрытия, или открытия (имеет смысл для родительского узла)
;  perv dd ? ;+ 4 индекс предыдущего элемента
;  next dd ? ;+ 8 индекс последующего элемента
;  tc dd ?   ;+12 врем. создания
;  td dd ?   ;+16 врем. удаления
;ends

tl_info_size  equ  word[edi +4] ;размер данных выделяемых для каждого узла (пользовательськие данные + текст для подписи)
tl_style      equ dword[edi+10] ;стили элемента
tl_data_nodes equ dword[edi+14] ;указатель на структуры узлов
tl_img_cx     equ  word[edi+22] ;ширина иконок
tl_img_cy     equ  word[edi+24] ;высота иконок
tl_data_img_sys equ dword[edi+26] ;указатель на системные изображения (стрелки, плюсики)
tl_ch_tim     equ dword[edi+30] ;количество изменений в файле
tl_tim_undo   equ dword[edi+38] ;количество отмененных действий
tl_cur_pos    equ dword[edi+42] ;позиция курсора
tl_col_bkg    equ dword[edi+46] ;цвет фона
tl_col_zag    equ dword[edi+50] ;цвет заголовка
tl_col_txt    equ dword[edi+54] ;цвет текста
tl_box_left   equ dword[edi+58]
tl_box_top    equ dword[edi+62]
tl_box_width  equ dword[edi+66]
tl_box_height equ dword[edi+70]
tl_capt_cy    equ  word[edi+74] ;высота подписи
tl_info_capt_offs equ word[edi+76] ;сдвиг для начала текста (подписи узла)
tl_info_capt_len equ word[edi+78] ;длинна текста подписи узла (если = 0 то до конца структуры)
tl_el_focus   equ dword[edi+80] ;указатель на структуру элемента в фокусе
tl_p_scrol    equ dword[edi+84] ;указатель на структуру скроллинга
tl_on_press   equ dword[edi+96] ;указатель на функцию, которая вызывается при нажатии Enter

;константы стиля
tl_key_no_edit   equ   1b ;элемент нельзя редактировать на клавиатуре (изменять уровни, удалять)
tl_draw_par_line equ  10b ;рисовать линии к родительскому узлу
tl_list_box_mode equ 100b ;стиль не отображает уровни (как в ListBox все одного уровня)

;константы для функций
tl_err_save_memory_size equ  10b ;не хватает памяти для сохранения элемента
tl_err_load_caption     equ   1b ;в памяти нет заголовка 'tree'
tl_err_load_info_size   equ 100b ;не совпадает размер информационной структуры при открытии
tl_load_mode_add        equ 0x20000 ;опция считывания в режиме добавления информации
tl_save_load_heder_size equ 26 ;размер заголовка для записи/чтения элементов

;data_info	 dd ? ;+ 0 указатель на основные даные
;info_max_count dd ? ;+ 6 максимальное колличество структур
;data_img	 dd ? ;+18 указатель на изображения
;ls_tim		dd ? ;+34 время последнего сохранения
;on_activate dd ? ;+92 указатель на функцию при активировании узла

struc tree_list info_size,info_max_count,style, img_cx,img_cy,\
    col_bkg,col_zag,col_txt, box_l,box_t,box_w,box_h, capt_cy,info_capt_offs,\
    info_capt_len,el_focus, p_scrol,on_press {
  .data_info	dd 0
  .info_size	dw info_size
  .info_max_count dd info_max_count
  .style	    dd style
  .data_nodes	dd 0
  .data_img	 dd 0
  .img_cx	   dw img_cx
  .img_cy	   dw img_cy
  .data_img_sys	 dd 0
  .ch_tim		  dd 0
  .ls_tim		  dd 0
  .tim_undo	 dd 0
  .cur_pos	  dd 0
  .col_bkg	  dd col_bkg
  .col_zag	  dd col_zag
  .col_txt	  dd col_txt
  .box_left   dd box_l
  .box_top    dd box_t
  .box_width  dd box_w
  .box_height dd box_h
  .capt_cy	   dw capt_cy
  .info_capt_offs dw info_capt_offs
  .info_capt_len dw info_capt_len
  .el_focus dd el_focus
  .p_scrol  dd p_scrol
  rb 4
  .on_activate dd 0
  .on_press dd on_press
}

;-----------------------------------------------------------------------------
;функция для выделения памяти
;input:
; ecx = size data
;otput:
; eax = pointer to memory
align 4
mem_Alloc:
  push ebx
  mov eax,68
  mov ebx,12
  int 0x40
  pop ebx
  ret
;-----------------------------------------------------------------------------
;функция для освобождения памяти
;input:
; ecx = pointer to memory
align 4
mem_Free:
  push eax ebx
  cmp ecx,0
  jz @f
    mov eax,68
    mov ebx,13
    int 0x40
  @@:
  pop ebx eax
  ret

macro use_tree_list
{
align 4
tl_data_init: ;выделние памяти для структур списка и основной информации (конструктор)
  push ebp
  mov ebp,esp
  push eax ecx edi
    mov edi,dword[ebp+8]

    xor ecx,ecx
    mov cx,tl_info_size
    imul ecx,dword[edi+6]
    call mem_Alloc
    mov dword[edi],eax ;копируем указатель на полученую память в структуру
    mov dword[edi+18],0 ;обнуляем указатель 'data_img'
    mov tl_data_img_sys,0 ;обнуляем указатель 'data_img_sys'

    mov ecx,sizeof.TreeList
    imul ecx,dword[edi+6]
    call mem_Alloc
    mov tl_data_nodes,eax ;копируем указатель на полученую память в структуру

    push dword edi
    call tl_info_clear

    ;настройки дочернего скроллинга
    cmp tl_p_scrol,0
    je @f
      mov eax,tl_p_scrol
      ;*** цветовые настройки ***
      mov ecx,tl_col_bkg
      mov dword[eax+28],ecx ;+28 .bckg_col
      mov ecx,tl_col_zag
      mov dword[eax+32],ecx ;+32 .frnt_col
      mov ecx,tl_col_txt
      mov dword[eax+36],ecx ;+32 .line_col
      ;*** настройки размеров ***
      mov ecx,tl_box_left
      add ecx,tl_box_width
      mov word[eax+2],cx
      mov ecx,tl_box_height
      mov word[eax+4],cx
      mov ecx,tl_box_top
      mov word[eax+6],cx
    @@:
  pop edi ecx eax
  pop ebp
  ret 4

align 4
tl_data_clear: ;очистка памяти элемента (деструктор)
  push ebp
  mov ebp,esp
    push ecx edi
    mov edi,dword[ebp+8]
    cmp dword[edi+18],0 ;data_img
    je @f
      mov ecx,dword[edi+18]
      call mem_Free ;чистка системных иконок
    @@:
    cmp tl_data_img_sys,0
    je @f
      mov ecx,tl_data_img_sys
      call mem_Free ;чистка системных иконок
    @@:
    mov ecx,dword[edi]
    call mem_Free

    mov ecx,tl_data_nodes
    call mem_Free
    pop edi ecx
  pop ebp
  ret 4

align 4
tl_info_clear: ;очистка списка (информации)
  push ebp
  mov ebp,esp
    push eax ecx edi
    mov edi,dword[ebp+8]
    mov tl_ch_tim,0
    mov dword[edi+34],0 ;ls_tim
    mov tl_tim_undo,0
    mov tl_cur_pos,0
    ;xor ecx,ecx
    mov ecx,sizeof.TreeList
    imul ecx,dword[edi+6]
    mov eax,tl_data_nodes
    @@:
      mov byte[eax],0 ;чистим узлы 0-ми
      inc eax
      loop @b
    mov eax,tl_data_nodes ;указатель на 0-й узел
    mov dword[eax+8],1 ;указатель next в 0-м узле приравниваем к 1

    cmp tl_p_scrol,0 ;обработка скроллинга
    je @f
      mov eax,tl_p_scrol
      mov dword[eax+24],0 ;+24 .position
      call tb_scrol_resize
    @@:
    pop edi ecx eax
  pop ebp
  ret 4


align 4
tl_key: ;реакция на клавиатуру
  push ebp
  mov ebp,esp
    push ebx ecx edi
    mov edi,dword[ebp+8]

    mov ebx,tl_el_focus
    cmp dword[ebx],edi
    jne .no_focus ;элемент не в фокусе

    push eax
    mov eax,66
    mov ebx,2
    int 0x40  ;получить режим ввода с клавиатуры

    lea ecx,[tl_key_scan]
    cmp eax,1 ;1 = сканкоды
    je @f
      lea ecx,[tl_key_ascii]
    @@:
    pop eax

    xor bx,bx
    cmp ah,byte[ecx] ;Enter
    jne @f
      cmp tl_on_press,0
      je @f
        call tl_on_press
    @@:
    cmp ah,byte[ecx+1] ;Space
    jne @f
      push dword edi
      call tl_node_close_open
    @@:
    cmp ah,byte[ecx+2] ;Up
    jne @f
      push dword edi
      call tl_cur_perv
    @@:
    cmp ah,byte[ecx+3] ;Down
    jne @f
      push dword edi
      call tl_cur_next
    @@:
    cmp ah,byte[ecx+7] ;Page Up
    jne @f
      push dword edi
      call tl_cur_page_up
    @@:
    cmp ah,byte[ecx+8] ;Page Down
    jne @f
      push dword edi
      call tl_cur_page_down
    @@:

    bt tl_style,0 ;tl_key_no_edit
    jc .no_edit
      cmp ah,byte[ecx+4] ;Left
      jne @f
	push dword edi
	call tl_node_lev_dec
	mov bx,1
      @@:
      cmp ah,byte[ecx+5] ;Right
      jne @f
	push dword edi
	call tl_node_lev_inc
	mov bx,1
      @@:
      cmp ah,byte[ecx+6] ;Delete
      jne @f
	push dword edi
	call tl_node_delete
	mov bx,1
      @@:
    .no_edit:

    cmp bx,1
    jne .no_focus
      push dword edi
      call tl_draw
    .no_focus:

    pop edi ecx ebx
  pop ebp
  ret 4

align 4
tl_mouse: ;реакция на мышь
  push ebp
  mov ebp,esp
    push eax ebx ecx edx edi esi
    mov edi,dword[ebp+8]

    mov eax,37
    mov ebx,2
    int 0x40

    bt eax,0 ;left mouse button press
    jae .no_draw

    mov eax,37
    mov ebx,1
    int 0x40

    mov ebx,tl_box_left
    shl ebx,16
    cmp eax,ebx ;левая граница окна
    jl .no_in_wnd

    mov ebx,tl_box_left
    add ebx,tl_box_width
    shl ebx,16
    cmp eax,ebx ;правая граница окна
    jg .test_scroll ;.no_in_wnd

    mov ebx,tl_box_top
    add ebx,tl_box_height
    cmp ax,bx ;нижняя граница окна
    jg .no_in_wnd

    sub ebx,tl_box_height
    add bx,tl_capt_cy
    cmp ax,bx ;верхняя граница окна + высота подписи
    jl .no_in_wnd

    mov esi,tl_el_focus
    mov dword[esi],edi ;set focus

    ; if '+' or '-' press
    mov esi,eax
    shr esi,16
    sub esi,tl_box_left ;esi = mouse x coord in element window

    and eax,0xffff
    sub ax,bx
    xor edx,edx
    xor ecx,ecx
    mov cx,tl_img_cy
    div ecx
    cmp tl_p_scrol,0 ;учитываем скроллинг
    je @f
      mov edx,tl_p_scrol
      add eax,dword[edx+24] ;добавляем скроллинг на верху
    @@:

    mov ecx,eax
    call tl_get_node_count ;eax = node count
    cmp eax,ecx
    jl @f
      mov eax,ecx ;если курсор не вышел за пределы узлов, восстанавливаем старое значение eax
    @@:

    cmp eax,tl_cur_pos ;если новое значение курсора совпало с предыдущим
    je @f ;то не стираем курсор
    push esi
      mov esi,tl_box_top
      add esi,tl_box_height ;esi = coord bottom border
      call tl_draw_null_cursor ;стираем курсор
    pop esi
    @@:

    mov tl_cur_pos,eax

    ; if '+' or '-' press
    call tl_get_cur_node_index ;eax = node index
    cmp eax,2
    jl .no_open_close ;курсор стоит на пустом месте, без узлов
    imul eax,sizeof.TreeList
    add eax,tl_data_nodes
    xor bx,bx
    mov bl,byte[eax+2] ;+2 lev сохраняем уровень текущего узла
    inc bx ;+ поле для курсора

    cmp si,tl_img_cx
    jl .no_open_close ;мышей попали на левое поле для курсора, где точно нет '+' и '-'
      mov eax,esi
      xor edx,edx
      xor ecx,ecx
      mov cx,tl_img_cx
      div ecx

      cmp ax,bx
      jne .no_open_close

      push dword edi
      call tl_node_close_open
    .no_open_close:

      mov esi,tl_box_top
      add esi,tl_box_height ;esi = coord bottom border
      call tl_draw_cursor ;перерисовка курсора
      call tl_draw_caption_cur_pos
      jmp .no_draw
;--- mouse event for children scrollbar ----------------------------------------
.test_scroll:
  mov edx,tl_p_scrol
  cmp edx,0
  je .no_in_wnd ;пользователь не создал дочернего скроллинга
    shr ebx,16
    add bx,word[edx] ;+0 .size_x
    shl ebx,16
    cmp eax,ebx ;правая граница окна
    jg .no_in_wnd

    mov eax,dword[edx+16] ;+16 .max_area
    cmp eax,dword[edx+20] ;+20 .cur_area
    jbe .no_in_wnd ;все узлы попадают в окно скроллинга
      push dword edx
      call scroll_bar_vertical.mouse ;scrollbar_ver_mouse

      cmp dword[edx+40],0 ;+40 .redraw
      je  @f
        mov dword[edx+40],0 ;+40 .redraw
        push dword edi
        call tl_draw ;произошли изменения скроллинга
      @@:
      cmp dword[edx+46],0 ;+46 .delta2
      jne .no_draw ;попали на скроллинг - не снимаем фокус с TreeList
;-------------------------------------------------------------------------------
    .no_in_wnd: ;не попали в окно - потеря фокуса (при условии что фокус был на данном эелементе)
      mov ebx,tl_el_focus
      cmp dword[ebx],edi
      jne .no_draw ;элемент не в фокусе
        mov dword[ebx],0 ;reset focus
        mov esi,tl_box_top
        add esi,tl_box_height ;esi = coord bottom border
        call tl_draw_cursor ;рисуем курсор с потеряным фокусом
    .no_draw:

    pop esi edi edx ecx ebx eax
  pop ebp
  ret 4

align 4
tl_info_undo: ;отмена действия
  push ebp
  mov ebp,esp
  push eax edi
    mov edi,dword[ebp+8]
    mov eax,tl_tim_undo
    cmp tl_ch_tim,eax
    jbe @f
      inc tl_tim_undo
      call tb_scrol_resize ;обработка скроллинга
    @@:
  pop edi eax
  pop ebp
  ret 4

align 4
tl_info_redo: ;повтор действия
  push ebp
  mov ebp,esp
  push edi
    mov edi,dword[ebp+8]
    cmp tl_tim_undo,1
    jl @f
      dec tl_tim_undo
      call tb_scrol_resize ;обработка скроллинга
    @@:
  pop edi
  pop ebp
  ret 4

align 4
tl_info_set_undo: ;удаление отмененных действий
;  push ebp
;  mov ebp,esp
;  push edi
;    mov edi,dword[ebp+8]

;  mov [dragk],0 ;заканчиваем выделение от клавиатуры
  cmp tl_tim_undo,1
  jl .no_work

  push eax ebx ecx edx
  mov edx,tl_data_nodes
  mov ecx,edx
  add ecx,sizeof.TreeList
  call tl_move_next ;long i=node[0].next;
  mov eax,tl_tim_undo
  sub tl_ch_tim,eax ;ch_tim-=tim_undo;
  mov eax,tl_ch_tim
  cmp [edi+34],eax ;if(ls_tim>ch_tim)
  jle @f
    mov dword[edi+34],0 ;ls_tim=0
  @@:
    cmp edx,ecx
    jle @f

    ;if(node[i].tc>ch_tim){ // если создание символа было отменено
    cmp dword[edx+12],eax
    jle .no_u1
      mov dword[edx+12],0
      mov dword[edx+16],0

      mov ebx, dword[edx+4]
      imul ebx,sizeof.TreeList
      add ebx, tl_data_nodes ;.next
      push dword[edx+8] ;node[node[i].perv].next=node[i].next;
      pop dword[ebx+8]

      mov ebx, dword[edx+8]
      imul ebx,sizeof.TreeList
      add ebx, tl_data_nodes ;.perv
      push dword[edx+4] ;node[node[i].next].perv=node[i].perv;
      pop dword[ebx+4]

    .no_u1:

    ;else if(node[i].td>ch_tim) node[i].td=0; // если удаление символа было отменено
    cmp dword[edx+16],eax
    jle .no_u2
      mov dword[edx+16],0
    .no_u2:

    call tl_move_next
    jmp @b
  @@:
  mov tl_tim_undo,0
;  mov eax,[edi+?] ;co_tim
;  cmp tl_ch_tim,eax ;ch_tim
;  jge @f
;    mov [edi+?],0 ;co_tim
;  @@:
  pop edx ecx ebx eax
  .no_work:

;  pop edi
;  pop ebp
;  ret 4
  ret

align 4
tl_draw: ;вывод списка на экран
  push ebp
  mov ebp,esp
    push eax ebx ecx edx edi esi
    ;draw dir_list main rect
    mov edi,dword[ebp+8]
    mov ebx,tl_box_left
    shl ebx,16
    add ebx,tl_box_width
    mov ecx,tl_box_top
    shl ecx,16
    mov cx,tl_capt_cy
    mov edx,tl_col_zag
    mov eax,13
    int 0x40 ;draw window caption

    add ecx,tl_box_top
    shl ecx,16
    add ecx,tl_box_height
    sub cx,tl_capt_cy
    mov edx,tl_col_bkg
    int 0x40 ;draw window client rect

    cmp tl_capt_cy,9 ;9 - minimum caption height
    jl @f
    mov ebx,edi ;calculate cursor position
    mov eax,tl_cur_pos
    inc eax
    lea edi,[txt_capt_cur]
    add edi,7
    call tl_convert_to_str

    mov edi,ebx
    mov eax,tl_tim_undo
    lea edi,[txt_capt_otm]
    add edi,7
    call tl_convert_to_str
    mov edi,ebx ;restore edi

    mov eax,4 ;draw text captions
    mov ebx,tl_box_left
    shl ebx,16
    add ebx,5*65536+3
    add ebx,tl_box_top
    mov ecx,tl_col_txt
    or	ecx,0x80000000
    lea edx,[txt_capt_cur]
    int 0x40

    mov ebx,tl_box_left
    shl ebx,16
    add ebx,100*65536+3
    add ebx,tl_box_top
    lea edx,[txt_capt_otm]
    int 0x40
    @@:

    ;cycle to nodes
    xor eax,eax
    mov edx,tl_data_nodes
    mov ecx,edx
    add ecx,sizeof.TreeList

    ;*** пропуск узлов, которые промотаны скроллингом ***
    cmp tl_p_scrol,0 ;если есть указатель на скроллинг
    je .end_c1
    mov esi,tl_p_scrol
    cmp dword[esi+24],0 ;если скроллинг на верху, выходим
    je .end_c1
      @@:
	call tl_iterat_next
	cmp edx,ecx
	jle .end_draw
	inc eax
	cmp eax,dword[esi+24]
	jge .end_c1
	jmp @b
    .end_c1:

    xor eax,eax
    mov esi,tl_box_top
    add esi,tl_box_height ;esi = coord bottom border
    @@:
      call tl_iterat_next
      cmp edx,ecx
      jle @f
      call tl_draw_node
      inc eax
      jmp @b
    @@:

    call tl_draw_cursor
    .end_draw:
    pop esi edi edx ecx ebx eax
  pop ebp
  ret 4

;input:
; ecx = pointer to 1 node struct
; edx = pointer to some node struct
; edi = pointer to 'TreeList' struct
;output:
; edx = pointer to next node struct
align 4
tl_iterat_next:
  push bx
  mov bl,0x7f
  cmp byte[edx+3],1
  jne @f
    mov bl,byte[edx+2]
  @@:

  cmp tl_tim_undo,0
  je .else

  push eax
  .beg0:
    call tl_move_next
    cmp edx,ecx
    jle @f
    call tl_node_not_vis ;пропуск удаленных и отмененных
    cmp al,1
    je .beg0
    cmp bl,byte[edx+2] ;пропуск закрытых
    jl .beg0
  @@:
  pop eax
  pop bx
  ret

  .else:
    call tl_move_next
    cmp edx,ecx
    jle .endif
    cmp dword[edx+16],0 ;td = 'time delete' -> пропуск удаленных
    jne .else
    cmp bl,byte[edx+2] ;пропуск закрытых
    jl .else
  .endif:
  pop bx
  ret

;input:
; ecx = pointer to 1 node struct
; edx = pointer to some node struct
; edi = pointer to 'TreeList' struct
align 4
tl_iterat_next_all:
  cmp tl_tim_undo,0
  je .else

  push eax
  @@:
    call tl_move_next
    cmp edx,ecx
    jle @f
    call tl_node_not_vis
    cmp al,1
    je @b
  @@:
  pop eax
  ret
  .else:
    call tl_move_next
    cmp edx,ecx
    jle .endif
    cmp dword[edx+16],0 ;td -> time delete
    jne .else
  .endif:
  ret

;input:
; ecx = pointer to 1 node struct
; edx = pointer to some node struct
; edi = pointer to 'TreeList' struct
align 4
tl_iterat_perv:
  push eax

;  mov bl,byte[edx+2]

  cmp tl_tim_undo,0
  je .beg1

  push eax
  .beg0:
    call tl_move_perv
    cmp edx,ecx
    jle @f
    call tl_node_not_vis ;пропуск удаленных и отмененных
    cmp al,1
    je .beg0

  .beg1:
    call tl_move_perv
    cmp edx,ecx
    jle @f
    cmp dword[edx+16],0 ;td = 'time delete' -> пропуск удаленных
    jne .beg1

  @@:
    call tl_move_max_clo_par
  pop eax
  ret


;input:
; edx = pointer to some node struct
; edi = pointer to 'TreeList' struct
;output:
; edx = pointer closed parent node with maximum level
align 4
tl_move_max_clo_par: ;находит родительский закрытый узел максимального уровня
  push eax ebx
  mov eax,edx
  xor ebx,ebx
  .beg:
    call tl_move_par
    cmp byte[edx+3],1 ;родительский узел закрыт ?
    jne @f
      mov eax,edx
    @@:
    cmp ebx,edx
    je .end_f
      mov ebx,edx
    jmp .beg
  .end_f:
  mov edx,eax
  pop ebx eax
  ret

;input:
; edx = pointer to some node struct
; edi = pointer to 'TreeList' struct
;output:
; edx = pointer to next node struct
align 4
tl_move_next:
  mov edx,dword[edx+8]
  imul edx,sizeof.TreeList
  add edx,tl_data_nodes
  ret

;input:
; edx = pointer to some node struct
; edi = pointer to 'TreeList' struct
;output:
; edx = pointer to perv node struct
align 4
tl_move_perv:
  mov edx,dword[edx+4]
  imul edx,sizeof.TreeList
  add edx,tl_data_nodes
  ret

;input:
; ecx =
; edx = pointer to some node struct
; edi = pointer to 'TreeList' struct
;output:
; edx = pointer to parent node struct
align 4
tl_move_par: ;передвигаемся на родительский узел, если такого нет, то оставляем старое значение указателя
 cmp byte[edx+2],0
 je .end_f ;узел 0-го уровня не может быть дочерним
 push eax ebx esi
 mov esi,edx ;copy node pointer (edx)
 mov bl,byte[edx+2]
 @@:
   call tl_move_perv
   cmp edx,ecx
   jle @f ;все выше стоящие узлы не родительские
   call tl_node_not_vis ;пропуск удаленных и отмененных
   cmp al,1
   je @b
   cmp byte[edx+2],bl
   jl .end_0 ;удачно нашли родительский узел
   jmp @b
 @@:
   mov esi,ebx ;restore node pointer
 .end_0:
 pop esi ebx eax
 .end_f:
 ret

;input:
; edx = pointer to symbol struct
; edi = pointer to 'TreeList' struct
;output:
; al = 1 if sumbol not visible
; (node[i].td+tim_Undo<=ch_tim && node[i].td) || (node[i].tc>ch_tim-tim_Undo)
align 4
tl_node_not_vis:
  cmp dword[edx+16],0
  je @f
  mov eax,dword[edx+16] ;eax=node[i].td
  add eax,tl_tim_undo
  cmp eax,tl_ch_tim
  jg @f
    mov al,1
    ret
  @@:

  mov eax,tl_ch_tim
  sub eax,tl_tim_undo
  cmp dword[edx+12],eax ;tc -> time create
  jle @f
    mov al,1
    ret
  @@:
  xor al,al
  ret


;input:
; edi = pointer to TreeInfo struct
; esi = coord bottom border
align 4
tl_draw_cursor: ;рисуем курсор на экране
  push eax ebx ecx edx esi
    call tl_get_display_cur_pos ;eax = cursor pos in screen
    cmp eax,0
    jl .end_f ;курсор находится выше окна, в области прокрученной скроллингом

    cmp tl_data_img_sys,0 ;смотрим есть ли указатель на картинку системных иконок
    jne @f
      mov ebx,tl_box_left
      shl ebx,16
      mov bx,tl_img_cx
      xor ecx,ecx
      mov cx,tl_img_cy
      imul ecx,eax
      add ecx,tl_box_top
      add cx,tl_capt_cy

      ;crop image if on the border
      cmp esi,ecx ;если курсор внизу и его вообще не видно
      jl .end_f

      sub esi,ecx
      shl ecx,16
      mov cx,tl_img_cy
      cmp si,tl_img_cy
      jge .crop0
        mov cx,si ;если курсор виден частично (попал на нижнюю границу)
      .crop0:

      mov edx,tl_col_txt
      mov eax,13
      int 0x40 ;рисуем простой прямоугольник, т.к. нет системных иконок
      jmp .end_f
    @@:
      mov ebx,tl_data_img_sys
      imul ax,tl_img_cy
      mov edx,tl_box_left
      shl edx,16
      mov dx,ax
      add edx,tl_box_top
      add dx,tl_capt_cy

      mov ecx,tl_el_focus ;проверяем в фокусе элемент или нет
      cmp dword[ecx],edi
      je .focus
        xor eax,eax
        xor ecx,ecx
        mov cx,tl_img_cx
        mov ax,tl_img_cy
        imul eax,ecx
        imul eax,4*3 ;4=icon index 3=rgb
        add ebx,eax
      .focus:

      mov cx,tl_img_cx
      shl ecx,16
      mov cx,tl_img_cy

      ;crop image if on the border
      cmp si,dx ;если курсор внизу и его вообще не видно
      jl .end_f

      sub si,dx
      cmp si,tl_img_cy
      jge .crop1
	mov cx,si ;если курсор виден частично (попал на нижнюю границу)
      .crop1:

      mov eax,7
      int 0x40 ;рисуем иконку курсора
    .end_f:
  pop esi edx ecx ebx eax
  ret

;input:
; edi = pointer to TreeInfo struct
; esi = coord bottom border
align 4
tl_draw_null_cursor: ;стираем курсор на экране
  push eax ebx ecx edx esi
    call tl_get_display_cur_pos ;eax = cursor pos in screen
    cmp eax,0
    jl .end_f ;курсор находится выше окна, в области прокрученной скроллингом

    mov ebx,tl_box_left
    shl ebx,16
    mov bx,tl_img_cx
    xor ecx,ecx
    mov cx,tl_img_cy
    imul ecx,eax
    add ecx,tl_box_top
    add cx,tl_capt_cy

    ;crop image if on the border
    cmp esi,ecx ;если курсор внизу и его вообще не видно
    jl .end_f

    sub esi,ecx
    shl ecx,16
    mov cx,tl_img_cy
    cmp si,tl_img_cy
    jge @f
      mov cx,si ;если курсор виден частично (попал на нижнюю границу)
    @@:

    mov edx,tl_col_bkg
    mov eax,13
    int 0x40 ;рисуем простой прямоугольник с фоновым цветом

    .end_f:
  pop esi edx ecx ebx eax
  ret

;input:
; edi = pointer to TreeInfo struct
;output:
; eax = index
align 4
tl_get_display_cur_pos: ;берет позицию курсора, относительно экрана
   mov eax,tl_cur_pos
   cmp tl_p_scrol,0
   je @f
     push ebx
       mov ebx,tl_p_scrol
       mov ebx,dword[ebx+24]
       sub eax,ebx ;отнимаем позицию скроллинга
     pop ebx
  @@:
  ret

;input:
; eax = node position
; edx = pointer to some node struct
; edi = pointer to TreeInfo struct
; esi = coord of bottom border
align 4
tl_draw_node:
  push eax ebx ecx edx esi

    mov ebx,1 ;1 - место под курсор и под знак +,-
    bt tl_style,2 ;tl_list_box_mode
    jc @f
      inc ebx ;+1 - место под знак +,-
    @@:
    add bl,byte[edx+2];get level
    imul bx,tl_img_cx
    add ebx,tl_box_left

    shl ebx,16
    mov bx,tl_img_cx
    xor ecx,ecx
    mov cx,tl_img_cy
    imul ecx,eax
    add ecx,tl_box_top
    add cx,tl_capt_cy

    ;crop image if on the border
    cmp esi,ecx ;если узел внизу и его вообще не видно
    jl .end_draw

    sub esi,ecx
    shl ecx,16
    mov cx,tl_img_cy
    cmp si,tl_img_cy
    jge @f
      mov cx,si ;если узел виден частично (попал на нижнюю границу)
      jmp .crop ;пропускаем рисование надписи, которая скорее всего тоже вылезет за нижнюю границу
    @@:
      call tl_draw_node_caption
    .crop:
    mov esi,ecx ;save ecx

    cmp dword[edi+18],0 ;data_img
    jne .draw_img_n
    push edx
      mov edx,tl_col_txt
      mov eax,13
      int 0x40 ;draw node rect
    pop edx
    jmp @f
    .draw_img_n:
    push ebx edx esi
      xor esi,esi
      mov si,word[edx] ;get icon type
      mov edx,ebx
      ror ecx,16
      mov dx,cx
      mov cx,bx
      ror ecx,16
      mov ebx,3 ;rgb = 3 bytes
      imul bx,tl_img_cx
      imul bx,tl_img_cy
      imul ebx,esi ;esi = icon index
      add ebx,dword[edi+18] ;data_img

      mov eax,7
      int 0x40 ;draw node icon '-'
    pop esi edx ebx
    @@:

    mov al,byte[edx+2] ;draw minus '-'
    mov ecx,tl_data_nodes
    add ecx,sizeof.TreeList

    mov ah,10 ;get icon index '+' or '-' ?
    cmp byte[edx+3],1
    jne .close
      dec ah
    .close:

    call tl_draw_node_icon_opn_clo
    bt tl_style,1
    jae .end_draw
      call tl_draw_node_icon_par_lin
      call tl_draw_node_icon_par_lin_up
    .end_draw:
  pop esi edx ecx ebx eax
  ret

;input:
; ecx = pointer to 1 node struct
;...
align 4
tl_draw_node_icon_opn_clo: ;рисует иконки открытого или закрытого узла (обычно + или -)
  push eax ebx ecx edx esi
    inc al
    call tl_iterat_next_all ;get next visible item
    cmp edx,ecx
    jle @f
      mov ecx,esi ;load ecx
      cmp al,byte[edx+2]
      jne @f
      ror ebx,16
      sub bx,tl_img_cx
      ror ebx,16
      cmp tl_data_img_sys,0
      jne .draw_img_s
	mov edx,tl_col_txt
	mov eax,13
	int 0x40 ;draw minus rect, if not system icons
	jmp @f
      .draw_img_s:
      mov ecx,esi ;load ecx
      mov edx,ebx
      ror ecx,16
      mov dx,cx
      mov cx,bx
      ror ecx,16
      mov ebx,3 ;rgb = 3 bytes
      imul bx,tl_img_cx
      imul bx,tl_img_cy
      shr eax,8
      and eax,0xff
      imul ebx,eax ;eax = icon index
      add ebx,tl_data_img_sys
      mov eax,7
      int 0x40 ;draw minus icon '-'
    @@:
  pop esi edx ecx ebx eax
  ret

;input:
; al = уровень элемента
;...
align 4
tl_draw_node_icon_par_lin:
  cmp byte[edx+3],1
  je .close
  push eax ebx ecx edx esi
    cmp al,0
    je @f
;    dec al
;    call tl_iterat_perv ;get perv visible item

    call tl_iterat_next_all ;get next visible item
    cmp edx,ecx
    jle .line3 ;if end of list
      cmp al,byte[edx+2]
      jne .line3 ;jg ???
      mov eax,3 ;line in middle element
      jmp .line2
    .line3:
      mov eax,6 ;line in end element
    .line2:

      mov ecx,esi ;load ecx
      ror ebx,16
      sub bx,tl_img_cx
      ror ebx,16
      cmp tl_data_img_sys,0
      jne .draw_img_s
	mov edx,tl_col_txt
	mov eax,13
	int 0x40 ;draw minus rect, if not system icons
	jmp @f
      .draw_img_s:
;      mov ecx,esi ;load ecx
      mov edx,ebx
      ror ecx,16
      mov dx,cx
      mov cx,bx
      ror ecx,16
      mov ebx,3 ;rgb = 3 bytes
      imul bx,tl_img_cx
      imul bx,tl_img_cy

;      shr eax,8
;      and eax,0xff
      imul ebx,eax ;eax = icon index
      add ebx,tl_data_img_sys
      mov eax,7
      int 0x40 ;draw line icon
    @@:
  pop esi edx ecx ebx eax
  .close:
  ret



;icon:
; al = уровень элемента
;...
align 4
tl_draw_node_icon_par_lin_up:
  push eax ebx ecx edx esi
    cmp tl_data_img_sys,0 ;if not image
    je @f
    cmp al,0
    je @f

;---------
    xor esi,esi ;в si будем насчитывать кол-во иконок, нужных для прорисовки линии
    .cycle0:
      call tl_iterat_perv ;get perv visible item
      cmp edx,ecx
      jle .cycle1 ;if begin of list

      cmp byte[edx+2],al
      jle .cycle1 ;уровень верхнего элемента не требует прорисовки
      inc si
      jmp .cycle0
    .cycle1:
      cmp si,0 ;si = кол-во иконок линии которые нужно нарисовать сверху
      je @f
      shl esi,16

      pop ecx ;esi->ecx
      push ecx ;save esi

      ror ebx,16
      sub bx,tl_img_cx
      ror ebx,16

      mov edx,ebx
      ror ecx,16
      mov dx,cx
      mov cx,bx
      ror ecx,16
      mov cx,tl_img_cy ;restore size y (if crop)
      mov ebx,3 ;rgb = 3 bytes
      imul bx,tl_img_cx
      imul bx,tl_img_cy
      ;imul ebx,1
      add ebx,tl_data_img_sys

      add esi,tl_box_top
      add si,tl_capt_cy ;si = верхняя граница окна
      mov eax,7
;---------
      .cycle2:
      sub dx,tl_img_cy ;поднимаем координату y вверх
      cmp dx,si
      jl @f
;        int 0x40 ;draw line icon
        cmp esi,0x10000
        jl @f
        int 0x40 ;draw line icon
        sub esi,0x10000 ;уменьшаем счетчик иконок
      jmp .cycle2
    @@:
  pop esi edx ecx ebx eax
  ret

;input:
; edi = pointer to TreeInfo struct
;output:
; eax = rows
align 4
tl_get_rows_count:
  push ecx edx
    mov eax,tl_box_height
    sub ax,tl_capt_cy
    xor ecx,ecx
    mov cx,tl_img_cy
    xor edx,edx
    div ecx
  pop edx ecx
  ret

;input:
; eax = node position
; ebx = [координата по оси x]*65536 + [img_cx]
; ecx = [координата по оси y]*65536 + [img_cy]
; edx = pointer to some node struct
; edi = pointer to TreeInfo struct
align 4
tl_draw_node_caption:
    push ebx ecx edx esi

    xor esi,esi
    mov si,tl_info_size
    cmp si,tl_info_capt_offs
    jle @f ;if caption size <= 0

    push eax
      call tl_get_node_index ;eax = node index
      imul esi,eax
    pop eax
      add si,tl_info_capt_offs
      add esi,dword[edi]
      mov edx,esi

      shr ebx,16
      add bx,tl_img_cx ;сдвигаем надпись по горизонтали --->
      add bx,3 ;отступ
      ;bx = coord. x
      call tl_strlen ;eax = strlen
      call tl_get_draw_text_len
      mov cx,bx
      ror ecx,16
      mov ebx,ecx
      add bx,tl_img_cy ;выравнивиние по нижней границе иконки
      sub bx,9 ;отнимаем высоту текста
      mov ecx,tl_col_txt
      and ecx,0xffffff
;      or ecx,0x80000000 ;text is ASCIIZ
      mov eax,4
      int 0x40
    @@:
    pop esi edx ecx ebx
  ret

;input:
; eax = strlen
; ebx = text coord x
;output:
; esi = text len
align 4
tl_get_draw_text_len:
  push eax ecx edx
    mov esi,eax ;берем длинну строки

    mov eax,tl_box_left
    add eax,tl_box_width
    cmp eax,ebx
    jle .text_null ;если подпись полностью вся за экраном
    sub eax,ebx
    xor edx,edx
    mov ecx,6 ;ширина системного шрифта
    div ecx ;смотрим сколько символов может поместиться на экране

    cmp esi,eax
    jl @f
      mov esi,eax ;если длинна текста меньше, чем все место под строку
    jmp @f
    .text_null:
      xor esi,esi
    @@:
  pop edx ecx eax
  ret

;input:
; esi = pointer to string
;output:
; eax = strlen
align 4
tl_strlen:
  mov eax,esi
  @@:
    cmp byte[eax],0
    je @f
    inc eax
    loop @b
  @@:
  sub eax,esi
  ret

;input:
;dword[ebp+ 8] - pointer to node info
;dword[ebp+12] - options
;dword[ebp+16] - pointer to 'TreeList' struct
align 4
tl_node_add: ;добавить узел
  push ebp
  mov ebp,esp
  push eax ebx ecx edx edi
    mov edi,dword[ebp+16]

    call tl_info_set_undo

    mov ebx,sizeof.TreeList
    imul ebx,dword[edi+6] ;+6 макс. количество узлов
    add ebx,tl_data_nodes
;--
    call tl_get_cur_node_index ;eax=po_t
    imul eax,sizeof.TreeList
    add eax,tl_data_nodes
    mov edx,eax
    call tl_move_perv
    call tl_get_node_index ;eax = index of pointer [edx]
;--
    mov edx,sizeof.TreeList
    shl edx,1
    add edx,tl_data_nodes
    @@: ;for(i=2;i<nodeMax;i++)
      cmp dword [edx+12],0
      jne .u0
      cmp dword [edx+16],0
      jne .u0

	inc  tl_ch_tim
	mov cx,word[ebp+14] ;get type
	mov word[edx],cx
 mov cl,byte[ebp+13]
 mov byte[edx+3],cl  ;node[i].clo
	mov   byte[edx+2], 0 ;node[i].lev=0
  bt tl_style,2 ;tl_list_box_mode
  jc .l_box_m
    mov cl,byte[ebp+12]
    mov byte[edx+2],cl  ;node[i].lev
  .l_box_m:
	push tl_ch_tim       ;node[i].tc=ch_tim;
	pop  dword[edx+12]
	mov  dword[edx+4], eax ;node[i].perv=po_t;
	;*** copy node data ***
	push esi
	xor ecx,ecx
	mov cx,tl_info_size
	mov esi,ecx

	push eax
	  call tl_get_node_index ;eax = node index
	  imul esi,eax
	pop eax
	add esi,dword[edi]
	mov edi,dword[ebp+8] ;pointer to node data
	xchg edi,esi
	rep movsb

	mov esi,edi
	mov edi,dword[ebp+16] ;restore edi
	mov cx,tl_info_capt_offs
	cmp cx,tl_info_size
	jge .no_text_data
 cmp tl_info_capt_len,0 ;проверяем есть ли ограничение на длинну строки
 je .no_len_ogran
   add cx,tl_info_capt_len
   and ecx,0xffff
   add esi,ecx
   mov cx,tl_info_size
   sub esi,ecx
 .no_len_ogran:
	  dec esi
	  mov byte[esi],0
	.no_text_data:
	pop esi ;restore esi

	mov ecx,eax
	imul ecx,sizeof.TreeList
	add ecx,tl_data_nodes ; *** ecx = node[po_t] ***
	add ecx,8   ; *** ecx = node[po_t].next ***
	push dword [ecx] ;node[i].next=node[po_t].next;
	pop dword [edx+8]

	call tl_get_node_index ;*** eax = i ***
	cmp eax,dword[edi+6] ;info_max_count
	jge .u0

	mov [ecx],eax ;node[po_t].next=i; // ссылки перенаправляем
	mov ecx,[edx+8] ; *** ecx = node[i].next ***
	imul ecx,sizeof.TreeList
	add ecx,tl_data_nodes ; *** ecx = node[node[i].next] ***
	mov [ecx+4],eax ;node[node[i].next].perv=i;

	call tb_scrol_resize ;обработка скроллинга
    jmp @f
      .u0:
      add edx,sizeof.TreeList
      cmp edx,ebx ;enf of node memory ?
      jle @b
    @@:
  pop edi edx ecx ebx eax
  pop ebp
  ret 12

;input:
; edi = pointer to TreeInfo struct
align 4
tb_scrol_resize:
  push eax ecx edx
  cmp tl_p_scrol,0 ;обработка скроллинга
  je @f
    call tl_get_node_count ;eax = node count
    mov ecx,eax
    call tl_get_rows_count
    cmp ecx,eax
    jg .ye_sb
      xor ecx,ecx
    .ye_sb:

    mov edx,tl_p_scrol
    mov dword[edx+20],eax ;+20 .cur_area
    mov dword[edx+16],ecx ;+16 .max_area
    push dword edx ;pointer to scroll struct
    call scroll_bar_vertical.draw
  @@:
  pop edx ecx eax
ret

;input:
;dword[ebp+ 8] - pointer to node info
;dword[ebp+12] - pointer to 'TreeList' struct
align 4
tl_node_set_data:
  push ebp
  mov ebp,esp
  push eax ecx edx edi esi
    mov edi,dword[ebp+12]
    call tl_get_cur_node_index ;eax=po_t
    cmp eax,2
    jl @f
      xor ecx,ecx
      mov cx,tl_info_size
      imul eax,ecx
      add eax,dword[edi]
      mov edi,eax
      mov esi,dword[ebp+8] ;pointer to node data
      rep movsb

      mov esi,edi
      mov edi,dword[ebp+12] ;restore edi
      mov cx,tl_info_capt_offs
      cmp cx,tl_info_size
      jge .no_text_data
        mov ax,tl_info_capt_len ;проверяем есть ли ограничение на длинну текста
        cmp ax,0
        je .no_limit
        add cx,ax ;cx = tl_info_capt_offs + tl_info_capt_len
        and ecx,0xffff
        xor eax,eax
        mov ax,tl_info_size
        cmp eax,ecx
        jl .no_limit ;пользователь задал слишком большую длинну текста
        add esi,ecx
        sub esi,eax
        .no_limit:
          dec esi
          mov byte[esi],0 ;обнуляем последний символ подписи, что-бы не глючило если пользователь задал неправильную структуру
      .no_text_data:

    @@:
  pop esi edi edx ecx eax
  pop ebp
  ret 8

;input:
;dword[ebp+ 8] - pointer to 'TreeList' struct
align 4
tl_node_get_data: ;взять указатель на данные узла под курсором
  push ebp
  mov ebp,esp
  push eax ecx edi
    mov edi,dword[ebp+8]
    call tl_get_cur_node_index ;eax=po_t
    mov dword[ebp+8],0 ;if return 0 pointer
    cmp eax,2
    jl @f
      xor ecx,ecx
      mov cx,tl_info_size
      imul eax,ecx
      add eax,dword[edi]
      mov dword[ebp+8],eax ;return node data pointer
    @@:
  pop edi ecx eax
  pop ebp
  ret

;input:
;dword[ebp+ 8] - node index
;dword[ebp+12] - pointer to 'TreeList' struct
align 4
tl_node_poi_get_info: ;взять указатель на структуру узла в указанной позиции
  push ebp
  mov ebp,esp
  push eax ecx edx edi
    mov edi,dword[ebp+12]
    mov eax,dword[ebp+8]

    ;cycle to nodes
    mov edx,tl_data_nodes
    mov ecx,edx
    add ecx,sizeof.TreeList
    @@:
      call tl_iterat_next_all
      cmp edx,ecx
      jle @f
      dec eax
      cmp eax,0
      jg @b
      jmp .find
    @@:
      xor edx,edx
    .find:
    mov dword[ebp+12],edx
  pop edi edx ecx eax
  pop ebp
  ret 4

;input:
;dword[ebp+ 8] - node param struct
;dword[ebp+12] - pointer to 'TreeList' struct
align 4
tl_node_poi_get_next_info: ;взять указатель на следущую структуру узла
  push ebp
  mov ebp,esp
  push ecx edx edi
    mov edi,dword[ebp+12]
    mov edx,dword[ebp+8]

    mov ecx,tl_data_nodes
    add ecx,sizeof.TreeList

    call tl_iterat_next_all
    cmp edx,ecx
    jg @f
      xor edx,edx
    @@:

    mov dword[ebp+12],edx
  pop edi edx ecx
  pop ebp
  ret 4

;input:
;dword[ebp+ 8] - node param struct
;dword[ebp+12] - pointer to 'TreeList' struct
align 4
tl_node_poi_get_data: ;взять указатель на данные узла
  push ebp
  mov ebp,esp
  push eax ecx edi
    mov edi,dword[ebp+12]
    mov edx,dword[ebp+8]

    mov dword[ebp+12],0
    call tl_get_node_index ;eax = node index
    cmp eax,2
    jl @f
      xor ecx,ecx
      mov cx,tl_info_size
      imul eax,ecx
      add eax,dword[edi]
      mov dword[ebp+12],eax ;return node data pointer
    @@:
  pop edi ecx eax
  pop ebp
  ret 4

;input:
; edi = pointer 'tl' struct
;output:
; eax = index of current node
align 4
tl_get_cur_node_index: ;берет позицию под курсором
  push ecx edx
    ;cycle to nodes
    xor eax,eax
    mov edx,tl_data_nodes
    mov ecx,edx
    add ecx,sizeof.TreeList
    @@:
      call tl_iterat_next
      cmp edx,ecx
      jle @f
      cmp eax,tl_cur_pos
      je @f
      inc eax
      jmp @b
    @@:
  mov eax,edx
  sub eax,tl_data_nodes
  xor edx,edx
  mov ecx,sizeof.TreeList
  div ecx
  pop edx ecx
  ret

;input:
; edx = pointer node memory
; edi = pointer 'tl' struct
;output:
; eax = struct index of current node
align 4
tl_get_node_index: ;берет позицию указанного символа
  push ecx edx
  mov eax,edx
  sub eax,tl_data_nodes
  xor edx,edx
  mov ecx,sizeof.TreeList
  div ecx
  pop edx ecx
  ret

align 4
tl_node_delete: ;удалить узел
  push ebp
  mov ebp,esp
  push eax edx edi
    mov edi,dword[ebp+8]
    call tl_get_cur_node_index ;eax=po_t
    cmp eax,2
    jl @f
      imul eax,sizeof.TreeList
      add eax,tl_data_nodes
      mov edx,eax
      inc tl_ch_tim
      mov eax,tl_ch_tim
      mov dword[edx+16],eax
      call tb_scrol_resize ;обработка скроллинга
    @@:
  pop edi edx eax
  pop ebp
  ret 4

align 4
tl_cur_beg: ;поставить курсор на первый узел
  push ebp
  mov ebp,esp
  push edi
    mov edi,dword[ebp+8]
    mov tl_cur_pos,0
    cmp tl_p_scrol,0
    je @f
      mov edi,tl_p_scrol
      mov dword[edi+24],0
      push dword edi
      mov edi,dword[ebp+8]
      call scroll_bar_vertical.draw
    @@:
  pop edi

  pop ebp
  ret 4

align 4
tl_cur_next: ;перенести курсор на 1 позицию ниже
  push ebp
  mov ebp,esp
  push eax ebx edi esi
    mov edi,dword[ebp+8]
    call tl_get_node_count ;eax = node count
    ;inc eax
    cmp tl_cur_pos,eax
    jge .no_redraw
      mov esi,tl_box_top
      add esi,tl_box_height ;esi = coord bottom border
      call tl_draw_null_cursor ;стираем курсор
      inc tl_cur_pos

    cmp tl_p_scrol,0 ;if not scrol struct
    je @f
    call tl_get_rows_count ;eax = rows count
    mov ebx,tl_p_scrol
    add eax,dword[ebx+24] ;.position +24
    cmp tl_cur_pos,eax
    jl @f
      inc dword[ebx+24] ;.position +24
      push dword ebx
      call scroll_bar_vertical.draw

      mov edi,dword[ebp+8] ;restore edi
      push dword edi
      call tl_draw ;полная перерисовка окна
      jmp .no_redraw
    @@:
      mov edi,dword[ebp+8] ;restore edi
      call tl_draw_cursor ;перерисовка курсора
      call tl_draw_caption_cur_pos
    .no_redraw:
  pop esi edi ebx eax
  pop ebp
  ret 4


;input:
; edi = pointer 'tl' struct
;output:
; eax = struct index of current node
align 4
tl_get_node_count: ;берет число всех видимых узлов (не считая закрытых дочерних)
  push ecx edx
    ;cycle to nodes
    xor eax,eax
    mov edx,tl_data_nodes
    mov ecx,edx
    add ecx,sizeof.TreeList
    @@:
      call tl_iterat_next
      cmp edx,ecx
      jle @f
      inc eax
      jmp @b
    @@:
  pop edx ecx
  ret

;input:
; edi = pointer 'tl' struct
;output:
; eax = struct index of current node
align 4
tl_get_node_count_all: ;берет число всех видимых узлов (считая закрытые дочерние)
  push ecx edx
    ;cycle to nodes
    xor eax,eax
    mov edx,tl_data_nodes
    mov ecx,edx
    add ecx,sizeof.TreeList
    @@:
      call tl_iterat_next_all
      cmp edx,ecx
      jle @f
      inc eax
      jmp @b
    @@:
  pop edx ecx
  ret

align 4
tl_cur_perv: ;перенести курсор на 1 позицию выше
  push ebp
  mov ebp,esp
  push eax edi esi
    mov edi,dword[ebp+8]
    cmp tl_cur_pos,0
    je .no_redraw
      mov esi,tl_box_top
      add esi,tl_box_height ;esi = coord bottom border
      call tl_draw_null_cursor ;стираем курсор
      dec tl_cur_pos ;двигаем курсор вверх

    cmp tl_p_scrol,0 ;если есть указатель на скроллинг
    je @f
    mov eax,tl_p_scrol
    cmp dword[eax+24],0 ;если скроллинг на верху, выходим
    je @f
    mov edi,tl_cur_pos
    cmp edi,dword[eax+24] ;если курсор ушел выше скроллинга, тогда опускаем скроллинг
    jge @f
      dec dword[eax+24]
      push dword eax
      mov edi,dword[ebp+8]
      call scroll_bar_vertical.draw
      mov edi,dword[ebp+8] ;restore edi
      push dword edi
      call tl_draw ;полная перерисовка окна
      jmp .no_redraw
    @@:
      mov edi,dword[ebp+8] ;restore edi
      ;mov esi,tl_box_top
      ;add esi,tl_box_height ;esi = coord bottom border
      call tl_draw_cursor ;перерисовка курсора
      call tl_draw_caption_cur_pos
    .no_redraw:
  pop esi edi eax
  pop ebp
  ret 4

align 4
tl_cur_page_up: ;перенести курсор на 1 страницу выше
  push ebp
  mov ebp,esp
  push eax edi esi
    mov edi,dword[ebp+8]

    cmp tl_p_scrol,0 ;если есть указатель на скроллинг
    je .no_redraw

    mov esi,tl_p_scrol
    call tl_get_rows_count ;eax = rows count

    cmp tl_cur_pos,0
    jne @f
    cmp dword[esi+24],0 ;если скроллинг на верху, выходим
    jne @f
      jmp .no_redraw
    @@:
      cmp tl_cur_pos,eax ;проверяем позицию курсора и кол-во сток на странице
      jl @f ;если меньше, то приравниваем к 0, что-бы не отнять больше чем надо
        sub tl_cur_pos,eax
        jmp .cursor
      @@:
        mov tl_cur_pos,0
      .cursor:
      cmp dword[esi+24],eax
      jl @f
        sub dword[esi+24],eax
        jmp .scroll
      @@:
        mov dword[esi+24],0
      .scroll:
      ;перерисовки окна и скроллинга
      push dword edi
      call tl_draw ;draw window
      push dword esi
      call scroll_bar_vertical.draw
    .no_redraw:
  pop esi edi eax
  pop ebp
  ret 4

align 4
tl_cur_page_down: ;перенести курсор на 1 страницу ниже
  push ebp
  mov ebp,esp
  push eax ebx ecx edi esi
;eax - кол-во строк на странице
;ebx - макс. позиция курсора
;ecx - макс. позиция скроллинга
    mov edi,dword[ebp+8]

    cmp tl_p_scrol,0 ;если есть указатель на скроллинг
    je .no_redraw

    mov esi,tl_p_scrol
    call tl_get_node_count ;eax = node count
    mov ebx,eax
    call tl_get_rows_count ;eax = rows count

    mov ecx,ebx
    inc ecx ;если нижний узел виден на половину
    cmp ecx,eax ;if (ecx>eax) { ecx=ecx-eax } else { ecx=0 }
    jl @f
      sub ecx,eax ;уменьшаем максимальную позицию скроллинга, так что-бы были видны последние узлы
      jmp .control
    @@:
      xor ecx,ecx ;ecx=0 - все узлы влазят в экран, скроллинг не нужен
    .control:

    cmp tl_cur_pos,ebx ;курсор внизу ?
    jl @f
    cmp dword[esi+24],ecx ;скроллинг внизу ?
    jl @f
      jmp .no_redraw
    @@:

      add tl_cur_pos,eax ;перемещаем курсор
      cmp tl_cur_pos,ebx
      jl @f
        mov tl_cur_pos,ebx
      @@:

      add dword[esi+24],eax ;перемещаем скроллинг
      cmp dword[esi+24],ecx
      jl @f
        mov dword[esi+24],ecx
      @@:

      ;перерисовки окна и скроллинга
      push dword edi
      call tl_draw ;draw window
      push dword esi
      call scroll_bar_vertical.draw
    .no_redraw:
  pop esi edi ecx ebx eax
  pop ebp
  ret 4

align 4
tl_node_close_open: ;открыть/закрыть узел (работает с узлами которые имеют дочерние узлы)
  push ebp
  mov ebp,esp
  push eax edx edi
    mov edi,dword[ebp+8]
    call tl_get_cur_node_index ;eax = позиция узла на котором стоит курсор
    cmp eax,2 ;курсор стоит на узле ?
    jl @f
      imul eax,sizeof.TreeList
      add eax,tl_data_nodes
      ;eax = указатель на структуру узла выбранного курсором
      push dword edi
      push dword eax
      call tl_node_poi_get_next_info
      pop dword edx ;edx = указатель на структуру узла который идет после узла eax
      cmp edx,0 ;есть ли узлы ниже выбранного нами ?
      je @f
	mov dl,byte[edx+2] ;берем уровень нижнего узла
	cmp byte[eax+2],dl ;+2 = .lev
	jge @f ;если нижние узлы меньшего уровня, значит они не дочерние, конец функции
	  xor byte[eax+3],1 ;+3 = .clo *** открытие/закрытие узла ***
	  call tb_scrol_resize ;обработка скроллинга

	  push dword edi
	  call tl_draw ;обновление окна
    @@:
  pop edi edx eax
  pop ebp
  ret 4

align 4
tl_node_lev_inc: ;увеличить уровень
  push ebp
  mov ebp,esp
  push eax edx edi
    mov edi,dword[ebp+8]
    bt tl_style,2 ;tl_list_box_mode
    jc @f
    call tl_get_cur_node_index ;eax=po_t
    cmp eax,2
    jl @f
      imul eax,sizeof.TreeList
      add eax,tl_data_nodes
      mov edx,eax
      inc word[edx+2]
    @@:
  pop edi edx eax
  pop ebp
  ret 4

align 4
tl_node_lev_dec: ;уменьшить уровень
  push ebp
  mov ebp,esp
  push eax edx edi
    mov edi,dword[ebp+8]
    call tl_get_cur_node_index ;eax=po_t
    cmp eax,2
    jl @f
      imul eax,sizeof.TreeList
      add eax,tl_data_nodes
      mov edx,eax
      cmp word[edx+2],0
      je @f
      dec word[edx+2]
    @@:
  pop edi edx eax
  pop ebp
  ret 4

align 4
tl_node_move_up: ;перемещаем узел вверх
  push ebp
  mov ebp,esp
  push eax ebx ecx edx edi esi
    mov edi,dword[ebp+8]
    call tl_get_cur_node_index ;eax=po_t
    cmp eax,2
    jl @f
      mov ebx,eax ;copy index of node struct
      mov edx,tl_data_nodes
      mov ecx,edx
      add ecx,sizeof.TreeList
      imul eax,sizeof.TreeList
      add eax,edx ;eax = pointer to 2 node struct
      mov edx,eax ;edx = pointer to 2 node struct
      mov esi,eax ;esi = pointer to 2 node struct
      call tl_iterat_perv ;edx = pointer to 1 node struct
      call tl_get_node_index ;eax = index of 1 node struct
      cmp edx,ecx
      jle @f
        cmp dword[edx+8],ebx ;+8 next
        jne .po8
          call tl_node_move_po6 ;узлы идут подряд меняем 6 ссылок
          jmp .cur_mov
        .po8:
          call tl_node_move_po8 ;узлы идут не подряд меняем 8 ссылок
        .cur_mov:
          push dword edi
          call tl_cur_perv
          push dword edi
          call tl_draw
    @@:
  pop esi edi edx ecx ebx eax
  pop ebp
  ret 4

align 4
tl_node_move_down: ;перемещаем узел вниз
  push ebp
  mov ebp,esp
  push eax ebx ecx edx edi esi
    mov edi,dword[ebp+8]
    call tl_get_cur_node_index ;eax=po_t
    cmp eax,2
    jl @f
      mov ebx,eax ;copy index of node struct
      mov edx,tl_data_nodes
      mov ecx,edx
      add ecx,sizeof.TreeList
      imul eax,sizeof.TreeList
      add eax,edx ;eax = pointer to 1 node struct
      mov edx,eax ;edx = pointer to 1 node struct
      mov esi,eax ;esi = pointer to 1 node struct
      call tl_iterat_next ;edx = pointer to 2 node struct
      call tl_get_node_index ;eax = index of 2 node struct
      cmp edx,ecx
      jle @f
        cmp dword[esi+8],eax ;+8 next
        jne .po8
          xchg eax,ebx ;меняе порядок следования заменяемых узлов
          xchg edx,esi
          call tl_node_move_po6 ;узлы идут подряд меняем 6 ссылок
          jmp .cur_mov
        .po8: ;а тут порядок следования узлов не меняем
          call tl_node_move_po8 ;узлы идут не подряд меняем 8 ссылок
        .cur_mov:
          push dword edi
          call tl_cur_next
          push dword edi
          call tl_draw
    @@:
  pop esi edi edx ecx ebx eax
  pop ebp
  ret 4

align 4
tl_node_move_po6:
  mov ecx,edx ;save node pointer
  call tl_move_perv
  mov dword[edx+8],ebx

  mov edx,esi
  call tl_move_next
  mov dword[edx+4],eax
  mov edx,ecx ;restore node pointer

  ;+4 perv
  mov ecx,dword[edx+4]
  mov dword[esi+4],ecx
  ;+8 next
  mov ecx,dword[esi+8]
  mov dword[edx+8],ecx

  mov dword[edx+4],ebx
  mov dword[esi+8],eax
  ret

;input
;eax = index 1 node struct
;ebx = index 2 node struct
;edx = pointer 1 node struct
;esi = pointer 2 node struct
;edi = pointer to 'TreeList' struct
;output:
;eax = ?
;ebx = ?
;ecx = ?
align 4
tl_node_move_po8:
;  push ecx
  mov ecx,edx ;save node pointer
  call tl_move_perv
  mov dword[edx+8],ebx
  mov edx,ecx
  call tl_move_next
  mov dword[edx+4],ebx
  mov edx,esi
  call tl_move_perv
  mov dword[edx+8],eax
  mov edx,esi
  call tl_move_next
  mov dword[edx+4],eax
  mov edx,ecx ;restore node pointer
;  pop ecx

  ;+4 perv
  mov eax,dword[edx+4]
  mov ebx,dword[esi+4]
  xchg eax,ebx
  mov dword[edx+4],eax
  mov dword[esi+4],ebx
  ;+8 next
  mov eax,dword[edx+8]
  mov ebx,dword[esi+8]
  xchg eax,ebx
  mov dword[edx+8],eax
  mov dword[esi+8],ebx
  ret

;input:
; edi = pointer to 'TreeList' struct
align 4
tl_draw_caption_cur_pos:
  cmp tl_capt_cy,9 ;9 - minimum caption height
  jl @f
  push eax ebx ecx edx edi esi
    mov ebx,edi ;calculate cursor position
    mov eax,tl_cur_pos
    inc eax
    lea edi,[txt_capt_cur]
    add edi,7
    call tl_convert_to_str
    mov edi,ebx

    mov eax,4 ;draw text captions
    mov ebx,tl_box_left
    shl ebx,16
    add ebx,5*65536+3
    add ebx,tl_box_top
    mov ecx,tl_col_txt
    or	ecx,0xc0000000 ;0x40000000 закрашивать фон цветом edi
    lea edx,[txt_capt_cur]
    mov edi,tl_col_zag
    int 0x40

  pop esi edi edx ecx ebx eax
  @@:
  ret

;input:
;dword[ebp+ 8] - memory size
;dword[ebp+12] - pointer to memory
;dword[ebp+16] - options: 0 - first element, 1 - add next element
;dword[ebp+20] - pointer to 'TreeList' struct
;output:
;dword[ebp+ 8] - error code
align 4
tl_save_mem:
  push ebp
  mov ebp,esp
    push eax ebx ecx edx edi esi
    mov esi,dword[ebp+12]
    mov edi,dword[ebp+20]

    cmp dword[ebp+16],0 ;add mode
    je @f
      .beg_cycle:
      cmp dword[esi],0x65657274 ;0x65657274 = 'tree'
      jne @f
      xor ebx,ebx
      mov bx,word[esi+4]
      imul ebx,dword[esi+6]
      add ebx,tl_save_load_heder_size
      add esi,ebx
      jmp .beg_cycle
    @@:

    xor ebx,ebx
    mov bx,tl_info_size

    call tl_get_node_count_all ;eax = all node count

    mov ecx,eax  ;вычисляем сколько памяти должно быть заполнено
    imul ecx,ebx ;умножаем на размер структуры узла
    add ecx,tl_save_load_heder_size+1 ;element header +1 end element sumbol
    add ecx,esi  ;добавляем указатель на начало памяти (с учетом ранее записанных структур)
    sub ecx,dword[ebp+12] ;отнимаем указатель на начало памяти (без ранее записанных структур)
    cmp ecx,dword[ebp+8]  ;ecx = element memory size
    jg .err_mem_size

    ;save tree params (in header)
    mov dword[esi],0x65657274 ;0x65657274 = 'tree'
    mov word[esi+4],bx
    mov dword[esi+6],eax ;element count

    mov eax,tl_style
    mov dword[esi+10],eax

    mov eax,tl_cur_pos
    mov dword[esi+14],eax

    mov ax,tl_info_capt_offs
    mov word[esi+18],ax

    mov ax,tl_info_capt_len
    mov word[esi+20],ax

    ;copy scroll position
    mov edx,tl_p_scrol
    mov eax,dword[edx+24] ;+24 .position
    mov dword[esi+22],eax

    add esi,tl_save_load_heder_size ;add header size

    ;cycle to nodes
    mov edx,tl_data_nodes
    mov ecx,edx
    add ecx,sizeof.TreeList
    @@:
      call tl_iterat_next_all
      cmp edx,ecx
      jle @f
;save node params
call tl_get_node_index ;eax = index of pointer [edx]
mov dword[esi],eax

add esi,4
mov eax,dword[edx] ;eax = (type; lev; clo)
mov dword[esi],eax
add esi,4

push dword edi
push dword edx
call tl_node_poi_get_data
pop dword eax

;call tl_node_copy_data
push ecx edi
  mov edi,eax
  mov ecx,ebx
  xchg esi,edi
  rep movsb
  mov esi,edi
pop edi ecx
;add esi,ebx
      jmp @b
    @@:
    mov byte[esi],0 ;end of 'treelist'
    mov dword[ebp+20],0 ;return error code
    jmp @f
      .err_mem_size:
      or dword[ebp+20],tl_err_save_memory_size
    @@:
    pop esi edi edx ecx ebx eax
  pop ebp
  ret 12

;input:
;dword[ebp+ 8] - memory size
;dword[ebp+12] - pointer to memory
;word[ebp+16] - options: element index
;word[ebp+18] - options: 2*(add mode)+(init mode)
;dword[ebp+20] - pointer to 'TreeList' struct
;output:
;dword[ebp+ 8] - error code
align 4
tl_load_mem:
  push ebp
  mov ebp,esp
    push eax ebx ecx edx edi esi
    mov esi,dword[ebp+12]
    mov edi,dword[ebp+20]

    mov dword[ebp+20],0 ;return error code

    xor ecx,ecx
    mov cx,word[ebp+16]
    cmp cx,0 ;load in array mode
    je @f
      .beg_cycle:
      cmp dword[esi],0x65657274 ;0x65657274 = 'tree'
      jne .no_tree
      xor ebx,ebx
      mov bx,word[esi+4]
      imul ebx,dword[esi+6]
      add ebx,tl_save_load_heder_size
      add esi,ebx
      loop .beg_cycle
    @@:

    cmp dword[esi],0x65657274 ;0x65657274 = 'tree'
    jne .no_tree
      bt word[ebp+18],1 ;load in add mode
      jc @f
        push dword edi
        call tl_info_clear
      @@:

      xor ebx,ebx
      mov bx,word[esi+4] ;info_size
      cmp bx,tl_info_size
      je @f
        or dword[ebp+20],tl_err_load_info_size
      @@:
      mov ecx,dword[esi+6] ;count nodes
      cmp ecx,1
      jl .end_f
      mov edx,esi ;save header pointer
      add esi,tl_save_load_heder_size

      @@:
;load node params
push dword edi
mov eax,dword[esi+4]
ror eax,16
push dword eax ;options (type; lev; clo)
add esi,8
push dword esi
call tl_node_add

push dword edi
call tl_cur_next
;...
add esi,ebx
        loop @b

      bt word[ebp+18],1 ;load in add mode
      jc .no_tree
        mov eax,dword[edx+14] ;set cursor pos
        mov tl_cur_pos,eax
        mov eax,dword[edx+22] ;set scroll pos
        mov ebx,tl_p_scrol
        cmp ebx,0
        je .end_f
          mov dword[ebx+24],eax ;+24 .position
          push dword ebx ;pointer to scroll struct
          call scroll_bar_vertical.draw

      jmp .end_f
    .no_tree:
      mov dword[ebp+20],tl_err_load_caption
    .end_f:
    pop esi edi edx ecx ebx eax
  pop ebp
  ret 12

;ascii scan key
;  13    28 Enter
;  32    57 Space
; 178    72 Up
; 177    80 Down
; 176    75 Left
; 179    77 Right
; 182    83 Delete
; 184    73 Pg Up
; 183    81 Pg Dn

tl_key_ascii db 13,32,178,177,176,179,182,184,183
tl_key_scan  db 28,57, 72, 80, 75, 77, 83, 73, 81

txt_capt_cur db '‘ва®Є       ',0
txt_capt_otm db 'Ћв¬Ґ­л      ',0

;этот код не мой, он преобразует число в строку
;input:
; eax = value
; edi = string buffer
;output:
; edi =
align 4
tl_convert_to_str:
  pushad
    mov dword[edi+1],0x20202020
    call .str
  popad
  ret

align 4
.str:
  mov ecx,0x0a ;задается система счисления изменяются регистры ebx,eax,ecx,edx входные параметры eax - число
    ;преревод числа в ASCII строку взодные данные ecx=система счисленя edi адрес куда записывать, будем строку, причем конец переменной 
  cmp eax,ecx  ;сравнить если в eax меньше чем в ecx то перейти на @@-1 т.е. на pop eax
  jb @f
  xor edx,edx  ;очистить edx
  div ecx      ;разделить - остаток в edx
  push edx     ;положить в стек
  ;dec edi             ;смещение необходимое для записи с конца строки
  call .str;перейти на саму себя т.е. вызвать саму себя и так до того момента пока в eax не станет меньше чем в ecx
  pop eax
  @@: ;cmp al,10 ;проверить не меньше ли значение в al чем 10 (для системы счисленя 10 данная команда - лишная))
  ;sbb al,$69  ;- честно данная инструкция меня заставляет задуматься т.е. я не знаю как это работает
  ;das        ;после данной команды как бы происходит уменьшение al на 66h  (в книге написано другое)
  or al,0x30  ;данная команда короче  чем две выше 
  stosb       ;записать элемент из регистра al в ячеку памяти es:edi
  ret         ;вернуться чень интересный ход т.к. пока в стеке храниться кол-во вызовов то столько раз мы и будем вызываться
}
