diff options
author | Pixel <pixel@nobis-crew.org> | 2009-11-04 11:56:41 -0800 |
---|---|---|
committer | Pixel <pixel@nobis-crew.org> | 2009-11-04 11:59:33 -0800 |
commit | d577d991b97ae2b5ee1af23641bcffc3f83af5b2 (patch) | |
tree | 590639d50205d1bcfaff2a7d2dc6ebf3f373c7ed /iup/src/mot |
Initial import. Contains the im, cd and iup librairies, and a "working" Makefile for them under linux.
Diffstat (limited to 'iup/src/mot')
33 files changed, 14620 insertions, 0 deletions
diff --git a/iup/src/mot/iupmot_button.c b/iup/src/mot/iupmot_button.c new file mode 100755 index 0000000..2d93588 --- /dev/null +++ b/iup/src/mot/iupmot_button.c @@ -0,0 +1,301 @@ +/** \file + * \brief Button Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/PushB.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_button.h" +#include "iup_drv.h" +#include "iup_image.h" +#include "iup_key.h" + +#include "iupmot_drv.h" + + +void iupdrvButtonAddBorders(int *x, int *y) +{ + int border_size = 2*5; + (*x) += border_size; + (*y) += border_size; +} + +static int motButtonSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_BUTTON_TEXT) + { + iupmotSetMnemonicTitle(ih, value); + return 1; + } + + return 0; +} + +static int motButtonSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + unsigned char align; + char value1[30]="", value2[30]=""; + + iupStrToStrStr(value, value1, value2, ':'); /* value2 is ignored, NOT supported in Motif */ + + if (iupStrEqualNoCase(value1, "ARIGHT")) + align = XmALIGNMENT_END; + else if (iupStrEqualNoCase(value1, "ACENTER")) + align = XmALIGNMENT_CENTER; + else /* "ALEFT" */ + align = XmALIGNMENT_BEGINNING; + + XtVaSetValues (ih->handle, XmNalignment, align, NULL); + return 1; +} + +static int motButtonSetImageAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_BUTTON_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelPixmap, 0); + + if (!iupAttribGet(ih, "IMINACTIVE")) + { + /* if not active and IMINACTIVE is not defined + then automaticaly create one based on IMAGE */ + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 1); /* make_inactive */ + } + return 1; + } + else + return 0; +} + +static int motButtonSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_BUTTON_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 0); + return 1; + } + else + return 0; +} + +static int motButtonSetImPressAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_BUTTON_IMAGE) + { + iupmotSetPixmap(ih, value, XmNarmPixmap, 0); + return 1; + } + else + return 0; +} + +static int motButtonSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + } + return 0; +} + +static int motButtonSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (iupAttribGet(ih, "IMPRESS") || iupAttribGetBoolean(ih, "FLAT")) + { + /* ignore given value, must use only from parent */ + value = iupBaseNativeParentGetBgColor(ih); + + if (iupdrvBaseSetBgColorAttrib(ih, value)) + return 1; + } + + return iupdrvBaseSetBgColorAttrib(ih, value); +} + +static int motButtonSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + if (iupAttribGet(ih, "IMPRESS") || iupAttribGetBoolean(ih, "FLAT")) + { + /* ignore given value, must use only from parent */ + value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + if (iupdrvBaseSetBgColorAttrib(ih, value)) + return 1; + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL); + return 1; + } + } + } + return 0; +} + +static void motButtonActivateCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + Icallback cb; + + /* Must manually hide the tip if the button is pressed. */ + iupmotTipLeaveNotify(); + + cb = IupGetCallback(ih, "ACTION"); + if (cb) + { + if (cb(ih) == IUP_CLOSE) + IupExitLoop(); + } + (void)w; + (void)call_data; +} + +static void motButtonEnterLeaveWindowEvent(Widget w, Ihandle* ih, XEvent *evt, Boolean *cont) +{ + iupmotEnterLeaveWindowEvent(w, ih, evt, cont); + + if (evt->type == EnterNotify) + XtVaSetValues(ih->handle, XmNshadowThickness, 2, NULL); + else if (evt->type == LeaveNotify) + XtVaSetValues(ih->handle, XmNshadowThickness, 0, NULL); +} + +static int motButtonMapMethod(Ihandle* ih) +{ + char* value; + int num_args = 0; + Arg args[30]; + + value = iupAttribGet(ih, "IMAGE"); + if (value) + { + ih->data->type = IUP_BUTTON_IMAGE; + iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP); + } + else + { + ih->data->type = IUP_BUTTON_TEXT; + iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + } + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Label */ + iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ + iupmotSetArg(args, num_args, XmNmarginLeft, 0); + iupmotSetArg(args, num_args, XmNmarginBottom, 0); + iupmotSetArg(args, num_args, XmNmarginRight, 0); + /* PushButton */ + iupmotSetArg(args, num_args, XmNfillOnArm, False); + + /* Primitive */ + if (iupAttribGetBoolean(ih, "FOCUSONCLICK")) + { + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + } + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmPushButtonWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + value = iupAttribGet(ih, "IMPRESS"); + if (iupAttribGetBoolean(ih, "FLAT") && !value) + { + XtVaSetValues(ih->handle, XmNshadowThickness, 0, NULL); + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)motButtonEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)motButtonEnterLeaveWindowEvent, (XtPointer)ih); + } + else + { + if (value && !iupAttribGetStr(ih, "IMPRESSBORDER")) + XtVaSetValues(ih->handle, XmNshadowThickness, 0, NULL); + else + XtVaSetValues(ih->handle, XmNshadowThickness, 2, NULL); + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + } + + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNactivateCallback, (XtCallbackProc)motButtonActivateCallback, (XtPointer)ih); + XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih); + + /* Disable Drag Source */ + iupmotDisableDragSource(ih->handle); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + if (ih->data->type == IUP_BUTTON_TEXT) + iupmotSetString(ih->handle, XmNlabelString, ""); + + return IUP_NOERROR; +} + +void iupdrvButtonInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motButtonMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", iupmotGetBgColorAttrib, motButtonSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motButtonSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, motButtonSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupButton only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, motButtonSetAlignmentAttrib, "ACENTER:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "IMAGE", NULL, motButtonSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, motButtonSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, motButtonSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FOCUSONCLICK", NULL, NULL, IUPAF_SAMEASSYSTEM, "YES", IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "PADDING", iupButtonGetPaddingAttrib, motButtonSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); +} diff --git a/iup/src/mot/iupmot_canvas.c b/iup/src/mot/iupmot_canvas.c new file mode 100755 index 0000000..7777cf3 --- /dev/null +++ b/iup/src/mot/iupmot_canvas.c @@ -0,0 +1,639 @@ +/** \file + * \brief Canvas Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/ScrolledW.h> +#include <Xm/DrawingA.h> +#include <Xm/ScrollBar.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_canvas.h" +#include "iup_key.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + + +static void motDialogScrollbarCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + int op = (int)client_data, ipage, ipos; + Ihandle *ih; + IFniff cb; + double posx, posy; + (void)call_data; + + XtVaGetValues(w, XmNuserData, &ih, NULL); + if (!ih) return; + + XtVaGetValues(w, + XmNvalue, &ipos, + XmNpageIncrement, &ipage, + NULL); + + if (op > IUP_SBDRAGV) + { + iupCanvasCalcScrollRealPos(iupAttribGetFloat(ih,"XMIN"), iupAttribGetFloat(ih,"XMAX"), &posx, + IUP_SB_MIN, IUP_SB_MAX, ipage, &ipos); + ih->data->posx = (float)posx; + posy = ih->data->posy; + } + else + { + iupCanvasCalcScrollRealPos(iupAttribGetFloat(ih,"YMIN"), iupAttribGetFloat(ih,"YMAX"), &posy, + IUP_SB_MIN, IUP_SB_MAX, ipage, &ipos); + ih->data->posy = (float)posy; + posx = ih->data->posx; + } + + cb = (IFniff)IupGetCallback(ih,"SCROLL_CB"); + if (cb) + cb(ih, op, (float)posx, (float)posy); + else + { + IFnff cb = (IFnff)IupGetCallback(ih,"ACTION"); + if (cb) + cb (ih, (float)posx, (float)posy); + } +} + +static void motCanvasResizeCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + Dimension width, height; + IFnii cb; + (void)call_data; + + if (!XtWindow(w) || !ih) return; + + /* client size */ + XtVaGetValues(w, XmNwidth, &width, + XmNheight, &height, + NULL); + + cb = (IFnii)IupGetCallback(ih,"RESIZE_CB"); + if (cb) + cb(ih,width,height); +} + +static int motCanvasSetBgColorAttrib(Ihandle* ih, const char* value); + +static void motCanvasExposeCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + IFnff cb; + (void)call_data; + + if (!XtWindow(w) || !ih) return; + + cb = (IFnff)IupGetCallback(ih,"ACTION"); + if (cb) + { + if (!iupAttribGet(ih, "_IUPMOT_NO_BGCOLOR")) + motCanvasSetBgColorAttrib(ih, iupAttribGetStr(ih, "BGCOLOR")); /* reset to update window attributes */ + + cb (ih, ih->data->posx, ih->data->posy); + } +} + +static void motCanvasInputCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + XEvent *evt = ((XmDrawingAreaCallbackStruct*)call_data)->event; + + if (!XtWindow(w) || !ih) return; + + switch (evt->type) + { + case ButtonPress: + /* Force focus on canvas click */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) + XmProcessTraversal(w, XmTRAVERSE_CURRENT); + /* break missing on purpose... */ + case ButtonRelease: + { + XButtonEvent *but_evt = (XButtonEvent*)evt; + Boolean cont = True; + iupmotButtonPressReleaseEvent(w, ih, evt, &cont); + if (cont == False) + return; + + if ((evt->type==ButtonPress) && (but_evt->button==Button4 || but_evt->button==Button5)) + { + IFnfiis wcb = (IFnfiis)IupGetCallback(ih, "WHEEL_CB"); + if (wcb) + { + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + int delta = but_evt->button==Button4? 1: -1; + iupmotButtonKeySetStatus(but_evt->state, but_evt->button, status, 0); + + wcb(ih, (float)delta, but_evt->x, but_evt->y, status); + } + else + { + IFniff scb = (IFniff)IupGetCallback(ih,"SCROLL_CB"); + float posy = ih->data->posy; + int delta = but_evt->button==Button4? 1: -1; + int op = but_evt->button==Button4? IUP_SBUP: IUP_SBDN; + posy -= delta*iupAttribGetFloat(ih, "DY")/10.0f; + IupSetfAttribute(ih, "POSY", "%g", posy); + if (scb) + scb(ih,op,ih->data->posx,ih->data->posy); + } + } + } + break; + } +} + +static void motCanvasSetScrollInfo(Widget sb, int imin, int imax, int ipos, int ipage, int iline) +{ + XtVaSetValues(sb, + XmNminimum, imin, + XmNmaximum, imax, + XmNvalue, ipos, + XmNincrement, iline, + XmNpageIncrement, ipage, + XmNsliderSize, ipage, /* to make the thumb proportional */ + NULL); +} + +static int motCanvasSetDXAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_HORIZ) + { + double posx, xmin, xmax, linex; + float dx; + int iposx, ipagex, ilinex; + Widget sb_horiz, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb_horiz, NULL); + if (!sb_horiz) return 1; + + if (!iupStrToFloat(value, &dx)) + return 1; + + xmin = iupAttribGetFloat(ih, "XMIN"); + xmax = iupAttribGetFloat(ih, "XMAX"); + posx = ih->data->posx; + + iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx, + IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx); + + if (!iupAttribGet(ih,"LINEX")) + { + ilinex = ipagex/10; + if (!ilinex) + ilinex = 1; + } + else + { + /* line and page convertions are the same */ + linex = iupAttribGetFloat(ih,"LINEX"); + iupCanvasCalcScrollIntPos(xmin, xmax, linex, 0, + IUP_SB_MIN, IUP_SB_MAX, &ilinex, NULL); + } + + if (dx >= (xmax-xmin)) + { + if (iupAttribGetBoolean(ih, "XAUTOHIDE")) + XtUnmanageChild(sb_horiz); + else + XtSetSensitive(sb_horiz, 0); + return 1; + } + else + { + if (!XtIsManaged(sb_horiz)) + XtManageChild(sb_horiz); + XtSetSensitive(sb_horiz, 1); + } + + motCanvasSetScrollInfo(sb_horiz, IUP_SB_MIN, IUP_SB_MAX, iposx, ipagex, ilinex); + + /* update position because it could be corrected */ + iupCanvasCalcScrollRealPos(xmin, xmax, &posx, + IUP_SB_MIN, IUP_SB_MAX, ipagex, &iposx); + + ih->data->posx = (float)posx; + } + return 1; +} + +static int motCanvasSetPosXAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_HORIZ) + { + double xmin, xmax, dx; + float posx; + int iposx, ipagex; + Widget sb_horiz, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb_horiz, NULL); + if (!sb_horiz) return 1; + + if (!iupStrToFloat(value, &posx)) + return 1; + + xmin = iupAttribGetFloat(ih, "XMIN"); + xmax = iupAttribGetFloat(ih, "XMAX"); + dx = iupAttribGetFloat(ih, "DX"); + + if (posx < xmin) posx = (float)xmin; + if (posx > (xmax - dx)) posx = (float)(xmax - dx); + ih->data->posx = posx; + + iupCanvasCalcScrollIntPos(xmin, xmax, dx, posx, + IUP_SB_MIN, IUP_SB_MAX, &ipagex, &iposx); + + XtVaSetValues(sb_horiz, XmNvalue, iposx, NULL); + } + return 1; +} + +static int motCanvasSetDYAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_VERT) + { + double posy, ymin, ymax, liney; + float dy; + int iposy, ipagey, iliney; + Widget sb_vert, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb_vert, NULL); + if (!sb_vert) return 1; + + if (!iupStrToFloat(value, &dy)) + return 1; + + ymin = iupAttribGetFloat(ih, "YMIN"); + ymax = iupAttribGetFloat(ih, "YMAX"); + posy = ih->data->posy; + + iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy, + IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy); + + if (!iupAttribGet(ih,"LINEY")) + { + iliney = ipagey/10; + if (!iliney) + iliney = 1; + } + else + { + /* line and page convertions are the same */ + liney = iupAttribGetFloat(ih,"LINEY"); + iupCanvasCalcScrollIntPos(ymin, ymax, liney, 0, + IUP_SB_MIN, IUP_SB_MAX, &iliney, NULL); + } + + if (dy >= (ymax-ymin)) + { + if (iupAttribGetBoolean(ih, "YAUTOHIDE")) + XtUnmanageChild(sb_vert); + else + XtSetSensitive(sb_vert, 0); + return 1; + } + else + { + if (!XtIsManaged(sb_vert)) + XtManageChild(sb_vert); + XtSetSensitive(sb_vert, 1); + } + + motCanvasSetScrollInfo(sb_vert, IUP_SB_MIN, IUP_SB_MAX, iposy, ipagey, iliney); + + /* update position because it could be corrected */ + iupCanvasCalcScrollRealPos(ymin, ymax, &posy, + IUP_SB_MIN, IUP_SB_MAX, ipagey, &iposy); + + ih->data->posy = (float)posy; + } + return 1; +} + +static int motCanvasSetPosYAttrib(Ihandle* ih, const char *value) +{ + if (ih->data->sb & IUP_SB_VERT) + { + double ymin, ymax, dy; + float posy; + int iposy, ipagey; + Widget sb_vert, sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb_vert, NULL); + if (!sb_vert) return 1; + + if (!iupStrToFloat(value, &posy)) + return 1; + + ymin = iupAttribGetFloat(ih, "YMIN"); + ymax = iupAttribGetFloat(ih, "YMAX"); + dy = iupAttribGetFloat(ih, "DY"); + + if (posy < ymin) posy = (float)ymin; + if (posy > (ymax - dy)) posy = (float)(ymax - dy); + ih->data->posy = posy; + + iupCanvasCalcScrollIntPos(ymin, ymax, dy, posy, + IUP_SB_MIN, IUP_SB_MAX, &ipagey, &iposy); + + XtVaSetValues(sb_vert, XmNvalue, iposy, NULL); + } + return 1; +} + +static char* motCanvasGetXDisplayAttrib(Ihandle *ih) +{ + (void)ih; + return (char*)iupmot_display; +} + +static char* motCanvasGetXScreenAttrib(Ihandle *ih) +{ + (void)ih; + return (char*)iupmot_screen; +} + +static char* motCanvasGetXWindowAttrib(Ihandle *ih) +{ + return (char*)XtWindow(ih->handle); +} + +static char* motCanvasGetClientSizeAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + Dimension width, height; + XtVaGetValues(ih->handle, XmNwidth, &width, + XmNheight, &height, + NULL); + + sprintf(str, "%dx%d", (int)width, (int)height); + return str; +} + +static int motCanvasSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + + /* ignore given value, must use only from parent for the scrollbars */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + Widget sb; + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + + iupmotSetBgColor(sb_win, color); + + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + } + + if (!IupGetCallback(ih, "ACTION")) + iupdrvBaseSetBgColorAttrib(ih, value); /* Use the given value only here */ + else + { + XSetWindowAttributes attrs; + attrs.background_pixmap = None; + XChangeWindowAttributes(iupmot_display, XtWindow(ih->handle), CWBackPixmap, &attrs); + iupAttribSetStr(ih, "_IUPMOT_NO_BGCOLOR", "1"); + } + + return 1; +} + +static void motCanvasLayoutUpdateMethod(Ihandle *ih) +{ + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + Dimension border; + + /* IMPORTANT: + The ScrolledWindow border, added by the Core, is NOT included in the Motif size. + So when setting the size, we must compensate the border, + so the actual size will be the size we expect. + */ + + XtVaGetValues(sb_win, XmNborderWidth, &border, NULL); + + XtVaSetValues(sb_win, + XmNx, (XtArgVal)ih->x, + XmNy, (XtArgVal)ih->y, + XmNwidth, (XtArgVal)(ih->currentwidth-2*border), + XmNheight, (XtArgVal)(ih->currentheight-2*border), + NULL); +} + +static int motCanvasMapMethod(Ihandle* ih) +{ + Widget sb_win; + char *visual; + int num_args = 0; + Arg args[20]; + + if (!ih->parent) + return IUP_ERROR; + + ih->data->sb = iupBaseGetScrollbar(ih); + + /******************************/ + /* Create the scrolled window */ + /******************************/ + + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); + iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and draw area */ + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + if (iupAttribGetBoolean(ih, "BORDER")) + { + iupmotSetArg(args, num_args, XmNborderWidth, 1); + iupmotSetArg(args, num_args, XmNborderColor, iupmotColorGetPixelStr("0 0 0")); + } + else + iupmotSetArg(args, num_args, XmNborderWidth, 0); + + sb_win = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmScrolledWindowWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!sb_win) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + /****************************/ + /* Create the drawing area */ + /****************************/ + + num_args = 0; + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNresizePolicy, XmRESIZE_NONE); /* no automatic resize of children */ + if (ih->iclass->is_interactive) + { + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); /* include in navigation */ + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + } + else + { + iupmotSetArg(args, num_args, XmNnavigationType, XmNONE); + iupmotSetArg(args, num_args, XmNtraversalOn, False); + } + + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + + visual = IupGetAttribute(ih, "VISUAL"); /* defined by the OpenGL Canvas or NULL */ + if (visual) + { + Colormap colormap = (Colormap)iupAttribGet(ih, "COLORMAP"); + if (colormap) + iupmotSetArg(args, num_args, XmNcolormap,colormap); + + iupmotDialogSetVisual(ih, visual); + } + + ih->handle = XtCreateManagedWidget( + "draw_area", /* child identifier */ + xmDrawingAreaWidgetClass, /* widget class */ + sb_win, /* widget parent */ + args, num_args); + + if (!ih->handle) + { + XtDestroyWidget(sb_win); + return IUP_ERROR; + } + + if (visual) + iupmotDialogResetVisual(ih); + + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)sb_win); + XtVaSetValues(sb_win, XmNworkWindow, ih->handle, NULL); + + { + XSetWindowAttributes attrs; + attrs.bit_gravity = ForgetGravity; /* For the DrawingArea widget gets Expose events when you resize it to be smaller. */ + + if (iupAttribGetBoolean(ih, "BACKINGSTORE")) + attrs.backing_store = WhenMapped; + else + attrs.backing_store = NotUseful; + + XChangeWindowAttributes(iupmot_display, XtWindow(ih->handle), CWBitGravity|CWBackingStore, &attrs); + } + + if (ih->data->sb & IUP_SB_HORIZ) + { + Widget sb_horiz = XtVaCreateManagedWidget("sb_horiz", + xmScrollBarWidgetClass, sb_win, + XmNorientation, XmHORIZONTAL, + XmNsliderMark, XmTHUMB_MARK, + XmNuserData, ih, + NULL); + + XtAddCallback(sb_horiz, XmNvalueChangedCallback, motDialogScrollbarCallback, (void*)IUP_SBPOSH); + XtAddCallback(sb_horiz, XmNdragCallback, motDialogScrollbarCallback, (void*)IUP_SBDRAGH); + XtAddCallback(sb_horiz, XmNdecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBLEFT); + XtAddCallback(sb_horiz, XmNincrementCallback, motDialogScrollbarCallback, (void*)IUP_SBRIGHT); + XtAddCallback(sb_horiz, XmNpageDecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGLEFT); + XtAddCallback(sb_horiz, XmNpageIncrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGRIGHT); + + XtVaSetValues(sb_win, XmNhorizontalScrollBar, sb_horiz, NULL); + } + + if (ih->data->sb & IUP_SB_VERT) + { + Widget sb_vert = XtVaCreateManagedWidget("sb_vert", + xmScrollBarWidgetClass, sb_win, + XmNorientation, XmVERTICAL, + XmNsliderMark, XmTHUMB_MARK, + XmNuserData, ih, + NULL); + + XtAddCallback(sb_vert, XmNvalueChangedCallback, motDialogScrollbarCallback, (void*)IUP_SBPOSV); + XtAddCallback(sb_vert, XmNdragCallback, motDialogScrollbarCallback, (void*)IUP_SBDRAGV); + XtAddCallback(sb_vert, XmNdecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBUP); + XtAddCallback(sb_vert, XmNincrementCallback, motDialogScrollbarCallback, (void*)IUP_SBDN); + XtAddCallback(sb_vert, XmNpageDecrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGUP); + XtAddCallback(sb_vert, XmNpageIncrementCallback, motDialogScrollbarCallback, (void*)IUP_SBPGDN); + + XtVaSetValues(sb_win, XmNverticalScrollBar, sb_vert, NULL); + } + + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNexposeCallback, (XtCallbackProc)motCanvasExposeCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNresizeCallback, (XtCallbackProc)motCanvasResizeCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNinputCallback, (XtCallbackProc)motCanvasInputCallback, (XtPointer)ih); + + XtAddEventHandler(ih->handle, EnterWindowMask, False,(XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False,(XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + + XtAddEventHandler(ih->handle, FocusChangeMask, False,(XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyReleaseMask, False, (XtEventHandler)iupmotCanvasKeyReleaseEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih); + + /* initialize the widget */ + XtRealizeWidget(sb_win); + + return IUP_NOERROR; +} + +void iupdrvCanvasInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motCanvasMapMethod; + ic->LayoutUpdate = motCanvasLayoutUpdateMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motCanvasSetBgColorAttrib, "255 255 255", NULL, IUPAF_DEFAULT); /* force new default value */ + + /* IupCanvas only */ + iupClassRegisterAttribute(ic, "DRAWSIZE", motCanvasGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CURSOR", NULL, iupdrvBaseSetCursorAttrib, IUPAF_SAMEASSYSTEM, "ARROW", IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "DX", NULL, motCanvasSetDXAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "DY", NULL, motCanvasSetDYAttrib, "0.1", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "POSX", iupCanvasGetPosXAttrib, motCanvasSetPosXAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "POSY", iupCanvasGetPosYAttrib, motCanvasSetPosYAttrib, "0.0", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "YAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "XAUTOHIDE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED); + + /* IupCanvas X only */ + iupClassRegisterAttribute(ic, "XWINDOW", motCanvasGetXWindowAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "XDISPLAY", motCanvasGetXDisplayAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "XSCREEN", motCanvasGetXScreenAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "BACKINGSTORE", NULL, NULL, "YES", NULL, IUPAF_NOT_MAPPED); +} diff --git a/iup/src/mot/iupmot_clipboard.c b/iup/src/mot/iupmot_clipboard.c new file mode 100755 index 0000000..43a0087 --- /dev/null +++ b/iup/src/mot/iupmot_clipboard.c @@ -0,0 +1,208 @@ +/** \file + * \brief Clipboard for the Motif Driver. + * + * See Copyright Notice in "iup.h" + */ + + +#include <stdio.h> +#include <stdlib.h> + +#include <Xm/Xm.h> +#include <Xm/CutPaste.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" + +#include "iupmot_drv.h" + + +static Window motClipboardGetWindow(void) +{ + Ihandle* focus = IupGetFocus(); + Ihandle* dlg; + if (!focus) return (Window)NULL; + dlg = IupGetDialog(focus); + if (dlg) + return XtWindow(dlg->handle); + else + return (Window)NULL; +} + +static int motClipboardSetTextAttrib(Ihandle *ih, const char *value) +{ + long item_id = 0; + Window window = motClipboardGetWindow(); + XmString clip_label = XmStringCreateLocalized ("IupClipboard"); + (void)ih; + + if (XmClipboardStartCopy(iupmot_display, window, clip_label, CurrentTime, NULL, NULL, &item_id)!=ClipboardSuccess) + { + XmStringFree(clip_label); + return 0; + } + + XmStringFree(clip_label); + + XmClipboardCopy(iupmot_display, window, item_id, "STRING", (char*)value, (long)strlen(value)+1, 0, NULL); + XmClipboardEndCopy(iupmot_display, window, item_id); + return 0; +} + +static char* motClipboardGetTextAttrib(Ihandle *ih) +{ + unsigned long size; + char* str; + Window window = motClipboardGetWindow(); + (void)ih; + + if (XmClipboardInquireLength(iupmot_display, window, "STRING", &size)!=ClipboardSuccess) + return NULL; + + str = iupStrGetMemory(size+1); + + if (XmClipboardRetrieve(iupmot_display, window, "STRING", str, size+1, NULL, NULL)!=ClipboardSuccess) + return NULL; + + return str; +} + +static int motClipboardSetImageAttrib(Ihandle *ih, const char *value) +{ + Pixmap pixmap; + long item_id = 0; + Window window = motClipboardGetWindow(); + XmString clip_label = XmStringCreateLocalized ("IupClipboard"); + + if (XmClipboardStartCopy(iupmot_display, window, clip_label, CurrentTime, NULL, NULL, &item_id)!=ClipboardSuccess) + { + XmStringFree(clip_label); + return 0; + } + + XmStringFree(clip_label); + + pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + + XmClipboardCopy(iupmot_display, window, item_id, "PIXMAP", (char*)&pixmap, sizeof(Pixmap), 0, NULL); + XmClipboardEndCopy(iupmot_display, window, item_id); + + (void)ih; + return 0; +} + +static int motClipboardSetNativeImageAttrib(Ihandle *ih, const char *value) +{ + long item_id = 0; + Window window = motClipboardGetWindow(); + XmString clip_label = XmStringCreateLocalized ("IupClipboard"); + Pixmap pixmap = (Pixmap)value; + + if (XmClipboardStartCopy(iupmot_display, window, clip_label, CurrentTime, NULL, NULL, &item_id)!=ClipboardSuccess) + { + XmStringFree(clip_label); + return 0; + } + + XmStringFree(clip_label); + + XmClipboardCopy(iupmot_display, window, item_id, "PIXMAP", (char*)&pixmap, sizeof(Pixmap), 0, NULL); + XmClipboardEndCopy(iupmot_display, window, item_id); + + (void)ih; + return 0; +} + +static char* motClipboardGetNativeImageAttrib(Ihandle *ih) +{ + unsigned long size; + void* data; + Pixmap pixmap; + Window window = motClipboardGetWindow(); + (void)ih; + + if (XmClipboardInquireLength(iupmot_display, window, "PIXMAP", &size)!=ClipboardSuccess) + return NULL; + + data = XtMalloc(size); + + if (XmClipboardRetrieve(iupmot_display, window, "PIXMAP", data, size, NULL, NULL)!=ClipboardSuccess) + return NULL; + + pixmap = *((Pixmap*)data); + XtFree(data); + return (char*)pixmap; +} + +static int motClipboardIsAvailable(const char* format_name) +{ + Window window = motClipboardGetWindow(); + int count, i; + unsigned long max_length, length; + char* str; + + if (XmClipboardInquireCount(iupmot_display, window, &count, &max_length) != ClipboardSuccess) + return 0; + + str = iupStrGetMemory(max_length+1); + + for (i = 1; i<=count; i++) + { + if (XmClipboardInquireFormat(iupmot_display, window, i, str, max_length+1, &length)==ClipboardSuccess) + { + if (iupStrEqualNoCase(str, format_name)) + return 1; + } + } + + return 0; +} + +static char* motClipboardGetTextAvailableAttrib(Ihandle *ih) +{ + (void)ih; + if (motClipboardIsAvailable("STRING")) + return "YES"; + else + return "NO"; +} + +static char* motClipboardGetImageAvailableAttrib(Ihandle *ih) +{ + (void)ih; + if (motClipboardIsAvailable("PIXMAP")) + return "YES"; + else + return "NO"; +} + +/******************************************************************************/ + +Ihandle* IupClipboard(void) +{ + return IupCreate("clipboard"); +} + +Iclass* iupClipboardGetClass(void) +{ + Iclass* ic = iupClassNew(NULL); + + ic->name = "clipboard"; + ic->format = NULL; /* no parameters */ + ic->nativetype = IUP_TYPECONTROL; + ic->childtype = IUP_CHILDNONE; + ic->is_interactive = 0; + + /* Attribute functions */ + iupClassRegisterAttribute(ic, "TEXT", motClipboardGetTextAttrib, motClipboardSetTextAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "NATIVEIMAGE", motClipboardGetNativeImageAttrib, motClipboardSetNativeImageAttrib, NULL, NULL, IUPAF_NO_STRING|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, motClipboardSetImageAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TEXTAVAILABLE", motClipboardGetTextAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEAVAILABLE", motClipboardGetImageAvailableAttrib, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + + return ic; +} diff --git a/iup/src/mot/iupmot_color.c b/iup/src/mot/iupmot_color.c new file mode 100755 index 0000000..276bccc --- /dev/null +++ b/iup/src/mot/iupmot_color.c @@ -0,0 +1,380 @@ +/** \file + * \brief Motif Driver color management + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <limits.h> + +#include <Xm/Xm.h> +#include <X11/Xproto.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + + +/* local variables */ + +typedef struct _Icolor +{ + Colormap colormap; /* colormap for all canvas, dialogs and menus */ + XColor color_table[256]; /* colormap colors */ + int num_colors; /* number of colors in colormap */ + + int rshift; /* red shift for truecolor */ + int gshift; /* green shift for truecolor */ + int bshift; /* blue shift for truecolor */ + + int direct_conv[256]; /* used with directColor visuals */ +} Icolor; + +static Icolor mot_color; + + +/******************************************* + NOT TrueColor Functions +*******************************************/ + +static int motColor8BppErrorHandler(Display* dpy, XErrorEvent *err) +{ + char msg[80]; + + /* BadAcess in XFreeColors is OK */ + if (err->request_code==X_FreeColors && err->error_code==BadAccess) + return 0; + + XGetErrorText(dpy, err->error_code, msg, 80 ); + fprintf(stderr,"IUP Motif error handler: Xlib request %d: %s\n", err->request_code, msg); + + return 0; +} + +static unsigned long motColorNearestRGB(XColor* xc1) +{ + static int nearest_try = 0; + + int pos = 0, i; + unsigned long min_dist = ULONG_MAX, this_dist; + int dr, dg, db; + XColor* xc2; + + for (i=0; i<mot_color.num_colors; i++) + { + xc2 = &(mot_color.color_table[i]); + + dr = (xc1->red - xc2->red) / 850; /* 0.30 / 255 */ + dg = (xc1->green - xc2->green) / 432; /* 0.59 / 255 */ + db = (xc1->blue - xc2->blue) / 2318; /* 0.11 / 255 */ + + this_dist = dr*dr + dg*dg + db*db; + + if (this_dist < min_dist) + { + min_dist = this_dist; + pos = i; + } + } + + /* verifico se a cor ainda esta alocada */ + /* Try to allocate the closest match color. This should only + fail if the cell is read/write. Otherwise, we're incrementing + the cell's reference count. (comentario extraido da biblioteca Mesa) */ + if (!XAllocColor(iupmot_display, mot_color.colormap, + &(mot_color.color_table[pos]))) + { + /* nao esta, preciso atualizar a tabela e procurar novamente */ + /* isto acontece porque a cor encontrada pode ter sido de uma aplicacao que nao existe mais */ + /* uma vez atualizada, o problema nao ocorrera' na nova procura */ + /* ou a celula e' read write */ + + if (nearest_try == 1) + { + nearest_try = 0; + return mot_color.color_table[pos].pixel; + } + + XQueryColors(iupmot_display, mot_color.colormap, mot_color.color_table, mot_color.num_colors); + + nearest_try = 1; /* garante que so' vai tentar isso uma vez */ + return motColorNearestRGB(xc1); + } + + return mot_color.color_table[pos].pixel; +} + +static unsigned long motColorGetPixel_NotTrueColor(unsigned char cr, unsigned char cg, unsigned char cb) +{ + unsigned long pixel; + XColor xc; + xc.red = iupCOLOR8TO16(cr); + xc.green = iupCOLOR8TO16(cg); + xc.blue = iupCOLOR8TO16(cb); + xc.flags = DoRed | DoGreen | DoBlue; + + /* verificamos se a nova cor ja' esta' disponivel */ + if (!XAllocColor(iupmot_display, mot_color.colormap, &xc)) + { + /* nao estava disponivel, procuro pela mais proxima na tabela de cores */ + pixel = motColorNearestRGB(&xc); + } + else + { + /* ja' estava disponivel */ + /* atualizo a tabela de cores */ + mot_color.color_table[xc.pixel] = xc; + pixel = xc.pixel; + } + + return pixel; +} + +static void motColorGetRGB_NotTrueColor(unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue) +{ + XColor xc; + xc.pixel = pixel; + XQueryColor(iupmot_display, mot_color.colormap, &xc); + *red = (unsigned char)xc.red; + *green = (unsigned char)xc.green; + *blue = (unsigned char)xc.blue; +} + +static void motColorReserveColors(void) +{ + unsigned char r, g, b; + unsigned long background, foreground, shadow, highlight, selection; + XtVaGetValues(iupmot_appshell, XmNbackground, &background, NULL); + XmGetColors(DefaultScreenOfDisplay(iupmot_display), mot_color.colormap, + background, &foreground, &highlight, &shadow, &selection); + motColorGetRGB_NotTrueColor(background, &r, &g, &b); + motColorGetPixel_NotTrueColor(r, g, b); + motColorGetRGB_NotTrueColor(foreground, &r, &g, &b); + motColorGetPixel_NotTrueColor(r, g, b); + motColorGetRGB_NotTrueColor(shadow, &r, &g, &b); + motColorGetPixel_NotTrueColor(r, g, b); + motColorGetRGB_NotTrueColor(highlight, &r, &g, &b); + motColorGetPixel_NotTrueColor(r, g, b); + motColorGetRGB_NotTrueColor(selection, &r, &g, &b); + motColorGetPixel_NotTrueColor(r, g, b); +} + + +/******************************************* + TrueColor Functions +*******************************************/ + + +static void motColorGetRGB_TrueColor(unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue) +{ + unsigned long r = pixel & iupmot_visual->red_mask; + unsigned long g = pixel & iupmot_visual->green_mask; + unsigned long b = pixel & iupmot_visual->blue_mask; + if (mot_color.rshift<0) r = r >> (-mot_color.rshift); + else r = r << mot_color.rshift; + if (mot_color.gshift<0) g = g >> (-mot_color.gshift); + else g = g << mot_color.gshift; + if (mot_color.bshift<0) b = b >> (-mot_color.bshift); + else b = b << mot_color.bshift; + *red = iupCOLOR16TO8(r); + *green = iupCOLOR16TO8(g); + *blue = iupCOLOR16TO8(b); +} + +static unsigned long motColorGetPixel_TrueColor(unsigned char cr, unsigned char cg, unsigned char cb) +{ + unsigned long r = iupCOLOR8TO16(cr); + unsigned long g = iupCOLOR8TO16(cg); + unsigned long b = iupCOLOR8TO16(cb); + + if (mot_color.rshift<0) + r = r << (-mot_color.rshift); + else + r = r >> mot_color.rshift; + + if (mot_color.gshift<0) + g = g << (-mot_color.gshift); + else + g = g >> mot_color.gshift; + + if (mot_color.bshift<0) + b = b << (-mot_color.bshift); + else + b = b >> mot_color.bshift; + + r = r & iupmot_visual->red_mask; + g = g & iupmot_visual->green_mask; + b = b & iupmot_visual->blue_mask; + + return r | g | b; +} + +static int motColorHighBit(unsigned long ul) +{ +/* returns position of highest set bit in 'ul' as an integer (0-31), + or -1 if none */ + int i; unsigned long hb; + + hb = 0x80; hb = hb << 24; /* hb = 0x80000000UL */ + for (i=31; ((ul & hb) == 0) && i>=0; i--, ul<<=1); + return i; +} + +static void motColorMakeDirectCmap(Colormap cmap) +{ + int i, cmaplen, numgot; + unsigned char origgot[256]; + XColor c; + unsigned long rmask, gmask, bmask; + int rshift, gshift, bshift; + + rmask = iupmot_visual->red_mask; + gmask = iupmot_visual->green_mask; + bmask = iupmot_visual->blue_mask; + + rshift = motColorHighBit(rmask) - 15; + gshift = motColorHighBit(gmask) - 15; + bshift = motColorHighBit(bmask) - 15; + + if (rshift<0) rmask = rmask << (-rshift); + else rmask = rmask >> rshift; + + if (gshift<0) gmask = gmask << (-gshift); + else gmask = gmask >> gshift; + + if (bshift<0) bmask = bmask << (-bshift); + else bmask = bmask >> bshift; + + cmaplen = iupmot_visual->map_entries; + if (cmaplen>256) cmaplen=256; + + /* try to alloc a 'cmaplen' long grayscale colormap. May not get all + entries for whatever reason. Build table 'mot_color.direct_conv[]' that + maps range [0..(cmaplen-1)] into set of colors we did get */ + + for (i=0; i<256; i++) { origgot[i] = 0; mot_color.direct_conv[i] = i; } + + for (i=numgot=0; i<cmaplen; i++) + { + c.red = c.green = c.blue = (unsigned short)((i * 0xffff) / (cmaplen - 1)); + c.red = (unsigned short)(c.red & rmask); + c.green = (unsigned short)(c.green & gmask); + c.blue = (unsigned short)(c.blue & bmask); + c.flags = DoRed | DoGreen | DoBlue; + + if (XAllocColor(iupmot_display, cmap, &c)) + { + origgot[i] = 1; + numgot++; + } + } + + if (numgot == 0) + return; + + /* mot_color.direct_conv may or may not have holes in it. */ + for (i=0; i<cmaplen; i++) + { + if (!origgot[i]) + { + int numbak, numfwd; + numbak = numfwd = 0; + while ((i - numbak) >= 0 && !origgot[i-numbak]) numbak++; + while ((i + numfwd) < cmaplen && !origgot[i+numfwd]) numfwd++; + + if (i-numbak<0 || !origgot[i-numbak]) numbak = 999; + if (i+numfwd>=cmaplen || !origgot[i+numfwd]) numfwd = 999; + + if (numbak<numfwd) mot_color.direct_conv[i] = mot_color.direct_conv[i-numbak]; + else if (numfwd<999) mot_color.direct_conv[i] = mot_color.direct_conv[i+numfwd]; + } + } +} + + +/******************************************* + Exported Functions +*******************************************/ + +unsigned long (* iupmotColorGetPixel)(unsigned char r, unsigned char g, unsigned char b) = 0; +void (* iupmotColorGetRGB)(unsigned long pixel, unsigned char* red, unsigned char* green, unsigned char* blue) = 0; + +void iupmotColorInit(void) +{ + int depth = iupdrvGetScreenDepth(); + + if (depth > 8) + { + iupmotColorGetRGB = motColorGetRGB_TrueColor; + iupmotColorGetPixel = motColorGetPixel_TrueColor; + + /* make linear colormap for DirectColor visual */ + if (iupmot_visual->class == DirectColor) + motColorMakeDirectCmap(DefaultColormap(iupmot_display, iupmot_screen)); + + mot_color.rshift = 15 - motColorHighBit(iupmot_visual->red_mask); + mot_color.gshift = 15 - motColorHighBit(iupmot_visual->green_mask); + mot_color.bshift = 15 - motColorHighBit(iupmot_visual->blue_mask); + + mot_color.num_colors = 0; + mot_color.colormap = 0; + } + else + { + int i; + iupmotColorGetRGB = motColorGetRGB_NotTrueColor; + iupmotColorGetPixel = motColorGetPixel_NotTrueColor; + + mot_color.colormap = DefaultColormap(iupmot_display, iupmot_screen); + mot_color.num_colors = 1L << depth; + + for (i=0; i<mot_color.num_colors; i++) + mot_color.color_table[i].pixel = i; + + XQueryColors(iupmot_display, mot_color.colormap, mot_color.color_table, mot_color.num_colors); + XSetErrorHandler(motColor8BppErrorHandler); + + motColorReserveColors(); + } +} + +void iupmotColorFinish(void) +{ + if (mot_color.colormap) + { + unsigned long pixels[256]; + int i; + + /* release colors */ + for (i = 0; i < mot_color.num_colors; i++) + pixels[i] = mot_color.color_table[i].pixel; + + XFreeColors(iupmot_display, mot_color.colormap, pixels, mot_color.num_colors, 0); + + /* release palette */ + if (mot_color.colormap != DefaultColormap(iupmot_display, iupmot_screen)) + XFreeColormap(iupmot_display, mot_color.colormap); + } +} + +Colormap iupmotColorMap(void) +{ + return mot_color.colormap; +} + +unsigned long iupmotColorGetPixelStr(const char* color) +{ + unsigned char r, g, b; + if (!iupStrToRGB(color, &r, &g, &b)) + return (unsigned long)-1; + + return iupmotColorGetPixel(r, g, b); +} diff --git a/iup/src/mot/iupmot_color.h b/iup/src/mot/iupmot_color.h new file mode 100755 index 0000000..a306fd3 --- /dev/null +++ b/iup/src/mot/iupmot_color.h @@ -0,0 +1,36 @@ +/** \file + * \brief Motif Color Management + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMOT_COLOR_H +#define __IUPMOT_COLOR_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* Returns a pixel value from a RGB triple. */ +extern unsigned long (* iupmotColorGetPixel)(unsigned char r, unsigned char g, unsigned char b); + +/* Returns a RGB triple from a pixel value. */ +extern void (* iupmotColorGetRGB)(unsigned long pixel, unsigned char *r, unsigned char *g, unsigned char *b); + +/* initialize the toplevel colormap and the iupmotColorGet* functions */ +void iupmotColorInit(void); +void iupmotColorFinish(void); + +/* returns the toplevel colormap */ +Colormap iupmotColorMap(void); + +/* Returns a pixel value from a IUP color description. */ +unsigned long iupmotColorGetPixelStr(const char* color); + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/mot/iupmot_colordlg.c b/iup/src/mot/iupmot_colordlg.c new file mode 100755 index 0000000..7a949bf --- /dev/null +++ b/iup/src/mot/iupmot_colordlg.c @@ -0,0 +1,31 @@ +/** \file + * \brief IupColorDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" +#include "iup_dialog.h" + +#include "iupmot_drv.h" + + +static int motColorDlgPopup(Ihandle* ih, int x, int y) +{ + (void)ih; + (void)x; + (void)y; + return IUP_ERROR; +} + +void iupdrvColorDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = motColorDlgPopup; +} diff --git a/iup/src/mot/iupmot_common.c b/iup/src/mot/iupmot_common.c new file mode 100755 index 0000000..7b3f8b7 --- /dev/null +++ b/iup/src/mot/iupmot_common.c @@ -0,0 +1,630 @@ +/** \file + * \brief Motif Base Functions + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#include <Xm/Xm.h> +#include <Xm/ScrollBar.h> +#include <X11/cursorfont.h> + +#include "iup.h" +#include "iupkey.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_key.h" +#include "iup_str.h" +#include "iup_class.h" +#include "iup_attrib.h" +#include "iup_focus.h" +#include "iup_key.h" +#include "iup_drv.h" +#include "iup_image.h" +#include "iup_drv.h" + +#include "iupmot_color.h" +#include "iupmot_drv.h" + + + +void iupdrvActivate(Ihandle* ih) +{ + if (iupStrEqual(ih->iclass->name, "text") || iupStrEqual(ih->iclass->name, "multiline")) + XmProcessTraversal(ih->handle, XmTRAVERSE_CURRENT); + else + XtCallActionProc(ih->handle, "ArmAndActivate", 0, 0, 0 ); +} + +static int motActivateMnemonic(Ihandle *dialog, int c) +{ + Ihandle *ih; + char attrib[19] = "_IUPMOT_MNEMONIC_ "; + attrib[17] = (char)c; + ih = (Ihandle*)iupAttribGet(dialog, attrib); + if (iupObjectCheck(ih)) + { + iupdrvActivate(ih); + return IUP_IGNORE; + } + return IUP_CONTINUE; +} + +void iupmotSetMnemonicTitle(Ihandle *ih, const char* value) +{ + char c; + char* str; + + if (!value) + value = ""; + + str = iupStrProcessMnemonic(value, &c, -1); /* remove & and return in c */ + if (str != value) + { + KeySym keysym = iupmotKeyCharToKeySym(c); + XtVaSetValues(ih->handle, XmNmnemonic, keysym, NULL); /* works only for menus, but underlines the letter */ + + if (ih->iclass->nativetype != IUP_TYPEMENU) + { + Ihandle* dialog = IupGetDialog(ih); + char attrib[22] = "_IUPMOT_MNEMONIC_ \0CB"; + attrib[17] = (char)toupper(c); + + /* used by motActivateMnemonic */ + if (iupStrEqual(ih->iclass->name, "label")) + iupAttribSetStr(dialog, attrib, (char*)iupFocusNextInteractive(ih)); + else + iupAttribSetStr(dialog, attrib, (char*)ih); + + /* used by iupmotKeyPressEvent */ + attrib[18] = '_'; + IupSetCallback(dialog, attrib, (Icallback)motActivateMnemonic); + } + + iupmotSetString(ih->handle, XmNlabelString, str); + free(str); + } + else + { + XtVaSetValues (ih->handle, XmNmnemonic, NULL, NULL); + iupmotSetString(ih->handle, XmNlabelString, str); + } +} + +void iupmotSetString(Widget w, const char *resource, const char* value) +{ + XmString xm_str = XmStringCreateLocalized((String)value); + XtVaSetValues(w, resource, xm_str, NULL); + XmStringFree(xm_str); +} + +char* iupmotConvertString(XmString str) +{ + char* text = (char*)XmStringUnparse(str, NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); + char* buf = iupStrGetMemoryCopy(text); + XtFree(text); + return buf; +} + +#ifdef OLD_CONVERT +char* iupmotConvertString(XmString str) +{ + XmStringContext context; + char *text, *p, *buf; + unsigned int length; + XmStringComponentType type; + + if (!XmStringInitContext (&context, str)) + return NULL; + + buf = iupStrGetMemory(XmStringLength(str)); /* always greatter than strlen */ + + /* p keeps a running pointer through buf as text is read */ + p = buf; + while ((type = XmStringGetNextTriple(context, &length, (XtPointer)&text)) != XmSTRING_COMPONENT_END) + { + switch (type) + { + case XmSTRING_COMPONENT_TEXT: + memcpy(p, text, length); + p += length; + *p = 0; + break; + case XmSTRING_COMPONENT_TAB: + *p++ = '\t'; + *p = 0; + break; + case XmSTRING_COMPONENT_SEPARATOR: + *p++ = '\n'; + *p = 0; + break; + } + XtFree(text); + } + + XmStringFreeContext(context); + + return buf; +} +#endif + +void iupdrvReparent(Ihandle* ih) +{ + Widget native_parent = iupChildTreeGetNativeParentHandle(ih); + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + XReparentWindow(iupmot_display, XtWindow(widget), XtWindow(native_parent), 0, 0); +} + +void iupdrvBaseLayoutUpdateMethod(Ihandle *ih) +{ + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + XtVaSetValues(widget, + XmNx, (XtArgVal)ih->x, + XmNy, (XtArgVal)ih->y, + XmNwidth, (XtArgVal)ih->currentwidth, + XmNheight, (XtArgVal)ih->currentheight, + NULL); +} + +void iupdrvBaseUnMapMethod(Ihandle* ih) +{ + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + XtUnrealizeWidget(widget); /* To match the call to XtRealizeWidget */ + XtDestroyWidget(widget); /* To match the call to XtCreateManagedWidget */ +} + +void iupdrvDisplayUpdate(Ihandle *ih) +{ + XExposeEvent evt; + Dimension w, h; + + XtVaGetValues(ih->handle, XmNwidth, &w, + XmNheight, &h, + NULL); + + evt.type = Expose; + evt.display = iupmot_display; + evt.send_event = True; + evt.window = XtWindow(ih->handle); + + evt.x = 0; + evt.y = 0; + evt.width = w; + evt.height = h; + + evt.count = 0; + + /* POST a Redraw */ + XSendEvent(iupmot_display, XtWindow(ih->handle), False, ExposureMask, (XEvent*)&evt); +} + +void iupdrvDisplayRedraw(Ihandle *ih) +{ + Widget w; + + /* POST a Redraw */ + iupdrvDisplayUpdate(ih); + + /* if this element has an inner native parent (like IupTabs), + then redraw that native parent if different from the element. */ + w = (Widget)iupClassObjectGetInnerNativeContainerHandle(ih, (Ihandle*)IupGetAttribute(ih, "VALUE_HANDLE")); + if (w && w != ih->handle) + { + Widget handle = ih->handle; + ih->handle = w; + iupdrvDisplayUpdate(ih); + ih->handle = handle; + } + + /* flush exposure events. */ + XmUpdateDisplay(ih->handle); +} + +void iupdrvScreenToClient(Ihandle* ih, int *x, int *y) +{ + Window child; + XTranslateCoordinates(iupmot_display, RootWindow(iupmot_display, iupmot_screen), + XtWindow(ih->handle), + *x, *y, x, y, &child); +} + +void iupmotHelpCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + Icallback cb = IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + IupExitLoop(); + + (void)call_data; + (void)w; +} + +void iupmotEnterLeaveWindowEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + Icallback cb = NULL; + (void)cont; + (void)w; + + if (evt->type == EnterNotify) + { + iupmotTipEnterNotify(ih); + + cb = IupGetCallback(ih, "ENTERWINDOW_CB"); + } + else if (evt->type == LeaveNotify) + { + iupmotTipLeaveNotify(); + + cb = IupGetCallback(ih, "LEAVEWINDOW_CB"); + } + + if (cb) + cb(ih); +} + +int iupdrvBaseSetZorderAttrib(Ihandle* ih, const char* value) +{ + if (iupdrvIsVisible(ih)) + { + if (iupStrEqualNoCase(value, "TOP")) + XRaiseWindow(iupmot_display, XtWindow(ih->handle)); + else + XLowerWindow(iupmot_display, XtWindow(ih->handle)); + } + + return 0; +} + +void iupdrvSetVisible(Ihandle* ih, int visible) +{ + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + if (visible) + XtMapWidget(widget); + else + XtUnmapWidget(widget); +} + +int iupdrvIsVisible(Ihandle* ih) +{ + XWindowAttributes wa; + XGetWindowAttributes(iupmot_display, XtWindow(ih->handle), &wa); + return (wa.map_state == IsViewable); +} + +int iupdrvIsActive(Ihandle* ih) +{ + return XtIsSensitive(ih->handle); +} + +void iupdrvSetActive(Ihandle* ih, int enable) +{ + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + XtSetSensitive(widget, enable); +} + +char* iupmotGetXWindowAttrib(Ihandle *ih) +{ + return (char*)XtWindow(ih->handle); +} + +char* iupdrvBaseGetXAttrib(Ihandle *ih) +{ + int x, y; + Window child; + char* str = iupStrGetMemory(20); + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + /* Translating to absolute screen coordinates */ + /* source destination */ + XTranslateCoordinates(iupmot_display, + XtWindow(widget), RootWindow(iupmot_display, iupmot_screen), + 0, 0, &x, &y, + &child); + + sprintf(str, "%d", x); + return str; +} + +char* iupdrvBaseGetYAttrib(Ihandle *ih) +{ + int x, y; + Window child; + char* str = iupStrGetMemory(20); + Widget widget = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (!widget) widget = ih->handle; + + /* Translating to absolute screen coordinates */ + /* source destination */ + XTranslateCoordinates(iupmot_display, + XtWindow(widget), RootWindow(iupmot_display, iupmot_screen), + 0, 0, &x, &y, + &child); + + sprintf(str, "%d", y); + return str; +} + +void iupmotSetBgColor(Widget w, Pixel color) +{ + Pixel fgcolor; + XtVaGetValues(w, XmNforeground, &fgcolor, NULL); + XmChangeColor(w, color); + /* XmChangeColor also sets the XmNforeground color, so we must reset to the previous one. */ + XtVaSetValues(w, XmNforeground, fgcolor, NULL); + XtVaSetValues(w, XmNbackgroundPixmap, XmUNSPECIFIED_PIXMAP, NULL); +} + +int iupdrvBaseSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + iupmotSetBgColor(ih->handle, color); + + /* update internal image cache for controls that have the IMAGE attribute */ + iupImageUpdateParent(ih); + } + return 1; +} + +char* iupmotGetBgColorAttrib(Ihandle* ih) +{ + unsigned char r, g, b; + Pixel color; + char* str = iupStrGetMemory(20); + XtVaGetValues(ih->handle, XmNbackground, &color, NULL); + iupmotColorGetRGB(color, &r, &g, &b); + sprintf(str, "%d %d %d", (int)r, (int)g, (int)b); + return str; +} + +int iupdrvBaseSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + XtVaSetValues(ih->handle, XmNforeground, color, NULL); + return 1; +} + +void iupmotGetWindowSize(Ihandle *ih, int *width, int *height) +{ + Dimension w, h; + XtVaGetValues(ih->handle, XmNwidth, &w, + XmNheight, &h, + NULL); + *width = w; + *height = h; +} + +static Cursor motEmptyCursor(Ihandle* ih) +{ + /* creates an empty cursor */ + XColor cursor_color = {0L,0,0,0,0,0}; + char bitsnull[1] = {0x00}; + Pixmap pixmapnull; + Cursor cur; + + pixmapnull = XCreateBitmapFromData(iupmot_display, + XtWindow(ih->handle), + bitsnull, + 1,1); + + cur = XCreatePixmapCursor(iupmot_display, + pixmapnull, + pixmapnull, + &cursor_color, + &cursor_color, + 0,0); + + XFreePixmap(iupmot_display, pixmapnull); + + return cur; +} + +static Cursor motGetCursor(Ihandle* ih, const char* name) +{ + static struct { + const char* iupname; + int sysname; + } table[] = { + { "NONE", 0}, + { "NULL", 0}, + { "ARROW", XC_left_ptr}, + { "BUSY", XC_watch}, + { "CROSS", XC_crosshair}, + { "HAND", XC_hand2}, + { "HELP", XC_question_arrow}, + { "IUP", XC_question_arrow}, + { "MOVE", XC_fleur}, + { "PEN", XC_pencil}, + { "RESIZE_N", XC_top_side}, + { "RESIZE_S", XC_bottom_side}, + { "RESIZE_NS", XC_sb_v_double_arrow}, + { "RESIZE_W", XC_left_side}, + { "RESIZE_E", XC_right_side}, + { "RESIZE_WE", XC_sb_h_double_arrow}, + { "RESIZE_NE", XC_top_right_corner}, + { "RESIZE_SE", XC_bottom_right_corner}, + { "RESIZE_NW", XC_top_left_corner}, + { "RESIZE_SW", XC_bottom_left_corner}, + { "TEXT", XC_xterm}, + { "UPARROW", XC_center_ptr} + }; + + Cursor cur; + char str[50]; + int i, count = sizeof(table)/sizeof(table[0]); + + /* check the cursor cache first (per control)*/ + sprintf(str, "_IUPMOT_CURSOR_%s", name); + cur = (Cursor)iupAttribGet(ih, str); + if (cur) + return cur; + + /* check the pre-defined IUP names first */ + for (i = 0; i < count; i++) + { + if (iupStrEqualNoCase(name, table[i].iupname)) + { + if (table[i].sysname) + cur = XCreateFontCursor(iupmot_display, table[i].sysname); + else + cur = motEmptyCursor(ih); + + break; + } + } + + if (i == count) + { + /* check for a name defined cursor */ + cur = (Cursor)iupImageGetCursor(name); + } + + iupAttribSetStr(ih, str, (char*)cur); + return cur; +} + +int iupdrvBaseSetCursorAttrib(Ihandle* ih, const char* value) +{ + Cursor cur = motGetCursor(ih, value); + if (cur) + { + XDefineCursor(iupmot_display, XtWindow(ih->handle), cur); + return 1; + } + return 0; +} + +#include <Xm/XmP.h> +#include <Xm/DrawP.h> + +void iupdrvDrawFocusRect(Ihandle* ih, void* _gc, int x, int y, int w, int h) +{ + Drawable wnd = (Drawable)IupGetAttribute(ih, "XWINDOW"); /* Use IupGetAttribute to consult the native implemetation */ + GC gc = (GC)_gc; + XmeDrawHighlight(iupmot_display, wnd, gc, x, y, w, h, 1); +} + +void iupdrvBaseRegisterCommonAttrib(Iclass* ic) +{ + iupClassRegisterAttribute(ic, "XMFONTLIST", iupmotGetFontListAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "XFONTSTRUCT", iupmotGetFontStructAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); + iupClassRegisterAttribute(ic, "XFONTID", iupmotGetFontIdAttrib, NULL, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT|IUPAF_NO_STRING); +} + +static void motDoNothing(Widget w, XEvent* evt, String* params, Cardinal* num_params) +{ + (void)w; + (void)evt; + (void)params; + (void)num_params; +} + +void iupmotDisableDragSource(Widget w) +{ + char dragTranslations[] = "#override <Btn2Down>: iupDoNothing()"; + static int do_nothing_rec = 0; + if (!do_nothing_rec) + { + XtActionsRec rec = {"iupDoNothing", (XtActionProc)motDoNothing}; + XtAppAddActions(iupmot_appcontext, &rec, 1); + do_nothing_rec = 1; + } + XtOverrideTranslations(w, XtParseTranslationTable(dragTranslations)); +} + +int iupdrvGetScrollbarSize(void) +{ + return 15; +} + +void iupmotSetPixmap(Ihandle* ih, const char* name, const char* prop, int make_inactive) +{ + if (name) + { + Pixmap old_pixmap; + Pixmap pixmap = (Pixmap)iupImageGetImage(name, ih, make_inactive); + if (!pixmap) + pixmap = XmUNSPECIFIED_PIXMAP; + XtVaGetValues(ih->handle, prop, &old_pixmap, NULL); + if (pixmap != old_pixmap) + XtVaSetValues(ih->handle, prop, pixmap, NULL); + return; + } + + /* if not defined */ + XtVaSetValues(ih->handle, prop, XmUNSPECIFIED_PIXMAP, NULL); +} + +void iupmotButtonPressReleaseEvent(Widget w, Ihandle* ih, XEvent* evt, Boolean* cont) +{ + unsigned long elapsed; + static Time last = 0; + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + IFniiiis cb; + + XButtonEvent *but_evt = (XButtonEvent*)evt; + if (but_evt->button!=Button1 && + but_evt->button!=Button2 && + but_evt->button!=Button3 && + but_evt->button!=Button4 && + but_evt->button!=Button5) + return; + + cb = (IFniiiis) IupGetCallback(ih,"BUTTON_CB"); + if (cb) + { + int ret, doubleclick = 0; + int b = IUP_BUTTON1+(but_evt->button-1); + + /* Double/Single Click */ + if (but_evt->type==ButtonPress) + { + elapsed = but_evt->time - last; + last = but_evt->time; + if ((int)elapsed <= XtGetMultiClickTime(iupmot_display)) + doubleclick = 1; + } + + iupmotButtonKeySetStatus(but_evt->state, but_evt->button, status, doubleclick); + + ret = cb(ih, b, (but_evt->type==ButtonPress), but_evt->x, but_evt->y, status); + if (ret==IUP_CLOSE) + IupExitLoop(); + else if (ret==IUP_IGNORE) + *cont=False; + } + + (void)w; +} + +void iupmotPointerMotionEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + IFniis cb = (IFniis)IupGetCallback(ih,"MOTION_CB"); + if (cb) + { + XMotionEvent *motion_evt = (XMotionEvent*)evt; + char status[IUPKEY_STATUS_SIZE] = IUPKEY_STATUS_INIT; + iupmotButtonKeySetStatus(motion_evt->state, 0, status, 0); + cb(ih, motion_evt->x, motion_evt->y, status); + } + + (void)w; + (void)cont; +} diff --git a/iup/src/mot/iupmot_dialog.c b/iup/src/mot/iupmot_dialog.c new file mode 100755 index 0000000..4eeb834 --- /dev/null +++ b/iup/src/mot/iupmot_dialog.c @@ -0,0 +1,1069 @@ +/** \file + * \brief IupDialog class + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/BulletinB.h> +#include <Xm/MwmUtil.h> +#include <Xm/AtomMgr.h> +#include <Xm/Protocols.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_class.h" +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_dlglist.h" +#include "iup_attrib.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_drvinfo.h" +#include "iup_focus.h" +#include "iup_str.h" +#define _IUPDLG_PRIVATE +#include "iup_dialog.h" +#include "iup_image.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +Atom iupmot_wm_deletewindow = 0; /* used also by IupMessageDlg */ + +static int motDialogSetBgColorAttrib(Ihandle* ih, const char* value); + +/**************************************************************** + Utilities +****************************************************************/ + + +int iupdrvDialogIsVisible(Ihandle* ih) +{ + return iupdrvIsVisible(ih) || ih->data->show_state == IUP_MINIMIZE; +} + +void iupdrvDialogUpdateSize(Ihandle* ih) +{ + Dimension width, height; + XtVaGetValues(ih->handle, XmNwidth, &width, XmNheight, &height, NULL); + ih->currentwidth = width; + ih->currentheight = height; +} + +void iupdrvDialogGetSize(InativeHandle* handle, int *w, int *h) +{ + Dimension width, height; + XtVaGetValues(handle, XmNwidth, &width, XmNheight, &height, NULL); + if (w) *w = width; + if (h) *h = height; +} + +void iupmotDialogSetVisual(Ihandle* ih, void* visual) +{ + Ihandle *dialog = IupGetDialog(ih); + XtVaSetValues(dialog->handle, XmNvisual, visual, NULL); +} + +void iupmotDialogResetVisual(Ihandle* ih) +{ + Ihandle *dialog = IupGetDialog(ih); + XtVaSetValues(dialog->handle, XmNvisual, iupmot_visual, NULL); +} + +void iupdrvDialogSetVisible(Ihandle* ih, int visible) +{ + if (visible) + { + XtMapWidget(ih->handle); + XRaiseWindow(iupmot_display, XtWindow(ih->handle)); + while (!iupdrvDialogIsVisible(ih)); /* waits until window get mapped */ + } + else + { + /* if iupdrvIsVisible reports hidden, then it should be minimized */ + if (!iupdrvIsVisible(ih)) /* can NOT hide a minimized window, so map it first. */ + { + XtMapWidget(ih->handle); + XRaiseWindow(iupmot_display, XtWindow(ih->handle)); + while (!iupdrvDialogIsVisible(ih)); /* waits until window get mapped */ + } + + XtUnmapWidget(ih->handle); + while (iupdrvDialogIsVisible(ih)); /* waits until window gets unmapped */ + } +} + +void iupdrvDialogGetPosition(InativeHandle* handle, int *x, int *y) +{ + Dimension cur_x, cur_y; + XtVaGetValues(handle, XmNx, &cur_x, + XmNy, &cur_y, + NULL); + if (x) *x = cur_x; + if (y) *y = cur_y; +} + +void iupdrvDialogSetPosition(Ihandle *ih, int x, int y) +{ + XtVaSetValues(ih->handle, + XmNx, (XtArgVal)x, + XmNy, (XtArgVal)y, + NULL); +} + +static int motDialogGetMenuSize(Ihandle* ih) +{ + if (ih->data->menu) + return iupdrvMenuGetMenuBarSize(ih->data->menu); + else + return 0; +} + +void iupdrvDialogGetDecoration(Ihandle* ih, int *border, int *caption, int *menu) +{ + static int native_border = 0; + static int native_caption = 0; + + int has_caption = iupAttribGetBoolean(ih, "MAXBOX") || + iupAttribGetBoolean(ih, "MINBOX") || + iupAttribGetBoolean(ih, "MENUBOX") || + IupGetAttribute(ih, "TITLE"); /* must use IupGetAttribute to check from the native implementation */ + + int has_border = has_caption || + iupAttribGetBoolean(ih, "RESIZE") || + iupAttribGetBoolean(ih, "BORDER"); + + *menu = motDialogGetMenuSize(ih); + + if (ih->handle && iupdrvDialogIsVisible(ih)) + { + int win_border, win_caption; + if (iupdrvGetWindowDecor((void*)XtWindow(ih->handle), &win_border, &win_caption)) + { + *border = 0; + if (has_border) + *border = win_border; + + *caption = 0; + if (has_caption) + *caption = win_caption; + + if (!native_border && *border) + native_border = win_border; + + if (!native_caption && *caption) + native_caption = win_caption; + + return; + } + } + + /* I could not set the size of the window including the decorations when the dialog is hidden */ + /* So we have to estimate the size of borders and caption when the dialog is hidden */ + + *border = 0; + if (has_border) + { + if (native_border) + *border = native_border; + else + *border = 5; + } + + *caption = 0; + if (has_caption) + { + if (native_caption) + *caption = native_caption; + else + *caption = 20; + } +} + +static int motDialogQueryWMspecSupport(Atom feature) +{ + static Atom netsuppport = 0; + Atom type; + Atom *atoms; + int format; + unsigned long after, natoms, i; + + if (!netsuppport) + netsuppport = XmInternAtom(iupmot_display, "_NET_SUPPORTED", False); + + /* get all the features */ + XGetWindowProperty(iupmot_display, RootWindow(iupmot_display, iupmot_screen), + netsuppport, 0, LONG_MAX, False, XA_ATOM, &type, &format, &natoms, + &after, (unsigned char **)&atoms); + if (type != XA_ATOM || atoms == NULL) + { + if (atoms) XFree(atoms); + return 0; + } + + /* Lookup the feature we want */ + for (i = 0; i < natoms; i++) + { + if (atoms[i] == feature) + { + XFree(atoms); + return 1; + } + } + + XFree(atoms); + return 0; +} + +static void motDialogSetWindowManagerStyle(Ihandle* ih) +{ + MwmHints hints; + static Atom xwmhint = 0; + if (!xwmhint) + xwmhint = XmInternAtom(iupmot_display, "_MOTIF_WM_HINTS", False); + + hints.flags = (MWM_HINTS_FUNCTIONS | MWM_HINTS_DECORATIONS); + hints.functions = 0; + hints.decorations = 0; + hints.input_mode = 0; + hints.status = 0; + + if (IupGetAttribute(ih, "TITLE")) { /* must use IupGetAttribute to check from the native implementation */ + hints.functions |= MWM_FUNC_MOVE; + hints.decorations |= MWM_DECOR_TITLE; + } + + if (iupAttribGetBoolean(ih, "MENUBOX")) { + hints.functions |= MWM_FUNC_CLOSE; + hints.decorations |= MWM_DECOR_MENU; + } + + if (iupAttribGetBoolean(ih, "MINBOX")) { + hints.functions |= MWM_FUNC_MINIMIZE; + hints.decorations |= MWM_DECOR_MINIMIZE; + } + + if (iupAttribGetBoolean(ih, "MAXBOX")) { + hints.functions |= MWM_FUNC_MAXIMIZE; + hints.decorations |= MWM_DECOR_MAXIMIZE; + } + + if (iupAttribGetBoolean(ih, "RESIZE")) { + hints.functions |= MWM_FUNC_RESIZE; + hints.decorations |= MWM_DECOR_RESIZEH; + } + + if (iupAttribGetBoolean(ih, "BORDER")) + hints.decorations |= MWM_DECOR_BORDER; + + XChangeProperty(iupmot_display, XtWindow(ih->handle), + xwmhint, xwmhint, + 32, PropModeReplace, + (const unsigned char *) &hints, + PROP_MOTIF_WM_HINTS_ELEMENTS); +} + +static void motDialogChangeWMState(Ihandle* ih, Atom state1, Atom state2, int operation) +{ + static Atom wmstate = 0; + if (!wmstate) + wmstate = XmInternAtom(iupmot_display, "_NET_WM_STATE", False); + + if (iupdrvDialogIsVisible(ih)) + { + XEvent evt; + evt.type = ClientMessage; + evt.xclient.type = ClientMessage; + evt.xclient.serial = 0; + evt.xclient.send_event = True; + evt.xclient.display = iupmot_display; + evt.xclient.window = XtWindow(ih->handle); + evt.xclient.message_type = wmstate; + evt.xclient.format = 32; + evt.xclient.data.l[0] = operation; + evt.xclient.data.l[1] = state1; + evt.xclient.data.l[2] = state2; + evt.xclient.data.l[3] = 0; + evt.xclient.data.l[4] = 0; + + XSendEvent(iupmot_display, RootWindow(iupmot_display, iupmot_screen), False, + SubstructureRedirectMask | SubstructureNotifyMask, &evt); + } + else + { + if (operation) + { + if (state1 && state2) + { + Atom atoms[2]; + atoms[0] = state1; + atoms[0] = state2; + + XChangeProperty(iupmot_display, XtWindow(ih->handle), + wmstate, XA_ATOM, + 32, PropModeReplace, + (const unsigned char *)&atoms, 2); + } + else + { + XChangeProperty(iupmot_display, XtWindow(ih->handle), + wmstate, XA_ATOM, + 32, PropModeReplace, + (const unsigned char *)&state1, 1); + } + } + else + { + /* TODO: This is not working. The property is not correctly removed. */ + /* XDeleteProperty(iupmot_display, XtWindow(ih->handle), wmstate); */ + + /* Maybe the right way to do it is to retrieve all the atoms */ + /* and change again with all atoms except the one to remove */ + } + } +} + +static int motDialogSetFullScreen(Ihandle* ih, int fullscreen) +{ + static int support_fullscreen = -1; /* WARNING: The WM can be changed dinamically */ + + static Atom xwmfs = 0; + if (!xwmfs) + xwmfs = XmInternAtom(iupmot_display, "_NET_WM_STATE_FULLSCREEN", False); + + if (support_fullscreen == -1) + support_fullscreen = motDialogQueryWMspecSupport(xwmfs); + + if (support_fullscreen) + { + motDialogChangeWMState(ih, xwmfs, 0, fullscreen); + return 1; + } + + return 0; +} + +int iupdrvDialogSetPlacement(Ihandle* ih) +{ + char* placement; + ih->data->show_state = IUP_SHOW; + + if (iupAttribGetBoolean(ih, "FULLSCREEN")) + return 1; + + placement = iupAttribGet(ih, "PLACEMENT"); + if (!placement) + return 0; + + if (iupStrEqualNoCase(placement, "MINIMIZED")) + { + if (iupdrvDialogIsVisible(ih)) + XIconifyWindow(iupmot_display, XtWindow(ih->handle), iupmot_screen); + else + { + /* TODO: This is not working, so force a minimize after visible. */ + /*XWMHints wm_hints; */ + /*wm_hints.flags = StateHint; */ + /*wm_hints.initial_state = IconicState; */ + /*XSetWMHints(iupmot_display, XtWindow(ih->handle), &wm_hints); */ + + XtMapWidget(ih->handle); + XIconifyWindow(iupmot_display, XtWindow(ih->handle), iupmot_screen); + } + } + else if (iupStrEqualNoCase(placement, "MAXIMIZED")) + { + static Atom maxatoms[2] = {0, 0}; + if (!(maxatoms[0])) + { + maxatoms[0] = XmInternAtom(iupmot_display, "_NET_WM_STATE_MAXIMIZED_VERT", False); + maxatoms[1] = XmInternAtom(iupmot_display, "_NET_WM_STATE_MAXIMIZED_HORZ", False); + } + + motDialogChangeWMState(ih, maxatoms[0], maxatoms[1], 1); + } + else if (iupStrEqualNoCase(placement, "FULL")) + { + int width, height, x, y; + int border, caption, menu; + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + /* position the decoration outside the screen */ + x = -(border); + y = -(border+caption+menu); + + /* the dialog client area will cover the task bar */ + iupdrvGetFullSize(&width, &height); + + height += menu; /* the menu is included in the client area size in Motif. */ + + /* set the new size and position */ + /* The resize event will update the layout */ + XtVaSetValues(ih->handle, + XmNx, (XtArgVal)x, /* outside border */ + XmNy, (XtArgVal)y, + XmNwidth, (XtArgVal)width, /* client size */ + XmNheight, (XtArgVal)height, + NULL); + } + + iupAttribSetStr(ih, "PLACEMENT", NULL); /* reset to NORMAL */ + + return 1; +} + +/**************************************************************************** + Attributes +****************************************************************************/ + + +static int motDialogSetMinSizeAttrib(Ihandle* ih, const char* value) +{ + int decorwidth = 0, decorheight = 0; + int min_w = 1, min_h = 1; /* MINSIZE default value */ + iupStrToIntInt(value, &min_w, &min_h, 'x'); + + /* The minmax size restricts the client area */ + iupDialogGetDecorSize(ih, &decorwidth, &decorheight); + + if (min_w > decorwidth) + XtVaSetValues(ih->handle, XmNminWidth, min_w-decorwidth, NULL); + if (min_h > decorheight) + XtVaSetValues(ih->handle, XmNminHeight, min_h-decorheight, NULL); + + return 1; +} + +static int motDialogSetMaxSizeAttrib(Ihandle* ih, const char* value) +{ + int decorwidth = 0, decorheight = 0; + int max_w = 65535, max_h = 65535; /* MAXSIZE default value */ + iupStrToIntInt(value, &max_w, &max_h, 'x'); + + /* The minmax size restricts the client area */ + iupDialogGetDecorSize(ih, &decorwidth, &decorheight); + + if (max_w > decorwidth) + XtVaSetValues(ih->handle, XmNmaxWidth, max_w-decorwidth, NULL); + if (max_h > decorheight) + XtVaSetValues(ih->handle, XmNmaxHeight, max_h-decorheight, NULL); + + return 1; +} + +static char* motDialogGetXAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + int x; + iupdrvDialogGetPosition(ih->handle, &x, NULL); + + sprintf(str, "%d", x); + return str; +} + +static char* motDialogGetYAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + int y; + iupdrvDialogGetPosition(ih->handle, &y, NULL); + + sprintf(str, "%d", y); + return str; +} + +static int motDialogSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (!value) + value = ""; + + XtVaSetValues(ih->handle, XmNtitle, value, + XmNiconName, value, + NULL); + return 0; +} + +static char* motDialogGetTitleAttrib(Ihandle* ih) +{ + char* title; + XtVaGetValues(ih->handle, XmNtitle, &title, NULL); + + if (!title || title[0] == 0) + return NULL; + else + { + char* str = iupStrGetMemory(200); + strcpy(str, title); + return str; + } +} + +static char* motDialogGetClientSizeAttrib(Ihandle *ih) +{ + char* str = iupStrGetMemory(20); + + Dimension manager_width, manager_height; + Widget dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager"); + XtVaGetValues(dialog_manager, XmNwidth, &manager_width, + XmNheight, &manager_height, + NULL); + + sprintf(str, "%dx%d", (int)manager_width, (int)manager_height - motDialogGetMenuSize(ih)); + return str; +} + +static int motDialogSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager"); + XtVaSetValues(dialog_manager, XmNbackground, color, NULL); + XtVaSetValues(dialog_manager, XmNbackgroundPixmap, XmUNSPECIFIED_PIXMAP, NULL); + return 1; + } + return 0; +} + +static int motDialogSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + if (motDialogSetBgColorAttrib(ih, value)) + return 1; + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + Widget dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager"); + XtVaSetValues(dialog_manager, XmNbackgroundPixmap, pixmap, NULL); + return 1; + } + } + return 0; +} + +static int motDialogSetFullScreenAttrib(Ihandle* ih, const char* value) +{ + if (iupStrBoolean(value)) + { + if (!iupAttribGet(ih, "_IUPMOT_FS_STYLE")) + { + int visible = iupdrvDialogIsVisible(ih); + if (visible) + iupAttribSetStr(ih, "_IUPMOT_FS_STYLE", "VISIBLE"); + else + iupAttribSetStr(ih, "_IUPMOT_FS_STYLE", "HIDDEN"); + + /* save the previous decoration attributes */ + /* during fullscreen these attributes can be consulted by the application */ + iupAttribStoreStr(ih, "_IUPMOT_FS_MAXBOX", iupAttribGet(ih, "MAXBOX")); + iupAttribStoreStr(ih, "_IUPMOT_FS_MINBOX", iupAttribGet(ih, "MINBOX")); + iupAttribStoreStr(ih, "_IUPMOT_FS_MENUBOX",iupAttribGet(ih, "MENUBOX")); + iupAttribStoreStr(ih, "_IUPMOT_FS_RESIZE", iupAttribGet(ih, "RESIZE")); + iupAttribStoreStr(ih, "_IUPMOT_FS_BORDER", iupAttribGet(ih, "BORDER")); + iupAttribStoreStr(ih, "_IUPMOT_FS_TITLE", IupGetAttribute(ih, "TITLE")); /* must use IupGetAttribute to check from the native implementation */ + + /* remove the decorations attributes */ + iupAttribSetStr(ih, "MAXBOX", "NO"); + iupAttribSetStr(ih, "MINBOX", "NO"); + iupAttribSetStr(ih, "MENUBOX", "NO"); + IupSetAttribute(ih, "TITLE", NULL); iupAttribSetStr(ih, "TITLE", NULL); /* remove from the hash table if we are during IupMap */ + iupAttribSetStr(ih, "RESIZE", "NO"); + iupAttribSetStr(ih, "BORDER", "NO"); + + /* use WM fullscreen support */ + if (!motDialogSetFullScreen(ih, 1)) + { + /* or configure fullscreen manually */ + int decor; + int width, height; + + /* hide before changing decorations */ + if (visible) + { + iupAttribSetStr(ih, "_IUPMOT_SHOW_STATE", NULL); /* To avoid a SHOW_CB notification */ + XtUnmapWidget(ih->handle); + } + + /* save the previous position and size */ + iupAttribStoreStr(ih, "_IUPMOT_FS_X", IupGetAttribute(ih, "X")); /* must use IupGetAttribute to check from the native implementation */ + iupAttribStoreStr(ih, "_IUPMOT_FS_Y", IupGetAttribute(ih, "Y")); + iupAttribStoreStr(ih, "_IUPMOT_FS_SIZE", IupGetAttribute(ih, "RASTERSIZE")); + + /* save the previous decoration */ + XtVaGetValues(ih->handle, XmNmwmDecorations, &decor, NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_DECOR", (char*)decor); + + /* remove the decorations */ + XtVaSetValues(ih->handle, XmNmwmDecorations, (XtArgVal)0, NULL); + motDialogSetWindowManagerStyle(ih); + + /* get full screen size */ + iupdrvGetFullSize(&width, &height); + + /* set position and size */ + XtVaSetValues(ih->handle, XmNwidth, (XtArgVal)width, + XmNheight, (XtArgVal)height, + XmNx, (XtArgVal)0, + XmNy, (XtArgVal)0, + NULL); + + /* layout will be updated in motDialogConfigureNotify */ + if (visible) + XtMapWidget(ih->handle); + } + } + } + else + { + char* fs_style = iupAttribGet(ih, "_IUPMOT_FS_STYLE"); + if (fs_style) + { + /* can only switch back from full screen if window was visible */ + /* when fullscreen was set */ + if (iupStrEqualNoCase(fs_style, "VISIBLE")) + { + iupAttribSetStr(ih, "_IUPMOT_FS_STYLE", NULL); + + /* restore the decorations attributes */ + iupAttribStoreStr(ih, "MAXBOX", iupAttribGet(ih, "_IUPMOT_FS_MAXBOX")); + iupAttribStoreStr(ih, "MINBOX", iupAttribGet(ih, "_IUPMOT_FS_MINBOX")); + iupAttribStoreStr(ih, "MENUBOX",iupAttribGet(ih, "_IUPMOT_FS_MENUBOX")); + IupSetAttribute(ih, "TITLE", iupAttribGet(ih, "_IUPMOT_FS_TITLE")); /* TITLE is not stored in the HashTable */ + iupAttribStoreStr(ih, "RESIZE", iupAttribGet(ih, "_IUPMOT_FS_RESIZE")); + iupAttribStoreStr(ih, "BORDER", iupAttribGet(ih, "_IUPMOT_FS_BORDER")); + + if (!motDialogSetFullScreen(ih, 0)) + { + int border, caption, menu, x, y; + int visible = iupdrvDialogIsVisible(ih); + if (visible) + XtUnmapWidget(ih->handle); + + /* restore the decorations */ + XtVaSetValues(ih->handle, XmNmwmDecorations, (XtArgVal)(int)iupAttribGet(ih, "_IUPMOT_FS_DECOR"), NULL); + motDialogSetWindowManagerStyle(ih); + + /* the dialog decoration will not be considered yet in the next XtVaSetValues */ + /* so compensate the decoration when restoring the position and size */ + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + x = iupAttribGetInt(ih, "_IUPMOT_FS_X") - (border); + y = iupAttribGetInt(ih, "_IUPMOT_FS_Y") - (border+caption+menu); + + /* restore position and size */ + XtVaSetValues(ih->handle, + XmNx, (XtArgVal)x, + XmNy, (XtArgVal)y, + XmNwidth, (XtArgVal)(IupGetInt(ih, "_IUPMOT_FS_SIZE") - (2*border)), + XmNheight, (XtArgVal)(IupGetInt2(ih, "_IUPMOT_FS_SIZE") - (2*border+caption)), + NULL); + + /* layout will be updated in motDialogConfigureNotify */ + if (visible) + XtMapWidget(ih->handle); + + /* remove auxiliar attributes */ + iupAttribSetStr(ih, "_IUPMOT_FS_X", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_Y", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_SIZE", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_DECOR", NULL); + } + + /* remove auxiliar attributes */ + iupAttribSetStr(ih, "_IUPMOT_FS_MAXBOX", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_MINBOX", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_MENUBOX",NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_RESIZE", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_BORDER", NULL); + iupAttribSetStr(ih, "_IUPMOT_FS_TITLE", NULL); + } + } + } + return 1; +} + +static int motDialogSetIconAttrib(Ihandle* ih, const char *value) +{ + if (!value) + XtVaSetValues(ih->handle, XmNiconPixmap, NULL, NULL); + else + { + Pixmap icon = (Pixmap)iupImageGetIcon(value); + Pixmap icon_mask = (Pixmap)iupImageGetMask(value); + if (icon) + XtVaSetValues(ih->handle, XmNiconPixmap, icon, NULL); + if (icon_mask) + XtVaSetValues(ih->handle, XmNiconMask, icon, NULL); + } + return 1; +} + +/**************************************************************** + Callbacks and Events +****************************************************************/ + + +static void motDialogCBclose(Widget w, XtPointer client_data, XtPointer call_data) +{ + Icallback cb; + Ihandle *ih = (Ihandle*)client_data; + if (!ih) return; + (void)call_data; + (void)w; + + /* even when ACTIVE=NO the dialog gets this event */ + if (!iupdrvIsActive(ih)) + return; + + cb = IupGetCallback(ih, "CLOSE_CB"); + if (cb) + { + int ret = cb(ih); + if (ret == IUP_IGNORE) + return; + if (ret == IUP_CLOSE) + IupExitLoop(); + } + + IupHide(ih); /* default: close the window */ +} + +static void motDialogConfigureNotify(Widget w, XEvent *evt, String* s, Cardinal *card) +{ + IFnii cb; + int border, caption, menu; + XConfigureEvent *cevent = (XConfigureEvent *)evt; + Ihandle* ih; + (void)s; + (void)card; + + XtVaGetValues(w, XmNuserData, &ih, NULL); + if (!ih) return; + + if (ih->data->menu && ih->data->menu->handle) + { + XtVaSetValues(ih->data->menu->handle, + XmNwidth, (XtArgVal)(cevent->width), + NULL); + } + + if (ih->data->ignore_resize) return; + + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + /* update dialog size */ + ih->currentwidth = cevent->width + 2*border; + ih->currentheight = cevent->height + 2*border + caption; /* menu is inside the dialog_manager */ + + cb = (IFnii)IupGetCallback(ih, "RESIZE_CB"); + if (!cb || cb(ih, cevent->width, cevent->height - menu)!=IUP_IGNORE) /* width and height here are for the client area */ + { + ih->data->ignore_resize = 1; + IupRefresh(ih); + ih->data->ignore_resize = 0; + } +} + +static void motDialogCBStructureNotifyEvent(Widget w, XtPointer data, XEvent *evt, Boolean *cont) +{ + Ihandle *ih = (Ihandle*)data; + int state = -1; + (void)cont; + (void)w; + + switch(evt->type) + { + case MapNotify: + { + if (ih->data->show_state == IUP_MINIMIZE) /* it is a RESTORE. */ + state = IUP_RESTORE; + break; + } + case UnmapNotify: + { + if (ih->data->show_state != IUP_HIDE) /* it is a MINIMIZE. */ + state = IUP_MINIMIZE; + break; + } + } + + if (state < 0) + return; + + if (ih->data->show_state != state) + { + IFni cb; + ih->data->show_state = state; + + cb = (IFni)IupGetCallback(ih, "SHOW_CB"); + if (cb && cb(ih, state) == IUP_CLOSE) + IupExitLoop(); + } +} + +static void motDialogDestroyCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + /* If the IUP dialog was not destroyed, destroy it here. */ + if (iupObjectCheck(ih)) + IupDestroy(ih); + + /* this callback is usefull to destroy children dialogs when the parent is destroyed. */ + /* The application is responsable for destroying the children before this happen. */ + (void)w; + (void)call_data; +} + + +/**************************************************************** + Idialog +****************************************************************/ + +/* replace the common dialog SetChildrenPosition method because of + the menu that it is inside the dialog. */ +static void motDialogSetChildrenPositionMethod(Ihandle* ih, int x, int y) +{ + int menu_h = motDialogGetMenuSize(ih); + (void)x; + (void)y; + + /* Child coordinates are relative to client left-top corner. */ + iupBaseSetPosition(ih->firstchild, 0, menu_h); +} + +static void* motDialogGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child) +{ + (void)child; + return XtNameToWidget(ih->handle, "*dialog_manager"); +} + +static int motDialogMapMethod(Ihandle* ih) +{ + Widget dialog_manager; + InativeHandle* parent; + int mwm_decor = 0; + int num_args = 0; + Arg args[20]; + + if (iupAttribGetBoolean(ih, "DIALOGFRAME")) + { + iupAttribSetStr(ih, "RESIZE", "NO"); + iupAttribSetStr(ih, "MAXBOX", "NO"); + iupAttribSetStr(ih, "MINBOX", "NO"); + } + + /****************************/ + /* Create the dialog shell */ + /****************************/ + + if (iupAttribGet(ih, "TITLE")) + mwm_decor |= MWM_DECOR_TITLE; + if (iupAttribGetBoolean(ih, "MENUBOX")) + mwm_decor |= MWM_DECOR_MENU; + if (iupAttribGetBoolean(ih, "MINBOX")) + mwm_decor |= MWM_DECOR_MINIMIZE; + if (iupAttribGetBoolean(ih, "MAXBOX")) + mwm_decor |= MWM_DECOR_MAXIMIZE; + if (iupAttribGetBoolean(ih, "RESIZE")) + mwm_decor |= MWM_DECOR_RESIZEH; + if (iupAttribGetBoolean(ih, "BORDER")) + mwm_decor |= MWM_DECOR_BORDER; + + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* so XtRealizeWidget will not show the dialog */ + iupmotSetArg(args, num_args, XmNdeleteResponse, XmDO_NOTHING); + iupmotSetArg(args, num_args, XmNallowShellResize, True); /* Used so the BulletinBoard can control the shell size */ + iupmotSetArg(args, num_args, XmNtitle, ""); + iupmotSetArg(args, num_args, XmNvisual, iupmot_visual); + + if (iupmotColorMap()) + iupmotSetArg(args, num_args, XmNcolormap, iupmotColorMap()); + + if (mwm_decor != 0x7E) + iupmotSetArg(args, num_args, XmNmwmDecorations, mwm_decor); + + if (iupAttribGetBoolean(ih, "SAVEUNDER")) + iupmotSetArg(args, num_args, XmNsaveUnder, True); + + parent = iupDialogGetNativeParent(ih); + if (parent) + ih->handle = XtCreatePopupShell(NULL, topLevelShellWidgetClass, (Widget)parent, args, num_args); + else + ih->handle = XtAppCreateShell(NULL, "dialog", topLevelShellWidgetClass, iupmot_display, args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + XmAddWMProtocolCallback(ih->handle, iupmot_wm_deletewindow, motDialogCBclose, (XtPointer)ih); + + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, StructureNotifyMask, False, (XtEventHandler)motDialogCBStructureNotifyEvent, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNdestroyCallback, (XtCallbackProc)motDialogDestroyCallback, (XtPointer)ih); + + /*****************************/ + /* Create the dialog manager */ + /*****************************/ + + dialog_manager = XtVaCreateManagedWidget( + "dialog_manager", + xmBulletinBoardWidgetClass, + ih->handle, + XmNmarginWidth, 0, + XmNmarginHeight, 0, + XmNwidth, 100, /* set this to avoid size calculation problems */ + XmNheight, 100, + XmNborderWidth, 0, + XmNshadowThickness, 0, + XmNnoResize, iupAttribGetBoolean(ih, "RESIZE")? False: True, + XmNresizePolicy, XmRESIZE_NONE, /* no automatic resize of children */ + XmNuserData, ih, /* used only in motDialogConfigureNotify */ + XmNnavigationType, XmTAB_GROUP, + NULL); + + XtOverrideTranslations(dialog_manager, XtParseTranslationTable("<Configure>: iupDialogConfigure()")); + XtAddCallback(dialog_manager, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + XtAddEventHandler(dialog_manager, KeyPressMask, False,(XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + /* child dialogs must be always on top of the parent */ + if (parent) + XSetTransientForHint(iupmot_display, XtWindow(ih->handle), XtWindow(parent)); + + if (mwm_decor != 0x7E) /* some decoration was changed */ + motDialogSetWindowManagerStyle(ih); + + /* Ignore VISIBLE before mapping */ + iupAttribSetStr(ih, "VISIBLE", NULL); + + if (IupGetGlobal("_IUP_RESET_DLGBGCOLOR")) + { + iupmotSetGlobalColorAttrib(dialog_manager, XmNbackground, "DLGBGCOLOR"); + iupmotSetGlobalColorAttrib(dialog_manager, XmNforeground, "DLGFGCOLOR"); + IupSetGlobal("_IUP_RESET_DLGBGCOLOR", NULL); + } + + return IUP_NOERROR; +} + +static void motDialogUnMapMethod(Ihandle* ih) +{ + Widget dialog_manager; + if (ih->data->menu) + { + ih->data->menu->handle = NULL; /* the dialog will destroy the native menu */ + IupDestroy(ih->data->menu); + } + + dialog_manager = XtNameToWidget(ih->handle, "*dialog_manager"); + XtVaSetValues(dialog_manager, XmNuserData, NULL, NULL); + + XtRemoveEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtRemoveEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + XtRemoveEventHandler(ih->handle, StructureNotifyMask, False, (XtEventHandler)motDialogCBStructureNotifyEvent, (XtPointer)ih); + XtRemoveCallback(ih->handle, XmNdestroyCallback, (XtCallbackProc)motDialogDestroyCallback, (XtPointer)ih); + + XtRemoveEventHandler(dialog_manager, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + XtRemoveCallback(dialog_manager, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + iupdrvBaseUnMapMethod(ih); +} + +static void motDialogLayoutUpdateMethod(Ihandle *ih) +{ + int border, caption, menu; + + if (ih->data->ignore_resize || + iupAttribGet(ih, "_IUPMOT_FS_STYLE")) + return; + + /* for dialogs the position is not updated here */ + ih->data->ignore_resize = 1; + + iupdrvDialogGetDecoration(ih, &border, &caption, &menu); + + if (!iupAttribGetBoolean(ih, "RESIZE")) + { + int width = ih->currentwidth - 2*border; + int height = ih->currentheight - 2*border - caption; + XtVaSetValues(ih->handle, + XmNwidth, width, + XmNheight, height, + XmNminWidth, width, + XmNminHeight, height, + XmNmaxWidth, width, + XmNmaxHeight, height, + NULL); + } + else + { + XtVaSetValues(ih->handle, + XmNwidth, (XtArgVal)(ih->currentwidth - 2*border), /* excluding the border */ + XmNheight, (XtArgVal)(ih->currentheight - 2*border - caption), + NULL); + } + + ih->data->ignore_resize = 0; +} + +/***************************************************************/ + +void iupdrvDialogInitClass(Iclass* ic) +{ + /* Driver Dependent Class methods */ + ic->Map = motDialogMapMethod; + ic->UnMap = motDialogUnMapMethod; + ic->LayoutUpdate = motDialogLayoutUpdateMethod; + ic->SetChildrenPosition = motDialogSetChildrenPositionMethod; + ic->GetInnerNativeContainerHandle = motDialogGetInnerNativeContainerHandleMethod; + + if (!iupmot_wm_deletewindow) + { + /* Set up a translation table that captures "Resize" events + (also called ConfigureNotify or Configure events). */ + XtActionsRec rec = {"iupDialogConfigure", motDialogConfigureNotify}; + XtAppAddActions(iupmot_appcontext, &rec, 1); + + /* register atom to intercept the close button in the window frame */ + iupmot_wm_deletewindow = XmInternAtom(iupmot_display, "WM_DELETE_WINDOW", False); + } + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motDialogSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "X", motDialogGetXAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "Y", motDialogGetYAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + + /* Base Container */ + iupClassRegisterAttribute(ic, "CLIENTSIZE", motDialogGetClientSizeAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + + /* Special */ + iupClassRegisterAttribute(ic, "TITLE", motDialogGetTitleAttrib, motDialogSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupDialog only */ + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motDialogSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "ICON", NULL, motDialogSetIconAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FULLSCREEN", NULL, motDialogSetFullScreenAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MINSIZE", NULL, motDialogSetMinSizeAttrib, IUPAF_SAMEASSYSTEM, "1x1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "MAXSIZE", NULL, motDialogSetMaxSizeAttrib, IUPAF_SAMEASSYSTEM, "65535x65535", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SAVEUNDER", NULL, NULL, "YES", NULL, IUPAF_NO_INHERIT); + + /* IupDialog X Only */ + iupClassRegisterAttribute(ic, "XWINDOW", iupmotGetXWindowAttrib, NULL, NULL, NULL, IUPAF_NO_INHERIT|IUPAF_NO_STRING); +} diff --git a/iup/src/mot/iupmot_drv.h b/iup/src/mot/iupmot_drv.h new file mode 100755 index 0000000..8a536ef --- /dev/null +++ b/iup/src/mot/iupmot_drv.h @@ -0,0 +1,75 @@ +/** \file + * \brief Motif Driver + * + * See Copyright Notice in "iup.h" + */ + +#ifndef __IUPMOT_DRV_H +#define __IUPMOT_DRV_H + +#ifdef __cplusplus +extern "C" { +#endif + + +/* global variables, declared in iupmot_open.c */ +extern Widget iupmot_appshell; +extern Display* iupmot_display; +extern int iupmot_screen; +extern XtAppContext iupmot_appcontext; +extern Visual* iupmot_visual; +extern Atom iupmot_wm_deletewindow; + +/* dialog */ +void iupmotDialogSetVisual(Ihandle* ih, void* visual); +void iupmotDialogResetVisual(Ihandle* ih); + +/* focus */ +void iupmotFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont); + +/* key */ +void iupmotCanvasKeyReleaseEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont); +void iupmotKeyPressEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont); +KeySym iupmotKeyCharToKeySym(char c); +void iupmotButtonKeySetStatus(unsigned int state, unsigned int but, char* status, int doubleclick); +void iupmotKeyEncode(int key, unsigned int *keyval, unsigned int *state); + +/* font */ +char* iupmotGetFontListAttrib(Ihandle *ih); +XmFontList iupmotGetFontList(const char* foundry, const char* value); +char* iupmotFindFontList(XmFontList fontlist); +char* iupmotGetFontStructAttrib(Ihandle *ih); +char* iupmotGetFontIdAttrib(Ihandle *ih); + +/* tips */ +/* called from Enter/Leave events to check if a TIP is present. */ +void iupmotTipEnterNotify(Ihandle* ih); +void iupmotTipLeaveNotify(void); +void iupmotTipsFinish(void); + +/* common */ +void iupmotPointerMotionEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont); +void iupmotButtonPressReleaseEvent(Widget w, Ihandle* ih, XEvent* evt, Boolean* cont); +void iupmotEnterLeaveWindowEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont); +void iupmotHelpCallback(Widget w, Ihandle *ih, XtPointer call_data); +void iupmotSetString(Widget w, const char *resource, const char* value); +char* iupmotConvertString(XmString str); +void iupmotSetMnemonicTitle(Ihandle *ih, const char* value); +void iupmotDisableDragSource(Widget w); +void iupmotSetPixmap(Ihandle* ih, const char* name, const char* prop, int make_inactive); +void iupmotSetGlobalColorAttrib(Widget w, const char* xmname, const char* name); +void iupmotSetBgColor(Widget w, Pixel color); +char* iupmotGetBgColorAttrib(Ihandle* ih); + +void iupmotGetWindowSize(Ihandle *ih, int *width, int *height); + +char* iupmotGetXWindowAttrib(Ihandle *ih); + +#define iupmotSetArg(_a, _i, _n, _d) ((_a)[(_i)].name = (_n), (_a)[(_i)].value = (XtArgVal)(_d), (_i)++) + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/iup/src/mot/iupmot_filedlg.c b/iup/src/mot/iupmot_filedlg.c new file mode 100755 index 0000000..768dd2b --- /dev/null +++ b/iup/src/mot/iupmot_filedlg.c @@ -0,0 +1,578 @@ +/** \file + * \brief Motif IupFileDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <Xm/Xm.h> +#include <Xm/MwmUtil.h> +#include <Xm/FileSB.h> +#include <Xm/Protocols.h> +#include <Xm/SelectioB.h> +#include <Xm/MessageB.h> +#include <Xm/DrawingA.h> +#include <Xm/PushB.h> +#include <Xm/Frame.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" +#include "iup_dialog.h" +#include "iup_strmessage.h" +#include "iup_drvinfo.h" + +#include "iupmot_drv.h" + + +enum {IUP_DIALOGOPEN, IUP_DIALOGSAVE, IUP_DIALOGDIR}; + +static void motFileDlgAskUserCallback(Widget w, int* ret_code, XmSelectionBoxCallbackStruct* cbs) +{ + if (cbs->reason == XmCR_OK) + *ret_code = 1; + else + *ret_code = -1; + XtDestroyWidget(XtParent(w)); +} + +static int motFileDlgAskUser(Widget parent, const char* message) +{ + Widget questionbox; + Arg args[3]; + int ret_code = 0; + XmString title; + + XtSetArg(args[0], XmNautoUnmanage, False); + XtSetArg(args[1], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); + XtSetArg(args[2], XmNnoResize, True); + questionbox = XmCreateQuestionDialog(parent, "filedlg_question", args, 3); + iupmotSetString(questionbox, XmNmessageString, message); + XtVaGetValues(parent, XmNdialogTitle, &title, NULL); + XtVaSetValues(questionbox, XmNdialogTitle, title, NULL); + + XtAddCallback(questionbox, XmNokCallback, (XtCallbackProc)motFileDlgAskUserCallback, (XtPointer)&ret_code); + XtAddCallback(questionbox, XmNcancelCallback, (XtCallbackProc)motFileDlgAskUserCallback, (XtPointer)&ret_code); + XtUnmanageChild(XmMessageBoxGetChild(questionbox, XmDIALOG_HELP_BUTTON)); + XtManageChild(questionbox); + + while (ret_code == 0) + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + + XtUnmanageChild(questionbox); + + if (ret_code == 1) + return 1; + else + return 0; +} + +static int motFileDlgCheckValue(Ihandle* ih, Widget w) +{ + char* value = iupAttribGet(ih, "VALUE"); + int dialogtype = iupAttribGetInt(ih, "_IUPDLG_DIALOGTYPE"); + + if (dialogtype == IUP_DIALOGDIR) + { + if (!iupdrvIsDirectory(value)) /* if does not exist or not a directory */ + { + iupStrMessageShowError(ih, "IUP_INVALIDDIR"); + return 0; + } + } + else + { + if (iupdrvIsDirectory(value)) /* selected a directory */ + { + iupStrMessageShowError(ih, "IUP_INVALIDDIR"); + return 0; + } + else if (!iupdrvIsFile(value)) /* new file */ + { + value = iupAttribGet(ih, "ALLOWNEW"); + if (!value) + { + if (dialogtype == IUP_DIALOGSAVE) + value = "YES"; + else + value = "NO"; + } + + if (!iupStrBoolean(value)) + { + iupStrMessageShowError(ih, "IUP_FILENOTEXIST"); + return 0; + } + } + else if (dialogtype == IUP_DIALOGSAVE && !iupAttribGetInt(ih, "NOOVERWRITEPROMPT")) + { + if (!motFileDlgAskUser(w, iupStrMessageGet("IUP_FILEOVERWRITE"))) + return 0; + } + } + + return 1; +} + +static void motFileDlgCBclose(Widget w, XtPointer client_data, XtPointer call_data) +{ + Ihandle *ih = (Ihandle*)client_data; + if (!ih) return; + (void)call_data; + (void)w; + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "STATUS", "-1"); + iupAttribSetStr(ih, "_IUP_WM_DELETE", "1"); +} + +static void motFileDlgCallback(Widget w, Ihandle* ih, XmFileSelectionBoxCallbackStruct* call_data) +{ + (void)w; + if (call_data->reason == XmCR_OK) + { + int dialogtype = iupAttribGetInt(ih, "_IUPDLG_DIALOGTYPE"); + char* filename; + XmStringGetLtoR(call_data->value, XmSTRING_DEFAULT_CHARSET, &filename); + iupAttribStoreStr(ih, "VALUE", filename); + XtFree(filename); + + if (!motFileDlgCheckValue(ih, w)) + return; + + if (dialogtype == IUP_DIALOGDIR) + { + iupAttribSetStr(ih, "STATUS", "0"); + iupAttribSetStr(ih, "FILEEXIST", NULL); + } + else + { + IFnss file_cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (file_cb && file_cb(ih, iupAttribGet(ih, "VALUE"), "OK") == IUP_IGNORE) + return; + + if (iupdrvIsFile(iupAttribGet(ih, "VALUE"))) /* check if file exists */ + { + iupAttribSetStr(ih, "FILEEXIST", "YES"); + iupAttribSetStr(ih, "STATUS", "0"); + } + else + { + iupAttribSetStr(ih, "FILEEXIST", "NO"); + iupAttribSetStr(ih, "STATUS", "1"); + } + } + + if (!iupAttribGetBoolean(ih, "NOCHANGEDIR")) /* do change the current directory */ + { + /* XmFileSelection does not change the current directory */ + XmString xm_dir; + char* dir; + XtVaGetValues(w, XmNdirectory, &xm_dir, NULL); + XmStringGetLtoR(xm_dir, XmSTRING_DEFAULT_CHARSET, &dir); + iupdrvSetCurrentDirectory(dir); + XtFree(dir); + } + } + else if (call_data->reason == XmCR_CANCEL) + { + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "FILEEXIST", NULL); + iupAttribSetStr(ih, "STATUS", "-1"); + } +} + +static void motFileDlgHelpCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + Ihandle *ih = (Ihandle*)client_data; + Icallback cb = IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + { + iupAttribSetStr(ih, "VALUE", NULL); + iupAttribSetStr(ih, "FILEEXIST", NULL); + iupAttribSetStr(ih, "STATUS", "-1"); + } + + (void)call_data; + (void)w; +} + +typedef struct _ImotPromt +{ + XmString xm_dir; + int ret_code; +} ImotPromt; + +static void motFileDlgPromptCallback(Widget w, ImotPromt* prompt, XmSelectionBoxCallbackStruct* cbs) +{ + if (cbs->reason == XmCR_OK) + prompt->xm_dir = XmStringCopy(cbs->value); + + prompt->ret_code = 1; + XtDestroyWidget(XtParent(w)); +} + +static XmString motFileDlgPrompt(Widget parent, const char* message) +{ + Widget promptbox; + Arg args[2]; + ImotPromt prompt; + XmString title; + + XtSetArg(args[0], XmNautoUnmanage, False); + XtSetArg(args[1], XmNdialogStyle, XmDIALOG_FULL_APPLICATION_MODAL); + promptbox = XmCreatePromptDialog(parent, "filedlg_prompt", args, 2); + iupmotSetString(promptbox, XmNselectionLabelString, message); + XtVaGetValues(parent, XmNdialogTitle, &title, NULL); + XtVaSetValues(promptbox, XmNdialogTitle, title, NULL); + + prompt.ret_code = 0; + prompt.xm_dir = NULL; + + XtAddCallback(promptbox, XmNokCallback, (XtCallbackProc)motFileDlgPromptCallback, (XtPointer)&prompt); + XtAddCallback(promptbox, XmNcancelCallback, (XtCallbackProc)motFileDlgPromptCallback, (XtPointer)&prompt); + XtUnmanageChild(XmSelectionBoxGetChild(promptbox, XmDIALOG_HELP_BUTTON)); + XtManageChild(promptbox); + + while (prompt.ret_code == 0) + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + + XtUnmanageChild(promptbox); + + return prompt.xm_dir; +} + +static void motFileDlgNewFolderCallback(Widget w, Widget filebox, XtPointer call_data) +{ + XmString xm_new_dir = motFileDlgPrompt(filebox, iupStrMessageGet("IUP_NAMENEWFOLDER")); + if (xm_new_dir) + { + XmString xm_dir; + XtVaGetValues(filebox, XmNdirectory, &xm_dir, NULL); + xm_dir = XmStringConcat(xm_dir, xm_new_dir); + + { + char* dir; + XmStringGetLtoR(xm_dir, XmSTRING_DEFAULT_CHARSET, &dir); + iupdrvMakeDirectory(dir); + XtFree(dir); + } + + XtVaSetValues(filebox, XmNdirectory, xm_dir, NULL); + + XmStringFree(xm_dir); + XmStringFree(xm_new_dir); + } + + (void)call_data; + (void)w; +} + +static void motFileDlgPreviewCanvasResizeCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + Dimension width, height; + XtVaGetValues(w, XmNwidth, &width, + XmNheight, &height, + NULL); + + iupAttribSetInt(ih, "PREVIEWWIDTH", width); + iupAttribSetInt(ih, "PREVIEWHEIGHT", height); + + (void)call_data; +} + +static void motFileDlgUpdatePreviewGLCanvas(Ihandle* ih) +{ + Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS"); + if (glcanvas) + { + iupAttribSetStr(glcanvas, "XWINDOW", iupAttribGet(ih, "XWINDOW")); + glcanvas->iclass->Map(glcanvas); + } +} + +static void motFileDlgPreviewCanvasInit(Ihandle *ih, Widget w) +{ + XSetWindowAttributes attrs; + GC gc = XCreateGC(iupmot_display, XtWindow(w), 0, NULL); + iupAttribSetStr(ih, "PREVIEWDC", (char*)gc); + iupAttribSetStr(ih, "WID", (char*)w); + + iupAttribSetStr(ih, "XWINDOW", (char*)XtWindow(w)); + iupAttribSetStr(ih, "XDISPLAY", (char*)iupmot_display); + motFileDlgUpdatePreviewGLCanvas(ih); + + attrs.bit_gravity = ForgetGravity; /* For the DrawingArea widget gets Expose events when you resize it to be smaller. */ + attrs.background_pixmap = None; + XChangeWindowAttributes(iupmot_display, XtWindow(w), CWBitGravity|CWBackPixmap, &attrs); +} + +static void motFileDlgPreviewCanvasExposeCallback(Widget w, Ihandle *ih, XtPointer call_data) +{ + Widget filebox = (Widget)iupAttribGet(ih, "_IUPDLG_FILEBOX"); + char* filename; + XmString xm_file; + IFnss cb; + + if (!iupAttribGet(ih, "PREVIEWDC")) + motFileDlgPreviewCanvasInit(ih, w); + + XtVaGetValues(filebox, XmNdirSpec, &xm_file, NULL); + XmStringGetLtoR(xm_file, XmSTRING_DEFAULT_CHARSET, &filename); + + cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (iupdrvIsFile(filename)) + cb(ih, filename, "PAINT"); + else + cb(ih, NULL, "PAINT"); + + XtFree(filename); + (void)call_data; + (void)w; +} + +static void motFileDlgBrowseSelectionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* list_data) +{ + char* filename; + + XmStringGetLtoR(list_data->item, XmSTRING_DEFAULT_CHARSET, &filename); + + if (iupdrvIsFile(filename)) + { + IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + cb(ih, filename, "SELECT"); + } + + XtFree(filename); + (void)w; +} + +static int motFileDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + Widget filebox, dialog; + int dialogtype, style = XmDIALOG_FULL_APPLICATION_MODAL; + IFnss file_cb = NULL; + Widget preview_canvas = NULL; + char* value; + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + value = iupAttribGetStr(ih, "DIALOGTYPE"); + if (iupStrEqualNoCase(value, "SAVE")) + dialogtype = IUP_DIALOGSAVE; + else if (iupStrEqualNoCase(value, "DIR")) + dialogtype = IUP_DIALOGDIR; + else + dialogtype = IUP_DIALOGOPEN; + iupAttribSetInt(ih, "_IUPDLG_DIALOGTYPE", dialogtype); + + if (parent) + { + filebox = XmCreateFileSelectionDialog(parent, "filedialog", NULL, 0); + dialog = XtParent(filebox); + } + else + { + dialog = XtAppCreateShell(NULL, "filedialog", topLevelShellWidgetClass, iupmot_display, NULL, 0); + filebox = XmCreateFileSelectionBox(dialog, "filebox", NULL, 0); + style = XmDIALOG_MODELESS; + XtVaSetValues(dialog, + XmNmwmInputMode, MWM_INPUT_FULL_APPLICATION_MODAL, + XmNmappedWhenManaged, False, + XmNsaveUnder, True, + NULL); + } + if (!filebox) + return IUP_NOERROR; + + if (!iupAttribGetBoolean(ih, "SHOWHIDDEN")) + XtVaSetValues(filebox, XmNfileFilterStyle, XmFILTER_HIDDEN_FILES, NULL); + + value = iupAttribGet(ih, "TITLE"); + if (!value) + { + if (dialogtype == IUP_DIALOGSAVE) + value = "IUP_SAVEAS"; + else if (dialogtype == IUP_DIALOGOPEN) + value = "IUP_OPEN"; + else + value = "IUP_SELECTDIR"; + iupAttribSetStr(ih, "TITLE", iupStrMessageGet(value)); + } + iupmotSetString(filebox, XmNdialogTitle, value); + + XtVaSetValues(filebox, + XmNdialogStyle, style, + XmNautoUnmanage, False, + NULL); + + if (dialogtype == IUP_DIALOGDIR) + XtVaSetValues(filebox, XmNfileTypeMask, XmFILE_DIRECTORY, NULL); + + /* just check for the path inside FILE */ + value = iupAttribGet(ih, "FILE"); + if (value && value[0] == '/') + { + char* dir = iupStrFileGetPath(value); + iupAttribStoreStr(ih, "DIRECTORY", dir); + free(dir); + } + + /* set XmNdirectory before XmNpattern and before XmNdirSpec */ + + value = iupAttribGet(ih, "DIRECTORY"); + if (value) + iupmotSetString(filebox, XmNdirectory, value); + + value = iupAttribGet(ih, "FILTER"); + if (value) + { + char *filter = value; + char *p = strchr(value, ';'); + if (p) + { + int size = p-value; + filter = (char*)malloc(size+1); + memcpy(filter, value, size); + filter[size] = 0; + } + + iupmotSetString(filebox, XmNpattern, filter); + + if (filter != value) + free(filter); + } + + value = iupAttribGet(ih, "FILE"); + if (value) + { + char* file = value; + + if (value[0] != '/') /* if does not contains a full path, then add the directory */ + { + char* cur_dir = NULL; + char* dir = iupAttribGet(ih, "DIRECTORY"); + if (!dir) + { + cur_dir = iupdrvGetCurrentDirectory(); + dir = cur_dir; + } + + file = iupStrFileMakeFileName(dir, value); + + if (cur_dir) + free(cur_dir); + } + + /* clear value before setting. Do not know why we have to do this, + but if not cleared it will fail to set the XmNdirSpec value. */ + iupmotSetString(filebox, XmNdirSpec, ""); + iupmotSetString(filebox, XmNdirSpec, file); + + if (file != value) + free(file); + } + + if (!IupGetCallback(ih, "HELP_CB")) + XtUnmanageChild(XmFileSelectionBoxGetChild(filebox, XmDIALOG_HELP_BUTTON)); + + XtAddCallback(filebox, XmNokCallback, (XtCallbackProc)motFileDlgCallback, (XtPointer)ih); + XtAddCallback(filebox, XmNcancelCallback, (XtCallbackProc)motFileDlgCallback, (XtPointer)ih); + XtAddCallback(filebox, XmNhelpCallback, (XtCallbackProc)motFileDlgHelpCallback, (XtPointer)ih); + + if (dialogtype == IUP_DIALOGDIR) + { + Widget new_folder = XtVaCreateManagedWidget("new_folder", xmPushButtonWidgetClass, filebox, + XmNlabelType, XmSTRING, + NULL); + iupmotSetString(new_folder, XmNlabelString, iupStrMessageGet("IUP_CREATEFOLDER")); + XtAddCallback(new_folder, XmNactivateCallback, (XtCallbackProc)motFileDlgNewFolderCallback, (XtPointer)filebox); + } + else + { + file_cb = (IFnss)IupGetCallback(ih, "FILE_CB"); + if (file_cb) + { + Widget file_list = XmFileSelectionBoxGetChild(filebox, XmDIALOG_LIST); + XtAddCallback(file_list, XmNbrowseSelectionCallback, (XtCallbackProc)motFileDlgBrowseSelectionCallback, (XtPointer)ih); + + if (iupAttribGetBoolean(ih, "SHOWPREVIEW")) + { + Widget frame = XtVaCreateManagedWidget("preview_canvas", xmFrameWidgetClass, filebox, + XmNshadowType, XmSHADOW_ETCHED_IN, + NULL); + + preview_canvas = XtVaCreateManagedWidget("preview_canvas", xmDrawingAreaWidgetClass, frame, + XmNwidth, 180, + XmNheight, 150, + XmNresizePolicy, XmRESIZE_GROW, + NULL); + + XtAddCallback(preview_canvas, XmNexposeCallback, (XtCallbackProc)motFileDlgPreviewCanvasExposeCallback, (XtPointer)ih); + XtAddCallback(preview_canvas, XmNresizeCallback, (XtCallbackProc)motFileDlgPreviewCanvasResizeCallback, (XtPointer)ih); + + iupAttribSetStr(ih, "_IUPDLG_FILEBOX", (char*)filebox); + } + } + } + + XmAddWMProtocolCallback(dialog, iupmot_wm_deletewindow, motFileDlgCBclose, (XtPointer)ih); + XtManageChild(filebox); + + XtRealizeWidget(dialog); + ih->handle = dialog; + iupDialogUpdatePosition(ih); + ih->handle = NULL; /* reset handle */ + + if (file_cb) + { + if (preview_canvas) + motFileDlgPreviewCanvasInit(ih, preview_canvas); + + file_cb(ih, NULL, "INIT"); + } + + if (style == XmDIALOG_MODELESS) + XtPopup(dialog, XtGrabExclusive); + + /* while the user hasn't provided an answer, simulate main loop. + ** The answer changes as soon as the user selects one of the + ** buttons and the callback routine changes its value. */ + iupAttribSetStr(ih, "STATUS", NULL); + while (iupAttribGet(ih, "STATUS") == NULL) + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + + if (file_cb) + { + if (preview_canvas) + XFreeGC(iupmot_display, (GC)iupAttribGet(ih, "PREVIEWDC")); + + file_cb(ih, NULL, "FINISH"); + } + + if (!iupAttribGet(ih, "_IUP_WM_DELETE")) + { + XtUnmanageChild(filebox); + + if (style == XmDIALOG_MODELESS) + { + XtPopdown(dialog); + XtDestroyWidget(dialog); + } + } + + return IUP_NOERROR; +} + +void iupdrvFileDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = motFileDlgPopup; +} diff --git a/iup/src/mot/iupmot_focus.c b/iup/src/mot/iupmot_focus.c new file mode 100755 index 0000000..5b09bd9 --- /dev/null +++ b/iup/src/mot/iupmot_focus.c @@ -0,0 +1,35 @@ +/** \file + * \brief Motif Focus + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> + +#include <stdio.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_focus.h" +#include "iup_attrib.h" +#include "iup_assert.h" +#include "iup_drv.h" + +#include "iupmot_drv.h" + +void iupdrvSetFocus(Ihandle *ih) +{ + XmProcessTraversal(ih->handle, XmTRAVERSE_CURRENT); +} + +void iupmotFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + (void)w; + (void)cont; + + if (evt->type == FocusIn) + iupCallGetFocusCb(ih); + else if (evt->type == FocusOut) + iupCallKillFocusCb(ih); +} diff --git a/iup/src/mot/iupmot_font.c b/iup/src/mot/iupmot_font.c new file mode 100755 index 0000000..8da06dd --- /dev/null +++ b/iup/src/mot/iupmot_font.c @@ -0,0 +1,443 @@ +/** \file + * \brief Motif Font mapping + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> + +#include <Xm/Xm.h> +#include <Xm/XmP.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_attrib.h" +#include "iup_array.h" +#include "iup_object.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_assert.h" + +#include "iupmot_drv.h" + + +typedef struct _ImotFont +{ + char standardfont[1024]; + char xlfd[1024]; /* X-Windows Font Description */ + XmFontList fontlist; /* same as XmRenderTable */ + XFontStruct *fontstruct; + int charwidth, charheight; +} ImotFont; + +static Iarray* mot_fonts = NULL; + +static int motGetFontSize(char* font_name) +{ + int i = 0; + while (i < 8) + { + font_name = strchr(font_name, '-')+1; + i++; + } + + *(strchr(font_name, '-')) = 0; + return atoi(font_name); +} + +static XFontStruct* motLoadFont(const char* foundry, const char *typeface, int size, int bold, int italic, char *xlfd) +{ + XFontStruct* fontstruct; + char font_name[1024]; + char **font_names_list; + char *weight, *slant; + int i, num_fonts, font_size, near_size; + + /* no underline or strikeout support */ + + if (iupStrEqualNoCase(typeface, "System")) + typeface = "fixed"; + + if (!foundry) foundry = "*"; + + if (iupStrEqualNoCase(typeface, "fixed")) + foundry = "misc"; + + if (bold) + weight = "bold"; + else + weight = "medium"; + + if (italic) + slant = "i"; + else + slant = "r"; + + sprintf(font_name,"-%s-%s-%s-%s-*-*-*-*-*-*-*-*-*-*", foundry, typeface, weight, slant); + + font_names_list = XListFonts(iupmot_display, font_name, 32767, &num_fonts); + if (!num_fonts) + { + /* try changing 'i' to 'o', for italic */ + if (italic) + { + slant = "o"; + strstr(font_name, "-i-")[1] = 'o'; + font_names_list = XListFonts(iupmot_display, font_name, 32767, &num_fonts); + } + + if (!num_fonts) + return NULL; + } + + if (size < 0) /* if in pixels convert to points */ + { + double res = ((double)DisplayWidth(iupmot_display, iupmot_screen) / (double)DisplayWidthMM(iupmot_display, iupmot_screen)); /* pixels/mm */ + /* 1 point = 1/72 inch 1 inch = 25.4 mm */ + /* pixel = ((point/72)*25.4)*pixel/mm */ + size = (int)((-size/res)*2.83464567 + 0.5); /* from pixels to points */ + } + + size *= 10; /* convert to deci-points */ + + near_size = -1000; + for (i=0; i<num_fonts; i++) + { + font_size = motGetFontSize(font_names_list[i]); + + if (font_size == size) + { + near_size = font_size; + break; + } + + if (abs(font_size-size) < abs(near_size-size)) + near_size = font_size; + } + + XFreeFontNames(font_names_list); + + sprintf(font_name,"-%s-%s-%s-%s-*-*-*-%d-*-*-*-*-*-*", foundry, typeface, weight, slant, near_size); + fontstruct = XLoadQueryFont(iupmot_display, font_name); + + if (fontstruct) + strcpy(xlfd, font_name); + + return fontstruct; +} + +static XmFontList motFontCreateRenderTable(XFontStruct* fontstruct, int is_underline, int is_strikeout) +{ + XmFontList fontlist; + XmRendition rendition; + Arg args[10]; + int num_args = 0; + + iupmotSetArg(args, num_args, XmNfontType, XmFONT_IS_FONT); + iupmotSetArg(args, num_args, XmNfont, (XtPointer)fontstruct); + iupmotSetArg(args, num_args, XmNloadModel, XmLOAD_IMMEDIATE); + + if (is_underline) + iupmotSetArg(args, num_args, XmNunderlineType, XmSINGLE_LINE); + else + iupmotSetArg(args, num_args, XmNunderlineType, XmNO_LINE); + + if (is_strikeout) + iupmotSetArg(args, num_args, XmNstrikethruType, XmSINGLE_LINE); + else + iupmotSetArg(args, num_args, XmNstrikethruType, XmNO_LINE); + + rendition = XmRenditionCreate(NULL, "", args, num_args); + + fontlist = XmRenderTableAddRenditions(NULL, &rendition, 1, XmDUPLICATE); + + XmRenditionFree(rendition); + + return fontlist; +} + +static int motFontCalcCharWidth(XFontStruct *fontstruct) +{ + if (fontstruct->per_char) + { + int i, all=0; + int first = fontstruct->min_char_or_byte2; + int last = fontstruct->max_char_or_byte2; + if (first < 32) first = 32; /* space */ + if (last > 126) last = 126; /* tilde */ + for (i=first; i<=last; i++) + all += fontstruct->per_char[i].width; + return all/(last-first + 1); /* average character width */ + } + else + return fontstruct->max_bounds.width; +} + +static ImotFont* motFindFont(const char* foundry, const char *standardfont) +{ + char xlfd[1024]; + XFontStruct* fontstruct; + int i, count = iupArrayCount(mot_fonts); + int is_underline = 0, is_strikeout = 0; + + ImotFont* fonts = (ImotFont*)iupArrayGetData(mot_fonts); + + /* Check if the standardfont already exists in cache */ + for (i = 0; i < count; i++) + { + if (iupStrEqualNoCase(standardfont, fonts[i].standardfont)) + return &fonts[i]; + } + + /* not found, create a new one */ + if (standardfont[0] == '-') + { + fontstruct = XLoadQueryFont(iupmot_display, standardfont); + if (!fontstruct) return NULL; + strcpy(xlfd, standardfont); + } + else + { + int size = 0, + is_bold = 0, + is_italic = 0; + char typeface[1024]; + const char* mapped_name; + + if (!iupFontParsePango(standardfont, typeface, &size, &is_bold, &is_italic, &is_underline, &is_strikeout)) + return NULL; + + mapped_name = iupFontGetXName(typeface); + if (mapped_name) + strcpy(typeface, mapped_name); + + fontstruct = motLoadFont(foundry, typeface, size, is_bold, is_italic, xlfd); + if (!fontstruct) return NULL; + } + + /* create room in the array */ + fonts = (ImotFont*)iupArrayInc(mot_fonts); + + strcpy(fonts[i].standardfont, standardfont); + strcpy(fonts[i].xlfd, xlfd); + fonts[i].fontstruct = fontstruct; + fonts[i].fontlist = motFontCreateRenderTable(fontstruct, is_underline, is_strikeout); + fonts[i].charwidth = motFontCalcCharWidth(fontstruct); + fonts[i].charheight = fontstruct->ascent + fontstruct->descent; + + return &fonts[i]; +} + +char* iupdrvGetSystemFont(void) +{ + static char systemfont[200] = ""; + ImotFont* motfont = NULL; + char* font = XGetDefault(iupmot_display, "Iup", "fontList"); + if (font) + motfont = motFindFont(NULL, font); + + if (!motfont) + { + font = "Fixed, 11"; + motfont = motFindFont("misc", font); + } + + strcpy(systemfont, font); + return systemfont; +} + +char* iupmotFindFontList(XmFontList fontlist) +{ + int i, count = iupArrayCount(mot_fonts); + ImotFont* fonts = (ImotFont*)iupArrayGetData(mot_fonts); + + /* Check if the standardfont already exists in cache */ + for (i = 0; i < count; i++) + { + if (fontlist == fonts[i].fontlist) + return fonts[i].standardfont; + } + + return NULL; +} + +XmFontList iupmotGetFontList(const char* foundry, const char* value) +{ + ImotFont *motfont = motFindFont(foundry, value); + if (!motfont) + { + iupERROR1("Failed to create Font: %s", value); + return NULL; + } + + return motfont->fontlist; +} + +static ImotFont* motFontCreateNativeFont(Ihandle* ih, const char* value) +{ + ImotFont *motfont = motFindFont(iupAttribGet(ih, "FOUNDRY"), value); + if (!motfont) + { + iupERROR1("Failed to create Font: %s", value); + return NULL; + } + + iupAttribSetStr(ih, "_IUPMOT_FONT", (char*)motfont); + iupAttribSetStr(ih, "XLFD", motfont->xlfd); + return motfont; +} + +static ImotFont* motGetFont(Ihandle *ih) +{ + ImotFont* motfont = (ImotFont*)iupAttribGet(ih, "_IUPMOT_FONT"); + if (!motfont) + motfont = motFontCreateNativeFont(ih, iupGetFontAttrib(ih)); + return motfont; +} + +char* iupmotGetFontListAttrib(Ihandle *ih) +{ + ImotFont* motfont = motGetFont(ih); + if (!motfont) + return NULL; + else + return (char*)motfont->fontlist; +} + +char* iupmotGetFontStructAttrib(Ihandle *ih) +{ + ImotFont* motfont = motGetFont(ih); + if (!motfont) + return NULL; + else + return (char*)motfont->fontstruct; +} + +char* iupmotGetFontIdAttrib(Ihandle *ih) +{ + ImotFont* motfont = motGetFont(ih); + if (!motfont) + return NULL; + else + return (char*)motfont->fontstruct->fid; +} + +int iupdrvSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + ImotFont *motfont = motFontCreateNativeFont(ih, value); + if (!motfont) + return 1; + + /* If FONT is changed, must update the SIZE attribute */ + iupBaseUpdateSizeFromFont(ih); + + /* FONT attribute must be able to be set before mapping, + so the font is enable for size calculation. */ + if (ih->handle && (ih->iclass->nativetype != IUP_TYPEVOID)) + XtVaSetValues(ih->handle, XmNrenderTable, motfont->fontlist, NULL); + + return 1; +} + +int iupdrvFontGetStringWidth(Ihandle* ih, const char* str) +{ + XFontStruct* fontstruct; + int len; + char* line_end; + + if (!str || str[0]==0) + return 0; + + fontstruct = (XFontStruct*)iupmotGetFontStructAttrib(ih); + if (!fontstruct) + return 0; + + line_end = strchr(str, '\n'); + if (line_end) + len = line_end-str; + else + len = strlen(str); + + return XTextWidth(fontstruct, str, len); +} + +void iupdrvFontGetMultiLineStringSize(Ihandle* ih, const char* str, int *w, int *h) +{ + int num_lin, max_w; + + ImotFont* motfont = motGetFont(ih); + if (!motfont) + { + if (w) *w = 0; + if (h) *h = 0; + return; + } + + if (!str) + { + if (w) *w = 0; + if (h) *h = motfont->charheight * 1; + return; + } + + max_w = 0; + num_lin = 1; + if (str[0]) + { + int len, lw; + const char *nextstr; + const char *curstr = str; + do + { + nextstr = iupStrNextLine(curstr, &len); + lw = XTextWidth(motfont->fontstruct, curstr, len); + max_w = iupMAX(max_w, lw); + + curstr = nextstr; + if (*nextstr) + num_lin++; + } while(*nextstr); + } + + if (w) *w = max_w; + if (h) *h = motfont->charheight * num_lin; +} + + +void iupdrvFontGetCharSize(Ihandle* ih, int *charwidth, int *charheight) +{ + ImotFont* motfont = motGetFont(ih); + if (!motfont) + { + if (charwidth) *charwidth = 0; + if (charheight) *charheight = 0; + return; + } + + if (charheight) + *charheight = motfont->charheight; + + if (charwidth) + *charwidth = motfont->charwidth; +} + +void iupdrvFontInit(void) +{ + mot_fonts = iupArrayCreate(50, sizeof(ImotFont)); +} + +void iupdrvFontFinish(void) +{ + int i, count = iupArrayCount(mot_fonts); + ImotFont* fonts = (ImotFont*)iupArrayGetData(mot_fonts); + for (i = 0; i < count; i++) + { + XmFontListFree(fonts[i].fontlist); + fonts[i].fontlist = NULL; + XFreeFont(iupmot_display, fonts[i].fontstruct); + fonts[i].fontstruct = NULL; + } + iupArrayDestroy(mot_fonts); +} diff --git a/iup/src/mot/iupmot_fontdlg.c b/iup/src/mot/iupmot_fontdlg.c new file mode 100755 index 0000000..42767b2 --- /dev/null +++ b/iup/src/mot/iupmot_fontdlg.c @@ -0,0 +1,31 @@ +/** \file + * \brief IupFontDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" +#include "iup_dialog.h" + +#include "iupmot_drv.h" + + +static int motFontDlgPopup(Ihandle* ih, int x, int y) +{ + (void)ih; + (void)x; + (void)y; + return IUP_ERROR; +} + +void iupdrvFontDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = motFontDlgPopup; +} diff --git a/iup/src/mot/iupmot_frame.c b/iup/src/mot/iupmot_frame.c new file mode 100755 index 0000000..39de5d8 --- /dev/null +++ b/iup/src/mot/iupmot_frame.c @@ -0,0 +1,257 @@ +/** \file + * \brief Frame Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/Frame.h> +#include <Xm/Label.h> +#include <Xm/BulletinB.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" +#include "iup_image.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +void iupdrvFrameGetDecorOffset(Ihandle* ih, int *x, int *y) +{ + (void)ih; + *x = 0; + *y = 0; +} + +static int motFrameSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + + /* ignore given value, must use only from parent */ + value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget title_label, child_manager; + + iupmotSetBgColor(ih->handle, color); + + child_manager = XtNameToWidget(ih->handle, "*child_manager"); + iupmotSetBgColor(child_manager, color); + + title_label = XtNameToWidget(ih->handle, "*title_label"); + if (!title_label) return 1; + iupmotSetBgColor(title_label, color); + + return 1; + } + return 0; +} + +static int motFrameSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + + /* ignore given value, must use only from parent */ + value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget title_label, child_manager; + + iupmotSetBgColor(ih->handle, color); + + child_manager = XtNameToWidget(ih->handle, "*child_manager"); + iupmotSetBgColor(child_manager, color); + + title_label = XtNameToWidget(ih->handle, "*title_label"); + if (!title_label) return 1; + iupmotSetBgColor(title_label, color); + + return 1; + } + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + Widget child_manager = XtNameToWidget(ih->handle, "*child_manager"); + Widget title_label = XtNameToWidget(ih->handle, "*title_label"); + + XtVaSetValues(child_manager, XmNbackgroundPixmap, pixmap, NULL); + if (title_label) + XtVaSetValues(title_label, XmNbackgroundPixmap, pixmap, NULL); + + return 1; + } + } + return 0; +} + +static int motFrameSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget title_label = XtNameToWidget(ih->handle, "*title_label"); + if (!title_label) return 0; + XtVaSetValues(title_label, XmNforeground, color, NULL); + return 1; + } + return 0; +} + +static int motFrameSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetStandardFontAttrib(ih, value); + + if (ih->handle) + { + XmFontList fontlist; + Widget title_label = XtNameToWidget(ih->handle, "*title_label"); + if (!title_label) return 1; + + fontlist = (XmFontList)iupmotGetFontListAttrib(ih); + XtVaSetValues(title_label, XmNrenderTable, fontlist, NULL); + } + + return 1; +} + +static int motFrameSetTitleAttrib(Ihandle* ih, const char* value) +{ + Widget title_label = XtNameToWidget(ih->handle, "*title_label"); + if (title_label) + { + if (!value) value = ""; + iupmotSetString(title_label, XmNlabelString, value); + return 1; + } + return 0; +} + +static void* motFrameGetInnerNativeContainerHandleMethod(Ihandle* ih, Ihandle* child) +{ + (void)child; + return XtNameToWidget(ih->handle, "*child_manager"); +} + +static int motFrameMapMethod(Ihandle* ih) +{ + char *title; + int num_args = 0; + Arg args[20]; + Widget child_manager; + + if (!ih->parent) + return IUP_ERROR; + + title = iupAttribGet(ih, "TITLE"); + + if (title) + iupAttribSetStr(ih, "_IUPFRAME_HAS_TITLE", "1"); + else + { + char* value = iupAttribGetStr(ih, "SUNKEN"); + if (iupStrBoolean(value)) + iupmotSetArg(args, num_args, XmNshadowType, XmSHADOW_IN); + else + iupmotSetArg(args, num_args, XmNshadowType, XmSHADOW_ETCHED_IN); + } + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Manager */ + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + /* Frame */ + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* no shadow margins */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); /* no shadow margins */ + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmFrameWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + if (title) + { + Widget title_label; + num_args = 0; + /* Label */ + iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + /* Frame Constraint */ + iupmotSetArg(args, num_args, XmNchildType, XmFRAME_TITLE_CHILD); + title_label = XtCreateManagedWidget("title_label", xmLabelWidgetClass, ih->handle, args, num_args); + iupmotSetString(title_label, XmNlabelString, title); + } + + child_manager = XtVaCreateManagedWidget( + "child_manager", + xmBulletinBoardWidgetClass, + ih->handle, + /* Core */ + XmNborderWidth, 0, + /* Manager */ + XmNshadowThickness, 0, + XmNnavigationType, XmTAB_GROUP, + /* BulletinBoard */ + XmNmarginWidth, 0, + XmNmarginHeight, 0, + XmNresizePolicy, XmRESIZE_NONE, /* no automatic resize of children */ + /* Frame Constraint */ + XmNchildType, XmFRAME_WORKAREA_CHILD, + NULL); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvFrameInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motFrameMapMethod; + ic->GetInnerNativeContainerHandle = motFrameGetInnerNativeContainerHandleMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, motFrameSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motFrameSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motFrameSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motFrameSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, motFrameSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_globalattrib.c b/iup/src/mot/iupmot_globalattrib.c new file mode 100755 index 0000000..9567cf5 --- /dev/null +++ b/iup/src/mot/iupmot_globalattrib.c @@ -0,0 +1,155 @@ +/** \file + * \brief Motif Driver implementation of iupdrvSetGlobal + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> + +#include <stdio.h> + +#include "iup.h" + +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_strmessage.h" + +#include "iupmot_drv.h" + + +static void motGlobalSendKey(int key, int press) +{ + Window focus; + int revert_to; + XKeyEvent evt; + memset(&evt, 0, sizeof(XKeyEvent)); + evt.display = iupmot_display; + evt.send_event = True; + evt.root = DefaultRootWindow(iupmot_display); + + XGetInputFocus(iupmot_display, &focus, &revert_to); + evt.window = focus; + + iupmotKeyEncode(key, &evt.keycode, &evt.state); + if (!evt.keycode) + return; + + if (press & 0x01) + { + evt.type = KeyPress; + XSendEvent(iupmot_display, (Window)InputFocus, False, KeyPressMask, (XEvent*)&evt); + } + + if (press & 0x02) + { + evt.type = KeyRelease; + XSendEvent(iupmot_display, (Window)InputFocus, False, KeyReleaseMask, (XEvent*)&evt); + } +} + +int iupdrvSetGlobal(const char *name, const char *value) +{ + if (iupStrEqual(name, "LANGUAGE")) + { + iupStrMessageUpdateLanguage(value); + return 1; + } + if (iupStrEqual(name, "AUTOREPEAT")) + { + XKeyboardControl values; + if (iupStrBoolean(value)) + values.auto_repeat_mode = 1; + else + values.auto_repeat_mode = 0; + XChangeKeyboardControl(iupmot_display, KBAutoRepeatMode, &values); + return 0; + } + if (iupStrEqual(name, "CURSORPOS")) + { + int x, y; + if (iupStrToIntInt(value, &x, &y, 'x') == 2) + XWarpPointer(iupmot_display,None,RootWindow(iupmot_display, iupmot_screen),0,0,0,0,x,y); + return 0; + } + if (iupStrEqual(name, "KEYPRESS")) + { + int key; + if (iupStrToInt(value, &key)) + motGlobalSendKey(key, 0x01); + return 0; + } + if (iupStrEqual(name, "KEYRELEASE")) + { + int key; + if (iupStrToInt(value, &key)) + motGlobalSendKey(key, 0x02); + return 0; + } + if (iupStrEqual(name, "KEY")) + { + int key; + if (iupStrToInt(value, &key)) + motGlobalSendKey(key, 0x03); + return 0; + } + return 1; +} + +char* iupdrvGetGlobal(const char *name) +{ + if (iupStrEqual(name, "CURSORPOS")) + { + int x, y; + char* str = iupStrGetMemory(50); + iupdrvGetCursorPos(&x, &y); + sprintf(str, "%dx%d", x, y); + return str; + } + if (iupStrEqual(name, "SHIFTKEY")) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + return "ON"; + return "OFF"; + } + if (iupStrEqual(name, "CONTROLKEY")) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[1] == 'C') + return "ON"; + return "OFF"; + } + if (iupStrEqual(name, "MODKEYSTATE")) + { + char *str = iupStrGetMemory(5); + iupdrvGetKeyState(str); + return str; + } + if (iupStrEqual(name, "SCREENSIZE")) + { + char *str = iupStrGetMemory(50); + int w, h; + iupdrvGetScreenSize(&w, &h); + sprintf(str, "%dx%d", w, h); + return str; + } + if (iupStrEqual(name, "FULLSIZE")) + { + char *str = iupStrGetMemory(50); + int w, h; + iupdrvGetFullSize(&w, &h); + sprintf(str, "%dx%d", w, h); + return str; + } + if (iupStrEqual(name, "SCREENDEPTH")) + { + char *str = iupStrGetMemory(50); + int bpp = iupdrvGetScreenDepth(); + sprintf(str, "%d", bpp); + return str; + } + return NULL; +} diff --git a/iup/src/mot/iupmot_image.c b/iup/src/mot/iupmot_image.c new file mode 100755 index 0000000..b0078d5 --- /dev/null +++ b/iup/src/mot/iupmot_image.c @@ -0,0 +1,397 @@ +/** \file + * \brief Image Resource. + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> + +#include <stdio.h> +#include <limits.h> +#include <stdlib.h> +#include <memory.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_image.h" +#include "iup_drvinfo.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +void iupdrvImageGetRawData(void* handle, unsigned char* imgdata) +{ + Pixmap pixmap = (Pixmap)handle; + int w, h, y, x, bpp; + XImage *xi; + + if (!iupdrvImageGetInfo(handle, &w, &h, &bpp)) + return; + + if (bpp==8) + return; + + xi = XGetImage(iupmot_display, pixmap, 0, 0, w, h, ULONG_MAX, ZPixmap); + if (xi) + { + /* planes are separated in imgdata */ + int planesize = w*h; + unsigned char *r = imgdata, + *g = imgdata+planesize, + *b = imgdata+2*planesize; + for (y=0; y<h; y++) + { + int lineoffset = (h-1 - y)*w; /* imgdata is bottom up */ + for (x=0; x<w; x++) + { + iupmotColorGetRGB(XGetPixel(xi, x, y), r + lineoffset+x, g + lineoffset+x, b + lineoffset+x); + } + } + + XDestroyImage(xi); + } +} + +void* iupdrvImageCreateImageRaw(int width, int height, int bpp, iupColor* colors, int colors_count, unsigned char *imgdata) +{ + int y, x; + Pixmap pixmap; + GC gc; + + pixmap = XCreatePixmap(iupmot_display, + RootWindow(iupmot_display,iupmot_screen), + width, height, iupdrvGetScreenDepth()); + if (!pixmap) + return NULL; + + gc = XCreateGC(iupmot_display,pixmap,0,NULL); + + /* Pixmap is top-bottom */ + /* imgdata is bottom up */ + + if (bpp == 8) + { + Pixel color2pixel[256]; + int i; + for (i=0;i<colors_count;i++) + color2pixel[i] = iupmotColorGetPixel(colors[i].r, colors[i].g, colors[i].b); + + for (y=0;y<height;y++) + { + int lineoffset = (height-1 - y)*width; /* imgdata is bottom up */ + for(x=0;x<width;x++) + { + unsigned long p = color2pixel[imgdata[lineoffset+x]]; + XSetForeground(iupmot_display,gc,p); + XDrawPoint(iupmot_display,pixmap,gc,x,y); + } + } + } + else + { + /* planes are separated in imgdata */ + int planesize = width*height; + unsigned char *r = imgdata, + *g = imgdata+planesize, + *b = imgdata+2*planesize; + for (y=0;y<height;y++) + { + int lineoffset = (height-1 - y)*width; /* imgdata is bottom up */ + for(x=0;x<width;x++) + { + unsigned long p = iupmotColorGetPixel(r[lineoffset+x], g[lineoffset+x], b[lineoffset+x]); + XSetForeground(iupmot_display,gc,p); + XDrawPoint(iupmot_display,pixmap,gc,x,y); + } + } + } + + XFreeGC(iupmot_display,gc); + + return (void*)pixmap; +} + +void* iupdrvImageCreateImage(Ihandle *ih, const char* bgcolor, int make_inactive) +{ + int y, x, bpp, bgcolor_depend = 0, + width = ih->currentwidth, + height = ih->currentheight; + unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + Pixmap pixmap; + unsigned char bg_r=0, bg_g=0, bg_b=0; + GC gc; + Pixel color2pixel[256]; + + bpp = iupAttribGetInt(ih, "BPP"); + + iupStrToRGB(bgcolor, &bg_r, &bg_g, &bg_b); + + if (bpp == 8) + { + int i, colors_count = 0; + iupColor colors[256]; + + iupImageInitColorTable(ih, colors, &colors_count); + + for (i=0;i<colors_count;i++) + { + if (colors[i].a == 0) + { + colors[i].r = bg_r; + colors[i].g = bg_g; + colors[i].b = bg_b; + colors[i].a = 255; + bgcolor_depend = 1; + } + + if (make_inactive) + iupImageColorMakeInactive(&(colors[i].r), &(colors[i].g), &(colors[i].b), + bg_r, bg_g, bg_b); + + color2pixel[i] = iupmotColorGetPixel(colors[i].r, colors[i].g, colors[i].b); + } + } + + pixmap = XCreatePixmap(iupmot_display, + RootWindow(iupmot_display,iupmot_screen), + width, height, iupdrvGetScreenDepth()); + if (!pixmap) + return NULL; + + gc = XCreateGC(iupmot_display,pixmap,0,NULL); + for (y=0;y<height;y++) + { + for(x=0;x<width;x++) + { + unsigned long p; + if (bpp == 8) + p = color2pixel[imgdata[y*width+x]]; + else + { + int channels = (bpp==24)? 3: 4; + unsigned char *pixel_data = imgdata + y*width*channels + x*channels; + unsigned char r = *(pixel_data), + g = *(pixel_data+1), + b = *(pixel_data+2); + + if (bpp == 32) + { + unsigned char a = *(pixel_data+3); + if (a != 255) + { + r = iupALPHABLEND(r, bg_r, a); + g = iupALPHABLEND(g, bg_g, a); + b = iupALPHABLEND(b, bg_b, a); + bgcolor_depend = 1; + } + } + + if (make_inactive) + iupImageColorMakeInactive(&r, &g, &b, bg_r, bg_g, bg_b); + + p = iupmotColorGetPixel(r, g, b); + } + + XSetForeground(iupmot_display,gc,p); + XDrawPoint(iupmot_display,pixmap,gc,x,y); + } + } + XFreeGC(iupmot_display,gc); + + if (bgcolor_depend || make_inactive) + iupAttribSetStr(ih, "_IUP_BGCOLOR_DEPEND", "1"); + + return (void*)pixmap; +} + +void* iupdrvImageCreateIcon(Ihandle *ih) +{ + return iupdrvImageCreateImage(ih, NULL, 0); +} + +void* iupdrvImageCreateCursor(Ihandle *ih) +{ + int bpp,y,x,hx,hy, + width = ih->currentwidth, + height = ih->currentheight, + line_size = (width+7)/8, + size_bytes = line_size*height; + unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + char *sbits, *mbits, *sb, *mb; + Pixmap source, mask; + XColor fg, bg; + unsigned char r, g, b; + Cursor cursor; + + bpp = iupAttribGetInt(ih, "BPP"); + if (bpp > 8) + return NULL; + + sbits = (char*)malloc(2*size_bytes); + if (!sbits) return NULL; + memset(sbits, 0, 2*size_bytes); + mbits = sbits + size_bytes; + + sb = sbits; + mb = mbits; + for (y=0; y<height; y++) + { + for (x=0; x<width; x++) + { + int byte = x/8; + int bit = x%8; + int index = (int)imgdata[y*width+x]; + /* index==0 is transparent */ + if (index == 1) + sb[byte] = (char)(sb[byte] | (1<<bit)); + if (index != 0) + mb[byte] = (char)(mb[byte] | (1<<bit)); + } + + sb += line_size; + mb += line_size; + } + + r = 255; g = 255; b = 255; + iupStrToRGB(iupAttribGet(ih, "1"), &r, &g, &b ); + fg.red = iupCOLOR8TO16(r); + fg.green = iupCOLOR8TO16(g); + fg.blue = iupCOLOR8TO16(b); + fg.flags = DoRed | DoGreen | DoBlue; + + r = 0; g = 0; b = 0; + iupStrToRGB(iupAttribGet(ih, "2"), &r, &g, &b ); + bg.red = iupCOLOR8TO16(r); + bg.green = iupCOLOR8TO16(g); + bg.blue = iupCOLOR8TO16(b); + bg.flags = DoRed | DoGreen | DoBlue; + + hx=0; hy=0; + iupStrToIntInt(iupAttribGet(ih, "HOTSPOT"), &hx, &hy, ':'); + + source = XCreateBitmapFromData(iupmot_display, + RootWindow(iupmot_display,iupmot_screen), + sbits, width, height); + mask = XCreateBitmapFromData(iupmot_display, + RootWindow(iupmot_display,iupmot_screen), + mbits, width, height); + + cursor = XCreatePixmapCursor(iupmot_display, source, mask, &fg, &bg, hx, hy); + + free(sbits); + return (void*)cursor; +} + +void* iupdrvImageCreateMask(Ihandle *ih) +{ + int bpp,y,x, + width = ih->currentwidth, + height = ih->currentheight, + line_size = (width+7)/8, + size_bytes = line_size*height; + unsigned char *imgdata = (unsigned char*)iupAttribGetStr(ih, "WID"); + char *bits, *sb; + Pixmap mask; + unsigned char colors[256]; + + bpp = iupAttribGetInt(ih, "BPP"); + if (bpp > 8) + return NULL; + + bits = (char*)malloc(size_bytes); + if (!bits) return NULL; + memset(bits, 0, size_bytes); + + iupImageInitNonBgColors(ih, colors); + + sb = bits; + for (y=0; y<height; y++) + { + for (x=0; x<width; x++) + { + int byte = x/8; + int bit = x%8; + int index = (int)imgdata[y*width+x]; + if (colors[index]) + sb[byte] = (char)(sb[byte] | (1<<bit)); + } + + sb += line_size; + } + + mask = XCreateBitmapFromData(iupmot_display, + RootWindow(iupmot_display,iupmot_screen), + bits, width, height); + + free(bits); + return (void*)mask; +} + +void* iupdrvImageLoad(const char* name, int type) +{ + if (type == IUPIMAGE_CURSOR) + { + Cursor cursor = 0; + int id; + if (iupStrToInt(name, &id)) + cursor = XCreateFontCursor(iupmot_display, id); + return (void*)cursor; + } + else /* IUPIMAGE_IMAGE or IUPIMAGE_ICON */ + { + Screen* screen = ScreenOfDisplay(iupmot_display, iupmot_screen); + Pixmap pixmap = XmGetPixmap(screen, (char*)name, BlackPixelOfScreen(screen), WhitePixelOfScreen(screen)); + if (pixmap == XmUNSPECIFIED_PIXMAP) + { + unsigned int width, height; + int hotx, hoty; + pixmap = 0; + XReadBitmapFile(iupmot_display, RootWindow(iupmot_display,iupmot_screen), name, &width, &height, &pixmap, &hotx, &hoty); + } + return (void*)pixmap; + } +} + +int iupdrvImageGetInfo(void* handle, int *w, int *h, int *bpp) +{ + Pixmap pixmap = (Pixmap)handle; + Window root; + int x, y; + unsigned int width, height, b, depth; + if (!XGetGeometry(iupmot_display, pixmap, &root, &x, &y, &width, &height, &b, &depth)) + { + if (w) *w = 0; + if (h) *h = 0; + if (bpp) *bpp = 0; + return 0; + } + if (w) *w = width; + if (h) *h = height; + if (bpp) *bpp = iupImageNormBpp(depth); + return 1; +} + +int iupdrvImageGetRawInfo(void* handle, int *w, int *h, int *bpp, iupColor* colors, int *colors_count) +{ + /* How to get the pallete? */ + (void)colors; + (void)colors_count; + return iupdrvImageGetInfo(handle, w, h, bpp); +} + +void iupdrvImageDestroy(void* handle, int type) +{ + if (type == IUPIMAGE_CURSOR) + XFreeCursor(iupmot_display, (Cursor)handle); + else + { + Screen* screen = ScreenOfDisplay(iupmot_display, iupmot_screen); + if (!XmDestroyPixmap(screen, (Pixmap)handle)) + XFreePixmap(iupmot_display, (Pixmap)handle); + } +} + diff --git a/iup/src/mot/iupmot_key.c b/iup/src/mot/iupmot_key.c new file mode 100755 index 0000000..835b5d7 --- /dev/null +++ b/iup/src/mot/iupmot_key.c @@ -0,0 +1,425 @@ +/** \file + * \brief Motif Driver keyboard mapping + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <X11/keysym.h> + +#include <stdlib.h> +#include <stdio.h> +#include <ctype.h> + +#include "iup.h" +#include "iupcbs.h" +#include "iupkey.h" + +#include "iup_object.h" +#include "iup_key.h" +#include "iup_str.h" + +#include "iupmot_drv.h" + +typedef struct Imot2iupkey +{ + KeySym motcode; + int iupcode; + int s_iupcode; + int c_iupcode; + int m_iupcode; + int y_iupcode; +} Imot2iupkey; + +static Imot2iupkey motkey_map[] = { + +{ XK_Escape, K_ESC, K_sESC, K_cESC, K_mESC ,K_yESC }, +{ XK_Pause, K_PAUSE, K_sPAUSE, K_cPAUSE, K_mPAUSE ,K_yPAUSE }, +{ XK_Print, K_Print, K_sPrint, K_cPrint, K_mPrint ,K_yPrint }, +{ XK_Menu, K_Menu, K_sMenu, K_cMenu, K_mMenu ,K_yMenu }, + +{ XK_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME ,K_yHOME }, +{ XK_Up, K_UP, K_sUP, K_cUP, K_mUP ,K_yUP }, +{ XK_Prior, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP ,K_yPGUP }, +{ XK_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT ,K_yLEFT }, +{ XK_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE}, +{ XK_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT ,K_yRIGHT }, +{ XK_End, K_END, K_sEND, K_cEND, K_mEND ,K_yEND }, +{ XK_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN ,K_yDOWN }, +{ XK_Next, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN ,K_yPGDN }, +{ XK_Insert, K_INS, K_sINS, K_cINS, K_mINS ,K_yINS }, +{ XK_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL ,K_yDEL }, +{ XK_space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP }, +{ XK_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB }, +{ XK_Return, K_CR, K_sCR, K_cCR, K_mCR ,K_yCR }, +{ XK_BackSpace, K_BS, K_sBS, K_cBS, K_mBS ,K_yBS }, + +{ XK_1, K_1, K_exclam, K_c1, K_m1, K_y1 }, +{ XK_2, K_2, K_at, K_c2, K_m2, K_y2 }, +{ XK_3, K_3, K_numbersign, K_c3, K_m3, K_y3 }, +{ XK_4, K_4, K_dollar, K_c4, K_m4, K_y4 }, +{ XK_5, K_5, K_percent, K_c5, K_m5, K_y5 }, +{ XK_6, K_6, K_circum, K_c6, K_m6, K_y6 }, +{ XK_7, K_7, K_ampersand, K_c7, K_m7, K_y7 }, +{ XK_8, K_8, K_asterisk, K_c8, K_m8, K_y8 }, +{ XK_9, K_9, K_parentleft, K_c9, K_m9, K_y9 }, +{ XK_0, K_0, K_parentright, K_c0, K_m0, K_y0 }, + +{ XK_a, K_a, K_A, K_cA, K_mA, K_yA }, +{ XK_b, K_b, K_B, K_cB, K_mB, K_yB }, +{ XK_c, K_c, K_C, K_cC, K_mC, K_yC }, +{ XK_d, K_d, K_D, K_cD, K_mD, K_yD }, +{ XK_e, K_e, K_E, K_cE, K_mE, K_yE }, +{ XK_f, K_f, K_F, K_cF, K_mF, K_yF }, +{ XK_g, K_g, K_G, K_cG, K_mG, K_yG }, +{ XK_h, K_h, K_H, K_cH, K_mH, K_yH }, +{ XK_i, K_i, K_I, K_cI, K_mI, K_yI }, +{ XK_j, K_j, K_J, K_cJ, K_mJ, K_yJ }, +{ XK_k, K_k, K_K, K_cK, K_mK, K_yK }, +{ XK_l, K_l, K_L, K_cL, K_mL, K_yL }, +{ XK_m, K_m, K_M, K_cM, K_mM, K_yM }, +{ XK_n, K_n, K_N, K_cN, K_mN, K_yN }, +{ XK_o, K_o, K_O, K_cO, K_mO, K_yO }, +{ XK_p, K_p, K_P, K_cP, K_mP, K_yP }, +{ XK_q, K_q, K_Q, K_cQ, K_mQ, K_yQ }, +{ XK_r, K_r, K_R, K_cR, K_mR, K_yR }, +{ XK_s, K_s, K_S, K_cS, K_mS, K_yS }, +{ XK_t, K_t, K_T, K_cT, K_mT, K_yT }, +{ XK_u, K_u, K_U, K_cU, K_mU, K_yU }, +{ XK_v, K_v, K_V, K_cV, K_mV, K_yV }, +{ XK_w, K_w, K_W, K_cW, K_mW, K_yW }, +{ XK_x, K_x, K_X, K_cX, K_mX, K_yX }, +{ XK_y, K_y, K_Y, K_cY, K_mY, K_yY }, +{ XK_z, K_z, K_Z, K_cZ, K_mZ, K_yZ }, + +{ XK_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 }, +{ XK_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 }, +{ XK_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 }, +{ XK_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 }, +{ XK_F5, K_F5, K_sF5, K_cF5, K_mF5, K_yF5 }, +{ XK_F6, K_F6, K_sF6, K_cF6, K_mF6, K_yF6 }, +{ XK_F7, K_F7, K_sF7, K_cF7, K_mF7, K_yF7 }, +{ XK_F8, K_F8, K_sF8, K_cF8, K_mF8, K_yF8 }, +{ XK_F9, K_F9, K_sF9, K_cF9, K_mF9, K_yF9 }, +{ XK_F10, K_F10, K_sF10, K_cF10, K_mF10, K_yF10 }, +{ XK_F11, K_F11, K_sF11, K_cF11, K_mF11, K_yF11 }, +{ XK_F12, K_F12, K_sF12, K_cF12, K_mF12, K_yF12 }, + +{ XK_semicolon, K_semicolon, K_colon, K_cSemicolon, K_mSemicolon, K_ySemicolon }, +{ XK_equal, K_equal, K_plus, K_cEqual, K_mEqual, K_yEqual }, +{ XK_comma, K_comma, K_less, K_cComma, K_mComma, K_yComma }, +{ XK_minus, K_minus, K_underscore, K_cMinus, K_mMinus, K_yMinus }, +{ XK_period, K_period, K_greater, K_cPeriod, K_mPeriod, K_yPeriod }, +{ XK_slash, K_slash, K_question, K_cSlash, K_mSlash, K_ySlash }, +{ XK_grave, K_grave, K_tilde, 0, 0, 0 }, +{ XK_bracketleft, K_bracketleft, K_braceleft, K_cBracketleft, K_mBracketleft, K_yBracketleft }, +{ XK_backslash, K_backslash, K_bar, K_cBackslash, K_mBackslash, K_yBackslash }, +{ XK_bracketright,K_bracketright, K_braceright, K_cBracketright,K_mBracketright,K_yBracketright }, +{ XK_apostrophe, K_apostrophe, K_quotedbl, 0, 0, 0 }, + +{ XK_KP_0, K_0, K_0, K_c0, K_m0, K_y0 }, +{ XK_KP_1, K_1, K_1, K_c1, K_m1, K_y1 }, +{ XK_KP_2, K_2, K_2, K_c2, K_m2, K_y2 }, +{ XK_KP_3, K_3, K_3, K_c3, K_m3, K_y3 }, +{ XK_KP_4, K_4, K_4, K_c4, K_m4, K_y4 }, +{ XK_KP_5, K_5, K_5, K_c5, K_m5, K_y5 }, +{ XK_KP_6, K_6, K_6, K_c6, K_m6, K_y6 }, +{ XK_KP_7, K_7, K_7, K_c7, K_m7, K_y7 }, +{ XK_KP_8, K_8, K_8, K_c8, K_m8, K_y8 }, +{ XK_KP_9, K_9, K_9, K_c9, K_m9, K_y9 }, +{ XK_KP_Multiply, K_asterisk, K_sAsterisk, K_cAsterisk, K_mAsterisk, K_yAsterisk }, +{ XK_KP_Add, K_plus, K_sPlus, K_cPlus, K_mPlus, K_yPlus }, +{ XK_KP_Subtract, K_minus, K_sMinus, K_cMinus, K_mMinus, K_yMinus }, +{ XK_KP_Decimal, K_period, K_sPeriod, K_cPeriod, K_mPeriod, K_yPeriod }, +{ XK_KP_Divide, K_slash, K_sSlash, K_cSlash, K_mSlash, K_ySlash }, +{ XK_KP_Separator, K_comma, K_sComma, K_cComma, K_mComma, K_yComma }, + +{ XK_ccedilla, K_ccedilla, K_Ccedilla, K_cCcedilla, K_mCcedilla, K_yCcedilla }, + +{ XK_dead_tilde, K_tilde, K_circum, 0, 0, 0 }, +{ XK_dead_acute, K_acute, K_grave, 0, 0, 0 }, +{ XK_dead_grave, K_grave, K_tilde, 0, 0, 0 }, + +{ XK_KP_F1, K_F1, K_sF1, K_cF1, K_mF1, K_yF1 }, +{ XK_KP_F2, K_F2, K_sF2, K_cF2, K_mF2, K_yF2 }, +{ XK_KP_F3, K_F3, K_sF3, K_cF3, K_mF3, K_yF3 }, +{ XK_KP_F4, K_F4, K_sF4, K_cF4, K_mF4, K_yF4 }, +{ XK_KP_Space, K_SP, K_sSP, K_cSP, K_mSP ,K_ySP }, +{ XK_KP_Tab, K_TAB, K_sTAB, K_cTAB, K_mTAB ,K_yTAB }, +{ XK_KP_Equal, K_equal, 0, K_cEqual, K_mEqual, K_yEqual }, + +{ XK_KP_Enter, K_CR, K_sCR, K_cCR, K_mCR, K_yCR }, +{ XK_KP_Home, K_HOME, K_sHOME, K_cHOME, K_mHOME, K_yHOME }, +{ XK_KP_Up, K_UP, K_sUP, K_cUP, K_mUP, K_yUP }, +{ XK_KP_Page_Up, K_PGUP, K_sPGUP, K_cPGUP, K_mPGUP, K_yPGUP }, +{ XK_KP_Left, K_LEFT, K_sLEFT, K_cLEFT, K_mLEFT, K_yLEFT }, +{ XK_KP_Begin, K_MIDDLE,K_sMIDDLE, K_cMIDDLE,K_mMIDDLE,K_yMIDDLE}, +{ XK_KP_Right, K_RIGHT, K_sRIGHT, K_cRIGHT, K_mRIGHT, K_yRIGHT }, +{ XK_KP_End, K_END, K_sEND, K_cEND, K_mEND, K_yEND }, +{ XK_KP_Down, K_DOWN, K_sDOWN, K_cDOWN, K_mDOWN, K_yDOWN }, +{ XK_KP_Page_Down, K_PGDN, K_sPGDN, K_cPGDN, K_mPGDN, K_yPGDN }, +{ XK_KP_Insert, K_INS, K_sINS, K_cINS, K_mINS, K_yINS }, +{ XK_KP_Delete, K_DEL, K_sDEL, K_cDEL, K_mDEL, K_yDEL } + +}; + +void iupmotKeyEncode(int key, unsigned int *keyval, unsigned int *state) +{ + int i, iupcode = key & 0xFF; /* 0-255 interval */ + int count = sizeof(motkey_map)/sizeof(motkey_map[0]); + for (i = 0; i < count; i++) + { + Imot2iupkey* key_map = &(motkey_map[i]); + if (key_map->iupcode == iupcode) + { + *keyval = XKeysymToKeycode(iupmot_display, key_map->motcode); + *state = 0; + + if (iupcode != key) + { + if (key_map->c_iupcode == key) + *state = ControlMask; + else if (key_map->m_iupcode == key) + *state = Mod1Mask; + else if (key_map->y_iupcode == key) + *state = Mod4Mask; + else if (key_map->s_iupcode == key) + *state = ShiftMask; + } + return; + } + else if (key_map->s_iupcode == key) /* There are Shift keys bellow 256 */ + { + *keyval = XKeysymToKeycode(iupmot_display, key_map->motcode); + *state = ShiftMask; + return; + } + } +} + +static int motKeyMap2Iup(unsigned int state, int i) +{ + int code = 0; + if (state & ControlMask) /* Ctrl */ + code = motkey_map[i].c_iupcode; + else if (state & Mod1Mask || + state & Mod5Mask) /* Alt */ + code = motkey_map[i].m_iupcode; + else if (state & Mod4Mask) /* Apple/Win */ + code = motkey_map[i].y_iupcode; + else if (state & LockMask) /* CapsLock */ + { + if ((state & ShiftMask) || !iupKeyCanCaps(motkey_map[i].iupcode)) + return motkey_map[i].iupcode; + else + code = motkey_map[i].s_iupcode; + } + else if (state & ShiftMask) /* Shift */ + code = motkey_map[i].s_iupcode; + else + return motkey_map[i].iupcode; + + if (!code) + code = motkey_map[i].iupcode; + + return code; +} + +static int motKeyDecode(XKeyEvent *evt) +{ + int i; + KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + int count = sizeof(motkey_map)/sizeof(motkey_map[0]); + + if ((evt->state & Mod2Mask) && /* NumLock */ + (motcode >= XK_KP_Home) && + (motcode <= XK_KP_Delete)) + { + /* remap to numeric keys */ + KeySym remap_numkey[] = {XK_KP_7, XK_KP_4, XK_KP_8, XK_KP_6, XK_KP_2, XK_KP_9, XK_KP_3, XK_KP_1, XK_KP_5, XK_KP_0, XK_KP_Decimal}; + motcode = remap_numkey[motcode-XK_KP_Home]; + } + + for (i = 0; i < count; i++) + { + if (motkey_map[i].motcode == motcode) + return motKeyMap2Iup(evt->state, i); + } + + return 0; +} + +KeySym iupmotKeyCharToKeySym(char c) +{ + int i; + int count = sizeof(motkey_map)/sizeof(motkey_map[0]); + + for (i = 0; i < count; i++) + { + if (motkey_map[i].iupcode == c) + return motkey_map[i].motcode; + if (motkey_map[i].s_iupcode == c) + { + if (motkey_map[i].motcode >= XK_a && + motkey_map[i].motcode <= XK_z) + return motkey_map[i].motcode - (XK_a-XK_A); + } + } + + return 0; +} + +/* Discards keyrepeat by removing the keypress event from the queue. + * The pair keyrelease/keypress is always put together in the queue, + * by removing the keypress, we only worry about keyrelease. In case + * of a keyrelease, we ignore it if the next event is a keypress (which + * means repetition. Otherwise it is a real keyrelease. + * + * Returns 1 if the keypress is found in the queue and 0 otherwise. + */ +static int motKeyDiscardKeypressRepeat(XEvent *evt) +{ + XEvent ahead; + if (XEventsQueued(iupmot_display, QueuedAfterReading)) + { + XPeekEvent(iupmot_display, &ahead); + if (ahead.type == KeyPress && ahead.xkey.window == evt->xkey.window + && ahead.xkey.keycode == evt->xkey.keycode && ahead.xkey.time == evt->xkey.time) + { + /* Pop off the repeated KeyPress and ignore */ + XNextEvent(iupmot_display, evt); + /* Ignore the auto repeated KeyRelease/KeyPress pair */ + return 1; + } + } + /* No KeyPress found */ + return 0; +} + +/* this is called only for canvas */ +void iupmotCanvasKeyReleaseEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + if (motKeyDiscardKeypressRepeat(evt)) + { + /* call key_press because it was removed from the queue */ + iupmotKeyPressEvent(w, ih, evt, cont); + } + else + { + int result; + int code = motKeyDecode((XKeyEvent*)evt); + if (code == 0) + return; + result = iupKeyCallKeyPressCb(ih, code, 0); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return; + } + if (result == IUP_IGNORE) + { + *cont = False; + return; + } + } +} + +void iupmotKeyPressEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + int result; + int code = motKeyDecode((XKeyEvent*)evt); + if (code == 0) + return; + + if ((((XKeyEvent*)evt)->state & Mod1Mask || ((XKeyEvent*)evt)->state & Mod5Mask)) /* Alt */ + { + KeySym motcode = XKeycodeToKeysym(iupmot_display, ((XKeyEvent*)evt)->keycode, 0); + if (motcode < 128) + { + IFni cb; + Ihandle* dialog = IupGetDialog(ih); + char attrib[22] = "_IUPMOT_MNEMONIC_ _CB"; + attrib[17] = (char)toupper(motcode); + cb = (IFni)IupGetCallback(dialog, attrib); + if (cb) + { + cb(dialog, attrib[17]); + return; + } + } + } + + result = iupKeyCallKeyCb(ih, code); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return; + } + if (result == IUP_IGNORE) + { + *cont = False; + return; + } + + /* in the previous callback the dialog could be destroyed */ + if (iupObjectCheck(ih)) + { + /* this is called only for canvas */ + if (ih->iclass->nativetype==IUP_TYPECANVAS) + { + result = iupKeyCallKeyPressCb(ih, code, 1); + if (result == IUP_CLOSE) + { + IupExitLoop(); + return; + } + if (result == IUP_IGNORE) + { + *cont = False; + return; + } + } + + if (!iupKeyProcessNavigation(ih, code, ((XKeyEvent*)evt)->state & ShiftMask)) + { + *cont = False; + return; + } + } + + (void)w; +} + +void iupmotButtonKeySetStatus(unsigned int state, unsigned int but, char* status, int doubleclick) +{ + if (state & ShiftMask) + iupKEYSETSHIFT(status); + + if (state & ControlMask) + iupKEYSETCONTROL(status); + + if ((state & Button1Mask) || but==Button1) + iupKEYSETBUTTON1(status); + + if ((state & Button2Mask) || but==Button2) + iupKEYSETBUTTON2(status); + + if ((state & Button3Mask) || but==Button3) + iupKEYSETBUTTON3(status); + + if ((state & Button4Mask) || but==Button4) + iupKEYSETBUTTON4(status); + + if ((state & Button5Mask) || but==Button5) + iupKEYSETBUTTON5(status); + + if (state & Mod1Mask || state & Mod5Mask) /* Alt */ + iupKEYSETALT(status); + + if (state & Mod4Mask) /* Apple/Win */ + iupKEYSETSYS(status); + + if (doubleclick) + iupKEYSETDOUBLE(status); +} + diff --git a/iup/src/mot/iupmot_label.c b/iup/src/mot/iupmot_label.c new file mode 100755 index 0000000..52dfc9a --- /dev/null +++ b/iup/src/mot/iupmot_label.c @@ -0,0 +1,256 @@ +/** \file + * \brief Label Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/Label.h> +#include <Xm/Separator.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_label.h" +#include "iup_drv.h" +#include "iup_image.h" + +#include "iupmot_drv.h" + + +static int motLabelSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_TEXT) + { + iupmotSetMnemonicTitle(ih, value); + return 1; + } + + return 0; +} + +static int motLabelSetBgColorAttrib(Ihandle* ih, const char* value) +{ + /* ignore given value, must use only from parent */ + value = iupBaseNativeParentGetBgColor(ih); + + if (iupdrvBaseSetBgColorAttrib(ih, value)) + return 1; + return 0; +} + +static int motLabelSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + /* ignore given value, must use only from parent */ + value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + if (iupdrvBaseSetBgColorAttrib(ih, value)) + return 1; + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL); + return 1; + } + } + return 0; +} + +static int motLabelSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + unsigned char align; + char value1[30]="", value2[30]=""; + + iupStrToStrStr(value, value1, value2, ':'); /* value2 is ignored, NOT supported in Motif */ + + if (iupStrEqualNoCase(value1, "ARIGHT")) + align = XmALIGNMENT_END; + else if (iupStrEqualNoCase(value1, "ACENTER")) + align = XmALIGNMENT_CENTER; + else /* "ALEFT" */ + align = XmALIGNMENT_BEGINNING; + + XtVaSetValues(ih->handle, XmNalignment, align, NULL); + return 1; + } + else + return 0; +} + +static int motLabelSetImageAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelPixmap, 0); + + if (!iupdrvIsActive(ih)) + { + if (!iupAttribGet(ih, "IMINACTIVE")) + { + /* if not active and IMINACTIVE is not defined + then automaticaly create one based on IMAGE */ + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 1); /* make_inactive */ + } + } + return 1; + } + else + return 0; +} + +static int motLabelSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_LABEL_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 0); + return 1; + } + else + return 0; +} + +static int motLabelSetActiveAttrib(Ihandle* ih, const char* value) +{ + /* update the inactive image if necessary */ + if (ih->data->type == IUP_LABEL_IMAGE && !iupStrBoolean(value)) + { + if (!iupAttribGet(ih, "IMINACTIVE")) + { + /* if not defined then automaticaly create one based on IMAGE */ + char* name = iupAttribGet(ih, "IMAGE"); + iupmotSetPixmap(ih, name, XmNlabelInsensitivePixmap, 1); /* make_inactive */ + } + } + + return iupBaseSetActiveAttrib(ih, value); +} + +static int motLabelSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle && ih->data->type != IUP_LABEL_SEP_HORIZ && ih->data->type != IUP_LABEL_SEP_VERT) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + } + return 0; +} + +static int motLabelMapMethod(Ihandle* ih) +{ + char* value; + int num_args = 0; + Arg args[20]; + WidgetClass widget_class; + + value = iupAttribGet(ih, "SEPARATOR"); + if (value) + { + widget_class = xmSeparatorWidgetClass; + if (iupStrEqualNoCase(value, "HORIZONTAL")) + { + ih->data->type = IUP_LABEL_SEP_HORIZ; + iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); + } + else /* "VERTICAL" */ + { + ih->data->type = IUP_LABEL_SEP_VERT; + iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); + } + } + else + { + value = iupAttribGet(ih, "IMAGE"); + widget_class = xmLabelWidgetClass; + if (value) + { + ih->data->type = IUP_LABEL_IMAGE; + iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP); + } + else + { + ih->data->type = IUP_LABEL_TEXT; + iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + } + } + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ + iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupmotSetArg(args, num_args, XmNhighlightThickness, 0); + /* Label */ + iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ + iupmotSetArg(args, num_args, XmNmarginLeft, 0); + iupmotSetArg(args, num_args, XmNmarginBottom, 0); + iupmotSetArg(args, num_args, XmNmarginRight, 0); + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + widget_class, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + /* Drag Source is enabled by default in label */ + iupmotDisableDragSource(ih->handle); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + if (ih->data->type == IUP_LABEL_TEXT) + iupmotSetString(ih->handle, XmNlabelString, ""); + + return IUP_NOERROR; +} + +void iupdrvLabelInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motLabelMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, motLabelSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", iupmotGetBgColorAttrib, motLabelSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motLabelSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, motLabelSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupLabel only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, motLabelSetAlignmentAttrib, "ALEFT:ACENTER", NULL, IUPAF_NO_INHERIT); /* force new default value */ + iupClassRegisterAttribute(ic, "IMAGE", NULL, motLabelSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PADDING", iupLabelGetPaddingAttrib, motLabelSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + + /* IupLabel GTK and Motif only */ + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, motLabelSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_list.c b/iup/src/mot/iupmot_list.c new file mode 100755 index 0000000..f8e73ed --- /dev/null +++ b/iup/src/mot/iupmot_list.c @@ -0,0 +1,1404 @@ +/** \file + * \brief List Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/List.h> +#include <Xm/ComboBox.h> +#include <Xm/ScrolledW.h> +#include <Xm/TextF.h> +#include <X11/keysym.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <time.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_mask.h" +#include "iup_key.h" +#include "iup_list.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +static void motListComboBoxSelectionCallback(Widget w, Ihandle* ih, XmComboBoxCallbackStruct* call_data); + + +void iupdrvListAddItemSpace(Ihandle* ih, int *h) +{ + if (ih->data->has_editbox) + *h += 1; + else + *h += 3; +} + +void iupdrvListAddBorders(Ihandle* ih, int *x, int *y) +{ + int border_size = 2*4; + (*x) += border_size; + (*y) += border_size; + + if (ih->data->is_dropdown) + { + if (ih->data->has_editbox) + { + /* extra border for the editbox */ + int internal_border_size = 2*2; + (*x) += internal_border_size; + (*y) += internal_border_size; + } + } + else + { + if (ih->data->has_editbox) + (*y) += 2*2; /* internal border between editbox and list */ + else + (*x) += 2; /* extra border for the simple list */ + } +} + +static int motListConvertXYToPos(Ihandle* ih, int x, int y) +{ + (void)x; + if (ih->data->has_editbox) + { + Widget cblist; + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + return XmListYToPos(cblist, (Position)y); /* XmListYToPos returns start at 1 */ + } + else + return XmListYToPos(ih->handle, (Position)y); +} + +int iupdrvListGetCount(Ihandle* ih) +{ + int count; + XtVaGetValues(ih->handle, XmNitemCount, &count, NULL); + return count; +} + +static void motListAddItem(Ihandle* ih, int pos, const char* value) +{ + XmString str = XmStringCreateLocalized((String)value); + /* The utility functions use 0=last 1=first */ + if (ih->data->is_dropdown || ih->data->has_editbox) + XmComboBoxAddItem(ih->handle, str, pos+1, False); + else + XmListAddItem(ih->handle, str, pos+1); + XmStringFree(str); +} + +static void motListAddSortedItem(Ihandle* ih, const char *value) +{ + char *text; + XmString *strlist; + int u_bound, l_bound = 0; + + XtVaGetValues(ih->handle, XmNitemCount, &u_bound, XmNitems, &strlist, NULL); + + u_bound--; + /* perform binary search */ + while (u_bound >= l_bound) + { + int i = l_bound + (u_bound - l_bound)/2; + text = (char*)XmStringUnparse(strlist[i], NULL, XmCHARSET_TEXT, XmCHARSET_TEXT, NULL, 0, XmOUTPUT_ALL); + if (!text) + break; + if (strcmp (text, value) > 0) + u_bound = i-1; /* newtext comes before item */ + else + l_bound = i+1; /* newtext comes after item */ + XtFree(text); + } + + motListAddItem(ih, l_bound, value); +} + +void iupdrvListAppendItem(Ihandle* ih, const char* value) +{ + if (iupAttribGetBoolean(ih, "SORT")) + motListAddSortedItem(ih, value); + else + motListAddItem(ih, -1, value); +} + +void iupdrvListInsertItem(Ihandle* ih, int pos, const char* value) +{ + if (iupAttribGetBoolean(ih, "SORT")) + motListAddSortedItem(ih, value); + else + motListAddItem(ih, pos, value); +} + +void iupdrvListRemoveItem(Ihandle* ih, int pos) +{ + /* The utility functions use 0=last 1=first */ + if (ih->data->is_dropdown || ih->data->has_editbox) + XmComboBoxDeletePos(ih->handle, pos+1); + else + XmListDeletePos(ih->handle, pos+1); +} + +void iupdrvListRemoveAllItems(Ihandle* ih) +{ + if (ih->data->is_dropdown || ih->data->has_editbox) + { + Widget cblist; + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + XmListDeleteAllItems(cblist); + XmComboBoxUpdate(ih->handle); + } + else + XmListDeleteAllItems(ih->handle); +} + + +/*********************************************************************************/ + + +static char* motListGetIdValueAttrib(Ihandle* ih, const char* name_id) +{ + int pos = iupListGetPos(ih, name_id); + if (pos != -1) + { + XmString* items; + XtVaGetValues(ih->handle, XmNitems, &items, NULL); + return iupmotConvertString(items[pos]); + } + return NULL; +} + +static int motListSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (sb_win) + { + Pixel color; + + /* ignore given value for the scrollbars, must use only from parent */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + Widget sb = NULL; + + iupmotSetBgColor(sb_win, color); + + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + } + + return iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */ + } + else + { + char* parent_value; + + /* use given value for Edit and List also */ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget cbedit, cblist, sb; + + iupmotSetBgColor(ih->handle, color); + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + if (cbedit) iupmotSetBgColor(cbedit, color); + + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + if (cblist) iupmotSetBgColor(cblist, color); + + XtVaGetValues(cblist, XmNverticalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + + XtVaGetValues(cblist, XmNhorizontalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + } + + /* but reset just the background, so the combobox will look like a button */ + parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + XtVaSetValues(ih->handle, XmNbackground, color, NULL); + + return 1; + } +} + +static int motListSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + XtVaSetValues(ih->handle, XmNforeground, color, NULL); + + if (ih->data->is_dropdown || ih->data->has_editbox) + { + Widget w; + XtVaGetValues(ih->handle, XmNtextField, &w, NULL); + XtVaSetValues(w, XmNforeground, color, NULL); + + XtVaGetValues(ih->handle, XmNlist, &w, NULL); + XtVaSetValues(w, XmNforeground, color, NULL); + } + } + + return 1; +} + +static char* motListGetValueAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + char *str, *xstr; + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + xstr = XmTextFieldGetString(cbedit); + str = iupStrGetMemoryCopy(xstr); + XtFree(xstr); + return str; + } + else + { + if (ih->data->is_dropdown) + { + char* str; + int pos; + XtVaGetValues(ih->handle, XmNselectedPosition, &pos, NULL); + str = iupStrGetMemory(50); + sprintf(str, "%d", pos+1); /* IUP starts at 1 */ + return str; + } + else + { + int *pos, sel_count; + if (XmListGetSelectedPos(ih->handle, &pos, &sel_count)) /* XmListGetSelectedPos starts at 1 */ + { + if (!ih->data->is_multiple) + { + char* str = iupStrGetMemory(50); + sprintf(str, "%d", pos[0]); + XtFree((char*)pos); + return str; + } + else + { + int i, count; + char* str; + XtVaGetValues(ih->handle, XmNitemCount, &count, NULL); + str = iupStrGetMemory(count+1); + memset(str, '-', count); + str[count]=0; + for (i=0; i<sel_count; i++) + str[pos[i]-1] = '+'; + XtFree((char*)pos); + return str; + } + } + } + } + + return NULL; +} + +static int motListSetValueAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->has_editbox) + { + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + if (!value) value = ""; + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */ + + XmTextFieldSetString(cbedit, (char*)value); + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + else + { + if (ih->data->is_dropdown) + { + int pos; + if (iupStrToInt(value, &pos)==1) + { + XtRemoveCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih); + + XtVaSetValues(ih->handle, XmNselectedPosition, pos-1, NULL); /* IUP starts at 1 */ + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); + + XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih); + } + } + else + { + if (!ih->data->is_multiple) + { + int pos; + if (iupStrToInt(value, &pos)==1) + { + XmListSelectPos(ih->handle, pos, FALSE); /* XmListSelectPos starts at 1 */ + iupAttribSetInt(ih, "_IUPLIST_OLDVALUE", pos); + } + else + { + XmListDeselectAllItems(ih->handle); + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + } + } + else + { + /* User has changed a multiple selection on a simple list. */ + int i, count, len; + + /* Clear all selections */ + XmListDeselectAllItems(ih->handle); + + if (!value) + { + iupAttribSetStr(ih, "_IUPLIST_OLDVALUE", NULL); + return 0; + } + + XtVaGetValues(ih->handle, XmNitemCount, &count, NULL); + len = strlen(value); + if (len < count) + count = len; + + XtVaSetValues(ih->handle, XmNselectionPolicy, XmMULTIPLE_SELECT, NULL); + + /* update selection list */ + for (i = 0; i<count; i++) + { + if (value[i]=='+') + XmListSelectPos(ih->handle, i+1, False); /* XmListSelectPos starts at 1 */ + } + + XtVaSetValues(ih->handle, XmNselectionPolicy, XmEXTENDED_SELECT, + XmNselectionMode, XmNORMAL_MODE, NULL); /* must also restore this */ + iupAttribStoreStr(ih, "_IUPLIST_OLDVALUE", value); + } + } + } + + return 0; +} + +static int motListSetVisibleItemsAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_dropdown) + { + int count; + if (iupStrToInt(value, &count)==1) + XtVaSetValues(ih->handle, XmNvisibleItemCount, count, NULL); + } + return 1; +} + +static int motListSetShowDropdownAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_dropdown) + { + if (iupStrBoolean(value)) + { + XButtonEvent ev; + memset(&ev, 0, sizeof(XButtonEvent)); + ev.type = ButtonPress; + ev.display = XtDisplay(ih->handle); + ev.send_event = True; + ev.root = RootWindow(iupmot_display, iupmot_screen); + ev.time = clock()*CLOCKS_PER_SEC; + ev.window = XtWindow(ih->handle); + ev.state = Button1Mask; + ev.button = Button1; + ev.same_screen = True; + XtCallActionProc(ih->handle, "CBDropDownList", (XEvent*)&ev, 0, 0 ); + } + else + XtCallActionProc(ih->handle, "CBDisarm", 0, 0, 0 ); + } + return 0; +} + +static int motListSetTopItemAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->is_dropdown) + { + int pos = 1; + if (iupStrToInt(value, &pos)) + { + if (ih->data->has_editbox) + { + Widget cblist; + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + XtVaSetValues(cblist, XmNtopItemPosition, pos, NULL); + } + else + XtVaSetValues(ih->handle, XmNtopItemPosition, pos, NULL); + } + } + return 0; +} + +static int motListSetSpacingAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->is_dropdown) + return 0; + + if (!iupStrToInt(value, &ih->data->spacing)) + ih->data->spacing = 0; + + if (ih->handle) + { + if (ih->data->has_editbox) + { + Widget cblist; + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + XtVaSetValues(cblist, XmNlistSpacing, ih->data->spacing*2, + XmNlistMarginWidth, ih->data->spacing, + XmNlistMarginHeight, ih->data->spacing, + NULL); + } + else + XtVaSetValues(ih->handle, XmNlistSpacing, ih->data->spacing*2, + XmNlistMarginWidth, ih->data->spacing, + XmNlistMarginHeight, ih->data->spacing, + NULL); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int motListSetPaddingAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + { + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaSetValues(cbedit, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int motListSetReadOnlyAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->has_editbox) + { + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaSetValues(cbedit, XmNeditable, iupStrBoolean(value)? False: True, NULL); + } + return 0; +} + +static char* motListGetReadOnlyAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + Boolean editable; + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaGetValues(cbedit, XmNeditable, &editable, NULL); + if (editable) + return "YES"; + else + return "NO"; + } + else + return NULL; +} + +static int motListSetInsertAttrib(Ihandle* ih, const char* value) +{ + if (!value) + return 0; + + if (ih->data->has_editbox) + { + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */ + XmTextFieldRemove(cbedit); + XmTextFieldInsert(cbedit, XmTextFieldGetInsertionPosition(cbedit), (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + + return 0; +} + +static int motListSetSelectedTextAttrib(Ihandle* ih, const char* value) +{ + XmTextPosition start, end; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + if (XmTextFieldGetSelectionPosition(cbedit, &start, &end) && start!=end) + { + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */ + XmTextFieldReplace(cbedit, start, end, (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + + return 0; +} + +static char* motListGetSelectedTextAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + char* selectedtext, *str; + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + selectedtext = XmTextFieldGetSelection(cbedit); + str = iupStrGetMemoryCopy(selectedtext); + XtFree(selectedtext); + return str; + } + else + return NULL; +} + +static int motListSetAppendAttrib(Ihandle* ih, const char* value) +{ + if (value && ih->data->has_editbox) + { + XmTextPosition pos; + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + pos = XmTextFieldGetLastPosition(cbedit); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); /* disable callbacks */ + XmTextFieldInsert(cbedit, pos+1, (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + return 0; +} + +static int motListSetSelectionAttrib(Ihandle* ih, const char* value) +{ + int start=1, end=1; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldClearSelection(cbedit, CurrentTime); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetSelection(cbedit, (XmTextPosition)0, (XmTextPosition)XmTextFieldGetLastPosition(cbedit), CurrentTime); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<1 || end<1) + return 0; + + start--; /* IUP starts at 1 */ + end--; + + /* end is inside the selection, in IUP is outside */ + end--; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetSelection(cbedit, (XmTextPosition)start, (XmTextPosition)end, CurrentTime); + + return 0; +} + +static char* motListGetSelectionAttrib(Ihandle* ih) +{ + XmTextPosition start = 0, end = 0; + char* str; + Widget cbedit; + if (!ih->data->has_editbox) + return NULL; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + if (!XmTextFieldGetSelectionPosition(cbedit, &start, &end) || start==end) + return NULL; + + str = iupStrGetMemory(100); + + /* end is inside the selection, in IUP is outside */ + end++; + + start++; /* IUP starts at 1 */ + end++; + sprintf(str, "%d:%d", (int)start, (int)end); + + return str; +} + +static int motListSetSelectionPosAttrib(Ihandle* ih, const char* value) +{ + int start=0, end=0; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldClearSelection(cbedit, CurrentTime); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetSelection(cbedit, (XmTextPosition)0, (XmTextPosition)XmTextFieldGetLastPosition(cbedit), CurrentTime); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<0 || end<0) + return 0; + + /* end is inside the selection, in IUP is outside */ + end--; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetSelection(cbedit, (XmTextPosition)start, (XmTextPosition)end, CurrentTime); + + return 0; +} + +static char* motListGetSelectionPosAttrib(Ihandle* ih) +{ + XmTextPosition start = 0, end = 0; + char* str; + Widget cbedit; + if (!ih->data->has_editbox) + return NULL; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + if (!XmTextFieldGetSelectionPosition(cbedit, &start, &end) || start==end) + return NULL; + + str = iupStrGetMemory(100); + + /* end is inside the selection, in IUP is outside */ + end++; + + sprintf(str, "%d:%d", (int)start, (int)end); + + return str; +} + +static int motListSetCaretAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + pos--; /* IUP starts at 1 */ + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetInsertionPosition(cbedit, (XmTextPosition)pos); + XmTextFieldShowPosition(cbedit, (XmTextPosition)pos); + + return 0; +} + +static char* motListGetCaretAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + XmTextPosition pos; + Widget cbedit; + char* str = iupStrGetMemory(50); + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + pos = XmTextFieldGetInsertionPosition(cbedit); + pos++; /* IUP starts at 1 */ + sprintf(str, "%d", (int)pos); + return str; + } + else + return NULL; +} + +static int motListSetCaretPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldSetInsertionPosition(cbedit, (XmTextPosition)pos); + XmTextFieldShowPosition(cbedit, (XmTextPosition)pos); + + return 0; +} + +static char* motListGetCaretPosAttrib(Ihandle* ih) +{ + if (ih->data->has_editbox) + { + XmTextPosition pos; + Widget cbedit; + char* str = iupStrGetMemory(50); + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + pos = XmTextFieldGetInsertionPosition(cbedit); + sprintf(str, "%d", (int)pos); + return str; + } + else + return NULL; +} + +static int motListSetScrollToAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + pos--; /* return to Motif referece */ + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldShowPosition(cbedit, (XmTextPosition)pos); + + return 0; +} + +static int motListSetScrollToPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XmTextFieldShowPosition(cbedit, (XmTextPosition)pos); + + return 0; +} + +static int motListSetNCAttrib(Ihandle* ih, const char* value) +{ + if (!ih->data->has_editbox) + return 0; + + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = INT_MAX; + + if (ih->handle) + { + Widget cbedit; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaSetValues(cbedit, XmNmaxLength, ih->data->nc, NULL); + } + return 0; +} + +static int motListSetClipboardAttrib(Ihandle *ih, const char *value) +{ + Widget cbedit; + if (!ih->data->has_editbox) + return 0; + + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + + if (iupStrEqualNoCase(value, "COPY")) + { + char *str = XmTextFieldGetSelection(cbedit); + + XmTextFieldCopy(cbedit, CurrentTime); + + /* do it also for the X clipboard */ + XStoreBytes(iupmot_display, str, strlen(str)+1); + XtFree(str); + } + else if (iupStrEqualNoCase(value, "CUT")) + { + char *str = XmTextFieldGetSelection(cbedit); + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + + XmTextFieldCut(cbedit, CurrentTime); + + /* do it also for the X clipboard */ + XStoreBytes(iupmot_display, str, strlen(str)+1); + XtFree(str); + XmTextFieldRemove(cbedit); + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + else if (iupStrEqualNoCase(value, "PASTE")) + { + int size; + char* str = XFetchBytes(iupmot_display, &size); + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + + XmTextFieldPaste(cbedit); /* TODO: this could force 2 pastes, check in CDE */ + + /* do it also for the X clipboard */ + XmTextFieldRemove(cbedit); + XmTextFieldInsert(cbedit, XmTextFieldGetInsertionPosition(cbedit), str); + XFree(str); + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + else if (iupStrEqualNoCase(value, "CLEAR")) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XmTextFieldRemove(cbedit); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + return 0; +} + + +/*********************************************************************************/ + + +static void motListEditModifyVerifyCallback(Widget cbedit, Ihandle *ih, XmTextVerifyPtr text) +{ + int start, end, key = 0; + char *value, *new_value, *insert_value; + KeySym motcode = 0; + IFnis cb; + + if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB")) + return; + + cb = (IFnis)IupGetCallback(ih, "EDIT_CB"); + if (!cb && !ih->data->mask) + return; + + if (text->event && text->event->type == KeyPress) + { + unsigned int state = ((XKeyEvent*)text->event)->state; + if (state & ControlMask || /* Ctrl */ + state & Mod1Mask || + state & Mod5Mask || /* Alt */ + state & Mod4Mask) /* Apple/Win */ + return; + + motcode = XKeycodeToKeysym(iupmot_display, ((XKeyEvent*)text->event)->keycode, 0); + } + + value = XmTextFieldGetString(cbedit); + start = text->startPos; + end = text->endPos; + insert_value = text->text->ptr; + + if (motcode == XK_Delete) + { + new_value = value; + iupStrRemove(value, start, end, 1); + } + else if (motcode == XK_BackSpace) + { + new_value = value; + iupStrRemove(value, start, end, -1); + } + else + { + if (!value) + new_value = iupStrDup(insert_value); + else if (insert_value) + new_value = iupStrInsert(value, insert_value, start, end); + else + new_value = value; + } + + if (insert_value && insert_value[0]!=0 && insert_value[1]==0) + key = insert_value[0]; + + if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) + { + if (new_value != value) free(new_value); + XtFree(value); + text->doit = False; /* abort processing */ + return; + } + + if (cb) + { + int cb_ret = cb(ih, key, (char*)new_value); + if (cb_ret==IUP_IGNORE) + text->doit = False; /* abort processing */ + else if (cb_ret==IUP_CLOSE) + { + IupExitLoop(); + text->doit = False; /* abort processing */ + } + else if (cb_ret!=0 && key!=0 && + cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) + { + insert_value[0] = (char)cb_ret; /* replace key */ + } + } + + if (new_value != value) free(new_value); + XtFree(value); +} + +static void motListEditMotionVerifyCallback(Widget w, Ihandle* ih, XmTextVerifyCallbackStruct* textverify) +{ + int pos; + + IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); + if (!cb) return; + + pos = textverify->newInsert; + + if (pos != ih->data->last_caret_pos) + { + ih->data->last_caret_pos = pos; + cb(ih, 1, pos+1, pos); + } + + (void)w; +} + +static void motListEditKeyPressEvent(Widget cbedit, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + *cont = True; + iupmotKeyPressEvent(cbedit, ih, (XEvent*)evt, cont); + if (*cont == False) + return; + + if (evt->state & ControlMask) /* Ctrl */ + { + KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_c) + { + motListSetClipboardAttrib(ih, "COPY"); + *cont = False; + return; + } + else if (motcode == XK_x) + { + motListSetClipboardAttrib(ih, "CUT"); + *cont = False; + return; + } + else if (motcode == XK_v) + { + motListSetClipboardAttrib(ih, "PASTE"); + *cont = False; + return; + } + else if (motcode == XK_a) + { + XmTextFieldSetSelection(cbedit, 0, XmTextFieldGetLastPosition(cbedit), CurrentTime); + *cont = False; + return; + } + } +} + +static void motListEditValueChangedCallback(Widget w, Ihandle* ih, XmAnyCallbackStruct* valuechanged) +{ + if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB")) + return; + + iupBaseCallValueChangedCb(ih); + + (void)valuechanged; + (void)w; +} + +static void motListDropDownPopupCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB"); + if (cb) + cb(ih, 1); + (void)w; + (void)call_data; +} + +static void motListDropDownPopdownCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + IFni cb = (IFni)IupGetCallback(ih, "DROPDOWN_CB"); + if (cb) + cb(ih, 0); + (void)w; + (void)call_data; +} + +static void motListDefaultActionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* call_data) +{ + if (call_data->event->type == ButtonPress || call_data->event->type == ButtonRelease) + { + IFnis cb = (IFnis) IupGetCallback(ih, "DBLCLICK_CB"); + if (cb) + { + int pos = call_data->item_position; /* Here Motif already starts at 1 */ + iupListSingleCallDblClickCallback(ih, cb, pos); + } + } + + (void)w; +} + +static void motListComboBoxSelectionCallback(Widget w, Ihandle* ih, XmComboBoxCallbackStruct* call_data) +{ + IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); + if (cb) + { + int pos = call_data->item_position; + if (pos==0) + { + /* must check if it is really checked or it is for the edit box */ + XmString* items; + XtVaGetValues(ih->handle, XmNitems, &items, NULL); + if (!XmStringCompare(call_data->item_or_text, items[0])) + return; + } + pos++; /* IUP starts at 1 */ + iupListSingleCallActionCallback(ih, cb, pos); + } + + if (!ih->data->has_editbox) + iupBaseCallValueChangedCb(ih); + + (void)w; +} + +static void motListBrowseSelectionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* call_data) +{ + IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); + if (cb) + { + int pos = call_data->item_position; /* Here Motif already starts at 1 */ + iupListSingleCallActionCallback(ih, cb, pos); + } + + if (!ih->data->has_editbox) + iupBaseCallValueChangedCb(ih); + + (void)w; +} + +static void motListExtendedSelectionCallback(Widget w, Ihandle* ih, XmListCallbackStruct* call_data) +{ + IFns multi_cb = (IFns)IupGetCallback(ih, "MULTISELECT_CB"); + IFnsii cb = (IFnsii) IupGetCallback(ih, "ACTION"); + if (multi_cb || cb) + { + int* pos = call_data->selected_item_positions; + int sel_count = call_data->selected_item_count; + int i; + + /* In Motif, the position of item is "plus one". + "iupListMultipleCallActionCallback" works with the list of selected items from the zero position. + So, "minus one" here. */ + for (i = 0; i < sel_count; i++) + pos[i] -= 1; + + iupListMultipleCallActionCallback(ih, cb, multi_cb, pos, sel_count); + } + + if (!ih->data->has_editbox) + iupBaseCallValueChangedCb(ih); + + (void)w; +} + + +/*********************************************************************************/ + + +static int motListMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + Widget parent = iupChildTreeGetNativeParentHandle(ih); + char* child_id = iupDialogGetChildIdStr(ih); + + if (ih->data->is_dropdown || ih->data->has_editbox) + { + /* could not set XmNmappedWhenManaged to False because the list and the edit box where not displayed */ + /* iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + iupmotSetArg(args, num_args, XmNmarginHeight, 0); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + + if (ih->data->has_editbox) + { + if (ih->data->is_dropdown) + iupmotSetArg(args, num_args, XmNcomboBoxType, XmDROP_DOWN_COMBO_BOX); /* hidden-list+edit */ + else + iupmotSetArg(args, num_args, XmNcomboBoxType, XmCOMBO_BOX); /* visible-list+edit */ + } + else + iupmotSetArg(args, num_args, XmNcomboBoxType, XmDROP_DOWN_LIST); /* hidden-list */ + + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ + xmComboBoxWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + } + else + { + Widget sb_win; + + /* Create the scrolled window */ + + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); + iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ + iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ + iupmotSetArg(args, num_args, XmNborderWidth, 0); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + sb_win = XtCreateManagedWidget( + child_id, /* child identifier */ + xmScrolledWindowWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!sb_win) + return IUP_ERROR; + + parent = sb_win; + child_id = "list"; + + /* Create the list */ + + num_args = 0; + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + + iupmotSetArg(args, num_args, XmNlistMarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNlistMarginWidth, 0); + iupmotSetArg(args, num_args, XmNlistSpacing, 0); + iupmotSetArg(args, num_args, XmNlistSizePolicy, XmCONSTANT); /* don't grow to fit, add scrollbar */ + + if (ih->data->is_multiple) + iupmotSetArg(args, num_args, XmNselectionPolicy, XmEXTENDED_SELECT); + else + iupmotSetArg(args, num_args, XmNselectionPolicy, XmBROWSE_SELECT); + + if (iupAttribGetBoolean(ih, "AUTOHIDE")) + iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); + else + iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); + + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ + xmListWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + } + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + if (ih->data->is_dropdown || ih->data->has_editbox) + { + Widget cbedit, cblist; + XtVaGetValues(ih->handle, XmNtextField, &cbedit, NULL); + XtVaGetValues(ih->handle, XmNlist, &cblist, NULL); + + XtAddEventHandler(cbedit, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(cbedit, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(cbedit, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddCallback(cbedit, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motListComboBoxSelectionCallback, (XtPointer)ih); + + if (ih->data->has_editbox) + { + XtAddEventHandler(cbedit, KeyPressMask, False, (XtEventHandler)motListEditKeyPressEvent, (XtPointer)ih); + XtAddCallback(cbedit, XmNmodifyVerifyCallback, (XtCallbackProc)motListEditModifyVerifyCallback, (XtPointer)ih); + XtAddCallback(cbedit, XmNmotionVerifyCallback, (XtCallbackProc)motListEditMotionVerifyCallback, (XtPointer)ih); + XtAddCallback(cbedit, XmNvalueChangedCallback, (XtCallbackProc)motListEditValueChangedCallback, (XtPointer)ih); + + /* Disable Drag Source */ + iupmotDisableDragSource(cbedit); + } + else + XtAddEventHandler(cbedit, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + + if (ih->data->is_dropdown) + { + XtVaSetValues(ih->handle, XmNvisibleItemCount, 5, NULL); + XtAddCallback(XtParent(XtParent(cblist)), XmNpopupCallback, (XtCallbackProc)motListDropDownPopupCallback, (XtPointer)ih); + XtAddCallback(XtParent(XtParent(cblist)), XmNpopdownCallback, (XtCallbackProc)motListDropDownPopdownCallback, (XtPointer)ih); + } + else + { + XtAddCallback(cblist, XmNdefaultActionCallback, (XtCallbackProc)motListDefaultActionCallback, (XtPointer)ih); + XtAddEventHandler(cblist, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih); + XtAddEventHandler(cblist, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih); + + /* Disable Drag Source */ + iupmotDisableDragSource(cblist); + } + } + else + { + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent); + XtVaSetValues(parent, XmNworkWindow, ih->handle, NULL); + + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + XtAddCallback (ih->handle, XmNbrowseSelectionCallback, (XtCallbackProc)motListBrowseSelectionCallback, (XtPointer)ih); + XtAddCallback (ih->handle, XmNextendedSelectionCallback, (XtCallbackProc)motListExtendedSelectionCallback, (XtPointer)ih); + XtAddCallback (ih->handle, XmNdefaultActionCallback, (XtCallbackProc)motListDefaultActionCallback, (XtPointer)ih); + } + + /* Disable Drag Source */ + iupmotDisableDragSource(ih->handle); + + /* initialize the widget */ + if (ih->data->is_dropdown || ih->data->has_editbox) + XtRealizeWidget(ih->handle); + else + XtRealizeWidget(parent); + + if (IupGetGlobal("_IUP_RESET_TXTCOLORS")) + { + iupmotSetGlobalColorAttrib(ih->handle, XmNbackground, "TXTBGCOLOR"); + iupmotSetGlobalColorAttrib(ih->handle, XmNforeground, "TXTFGCOLOR"); + IupSetGlobal("_IUP_RESET_TXTCOLORS", NULL); + } + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motListConvertXYToPos); + + iupListSetInitialItems(ih); + + return IUP_NOERROR; +} + +void iupdrvListInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motListMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motListSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motListSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupList only */ + iupClassRegisterAttributeId(ic, "IDVALUE", motListGetIdValueAttrib, iupListSetIdValueAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", motListGetValueAttrib, motListSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VISIBLE_ITEMS", NULL, motListSetVisibleItemsAttrib, IUPAF_SAMEASSYSTEM, "5", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, motListSetTopItemAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWDROPDOWN", NULL, motListSetShowDropdownAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupListGetSpacingAttrib, motListSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + + iupClassRegisterAttribute(ic, "PADDING", iupListGetPaddingAttrib, motListSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "SELECTEDTEXT", motListGetSelectedTextAttrib, motListSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", motListGetSelectionAttrib, motListSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTIONPOS", motListGetSelectionPosAttrib, motListSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARET", motListGetCaretAttrib, motListSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARETPOS", motListGetCaretPosAttrib, motListSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INSERT", NULL, motListSetInsertAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPEND", NULL, motListSetAppendAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", motListGetReadOnlyAttrib, motListSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "NC", iupListGetNCAttrib, motListSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, motListSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTO", NULL, motListSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, motListSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_loop.c b/iup/src/mot/iupmot_loop.c new file mode 100755 index 0000000..828ddcd --- /dev/null +++ b/iup/src/mot/iupmot_loop.c @@ -0,0 +1,108 @@ +/** \file + * \brief Motif Message Loop + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> + +#include <Xm/Xm.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iupmot_drv.h" + + +/* local variables */ +static int mot_mainloop = 0; +static int mot_exitmainloop = 0; +static IFidle mot_idle_cb = NULL; +static XtWorkProcId mot_idle_id; + + +static Boolean motIdlecbWorkProc(XtPointer client_data) +{ + (void)client_data; + if (mot_idle_cb) + { + int ret = mot_idle_cb(); + if (ret == IUP_CLOSE) + { + mot_idle_cb = NULL; + IupExitLoop(); + return True; /* removes the working procedure */ + } + if (ret == IUP_IGNORE) + { + mot_idle_cb = NULL; + return True; /* removes the working procedure */ + } + + return False; /* keeps the working procedure */ + } + + return True; /* removes the working procedure */ +} + +void iupdrvSetIdleFunction(Icallback f) +{ + if (mot_idle_cb) + XtRemoveWorkProc(mot_idle_id); + + mot_idle_cb = (IFidle)f; + + if (mot_idle_cb) + mot_idle_id = XtAppAddWorkProc(iupmot_appcontext, motIdlecbWorkProc, NULL); +} + +static int motLoopStep(void) +{ + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + return (mot_exitmainloop)? IUP_CLOSE : IUP_DEFAULT; +} + +void IupExitLoop(void) +{ + mot_exitmainloop = 1; +} + +int IupMainLoopLevel(void) +{ + return mot_mainloop; +} + +int IupMainLoop(void) +{ + mot_mainloop++; + mot_exitmainloop = 0; + + while (!mot_exitmainloop) + { + if (motLoopStep() == IUP_CLOSE) + break; + } + + mot_exitmainloop = 0; + mot_mainloop--; + return IUP_NOERROR; +} + +int IupLoopStep(void) +{ + if (!XtAppPending(iupmot_appcontext)) + return IUP_DEFAULT; + + return motLoopStep(); +} + +void IupFlush(void) +{ + while (XPending(iupmot_display) != 0) + { + if (motLoopStep() == IUP_CLOSE) + break; + } + + XFlush(iupmot_display); +} diff --git a/iup/src/mot/iupmot_menu.c b/iup/src/mot/iupmot_menu.c new file mode 100755 index 0000000..be9b953 --- /dev/null +++ b/iup/src/mot/iupmot_menu.c @@ -0,0 +1,457 @@ +/** \file + * \brief Menu Resources + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/RowColumn.h> +#include <Xm/Separator.h> +#include <Xm/CascadeB.h> +#include <Xm/ToggleB.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_label.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_image.h" +#include "iup_menu.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +static int mot_menu_exitloop = 0; + +int iupdrvMenuPopup(Ihandle* ih, int x, int y) +{ + XButtonEvent ev; + ev.x_root = x; + ev.y_root = y; + XmMenuPosition(ih->handle, &ev); + + XtManageChild(ih->handle); + + mot_menu_exitloop = 0; + while (!mot_menu_exitloop) + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + mot_menu_exitloop = 0; + + return IUP_NOERROR; +} + +int iupdrvMenuGetMenuBarSize(Ihandle* ih) +{ + int ch; + iupdrvFontGetCharSize(ih, NULL, &ch); + return 5 + ch + 5; +} + + +/*******************************************************************************************/ + + +static void motItemActivateCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + Icallback cb; + + if (XmIsToggleButton(ih->handle) && !iupAttribGetBoolean(ih, "AUTOTOGGLE") && !iupAttribGetBoolean(ih->parent, "RADIO")) + { + /* Motif by default will do autotoggle */ + XmToggleButtonSetState(ih->handle, !XmToggleButtonGetState(ih->handle),0); + } + + cb = IupGetCallback(ih, "ACTION"); + if (cb && cb(ih)==IUP_CLOSE) + IupExitLoop(); + + (void)w; + (void)call_data; +} + +static void motItemArmCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + Icallback cb = IupGetCallback(ih, "HIGHLIGHT_CB"); + if (cb) + cb(ih); + + (void)w; + (void)call_data; +} + +static void motMenuMapCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + Icallback cb = IupGetCallback(ih, "OPEN_CB"); + if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "OPEN_CB"); /* check also in the Submenu */ + if (cb) cb(ih); + + (void)w; + (void)call_data; +} + +static void motMenuUnmapCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + Icallback cb = IupGetCallback(ih, "MENUCLOSE_CB"); + if (!cb && ih->parent) cb = (Icallback)IupGetCallback(ih->parent, "MENUCLOSE_CB"); /* check also in the Submenu */ + if (cb) cb(ih); + + (void)w; + (void)call_data; +} + +static void motPopupMenuUnmapCallback(Widget w, Ihandle* ih, XtPointer call_data) +{ + motMenuUnmapCallback(w, ih, call_data); + mot_menu_exitloop = 1; +} + + +/*******************************************************************************************/ + + +static void motMenuUnMapMethod(Ihandle* ih) +{ + if (iupMenuIsMenuBar(ih)) + XtDestroyWidget(ih->handle); + else + XtDestroyWidget(XtParent(ih->handle)); /* in this case the RowColumn widget is a child of a MenuShell. */ +} + +static int motMenuMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + + if (iupMenuIsMenuBar(ih)) + { + /* top level menu used for MENU attribute in IupDialog (a menu bar) */ + + ih->handle = XtVaCreateManagedWidget( + iupMenuGetChildIdStr(ih), + xmRowColumnWidgetClass, + iupChildTreeGetNativeParentHandle(ih), + XmNrowColumnType, XmMENU_BAR, + XmNmarginHeight, 0, + XmNmarginWidth, 0, + XmNresizeWidth, False, + NULL); + if (!ih->handle) + return IUP_ERROR; + } + else + { + /* all XmCreate* functions here, also create RowColumn Widgets. */ + + if (ih->parent) + { + /* parent is a submenu */ + + if (iupAttribGetBoolean(ih, "RADIO")) + { + iupmotSetArg(args, num_args, XmNpacking, XmPACK_COLUMN); + iupmotSetArg(args, num_args, XmNradioBehavior, TRUE); + } + + ih->handle = XmCreatePulldownMenu( + ih->parent->handle, + iupMenuGetChildIdStr(ih), + args, + num_args); + if (!ih->handle) + return IUP_ERROR; + + /* update the CascadeButton */ + XtVaSetValues(ih->parent->handle, XmNsubMenuId, ih->handle, NULL); + + XtAddCallback(ih->handle, XmNmapCallback, (XtCallbackProc)motMenuMapCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNunmapCallback, (XtCallbackProc)motMenuUnmapCallback, (XtPointer)ih); + } + else + { + /* top level menu used for IupPopup */ + + iupmotSetArg(args, num_args, XmNpopupEnabled, XmPOPUP_AUTOMATIC); + + ih->handle = XmCreatePopupMenu( + iupmot_appshell, + iupMenuGetChildIdStr(ih), + args, + num_args); + if (!ih->handle) + return IUP_ERROR; + + XtAddCallback(ih->handle, XmNmapCallback, (XtCallbackProc)motMenuMapCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNunmapCallback, (XtCallbackProc)motPopupMenuUnmapCallback, (XtPointer)ih); + } + } + + ih->serial = iupMenuGetChildId(ih); /* must be after using the string */ + + return IUP_NOERROR; +} + +void iupdrvMenuInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motMenuMapMethod; + ic->UnMap = motMenuUnMapMethod; + + /* Used by iupdrvMenuGetMenuBarSize */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, NULL, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_DEFAULT); /* use inheritance to retrieve standard fonts */ + + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); +} + + +/*******************************************************************************************/ + + +static int motItemSetTitleImageAttrib(Ihandle* ih, const char* value) +{ + iupmotSetPixmap(ih, value, XmNlabelPixmap, 0); + return 1; +} + +static int motItemSetTitleAttrib(Ihandle* ih, const char* value) +{ + char *str; + + if (!value) + { + str = " "; + value = str; + } + else + str = iupMenuProcessTitle(ih, value); + + if (XmIsToggleButton(ih->handle)) + { + char *p = strchr(str, '\t'); + if (p) + { + int offset = (p-str); + char* new_value = iupStrDup(str); + char* acc_value = new_value + offset + 1; + new_value[offset] = 0; + iupmotSetMnemonicTitle(ih, new_value); + iupmotSetString(ih->handle, XmNacceleratorText, acc_value); + free(new_value); + + if (str != value) free(str); + return 1; + } + } + + iupmotSetMnemonicTitle(ih, str); + + if (str != value) free(str); + return 1; +} + +static int motItemSetValueAttrib(Ihandle* ih, const char* value) +{ + if (XmIsToggleButton(ih->handle)) + { + if (iupAttribGetBoolean(ih->parent, "RADIO")) + value = "ON"; + + XmToggleButtonSetState(ih->handle, iupStrBoolean(value),0); + } + return 0; +} + +static char* motItemGetValueAttrib(Ihandle* ih) +{ + if (XmIsToggleButton(ih->handle) && XmToggleButtonGetState(ih->handle)) + return "ON"; + else + return "OFF"; +} + +static int motItemMapMethod(Ihandle* ih) +{ + int pos; + + if (!ih->parent) + return IUP_ERROR; + + /* Menu bar can contain only CascadeButtons */ + if (iupMenuIsMenuBar(ih->parent)) + { + ih->handle = XtVaCreateManagedWidget( + iupMenuGetChildIdStr(ih), + xmCascadeButtonWidgetClass, + ih->parent->handle, + NULL); + + XtAddCallback(ih->handle, XmNactivateCallback, (XtCallbackProc)motItemActivateCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNcascadingCallback, (XtCallbackProc)motItemArmCallback, (XtPointer)ih); + } + else + { + int num_args = 0; + Arg args[10]; + + if (iupAttribGetBoolean(ih->parent, "RADIO")) + { + iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); + iupmotSetArg(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); + iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); + iupmotSetArg(args, num_args, XmNindicatorSize, 13); + iupmotSetArg(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); + } + else + { + if (iupAttribGetBoolean(ih, "HIDEMARK")) + iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); + else + iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK); + iupmotSetArg(args, num_args, XmNlabelType, iupAttribGet(ih, "TITLEIMAGE")? XmPIXMAP: XmSTRING); + } + + ih->handle = XtCreateManagedWidget( + iupMenuGetChildIdStr(ih), + xmToggleButtonWidgetClass, + ih->parent->handle, + args, + num_args); + + XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motItemActivateCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNarmCallback, (XtCallbackProc)motItemArmCallback, (XtPointer)ih); + } + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupMenuGetChildId(ih); /* must be after using the string */ + + XtAddCallback (ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + pos = IupGetChildPos(ih->parent, ih); + XtVaSetValues(ih->handle, XmNpositionIndex, pos, NULL); /* RowColumn Constraint */ + + iupUpdateStandardFontAttrib(ih); + + return IUP_NOERROR; +} + +void iupdrvItemInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motItemMapMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */ + + /* Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* IupItem only */ + iupClassRegisterAttribute(ic, "VALUE", motItemGetValueAttrib, motItemSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLE", NULL, motItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TITLEIMAGE", NULL, motItemSetTitleImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupItem Gtk and Motif only */ + iupClassRegisterAttribute(ic, "HIDEMARK", NULL, NULL, NULL, NULL, IUPAF_NOT_MAPPED); +} + + +/*******************************************************************************************/ + + +static int motSubmenuMapMethod(Ihandle* ih) +{ + int pos; + + if (!ih->parent) + return IUP_ERROR; + + ih->handle = XtVaCreateManagedWidget( + iupMenuGetChildIdStr(ih), + xmCascadeButtonWidgetClass, + ih->parent->handle, + NULL); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupMenuGetChildId(ih); /* must be after using the string */ + + pos = IupGetChildPos(ih->parent, ih); + XtVaSetValues(ih->handle, XmNpositionIndex, pos, NULL); /* RowColumn Constraint */ + + XtAddCallback(ih->handle, XmNcascadingCallback, (XtCallbackProc)motItemArmCallback, (XtPointer)ih); + + iupUpdateStandardFontAttrib(ih); + + return IUP_NOERROR; +} + +void iupdrvSubmenuInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motSubmenuMapMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + /* Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, iupdrvSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); /* use inheritance to retrieve standard fonts */ + + /* Visual */ + iupClassRegisterAttribute(ic, "ACTIVE", iupBaseGetActiveAttrib, iupBaseSetActiveAttrib, IUPAF_SAMEASSYSTEM, "YES", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* IupSubmenu only */ + iupClassRegisterAttribute(ic, "TITLE", NULL, motItemSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); +} + + +/*******************************************************************************************/ + + +static int motSeparatorMapMethod(Ihandle* ih) +{ + int pos; + + if (!ih->parent) + return IUP_ERROR; + + ih->handle = XtVaCreateManagedWidget( + iupMenuGetChildIdStr(ih), + xmSeparatorWidgetClass, + ih->parent->handle, + NULL); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupMenuGetChildId(ih); /* must be after using the string */ + + pos = IupGetChildPos(ih->parent, ih); + XtVaSetValues(ih->handle, XmNpositionIndex, pos, NULL); /* RowColumn Constraint */ + + return IUP_NOERROR; +} + +void iupdrvSeparatorInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motSeparatorMapMethod; + ic->UnMap = iupdrvBaseUnMapMethod; + + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, iupdrvBaseSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); +} diff --git a/iup/src/mot/iupmot_messagedlg.c b/iup/src/mot/iupmot_messagedlg.c new file mode 100755 index 0000000..6660503 --- /dev/null +++ b/iup/src/mot/iupmot_messagedlg.c @@ -0,0 +1,191 @@ +/** \file + * \brief Motif IupMessageDlg pre-defined dialog + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <Xm/Xm.h> +#include <Xm/MwmUtil.h> +#include <Xm/MessageB.h> +#include <Xm/Protocols.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drvinfo.h" +#include "iup_dialog.h" +#include "iup_strmessage.h" + +#include "iupmot_drv.h" + + +static void motMessageDlgDeleteWindowCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + Ihandle *ih = (Ihandle*)client_data; + if (!ih) return; + (void)call_data; + (void)w; + if (iupStrEqualNoCase(iupAttribGetStr(ih, "BUTTONS"), "OK")) + iupAttribSetStr(ih, "BUTTONRESPONSE", "1"); + else + iupAttribSetStr(ih, "BUTTONRESPONSE", "2"); + iupAttribSetStr(ih, "_IUP_WM_DELETE", "1"); +} + +static void motMessageDlgCallback(Widget w, Ihandle* ih, XmAnyCallbackStruct* call_data) +{ + (void)w; + if (call_data->reason == XmCR_OK) + iupAttribSetStr(ih, "BUTTONRESPONSE", "1"); + else if (call_data->reason == XmCR_CANCEL) + iupAttribSetStr(ih, "BUTTONRESPONSE", "2"); +} + +static void motMessageDlgHelpCallback(Widget w, XtPointer client_data, XtPointer call_data) +{ + Ihandle *ih = (Ihandle*)client_data; + Icallback cb = (Icallback)IupGetCallback(ih, "HELP_CB"); + if (cb && cb(ih) == IUP_CLOSE) + { + if (iupStrEqualNoCase(iupAttribGetStr(ih, "BUTTONS"), "OK")) + iupAttribSetStr(ih, "BUTTONRESPONSE", "1"); + else + iupAttribSetStr(ih, "BUTTONRESPONSE", "2"); + } + + (void)call_data; + (void)w; +} + +static int motMessageDlgPopup(Ihandle* ih, int x, int y) +{ + InativeHandle* parent = iupDialogGetNativeParent(ih); + Widget msgbox, dialog; + int style = XmDIALOG_FULL_APPLICATION_MODAL; + int type = XmDIALOG_MESSAGE; + int num_but = 2; + char *value; + + iupAttribSetInt(ih, "_IUPDLG_X", x); /* used in iupDialogUpdatePosition */ + iupAttribSetInt(ih, "_IUPDLG_Y", y); + + if (parent) + { + msgbox = XmCreateMessageDialog(parent, "messagedialog", NULL, 0); + dialog = XtParent(msgbox); + } + else + { + dialog = XtAppCreateShell(NULL, "messagedialog", topLevelShellWidgetClass, iupmot_display, NULL, 0); + msgbox = XmCreateMessageBox(dialog, "messagebox", NULL, 0); + style = XmDIALOG_MODELESS; + XtVaSetValues(dialog, + XmNmwmInputMode, MWM_INPUT_FULL_APPLICATION_MODAL, + XmNmappedWhenManaged, False, + XmNsaveUnder, True, + NULL); + } + if (!msgbox) + return IUP_NOERROR; + + value = iupAttribGetStr(ih, "DIALOGTYPE"); + if (iupStrEqualNoCase(value, "ERROR")) + type = XmDIALOG_ERROR; + else if (iupStrEqualNoCase(value, "WARNING")) + type = XmDIALOG_WARNING; + else if (iupStrEqualNoCase(value, "INFORMATION")) + type = XmDIALOG_INFORMATION; + else if (iupStrEqualNoCase(value, "QUESTION")) + type = XmDIALOG_QUESTION; + + + value = iupAttribGet(ih, "TITLE"); + if (value) + iupmotSetString(msgbox, XmNdialogTitle, value); + else + { + if (parent) + { + XmString title; + XtVaGetValues(parent, XmNdialogTitle, &title, NULL); + XtVaSetValues(msgbox, XmNdialogTitle, title, NULL); + } + } + + value = iupAttribGet(ih, "VALUE"); + if (value) + iupmotSetString(msgbox, XmNmessageString, value); + + XtVaSetValues(msgbox, + XmNdialogType, type, + XmNdialogStyle, style, + XmNautoUnmanage, False, + XmNnoResize, True, + NULL); + + value = iupAttribGetStr(ih, "BUTTONS"); + if (iupStrEqualNoCase(value, "OK")) + { + XtUnmanageChild(XmMessageBoxGetChild(msgbox, XmDIALOG_CANCEL_BUTTON)); + num_but = 1; + } + else if (iupStrEqualNoCase(value, "YESNO")) + { + iupmotSetString(msgbox, XmNokLabelString, iupStrMessageGet("IUP_YES")); + iupmotSetString(msgbox, XmNcancelLabelString, iupStrMessageGet("IUP_NO")); + } + + if (!IupGetCallback(ih, "HELP_CB")) + XtUnmanageChild(XmMessageBoxGetChild(msgbox, XmDIALOG_HELP_BUTTON)); + + if (num_but == 2 && iupAttribGetInt(ih, "BUTTONDEFAULT") == 2) + XtVaSetValues(msgbox, XmNdefaultButtonType, XmDIALOG_CANCEL_BUTTON, NULL); + else + XtVaSetValues(msgbox, XmNdefaultButtonType, XmDIALOG_OK_BUTTON, NULL); + + XtAddCallback(msgbox, XmNokCallback, (XtCallbackProc)motMessageDlgCallback, (XtPointer)ih); + XtAddCallback(msgbox, XmNcancelCallback, (XtCallbackProc)motMessageDlgCallback, (XtPointer)ih); + XtAddCallback(msgbox, XmNhelpCallback, (XtCallbackProc)motMessageDlgHelpCallback, (XtPointer)ih); + + XmAddWMProtocolCallback(dialog, iupmot_wm_deletewindow, motMessageDlgDeleteWindowCallback, (XtPointer)ih); + XtManageChild(msgbox); + + XtRealizeWidget(dialog); + ih->handle = dialog; + iupDialogUpdatePosition(ih); + ih->handle = NULL; /* reset handle */ + + if (style == XmDIALOG_MODELESS) + XtPopup(dialog, XtGrabExclusive); + + /* while the user hasn't provided an answer, simulate main loop. + ** The answer changes as soon as the user selects one of the + ** buttons and the callback routine changes its value. */ + iupAttribSetStr(ih, "BUTTONRESPONSE", NULL); + while (iupAttribGet(ih, "BUTTONRESPONSE") == NULL) + XtAppProcessEvent(iupmot_appcontext, XtIMAll); + + if (!iupAttribGet(ih, "_IUP_WM_DELETE")) + { + XtUnmanageChild(msgbox); + + if (style == XmDIALOG_MODELESS) + { + XtPopdown(dialog); + XtDestroyWidget(dialog); + } + } + + return IUP_NOERROR; +} + +void iupdrvMessageDlgInitClass(Iclass* ic) +{ + ic->DlgPopup = motMessageDlgPopup; +} diff --git a/iup/src/mot/iupmot_open.c b/iup/src/mot/iupmot_open.c new file mode 100755 index 0000000..a59dbff --- /dev/null +++ b/iup/src/mot/iupmot_open.c @@ -0,0 +1,141 @@ +/** \file + * \brief Motif Open/Close + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <locale.h> +#include <string.h> + +#include <Xm/Xm.h> + +#include "iup.h" + +#include "iup_object.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_globalattrib.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +/* global variables */ +Widget iupmot_appshell = 0; +Display* iupmot_display = 0; +int iupmot_screen = 0; +Visual* iupmot_visual = 0; +XtAppContext iupmot_appcontext = 0; + +void* iupdrvGetDisplay(void) +{ + return iupmot_display; +} + +void iupmotSetGlobalColorAttrib(Widget w, const char* xmname, const char* name) +{ + unsigned char r, g, b; + Pixel color; + + XtVaGetValues(w, xmname, &color, NULL); + iupmotColorGetRGB(color, &r, &g, &b); + + iupGlobalSetDefaultColorAttrib(name, r, g, b); +} + +int iupdrvOpen(int *argc, char ***argv) +{ + IupSetGlobal("DRIVER", "Motif"); + + /* XtSetLanguageProc(NULL, NULL, NULL); + Removed to avoid invalid locale in modern Linux that set LANG=en_US.UTF-8 */ + + /* We do NOT use XtVaOpenApplication because it crashes when using internal dummy argc and argv. + iupmot_appshell = XtVaOpenApplication(&iupmot_appcontext, "Iup", NULL, 0, argc, *argv, NULL, + sessionShellWidgetClass, NULL); */ + + XtToolkitInitialize(); + + iupmot_appcontext = XtCreateApplicationContext(); + + iupmot_display = XtOpenDisplay(iupmot_appcontext, NULL, NULL, "Iup", NULL, 0, argc, *argv); + if (!iupmot_display) + { + fprintf (stderr, "IUP error: cannot open display.\n"); + return IUP_ERROR; + } + + iupmot_appshell = XtAppCreateShell(NULL, "Iup", sessionShellWidgetClass, iupmot_display, NULL, 0); + if (!iupmot_appshell) + { + fprintf(stderr, "IUP error: cannot create shell.\n"); + return IUP_ERROR; + } + IupSetGlobal("APPSHELL", (char*)iupmot_appshell); + + IupStoreGlobal("SYSTEMLANGUAGE", setlocale(LC_ALL, NULL)); + + iupmot_screen = XDefaultScreen(iupmot_display); + + IupSetGlobal("XDISPLAY", (char*)iupmot_display); + IupSetGlobal("XSCREEN", (char*)iupmot_screen); + + /* screen depth can be 8bpp, but canvas can be 24bpp */ + { + XVisualInfo vinfo; + if (XMatchVisualInfo(iupmot_display, iupmot_screen, 24, TrueColor, &vinfo) || + XMatchVisualInfo(iupmot_display, iupmot_screen, 16, TrueColor, &vinfo)) + { + iupmot_visual = vinfo.visual; + IupSetGlobal("TRUECOLORCANVAS", "YES"); + } + else + { + iupmot_visual = DefaultVisual(iupmot_display, iupmot_screen); + IupSetGlobal("TRUECOLORCANVAS", "NO"); + } + } + + /* driver system version */ + { + int major = xmUseVersion/1000; + int minor = xmUseVersion - major * 1000; + IupSetfAttribute(NULL, "MOTIFVERSION", "%d.%d", major, minor); + IupSetfAttribute(NULL, "MOTIFNUMBER", "%d", (XmVERSION * 1000 + XmREVISION * 100 + XmUPDATE_LEVEL)); + + IupSetGlobal("XSERVERVENDOR", ServerVendor(iupmot_display)); + IupSetfAttribute(NULL, "XVENDORRELEASE", "%d", VendorRelease(iupmot_display)); + } + + iupmotColorInit(); + + /* dialog background color */ + { + iupmotSetGlobalColorAttrib(iupmot_appshell, XmNbackground, "DLGBGCOLOR"); + iupGlobalSetDefaultColorAttrib("DLGFGCOLOR", 0, 0, 0); + IupSetGlobal("_IUP_RESET_DLGBGCOLOR", "YES"); /* will update the DLGFGCOLOR when the first dialog is mapped */ + + iupGlobalSetDefaultColorAttrib("TXTBGCOLOR", 255, 255, 255); + iupGlobalSetDefaultColorAttrib("TXTFGCOLOR", 0, 0, 0); + IupSetGlobal("_IUP_RESET_TXTCOLORS", "YES"); /* will update the TXTCOLORS when the first text or list is mapped */ + } + + if (getenv("IUP_DEBUG")) + XSynchronize(iupmot_display, 1); + + return IUP_NOERROR; +} + +void iupdrvClose(void) +{ + iupmotColorFinish(); + iupmotTipsFinish(); + + if (iupmot_appshell) + XtDestroyWidget(iupmot_appshell); + + if (iupmot_appcontext) + XtDestroyApplicationContext(iupmot_appcontext); +} diff --git a/iup/src/mot/iupmot_progressbar.c b/iup/src/mot/iupmot_progressbar.c new file mode 100755 index 0000000..7266d38 --- /dev/null +++ b/iup/src/mot/iupmot_progressbar.c @@ -0,0 +1,165 @@ +/** \file +* \brief Progress bar Control +* +* See Copyright Notice in "iup.h" +*/ + +#include <Xm/Xm.h> +#include <Xm/Scale.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_progressbar.h" +#include "iup_drv.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +static int motProgressBarSetValueAttrib(Ihandle* ih, const char* value) +{ + if (!value) + ih->data->value = 0; + else + ih->data->value = atof(value); + iProgressBarCropValue(ih); + + XtVaSetValues(ih->handle, XmNvalue, (int)(SHRT_MAX * (ih->data->value - ih->data->vmin) / (ih->data->vmax - ih->data->vmin)), NULL); + + return 0; +} + +static int motProgressBarSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (!iupAttribGetStr(ih, "FGCOLOR")) + { + Pixel color; + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + r = (r*8)/10; + g = (g*8)/10; + b = (b*8)/10; + + color = iupmotColorGetPixel(r, g, b); + if (color != (Pixel)-1) + { + Widget w = XtNameToWidget(ih->handle, "*Scrollbar"); + XtVaSetValues(w, XmNtroughColor, color, NULL); + } + } + + return iupdrvBaseSetBgColorAttrib(ih, value); +} + + +static int motProgressBarSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget w = XtNameToWidget(ih->handle, "*Scrollbar"); + XtVaSetValues(w, XmNtroughColor, color, NULL); + } + + return 1; +} + +static void motProgressBarLayoutUpdateMethod(Ihandle *ih) +{ + unsigned char orientation; + XtVaGetValues(ih->handle, XmNorientation, &orientation, NULL); + + if (orientation == XmVERTICAL) + XtVaSetValues(ih->handle, XmNscaleWidth, ih->currentwidth, NULL); + else + XtVaSetValues(ih->handle, XmNscaleHeight, ih->currentheight, NULL); + + iupdrvBaseLayoutUpdateMethod(ih); +} + +static int motProgressBarMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ + iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupmotSetArg(args, num_args, XmNhighlightThickness, 0); + /* Scale */ + iupmotSetArg(args, num_args, XmNminimum, 0); + iupmotSetArg(args, num_args, XmNmaximum, SHRT_MAX); + iupmotSetArg(args, num_args, XmNslidingMode, XmTHERMOMETER); /* thermometer effect */ + iupmotSetArg(args, num_args, XmNsliderMark, XmNONE); + iupmotSetArg(args, num_args, XmNeditable, False); + iupmotSetArg(args, num_args, XmNshowValue, XmNONE); + + if (iupStrEqualNoCase(iupAttribGetStr(ih, "ORIENTATION"), "VERTICAL")) + { + iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); + + if (ih->currentheight < ih->currentwidth) + { + int tmp = ih->currentheight; + ih->currentheight = ih->currentwidth; + ih->currentwidth = tmp; + } + } + else + iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmScaleWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvProgressBarInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motProgressBarMapMethod; + ic->LayoutUpdate = motProgressBarLayoutUpdateMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motProgressBarSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motProgressBarSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + + /* IupProgressBar only */ + iupClassRegisterAttribute(ic, "VALUE", iProgressBarGetValueAttrib, motProgressBarSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "ORIENTATION", NULL, NULL, "HORIZONTAL", NULL, IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_tabs.c b/iup/src/mot/iupmot_tabs.c new file mode 100755 index 0000000..7c8a6b5 --- /dev/null +++ b/iup/src/mot/iupmot_tabs.c @@ -0,0 +1,593 @@ +/** \file +* \brief Tabs Control +* +* See Copyright Notice in "iup.h" +*/ + +#include <Xm/Xm.h> +#include <Xm/Notebook.h> +#include <Xm/BulletinB.h> +#include <Xm/PushB.h> +#include <Xm/Label.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_layout.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_dialog.h" +#include "iup_drv.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_tabs.h" +#include "iup_image.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +int iupdrvTabsExtraDecor(Ihandle* ih) +{ + (void)ih; + return 1; +} + +int iupdrvTabsGetLineCountAttrib(Ihandle* ih) +{ + (void)ih; + return 1; +} + +void iupdrvTabsSetCurrentTab(Ihandle* ih, int pos) +{ + Ihandle* child = IupGetChild(ih, pos); + Ihandle* prev_child = IupGetChild(ih, iupdrvTabsGetCurrentTab(ih)); + IupSetAttribute(child, "VISIBLE", "YES"); + IupSetAttribute(prev_child, "VISIBLE", "NO"); + + XtVaSetValues(ih->handle, XmNcurrentPageNumber, pos, NULL); +} + +int iupdrvTabsGetCurrentTab(Ihandle* ih) +{ + int pos; + XtVaGetValues(ih->handle, XmNcurrentPageNumber, &pos, NULL); + return pos; +} + +static void motTabsUpdatePageNumber(Ihandle* ih) +{ + int pos, old_pos; + Ihandle* child; + for (pos = 0, child = ih->firstchild; child; child = child->brother, pos++) + { + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (child_manager) + { + old_pos = iupAttribGetInt(child, "_IUPMOT_TABNUMBER"); /* did not work when using XtVaGetValues(child_manager, XmNpageNumber) */ + if (pos != old_pos) + { + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + XtVaSetValues(child_manager, XmNpageNumber, pos, NULL); + XtVaSetValues(tab_button, XmNpageNumber, pos, NULL); + iupAttribSetInt(child, "_IUPMOT_TABNUMBER", pos); + } + } + } +} + +static void motTabsUpdatePageBgPixmap(Ihandle* ih, Pixmap pixmap) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (child_manager) + XtVaSetValues(child_manager, XmNbackgroundPixmap, pixmap, NULL); + } +} + +static void motTabsUpdatePageBgColor(Ihandle* ih, Pixel color) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (child_manager) + iupmotSetBgColor(child_manager, color); + } +} + +static void motTabsUpdateButtonsFgColor(Ihandle* ih, Pixel color) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + XtVaSetValues(tab_button, XmNforeground, color, NULL); + } +} + +static void motTabsUpdateButtonsBgColor(Ihandle* ih, Pixel color) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + iupmotSetBgColor(tab_button, color); + } +} + +static void motTabsUpdateButtonsPadding(Ihandle* ih) +{ + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + { + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + XtVaSetValues(tab_button, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + } +} + +static void motTabsUpdatePageFont(Ihandle* ih) +{ + Ihandle* child; + XmFontList fontlist = (XmFontList)iupmotGetFontListAttrib(ih); + + for (child = ih->firstchild; child; child = child->brother) + { + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + XtVaSetValues(tab_button, XmNrenderTable, fontlist, NULL); + } +} + +/* ------------------------------------------------------------------------- */ +/* motTabs - Sets and Gets accessors */ +/* ------------------------------------------------------------------------- */ + +static int motTabsSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + + if (ih->handle) + motTabsUpdateButtonsPadding(ih); + return 0; +} + +static void motTabsUpdateTabType(Ihandle* ih) +{ + if (ih->data->type == ITABS_LEFT) + XtVaSetValues(ih->handle, XmNbackPagePlacement, XmBOTTOM_LEFT, + XmNorientation, XmHORIZONTAL, + NULL); + else if(ih->data->type == ITABS_RIGHT) + XtVaSetValues(ih->handle, XmNbackPagePlacement, XmBOTTOM_RIGHT, + XmNorientation, XmHORIZONTAL, + NULL); + else if(ih->data->type == ITABS_BOTTOM) + XtVaSetValues(ih->handle, XmNbackPagePlacement, XmBOTTOM_RIGHT, + XmNorientation, XmVERTICAL, + NULL); + else /* "TOP" */ + XtVaSetValues(ih->handle, XmNbackPagePlacement, XmTOP_RIGHT, + XmNorientation, XmVERTICAL, + NULL); +} + +static int motTabsSetTabTypeAttrib(Ihandle* ih, const char* value) +{ + if (iupStrEqualNoCase(value, "LEFT")) + ih->data->type = ITABS_LEFT; + else if(iupStrEqualNoCase(value, "RIGHT")) + ih->data->type = ITABS_RIGHT; + else if(iupStrEqualNoCase(value, "BOTTOM")) + ih->data->type = ITABS_BOTTOM; + else /* "TOP" */ + ih->data->type = ITABS_TOP; + + if (ih->handle) + motTabsUpdateTabType(ih); + + return 0; +} + +static int motTabsSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + + /* given value is used only for child, to the Tabs must use only from parent */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + iupmotSetBgColor(ih->handle, color); + motTabsUpdatePageBgColor(ih, color); + } + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + motTabsUpdateButtonsBgColor(ih, color); + + return 1; +} + +static int motTabsSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + /* given value is used only for child, to the Tabs must use only from parent */ + char* parent_value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + Pixel color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + iupmotSetBgColor(ih->handle, color); + motTabsUpdatePageBgColor(ih, color); + } + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(parent_value, ih, 0); + if (pixmap) + { + XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL); + motTabsUpdatePageBgPixmap(ih, pixmap); + } + } + + (void)value; + return 1; +} + +static int motTabsSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + XtVaSetValues(ih->handle, XmNforeground, color, NULL); + motTabsUpdateButtonsFgColor(ih, color); + return 1; + } + return 0; +} + +static int motTabsSetStandardFontAttrib(Ihandle* ih, const char* value) +{ + iupdrvSetStandardFontAttrib(ih, value); + if (ih->handle) + motTabsUpdatePageFont(ih); + return 1; +} + +static int motTabsSetTabTitleAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int pos; + if (value && iupStrToInt(name_id, &pos)==1) + { + Ihandle* child = IupGetChild(ih, pos); + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + iupmotSetString(tab_button, XmNlabelString, value); + } + return 1; +} + +static int motTabsSetTabImageAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + int pos; + if (value && iupStrToInt(name_id, &pos)==1) + { + Ihandle* child = IupGetChild(ih, pos); + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + if (tab_button) + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + XtVaSetValues(tab_button, XmNlabelPixmap, pixmap, NULL); + } + } + return 1; +} + + +/* ------------------------------------------------------------------------- */ +/* motTabs - Callback */ +/* ------------------------------------------------------------------------- */ + +void motTabsPageChangedCallback(Widget w, Ihandle* ih, XmNotebookCallbackStruct *nptr) +{ + if (nptr->reason == XmCR_MAJOR_TAB) + { + IFnnn cb; + Ihandle* child = IupGetChild(ih, nptr->page_number); + Ihandle* prev_child = IupGetChild(ih, nptr->prev_page_number); + IupSetAttribute(child, "VISIBLE", "YES"); + IupSetAttribute(prev_child, "VISIBLE", "NO"); + + cb = (IFnnn)IupGetCallback(ih, "TABCHANGE_CB"); + if (cb) + cb(ih, child, prev_child); + } + (void)w; +} + +static void motTabsConfigureNotify(Widget w, XEvent *evt, String* s, Cardinal *card) +{ + /* Motif does not process the changed of position and/or size of children outside the parent's client area. + Since Notebook pages are not resized until they are moved into the visible area, + we must update the children position and size when a tab page is resize. + Since tab pages are not hidden, they are moved outside the visible area, + a resize occours every time a tab is activated. + */ + Ihandle *child; + (void)s; + (void)card; + (void)evt; + + XtVaGetValues(w, XmNuserData, &child, NULL); + if (!child) return; + + iupLayoutUpdate(child); +} + +/* ------------------------------------------------------------------------- */ +/* motTabs - Methods and Init Class */ +/* ------------------------------------------------------------------------- */ + +static void motTabsChildAddedMethod(Ihandle* ih, Ihandle* child) +{ + if (IupGetName(child) == NULL) + iupAttribSetHandleName(child); + + if (ih->handle) + { + Widget child_manager; + Widget tab_button; + int num_args = 0, pos; + Arg args[30]; + char *tabtitle, *tabimage, *background; + Pixel color; + + /* open space for new tab number */ + motTabsUpdatePageNumber(ih); + + pos = IupGetChildPos(ih, child); + + /* Create pages */ + child_manager = XtVaCreateManagedWidget( + "child_manager", + xmBulletinBoardWidgetClass, + ih->handle, + /* Core */ + XmNborderWidth, 0, + /* Manager */ + XmNshadowThickness, 0, + XmNnavigationType, XmTAB_GROUP, + XmNuserData, child, /* used only in motTabsConfigureNotify */ + /* BulletinBoard */ + XmNmarginWidth, 0, + XmNmarginHeight, 0, + XmNresizePolicy, XmRESIZE_NONE, /* no automatic resize of children */ + /* Notebook Constraint */ + XmNnotebookChildType, XmPAGE, + XmNpageNumber, pos, + XmNresizable, True, + NULL); + + XtOverrideTranslations(child_manager, XtParseTranslationTable("<Configure>: iupTabsConfigure()")); + + tabtitle = iupAttribGet(child, "TABTITLE"); + if (!tabtitle) tabtitle = iupTabsAttribGetStrId(ih, "TABTITLE", pos); + tabimage = iupAttribGet(child, "TABIMAGE"); + if (!tabimage) tabimage = iupTabsAttribGetStrId(ih, "TABIMAGE", pos); + if (!tabtitle && !tabimage) + tabtitle = " "; + + /* Create tabs */ + /* Label */ + iupmotSetArg(args, num_args, XmNlabelType, tabtitle? XmSTRING: XmPIXMAP); + iupmotSetArg(args, num_args, XmNmarginHeight, 0); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + /* Notebook Constraint */ + iupmotSetArg(args, num_args, XmNnotebookChildType, XmMAJOR_TAB); + iupmotSetArg(args, num_args, XmNpageNumber, pos); + tab_button = XtCreateManagedWidget("tab_button", xmPushButtonWidgetClass, ih->handle, args, num_args); + + /* Disable Drag Source */ + iupmotDisableDragSource(tab_button); + + XtAddEventHandler(tab_button, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(tab_button, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(tab_button, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(tab_button, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + + if (tabtitle) + iupmotSetString(tab_button, XmNlabelString, tabtitle); + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(tabimage, ih, 0); + if (pixmap) + XtVaSetValues(tab_button, XmNlabelPixmap, pixmap, NULL); + } + + background = iupBaseNativeParentGetBgColorAttrib(ih); + color = iupmotColorGetPixelStr(background); + if (color != -1) + iupmotSetBgColor(child_manager, color); + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(background, ih, 0); + if (pixmap) + { + XtVaSetValues(child_manager, XmNbackgroundPixmap, pixmap, NULL); + } + } + + background = iupAttribGetStr(ih, "BGCOLOR"); + color = iupmotColorGetPixelStr(background); + if (color != -1) + iupmotSetBgColor(tab_button, color); + + color = iupmotColorGetPixelStr(IupGetAttribute(ih, "FGCOLOR")); + XtVaSetValues(tab_button, XmNforeground, color, NULL); + + XtRealizeWidget(child_manager); + XtRealizeWidget(tab_button); + + iupAttribSetStr(child, "_IUPTAB_CONTAINER", (char*)child_manager); + iupAttribSetStr(child, "_IUPMOT_TABBUTTON", (char*)tab_button); + iupAttribSetInt(child, "_IUPMOT_TABNUMBER", pos); + + if (pos == iupdrvTabsGetCurrentTab(ih)) + IupSetAttribute(child, "VISIBLE", "YES"); + else + IupSetAttribute(child, "VISIBLE", "NO"); + } +} + +static void motTabsChildRemovedMethod(Ihandle* ih, Ihandle* child) +{ + if (ih->handle) + { + Widget child_manager = (Widget)iupAttribGet(child, "_IUPTAB_CONTAINER"); + if (child_manager) + { + int cur_pos, pos; + Widget tab_button = (Widget)iupAttribGet(child, "_IUPMOT_TABBUTTON"); + + cur_pos = iupdrvTabsGetCurrentTab(ih); + pos = iupAttribGetInt(child, "_IUPMOT_TABNUMBER"); /* did not work when using XtVaGetValues(child_manager, XmNpageNumber) */ + if (cur_pos == pos) + { + if (cur_pos == 0) + cur_pos = 1; + else + cur_pos--; + + iupdrvTabsSetCurrentTab(ih, cur_pos); + } + + XtDestroyWidget(tab_button); + XtDestroyWidget(child_manager); + + /* compact the tab number usage */ + motTabsUpdatePageNumber(ih); + + iupAttribSetStr(child, "_IUPTAB_CONTAINER", NULL); + iupAttribSetStr(child, "_IUPMOT_TABBUTTON", NULL); + iupAttribSetStr(child, "_IUPMOT_TABNUMBER", NULL); + } + } +} + +static int motTabsMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + + if (!ih->parent) + return IUP_ERROR; + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Manager */ + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupmotSetArg(args, num_args, XmNhighlightThickness, 0); + /* Notebook */ + iupmotSetArg(args, num_args, XmNbindingType, XmNONE); + iupmotSetArg(args, num_args, XmNbindingWidth, 0); + iupmotSetArg(args, num_args, XmNfirstPageNumber, 0); /* IupTabs index always starts with zero */ + iupmotSetArg(args, num_args, XmNbackPageSize, 0); + iupmotSetArg(args, num_args, XmNbackPageNumber, 1); + iupmotSetArg(args, num_args, XmNframeShadowThickness, 2); + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmNotebookWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + /* Disable page scroller */ + { + Widget scroller; + scroller = XtNameToWidget(ih->handle, "*PageScroller"); + XtUnmanageChild(scroller); + } + + /* Callbacks */ + XtAddCallback(ih->handle, XmNpageChangedCallback, (XtCallbackProc)motTabsPageChangedCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + /* update Tab position */ + motTabsUpdateTabType(ih); + + /* current value is now given by the native system */ + iupAttribSetStr(ih, "_IUPTABS_VALUE_HANDLE", NULL); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + /* Create pages and tabs */ + if (ih->firstchild) + { + Ihandle* child; + for (child = ih->firstchild; child; child = child->brother) + motTabsChildAddedMethod(ih, child); + } + + return IUP_NOERROR; +} + +void iupdrvTabsInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motTabsMapMethod; + ic->ChildAdded = motTabsChildAddedMethod; + ic->ChildRemoved = motTabsChildRemovedMethod; + + { + /* Set up a translation table that captures "Resize" events + (also called ConfigureNotify or Configure events). */ + XtActionsRec rec = {"iupTabsConfigure", motTabsConfigureNotify}; + XtAppAddActions(iupmot_appcontext, &rec, 1); + } + + /* Driver Dependent Attribute functions */ + + /* Common */ + iupClassRegisterAttribute(ic, "STANDARDFONT", NULL, motTabsSetStandardFontAttrib, IUPAF_SAMEASSYSTEM, "DEFAULTFONT", IUPAF_NOT_MAPPED); + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTabsSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motTabsSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motTabsSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* IupTabs only */ + iupClassRegisterAttribute(ic, "TABTYPE", iupTabsGetTabTypeAttrib, motTabsSetTabTypeAttrib, IUPAF_SAMEASSYSTEM, "TOP", IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "TABORIENTATION", iupTabsGetTabOrientationAttrib, NULL, IUPAF_SAMEASSYSTEM, "HORIZONTAL", IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* can not be set, always HORIZONTAL in Motif */ + iupClassRegisterAttributeId(ic, "TABTITLE", NULL, motTabsSetTabTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TABIMAGE", NULL, motTabsSetTabImageAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PADDING", iupTabsGetPaddingAttrib, motTabsSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); +} diff --git a/iup/src/mot/iupmot_text.c b/iup/src/mot/iupmot_text.c new file mode 100755 index 0000000..4a8f936 --- /dev/null +++ b/iup/src/mot/iupmot_text.c @@ -0,0 +1,1165 @@ +/** \file + * \brief Text Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/TextF.h> +#include <Xm/Text.h> +#include <Xm/ScrolledW.h> +#include <Xm/SpinB.h> +#include <X11/keysym.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_mask.h" +#include "iup_drv.h" +#include "iup_array.h" +#include "iup_text.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +#ifndef XmIsSpinBox +#define XmIsSpinBox(w) XtIsSubclass(w, xmSpinBoxWidgetClass) +#endif + +#ifndef XmNwrap +#define XmNwrap "Nwrap" +#endif + +void iupdrvTextAddFormatTag(Ihandle* ih, Ihandle* formattag) +{ + (void)ih; + (void)formattag; +} + +void iupdrvTextAddSpin(int *w, int h) +{ + *w += h/2; +} + +void iupdrvTextAddBorders(int *w, int *h) +{ + int border_size = 2*5; + (*w) += border_size; + (*h) += border_size; +} + +static void motTextGetLinColFromPosition(const char *str, int pos, int *lin, int *col ) +{ + int i; + + *lin = 0; + *col = 0; + + for (i=0; i<pos; i++) + { + if (*str == '\n') + { + (*lin)++; + *col = 0; + } + else + (*col)++; + + str++; + } + + (*lin)++; /* IUP starts at 1 */ + (*col)++; +} + +static int motTextSetLinColToPosition(const char *str, int lin, int col) +{ + int pos=0, cur_lin=0, cur_col=0; + + lin--; /* IUP starts at 1 */ + col--; + + while (*str) + { + if (lin<=cur_lin && col<=cur_col) + break; + + if (*str == '\n') + { + cur_lin++; + cur_col = 0; + } + else + cur_col++; + + str++; + pos++; + } + + return pos; +} + +void iupdrvTextConvertLinColToPos(Ihandle* ih, int lin, int col, int *pos) +{ + char* str = XmTextGetString(ih->handle); + *pos = motTextSetLinColToPosition(str, lin, col); + XtFree(str); +} + +void iupdrvTextConvertPosToLinCol(Ihandle* ih, int pos, int *lin, int *col) +{ + char *str = XmTextGetString(ih->handle); + motTextGetLinColFromPosition(str, pos, lin, col); + XtFree(str); +} + +static int motTextConvertXYToPos(Ihandle* ih, int x, int y) +{ + return XmTextXYToPos(ih->handle, x, y); +} + + +/*******************************************************************************************/ + + +static int motTextSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + } + return 0; +} + +static int motTextSetReadOnlyAttrib(Ihandle* ih, const char* value) +{ + XtVaSetValues(ih->handle, XmNeditable, iupStrBoolean(value)? False: True, NULL); + return 0; +} + +static char* motTextGetReadOnlyAttrib(Ihandle* ih) +{ + Boolean editable; + XtVaGetValues(ih->handle, XmNeditable, &editable, NULL); + if (editable) + return "YES"; + else + return "NO"; +} + +static int motTextSetInsertAttrib(Ihandle* ih, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if (!value) + return 0; + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XmTextRemove(ih->handle); + XmTextInsert(ih->handle, XmTextGetInsertionPosition(ih->handle), (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + + return 0; +} + +static int motTextSetSelectedTextAttrib(Ihandle* ih, const char* value) +{ + XmTextPosition start, end; + + if (!value) + return 0; + + if (XmTextGetSelectionPosition(ih->handle, &start, &end) && start!=end) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XmTextReplace(ih->handle, start, end, (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + + return 0; +} + +static char* motTextGetSelectedTextAttrib(Ihandle* ih) +{ + char* selectedtext = XmTextGetSelection(ih->handle); + char* str = iupStrGetMemoryCopy(selectedtext); + XtFree(selectedtext); + return str; +} + +static int motTextSetAppendAttrib(Ihandle* ih, const char* value) +{ + XmTextPosition pos; + if (!ih->handle) /* do not store the action before map */ + return 0; + pos = XmTextGetLastPosition(ih->handle); + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + if (ih->data->is_multiline && ih->data->append_newline) + XmTextInsert(ih->handle, pos, "\n"); + if (value) + XmTextInsert(ih->handle, pos+1, (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + return 0; +} + +static int motTextSetSelectionAttrib(Ihandle* ih, const char* value) +{ + int start=1, end=1; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + XmTextClearSelection(ih->handle, CurrentTime); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + XmTextSetSelection(ih->handle, (XmTextPosition)0, (XmTextPosition)XmTextGetLastPosition(ih->handle), CurrentTime); + return 0; + } + + if (ih->data->is_multiline) + { + int lin_start=1, col_start=1, lin_end=1, col_end=1; + char *str; + + if (sscanf(value, "%d,%d:%d,%d", &lin_start, &col_start, &lin_end, &col_end)!=4) return 0; + if (lin_start<1 || col_start<1 || lin_end<1 || col_end<1) return 0; + + str = XmTextGetString(ih->handle); + start = motTextSetLinColToPosition(str, lin_start, col_start); + end = motTextSetLinColToPosition(str, lin_end, col_end); + XtFree(str); + } + else + { + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<1 || end<1) + return 0; + + start--; /* IUP starts at 1 */ + end--; + } + + /* end is inside the selection, in IUP is outside */ + end--; + + XmTextSetSelection(ih->handle, (XmTextPosition)start, (XmTextPosition)end, CurrentTime); + + return 0; +} + +static char* motTextGetSelectionAttrib(Ihandle* ih) +{ + XmTextPosition start = 0, end = 0; + char* str; + + if (!XmTextGetSelectionPosition(ih->handle, &start, &end) || start==end) + return NULL; + + str = iupStrGetMemory(100); + + /* end is inside the selection, in IUP is outside */ + end++; + + if (ih->data->is_multiline) + { + int start_col, start_lin, end_col, end_lin; + + char *value = XmTextGetString(ih->handle); + motTextGetLinColFromPosition(value, start, &start_lin, &start_col); + motTextGetLinColFromPosition(value, end, &end_lin, &end_col); + XtFree(value); + + sprintf(str,"%d,%d:%d,%d", start_lin, start_col, end_lin, end_col); + } + else + { + start++; /* IUP starts at 1 */ + end++; + sprintf(str, "%d:%d", (int)start, (int)end); + } + + return str; +} + +static int motTextSetSelectionPosAttrib(Ihandle* ih, const char* value) +{ + int start=0, end=0; + + if (!value || iupStrEqualNoCase(value, "NONE")) + { + XmTextClearSelection(ih->handle, CurrentTime); + return 0; + } + + if (iupStrEqualNoCase(value, "ALL")) + { + XmTextSetSelection(ih->handle, (XmTextPosition)0, (XmTextPosition)XmTextGetLastPosition(ih->handle), CurrentTime); + return 0; + } + + if (iupStrToIntInt(value, &start, &end, ':')!=2) + return 0; + + if(start<0 || end<0) + return 0; + + /* end is inside the selection, in IUP is outside */ + end--; + + XmTextSetSelection(ih->handle, (XmTextPosition)start, (XmTextPosition)end, CurrentTime); + + return 0; +} + +static char* motTextGetSelectionPosAttrib(Ihandle* ih) +{ + XmTextPosition start = 0, end = 0; + char* str; + + if (!XmTextGetSelectionPosition(ih->handle, &start, &end) || start==end) + return NULL; + + str = iupStrGetMemory(100); + + /* end is inside the selection, in IUP is outside */ + end++; + + sprintf(str, "%d:%d", (int)start, (int)end); + + return str; +} + +static int motTextSetCaretAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + + if (!value) + return 0; + + if (ih->data->is_multiline) + { + int lin = 1, col = 1; + char *str; + + iupStrToIntInt(value, &lin, &col, ','); + + str = XmTextGetString(ih->handle); + pos = motTextSetLinColToPosition(str, lin, col); + XtFree(str); + } + else + { + sscanf(value,"%i",&pos); + pos--; /* IUP starts at 1 */ + } + + XmTextSetInsertionPosition(ih->handle, (XmTextPosition)pos); + XmTextShowPosition(ih->handle, (XmTextPosition)pos); + + return 0; +} + +static char* motTextGetCaretAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(50); + + XmTextPosition pos = XmTextGetInsertionPosition(ih->handle); + + if (ih->data->is_multiline) + { + int col, lin; + + char *value = XmTextGetString(ih->handle); + motTextGetLinColFromPosition(value, pos, &lin, &col); + XtFree(value); + + sprintf(str, "%d,%d", lin, col); + } + else + { + pos++; /* IUP starts at 1 */ + sprintf(str, "%d", (int)pos); + } + + return str; +} + +static int motTextSetCaretPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + XmTextSetInsertionPosition(ih->handle, (XmTextPosition)pos); + XmTextShowPosition(ih->handle, (XmTextPosition)pos); + + return 0; +} + +static char* motTextGetCaretPosAttrib(Ihandle* ih) +{ + XmTextPosition pos = XmTextGetInsertionPosition(ih->handle); + char* str = iupStrGetMemory(50); + sprintf(str, "%d", (int)pos); + return str; +} + +static int motTextSetScrollToAttrib(Ihandle* ih, const char* value) +{ + int pos = 1; + + if (!value) + return 0; + + if (ih->data->is_multiline) + { + int lin = 1, col = 1, pos; + char* str; + + iupStrToIntInt(value, &lin, &col, ','); + if (lin < 1) lin = 1; + if (col < 1) col = 1; + + str = XmTextGetString(ih->handle); + pos = motTextSetLinColToPosition(str, lin, col); + XtFree(str); + } + else + { + sscanf(value,"%i",&pos); + if (pos < 1) pos = 1; + pos--; /* return to Motif referece */ + } + + XmTextShowPosition(ih->handle, (XmTextPosition)pos); + + return 0; +} + +static int motTextSetScrollToPosAttrib(Ihandle* ih, const char* value) +{ + int pos = 0; + + if (!value) + return 0; + + sscanf(value,"%i",&pos); + if (pos < 0) pos = 0; + + XmTextShowPosition(ih->handle, (XmTextPosition)pos); + + return 0; +} + +static int motTextSetNCAttrib(Ihandle* ih, const char* value) +{ + if (!iupStrToInt(value, &ih->data->nc)) + ih->data->nc = INT_MAX; + if (ih->handle) + XtVaSetValues(ih->handle, XmNmaxLength, ih->data->nc, NULL); + return 0; +} + +static int motTextSetClipboardAttrib(Ihandle *ih, const char *value) +{ + if (iupStrEqualNoCase(value, "COPY")) + { + char *str = XmTextGetSelection(ih->handle); + if (!str) return 0; + + XmTextCopy(ih->handle, CurrentTime); + + /* do it also for the X clipboard */ + XStoreBytes(iupmot_display, str, strlen(str)+1); + XtFree(str); + } + else if (iupStrEqualNoCase(value, "CUT")) + { + char *str = XmTextGetSelection(ih->handle); + if (!str) return 0; + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + + XmTextCut(ih->handle, CurrentTime); + + /* do it also for the X clipboard */ + XStoreBytes(iupmot_display, str, strlen(str)+1); + XtFree(str); + XmTextRemove(ih->handle); + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + else if (iupStrEqualNoCase(value, "PASTE")) + { + int size; + char* str = XFetchBytes(iupmot_display, &size); + if (!str) return 0; + + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + + XmTextPaste(ih->handle); /* TODO: this could force 2 pastes, check in CDE */ + + /* do it also for the X clipboard */ + XmTextRemove(ih->handle); + XmTextInsert(ih->handle, XmTextGetInsertionPosition(ih->handle), str); + XFree(str); + + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + else if (iupStrEqualNoCase(value, "CLEAR")) + { + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XmTextRemove(ih->handle); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + return 0; +} + +static int motTextSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (sb_win) + { + Pixel color; + + /* ignore given value for the scrollbars, must use only from parent */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + Widget sb = NULL; + + iupmotSetBgColor(sb_win, color); + + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + } + } + + return iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */ +} + +static int motTextSetSpinMinAttrib(Ihandle* ih, const char* value) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + int min; + if (iupStrToInt(value, &min)) + { + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XtVaSetValues(ih->handle, XmNminimumValue, min, NULL); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + } + return 1; +} + +static int motTextSetSpinMaxAttrib(Ihandle* ih, const char* value) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + int max; + if (iupStrToInt(value, &max)) + { + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XtVaSetValues(ih->handle, XmNmaximumValue, max, NULL); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + } + return 1; +} + +static int motTextSetSpinIncAttrib(Ihandle* ih, const char* value) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + int inc; + if (iupStrToInt(value, &inc)) + { + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XtVaSetValues(ih->handle, XmNincrementValue, inc, NULL); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + } + } + return 1; +} + +static int motTextSetSpinValueAttrib(Ihandle* ih, const char* value) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + int pos; + if (iupStrToInt(value, &pos)) + { + char* value = NULL; + int min, max; + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XtVaGetValues(ih->handle, XmNminimumValue, &min, + XmNmaximumValue, &max, NULL); + if (pos < min) pos = min; + if (pos > max) pos = max; + if (iupAttribGet(ih, "_IUPMOT_SPIN_NOAUTO")) + value = XmTextGetString(ih->handle); + + XtVaSetValues(ih->handle, XmNposition, pos, NULL); + + if (value) + { + XmTextSetString(ih->handle, (char*)value); + XtFree(value); + } + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + return 1; + } + } + return 0; +} + +static char* motTextGetSpinValueAttrib(Ihandle* ih) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + int pos; + char *str = iupStrGetMemory(50); + XtVaGetValues(ih->handle, XmNposition, &pos, NULL); + sprintf(str, "%d", pos); + return str; + } + return NULL; +} + +static int motTextSetValueAttrib(Ihandle* ih, const char* value) +{ + if (!value) value = ""; + motTextSetSpinValueAttrib(ih, value); + /* disable callbacks */ + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XmTextSetString(ih->handle, (char*)value); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + return 0; +} + +static char* motTextGetValueAttrib(Ihandle* ih) +{ + char* value = XmTextGetString(ih->handle); + char* str = iupStrGetMemoryCopy(value); + XtFree(value); + return str; +} + + +/******************************************************************************/ + + +static void motTextSpinModifyVerifyCallback(Widget w, Ihandle* ih, XmSpinBoxCallbackStruct *cbs) +{ + IFni cb = (IFni) IupGetCallback(ih, "SPIN_CB"); + if (cb) + { + int ret = cb(ih, cbs->position); + if (ret == IUP_IGNORE) + { + cbs->doit = 1; + return; + } + } + (void)w; + + iupAttribSetStr(ih, "_IUPMOT_SPIN_DISABLE_TEXT_CB", "1"); +} + +static void motTextModifyVerifyCallback(Widget w, Ihandle *ih, XmTextVerifyPtr text) +{ + int start, end, key = 0; + char *value, *new_value, *insert_value; + KeySym motcode = 0; + IFnis cb; + + if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB")) + return; + + if (iupAttribGet(ih, "_IUPMOT_SPIN_DISABLE_TEXT_CB")) + { + if (iupAttribGet(ih, "_IUPMOT_SPIN_NOAUTO")) + text->doit = False; + + iupAttribSetStr(ih, "_IUPMOT_SPIN_DISABLE_TEXT_CB", NULL); + return; + } + + cb = (IFnis)IupGetCallback(ih, "ACTION"); + if (!cb && !ih->data->mask) + return; + + if (text->event && text->event->type == KeyPress) + { + unsigned int state = ((XKeyEvent*)text->event)->state; + if (state & ControlMask || /* Ctrl */ + state & Mod1Mask || + state & Mod5Mask || /* Alt */ + state & Mod4Mask) /* Apple/Win */ + return; + + motcode = XKeycodeToKeysym(iupmot_display, ((XKeyEvent*)text->event)->keycode, 0); + } + + value = XmTextGetString(ih->handle); + start = text->startPos; + end = text->endPos; + insert_value = text->text->ptr; + + if (motcode == XK_Delete) + { + new_value = value; + iupStrRemove(value, start, end, 1); + } + else if (motcode == XK_BackSpace) + { + new_value = value; + iupStrRemove(value, start, end, -1); + } + else + { + if (!value) + new_value = iupStrDup(insert_value); + else if (insert_value) + new_value = iupStrInsert(value, insert_value, start, end); + else + new_value = value; + } + + if (insert_value && insert_value[0]!=0 && insert_value[1]==0) + key = insert_value[0]; + + if (ih->data->mask && iupMaskCheck(ih->data->mask, new_value)==0) + { + if (new_value != value) free(new_value); + XtFree(value); + text->doit = False; /* abort processing */ + return; + } + + if (cb) + { + int cb_ret = cb(ih, key, (char*)new_value); + if (cb_ret==IUP_IGNORE) + text->doit = False; /* abort processing */ + else if (cb_ret==IUP_CLOSE) + { + IupExitLoop(); + text->doit = False; /* abort processing */ + } + else if (cb_ret!=0 && key!=0 && + cb_ret != IUP_DEFAULT && cb_ret != IUP_CONTINUE) + { + insert_value[0] = (char)cb_ret; /* replace key */ + } + } + + if (text->doit) + { + /* Spin is not automatically updated when you directly edit the text */ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox) && !iupAttribGet(ih, "_IUPMOT_SPIN_NOAUTO")) + { + int pos; + if (iupStrToInt(new_value, &pos)) + { + XmTextPosition caret_pos = text->currInsert; + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", "1"); + XtVaSetValues(ih->handle, XmNposition, pos, NULL); + iupAttribSetStr(ih, "_IUPMOT_DISABLE_TEXT_CB", NULL); + /* do not handle all situations, but handle the basic ones */ + if (text->startPos == text->endPos) /* insert */ + caret_pos++; + else if (text->startPos < text->endPos && text->startPos < text->currInsert) /* backspace */ + caret_pos--; + XmTextSetInsertionPosition(ih->handle, caret_pos); + text->doit = False; + } + } + } + + if (new_value != value) free(new_value); + XtFree(value); + (void)w; +} + +static void motTextMotionVerifyCallback(Widget w, Ihandle* ih, XmTextVerifyCallbackStruct* textverify) +{ + int col, lin, pos; + + IFniii cb = (IFniii)IupGetCallback(ih, "CARET_CB"); + if (!cb) return; + + pos = textverify->newInsert; + + if (ih->data->is_multiline) + { + char *value = XmTextGetString(ih->handle); + motTextGetLinColFromPosition(value, pos, &lin, &col); + XtFree(value); + } + else + { + col = pos; + col++; /* IUP starts at 1 */ + lin = 1; + } + + if (pos != ih->data->last_caret_pos) + { + ih->data->last_caret_pos = pos; + cb(ih, lin, col, pos); + } + + (void)w; +} + +static void motTextValueChangedCallback(Widget w, Ihandle* ih, XmAnyCallbackStruct* valuechanged) +{ + if (iupAttribGet(ih, "_IUPMOT_DISABLE_TEXT_CB")) + return; + + iupBaseCallValueChangedCb(ih); + + (void)valuechanged; + (void)w; +} + +static void motTextKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + Widget spinbox; + + *cont = True; + iupmotKeyPressEvent(w, ih, (XEvent*)evt, cont); + if (*cont == False) + return; + + if (evt->state & ControlMask) /* Ctrl */ + { + KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_c) + motTextSetClipboardAttrib(ih, "COPY"); + else if (motcode == XK_x) + motTextSetClipboardAttrib(ih, "CUT"); + else if (motcode == XK_v) + motTextSetClipboardAttrib(ih, "PASTE"); + else if (motcode == XK_a) + XmTextSetSelection(ih->handle, 0, XmTextGetLastPosition(ih->handle), CurrentTime); + } + + spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_Left || motcode == XK_Right) + { + /* avoid spin increment using Left/Right arrows, + but must manually handle the new cursor position */ + XmTextPosition caret_pos = XmTextGetInsertionPosition(ih->handle); + XmTextSetInsertionPosition(ih->handle, (motcode == XK_Left)? caret_pos-1: caret_pos+1); + *cont = False; + } + } +} + + +/******************************************************************************/ + + +static void motTextLayoutUpdateMethod(Ihandle* ih) +{ + Widget spinbox = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + if (spinbox && XmIsSpinBox(spinbox)) + { + XtVaSetValues(ih->handle, + XmNwidth, (XtArgVal)ih->currentwidth-ih->currentheight/2, + XmNheight, (XtArgVal)ih->currentheight, + NULL); + + XtVaSetValues(spinbox, + XmNx, (XtArgVal)ih->x, + XmNy, (XtArgVal)ih->y, + XmNwidth, (XtArgVal)ih->currentwidth, + XmNheight, (XtArgVal)ih->currentheight, + XmNarrowSize, ih->currentheight/2, + NULL); + } + else + iupdrvBaseLayoutUpdateMethod(ih); +} + +static int motTextMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + Widget parent = iupChildTreeGetNativeParentHandle(ih); + char* child_id = iupDialogGetChildIdStr(ih); + int spin = 0; + WidgetClass widget_class = xmTextWidgetClass; + + if (ih->data->is_multiline) + { + Widget sb_win; + int wordwrap = 0; + + if (iupAttribGetBoolean(ih, "WORDWRAP")) + { + wordwrap = 1; + ih->data->sb &= ~IUP_SB_HORIZ; /* must remove the horizontal scroolbar */ + } + + /******************************/ + /* Create the scrolled window */ + /******************************/ + + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAPPLICATION_DEFINED); + iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmSTATIC); /* can NOT be XmAS_NEEDED because XmAPPLICATION_DEFINED */ + iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ + iupmotSetArg(args, num_args, XmNborderWidth, 0); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + sb_win = XtCreateManagedWidget( + child_id, /* child identifier */ + xmScrolledWindowWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!sb_win) + return IUP_ERROR; + + parent = sb_win; + child_id = "text"; + + num_args = 0; + iupmotSetArg(args, num_args, XmNeditMode, XmMULTI_LINE_EDIT); + if (wordwrap) + iupmotSetArg(args, num_args, XmNwordWrap, True); + } + else + { + widget_class = xmTextFieldWidgetClass; + + if (iupAttribGetBoolean(ih, "SPIN")) + { + Widget spinbox; + + num_args = 0; + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between spin and text */ + iupmotSetArg(args, num_args, XmNborderWidth, 0); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNmarginHeight, 0); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNarrowSize, 8); + + if (iupStrEqualNoCase(iupAttribGetStr(ih, "SPINALIGN"), "LEFT")) + iupmotSetArg(args, num_args, XmNarrowLayout, XmARROWS_BEGINNING); + else + iupmotSetArg(args, num_args, XmNarrowLayout, XmARROWS_END); + + spinbox = XtCreateManagedWidget( + child_id, /* child identifier */ + xmSpinBoxWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!spinbox) + return IUP_ERROR; + + XtAddCallback(spinbox, XmNmodifyVerifyCallback, (XtCallbackProc)motTextSpinModifyVerifyCallback, (XtPointer)ih); + + parent = spinbox; + child_id = "text"; + spin = 1; + + if (!iupAttribGetBoolean(ih, "SPINAUTO")) + iupAttribSetStr(ih, "_IUPMOT_SPIN_NOAUTO", "1"); + } + + num_args = 0; + iupmotSetArg(args, num_args, XmNeditMode, XmSINGLE_LINE_EDIT); + + if (spin) + { + /* Spin Constraints */ + iupmotSetArg(args, num_args, XmNspinBoxChildType, XmNUMERIC); + iupmotSetArg(args, num_args, XmNminimumValue, 0); + iupmotSetArg(args, num_args, XmNmaximumValue, 100); + iupmotSetArg(args, num_args, XmNposition, 0); + + if (iupAttribGetBoolean(ih, "SPINWRAP")) + iupmotSetArg(args, num_args, XmNwrap, TRUE); + else + iupmotSetArg(args, num_args, XmNwrap, FALSE); + } + else + { + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + } + } + + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNverifyBell, False); + iupmotSetArg(args, num_args, XmNspacing, 0); + + if (iupAttribGetBoolean(ih, "BORDER")) + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + else + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + if (ih->data->is_multiline) + { + if (ih->data->sb & IUP_SB_HORIZ) + iupmotSetArg(args, num_args, XmNscrollHorizontal, True); + else + iupmotSetArg(args, num_args, XmNscrollHorizontal, False); + + if (ih->data->sb & IUP_SB_VERT) + iupmotSetArg(args, num_args, XmNscrollVertical, True); + else + iupmotSetArg(args, num_args, XmNscrollVertical, False); + } + + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ + widget_class, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + if (ih->data->is_multiline) + { + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent); + XtVaSetValues(parent, XmNworkWindow, ih->handle, NULL); + } + else if (spin) + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent); + + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)motTextKeyPressEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)iupmotButtonPressReleaseEvent, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNmodifyVerifyCallback, (XtCallbackProc)motTextModifyVerifyCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNmotionVerifyCallback, (XtCallbackProc)motTextMotionVerifyCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motTextValueChangedCallback, (XtPointer)ih); + + /* Disable Drag Source */ + iupmotDisableDragSource(ih->handle); + + /* initialize the widget */ + if (ih->data->is_multiline || spin) + XtRealizeWidget(parent); + else + XtRealizeWidget(ih->handle); + + if (IupGetGlobal("_IUP_RESET_TXTCOLORS")) + { + iupmotSetGlobalColorAttrib(ih->handle, XmNbackground, "TXTBGCOLOR"); + iupmotSetGlobalColorAttrib(ih->handle, XmNforeground, "TXTFGCOLOR"); + IupSetGlobal("_IUP_RESET_TXTCOLORS", NULL); + } + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motTextConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTextInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motTextMapMethod; + ic->LayoutUpdate = motTextLayoutUpdateMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTextSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupText only */ + iupClassRegisterAttribute(ic, "PADDING", iupTextGetPaddingAttrib, motTextSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "VALUE", motTextGetValueAttrib, motTextSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTEDTEXT", motTextGetSelectedTextAttrib, motTextSetSelectedTextAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTION", motTextGetSelectionAttrib, motTextSetSelectionAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTIONPOS", motTextGetSelectionPosAttrib, motTextSetSelectionPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARET", motTextGetCaretAttrib, motTextSetCaretAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "CARETPOS", motTextGetCaretPosAttrib, motTextSetCaretPosAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INSERT", NULL, motTextSetInsertAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "APPEND", NULL, motTextSetAppendAttrib, NULL, NULL, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "READONLY", motTextGetReadOnlyAttrib, motTextSetReadOnlyAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "NC", iupTextGetNCAttrib, motTextSetNCAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "CLIPBOARD", NULL, motTextSetClipboardAttrib, NULL, NULL, IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "FORMATTING", NULL, NULL, NULL, NULL, IUPAF_READONLY|IUPAF_NOT_MAPPED|IUPAF_NO_INHERIT); /* formatting not supported in Motif */ + iupClassRegisterAttribute(ic, "SCROLLTO", NULL, motTextSetScrollToAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SCROLLTOPOS", NULL, motTextSetScrollToPosAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMIN", NULL, motTextSetSpinMinAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINMAX", NULL, motTextSetSpinMaxAttrib, IUPAF_SAMEASSYSTEM, "100", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPININC", NULL, motTextSetSpinIncAttrib, IUPAF_SAMEASSYSTEM, "1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPINVALUE", motTextGetSpinValueAttrib, motTextSetSpinValueAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_timer.c b/iup/src/mot/iupmot_timer.c new file mode 100755 index 0000000..d23867e --- /dev/null +++ b/iup/src/mot/iupmot_timer.c @@ -0,0 +1,70 @@ +/** \file + * \brief Timer for the Motif Driver. + * + * See Copyright Notice in "iup.h" + */ + + +#include <stdio.h> +#include <stdlib.h> + +#include <Xm/Xm.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_assert.h" +#include "iup_timer.h" + +#include "iupmot_drv.h" + + +static void motTimerProc(XtPointer client_data, XtIntervalId *id) +{ + Ihandle *ih = (Ihandle*)client_data; + Icallback cb; + (void)id; + + if (!iupObjectCheck(ih)) /* control could be destroyed before timer callback */ + return; + + ih->serial = -1; + /* we have to restart the timer everytime */ + iupdrvTimerRun(ih); + + cb = IupGetCallback(ih, "ACTION_CB"); + if (cb) + { + if (cb(ih)==IUP_CLOSE) + IupExitLoop(); + } +} + +void iupdrvTimerRun(Ihandle *ih) +{ + unsigned int time_ms; + + if (ih->serial > 0) /* timer already started */ + return; + + time_ms = iupAttribGetInt(ih, "TIME"); + if (time_ms > 0) + ih->serial = XtAppAddTimeOut(iupmot_appcontext, time_ms, motTimerProc, (XtPointer)ih); +} + +void iupdrvTimerStop(Ihandle* ih) +{ + if (ih->serial > 0) + { + XtRemoveTimeOut(ih->serial); + ih->serial = -1; + } +} + +void iupdrvTimerInitClass(Iclass* ic) +{ + (void)ic; +} diff --git a/iup/src/mot/iupmot_tips.c b/iup/src/mot/iupmot_tips.c new file mode 100755 index 0000000..25bdbea --- /dev/null +++ b/iup/src/mot/iupmot_tips.c @@ -0,0 +1,226 @@ +/** \file + * \brief Motif Driver TIPS Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/Label.h> + +#include <stdio.h> + +#include "iup.h" + +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvfont.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +/* Default offset from cursor */ +#define TIP_X_OFFSET 12 +#define TIP_Y_OFFSET 12 + +typedef struct _Imottips +{ + Widget Dialog; + Widget Label; + XtIntervalId ShowTimerId; /* Timer: from enterwin to show tip */ + XtIntervalId HideTimerId; /* Timer: from visible to hide tip */ + unsigned long ShowInterval; /* Time for tipPopupTimerId */ + unsigned long HideInterval; /* Time for tipActiveTimerId */ + int Visible; + Ihandle* ih; +} Imottips; + +static Imottips mot_tips = {0, 0, 0, 0, 0, 0}; + +static void motTipsShow(void) +{ + Window root, child; + int cx, cy, x, y; + unsigned int keys; + char* value; + + XQueryPointer(iupmot_display, RootWindow(iupmot_display, iupmot_screen), + &root, &child, &x, &y, &cx, &cy, &keys); + + value = iupAttribGet(mot_tips.ih, "TIPRECT"); + if (value) + { + int x1, x2, y1, y2, wx = x, wy = y; + sscanf(value, "%d %d %d %d", &x1, &y1, &x2, &y2); + iupdrvScreenToClient(mot_tips.ih, &wx, &wy); + if (wx < x1 || wx > x2 || wy < y1 || wy > y2) + { + iupmotTipLeaveNotify(); + return; + } + } + + XtVaSetValues(mot_tips.Dialog, + XmNx, (XtArgVal)(x+TIP_X_OFFSET), + XmNy, (XtArgVal)(y+TIP_Y_OFFSET), + NULL); + + if (mot_tips.Visible) + XRaiseWindow(iupmot_display, XtWindow(mot_tips.Dialog)); + else + XtMapWidget(mot_tips.Dialog); + + mot_tips.ShowTimerId = (XtIntervalId) NULL; + mot_tips.Visible = TRUE; +} + +static void motTipsHide(void) +{ + mot_tips.HideTimerId = (XtIntervalId) NULL; + iupmotTipLeaveNotify(); +} + +static int motTipsSet(Ihandle *ih) +{ + char* tipText = iupAttribGet(ih, "TIP"); + if (!tipText) + return FALSE; + + if (!mot_tips.Dialog) + { + mot_tips.Dialog = XtVaAppCreateShell(" ", "tip", + overrideShellWidgetClass, iupmot_display, + XmNmappedWhenManaged, False, + NULL); + + mot_tips.Label = XtVaCreateManagedWidget("label tip", + xmLabelWidgetClass, mot_tips.Dialog, /* must use IupGetAttribute to use inheritance */ + XmNforeground, iupmotColorGetPixelStr(IupGetAttribute(ih, "TIPFGCOLOR")), + XmNbackground, iupmotColorGetPixelStr(IupGetAttribute(ih, "TIPBGCOLOR")), + NULL); + + XtRealizeWidget(mot_tips.Dialog); + } + + /* set label font */ + { + XmFontList fontlist = (XmFontList)iupmotGetFontListAttrib(ih); + char* value = iupAttribGetStr(ih, "TIPFONT"); + if (value) + { + if (iupStrEqualNoCase(value, "SYSTEM")) + fontlist = NULL; + else + fontlist = iupmotGetFontList(iupAttribGet(ih, "TIPFOUNDRY"), value); + } + + if (fontlist) + XtVaSetValues(mot_tips.Label, XmNfontList, fontlist, NULL); + } + + /* set label contents */ + iupmotSetString(mot_tips.Label, XmNlabelString, tipText); + + /* set label size */ + { + int lw = 0, lh = 0; + iupdrvFontGetMultiLineStringSize(ih, tipText, &lw, &lh); + + /* add room for margin */ + lw += 2*(2); + lh += 2*(2); + + XtVaSetValues(mot_tips.Label, + XmNwidth, (XtArgVal)lw, + XmNheight, (XtArgVal)lh, + NULL); + XtVaSetValues(mot_tips.Dialog, + XmNwidth, (XtArgVal)lw, + XmNheight, (XtArgVal)lh, + NULL); + } + + mot_tips.ShowTimerId = (XtIntervalId) NULL; + mot_tips.HideTimerId = (XtIntervalId) NULL; + mot_tips.Visible = FALSE; + mot_tips.ShowInterval = 500; /* 1/2 second to show */ + + { + int delay = IupGetInt(ih, "TIPDELAY"); /* must use IupGetInt to use inheritance */ + mot_tips.HideInterval = delay + mot_tips.ShowInterval; + } + + return TRUE; +} + +int iupdrvBaseSetTipVisibleAttrib(Ihandle* ih, const char* value) +{ + /* must use IupGetAttribute to use inheritance */ + if (!IupGetAttribute(ih, "TIP")) + return 0; + + if (iupStrBoolean(value)) + iupmotTipEnterNotify(ih); + else + iupmotTipLeaveNotify(); + + return 0; +} + +void iupmotTipEnterNotify(Ihandle *ih) +{ + iupmotTipLeaveNotify(); + + if (motTipsSet(ih) == FALSE) + return; + + mot_tips.ih = ih; + + mot_tips.ShowTimerId = XtAppAddTimeOut( /* EnterWin to Show */ + iupmot_appcontext, + mot_tips.ShowInterval, + (XtTimerCallbackProc)motTipsShow, + NULL); + mot_tips.HideTimerId = XtAppAddTimeOut( /* Visible to Hide */ + iupmot_appcontext, + mot_tips.HideInterval, + (XtTimerCallbackProc)motTipsHide, + NULL); +} + +void iupmotTipLeaveNotify(void) +{ + if (mot_tips.ShowTimerId) + { + XtRemoveTimeOut(mot_tips.ShowTimerId); + mot_tips.ShowTimerId = (XtIntervalId) NULL; + } + if (mot_tips.HideTimerId) + { + XtRemoveTimeOut(mot_tips.HideTimerId); + mot_tips.HideTimerId = (XtIntervalId) NULL; + } + if (mot_tips.Visible) + { + XtUnmapWidget(mot_tips.Dialog); + mot_tips.Visible = FALSE; + } +} + +void iupmotTipsFinish(void) +{ + if (mot_tips.Dialog) + { + XtDestroyWidget(mot_tips.Dialog); + memset(&mot_tips, 0, sizeof(Imottips)); + } +} + +int iupdrvBaseSetTipAttrib(Ihandle* ih, const char* value) +{ + /* implement this stub here because of the other drivers. */ + (void)ih; + (void)value; + return 1; +} diff --git a/iup/src/mot/iupmot_toggle.c b/iup/src/mot/iupmot_toggle.c new file mode 100755 index 0000000..b18f24d --- /dev/null +++ b/iup/src/mot/iupmot_toggle.c @@ -0,0 +1,469 @@ +/** \file + * \brief Toggle Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/ToggleB.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_toggle.h" +#include "iup_drv.h" +#include "iup_image.h" +#include "iup_key.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +void iupdrvToggleAddCheckBox(int *x, int *y) +{ + (*x) += 15+6+3; + if ((*y) < 15+6) (*y) = 12+6; /* minimum height */ + (*y) += 6; +} + + +/*********************************************************************************/ + + +static int motToggleSetBgColorAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_TEXT) + { + char* parent_value = iupAttribGetInheritNativeParent(ih, "BGCOLOR"); + if (!parent_value) + { + /* if not defined at a native parent, + then change the toggle button color to the given color instead using the default */ + if (iupdrvBaseSetBgColorAttrib(ih, value)) /* let XmChangeColor do its job */ + { + parent_value = IupGetGlobal("DLGBGCOLOR"); + XtVaSetValues(ih->handle, XmNbackground, iupmotColorGetPixelStr(parent_value), NULL); /* reset just the background */ + + if (ih->data->radio) + XtVaSetValues(ih->handle, XmNselectColor, iupmotColorGetPixel(0, 0, 0), NULL); + XtVaSetValues(ih->handle, XmNunselectColor, iupmotColorGetPixelStr(value), NULL); + return 1; + } + } + else + { + /* ignore given value, must use only from parent */ + if (iupdrvBaseSetBgColorAttrib(ih, parent_value)) + { + if (ih->data->radio) + XtVaSetValues(ih->handle, XmNselectColor, iupmotColorGetPixel(0, 0, 0), NULL); + XtVaSetValues(ih->handle, XmNunselectColor, iupmotColorGetPixelStr(parent_value), NULL); + return 1; + } + } + return 0; + } + else + return iupdrvBaseSetBgColorAttrib(ih, value); +} + +static int motToggleSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_TEXT) + { + Pixel color; + + /* ignore given value, must use only from parent */ + value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + XtVaSetValues(ih->handle, XmNbackground, color, NULL); + return 1; + } + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL); + return 1; + } + } + } + return 0; +} + +static int motToggleSetTitleAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_TEXT) + { + iupmotSetMnemonicTitle(ih, value); + return 1; + } + + return 0; +} + +static int motToggleSetAlignmentAttrib(Ihandle* ih, const char* value) +{ + unsigned char align; + char value1[30]="", value2[30]=""; + + if (ih->data->type == IUP_TOGGLE_TEXT) + return 0; + + iupStrToStrStr(value, value1, value2, ':'); /* value2 is ignored, NOT supported in Motif */ + + if (iupStrEqualNoCase(value1, "ARIGHT")) + align = XmALIGNMENT_END; + else if (iupStrEqualNoCase(value1, "ACENTER")) + align = XmALIGNMENT_CENTER; + else /* "ALEFT" */ + align = XmALIGNMENT_BEGINNING; + + XtVaSetValues (ih->handle, XmNalignment, align, NULL); + return 1; +} + +static int motToggleSetImageAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelPixmap, 0); + + if (!iupAttribGet(ih, "IMINACTIVE")) + { + /* if not active and IMINACTIVE is not defined + then automaticaly create one based on IMAGE */ + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 1); /* make_inactive */ + } + return 1; + } + else + return 0; +} + +static int motToggleSetImInactiveAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + iupmotSetPixmap(ih, value, XmNlabelInsensitivePixmap, 0); + return 1; + } + else + return 0; +} + +static int motToggleSetImPressAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + iupmotSetPixmap(ih, value, XmNselectPixmap, 0); + return 1; + } + else + return 0; +} + +static int motToggleSetValueAttrib(Ihandle* ih, const char* value) +{ + Ihandle *radio; + unsigned char check; + + if (iupStrEqualNoCase(value,"NOTDEF")) + check = XmINDETERMINATE; + else if (iupStrBoolean(value)) + check = XmSET; + else + check = XmUNSET; + + /* This is necessary because Motif toggle does not have support for radio. + It is implemented using an external RadioBox that we do not use. */ + radio = iupRadioFindToggleParent(ih); + if (radio) + { + Ihandle* last_tg; + unsigned char oldcheck; + + XtVaGetValues(ih->handle, XmNset, &oldcheck, NULL); + + last_tg = (Ihandle*)iupAttribGet(radio, "_IUPMOT_LASTTOGGLE"); + if (check) + { + if (iupObjectCheck(last_tg) && last_tg != ih) + XtVaSetValues(last_tg->handle, XmNset, XmUNSET, NULL); + iupAttribSetStr(radio, "_IUPMOT_LASTTOGGLE", (char*)ih); + } + + if (last_tg != ih && oldcheck != check) + XtVaSetValues(ih->handle, XmNset, check, NULL); + } + else + XtVaSetValues(ih->handle, XmNset, check, NULL); + + return 0; +} + +static char* motToggleGetValueAttrib(Ihandle* ih) +{ + unsigned char check = 0; + XtVaGetValues (ih->handle, XmNset, &check, NULL); + if (check == XmINDETERMINATE) + return "NOTDEF"; + else if (check == XmSET) + return "ON"; + else + return "OFF"; +} + +static int motToggleSetPaddingAttrib(Ihandle* ih, const char* value) +{ + iupStrToIntInt(value, &ih->data->horiz_padding, &ih->data->vert_padding, 'x'); + if (ih->handle && ih->data->type == IUP_TOGGLE_IMAGE) + { + XtVaSetValues(ih->handle, XmNmarginHeight, ih->data->vert_padding, + XmNmarginWidth, ih->data->horiz_padding, NULL); + } + return 0; +} + +static char* motToggleGetSelectColorAttrib(Ihandle* ih) +{ + unsigned char r, g, b; + Pixel color; + char* str = iupStrGetMemory(20); + XtVaGetValues(ih->handle, XmNselectColor, &color, NULL); + iupmotColorGetRGB(color, &r, &g, &b); + sprintf(str, "%d %d %d", (int)r, (int)g, (int)b); + return str; +} + +static int motToggleSetSelectColorAttrib(Ihandle* ih, const char *value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + XtVaSetValues(ih->handle, XmNselectColor, color, NULL); + return 1; +} + +static void motToggleValueChangedCallback(Widget w, Ihandle* ih, XmToggleButtonCallbackStruct* call_data) +{ + Ihandle *radio; + IFni cb; + int check = call_data->set; + + /* Must manually hide the tip if the toggle is pressed. */ + iupmotTipLeaveNotify(); + + /* This is necessary because Motif toggle does not have support for radio. + It is implemented using an external RadioBox that we do not use. */ + radio = iupRadioFindToggleParent(ih); + if (radio) + { + if (check) + { + Ihandle* last_tg = (Ihandle*)iupAttribGet(radio, "_IUPMOT_LASTTOGGLE"); + if (iupObjectCheck(last_tg) && last_tg != ih) + { + /* uncheck last toggle */ + XtVaSetValues(last_tg->handle, XmNset, XmUNSET, NULL); + + cb = (IFni) IupGetCallback(last_tg, "ACTION"); + if (cb && cb(last_tg, 0) == IUP_CLOSE) + IupExitLoop(); + + iupBaseCallValueChangedCb(last_tg); + } + iupAttribSetStr(radio, "_IUPMOT_LASTTOGGLE", (char*)ih); + + if (last_tg != ih) + { + cb = (IFni)IupGetCallback(ih, "ACTION"); + if (cb && cb (ih, 1) == IUP_CLOSE) + IupExitLoop(); + + iupBaseCallValueChangedCb(ih); + } + } + else + { + /* Force stay checked */ + XtVaSetValues(ih->handle, XmNset, XmSET, NULL); + } + } + else + { + if (check == XmINDETERMINATE) + check = -1; + + cb = (IFni)IupGetCallback(ih, "ACTION"); + if (cb) + { + if (cb(ih, check) == IUP_CLOSE) + IupExitLoop(); + } + + iupBaseCallValueChangedCb(ih); + } + + (void)w; +} + +static int motToggleMapMethod(Ihandle* ih) +{ + Ihandle* radio = iupRadioFindToggleParent(ih); + char* value; + int num_args = 0; + Arg args[40]; + + if (radio) + ih->data->radio = 1; + + value = iupAttribGet(ih, "IMAGE"); + if (value) + { + ih->data->type = IUP_TOGGLE_IMAGE; + iupmotSetArg(args, num_args, XmNlabelType, XmPIXMAP); + } + else + { + ih->data->type = IUP_TOGGLE_TEXT; + iupmotSetArg(args, num_args, XmNlabelType, XmSTRING); + } + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + /* Label */ + iupmotSetArg(args, num_args, XmNrecomputeSize, False); /* no automatic resize from text */ + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNmarginTop, 0); /* no extra margins */ + iupmotSetArg(args, num_args, XmNmarginLeft, 0); + iupmotSetArg(args, num_args, XmNmarginBottom, 0); + iupmotSetArg(args, num_args, XmNmarginRight, 0); + + if (radio) + { + iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); + iupmotSetArg(args, num_args, XmNindicatorType, XmONE_OF_MANY_ROUND); + + if (!iupAttribGet(radio, "_IUPMOT_LASTTOGGLE")) + { + /* this is the first toggle in the radio, and the last toggle with VALUE=ON */ + iupAttribSetStr(ih, "VALUE","ON"); + } + } + else + { + if (ih->data->type == IUP_TOGGLE_TEXT && iupAttribGetBoolean(ih, "3STATE")) + iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_INDETERMINATE); + else + iupmotSetArg(args, num_args, XmNtoggleMode, XmTOGGLE_BOOLEAN); + iupmotSetArg(args, num_args, XmNindicatorType, XmN_OF_MANY); + } + + if (ih->data->type == IUP_TOGGLE_IMAGE) + { + iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_NONE); + iupmotSetArg(args, num_args, XmNalignment, XmALIGNMENT_CENTER); + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + } + else + { + iupmotSetArg(args, num_args, XmNspacing, 3); + iupmotSetArg(args, num_args, XmNindicatorOn, XmINDICATOR_CHECK_BOX); + iupmotSetArg(args, num_args, XmNalignment, XmALIGNMENT_BEGINNING); + if (radio) + { + iupmotSetArg(args, num_args, XmNindicatorSize, 13); + iupmotSetArg(args, num_args, XmNselectColor, iupmotColorGetPixel(0, 0, 0)); + } + else + iupmotSetArg(args, num_args, XmNindicatorSize, 15); + + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNdetailShadowThickness, 2); + } + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmToggleButtonWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); + + XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motToggleValueChangedCallback, (XtPointer)ih); + + /* Disable Drag Source */ + iupmotDisableDragSource(ih->handle); + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + if (ih->data->type == IUP_TOGGLE_TEXT) + iupmotSetString(ih->handle, XmNlabelString, ""); + + return IUP_NOERROR; +} + +void iupdrvToggleInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motToggleMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Overwrite Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", iupmotGetBgColorAttrib, motToggleSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motToggleSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, iupdrvBaseSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGFGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "TITLE", NULL, motToggleSetTitleAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupToggle only */ + iupClassRegisterAttribute(ic, "ALIGNMENT", NULL, motToggleSetAlignmentAttrib, IUPAF_SAMEASSYSTEM, "ACENTER:ACENTER", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGE", NULL, motToggleSetImageAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMINACTIVE", NULL, motToggleSetImInactiveAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMPRESS", NULL, motToggleSetImPressAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "VALUE", motToggleGetValueAttrib, motToggleSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SELECTCOLOR", motToggleGetSelectColorAttrib, motToggleSetSelectColorAttrib, NULL, NULL, IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "PADDING", iupToggleGetPaddingAttrib, motToggleSetPaddingAttrib, IUPAF_SAMEASSYSTEM, "0x0", IUPAF_NOT_MAPPED); +} diff --git a/iup/src/mot/iupmot_tree.c b/iup/src/mot/iupmot_tree.c new file mode 100755 index 0000000..eb230af --- /dev/null +++ b/iup/src/mot/iupmot_tree.c @@ -0,0 +1,2848 @@ +#include <Xm/Xm.h> +#include <Xm/Form.h> +#include <Xm/Container.h> +#include <Xm/IconG.h> +#include <Xm/ScrolledW.h> +#include <Xm/XmosP.h> +#include <Xm/Text.h> +#include <Xm/Transfer.h> +#include <Xm/DragDrop.h> +#include <X11/keysym.h> + +#include <sys/stat.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> +#include <time.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_dialog.h" +#include "iup_layout.h" +#include "iup_attrib.h" +#include "iup_str.h" +#include "iup_drv.h" +#include "iup_drvinfo.h" +#include "iup_drvfont.h" +#include "iup_stdcontrols.h" +#include "iup_key.h" +#include "iup_image.h" +#include "iup_array.h" +#include "iup_tree.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +typedef struct _motTreeItemData +{ + Pixmap image, image_mask; + Pixmap image_expanded, image_expanded_mask; + unsigned char kind; + void* userdata; +} motTreeItemData; + + +static void motTreeShowEditField(Ihandle* ih, Widget wItem); +static int motTreeGetNodeId(Ihandle* ih, Widget wItem); + +typedef int (*motTreeNodeFunc)(Ihandle* ih, Widget wItem, void* userdata); + +static int motTreeForEach(Ihandle* ih, Widget wItem, motTreeNodeFunc func, void* userdata) +{ + WidgetList wItemChildList = NULL; + int i, numChild; + + if (!wItem) + wItem = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + if (!func(ih, wItem, userdata)) + return 0; + + numChild = XmContainerGetItemChildren(ih->handle, wItem, &wItemChildList); + for (i=0; i<numChild; i++) + { + /* Recursively traverse child items */ + if (!motTreeForEach(ih, wItemChildList[i], func, userdata)) + { + XtFree((char*)wItemChildList); + return 0; + } + } + if (wItemChildList) XtFree((char*)wItemChildList); + + return 1; +} + +/*****************************************************************************/ +/* COPYING ITEMS (Branches and its children) */ +/*****************************************************************************/ +/* Insert the copied item in a new location. Returns the new item. */ +static Widget motTreeCopyItem(Ihandle* ih, Widget wItem, Widget wParent, int pos, int full_copy) +{ + Widget wNewItem; + XmString title; + motTreeItemData *itemData; + Pixel fgcolor, bgcolor; + int num_args = 0; + Arg args[30]; + Pixmap image = XmUNSPECIFIED_PIXMAP, mask = XmUNSPECIFIED_PIXMAP; + unsigned char state; + + iupmotSetArg(args, num_args, XmNentryParent, wParent); + iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + /* Get values to copy */ + XtVaGetValues(wItem, XmNlabelString, &title, + XmNuserData, &itemData, + XmNforeground, &fgcolor, + XmNsmallIconPixmap, &image, + XmNsmallIconMask, &mask, + XmNoutlineState, &state, + NULL); + + if (full_copy) /* during a full copy the userdata reference is not copied */ + { + /* create a new one */ + motTreeItemData* itemDataNew = malloc(sizeof(motTreeItemData)); + memcpy(itemDataNew, itemData, sizeof(motTreeItemData)); + itemDataNew->userdata = NULL; + itemData = itemDataNew; + } + + iupmotSetArg(args, num_args, XmNlabelString, title); + iupmotSetArg(args, num_args, XmNuserData, itemData); + iupmotSetArg(args, num_args, XmNforeground, fgcolor); + iupmotSetArg(args, num_args, XmNsmallIconPixmap, image); + iupmotSetArg(args, num_args, XmNsmallIconMask, mask); + iupmotSetArg(args, num_args, XmNoutlineState, state); + + iupmotSetArg(args, num_args, XmNentryParent, wParent); + iupmotSetArg(args, num_args, XmNpositionIndex, pos); + + XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); + iupmotSetArg(args, num_args, XmNbackground, bgcolor); + + wNewItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); + + /* Root always expanded */ + XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); + + XtRealizeWidget(wNewItem); + + return wNewItem; +} + +static void motTreeCopyChildren(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int full_copy) +{ + WidgetList wItemChildList = NULL; + int i = 0; + int numChild = XmContainerGetItemChildren(ih->handle, wItemSrc, &wItemChildList); + while(i != numChild) + { + Widget wNewItem = motTreeCopyItem(ih, wItemChildList[i], wItemDst, i, full_copy); /* Use the same order they where enumerated */ + + /* Recursively transfer all the items */ + motTreeCopyChildren(ih, wItemChildList[i], wNewItem, full_copy); + + /* Go to next sibling item */ + i++; + } + + if (wItemChildList) XtFree((char*)wItemChildList); +} + +/* Copies all items in a branch to a new location. Returns the new branch node. */ +static Widget motTreeCopyNode(Ihandle* ih, Widget wItemSrc, Widget wItemDst, int full_copy) +{ + Widget wNewItem, wParent; + motTreeItemData *itemDataDst; + unsigned char stateDst; + int pos; + + XtVaGetValues(wItemDst, XmNoutlineState, &stateDst, + XmNuserData, &itemDataDst, + NULL); + + if (itemDataDst->kind == ITREE_BRANCH && stateDst == XmEXPANDED) + { + /* copy as first child of expanded branch */ + wParent = wItemDst; + pos = 0; + } + else + { + /* copy as next brother of item or collapsed branch */ + XtVaGetValues(wItemDst, XmNentryParent, &wParent, NULL); + XtVaGetValues(wItemDst, XmNpositionIndex, &pos, NULL); + pos++; + } + + wNewItem = motTreeCopyItem(ih, wItemSrc, wParent, pos, full_copy); + + motTreeCopyChildren(ih, wItemSrc, wNewItem, full_copy); + + return wNewItem; +} + +static void motTreeContainerDeselectAll(Ihandle *ih) +{ + XKeyEvent ev; + + memset(&ev, 0, sizeof(XKeyEvent)); + ev.type = KeyPress; + ev.display = XtDisplay(ih->handle); + ev.send_event = True; + ev.root = RootWindow(iupmot_display, iupmot_screen); + ev.time = clock()*CLOCKS_PER_SEC; + ev.window = XtWindow(ih->handle); + ev.state = ControlMask; + ev.keycode = XK_backslash; + ev.same_screen = True; + + XtCallActionProc(ih->handle, "ContainerDeselectAll", (XEvent*)&ev, 0, 0); +} + +static void motTreeContainerSelectAll(Ihandle *ih) +{ + XKeyEvent ev; + + memset(&ev, 0, sizeof(XKeyEvent)); + ev.type = KeyPress; + ev.display = XtDisplay(ih->handle); + ev.send_event = True; + ev.root = RootWindow(iupmot_display, iupmot_screen); + ev.time = clock()*CLOCKS_PER_SEC; + ev.window = XtWindow(ih->handle); + ev.state = ControlMask; + ev.keycode = XK_slash; + ev.same_screen = True; + + XtCallActionProc(ih->handle, "ContainerSelectAll", (XEvent*)&ev, 0, 0); +} + +static Widget motTreeGetLastVisibleNode(Ihandle* ih, Widget wItem) +{ + unsigned char itemState; + + XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); + + if (itemState == XmEXPANDED) + { + WidgetList wChildrenTree = NULL; + int numChildren = XmContainerGetItemChildren(ih->handle, wItem, &wChildrenTree); + if(numChildren) + wItem = motTreeGetLastVisibleNode(ih, wChildrenTree[numChildren - 1]); + if (wChildrenTree) XtFree((char*)wChildrenTree); + } + + return wItem; +} + +static Widget motTreeFindVisibleNodeId(Ihandle* ih, WidgetList itemList, int numItems, Widget itemNode) +{ + Widget itemChild; + WidgetList itemChildList; + int i = 0; + int numChild; + unsigned char itemState; + + while(i != numItems) + { + /* ID control to traverse items */ + ih->data->id_control++; /* not the real id since it counts only the visible ones */ + + /* StateID founded! */ + if(itemList[i] == itemNode) + return itemList[i]; + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); + + /* The itemWidget has child and it is expanded (visible) */ + if (numChild && itemState == XmEXPANDED) + { + /* pass the list of children of this item */ + itemChild = motTreeFindVisibleNodeId(ih, itemChildList, numChild, itemNode); + + /* StateID founded! */ + if(itemChild) + { + XtFree((char*)itemChildList); + return itemChild; + } + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } + + return NULL; +} + +static Widget motTreeFindVisibleNodeFromId(Ihandle* ih, WidgetList itemList, int numItems) +{ + Widget itemChild; + WidgetList itemChildList; + int i = 0; + int numChild; + unsigned char itemState; + + while(i != numItems) + { + /* ID control to traverse items */ + ih->data->id_control--; /* not the real id since it counts only the visible ones */ + + /* StateID founded! */ + if(ih->data->id_control < 0) + return itemList[i]; + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); + + /* The itemWidget has child and it is expanded (visible) */ + if (numChild && itemState == XmEXPANDED) + { + /* pass the list of children of this item */ + itemChild = motTreeFindVisibleNodeFromId(ih, itemChildList, numChild); + + /* StateID founded! */ + if(ih->data->id_control < 0) + { + if (itemChildList) XtFree((char*)itemChildList); + return itemChild; + } + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } + + return NULL; +} + +static Widget motTreeGetNextVisibleNode(Ihandle* ih, Widget wRoot, Widget wItem) +{ + Widget wNext; + + ih->data->id_control = -1; + motTreeFindVisibleNodeId(ih, &wRoot, 1, wItem); + ih->data->id_control++; /* more 1 visible node */ + + wNext = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); + + if (ih->data->id_control >= 0) + wNext = motTreeGetLastVisibleNode(ih, wRoot); + + return wNext; +} + +static Widget motTreeGetPreviousVisibleNode(Ihandle* ih, Widget wRoot, Widget wItem) +{ + ih->data->id_control = -1; + motTreeFindVisibleNodeId(ih, &wRoot, 1, wItem); + ih->data->id_control--; /* less 1 visible node */ + + if (ih->data->id_control < 0) + ih->data->id_control = 0; /* Begin of tree = Root id */ + + return motTreeFindVisibleNodeFromId(ih, &wRoot, 1); +} + +static void motTreeUpdateBgColor(Ihandle* ih, WidgetList itemList, int numItems, Pixel bgcolor) +{ + WidgetList itemChildList; + int i = 0; + int numChild; + + while(i != numItems) + { + XtVaSetValues(itemList[i], XmNbackground, bgcolor, NULL); + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + if(numChild) + motTreeUpdateBgColor(ih, itemChildList, numChild, bgcolor); + if (itemChildList) XtFree((char*)itemChildList); + + /* Go to next sibling item */ + i++; + } +} + +static void motTreeUpdateImages(Ihandle* ih, WidgetList itemList, int numItems, int mode) +{ + motTreeItemData *itemData; + int i = 0; + + /* called when one of the default images is changed */ + + while(i != numItems) + { + /* Get node attributes */ + XtVaGetValues(itemList[i], XmNuserData, &itemData, NULL); + + if (itemData->kind == ITREE_BRANCH) + { + unsigned char itemState; + XtVaGetValues(itemList[i], XmNoutlineState, &itemState, NULL); + + if (itemState == XmEXPANDED) + { + if (mode == ITREE_UPDATEIMAGE_EXPANDED) + { + XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image_expanded!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded: (Pixmap)ih->data->def_image_expanded, NULL); + XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_expanded_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded_mask: (Pixmap)ih->data->def_image_expanded_mask, NULL); + } + } + else + { + if (mode == ITREE_UPDATEIMAGE_COLLAPSED) + { + XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_collapsed, NULL); + XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_collapsed_mask, NULL); + } + } + + /* Recursively traverse child items */ + { + WidgetList itemChildList; + int numChild; + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + motTreeUpdateImages(ih, itemChildList, numChild, mode); + if (itemChildList) XtFree((char*)itemChildList); + } + } + else + { + if (mode == ITREE_UPDATEIMAGE_LEAF) + { + XtVaSetValues(itemList[i], XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_leaf, NULL); + XtVaSetValues(itemList[i], XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_leaf_mask, NULL); + } + } + + /* Go to next sibling node */ + i++; + } +} + +static int motTreeSelectFunc(Ihandle* ih, Widget wItem, int *select) +{ + int do_select = *select; + if (do_select == -1) + { + unsigned char isSelected; + XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); + do_select = (isSelected == XmSELECTED)? 0: 1; /* toggle */ + } + + if (do_select) + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + else + XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + + (void)ih; + return 1; +} + +static void motTreeInvertAllNodeMarking(Ihandle* ih) +{ + int select = -1; + motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSelectFunc, &select); +} + +typedef struct _motTreeRange{ + Widget wItem1, wItem2; + char inside, clear; +}motTreeRange; + +static int motTreeSelectRangeFunc(Ihandle* ih, Widget wItem, motTreeRange* range) +{ + int end_range = 0; + + if (range->inside == 0) /* detect the range start */ + { + if (range->wItem1 == wItem) range->inside=1; + else if (range->wItem2 == wItem) range->inside=1; + } + else if (range->inside == 1) /* detect the range end */ + { + if (range->wItem1 == wItem) end_range=1; + else if (range->wItem2 == wItem) end_range=1; + } + + if (range->inside == 1) /* if inside, select */ + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + else if (range->clear) /* if outside and clear, unselect */ + XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + + if (end_range || (range->inside && range->wItem1==range->wItem2)) + range->inside=-1; /* update after selecting the node */ + + (void)ih; + return 1; +} + +static void motTreeSelectRange(Ihandle* ih, Widget wItem1, Widget wItem2, int clear) +{ + motTreeRange range; + range.wItem1 = wItem1; + range.wItem2 = wItem2; + range.inside = 0; + range.clear = (char)clear; + motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSelectRangeFunc, &range); +} + +void motTreeExpandCollapseAllNodes(Ihandle* ih, WidgetList itemList, int numItems, unsigned char itemState) +{ + WidgetList itemChildList; + int numChild; + int i = 0; + + while(i != numItems) + { + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + + if(numChild) + { + XtVaSetValues(itemList[i], XmNoutlineState, itemState, NULL); + motTreeExpandCollapseAllNodes(ih, itemChildList, numChild, itemState); + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } +} + +static void motTreeDestroyItemData(Ihandle* ih, Widget wItem) +{ + motTreeItemData *itemData = NULL; + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + if (itemData) + { + IFnis cb = (IFnis)IupGetCallback(ih, "NODEREMOVED_CB"); + if (cb) cb(ih, motTreeGetNodeId(ih, wItem), (char*)itemData->userdata); + free(itemData); + XtVaSetValues(wItem, XmNuserData, NULL, NULL); + } +} + +static void motTreeRemoveChildren(Ihandle* ih, WidgetList itemList, int numItems, int del_userdata) +{ + WidgetList itemChildList; + int numChild; + int i = 0; + + while(i != numItems) + { + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + if (numChild) + motTreeRemoveChildren(ih, itemChildList, numChild, del_userdata); + + if (del_userdata) + motTreeDestroyItemData(ih, itemList[i]); + + XtDestroyWidget(itemList[i]); + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } +} + +static void motTreeRemoveNode(Ihandle* ih, Widget wItem, int del_userdata) +{ + WidgetList wChildList = NULL; + int numChild = XmContainerGetItemChildren(ih->handle, wItem, &wChildList); + if (numChild) + motTreeRemoveChildren(ih, wChildList, numChild, del_userdata); + if (del_userdata) + motTreeDestroyItemData(ih, wItem); + XtDestroyWidget(wItem); + if (wChildList) XtFree((char*)wChildList); +} + +static Widget motTreeFindNodeID(Ihandle* ih, WidgetList itemList, int numItems, Widget itemNode) +{ + Widget itemChild; + WidgetList itemChildList; + int i = 0; + int numChild; + + while(i != numItems) + { + /* ID control to traverse items */ + ih->data->id_control++; + + /* StateID founded! */ + if(itemList[i] == itemNode) + return itemList[i]; + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + if(numChild) + { + /* pass the list of children of this item */ + itemChild = motTreeFindNodeID(ih, itemChildList, numChild, itemNode); + + /* StateID founded! */ + if(itemChild) + { + if (itemChildList) XtFree((char*)itemChildList); + return itemChild; + } + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } + + return NULL; +} + +static Widget motTreeFindNodeFromID(Ihandle* ih, WidgetList itemList, int numItems) +{ + Widget itemChild; + WidgetList itemChildList; + int i = 0; + int numChild; + + while(i != numItems) + { + /* ID control to traverse items */ + ih->data->id_control--; + + /* StateID founded! */ + if(ih->data->id_control < 0) + return itemList[i]; + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + if(numChild) + { + /* pass the list of children of this item */ + itemChild = motTreeFindNodeFromID(ih, itemChildList, numChild); + + /* StateID founded! */ + if(ih->data->id_control < 0) + { + if (itemChildList) XtFree((char*)itemChildList); + return itemChild; + } + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } + + return NULL; +} + +static int motTreeGetNodeId(Ihandle* ih, Widget wItem) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->id_control = -1; + if (motTreeFindNodeID(ih, &wRoot, 1, wItem)) + return ih->data->id_control; + else + return -1; +} + +static Widget motTreeFindUserDataID(Ihandle* ih, WidgetList itemList, int numItems, void* userdata) +{ + Widget itemChild; + WidgetList itemChildList; + motTreeItemData *itemData; + int i = 0; + int numChild; + + while(i != numItems) + { + /* ID control to traverse items */ + ih->data->id_control++; + + XtVaGetValues(itemList[i], XmNuserData, &itemData, NULL); + + /* StateID founded! */ + if(itemData->userdata == userdata) + return itemList[i]; + + /* Check whether we have child items */ + itemChildList = NULL; + numChild = XmContainerGetItemChildren(ih->handle, itemList[i], &itemChildList); + if(numChild) + { + /* pass the list of children of this item */ + itemChild = motTreeFindUserDataID(ih, itemChildList, numChild, userdata); + + /* StateID founded! */ + if (itemChild) + { + if (itemChildList) XtFree((char*)itemChildList); + return itemChild; + } + } + + if (itemChildList) XtFree((char*)itemChildList); + /* Go to next sibling item */ + i++; + } + + return NULL; +} + +static int motTreeGetUserDataId(Ihandle* ih, void* userdata) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->id_control = -1; + if (motTreeFindUserDataID(ih, &wRoot, 1, userdata)) + return ih->data->id_control; + else + return -1; +} + +static void motTreeSetFocusNode(Ihandle* ih, Widget wItem) +{ + iupAttribSetStr(ih, "_IUPTREE_LAST_FOCUS", (char*)wItem); + XmProcessTraversal(wItem, XmTRAVERSE_CURRENT); +} + +static Widget motTreeGetFocusNode(Ihandle* ih) +{ + Widget wItem = XmGetFocusWidget(ih->handle); /* returns the focus in the dialog */ + if (wItem && XtParent(wItem) == ih->handle) /* is a node */ + return wItem; + + return (Widget)iupAttribGet(ih, "_IUPTREE_LAST_FOCUS"); +} + +static Widget motTreeFindNodeFromString(Ihandle* ih, const char* name_id) +{ + if (name_id[0]) + { + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + iupStrToInt(name_id, &ih->data->id_control); + return motTreeFindNodeFromID(ih, &wRoot, 1); + } + else + return motTreeGetFocusNode(ih); +} + +static void motTreeEnterLeaveWindowEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + if (iupAttribGet(ih, "_IUPTREE_EDITFIELD")) + return; + + /* usually when one Gadget is selected different than the previous one, + leave/enter events are generated. But we could not find the exact condition, + so this is a workaround. Some leave events will be lost. */ + if (evt->type == EnterNotify) + { + if (iupAttribGet(ih, "_IUPTREE_IGNORE_ENTERLEAVE")) + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_ENTERLEAVE", NULL); + return; + } + } + else if (evt->type == LeaveNotify) + { + if (iupAttribGet(ih, "_IUPTREE_IGNORE_ENTERLEAVE")) + return; + } + + iupmotEnterLeaveWindowEvent(w, ih, evt, cont); +} + +static void motTreeFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + unsigned char selpol; + Widget wItem = XmGetFocusWidget(w); /* returns the focus in the dialog */ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + if (XtParent(wItem) == w) /* is a node */ + iupAttribSetStr(ih, "_IUPTREE_LAST_FOCUS", (char*)wItem); + + if (wItem == NULL || wItem == wRoot) + { + iupmotFocusChangeEvent(w, ih, evt, cont); + return; + } + + XtVaGetValues(w, XmNselectionPolicy, &selpol, NULL); + if (selpol != XmSINGLE_SELECT) + return; + + if (evt->type == FocusIn && !iupStrBoolean(IupGetGlobal("CONTROLKEY"))) + { + XtVaSetValues(w, XmNselectedObjects, NULL, NULL); + XtVaSetValues(w, XmNselectedObjectCount, 0, NULL); + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } +} + +void iupdrvTreeAddNode(Ihandle* ih, const char* name_id, int kind, const char* title, int add) +{ + Widget wItemPrev = motTreeFindNodeFromString(ih, name_id); + Widget wNewItem; + XmString itemTitle; + motTreeItemData *itemData, *itemDataPrev; + Pixel bgcolor, fgcolor; + int kindPrev, num_args = 0; + Arg args[30]; + + if (!wItemPrev) + return; + + itemData = calloc(1, sizeof(motTreeItemData)); + itemData->image = XmUNSPECIFIED_PIXMAP; + itemData->image_expanded = XmUNSPECIFIED_PIXMAP; + itemData->image_mask = XmUNSPECIFIED_PIXMAP; + itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP; + itemData->kind = (unsigned char)kind; + + itemTitle = XmStringCreateLocalized((String)title); + + /* Get default colors */ + XtVaGetValues(ih->handle, XmNforeground, &fgcolor, NULL); + XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); + + /* Get the kind of previous item */ + XtVaGetValues(wItemPrev, XmNuserData, &itemDataPrev, NULL); + kindPrev = itemDataPrev->kind; + + if (kindPrev == ITREE_BRANCH && add) + { + /* wItemPrev is parent of the new item (firstchild of it) */ + iupmotSetArg(args, num_args, XmNentryParent, wItemPrev); + iupmotSetArg(args, num_args, XmNpositionIndex, 0); + } + else + { + /* wItemPrev is sibling of the new item (set its parent to the new item) */ + Widget wItemParent; + int pos; + + XtVaGetValues(wItemPrev, XmNentryParent, &wItemParent, NULL); + XtVaGetValues(wItemPrev, XmNpositionIndex, &pos, NULL); + + iupmotSetArg(args, num_args, XmNentryParent, wItemParent); + iupmotSetArg(args, num_args, XmNpositionIndex, pos+1); + } + + iupmotSetArg(args, num_args, XmNuserData, itemData); + iupmotSetArg(args, num_args, XmNforeground, fgcolor); + iupmotSetArg(args, num_args, XmNbackground, bgcolor); + iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNlabelString, itemTitle); + + if (kind == ITREE_BRANCH) + { + if (ih->data->add_expanded) + { + iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_expanded); + iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_expanded_mask); + } + else + { + iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_collapsed); + iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_collapsed_mask); + } + } + else + { + iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_leaf); + iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_leaf_mask); + } + + + wNewItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); + + if (kind == ITREE_BRANCH) + { + if (ih->data->add_expanded) + { + iupAttribSetStr(ih, "_IUP_IGNORE_BRANCHOPEN", "1"); + XtVaSetValues(wNewItem, XmNoutlineState, XmEXPANDED, NULL); + } + else + XtVaSetValues(wNewItem, XmNoutlineState, XmCOLLAPSED, NULL); + } + + /* Root always expanded */ + XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); + + XtRealizeWidget(wNewItem); + XmStringFree(itemTitle); +} + +static void motTreeAddRootNode(Ihandle* ih) +{ + Widget wRootItem; + motTreeItemData *itemData; + Pixel bgcolor, fgcolor; + int num_args = 0; + Arg args[30]; + + itemData = calloc(1, sizeof(motTreeItemData)); + itemData->image = XmUNSPECIFIED_PIXMAP; + itemData->image_expanded = XmUNSPECIFIED_PIXMAP; + itemData->image_mask = XmUNSPECIFIED_PIXMAP; + itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP; + itemData->kind = ITREE_BRANCH; + + /* Get default foreground color */ + XtVaGetValues(ih->handle, XmNforeground, &fgcolor, NULL); + XtVaGetValues(ih->handle, XmNbackground, &bgcolor, NULL); + + iupmotSetArg(args, num_args, XmNentryParent, NULL); + iupmotSetArg(args, num_args, XmNuserData, itemData); + iupmotSetArg(args, num_args, XmNforeground, fgcolor); + iupmotSetArg(args, num_args, XmNbackground, bgcolor); + iupmotSetArg(args, num_args, XmNoutlineState, XmEXPANDED); + iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNviewType, XmSMALL_ICON); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNtraversalOn, True); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + iupmotSetArg(args, num_args, XmNsmallIconPixmap, ih->data->def_image_expanded); + iupmotSetArg(args, num_args, XmNsmallIconMask, ih->data->def_image_expanded_mask); + + wRootItem = XtCreateManagedWidget("icon", xmIconGadgetClass, ih->handle, args, num_args); + + /* Select the new item */ + XtVaSetValues(wRootItem, XmNvisualEmphasis, XmSELECTED, NULL); + + XtRealizeWidget(wRootItem); + + /* Save the root node for later use */ + iupAttribSetStr(ih, "_IUPTREE_ROOTITEM", (char*)wRootItem); + + /* MarkStart node */ + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)wRootItem); + + /* Set the default VALUE */ + /* In Motif this will set also the current focus */ + motTreeSetFocusNode(ih, wRootItem); +} + +/*****************************************************************************/ + +static int motTreeSetImageExpandedAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + motTreeItemData *itemData; + unsigned char itemState; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); + itemData->image_expanded = (Pixmap)iupImageGetImage(value, ih, 0); + if (!itemData->image_expanded) + { + itemData->image_expanded = XmUNSPECIFIED_PIXMAP; + itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP; + } + else + { + itemData->image_expanded_mask = (Pixmap)iupImageGetMask(value); + if (!itemData->image_expanded_mask) itemData->image_expanded_mask = XmUNSPECIFIED_PIXMAP; + } + + if (itemData->kind == ITREE_BRANCH && itemState == XmEXPANDED) + { + if (itemData->image_expanded == XmUNSPECIFIED_PIXMAP) + XtVaSetValues(wItem, XmNsmallIconPixmap, (Pixmap)ih->data->def_image_expanded, + XmNsmallIconMask, (Pixmap)ih->data->def_image_expanded_mask, + NULL); + else + XtVaSetValues(wItem, XmNsmallIconPixmap, itemData->image_expanded, + XmNsmallIconMask, itemData->image_expanded_mask, + NULL); + } + + return 1; +} + +static int motTreeSetImageAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + motTreeItemData *itemData; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + itemData->image = (Pixmap)iupImageGetImage(value, ih, 0); + if (!itemData->image) + { + itemData->image = XmUNSPECIFIED_PIXMAP; + itemData->image_mask = XmUNSPECIFIED_PIXMAP; + } + else + { + itemData->image_mask = (Pixmap)iupImageGetMask(value); + if (!itemData->image_mask) itemData->image_mask = XmUNSPECIFIED_PIXMAP; + } + + if (itemData->kind == ITREE_BRANCH) + { + unsigned char itemState; + XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); + if (itemState == XmCOLLAPSED) + { + if (itemData->image == XmUNSPECIFIED_PIXMAP) + XtVaSetValues(wItem, XmNsmallIconPixmap, (Pixmap)ih->data->def_image_collapsed, + XmNsmallIconMask, (Pixmap)ih->data->def_image_collapsed_mask, + NULL); + else + XtVaSetValues(wItem, XmNsmallIconPixmap, itemData->image, + XmNsmallIconMask, itemData->image_mask, + NULL); + } + } + else + { + if (itemData->image == XmUNSPECIFIED_PIXMAP) + XtVaSetValues(wItem, XmNsmallIconPixmap, (Pixmap)ih->data->def_image_leaf, + XmNsmallIconMask, (Pixmap)ih->data->def_image_leaf_mask, + NULL); + else + XtVaSetValues(wItem, XmNsmallIconPixmap, itemData->image, + XmNsmallIconMask, itemData->image_mask, + NULL); + } + + return 1; +} + +static int motTreeSetImageBranchExpandedAttrib(Ihandle* ih, const char* value) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->def_image_expanded = iupImageGetImage(value, ih, 0); + if (!ih->data->def_image_expanded) + { + ih->data->def_image_expanded = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_expanded_mask = iupImageGetMask(value); + if (!ih->data->def_image_expanded_mask) ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + /* Update all images, starting at root node */ + motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_EXPANDED); + + return 1; +} + +static int motTreeSetImageBranchCollapsedAttrib(Ihandle* ih, const char* value) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->def_image_collapsed = iupImageGetImage(value, ih, 0); + if (!ih->data->def_image_collapsed) + { + ih->data->def_image_collapsed = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_collapsed_mask = iupImageGetMask(value); + if (!ih->data->def_image_collapsed_mask) ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + /* Update all images, starting at root node */ + motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_COLLAPSED); + + return 1; +} + +static int motTreeSetImageLeafAttrib(Ihandle* ih, const char* value) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + ih->data->def_image_leaf = iupImageGetImage(value, ih, 0); + if (!ih->data->def_image_leaf) + { + ih->data->def_image_leaf = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_leaf_mask = iupImageGetMask(value); + if (!ih->data->def_image_leaf_mask) ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + /* Update all images, starting at root node */ + motTreeUpdateImages(ih, &wRoot, 1, ITREE_UPDATEIMAGE_LEAF); + + return 1; +} + +static char* motTreeGetStateAttrib(Ihandle* ih, const char* name_id) +{ + int hasChildren; + unsigned char itemState; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + XtVaGetValues(wItem, XmNnumChildren, &hasChildren, NULL); + XtVaGetValues(wItem, XmNoutlineState, &itemState, NULL); + + if (hasChildren) + { + if(itemState == XmEXPANDED) + return "EXPANDED"; + else + return "COLLAPSED"; + } + + return NULL; +} + +static int motTreeSetStateAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + if (iupStrEqualNoCase(value, "EXPANDED")) + XtVaSetValues(wItem, XmNoutlineState, XmEXPANDED, NULL); + else + XtVaSetValues(wItem, XmNoutlineState, XmCOLLAPSED, NULL); + + return 0; +} + +static char* motTreeGetColorAttrib(Ihandle* ih, const char* name_id) +{ + unsigned char r, g, b; + Pixel color; + char* str; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + XtVaGetValues(wItem, XmNforeground, &color, NULL); + iupmotColorGetRGB(color, &r, &g, &b); + + str = iupStrGetMemory(20); + sprintf(str, "%d %d %d", (int)r, (int)g, (int)b); + return str; +} + +static int motTreeSetColorAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Pixel color; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + XtVaSetValues(wItem, XmNforeground, color, NULL); + return 0; +} + +static char* motTreeGetDepthAttrib(Ihandle* ih, const char* name_id) +{ + Widget wRoot; + int dep = 0; + char* depth; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + while((wRoot != wItem) && (wItem != NULL)) + { + XtVaGetValues(wItem, XmNentryParent, &wItem, NULL); + dep++; + } + + depth = iupStrGetMemory(10); + sprintf(depth, "%d", dep); + return depth; +} + +static int motTreeSetMoveNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Widget wItemDst, wParent, wItemSrc; + + if (!ih->handle) /* do not store the action before map */ + return 0; + wItemSrc = motTreeFindNodeFromString(ih, name_id); + if (!wItemSrc) + return 0; + wItemDst = motTreeFindNodeFromString(ih, value); + if (!wItemDst) + return 0; + + /* If Drag item is an ancestor of Drop item then return */ + wParent = wItemDst; + while(wParent) + { + XtVaGetValues(wParent, XmNentryParent, &wParent, NULL); + if (wParent == wItemSrc) + return 0; + } + + /* Copying the node and its children to the new position */ + motTreeCopyNode(ih, wItemSrc, wItemDst, 0); /* not a full copy, preserve user data */ + + /* Deleting the node (and its children) inserted into the old position */ + motTreeRemoveNode(ih, wItemSrc, 0); /* do not delete the user data, we copy the references in CopyNode */ + + return 0; +} + +static int motTreeSetCopyNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Widget wItemDst, wParent, wItemSrc; + + if (!ih->handle) /* do not store the action before map */ + return 0; + wItemSrc = motTreeFindNodeFromString(ih, name_id); + if (!wItemSrc) + return 0; + wItemDst = motTreeFindNodeFromString(ih, value); + if (!wItemDst) + return 0; + + /* If Drag item is an ancestor of Drop item then return */ + wParent = wItemDst; + while(wParent) + { + XtVaGetValues(wParent, XmNentryParent, &wParent, NULL); + if (wParent == wItemSrc) + return 0; + } + + /* Copying the node and its children to the new position */ + motTreeCopyNode(ih, wItemSrc, wItemDst, 1); + + return 0; +} + +static char* motTreeGetParentAttrib(Ihandle* ih, const char* name_id) +{ + Widget wItemParent; + char* str; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + /* get the parent item */ + XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL); + if (!wItemParent) + return NULL; + + str = iupStrGetMemory(10); + sprintf(str, "%d", motTreeGetNodeId(ih, wItemParent)); + return str; +} + +static char* motTreeGetChildCountAttrib(Ihandle* ih, const char* name_id) +{ + char* str; + WidgetList wList = NULL; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + str = iupStrGetMemory(10); + sprintf(str, "%d", XmContainerGetItemChildren(ih->handle, wItem, &wList)); + if (wList) XtFree((char*)wList); + return str; +} + +static int motTreeCount(Ihandle* ih, Widget wItem) +{ + WidgetList wList = NULL; + int i, count = 0; + int childCount = XmContainerGetItemChildren(ih->handle, wItem, &wList); + count++; + for (i=0; i<childCount; i++) + count += motTreeCount(ih, wList[i]); + if (wList) XtFree((char*)wList); + return count; +} + +static char* motTreeGetCountAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(10); + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + sprintf(str, "%d", motTreeCount(ih, wRoot)); + return str; +} + +static char* motTreeGetKindAttrib(Ihandle* ih, const char* name_id) +{ + motTreeItemData *itemData; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + + if(itemData->kind == ITREE_BRANCH) + return "BRANCH"; + else + return "LEAF"; +} + +static char* motTreeGetValueAttrib(Ihandle* ih) +{ + char* str; + Widget wItem = motTreeGetFocusNode(ih); + if (!wItem) + return "0"; /* default VALUE is root */ + + str = iupStrGetMemory(10); + sprintf(str, "%d", motTreeGetNodeId(ih, wItem)); + return str; +} + +static int motTreeSetMarkAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + return 0; + + if(iupStrEqualNoCase(value, "CLEARALL")) + motTreeContainerDeselectAll(ih); + else if(iupStrEqualNoCase(value, "MARKALL")) + motTreeContainerSelectAll(ih); + else if(iupStrEqualNoCase(value, "INVERTALL")) /* INVERTALL *MUST* appear before INVERT, or else INVERTALL will never be called. */ + motTreeInvertAllNodeMarking(ih); + else if(iupStrEqualPartial(value, "INVERT")) + { + unsigned char isSelected; + Widget wItem = motTreeFindNodeFromString(ih, &value[strlen("INVERT")]); + if (!wItem) + return 0; + + XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); + if (isSelected == XmSELECTED) + XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + else + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } + else if(iupStrEqualNoCase(value, "BLOCK")) + { + Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_MARKSTART_NODE"); + Widget wFocusItem = motTreeGetFocusNode(ih); + if(!wFocusItem || !wItem) + return 0; + motTreeSelectRange(ih, wFocusItem, wItem, 0); + } + else + { + Widget wItem1, wItem2; + char str1[50], str2[50]; + if (iupStrToStrStr(value, str1, str2, '-')!=2) + return 0; + + wItem1 = motTreeFindNodeFromString(ih, str1); + if (!wItem1) + return 0; + wItem2 = motTreeFindNodeFromString(ih, str2); + if (!wItem2) + return 0; + + motTreeSelectRange(ih, wItem1, wItem2, 0); + } + + return 1; +} + +static int motTreeSetValueAttrib(Ihandle* ih, const char* value) +{ + Widget wRoot, wItem; + + if (motTreeSetMarkAttrib(ih, value)) + return 0; + + wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + if (iupStrEqualNoCase(value, "ROOT")) + wItem = wRoot; + else if(iupStrEqualNoCase(value, "LAST")) + wItem = motTreeGetLastVisibleNode(ih, wRoot); + else if(iupStrEqualNoCase(value, "PGUP")) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + if(!wItemFocus) + return 0; + + ih->data->id_control = -1; + motTreeFindVisibleNodeId(ih, &wRoot, 1, wItemFocus); + ih->data->id_control -= 10; /* less 10 visible nodes */ + + if(ih->data->id_control < 0) + ih->data->id_control = 0; /* Begin of tree = Root id */ + + wItem = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); + } + else if(iupStrEqualNoCase(value, "PGDN")) + { + Widget wNext, wItemFocus; + + wItemFocus = motTreeGetFocusNode(ih); + if(!wItemFocus) + return 0; + + ih->data->id_control = -1; + motTreeFindVisibleNodeId(ih, &wRoot, 1, wItemFocus); + ih->data->id_control += 10; /* more 10 visible nodes */ + + wNext = motTreeFindVisibleNodeFromId(ih, &wRoot, 1); + + if (ih->data->id_control >= 0) + wNext = motTreeGetLastVisibleNode(ih, wRoot); + + wItem = wNext; + } + else if(iupStrEqualNoCase(value, "NEXT")) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + if (!wItemFocus) + return 0; + + wItem = motTreeGetNextVisibleNode(ih, wRoot, wItemFocus); + } + else if(iupStrEqualNoCase(value, "PREVIOUS")) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + if(!wItemFocus) + return 0; + + wItem = motTreeGetPreviousVisibleNode(ih, wRoot, wItemFocus); + } + else + wItem = motTreeFindNodeFromString(ih, value); + + if (!wItem) + return 0; + + /* select */ + if (ih->data->mark_mode==ITREE_MARK_SINGLE) + { + /* clear previous selection */ + XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); + XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); + + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } + + /* set focus (will scroll to visible) */ + motTreeSetFocusNode(ih, wItem); + + iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", motTreeGetNodeId(ih, wItem)); + + return 0; +} + +static int motTreeSetMarkStartAttrib(Ihandle* ih, const char* name_id) +{ + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + iupAttribSetStr(ih, "_IUPTREE_MARKSTART_NODE", (char*)wItem); + + return 1; +} + +static char* motTreeGetMarkedAttrib(Ihandle* ih, const char* name_id) +{ + unsigned char isSelected; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + XtVaGetValues(wItem, XmNvisualEmphasis, &isSelected, NULL); + + if(isSelected == XmSELECTED) + return "YES"; + else + return "NO"; +} + +static int motTreeSetMarkedAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + if (iupStrBoolean(value)) + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + else + XtVaSetValues(wItem, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + + return 0; +} + +static char* motTreeGetTitle(Widget wItem) +{ + char *title; + XmString itemTitle; + XtVaGetValues(wItem, XmNlabelString, &itemTitle, NULL); + title = iupmotConvertString(itemTitle); + XmStringFree(itemTitle); + return title; +} + +static char* motTreeGetTitleAttrib(Ihandle* ih, const char* name_id) +{ + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + return motTreeGetTitle(wItem); +} + +static int motTreeSetTitleAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + iupmotSetString(wItem, XmNlabelString, value); + + return 0; +} + +static int motTreeSetTitleFontAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + XmFontList fontlist = NULL; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + if (value) + { + char attr[20]; + sprintf(attr, "TITLEFOUNDRY%s", name_id); + fontlist = iupmotGetFontList(iupAttribGet(ih, attr), value); + } + XtVaSetValues(wItem, XmNrenderTable, fontlist, NULL); + + return 0; +} + +static char* motTreeGetTitleFontAttrib(Ihandle* ih, const char* name_id) +{ + XmFontList fontlist; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + XtVaGetValues(wItem, XmNrenderTable, &fontlist, NULL); + return iupmotFindFontList(fontlist); +} + +static char* motTreeGetFindUserDataAttrib(Ihandle* ih, const char* name_id) +{ + int id; + char* str = (char*)(name_id+1); /* skip ':' */ + void* userdata = NULL; + if (sscanf(str, "%p", &userdata)!=1) + return NULL; + id = motTreeGetUserDataId(ih, userdata); + if (id == -1) + return NULL; + str = iupStrGetMemory(16); + sprintf(str, "%d", id); + return str; +} + +static char* motTreeGetUserDataAttrib(Ihandle* ih, const char* name_id) +{ + motTreeItemData *itemData; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return NULL; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + + return itemData->userdata; +} + +static int motTreeSetUserDataAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + motTreeItemData *itemData; + Widget wItem = motTreeFindNodeFromString(ih, name_id); + if (!wItem) + return 0; + + XtVaGetValues(wItem, XmNuserData, &itemData, NULL); + itemData->userdata = (void*)value; + + return 0; +} + +static int motTreeSetRenameAttrib(Ihandle* ih, const char* value) +{ + if (ih->data->show_rename) + { + IFni cbShowRename = (IFni)IupGetCallback(ih, "SHOWRENAME_CB"); + Widget wItemFocus = motTreeGetFocusNode(ih); + if (cbShowRename) + cbShowRename(ih, motTreeGetNodeId(ih, wItemFocus)); + motTreeShowEditField(ih, wItemFocus); + } + else + { + IFnis cbRenameNode = (IFnis)IupGetCallback(ih, "RENAMENODE_CB"); + if (cbRenameNode) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + cbRenameNode(ih, motTreeGetNodeId(ih, wItemFocus), motTreeGetTitle(wItemFocus)); + } + } + + (void)value; + return 0; +} + +static int motTreeSetDelNodeAttrib(Ihandle* ih, const char* name_id, const char* value) +{ + if (!ih->handle) /* do not store the action before map */ + return 0; + if(iupStrEqualNoCase(value, "SELECTED")) /* selected here means the specified one */ + { + Widget wItem = motTreeFindNodeFromString(ih, name_id); + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + /* the root node can't be deleted */ + if(!wItem || wItem == wRoot) /* root is the unique child */ + return 0; + + /* deleting the specified node (and it's children) */ + motTreeRemoveNode(ih, wItem, 1); + } + else if(iupStrEqualNoCase(value, "CHILDREN")) /* children of the specified one */ + { + Widget wItem = motTreeFindNodeFromString(ih, name_id); + + if(!wItem) + return 0; + + { + /* deleting the selected node's children only */ + WidgetList wItemList = NULL; + int numChild = XmContainerGetItemChildren(ih->handle, wItem, &wItemList); + if(numChild) + motTreeRemoveChildren(ih, wItemList, numChild, 1); + if (wItemList) XtFree((char*)wItemList); + } + } + else if(iupStrEqualNoCase(value, "MARKED")) /* Delete the array of marked nodes */ + { + WidgetList wSelectedItemList = NULL; + Widget wRoot; + int countItems, i; + + XtVaGetValues(ih->handle, XmNselectedObjects, &wSelectedItemList, + XmNselectedObjectCount, &countItems, NULL); + + wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + for(i = 0; i < countItems; i++) + { + int ok = XmIsIconGadget(wSelectedItemList[i]); + if ((wSelectedItemList[i] != wRoot) && ok) /* the root node can't be deleted */ + motTreeRemoveNode(ih, wSelectedItemList[i], 1); + } + } + + return 0; +} + +static char* motTreeGetIndentationAttrib(Ihandle* ih) +{ + char* str = iupStrGetMemory(255); + Dimension indent; + XtVaGetValues(ih->handle, XmNoutlineIndentation, &indent, NULL); + sprintf(str, "%d", (int)indent); + return str; +} + +static int motTreeSetIndentationAttrib(Ihandle* ih, const char* value) +{ + int indent; + if (iupStrToInt(value, &indent)) + XtVaSetValues(ih->handle, XmNoutlineIndentation, (Dimension)indent, NULL); + return 0; +} + +static int motTreeSetTopItemAttrib(Ihandle* ih, const char* value) +{ + Widget wItem = motTreeFindNodeFromString(ih, value); + Widget sb_win; + Widget wItemParent; + + if (!wItem) + return 0; + + /* expand all parents */ + XtVaGetValues(wItem, XmNentryParent, &wItemParent, NULL); + while(wItemParent) + { + XtVaSetValues(wItemParent, XmNoutlineState, XmEXPANDED, NULL); + XtVaGetValues(wItemParent, XmNentryParent, &wItemParent, NULL); + } + + sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + XmScrollVisible(sb_win, wItem, 0, 0); + + return 0; +} + +static int motTreeSpacingFunc(Ihandle* ih, Widget wItem, void *data) +{ + XtVaSetValues(wItem, XmNmarginHeight, ih->data->spacing, NULL); + (void)data; + return 1; +} + +static int motTreeSetSpacingAttrib(Ihandle* ih, const char* value) +{ + if (!iupStrToInt(value, &ih->data->spacing)) + ih->data->spacing = 1; + + if (ih->data->spacing < 1) + ih->data->spacing = 1; + + if (ih->handle) + { + motTreeForEach(ih, NULL, (motTreeNodeFunc)motTreeSpacingFunc, 0); + return 0; + } + else + return 1; /* store until not mapped, when mapped will be set again */ +} + +static int motTreeSetExpandAllAttrib(Ihandle* ih, const char* value) +{ + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + if (iupStrBoolean(value)) + motTreeExpandCollapseAllNodes(ih, &wRoot, 1, XmEXPANDED); + else + { + motTreeExpandCollapseAllNodes(ih, &wRoot, 1, XmCOLLAPSED); + + /* The root node is always expanded */ + XtVaSetValues((Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"), XmNoutlineState, XmEXPANDED, NULL); + } + + return 0; +} + +static int motTreeSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + Pixel color; + + /* ignore given value for the scrollbars, must use only from parent */ + char* parent_value = iupBaseNativeParentGetBgColor(ih); + + color = iupmotColorGetPixelStr(parent_value); + if (color != (Pixel)-1) + { + Widget sb = NULL; + + iupmotSetBgColor(sb_win, color); + + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb, NULL); + if (sb) iupmotSetBgColor(sb, color); + } + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + Widget wRoot; + Widget clipwin = NULL; + + XtVaGetValues(sb_win, XmNclipWindow, &clipwin, NULL); + if (clipwin) iupmotSetBgColor(clipwin, color); + + wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + /* Update all children, starting at root node */ + motTreeUpdateBgColor(ih, &wRoot, 1, color); + } + + iupdrvBaseSetBgColorAttrib(ih, value); /* use given value for contents */ + + /* update internal image cache */ + iupTreeUpdateImages(ih); + + return 1; +} + +static int motTreeSetFgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + XtVaSetValues(ih->handle, XmNforeground, color, NULL); + + return 1; +} + +void iupdrvTreeUpdateMarkMode(Ihandle *ih) +{ + XtVaSetValues(ih->handle, XmNselectionPolicy, (ih->data->mark_mode==ITREE_MARK_SINGLE)? XmSINGLE_SELECT: XmEXTENDED_SELECT, NULL); +} + +/************************************************************************************************/ + + +static void motTreeSetRenameCaretPos(Widget cbEdit, const char* value) +{ + int pos = 1; + + if (iupStrToInt(value, &pos)) + { + if (pos < 1) pos = 1; + pos--; /* IUP starts at 1 */ + + XtVaSetValues(cbEdit, XmNcursorPosition, pos, NULL); + } +} + +static void motTreeSetRenameSelectionPos(Widget cbEdit, const char* value) +{ + int start = 1, end = 1; + + if (iupStrToIntInt(value, &start, &end, ':') != 2) + return; + + if(start < 1 || end < 1) + return; + + start--; /* IUP starts at 1 */ + end--; + + XmTextSetSelection(cbEdit, start, end, CurrentTime); +} + +/*****************************************************************************/ + +static int motTreeCallBranchCloseCb(Ihandle* ih, Widget wItem) +{ + IFni cbBranchClose = (IFni)IupGetCallback(ih, "BRANCHCLOSE_CB"); + + if(cbBranchClose) + return cbBranchClose(ih, motTreeGetNodeId(ih, wItem)); + + return IUP_DEFAULT; +} + +static int motTreeCallBranchOpenCb(Ihandle* ih, Widget wItem) +{ + IFni cbBranchOpen; + + if (iupAttribGet(ih, "_IUP_IGNORE_BRANCHOPEN")) + { + iupAttribSetStr(ih, "_IUP_IGNORE_BRANCHOPEN", NULL); + return IUP_DEFAULT; + } + + cbBranchOpen = (IFni)IupGetCallback(ih, "BRANCHOPEN_CB"); + if (cbBranchOpen) + return cbBranchOpen(ih, motTreeGetNodeId(ih, wItem)); + + return IUP_DEFAULT; +} + +static void motTreeCallMultiSelectionCb(Ihandle* ih) +{ + IFnIi cbMulti = (IFnIi)IupGetCallback(ih, "MULTISELECTION_CB"); + IFnii cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + WidgetList wSelectedItemList = NULL; + Widget wRoot; + int countItems; + + wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + + XtVaGetValues(ih->handle, XmNselectedObjects, &wSelectedItemList, + XmNselectedObjectCount, &countItems, NULL); + if (countItems == 0) + return; + + if (cbMulti || cbSelec) + { + int* id_rowItem = malloc(sizeof(int) * countItems); + int i = 0; + + for(i = 0; i < countItems; i++) + id_rowItem[i] = motTreeGetNodeId(ih, wSelectedItemList[i]); + + if (cbMulti) + cbMulti(ih, id_rowItem, countItems); + else + { + for (i=0; i<countItems; i++) + cbSelec(ih, id_rowItem[i], 1); + } + + free(id_rowItem); + } +} + +static int motTreeConvertXYToPos(Ihandle* ih, int x, int y) +{ + Widget wItem = XmObjectAtPoint(ih->handle, (Position)x, (Position)y); + if (wItem) + return motTreeGetNodeId(ih, wItem); + return -1; +} + +static void motTreeCallRightClickCb(Ihandle* ih, int x, int y) +{ + IFni cbRightClick = (IFni)IupGetCallback(ih, "RIGHTCLICK_CB"); + if (cbRightClick) + { + int id = motTreeConvertXYToPos(ih, x, y); + if (id != -1) + cbRightClick(ih, id); + } +} + +static void motTreeCallRenameCb(Ihandle* ih) +{ + IFnis cbRename; + Widget wItem, wEdit; + int ignore = 0; + String title = NULL; + + wItem = (Widget)iupAttribGet(ih, "_IUPTREE_SELECTED"); + wEdit = (Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD"); + + XtVaGetValues((Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD"), XmNvalue, &title, NULL); + + cbRename = (IFnis)IupGetCallback(ih, "RENAME_CB"); + if (cbRename) + { + if (cbRename(ih, motTreeGetNodeId(ih, wItem), title) == IUP_IGNORE) + ignore = 1; + } + + if (!ignore) + iupmotSetString(wItem, XmNlabelString, title); + + XtDestroyWidget(wEdit); + + iupAttribSetStr(ih, "_IUPTREE_EDITFIELD", NULL); + iupAttribSetStr(ih, "_IUPTREE_SELECTED", NULL); +} + +static int motTreeCallDragDropCb(Ihandle* ih, Widget wItemDrag, Widget wItemDrop, int *is_ctrl) +{ + IFniiii cbDragDrop = (IFniiii)IupGetCallback(ih, "DRAGDROP_CB"); + int is_shift = 0; + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + is_shift = 1; + if (key[1] == 'C') + *is_ctrl = 1; + else + *is_ctrl = 0; + + if (cbDragDrop) + { + int drag_id = motTreeGetNodeId(ih, wItemDrag); + int drop_id = motTreeGetNodeId(ih, wItemDrop); + return cbDragDrop(ih, drag_id, drop_id, is_shift, *is_ctrl); + } + + return IUP_CONTINUE; /* allow to move by default if callback not defined */ +} + +static void motTreeEditFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + if (evt->type == FocusOut) + motTreeCallRenameCb(ih); + + (void)cont; + (void)w; +} + +static void motTreeEditKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + KeySym motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_Return) + { + Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_SELECTED"); + motTreeCallRenameCb(ih); + motTreeSetFocusNode(ih, wItem); + } + else if (motcode == XK_Escape) + { + Widget wEdit = (Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD"); + Widget wItem = (Widget)iupAttribGet(ih, "_IUPTREE_SELECTED"); + + XtDestroyWidget(wEdit); + motTreeSetFocusNode(ih, wItem); + + iupAttribSetStr(ih, "_IUPTREE_EDITFIELD", NULL); + iupAttribSetStr(ih, "_IUPTREE_SELECTED", NULL); + } + + (void)cont; + (void)w; +} + +static void motTreeScrollbarOffset(Widget sb_win, Position *x, Position *y) +{ + Widget sb_horiz, sb_vert; + XtVaGetValues(sb_win, XmNhorizontalScrollBar, &sb_horiz, NULL); + if (sb_horiz) + { + int pos; + XtVaGetValues(sb_horiz, XmNvalue, &pos, NULL); + *x = *x - (Position)pos; + } + XtVaGetValues(sb_win, XmNverticalScrollBar, &sb_vert, NULL); + if (sb_vert) + { + int pos; + XtVaGetValues(sb_vert, XmNvalue, &pos, NULL); + *y = *y - (Position)pos; + } +} + +static void motTreeShowEditField(Ihandle* ih, Widget wItem) +{ + int num_args = 0, w_img = 0; + Arg args[30]; + Position x, y; + Dimension w, h; + char* child_id = iupDialogGetChildIdStr(ih); + Widget cbEdit; + XmString title; + char* value; + Pixel color; + Pixmap image = XmUNSPECIFIED_PIXMAP; + XmFontList fontlist; + Widget sb_win = (Widget)iupAttribGet(ih, "_IUP_EXTRAPARENT"); + + XtVaGetValues(wItem, XmNx, &x, + XmNy, &y, + XmNwidth, &w, + XmNheight, &h, + XmNlabelString, &title, + XmNsmallIconPixmap, &image, + XmNforeground, &color, + XmNrenderTable, &fontlist, + NULL); + + motTreeScrollbarOffset(sb_win, &x, &y); + iupdrvImageGetInfo((void*)image, &w_img, NULL, NULL); + w_img += 3; /* add some room for borders */ + + iupmotSetArg(args, num_args, XmNx, x+w_img); /* x-position */ + iupmotSetArg(args, num_args, XmNy, y); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, w-w_img); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, h); /* default height to avoid 0 */ + iupmotSetArg(args, num_args, XmNmarginHeight, ih->data->spacing); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + iupmotSetArg(args, num_args, XmNforeground, color); + iupmotSetArg(args, num_args, XmNrenderTable, fontlist); + iupmotSetArg(args, num_args, XmNvalue, iupmotConvertString(title)); + iupmotSetArg(args, num_args, XmNtraversalOn, True); + + cbEdit = XtCreateManagedWidget( + child_id, /* child identifier */ + xmTextWidgetClass, /* widget class */ + sb_win, + args, num_args); + + /* Disable Drag Source */ + iupmotDisableDragSource(cbEdit); + + XtAddEventHandler(cbEdit, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(cbEdit, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(cbEdit, FocusChangeMask, False, (XtEventHandler)motTreeEditFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(cbEdit, KeyPressMask, False, (XtEventHandler)motTreeEditKeyPressEvent, (XtPointer)ih); + + iupAttribSetStr(ih, "_IUPTREE_SELECTED", (char*)wItem); + iupAttribSetStr(ih, "_IUPTREE_EDITFIELD", (char*)cbEdit); + + XmProcessTraversal(cbEdit, XmTRAVERSE_CURRENT); + + XmTextSetSelection(cbEdit, (XmTextPosition)0, (XmTextPosition)XmTextGetLastPosition(cbEdit), CurrentTime); + + value = iupAttribGetStr(ih, "RENAMECARET"); + if (value) + motTreeSetRenameCaretPos(cbEdit, value); + + value = iupAttribGetStr(ih, "RENAMESELECTION"); + if (value) + motTreeSetRenameSelectionPos(cbEdit, value); + + /* the parents callbacks can be called while editing + so we must avoid their processing if _IUPTREE_EDITFIELD is defined. */ +} + +static void motTreeSelectionCallback(Widget w, Ihandle* ih, XmContainerSelectCallbackStruct *nptr) +{ + IFnii cbSelec; + int is_ctrl = 0; + (void)w; + (void)nptr; + +printf("SelectionCallback(%d)\n", nptr->selected_item_count); + + if (ih->data->mark_mode == ITREE_MARK_MULTIPLE) + { + char key[5]; + iupdrvGetKeyState(key); + if (key[0] == 'S') + return; + else if (key[1] == 'C') + is_ctrl = 1; + + if (nptr->selected_item_count>1 && !is_ctrl) + { + if (IupGetCallback(ih, "MULTISELECTION_CB")) + { + if (nptr->auto_selection_type==XmAUTO_NO_CHANGE) + motTreeCallMultiSelectionCb(ih); + } + else + { + if (nptr->auto_selection_type==XmAUTO_MOTION) + motTreeCallMultiSelectionCb(ih); + } + return; + } + } + + cbSelec = (IFnii)IupGetCallback(ih, "SELECTION_CB"); + if (cbSelec) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + int curpos = motTreeGetNodeId(ih, wItemFocus); + if (is_ctrl) + { + unsigned char isSelected; + XtVaGetValues(wItemFocus, XmNvisualEmphasis, &isSelected, NULL); + cbSelec(ih, curpos, isSelected == XmSELECTED? 1: 0); + } + else + { + int oldpos = iupAttribGetInt(ih, "_IUPTREE_OLDVALUE"); + if (oldpos != curpos) + { + cbSelec(ih, oldpos, 0); /* unselected */ + cbSelec(ih, curpos, 1); /* selected */ + + iupAttribSetInt(ih, "_IUPTREE_OLDVALUE", curpos); + } + } + } +} + +static void motTreeDefaultActionCallback(Widget w, Ihandle* ih, XmContainerSelectCallbackStruct *nptr) +{ + unsigned char itemState; + WidgetList wSelectedItemList = NULL; + int countItems; + motTreeItemData *itemData; + Widget wItem; + (void)w; + + wSelectedItemList = nptr->selected_items; + countItems = nptr->selected_item_count; + + if (!countItems || (Widget)iupAttribGet(ih, "_IUPTREE_EDITFIELD")) + return; + + /* this works also when using multiple selection */ + wItem = wSelectedItemList[0]; + + XtVaGetValues(wItem, XmNoutlineState, &itemState, + XmNuserData, &itemData, NULL); + + if (itemData->kind == ITREE_BRANCH) + { + if (itemState == XmEXPANDED) + XtVaSetValues(wItem, XmNoutlineState, XmCOLLAPSED, NULL); + else + XtVaSetValues(wItem, XmNoutlineState, XmEXPANDED, NULL); + } + else + { + IFni cbExecuteLeaf = (IFni)IupGetCallback(ih, "EXECUTELEAF_CB"); + if (cbExecuteLeaf) + cbExecuteLeaf(ih, motTreeGetNodeId(ih, wItem)); + } +} + +static void motTreeOutlineChangedCallback(Widget w, Ihandle* ih, XmContainerOutlineCallbackStruct *nptr) +{ + motTreeItemData *itemData; + XtVaGetValues(nptr->item, XmNuserData, &itemData, NULL); + + if (nptr->reason == XmCR_EXPANDED) + { + if (motTreeCallBranchOpenCb(ih, nptr->item) == IUP_IGNORE) + nptr->new_outline_state = XmCOLLAPSED; /* prevent the change */ + else + { + XtVaSetValues(nptr->item, XmNsmallIconPixmap, (itemData->image_expanded!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded: (Pixmap)ih->data->def_image_expanded, NULL); + XtVaSetValues(nptr->item, XmNsmallIconMask, (itemData->image_expanded_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_expanded_mask: (Pixmap)ih->data->def_image_expanded_mask, NULL); + } + } + else if (nptr->reason == XmCR_COLLAPSED) + { + if (motTreeCallBranchCloseCb(ih, nptr->item) == IUP_IGNORE) + nptr->new_outline_state = XmEXPANDED; /* prevent the change */ + else + { + XtVaSetValues(nptr->item, XmNsmallIconPixmap, (itemData->image!=XmUNSPECIFIED_PIXMAP)? itemData->image: (Pixmap)ih->data->def_image_collapsed, NULL); + XtVaSetValues(nptr->item, XmNsmallIconMask, (itemData->image_mask!=XmUNSPECIFIED_PIXMAP)? itemData->image_mask: (Pixmap)ih->data->def_image_collapsed_mask, NULL); + } + } + + (void)w; +} + +static void motTreeTraverseObscuredCallback(Widget widget, Ihandle* ih, XmTraverseObscuredCallbackStruct *cbs) +{ + (void)ih; + /* allow to do automatic scroll when navigating in the tree */ + XmScrollVisible(widget, cbs->traversal_destination, 10, 10); +} + +static void motTreeKeyReleaseEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + KeySym motcode; + + if (iupAttribGet(ih, "_IUPTREE_EDITFIELD")) + return; + + motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_Down || motcode == XK_U || motcode == XK_Home || motcode == XK_End) + { + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & ShiftMask)) + motTreeCallMultiSelectionCb(ih); + } + + (void)w; + (void)cont; +} + +static void motTreeKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + KeySym motcode; + + if (iupAttribGet(ih, "_IUPTREE_EDITFIELD")) + return; + + *cont = True; + iupmotKeyPressEvent(w, ih, (XEvent*)evt, cont); + if (*cont == False) + return; + + motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + if (motcode == XK_F2) + motTreeSetRenameAttrib(ih, NULL); + else if (motcode == XK_F1) + iupmotHelpCallback(w, ih, NULL); + else if ((motcode == XK_Down || motcode == XK_Up) && (evt->state & ControlMask)) + { + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + Widget wItem; + Widget wItemFocus = motTreeGetFocusNode(ih); + + /* Ctrl+Arrows move only focus */ + if (motcode == XK_Down) + wItem = motTreeGetNextVisibleNode(ih, wRoot, wItemFocus); + else + wItem = motTreeGetPreviousVisibleNode(ih, wRoot, wItemFocus); + + motTreeSetFocusNode(ih, wItem); + *cont = False; + } + else if(motcode == XK_Home || motcode == XK_End) + { + Widget wRoot = (Widget)iupAttribGet(ih, "_IUPTREE_ROOTITEM"); + Widget wItem; + + /* Not processed by Motif */ + + if (motcode == XK_Home) + wItem = wRoot; + else + wItem = motTreeGetLastVisibleNode(ih, wRoot); + + /* Ctrl+Arrows move only focus */ + if (!(evt->state & ControlMask)) + { + /* Shift+Arrows select block */ + if (evt->state & ShiftMask) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + if (!wItemFocus) + return; + motTreeSelectRange(ih, wItemFocus, wItem, 1); + } + else + { + /* clear previous selection */ + XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); + XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); + + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } + } + + motTreeSetFocusNode(ih, wItem); + *cont = False; + } + else if(motcode == XK_space && (evt->state & ControlMask)) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + if (wItemFocus) + { + unsigned char isSelected; + XtVaGetValues(wItemFocus, XmNvisualEmphasis, &isSelected, NULL); + if (isSelected == XmSELECTED) + XtVaSetValues(wItemFocus, XmNvisualEmphasis, XmNOT_SELECTED, NULL); + else + XtVaSetValues(wItemFocus, XmNvisualEmphasis, XmSELECTED, NULL); + } + } +} + +static void motTreeButtonEvent(Widget w, Ihandle* ih, XButtonEvent* evt, Boolean* cont) +{ + (void)w; + (void)cont; + + if (iupAttribGet(ih, "_IUPTREE_EDITFIELD")) + return; + + *cont = True; + iupmotButtonPressReleaseEvent(w, ih, (XEvent*)evt, cont); + if (*cont == False) + return; + + if (evt->type==ButtonPress) + { + iupAttribSetStr(ih, "_IUPTREE_IGNORE_ENTERLEAVE", "1"); + + if (evt->button==Button1) + { + Widget wItemFocus = motTreeGetFocusNode(ih); + static Widget wLastItem = NULL; + static Time last = 0; + int clicktwice = 0, doubleclicktime = XtGetMultiClickTime(iupmot_display); + int elapsed = (int)(evt->time - last); + last = evt->time; + + /* stay away from double click and leave some room for clicks */ + if (elapsed > (3*doubleclicktime)/2 && elapsed <= 3*doubleclicktime) + clicktwice = 1; + + if (clicktwice && wLastItem && wLastItem==wItemFocus) + { + motTreeSetRenameAttrib(ih, NULL); + *cont = False; + } + wLastItem = wItemFocus; + } + else if (evt->button==Button3) + motTreeCallRightClickCb(ih, evt->x, evt->y); + } + else if (evt->type==ButtonRelease) + { + if (evt->button==Button1) + { + if (ih->data->mark_mode==ITREE_MARK_MULTIPLE && (evt->state & ShiftMask)) + motTreeCallMultiSelectionCb(ih); + } + } +} + +static void motTreeTransferProc(Widget drop_context, XtPointer client_data, Atom *seltype, Atom *type, XtPointer value, unsigned long *length, int format) +{ + Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False); + Widget wItemDrop = (Widget)client_data; + Widget wItemDrag = (Widget)value; + + if (*type == atomTreeItem) + { + Widget wParent; + Ihandle* ih = NULL; + int is_ctrl; + + if (!wItemDrop || wItemDrag == wItemDrop) + return; + + wParent = wItemDrop; + while(wParent) + { + XtVaGetValues(wParent, XmNentryParent, &wParent, NULL); + if (wParent == wItemDrag) + return; + } + + XtVaGetValues(XtParent(wItemDrag), XmNuserData, &ih, NULL); + + if (motTreeCallDragDropCb(ih, wItemDrag, wItemDrop, &is_ctrl) == IUP_CONTINUE) + { + /* Copy the dragged item to the new position. */ + Widget wNewItem = motTreeCopyNode(ih, wItemDrag, wItemDrop, is_ctrl); + + if (!is_ctrl) + { + /* do not delete the user data, we copy the references in CopyNode */ + motTreeRemoveNode(ih, wItemDrag, 0); + } + + /* Select the dragged item */ + XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); + XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); + XtVaSetValues(wNewItem, XmNvisualEmphasis, XmSELECTED, NULL); + + motTreeSetFocusNode(ih, wNewItem); + } + } + + (void)drop_context; + (void)seltype; + (void)format; + (void)length; +} + +static void motTreeDropProc(Widget w, XtPointer client_data, XmDropProcCallbackStruct* drop_data) +{ + Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False); + XmDropTransferEntryRec transferList[2]; + Arg args[10]; + int i, num_args = 0; + Widget wItemDrop, drop_context; + Cardinal numExportTargets; + Atom *exportTargets; + Boolean found = False; + (void)client_data; + + drop_context = drop_data->dragContext; + + /* retrieve the data targets */ + iupmotSetArg(args, num_args, XmNexportTargets, &exportTargets); + iupmotSetArg(args, num_args, XmNnumExportTargets, &numExportTargets); + XtGetValues(drop_context, args, num_args); + + for (i = 0; i < (int)numExportTargets; i++) + { + if (exportTargets[i] == atomTreeItem) + { + found = True; + break; + } + } + + wItemDrop = XmObjectAtPoint(w, drop_data->x, drop_data->y); + if (!wItemDrop) + found = False; + + num_args = 0; + if ((!found) || (drop_data->dropAction != XmDROP) || (drop_data->operation != XmDROP_COPY && drop_data->operation != XmDROP_MOVE)) + { + iupmotSetArg(args, num_args, XmNtransferStatus, XmTRANSFER_FAILURE); + iupmotSetArg(args, num_args, XmNnumDropTransfers, 0); + } + else + { + /* set up transfer requests for drop site */ + transferList[0].target = atomTreeItem; + transferList[0].client_data = (XtPointer)wItemDrop; + iupmotSetArg(args, num_args, XmNdropTransfers, transferList); + iupmotSetArg(args, num_args, XmNnumDropTransfers, 1); + iupmotSetArg(args, num_args, XmNtransferProc, motTreeTransferProc); + } + + XmDropTransferStart(drop_context, args, num_args); +} + +static void motTreeDragDropFinishCallback(Widget drop_context, XtPointer client_data, XtPointer call_data) +{ + Widget source_icon = NULL; + XtVaGetValues(drop_context, XmNsourceCursorIcon, &source_icon, NULL); + if (source_icon) + XtDestroyWidget(source_icon); + (void)call_data; + (void)client_data; +} + +static void motTreeDragMotionCallback(Widget drop_context, Widget wItemDrag, XmDragMotionCallbackStruct* drag_motion) +{ + Ihandle* ih = NULL; + XtVaGetValues(XtParent(wItemDrag), XmNuserData, &ih, NULL); + if (!iupAttribGet(ih, "NODRAGFEEDBACK")) + { + Widget wItem; + int x = drag_motion->x; + int y = drag_motion->y; + iupdrvScreenToClient(ih, &x, &y); + wItem = XmObjectAtPoint(ih->handle, (Position)x, (Position)y); + if (wItem) + { + XtVaSetValues(ih->handle, XmNselectedObjects, NULL, NULL); + XtVaSetValues(ih->handle, XmNselectedObjectCount, 0, NULL); + XtVaSetValues(wItem, XmNvisualEmphasis, XmSELECTED, NULL); + } + } + (void)drop_context; +} + +static Boolean motTreeConvertProc(Widget drop_context, Atom *selection, Atom *target, Atom *type_return, + XtPointer *value_return, unsigned long *length_return, int *format_return) +{ + Atom atomMotifDrop = XInternAtom(iupmot_display, "_MOTIF_DROP", False); + Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False); + Widget wItemDrag = NULL; + + /* check if we are dealing with a drop */ + if (*selection != atomMotifDrop || *target != atomTreeItem) + return False; + + XtVaGetValues(drop_context, XmNclientData, &wItemDrag, NULL); + if (!wItemDrag) + return False; + + /* format the value for transfer */ + *type_return = atomTreeItem; + *value_return = (XtPointer)wItemDrag; + *length_return = 1; + *format_return = 32; + return True; +} + +static void motTreeStartDrag(Widget w, XButtonEvent* evt, String* params, Cardinal* num_params) +{ + Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False); + Atom exportList[1]; + Widget drag_icon, drop_context; + Pixmap pixmap = 0, mask = 0; + int num_args = 0; + Arg args[40]; + Pixel fg, bg; + Widget wItemDrag = XmObjectAtPoint(w, (Position)evt->x, (Position)evt->y); + if (!wItemDrag) + return; + + XtVaGetValues(wItemDrag, XmNsmallIconPixmap, &pixmap, + XmNsmallIconMask, &mask, + XmNbackground, &bg, + XmNforeground, &fg, + NULL); + + iupmotSetArg(args, num_args, XmNpixmap, pixmap); + iupmotSetArg(args, num_args, XmNmask, mask); + drag_icon = XmCreateDragIcon(w, "drag_icon", args, num_args); + + exportList[0] = atomTreeItem; + + /* specify resources for DragContext for the transfer */ + num_args = 0; + iupmotSetArg(args, num_args, XmNcursorBackground, bg); + iupmotSetArg(args, num_args, XmNcursorForeground, fg); + /* iupmotSetArg(args, num_args, XmNsourcePixmapIcon, drag_icon); works, but only outside the dialog, inside disapears */ + iupmotSetArg(args, num_args, XmNsourceCursorIcon, drag_icon); /* does not work, shows the default cursor */ + iupmotSetArg(args, num_args, XmNexportTargets, exportList); + iupmotSetArg(args, num_args, XmNnumExportTargets, 1); + iupmotSetArg(args, num_args, XmNdragOperations, XmDROP_MOVE|XmDROP_COPY); + iupmotSetArg(args, num_args, XmNconvertProc, motTreeConvertProc); + iupmotSetArg(args, num_args, XmNclientData, wItemDrag); + + /* start the drag and register a callback to clean up when done */ + drop_context = XmDragStart(w, (XEvent*)evt, args, num_args); + XtAddCallback(drop_context, XmNdragDropFinishCallback, (XtCallbackProc)motTreeDragDropFinishCallback, NULL); + XtAddCallback(drop_context, XmNdragMotionCallback, (XtCallbackProc)motTreeDragMotionCallback, (XtPointer)wItemDrag); + + (void)params; + (void)num_params; +} + +static void motTreeEnableDragDrop(Widget w) +{ + Atom atomTreeItem = XInternAtom(iupmot_display, "TREE_ITEM", False); + Atom importList[1]; + Arg args[40]; + int num_args = 0; + char dragTranslations[] = "#override <Btn2Down>: StartDrag()"; + static int do_rec = 0; + if (!do_rec) + { + XtActionsRec rec = {"StartDrag", (XtActionProc)motTreeStartDrag}; + XtAppAddActions(iupmot_appcontext, &rec, 1); + do_rec = 1; + } + XtOverrideTranslations(w, XtParseTranslationTable(dragTranslations)); + + importList[0] = atomTreeItem; + iupmotSetArg(args, num_args, XmNimportTargets, importList); + iupmotSetArg(args, num_args, XmNnumImportTargets, 1); + iupmotSetArg(args, num_args, XmNdropSiteOperations, XmDROP_MOVE|XmDROP_COPY); + iupmotSetArg(args, num_args, XmNdropProc, motTreeDropProc); + XmDropSiteUpdate(w, args, num_args); + + XtVaSetValues(XmGetXmDisplay(iupmot_display), XmNenableDragIcon, True, NULL); +} + +static int motTreeMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[40]; + Widget parent = iupChildTreeGetNativeParentHandle(ih); + char* child_id = iupDialogGetChildIdStr(ih); + Widget sb_win; + + /******************************/ + /* Create the scrolled window */ + /******************************/ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNscrollingPolicy, XmAUTOMATIC); + iupmotSetArg(args, num_args, XmNvisualPolicy, XmVARIABLE); + iupmotSetArg(args, num_args, XmNscrollBarDisplayPolicy, XmAS_NEEDED); + iupmotSetArg(args, num_args, XmNspacing, 0); /* no space between scrollbars and text */ + iupmotSetArg(args, num_args, XmNborderWidth, 0); + iupmotSetArg(args, num_args, XmNshadowThickness, 2); + + sb_win = XtCreateManagedWidget( + child_id, /* child identifier */ + xmScrolledWindowWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!sb_win) + return IUP_ERROR; + + XtAddCallback (sb_win, XmNtraverseObscuredCallback, (XtCallbackProc)motTreeTraverseObscuredCallback, (XtPointer)ih); + + parent = sb_win; + child_id = "container"; + + num_args = 0; + + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + + iupmotSetArg(args, num_args, XmNmarginHeight, 0); /* default padding */ + iupmotSetArg(args, num_args, XmNmarginWidth, 0); + + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNshadowThickness, 0); + + iupmotSetArg(args, num_args, XmNlayoutType, XmOUTLINE); + iupmotSetArg(args, num_args, XmNentryViewType, XmSMALL_ICON); + iupmotSetArg(args, num_args, XmNselectionPolicy, XmSINGLE_SELECT); + iupmotSetArg(args, num_args, XmNoutlineIndentation, 20); + + if (iupAttribGetBoolean(ih, "HIDELINES")) + iupmotSetArg(args, num_args, XmNoutlineLineStyle, XmNO_LINE); + else + iupmotSetArg(args, num_args, XmNoutlineLineStyle, XmSINGLE); + + if (iupAttribGetBoolean(ih, "HIDEBUTTONS")) + iupmotSetArg(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_ABSENT); + else + iupmotSetArg(args, num_args, XmNoutlineButtonPolicy, XmOUTLINE_BUTTON_PRESENT); + + ih->handle = XtCreateManagedWidget( + child_id, /* child identifier */ + xmContainerWidgetClass, /* widget class */ + parent, /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + iupAttribSetStr(ih, "_IUP_EXTRAPARENT", (char*)parent); + + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)motTreeEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)motTreeEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)motTreeFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)motTreeKeyPressEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, KeyReleaseMask, False, (XtEventHandler)motTreeKeyReleaseEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)motTreeButtonEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, PointerMotionMask, False, (XtEventHandler)iupmotPointerMotionEvent, (XtPointer)ih); + + /* Callbacks */ + /* XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); NOT WORKING */ + XtAddCallback(ih->handle, XmNoutlineChangedCallback, (XtCallbackProc)motTreeOutlineChangedCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNdefaultActionCallback, (XtCallbackProc)motTreeDefaultActionCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNselectionCallback, (XtCallbackProc)motTreeSelectionCallback, (XtPointer)ih); + + XtRealizeWidget(parent); + + if (ih->data->show_dragdrop) + { + motTreeEnableDragDrop(ih->handle); + XtVaSetValues(ih->handle, XmNuserData, ih, NULL); /* to be used in motTreeTransferProc */ + } + else + iupmotDisableDragSource(ih->handle); + + /* Force background update before setting the images */ + { + char* value = iupAttribGet(ih, "BGCOLOR"); + if (value) + { + motTreeSetBgColorAttrib(ih, value); + iupAttribSetStr(ih, "BGCOLOR", NULL); + } + } + + /* Initialize the default images */ + ih->data->def_image_leaf = iupImageGetImage("IMGLEAF", ih, 0); + if (!ih->data->def_image_leaf) + { + ih->data->def_image_leaf = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_leaf_mask = iupImageGetMask("IMGLEAF"); + if (!ih->data->def_image_leaf_mask) ih->data->def_image_leaf_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + ih->data->def_image_collapsed = iupImageGetImage("IMGCOLLAPSED", ih, 0); + if (!ih->data->def_image_collapsed) + { + ih->data->def_image_collapsed = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_collapsed_mask = iupImageGetMask("IMGCOLLAPSED"); + if (!ih->data->def_image_collapsed_mask) ih->data->def_image_collapsed_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + ih->data->def_image_expanded = iupImageGetImage("IMGEXPANDED", ih, 0); + if (!ih->data->def_image_expanded) + { + ih->data->def_image_expanded = (void*)XmUNSPECIFIED_PIXMAP; + ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + else + { + ih->data->def_image_expanded_mask = iupImageGetMask("IMGEXPANDED"); + if (!ih->data->def_image_expanded_mask) ih->data->def_image_expanded_mask = (void*)XmUNSPECIFIED_PIXMAP; + } + + motTreeAddRootNode(ih); + + IupSetCallback(ih, "_IUP_XY2POS_CB", (Icallback)motTreeConvertXYToPos); + + return IUP_NOERROR; +} + +void iupdrvTreeInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motTreeMapMethod; + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motTreeSetBgColorAttrib, "TXTBGCOLOR", NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "FGCOLOR", NULL, motTreeSetFgColorAttrib, IUPAF_SAMEASSYSTEM, "TXTFGCOLOR", IUPAF_DEFAULT); + + /* IupTree Attributes - GENERAL */ + iupClassRegisterAttribute(ic, "EXPANDALL", NULL, motTreeSetExpandAllAttrib, NULL, NULL, IUPAF_WRITEONLY||IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "INDENTATION", motTreeGetIndentationAttrib, motTreeSetIndentationAttrib, NULL, NULL, IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "COUNT", motTreeGetCountAttrib, NULL, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SPACING", iupTreeGetSpacingAttrib, motTreeSetSpacingAttrib, NULL, NULL, IUPAF_NOT_MAPPED); + iupClassRegisterAttribute(ic, "TOPITEM", NULL, motTreeSetTopItemAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + /* IupTree Attributes - IMAGES */ + iupClassRegisterAttributeId(ic, "IMAGE", NULL, motTreeSetImageAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "IMAGEEXPANDED", NULL, motTreeSetImageExpandedAttrib, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute(ic, "IMAGELEAF", NULL, motTreeSetImageLeafAttrib, IUPAF_SAMEASSYSTEM, "IMGLEAF", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEBRANCHCOLLAPSED", NULL, motTreeSetImageBranchCollapsedAttrib, IUPAF_SAMEASSYSTEM, "IMGCOLLAPSED", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "IMAGEBRANCHEXPANDED", NULL, motTreeSetImageBranchExpandedAttrib, IUPAF_SAMEASSYSTEM, "IMGEXPANDED", IUPAF_NO_INHERIT); + + /* IupTree Attributes - NODES */ + iupClassRegisterAttributeId(ic, "STATE", motTreeGetStateAttrib, motTreeSetStateAttrib, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "DEPTH", motTreeGetDepthAttrib, NULL, IUPAF_READONLY|IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "KIND", motTreeGetKindAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "PARENT", motTreeGetParentAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COLOR", motTreeGetColorAttrib, motTreeSetColorAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "NAME", motTreeGetTitleAttrib, motTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLE", motTreeGetTitleAttrib, motTreeSetTitleAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "USERDATA", motTreeGetUserDataAttrib, motTreeSetUserDataAttrib, IUPAF_NO_STRING|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "CHILDCOUNT", motTreeGetChildCountAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "TITLEFONT", motTreeGetTitleFontAttrib, motTreeSetTitleFontAttrib, IUPAF_NO_INHERIT); + + /* IupTree Attributes - MARKS */ + iupClassRegisterAttributeId(ic, "MARKED", motTreeGetMarkedAttrib, motTreeSetMarkedAttrib, IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARK", NULL, motTreeSetMarkAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "STARTING", NULL, motTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute (ic, "MARKSTART", NULL, motTreeSetMarkStartAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + iupClassRegisterAttribute (ic, "VALUE", motTreeGetValueAttrib, motTreeSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + + /* IupTree Attributes - ACTION */ + iupClassRegisterAttributeId(ic, "DELNODE", NULL, motTreeSetDelNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "RENAME", NULL, motTreeSetRenameAttrib, NULL, NULL, IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "MOVENODE", NULL, motTreeSetMoveNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "COPYNODE", NULL, motTreeSetCopyNodeAttrib, IUPAF_NOT_MAPPED|IUPAF_WRITEONLY|IUPAF_NO_INHERIT); + iupClassRegisterAttributeId(ic, "FINDUSERDATA", motTreeGetFindUserDataAttrib, NULL, IUPAF_READONLY|IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupmot_val.c b/iup/src/mot/iupmot_val.c new file mode 100755 index 0000000..200d2b4 --- /dev/null +++ b/iup/src/mot/iupmot_val.c @@ -0,0 +1,488 @@ +/** \file + * \brief Valuator Control + * + * See Copyright Notice in "iup.h" + */ + +#include <Xm/Xm.h> +#include <Xm/Scale.h> +#include <Xm/SeparatoG.h> +#include <X11/keysym.h> + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <math.h> +#include <memory.h> +#include <stdarg.h> +#include <limits.h> + +#include "iup.h" +#include "iupcbs.h" + +#include "iup_object.h" +#include "iup_childtree.h" +#include "iup_attrib.h" +#include "iup_dialog.h" +#include "iup_str.h" +#include "iup_val.h" +#include "iup_image.h" +#include "iup_drv.h" + +#include "iupmot_drv.h" +#include "iupmot_color.h" + + +void iupdrvValGetMinSize(Ihandle* ih, int *w, int *h) +{ + int ticks_size = 0; + if (iupAttribGetInt(ih, "SHOWTICKS")) + ticks_size = 8; + + if (ih->data->type == IVAL_HORIZONTAL) + { + *w = 30; + *h = 20+ticks_size; + } + else + { + *w = 20+ticks_size; + *h = 30; + } +} + +static void motValRemoveOldTicks(Widget scale) +{ + WidgetList children = (WidgetList)0; + Cardinal num_children = (Cardinal)0; + Cardinal i; + String name; + + XtVaGetValues(scale, XmNchildren, &children, + XmNnumChildren, &num_children, + NULL); + + for (i = 0; i < num_children; i++) + { + if (XmIsSeparatorGadget(children[i])) + { + if ((name = XtName(children[i])) != (String)0) + { + if ((strcmp(name, "BigTic") == 0) || + (strcmp(name, "MedTic") == 0) || + (strcmp(name, "SmallTic") == 0)) + { + XtDestroyWidget(children[i]); + } + } + } + } +} + +static int motValSetShowTicksAttrib(Ihandle* ih, const char* value) +{ + int tick_freq, show_ticks; + + if (!ih->data->show_ticks) /* can only set if already not zero */ + return 0; + + show_ticks = atoi(value); + if (show_ticks<2) show_ticks=2; + ih->data->show_ticks = show_ticks; + + motValRemoveOldTicks(ih->handle); + + /* Defines the interval frequency for tick marks */ + tick_freq = SHRT_MAX/(show_ticks-1); + XmScaleSetTicks(ih->handle, tick_freq, 0, 0, 8, 0, 0); + return 0; +} + +static int motValSetPageStepAttrib(Ihandle* ih, const char* value) +{ + int pagesize; + ih->data->pagestep = atof(value); + pagesize = (int)(ih->data->pagestep*SHRT_MAX); + XtVaSetValues(ih->handle, XmNscaleMultiple, pagesize, NULL); + return 0; /* do not store value in hash table */ +} + +static int motValSetStepAttrib(Ihandle* ih, const char* value) +{ + ih->data->step = atof(value); + return 0; /* do not store value in hash table */ +} + +static int motValSetValueAttrib(Ihandle* ih, const char* value) +{ + int ival; + + ih->data->val = atof(value); + iupValCropValue(ih); + + ival = (int)(((ih->data->val-ih->data->vmin)/(ih->data->vmax - ih->data->vmin))*SHRT_MAX); + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + + return 0; /* do not store value in hash table */ +} + +static int motValSetBgColorAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + unsigned char r, g, b; + if (!iupStrToRGB(value, &r, &g, &b)) + return 0; + + r = (r*8)/10; + g = (g*8)/10; + b = (b*8)/10; + + color = iupmotColorGetPixel(r, g, b); + if (color != (Pixel)-1) + { + Widget w = XtNameToWidget(ih->handle, "*Scrollbar"); + XtVaSetValues(w, XmNtroughColor, color, NULL); + } + + return iupdrvBaseSetBgColorAttrib(ih, value); +} + +static int motValSetBackgroundAttrib(Ihandle* ih, const char* value) +{ + Pixel color; + + /* ignore given value, must use only from parent */ + value = iupAttribGetInheritNativeParent(ih, "BACKGROUND"); + + color = iupmotColorGetPixelStr(value); + if (color != (Pixel)-1) + { + XtVaSetValues(ih->handle, XmNbackground, color, NULL); + return 1; + } + else + { + Pixmap pixmap = (Pixmap)iupImageGetImage(value, ih, 0); + if (pixmap) + { + XtVaSetValues(ih->handle, XmNbackgroundPixmap, pixmap, NULL); + return 1; + } + } + return 0; +} + + +/*********************************************************************************************/ + + +static void motValCallAction(Ihandle* ih, int ival, int cb_state) +{ + double old_val = ih->data->val; + IFn cb; + + ih->data->val = (((double)ival/(double)SHRT_MAX)*(ih->data->vmax - ih->data->vmin)) + ih->data->vmin; + iupValCropValue(ih); + + cb = (IFn)IupGetCallback(ih, "VALUECHANGED_CB"); + if (cb) + { + if (ih->data->val == old_val) + return; + + cb(ih); + } + else + { + IFnd cb_old; + if (cb_state == 0) + cb_old = (IFnd) IupGetCallback(ih, "MOUSEMOVE_CB"); + else if (cb_state == -1) + cb_old = (IFnd) IupGetCallback(ih, "BUTTON_RELEASE_CB"); + else + cb_old = (IFnd) IupGetCallback(ih, "BUTTON_PRESS_CB"); + + if (cb_old) + cb_old(ih, ih->data->val); + } +} + +static void motValIncPageValue(Ihandle *ih, int dir) +{ + int pagesize, ival; + pagesize = (int)(ih->data->pagestep*SHRT_MAX); + + if (ih->data->inverted) + dir *= -1; + + XtVaGetValues(ih->handle, XmNvalue, &ival, NULL); + ival += dir*pagesize; + if (ival < 0) ival = 0; + if (ival > SHRT_MAX) ival = SHRT_MAX; + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + + motValCallAction(ih, ival, 1); +} + +static void motValIncLineValue(Ihandle *ih, int dir) +{ + int linesize, ival; + linesize = (int)(ih->data->step*SHRT_MAX); + + if (ih->data->inverted) + dir *= -1; + + XtVaGetValues(ih->handle, XmNvalue, &ival, NULL); + ival += dir*linesize; + if (ival < 0) ival = 0; + if (ival > SHRT_MAX) ival = SHRT_MAX; + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + + motValCallAction(ih, ival, 1); +} + +static void motValKeyPressEvent(Widget w, Ihandle *ih, XKeyEvent *evt, Boolean *cont) +{ + KeySym motcode; + + *cont = True; + iupmotKeyPressEvent(w, ih, (XEvent*)evt, cont); + if (*cont == False) + return; + + motcode = XKeycodeToKeysym(iupmot_display, evt->keycode, 0); + + /* add missing support for numeric keyboard */ + /* add missing support for left/right in vertical + and up/down in horizontal */ + if (motcode == XK_Left || motcode == XK_KP_Left || + motcode == XK_Up || motcode == XK_KP_Up) + { + motValIncLineValue(ih, -1); + *cont = False; + return; + } + if (motcode == XK_Right || motcode == XK_KP_Right || + motcode == XK_Down || motcode == XK_KP_Down) + { + motValIncLineValue(ih, 1); + *cont = False; + return; + } + if (motcode == XK_Prior || motcode == XK_KP_Page_Up) + { + motValIncPageValue(ih, -1); + *cont = False; + return; + } + if (motcode == XK_Next || motcode == XK_KP_Page_Down) + { + motValIncPageValue(ih, 1); + *cont = False; + return; + } + + /* change Home and End default behaviour */ + if (ih->data->inverted) + { + if (motcode==XK_Home || motcode==XK_KP_Home) + { + int ival = SHRT_MAX; /* set to maximum */ + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + motValCallAction(ih, ival, 1); + *cont = False; + return; + } + if (motcode==XK_End || motcode==XK_KP_End) + { + int ival = 0; /* set to minimum */ + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + motValCallAction(ih, ival, 1); + *cont = False; + return; + } + } + else + { + /* add missing support for numeric keyboard */ + if (motcode==XK_KP_Home) + { + int ival = 0; /* set to minimum */ + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + motValCallAction(ih, ival, 1); + *cont = False; + return; + } + if (motcode==XK_KP_End) + { + int ival = SHRT_MAX; /* set to maximum */ + XtVaSetValues(ih->handle, XmNvalue, ival, NULL); + motValCallAction(ih, ival, 1); + *cont = False; + return; + } + } +} + +static void motValValueChangedCallback(Widget w, Ihandle* ih, XmScaleCallbackStruct *cbs) +{ + int cb_state = 1; + + if(cbs->reason == XmCR_DRAG) + cb_state = 0; + else if (cbs->event && (cbs->event->type==ButtonRelease || cbs->event->type==KeyRelease)) + cb_state = -1; + + motValCallAction(ih, cbs->value, cb_state); + + (void)w; +} + +static void motValButtonPressReleaseEvent(Widget w, Ihandle* ih, XButtonEvent* evt, Boolean* cont) +{ + (void)w; + (void)cont; + + /* When Button1 is pressed, the Scrollbar loses its focus to the scale, + So we avoid calling GETFOCUS/KILLFOCUS. + */ + + if (evt->type==ButtonPress && evt->button==Button1) + { + iupAttribSetStr(ih, "_IUPVAL_IGNOREFOCUS", "1"); + } + if (evt->type==ButtonRelease && evt->button==Button1) + { + iupAttribSetStr(ih, "_IUPVAL_IGNOREFOCUS", NULL); + iupAttribSetStr(ih, "_IUPVAL_IGNOREKILLFOCUS", "1"); + } +} + +static void motValFocusChangeEvent(Widget w, Ihandle *ih, XEvent *evt, Boolean *cont) +{ + if (iupAttribGet(ih, "_IUPVAL_IGNOREFOCUS")) + return; + + if (evt->type == FocusOut && iupAttribGet(ih, "_IUPVAL_IGNOREKILLFOCUS")) + { + iupAttribSetStr(ih, "_IUPVAL_IGNOREKILLFOCUS", NULL); + return; + } + + iupmotFocusChangeEvent(w, ih, evt, cont); +} + + +/*********************************************************************************************/ + + +static int motValMapMethod(Ihandle* ih) +{ + int num_args = 0; + Arg args[30]; + int show_ticks; + + /* Core */ + iupmotSetArg(args, num_args, XmNmappedWhenManaged, False); /* not visible when managed */ + iupmotSetArg(args, num_args, XmNx, 0); /* x-position */ + iupmotSetArg(args, num_args, XmNy, 0); /* y-position */ + iupmotSetArg(args, num_args, XmNwidth, 10); /* default width to avoid 0 */ + iupmotSetArg(args, num_args, XmNheight, 10); /* default height to avoid 0 */ + /* Primitive */ + if (iupAttribGetBoolean(ih, "CANFOCUS")) + iupmotSetArg(args, num_args, XmNtraversalOn, True); + else + iupmotSetArg(args, num_args, XmNtraversalOn, False); + iupmotSetArg(args, num_args, XmNhighlightThickness, 2); + iupmotSetArg(args, num_args, XmNnavigationType, XmTAB_GROUP); + /* Scale */ + iupmotSetArg(args, num_args, XmNminimum, 0); + iupmotSetArg(args, num_args, XmNmaximum, SHRT_MAX); + iupmotSetArg(args, num_args, XmNslidingMode, XmSLIDER); + iupmotSetArg(args, num_args, XmNsliderMark, XmETCHED_LINE); + iupmotSetArg(args, num_args, XmNsliderSize, 16); + iupmotSetArg(args, num_args, XmNshowValue, XmNONE); + + if (ih->data->type == IVAL_HORIZONTAL) + { + iupmotSetArg(args, num_args, XmNorientation, XmHORIZONTAL); + if (ih->data->inverted) + iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_LEFT); + else + iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_RIGHT); + } + else + { + iupmotSetArg(args, num_args, XmNorientation, XmVERTICAL); + if (ih->data->inverted) + iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_TOP); + else + iupmotSetArg(args, num_args, XmNprocessingDirection, XmMAX_ON_BOTTOM); + } + + ih->handle = XtCreateManagedWidget( + iupDialogGetChildIdStr(ih), /* child identifier */ + xmScaleWidgetClass, /* widget class */ + iupChildTreeGetNativeParentHandle(ih), /* widget parent */ + args, num_args); + + if (!ih->handle) + return IUP_ERROR; + + /* callbacks */ + XtAddEventHandler(ih->handle, EnterWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + XtAddEventHandler(ih->handle, LeaveWindowMask, False, (XtEventHandler)iupmotEnterLeaveWindowEvent, (XtPointer)ih); + + /* XmScale changes the default behavior of these, must set directly into the scrollbar */ + /* XtAddEventHandler(ih->handle, FocusChangeMask, False, (XtEventHandler)iupmotFocusChangeEvent, (XtPointer)ih); */ + /* XtAddEventHandler(ih->handle, KeyPressMask, False, (XtEventHandler)iupmotKeyPressEvent, (XtPointer)ih); */ + + XtAddCallback(ih->handle, XmNdragCallback, (XtCallbackProc)motValValueChangedCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNvalueChangedCallback, (XtCallbackProc)motValValueChangedCallback, (XtPointer)ih); + XtAddCallback(ih->handle, XmNhelpCallback, (XtCallbackProc)iupmotHelpCallback, (XtPointer)ih); + + { + Widget sb = XtNameToWidget(ih->handle, "Scrollbar"); /* TODO: Test this in other Motifs */ + if (sb) + { + XtAddEventHandler(sb, FocusChangeMask, False, (XtEventHandler)motValFocusChangeEvent, (XtPointer)ih); + XtAddEventHandler(sb, KeyPressMask, False, (XtEventHandler)motValKeyPressEvent, (XtPointer)ih); + XtAddEventHandler(sb, ButtonPressMask|ButtonReleaseMask, False, (XtEventHandler)motValButtonPressReleaseEvent, (XtPointer)ih); + } + } + + /* Ticks can only be created before XtRealizeWidget */ + show_ticks = iupAttribGetInt(ih, "SHOWTICKS"); + if (show_ticks) + { + if (show_ticks<2) show_ticks=2; + ih->data->show_ticks = show_ticks; /* non zero value, can be changed later, but not to zero */ + } + + ih->serial = iupDialogGetChildId(ih); /* must be after using the string */ + + /* initialize the widget */ + XtRealizeWidget(ih->handle); + + return IUP_NOERROR; +} + +void iupdrvValInitClass(Iclass* ic) +{ + /* Driver Dependent Class functions */ + ic->Map = motValMapMethod; + + /* Driver Dependent Attribute functions */ + + /* Visual */ + iupClassRegisterAttribute(ic, "BGCOLOR", NULL, motValSetBgColorAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "BACKGROUND", NULL, motValSetBackgroundAttrib, IUPAF_SAMEASSYSTEM, "DLGBGCOLOR", IUPAF_DEFAULT); + + /* Special */ + + /* IupVal only */ + iupClassRegisterAttribute(ic, "VALUE", iupValGetValueAttrib, motValSetValueAttrib, NULL, NULL, IUPAF_NO_DEFAULTVALUE|IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "PAGESTEP", iupValGetPageStepAttrib, motValSetPageStepAttrib, IUPAF_SAMEASSYSTEM, "0.1", IUPAF_NO_INHERIT); + iupClassRegisterAttribute(ic, "SHOWTICKS", iupValGetShowTicksAttrib, motValSetShowTicksAttrib, IUPAF_SAMEASSYSTEM, "0", IUPAF_DEFAULT); + iupClassRegisterAttribute(ic, "STEP", iupValGetStepAttrib, motValSetStepAttrib, IUPAF_SAMEASSYSTEM, "0.01", IUPAF_NO_INHERIT); +} diff --git a/iup/src/mot/iupunix_help.c b/iup/src/mot/iupunix_help.c new file mode 100755 index 0000000..02be1da --- /dev/null +++ b/iup/src/mot/iupunix_help.c @@ -0,0 +1,44 @@ +/** \file + * \brief Motif Driver IupHelp + * + * See Copyright Notice in "iup.h" + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "iup.h" + +#include "iup_str.h" + +int IupHelp(const char *url) +{ + char *cmd; + int ret; + char *browser = getenv("IUP_HELPAPP"); + if (!browser) + browser = IupGetGlobal("HELPAPP"); + + if (!browser) + { + char* system = IupGetGlobal("SYSTEM"); + if (iupStrEqualNoCase(system, "Linux") || + iupStrEqualNoCase(system, "FreeBSD")) + browser = "firefox"; + else if (iupStrEqualNoCase(system, "Darwin")) + browser = "safari"; + else if (iupStrEqualPartial(system, "CYGWIN")) + browser = "iexplore"; + else + browser = "netscape"; + } + + cmd = (char*)malloc(sizeof(char)*(strlen(url)+strlen(browser)+3)); + sprintf(cmd, "%s %s &", browser, url); + ret = system(cmd); + free(cmd); + if (ret == -1) + return -1; + return 1; +} diff --git a/iup/src/mot/iupunix_info.c b/iup/src/mot/iupunix_info.c new file mode 100755 index 0000000..b522638 --- /dev/null +++ b/iup/src/mot/iupunix_info.c @@ -0,0 +1,305 @@ +/** \file + * \brief UNIX System Information + * + * See Copyright Notice in "iup.h" + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <limits.h> +#include <sys/stat.h> + +/* This module should depend only on IUP core headers + and UNIX system headers. NO Motif headers allowed. */ + +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/Xatom.h> +#include <sys/utsname.h> +#include <unistd.h> +#include <errno.h> +#include <sys/stat.h> + +#include "iup_str.h" +#include "iup_drvinfo.h" + + +int iupdrvMakeDirectory(const char* name) +{ + mode_t oldmask = umask((mode_t)0); + int fail = mkdir(name, S_IRUSR | S_IWUSR | S_IXUSR | S_IRGRP | + S_IWGRP | S_IXGRP | S_IROTH | S_IXOTH); + umask (oldmask); + if (fail) + return 0; + return 1; +} + +int iupdrvIsFile(const char* name) +{ + struct stat status; + if (stat(name, &status) != 0) + return 0; + if (S_ISDIR(status.st_mode)) + return 0; + return 1; +} + +int iupdrvIsDirectory(const char* name) +{ + struct stat status; + if (stat(name, &status) != 0) + return 0; + if (S_ISDIR(status.st_mode)) + return 1; + return 0; +} + +char* iupdrvGetCurrentDirectory(void) +{ + size_t size = 256; + char *buffer = (char *)malloc(size); + + for (;;) + { + if (getcwd(buffer, size) != NULL) + return buffer; + + if (errno != ERANGE) + { + free(buffer); + return NULL; + } + + size += size; + buffer = (char *)realloc(buffer, size); + } + + return NULL; +} + +int iupdrvSetCurrentDirectory(const char* dir) +{ + return chdir(dir) == 0? 1: 0; +} + +int iupdrvGetWindowDecor(void* wnd, int *border, int *caption) +{ + XWindowAttributes wa; + wa.x = 0; wa.y = 0; + XGetWindowAttributes((Display*)iupdrvGetDisplay(), (Window)wnd, &wa); + if (wa.x > 0 && wa.y > 0 && wa.y >= wa.x) + { + *border = wa.x; + *caption = wa.y - *border; + return 1; + } + + *border = 0; + *caption = 0; + + return 0; +} + +static int xGetWorkAreaSize(Display* display, int screen, int *width, int *height) +{ + /* _NET_WORKAREA, x, y, width, height CARDINAL[][4]/32 */ + static Atom workarea = 0; + Atom type; + long *data; + int format; + unsigned long after, ndata; + + if (!workarea) + workarea = XInternAtom(display, "_NET_WORKAREA", False); + + XGetWindowProperty(display, RootWindow(display, screen), + workarea, 0, LONG_MAX, False, XA_CARDINAL, &type, &format, &ndata, + &after, (unsigned char **)&data); + if (type != XA_CARDINAL || data == NULL) + { + if (data) XFree(data); + return 0; + } + + *width = data[2]; /* get only for the first desktop */ + *height = data[3]; + + XFree(data); + return 1; +} + +void iupdrvGetScreenSize(int *width, int *height) +{ + Display* display = (Display*)iupdrvGetDisplay(); + int screen = XDefaultScreen(display); + if (!xGetWorkAreaSize(display, screen, width, height)) + { + *width = DisplayWidth(display, screen); + *height = DisplayHeight(display, screen); + } +} + +void iupdrvGetFullSize(int *width, int *height) +{ + Display* display = (Display*)iupdrvGetDisplay(); + int screen = XDefaultScreen(display); + Window root = RootWindow(display, screen); + XWindowAttributes wa; + XGetWindowAttributes(display, root, &wa); + *width = wa.width; + *height = wa.height; +} + +static int xCheckVisualInfo(Display* drv_display, int bpp) +{ + int nitems; + XVisualInfo info, *ret_info; + + info.depth = bpp; + ret_info = XGetVisualInfo(drv_display, VisualDepthMask, &info, &nitems); + if (ret_info != NULL) + { + XFree(ret_info); + return 1; + } + return 0; +} + +int iupdrvGetScreenDepth(void) +{ + static int first = 1; + static int bpp; + + if (first) + { + Display* drv_display = (Display*)iupdrvGetDisplay(); + + if (xCheckVisualInfo(drv_display, 24)) + { + bpp = 24; + return bpp; + } + + if (xCheckVisualInfo(drv_display, 16)) + { + bpp = 16; + return bpp; + } + + if (xCheckVisualInfo(drv_display, 8)) + { + bpp = 8; + return bpp; + } + + if (xCheckVisualInfo(drv_display, 4)) + { + bpp = 4; + return bpp; + } + + bpp = 2; + + first = 0; + } + + return bpp; +} + +void iupdrvGetCursorPos(int *x, int *y) +{ + Window root, child; + int cx, cy; + unsigned int keys; + Display* display = (Display*)iupdrvGetDisplay(); + int screen = XDefaultScreen(display); + + XQueryPointer(display, RootWindow(display, screen), + &root, &child, x, y, &cx, &cy, &keys); +} + +static int xCheckModifier(KeyCode* modifiermap, int max_keypermod, int index, const char* keys) +{ + int i; + for (i = 0; i < max_keypermod; i++) + { + KeyCode key = modifiermap[max_keypermod * index + i]; + if (key) + { + int KeyIndex = key / 8; + int KeyMask = 1 << (key % 8); + if (keys[KeyIndex] & KeyMask) + return 1; + } + } + return 0; +} + +void iupdrvGetKeyState(char* key) +{ + char keys[32]; + Display* display = (Display*)iupdrvGetDisplay(); + XModifierKeymap *modMap = XGetModifierMapping(display); + XQueryKeymap(display, keys); + + if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, ShiftMapIndex, keys)) + key[0] = 'S'; + else + key[0] = ' '; + if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, ControlMapIndex, keys)) + key[1] = 'C'; + else + key[1] = ' '; + if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, Mod1MapIndex, keys) || + xCheckModifier(modMap->modifiermap, modMap->max_keypermod, Mod5MapIndex, keys)) + key[2] = 'A'; + else + key[2] = ' '; + if (xCheckModifier(modMap->modifiermap, modMap->max_keypermod, Mod4MapIndex, keys)) + key[3] = 'Y'; + else + key[3] = ' '; + + key[4] = 0; + + XFreeModifiermap(modMap); +} + +char *iupdrvGetSystemName(void) +{ + struct utsname un; + char *str = iupStrGetMemory(50); + + uname(&un); + strcpy(str, un.sysname); + + return str; +} + +char *iupdrvGetSystemVersion(void) +{ + struct utsname un; + char *str = iupStrGetMemory(60); + + uname(&un); + strcpy(str, un.release); + strcat(str, "."); + strcat(str, un.version); + + return str; +} + +char *iupdrvGetComputerName(void) +{ + char* str = iupStrGetMemory(50); + gethostname(str, 50); + return str; +} + +char *iupdrvGetUserName(void) +{ + return (char*)getlogin(); +} |