desktop.anubis
14.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
The Anubis/Paradize Project.
The desktop widget.
Copyright (c) Alain Prouté 2004-2005.
Authors: Alain Prouté
Olivier Duvernois
read tools/basis.anubis
read widget.anubis
This is the 'desktop' widget. A 'desktop' is just a rectangular area on top of which
several widgets may be stacked in arbitrary positions and order. Each widget is put
into an invisible so-called 'support'. Each support may move within the desktop, and
may receives commands through a variable containing a:
public type WidgetSupportCommand:
hide, // hide the widget in the support (if it is visible)
show, // show the widget in the support (if it is not visible)
expose, // move the support to top of stack
delete. // delete the support
The desktop itself may also receive commands through a variable. These commands have the
following type:
public type WidgetDesktopCommand:
none, // may be used as initial value
add (Int32 x, // add a new support at position (x,y)
Int32 y,
Int32 z, // and stacking order z
Widget,
Var(WidgetSupportCommand)), // the initial command will be executed
delete_all. // delete all supports
The initial stack of widgets is given as a list of 'WidgetSupport', the head of list
being on top of the stack:
public type WidgetSupport:
support (Int32 x, // position relative to desktop
Int32 y,
Widget content,
Var(WidgetSupportCommand) command).
The desktop also has a background color, and a non mandatory background widget. The
background handler is executed when the background (not the background widget) is
clicked. The desktop is created by:
public define Widget
create_desktop
(
Int32 width_of_desktop,
Int32 height_of_desktop,
RGB background_color,
Maybe(Widget) background_widget,
One -> WidgetAnswer background_handler,
List(WidgetSupport) stack_of_widgets,
Var(WidgetDesktopCommand) commands
).
If one of the widgets in the stack is transmitted a mouse left down click event and
does not handle it, the desktop captures the mouse. While the mouse remains captured,
moving the mouse moves the widget. When the mouse is liberated, the widget is put on
top of the stack if it has not been moved (actually, if its final position is the same
as its initial position).
--- That's all for the public part ! --------------------------------------------------
read tools.anubis
*** (1) Setting positions of childs in a desktop.
The initial list of childs is of type List(WidgetSupport). However, since each widget
contains its own position (absolute and relative to its father), the relative position
of a child relative to the desktop will be used as the official source for the
position. Hence, when the desktop is created, the list of 'WidgetSupport' (within which
all widgets have relative position (0,0)), is transformed into a list of 'Widget', with
relative positions correctly set. Also a monitor is attached to the command variable.
type Child:
child(Var(Maybe(MonitoringTicket(WidgetSupportCommand))),
Var(WidgetSupportCommand),
Widget).
define List(Child)
prepare_childs
(
List(WidgetSupport) l
) =
if l is
{
[ ] then [ ],
[supp1 . supps] then
if supp1 is support(x,y,wid,vc) then
store_relative_position(wid,position(x,y));
[child(var(failure),vc,wid) . prepare_childs(supps)]
}.
Now, setting the position of a child amounts to setting its position to its current
position. The background widget is centered within the desktop.
define One
set_childs_positions
(
WidgetPositionToolBox ptb,
Int32 width, // of desktop
Int32 height,
List(Child) childs,
Maybe(Widget) mbbgwidget
) =
if childs is
{
[ ] then if mbbgwidget is
{
failure then unique,
success(bgw) then
if get_size(bgw)(unique) is (w,h) then
set_position(bgw)(ptb,position((width-w)>>1,(height-h)>>1))
},
[c1 . cs] then if c1 is child(tick,vc,w1) then
set_position(w1)(ptb,get_position(w1)(unique));
set_childs_positions(ptb,width,height,cs,mbbgwidget)
}.
*** (2) Desktop redraw function.
Redrawing the desktop consists in redrawing the first widget of the stack, then the
second widget of the stack, but only outside the first one, and so on to the background
widget and the background color.
define One
redraw_desktop
(
WidgetDrawToolBox dtb,
RGB bcolor, // background color
Maybe(Widget) backw, // background widget
List(Child) stack, // stack of child widgets
List(WidgetRectangle) where // where to draw
) =
if stack is
{
[ ] then
if backw is
{
failure then
forget(map((WidgetRectangle r) |-> draw(dtb)(r,bcolor),where)),
success(wid) then
forget(map((WidgetRectangle r) |-> redraw(wid)(dtb,r),where));
if get_position(wid)(unique) is position(x1,y1) then
if get_size(wid)(unique) is (w1,h1) then
redraw_desktop(dtb,bcolor,failure,[],where - rect(x1,y1,x1+w1,y1+h1))
},
[c1 . cs] then if c1 is child(ticket,cv1,wid1) then
if *cv1 is
{
hide then unique,
show then forget(map((WidgetRectangle r) |-> redraw(wid1)(dtb,r),where)),
expose then forget(map((WidgetRectangle r) |-> redraw(wid1)(dtb,r),where)),
delete then alert,
};
if *cv1 = hide
then
redraw_desktop(dtb,bcolor,backw,cs,where)
else
(if get_position(wid1)(unique) is position(x1,y1) then
if get_size(wid1)(unique) is (w1,h1) then
redraw_desktop(dtb,bcolor,backw,cs,where - rect(x1,y1,x1+w1,y1+h1)))
}.
*** (3) Desktop event handler.
The next function removes the n-th element from a list of childs.
define List($T)
remove_nth
(
Int32 n,
List($T) l
) =
if n < 0 then alert else
if l is
{
[ ] then alert,
[w1 . ws] then
if n = 0
then ws
else [w1 . remove_nth(n-1,ws)]
}.
Below is the event handler for the captured mouse. It is called with the initial
position of the mouse (at the moment it was captured), and its previous position (taken
from the previous mouse event). The widget of the stack which has been selected is also
given, together with its depth in the stack. Finally, the variable holding the whole
stack is also given. This is useful when putting a widget on top of the stack.
While the mouse is not liberated, the selected widget is just moved within the desktop
(following the mouse movements). When the mouse is liberated, we compare the current
position with the initial position. If they are equal the widget is put on top of the
stack.
define (KeyboardState,WidgetMouseCapturedEvent) -> WidgetAnswer
captured_mouse_handler
(
Int32 ix, // initial mouse position
Int32 iy,
Var(Int32) px, // previous mouse position
Var(Int32) py,
Int32 n, // depth of 'wid' in stack
Child ch, // mouse impacted widget
Var(List(Child)) childs_loc
) =
(KeyboardState ks, WidgetMouseCapturedEvent e) |->
if e is
{
moved(x,y) then if ch is child(_,_,wid) then
if get_position(wid)(unique) is position(wx,wy) then
with dx = x-*px,
dy = y-*py,
nwx = wx+dx,
nwy = wy+dy,
store_relative_position(wid,position(nwx,nwy));
px <- x;
py <- y;
if get_size(wid)(unique) is (w,h) then
handled(union([rect(wx,wy,wx+w,wy+h),
rect(nwx,nwy,nwx+w,nwy+h)])),
liberated(x,y) then
if (x = ix & y = iy)
then (childs_loc <- [ch . remove_nth(n,*childs_loc)];
if ch is child(_,_,wid) then
if get_size(wid)(unique) is (w,h) then
if get_position(wid)(unique) is position(wx,wy) then
handled([rect(wx,wy,wx+w,wy+h)]))
else handled([])
}.
Below is a function used for dispatching the events amongh the widgets of the stack
(and the background widget). The coordinates of the mouse pointer are compared with the
rectangles of all widgets of the stack beginning by the top widget. The first widget in
the rectangle of which the mouse lies receives the event. If the event is not handled
by the widget, and if it is a left down click, the mouse is captured. If no widget in
the stack receives the event, the background widget (if any) is tryied out. If the
background widget does not receive the event, the background handler is called.
define WidgetAnswer
dispatch_event
(
WidgetEventToolBox etb,
WidgetNormalEvent e,
Int32 x,
Int32 y,
Int32 n, // current depth in stack
List(Child) childs,
Var(List(Child)) childs_loc,
Maybe(Widget) mbbgwidget,
One -> WidgetAnswer bghandler
) =
if childs is
{
[ ] then if mbbgwidget is
{
failure then bghandler(unique),
success(bgwid) then
if get_position(bgwid)(unique) is position(x1,y1) then
if get_size(bgwid)(unique) is (w1,h1) then
if (x1 =< x & x < x1+w1 & y1 =< y & y < y1+h1)
then main_event_handler(bgwid)(etb,e)
else dispatch_event(etb,e,x,y,n+1,[],childs_loc,failure,bghandler)
},
[ch1 . chs] then if ch1 is child(tv1,cv1,wid1) then
if *tv1 is
{
failure then
tv1 <- success(register_monitor(cv1,
(One u) |-> if *cv1 is
{
hide then forget(queue_event(etb,expose)),
show then forget(queue_event(etb,expose)),
expose then forget(queue_event(etb,expose)),
delete then unique
})),
success(_) then unique
};
if get_position(wid1)(unique) is position(x1,y1) then
if get_size(wid1)(unique) is (w1,h1) then
if (x1 =< x & x < x1+w1 & y1 =< y & y < y1+h1 & *cv1 /= hide)
then with answer = main_event_handler(wid1)(etb,e),
if answer is
{
not_handled(l) then if e is
{
mouse_gone then handled([]),
mouse_move(ks,x2,y2) then answer,
mouse_click(ks,mc,x2,y2) then if mc is
{
left_down then forget(capture_mouse(etb,
captured_mouse_handler(x2,y2,var(x2),var(y2),n,ch1,childs_loc)));
handled([]),
left_up then not_handled([]),
middle_down then not_handled([]),
middle_up then not_handled([]),
right_down then not_handled([]),
right_up then not_handled([])
}
}
handled(l) then answer,
resized then answer
}
else dispatch_event(etb,e,x,y,n+1,chs,childs_loc,mbbgwidget,bghandler)
}.
Finally, below is the event handler for the desktop.
define WidgetAnswer
desktop_event_handler
(
WidgetEventToolBox etb,
WidgetNormalEvent e,
Var(List(Child)) childs_loc,
Maybe(Widget) mbbgwidget,
One -> WidgetAnswer bghandler
) =
if e is
{
mouse_gone then handled([]),
mouse_move(ks,x,y) then dispatch_event(etb,e,x,y,0,*childs_loc,childs_loc,mbbgwidget,bghandler),
mouse_click(ks,mc,x,y) then dispatch_event(etb,e,x,y,0,*childs_loc,childs_loc,mbbgwidget,bghandler)
}.
*** (4) Creating the desktop.
We just have to prepare the childs as explained above, and put the result in a new
variable.
public define Widget
create_desktop
(
Int32 width,
Int32 height,
RGB bgcolor,
Maybe(Widget) mbbgwidget,
One -> WidgetAnswer bghandler,
List(WidgetSupport) stack,
Var(WidgetDesktopCommand) commands,
) =
with childs = var(prepare_childs(stack)),
create_widget(
/* set childs positions */
(WidgetPositionToolBox ptb) |-> set_childs_positions(ptb,width,height,*childs,mbbgwidget),
/* get size */
(One u) |-> (width,height),
/* redraw */
(WidgetDrawToolBox dtb) |->
redraw_desktop(dtb,
bgcolor,
mbbgwidget,
*childs,
[rect(0,0,width,height)]),
/* duplicate */
(One u) |-> create_desktop(width,height,bgcolor,mbbgwidget,bghandler,stack,commands),
/* change size */
(Int32 w, Int32 h) |-> unique,
/* handle normal events */
(WidgetEventToolBox etb, WidgetNormalEvent e) |->
desktop_event_handler(etb,e,childs,mbbgwidget,bghandler),
/* registrations */
[ ]
).