Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / programs / dtappbuilder / src / ab / abobj_move.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  
24 /*
25  *      $XConsortium: abobj_move.c /main/3 1995/11/06 17:17:00 rswiston $
26  *
27  * @(#)abobj_move.c     1.25 15 Feb 1994      cde_app_builder/src/ab
28  *
29  *      RESTRICTED CONFIDENTIAL INFORMATION:
30  *
31  *      The information in this document is subject to special
32  *      restrictions in a confidential disclosure agreement between
33  *      HP, IBM, Sun, USL, SCO and Univel.  Do not distribute this
34  *      document outside HP, IBM, Sun, USL, SCO, or Univel without
35  *      Sun's specific written approval.  This document and all copies
36  *      and derivative works thereof must be returned or destroyed at
37  *      Sun's request.
38  *
39  *      Copyright 1993 Sun Microsystems, Inc.  All rights reserved.
40  *
41  */
42
43
44 /*
45  ***********************************************************************
46  * ab_move.c - Implements moving UI objects around
47  *        
48  *
49  ***********************************************************************
50  */
51 #include <stdio.h>
52 #include <X11/Intrinsic.h>
53 #include <X11/StringDefs.h>
54 #include <ab_private/x_util.h>
55 #include <ab_private/objxm.h>
56 #include <ab_private/abobj_edit.h>
57 #include "abobjP.h"
58
59 /* XRectangle Transformation macros used for passing rects up/down embedded
60  * coordinate systems.
61  */
62 #define rect_passtoparent(a, b, rect) \
63         {(rect)->x = (unsigned short)(rect)->x + (a); (rect)->y = (unsigned short)(rect)->y + (b);}
64
65 #define rect_passtochild(a, b, rect) \
66         {(rect)->x = (rect)->x - (a); (rect)->y = (rect)->y - (b);}
67
68 const int    AB_drag_threshold = 4;
69
70
71 static void     undo_move(
72                     ABUndoRec   undo_rec
73                 );
74
75 /*************************************************************************
76 **                                                                      **
77 **       Private Data                                                   **
78 **                                                                      **
79 **************************************************************************/
80 static XRectangle drag_init_rect, orig_rect, move_rect;
81 static Boolean    first_move = True;
82 static ABObj      xy_obj;
83 static Widget     xy_widget;
84 static Widget     parent;
85 static ABSelectedRec sel; 
86
87 /*************************************************************************
88 **                                                                      **
89 **       Function Definitions                                           **
90 **                                                                      **
91 **************************************************************************/
92 int
93 abobjP_move_object_outline(
94     ABObj               obj, 
95     XMotionEvent        *mevent
96 )
97 {
98     static XRectangle parent_rect;
99     static XRectangle last_rect;
100     static int        x_offset, y_offset;
101     static Dimension  border_w;
102     static Display    *dpy;
103     XRectangle        widget_rect;
104     int               trans_x, trans_y;
105
106     /* First time: set up initial move variables */
107     if (first_move)
108     {
109         if (obj_is_item(obj))
110             obj = obj_get_parent(obj);
111
112         obj    = obj_get_root(obj);
113         
114         /* Multiple objects might be selected...*/ 
115         if (obj_is_control(obj) || 
116             obj_is_group(obj) ||
117             obj_is_pane(obj)) 
118         { 
119             abobj_get_selected(obj_get_root(obj_get_parent(obj)), False, False, &sel);
120         } 
121         else
122         {
123             sel.count = 1; 
124             sel.list = (ABObj*)util_malloc(sizeof(ABObj));
125             sel.list[0] = obj;
126         }
127
128         xy_obj = objxm_comp_get_subobj(obj, AB_CFG_POSITION_OBJ);
129         xy_widget = (Widget)xy_obj->ui_handle;
130
131         if (xy_widget == NULL)
132         {
133             if (util_get_verbosity() > 2)
134                 fprintf(stderr,"abobjP_move_object_outline: %s :no POSITION widget\n",
135                         util_strsafe(obj_get_name(obj)));
136             return ERROR;
137         }
138
139         dpy    = XtDisplay(xy_widget);
140         parent = XtParent(xy_widget);
141
142         x_get_widget_rect(xy_widget, &widget_rect);
143         x_get_widget_rect(parent, &parent_rect);
144
145         if (sel.count > 1)
146         {
147             abobj_get_rect_for_objects(sel.list, sel.count, &orig_rect);
148         } 
149         else
150         {
151             orig_rect = widget_rect;
152             XtVaGetValues(xy_widget, XtNborderWidth, &border_w, NULL);
153             orig_rect.width  += (2*border_w);
154             orig_rect.height += (2*border_w);
155             orig_rect.width--;
156             orig_rect.height--;
157         }
158         move_rect = orig_rect;
159
160         drag_init_rect.x     = mevent->x - AB_drag_threshold;
161         drag_init_rect.y     = mevent->y - AB_drag_threshold;
162         drag_init_rect.width = drag_init_rect.height = 2 * AB_drag_threshold;
163
164         x_offset = widget_rect.x - orig_rect.x + mevent->x;
165         y_offset = widget_rect.y - orig_rect.y + mevent->y;
166
167         first_move  = False;
168
169         rect_zero_out(&last_rect);
170     }
171     /* Don't begin rendering move outline until pointer is out of
172      * the drag_init bounding box
173      */
174     else if (!rect_includespoint(&drag_init_rect, mevent->x, mevent->y))
175     {    
176         Window win;
177
178         /* event coords are relative to widget-must translate to parent */
179         XTranslateCoordinates(dpy, XtWindow(xy_widget), XtWindow(parent),
180             mevent->x, mevent->y, &trans_x, &trans_y, &win);
181
182         move_rect.x = trans_x - x_offset;
183         move_rect.y = trans_y - y_offset;
184
185         /* Ensure move outline is within the parent's rect */
186         if (move_rect.x < 0)
187             move_rect.x = 0;
188         else if ((move_rect.x + (short)move_rect.width + 1) >= (short)parent_rect.width)
189             move_rect.x = parent_rect.width - (move_rect.width + 1);
190
191         if (move_rect.y < 0)
192             move_rect.y = 0;
193         else if ((move_rect.y + (short)move_rect.height + 1) >= (short)parent_rect.height)
194             move_rect.y = parent_rect.height - (move_rect.height + 1);
195
196         /* If cursor has moved since last event, erase previous outline
197          * and render new one (using XOR function)
198          */
199         if (!rect_equal(&move_rect, &last_rect))
200         {
201             if (!rect_isnull(&last_rect))
202                 x_box_r(parent, &last_rect);
203             x_box_r(parent, &move_rect);
204             last_rect = move_rect;
205         }
206     }
207     return OK;
208 }
209
210 /*
211  * Move the object to the location of the last drag rect
212  */
213 int
214 abobj_move(
215     ABObj     obj, 
216     XEvent    *event
217 )
218 {
219     short       x_delta = 0;
220     short       y_delta = 0;
221
222     if (!first_move)
223     {
224         first_move = True;
225
226         /* erase last box */
227         x_box_r(parent, &move_rect);
228
229         x_delta = move_rect.x - orig_rect.x;
230         y_delta = move_rect.y - orig_rect.y;
231
232         /*
233          * Before the move is performed, record undo information
234          */
235         (void)abobj_set_undo(sel.list, sel.count, undo_move, AB_UNDO_MOVE);
236
237         abobj_nudge_selected(sel.list, sel.count, x_delta, y_delta, True);
238
239         util_free(sel.list);
240         return OK;
241     }
242     return ERROR;
243
244 }
245 void
246 abobj_nudge_selected(
247     ABObj       *sel_list,
248     int         sel_count,
249     short       x_delta,
250     short       y_delta,
251     BOOL        reselect
252 )
253 {
254     ABObj       moveobj;
255     ABObj       xyobj;
256     XRectangle  new_rect;
257     int         i;
258
259     for (i=0; i < sel_count; i++)
260     {
261         if (obj_is_layers(obj_get_parent(sel_list[i])))
262             moveobj = obj_get_parent(sel_list[i]);
263         else
264             moveobj = sel_list[i];
265  
266         xyobj = objxm_comp_get_subobj(moveobj, AB_CFG_POSITION_OBJ);
267          
268         x_get_widget_rect(objxm_get_widget(xyobj), &new_rect);
269         new_rect.x += x_delta;
270         new_rect.y += y_delta;
271  
272         /* Move object */
273         abobj_set_xy(moveobj, new_rect.x, new_rect.y);
274
275 /*
276         if (xyobj->attachments)
277             abobj_calculate_new_layout(xyobj, new_rect.x, new_rect.y,
278                         new_rect.width, new_rect.height);
279 */
280  
281         abobj_tree_instantiate_changes(moveobj);
282
283         /* 
284          * UGLY WORKAROUND for Motif bug which prevents a 1 pixel move
285          * to the Left from working if only 1 object is being moved...
286          */
287         if (sel_count == 1 && x_delta == -1) 
288             abobj_force_dang_form_resize(moveobj);      
289
290         if (reselect)
291             abobj_select(sel_list[i]);
292    }
293
294 }
295
296
297 void    
298 abobj_move_selected(
299     ABObj       *sel_list, 
300     int          sel_count,
301     XRectangle  *start, 
302     XRectangle  *stop
303 )
304 {
305         ABObj           obj;
306         XRectangle      obj_rect;
307         int             i;
308
309         /*
310          * Loop through all selected objects with the same owner.  Only
311          * move selected objects, groups without anchors, and anchored groups
312          * if the anchor is also selected.
313          */
314          /* andy, revisit to add in all the group and anchor stuff */
315         for (i = 0; i < sel_count; i++) 
316         {
317             obj = sel_list[i];
318             x_get_widget_rect(objxm_get_widget(obj), &obj_rect);
319             rect_passtochild(start->x, start->y, &obj_rect);
320             rect_passtoparent(stop->x, stop->y, &obj_rect);
321             /*
322             undo_record_move(obj);
323             */
324             abobj_set_xy(obj, (int)obj_rect.x, (int)obj_rect.y);
325             abobj_instantiate_changes(obj); 
326         }
327 }
328
329 /*
330  * Undo function for move
331  * NOTE: may need to change when moving multiple objects is
332  * implemented.
333  */
334 static void
335 undo_move(
336     ABUndoRec   undo_rec
337 )
338 {
339     int         i, 
340                 x, 
341                 y;
342     ABObj       obj;
343
344     if (!undo_rec)
345         return;
346
347     /*
348      * Set undo to undo this move (undo of undo)
349      */
350     (void)abobj_set_undo(undo_rec->list, undo_rec->count, 
351                 undo_move, AB_UNDO_MOVE);
352
353     /*
354      * For each object that was moved previously
355      */
356     for (i = 0; i < undo_rec->count; ++i)
357     {
358         /*
359          * If undo record is not the right type, something is WRONG !!
360          */
361         if (undo_rec->info_list[i].type != AB_UNDO_MOVE)
362             continue;
363
364         /*
365          * Get previous x,y and object taht was moved
366          */
367         x = undo_rec->info_list[i].info.move.x;
368         y = undo_rec->info_list[i].info.move.y;
369         obj = undo_rec->list[i];
370
371         /* Move object */
372         abobj_set_xy(obj, x, y); 
373
374         if (xy_obj->attachments)
375             abobj_calculate_new_layout(xy_obj, x, y,
376                 move_rect.width, move_rect.height);
377
378         abobj_instantiate_changes(obj); 
379     }
380 }
381
382 BOOL
383 abobj_is_movable(
384     ABObj       obj
385 )
386 {
387     BOOL                movable = True;
388     ABObj               pobj;
389     AB_CONTAINER_TYPE   cont_type;
390
391     /* If object is a child of a Group and the group has a
392      * defined layout type, then it is not movable
393      */
394     pobj = obj_get_root(obj_get_parent(obj));
395     if (obj_is_group(pobj) &&
396         obj_get_group_type(pobj) != AB_GROUP_IGNORE)
397         movable = False;
398
399     switch(obj_get_type(obj))
400     {
401         case AB_TYPE_TEXT_PANE:
402         case AB_TYPE_TERM_PANE:
403         case AB_TYPE_DRAWING_AREA:
404         case AB_TYPE_CONTAINER:
405         {
406             /* If object is child of PanedWindow, it cannot be moved */
407             if (obj_is_paned_win(pobj))
408                 movable = False;
409             else if (obj_is_container(obj))
410             {
411                 cont_type = obj_get_container_type(obj);
412                 if (cont_type == AB_CONT_MENU_BAR ||
413                     cont_type == AB_CONT_TOOL_BAR ||
414                     cont_type == AB_CONT_FOOTER ||
415                     cont_type == AB_CONT_BUTTON_PANEL)
416                     movable = False;
417             }
418             break;
419         }
420         default:
421             break;
422     }
423     return movable;
424 }