From c9e5db5aa5b180de94aa948727aa4718ba670f70 Mon Sep 17 00:00:00 2001 From: Joonas Javanainen Date: Sat, 4 Nov 2017 10:07:48 +0200 Subject: [PATCH] Add ColorPicker widget --- CHANGELOG.markdown | 1 + imgui-examples/examples/test_window_impl.rs | 49 ++++++- src/color_editors.rs | 150 ++++++++++++++++++++ src/lib.rs | 9 +- 4 files changed, 202 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown index 0c496bc..96984b6 100644 --- a/CHANGELOG.markdown +++ b/CHANGELOG.markdown @@ -5,6 +5,7 @@ ### Added - Namespaced flags (e.g. `ImGuiWindowFlags`) +- Color picker widget ### Changed diff --git a/imgui-examples/examples/test_window_impl.rs b/imgui-examples/examples/test_window_impl.rs index b847786..edcab61 100644 --- a/imgui-examples/examples/test_window_impl.rs +++ b/imgui-examples/examples/test_window_impl.rs @@ -43,25 +43,35 @@ struct State { auto_resize_state: AutoResizeState, file_menu: FileMenuState, radio_button: i32, - color_picker: ColorPickerState, + color_edit: ColorEditState, } -struct ColorPickerState { +struct ColorEditState { color: [f32; 4], hdr: bool, alpha_preview: bool, alpha_half_preview: bool, options_menu: bool, + alpha: bool, + alpha_bar: bool, + side_preview: bool, + ref_color: bool, + ref_color_v: [f32; 4], } -impl Default for ColorPickerState { +impl Default for ColorEditState { fn default() -> Self { - ColorPickerState { + ColorEditState { color: [114.0 / 255.0, 144.0 / 255.0, 154.0 / 255.0, 200.0 / 255.0], hdr: false, alpha_preview: true, alpha_half_preview: false, options_menu: true, + alpha: true, + alpha_bar: true, + side_preview: true, + ref_color: false, + ref_color_v: [1.0, 0.0, 1.0, 0.5], } } } @@ -108,7 +118,7 @@ impl Default for State { auto_resize_state: Default::default(), file_menu: Default::default(), radio_button: 0, - color_picker: ColorPickerState::default(), + color_edit: ColorEditState::default(), } } } @@ -422,7 +432,7 @@ fn show_test_window<'a>(ui: &Ui<'a>, state: &mut State, opened: &mut bool) { }); ui.tree_node(im_str!("Color/Picker Widgets")).build(|| { - let ref mut s = state.color_picker; + let ref mut s = state.color_edit; ui.checkbox(im_str!("With HDR"), &mut s.hdr); ui.same_line(0.0); show_help_marker(ui, im_str!("Currently all this does is to lift the 0..1 limits on dragging widgets.")); @@ -471,6 +481,33 @@ fn show_test_window<'a>(ui: &Ui<'a>, state: &mut State, opened: &mut bool) { .inputs(false) .label(false) .build(); + + ui.text(im_str!("Color picker:")); + ui.checkbox(im_str!("With Alpha"), &mut s.alpha); + ui.checkbox(im_str!("With Alpha Bar"), &mut s.alpha_bar); + ui.checkbox(im_str!("With Side Preview"), &mut s.side_preview); + if s.side_preview { + ui.same_line(0.0); + ui.checkbox(im_str!("With Ref Color"), &mut s.ref_color); + if s.ref_color { + ui.same_line(0.0); + ui.color_edit(im_str!("##RefColor"), &mut s.ref_color_v) + .flags(misc_flags) + .inputs(false) + .build(); + } + } + let mut b = ui.color_picker(im_str!("MyColor##4"), &mut s.color) + .flags(misc_flags) + .alpha(s.alpha) + .alpha_bar(s.alpha_bar) + .side_preview(s.side_preview) + .rgb(true); + + if s.ref_color { + b = b.reference_color(s.ref_color_v) + } + b.build(); }); } if ui.collapsing_header(im_str!("Popups & Modal windows")) diff --git a/src/color_editors.rs b/src/color_editors.rs index cf8dfb3..b0d66bc 100644 --- a/src/color_editors.rs +++ b/src/color_editors.rs @@ -1,5 +1,6 @@ use imgui_sys; use std::marker::PhantomData; +use std::ptr; use {ImGuiColorEditFlags, ImStr, Ui}; @@ -9,6 +10,15 @@ pub enum EditableColor<'p> { Float4(&'p mut [f32; 4]), } +impl<'p> EditableColor<'p> { + fn as_mut_ptr(&mut self) -> *mut f32 { + match *self { + EditableColor::Float3(ref mut value) => value.as_mut_ptr(), + EditableColor::Float4(ref mut value) => value.as_mut_ptr(), + } + } +} + impl<'p> From<&'p mut [f32; 3]> for EditableColor<'p> { fn from(value: &'p mut [f32; 3]) -> EditableColor<'p> { EditableColor::Float3(value) } } @@ -24,6 +34,12 @@ pub enum ColorEditMode { HEX, } +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum ColorPickerMode { + HueBar, + HueWheel, +} + #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub enum EditableColorFormat { U8, @@ -155,3 +171,137 @@ impl<'ui, 'p> ColorEdit<'ui, 'p> { } } } + + +#[must_use] +pub struct ColorPicker<'ui, 'p> { + label: &'p ImStr, + value: EditableColor<'p>, + flags: ImGuiColorEditFlags, + ref_color: Option<[f32; 4]>, + _phantom: PhantomData<&'ui Ui<'ui>>, +} + +impl<'ui, 'p> ColorPicker<'ui, 'p> { + pub fn new(_: &Ui<'ui>, label: &'p ImStr, value: EditableColor<'p>) -> Self { + ColorPicker { + label, + value, + flags: ImGuiColorEditFlags::empty(), + ref_color: None, + _phantom: PhantomData, + } + } + #[inline] + pub fn flags(mut self, flags: ImGuiColorEditFlags) -> Self { + self.flags = flags; + self + } + #[inline] + pub fn alpha(mut self, value: bool) -> Self { + self.flags.set(ImGuiColorEditFlags::NoAlpha, !value); + self + } + #[inline] + pub fn small_preview(mut self, value: bool) -> Self { + self.flags.set(ImGuiColorEditFlags::NoSmallPreview, !value); + self + } + #[inline] + pub fn inputs(mut self, value: bool) -> Self { + self.flags.set(ImGuiColorEditFlags::NoInputs, !value); + self + } + #[inline] + pub fn tooltip(mut self, value: bool) -> Self { + self.flags.set(ImGuiColorEditFlags::NoTooltip, !value); + self + } + #[inline] + pub fn label(mut self, value: bool) -> Self { + self.flags.set(ImGuiColorEditFlags::NoLabel, !value); + self + } + #[inline] + pub fn side_preview(mut self, value: bool) -> Self { + self.flags.set(ImGuiColorEditFlags::NoSidePreview, !value); + self + } + #[inline] + pub fn alpha_bar(mut self, value: bool) -> Self { + self.flags.set(ImGuiColorEditFlags::AlphaBar, value); + self + } + #[inline] + pub fn preview(mut self, preview: EditableColorPreview) -> Self { + self.flags.set( + ImGuiColorEditFlags::AlphaPreviewHalf, + preview == EditableColorPreview::HalfAlpha, + ); + self.flags.set( + ImGuiColorEditFlags::AlphaPreview, + preview == EditableColorPreview::Alpha, + ); + self + } + #[inline] + pub fn rgb(mut self, value: bool) -> Self { + self.flags.set(ImGuiColorEditFlags::RGB, value); + self + } + #[inline] + pub fn hsv(mut self, value: bool) -> Self { + self.flags.set(ImGuiColorEditFlags::HSV, value); + self + } + #[inline] + pub fn hex(mut self, value: bool) -> Self { + self.flags.set(ImGuiColorEditFlags::HEX, value); + self + } + #[inline] + pub fn mode(mut self, mode: ColorPickerMode) -> Self { + self.flags.set( + ImGuiColorEditFlags::PickerHueBar, + mode == ColorPickerMode::HueBar, + ); + self.flags.set( + ImGuiColorEditFlags::PickerHueWheel, + mode == ColorPickerMode::HueWheel, + ); + self + } + #[inline] + pub fn format(mut self, format: EditableColorFormat) -> Self { + self.flags.set( + ImGuiColorEditFlags::Uint8, + format == EditableColorFormat::U8, + ); + self.flags.set( + ImGuiColorEditFlags::Float, + format == EditableColorFormat::Float, + ); + self + } + #[inline] + pub fn reference_color(mut self, ref_color: [f32; 4]) -> Self { + self.ref_color = Some(ref_color); + self + } + pub fn build(mut self) -> bool { + if let EditableColor::Float3(_) = self.value { + self.flags.insert(ImGuiColorEditFlags::NoAlpha); + } + let ref_color = self.ref_color.as_ref().map(|c| c.as_ptr()).unwrap_or( + ptr::null(), + ); + unsafe { + imgui_sys::igColorPicker4( + self.label.as_ptr(), + self.value.as_mut_ptr(), + self.flags, + ref_color, + ) + } + } +} diff --git a/src/lib.rs b/src/lib.rs index d87881b..b1f33aa 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,7 @@ pub use imgui_sys::{ImDrawIdx, ImDrawVert, ImGuiColorEditFlags, ImGuiInputTextFl ImGuiSelectableFlags, ImGuiCond, ImGuiCol, ImGuiStyle, ImGuiTreeNodeFlags, ImGuiWindowFlags, ImVec2, ImVec4}; pub use child_frame::ChildFrame; -pub use color_editors::{ColorEdit, ColorEditMode, EditableColor, EditableColorFormat}; +pub use color_editors::{ColorEdit, ColorEditMode, ColorPicker, EditableColor, EditableColorFormat}; pub use input::{InputFloat, InputFloat2, InputFloat3, InputFloat4, InputInt, InputInt2, InputInt3, InputInt4, InputText}; pub use menus::{Menu, MenuItem}; @@ -657,6 +657,13 @@ impl<'ui> Ui<'ui> { pub fn color_edit4<'p>(&self, label: &'p ImStr, value: &'p mut [f32; 4]) -> ColorEdit<'ui, 'p> { self.color_edit(label, value) } + pub fn color_picker<'p, V: Into>>( + &self, + label: &'p ImStr, + value: V, + ) -> ColorPicker<'ui, 'p> { + ColorPicker::new(self, label, value.into()) + } } // Widgets: Trees