1 /* Part of XPCE --- The SWI-Prolog GUI toolkit
2
3 Author: Jan Wielemaker and Anjo Anjewierden
4 E-mail: jan@swi.psy.uva.nl
5 WWW: http://www.swi.psy.uva.nl/projects/xpce/
6 Copyright (c) 1985-2002, University of Amsterdam
7 All rights reserved.
8
9 Redistribution and use in source and binary forms, with or without
10 modification, are permitted provided that the following conditions
11 are met:
12
13 1. Redistributions of source code must retain the above copyright
14 notice, this list of conditions and the following disclaimer.
15
16 2. Redistributions in binary form must reproduce the above copyright
17 notice, this list of conditions and the following disclaimer in
18 the documentation and/or other materials provided with the
19 distribution.
20
21 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
24 FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
25 COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
26 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
27 BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
28 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
29 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
31 ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
32 POSSIBILITY OF SUCH DAMAGE.
33 */
34
35 #include <h/kernel.h>
36 #include <h/graphics.h>
37
38 static status
initialisePopupGesture(PopupGesture g,PopupObj popup,Name button,Modifier modifier)39 initialisePopupGesture(PopupGesture g, PopupObj popup,
40 Name button, Modifier modifier)
41 { if ( isDefault(popup) )
42 popup = NIL;
43
44 initialiseGesture((Gesture) g, button, modifier);
45 assign(g, popup, popup);
46
47 succeed;
48 }
49
50
51 static status
cancelPopupGesture(PopupGesture g,EventObj ev)52 cancelPopupGesture(PopupGesture g, EventObj ev)
53 { assign(g, current, NIL);
54 assign(g, context, NIL);
55
56 return cancelGesture((Gesture)g, ev);
57 }
58
59
60 static status
updatePopupGesture(PopupGesture g,EventObj ev)61 updatePopupGesture(PopupGesture g, EventObj ev)
62 { PopupObj p;
63 Any rec = getMasterEvent(ev);
64
65 DEBUG(NAME_popup, Cprintf("updatePopupGesture(): rec=%s\n", pp(rec)));
66
67 if ( notNil(g->popup) )
68 { if ( instanceOfObject(g->popup, ClassFunction) )
69 { TRY( p = getForwardReceiverFunction((Function) g->popup, rec,
70 rec, ev, EAV) );
71 TRY( p = checkType(p, nameToType(NAME_popup), g));
72 } else
73 p = g->popup;
74 } else
75 { if ( !(p = get(rec, NAME_popup, EAV)) ||
76 !instanceOfObject(p, ClassPopup) )
77 fail;
78 }
79
80 assign(g, current, p);
81 if ( isNil(g->context) )
82 assign(g, context, notNil(p->context) ? p->context : rec);
83 send(p, NAME_update, g->context, EAV);
84
85 if ( p->active == OFF || emptyChain(p->members) )
86 { send(g, NAME_cancel, ev, EAV);
87 fail;
88 }
89
90 succeed;
91 }
92
93
94 static status
eventPopupGesture(PopupGesture g,EventObj ev)95 eventPopupGesture(PopupGesture g, EventObj ev)
96 { if ( g->status == NAME_active && isUpEvent(ev) )
97 { PceWindow sw;
98
99 if ( !(sw = getWindowGraphical(ev->receiver)) )
100 sw = ev->window;
101
102 if ( notNil(g->current) && g->current->displayed == OFF )
103 { send(g->current, NAME_open, ev->receiver,
104 getAreaPositionEvent(ev, DEFAULT), EAV);
105 attributeObject(g, NAME_Stayup, ON);
106 grabPointerWindow(sw, ON);
107 focusWindow(sw, ev->receiver, (Recogniser) g, g->cursor, NIL);
108 } else if ( valInt(getClickTimeEvent(ev)) < 400 &&
109 getAttributeObject(g, NAME_Stayup) != ON )
110 { attributeObject(g, NAME_Stayup, ON);
111 grabPointerWindow(sw, ON);
112 focusWindow(sw, ev->receiver, (Recogniser) g, g->cursor, NIL);
113 } else
114 { send(g, NAME_terminate, EAV);
115 if ( isNil(g->current) )
116 { grabPointerWindow(sw, OFF);
117 focusWindow(sw, NIL, NIL, NIL, NIL);
118 deleteAttributeObject(g, NAME_Stayup);
119 assign(g, status, NAME_inactive);
120 }
121 }
122
123 succeed;
124 } else if ( notNil(g->current) && g->current->displayed == ON )
125 return postEvent(ev, (Graphical) g->current, DEFAULT);
126
127 if ( eventGesture(g, ev) )
128 succeed;
129
130 if ( g->status == NAME_active && isAEvent(ev, NAME_keyboard) )
131 { Name key;
132
133 TRY(updatePopupGesture(g, ev));
134 key = characterName(getIdEvent(ev));
135
136 if ( send(g->current, NAME_key, key, EAV) )
137 { Any context = g->context;
138 PopupObj current = g->current;
139
140 assign(g, context, NIL);
141 assign(g, current, NIL);
142
143 send(current, NAME_execute, context, EAV);
144 succeed;
145 } else
146 send(g, NAME_cancel, ev, EAV);
147 }
148
149 fail;
150 }
151
152
153 /********************************
154 * GESTURE BEHAVIOUR *
155 ********************************/
156
157 static status
verifyPopupGesture(PopupGesture g,EventObj ev)158 verifyPopupGesture(PopupGesture g, EventObj ev)
159 { return updatePopupGesture(g, ev);
160 }
161
162
163 static status
initiatePopupGesture(PopupGesture g,EventObj ev)164 initiatePopupGesture(PopupGesture g, EventObj ev)
165 { if ( isNil(g->max_drag_distance) )
166 { send(g->current, NAME_open, ev->receiver,
167 getAreaPositionEvent(ev, DEFAULT), EAV);
168 postEvent(ev, (Graphical) g->current, DEFAULT);
169 }
170
171 succeed;
172 }
173
174
175 static status
dragPopupGesture(PopupGesture g,EventObj ev)176 dragPopupGesture(PopupGesture g, EventObj ev)
177 { if ( notNil(g->current) && g->current->displayed == ON )
178 { DEBUG(NAME_popup, Cprintf("Posting drag to %s\n", pp(g->current)));
179 return postEvent(ev, (Graphical) g->current, DEFAULT);
180 } else
181 { if ( notNil(g->max_drag_distance) )
182 { PceWindow sw;
183
184 if ( instanceOfObject((sw=ev->window), ClassWindow) &&
185 valInt(getDistanceEvent(sw->focus_event, ev)) >
186 valInt(g->max_drag_distance) )
187 send(g, NAME_cancel, ev, EAV);
188 }
189 }
190
191 fail;
192 }
193
194
195 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
196 To avoid dangling references, the context and current are first copied
197 to local variables.
198 - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
199
200 static status
terminatePopupGesture(PopupGesture g,EventObj ev)201 terminatePopupGesture(PopupGesture g, EventObj ev)
202 { Any context = g->context;
203 PopupObj current = g->current;
204
205 if ( notNil(current) )
206 { postEvent(ev, (Graphical) current, DEFAULT);
207
208 if ( current->displayed == OFF ) /* for stayup */
209 { PceWindow sw;
210
211 if ( !(sw = getWindowGraphical(ev->receiver)) )
212 sw = ev->window;
213
214 assign(g, context, NIL);
215 assign(g, current, NIL);
216
217 grabPointerWindow(sw, OFF);
218 send(current, NAME_execute, context, EAV);
219 focusWindow(sw, NIL, NIL, NIL, NIL);
220 }
221 }
222
223 succeed;
224 }
225
226
227 /*******************************
228 * CLASS DECLARATION *
229 *******************************/
230
231 /* Type declarations */
232
233 static char *T_initialise[] =
234 { "popup=[popup|function]", "button=[button_name]", "modifier=[modifier]" };
235
236 /* Instance Variables */
237
238 static vardecl var_popupGesture[] =
239 { IV(NAME_popup, "popup|function*", IV_BOTH,
240 NAME_popup, "Popup displayed"),
241 IV(NAME_current, "popup*", IV_NONE,
242 NAME_popup, "Currently visible popup"),
243 IV(NAME_context, "any", IV_BOTH,
244 NAME_context, "Context to be send with the ->execute"),
245 IV(NAME_maxDragDistance, "int*", IV_BOTH,
246 NAME_cancel, "Cancel after dragging this far")
247 };
248
249 /* Send Methods */
250
251 static senddecl send_popupGesture[] =
252 { SM(NAME_drag, 1, "event", dragPopupGesture,
253 DEFAULT, "Pass drag events to popup"),
254 SM(NAME_initialise, 3, T_initialise, initialisePopupGesture,
255 DEFAULT, "Create from popup, button and modifier"),
256 SM(NAME_initiate, 1, "event", initiatePopupGesture,
257 DEFAULT, "Show popup"),
258 SM(NAME_terminate, 1, "event", terminatePopupGesture,
259 DEFAULT, "Unshow popup and execute selected item"),
260 SM(NAME_verify, 1, "event", verifyPopupGesture,
261 DEFAULT, "Verify popup can be activated"),
262 SM(NAME_cancel, 1, "event", cancelPopupGesture,
263 NAME_cancel, "Cancel this gesture and try the next"),
264 SM(NAME_event, 1, "event", eventPopupGesture,
265 NAME_accelerator, "Handle accelerators")
266 };
267
268 /* Get Methods */
269
270 #define get_popupGesture NULL
271 /*
272 static getdecl get_popupGesture[] =
273 {
274 };
275 */
276
277 /* Resources */
278
279 static classvardecl rc_popupGesture[] =
280 { RC(NAME_button, "button_name", "right",
281 "Active on which button (right)"),
282 RC(NAME_cursor, "cursor", "right_ptr",
283 "Cursor while active"),
284 RC(NAME_modifier, "modifier", "",
285 "Condition on shift, control and meta"),
286 RC(NAME_maxDragDistance, "int*", "5",
287 "Cancel after dragging this far")
288 };
289
290 /* Class Declaration */
291
292 static Name popupGesture_termnames[] = { NAME_popup, NAME_button, NAME_modifier };
293
294 ClassDecl(popupGesture_decls,
295 var_popupGesture, send_popupGesture,
296 get_popupGesture, rc_popupGesture,
297 3, popupGesture_termnames,
298 "$Rev$");
299
300 status
makeClassPopupGesture(Class class)301 makeClassPopupGesture(Class class)
302 { return declareClass(class, &popupGesture_decls);
303 }
304
305
306
307 Recogniser
popupGesture()308 popupGesture()
309 { if ( GESTURE_popup == NULL )
310 GESTURE_popup = globalObject(NAME_PopupGesture, ClassPopupGesture, EAV);
311
312 return (Recogniser) GESTURE_popup;
313 }
314
315