gyroflow/gyroflow-ofx

"Load preset/lens profile" button should open Gyroflow's camera_presets folder by default

latenitefilms opened this issue · 2 comments

Currently on macOS when you press the Load preset/lens profile button, it just defaults to the user's Desktop in the file open dialog. It would be better if it defaulted to /Applications/Gyroflow.app/Contents/Resources/camera_presets (assuming Gyroflow is installed).

Untested, and missing some logic, but maybe something along the lines of:

if in_args.get_name()? == "LoadLens" {
    let instance_data: &mut InstanceData = effect.get_instance_data()?;

    // Remember the current directory
    let current_dir = std::env::current_dir()?;

    // Set the default path
    let default_dir = "/Applications/Gyroflow.app/Contents/Resources/camera_presets";
    std::env::set_current_dir(&default_dir)?;

    let d = rfd::FileDialog::new().add_filter("Lens profiles and presets", &["json", "gyroflow"]);
    if let Some(d) = d.pick_file() {
        let d = d.display().to_string();
        if !d.is_empty() {
            if let Ok(contents) = std::fs::read_to_string(&d) {
                if d.ends_with(".json") {
                    instance_data.param_embedded_lens.set_value(contents)?;
                } else {
                    instance_data.param_embedded_preset.set_value(contents)?;
                }
            }
            instance_data.clear_stab();
        }
    }

    // Set back the original directory
    std::env::set_current_dir(current_dir)?;
}

However, we should also check that Gyroflow is actually installed. Maybe something along the lines of...

extern crate objc;
extern crate objc_foundation;
use objc::runtime::Object;
use objc::declare::ClassDecl;
use objc::runtime::Class;
use objc::runtime::Sel;
use objc_foundation::{NSString, INSString};
use std::ffi::CStr;

#[link(name = "Foundation", kind = "framework")]
extern {}

fn gyroflow_installed() -> bool {
    let bundle_id = NSString::from_str("xyz.gyroflow");
    let nsworkspace: *mut Object = msg_send![class!(NSWorkspace), sharedWorkspace];
    let url: *mut Object = msg_send![nsworkspace, URLForApplicationWithBundleIdentifier:bundle_id];
    !url.is_null()
}

fn main() {
    if gyroflow_installed() {
        println!("Gyroflow is installed!");
    } else {
        println!("Gyroflow is not installed!");
    }
}

Combining the two:

use objc::runtime::Object;
use objc::declare::ClassDecl;
use objc::rc::StrongPtr;
use objc_foundation::{INSObject, INSString, INSArray, NSArray, NSString};
use objc_id::Id;
use objc::sel;
use objc::sel_impl;
use std::path::Path;

if in_args.get_name()? == "LoadLens" {
    let instance_data: &mut InstanceData = effect.get_instance_data()?;
    let mut d = rfd::FileDialog::new().add_filter("Lens profiles and presets", &["json", "gyroflow"]);

    let bundle_id: StrongPtr = NSString::from_str("xyz.gyroflow").retain();

    let ns_workspace: StrongPtr = unsafe { msg_send![class!(NSWorkspace), sharedWorkspace] };
    let app_url: StrongPtr = unsafe { msg_send![ns_workspace.as_ref(), URLForApplicationWithBundleIdentifier:bundle_id] };

    if let Some(url) = app_url {
        let path: StrongPtr = unsafe { msg_send![url.as_ref(), path] };
        let rust_string = path.as_str().unwrap().to_string();
        let default_dir = rust_string + "/Contents/Resources/camera_presets";
        if Path::new(&default_dir).exists() {
            d = d.set_directory(&default_dir);
        }
    }

    if let Some(d) = d.pick_file() {
        let d = d.display().to_string();
        if !d.is_empty() {
            if let Ok(contents) = std::fs::read_to_string(&d) {
                if d.ends_with(".json") {
                    instance_data.param_embedded_lens.set_value(contents)?;
                } else {
                    instance_data.param_embedded_preset.set_value(contents)?;
                }
            }
            instance_data.clear_stab();
        }
    }
}

We'd also need to do the equivalent for Windows and Linux.

@AdrianEddy said we should use this set_directory method.

There's also this existing method for getting the exeLocation:

pub fn open_gyroflow(&self) {
        if let Some(v) = gyroflow_core::util::get_setting("exeLocation") {

Done in e498d34