713 lines
16 KiB
C
713 lines
16 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 libraries and programs; if not, write
|
|
* to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
|
|
* Floor, Boston, MA 02110-1301 USA
|
|
*/
|
|
|
|
/*
|
|
* $XConsortium: abobj_select.c /main/3 1995/11/06 17:17:19 rswiston $
|
|
*
|
|
* @(#)abobj_select.c 1.37 15 Feb 1994 cde_app_builder/src/ab
|
|
*
|
|
* 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.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
***********************************************************************
|
|
* ab_select.c - Implements "select" behavior of a UI object
|
|
*
|
|
*
|
|
***********************************************************************
|
|
*/
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <X11/Intrinsic.h>
|
|
#include <X11/cursorfont.h>
|
|
#include <X11/StringDefs.h>
|
|
#include <Xm/Xm.h>
|
|
#include <Xm/ScrolledW.h>
|
|
#include <ab_private/trav.h>
|
|
#include <ab_private/ui_util.h>
|
|
#include <ab_private/x_util.h>
|
|
#include <ab_private/objxm.h>
|
|
#include <ab_private/proj.h>
|
|
#include "abobjP.h"
|
|
|
|
const int AB_selected_rect_size = 7;
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Private Function Declarations **
|
|
** **
|
|
**************************************************************************/
|
|
|
|
static void select_feedback(
|
|
ABObj selObj,
|
|
BOOL on
|
|
);
|
|
static void select_footer(
|
|
ABObj obj,
|
|
BOOL on
|
|
);
|
|
static void turnon_select_feedback(
|
|
ABObj selObj,
|
|
BOOL resizable
|
|
);
|
|
|
|
static void turnoff_select_feedback(
|
|
ABObj selObj,
|
|
BOOL resizable
|
|
);
|
|
|
|
static void draw_select_feedback(
|
|
ABObj selObj,
|
|
BOOL resizable
|
|
);
|
|
/*
|
|
* Event Handlers
|
|
*/
|
|
static void monitor_cursor(
|
|
Widget w,
|
|
XtPointer clientdata,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
);
|
|
|
|
static void select_feedback_redraw(
|
|
Widget w,
|
|
XtPointer clientdata,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
);
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Private Data **
|
|
** **
|
|
**************************************************************************/
|
|
static GC AB_grab_handle_gc;
|
|
static XRectangle rb_rect;
|
|
static Widget rb_widget;
|
|
static BOOL first_time = TRUE;
|
|
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Function Definitions **
|
|
** **
|
|
**************************************************************************/
|
|
|
|
/*
|
|
* cause the object to appear "selected"
|
|
*/
|
|
void
|
|
abobj_select(
|
|
ABObj obj
|
|
)
|
|
{
|
|
AB_CONTAINER_TYPE cont_type;
|
|
ABObj rootObj = obj_get_root(obj);
|
|
ABObj selObj;
|
|
|
|
/* Make sure the window is on screen */
|
|
if (obj_is_window(rootObj))
|
|
ui_win_front(objxm_get_widget(rootObj));
|
|
|
|
proj_set_cur_module(obj_get_module(obj));
|
|
|
|
if (obj_is_selected(rootObj))
|
|
return;
|
|
|
|
obj_set_is_selected(rootObj, TRUE);
|
|
|
|
if (obj_is_module(rootObj))
|
|
return;
|
|
|
|
if (obj_is_item(obj))
|
|
{
|
|
rootObj = obj_get_root(obj_get_parent(obj));
|
|
obj_set_is_selected(rootObj, TRUE);
|
|
}
|
|
|
|
selObj = objxm_comp_get_subobj(rootObj, AB_CFG_SELECT_OBJ);
|
|
|
|
if (selObj == NULL)
|
|
{
|
|
if (util_get_verbosity() > 0)
|
|
fprintf(stderr, "abobj_select: %s :no selection object\n",
|
|
obj_get_name(rootObj));
|
|
return;
|
|
}
|
|
|
|
if (obj_is_window(rootObj))
|
|
select_footer(selObj, True);
|
|
else
|
|
turnon_select_feedback(selObj, abobj_is_directly_resizable(rootObj));
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* remove "select" feedback from object
|
|
*/
|
|
void
|
|
abobj_deselect(
|
|
ABObj obj
|
|
)
|
|
{
|
|
AB_CONTAINER_TYPE cont_type;
|
|
ABObj rootObj = obj_get_root(obj);
|
|
ABObj selObj;
|
|
|
|
if (!obj_is_selected(rootObj))
|
|
return;
|
|
|
|
obj_set_is_selected(rootObj, FALSE);
|
|
|
|
if (obj_is_module(obj))
|
|
return;
|
|
|
|
if (obj_is_item(obj))
|
|
{
|
|
rootObj = obj_get_root(obj_get_parent(obj));
|
|
obj_set_is_selected(rootObj, FALSE);
|
|
}
|
|
|
|
selObj = objxm_comp_get_subobj(rootObj, AB_CFG_SELECT_OBJ);
|
|
|
|
if (selObj == NULL)
|
|
{
|
|
if (util_get_verbosity() > 0)
|
|
fprintf(stderr, "abobj_deselect: %s :no selection object\n",
|
|
obj_get_name(rootObj));
|
|
return;
|
|
}
|
|
|
|
if (obj_is_window(rootObj))
|
|
select_footer(selObj, False);
|
|
else
|
|
turnoff_select_feedback(selObj, abobj_is_directly_resizable(rootObj));
|
|
|
|
}
|
|
|
|
void
|
|
abobj_deselect_all(
|
|
ABObj root
|
|
)
|
|
{
|
|
ABObj obj = root;
|
|
AB_TRAVERSAL trav;
|
|
|
|
if (obj == NULL)
|
|
return;
|
|
|
|
for (trav_open(&trav, obj, AB_TRAV_UI);
|
|
(obj = trav_next(&trav)) != NULL; )
|
|
{
|
|
if (obj_is_selected(obj))
|
|
abobj_deselect(obj);
|
|
}
|
|
trav_close(&trav);
|
|
|
|
/*
|
|
* The browser displays the module as well,
|
|
* so we must deselect it when abobj_deselect_all() is
|
|
* called
|
|
*/
|
|
if (obj_is_project(root))
|
|
{
|
|
for (trav_open(&trav, root, AB_TRAV_MODULES);
|
|
(obj = trav_next(&trav)) != NULL; )
|
|
{
|
|
if (obj_is_selected(obj))
|
|
abobj_deselect(obj);
|
|
}
|
|
trav_close(&trav);
|
|
}
|
|
else
|
|
{
|
|
ABObj module = obj_get_module(root);
|
|
|
|
if (obj_is_selected(module))
|
|
abobj_deselect(module);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* abobj_get_selected- Return an array containing ptrs to
|
|
* all selected ABObjs in a given
|
|
*/
|
|
int
|
|
abobj_get_selected(
|
|
ABObj root,
|
|
BOOL include_root,
|
|
BOOL include_items,
|
|
ABSelectedRec *sel
|
|
)
|
|
{
|
|
ABObj obj = root;
|
|
AB_TRAVERSAL trav;
|
|
|
|
sel->count = 0;
|
|
sel->list = NULL;
|
|
|
|
if (obj == NULL)
|
|
return -1;
|
|
|
|
/* First count up all selected objs */
|
|
for (trav_open(&trav, obj, AB_TRAV_SALIENT_UI);
|
|
(obj = trav_next(&trav)) != NULL; )
|
|
{
|
|
if (obj_is_selected(obj) &&
|
|
!(obj_is_item(obj) && !include_items) &&
|
|
!(obj == root && !include_root))
|
|
(sel->count)++;
|
|
}
|
|
trav_close(&trav);
|
|
|
|
/* Now alloc & fill array with selected objs */
|
|
obj = root;
|
|
if (sel->count > 0)
|
|
{
|
|
int i = 0;
|
|
sel->list = (ABObj*)XtMalloc(sel->count * sizeof(ABObj));
|
|
|
|
for (trav_open(&trav, obj, AB_TRAV_SALIENT_UI);
|
|
(obj = trav_next(&trav)) != NULL; )
|
|
{
|
|
if (obj_is_selected(obj) &&
|
|
!(obj_is_item(obj) && !include_items) &&
|
|
!(obj == root && !include_root))
|
|
sel->list[i++] = obj;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/*
|
|
* Sort list of selected objects
|
|
*/
|
|
void
|
|
abobj_sort_sel_list(
|
|
ABObj *sel_list,
|
|
int sel_count,
|
|
int sort
|
|
)
|
|
{
|
|
int i, j;
|
|
int x1, y1, x2, y2;
|
|
ABObj tmp_obj;
|
|
|
|
/*
|
|
* Sort the list of objects based on x and y values
|
|
*/
|
|
for (i = 0; i < sel_count; i++)
|
|
{
|
|
for (j = i; j < sel_count; j++)
|
|
{
|
|
x1 = obj_get_x(sel_list[i]);
|
|
y1 = obj_get_y(sel_list[i]);
|
|
x2 = obj_get_x(sel_list[j]);
|
|
y2 = obj_get_y(sel_list[j]);
|
|
|
|
if (sort == XSORT)
|
|
{
|
|
if (x2 < x1 || (x2 == x1 && y2 < y1))
|
|
{
|
|
tmp_obj = sel_list[i];
|
|
sel_list[i] = sel_list[j];
|
|
sel_list[j] = tmp_obj;
|
|
}
|
|
} else
|
|
{
|
|
if (y2 < y1 || (y2 == y1 && x2 < x1))
|
|
{
|
|
tmp_obj = sel_list[i];
|
|
sel_list[i] = sel_list[j];
|
|
sel_list[j] = tmp_obj;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
* render select feedback for objects which do not have grab handles
|
|
*/
|
|
static void
|
|
select_feedback(
|
|
ABObj selObj,
|
|
BOOL on
|
|
)
|
|
{
|
|
Widget selWidget;
|
|
Pixel contrast;
|
|
|
|
selWidget = (Widget)selObj->ui_handle;
|
|
|
|
if (selWidget == NULL)
|
|
{
|
|
if (util_get_verbosity() > 0)
|
|
fprintf(stderr, "select_feedback: %s :no selection widget\n",
|
|
obj_get_name(selObj));
|
|
return;
|
|
}
|
|
|
|
if (on)
|
|
{
|
|
contrast = x_contrast_color(selWidget);
|
|
XtVaSetValues(selWidget,
|
|
XmNborderWidth, (XtArgVal)2,
|
|
XmNborderColor, contrast,
|
|
NULL);
|
|
}
|
|
else
|
|
XtVaSetValues(selWidget, XmNborderWidth, (XtArgVal)0, NULL);
|
|
|
|
}
|
|
|
|
static void
|
|
select_footer(
|
|
ABObj selObj,
|
|
BOOL on
|
|
)
|
|
{
|
|
Widget selWidget;
|
|
Pixel contrast;
|
|
XmString xmstr;
|
|
|
|
if (!(selWidget = (Widget)selObj->ui_handle))
|
|
return;
|
|
|
|
if (on)
|
|
{
|
|
contrast = x_contrast_color(selWidget);
|
|
|
|
xmstr = XmStringCreateLocalized("Window SELECTED ");
|
|
XtVaSetValues(selWidget,
|
|
XmNlabelString, xmstr,
|
|
XmNforeground, contrast,
|
|
NULL);
|
|
XmStringFree(xmstr);
|
|
}
|
|
else /* off */
|
|
{
|
|
xmstr = XmStringCreateLocalized(" ");
|
|
XtVaSetValues(selWidget,
|
|
XmNlabelString, xmstr,
|
|
NULL);
|
|
XmStringFree(xmstr);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/*
|
|
* set event handlers to draw the grab handles on
|
|
* the object's selection widget
|
|
*/
|
|
static void
|
|
turnon_select_feedback(
|
|
ABObj selObj,
|
|
BOOL resizable
|
|
)
|
|
{
|
|
Widget selWidget;
|
|
|
|
selWidget = (Widget)selObj->ui_handle;
|
|
|
|
if (selWidget == NULL)
|
|
return;
|
|
|
|
draw_select_feedback(selObj, resizable);
|
|
|
|
XtAddEventHandler(selWidget, StructureNotifyMask | ExposureMask, FALSE,
|
|
select_feedback_redraw, (XtPointer)(uintptr_t) resizable);
|
|
|
|
XtAddEventHandler(selWidget, PointerMotionMask, FALSE,
|
|
monitor_cursor, (XtPointer)selObj);
|
|
|
|
}
|
|
|
|
/*
|
|
* remove the expose event handlers and clear the
|
|
* grab handles off the widget
|
|
*/
|
|
static void
|
|
turnoff_select_feedback(
|
|
ABObj selObj,
|
|
BOOL resizable
|
|
)
|
|
{
|
|
XRectangle w_rect;
|
|
Widget selWidget;
|
|
|
|
selWidget = (Widget)selObj->ui_handle;
|
|
|
|
if (selWidget == NULL)
|
|
return;
|
|
|
|
x_get_widget_rect(selWidget, &w_rect);
|
|
|
|
XtRemoveEventHandler(selWidget, StructureNotifyMask | ExposureMask, FALSE,
|
|
select_feedback_redraw, (XtPointer)(uintptr_t) resizable);
|
|
|
|
XtRemoveEventHandler(selWidget, PointerMotionMask, FALSE,
|
|
monitor_cursor, (XtPointer)selObj);
|
|
|
|
/* Make sure cursor is reset to normal */
|
|
monitor_cursor(selWidget, selObj, NULL, NULL);
|
|
|
|
ui_refresh_widget_tree(selWidget);
|
|
|
|
}
|
|
|
|
/*
|
|
* Draw the grabhandles on the selection-widget for the object
|
|
*/
|
|
static void
|
|
draw_select_feedback(
|
|
ABObj selObj,
|
|
BOOL resizable
|
|
)
|
|
{
|
|
ABObj obj;
|
|
Widget selWidget;
|
|
Dimension width = 0;
|
|
Dimension height = 0;
|
|
int x0,y0,x1,y1;
|
|
int border_w;
|
|
Display *display;
|
|
Drawable drawable;
|
|
XGCValues gc_val;
|
|
unsigned long bg, color_contrast;
|
|
int grabbox_size;
|
|
|
|
obj = obj_get_root(selObj);
|
|
|
|
selWidget = (Widget)selObj->ui_handle;
|
|
|
|
if ( (obj_is_drawing_area(obj) || obj_is_text_pane(obj)) &&
|
|
(obj_has_hscrollbar(obj) || obj_has_vscrollbar(obj)) )
|
|
{
|
|
ABObj swobj = objxm_comp_get_subobj(obj, AB_CFG_SIZE_OBJ);
|
|
Widget cwidget;
|
|
|
|
XtVaGetValues((Widget)swobj->ui_handle,
|
|
XmNclipWindow, &cwidget,
|
|
NULL);
|
|
|
|
if (cwidget)
|
|
{
|
|
XtVaGetValues(cwidget,
|
|
XtNwidth, &width,
|
|
XtNheight, &height,
|
|
NULL);
|
|
|
|
XtVaGetValues(selWidget,
|
|
XtNbackground, &bg,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
if (height == 0 || width == 0)
|
|
XtVaGetValues(selWidget,
|
|
XtNwidth, &width,
|
|
XtNheight, &height,
|
|
XtNbackground,&bg,
|
|
NULL);
|
|
|
|
/*
|
|
if (obj_is_control(obj))
|
|
grabbox_size = (AB_selected_rect_size / 2) + 1;
|
|
else
|
|
*/
|
|
grabbox_size = AB_selected_rect_size;
|
|
|
|
if (obj_is_control(obj))
|
|
border_w = 1;
|
|
else
|
|
border_w = 2;
|
|
|
|
x0 = y0 = border_w - 1;
|
|
x1 = width - grabbox_size;
|
|
y1 = height - grabbox_size;
|
|
|
|
color_contrast = x_contrast_color(selWidget);
|
|
|
|
display = (Display *) XtDisplay(selWidget);
|
|
drawable = (Drawable) XtWindow(selWidget);
|
|
|
|
if (!AB_grab_handle_gc)
|
|
{
|
|
gc_val.foreground = color_contrast;
|
|
gc_val.line_width = border_w;
|
|
gc_val.function = GXcopy;
|
|
gc_val.subwindow_mode = IncludeInferiors;
|
|
AB_grab_handle_gc = XCreateGC(display, drawable,
|
|
(GCFunction | GCForeground | GCLineWidth | GCSubwindowMode),
|
|
&gc_val);
|
|
}
|
|
else
|
|
{
|
|
XSetForeground(display, AB_grab_handle_gc, color_contrast);
|
|
XSetLineAttributes(display, AB_grab_handle_gc, border_w,
|
|
LineSolid, CapButt, JoinMiter);
|
|
}
|
|
|
|
/* Draw Select Rectangle */
|
|
XDrawRectangle(display, drawable, AB_grab_handle_gc,
|
|
x0, y0,
|
|
width-border_w, height-border_w);
|
|
|
|
/* If Obj is Resizable, Draw Resize handles */
|
|
if (resizable)
|
|
{
|
|
/* North-West */
|
|
XFillRectangle(display, drawable, AB_grab_handle_gc, x0, y0,
|
|
grabbox_size, grabbox_size);
|
|
/* South-West */
|
|
XFillRectangle(display, drawable, AB_grab_handle_gc, x0, y1,
|
|
grabbox_size, grabbox_size);
|
|
/* North-East */
|
|
XFillRectangle(display, drawable, AB_grab_handle_gc, x1, y0,
|
|
grabbox_size, grabbox_size);
|
|
/* South-East */
|
|
XFillRectangle(display, drawable, AB_grab_handle_gc, x1, y1,
|
|
grabbox_size, grabbox_size);
|
|
/* North */
|
|
XFillRectangle(display, drawable, AB_grab_handle_gc, (x0+x1)/2, y0,
|
|
grabbox_size, grabbox_size);
|
|
/* South */
|
|
XFillRectangle(display, drawable, AB_grab_handle_gc, (x0+x1)/2, y1,
|
|
grabbox_size, grabbox_size);
|
|
/* West */
|
|
XFillRectangle(display, drawable, AB_grab_handle_gc, x0, (y0+y1)/2,
|
|
grabbox_size, grabbox_size);
|
|
/* East */
|
|
XFillRectangle(display, drawable, AB_grab_handle_gc, x1, (y0+y1)/2,
|
|
grabbox_size, grabbox_size);
|
|
}
|
|
XFlush(display);
|
|
|
|
}
|
|
|
|
/*
|
|
* EventHandler: detect when cursor moves over grab handles
|
|
*/
|
|
static void
|
|
monitor_cursor(
|
|
Widget selWidget,
|
|
XtPointer clientdata,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
)
|
|
{
|
|
ABObj selObj = (ABObj)clientdata;
|
|
XMotionEvent *mevent;
|
|
Cursor resize_cursor;
|
|
RESIZE_DIR dir;
|
|
static Boolean cursor_changed = FALSE;
|
|
Window win;
|
|
Display *dpy;
|
|
|
|
|
|
if (event != NULL)
|
|
{
|
|
if (event->type != MotionNotify)
|
|
return;
|
|
else
|
|
mevent = (XMotionEvent*)event;
|
|
|
|
dir = abobjP_find_resize_direction(selObj, selWidget, event);
|
|
}
|
|
else
|
|
dir = NONE;
|
|
|
|
dpy = XtDisplay(selWidget);
|
|
win = XtWindow(selWidget);
|
|
|
|
if (dir == NONE)
|
|
{
|
|
if (cursor_changed)
|
|
{
|
|
XUndefineCursor(dpy, win);
|
|
cursor_changed = FALSE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ((resize_cursor = abobjP_get_resize_cursor(selWidget, dir)) != 0)
|
|
{
|
|
XDefineCursor(dpy, win, resize_cursor);
|
|
cursor_changed = TRUE;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/*
|
|
* EventHandler: render grab handles on widget for Expose events
|
|
*/
|
|
static void
|
|
select_feedback_redraw(
|
|
Widget selWidget,
|
|
XtPointer clientdata,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
)
|
|
{
|
|
ABObj selObj = NULL;
|
|
BOOL resizable = (BOOL)((uintptr_t) clientdata);
|
|
Boolean redraw = FALSE;
|
|
|
|
selObj = objxm_get_obj_from_widget(selWidget);
|
|
|
|
if (event->type == ConfigureNotify)
|
|
{
|
|
XRectangle w_rect;
|
|
x_get_widget_rect(selWidget, &w_rect);
|
|
|
|
/* ClearArea is roundtrip, should use XOR..*/
|
|
ui_refresh_widget_tree(selWidget);
|
|
redraw = TRUE;
|
|
}
|
|
else if (event->type == Expose)
|
|
redraw = TRUE;
|
|
|
|
if (redraw)
|
|
draw_select_feedback(selObj, resizable);
|
|
}
|
|
|