Skip to content

Commit 8ea9b33

Browse files
committed
Initial commit
0 parents  commit 8ea9b33

File tree

8 files changed

+181
-0
lines changed

8 files changed

+181
-0
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
target
2+
Cargo.lock

Cargo.toml

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[package]
2+
name = "nfd"
3+
version = "0.0.1"
4+
authors = ["Saurav Sachidanand <[email protected]>"]
5+
6+
build = "build.rs"
7+
8+
[dependencies]
9+
libc = "0.2.7"

LICENSE.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
Copyright (c) 2015 Saurav Sachidanand
2+
3+
Permission is hereby granted, free of charge, to any person obtaining a copy
4+
of this software and associated documentation files (the "Software"), to deal
5+
in the Software without restriction, including without limitation the rights
6+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7+
copies of the Software, and to permit persons to whom the Software is
8+
furnished to do so, subject to the following conditions:
9+
10+
The above copyright notice and this permission notice shall be included in
11+
all copies or substantial portions of the Software.
12+
13+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19+
THE SOFTWARE.

README.md

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# nfd-rs ![](https://img.shields.io/badge/license-MIT-blue.svg)
2+
3+
`nfd-rs` is a Rust binding to the library [nativefiledialog](https://github.com/mlabbe/nativefiledialog), that provides a convenient cross-platform interface to opening file dialogs on Linux, OS X and Windows.
4+
5+
Currently, only single file and save dialogs are supported, and the crate has been tested only on OS X. And yes, APIs may break with newer versions.
6+
7+
## Usage
8+
9+
* Add the dependency `nfd` in your ```Cargo.toml```
10+
```toml
11+
[dependencies]
12+
nfd = "0.0.1"
13+
```
14+
15+
* Open a single file dialog
16+
```rust
17+
extern crate nfd;
18+
19+
use nfd::*;
20+
21+
fn main() {
22+
let filter_str = "";
23+
let default_path = "~";
24+
let result = open_file_dialog(filter_str, default_path);
25+
26+
match result {
27+
NFDResult::Okay(file_path) => println!("File path = {:?}", file_path),
28+
NFDResult::Cancel => println!("User canceled"),
29+
NFDResult::Error(error) => println!("Error: {}", error),
30+
}
31+
}
32+
```
33+
34+
## To build
35+
Follow the instructions [here](https://github.com/mlabbe/nativefiledialog/blob/master/README.md) to build libraries in C and an OS-specific language. Then, set the `NFD_LIB_DIR` environment variable to the path of the directory in which the libraries are stored. Now run `cargo build`.

build.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
use std::env;
2+
3+
fn main() {
4+
let ndf_lib_dir = env::var("NFD_LIB_DIR").unwrap();
5+
println!("cargo:rustc-link-search=native={}",ndf_lib_dir);
6+
println!("cargo:rustc-link-lib=static=nfd");
7+
println!("cargo:rustc-link-lib=framework=AppKit");
8+
}

examples/example.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
extern crate nfd;
2+
3+
use nfd::*;
4+
5+
fn main() {
6+
let filter_str = "";
7+
let default_path = "~";
8+
let result = open_file_dialog(filter_str, default_path);
9+
10+
match result {
11+
NFDResult::Okay(file_path) => println!("File path = {:?}", file_path),
12+
NFDResult::Cancel => println!("User canceled"),
13+
NFDResult::Error(error) => println!("Error: {}", error),
14+
}
15+
}

src/ffi.rs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use libc::c_char;
2+
3+
#[repr(C)]
4+
pub enum nfdresult_t {
5+
NFD_ERROR,
6+
NFD_OKAY,
7+
NFD_CANCEL
8+
}
9+
10+
#[link(name = "nfd")]
11+
extern {
12+
pub fn NFD_OpenDialog(filter_list: *const c_char, default_path: *const c_char, outPath: *mut *mut c_char) -> nfdresult_t;
13+
pub fn NFD_SaveDialog(filter_list: *const c_char, default_path: *const c_char, outPath: *mut *mut c_char) -> nfdresult_t;
14+
15+
pub fn NFD_GetError() -> *const c_char;
16+
}

src/lib.rs

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
extern crate libc;
2+
3+
mod ffi;
4+
5+
use libc::c_char;
6+
use std::ffi::*;
7+
use ffi::*;
8+
9+
/// Result of opening a file dialog
10+
pub enum NFDResult {
11+
/// User pressed okay. `String` is the file path selected
12+
Okay(String),
13+
/// User pressed cancel
14+
Cancel,
15+
/// Program error. `String` is the error description
16+
Error(String),
17+
}
18+
19+
enum DialogType {
20+
SingleFile,
21+
SaveFile
22+
}
23+
24+
/// Open single file dialog
25+
#[inline(always)]
26+
pub fn open_file_dialog(filter_list: &str, default_path: &str) -> NFDResult {
27+
open_dialog(filter_list, default_path, &DialogType::SingleFile)
28+
}
29+
30+
/// Open save dialog
31+
#[inline(always)]
32+
pub fn open_save_dialog(filter_list: &str, default_path: &str) -> NFDResult {
33+
open_dialog(filter_list, default_path, &DialogType::SaveFile)
34+
}
35+
36+
fn open_dialog(filter_list: &str, default_path: &str, dialog_type: &DialogType) -> NFDResult {
37+
38+
let mut final_cstring = CString::new("").unwrap();
39+
let out_path = CString::new("").unwrap().into_raw() as *mut *mut c_char;
40+
let result: nfdresult_t;
41+
42+
unsafe {
43+
result = match dialog_type {
44+
&DialogType::SingleFile => {
45+
NFD_OpenDialog(
46+
CString::new(filter_list).unwrap().as_ptr(),
47+
CString::new(default_path).unwrap().as_ptr(),
48+
out_path)
49+
},
50+
51+
&DialogType::SaveFile => {
52+
NFD_SaveDialog(
53+
CString::new(filter_list).unwrap().as_ptr(),
54+
CString::new(default_path).unwrap().as_ptr(),
55+
out_path)
56+
},
57+
};
58+
59+
match result {
60+
nfdresult_t::NFD_OKAY => {
61+
final_cstring = CString::from_raw(*out_path);
62+
},
63+
nfdresult_t::NFD_ERROR => {
64+
final_cstring = CStr::from_ptr(NFD_GetError()).to_owned();
65+
}
66+
_ => {},
67+
}
68+
}
69+
70+
let final_string = final_cstring.to_str().unwrap().to_string();
71+
72+
match result {
73+
nfdresult_t::NFD_OKAY => NFDResult::Okay(final_string),
74+
nfdresult_t::NFD_CANCEL => NFDResult::Cancel,
75+
nfdresult_t::NFD_ERROR => NFDResult::Error(final_string)
76+
}
77+
}

0 commit comments

Comments
 (0)