568 lines
17 KiB
C
568 lines
17 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: Container.C /main/2 1995/07/17 14:05:19 drk $ */
|
|
/* *
|
|
* (c) Copyright 1993, 1994 Hewlett-Packard Company *
|
|
* (c) Copyright 1993, 1994 International Business Machines Corp. *
|
|
* (c) Copyright 1993, 1994 Sun Microsystems, Inc. *
|
|
* (c) Copyright 1993, 1994 Novell, Inc. *
|
|
*/
|
|
|
|
#include "Container.h"
|
|
#include "IconObj.h"
|
|
|
|
#include <Xm/Xm.h>
|
|
#include <Xm/DropSMgr.h>
|
|
#include "Icon.h"
|
|
#include "WorkArea.h"
|
|
#include <Xm/ScrolledW.h>
|
|
#include <Xm/PanedW.h>
|
|
#include <Xm/Form.h>
|
|
#include <Xm/RowColumn.h>
|
|
#include <Xm/DrawingA.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
Container::Container(MotifUI *parent,
|
|
char *name,
|
|
ContainerType container_type,
|
|
SelectionType select_type)
|
|
: MotifUI(parent, name, NULL)
|
|
{
|
|
CreateContainer(parent, name, NULL, container_type, select_type);
|
|
}
|
|
|
|
Container::Container(char *category,
|
|
MotifUI *parent,
|
|
char *name,
|
|
ContainerType container_type,
|
|
SelectionType select_type)
|
|
: MotifUI(parent, name, category)
|
|
{
|
|
CreateContainer(parent, name, category, container_type, select_type);
|
|
}
|
|
|
|
static XtTranslations trans_tbl = NULL;
|
|
static XtActionsRec action_table[] = {{"ResizeRC", NULL}};
|
|
|
|
void Container::CreateContainer(MotifUI *parent, char * /*name*/,
|
|
char * /*category*/,
|
|
ContainerType container_type,
|
|
SelectionType select_type)
|
|
{
|
|
Arg args[15];
|
|
int n;
|
|
Pixel pixel;
|
|
Widget parentW;
|
|
Widget superNode;
|
|
int radio_behavior = false;
|
|
int _shadowThickness;
|
|
|
|
if (!trans_tbl)
|
|
{
|
|
action_table[0].proc = (XtActionProc) ResizeRC;
|
|
trans_tbl = XtParseTranslationTable("<Configure>:ResizeRC()");
|
|
XtAppAddActions(appContext, action_table, XtNumber(action_table));
|
|
}
|
|
|
|
_xm_update_message = NULL;
|
|
_select_type = select_type;
|
|
_last_selected = NULL;
|
|
parentW = parent->InnerWidget();
|
|
if (GuiIsIcon(parentW))
|
|
superNode = parentW;
|
|
else
|
|
superNode = NULL;
|
|
if (!XtIsComposite(parentW))
|
|
parentW = XtParent(parentW);
|
|
if (select_type == SINGLE_SELECT)
|
|
radio_behavior = true;
|
|
|
|
switch (_container_type = container_type)
|
|
{
|
|
case FORM:
|
|
_w = XtVaCreateManagedWidget("form", xmFormWidgetClass,
|
|
parentW, NULL);
|
|
_workArea = _w;
|
|
break;
|
|
case SCROLLED_FORM:
|
|
_w = XtVaCreateManagedWidget("sw", xmScrolledWindowWidgetClass,
|
|
parentW, NULL);
|
|
_workArea = XtVaCreateManagedWidget("form", xmFormWidgetClass,
|
|
_w, NULL);
|
|
break;
|
|
case CANVAS:
|
|
_w = XtVaCreateManagedWidget("canvas", xmDrawingAreaWidgetClass,
|
|
parentW, NULL);
|
|
_workArea = _w;
|
|
break;
|
|
case SCROLLED_CANVAS:
|
|
_w = XtVaCreateManagedWidget("sw", xmScrolledWindowWidgetClass,
|
|
parentW, NULL);
|
|
_workArea = XtVaCreateManagedWidget("canvas", xmDrawingAreaWidgetClass,
|
|
_w, NULL);
|
|
break;
|
|
case HORIZONTAL_ROW_COLUMN:
|
|
_w = XtVaCreateManagedWidget("rc", xmRowColumnWidgetClass, parentW,
|
|
XmNorientation, XmHORIZONTAL,
|
|
XmNradioBehavior, radio_behavior, NULL);
|
|
_workArea = _w;
|
|
break;
|
|
case SCROLLED_HORIZONTAL_ROW_COLUMN:
|
|
_w = XtVaCreateManagedWidget("sw", xmScrolledWindowWidgetClass, parentW,
|
|
GuiNisOpened, false, GuiNisWorkArea, true,
|
|
GuiNsuperNode, superNode, XmNspacing, 0,
|
|
XmNscrollBarDisplayPolicy, XmAS_NEEDED,
|
|
XmNscrollingPolicy, XmAUTOMATIC,
|
|
XmNheight, Parent()->Height(), NULL);
|
|
XtAddCallback(_w, XmNtraverseObscuredCallback, MakeChildVisible, NULL);
|
|
_workArea = XtVaCreateManagedWidget("rc", xmRowColumnWidgetClass, _w,
|
|
XmNorientation, XmHORIZONTAL,
|
|
XmNradioBehavior, radio_behavior,
|
|
XmNpacking, XmPACK_TIGHT,
|
|
XmNadjustLast, False,
|
|
XmNuserData, this, NULL);
|
|
XtAddCallback(XtParent(_workArea), XmNresizeCallback,
|
|
ResizeSW, (XtPointer) this);
|
|
XtOverrideTranslations(_workArea, trans_tbl);
|
|
break;
|
|
case VERTICAL_ROW_COLUMN:
|
|
_w = XtVaCreateManagedWidget("rc", xmRowColumnWidgetClass, parentW,
|
|
XmNradioBehavior, radio_behavior, NULL);
|
|
_workArea = _w;
|
|
break;
|
|
case SCROLLED_VERTICAL_ROW_COLUMN:
|
|
_w = XtVaCreateManagedWidget("sw", xmScrolledWindowWidgetClass, parentW,
|
|
GuiNisOpened, false, GuiNisWorkArea, true,
|
|
GuiNsuperNode, superNode, XmNspacing, 0,
|
|
XmNradioBehavior, radio_behavior,
|
|
XmNscrollBarDisplayPolicy, XmAS_NEEDED,
|
|
XmNscrollingPolicy, XmAUTOMATIC, NULL);
|
|
_workArea = XtVaCreateManagedWidget("rc", xmRowColumnWidgetClass, _w,
|
|
XmNradioBehavior, radio_behavior,
|
|
NULL);
|
|
break;
|
|
case PANE:
|
|
_w = XtVaCreateManagedWidget("pane", xmPanedWindowWidgetClass,
|
|
parentW, NULL);
|
|
_workArea = _w;
|
|
break;
|
|
case SCROLLED_PANE:
|
|
_w = XtVaCreateManagedWidget("sw", xmScrolledWindowWidgetClass,
|
|
parentW, NULL);
|
|
_workArea = XtVaCreateManagedWidget("form", xmPanedWindowWidgetClass,
|
|
_w, NULL);
|
|
break;
|
|
case WORK_AREA:
|
|
_w = XtVaCreateManagedWidget("form", workAreaWidgetClass,
|
|
parentW, NULL);
|
|
_workArea = _w;
|
|
break;
|
|
case ICON_LIST:
|
|
_w = XtVaCreateManagedWidget("form", workAreaWidgetClass,
|
|
parentW, GuiNisList, True, NULL);
|
|
_workArea = _w;
|
|
break;
|
|
case SCROLLED_ICON_LIST:
|
|
case SCROLLED_WORK_AREA:
|
|
if (Parent()->UIClass() == DIALOG)
|
|
_shadowThickness = 0;
|
|
else
|
|
_shadowThickness = shadowThickness;
|
|
_w = XtVaCreateManagedWidget("form", xmFormWidgetClass,
|
|
parentW,
|
|
XmNshadowThickness, _shadowThickness,
|
|
XmNshadowType, XmSHADOW_OUT, NULL);
|
|
n = 0;
|
|
if (_container_type == SCROLLED_ICON_LIST)
|
|
{
|
|
XtSetArg(args[n], GuiNisList, True); n++;
|
|
}
|
|
else
|
|
{
|
|
XtSetArg(args[n], XmNalignment, XmALIGNMENT_BEGINNING); n++;
|
|
XtSetArg(args[n], XmNentryVerticalAlignment,
|
|
XmALIGNMENT_CONTENTS_BOTTOM);
|
|
n++;
|
|
}
|
|
XtSetArg(args[n], XmNtopAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg(args[n], XmNtopOffset, 6); n++;
|
|
XtSetArg(args[n], XmNleftAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg(args[n], XmNleftOffset, 6); n++;
|
|
XtSetArg(args[n], XmNrightAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg(args[n], XmNrightOffset, 6); n++;
|
|
XtSetArg(args[n], XmNbottomAttachment, XmATTACH_FORM); n++;
|
|
XtSetArg(args[n], XmNbottomOffset, 6); n++;
|
|
XtSetArg(args[n], GuiNlineOffset, 20); n++;
|
|
XtSetArg(args[n], GuiNlineThickness, 2); n++;
|
|
XtSetArg(args[n], XmNuserData, this); n++;
|
|
|
|
_workArea = GuiCreateScrolledWorkArea(_w, "workArea", args, n);
|
|
XtManageChild(_workArea);
|
|
break;
|
|
}
|
|
|
|
if (_workArea == _w)
|
|
{
|
|
_clipWidget = _sw = _vbar = _hbar = NULL;
|
|
}
|
|
else
|
|
{
|
|
_clipWidget = XtParent(_workArea);
|
|
_sw = XtParent(_clipWidget);
|
|
XtVaGetValues(_sw, XmNverticalScrollBar, &_vbar,
|
|
XmNhorizontalScrollBar, &_hbar, NULL);
|
|
if (container_type == SCROLLED_HORIZONTAL_ROW_COLUMN)
|
|
XtUnmanageChild(_vbar);
|
|
|
|
if (depth > 1 &&
|
|
(container_type == SCROLLED_WORK_AREA ||
|
|
container_type == SCROLLED_ICON_LIST))
|
|
{
|
|
XtVaGetValues(_vbar, XmNtroughColor, &pixel, NULL);
|
|
XtVaSetValues(_workArea, XmNbackground, pixel, NULL);
|
|
XtVaSetValues(_clipWidget, XmNbackground, pixel, NULL);
|
|
}
|
|
}
|
|
InstallHelpCB();
|
|
InstallDestroyCB();
|
|
}
|
|
|
|
boolean Container::SetIcon(IconStyle)
|
|
{
|
|
if (_container_type == SCROLLED_HORIZONTAL_ROW_COLUMN)
|
|
XtAppAddTimeOut(appContext, 500, ResizeTimeOut, this);
|
|
return true;
|
|
}
|
|
|
|
void Container::DoBeginUpdate()
|
|
{
|
|
XtAddEventHandler(XtParent(_workArea), ExposureMask, FALSE,
|
|
&Container::UpdateAreaMessage, (XtPointer) this);
|
|
|
|
if (_container_type == SCROLLED_WORK_AREA ||
|
|
_container_type == WORK_AREA ||
|
|
_container_type == SCROLLED_ICON_LIST ||
|
|
_container_type == ICON_LIST)
|
|
{
|
|
if (XtIsRealized(_workArea))
|
|
XtUnmapWidget(_workArea);
|
|
GuiWorkAreaDisableRedisplay(_workArea);
|
|
XmDropSiteStartUpdate(XtParent(_workArea));
|
|
}
|
|
else
|
|
XtUnmanageChild(_workArea);
|
|
}
|
|
|
|
void Container::DoEndUpdate()
|
|
{
|
|
XtRemoveEventHandler(XtParent(_workArea), ExposureMask, FALSE,
|
|
&Container::UpdateAreaMessage, (XtPointer) this);
|
|
StringFree(_xm_update_message);
|
|
if (XtIsRealized(_workArea))
|
|
XClearArea(display, XtWindow(XtParent(_workArea)), 0, 0, 0, 0, TRUE);
|
|
_xm_update_message = NULL;
|
|
if (_container_type == SCROLLED_WORK_AREA ||
|
|
_container_type == WORK_AREA ||
|
|
_container_type == SCROLLED_ICON_LIST ||
|
|
_container_type == ICON_LIST)
|
|
{
|
|
if (XtIsRealized(_workArea))
|
|
XtMapWidget(_workArea);
|
|
GuiWorkAreaEnableRedisplay(_workArea);
|
|
XmDropSiteEndUpdate(XtParent(_workArea));
|
|
}
|
|
else
|
|
{
|
|
XtManageChild(_workArea);
|
|
if (_container_type == SCROLLED_HORIZONTAL_ROW_COLUMN)
|
|
XtAppAddTimeOut(appContext, 500, ResizeTimeOut, this);
|
|
}
|
|
}
|
|
|
|
void Container::DoUpdateMessage(char *message)
|
|
{
|
|
StringFree(_xm_update_message);
|
|
_xm_update_message = StringCreate(message);
|
|
if (XtIsRealized(_workArea))
|
|
XClearArea(display, XtWindow(XtParent(_workArea)), 0, 0, 0, 0, TRUE);
|
|
Refresh();
|
|
}
|
|
|
|
void Container::SelectionPolicy(SelectionType)
|
|
{
|
|
}
|
|
|
|
void Container::NotifyDelete(BaseUI *obj)
|
|
{
|
|
MotifUI::NotifyDelete(obj);
|
|
if (_last_selected == obj)
|
|
_last_selected = NULL;
|
|
if (_container_type == SCROLLED_HORIZONTAL_ROW_COLUMN)
|
|
XtAppAddTimeOut(appContext, 500, ResizeTimeOut, this);
|
|
}
|
|
|
|
void Container::NotifyVisiblity(BaseUI *obj)
|
|
{
|
|
if (_last_selected == obj)
|
|
_last_selected->Selected(false);
|
|
}
|
|
|
|
void Container::NotifySelected(BaseUI *obj)
|
|
{
|
|
switch (_select_type)
|
|
{
|
|
case SINGLE_SELECT:
|
|
if (_last_selected && _last_selected != obj)
|
|
{
|
|
if (obj->Selected())
|
|
_last_selected->Selected(false);
|
|
}
|
|
if (obj->Selected())
|
|
_last_selected = obj;
|
|
else
|
|
_last_selected = NULL;
|
|
break;
|
|
case MULTIPLE_SELECT:
|
|
break;
|
|
case EXTENDED_SELECT:
|
|
break;
|
|
case BROWSE_SELECT:
|
|
break;
|
|
}
|
|
}
|
|
|
|
// Open Animation stuff
|
|
|
|
static GC CreateGC(Widget w);
|
|
|
|
void Container::OpenAnimation(MotifUI *obj)
|
|
{
|
|
if (!_update || !_w || !XtIsRealized(_w))
|
|
return;
|
|
|
|
Dimension w, h, w2, h2;
|
|
int x0, y0, x1, y1, x2, y2, x_inc1, y_inc1, x_inc2, y_inc2, n;
|
|
Window window, area;
|
|
Widget widget;
|
|
GC gc;
|
|
|
|
if (_clipWidget)
|
|
widget = _clipWidget;
|
|
else
|
|
widget = _w;
|
|
|
|
XtVaGetValues(widget, XmNwidth, &w, XmNheight, &h, NULL);
|
|
XtVaGetValues(obj->BaseWidget(), XmNwidth, &w2, XmNheight, &h2, NULL);
|
|
|
|
area = XtWindow(widget);
|
|
x1 = (int)w2 / 2;
|
|
y1 = (int)h2 / 2;
|
|
XTranslateCoordinates(display, XtWindow(obj->BaseWidget()), area,
|
|
x1, y1, &x0, &y0, &window);
|
|
n = 8;
|
|
x_inc1 = -x0 / n;
|
|
if (x_inc1 == 0)
|
|
x_inc1 = -1;
|
|
y_inc1 = -y0 / n;
|
|
if (y_inc1 == 0)
|
|
y_inc1 = -1;
|
|
x_inc2 = (int)(w - x0) / n;
|
|
if (x_inc2 == 0)
|
|
x_inc2 = 1;
|
|
y_inc2 = (int)(h - y0) / n;
|
|
if (y_inc2 == 0)
|
|
y_inc2 = 1;
|
|
x1 = x0 + x_inc1;
|
|
y1 = y0 + y_inc1;
|
|
x2 = x0 + x_inc2;
|
|
y2 = y0 + y_inc2;
|
|
|
|
gc = CreateGC(widget);
|
|
while (--n)
|
|
{
|
|
XDrawRectangle(display, area, gc, x1, y1, x2 - x1, y2 - y1);
|
|
XFlush(display);
|
|
x1 += x_inc1;
|
|
y1 += y_inc1;
|
|
x2 += x_inc2;
|
|
y2 += y_inc2;
|
|
MicroSleep(OPEN_TIME);
|
|
}
|
|
n = 8;
|
|
x1 = x0 + x_inc1;
|
|
y1 = y0 + y_inc1;
|
|
x2 = x0 + x_inc2;
|
|
y2 = y0 + y_inc2;
|
|
|
|
while (--n)
|
|
{
|
|
XDrawRectangle(display, area, gc, x1, y1, x2 - x1, y2 - y1);
|
|
XFlush(display);
|
|
x1 += x_inc1;
|
|
y1 += y_inc1;
|
|
x2 += x_inc2;
|
|
y2 += y_inc2;
|
|
MicroSleep(OPEN_TIME);
|
|
}
|
|
XtReleaseGC(widget, gc);
|
|
}
|
|
|
|
static GC CreateGC(Widget w)
|
|
{
|
|
XGCValues values;
|
|
|
|
XtVaGetValues(w, XmNforeground, &values.foreground,
|
|
XmNbackground, &values.background, NULL);
|
|
// Set the fg to the XOR of the fg and bg, so if it is
|
|
// XOR'ed with bg, the result will be fg and vice-versa.
|
|
// This effectively achieves inverse video for the line.
|
|
|
|
values.foreground = values.foreground ^ values.background;
|
|
// Set the rubber band gc to use XOR mode and draw a dashed line.
|
|
|
|
values.function = GXxor;
|
|
values.subwindow_mode = IncludeInferiors;
|
|
return (XtGetGC(w, GCForeground | GCBackground |
|
|
GCSubwindowMode | GCFunction, &values));
|
|
}
|
|
|
|
void Container::UpdateAreaMessage(Widget widget, XtPointer client_data,
|
|
XEvent * /*event*/, Boolean * /*continued*/)
|
|
{
|
|
unsigned char direction;
|
|
XGCValues values;
|
|
XtGCMask valueMask;
|
|
Dimension width, height;
|
|
Dimension w, h;
|
|
int x, y;
|
|
|
|
static GC gc = (GC) NULL;
|
|
|
|
Container *container = (Container *) client_data;
|
|
|
|
if (!container->_xm_update_message)
|
|
return;
|
|
|
|
if (!gc)
|
|
{
|
|
XtVaGetValues(widget, XmNforeground, &values.foreground, NULL);
|
|
if (container->font)
|
|
valueMask = GCFont | GCForeground;
|
|
else
|
|
valueMask = GCForeground;
|
|
values.font = container->font;
|
|
gc = XCreateGC(display, root, valueMask, &values);
|
|
}
|
|
XClearArea(display, XtWindow(widget), 0, 0, 0, 0, FALSE);
|
|
XtVaGetValues(widget, XmNwidth, &width, XmNheight, &height, NULL);
|
|
XtVaGetValues(container->_workArea, XmNstringDirection, &direction, NULL);
|
|
XmStringExtent(container->userFont, container->_xm_update_message, &w, &h);
|
|
x = (Dimension)(width - w) / 2;
|
|
y = (Dimension)(height - h) / 2;
|
|
XmStringDraw(display, XtWindow(widget), container->userFont,
|
|
container->_xm_update_message,
|
|
gc, x, y, w, XmALIGNMENT_CENTER, direction, NULL);
|
|
}
|
|
|
|
void Container::MakeChildVisible(Widget widget, XtPointer, XtPointer call_data)
|
|
{
|
|
XmTraverseObscuredCallbackStruct *cb;
|
|
Widget w;
|
|
|
|
cb = (XmTraverseObscuredCallbackStruct *) call_data;
|
|
w = cb->traversal_destination;
|
|
XmScrollVisible(widget, w, 0, 0);
|
|
}
|
|
|
|
void Container::ResizeTimeOut(void *data, XtIntervalId * /*id*/)
|
|
{
|
|
Container *obj = (Container *)data;
|
|
int h4 = obj->Parent()->Height();
|
|
Dimension h1, h2, h3;
|
|
|
|
if (obj->NumChildren())
|
|
{
|
|
Dimension max_height;
|
|
MotifUI **children = (MotifUI **)obj->Children();
|
|
int i;
|
|
XtWidgetGeometry preferred;
|
|
|
|
max_height = 0;
|
|
for (i = 0; i < obj->NumChildren(); i++)
|
|
{
|
|
if (XtIsManaged(children[i]->BaseWidget()))
|
|
{
|
|
XtQueryGeometry(children[i]->BaseWidget(), NULL, &preferred);
|
|
if ((h1 = preferred.height) > max_height)
|
|
{
|
|
max_height = h1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
Position y;
|
|
if (max_height)
|
|
XtVaGetValues(children[0]->BaseWidget(), XmNy, &y, NULL);
|
|
else
|
|
y = 0;
|
|
h1 = max_height + (2 * y);
|
|
}
|
|
else
|
|
XtVaGetValues(obj->_workArea, XmNheight, &h1, NULL);
|
|
XtVaGetValues(obj->_clipWidget, XmNheight, &h2, NULL);
|
|
XtVaGetValues(obj->_w, XmNheight, &h3, NULL);
|
|
h3 = h3 - h2 + h1;
|
|
if (h2 != h1)
|
|
{
|
|
if (h4 > (int)h3)
|
|
h3 = h4;
|
|
else if (obj->NumChildren() == 0)
|
|
return;
|
|
h4 = h3;
|
|
}
|
|
else if (h4 <= (int)h3)
|
|
return;
|
|
XtVaSetValues(obj->_w, XmNheight, h4, NULL);
|
|
obj->Refresh();
|
|
XtVaGetValues(obj->_w, XmNheight, &h3, NULL);
|
|
if (h3 != h4)
|
|
XtAppAddTimeOut(obj->appContext, 500, ResizeTimeOut, obj);
|
|
}
|
|
|
|
void Container::ResizeSW(Widget w, XtPointer client_data, XtPointer)
|
|
{
|
|
// Don't calculate resize here, since the scroll bar hasn't been
|
|
// updated. Instead, add a sufficient timeout to calculate the resize
|
|
// after the scroll bar has updated it's XmNvalue resource
|
|
XtAppAddTimeOut(XtWidgetToApplicationContext(w),
|
|
500, ResizeTimeOut, client_data);
|
|
}
|
|
|
|
void Container::ResizeRC(Widget w, XEvent *, String *, int *)
|
|
{
|
|
Container *obj;
|
|
XtVaGetValues(w, XmNuserData, &obj, NULL);
|
|
XtAppAddTimeOut(obj->appContext, 500, ResizeTimeOut, obj);
|
|
}
|