diff --git a/README.md b/README.md index 1f3520e..a9d9c47 100644 --- a/README.md +++ b/README.md @@ -93,12 +93,12 @@ created for 64-bit floats. - [x] Plot limit setting - [x] imgui-rs style safe push/pop stacks - [x] Plot tick setting - - [ ] Input remapping + - [x] Pixel to plot position + - [x] Plot to pixel position - [x] Set Y axis setting for subsequent elements + - [ ] Input remapping - [ ] Set non-default Y axis ticks and labels - [ ] Plot position and size reading - - [ ] Pixel to plot position - - [ ] Plot to pixel position - [ ] Push/pop plotclip rect (?) # Developer documentation diff --git a/implot-examples/examples-shared/src/line_plots.rs b/implot-examples/examples-shared/src/line_plots.rs index b2fb3d3..b19a453 100644 --- a/implot-examples/examples-shared/src/line_plots.rs +++ b/implot-examples/examples-shared/src/line_plots.rs @@ -4,10 +4,11 @@ use imgui::{im_str, CollapsingHeader, Condition, Ui, Window}; use implot::{ get_plot_limits, get_plot_mouse_position, get_plot_query, is_plot_hovered, is_plot_queried, - push_style_color, push_style_var_f32, push_style_var_i32, set_colormap_from_preset, - set_colormap_from_vec, set_plot_y_axis, AxisFlags, Colormap, ImPlotLimits, ImPlotPoint, - ImPlotRange, ImVec4, Marker, Plot, PlotColorElement, PlotFlags, PlotLine, PlotLocation, - PlotOrientation, PlotUi, StyleVar, YAxisChoice, + pixels_to_plot_vec2, plot_to_pixels_vec2, push_style_color, push_style_var_f32, + push_style_var_i32, set_colormap_from_preset, set_colormap_from_vec, set_plot_y_axis, + AxisFlags, Colormap, ImPlotLimits, ImPlotPoint, ImPlotRange, ImVec2, ImVec4, Marker, Plot, + PlotColorElement, PlotFlags, PlotLine, PlotLocation, PlotOrientation, PlotUi, StyleVar, + YAxisChoice, }; pub fn show_basic_plot(ui: &Ui, plot_ui: &PlotUi) { @@ -134,7 +135,9 @@ pub fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) { let content_width = ui.window_content_region_width(); // Create some containers for exfiltrating data from the closure below - let mut hover_pos: Option = None; + let mut hover_pos_plot: Option = None; + let mut hover_pos_pixels: Option = None; + let mut hover_pos_from_pixels: Option = None; let mut plot_limits: Option = None; let mut query_limits: Option = None; @@ -150,9 +153,20 @@ pub fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) { .with_plot_flags(&(PlotFlags::NONE | PlotFlags::QUERY)) .build(plot_ui, || { if is_plot_hovered() { - hover_pos = Some(get_plot_mouse_position(None)); + hover_pos_plot = Some(get_plot_mouse_position(None)); + hover_pos_pixels = Some(plot_to_pixels_vec2(&(hover_pos_plot.unwrap()), None)); } + // Getting the plot position from pixels also works when the plot is not hovered, + // the coordinates are then simply outside the visible range. + hover_pos_from_pixels = Some(pixels_to_plot_vec2( + &ImVec2 { + x: ui.io().mouse_pos[0], + y: ui.io().mouse_pos[1], + }, + None, + )); + if is_plot_queried() { query_limits = Some(get_plot_query(None)); } @@ -162,15 +176,33 @@ pub fn show_query_features_plot(ui: &Ui, plot_ui: &PlotUi) { // Print some previously-exfiltrated info. This is because calling // things like is_plot_hovered or get_plot_mouse_position() outside // of an actual Plot is not allowed. - if let Some(pos) = hover_pos { + if let Some(pos) = hover_pos_plot { ui.text(im_str!("hovered at {}, {}", pos.x, pos.y)); } + if let Some(pixel_position) = hover_pos_pixels { + // Try out converting plot mouse position to pixel position + ui.text(im_str!( + "pixel pos from plot: {}, {}", + pixel_position.x, + pixel_position.y + )); + ui.text(im_str!( + "pixel pos from imgui: {}, {}", + ui.io().mouse_pos[0], + ui.io().mouse_pos[1] + )); + } if let Some(limits) = plot_limits { ui.text(im_str!("Plot limits are {:#?}", limits)); } if let Some(query) = query_limits { ui.text(im_str!("Query limits are {:#?}", query)); } + + // Try out converting pixel position to plot position + if let Some(pos) = hover_pos_from_pixels { + ui.text(im_str!("plot pos from imgui: {}, {}", pos.x, pos.y,)); + } } pub fn show_style_plot(ui: &Ui, plot_ui: &PlotUi) { diff --git a/src/lib.rs b/src/lib.rs index e47954c..fc41be3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -44,6 +44,14 @@ pub enum YAxisChoice { Third = sys::ImPlotYAxis__ImPlotYAxis_3, } +/// Turn an Option into an i32. Picks IMPLOT_AUTO for None. +fn y_axis_choice_option_to_i32(y_axis_choice: Option) -> i32 { + match y_axis_choice { + Some(choice) => choice as i32, + None => IMPLOT_AUTO, + } +} + /// A temporary reference for building plots. This does not really do anything on its own at /// this point, but it is used to enforce that a context is created and active for other features, /// such as creating plots. @@ -395,10 +403,7 @@ pub fn is_plot_queried() -> bool { /// for the specified choice of Y axis. If `None` is the Y axis choice, that means the /// most recently selected Y axis is chosen. pub fn get_plot_mouse_position(y_axis_choice: Option) -> ImPlotPoint { - let y_axis_choice_i32 = match y_axis_choice { - Some(choice) => choice as i32, - None => IMPLOT_AUTO, - }; + let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); let mut point = ImPlotPoint { x: 0.0, y: 0.0 }; // doesn't seem to have default() unsafe { sys::ImPlot_GetPlotMousePos(&mut point as *mut ImPlotPoint, y_axis_choice_i32); @@ -406,13 +411,87 @@ pub fn get_plot_mouse_position(y_axis_choice: Option) -> ImPlotPoin point } +/// Convert pixels, given as an `ImVec2`, to a position in the current plot's coordinate system. +/// Uses the specified Y axis, if any, otherwise whatever was previously chosen. +pub fn pixels_to_plot_vec2( + pixel_position: &ImVec2, + y_axis_choice: Option, +) -> ImPlotPoint { + let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); + let mut point = ImPlotPoint { x: 0.0, y: 0.0 }; // doesn't seem to have default() + unsafe { + sys::ImPlot_PixelsToPlotVec2( + &mut point as *mut ImPlotPoint, + *pixel_position, + y_axis_choice_i32, + ); + } + point +} + +/// Convert pixels, given as floats `x` and `y`, to a position in the current plot's coordinate +/// system. Uses the specified Y axis, if any, otherwise whatever was previously chosen. +pub fn pixels_to_plot_f32( + pixel_position_x: f32, + pixel_position_y: f32, + y_axis_choice: Option, +) -> ImPlotPoint { + let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); + let mut point = ImPlotPoint { x: 0.0, y: 0.0 }; // doesn't seem to have default() + unsafe { + sys::ImPlot_PixelsToPlotFloat( + &mut point as *mut ImPlotPoint, + pixel_position_x, + pixel_position_y, + y_axis_choice_i32, + ); + } + point +} + +/// Convert a position in the current plot's coordinate system to pixels. Uses the specified Y +/// axis, if any, otherwise whatever was previously chosen. +/// +pub fn plot_to_pixels_vec2( + plot_position: &ImPlotPoint, + y_axis_choice: Option, +) -> ImVec2 { + let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); + let mut pixel_position = ImVec2 { x: 0.0, y: 0.0 }; // doesn't seem to have default() + unsafe { + sys::ImPlot_PlotToPixelsPlotPoInt( + &mut pixel_position as *mut ImVec2, + *plot_position, + y_axis_choice_i32, + ); + } + pixel_position +} + +/// Convert a position in the current plot's coordinate system to pixels. Uses the specified Y +/// axis, if any, otherwise whatever was previously chosen. +pub fn plot_to_pixels_f32( + plot_position_x: f64, + plot_position_y: f64, + y_axis_choice: Option, +) -> ImVec2 { + let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); + let mut pixel_position = ImVec2 { x: 0.0, y: 0.0 }; // doesn't seem to have default() + unsafe { + sys::ImPlot_PlotToPixelsdouble( + &mut pixel_position as *mut ImVec2, + plot_position_x, + plot_position_y, + y_axis_choice_i32, + ); + } + pixel_position +} + /// Returns the current or most recent plot axis range for the specified choice of Y axis. If /// `None` is the Y axis choice, that means the most recently selected Y axis is chosen. pub fn get_plot_limits(y_axis_choice: Option) -> ImPlotLimits { - let y_axis_choice_i32 = match y_axis_choice { - Some(choice) => choice as i32, - None => IMPLOT_AUTO, - }; + let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); // ImPlotLimits doesn't seem to have default() let mut limits = ImPlotLimits { X: ImPlotRange { Min: 0.0, Max: 0.0 }, @@ -427,10 +506,7 @@ pub fn get_plot_limits(y_axis_choice: Option) -> ImPlotLimits { /// Returns the query limits of the current or most recent plot, for the specified choice of Y /// axis. If `None` is the Y axis choice, that means the most recently selected Y axis is chosen. pub fn get_plot_query(y_axis_choice: Option) -> ImPlotLimits { - let y_axis_choice_i32 = match y_axis_choice { - Some(choice) => choice as i32, - None => IMPLOT_AUTO, - }; + let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); // ImPlotLimits doesn't seem to have default() let mut limits = ImPlotLimits { X: ImPlotRange { Min: 0.0, Max: 0.0 }, @@ -457,10 +533,7 @@ pub fn is_plot_x_axis_hovered() -> bool { /// Returns true if the YAxis[n] plot area in the current plot is hovered. If `None` is the Y axis /// choice, that means the most recently selected Y axis is chosen. pub fn is_plot_y_axis_hovered(y_axis_choice: Option) -> bool { - let y_axis_choice_i32 = match y_axis_choice { - Some(choice) => choice as i32, - None => IMPLOT_AUTO, - }; + let y_axis_choice_i32 = y_axis_choice_option_to_i32(y_axis_choice); unsafe { sys::ImPlot_IsPlotYAxisHovered(y_axis_choice_i32) } }