;Эффективное программирование в KOLIBRI ;Оптимизированный компонент CheckBox (Исходный вариант от Maxxxx32) ;Оптимизирован вывод строки надписи для CheckBox'a + теперь, при проверке не происходит подсчет кол-ва символов в строке ;Оптимизация команд - отказался от сохранения регистров в стеке. ;17.07.2006 произведена оптимизация, при установке чек бокса в положение включено последующие чек боксы в тот же промежуток времени не проверяются ; - Теплов Алексей www.test-kolibri.narod.ru macro use_check_box { ch_text_margin=4 ;расстояние от прямоугольника чек бокса до надписи ch_size=10 ;размер квадрата чек бокса ch_left equ [edi] ;координата начала рисования по х ch_top equ [edi+2] ;координата начала рисования по у ch_color equ [edi+4] ;цвет внутри checkbox ch_border_color equ [edi+8] ;цвет рамки checkbox ch_text_color equ [edi+12] ;цвет текста ch_text_ptr equ [edi+16] ;указатель на начало текстовой строки ch_text_length equ [edi+20] ;длина надписи (2^64 такой длины может быть текст) ch_flags equ [edi+24] ;флаги check_box: .draw: pusha ;сохраним все регистры mov eax,38 ;рисование линии mov bx,ch_left ;положение по х ;mov cx,bx ;сохраним в регистре cx значение bx push bx ;3 - микрооперации используя стек можно выиграть в размере, используя регистры - в скорости shl ebx,16 ;сдвинем на 16 разрядов в лево (умножим на 65536) pop bx ;2 - микрооперации на данный момент сформирована [координата начала по оси x]*65536 + [координата начала по оси x] ;mov bx,cx ;восстановим значение bx mov cx,ch_top ;загрузим в cx значение y mov si,cx ;сохраним значение регистра cx в регистр указатель si ;push cx shl ecx,16 ; сдвинем на 16 разрядов в лево (умножим на 65536) mov cx,si ;восстановим значение регистра cx mov cx,si ;восстановим значение регистра cx ;pop cx ;[координата начала по оси y]*65536 + [координата начала по оси y] ;push cx add cx,ch_size ;[координата начала по оси y]*65536 + [координата конца по оси y] mov edx,ch_border_color ;Цвет линии int 0x40 ;рисование вертикальной левой линии квадрата (прямоугольника) ; mov bp,bx ;сохраним регистр bx в регистре указателя базы ;push bx ;втолкнуть в bx [координата начала по оси х]*65536 + [координата начала по оси x] add bx,ch_size ;[координата начала + длина стороны по оси х] ror ebx,16 ;[координата начала + дина стороны по оси х]*65536 add bx,ch_size ;[координата начала+длина стороны по оси х]*65536 + [координата начала+длина стороны по оси x] int 0x40 mov bx,bp ;восстановим значение регистра bx ;pop bx mov cx,si ;сохраним значение регистра cx в регистр указатель ;pop cx int 0x40 add cx,ch_size ;добавим размер стороны mov si,cx ;сохраним значение регистра cx в регистр указатель si ;push cx shl ecx,16 mov cx,si ;pop cx int 0x40 ;нарисовали прямоугольник mov eax,13 ;закрашиваем его. Функция 13 - нарисовать полосу mov bx,ch_left ;загрузить в bx, положение по х add bx,1 ;сдвинем на 1 т.е. прибавим 1 иначе затрется рамка shl ebx,16 ;сдвинем на 16 разрядов в лево (умножим на 65536) mov bx,ch_size ;прибавим длину стороны прямоугольника sub bx,1 ;вычтем 1 т.к. иначе затрется рамка mov bp,bx ; сохраним регистр bx в регистре указателя базы ;push bx mov cx,ch_top ;загрузим координаты по y add cx,1 ;сдвинем на 1 т.е. прибавим 1 иначе затрется рамка shl ecx,16 ;сдвинем на 16 разрядов в лево (умножим на 65536) mov cx,bp ;восстановим значение регистра cx ;pop cx mov edx,ch_color ;загрузим цвет полосы int 0x40 ;закрасили bt dword ch_flags,1 ;достать значение бита из переменной и поместить в флаг CF jnc @f ;в если CF=1, то выполним следующую процедуру иначе перейти на нижнюю @@ call .draw_ch ;нарисовать включенный чек бокс @@: ;---------------------------- ;расчет куда будет произведен вывод текста ;---------------------------- mov bx,ch_left ;загрузить значение х для чек бокса add bx,(ch_size+ch_text_margin) ;добавить размер стороны и расстояние на котором начнется вывод текста shl ebx,16 ;сдвинем на 16 разрядов в лево (умножим на 65536) mov bx,ch_top ;загрузим значение по y add bx,(ch_size-9+2) ;добавим значение длины стороны -9+2 mov ecx,ch_text_color ;загрузим цвет надписи mov edx,ch_text_ptr ;укажем адрес от куда нужно выводить строку mov esi,ch_text_length ;Загрузим длину надписи в esi xor eax,eax ;внесем в eax значение вывода надписи на канву add eax,4 int 0x40 ;Вывод popa ;восстановить значения регистров из стека ret ;выйдем из процедуры .clear_ch: ;очистка чек бокса mov edx,ch_color ;цвет внутри чек бокса jmp @f ;безусловный прыжок на нижнюю метку @@ .draw_ch: ;нарисовать включенный чек бокс mov edx,ch_border_color ;загрузить цвет @@: mov bx,ch_left ;загрузить координату по х add bx,(ch_size/3) ;добавить (сторона прямоугольника/3) shl ebx,16 ;сдвинем на 16 разрядов в лево (умножим на 65536) mov bx,(ch_size/2) ;загрузить (сторона прямоугольника/2) mov bp,bx ;сохраним регистр bx в регистре указателя базы ;push bx mov cx,ch_top ;загрузить координату по у add cx,(ch_size/3) ;добавить (сторона прямоугольника/3) shl ecx,16 ;сдвинем на 16 разрядов в лево (умножим на 65536) mov cx,bp ;загрузим значения регистра указателя базы в cx ;pop cx mov eax,13 ;в eax - значения функции для вывода полосы т.е. по сути прямоугольника, который отображает включенный компонент чек бокс int 0x40 ;вывод ret ;выйти из процедуры .mouse: ;обработка мыши pusha mov eax,37 ;будем что то делать если у нас что - нить нажато xor ebx,ebx ;обнулить регистр ebx (изменяет флаги) add ebx,2 ;внести в регистр значение 2 int 0x40 ;проверка не нажал ли пользователь кнопку мышки test eax,eax ;проверка если у нас в eax=0, то установим флаг и выйдем jnz @f ;перейти на нижнюю метку @@ btr dword ch_flags,2 ;извлечение значения заданного бита в флаг cf и изменение его значения на нулевое. popa ;если ничего не произошло, то восстановим значения регистров из стека ret ;выход @@: bts dword ch_flags,2 ;проверка флага т.е. перенос в cf значение бита и установка бита в состояние включено jc .mouse_end ;если CF=1 то перейти в конец т.е. это выход mov esi,ch_text_length ;загрузить кол-во символов в текстовой строке ;Умножение на 6 Быстрое умножение можно воспользоваться любым мз методов, но на старых Процессорах (386,486,P1)быстрее будет с инструкцией Lea ;lea esi,[eax*2+eax] ;shl eax,1 imul esi,6 ; или можно и так умножить на 6 add esi,ch_text_margin ;добавить 3 - расстояние от чек бокса до надписи mov eax,37 ;получим координаты мышки xor ebx,ebx ;обнулить регистр add ebx,1 ;добавить 1 int 0x40 ;получить координаты курсора относительно окна mov bx,ch_top ;загрузить в bx значение координаты у cmp ax,bx ;сравнить с с координатой курсора jl .mouse_end ;SF <> OF если меньше add bx,ch_size ;добавить размер cmp ax,bx ;сравнить jg .mouse_end ;ZF = 0 и SF = OF если больше shr eax,16 ;разделим на 65536 или просто сдвинем биты на 16 значений mov bx,ch_left ;произведем аналогичное сравнение cmp ax,bx ;сравнить регистры jl .mouse_end ;если меньше add bx,ch_size ;добавить длину стороны прямоугольника add bx,si ;Учесть в значении по х еще и длину надписи к чекбоксу cmp ax,bx ;стравнить регистры jg .mouse_end ;если больше bts dword ch_flags,1 ;извлечение значения заданного бита в флаг cf и изменение его значения на 1. jc @f ;CF=1 то перейти на нижнюю @@ call .draw_ch ;отобразить включенный чек бокс mov dword [esp+24],1 ;дальнейшая проверка чек боксов бесмыслена, по этому в стек, где располагается ecx поместитм 0 jmp .mouse_end ;выйти @@: btr dword ch_flags,1 ;извлечение значения заданного бита в флаг cf и изменение его значения на нулевое. call .clear_ch ;выключить чек бокс т.е. на месте закрашенного прямоугольника отобразить цвет фона. .mouse_end: popa ;восстановить регистры из стека ret ;выйти } struc check_box left,top,color,border_color,text_color,text,text_length,flags { ;структура параметров для чек бокса .left: dw left ;+0 ;положение по х .top: dw top ;+2 ;положение по у .color: dd color ;+4 ;цвет внутри чек бокса .border_color: dd border_color ;+8 цвет рамки .text_color: dd text_color ;+12 цвет текста надписи .text: dd text ;+16 адрес в коде программы где расположен текстр .text_length: dd text_length ; +20 длина текста .flags: dd flags+0 ;+24 флаги } ch_struc_size=28 ;общая структура 28 байт macro draw_check_boxes start,end ;рисовать чек боксы { mov edi,start ;Указатель на начало данных чек боксов т.е. на начало данных первого чекбокса mov ecx,((end-start)/ch_struc_size) ;Количество чек боксов @@: call check_box.draw ;Отобразить чек бокс add edi,ch_struc_size ;Указатель на последующие чек боксы т.е. +28 loop @b ;прыгнуть если в ecx/cx значение не 0 на верхнюю @@ } macro mouse_check_boxes start,end ;установка чек боксов, в зависимости от события { mov edi,start ; Указатель на начало данных чек боксов т.е. на начало данных первого чекбокса mov ecx,((end-start)/ch_struc_size) ;Количество чек боксов @@: call check_box.mouse ;проверка мышки и обработка событий add edi,ch_struc_size ;Указатель на последующие чек боксы loop @b ;прыгнуть если в ecx/cx значение не 0 на верхнюю @@ } macro check_boxes_set_sys_color start,end,color_table { mov edi,start mov ecx,((end-start)/ch_struc_size) mov esi,color_table @@: push dword [esi+32] pop dword ch_text_color push dword [esi+36] pop dword ch_border_color add edi,ch_struc_size loop @b }