// // Portable File Dialogs // // Copyright © 2018—2020 Sam Hocevar // // This library is free software. It comes without any warranty, to // the extent permitted by applicable law. You can redistribute it // and/or modify it under the terms of the Do What the **** You Want // to Public License, Version 2, as published by the WTFPL Task Force. // See http://www.wtfpl.net/ for more details. // #pragma once #include // std::string #include // std::shared_ptr #include // std::map #include namespace pfd { enum class button { cancel = -1, ok, yes, no, abort, retry, ignore, }; enum class choice { ok = 0, ok_cancel, yes_no, yes_no_cancel, retry_cancel, abort_retry_ignore, }; enum class icon { info = 0, warning, error, question, }; // Additional option flags for various dialog constructors enum class opt : uint8_t { none = 0, // For file open, allow multiselect. multiselect = 0x1, // For file save, force overwrite and disable the confirmation dialog. force_overwrite = 0x2, // For folder select, force path to be the provided argument instead // of the last opened directory, which is the Microsoft-recommended, // user-friendly behaviour. force_path = 0x4, }; inline opt operator |(opt a, opt b) { return opt(uint8_t(a) | uint8_t(b)); } inline bool operator &(opt a, opt b) { return bool(uint8_t(a) & uint8_t(b)); } // The settings class, only exposing to the user a way to set verbose mode // and to force a rescan of installed desktop helpers (zenity, kdialog…). class settings { public: static bool available(); static void verbose(bool value); static void rescan(); protected: explicit settings(bool resync = false); bool check_program(std::string const &program); constexpr bool is_osascript() const { #if __APPLE__ return true; #else return false; #endif } bool is_zenity() const { return flags(flag::has_zenity) || flags(flag::has_matedialog) || flags(flag::has_qarma); } bool is_kdialog() const { return flags(flag::has_kdialog); } enum class flag { is_scanned = 0, is_verbose, has_zenity, has_matedialog, has_qarma, has_kdialog, is_vista, max_flag, }; // Static array of flags for internal state bool const &flags(flag in_flag) const; // Non-const getter for the static array of flags bool &flags(flag in_flag); }; // Internal classes, not to be used by client applications namespace internal { // Process wait timeout, in milliseconds constexpr int default_wait_timeout = 20; class executor; class dialog : protected settings { public: virtual ~dialog(); bool ready(int timeout = default_wait_timeout) const; bool kill() const; protected: explicit dialog(); std::vector desktop_helper() const; static std::string buttons_to_name(choice _choice); static std::string get_icon_name(icon _icon); std::string powershell_quote(std::string const &str) const; std::string osascript_quote(std::string const &str) const; std::string shell_quote(std::string const &str) const; // Keep handle to executing command std::shared_ptr m_async; }; class file_dialog : public internal::dialog { protected: enum type { open, save, folder, }; file_dialog(type in_type, std::string const &title, std::string const &default_path = "", std::vector const &filters = {}, opt options = opt::none); protected: std::string string_result(); std::vector vector_result(); class Impl; std::shared_ptr m_impl; }; } // namespace internal // // The notify widget // class notify : public internal::dialog { public: notify(std::string const &title, std::string const &message, icon _icon = icon::info); }; // // The message widget // class message : public internal::dialog { public: message(std::string const &title, std::string const &text, choice _choice = choice::ok_cancel, icon _icon = icon::info); button result(); private: // Some extra logic to map the exit code to button number std::map m_mappings; }; // // The open_file, save_file, and open_folder widgets // class open_file : public internal::file_dialog { public: explicit open_file(std::string const &title, std::string const &default_path = "", std::vector const &filters = { "All Files", "*" }, opt options = opt::none) : file_dialog(type::open, title, default_path, filters, options) {} std::vector result() { return vector_result(); } }; class save_file : public internal::file_dialog { public: explicit save_file(std::string const &title, std::string const &default_path = "", std::vector const &filters = { "All Files", "*" }, opt options = opt::none) : file_dialog(type::save, title, default_path, filters, options) {} std::string result() { return string_result(); } }; class select_folder : public internal::file_dialog { public: explicit select_folder(std::string const &title, std::string const &default_path = "", opt options = opt::none) : file_dialog(type::folder, title, default_path, {}, options) {} std::string result() { return string_result(); } }; } // namespace pfd