1339 lines
38 KiB
C
1339 lines
38 KiB
C
/*
|
|
* CDE - Common Desktop Environment
|
|
*
|
|
* Copyright (c) 1993-2012, The Open Group. All rights reserved.
|
|
*
|
|
* These libraries and programs are free software; you can
|
|
* redistribute them and/or modify them under the terms of the GNU
|
|
* Lesser General Public License as published by the Free Software
|
|
* Foundation; either version 2 of the License, or (at your option)
|
|
* any later version.
|
|
*
|
|
* These libraries and programs are distributed in the hope that
|
|
* they will be useful, but WITHOUT ANY WARRANTY; without even the
|
|
* implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU Lesser General Public License for more
|
|
* details.
|
|
*
|
|
* You should have received a copy of the GNU Lesser General Public
|
|
* License along with these librararies and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/*
|
|
* $XConsortium: pal_create.c /main/4 1996/07/25 09:19:49 mustafa $
|
|
*
|
|
* @(#)pal_create.c 1.102 19 May 1995
|
|
*
|
|
* RESTRICTED CONFIDENTIAL INFORMATION:
|
|
*
|
|
* The information in this document is subject to special
|
|
* restrictions in a confidential disclosure agreement between
|
|
* HP, IBM, Sun, USL, SCO and Univel. Do not distribute this
|
|
* document outside HP, IBM, Sun, USL, SCO, or Univel without
|
|
* Sun's specific written approval. This document and all copies
|
|
* and derivative works thereof must be returned or destroyed at
|
|
* Sun's request.
|
|
*
|
|
* Copyright 1993 Sun Microsystems, Inc. All rights reserved.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
***********************************************************************
|
|
* pal_create.c - Implements object creation (dragging & dropping items
|
|
* off the palette)
|
|
*
|
|
***********************************************************************
|
|
*/
|
|
#include <stdio.h>
|
|
#include <X11/Intrinsic.h>
|
|
#include <Xm/Xm.h>
|
|
#include <Xm/BulletinB.h>
|
|
#include <Xm/CascadeB.h>
|
|
#include <Xm/Form.h>
|
|
#include <Xm/Label.h>
|
|
#include <Xm/TextF.h>
|
|
#include <Xm/ToggleB.h>
|
|
#include <Xm/SelectioB.h>
|
|
#include <Xm/Scale.h>
|
|
#include <Dt/SpinBox.h>
|
|
#include <Dt/ComboBox.h>
|
|
#include <ab_private/trav.h>
|
|
#include <ab_private/objxm.h>
|
|
#include <ab_private/brws.h>
|
|
#include <ab_private/proj.h>
|
|
#include <ab_private/abobj.h>
|
|
#include <ab_private/abobj_set.h>
|
|
#include <ab_private/abobj_edit.h>
|
|
#include <ab_private/ab.h>
|
|
#include <ab_private/pal.h>
|
|
#include <ab_private/prop.h>
|
|
#include <ab_private/ui_util.h>
|
|
#include <ab_private/x_util.h>
|
|
#include "dtbuilder.h"
|
|
#include "palette_ui.h"
|
|
|
|
const int AB_max_item_height = 64;
|
|
const int AB_max_item_width = 256;
|
|
|
|
/*
|
|
* Default (x,y) positions of objects when dragged out
|
|
* from palette. This is only used when the objects are not
|
|
* dropped onto the interface created, but dropped instead
|
|
* onto the browser.
|
|
*/
|
|
#define AB_DEFAULT_X 0
|
|
#define AB_DEFAULT_Y 0
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Private Function Declarations **
|
|
** **
|
|
**************************************************************************/
|
|
static void palitem_update_type(
|
|
Widget w,
|
|
XtPointer cd,
|
|
XEvent *ev,
|
|
Boolean *cont
|
|
);
|
|
static void palitem_select_event(
|
|
Widget w,
|
|
XtPointer cd,
|
|
XEvent *ev,
|
|
Boolean *cont
|
|
);
|
|
static void palitem_drag_action(
|
|
Widget w,
|
|
int subtype,
|
|
XEvent *event
|
|
);
|
|
static void palitem_release_event(
|
|
Widget w,
|
|
XtPointer cd,
|
|
XEvent *ev,
|
|
Boolean *cont
|
|
);
|
|
static void create_obj_action(
|
|
Widget w,
|
|
int subtype,
|
|
XEvent *event
|
|
);
|
|
static char *locate_obj_parent(
|
|
ABObj obj,
|
|
Widget widget,
|
|
int x,
|
|
int y,
|
|
ABObj *parentptr,
|
|
BOOL *ModuleCreated
|
|
);
|
|
static Boolean initiate_drag(
|
|
Widget w,
|
|
int subtype,
|
|
int *x,
|
|
int *y,
|
|
int *xhot,
|
|
int *yhot
|
|
);
|
|
static XImage *build_item_image(
|
|
Widget w
|
|
);
|
|
static void image_copy(
|
|
Widget w,
|
|
XImage *from,
|
|
XImage *to,
|
|
int width,
|
|
int gx,
|
|
int px
|
|
);
|
|
ABObj locate_obj_at_rootxy(
|
|
int x,
|
|
int y,
|
|
int *p_wx,
|
|
int *p_wy
|
|
);
|
|
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Private Data **
|
|
** **
|
|
**************************************************************************/
|
|
static Widget palette_widget = NULL;
|
|
static Cursor drag_cursor;
|
|
static int drag_cursor_xhot;
|
|
static int drag_cursor_yhot;
|
|
static Boolean drag_on = FALSE;
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Function Definitions **
|
|
** **
|
|
**************************************************************************/
|
|
/*
|
|
* Set up palette item(widget) to handle select-drag operation
|
|
*/
|
|
void
|
|
pal_enable_item_drag(
|
|
Widget widget,
|
|
int subtype
|
|
)
|
|
{
|
|
static int st_subtype;
|
|
|
|
st_subtype = subtype;
|
|
XtInsertEventHandler(widget, ButtonPressMask, FALSE,
|
|
palitem_select_event, (XtPointer)&st_subtype, XtListHead);
|
|
XtInsertEventHandler(widget, ButtonReleaseMask, FALSE,
|
|
palitem_release_event, (XtPointer)&st_subtype, XtListHead);
|
|
XtAddEventHandler(widget, EnterWindowMask|LeaveWindowMask, FALSE,
|
|
palitem_update_type, (XtPointer)&st_subtype);
|
|
|
|
/* We need to keep track of the main palette widget
|
|
* for drag-behavior purposes
|
|
*/
|
|
if (!palette_widget)
|
|
{
|
|
if ((palette_widget = dtb_palette_ab_palette_main.palette_cpanel) == NULL)
|
|
{
|
|
if (util_get_verbosity() > 2)
|
|
fprintf(stderr,"pal_enable_item_drag: couldn't find \"%s\"\n",
|
|
XtName(dtb_palette_ab_palette_main.palette_cpanel));
|
|
palette_widget = XtParent(XtParent(widget));
|
|
}
|
|
}
|
|
}
|
|
static void
|
|
palitem_update_type(
|
|
Widget w,
|
|
XtPointer clientData,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
)
|
|
{
|
|
PalItemInfo *palitem;
|
|
int subtype = *((int*)clientData);
|
|
String objname;
|
|
int i;
|
|
|
|
XtVaGetValues(w, XmNuserData, &palitem, NULL);
|
|
|
|
if (event->type == EnterNotify)
|
|
{
|
|
objname = palitem->name;
|
|
|
|
for(i=0; i < palitem->num_subinfo; i++)
|
|
if (palitem->subinfo[i].subtype == subtype)
|
|
{
|
|
objname = palitem->subinfo[i].subname;
|
|
break;
|
|
}
|
|
|
|
ab_update_stat_region(AB_STATUS_OBJ_TYPE, objname);
|
|
}
|
|
else /* LeaveNotify */
|
|
ab_update_stat_region(AB_STATUS_OBJ_TYPE, " ");
|
|
|
|
}
|
|
|
|
/*
|
|
* EventHandler: ButtonPress activated on palette item
|
|
*/
|
|
static void
|
|
palitem_select_event(
|
|
Widget w,
|
|
XtPointer clientData,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
)
|
|
{
|
|
XButtonEvent *bevent;
|
|
int subtype = *((int*)clientData);
|
|
|
|
if (event->type != ButtonPress)
|
|
return;
|
|
|
|
bevent = (XButtonEvent*)event;
|
|
*cont_dispatch = FALSE;
|
|
|
|
if (AB_builder_mode != MODE_BUILD)
|
|
return;
|
|
|
|
if (bevent->button == 1 ||
|
|
(AB_btn1_transfer != True && bevent->button == 2))
|
|
palitem_drag_action(w, subtype, event);
|
|
|
|
}
|
|
|
|
/*
|
|
* Action Proc: Palette item has been selected - begin drag
|
|
*/
|
|
static void
|
|
palitem_drag_action(
|
|
Widget widget,
|
|
int subtype,
|
|
XEvent *event
|
|
)
|
|
{
|
|
int x, y;
|
|
Display *dpy = XtDisplay(widget);
|
|
|
|
if (event->type == ButtonPress)
|
|
{
|
|
XButtonEvent *bevent = (XButtonEvent*)event;
|
|
|
|
x = bevent->x;
|
|
y = bevent->y;
|
|
|
|
if (!initiate_drag(widget, subtype, &x, &y, &drag_cursor_xhot, &drag_cursor_yhot))
|
|
{
|
|
drag_on = FALSE;
|
|
if (util_get_verbosity() > 2)
|
|
fprintf(stderr, "palitem_drag_action: couldn't begin drag\n");
|
|
}
|
|
else
|
|
drag_on = TRUE;
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* EventHandler: ButtonRelease activated on palette item
|
|
*/
|
|
static void
|
|
palitem_release_event(
|
|
Widget w,
|
|
XtPointer clientData,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
)
|
|
{
|
|
XButtonEvent *bevent;
|
|
int subtype = *((int*)clientData);
|
|
|
|
if (event->type != ButtonRelease)
|
|
return;
|
|
|
|
bevent = (XButtonEvent*)event;
|
|
*cont_dispatch = FALSE;
|
|
|
|
if (AB_builder_mode != MODE_BUILD)
|
|
return;
|
|
|
|
if (bevent->button == 1 ||
|
|
(AB_btn1_transfer != True && bevent->button == 2))
|
|
create_obj_action(w, subtype, event);
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* Action Proc: Palette item has been released; if drag was taking
|
|
* place, release the pointer grab and create object
|
|
*/
|
|
static void
|
|
create_obj_action(
|
|
Widget widget,
|
|
int subtype,
|
|
XEvent *event
|
|
)
|
|
{
|
|
ABObj project = proj_get_project();
|
|
ABObj obj = NULL;
|
|
ABObj obj_parent = NULL;
|
|
PalItemInfo *palitem;
|
|
Display *dpy;
|
|
char *errmsg = NULL;
|
|
BOOL ModuleCreated = FALSE;
|
|
XmString xm_buf = (XmString) NULL;
|
|
|
|
dpy = XtDisplay(widget);
|
|
|
|
if (drag_on)
|
|
{
|
|
XUngrabPointer(dpy, CurrentTime);
|
|
XFreeCursor(dpy, drag_cursor);
|
|
drag_on = FALSE;
|
|
}
|
|
|
|
if (event->type == ButtonRelease)
|
|
{
|
|
Window xy_win;
|
|
int wx, wy;
|
|
XButtonEvent *bevent = (XButtonEvent *)event;
|
|
XtVaGetValues(widget, XmNuserData, &palitem, NULL);
|
|
|
|
/* Creation may take awhile, so set busy cursor */
|
|
xy_win = x_xwin_at_rootxy(AB_toplevel, bevent->x_root,
|
|
bevent->y_root, &wx, &wy);
|
|
ab_set_busy_cursor(TRUE);
|
|
ui_set_busy_cursor(xy_win, TRUE);
|
|
|
|
obj = obj_create(palitem->type, NULL);
|
|
|
|
if (palitem->type == AB_TYPE_SCALE)
|
|
obj_set_read_only(obj, subtype);
|
|
|
|
if (subtype != AB_NO_SUBTYPE)
|
|
obj_set_subtype(obj, subtype);
|
|
|
|
if (errmsg = locate_obj_parent(obj, widget, bevent->x_root,
|
|
bevent->y_root, &obj_parent, &ModuleCreated))
|
|
{
|
|
obj_destroy(obj);
|
|
if (!util_streq(errmsg, ""))
|
|
{
|
|
xm_buf = XmStringCreateLocalized(errmsg);
|
|
dtb_palette_error_msg_initialize(&dtb_palette_error_msg);
|
|
(void)dtb_show_modal_message(dtb_get_toplevel_widget(),
|
|
&dtb_palette_error_msg, xm_buf, NULL, NULL);
|
|
XmStringFree(xm_buf);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (pal_initialize_obj(obj) == ERROR)
|
|
fprintf(stderr, "create_obj_action: couldn't initialize object\n");
|
|
else if (abobj_show_tree(obj, TRUE) == -1)
|
|
fprintf(stderr,"create_obj_action: couldn't show object\n");
|
|
else
|
|
{
|
|
/* set the initial visiblity of new layers to false */
|
|
if (obj_is_layers(obj_parent))
|
|
obj_set_is_initially_visible(obj, FALSE);
|
|
|
|
/* Deselect any objects that happen to be selected */
|
|
abobj_deselect_all(project);
|
|
aob_deselect_all_objects(project);
|
|
|
|
/* Make the new obj selected */
|
|
abobj_select(obj);
|
|
|
|
/* Set the dirty bit on the module */
|
|
abobj_set_save_needed(obj_get_module(obj), TRUE);
|
|
|
|
/* If the window is the first one dragged out and
|
|
* its parent (the module) has not been named yet,
|
|
* popup the module name dialog. The only time a
|
|
* module will have not been named by the user is
|
|
* when it is created at the time the first window
|
|
* is dragged from the palette.
|
|
*/
|
|
if( obj_is_window(obj) && ModuleCreated )
|
|
{
|
|
/* Pop up the name dialog */
|
|
proj_show_name_dlg(obj_parent, objxm_get_widget(obj));
|
|
}
|
|
|
|
/*
|
|
* Once an object is successfully dragged out from the
|
|
* palette, disable undo. Object creation is not undo-able.
|
|
*/
|
|
abobj_cancel_undo();
|
|
}
|
|
}
|
|
/* Restore to original cursor */
|
|
ab_set_busy_cursor(FALSE);
|
|
ui_set_busy_cursor(xy_win, FALSE);
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Make a cursor from the palette item's image & cursor
|
|
* and grab the cursor...
|
|
*/
|
|
static Boolean
|
|
initiate_drag(
|
|
Widget w,
|
|
int subtype,
|
|
int *x,
|
|
int *y,
|
|
int *xhot,
|
|
int *yhot
|
|
)
|
|
{
|
|
|
|
static unsigned int max_c_width = 0; /* The maximum cursor size */
|
|
static unsigned int max_c_height = 0;
|
|
static Pixmap item_pixmap = NULL;/* pixmap for cursor */
|
|
static GC p_gc = NULL; /* GC used for pixmap creation */
|
|
char *server_vendor = NULL;
|
|
PalItemInfo *palitem; /* palette obj */
|
|
PalSubtypeInfo *palitem_subptr = NULL;
|
|
Widget item_widget = w; /* widget used for cursor image */
|
|
XRectangle w_rect; /* widget width,height,x,y */
|
|
int c_width, c_height; /* cursor width & height */
|
|
int cc_width, cc_height;/* copycursor width & height */
|
|
Display *dpy;
|
|
Window win;
|
|
int i;
|
|
|
|
if (max_c_width == 0) /* Need to Query server's Cursor constraints */
|
|
{
|
|
server_vendor = XServerVendor(XtDisplay(w));
|
|
|
|
if (strcmp(server_vendor, "Sun Microsystems, Inc.") == 0)
|
|
{
|
|
/*
|
|
* On a Sun X server, a call to XQueryBestSize() will return a limit
|
|
* based on a *hardware* cursor; this is misleading because the
|
|
* server actually supports a much larger software cursor (only limited
|
|
* by the screen size); therefore set the limit based on screen size.
|
|
*/
|
|
max_c_width = WidthOfScreen(XtScreen(w));
|
|
max_c_height = HeightOfScreen(XtScreen(w));
|
|
}
|
|
else
|
|
/* Ask for a big size to get the maximum */
|
|
XQueryBestSize(XtDisplay(w), CursorShape, XtWindow(w), 1000, 1000,
|
|
&max_c_width, &max_c_height);
|
|
|
|
util_dprintf(0, "For Server(%s) Max Cursor size = %dx%d\n",
|
|
server_vendor, max_c_width, max_c_height);
|
|
/*
|
|
* Need to leave room for the outlining of the object's image
|
|
* which is taken care of in x_create_stencil_cursor().
|
|
*/
|
|
max_c_width -= 2;
|
|
max_c_height -= 2;
|
|
}
|
|
|
|
XtVaGetValues(w,
|
|
XmNuserData, &palitem,
|
|
XtNwidth, &(w_rect.width),
|
|
XtNheight, &(w_rect.height),
|
|
XtNx, &(w_rect.x),
|
|
XtNy, &(w_rect.y),
|
|
NULL);
|
|
/*
|
|
* Create Drag Cursor containing item's image
|
|
*/
|
|
|
|
/*
|
|
* If item is a choice setting or textfield, need to
|
|
* use the parent container's image for the cursor;
|
|
* also must translate the cursor x,y position to
|
|
* the parent's rectangle coordinates
|
|
*
|
|
* NOTE:
|
|
* For SpinBox, this is done if the widget passed
|
|
* is not a subclass of spinbox. (We cannot assume
|
|
* what these widgets are composed of).
|
|
*/
|
|
if ((palitem->type == AB_TYPE_CHOICE &&
|
|
XtIsSubclass(w, xmToggleButtonWidgetClass)) ||
|
|
(palitem->type == AB_TYPE_CONTAINER &&
|
|
XtIsSubclass(w, xmCascadeButtonWidgetClass)) ||
|
|
(palitem->type == AB_TYPE_TEXT_FIELD &&
|
|
(XtIsSubclass(w, xmLabelWidgetClass) ||
|
|
XtIsSubclass(w, xmTextFieldWidgetClass))) ||
|
|
(palitem->type == AB_TYPE_SPIN_BOX &&
|
|
!XtIsSubclass(w, dtSpinBoxWidgetClass)) ||
|
|
(palitem->type == AB_TYPE_COMBO_BOX &&
|
|
!XtIsSubclass(w, dtComboBoxWidgetClass)) ||
|
|
(palitem->type == AB_TYPE_SCALE &&
|
|
!XtIsSubclass(w, xmScaleWidgetClass)))
|
|
{
|
|
item_widget = XtParent(w);
|
|
|
|
*x += w_rect.x;
|
|
*y += w_rect.y;
|
|
|
|
XtVaGetValues(item_widget,
|
|
XmNuserData, (XtArgVal)&palitem,
|
|
XtNwidth, (XtArgVal)&(w_rect.width),
|
|
XtNheight, (XtArgVal)&(w_rect.height),
|
|
NULL);
|
|
}
|
|
|
|
dpy = (Display *)XtDisplay(item_widget);
|
|
win = (Window) XtWindow(item_widget);
|
|
|
|
cc_width = AB_cp_cursor_width;
|
|
cc_height = AB_cp_cursor_height;
|
|
|
|
if (dtb_app_resource_rec.use_small_drag_cursor == FALSE)
|
|
{
|
|
c_width = AB_max_item_width + cc_width + 4;
|
|
c_height = AB_max_item_height + cc_height + 4;
|
|
}
|
|
else /* Need Drag Cursor <= 32x32 */
|
|
{
|
|
c_width = 28;
|
|
c_height = 28;
|
|
}
|
|
|
|
/*
|
|
* Ensure cursor is within server limits
|
|
* Note that on some servers (HP, IBM) the cursor limitation
|
|
* will cause some object drag-cursors to be cropped.
|
|
* Unfortunately, for 1.0, there is nothing we can do about
|
|
* this.
|
|
*/
|
|
if (c_width > max_c_width)
|
|
c_width = max_c_width;
|
|
if (c_height > max_c_height)
|
|
c_height = max_c_height;
|
|
|
|
if (!p_gc) /* First-time thru: Create Cursor pixmaps & GC */
|
|
{
|
|
XGCValues values;
|
|
Pixel fg_pixel, bg_pixel;
|
|
|
|
item_pixmap = XCreatePixmap(dpy, win, c_width, c_height, 1);
|
|
|
|
fg_pixel = BlackPixelOfScreen(XtScreen(item_widget));
|
|
bg_pixel = WhitePixelOfScreen(XtScreen(item_widget));
|
|
|
|
values.foreground = fg_pixel;
|
|
values.background = bg_pixel;
|
|
p_gc = XCreateGC(dpy, item_pixmap, GCForeground|GCBackground, &values);
|
|
}
|
|
|
|
/* Find the appropriate palette pixmap for the object subtype */
|
|
for (i=0; i < palitem->num_subinfo; i++)
|
|
if (palitem->subinfo[i].subtype == subtype)
|
|
{
|
|
palitem_subptr = &(palitem->subinfo[i]);
|
|
break;
|
|
}
|
|
|
|
/* This should never happen! */
|
|
if (palitem_subptr == NULL)
|
|
{
|
|
util_dprintf(0,"initiate_drag: could not find palette object subtype info\n");
|
|
return FALSE;
|
|
}
|
|
|
|
if (!palitem_subptr->pixmap)
|
|
{
|
|
XImage *item_image;
|
|
|
|
item_image = build_item_image(item_widget);
|
|
/* no error recovery here. Do we care? */
|
|
|
|
palitem_subptr->pmwidth = w_rect.width + 4;
|
|
palitem_subptr->pmheight = w_rect.height + 4;
|
|
palitem_subptr->pixmap = XCreatePixmap(dpy, win, palitem_subptr->pmwidth,
|
|
palitem_subptr->pmheight, 1);
|
|
|
|
XSetFunction(dpy, p_gc, GXclear);
|
|
XFillRectangle(dpy, palitem_subptr->pixmap, p_gc, 0, 0,
|
|
w_rect.width + 4, w_rect.height + 4);
|
|
|
|
XSetFunction(dpy, p_gc, GXcopy);
|
|
XPutImage(dpy, palitem_subptr->pixmap, p_gc, item_image, 0, 0,
|
|
2, 2, item_image->width, item_image->height);
|
|
|
|
XDestroyImage(item_image);
|
|
}
|
|
|
|
XSetFunction(dpy, p_gc, GXclear);
|
|
XFillRectangle(dpy, item_pixmap, p_gc, 0, 0, c_width, c_height);
|
|
|
|
XSetFunction(dpy, p_gc, GXcopy);
|
|
if (dtb_app_resource_rec.use_small_drag_cursor == FALSE)
|
|
{
|
|
/* Copy the item's image pixmap onto the cursor_pixmap */
|
|
XCopyArea(dpy, palitem_subptr->pixmap, item_pixmap, p_gc, 0, 0,
|
|
c_width, c_height, 0, 0);
|
|
|
|
*xhot = *x + 2;
|
|
*yhot = *y + 2;
|
|
}
|
|
else /* dtb_app_resource_rec.use_small_drag_cursor == TRUE */
|
|
{
|
|
int rw, rh;
|
|
BOOL is_win = FALSE;
|
|
|
|
/* Render a simple shape describing basic type of
|
|
* object is being dragged....
|
|
*/
|
|
switch(palitem->type)
|
|
{
|
|
case AB_TYPE_BASE_WINDOW:
|
|
case AB_TYPE_DIALOG:
|
|
rw = 25;
|
|
rh = 16;
|
|
is_win = TRUE;
|
|
*xhot = 6;
|
|
*yhot = 6;
|
|
break;
|
|
case AB_TYPE_CONTAINER:
|
|
case AB_TYPE_DRAWING_AREA:
|
|
case AB_TYPE_TEXT_PANE:
|
|
case AB_TYPE_TERM_PANE:
|
|
rw = 24;
|
|
rh = 15;
|
|
*xhot = 6;
|
|
*yhot = 6;
|
|
break;
|
|
default: /* Controls */
|
|
rw = 24;
|
|
rh = 10;
|
|
*xhot = 5;
|
|
*yhot = 5;
|
|
}
|
|
XDrawRectangle(dpy, item_pixmap, p_gc, 0, 0, rw, rh);
|
|
if (is_win)
|
|
XDrawLine(dpy, item_pixmap, p_gc, 0, 4, rw, 4);
|
|
|
|
}
|
|
|
|
/* overlay image of copycursor on item image */
|
|
XSetFunction(dpy, p_gc, GXor);
|
|
x_graphics_op(dpy, item_pixmap, p_gc, *xhot, *yhot,
|
|
cc_width, cc_height, AB_cp_cursor_pixmap);
|
|
|
|
/*
|
|
* Ensure hot-spot is within server cursor size
|
|
*/
|
|
if (*xhot > c_width)
|
|
*xhot = c_width - 4;
|
|
if (*yhot > c_height)
|
|
*yhot = c_height - 4;
|
|
|
|
drag_cursor = x_create_stencil_cursor(item_widget, item_pixmap,
|
|
c_width, c_height, *xhot, *yhot);
|
|
|
|
if (XGrabPointer(dpy, win, FALSE,
|
|
ButtonReleaseMask | PointerMotionMask,
|
|
GrabModeAsync, GrabModeAsync, None, drag_cursor,
|
|
CurrentTime) == GrabSuccess)
|
|
return TRUE;
|
|
else
|
|
XFreeCursor(dpy, drag_cursor);
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
/*
|
|
* Get a 1-bit image of the palette item
|
|
*/
|
|
static XImage *
|
|
build_item_image(
|
|
Widget widget
|
|
)
|
|
{
|
|
XRectangle w_rect;
|
|
Window win;
|
|
Display *dpy;
|
|
XImage *get_image,
|
|
*new_image;
|
|
XWindowAttributes attr;
|
|
char *new_image_data;
|
|
|
|
/*
|
|
* Get the item's bounding rect and other associated information.
|
|
*/
|
|
x_get_widget_rect(widget, &w_rect);
|
|
|
|
win = (Window)XtWindow(widget);
|
|
dpy = (Display *)XtDisplay(widget);
|
|
|
|
/*
|
|
* Get the item's image and it's attributes (including visual).
|
|
*/
|
|
get_image = XGetImage(dpy,
|
|
win,
|
|
0,
|
|
0,
|
|
w_rect.width,
|
|
w_rect.height,
|
|
AllPlanes,
|
|
XYPixmap);
|
|
|
|
XGetWindowAttributes(dpy, win, &attr);
|
|
|
|
/*
|
|
* Create a new blank image.
|
|
*/
|
|
new_image_data = (char *)XtMalloc((w_rect.width * w_rect.height) * sizeof(char));
|
|
new_image = XCreateImage(dpy,
|
|
attr.visual,
|
|
1,
|
|
XYBitmap,
|
|
0,
|
|
new_image_data,
|
|
w_rect.width,
|
|
w_rect.height,
|
|
8,
|
|
0);
|
|
|
|
/*
|
|
* Copy the specified planes from the "get" image to the new image.
|
|
*/
|
|
image_copy(widget, get_image, new_image, w_rect.width, 0, 0);
|
|
|
|
XDestroyImage(get_image);
|
|
return(new_image);
|
|
}
|
|
|
|
|
|
/*
|
|
* Copy item's outline image to a 1 bit image
|
|
*/
|
|
static void
|
|
image_copy(
|
|
Widget widget,
|
|
XImage *from_image,
|
|
XImage *to_image,
|
|
int image_width,
|
|
int get_x,
|
|
int put_x
|
|
)
|
|
{
|
|
register int i, j, k, pix;
|
|
Pixel background;
|
|
Pixel foreground;
|
|
Pixel bshadow, tshadow;
|
|
Pixel black, white;
|
|
|
|
/*
|
|
* Only draw bits that are not part of the background and, if
|
|
* color, the depression color (BG2).
|
|
*/
|
|
XtVaGetValues(widget,
|
|
XtNbackground, &background,
|
|
XtNforeground, &foreground,
|
|
XmNbottomShadowColor, &bshadow,
|
|
XmNtopShadowColor, &tshadow,
|
|
NULL);
|
|
|
|
black = BlackPixelOfScreen(XtScreen(widget));
|
|
white = WhitePixelOfScreen(XtScreen(widget));
|
|
|
|
for (i = 0; i < from_image->height; i++)
|
|
{
|
|
for (j = get_x, k = put_x; j < image_width; j++, k++)
|
|
{
|
|
pix = XGetPixel(from_image, j, i);
|
|
if ((pix == foreground ||
|
|
pix == bshadow ||
|
|
pix == tshadow ||
|
|
pix == black ||
|
|
pix == white) &&
|
|
pix != background)
|
|
XPutPixel(to_image, k, i, black);
|
|
else
|
|
XPutPixel(to_image, k, i, white);
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Figure out which ui object the palette item was dropped on
|
|
*/
|
|
static char *
|
|
locate_obj_parent(
|
|
ABObj obj,
|
|
Widget widget,
|
|
int x,
|
|
int y,
|
|
ABObj *parentptr,
|
|
BOOL *ModuleCreated
|
|
)
|
|
{
|
|
ABObj project = proj_get_project();
|
|
ABObj module = proj_get_cur_module();
|
|
ABObj obj_parent = (ABObj) NULL;
|
|
Display *dpy = (Display *)XtDisplay(widget);
|
|
int w_x, w_y;
|
|
DTB_MODAL_ANSWER answer = DTB_ANSWER_NONE;
|
|
STRING errmsg = (STRING) NULL;
|
|
STRING i18n_msg = (STRING) NULL;
|
|
|
|
*ModuleCreated = FALSE;
|
|
|
|
if (obj_is_window(obj))
|
|
{
|
|
if (x_rootxy_inside_widget(palette_widget, x, y))
|
|
return "";
|
|
|
|
if ( module == NULL )
|
|
{
|
|
obj_parent = obj_create(AB_TYPE_MODULE, project);
|
|
obj_set_name(obj_parent, "module");
|
|
abobj_show_tree(obj_parent, FALSE);
|
|
proj_set_cur_module(obj_parent);
|
|
*ModuleCreated = TRUE;
|
|
}
|
|
else
|
|
{
|
|
obj_parent = module;
|
|
}
|
|
obj_append_child(obj_parent, obj);
|
|
|
|
obj->x = x - drag_cursor_xhot;
|
|
obj->y = y - drag_cursor_yhot;
|
|
}
|
|
else
|
|
{
|
|
obj_parent = locate_obj_at_rootxy(x, y, &w_x, &w_y);
|
|
|
|
obj->x = w_x - drag_cursor_xhot;
|
|
obj->y = w_y - drag_cursor_yhot;
|
|
|
|
/* If not dropped on an object, but is still within
|
|
* palette, just ignore the drag...
|
|
*/
|
|
if (obj_parent == NULL &&
|
|
x_rootxy_inside_widget(palette_widget, x, y))
|
|
return "";
|
|
|
|
if (obj_is_menubar(obj))
|
|
{
|
|
AB_TRAVERSAL trav;
|
|
ABObj winobj;
|
|
ABObj nobj;
|
|
|
|
if (obj_parent != NULL)
|
|
{
|
|
winobj = obj_parent;
|
|
while(!(obj_is_window(winobj) && !obj_is_sub(winobj)))
|
|
winobj = obj_get_parent(winobj);
|
|
|
|
if (!obj_is_base_win(winobj))
|
|
obj_parent = NULL;
|
|
else /* Check to make sure there isn't already a Menubar for
|
|
* this window
|
|
*/
|
|
{
|
|
for (trav_open(&trav, winobj, AB_TRAV_UI);
|
|
(nobj = trav_next(&trav)) != NULL; )
|
|
if (obj_is_menubar(nobj))
|
|
{
|
|
i18n_msg = catgets(Dtb_project_catd, 100, 11,
|
|
"There is already a Menubar for this window.");
|
|
|
|
/* If we have an old buffer lying around, free it */
|
|
if (errmsg != (STRING) NULL)
|
|
util_free(errmsg);
|
|
|
|
errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
|
|
strcpy(errmsg, i18n_msg);
|
|
return (errmsg);
|
|
}
|
|
|
|
obj_parent = objxm_comp_get_subobj(winobj, AB_CFG_MENU_PARENT_OBJ);
|
|
}
|
|
}
|
|
if (obj_parent == NULL)
|
|
{
|
|
i18n_msg = catgets(Dtb_project_catd, 100, 15,
|
|
"Menubars must be dropped on a Main Window.");
|
|
|
|
/* If we have an old buffer lying around, free it */
|
|
if (errmsg != (STRING) NULL)
|
|
util_free(errmsg);
|
|
|
|
errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
|
|
strcpy(errmsg, i18n_msg);
|
|
return (errmsg);
|
|
}
|
|
|
|
}
|
|
else if (obj_is_container(obj) && !obj_is_control_panel(obj))
|
|
{
|
|
if (obj_parent == NULL ||
|
|
(!(obj_is_container(obj_parent) &&
|
|
obj_is_sub(obj_parent) &&
|
|
obj_is_window(obj_get_root(obj_parent)) &&
|
|
!obj_is_file_chooser(obj_parent))))
|
|
{
|
|
i18n_msg = catgets(Dtb_project_catd, 100, 12,
|
|
"Containers must be dropped on\na Main Window or Custom Dialog.");
|
|
/* If we have an old buffer lying around, free it */
|
|
if (errmsg != (STRING) NULL)
|
|
util_free(errmsg);
|
|
|
|
errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
|
|
strcpy(errmsg, i18n_msg);
|
|
return (errmsg);
|
|
}
|
|
}
|
|
else if (obj_is_pane(obj))
|
|
{
|
|
if (obj_parent != NULL &&
|
|
(obj_is_pane(obj_parent) &&
|
|
!obj_is_window(obj_get_root(obj_parent))))
|
|
{
|
|
ABObj grandparent = NULL;
|
|
ABObj great_grandparent = NULL;
|
|
grandparent = obj_get_parent(obj_get_root(obj_parent));
|
|
great_grandparent = obj_get_parent(grandparent);
|
|
|
|
/* The child is a textpane, termpane, or drawing area
|
|
* and the parent (object being dropped upon) is a
|
|
* control pane that is not part of a panedWindow.
|
|
*/
|
|
if (!obj_is_control_panel(obj) &&
|
|
obj_is_control_panel(obj_parent) &&
|
|
!obj_is_paned_win(grandparent))
|
|
{
|
|
/* If the parent of obj_parent is a layered pane
|
|
* then we have to check if the layered pane is
|
|
* a child of a panedwindow. If so, then we should
|
|
* ask the user whether he wants to make the pane
|
|
* a child of the control pane, a new layer, or
|
|
* a new pane in the paned window.
|
|
*/
|
|
if (obj_is_layers(grandparent) &&
|
|
obj_is_paned_win(great_grandparent))
|
|
{
|
|
dtb_palette_chld_layr_pw_msg_initialize(
|
|
&dtb_palette_chld_layr_pw_msg);
|
|
answer = dtb_show_modal_message(
|
|
(Widget)obj_parent->ui_handle,
|
|
&dtb_palette_chld_layr_pw_msg,
|
|
NULL, NULL, NULL);
|
|
switch(answer)
|
|
{
|
|
/* Create as a child of the control pane */
|
|
case DTB_ANSWER_ACTION1:
|
|
break;
|
|
|
|
/* Create as a new layer */
|
|
case DTB_ANSWER_ACTION2:
|
|
obj_parent = abobj_handle_layered_pane(obj, obj_parent);
|
|
break;
|
|
|
|
/* Create as a new pane in the paned window */
|
|
case DTB_ANSWER_ACTION3:
|
|
obj_parent = great_grandparent;
|
|
break;
|
|
|
|
case DTB_ANSWER_CANCEL:
|
|
return "";
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Popup Modal Message and wait for answer */
|
|
dtb_palette_chld_or_layr_msg_initialize(
|
|
&dtb_palette_chld_or_layr_msg);
|
|
answer = dtb_show_modal_message(
|
|
(Widget)obj_parent->ui_handle,
|
|
&dtb_palette_chld_or_layr_msg,
|
|
NULL, NULL, NULL);
|
|
switch(answer)
|
|
{
|
|
case DTB_ANSWER_ACTION1: /* As Child */
|
|
break;
|
|
|
|
case DTB_ANSWER_ACTION2: /* As Layered Pane */
|
|
obj_parent = abobj_handle_layered_pane(obj, obj_parent);
|
|
break;
|
|
|
|
case DTB_ANSWER_CANCEL:
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
/* The child is a control pane or the parent is
|
|
* not a control pane (i.e. a textpane child of
|
|
* a control pane). The parent is not part of a
|
|
* panedWindow.
|
|
*/
|
|
else if (!obj_is_paned_win(grandparent))
|
|
{
|
|
/* If Pane was dropped on a Pane which is a NORMAL child of
|
|
* a Control Pane, then use the Control Pane as the actual
|
|
* parent instead of the pane.
|
|
*/
|
|
if (obj_is_control_panel(obj_get_root(grandparent)))
|
|
{
|
|
obj_parent = grandparent;
|
|
}
|
|
|
|
/* Check if the grandparent is a layered pane.
|
|
* If so, then we have to check it is part of
|
|
* a panedwindow. If it is, then we need to
|
|
* ask the user whether to create the pane as
|
|
* a layered pane or a new pane in the paned
|
|
* window.
|
|
*/
|
|
if (obj_is_layers(grandparent) &&
|
|
obj_is_paned_win(great_grandparent))
|
|
{
|
|
dtb_palette_layr_pw_msg_initialize(
|
|
&dtb_palette_layr_pw_msg);
|
|
answer = dtb_show_modal_message(
|
|
(Widget)obj_parent->ui_handle,
|
|
&dtb_palette_layr_pw_msg,
|
|
NULL, NULL, NULL);
|
|
switch(answer)
|
|
{
|
|
case DTB_ANSWER_ACTION1: /* Layered Pane */
|
|
obj_parent = abobj_handle_layered_pane(obj, obj_parent);
|
|
break;
|
|
|
|
case DTB_ANSWER_ACTION2: /* PanedWindow Pane */
|
|
obj_parent = grandparent;
|
|
break;
|
|
|
|
case DTB_ANSWER_CANCEL:
|
|
return "";
|
|
|
|
case DTB_ANSWER_HELP:
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* Popup Modal Message and wait for answer */
|
|
dtb_palette_layered_pane_msg_initialize(
|
|
&dtb_palette_layered_pane_msg);
|
|
answer = dtb_show_modal_message(
|
|
(Widget)obj_parent->ui_handle,
|
|
&dtb_palette_layered_pane_msg,
|
|
NULL, NULL, NULL);
|
|
switch(answer)
|
|
{
|
|
case DTB_ANSWER_ACTION2: /* Layered Pane */
|
|
obj_parent = abobj_handle_layered_pane(obj, obj_parent);
|
|
break;
|
|
|
|
case DTB_ANSWER_CANCEL: /* Cancel */
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
/* A termpane, textpane, or draw area is being dropped
|
|
* on another pane (not control pane) and that pane
|
|
* is inside a paned window.
|
|
*
|
|
* OR
|
|
*
|
|
* The object being dragged is a control pane and
|
|
* the parent is part of a panedWindow.
|
|
*/
|
|
else if (!obj_is_control_panel(obj_parent) ||
|
|
obj_is_control_panel(obj))
|
|
{
|
|
dtb_palette_layr_pw_msg_initialize(
|
|
&dtb_palette_layr_pw_msg);
|
|
answer = dtb_show_modal_message(
|
|
(Widget)obj_parent->ui_handle,
|
|
&dtb_palette_layr_pw_msg,
|
|
NULL, NULL, NULL);
|
|
switch(answer)
|
|
{
|
|
case DTB_ANSWER_ACTION1: /* Layered Pane */
|
|
obj_parent = abobj_handle_layered_pane(obj, obj_parent);
|
|
break;
|
|
|
|
case DTB_ANSWER_ACTION2: /* PanedWindow Pane */
|
|
obj_parent = grandparent;
|
|
break;
|
|
|
|
case DTB_ANSWER_CANCEL:
|
|
return "";
|
|
|
|
case DTB_ANSWER_HELP:
|
|
break;
|
|
}
|
|
}
|
|
/* The obj is a textpane, termpane, or draw area
|
|
* and the parent of obj_parent is a panedWindow.
|
|
*/
|
|
else
|
|
{
|
|
dtb_palette_chld_layr_pw_msg_initialize(
|
|
&dtb_palette_chld_layr_pw_msg);
|
|
answer = dtb_show_modal_message(
|
|
(Widget)obj_parent->ui_handle,
|
|
&dtb_palette_chld_layr_pw_msg,
|
|
NULL, NULL, NULL);
|
|
switch(answer)
|
|
{
|
|
/* Create as a child of the control pane */
|
|
case DTB_ANSWER_ACTION1:
|
|
break;
|
|
|
|
/* Create as a new layer */
|
|
case DTB_ANSWER_ACTION2:
|
|
obj_parent = abobj_handle_layered_pane(obj, obj_parent);
|
|
break;
|
|
|
|
/* Create as a new pane in the paned window */
|
|
case DTB_ANSWER_ACTION3:
|
|
obj_parent = obj_get_parent(obj_parent);
|
|
break;
|
|
|
|
case DTB_ANSWER_CANCEL:
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* Dropping panes onto a group
|
|
*/
|
|
else if (obj_parent != NULL && obj_is_group(obj_parent))
|
|
{
|
|
if (obj_is_control_panel(obj))
|
|
{
|
|
i18n_msg = catgets(Dtb_project_catd, 100, 59,
|
|
"Control Panes must be dropped on a Main Window,\nCustom Dialog, or another pane.");
|
|
|
|
/* If we have an old buffer lying around, free it */
|
|
|
|
if (errmsg != (STRING) NULL)
|
|
util_free(errmsg);
|
|
|
|
errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
|
|
strcpy(errmsg, i18n_msg);
|
|
return (errmsg);
|
|
}
|
|
else
|
|
{
|
|
dtb_palette_child_of_group_msg_initialize(
|
|
&dtb_palette_child_of_group_msg);
|
|
answer = dtb_show_modal_message(
|
|
(Widget)obj_parent->ui_handle,
|
|
&dtb_palette_child_of_group_msg,
|
|
NULL, NULL, NULL);
|
|
switch(answer)
|
|
{
|
|
/* OK - Create as a child of group */
|
|
case DTB_ANSWER_ACTION1:
|
|
break;
|
|
|
|
case DTB_ANSWER_CANCEL:
|
|
return "";
|
|
}
|
|
}
|
|
}
|
|
else if (obj_parent == NULL ||
|
|
(!(obj_is_container(obj_parent) &&
|
|
!obj_is_menubar(obj_parent))))
|
|
{
|
|
i18n_msg = catgets(Dtb_project_catd, 100, 13,
|
|
"Panes must be dropped on a Main Window,\nCustom Dialog, or another pane.");
|
|
|
|
/* If we have an old buffer lying around, free it */
|
|
|
|
if (errmsg != (STRING) NULL)
|
|
util_free(errmsg);
|
|
|
|
errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
|
|
strcpy(errmsg, i18n_msg);
|
|
return (errmsg);
|
|
}
|
|
|
|
}
|
|
else if (obj_is_control(obj))
|
|
{
|
|
if (obj_parent == NULL ||
|
|
(!obj_is_control_panel(obj_get_root(obj_parent)) &&
|
|
!obj_is_group(obj_get_root(obj_parent))))
|
|
{
|
|
i18n_msg = catgets(Dtb_project_catd, 100, 14,
|
|
"Controls must be dropped on\na Control Pane or Group.");
|
|
/* If we have an old buffer lying around, free it */
|
|
if (errmsg != (STRING) NULL)
|
|
util_free(errmsg);
|
|
|
|
errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
|
|
strcpy(errmsg, i18n_msg);
|
|
return (errmsg);
|
|
}
|
|
|
|
}
|
|
else
|
|
{
|
|
i18n_msg = catgets(Dtb_project_catd, 100, 16,
|
|
"Unknown object type.");
|
|
|
|
/* If we have an old buffer lying around, free it */
|
|
if (errmsg != (STRING) NULL)
|
|
util_free(errmsg);
|
|
|
|
errmsg = (STRING) util_malloc(strlen(i18n_msg) + 1);
|
|
strcpy(errmsg, i18n_msg);
|
|
return (errmsg);
|
|
}
|
|
|
|
obj_append_child(obj_parent, obj);
|
|
}
|
|
|
|
*parentptr = obj_parent;
|
|
return NULL;
|
|
|
|
}
|
|
|
|
ABObj
|
|
locate_obj_at_rootxy(
|
|
int x,
|
|
int y,
|
|
int *p_wx,
|
|
int *p_wy
|
|
)
|
|
{
|
|
ABObj project = proj_get_project();
|
|
ABObj obj = project;
|
|
AB_TRAVERSAL trav;
|
|
Window window;
|
|
Widget widget;
|
|
|
|
if (obj == NULL)
|
|
return NULL;
|
|
|
|
window = x_xwin_at_rootxy(AB_toplevel, x, y, p_wx, p_wy);
|
|
if (window == 0)
|
|
return NULL;
|
|
|
|
for (trav_open(&trav, obj, AB_TRAV_UI);
|
|
(obj = trav_next(&trav)) != NULL; )
|
|
{
|
|
widget = (Widget)obj->ui_handle;
|
|
|
|
if (widget != NULL &&
|
|
XtIsRealized(widget) &&
|
|
XtWindow(widget) == window)
|
|
{
|
|
return obj;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Are we in the draw area of any browser window ?
|
|
*/
|
|
if (aob_is_browser_win(project, window))
|
|
{
|
|
ABObj browser_obj;
|
|
|
|
/*
|
|
* Get the ABObj that the ptr is currently above
|
|
*/
|
|
browser_obj = aob_get_object_from_xy(project, window, *p_wx, *p_wy);
|
|
|
|
if (browser_obj)
|
|
{
|
|
/*
|
|
* Return the config parent of the ABObj.
|
|
* This needs to be done because the ABObj shown on the
|
|
* browser and the ABObj of the interface objects as
|
|
* seen by the user are different things.
|
|
*
|
|
* Also, since we are dealing with browser coordinates
|
|
* here (and not precise positions on the parent obj),
|
|
* set the position (x,y) to some default.
|
|
*
|
|
* drag_cursor_[x,y]hot is added here because it is
|
|
* subtracted later to determine the exact position
|
|
* of the object.
|
|
*/
|
|
*p_wx = AB_DEFAULT_X + drag_cursor_xhot;
|
|
*p_wy = AB_DEFAULT_Y + drag_cursor_yhot;
|
|
return (objxm_comp_get_subobj(browser_obj, AB_CFG_PARENT_OBJ));
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|