summaryrefslogtreecommitdiff
path: root/iup/src/win/iupwin_filedlg.c
diff options
context:
space:
mode:
Diffstat (limited to 'iup/src/win/iupwin_filedlg.c')
-rwxr-xr-xiup/src/win/iupwin_filedlg.c580
1 files changed, 580 insertions, 0 deletions
diff --git a/iup/src/win/iupwin_filedlg.c b/iup/src/win/iupwin_filedlg.c
new file mode 100755
index 0000000..da66b4b
--- /dev/null
+++ b/iup/src/win/iupwin_filedlg.c
@@ -0,0 +1,580 @@
+/** \file
+ * \brief IupFileDlg pre-defined dialog
+ *
+ * See Copyright Notice in "iup.h"
+ */
+
+#include <windows.h>
+#include <commdlg.h>
+#include <shlobj.h>
+
+#include <stdio.h>
+
+#include "iup.h"
+#include "iupcbs.h"
+
+#include "iup_object.h"
+#include "iup_attrib.h"
+#include "iup_str.h"
+#include "iup_dialog.h"
+#include "iup_drvinfo.h"
+
+#include "iupwin_drv.h"
+
+
+#ifndef OFN_FORCESHOWHIDDEN
+#define OFN_FORCESHOWHIDDEN 0x10000000 /* Show All files including System and hidden files */
+#endif
+
+#define MAX_FILENAME_SIZE 65000
+#define IUP_PREVIEWCANVAS 3000
+
+enum {IUP_DIALOGOPEN, IUP_DIALOGSAVE, IUP_DIALOGDIR};
+
+
+static void winFileDlgStrReplacePathSlash(char* name)
+{
+ /* check for "/" */
+ int i, len = strlen(name);
+ for (i = 0; i < len; i++)
+ {
+ if (name[i] == '/')
+ name[i] = '\\';
+ }
+}
+
+static INT CALLBACK winFileDlgBrowseCallback(HWND hWnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
+{
+ (void)lParam;
+ if (uMsg == BFFM_INITIALIZED)
+ {
+ char* value;
+ Ihandle* ih = (Ihandle*)lpData;
+ ih->handle = hWnd;
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+ value = iupStrDup(iupAttribGet(ih, "DIRECTORY"));
+ if (value)
+ {
+ winFileDlgStrReplacePathSlash(value);
+ SendMessage(hWnd, BFFM_SETSELECTION, TRUE, (LPARAM)value);
+ free(value);
+ }
+ }
+ else if (uMsg == BFFM_SELCHANGED)
+ {
+ char* buffer = iupStrGetMemory(MAX_FILENAME_SIZE);
+ ITEMIDLIST* selecteditem = (ITEMIDLIST*)lParam;
+ buffer[0] = 0;
+ SHGetPathFromIDList(selecteditem, buffer);
+ if (buffer[0] == 0)
+ SendMessage(hWnd, BFFM_ENABLEOK, 0, (LPARAM)FALSE);
+ else
+ SendMessage(hWnd, BFFM_ENABLEOK, 0, (LPARAM)TRUE);
+ }
+ return 0;
+}
+
+static void winFileDlgGetFolder(Ihandle *ih)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ BROWSEINFO browseinfo;
+ char buffer[MAX_PATH];
+ ITEMIDLIST *selecteditem;
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ ZeroMemory(&browseinfo, sizeof(BROWSEINFO));
+ browseinfo.lpszTitle = iupAttribGet(ih, "TITLE");
+ browseinfo.pszDisplayName = buffer;
+ browseinfo.lpfn = winFileDlgBrowseCallback;
+ browseinfo.lParam = (LPARAM)ih;
+ browseinfo.ulFlags = BIF_NEWDIALOGSTYLE;
+ browseinfo.hwndOwner = parent;
+
+ selecteditem = SHBrowseForFolder(&browseinfo);
+ if (!selecteditem)
+ {
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ }
+ else
+ {
+ SHGetPathFromIDList(selecteditem, buffer);
+ iupAttribStoreStr(ih, "VALUE", buffer);
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "FILTERUSED", NULL);
+}
+
+/************************************************************************************************/
+
+static UINT_PTR CALLBACK winFileDlgSimpleHook(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ (void)wParam;
+ switch(uiMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ OPENFILENAME* openfilename = (OPENFILENAME*)lParam;
+ Ihandle* ih = (Ihandle*)openfilename->lCustData;
+ ih->handle = GetParent(hWnd);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+ SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)ih);
+ break;
+ }
+ case WM_DESTROY:
+ {
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (cb) cb(ih, NULL, "FINISH");
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ LPOFNOTIFY pofn = (LPOFNOTIFY)lParam;
+ Ihandle* ih = (Ihandle*)pofn->lpOFN->lCustData;
+ switch (pofn->hdr.code)
+ {
+ case CDN_INITDONE:
+ {
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (cb) cb(ih, NULL, "INIT");
+ break;
+ }
+ case CDN_FILEOK:
+ case CDN_SELCHANGE:
+ {
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ if (cb)
+ {
+ char* filename = iupStrGetMemory(MAX_FILENAME_SIZE);
+ if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE)
+ {
+ int ret;
+ char* file_msg;
+
+ if (!iupdrvIsFile(filename))
+ break;
+
+ if (pofn->hdr.code == CDN_FILEOK)
+ file_msg = "OK";
+ else
+ file_msg = "SELECT";
+
+ ret = cb(ih, filename, file_msg);
+ if (pofn->hdr.code == CDN_FILEOK && ret == IUP_IGNORE)
+ {
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1L);
+ return 1; /* will refuse the file */
+ }
+ }
+ }
+ break;
+ }
+ case CDN_HELP:
+ {
+ Icallback cb = (Icallback) IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ EndDialog(GetParent(hWnd), IDCANCEL);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static void winFileDlgSetPreviewCanvasPos(HWND hWnd, HWND hWndPreview)
+{
+ int height, width, ypos, xpos;
+ RECT rect, dlgrect;
+ HWND hWndFileList = GetDlgItem(GetParent(hWnd), 0x0471);
+ HWND hWndFileCombo = GetDlgItem(GetParent(hWnd), 0x047C);
+
+ /* GetWindowRect return screen coordinates, must convert to parent's client coordinates */
+ GetWindowRect(hWnd, &dlgrect);
+
+ GetWindowRect(hWndPreview, &rect);
+ ypos = rect.top - dlgrect.top; /* keep the same vertical position, at first time this is 0 */
+ height = rect.bottom-rect.top; /* keep the same height */
+
+ GetWindowRect(hWndFileList, &rect);
+ xpos = rect.left - dlgrect.left; /* horizontally align with file list at left */
+
+ GetWindowRect(hWndFileCombo, &rect);
+ width = (rect.right - dlgrect.left) - xpos; /* set size to align with file combo at right */
+
+ /* also position the child window that contains the template, must have room for the preview canvas */
+ if (ypos) /* first time does nothing */
+ SetWindowPos(hWnd, HWND_BOTTOM, 0, 0, (rect.right - dlgrect.left), (dlgrect.bottom - dlgrect.top), SWP_NOMOVE|SWP_NOZORDER);
+
+ SetWindowPos(hWndPreview, HWND_TOP, xpos, ypos, width, height, SWP_NOZORDER);
+}
+
+static void winFileDlgUpdatePreviewGLCanvas(Ihandle* ih)
+{
+ Ihandle* glcanvas = IupGetAttributeHandle(ih, "PREVIEWGLCANVAS");
+ if (glcanvas)
+ {
+ iupAttribSetStr(glcanvas, "HWND", iupAttribGet(ih, "HWND"));
+ glcanvas->iclass->Map(glcanvas);
+ }
+}
+
+static UINT_PTR CALLBACK winFileDlgPreviewHook(HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam)
+{
+ /* hWnd here is a handle to the child window that contains the template,
+ NOT the file dialog. Only the preview canvas is a child of this window. */
+
+ switch(uiMsg)
+ {
+ case WM_INITDIALOG:
+ {
+ OPENFILENAME* openfilename = (OPENFILENAME*)lParam;
+ Ihandle* ih = (Ihandle*)openfilename->lCustData;
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+
+ ih->handle = GetParent(hWnd);
+ iupDialogUpdatePosition(ih);
+ ih->handle = NULL; /* reset handle */
+
+ if (hWndPreview)
+ {
+ RECT rect;
+
+ winFileDlgSetPreviewCanvasPos(hWnd, hWndPreview);
+
+ GetClientRect(hWndPreview, &rect);
+ iupAttribSetInt(ih, "PREVIEWWIDTH", rect.right - rect.left);
+ iupAttribSetInt(ih, "PREVIEWHEIGHT", rect.bottom - rect.top);
+ }
+ SetWindowLongPtr(hWnd, DWLP_USER, (LONG_PTR)ih);
+ iupAttribSetStr(ih, "WID", (char*)hWndPreview);
+ iupAttribSetStr(ih, "HWND", (char*)hWndPreview);
+ winFileDlgUpdatePreviewGLCanvas(ih);
+ break;
+ }
+ case WM_DRAWITEM:
+ {
+ if (wParam == IUP_PREVIEWCANVAS)
+ {
+ LPDRAWITEMSTRUCT lpDrawItem = (LPDRAWITEMSTRUCT)lParam;
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ char* filename = iupStrGetMemory(MAX_FILENAME_SIZE);
+ iupAttribSetStr(ih, "PREVIEWDC", (char*)lpDrawItem->hDC);
+ if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE)
+ {
+ if (iupdrvIsFile(filename))
+ cb(ih, filename, "PAINT");
+ else
+ cb(ih, NULL, "PAINT");
+ }
+ else
+ cb(ih, NULL, "PAINT");
+ iupAttribSetStr(ih, "PREVIEWDC", NULL);
+ }
+ break;
+ }
+ case WM_SIZE:
+ {
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+ if (hWndPreview)
+ {
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ RECT rect;
+
+ winFileDlgSetPreviewCanvasPos(hWnd, hWndPreview);
+
+ GetClientRect(hWndPreview, &rect);
+ iupAttribSetInt(ih, "PREVIEWWIDTH", rect.right-rect.left);
+
+ RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);
+ }
+ break;
+ }
+ case WM_DESTROY:
+ {
+ Ihandle* ih = (Ihandle*)GetWindowLongPtr(hWnd, DWLP_USER);
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ cb(ih, NULL, "FINISH");
+ break;
+ }
+ case WM_NOTIFY:
+ {
+ LPOFNOTIFY pofn = (LPOFNOTIFY)lParam;
+ Ihandle* ih = (Ihandle*)pofn->lpOFN->lCustData;
+ IFnss cb = (IFnss)IupGetCallback(ih, "FILE_CB");
+ switch (pofn->hdr.code)
+ {
+ case CDN_INITDONE:
+ {
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+ cb(ih, NULL, "INIT");
+ if (hWndPreview) RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);
+ break;
+ }
+ case CDN_FILEOK:
+ case CDN_SELCHANGE:
+ {
+ HWND hWndPreview = GetDlgItem(hWnd, IUP_PREVIEWCANVAS);
+ char* filename = iupStrGetMemory(MAX_FILENAME_SIZE);
+ if (CommDlg_OpenSave_GetFilePath(GetParent(hWnd), filename, MAX_FILENAME_SIZE) <= MAX_FILENAME_SIZE)
+ {
+ int ret;
+ char* file_msg;
+
+ if (!iupdrvIsFile(filename))
+ break;
+
+ if (pofn->hdr.code == CDN_FILEOK)
+ file_msg = "OK";
+ else
+ file_msg = "SELECT";
+
+ ret = cb(ih, filename, file_msg);
+ if (pofn->hdr.code == CDN_FILEOK && ret == IUP_IGNORE)
+ {
+ SetWindowLongPtr(hWnd, DWLP_MSGRESULT, 1L);
+ return 1; /* will refuse the file */
+ }
+ }
+ if (pofn->hdr.code == CDN_SELCHANGE && hWndPreview)
+ RedrawWindow(hWndPreview, NULL, NULL, RDW_INVALIDATE|RDW_UPDATENOW);
+ break;
+ }
+ case CDN_HELP:
+ {
+ Icallback cb = (Icallback) IupGetCallback(ih, "HELP_CB");
+ if (cb && cb(ih) == IUP_CLOSE)
+ EndDialog(GetParent(hWnd), IDCANCEL);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static char* winFileDlgStrReplaceSeparator(const char* name)
+{
+ int i=0;
+ char* buffer = (char*)malloc(strlen(name)+2);
+
+ /* replace symbols "|" by terminator "\0" */
+
+ while (*name)
+ {
+ buffer[i] = *name;
+
+ if (buffer[i] == '|')
+ buffer[i] = 0;
+
+ i++;
+ name++;
+ }
+
+ buffer[i] = 0;
+ buffer[i+1] = 0; /* additional 0 at the end */
+ return buffer;
+}
+
+static int winFileDlgPopup(Ihandle *ih, int x, int y)
+{
+ InativeHandle* parent = iupDialogGetNativeParent(ih);
+ OPENFILENAME openfilename;
+ int result, dialogtype;
+ 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;
+
+ if (dialogtype == IUP_DIALOGDIR)
+ {
+ winFileDlgGetFolder(ih);
+ return IUP_NOERROR;
+ }
+
+ if (!parent)
+ parent = GetActiveWindow();
+
+ ZeroMemory(&openfilename, sizeof(OPENFILENAME));
+ openfilename.lStructSize = sizeof(OPENFILENAME);
+ openfilename.hwndOwner = parent;
+
+ value = iupAttribGet(ih, "EXTFILTER");
+ if (value)
+ {
+ int index;
+ openfilename.lpstrFilter = winFileDlgStrReplaceSeparator(value);
+
+ value = iupAttribGet(ih, "FILTERUSED");
+ if (iupStrToInt(value, &index))
+ openfilename.nFilterIndex = index;
+ else
+ openfilename.nFilterIndex = 1;
+ }
+ else
+ {
+ value = iupAttribGet(ih, "FILTER");
+ if (value)
+ {
+ int sz1, sz2;
+ char* info = iupAttribGet(ih, "FILTERINFO");
+ if (!info)
+ info = value;
+
+ /* concat FILTERINFO+FILTER */
+ sz1 = strlen(info)+1;
+ sz2 = strlen(value)+1;
+ openfilename.lpstrFilter = (char*)malloc(sz1+sz2+1);
+
+ memcpy((char*)openfilename.lpstrFilter, info, sz1);
+ memcpy((char*)openfilename.lpstrFilter+sz1, value, sz2);
+ ((char*)openfilename.lpstrFilter)[sz1+sz2] = 0; /* additional 0 at the end */
+ openfilename.nFilterIndex = 1;
+ }
+ }
+
+ openfilename.lpstrFile = (char*)malloc(MAX_FILENAME_SIZE+1);
+ value = iupAttribGet(ih, "FILE");
+ if (value)
+ {
+ strncpy(openfilename.lpstrFile, value, MAX_FILENAME_SIZE);
+ winFileDlgStrReplacePathSlash(openfilename.lpstrFile);
+ }
+ else
+ openfilename.lpstrFile[0] = 0;
+
+ openfilename.nMaxFile = MAX_FILENAME_SIZE;
+
+ openfilename.lpstrInitialDir = iupStrDup(iupAttribGet(ih, "DIRECTORY"));
+ if (openfilename.lpstrInitialDir)
+ winFileDlgStrReplacePathSlash((char*)openfilename.lpstrInitialDir);
+
+ openfilename.lpstrTitle = iupAttribGet(ih, "TITLE");
+ openfilename.Flags = OFN_PATHMUSTEXIST | OFN_HIDEREADONLY;
+
+ if (!iupAttribGetBoolean(ih, "NOOVERWRITEPROMPT"))
+ openfilename.Flags |= OFN_OVERWRITEPROMPT;
+
+ if (iupAttribGetBoolean(ih, "SHOWHIDDEN"))
+ openfilename.Flags |= OFN_FORCESHOWHIDDEN;
+
+ value = iupAttribGet(ih, "ALLOWNEW");
+ if (!value)
+ {
+ if (dialogtype == IUP_DIALOGSAVE)
+ value = "YES";
+ else
+ value = "NO";
+ }
+ if (iupStrBoolean(value))
+ openfilename.Flags |= OFN_CREATEPROMPT;
+ else
+ openfilename.Flags |= OFN_FILEMUSTEXIST;
+
+ if (iupAttribGetBoolean(ih, "NOCHANGEDIR"))
+ openfilename.Flags |= OFN_NOCHANGEDIR;
+
+ if (iupAttribGetBoolean(ih, "MULTIPLEFILES"))
+ openfilename.Flags |= OFN_ALLOWMULTISELECT;
+
+ openfilename.lpfnHook = winFileDlgSimpleHook;
+ openfilename.Flags |= OFN_ENABLEHOOK | OFN_EXPLORER | OFN_ENABLESIZING;
+ openfilename.lCustData = (LPARAM)ih;
+
+ if (iupAttribGetBoolean(ih, "SHOWPREVIEW") && IupGetCallback(ih, "FILE_CB"))
+ {
+ openfilename.Flags |= OFN_ENABLETEMPLATE;
+ openfilename.hInstance = iupwin_dll_hinstance? iupwin_dll_hinstance: iupwin_hinstance;
+ openfilename.lpTemplateName = "iupPreviewDlg";
+ openfilename.lpfnHook = winFileDlgPreviewHook;
+ }
+
+ if (IupGetCallback(ih, "HELP_CB"))
+ openfilename.Flags |= OFN_SHOWHELP;
+
+ if (dialogtype == IUP_DIALOGOPEN)
+ result = GetOpenFileName(&openfilename);
+ else
+ result = GetSaveFileName(&openfilename);
+
+ if (result)
+ {
+ if (iupAttribGetBoolean(ih, "MULTIPLEFILES"))
+ {
+ int i = 0;
+
+ /* If there is more than one file, replace terminator by the separator */
+ if (openfilename.lpstrFile && openfilename.lpstrFile[openfilename.nFileOffset-1] == 0 && openfilename.nFileOffset>0)
+ {
+ while (openfilename.lpstrFile[i] != 0 || openfilename.lpstrFile[i+1] != 0)
+ {
+ if (openfilename.lpstrFile[i]==0)
+ openfilename.lpstrFile[i] = '|';
+ i++;
+ }
+ openfilename.lpstrFile[i] = '|';
+ }
+
+ iupAttribSetStr(ih, "STATUS", "0");
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ }
+ else
+ {
+ if (iupdrvIsFile(openfilename.lpstrFile)) /* check if file exists */
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "YES");
+ iupAttribSetStr(ih, "STATUS", "0");
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILEEXIST", "NO");
+ iupAttribSetStr(ih, "STATUS", "1");
+ }
+ }
+
+ iupAttribStoreStr(ih, "VALUE", openfilename.lpstrFile);
+ iupAttribSetInt(ih, "FILTERUSED", (int)openfilename.nFilterIndex);
+ }
+ else
+ {
+ iupAttribSetStr(ih, "FILTERUSED", NULL);
+ iupAttribSetStr(ih, "VALUE", NULL);
+ iupAttribSetStr(ih, "FILEEXIST", NULL);
+ iupAttribSetStr(ih, "STATUS", "-1");
+ }
+
+ if (openfilename.lpstrFilter) free((char*)openfilename.lpstrFilter);
+ if (openfilename.lpstrInitialDir) free((char*)openfilename.lpstrInitialDir);
+ if (openfilename.lpstrFile) free(openfilename.lpstrFile);
+
+ return IUP_NOERROR;
+}
+
+void iupdrvFileDlgInitClass(Iclass* ic)
+{
+ ic->DlgPopup = winFileDlgPopup;
+
+ /* IupFileDialog Windows and GTK Only */
+ iupClassRegisterAttribute(ic, "EXTFILTER", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTERINFO", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "FILTERUSED", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+ iupClassRegisterAttribute(ic, "MULTIPLEFILES", NULL, NULL, NULL, NULL, IUPAF_NO_INHERIT);
+}