diff --git a/implot-sys/Cargo.toml b/implot-sys/Cargo.toml index 41c1abe..c1d4135 100644 --- a/implot-sys/Cargo.toml +++ b/implot-sys/Cargo.toml @@ -7,6 +7,7 @@ description = "Raw FFI bindings to implot" license = "MIT/Apache-2.0" categories = ["gui", "external-ffi-bindings"] build = "build.rs" +links = "implot" [dependencies] imgui-sys = { git = "https://github.com/Gekkio/imgui-rs/", branch = "master" } diff --git a/implot-sys/build.rs b/implot-sys/build.rs index 593df07..37341b6 100644 --- a/implot-sys/build.rs +++ b/implot-sys/build.rs @@ -5,7 +5,7 @@ // for now, but expected to diverge from that over time. use std::{env, fs, io, path::Path}; -//use bindgen; // Not used anymore, TODO(4bb4) remove +use bindgen; const CPP_FILES: [&str; 2] = [ "third-party/cimplot/cimplot.cpp", @@ -45,8 +45,8 @@ fn main() -> io::Result<()> { let cimgui_include_path = env::var_os("DEP_IMGUI_THIRD_PARTY").expect("DEP_IMGUI_THIRD_PARTY not defined"); let imgui_include_path = Path::new(&cimgui_include_path).join("imgui"); - build.include(cimgui_include_path); - build.include(imgui_include_path); + build.include(&cimgui_include_path); + build.include(&imgui_include_path); // Taken from the imgui-sys build as well build.flag_if_supported("-Wno-return-type-c-linkage"); @@ -58,21 +58,20 @@ fn main() -> io::Result<()> { build.compile("cimplot"); // --- Create bindgen bindings - // TODO(4bb4) move this out to separate shell script (see #1) - // The actual generate() errors out right now with parsing errors, - // will probably need to whiltelist things, fix preprocessor definitions, - // bindgen settings or some combination thereof. - //let _bindings = bindgen::Builder::default() - //.header(imgui_third_party.into_string().unwrap() + "/cimgui.h") - //.header("wrapper.h") - //.parse_callbacks(Box::new(bindgen::CargoCallbacks)); - //.generate() - //.expect("Unable to generate bindings"); + // TODO(4bb4) move this out to separate shell script (see #1) so users don't have + // to have clang installed to build this crate. + let bindings = bindgen::Builder::default() + .header(&(cimgui_include_path.into_string().unwrap() + "/cimgui.h")) + .header("third-party/cimplot/cimplot.h") + .parse_callbacks(Box::new(bindgen::CargoCallbacks)) + .clang_arg("-DCIMGUI_DEFINE_ENUMS_AND_STRUCTS=1") + .generate() + .expect("Unable to generate bindings"); - //let out_path = std::path::PathBuf::from(env::var("OUT_DIR").unwrap()); - //bindings - //.write_to_file(out_path.join("bindings.rs")) - //.expect("Couldn't write bindings!"); + let out_path = std::path::PathBuf::from(env::var("OUT_DIR").unwrap()); + bindings + .write_to_file(out_path.join("bindings.rs")) + .expect("Couldn't write bindings!"); Ok(()) } diff --git a/implot-sys/src/lib.rs b/implot-sys/src/lib.rs index ff69c01..1ba51b5 100644 --- a/implot-sys/src/lib.rs +++ b/implot-sys/src/lib.rs @@ -1,3 +1,7 @@ -fn _does_nothing() { - println!("This does nothing yet"); -} +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] + +// TODO(4bb4) change this to include the bindings we hand-generate +// once that is happening +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/testexample/Cargo.toml b/testexample/Cargo.toml new file mode 100644 index 0000000..4d13a1c --- /dev/null +++ b/testexample/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "imgui-examples" +version = "0.0.0" +edition = "2018" +authors = ["Joonas Javanainen ", "imgui-rs contributors"] +description = "imgui crate examples using Glium backend" +homepage = "https://github.com/Gekkio/imgui-rs" +repository = "https://github.com/Gekkio/imgui-rs" +license = "MIT/Apache-2.0" +publish = false + +[dependencies] +clipboard = "0.5" +glium = { version = "0.27", default-features = true } +image = "0.23" +imgui-sys = { git = "https://github.com/Gekkio/imgui-rs/", branch = "master" } +imgui = { git = "https://github.com/Gekkio/imgui-rs/", branch = "master" } +imgui-glium-renderer = { git = "https://github.com/Gekkio/imgui-rs/", branch = "master" } +imgui-winit-support = { git = "https://github.com/Gekkio/imgui-rs/", branch = "master" } + +implot-sys = { path = "../implot-sys" } diff --git a/testexample/src/main.rs b/testexample/src/main.rs new file mode 100644 index 0000000..ba751dc --- /dev/null +++ b/testexample/src/main.rs @@ -0,0 +1,67 @@ +use imgui::*; +use implot_sys; + +mod support; + +fn main() { + let system = support::init(file!()); + system.main_loop(move |_, ui| { + Window::new(im_str!("Hello world")) + .size([300.0, 110.0], Condition::FirstUseEver) + .build(ui, || { + ui.text(im_str!("Hello world!")); + ui.text(im_str!("こんにちは世界!")); + ui.text(im_str!("This...is...imgui-rs!")); + ui.separator(); + let mouse_pos = ui.io().mouse_pos; + ui.text(format!( + "Mouse Position: ({:.1},{:.1})", + mouse_pos[0], mouse_pos[1] + )); + + // TODO(4bb4) Replace this with safe bindings once those are written + + let x_values: [f64; 4] = [1.0, 2.0, 4.0, 5.0]; + let y_values: [f64; 4] = [1.0, 0.0, 0.0, 1.0]; + unsafe { + if implot_sys::ImPlot_BeginPlot( + im_str!("My Plot").as_ptr() as *const i8, + im_str!("x").as_ptr() as *const i8, + im_str!("y").as_ptr() as *const i8, + implot_sys::ImVec2 { x: 600.0, y: 600.0 }, + 0xFF, + 7, + 7, + 0, + 0, + ) { + implot_sys::ImPlot_PlotLinedoublePtrdoublePtr( + im_str!("Mouth").as_ptr() as *const i8, + x_values.as_ptr(), + y_values.as_ptr(), + x_values.len() as i32, + 0, + 8, + ); + implot_sys::ImPlot_PlotLinedoublePtrdoublePtr( + im_str!("Left eye").as_ptr() as *const i8, + [2.0, 2.0].as_ptr(), + [2.0, 1.0].as_ptr(), + 2i32, + 0, + 8, + ); + implot_sys::ImPlot_PlotLinedoublePtrdoublePtr( + im_str!("Right eye").as_ptr() as *const i8, + [4.0, 4.0].as_ptr(), + [2.0, 1.0].as_ptr(), + 2i32, + 0, + 8, + ); + implot_sys::ImPlot_EndPlot(); + } + } + }); + }); +} diff --git a/testexample/src/support/clipboard.rs b/testexample/src/support/clipboard.rs new file mode 100644 index 0000000..7268798 --- /dev/null +++ b/testexample/src/support/clipboard.rs @@ -0,0 +1,24 @@ +// Taken directly from imgui-rs examples at +// +// https://github.com/Gekkio/imgui-rs/tree/master/imgui-examples/examples/support +// +// Not my code. Originally by Joonas Javanainen and the ImGUI-rs contributors +use clipboard::{ClipboardContext, ClipboardProvider}; +use imgui::{ClipboardBackend, ImStr, ImString}; + +pub struct ClipboardSupport(ClipboardContext); + +pub fn init() -> Option { + ClipboardContext::new() + .ok() + .map(|ctx| ClipboardSupport(ctx)) +} + +impl ClipboardBackend for ClipboardSupport { + fn get(&mut self) -> Option { + self.0.get_contents().ok().map(|text| text.into()) + } + fn set(&mut self, text: &ImStr) { + let _ = self.0.set_contents(text.to_str().to_owned()); + } +} diff --git a/testexample/src/support/mod.rs b/testexample/src/support/mod.rs new file mode 100644 index 0000000..33c8d0f --- /dev/null +++ b/testexample/src/support/mod.rs @@ -0,0 +1,133 @@ +// Taken directly from imgui-rs examples at +// +// https://github.com/Gekkio/imgui-rs/tree/master/imgui-examples/examples/support +// +// Not my code. Originally by Joonas Javanainen and the ImGUI-rs contributors +use glium::glutin; +use glium::glutin::event::{Event, WindowEvent}; +use glium::glutin::event_loop::{ControlFlow, EventLoop}; +use glium::glutin::window::WindowBuilder; +use glium::{Display, Surface}; +use imgui::{Context, FontConfig, FontGlyphRanges, FontSource, Ui}; +use imgui_glium_renderer::Renderer; +use imgui_winit_support::{HiDpiMode, WinitPlatform}; +use std::time::Instant; + +mod clipboard; + +pub struct System { + pub event_loop: EventLoop<()>, + pub display: glium::Display, + pub imgui: Context, + pub platform: WinitPlatform, + pub renderer: Renderer, + pub font_size: f32, +} + +pub fn init(title: &str) -> System { + let title = match title.rfind('/') { + Some(idx) => title.split_at(idx + 1).1, + None => title, + }; + let event_loop = EventLoop::new(); + let context = glutin::ContextBuilder::new().with_vsync(true); + let builder = WindowBuilder::new() + .with_title(title.to_owned()) + .with_inner_size(glutin::dpi::LogicalSize::new(1024f64, 768f64)); + let display = + Display::new(builder, context, &event_loop).expect("Failed to initialize display"); + + let mut imgui = Context::create(); + imgui.set_ini_filename(None); + + if let Some(backend) = clipboard::init() { + imgui.set_clipboard_backend(Box::new(backend)); + } else { + eprintln!("Failed to initialize clipboard"); + } + + let mut platform = WinitPlatform::init(&mut imgui); + { + let gl_window = display.gl_window(); + let window = gl_window.window(); + platform.attach_window(imgui.io_mut(), &window, HiDpiMode::Rounded); + } + + let hidpi_factor = platform.hidpi_factor(); + let font_size = (13.0 * hidpi_factor) as f32; + imgui.fonts().add_font(&[FontSource::DefaultFontData { + config: Some(FontConfig { + size_pixels: font_size, + ..FontConfig::default() + }), + }]); + + imgui.io_mut().font_global_scale = (1.0 / hidpi_factor) as f32; + + let renderer = Renderer::init(&mut imgui, &display).expect("Failed to initialize renderer"); + + System { + event_loop, + display, + imgui, + platform, + renderer, + font_size, + } +} + +impl System { + pub fn main_loop(self, mut run_ui: F) { + let System { + event_loop, + display, + mut imgui, + mut platform, + mut renderer, + .. + } = self; + let mut last_frame = Instant::now(); + + event_loop.run(move |event, _, control_flow| match event { + Event::NewEvents(_) => { + let now = Instant::now(); + imgui.io_mut().update_delta_time(now - last_frame); + last_frame = now; + } + Event::MainEventsCleared => { + let gl_window = display.gl_window(); + platform + .prepare_frame(imgui.io_mut(), &gl_window.window()) + .expect("Failed to prepare frame"); + gl_window.window().request_redraw(); + } + Event::RedrawRequested(_) => { + let mut ui = imgui.frame(); + + let mut run = true; + run_ui(&mut run, &mut ui); + if !run { + *control_flow = ControlFlow::Exit; + } + + let gl_window = display.gl_window(); + let mut target = display.draw(); + target.clear_color_srgb(1.0, 1.0, 1.0, 1.0); + platform.prepare_render(&ui, gl_window.window()); + let draw_data = ui.render(); + renderer + .render(&mut target, draw_data) + .expect("Rendering failed"); + target.finish().expect("Failed to swap buffers"); + } + Event::WindowEvent { + event: WindowEvent::CloseRequested, + .. + } => *control_flow = ControlFlow::Exit, + event => { + let gl_window = display.gl_window(); + platform.handle_event(imgui.io_mut(), gl_window.window(), &event); + } + }) + } +}