dtwm: basic multihead(xinerama only) support
[oweals/cde.git] / cde / programs / dticon / graphics.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: graphics.c /main/4 1995/11/02 14:05:07 rswiston $ */
24 /*********************************************************************
25 *  (c) Copyright 1993, 1994 Hewlett-Packard Company
26 *  (c) Copyright 1993, 1994 International Business Machines Corp.
27 *  (c) Copyright 1993, 1994 Sun Microsystems, Inc.
28 *  (c) Copyright 1993, 1994 Unix System Labs, Inc., a subsidiary of
29 *      Novell, Inc.
30 **********************************************************************/
31 /******************************************************************************
32  **  Program:           dticon
33  **
34  **  Description:       X11-based multi-color icon editor
35  **
36  **  File:              graphics.c, which contains the following subroutines or
37  **                     functions:
38  **                       Flicker_Arc()
39  **                       Circle_Box()
40  **                       Set_HotBox_Coords()
41  **                       Start_HotBox()
42  **                       Do_HotBox()
43  **                       Stop_HotBox()
44  **
45  ******************************************************************************
46  **
47  **  Copyright Hewlett-Packard Company, 1990, 1991, 1992.
48  **  All rights are reserved.  Copying or reproduction of this program,
49  **  except for archival purposes, is prohibited without prior written
50  **  consent of Hewlett-Packard Company.
51  **
52  **  Hewlett-Packard makes no representations about the suitibility of this
53  **  software for any purpose.  It is provided "as is" without express or
54  **  implied warranty.
55  **
56  ******************************************************************************/
57 #include <Xm/Xm.h>
58 #include <math.h>
59 #include "externals.h"
60
61 extern GC scratch_gc;
62
63 Widget editMenu_cut_pb;
64 Widget editMenu_copy_pb;
65 Widget editMenu_rotate_pb;
66 Widget editMenu_flip_pb;
67 Widget editMenu_scale_pb;
68
69 extern void Stop_HotBox(void);
70
71 /***************************************************************************
72  *                                                                         *
73  * Routine:   Flicker_Arc                                                  *
74  *                                                                         *
75  * Purpose:   Given 2 points (top-left and bottom-right), draw an          *
76  *            invertable ellipse around the box they form.                 *
77  *                                                                         *
78  *X11***********************************************************************/
79
80 void
81 Flicker_Arc(
82         Window win,
83         int x1,
84         int y1,
85         int x2,
86         int y2 )
87 {
88   int x, y, width, height;
89
90   x = min(x1, x2);
91   y = min(y1, y2);
92   width  = abs(x1 - x2);
93   height = abs(y1 - y2);
94
95 #ifdef DEBUG
96   if (debug)
97     stat_out("Doing Flicker_Arc: x=%d, y=%d, width=%d, height=%d\n",
98                 x, y, width, height);
99 #endif
100
101   if ((width > 0) && (height > 0))
102     XDrawArc(dpy, win, Flicker_gc, x, y, width, height, 0, 360*64);
103 }
104
105
106 /***************************************************************************
107  *                                                                         *
108  * Routine:   Circle_Box                                                   *
109  *                                                                         *
110  * Purpose:   Given 2 points (the center and radius of a circle)           *
111  *            generate a box which would exactly enclose this circle,      *
112  *            and then draw a flickering circle that matches the box.      *
113  *            WARNING: [x1,y1] are always assumed to be the centerpoint    *
114  *            and this routine will generate bogus results if this is      *
115  *            not TRUE.                                                    *
116  *                                                                         *
117  *X11***********************************************************************/
118
119 void
120 Circle_Box(
121         Window win,
122         int x1,
123         int y1,
124         int x2,
125         int y2,
126         XRectangle *box )
127 {
128   int radius, top_x, top_y, bottom_x, bottom_y, width, height;
129   double size;
130
131 #ifdef DEBUG
132   if (debug)
133     stat_out("Entering Circle_Box\n");
134 #endif
135
136   width  = mag(x1, x2);
137   height = mag(y1, y2);
138   size   = (double) ((width * width) + (height * height));
139   radius = (int) sqrt(size);
140
141   top_x = x1 - radius;
142   top_y = y1 - radius;
143   bottom_x  = x1 + radius;
144   bottom_y  = y1 + radius;
145
146 #ifdef DEBUG
147   if (debug)
148     stat_out("  Circle_Box values: tx=%d, ty=%d, bx=%d, by=%d\n",
149                         top_x, top_y, bottom_x, bottom_x);
150 #endif
151
152   Flicker_Arc(win, top_x, top_y, bottom_x, bottom_y);
153
154   box->x = top_x;
155   box->y = top_y;
156   box->width  = bottom_x - top_x + 1;
157   box->height = bottom_y - top_y + 1;
158 #ifdef DEBUG
159   if (debug)
160     stat_out("Leaving Circle_Box\n");
161 #endif
162 }
163
164
165 /***************************************************************************
166  *                                                                         *
167  * Routine:   Set_HotBox_Coords                                            *
168  *                                                                         *
169  * Purpose:   A SELECT operation has just occurred.  Initiate a timer      *
170  *            calculate the area to enclose.                               *
171  *            not TRUE.                                                    *
172  *                                                                         *
173  *X11***********************************************************************/
174
175 #define FLASH_INTERVAL    300
176 static Boolean FlashState=False;
177 static int flash_x, flash_y, flash_width, flash_height;
178 static int box_x1, box_y1, box_x2, box_y2;
179 static XtIntervalId selectTimerID;
180 static void Do_HotBox();
181
182 void
183 Set_HotBox_Coords( void )
184 {
185   int min_x, min_y, max_x, max_y, tmp_x, tmp_y;
186
187   min_x = min(ix, last_ix);
188   min_y = min(iy, last_iy);
189   max_x = max(ix, last_ix);
190   max_y = max(iy, last_iy);
191
192 /*** make sure all four points are on the tablet ***/
193
194   if (min_x < 0)
195     min_x = 0;
196   if (min_y < 0)
197     min_y = 0;
198   if ((max_x) >= icon_width)
199     max_x = icon_width-1;
200   if ((max_y) >= icon_height)
201     max_y = icon_height-1;
202
203   select_box.x = min_x;
204   select_box.y = min_y;
205   select_box.width  = max_x - min_x + 1;
206   select_box.height = max_y - min_y + 1;
207
208   box_x1 = min_x;
209   box_y1 = min_y;
210   box_x2 = max_x+1;
211   box_y2 = max_y+1;
212
213   Tablet_Coords(min_x, min_y, &flash_x, &flash_y);
214   Tablet_Coords(max_x+1, max_y+1, &tmp_x, &tmp_y);
215   flash_width  = tmp_x - flash_x;
216   flash_height = tmp_y - flash_y;
217
218 #ifdef DEBUG
219   if (debug) {
220     stat_out("  select_box: x=%d, y=%d, width=%d, height=%d\n",
221                 select_box.x, select_box.y,
222                 select_box.width, select_box.height);
223     stat_out("  flash box: x=%d, y=%d, width=%d, height=%d\n",
224                 flash_x, flash_y, flash_width, flash_height);
225    }
226 #endif
227 }
228
229
230 /***************************************************************************
231  *                                                                         *
232  * Routine:   Start_HotBox                                                 *
233  *                                                                         *
234  * Purpose:   A SELECT operation has just occurred.  Initiate a timer      *
235  *            which flashes a 1-pixel wide box around the perimeter of     *
236  *            the selected rectangle every FLASH_INTERVAL milliseconds.    *
237  *            Use the global variables ix, iy, last_ix, last_iy to         *
238  *            calculate the area to enclose.                               *
239  *                                                                         *
240  *X11***********************************************************************/
241
242 void
243 Start_HotBox(
244         int flag )
245 {
246
247 #ifdef DEBUG
248   if (debug)
249     stat_out("Entering Start_HotBox\n");
250 #endif
251
252   Selected = True;
253   /* turn on stuff that uses the selected area */
254   XtSetSensitive( editMenu_cut_pb, True);
255   XtSetSensitive( editMenu_copy_pb, True);
256   XtSetSensitive(editMenu_rotate_pb, True);
257   XtSetSensitive(editMenu_flip_pb,  True);
258   XtSetSensitive(editMenu_scale_pb,  True);
259   XSync(dpy, 0);
260   if (flag == INITIAL)
261     Set_HotBox_Coords();
262
263   selectTimerID = XtAppAddTimeOut(AppContext,
264                                   FLASH_INTERVAL,
265                                   (XtTimerCallbackProc) Do_HotBox,
266                                   NULL);
267
268 #ifdef DEBUG
269   if (debug)
270     stat_out("Leaving Start_HotBox - TimerID=%d\n", selectTimerID);
271 #endif
272
273 }
274
275
276 /***************************************************************************
277  *                                                                         *
278  * Routine:   Do_HotBox                                                    *
279  *                                                                         *
280  * Purpose:   Flash one alternating pulse around the selected area, and    *
281  *            then re-set itself to activate again in FLASH_INTERVAL       *
282  *            milliseconds.                                                *
283  *                                                                         *
284  * note: Check selectTimerID so that timeouts added for previous selects   *
285  *       are ignored.  ex: if new select is started before previous select *
286  *       timeout is serviced, "Selected" will already be set to true again *
287  *       (for new select) when timeout from old selection is called... so  *
288  *       now Stop_HotBox is called immediately (before HotBox Coords are   *
289  *       set for new select), and last timeout is ignored.                 *
290  *                                                                         *
291  *X11***********************************************************************/
292
293 static void
294 Do_HotBox(
295         XtPointer *client_data,
296         XtIntervalId *local_id )
297 {
298
299 #ifdef DEBUG
300   if (debug)
301     stat_out(". ");
302 #endif
303
304   if (GraphicsOp != SELECT)
305     Selected = False;
306   if (*local_id == selectTimerID)
307   {
308     if (Selected)
309     {
310       if (FlashState) {
311         FlashState = False;
312         XSetForeground(dpy, scratch_gc, black_pixel);
313       }
314       else
315       {
316         FlashState = True;
317         XSetForeground(dpy, scratch_gc, white_pixel);
318       }
319     XSetLineAttributes(dpy, scratch_gc, 1, LineSolid, CapButt, JoinMiter);
320     XDrawRectangle(dpy, tablet_win, scratch_gc,
321         flash_x, flash_y, flash_width, flash_height);
322     selectTimerID=XtAppAddTimeOut(AppContext,
323                                   FLASH_INTERVAL,
324                                   (XtTimerCallbackProc) Do_HotBox,
325                                   NULL);
326     }
327     else
328       Stop_HotBox();
329   }
330 }
331
332
333 /***************************************************************************
334  *                                                                         *
335  * Routine:   Stop_HotBox                                                  *
336  *                                                                         *
337  * Purpose:   Undo the last Selected border operation.                     *
338  *                                                                         *
339  *X11***********************************************************************/
340
341 void
342 Stop_HotBox( void )
343 {
344   int min_x, min_y, max_x, max_y, tmp_x, tmp_y;
345   static int tmp_ix, tmp_iy;
346   static Boolean Rotate_Move=False;
347
348 #ifdef DEBUG
349   if (debug)
350     stat_out("Entering Stop_HotBox\n");
351 #endif
352
353   if (GridEnabled) {
354     XDrawLine(dpy, tablet_win, Grid_gc,
355                 flash_x, flash_y, (flash_x+flash_width), flash_y);
356     XDrawLine(dpy, tablet_win, Grid_gc,
357                 flash_x, (flash_y+flash_height), (flash_x+flash_width),
358                 (flash_y+flash_height));
359     XDrawLine(dpy, tablet_win, Grid_gc,
360                 flash_x, flash_y, flash_x, (flash_y+flash_height));
361     XDrawLine(dpy, tablet_win, Grid_gc,
362                 (flash_x+flash_width), flash_y, (flash_x+flash_width),
363                 (flash_y+flash_height));
364    }
365   else {
366     /* since Rotate left and right moves ix and iy revert to tmp_ix, tmp_iy */
367     if (Rotate_Move) { Rotate_Move = False;
368                        ix = tmp_ix;
369                        iy = tmp_iy; }
370     min_x = min(ix, last_ix);
371     min_y = min(iy, last_iy);
372     max_x = max(ix, last_ix);
373     max_y = max(iy, last_iy);
374     if (++max_x >= icon_width) max_x--;
375     if (++max_y >= icon_height) max_y--;
376     Transfer_Back_Image(min_x, min_y, max_x, max_y, HOLLOW);
377     /* if it is a Rotate Op. then keep ix, iy */
378     if(GraphicsOp == S_ROTATE) { Rotate_Move = True;
379                                  tmp_ix = ix;
380                                  tmp_iy = iy; }
381    }
382
383 #ifdef DEBUG
384   if (debug)
385     stat_out("Leaving Stop_HotBox\n");
386 #endif
387
388 }