Initial revision
[ssr] / StraySrc / Glass / !Glass / c / wMousePtr
1 /*
2 * wMousePtr.c
3 *
4 * Finding the posisiton and changing the shape of the mouse pointer
5 *
6 * © 1994-1998 Straylight
7 */
8
9 /*----- Licensing note ----------------------------------------------------*
10 *
11 * This file is part of Straylight's Glass.
12 *
13 * Glass is free software; you can redistribute it and/or modify
14 * it under the terms of the GNU General Public License as published by
15 * the Free Software Foundation; either version 2, or (at your option)
16 * any later version.
17 *
18 * Glass is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU General Public License for more details.
22 *
23 * You should have received a copy of the GNU General Public License
24 * along with Glass. If not, write to the Free Software Foundation,
25 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
26 */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 /*
31 * ANSI standard headers
32 */
33
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37
38 /*
39 * Steel headers
40 */
41
42 #define _STDAPP
43 #define _LOWLVL
44 #include "steel/Steel.h"
45
46 #include "steel/pointer.h"
47
48 /*
49 * Glass headers
50 */
51
52 #include "gStruct.h"
53 #include "gMenus.h"
54 #include "gIcons.h"
55
56 #include "glass.h"
57 #include "gPrefs.h"
58 #include "window.h"
59 #include "_window.h"
60
61 /*----- Tables ------------------------------------------------------------*/
62
63 /*
64 * This table defines the mapping from drag zones to pointer shapes, to
65 * indicate to the user what operations are possible. There is some
66 * redundancy since there are some 'reserved' zone numbers, and they go up
67 * to &F. Each entry takes up 20 bytes, though, so things aren't exactly
68 * critical as a result of this.
69 */
70
71 static struct
72 {
73 char name[12];
74 int x;
75 int y;
76 }
77 window__ptr[]=
78 {
79 "",0,0, /* 0 */
80 "ptr_tb",7,5, /* 1 */
81 "ptr_tb",7,5, /* 2 */
82 "",0,0, /* 3 */
83 "ptr_lr",11,4, /* 4 */
84 "ptr_tlbr",9,5, /* 5 */
85 "ptr_trbl",9,5, /* 6 */
86 "ptr_hand",10,9, /* 7 */
87 "ptr_lr",11,4, /* 8 */
88 "ptr_trbl",9,5, /* 9 */
89 "ptr_tlbr",9,5, /* a */
90 "",0,0, /* b */
91 "",0,0, /* c */
92 "ptr_tb",7,5, /* d */
93 "ptr_lr",11,4, /* e */
94 "",0,0, /* f */
95 };
96
97 /*----- Main code ---------------------------------------------------------*/
98
99 /*
100 * BOOL window__inSizedBox(int px,int py,int x,int y,int d)
101 *
102 * Use
103 * Returns whether the point passed as (px,py) is contained within the
104 * square box with bottom-left corner (x,y) and side length d.
105 *
106 * Parameters
107 * As described above
108 *
109 * Returns
110 * TRUE if the point lies within the box, or FALSE if not
111 */
112
113 static BOOL window__inSizedBox(int px,int py,int x,int y,int d)
114 {
115 x&=~(wimpt_dx()-1);
116 y&=~(wimpt_dy()-1);
117 d=(d+wimpt_dy()-1) &~ (wimpt_dy()-1);
118 if (px>=x && py>=y && px<=x+d && py<=y+d)
119 return (TRUE);
120 else
121 return (FALSE);
122 }
123
124 /*
125 * int window__pointerInfo(glass_windPointer *w,int from,BOOL zones)
126 *
127 * Use
128 * Returns the icon number of the icon which the pointer is over. Guides
129 * are also checked for.
130 *
131 * Parameters
132 * glass_windPointer *w == the window to use info from
133 * int from == number to search down from (or -1 for the top). This is
134 * useful for selection, multiple clicks moving down overlapping icons.
135 * BOOL zones == search for drag zones. If this is set, the routine
136 * searches for selected icons only. If it is clear, zones are not
137 * checked.
138 *
139 * Returns
140 * An icon number, or -1 for the background.
141 */
142
143 #define HW window__HANDLEWIDTH
144
145 int window__pointerInfo(glass_windPointer *w,int from,BOOL zones)
146 {
147 int i;
148 wimp_mousestr m;
149 int ox;
150 int oy;
151 int tries;
152 wimp_box box;
153 BOOL found=FALSE;
154
155 /* --- Find out where the pointer is in the window --- */
156
157 wimpt_noerr(wimp_get_point_info(&m));
158 if (m.w!=w->h)
159 return (-1);
160 zones=zones&&!w->renumber;
161 ox=w->def->desc.w.box.x0-w->def->desc.w.scx;
162 oy=w->def->desc.w.box.y1-w->def->desc.w.scy;
163 m.x-=ox;
164 m.y-=oy;
165
166 /* --- Start the search from the right place --- *
167 *
168 * The search can be relative to an icon, for the depth-selection system
169 * to work. If this is the case, we do two passes through the icon array
170 * and start off half-way through. If we're just searching from the top
171 * then we just do one pass.
172 */
173
174 if (from==-1)
175 {
176 i=w->def->desc.w.nicons-1;
177 tries=1;
178 }
179 else
180 {
181 i=from-1;
182 tries=2;
183 }
184
185 /* --- The main search loop --- *
186 *
187 * There's nothing really exciting about this. It's just a brute-force
188 * rectangle comparison. If it finds something, then it returns
189 * immediately.
190 *
191 * We try to be a little cleverer -- we check if the pointer is anywhere
192 * near the icon rectangle and only read the actual bounding area if it
193 * is really worthwhile.
194 */
195
196 for (;tries;tries--)
197 {
198 while (i>=0) /* Find higher icons first... */
199 {
200 if (w->def->i[i].i.flags & wimp_IDELETED)
201 {
202 i--;
203 continue; /* Don't find deleted icons... */
204 }
205 if (m.x>=w->def->i[i].i.box.x0-20-HW &&
206 m.x<=w->def->i[i].i.box.x1+20+HW &&
207 m.y>=w->def->i[i].i.box.y0-20-HW &&
208 m.y<=w->def->i[i].i.box.y1+32+HW)
209 { /* Roughly in the right place */
210
211 /* --- Find the actual bounding box of the icon --- */
212
213 window_boundingBox(w,i,&box);
214
215 /* --- If we're searching for drag zones, do that --- */
216
217 if (w->def->i[i].selected && zones)
218 {
219 if (window__inSizedBox(m.x,
220 m.y,
221 box.x1-HW,
222 box.y0-wimpt_dy()-HW,
223 HW*2))
224 return (i | window__BOTTOMRIGHT);
225 if (window__inSizedBox(m.x,
226 m.y,
227 box.x0-wimpt_dx()-HW,
228 box.y0-wimpt_dy()-HW,
229 HW*2))
230 return (i | window__BOTTOMLEFT);
231 if (window__inSizedBox(m.x,
232 m.y,
233 box.x0-wimpt_dx()-HW,
234 box.y1-HW,
235 HW*2))
236 return (i | window__TOPLEFT);
237 if (window__inSizedBox(m.x,
238 m.y,
239 box.x1-HW,
240 box.y1-HW,
241 HW*2))
242 return (i | window__TOPRIGHT);
243 if (gPrefs_current()->sEdgeHandles)
244 {
245 if (window__inSizedBox(m.x,
246 m.y,
247 box.x0+(box.x1-box.x0-HW*2)/2,
248 box.y0-wimpt_dy()-HW,
249 HW*2))
250 return (i | window__BOTTOM);
251 if (window__inSizedBox(m.x,
252 m.y,
253 box.x1-HW,
254 box.y0+(box.y1-box.y0-HW*2)/2,
255 HW*2))
256 return (i | window__RIGHT);
257 if (window__inSizedBox(m.x,
258 m.y,
259 box.x0-wimpt_dx()-HW,
260 box.y0+(box.y1-box.y0-HW*2)/2,
261 HW*2))
262 return (i | window__LEFT);
263 if (window__inSizedBox(m.x,
264 m.y,
265 box.x0+(box.x1-box.x0-HW*2)/2,
266 box.y1-HW,
267 HW*2))
268 return (i | window__TOP);
269 }
270 }
271
272 /* --- If no match in the zones, check the actual icon --- *
273 *
274 * If it's in the icon, then we've found a match. If we're searching
275 * for drag zones, and it's not selected, then just remember we've
276 * found an icon, so don't try to match guidelines. Otherwise, we
277 * just return the match.
278 */
279
280 if (m.x>=box.x0 && m.x<box.x1 && m.y>=box.y0 && m.y<box.y1)
281 {
282 if (zones) {
283 if (w->def->i[i].selected)
284 return (i | window__MAIN);
285 else
286 found=TRUE;
287 } else
288 return (i);
289 }
290 }
291 i--;
292 }
293 i=w->def->desc.w.nicons-1;
294 }
295
296 /* --- We couldn't find anything in the icons, so try guidelines --- */
297
298 if (!found)
299 {
300 for (i=0;i<glass_GUIDELIMIT;i++)
301 {
302 if (w->guide[i].active)
303 {
304 if (w->guide[i].horiz && abs(m.y-w->guide[i].coord)<8)
305 return (i | window__HORGUIDE);
306 else if (abs(m.x-w->guide[i].coord)<8)
307 return (i | window__VERGUIDE);
308 }
309 }
310 }
311
312 /* --- Not a sausage, so we failed --- */
313
314 return (-1);
315 }
316
317 #undef HW
318
319 /*
320 * BOOL window__pointerOverIcon(glass_windPointer *w,int icon)
321 *
322 * Use
323 * Informs the caller if the pointer is over the bounding box of the icon
324 * specified.
325 *
326 * Parameters
327 * glass_windPointer *w == window containing icon
328 * int icon == icon to check for
329 */
330
331 BOOL window__pointerOverIcon(glass_windPointer *w,int icon)
332 {
333 wimp_box box;
334 wimp_wstate s;
335 wimp_mousestr m;
336 wimpt_noerr(wimp_get_wind_state(w->h,&s));
337 wimpt_noerr(wimp_get_point_info(&m));
338 window_boundingBox(w,icon,&box);
339 m.x-=s.o.box.x0-s.o.x;
340 m.y-=s.o.box.y1-s.o.y;
341 return (m.x>=box.x0 && m.x<=box.x1 && m.y>=box.y0 && m.y<=box.y1);
342 }
343
344 /*
345 * void window__setPtrShape(int icon)
346 *
347 * Use
348 * Sets the pointer shape accoding to the 'drag zone' part of the given
349 * icon number.
350 *
351 * Parameters
352 * int icon == the icon number
353 */
354
355 void window__setPtrShape(int icon)
356 {
357 static int last;
358 static int wouldbe;
359 sprite_id sid;
360 if (icon==-2)
361 icon=wouldbe;
362 wouldbe=icon;
363 if (window__qDragType()!=-1)
364 icon=window__qDragType();
365 icon=(icon&window__ZONEMASK)>>24;
366 if (icon==last)
367 return;
368 if (window__ptr[icon].name[0])
369 {
370 sid.s.name=window__ptr[icon].name;
371 sid.tag=0;
372 pointer_set_shape(resspr_area(),
373 &sid,
374 window__ptr[icon].x,
375 window__ptr[icon].y);
376 }
377 else
378 pointer_reset_shape();
379 last=icon;
380 }