mirror of
https://github.com/eliasstepanik/imgui-rs.git
synced 2026-01-11 21:48:36 +00:00
window_draw_list.rs: Basic structure to wrap ImGui's draw API
This patch makes the basic structure for a wrapper around Dear ImGui's drawing API. 1. Implement `with_window_draw_list` method on Ui. Call this method to get access to the `WindowDrawList` object. This object holds the methods to access ImGui's drawing API. 2. Dear ImGui uses the ImU32 (an unsigned c_int) to represent colors in the drawing API. This commit wraps this type with ImColor for convenience. Any color representation (3or4-tuples, 3or4-arrays, ImU32 or ImVec4) can be converted into ImColor for convenience. 3. Difference between WindowDrawList and ChannelsSplit: Most drawing functions can be called on WindowDrawList and ChannelsSplit objects. However for safety, some functions can only be called on WindowDrawList or ChannelsSplit instance. For example `channels_set_current` can only be called after channels have been split. To avoid code duplication, functions common to WindowDrawList and ChannelsSplit are implemented within the `impl_draw_list_methods` macro. 4. Implement drawing functions (in this commit, add_line only). Calling `add_line` returns a default representation of the line to be drawn, but does not draw it. Then parameters, such as thickness, can be set. You must call `build` to draw the line. All drawing functions will be implemented following this pattern.
This commit is contained in:
parent
b6e5086eb2
commit
db97041936
27
src/lib.rs
27
src/lib.rs
@ -27,6 +27,7 @@ pub use string::{ImStr, ImString};
|
||||
pub use style::StyleVar;
|
||||
pub use trees::{CollapsingHeader, TreeNode};
|
||||
pub use window::Window;
|
||||
pub use window_draw_list::{ImColor, WindowDrawList};
|
||||
|
||||
mod child_frame;
|
||||
mod color_editors;
|
||||
@ -41,6 +42,7 @@ mod string;
|
||||
mod style;
|
||||
mod trees;
|
||||
mod window;
|
||||
mod window_draw_list;
|
||||
|
||||
pub struct ImGui {
|
||||
// We need to keep ownership of the ImStr values to ensure the *const char pointer
|
||||
@ -1211,3 +1213,28 @@ impl<'ui> Ui<'ui> {
|
||||
unsafe { sys::igEndGroup(); }
|
||||
}
|
||||
}
|
||||
|
||||
/// # Draw list for custom drawing
|
||||
impl<'ui> Ui<'ui> {
|
||||
/// Get access to drawing API
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// fn custom_draw(ui: &Ui) {
|
||||
/// ui.with_window_draw_list(|draw_list| {
|
||||
/// // Draw a line
|
||||
/// const WHITE: [f32; 3] = [1.0, 1.0, 1.0];
|
||||
/// draw_list.add_line([100.0, 100.0], [200.0, 200.0], WHITE).build();
|
||||
/// // Continue drawing ...
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
pub fn with_window_draw_list<F>(&self, f: F)
|
||||
where
|
||||
F: FnOnce(&WindowDrawList),
|
||||
{
|
||||
let window_draw_list = WindowDrawList::new(self);
|
||||
f(&window_draw_list);
|
||||
}
|
||||
}
|
||||
|
||||
179
src/window_draw_list.rs
Normal file
179
src/window_draw_list.rs
Normal file
@ -0,0 +1,179 @@
|
||||
use sys;
|
||||
use sys::{ImDrawList, ImU32};
|
||||
|
||||
use super::{ImVec2, ImVec4, Ui};
|
||||
|
||||
use std::marker::PhantomData;
|
||||
|
||||
/// Wrap `ImU32` (a type typically used by ImGui to store packed colors)
|
||||
/// This type is used to represent the color of drawing primitives in ImGui's
|
||||
/// custom drawing API.
|
||||
///
|
||||
/// The type implements `From<ImU32>`, `From<ImVec4>`, `From<[f32; 4]>`,
|
||||
/// `From<[f32; 3]>`, `From<(f32, f32, f32, f32)>` and `From<(f32, f32, f32)>`
|
||||
/// for convenience. If alpha is not provided, it is assumed to be 1.0 (255).
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct ImColor(ImU32);
|
||||
|
||||
impl From<ImColor> for ImU32 {
|
||||
fn from(color: ImColor) -> Self { color.0 }
|
||||
}
|
||||
|
||||
impl From<ImU32> for ImColor {
|
||||
fn from(color: ImU32) -> Self { ImColor(color) }
|
||||
}
|
||||
|
||||
impl From<ImVec4> for ImColor {
|
||||
fn from(v: ImVec4) -> Self { ImColor(unsafe { sys::igColorConvertFloat4ToU32(v) }) }
|
||||
}
|
||||
|
||||
impl From<[f32; 4]> for ImColor {
|
||||
fn from(v: [f32; 4]) -> Self { ImColor(unsafe { sys::igColorConvertFloat4ToU32(v.into()) }) }
|
||||
}
|
||||
|
||||
impl From<(f32, f32, f32, f32)> for ImColor {
|
||||
fn from(v: (f32, f32, f32, f32)) -> Self {
|
||||
ImColor(unsafe { sys::igColorConvertFloat4ToU32(v.into()) })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[f32; 3]> for ImColor {
|
||||
fn from(v: [f32; 3]) -> Self { [v[0], v[1], v[2], 1.0].into() }
|
||||
}
|
||||
|
||||
impl From<(f32, f32, f32)> for ImColor {
|
||||
fn from(v: (f32, f32, f32)) -> Self { [v.0, v.1, v.2, 1.0].into() }
|
||||
}
|
||||
|
||||
/// All types from which ImGui's custom draw API can be used implement this
|
||||
/// trait. This trait is internal to this library and implemented by
|
||||
/// `WindowDrawList` and `ChannelsSplit`.
|
||||
pub trait DrawAPI<'ui> {
|
||||
/// Get draw_list object
|
||||
fn draw_list(&self) -> *mut ImDrawList;
|
||||
}
|
||||
|
||||
/// Object implementing the custom draw API.
|
||||
pub struct WindowDrawList<'ui> {
|
||||
draw_list: *mut ImDrawList,
|
||||
_phantom: PhantomData<&'ui Ui<'ui>>,
|
||||
}
|
||||
|
||||
impl<'ui> DrawAPI<'ui> for WindowDrawList<'ui> {
|
||||
fn draw_list(&self) -> *mut ImDrawList { self.draw_list }
|
||||
}
|
||||
|
||||
impl<'ui> WindowDrawList<'ui> {
|
||||
pub fn new(_: &Ui<'ui>) -> Self {
|
||||
Self {
|
||||
draw_list: unsafe { sys::igGetWindowDrawList() },
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Split into *channels_count* drawing channels.
|
||||
/// At the end of the closure, the channels are merged. The objects
|
||||
/// are then drawn in the increasing order of their channel number, and not
|
||||
/// in the all order they were called.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// fn custom_drawing(ui: &Ui) {
|
||||
/// ui.with_window_draw_list(|draw_list| {
|
||||
/// draw_list.channels_split(2, |draw_list| {
|
||||
/// draw_list.channels_set_current(1);
|
||||
/// // ... Draw channel 1
|
||||
/// draw_list.channels_set_current(0);
|
||||
/// // ... Draw channel 0
|
||||
/// });
|
||||
/// });
|
||||
/// }
|
||||
/// ```
|
||||
pub fn channels_split<F: FnOnce(&ChannelsSplit)>(&self, channels_count: u32, f: F) {
|
||||
unsafe { sys::ImDrawList_ChannelsSplit(self.draw_list, channels_count as i32) };
|
||||
f(&ChannelsSplit(self));
|
||||
unsafe { sys::ImDrawList_ChannelsMerge(self.draw_list) };
|
||||
}
|
||||
}
|
||||
|
||||
/// Represent the drawing interface within a call to `channels_split`.
|
||||
pub struct ChannelsSplit<'ui>(&'ui WindowDrawList<'ui>);
|
||||
|
||||
impl<'ui> DrawAPI<'ui> for ChannelsSplit<'ui> {
|
||||
fn draw_list(&self) -> *mut ImDrawList { self.0.draw_list }
|
||||
}
|
||||
|
||||
impl<'ui> ChannelsSplit<'ui> {
|
||||
/// Change current channel
|
||||
pub fn channels_set_current(&self, channel_index: u32) {
|
||||
unsafe { sys::ImDrawList_ChannelsSetCurrent(self.draw_list(), channel_index as i32) };
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_draw_list_methods {
|
||||
($T: ident) => {
|
||||
impl<'ui> $T<'ui>
|
||||
where
|
||||
$T<'ui>: DrawAPI<'ui>,
|
||||
{
|
||||
/// Returns a line from point `p1` to `p2` with color `c`.
|
||||
pub fn add_line<P1, P2, C>(&self, p1: P1, p2: P2, c: C) -> Line<'ui, $T>
|
||||
where
|
||||
P1: Into<ImVec2>,
|
||||
P2: Into<ImVec2>,
|
||||
C: Into<ImColor>,
|
||||
{
|
||||
Line::new(self, p1, p2, c)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_draw_list_methods!(WindowDrawList);
|
||||
impl_draw_list_methods!(ChannelsSplit);
|
||||
|
||||
/// Represents a line about to be drawn
|
||||
pub struct Line<'ui, D: 'ui> {
|
||||
p1: ImVec2,
|
||||
p2: ImVec2,
|
||||
color: ImColor,
|
||||
thickness: f32,
|
||||
draw_list: &'ui D,
|
||||
}
|
||||
|
||||
impl<'ui, D: DrawAPI<'ui>> Line<'ui, D> {
|
||||
fn new<P1, P2, C>(draw_list: &'ui D, p1: P1, p2: P2, c: C) -> Self
|
||||
where
|
||||
P1: Into<ImVec2>,
|
||||
P2: Into<ImVec2>,
|
||||
C: Into<ImColor>,
|
||||
{
|
||||
Self {
|
||||
p1: p1.into(),
|
||||
p2: p2.into(),
|
||||
color: c.into(),
|
||||
thickness: 1.0,
|
||||
draw_list,
|
||||
}
|
||||
}
|
||||
|
||||
/// Set line's thickness (default to 1.0 pixel)
|
||||
pub fn thickness(mut self, thickness: f32) -> Self {
|
||||
self.thickness = thickness;
|
||||
self
|
||||
}
|
||||
|
||||
/// Draw the line on the window
|
||||
pub fn build(self) {
|
||||
unsafe {
|
||||
sys::ImDrawList_AddLine(
|
||||
self.draw_list.draw_list(),
|
||||
self.p1,
|
||||
self.p2,
|
||||
self.color.into(),
|
||||
self.thickness,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user