summary refs log tree commit diff stats
path: root/lib/impure/dialogs.nim
diff options
context:
space:
mode:
Diffstat (limited to 'lib/impure/dialogs.nim')
-rw-r--r--lib/impure/dialogs.nim234
1 files changed, 234 insertions, 0 deletions
diff --git a/lib/impure/dialogs.nim b/lib/impure/dialogs.nim
new file mode 100644
index 000000000..cf81a3d29
--- /dev/null
+++ b/lib/impure/dialogs.nim
@@ -0,0 +1,234 @@
+#
+#
+#            Nimrod's Runtime Library
+#        (c) Copyright 2009 Andreas Rumpf
+#
+#    See the file "copying.txt", included in this
+#    distribution, for details about the copyright.
+#
+
+
+## This module implements portable dialogs for Nimrod; the implementation
+## builds on the GTK interface. On Windows, native dialogs are shown if
+## appropriate.
+
+import
+  glib2, gtk2
+
+when defined(Windows):
+  import windows, ShellAPI, os
+
+type
+  PWindow* = PGtkWindow ## A shortcut for a GTK window.
+
+proc info*(window: PWindow, msg: string) =
+  ## Shows an information message to the user. The process waits until the
+  ## user presses the OK button.
+  when defined(Windows):
+    discard MessageBoxA(0, msg, "Information", MB_OK or MB_ICONINFORMATION)
+  else:
+    var dialog = GTK_DIALOG(gtk_message_dialog_new(window,
+                GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT,
+                GTK_MESSAGE_INFO, GTK_BUTTONS_OK, "%s", cstring(msg)))
+    gtk_window_set_title(dialog, "Information")
+    discard gtk_dialog_run(dialog)
+    gtk_widget_destroy(dialog)
+
+proc warning*(window: PWindow, msg: string) =
+  ## Shows a warning message to the user. The process waits until the user
+  ## presses the OK button.
+  when defined(Windows):
+    discard MessageBoxA(0, msg, "Warning", MB_OK or MB_ICONWARNING)
+  else:
+    var dialog = GTK_DIALOG(gtk_message_dialog_new(window,
+                GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT,
+                GTK_MESSAGE_WARNING, GTK_BUTTONS_OK, "%s", cstring(msg)))
+    gtk_window_set_title(dialog, "Warning")
+    discard gtk_dialog_run(dialog)
+    gtk_widget_destroy(dialog)
+
+proc error*(window: PWindow, msg: string) =
+  ## Shows an error message to the user. The process waits until the user
+  ## presses the OK button.
+  when defined(Windows):
+    discard MessageBoxA(0, msg, "Error", MB_OK or MB_ICONERROR)
+  else:
+    var dialog = GTK_DIALOG(gtk_message_dialog_new(window,
+                GTK_DIALOG_MODAL or GTK_DIALOG_DESTROY_WITH_PARENT,
+                GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "%s", cstring(msg)))
+    gtk_window_set_title(dialog, "Error")
+    discard gtk_dialog_run(dialog)
+    gtk_widget_destroy(dialog)
+
+
+proc ChooseFileToOpen*(window: PWindow, root: string = ""): string =
+  ## Opens a dialog that requests a filename from the user. Returns ""
+  ## if the user closed the dialog without selecting a file. On Windows,
+  ## the native dialog is used, else the GTK dialog is used.
+  when defined(Windows):
+    var
+      opf: TOPENFILENAME
+      buf: array [0..2047, char]
+    opf.lStructSize = sizeof(opf)
+    if root.len > 0:
+      opf.lpstrInitialDir = root
+    opf.lpstrFilter = "All Files\0*.*\0\0"
+    opf.flags = OFN_FILEMUSTEXIST
+    opf.lpstrFile = buf
+    opf.nMaxFile = sizeof(buf)
+    var res = GetOpenFileName(addr(opf))
+    if res != 0:
+      result = $buf
+    else:
+      result = ""
+  else:
+    var
+      chooser: PGtkDialog
+    chooser = GTK_DIALOG(gtk_file_chooser_dialog_new("Open File", window,
+                GTK_FILE_CHOOSER_ACTION_OPEN,
+                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil))
+    if root.len > 0:
+      discard gtk_file_chooser_set_current_folder(chooser, root)
+    if gtk_dialog_run(chooser) == cint(GTK_RESPONSE_OK):
+      var x = gtk_file_chooser_get_filename(chooser)
+      result = $x
+      g_free(x)
+    else:
+      result = ""
+    gtk_widget_destroy(chooser)
+
+proc ChooseFilesToOpen*(window: PWindow, root: string = ""): seq[string] =
+  ## Opens a dialog that requests filenames from the user. Returns ``@[]``
+  ## if the user closed the dialog without selecting a file. On Windows,
+  ## the native dialog is used, else the GTK dialog is used.
+  when defined(Windows):
+    var
+      opf: TOPENFILENAME
+      buf: array [0..2047*4, char]
+    opf.lStructSize = sizeof(opf)
+    if root.len > 0:
+      opf.lpstrInitialDir = root
+    opf.lpstrFilter = "All Files\0*.*\0\0"
+    opf.flags = OFN_FILEMUSTEXIST or OFN_ALLOWMULTISELECT or OFN_EXPLORER
+    opf.lpstrFile = buf
+    opf.nMaxFile = sizeof(buf)
+    var res = GetOpenFileName(addr(opf))
+    result = @[]
+    if res != 0:
+      # parsing the result is horrible:
+      var
+        i = 0
+        s: string
+        path = ""
+      while buf[i] != '\0':
+        add(path, buf[i])
+        inc(i)
+      inc(i)
+      if buf[i] != '\0':
+        while true:
+          s = ""
+          while buf[i] != '\0':
+            add(s, buf[i])
+            inc(i)
+          add(result, s)
+          inc(i)
+          if buf[i] == '\0': break
+        for i in 0..result.len-1: result[i] = os.joinPath(path, result[i])
+  else:
+    var
+      chooser: PGtkDialog
+    chooser = GTK_DIALOG(gtk_file_chooser_dialog_new("Open Files", window,
+                GTK_FILE_CHOOSER_ACTION_OPEN,
+                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil))
+    if root.len > 0:
+      discard gtk_file_chooser_set_current_folder(chooser, root)
+    gtk_file_chooser_set_select_multiple(chooser, true)
+    result = @[]
+    if gtk_dialog_run(chooser) == cint(GTK_RESPONSE_OK):
+      var L = gtk_file_chooser_get_filenames(chooser)
+      var it = L
+      while it != nil:
+        add(result, $cast[cstring](it.data))
+        g_free(it.data)
+        it = it.next
+      g_slist_free(L)
+    gtk_widget_destroy(chooser)
+
+
+proc ChooseFileToSave*(window: PWindow, root: string = ""): string =
+  ## Opens a dialog that requests a filename to save to from the user.
+  ## Returns "" if the user closed the dialog without selecting a file.
+  ## On Windows, the native dialog is used, else the GTK dialog is used.
+  when defined(Windows):
+    var
+      opf: TOPENFILENAME
+      buf: array [0..2047, char]
+    opf.lStructSize = sizeof(opf)
+    if root.len > 0:
+      opf.lpstrInitialDir = root
+    opf.lpstrFilter = "All Files\0*.*\0\0"
+    opf.flags = OFN_OVERWRITEPROMPT
+    opf.lpstrFile = buf
+    opf.nMaxFile = sizeof(buf)
+    var res = GetSaveFileName(addr(opf))
+    if res != 0:
+      result = $buf
+    else:
+      result = ""
+  else:
+    var
+      chooser: PGtkDialog
+    chooser = GTK_DIALOG(gtk_file_chooser_dialog_new("Save File", window,
+                GTK_FILE_CHOOSER_ACTION_SAVE,
+                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil))
+    if root.len > 0:
+      discard gtk_file_chooser_set_current_folder(chooser, root)
+    gtk_file_chooser_set_do_overwrite_confirmation(chooser, true)
+    if gtk_dialog_run(chooser) == cint(GTK_RESPONSE_OK):
+      var x = gtk_file_chooser_get_filename(chooser)
+      result = $x
+      g_free(x)
+    else:
+      result = ""
+    gtk_widget_destroy(chooser)
+
+
+proc ChooseDir*(window: PWindow, root: string = ""): string =
+  ## Opens a dialog that requests a directory from the user.
+  ## Returns "" if the user closed the dialog without selecting a directory.
+  ## On Windows, the native dialog is used, else the GTK dialog is used.
+  when defined(Windows):
+    var
+      lpItemID: PItemIDList
+      BrowseInfo: TBrowseInfo
+      DisplayName: array [0..MAX_PATH, char]
+      TempPath: array [0..MAX_PATH, char]
+    Result = ""
+    #BrowseInfo.hwndOwner = Application.Handle
+    BrowseInfo.pszDisplayName = DisplayName
+    BrowseInfo.ulFlags = 1 #BIF_RETURNONLYFSDIRS
+    lpItemID = SHBrowseForFolder(cast[LPBrowseInfo](addr(BrowseInfo)))
+    if lpItemId != nil:
+      discard SHGetPathFromIDList(lpItemID, TempPath)
+      Result = $TempPath
+      discard GlobalFreePtr(lpItemID)
+  else:
+    var
+      chooser: PGtkDialog
+    chooser = GTK_DIALOG(gtk_file_chooser_dialog_new("Select Directory", window,
+                GTK_FILE_CHOOSER_ACTION_SELECT_FOLDER,
+                GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                GTK_STOCK_OPEN, GTK_RESPONSE_OK, nil))
+    if root.len > 0:
+      discard gtk_file_chooser_set_current_folder(chooser, root)
+    if gtk_dialog_run(chooser) == cint(GTK_RESPONSE_OK):
+      var x = gtk_file_chooser_get_filename(chooser)
+      result = $x
+      g_free(x)
+    else:
+      result = ""
+    gtk_widget_destroy(chooser)
+