chiark / gitweb /
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 }