1791 lines
41 KiB
C
1791 lines
41 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: ui_util.c /main/3 1995/11/06 17:56:30 rswiston $
|
|
*
|
|
* @(#)ui_util.c 1.38 14 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.
|
|
*
|
|
*/
|
|
|
|
|
|
/*
|
|
***********************************************************************
|
|
* ui_util.c - User-Interface support functions
|
|
*
|
|
*
|
|
***********************************************************************
|
|
*/
|
|
#ifndef _POSIX_SOURCE /* POSIX guarantees portability of time functions */
|
|
#define _POSIX_SOURCE 1
|
|
#endif
|
|
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <time.h>
|
|
#include <X11/Intrinsic.h>
|
|
#include <X11/Composite.h>
|
|
#include <X11/Shell.h>
|
|
#include <X11/cursorfont.h>
|
|
#include <Xm/XmAll.h>
|
|
/*
|
|
#include <Xm/Protocols.h>
|
|
#include <Xm/CascadeB.h>
|
|
#include <Xm/DialogS.h>
|
|
#include <Xm/Form.h>
|
|
#include <Xm/List.h>
|
|
#include <Xm/ScrolledW.h>
|
|
#include <Xm/RowColumn.h>
|
|
#include <Xm/TextF.h>
|
|
#include <Xm/Text.h>
|
|
#include <Xm/MessageB.h>
|
|
#include <Xm/PushB.h>
|
|
*/
|
|
#include <Dt/SpinBox.h>
|
|
#include <Dt/TermPrim.h>
|
|
#include <Dt/Term.h>
|
|
#include <ab_private/XmAll.h>
|
|
#include <ab_private/x_util.h>
|
|
#include <ab_private/ui_util.h>
|
|
#include <ab_private/objxm.h>
|
|
#include <ab_private/ab.h>
|
|
#include <Dt/xpm.h> /* will this be in include/Dt? */
|
|
#include "dtbuilder.h"
|
|
#include "dtb_utils.h"
|
|
|
|
extern Widget AB_toplevel;
|
|
|
|
typedef struct
|
|
{
|
|
XtIntervalId timerId;
|
|
BOOL synced;
|
|
time_t start_time;
|
|
long timeout_ticks;
|
|
time_t last_expose_ticks;
|
|
Display *display;
|
|
Window window;
|
|
} SyncDataRec, *SyncData;
|
|
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Private Function Declarations **
|
|
** **
|
|
**************************************************************************/
|
|
static void init_obj_pixmaps();
|
|
|
|
static void rubberband_finish(
|
|
Widget widget,
|
|
XEvent *event,
|
|
XtPointer client_data
|
|
);
|
|
|
|
static void rubberband_release(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
);
|
|
|
|
static void rubberband_draw(
|
|
Widget widget,
|
|
XEvent *event,
|
|
XtPointer client_data
|
|
);
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Data **
|
|
** **
|
|
**************************************************************************/
|
|
|
|
static const long sync_notify_value = (long)0x45a55a54;
|
|
|
|
|
|
/*
|
|
* Array that maps from:
|
|
* (obj type, obj subtype) -> pixmap
|
|
* It contains the data that will be used to create the pixmap.
|
|
*/
|
|
static UiObjPixmap object_pixmaps[] =
|
|
{
|
|
/* { (AB_OBJECT_TYPE), (int), (char *), (Pixmap), u_int, u_int } */
|
|
{AB_TYPE_MODULE, AB_NO_SUBTYPE, "DtABmdl", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_BASE_WINDOW, AB_NO_SUBTYPE, "DtABbw2", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_DIALOG, AB_NO_SUBTYPE, "DtABpuw2", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_FILE_CHOOSER, AB_NO_SUBTYPE, "DtABfsb2", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_CONTAINER, AB_CONT_BUTTON_PANEL, "DtABcnt2", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_CONTAINER, AB_CONT_ABSOLUTE, "DtABcnt2", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_CONTAINER, AB_CONT_RELATIVE, "DtABcnt2", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_CONTAINER, AB_CONT_PANED, "DtABpnw", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_CONTAINER, AB_CONT_MENU_BAR, "DtABmbr", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_CONTAINER, AB_CONT_TOOL_BAR, "DtABcnt2", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_CONTAINER, AB_CONT_FOOTER, "DtABcnt2", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_CONTAINER, AB_CONT_GROUP, "DtABgrp", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_DRAWING_AREA, AB_NO_SUBTYPE, "DtABdrw2", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_TEXT_PANE, AB_NO_SUBTYPE, "DtABtxp2", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_BUTTON, AB_BUT_PUSH, "DtABbtn", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_BUTTON, AB_BUT_DRAWN, "DtABbtn", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_BUTTON, AB_BUT_MENU, "DtABmbt", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_LIST, AB_NO_SUBTYPE, "DtABlst", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_CHOICE, AB_CHOICE_OPTION_MENU, "DtABopm", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_CHOICE, AB_CHOICE_EXCLUSIVE, "DtABrad", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_CHOICE, AB_CHOICE_NONEXCLUSIVE, "DtABchk", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_ITEM, AB_ITEM_FOR_MENU, "DtABcas", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_ITEM, AB_ITEM_FOR_MENUBAR, "DtABcas", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_ITEM, AB_ITEM_FOR_CHOICE, "DtABitm", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_ITEM, AB_ITEM_FOR_LIST, "DtABitm", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_ITEM, AB_ITEM_FOR_COMBO_BOX, "DtABitm", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_ITEM, AB_ITEM_FOR_SPIN_BOX, "DtABitm", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_TEXT_FIELD, AB_NO_SUBTYPE, "DtABtxf", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_MENU, AB_MENU_PULLDOWN, "DtABpum", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_SCALE, AB_SCALE_SCALE, "DtABsld", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_SCALE, AB_SCALE_GAUGE, "DtABgau", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_COMBO_BOX, AB_NO_SUBTYPE, "DtABcmb", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_SPIN_BOX, AB_NO_SUBTYPE, "DtABspb", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_TERM_PANE, AB_NO_SUBTYPE, "DtABtmp2", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_SEPARATOR, AB_NO_SUBTYPE, "DtABsep", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_LABEL, AB_NO_SUBTYPE, "DtABlbl", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_MESSAGE, AB_MSG_ERROR, "DtABmbx", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_MESSAGE, AB_MSG_INFORMATION, "DtABmbx", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_MESSAGE, AB_MSG_QUESTION, "DtABmbx", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_MESSAGE, AB_MSG_WARNING, "DtABmbx", (Pixmap)NULL, 0, 0},
|
|
{AB_TYPE_MESSAGE, AB_MSG_WORKING, "DtABmbx", (Pixmap)NULL, 0, 0},
|
|
|
|
{AB_TYPE_LAYERS, AB_NO_SUBTYPE, "DtABlyr", (Pixmap)NULL, 0, 0},
|
|
|
|
/* The last entry has to be this !!*/
|
|
{AB_TYPE_UNKNOWN, AB_NO_SUBTYPE, (char *)NULL, (Pixmap)NULL, 0, 0},
|
|
};
|
|
|
|
/*
|
|
* Default pixmap
|
|
*/
|
|
static Pixmap default_pixmap = NULL;
|
|
static unsigned int default_pixmap_width = 0;
|
|
static unsigned int default_pixmap_height = 0;
|
|
|
|
/*
|
|
* State variables for rubber banding
|
|
*/
|
|
static Boolean rband_in_progress= False;
|
|
static Boolean just_rbanded = False;
|
|
static XRectangle rb_rect;
|
|
static Widget rb_widget = NULL;
|
|
static BOOL rb_first_time = TRUE;
|
|
static UiRubberBandFunc rubberband_func = NULL;
|
|
|
|
/*************************************************************************
|
|
** **
|
|
** Function Definitions **
|
|
** **
|
|
**************************************************************************/
|
|
void
|
|
ui_win_front(
|
|
Widget widget
|
|
)
|
|
{
|
|
Widget p_shell;
|
|
|
|
if (widget == NULL)
|
|
return;
|
|
|
|
p_shell = ui_get_ancestor_shell(widget);
|
|
|
|
if (XtIsRealized(p_shell))
|
|
XRaiseWindow(XtDisplay(p_shell),XtWindow(p_shell));
|
|
else
|
|
if (util_get_verbosity() > 0)
|
|
fprintf(stderr,"ui_win_front: widget not realized\n");
|
|
|
|
}
|
|
|
|
void
|
|
ui_win_show(
|
|
Widget widget,
|
|
BOOL show,
|
|
XtGrabKind grab_kind
|
|
)
|
|
{
|
|
Widget shell;
|
|
Widget dialog;
|
|
|
|
shell = ui_get_ancestor_shell(widget);
|
|
|
|
if (show)
|
|
XtPopup(shell, grab_kind);
|
|
else
|
|
XtPopdown(shell);
|
|
}
|
|
|
|
void
|
|
ui_win_set_resizable(
|
|
Widget widget,
|
|
BOOL resizable,
|
|
BOOL remap
|
|
)
|
|
{
|
|
Widget shell;
|
|
int decor = 0;
|
|
int new_decor = 0;
|
|
int func = 0;
|
|
int new_func = 0;
|
|
|
|
shell = ui_get_ancestor_shell(widget);
|
|
|
|
XtVaGetValues(shell,
|
|
XmNmwmDecorations, &decor,
|
|
XmNmwmFunctions, &func,
|
|
NULL);
|
|
|
|
if (func & MWM_FUNC_ALL)
|
|
{
|
|
new_func |= MWM_FUNC_ALL;
|
|
if (!resizable)
|
|
new_func |= MWM_FUNC_RESIZE;
|
|
}
|
|
else
|
|
{
|
|
new_func = func;
|
|
if (resizable && !(func & MWM_FUNC_RESIZE))
|
|
new_func |= MWM_FUNC_RESIZE;
|
|
else if (!resizable && (func & MWM_FUNC_RESIZE))
|
|
new_func &= ~MWM_FUNC_RESIZE;
|
|
}
|
|
|
|
if (decor & MWM_DECOR_ALL)
|
|
{
|
|
new_decor |= MWM_DECOR_ALL;
|
|
if (!resizable)
|
|
new_decor |= MWM_DECOR_RESIZEH;
|
|
}
|
|
else
|
|
{
|
|
new_decor = decor;
|
|
if (resizable && !(decor & MWM_DECOR_RESIZEH))
|
|
new_decor |= MWM_DECOR_RESIZEH;
|
|
else if (!resizable && (decor & MWM_DECOR_RESIZEH))
|
|
new_decor &= ~MWM_DECOR_RESIZEH;
|
|
}
|
|
|
|
if (new_func != func || new_decor != decor)
|
|
{
|
|
/* If requested, unmap & remap the window.
|
|
* Unfortunately, this is the only way to get the window
|
|
* manager to change the decorations for an already mapped
|
|
* window.
|
|
*/
|
|
if (remap)
|
|
XtPopdown(shell);
|
|
|
|
XtVaSetValues(shell,
|
|
XmNmwmDecorations, new_decor,
|
|
XmNmwmFunctions, new_func,
|
|
NULL);
|
|
|
|
if (remap)
|
|
XtPopup(shell, XtGrabNone);
|
|
}
|
|
}
|
|
|
|
void
|
|
ui_field_set_string(
|
|
Widget field,
|
|
STRING valuestr
|
|
)
|
|
{
|
|
|
|
XtVaSetValues(field,
|
|
XmNvalue, (XtArgVal)(valuestr? valuestr : ""),
|
|
XmNcursorPosition, (XtArgVal)valuestr? strlen(valuestr) : 0,
|
|
NULL);
|
|
|
|
}
|
|
|
|
STRING
|
|
ui_field_get_string(
|
|
Widget field
|
|
)
|
|
{
|
|
char *string = NULL;
|
|
|
|
if (XtIsSubclass(field, xmTextFieldWidgetClass))
|
|
string = XmTextFieldGetString(field);
|
|
else if (XtIsSubclass(field, xmTextWidgetClass))
|
|
string = XmTextGetString(field);
|
|
|
|
return((STRING)string);
|
|
}
|
|
|
|
void
|
|
ui_field_select_string(
|
|
Widget field,
|
|
BOOL assign_focus
|
|
)
|
|
{
|
|
STRING valuestr = NULL;
|
|
|
|
valuestr = ui_field_get_string(field);
|
|
|
|
if (XtIsSubclass(field, xmTextFieldWidgetClass))
|
|
XmTextFieldSetSelection(field, 0, strlen(valuestr), CurrentTime);
|
|
else if (XtIsSubclass(field, xmTextWidgetClass))
|
|
XmTextSetSelection(field, 0, strlen(valuestr), CurrentTime);
|
|
|
|
if (assign_focus)
|
|
XmProcessTraversal(field, XmTRAVERSE_CURRENT);
|
|
|
|
util_free(valuestr);
|
|
}
|
|
|
|
void
|
|
ui_field_set_editable(
|
|
Widget field,
|
|
BOOL editable
|
|
)
|
|
{
|
|
XtVaSetValues(field,
|
|
XmNeditable, editable,
|
|
XmNcursorPositionVisible, editable,
|
|
NULL);
|
|
}
|
|
|
|
void
|
|
ui_set_active(
|
|
Widget widget,
|
|
BOOL state
|
|
)
|
|
{
|
|
XtSetSensitive(widget, (Boolean)state);
|
|
|
|
if (XtIsComposite(widget))
|
|
{
|
|
int i, num_children = 0;
|
|
WidgetList children = NULL;
|
|
|
|
XtVaGetValues(widget,
|
|
XmNnumChildren, &num_children,
|
|
XmNchildren, &children,
|
|
NULL);
|
|
|
|
for (i = 0; i < num_children; i++)
|
|
{
|
|
int c = 0, num_children_children = 0;
|
|
WidgetList children_children = NULL;
|
|
|
|
XtSetSensitive(children[i], (Boolean)state);
|
|
|
|
/* REMIND: Hack to get scrolling list to grey out */
|
|
|
|
XtVaGetValues(children[i],
|
|
XmNnumChildren, &num_children_children,
|
|
XmNchildren, &children_children,
|
|
NULL);
|
|
|
|
if (num_children_children > 0)
|
|
{
|
|
for (c = 0; c < num_children_children; c++)
|
|
XtSetSensitive(children_children[c], (Boolean)state);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void
|
|
ui_set_visible(
|
|
Widget widget,
|
|
BOOL viz
|
|
)
|
|
{
|
|
if (viz == TRUE && !XtIsManaged(widget))
|
|
XtManageChild(widget);
|
|
|
|
else if (viz == FALSE && XtIsManaged(widget))
|
|
XtUnmanageChild(widget);
|
|
|
|
}
|
|
|
|
void
|
|
ui_set_label_string(
|
|
Widget widget,
|
|
STRING string
|
|
)
|
|
{
|
|
XmString xmlabel;
|
|
|
|
xmlabel = XmStringCreateLocalized(string);
|
|
|
|
XtVaSetValues(widget, XmNlabelString, xmlabel, NULL);
|
|
|
|
XmStringFree(xmlabel);
|
|
}
|
|
|
|
void
|
|
ui_set_label_glyph(
|
|
Widget widget,
|
|
STRING fileName
|
|
)
|
|
{
|
|
Pixmap labelPixmap = NULL;
|
|
Pixmap labelInsensitivePixmap = NULL;
|
|
|
|
XtVaGetValues(widget,
|
|
XmNlabelPixmap, &labelPixmap,
|
|
XmNlabelInsensitivePixmap, &labelInsensitivePixmap,
|
|
NULL);
|
|
|
|
if (dtb_set_label_from_image_file(widget, fileName) < 0)
|
|
return;
|
|
|
|
/* sucess, destroy the old pixmaps */
|
|
if (labelPixmap)
|
|
XmDestroyPixmap(XtScreen(widget), labelPixmap);
|
|
|
|
if (labelInsensitivePixmap)
|
|
XmDestroyPixmap(XtScreen(widget), labelInsensitivePixmap);
|
|
}
|
|
|
|
|
|
Widget
|
|
ui_get_ancestor_shell(
|
|
Widget widget
|
|
)
|
|
{
|
|
Widget shell = widget;
|
|
|
|
while(shell && !XtIsSubclass(shell, shellWidgetClass))
|
|
shell = XtParent(shell);
|
|
|
|
return shell;
|
|
|
|
}
|
|
|
|
Widget
|
|
ui_get_ancestor_dialog(
|
|
Widget widget
|
|
)
|
|
{
|
|
Widget dialog = widget;
|
|
|
|
while(dialog && !XtIsSubclass(XtParent(dialog), shellWidgetClass))
|
|
dialog = XtParent(dialog);
|
|
|
|
return dialog;
|
|
}
|
|
|
|
Widget
|
|
ui_build_menu(
|
|
Widget parent,
|
|
int menu_type,
|
|
int num_columns,
|
|
char *menu_title,
|
|
char *menu_name,
|
|
MenuItem *menu_items
|
|
)
|
|
{
|
|
Widget menu,
|
|
cascade,
|
|
widget;
|
|
Arg args[4];
|
|
int i;
|
|
XmString xmlabel;
|
|
int n = 0;
|
|
|
|
if (num_columns > 1)
|
|
{
|
|
XtSetArg(args[n], XmNpacking, XmPACK_COLUMN); n++;
|
|
XtSetArg(args[n], XmNnumColumns, num_columns); n++;
|
|
}
|
|
if (menu_type == XmMENU_PULLDOWN)
|
|
menu = XmCreatePulldownMenu(parent, "pulldown_menu", args, n);
|
|
else
|
|
{
|
|
XtSetArg(args[n], XmNwhichButton, AB_BMenu); n++;
|
|
menu = XmCreatePopupMenu(parent, "popup_menu", args, n);
|
|
}
|
|
|
|
if (menu_type == XmMENU_PULLDOWN)
|
|
{
|
|
cascade = XtVaCreateManagedWidget(menu_name,
|
|
xmCascadeButtonWidgetClass, parent,
|
|
XmNsubMenuId, menu,
|
|
NULL);
|
|
|
|
if (menu_title)
|
|
{
|
|
xmlabel = XmStringCreateLocalized(menu_title);
|
|
XtVaSetValues(cascade, XmNlabelString, xmlabel, NULL);
|
|
XmStringFree(xmlabel);
|
|
}
|
|
}
|
|
|
|
for (i = 0; menu_items[i].label != NULL; i++)
|
|
{
|
|
if (menu_items[i].subitems)
|
|
{
|
|
widget = ui_build_menu(menu, XmMENU_PULLDOWN,
|
|
menu_items[i].num_columns,
|
|
menu_items[i].label,
|
|
menu_items[i].name,
|
|
(MenuItem *)menu_items[i].subitems);
|
|
|
|
XtVaSetValues(widget, XmNuserData, (XtArgVal)menu_items[i].user_data, NULL);
|
|
}
|
|
else
|
|
{
|
|
widget = XtVaCreateManagedWidget(menu_items[i].name,
|
|
*menu_items[i].wclass,
|
|
menu,
|
|
XmNuserData, (XtArgVal)menu_items[i].user_data,
|
|
NULL);
|
|
|
|
if (menu_items[i].label != NULL)
|
|
{
|
|
xmlabel = XmStringCreateLocalized(menu_items[i].label);
|
|
XtVaSetValues(widget, XmNlabelString, xmlabel, NULL);
|
|
XmStringFree(xmlabel);
|
|
}
|
|
|
|
/* If label is glyph type, then change type and call
|
|
* routine to set glyph.
|
|
*/
|
|
if (menu_items[i].label_type == AB_LABEL_GLYPH)
|
|
{
|
|
XtVaSetValues(widget, XmNlabelType, XmPIXMAP, NULL);
|
|
dtb_set_label_from_bitmap_data(widget,
|
|
menu_items[i].pixwidth,
|
|
menu_items[i].pixheight,
|
|
menu_items[i].bits);
|
|
|
|
}
|
|
}
|
|
|
|
if (menu_items[i].active == FALSE)
|
|
XtSetSensitive(widget, FALSE);
|
|
else if (menu_items[i].callback != NULL)
|
|
XtAddCallback(widget, XmNactivateCallback,
|
|
menu_items[i].callback,
|
|
menu_items[i].client_data);
|
|
}
|
|
|
|
if (menu_type == XmMENU_POPUP)
|
|
return menu;
|
|
else
|
|
return cascade;
|
|
}
|
|
|
|
void
|
|
ui_populate_pulldown_menu(
|
|
Widget menu,
|
|
int num_columns,
|
|
MenuItem *menu_items
|
|
)
|
|
{
|
|
Widget widget;
|
|
Arg args[4];
|
|
int i;
|
|
XmString xmlabel;
|
|
int n = 0;
|
|
|
|
if (!menu)
|
|
return;
|
|
|
|
if (num_columns > 1)
|
|
{
|
|
XtSetArg(args[n], XmNpacking, XmPACK_COLUMN); n++;
|
|
XtSetArg(args[n], XmNnumColumns, num_columns); n++;
|
|
|
|
XtSetValues(menu, args, n);
|
|
}
|
|
|
|
for (i = 0; menu_items[i].label != NULL; i++)
|
|
{
|
|
if (menu_items[i].subitems)
|
|
{
|
|
widget = ui_build_menu(menu, XmMENU_PULLDOWN,
|
|
menu_items[i].num_columns,
|
|
menu_items[i].label,
|
|
menu_items[i].name,
|
|
(MenuItem *)menu_items[i].subitems);
|
|
|
|
XtVaSetValues(widget, XmNuserData, (XtArgVal)menu_items[i].user_data, NULL);
|
|
}
|
|
else
|
|
{
|
|
widget = XtVaCreateManagedWidget(menu_items[i].name,
|
|
*menu_items[i].wclass,
|
|
menu,
|
|
XmNuserData, (XtArgVal)menu_items[i].user_data,
|
|
NULL);
|
|
|
|
if (menu_items[i].label != NULL)
|
|
{
|
|
xmlabel = XmStringCreateLocalized(menu_items[i].label);
|
|
XtVaSetValues(widget, XmNlabelString, xmlabel, NULL);
|
|
XmStringFree(xmlabel);
|
|
}
|
|
|
|
/* If label is glyph type, then change type and call
|
|
* routine to set glyph.
|
|
*/
|
|
if (menu_items[i].label_type == AB_LABEL_GLYPH)
|
|
{
|
|
XtVaSetValues(widget, XmNlabelType, XmPIXMAP, NULL);
|
|
dtb_set_label_from_bitmap_data(widget,
|
|
menu_items[i].pixwidth,
|
|
menu_items[i].pixheight,
|
|
menu_items[i].bits);
|
|
|
|
}
|
|
}
|
|
|
|
if (menu_items[i].active == FALSE)
|
|
XtSetSensitive(widget, FALSE);
|
|
else if (menu_items[i].callback != NULL)
|
|
XtAddCallback(widget, XmNactivateCallback,
|
|
menu_items[i].callback,
|
|
menu_items[i].client_data);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void
|
|
ui_size_to_row_col(
|
|
Widget text,
|
|
unsigned short width,
|
|
unsigned short height,
|
|
int *row_ptr,
|
|
int *col_ptr
|
|
)
|
|
{
|
|
|
|
Widget parent;
|
|
Widget vsb, hsb;
|
|
Dimension spacing = 0;
|
|
Dimension text_spacing = 0;
|
|
Dimension hsb_height = 0;
|
|
Dimension vsb_width = 0;
|
|
Dimension margin_w = 0;
|
|
Dimension margin_h = 0;
|
|
Dimension p_margin_w = 0;
|
|
Dimension p_margin_h = 0;
|
|
XmFontList fontlist;
|
|
XFontStruct *font;
|
|
unsigned long charwidth;
|
|
unsigned long lineheight;
|
|
Dimension pane_width, pane_height;
|
|
|
|
if (XtIsSubclass(text, dtTermWidgetClass))
|
|
XtVaGetValues(text,
|
|
XmNmarginWidth, &margin_w,
|
|
XmNmarginHeight,&margin_h,
|
|
DtNuserFont, &fontlist,
|
|
NULL);
|
|
else
|
|
XtVaGetValues(text,
|
|
XmNmarginWidth, &margin_w,
|
|
XmNmarginHeight,&margin_h,
|
|
XmNfontList, &fontlist,
|
|
XmNlistSpacing, &text_spacing,
|
|
NULL);
|
|
|
|
parent = XtParent(text);
|
|
|
|
if (XtIsSubclass(parent, xmScrolledWindowWidgetClass))
|
|
{
|
|
XtVaGetValues(parent,
|
|
XmNhorizontalScrollBar, &hsb,
|
|
XmNverticalScrollBar, &vsb,
|
|
XmNspacing, &spacing,
|
|
NULL);
|
|
if (hsb)
|
|
XtVaGetValues(hsb,
|
|
XmNheight, &hsb_height,
|
|
NULL);
|
|
if (vsb)
|
|
XtVaGetValues(vsb,
|
|
XmNwidth, &vsb_width,
|
|
NULL);
|
|
}
|
|
else if (XtIsSubclass(parent, xmRowColumnWidgetClass))
|
|
XtVaGetValues(parent,
|
|
XmNmarginWidth, &p_margin_w,
|
|
XmNmarginHeight, &p_margin_h,
|
|
NULL);
|
|
|
|
font = objxm_fontlist_to_font(fontlist);
|
|
|
|
if ((!XGetFontProperty(font, XA_QUAD_WIDTH, &charwidth)) || charwidth == 0) {
|
|
if (font->per_char && font->min_char_or_byte2 <= '0' &&
|
|
font->max_char_or_byte2 >= '0')
|
|
charwidth = font->per_char['0' - font->min_char_or_byte2].width;
|
|
else
|
|
charwidth = font->max_bounds.width;
|
|
}
|
|
lineheight = font->max_bounds.ascent + font->max_bounds.descent +
|
|
text_spacing;
|
|
|
|
/* Calculate new pane size */
|
|
pane_width = width - (vsb_width + spacing) - (2*p_margin_w);
|
|
pane_height = height - (hsb_height + spacing) - (2*p_margin_h);
|
|
|
|
*row_ptr = (int)((pane_height - (2*margin_h))/lineheight);
|
|
*col_ptr = (int)((pane_width - (2*margin_w))/charwidth);
|
|
|
|
/* For some reason, above calculations result in rows being 1 too
|
|
* large for a scrolled list widget; put in workaround until
|
|
* error in calculations is found...
|
|
*/
|
|
/*
|
|
REMIND: versions of Motif beyond August 10 don't need this
|
|
if (XtIsSubclass(text, xmListWidgetClass) && *row_ptr > 1)
|
|
(*row_ptr)--;
|
|
*/
|
|
|
|
}
|
|
|
|
int
|
|
ui_set_busy_cursor(
|
|
Window window,
|
|
BOOL on
|
|
)
|
|
{
|
|
static Cursor busy_cursor = NULL;
|
|
static Display *dpy = NULL;
|
|
|
|
if (on) /* Turn ON busy cursor */
|
|
{
|
|
dpy = XtDisplay(AB_toplevel);
|
|
|
|
if (busy_cursor == NULL)
|
|
busy_cursor = XCreateFontCursor(dpy, XC_watch);
|
|
|
|
XDefineCursor(dpy, window, busy_cursor);
|
|
}
|
|
else if (dpy != NULL) /* Turn OFF busy cursor */
|
|
{
|
|
XUndefineCursor(dpy, window);
|
|
dpy = NULL;
|
|
}
|
|
return 0;
|
|
|
|
}
|
|
|
|
/*
|
|
* init_obj_pixmaps()
|
|
* Initialize object pixmaps
|
|
*/
|
|
static void
|
|
init_obj_pixmaps
|
|
(
|
|
)
|
|
{
|
|
Display *dpy;
|
|
Pixmap tmp;
|
|
int i,
|
|
x,
|
|
y,
|
|
status;
|
|
unsigned int w, h, d, bw;
|
|
Window root;
|
|
static int init = False;
|
|
extern Widget AB_toplevel;
|
|
|
|
/*
|
|
* Return immediately if this function was called once before
|
|
*/
|
|
if (init)
|
|
return;
|
|
|
|
dpy = XtDisplay(AB_toplevel);
|
|
|
|
/*
|
|
* Loop thru object_pixmaps array uintil until last entry.
|
|
* The last entry should have type == AB_TYPE_UNKNOWN
|
|
*/
|
|
for (i=0; (object_pixmaps[i].type != AB_TYPE_UNKNOWN); ++i)
|
|
{
|
|
/*
|
|
* Create pixmap
|
|
*/
|
|
status = dtb_cvt_image_file_to_pixmap(AB_toplevel,
|
|
object_pixmaps[i].filename, &tmp);
|
|
|
|
if (!status)
|
|
{
|
|
/*
|
|
* Get width/height of pixmap
|
|
*/
|
|
if (XGetGeometry(dpy, tmp, &root, &x, &y, &w, &h, &bw, &d))
|
|
{
|
|
object_pixmaps[i].pixmap = tmp;
|
|
object_pixmaps[i].width = w;
|
|
object_pixmaps[i].height = h;
|
|
}
|
|
else
|
|
fprintf(stderr, "XGetGeometry: returned error\n");
|
|
}
|
|
}
|
|
|
|
/*
|
|
* Create default pixmap
|
|
*/
|
|
status = dtb_cvt_image_file_to_pixmap(AB_toplevel,
|
|
"DtABdfl", &default_pixmap);
|
|
|
|
if (default_pixmap)
|
|
{
|
|
/*
|
|
* Get default pixmap width/height
|
|
*/
|
|
if (XGetGeometry(dpy, default_pixmap,
|
|
&root, &x, &y, &w, &h, &bw, &d))
|
|
{
|
|
default_pixmap_width = w;
|
|
default_pixmap_height = h;
|
|
}
|
|
else
|
|
fprintf(stderr, "XGetGeometry: returned error\n");
|
|
}
|
|
|
|
/*
|
|
* Set init flag
|
|
*/
|
|
init = True;
|
|
}
|
|
|
|
|
|
/*
|
|
* ui_get_obj_pixmap
|
|
* based on an object's type and subtype, return a pixmap, and
|
|
* it's width/height. This pixmap typically can be used to represent
|
|
* the object in viewers/browsers.
|
|
*/
|
|
void
|
|
ui_get_obj_pixmap
|
|
(
|
|
AB_OBJ *obj,
|
|
Pixmap *pixmap, /* RETURN */
|
|
unsigned int *width, /* RETURN */
|
|
unsigned int *height /* RETURN */
|
|
)
|
|
{
|
|
int i;
|
|
AB_OBJECT_TYPE type;
|
|
int subtype;
|
|
Pixmap p = NULL;
|
|
BOOL found = FALSE;
|
|
|
|
if (!obj || !pixmap || !width || !height)
|
|
return;
|
|
|
|
/*
|
|
* Initialize pixmaps
|
|
*/
|
|
init_obj_pixmaps();
|
|
|
|
/*
|
|
* Get object type/subtype
|
|
*/
|
|
type = obj_get_type(obj);
|
|
subtype = obj_get_subtype(obj);
|
|
|
|
/*
|
|
* Special case for scale/gauge
|
|
* The subtype field is not used. Instead it's read-only
|
|
* state is used to determine if it is a scale/gauge.
|
|
*/
|
|
if (type == AB_TYPE_SCALE)
|
|
{
|
|
if (obj_get_read_only(obj) == False)
|
|
subtype = AB_SCALE_SCALE;
|
|
else /* Gauge */
|
|
subtype = AB_SCALE_GAUGE;
|
|
}
|
|
|
|
/*
|
|
* Search for object type/subtype match
|
|
*/
|
|
for (i=0; (object_pixmaps[i].type != AB_TYPE_UNKNOWN); ++i)
|
|
{
|
|
if ((type == object_pixmaps[i].type) &&
|
|
(subtype == object_pixmaps[i].subtype))
|
|
{
|
|
*pixmap = object_pixmaps[i].pixmap;
|
|
*width = object_pixmaps[i].width;
|
|
*height = object_pixmaps[i].height;
|
|
|
|
if (*pixmap)
|
|
found = TRUE;
|
|
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* If no match, return the default pixmap
|
|
*/
|
|
if (!found)
|
|
{
|
|
*pixmap = default_pixmap;
|
|
*width = default_pixmap_width;
|
|
*height = default_pixmap_height;
|
|
}
|
|
}
|
|
|
|
void
|
|
ui_add_window_close_callback(
|
|
Widget shell,
|
|
XtCallbackProc delete_callback,
|
|
XtPointer client_data,
|
|
unsigned char delete_response
|
|
)
|
|
{
|
|
Atom WM_DELETE_WINDOW;
|
|
|
|
WM_DELETE_WINDOW = XmInternAtom(XtDisplay(shell), "WM_DELETE_WINDOW", False);
|
|
|
|
XtVaSetValues(shell, XmNdeleteResponse, delete_response, NULL);
|
|
XmAddWMProtocolCallback(shell, WM_DELETE_WINDOW, delete_callback, client_data);
|
|
|
|
}
|
|
|
|
void
|
|
ui_remove_window_close_callback(
|
|
Widget shell,
|
|
XtCallbackProc delete_callback,
|
|
XtPointer client_data
|
|
)
|
|
{
|
|
Atom WM_DELETE_WINDOW;
|
|
|
|
WM_DELETE_WINDOW = XmInternAtom(XtDisplay(shell),"WM_DELETE_WINDOW",False);
|
|
XmRemoveWMProtocolCallback(shell,WM_DELETE_WINDOW,
|
|
delete_callback, client_data);
|
|
}
|
|
|
|
void
|
|
ui_add_window_iconify_handler(
|
|
Widget shell,
|
|
XtEventHandler iconify_proc,
|
|
XtPointer client_data
|
|
)
|
|
{
|
|
XtAddEventHandler(shell, StructureNotifyMask, False, iconify_proc,
|
|
(XtPointer)client_data);
|
|
}
|
|
|
|
void
|
|
ui_remove_window_iconify_handler(
|
|
Widget shell,
|
|
XtEventHandler iconify_proc,
|
|
XtPointer client_data
|
|
)
|
|
{
|
|
XtRemoveEventHandler(shell, StructureNotifyMask, False, iconify_proc,
|
|
(XtPointer)client_data);
|
|
}
|
|
|
|
void
|
|
ui_refresh_widget_tree(
|
|
Widget widget
|
|
)
|
|
{
|
|
WidgetList children;
|
|
int num_children = 0;
|
|
int i;
|
|
|
|
if (widget == NULL || !XtIsWidget(widget) || !XtIsRealized(widget))
|
|
return;
|
|
|
|
if (XtIsSubclass(widget, compositeWidgetClass))
|
|
{
|
|
XtVaGetValues(widget,
|
|
XmNnumChildren, &num_children,
|
|
XmNchildren, &children,
|
|
NULL);
|
|
|
|
/* Use recursion to traverse all the way to leaf nodes...*/
|
|
for (i=0; i < num_children; i++)
|
|
ui_refresh_widget_tree(children[i]);
|
|
}
|
|
XClearArea(XtDisplay(widget), XtWindow(widget), 0, 0, 0, 0, TRUE);
|
|
}
|
|
|
|
|
|
static Bool
|
|
event_is_expose(XEvent *event)
|
|
{
|
|
Bool is_expose = FALSE;
|
|
|
|
switch (event->type)
|
|
{
|
|
case CreateNotify:
|
|
case DestroyNotify:
|
|
case Expose:
|
|
case GraphicsExpose:
|
|
case MapNotify:
|
|
case MapRequest:
|
|
case NoExpose:
|
|
case UnmapNotify:
|
|
case VisibilityNotify:
|
|
is_expose= TRUE;
|
|
break;
|
|
}
|
|
|
|
return is_expose;
|
|
}
|
|
|
|
|
|
static void
|
|
sync_timeout_proc(
|
|
XtPointer clientData,
|
|
XtIntervalId *intervalIdPtr
|
|
)
|
|
{
|
|
SyncData syncData = (SyncData)clientData;
|
|
time_t cur_time = time(NULL);
|
|
BOOL done = FALSE;
|
|
|
|
if (syncData->synced)
|
|
{
|
|
return;
|
|
}
|
|
|
|
done =
|
|
((syncData->timeout_ticks - syncData->last_expose_ticks) >= 5);
|
|
|
|
if (done)
|
|
{
|
|
XEvent event;
|
|
Display *display = syncData->display;
|
|
Window window = syncData->window;
|
|
int i = 0;
|
|
int rc = 0;
|
|
long event_mask = 0;
|
|
|
|
syncData->synced = TRUE;
|
|
|
|
/*
|
|
* Fill in the event
|
|
*/
|
|
event.type = ClientMessage;
|
|
event.xclient.display = display;
|
|
event.xclient.window = window;
|
|
event.xclient.message_type = 0;
|
|
event.xclient.format = 32;
|
|
for (i = 0; i < 8; ++i)
|
|
{
|
|
event.xclient.data.l[i] = sync_notify_value;
|
|
}
|
|
rc = XSendEvent(display, window, True, event_mask, &event);
|
|
if (rc == 0)
|
|
{
|
|
util_dprintf(0, "BIG TIME ERROR: send event failed\n");
|
|
}
|
|
}
|
|
|
|
if (!(syncData->synced))
|
|
{
|
|
syncData->timerId = XtAppAddTimeOut(
|
|
XtWidgetToApplicationContext(AB_toplevel), 100,
|
|
sync_timeout_proc, (XtPointer)clientData);
|
|
}
|
|
|
|
++(syncData->timeout_ticks);
|
|
}
|
|
|
|
|
|
int
|
|
ui_sync_display_of_widget(Widget widget)
|
|
{
|
|
int return_value = 0;
|
|
XtAppContext appContext =
|
|
XtWidgetToApplicationContext(widget);
|
|
XEvent eventRec, *event = &eventRec;
|
|
SyncDataRec syncData;
|
|
Bool ignore_event = FALSE;
|
|
Widget ancestor = widget;
|
|
Widget last_ancestor = ancestor;
|
|
Widget sync_widget = NULL;
|
|
Screen *screen = NULL;
|
|
|
|
syncData.timerId = 0;
|
|
syncData.synced = FALSE;
|
|
syncData.start_time = time(NULL);
|
|
syncData.last_expose_ticks = 0;
|
|
syncData.timeout_ticks = 0;
|
|
syncData.display = NULL;
|
|
syncData.window = NULL;
|
|
#define last_expose_ticks (syncData.last_expose_ticks)
|
|
#define synced (syncData.synced)
|
|
#define timeout_ticks (syncData.timeout_ticks)
|
|
|
|
syncData.display = XtDisplay(widget);
|
|
screen = XtScreen(widget);
|
|
syncData.window = RootWindowOfScreen(screen);
|
|
|
|
/*
|
|
* Find topmost parent of this widget that belongs to application.
|
|
* This is in case this widget is destroyed (common for popups)
|
|
*/
|
|
last_ancestor = ancestor = widget;
|
|
while ((ancestor != NULL) &&
|
|
(XtWidgetToApplicationContext(ancestor) == appContext))
|
|
{
|
|
last_ancestor = ancestor;
|
|
ancestor = XtParent(ancestor);
|
|
}
|
|
sync_widget = last_ancestor;
|
|
syncData.window = XtWindow(sync_widget);
|
|
|
|
syncData.timerId = XtAppAddTimeOut(appContext, 100,
|
|
sync_timeout_proc, (XtPointer)&syncData);
|
|
|
|
while (!synced)
|
|
{
|
|
XtAppNextEvent(appContext, event);
|
|
ignore_event = ( (event->type == ClientMessage)
|
|
&& (event->xclient.data.l[0] == sync_notify_value));
|
|
if (!ignore_event)
|
|
{
|
|
XtDispatchEvent(event);
|
|
}
|
|
|
|
if (event_is_expose(event))
|
|
{
|
|
last_expose_ticks = timeout_ticks;
|
|
}
|
|
if (difftime(time(NULL), syncData.start_time) >= 5)
|
|
{
|
|
/* we've done this long enough - give up */
|
|
synced = TRUE;
|
|
}
|
|
} /* while !synced */
|
|
|
|
XtRemoveTimeOut(syncData.timerId); syncData.timerId = 0;
|
|
return return_value;
|
|
#undef last_expose_ticks
|
|
#undef synced
|
|
#undef timeout_ticks
|
|
}
|
|
|
|
/*
|
|
* Rubber banding convenience routines
|
|
*/
|
|
|
|
/*
|
|
* Rubberbanding has just finished.
|
|
* Finish up rubber banding:
|
|
* - erase last box drawn
|
|
* - call rubber band func
|
|
* - reset some state variables
|
|
*/
|
|
static void
|
|
rubberband_finish(
|
|
Widget widget,
|
|
XEvent *event,
|
|
XtPointer client_data
|
|
)
|
|
{
|
|
if (!rb_first_time)
|
|
{
|
|
/* erase last box */
|
|
x_box_r(rb_widget, &rb_rect);
|
|
|
|
/*
|
|
* If a rubber band func was supplied, call it
|
|
*/
|
|
if (rubberband_func)
|
|
rubberband_func(widget, event, &rb_rect, client_data);
|
|
|
|
rubberband_func = NULL;
|
|
rb_first_time = TRUE;
|
|
}
|
|
}
|
|
|
|
/*
|
|
* EventHandler: rubberband action is completed...
|
|
* Call rubberband_finish() which calls the rubber
|
|
* band func.
|
|
*/
|
|
static void
|
|
rubberband_release(
|
|
Widget widget,
|
|
XtPointer client_data,
|
|
XEvent *event,
|
|
Boolean *cont_dispatch
|
|
)
|
|
{
|
|
if (event->type != ButtonRelease)
|
|
return;
|
|
|
|
if (rband_in_progress)
|
|
{
|
|
XtUngrabPointer(widget, CurrentTime);
|
|
XtRemoveEventHandler(widget, ButtonReleaseMask, False,
|
|
rubberband_release, client_data);
|
|
rband_in_progress = False;
|
|
|
|
if (just_rbanded)
|
|
{
|
|
rubberband_finish(widget, event, client_data);
|
|
just_rbanded = False;
|
|
*cont_dispatch = False;
|
|
}
|
|
}
|
|
}
|
|
|
|
/*
|
|
* rubberband_draw()
|
|
* Draws the rubber band box seen when the mouse is dragged
|
|
*/
|
|
static void
|
|
rubberband_draw(
|
|
Widget widget,
|
|
XEvent *event,
|
|
XtPointer client_data
|
|
)
|
|
{
|
|
short x,y;
|
|
|
|
if (event->type == ButtonPress)
|
|
{
|
|
x = (short)((XButtonEvent*)event)->x;
|
|
y = (short)((XButtonEvent*)event)->y;
|
|
}
|
|
else if (event->type == MotionNotify)
|
|
{
|
|
x = (short)((XMotionEvent*)event)->x;
|
|
y = (short)((XMotionEvent*)event)->y;
|
|
}
|
|
else
|
|
return;
|
|
|
|
if (rb_first_time)
|
|
{
|
|
rb_widget = widget;
|
|
|
|
rb_rect.x = x;
|
|
rb_rect.y = y;
|
|
|
|
rb_first_time = FALSE;
|
|
}
|
|
else
|
|
x_box_r(rb_widget, &rb_rect);
|
|
|
|
rb_rect.width = x - rb_rect.x;
|
|
rb_rect.height = y - rb_rect.y;
|
|
|
|
x_box_r(rb_widget, &rb_rect);
|
|
|
|
}
|
|
|
|
/*
|
|
* Starts up the rubber band UI.
|
|
* It grab the pointer and adds an event handler
|
|
* which detects the ButtonRelease. It also sets the
|
|
* rubber band func.
|
|
*/
|
|
int
|
|
ui_initiate_rubberband(
|
|
Widget widget,
|
|
Boolean confine_to_window,
|
|
UiRubberBandFunc rb_func,
|
|
XtPointer client_data
|
|
)
|
|
{
|
|
|
|
XtAddEventHandler(widget, ButtonReleaseMask, False,
|
|
rubberband_release, client_data);
|
|
|
|
if (XtGrabPointer(widget, False,
|
|
ButtonReleaseMask | ButtonMotionMask | PointerMotionMask,
|
|
GrabModeAsync, GrabModeAsync,
|
|
confine_to_window ? XtWindow(widget) : None,
|
|
NULL, CurrentTime) == GrabSuccess)
|
|
{
|
|
rband_in_progress = True;
|
|
rubberband_func = rb_func;
|
|
return OK;
|
|
}
|
|
|
|
rband_in_progress = False;
|
|
rubberband_func = NULL;
|
|
return ERROR;
|
|
}
|
|
|
|
|
|
/*
|
|
* ui_button_drag: drag action ...
|
|
* Called by the drag button event handler for the widget
|
|
* where rubber banding is desired.
|
|
*/
|
|
void
|
|
ui_button_drag(
|
|
Widget widget,
|
|
XEvent *event,
|
|
XtPointer client_data
|
|
)
|
|
{
|
|
if (event->type == MotionNotify)
|
|
{
|
|
if (rband_in_progress)
|
|
{
|
|
rubberband_draw(widget, event, client_data);
|
|
just_rbanded = True;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Widget
|
|
ui_optionmenu_add_item(
|
|
Widget opmenu,
|
|
STRING item_str
|
|
)
|
|
{
|
|
XmString xmitem;
|
|
Widget cascade_btn = NULL;
|
|
Widget menu = NULL;
|
|
Widget mpb = NULL;
|
|
int ret = 0;
|
|
|
|
if ((cascade_btn = XmOptionButtonGadget(opmenu)) != NULL)
|
|
{
|
|
XtVaGetValues(cascade_btn, XmNsubMenuId, &menu, NULL);
|
|
if (menu)
|
|
{
|
|
xmitem = XmStringCreateLocalized(item_str);
|
|
mpb = XtVaCreateManagedWidget(item_str,
|
|
xmPushButtonWidgetClass,
|
|
menu,
|
|
XmNlabelString, xmitem,
|
|
NULL);
|
|
XmStringFree(xmitem);
|
|
}
|
|
}
|
|
|
|
return (mpb);
|
|
}
|
|
|
|
int
|
|
ui_optionmenu_delete_item(
|
|
Widget opmenu,
|
|
STRING item_str
|
|
)
|
|
{
|
|
Widget item = NULL;
|
|
int iRet = 0;
|
|
|
|
item = ui_optionmenu_find_item(opmenu, item_str);
|
|
if (item != NULL)
|
|
{
|
|
XtDestroyWidget(item);
|
|
}
|
|
else
|
|
{
|
|
iRet = -1;
|
|
}
|
|
|
|
return (iRet);
|
|
}
|
|
|
|
Widget
|
|
ui_optionmenu_replace_item(
|
|
Widget opmenu,
|
|
STRING old_item_str,
|
|
STRING new_item_str
|
|
)
|
|
{
|
|
Widget item = NULL;
|
|
Widget opmenu_label = NULL;
|
|
XmString xmstr = NULL;
|
|
XmString new_item_xmstr = NULL;
|
|
XmString old_item_xmstr = NULL;
|
|
|
|
item = ui_optionmenu_find_item(opmenu, old_item_str);
|
|
if (item != NULL)
|
|
{
|
|
new_item_xmstr = XmStringCreateLocalized(new_item_str);
|
|
|
|
/* Check if the item we're replacing is the one
|
|
* which is currently showing in the optionmenu.
|
|
* If so, change the string.
|
|
*/
|
|
old_item_xmstr = XmStringCreateLocalized(old_item_str);
|
|
opmenu_label = XmOptionButtonGadget(opmenu);
|
|
XtVaGetValues(opmenu_label, XmNlabelString, &xmstr, NULL);
|
|
if (XmStringCompare(xmstr, old_item_xmstr))
|
|
{
|
|
XtVaSetValues(opmenu_label,
|
|
XmNlabelString, new_item_xmstr,
|
|
NULL);
|
|
}
|
|
|
|
/* Change the button label to the new string */
|
|
XtVaSetValues(item, XmNlabelString, new_item_xmstr, NULL);
|
|
|
|
XmStringFree(xmstr);
|
|
XmStringFree(old_item_xmstr);
|
|
XmStringFree(new_item_xmstr);
|
|
}
|
|
return (item);
|
|
}
|
|
|
|
Widget
|
|
ui_optionmenu_find_item(
|
|
Widget opmenu,
|
|
STRING item_str
|
|
)
|
|
{
|
|
Widget cascade_btn = NULL;
|
|
Widget menu = NULL;
|
|
Widget found_item = NULL;
|
|
WidgetList children = NULL;
|
|
XmString search_item, child = NULL;
|
|
int i, numChildren = 0;
|
|
BOOL Found = FALSE;
|
|
|
|
if ((cascade_btn = XmOptionButtonGadget(opmenu)) != NULL)
|
|
{
|
|
XtVaGetValues(cascade_btn, XmNsubMenuId, &menu, NULL);
|
|
if (menu)
|
|
{
|
|
search_item = XmStringCreateLocalized(item_str);
|
|
XtVaGetValues(menu,
|
|
XmNnumChildren, &numChildren,
|
|
XmNchildren, &children,
|
|
NULL);
|
|
for (i=0; i < numChildren && !Found; i++)
|
|
{
|
|
XtVaGetValues(children[i], XmNlabelString, &child, NULL);
|
|
if (XmStringCompare(search_item, child))
|
|
{
|
|
Found = TRUE;
|
|
found_item = children[i];
|
|
}
|
|
}
|
|
XmStringFree(search_item);
|
|
XmStringFree(child);
|
|
}
|
|
}
|
|
return (found_item);
|
|
}
|
|
|
|
int
|
|
ui_optionmenu_num_items(
|
|
Widget opmenu
|
|
)
|
|
{
|
|
Widget cascade_btn = NULL;
|
|
Widget menu = NULL;
|
|
int numChildren = 0;
|
|
|
|
if ( (opmenu != NULL) &&
|
|
((cascade_btn = XmOptionButtonGadget(opmenu)) != NULL)
|
|
)
|
|
{
|
|
XtVaGetValues(cascade_btn, XmNsubMenuId, &menu, NULL);
|
|
if (menu)
|
|
{
|
|
XtVaGetValues(menu,
|
|
XmNnumChildren, &numChildren,
|
|
NULL);
|
|
}
|
|
}
|
|
return (numChildren);
|
|
}
|
|
|
|
|
|
void
|
|
ui_optionmenu_change_label(
|
|
Widget opmenu,
|
|
STRING new_str
|
|
)
|
|
{
|
|
Widget opmenu_label = NULL;
|
|
XmString new_xmstr;
|
|
XmString old_xmstr = NULL;
|
|
|
|
opmenu_label = XmOptionButtonGadget(opmenu);
|
|
if ((opmenu_label != NULL) && (new_str != NULL))
|
|
{
|
|
new_xmstr = XmStringCreateLocalized(new_str);
|
|
XtVaGetValues(opmenu_label, XmNlabelString, &old_xmstr, NULL);
|
|
|
|
/* If the two labels are different, then change
|
|
* the optionmenu label.
|
|
*/
|
|
if (!XmStringCompare(old_xmstr, new_xmstr))
|
|
{
|
|
XtVaSetValues(opmenu_label,
|
|
XmNlabelString, new_xmstr,
|
|
NULL);
|
|
}
|
|
XmStringFree(new_xmstr);
|
|
}
|
|
}
|
|
|
|
void
|
|
ui_optionmenu_change_label_pixmap(
|
|
Widget opmenu,
|
|
Pixmap pixmap
|
|
)
|
|
{
|
|
Widget opmenu_label;
|
|
|
|
opmenu_label = XmOptionButtonGadget(opmenu);
|
|
|
|
if (opmenu_label != NULL)
|
|
{
|
|
XtVaSetValues(opmenu_label,
|
|
XmNlabelPixmap, pixmap,
|
|
XmNlabelType, XmPIXMAP,
|
|
NULL);
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Set the label string on an object
|
|
** (converts it to XmString internally, if needed)
|
|
*/
|
|
void
|
|
ui_obj_set_label_string(
|
|
ABObj obj,
|
|
STRING label
|
|
)
|
|
{
|
|
ABObj labelObj = NULL;
|
|
|
|
if (obj == NULL)
|
|
return;
|
|
|
|
switch (obj_get_type(obj))
|
|
{
|
|
case AB_TYPE_BUTTON:
|
|
case AB_TYPE_CHOICE:
|
|
case AB_TYPE_COMBO_BOX:
|
|
case AB_TYPE_LABEL:
|
|
case AB_TYPE_LIST:
|
|
case AB_TYPE_SPIN_BOX:
|
|
case AB_TYPE_SCALE:
|
|
case AB_TYPE_TEXT_FIELD:
|
|
labelObj = objxm_comp_get_subobj(obj, AB_CFG_LABEL_OBJ);
|
|
if (labelObj == NULL || objxm_get_widget(labelObj) == NULL)
|
|
return;
|
|
|
|
ui_set_label_string(objxm_get_widget(labelObj), label);
|
|
break;
|
|
|
|
case AB_TYPE_ITEM:
|
|
switch(obj_get_item_type(obj))
|
|
{
|
|
case AB_ITEM_FOR_MENU:
|
|
case AB_ITEM_FOR_MENUBAR:
|
|
case AB_ITEM_FOR_CHOICE:
|
|
labelObj = objxm_comp_get_subobj(obj, AB_CFG_LABEL_OBJ);
|
|
if (labelObj == NULL || objxm_get_widget(labelObj) == NULL)
|
|
return;
|
|
|
|
ui_set_label_string(objxm_get_widget(labelObj), label);
|
|
break;
|
|
|
|
case AB_ITEM_FOR_COMBO_BOX:
|
|
case AB_ITEM_FOR_LIST:
|
|
case AB_ITEM_FOR_SPIN_BOX:
|
|
{
|
|
ABObj p_obj = obj_get_parent(obj);
|
|
Widget parent = objxm_get_widget(p_obj);
|
|
AB_ITEM_TYPE itype = (AB_ITEM_TYPE)obj_get_subtype(obj);
|
|
int pos;
|
|
int num_items;
|
|
XmString xmitem;
|
|
|
|
if (parent != NULL)
|
|
{
|
|
xmitem = XmStringCreateLocalized(label);
|
|
pos = obj_get_child_num(obj);
|
|
pos++; /* XmList starts at 1 */
|
|
|
|
if (obj_is_combo_box_item(obj))
|
|
parent = ui_combobox_get_list_widget(parent);
|
|
|
|
if (obj_is_list_item(obj) ||
|
|
obj_is_combo_box_item(obj))
|
|
XtVaGetValues(parent,
|
|
XmNitemCount, &num_items,
|
|
NULL);
|
|
else if (obj_is_spin_box_item(obj))
|
|
XtVaGetValues(parent,
|
|
DtNnumValues, &num_items,
|
|
NULL);
|
|
|
|
if (pos <= num_items)
|
|
{
|
|
if (obj_is_list_item(obj) ||
|
|
obj_is_combo_box_item(obj))
|
|
{
|
|
XmListReplacePositions(parent, &pos,
|
|
&xmitem, 1);
|
|
}
|
|
else
|
|
{
|
|
DtSpinBoxDeletePos(parent, pos);
|
|
DtSpinBoxAddItem(parent, xmitem, pos);
|
|
}
|
|
}
|
|
XmStringFree(xmitem);
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case AB_TYPE_BASE_WINDOW:
|
|
case AB_TYPE_DIALOG:
|
|
case AB_TYPE_FILE_CHOOSER:
|
|
labelObj = objxm_comp_get_subobj(obj, AB_CFG_LABEL_OBJ);
|
|
if (labelObj == NULL || objxm_get_widget(labelObj) == NULL)
|
|
return;
|
|
|
|
XtVaSetValues(objxm_get_widget(labelObj), XmNtitle, label, NULL);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Set the label glyph (ie graphic) on an object
|
|
*/
|
|
void
|
|
ui_obj_set_label_glyph(
|
|
ABObj obj,
|
|
STRING fileName
|
|
)
|
|
{
|
|
ABObj labelObj = NULL;
|
|
|
|
if (obj == NULL)
|
|
return;
|
|
|
|
if (util_strempty(fileName))
|
|
return;
|
|
|
|
labelObj = objxm_comp_get_subobj(obj, AB_CFG_LABEL_OBJ);
|
|
if (labelObj == NULL || objxm_get_widget(labelObj) == NULL)
|
|
return;
|
|
|
|
switch (obj_get_type(obj))
|
|
{
|
|
case AB_TYPE_BUTTON:
|
|
case AB_TYPE_CHOICE:
|
|
case AB_TYPE_COMBO_BOX:
|
|
case AB_TYPE_LABEL:
|
|
case AB_TYPE_LIST:
|
|
case AB_TYPE_SPIN_BOX:
|
|
case AB_TYPE_SCALE:
|
|
case AB_TYPE_TEXT_FIELD:
|
|
ui_set_label_glyph(objxm_get_widget(labelObj), fileName);
|
|
break;
|
|
|
|
case AB_TYPE_ITEM:
|
|
switch(obj_get_item_type(obj))
|
|
{
|
|
case AB_ITEM_FOR_MENU:
|
|
case AB_ITEM_FOR_MENUBAR:
|
|
case AB_ITEM_FOR_CHOICE:
|
|
ui_set_label_glyph(objxm_get_widget(labelObj), fileName);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
/*
|
|
** Set the label on an object
|
|
** string and glyphs are supported
|
|
*/
|
|
void
|
|
ui_obj_set_label(
|
|
ABObj obj,
|
|
STRING label
|
|
)
|
|
{
|
|
if (obj == NULL)
|
|
return;
|
|
|
|
switch (obj_get_label_type(obj))
|
|
{
|
|
case AB_LABEL_STRING:
|
|
ui_obj_set_label_string(obj, label);
|
|
break;
|
|
|
|
case AB_LABEL_GLYPH:
|
|
ui_obj_set_label_glyph(obj, label);
|
|
break;
|
|
|
|
default:
|
|
return;
|
|
}
|
|
}
|
|
|