;********************************* ;* * ;* PAINT 0.02 для MenuetOS * ;* * ;* Компилировать FASM'ом * ;* * ;********************************* ;****************************************************************************** ; Эту программу не нужно серьезно рассматривать - это всего лишь пример, ; в котором показано, как работать с некоторыми системными функциями МеОС, ; но никак не нормальный графический редактор. Код программы ОЧЕНЬ простой, ; и она предназначена для тех, кто только начинает изучать ассемблер, ; поэтому я стремился сделать его как можно более понятным. ; Тем не менее, код довольно неплохо оптимизирован, хотя это немного ; может затруднить его понимание. Я постарался тщательно прокомментировать ; сложные места. Кстати, идея программы принадлежит не мне, а Sniper'у, для ; которого вобщем-то все и писалось. ; Удачи в изучении асма! ; Иван Поддубный, ivan-yar@bk.ru ;****************************************************************************** ; Подключаем необходимые макросы include '../../../macros.inc' ;****************************************************************************** ; НАЧАЛО ПРОГРАММЫ use32 org 0x0 db 'MENUET01' ; 8 byte id dd 0x01 ; title version dd START ; start of code dd I_END ; size of image dd E_END ; memory for app dd E_END ; esp dd 0x0,0x0 ; I_Param , I_Icon ; ОБЛАСТЬ КОДА START: mov eax,40 ; сообщим системе, какие события будем обрабатывать mov ebx,0100101b ; маска событий - перерисовка (1) + кнопка (3) + мышь (6 int 0x40 ; эта команда вызывает системную функцию mov [workarea.cx],5 ; координаты рабочей (клиентской) области mov [workarea.cy],30 ; для рисования red: call draw_window ; вызываем процедуру отрисовки окна still: ; ГЛАВНЫЙ ЦИКЛ ПРОГРАММЫ - ЦИКЛ ОБРАБОТКИ СООБЩЕНИЙ mov eax,10 ; функция 10 - ждать события; программа останавливается на int 0x40 ; следующая команда не будет выполнена до тех пор, пока ; не произойдёт событие ; теперь регистр eax содержит номер события ; поочередно сравним его со всеми возможными значениями, чтобы вызвать ; нужный обработчик cmp eax,1 ; перерисовать окно ? je red ; если регистр eax равен единице, то переходим на метку red cmp eax,3 ; нажата кнопка ? je button cmp eax,6 ; мышь? je mouse jmp still ; если произошло событие, которое мы не обрабатываем, ; просто возвращаемся к началу цикла, хотя такого быть ; не должно! Т.е. если эту команду отсюда убрать, то ; ничего страшного не случится. ;****************************************************************************** button: ; обработчик нажатия кнопки в окне программы mov eax,17 ; функция N17 - получить идентификатор нажатой кнопки int 0x40 ; теперь в регистре ah содержится идентификатор. shr eax,8 ; ah -> al (сдвиг на 8 бит вправо) dec al ; идентификатор_кнопки--; jnz .noclose ; если результат предыдущей команды равен нулю, закрываемся ; иначе - идём на метку noclose or eax,-1 ; выход из программы int 0x40 .noclose: ; если мы сюда попали, значит идентификатор кнопки не был равен нулю... ; теперь у нас в eax содержится (номер цветной кнопки - 1), ; т.е или 1, или 2, ... ,или 5 ; уменьшим на 1: dec eax ; вот эта вот команда извлекает в eax двойное слово по адресу colors+eax*4 ; где colors - смещение метки colors, после которой идет последовательность ; цветов, eax*4 - номер цвета, умноженный на 4, т.к. на один цвет нужно ; четыре байта. mov eax,[colors+eax*4] ; теперь мы установим цвет, содержащийся в регистре eax как основной: mov [active_color],eax ; ну вот, собственно, и всё, что от нас требовалось ;) ; вернёмся к началу цикла обработки событий jmp still ;****************************************************************************** mouse: ; обработчик мыши mov eax,37 ; сначала получим текущие координаты мыши mov ebx,1 int 0x40 mov ebx,eax ; преобразуем их shr eax,16 ; eax=x; and ebx,0xffff ; ebx=y; cmp ebx,22 jb save_canvas sub eax,[workarea.cx] ; x-=[workarea.cx] cmp eax,0 ; если мышь левее клиентской области, jle .not_pressed ; ничего не рисуем cmp eax,[workarea.sx] ; если мышь правее... jae .not_pressed sub ebx,[workarea.cy] cmp ebx,0 ; ...выше... jle .not_pressed cmp ebx,[workarea.sy] ; ...ниже... jae .not_pressed ; какие кнопки нажаты? mov eax,37 mov ebx,2 int 0x40 ; если левая кнопка (т.е. eax = 1), те пойдём дальше cmp eax,1 je .leftbtn .not_pressed: ; Левая кнопка не нажата, запомним текущие координаты и будем ждать события mov [mouse_pressed],0 ; мышь не нажата mov eax,37 ; получим координаты mov ebx,1 int 0x40 mov ebx,eax shr eax,16 and ebx,0xffff mov [old_x],eax ; запомним их mov [old_y],ebx jmp still .leftbtn: ; Левая кнопка нажата, надо это записать! mov [mouse_pressed],1 ; Получим координаты курсора мыши (относительно окна) mcall 37,1 ; получить состояние мыши ; Переделаем их так, чтобы они были в разных регистрах, т.е. eax и ebx mov ebx,eax shr eax,16 and ebx,0xffff ; Подготовим параметры для функции рисования линии mov ecx,[old_x] ; для начала загрузим старые координаты mov edx,[old_y] mov [old_x],eax ; теперь сохраним текущие в старые mov [old_y],ebx shl ecx,16 ; в верхнее слово начальные (текущие) координаты shl edx,16 add eax,ecx ; а в нижнее слово конечные, т.е. старые add ebx,edx mov ecx,ebx ; поменяем регистры так, как эту нужно 38 функции mov ebx,eax mov eax,38 ; номер функции в eax mov edx,[active_color] ; в edx цвет int 0x40 ;  - попробуйте поставить другие значения (00090001) mov edi,0x00010001 ; чтобы линия не была слишком тонкой, add ebx,edi ; нарисуем рядом еще 3! int 0x40 add ecx,edi int 0x40 sub ebx,edi int 0x40 sub ebx,edi ; ну а чтобы смотрелось совсем круто, int 0x40 ; дорисуем еще 5! sub ecx,edi int 0x40 sub ecx,edi int 0x40 add ebx,edi int 0x40 add ebx,edi int 0x40 jmp still ;****************************************************************************** save_canvas: mov eax,[proc_info.box.width] add eax,[workarea.cx] mov ebx,[proc_info.box.height] add ebx,[workarea.cy] jmp still ;****************************************************************************** ; ********************************************* ; ******* ОПРЕДЕЛЕНИЕ И ОТРИСОВКА ОКНА ******* ; ********************************************* draw_window: mcall 48,3,sc,sizeof.system_colors ; ПОДГРУЖАЕМ СИСТЕМНЫЕ ЦВЕТА mcall 12, 1 ; начало отрисовки окна mov edx, [sc.work] or edx, 0x33000000 mcall 0, (100 shl 16)+400, (100 shl 16)+300, , , title ; рисуем окно mcall 12, 1 mcall 9,proc_info,-1 ; получим информацию о своем потоке mov eax,[proc_info.box.width] ; настроим размер рабочей области sub eax,20 ; (х размер окна - 20) mov [workarea.sx],eax mov eax,[proc_info.box.height] sub eax,63 ; (у размер - 63) mov [workarea.sy],eax cmp [proc_info.box.height],80 jb .finish mov eax, 8 mov edx, 1 ; создаём кнопки выбора цвета: mov ebx,10*65536+15 ; начальная x координата и размер mov ecx, 7*65536+15 ; начальная y координата & size .new_button: inc edx ; идентификатор++; mov esi,[btn_colors-8+edx*4] ; цвет кнопки int 0x40 ; ставим кнопку add ebx,18*65536 ; следующая кнопка правее на 12 cmp edx,9 ; сравниваем edx (идентификатор) с 9 jbe .new_button ; если меньше или равно -> ещё одну кпоку mov eax,13 ; чистим "холст" - клиентскую область mov ebx,[workarea.cx] mov ecx,[workarea.cy] shl ebx,16 shl ecx,16 add ebx,[workarea.sx] add ecx,[workarea.sy] mov edx,0xffffff mcall 13 .finish: ret ;****************************************************************************** ; начало области инициализированных данных ; если кто ещё не знает, что значит "инициализированные", то поясняю: ; это те данные, которым присвоено начальное значение ;data title db 'Simple Paint v0.3',0 mouse_pressed db 0 ; показывает, нажата ли была мышь в предыдущий момент ; цвета кнопок btn_colors: dd 0xdddddd ; white dd 0x444444 ; black dd 0x00dd00 ; green dd 0x0000dd ; blue dd 0xdd0000 ; red dd 0xdd00dd ; magenta dd 0xdddd00 ; yellow dd 0x00dddd ; cyan dd 0x559955 ; warm green ; цвета кисти (в том же порядке, что и цвета кнопок) colors: dd 0xffffff ; белый dd 0x000000 ; черный dd 0x00ff00 ; зеленый dd 0x0000ff ; синий dd 0xff0000 ; красный dd 0xff00ff ; пурпурный dd 0xffff00 ; желтый dd 0x00ffff ; голубой dd 0x77bb77 ; теплый зеленый ;****************************************************************************** ; а вот тут начинается область НЕинициализированных данных, т.е. ; здесь данным значения не присвоены. В отличие от иниц., не увеличивают размер ; файла I_END: active_color dd ? ; активный цвет old_x dd ? ; старые координаты мыши old_y dd ? workarea: ; координаты и размеры клиентской области .cx dd ? ; c - коодинаты .cy dd ? .sx dd ? ; s - размеры .sy dd ? sc system_colors ; системные цвета proc_info process_information ; информация о процессе restflag dd ? canvas rb 800*600*3 E_END: