diff options
Diffstat (limited to 'iup/src/mot/iupmot_filedlg.c')
-rwxr-xr-x | iup/src/mot/iupmot_filedlg.c | 578 |
1 files changed, 578 insertions, 0 deletions
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; +} |