Subversion Repositories Kolibri OS

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
3497 yogev_ezra 1
;*********************************
2
;*                               *
3
;*    PAINT 0.02 для MenuetOS    *
4
;*                               *
5
;*     Компилировать FASM'ом     *
6
;*                               *
7
;*********************************
8
 
9
;******************************************************************************
10
; Эту программу не нужно серьезно рассматривать - это всего лишь пример,
11
; в котором показано, как работать с некоторыми системными функциями МеОС,
12
; но никак не нормальный графический редактор. Код программы ОЧЕНЬ простой,
13
; и она предназначена для тех, кто только начинает изучать ассемблер,
14
; поэтому я стремился сделать его как можно более понятным.
15
; Тем не менее, код довольно неплохо оптимизирован, хотя это немного
16
; может затруднить его понимание. Я постарался тщательно прокомментировать
17
; сложные места. Кстати, идея программы принадлежит не мне, а Sniper'у, для
18
; которого вобщем-то все и писалось.
19
;   Удачи в изучении асма!
20
;   Иван Поддубный, ivan-yar@bk.ru
21
;******************************************************************************
22
 
23
; Подключаем необходимые макросы
24
include 'macros.inc'
25
 
26
;******************************************************************************
27
 
28
; НАЧАЛО ПРОГРАММЫ
29
meos_app_start
30
; ОБЛАСТЬ КОДА
31
code
32
    mov  eax,40       ; сообщим системе, какие события будем обрабатывать
33
    mov  ebx,0100101b ; маска событий - перерисовка (1) + кнопка (3) + мышь (6
34
    int  0x40         ; эта команда вызывает системную функцию
35
 
36
    mov  [workarea.cx],10  ; координаты рабочей (клиентской) области
37
    mov  [workarea.cy],45  ; для рисования
38
 
39
red:
40
    call draw_window   ; вызываем процедуру отрисовки окна
41
 
42
still:            ; ГЛАВНЫЙ ЦИКЛ ПРОГРАММЫ - ЦИКЛ ОБРАБОТКИ СООБЩЕНИЙ
43
 
44
    mov  eax,10   ; функция 10 - ждать события; программа останавливается на
45
    int  0x40     ; следующая команда не будет выполнена до тех пор, пока
46
                  ; не произойдёт событие
47
 
48
    ; теперь регистр eax содержит номер события
49
    ; поочередно сравним его со всеми возможными значениями, чтобы вызвать
50
    ; нужный обработчик
51
 
52
    cmp  eax,1    ; перерисовать окно ?
53
    je   red      ; если регистр eax равен единице, то переходим на метку red
54
    cmp  eax,3    ; нажата кнопка ?
55
    je   button
56
    cmp  eax,6    ; мышь?
57
    je   mouse
58
 
59
    jmp  still    ; если произошло событие, которое мы не обрабатываем,
60
                  ; просто возвращаемся к началу цикла, хотя такого быть
61
                  ; не должно! Т.е. если эту команду отсюда убрать, то
62
                  ; ничего страшного не случится.
63
 
64
;******************************************************************************
65
 
66
  button:        ; обработчик нажатия кнопки в окне программы
67
    mov  eax,17  ; функция N17 - получить идентификатор нажатой кнопки
68
    int  0x40
69
 
70
    ; теперь в регистре ah содержится идентификатор.
71
 
72
    shr  eax,8   ; ah -> al (сдвиг на 8 бит вправо)
73
 
74
    dec  al       ; идентификатор_кнопки--;
75
    jnz  .noclose ; если результат предыдущей команды равен нулю, закрываемся
76
                  ; иначе - идём на метку noclose
77
 
78
    or   eax,-1  ; выход из программы
79
    int  0x40
80
 
81
  .noclose:
82
    ; если мы сюда попали, значит идентификатор кнопки не был равен нулю...
83
    ; теперь у нас в eax содержится (номер цветной кнопки - 1),
84
    ; т.е или 1, или 2, ... ,или 5
85
 
86
    ; уменьшим на 1:
87
    dec  eax
88
 
89
    ; вот эта вот команда извлекает в eax двойное слово по адресу colors+eax*4
90
    ; где colors - смещение метки colors, после которой идет последовательность
91
    ; цветов, eax*4 - номер цвета, умноженный на 4, т.к. на один цвет нужно
92
    ; четыре байта.
93
    mov  eax,[colors+eax*4]
94
 
95
    ; теперь мы установим цвет, содержащийся в регистре eax как основной:
96
    mov  [active_color],eax
97
 
98
    ; ну вот, собственно, и всё, что от нас требовалось ;)
99
    ; вернёмся к началу цикла обработки событий
100
    jmp  still
101
 
102
;******************************************************************************
103
 
104
  mouse:          ; обработчик мыши
105
    mov  eax,37             ; сначала получим текущие координаты мыши
106
    mov  ebx,1
107
    int  0x40
108
 
109
    mov  ebx,eax            ; преобразуем их
110
    shr  eax,16             ;   eax=x;
111
    and  ebx,0xffff         ;   ebx=y;
112
 
113
    cmp  ebx,22
114
    jb   save_canvas
115
 
116
    sub  eax,[workarea.cx]  ; x-=[workarea.cx]
117
    cmp  eax,0              ; если мышь левее клиентской области,
118
    jle  .not_pressed       ;   ничего не рисуем
119
    cmp  eax,[workarea.sx]  ; если мышь правее...
120
    jae  .not_pressed
121
 
122
    sub  ebx,[workarea.cy]
123
    cmp  ebx,0              ; ...выше...
124
    jle  .not_pressed
125
    cmp  ebx,[workarea.sy]  ; ...ниже...
126
    jae  .not_pressed
127
 
128
    ; какие кнопки нажаты?
129
    mov  eax,37
130
    mov  ebx,2
131
    int  0x40
132
 
133
    ; если левая кнопка (т.е. eax = 1), те пойдём дальше
134
    cmp  eax,1
135
    je   .leftbtn
136
 
137
  .not_pressed:
138
    ; Левая кнопка не нажата, запомним текущие координаты и будем ждать события
139
    mov  [mouse_pressed],0   ; мышь не нажата
140
    mov  eax,37              ; получим координаты
141
    mov  ebx,1
142
    int  0x40
143
    mov  ebx,eax
144
    shr  eax,16
145
    and  ebx,0xffff
146
    mov  [old_x],eax         ; запомним их
147
    mov  [old_y],ebx
148
    jmp  still
149
 
150
  .leftbtn:
151
    ; Левая кнопка нажата, надо это записать!
152
    mov  [mouse_pressed],1
153
 
154
    ; Получим координаты курсора мыши (относительно окна)
155
    mov  eax,37              ; функция 37 - получить состояние мыши
156
    mov  ebx,1               ; подфункция 1
157
    int  0x40
158
 
159
    ; Переделаем их так, чтобы они были в разных регистрах, т.е. eax и ebx
160
    mov  ebx,eax
161
    shr  eax,16
162
    and  ebx,0xffff
163
 
164
    ; Подготовим параметры для функции рисования линии
165
    mov  ecx,[old_x]     ; для начала загрузим старые координаты
166
    mov  edx,[old_y]
167
    mov  [old_x],eax     ; теперь сохраним текущие в старые
168
    mov  [old_y],ebx
169
    shl  ecx,16          ; в верхнее слово начальные (текущие) координаты
170
    shl  edx,16
171
    add  eax,ecx         ; а в нижнее слово конечные, т.е. старые
172
    add  ebx,edx
173
 
174
    mov  ecx,ebx             ; поменяем регистры так, как эту нужно 38 функции
175
    mov  ebx,eax
176
    mov  eax,38              ; номер функции в eax
177
    mov  edx,[active_color]  ; в edx цвет
178
    int  0x40
179
 
180
;             - попробуйте поставить другие значения (00090001)
181
    mov  edi,0x00010001      ; чтобы линия не была слишком тонкой,
182
    add  ebx,edi             ; нарисуем рядом еще 3!
183
    int  0x40
184
    add  ecx,edi
185
    int  0x40
186
    sub  ebx,edi
187
    int  0x40
188
 
189
    sub  ebx,edi             ; ну а чтобы смотрелось совсем круто,
190
    int  0x40                ; дорисуем еще 5!
191
    sub  ecx,edi
192
    int  0x40
193
    sub  ecx,edi
194
    int  0x40
195
    add  ebx,edi
196
    int  0x40
197
    add  ebx,edi
198
    int  0x40
199
 
200
  jmp still
201
 
202
;******************************************************************************
203
 
204
save_canvas:
205
    mov  eax,[process.x_size]
206
    add  eax,[workarea.cx]
207
    mov  ebx,[process.y_size]
208
    add  ebx,[workarea.cy]
209
 
210
    jmp still
211
 
212
;******************************************************************************
213
 
214
;   *********************************************
215
;   *******  ОПРЕДЕЛЕНИЕ И ОТРИСОВКА ОКНА *******
216
;   *********************************************
217
 
218
draw_window:
219
 
220
    mov  eax,48                    ; ПОДГРУЖАЕМ СИСТЕМНЫЕ ЦВЕТА
221
    mov  ebx,3
222
    mov  ecx,sc
223
    mov  edx,sizeof.system_colors
224
    int  0x40
225
 
226
    mov  eax,12      ; функция 12: сообщить ОС об отрисовке окна
227
    mov  ebx,1       ; 1, начинаем рисовать
228
    int  0x40
229
 
230
                                   ; СОЗДАЁМ ОКНО
231
    mov  eax,0                     ; функция 0 : определить и отрисовать окно
232
    mov  ebx,100*65536+400         ; [x старт] *65536 + [x размер]
233
    mov  ecx,100*65536+300         ; [y старт] *65536 + [y размер]
234
    mov  edx,[sc.work]             ; цвет рабочей области  RRGGBB,8->color gl
235
    or   edx,0x02000000
236
    mov  esi,[sc.grab]             ; цвет полосы заголовка RRGGBB,8->color gl
237
    or   esi,0x80000000
238
    mov  edi,[sc.frame]            ; цвет рамки            RRGGBB
239
    int  0x40
240
 
241
    mov  eax,9                     ; получим информацию о себе
242
    mov  ebx,process
243
    mov  ecx,-1
244
    int  0x40
245
 
246
    mov  eax,[process.x_size]      ; настроим размер рабочей области
247
    add  eax,-20                   ;   (х размер окна - 20)
248
    mov  [workarea.sx],eax         ;
249
    mov  eax,[process.y_size]      ;
250
    add  eax,-60                   ;   (у размер - 60)
251
    mov  [workarea.sy],eax         ;
252
 
253
                                   ; ЗАГОЛОВОК ОКНА
254
    mov  eax,4                     ; функция 4 : написать в окне текст
255
    mov  ebx,8*65536+8             ; [x] *65536 + [y]
256
    mov  ecx,[sc.grab_text]        ; цвет
257
    or   ecx,0x10000000            ; шрифт
258
    mov  edx,header                ; адрес строки
259
    mov  esi,header_len            ; и её длина
260
    int  0x40
261
 
262
                                   ; КНОПКА ЗАКРЫТИЯ ОКНА
263
    mov  eax,8                     ; функция 8 : определить и нарисовать кнопку
264
;   mov  ebx,(300-19)*65536+12     ; [x старт] *65536 + [x размер]
265
    mov  ebx,[process.x_size]
266
    add  ebx,-19
267
    shl  ebx,16
268
    add  ebx,12
269
    mov  ecx,5*65536+12            ; [y старт] *65536 + [y размер]
270
    mov  edx,1                     ; идентификатор кнопки
271
    mov  esi,[sc.grab_button]      ; цвет кнопки RRGGBB
272
    int  0x40
273
 
274
    cmp  [process.y_size],80
275
    jb   .finish
276
 
277
    ; создаём кнопки выбора цвета:
278
    mov  ebx,10*65536+10           ; начальная x координата и размер
279
    mov  ecx,27*65536+10           ; начальная y координата & size
280
 .new_button:
281
    inc  edx                       ; идентификатор++;
282
    mov  esi,[btn_colors-8+edx*4]  ; цвет кнопки
283
    int  0x40                      ; ставим кнопку
284
    add  ebx,12*65536              ; следующая кнопка правее на 12
285
    cmp  edx,9                     ; сравниваем edx (идентификатор) с 9
286
    jbe  .new_button               ; если меньше или равно -> ещё одну кпоку
287
 
288
    mov  eax,13                    ; чистим "холст" - клиентскую область
289
    mov  ebx,[workarea.cx]
290
    mov  ecx,[workarea.cy]
291
    shl  ebx,16
292
    shl  ecx,16
293
    add  ebx,[workarea.sx]
294
    add  ecx,[workarea.sy]
295
    mov  edx,0xffffff
296
    int  0x40
297
 
298
 .finish:
299
    mov  eax,12      ; сообщаем системе о завершении отрисовки окна
300
    mov  ebx,2
301
    int  0x40
302
 
303
    ret
304
 
305
;******************************************************************************
306
; начало области инициализированных данных
307
; если кто ещё не знает, что значит "инициализированные", то поясняю:
308
; это те данные, которым присвоено начальное значение
309
data
310
 
311
header:                  ; строка заголовка
312
   db  'PAINT v0.2 for MenuetOS'
313
header_len = $ - header  ; и её длина
314
 
315
   mouse_pressed   db  0 ; показывает, нажата ли была мышь в предыдущий момент
316
 
317
; цвета кнопок
318
btn_colors:
319
   dd 0xdddddd ; white
320
   dd 0x444444 ; black
321
   dd 0x00dd00 ; green
322
   dd 0x0000dd ; blue
323
   dd 0xdd0000 ; red
324
   dd 0xdd00dd ; magenta
325
   dd 0xdddd00 ; yellow
326
   dd 0x00dddd ; cyan
327
   dd 0x559955 ; warm green
328
 
329
; цвета кисти (в том же порядке, что и цвета кнопок)
330
colors:
331
   dd 0xffffff ; белый
332
   dd 0x000000 ; черный
333
   dd 0x00ff00 ; зеленый
334
   dd 0x0000ff ; синий
335
   dd 0xff0000 ; красный
336
   dd 0xff00ff ; пурпурный
337
   dd 0xffff00 ; желтый
338
   dd 0x00ffff ; голубой
339
   dd 0x77bb77 ; теплый зеленый
340
 
341
;******************************************************************************
342
; а вот тут начинается область НЕинициализированных данных, т.е.
343
; здесь данным значения не присвоены. В отличие от иниц., не увеличивают размер
344
; файла
345
 
346
udata
347
 
348
   active_color    dd  ?           ; активный цвет
349
 
350
   old_x           dd  ?           ; старые координаты мыши
351
   old_y           dd  ?
352
 
353
   workarea:                       ; координаты и размеры клиентской области
354
       .cx     dd  ?               ;   c - коодинаты
355
       .cy     dd  ?
356
       .sx     dd  ?               ;   s - размеры
357
       .sy     dd  ?
358
 
359
   sc          system_colors       ; системные цвета
360
   process     process_information ; информация о процессе
361
 
362
   restflag    dd  ?
363
   canvas      rb  800*600*3
364
 
365
meos_app_end