Redesign child window API

This commit is contained in:
Joonas Javanainen 2019-07-13 00:54:03 +03:00
parent c71c1ea22d
commit f4549d93ac
No known key found for this signature in database
GPG Key ID: D39CCA5CB19B9179
6 changed files with 304 additions and 145 deletions

View File

@ -12,6 +12,7 @@
- Redesigned window API
- Redesigned progress bar API
- Redesigned color editor/picker API
- Redesigned child window API (previously known as child frame)
- Updated layout API
- Renderer errors implement std::error::Error
- Glium renderer re-exports imgui and glium

View File

@ -749,9 +749,10 @@ fn show_example_menu_file<'a>(ui: &Ui<'a>, state: &mut FileMenuState) {
ui.menu_item(im_str!("Enabled"))
.selected(&mut state.enabled)
.build();
ui.child_frame(im_str!("child"), [0.0, 60.0])
.show_borders(true)
.build(|| {
ChildWindow::new("child")
.size([0.0, 60.0])
.border(true)
.build(ui, || {
for i in 0..10 {
ui.text(format!("Scrolling Text {}", i));
}

View File

@ -1,114 +0,0 @@
use std::marker::PhantomData;
use crate::sys;
use crate::window::WindowFlags;
use crate::{ImStr, Ui};
#[must_use]
pub struct ChildFrame<'ui, 'p> {
name: &'p ImStr,
size: [f32; 2],
border: bool,
flags: WindowFlags,
_phantom: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui, 'p> ChildFrame<'ui, 'p> {
pub fn new(_: &Ui<'ui>, name: &'p ImStr, size: [f32; 2]) -> ChildFrame<'ui, 'p> {
ChildFrame {
name,
size: size.into(),
border: false,
flags: WindowFlags::empty(),
_phantom: PhantomData,
}
}
#[inline]
pub fn movable(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_MOVE, !value);
self
}
#[inline]
pub fn show_scrollbar(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_SCROLLBAR, !value);
self
}
#[inline]
pub fn show_scrollbar_with_mouse(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_SCROLL_WITH_MOUSE, !value);
self
}
#[inline]
pub fn collapsible(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_COLLAPSE, !value);
self
}
#[inline]
pub fn always_resizable(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::ALWAYS_AUTO_RESIZE, value);
self
}
#[inline]
pub fn show_borders(mut self, value: bool) -> Self {
self.border = value;
self
}
#[inline]
pub fn input_allow(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_INPUTS, !value);
self
}
#[inline]
pub fn show_menu(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::MENU_BAR, value);
self
}
#[inline]
pub fn scrollbar_horizontal(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::HORIZONTAL_SCROLLBAR, value);
self
}
#[inline]
pub fn focus_on_appearing(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_FOCUS_ON_APPEARING, !value);
self
}
#[inline]
pub fn bring_to_front_on_focus(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::NO_BRING_TO_FRONT_ON_FOCUS, !value);
self
}
#[inline]
pub fn always_show_vertical_scroll_bar(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::ALWAYS_VERTICAL_SCROLLBAR, value);
self
}
#[inline]
pub fn always_show_horizontal_scroll_bar(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::ALWAYS_HORIZONTAL_SCROLLBAR, value);
self
}
#[inline]
pub fn always_use_window_padding(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::ALWAYS_USE_WINDOW_PADDING, value);
self
}
pub fn build<F: FnOnce()>(self, f: F) {
let render_child_frame = unsafe {
sys::igBeginChild(
self.name.as_ptr(),
self.size.into(),
self.border,
self.flags.bits() as i32,
)
};
if render_child_frame {
f();
}
unsafe { sys::igEndChild() };
}
}

View File

@ -9,7 +9,6 @@ use std::ptr;
use std::str;
use std::thread;
pub use self::child_frame::ChildFrame;
pub use self::clipboard::*;
pub use self::context::*;
pub use self::drag::{
@ -45,11 +44,11 @@ pub use self::style::*;
pub use self::trees::{CollapsingHeader, TreeNode};
pub use self::widget::color_editors::*;
pub use self::widget::progress_bar::*;
pub use self::window::child_window::*;
pub use self::window::*;
pub use self::window_draw_list::{ChannelsSplit, ImColor, WindowDrawList};
use internal::RawCast;
mod child_frame;
mod clipboard;
mod columns;
mod context;
@ -677,32 +676,6 @@ impl<'ui> Ui<'ui> {
}
}
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 = Context::create();
/// # let ui = imgui.frame();
/// Window::new(im_str!("ChatWindow"))
/// .title_bar(true)
/// .scrollable(false)
/// .build(&ui, || {
/// 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>(&self, name: &'p ImStr, size: [f32; 2]) -> ChildFrame<'ui, 'p> {
ChildFrame::new(self, name, size)
}
}
/// # Utilities
impl<'ui> Ui<'ui> {
/// Returns `true` if the last item is being hovered by the mouse.

297
src/window/child_window.rs Normal file
View File

@ -0,0 +1,297 @@
use std::f32;
use std::marker::PhantomData;
use std::os::raw::{c_char, c_void};
use crate::sys;
use crate::window::WindowFlags;
use crate::{Id, Ui};
/// Builder for a child window
#[derive(Clone, Debug)]
#[must_use]
pub struct ChildWindow<'a> {
id: Id<'a>,
flags: WindowFlags,
size: [f32; 2],
content_size: [f32; 2],
focused: bool,
bg_alpha: f32,
border: bool,
}
impl<'a> ChildWindow<'a> {
/// Creates a new child window builder with the given ID
pub fn new<T: Into<Id<'a>>>(id: T) -> ChildWindow<'a> {
ChildWindow {
id: id.into(),
flags: WindowFlags::empty(),
size: [0.0, 0.0],
content_size: [0.0, 0.0],
focused: false,
bg_alpha: f32::NAN,
border: false,
}
}
/// Replace current window flags with the given value
#[inline]
pub fn flags(mut self, flags: WindowFlags) -> Self {
self.flags = flags;
self
}
/// Sets the child window size.
///
/// For each independent axis of size:
///
/// - `> 0.0`: fixed size
/// - `= 0.0`: use remaining host window size
/// - `< 0.0`: use remaining host window size minus abs(size)
#[inline]
pub fn size(mut self, size: [f32; 2]) -> Self {
self.size = size;
self
}
/// Sets the window content size, which can be used to enforce scrollbars.
///
/// Does not include window decorations (title bar, menu bar, etc.). Set one of the values to
/// 0.0 to leave the size automatic.
#[inline]
pub fn content_size(mut self, size: [f32; 2]) -> Self {
self.content_size = size;
self
}
/// Sets the window focused state, which can be used to bring the window to front
#[inline]
pub fn focused(mut self, focused: bool) -> Self {
self.focused = focused;
self
}
/// Sets the background color alpha value.
///
/// See also `draw_background`
#[inline]
pub fn bg_alpha(mut self, bg_alpha: f32) -> Self {
self.bg_alpha = bg_alpha;
self
}
/// Enables/disables the child window border.
///
/// Disabled by default.
#[inline]
pub fn border(mut self, border: bool) -> Self {
self.border = border;
self
}
/// Enables/disables scrollbars (scrolling is still possible with the mouse or
/// programmatically).
///
/// Enabled by default.
#[inline]
pub fn scroll_bar(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_SCROLLBAR, !value);
self
}
/// Enables/disables vertical scrolling with the mouse wheel.
///
/// Enabled by default.
/// When enabled, child windows forward the mouse wheel to the parent unless `NO_SCROLLBAR`
/// is also set.
#[inline]
pub fn scrollable(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_SCROLL_WITH_MOUSE, !value);
self
}
/// Enables/disables resizing the window to its content on every frame.
///
/// Disabled by default.
#[inline]
pub fn always_auto_resize(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::ALWAYS_AUTO_RESIZE, value);
self
}
/// Enables/disables drawing of background color and outside border.
///
/// Enabled by default.
#[inline]
pub fn draw_background(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_BACKGROUND, !value);
self
}
/// Enables/disables catching mouse input.
///
/// Enabled by default.
/// Note: Hovering test will pass through when disabled
#[inline]
pub fn mouse_inputs(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_MOUSE_INPUTS, !value);
self
}
/// Enables/disables the menu bar.
///
/// Disabled by default.
#[inline]
pub fn menu_bar(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::MENU_BAR, value);
self
}
/// Enables/disables the horizontal scrollbar.
///
/// Disabled by default.
#[inline]
pub fn horizontal_scrollbar(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::HORIZONTAL_SCROLLBAR, value);
self
}
/// Enables/disables taking focus when transitioning from hidden to visible state.
///
/// Enabled by default.
#[inline]
pub fn focus_on_appearing(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_FOCUS_ON_APPEARING, !value);
self
}
/// Enables/disables bringing the window to front when taking focus (e.g. clicking it or
/// programmatically giving it focus).
///
/// Enabled by default.
#[inline]
pub fn bring_to_front_on_focus(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::NO_BRING_TO_FRONT_ON_FOCUS, !value);
self
}
/// When enabled, forces the vertical scrollbar to render regardless of the content size.
///
/// Disabled by default.
#[inline]
pub fn always_vertical_scrollbar(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::ALWAYS_VERTICAL_SCROLLBAR, value);
self
}
/// When enabled, forces the horizontal scrollbar to render regardless of the content size.
///
/// Disabled by default.
#[inline]
pub fn always_horizontal_scrollbar(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::ALWAYS_HORIZONTAL_SCROLLBAR, value);
self
}
/// When enabled, ensures child windows without border use `style.window_padding`.
///
/// Disabled by default.
#[inline]
pub fn always_use_window_padding(mut self, value: bool) -> Self {
self.flags
.set(WindowFlags::ALWAYS_USE_WINDOW_PADDING, value);
self
}
/// Enables/disables gamepad/keyboard navigation within the window.
///
/// Enabled by default.
#[inline]
pub fn nav_inputs(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_NAV_INPUTS, !value);
self
}
/// Enables/disables focusing toward this window with gamepad/keyboard navigation (e.g.
/// CTRL+TAB).
///
/// Enabled by default.
#[inline]
pub fn nav_focus(mut self, value: bool) -> Self {
self.flags.set(WindowFlags::NO_NAV_FOCUS, !value);
self
}
/// Disable gamepad/keyboard navigation and focusing.
///
/// Shorthand for
/// ```text
/// .nav_inputs(false)
/// .nav_focus(false)
/// ```
#[inline]
pub fn no_nav(mut self) -> Self {
self.flags |= WindowFlags::NO_NAV;
self
}
/// Don't handle input.
///
/// Shorthand for
/// ```text
/// .mouse_inputs(false)
/// .nav_inputs(false)
/// .nav_focus(false)
/// ```
#[inline]
pub fn no_inputs(mut self) -> Self {
self.flags |= WindowFlags::NO_INPUTS;
self
}
/// Builds this window, pushes it to the window stack, and starts appending to it
pub fn begin<'ui>(self, _: &'ui Ui<'ui>) -> ChildWindowToken<'ui> {
if self.content_size[0] != 0.0 || self.content_size[1] != 0.0 {
unsafe { sys::igSetNextWindowContentSize(self.content_size.into()) };
}
if self.focused {
unsafe { sys::igSetNextWindowFocus() };
}
if self.bg_alpha.is_finite() {
unsafe { sys::igSetNextWindowBgAlpha(self.bg_alpha) };
}
let id = unsafe {
match self.id {
Id::Int(i) => sys::igGetIDPtr(i as *const c_void),
Id::Ptr(p) => sys::igGetIDPtr(p),
Id::Str(s) => {
let start = s.as_ptr() as *const c_char;
let end = start.add(s.len());
sys::igGetIDRange(start, end)
}
}
};
let should_render = unsafe {
sys::igBeginChildID(id, self.size.into(), self.border, self.flags.bits() as i32)
};
ChildWindowToken {
should_render,
should_end: true,
_ui: PhantomData,
}
}
/// Builds this child window using the given closure to create the window content.
///
/// Note: the closure is not called if no window content is visible (e.g. window is collapsed
/// or fully clipped).
pub fn build<F: FnOnce()>(self, ui: &Ui, f: F) {
let window = self.begin(ui);
if window.should_render {
f();
}
window.end();
}
}
/// Represents a child window pushed to the window stack
pub struct ChildWindowToken<'ui> {
/// True, if the child window contents should be rendered
pub should_render: bool,
should_end: bool,
_ui: PhantomData<&'ui Ui<'ui>>,
}
impl<'ui> ChildWindowToken<'ui> {
/// Finishes the current child window and pops it from the window stack
pub fn end(mut self) {
self.should_end = false;
unsafe { sys::igEndChild() };
}
}
impl<'ui> Drop for ChildWindowToken<'ui> {
fn drop(&mut self) {
if self.should_end {
unsafe { sys::igEndChild() };
}
}
}

View File

@ -7,6 +7,7 @@ use crate::string::ImStr;
use crate::sys;
use crate::{Condition, Ui};
pub(crate) mod child_window;
pub(crate) mod content_region;
pub(crate) mod scroll;