Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal for API evolution, to make room for future funtionality. #84

Open
gamagan opened this issue Mar 9, 2023 · 0 comments
Open

Comments

@gamagan
Copy link

gamagan commented Mar 9, 2023

Hello,

Currently, the API for PFD works well for the functionality it provides.
However, there is a possibility for growth in this space of portable dialogs,
which will (eventually) necessitate updating the interface to accept more data.

My own request, to allow setting the parent window for the dialogs, is an example
of possible evolution: #82

At the same time, the library needs to deal with, at least, 3 platforms; each of which has
their own particular needs: Windows, Linux, and macOS.

To support this evolution and the need to support multiple platforms, I propose that the interface
to the user facing functions/constructor (eg: save_file, open_file, select_folder, message) be updated to
receive a single struct. This struct contains all the info needed by the function/constructor.

  1. Each function receives a struct specific to it. Common functionality can be placed in a base struct.
  2. Struct args provide a straightforward way to pass lots of data, and to pass platform specific bits, as well.
  3. Based on the current design, it should be possible to instantiate a default struct for the function
    and call that function with that default object and get something showing on screen.
    This is nice, from an ergonomic perspective, because it gets the user interacting with a dialog with minimal fuss.
     pfd::open_file_info info;
     auto r = pfd::open_file(info).result();
    
  4. In the future, updating these struct params can be done without further changing the public function signatures.
    New fields can just be added to the structs.
  5. Instead of calling the construtors directly, call functions that return the constructed objects. That provides more flexibility for evolving the api.
// open_file_diag open_file(open_file_info&&); // maybe
open_file_diag open_file(const open_file_info& info) {
    // Possibly inspect the 'info' object and assert() on debug.
    constexpr auto ctx = get_ctx_object(); // Who knows, maybe this is a compile-time object, configured by the user-dev.
    open_file_diag diag(ctx, info);        // Example of additional 'ctx' object that dialog objects could accept. Just an example.
    return diag;                           // No copy performed: C++ now guarantees NRVO.
}

Example 'info/param' API:

struct base_info {
    std::string title = "untitled";
    // ...
};

struct open_file_info : base_info {
    // Common platform properties at the top-level.        
    std::vector<std::string> filters = {"All Files (*.*)", "*.*"};
    bool force_folder = false;

    // Platform specific bits within 'namespacing' objects.
    #ifdef IS_LINUX
        struct {
            // ...
        } linux;
    #elif IS_WINDOWS
        struct {
            HWND owner_hwnd = 0;
        } windows;
    #elif IS_MAC
        struct {
            // ...
        } mac;
    #else
        #error Unsupported platform.
    #endif    
};

open_file_info info;
info.title   = "My Open Dialog";
info.filters = {"Text (*.txt)", "*.txt", "Binary (*.b, *.bc, *.bin)", "*.b *.bc *.bin"};

#ifdef IS_WINDOWS
info.windows.owner_hwnd = get_owner_hwnd();
#endif

auto r = pfd::open_file(info).result();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant