diff --git a/src/child_frame.rs b/src/child_frame.rs new file mode 100644 index 0000000..8ba8ac0 --- /dev/null +++ b/src/child_frame.rs @@ -0,0 +1,121 @@ +use imgui_sys; +use ImStr; +use ImVec2; +use ImGuiWindowFlags; + +use super::{ImGuiWindowFlags_NoMove, ImGuiWindowFlags_NoScrollbar, ImGuiWindowFlags_NoScrollWithMouse, + ImGuiWindowFlags_NoCollapse, ImGuiWindowFlags_AlwaysAutoResize, + ImGuiWindowFlags_ShowBorders, ImGuiWindowFlags_NoInputs, ImGuiWindowFlags_MenuBar, + ImGuiWindowFlags_HorizontalScrollbar, ImGuiWindowFlags_NoFocusOnAppearing, + ImGuiWindowFlags_NoBringToFrontOnFocus, ImGuiWindowFlags_AlwaysVerticalScrollbar, + ImGuiWindowFlags_AlwaysHorizontalScrollbar, ImGuiWindowFlags_AlwaysUseWindowPadding}; + +#[must_use] +pub struct ChildFrame<'p> { + name: &'p ImStr, + size: ImVec2, + flags: ImGuiWindowFlags, +} + +impl<'p> ChildFrame<'p> { + pub fn new(name: &'p ImStr, size: ImVec2) -> ChildFrame<'p> { + ChildFrame { + name: name, + size: size, + flags: ImGuiWindowFlags::empty(), + } + } + #[inline] + pub fn movable(mut self, value: bool) -> Self { + self.flags.set(ImGuiWindowFlags_NoMove, !value); + self + } + #[inline] + pub fn show_scrollbar(mut self, value: bool) -> Self { + self.flags.set(ImGuiWindowFlags_NoScrollbar, !value); + self + } + #[inline] + pub fn show_scrollbar_with_mouse(mut self, value: bool) -> Self { + self.flags.set(ImGuiWindowFlags_NoScrollWithMouse, !value); + self + } + #[inline] + pub fn collapsible(mut self, value: bool) -> Self { + self.flags.set(ImGuiWindowFlags_NoCollapse, !value); + self + } + #[inline] + pub fn always_resizable(mut self, value: bool) -> Self { + self.flags.set(ImGuiWindowFlags_AlwaysAutoResize, value); + self + } + #[inline] + pub fn show_borders(mut self, value: bool) -> Self { + self.flags.set(ImGuiWindowFlags_ShowBorders, value); + self + } + #[inline] + pub fn input_allow(mut self, value: bool) -> Self { + self.flags.set(ImGuiWindowFlags_NoInputs, !value); + self + } + #[inline] + pub fn show_menu(mut self, value: bool) -> Self { + self.flags.set(ImGuiWindowFlags_MenuBar, value); + self + } + #[inline] + pub fn scrollbar_horizontal(mut self, value: bool) -> Self { + self.flags.set(ImGuiWindowFlags_HorizontalScrollbar, value); + self + } + #[inline] + pub fn focus_on_appearing(mut self, value: bool) -> Self { + self.flags.set(ImGuiWindowFlags_NoFocusOnAppearing, !value); + self + } + #[inline] + pub fn bring_to_front_on_focus(mut self, value: bool) -> Self { + self.flags.set( + ImGuiWindowFlags_NoBringToFrontOnFocus, + !value, + ); + self + } + #[inline] + pub fn always_show_vertical_scroll_bar(mut self, value: bool) -> Self { + self.flags.set( + ImGuiWindowFlags_AlwaysVerticalScrollbar, + value, + ); + self + } + #[inline] + pub fn always_show_horizontal_scroll_bar(mut self, value: bool) -> Self { + self.flags.set( + ImGuiWindowFlags_AlwaysHorizontalScrollbar, + value, + ); + self + } + #[inline] + pub fn always_use_window_padding(mut self, value: bool) -> Self { + self.flags.set( + ImGuiWindowFlags_AlwaysUseWindowPadding, + value, + ); + self + } + pub fn build(self, f: F) { + // See issue for history. + // https://github.com/Gekkio/imgui-rs/pull/58 + let show_border = false; + + let render_child_frame = unsafe { imgui_sys::igBeginChild(self.name.as_ptr(), self.size, show_border, self.flags) }; + if render_child_frame { + f(); + } + unsafe { imgui_sys::igEndChild() }; + } +} diff --git a/src/lib.rs b/src/lib.rs index f5e037d..d776bf1 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,7 @@ pub use imgui_sys::{ImDrawIdx, ImDrawVert, ImGuiInputTextFlags, ImGuiInputTextFl ImGuiSelectableFlags_DontClosePopups, ImGuiSelectableFlags_SpanAllColumns, ImGuiSetCond, ImGuiSetCond_Always, ImGuiSetCond_Appearing, ImGuiSetCond_FirstUseEver, ImGuiSetCond_Once, ImGuiCol, ImGuiStyle, ImGuiTreeNodeFlags, + ImGuiSetCond_FirstUseEver, ImGuiSetCond_Once, ImGuiCol, ImGuiStyle, ImGuiStyleVar, ImGuiTreeNodeFlags, ImGuiTreeNodeFlags_AllowOverlapMode, ImGuiTreeNodeFlags_Bullet, ImGuiTreeNodeFlags_CollapsingHeader, ImGuiTreeNodeFlags_DefaultOpen, ImGuiTreeNodeFlags_Framed, ImGuiTreeNodeFlags_Leaf, @@ -35,6 +36,7 @@ pub use imgui_sys::{ImDrawIdx, ImDrawVert, ImGuiInputTextFlags, ImGuiInputTextFl ImGuiWindowFlags_NoSavedSettings, ImGuiWindowFlags_NoScrollWithMouse, ImGuiWindowFlags_NoScrollbar, ImGuiWindowFlags_NoTitleBar, ImGuiWindowFlags_ShowBorders, ImVec2, ImVec4}; +pub use child_frame::ChildFrame; pub use input::{ColorEdit3, ColorEdit4, InputFloat, InputFloat2, InputFloat3, InputFloat4, InputInt, InputInt2, InputInt3, InputInt4, InputText}; pub use menus::{Menu, MenuItem}; @@ -44,9 +46,11 @@ pub use progressbar::ProgressBar; pub use sliders::{SliderFloat, SliderFloat2, SliderFloat3, SliderFloat4, SliderInt, SliderInt2, SliderInt3, SliderInt4}; pub use string::{ImStr, ImString}; +pub use style::StyleVar; pub use trees::{CollapsingHeader, TreeNode}; pub use window::Window; +mod child_frame; mod input; mod menus; mod plothistogram; @@ -54,6 +58,7 @@ mod plotlines; mod progressbar; mod sliders; mod string; +mod style; mod trees; mod window; @@ -391,6 +396,7 @@ impl<'ui> Ui<'ui> { } pub fn separator(&self) { unsafe { imgui_sys::igSeparator() }; } + pub fn new_line(&self) { unsafe { imgui_sys::igNewLine() } } pub fn same_line(&self, pos_x: f32) { unsafe { imgui_sys::igSameLine(pos_x, -1.0f32) } } pub fn same_line_spacing(&self, pos_x: f32, spacing_w: f32) { unsafe { imgui_sys::igSameLine(pos_x, spacing_w) } @@ -723,6 +729,20 @@ impl<'ui> Ui<'ui> { } } +impl<'ui> Ui<'ui> { + /// Calculate the size required for a given text string. + /// + /// hide_text_after_double_hash allows the user to insert comments into their text, using a double hash-tag prefix. + /// This is a feature of imgui. + /// + /// wrap_width allows you to request a width at which to wrap the text to a newline for the calculation. + pub fn calc_text_size(&self, text: &ImStr, hide_text_after_double_hash: bool, wrap_width: f32) -> ImVec2 { + let mut buffer = ImVec2::new(0.0, 0.0); + unsafe { imgui_sys::igCalcTextSize(&mut buffer as *mut ImVec2, text.as_ptr(), std::ptr::null(), hide_text_after_double_hash, wrap_width); } + buffer + } +} + impl<'ui> Ui<'ui> { /// Creates a progress bar. Fraction is the progress level with 0.0 = 0% and 1.0 = 100%. /// @@ -739,6 +759,93 @@ impl<'ui> Ui<'ui> { pub fn progress_bar<'p>(&self, fraction: f32) -> ProgressBar<'p> { ProgressBar::new(fraction) } } +impl<'ui> Ui<'ui> { + /// Creates a child frame. Size is size of child_frame within parent window. + /// + /// # Example + /// ```rust,no_run + /// # use imgui::*; + /// # let mut imgui = ImGui::init(); + /// # let ui = imgui.frame((0, 0), (0, 0), 0.1); + /// ui.window(im_str!("ChatWindow")) + /// .title_bar(true) + /// .scrollable(false) + /// .build(|| { + /// ui.separator(); + /// + /// ui.child_frame(im_str!("child frame"), (400.0, 100.0)) + /// .show_borders(true) + /// .always_show_vertical_scroll_bar(true) + /// .build(|| { + /// ui.text_colored((1.0, 0.0, 0.0, 1.0), im_str!("hello mate!")); + /// }); + /// }); + pub fn child_frame<'p, S: Into>(&self, name: &'p ImStr, size: S) -> ChildFrame<'p> { ChildFrame::new(name, size.into()) } +} + +impl<'ui> Ui<'ui> { + /// Runs a function after temporarily pushing a value to the style stack. + /// + /// # Example + /// ```rust,no_run + /// # use imgui::*; + /// # let mut imgui = ImGui::init(); + /// # let ui = imgui.frame((0, 0), (0, 0), 0.1); + /// ui.with_style_var(StyleVar::Alpha(0.2), || { + /// ui.text(im_str!("AB")); + /// }); + /// ``` + pub fn with_style_var(&self, style_var: StyleVar, f: F) { + self.push_style_var(style_var); + f(); + unsafe { imgui_sys::igPopStyleVar(1) } + } + + /// Runs a function after temporarily pushing an array of values into the stack. Supporting + /// multiple is also easy since you can freely mix and match them in a safe manner. + /// + /// # Example + /// ```rust,no_run + /// # use imgui::*; + /// # let mut imgui = ImGui::init(); + /// # let ui = imgui.frame((0, 0), (0, 0), 0.1); + /// # let styles = [StyleVar::Alpha(0.2), StyleVar::WindowPadding(ImVec2::new(1.0, 1.0))]; + /// ui.with_style_vars(&styles, || { + /// ui.text(im_str!("A")); + /// ui.text(im_str!("B")); + /// ui.text(im_str!("C")); + /// ui.text(im_str!("D")); + /// }); + /// ``` + pub fn with_style_vars(&self, style_vars: &[StyleVar], f: F) { + for &style_var in style_vars { + self.push_style_var(style_var); + } + f(); + unsafe { imgui_sys::igPopStyleVar(style_vars.len() as i32) }; + } + + #[inline] + fn push_style_var(&self, style_var: StyleVar) { + use StyleVar::*; + use imgui_sys::{igPushStyleVar, igPushStyleVarVec}; + match style_var { + Alpha(v) => unsafe { igPushStyleVar(ImGuiStyleVar::Alpha, v) }, + WindowPadding(v) => unsafe { igPushStyleVarVec(ImGuiStyleVar::WindowPadding, v) }, + WindowRounding(v) => unsafe { igPushStyleVar(ImGuiStyleVar::WindowRounding, v) }, + WindowMinSize(v) => unsafe { igPushStyleVarVec(ImGuiStyleVar::WindowMinSize, v) }, + ChildWindowRounding(v) => unsafe { igPushStyleVar(ImGuiStyleVar::ChildWindowRounding, v) }, + FramePadding(v) => unsafe { igPushStyleVarVec(ImGuiStyleVar::FramePadding, v) }, + FrameRounding(v) => unsafe { igPushStyleVar(ImGuiStyleVar::FrameRounding, v) }, + ItemSpacing(v) => unsafe { igPushStyleVarVec(ImGuiStyleVar::ItemSpacing, v) }, + ItemInnerSpacing(v) => unsafe { igPushStyleVarVec(ImGuiStyleVar::ItemInnerSpacing, v) }, + IndentSpacing(v) => unsafe { igPushStyleVar(ImGuiStyleVar::IndentSpacing, v) }, + GrabMinSize(v) => unsafe { igPushStyleVar(ImGuiStyleVar::GrabMinSize, v) }, + ButtonTextAlign(v) => unsafe { igPushStyleVarVec(ImGuiStyleVar::ButtonTextAlign, v) } + } + } +} + impl<'ui> Ui<'ui> { /// Runs a function after temporarily pushing a value to the color stack. /// diff --git a/src/style.rs b/src/style.rs new file mode 100644 index 0000000..04c683c --- /dev/null +++ b/src/style.rs @@ -0,0 +1,17 @@ +use ImVec2; + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum StyleVar { + Alpha(f32), + WindowPadding(ImVec2), + WindowRounding(f32), + WindowMinSize(ImVec2), + ChildWindowRounding(f32), + FramePadding(ImVec2), + FrameRounding(f32), + ItemSpacing(ImVec2), + ItemInnerSpacing(ImVec2), + IndentSpacing(f32), + GrabMinSize(f32), + ButtonTextAlign(ImVec2), +}