diff --git a/demo/common/src/lib.rs b/demo/common/src/lib.rs index 6af92428..41689815 100644 --- a/demo/common/src/lib.rs +++ b/demo/common/src/lib.rs @@ -11,7 +11,7 @@ //! A demo app for Pathfinder. use crate::device::{GroundLineVertexArray, GroundProgram, GroundSolidVertexArray}; -use crate::ui::{DemoUI, UIAction}; +use crate::ui::{BackgroundColor, DemoUI, UIAction}; use crate::window::{Event, Keycode, SVGPath, Window, WindowSize}; use clap::{App, Arg}; use image::ColorType; @@ -60,10 +60,12 @@ const CAMERA_ZOOM_AMOUNT_2D: f32 = 0.1; const NEAR_CLIP_PLANE: f32 = 0.01; const FAR_CLIP_PLANE: f32 = 10.0; -const LIGHT_BG_COLOR: ColorU = ColorU { r: 248, g: 248, b: 248, a: 255 }; -const DARK_BG_COLOR: ColorU = ColorU { r: 32, g: 32, b: 32, a: 255 }; -const GROUND_SOLID_COLOR: ColorU = ColorU { r: 80, g: 80, b: 80, a: 255 }; -const GROUND_LINE_COLOR: ColorU = ColorU { r: 127, g: 127, b: 127, a: 255 }; +const LIGHT_BG_COLOR: ColorU = ColorU { r: 248, g: 248, b: 248, a: 255 }; +const DARK_BG_COLOR: ColorU = ColorU { r: 32, g: 32, b: 32, a: 255 }; +const TRANSPARENT_BG_COLOR: ColorU = ColorU { r: 0, g: 0, b: 0, a: 0 }; + +const GROUND_SOLID_COLOR: ColorU = ColorU { r: 80, g: 80, b: 80, a: 255 }; +const GROUND_LINE_COLOR: ColorU = ColorU { r: 127, g: 127, b: 127, a: 255 }; const APPROX_FONT_SIZE: f32 = 16.0; @@ -90,7 +92,7 @@ pub struct DemoApp where W: Window { frame_counter: u32, pending_screenshot_path: Option, mouselook_enabled: bool, - dirty: bool, + pub dirty: bool, expire_message_event_id: u32, message_epoch: u32, last_mouse_position: Point2DI32, @@ -185,6 +187,9 @@ impl DemoApp where W: Window { } pub fn prepare_frame(&mut self, events: Vec) -> u32 { + // Clear dirty flag. + self.dirty = false; + // Handle events. let ui_events = self.handle_events(events); @@ -595,6 +600,7 @@ impl DemoApp where W: Window { fn handle_ui_action(&mut self, ui_action: &mut UIAction) { match ui_action { UIAction::None => {} + UIAction::ModelChanged => self.dirty = true, UIAction::TakeScreenshot(ref path) => { self.pending_screenshot_path = Some((*path).clone()); self.dirty = true; @@ -643,7 +649,11 @@ impl DemoApp where W: Window { } fn background_color(&self) -> ColorU { - if self.ui.dark_background_enabled { DARK_BG_COLOR } else { LIGHT_BG_COLOR } + match self.ui.background_color { + BackgroundColor::Light => LIGHT_BG_COLOR, + BackgroundColor::Dark => DARK_BG_COLOR, + BackgroundColor::Transparent => TRANSPARENT_BG_COLOR, + } } } @@ -813,6 +823,7 @@ pub struct Options { pub mode: Mode, pub input_path: SVGPath, pub ui: UIVisibility, + pub background_color: BackgroundColor, hidden_field_for_future_proofing: (), } @@ -823,6 +834,7 @@ impl Default for Options { mode: Mode::TwoD, input_path: SVGPath::Default, ui: UIVisibility::All, + background_color: BackgroundColor::Light, hidden_field_for_future_proofing: (), } } @@ -849,6 +861,14 @@ impl Options { .possible_values(&["none", "stats", "all"]) .help("How much UI to show"), ) + .arg( + Arg::with_name("background") + .short("b") + .long("background") + .takes_value(true) + .possible_values(&["light", "dark", "transparent"]) + .help("The background color to use"), + ) .arg(Arg::with_name("INPUT").help("Path to the SVG file to render").index(1)) .get_matches(); @@ -870,12 +890,21 @@ impl Options { }; } + if let Some(background_color) = matches.value_of("background") { + self.background_color = match background_color { + "light" => BackgroundColor::Light, + "dark" => BackgroundColor::Dark, + _ => BackgroundColor::Transparent, + }; + } + if let Some(path) = matches.value_of("INPUT") { self.input_path = SVGPath::Path(PathBuf::from(path)); }; } - fn adjust_thread_pool_settings(&self, mut thread_pool_builder: ThreadPoolBuilder) -> ThreadPoolBuilder { + fn adjust_thread_pool_settings(&self, mut thread_pool_builder: ThreadPoolBuilder) + -> ThreadPoolBuilder { if let Some(jobs) = self.jobs { thread_pool_builder = thread_pool_builder.num_threads(jobs); } diff --git a/demo/common/src/ui.rs b/demo/common/src/ui.rs index 706a75ac..da065389 100644 --- a/demo/common/src/ui.rs +++ b/demo/common/src/ui.rs @@ -29,6 +29,9 @@ const SLIDER_KNOB_HEIGHT: i32 = 48; const EFFECTS_PANEL_WIDTH: i32 = 550; const EFFECTS_PANEL_HEIGHT: i32 = BUTTON_HEIGHT * 3 + PADDING * 4; +const BACKGROUND_PANEL_WIDTH: i32 = 250; +const BACKGROUND_PANEL_HEIGHT: i32 = BUTTON_HEIGHT * 3; + const ROTATE_PANEL_WIDTH: i32 = SLIDER_WIDTH + PADDING * 2; const ROTATE_PANEL_HEIGHT: i32 = PADDING * 2 + SLIDER_HEIGHT; @@ -37,8 +40,7 @@ static OPEN_PNG_NAME: &'static str = "demo-open"; static ROTATE_PNG_NAME: &'static str = "demo-rotate"; static ZOOM_IN_PNG_NAME: &'static str = "demo-zoom-in"; static ZOOM_OUT_PNG_NAME: &'static str = "demo-zoom-out"; -static BG_LIGHT_PNG_NAME: &'static str = "demo-bg-light"; -static BG_DARK_PNG_NAME: &'static str = "demo-bg-dark"; +static BACKGROUND_PNG_NAME: &'static str = "demo-background"; static SCREENSHOT_PNG_NAME: &'static str = "demo-screenshot"; pub struct DemoUI where D: Device { @@ -47,17 +49,17 @@ pub struct DemoUI where D: Device { rotate_texture: D::Texture, zoom_in_texture: D::Texture, zoom_out_texture: D::Texture, - bg_light_texture: D::Texture, - bg_dark_texture: D::Texture, + background_texture: D::Texture, screenshot_texture: D::Texture, effects_panel_visible: bool, + background_panel_visible: bool, rotate_panel_visible: bool, // FIXME(pcwalton): Factor the below out into a model class. pub mode: Mode, - pub dark_background_enabled: bool, + pub background_color: BackgroundColor, pub gamma_correction_effect_enabled: bool, pub stem_darkening_effect_enabled: bool, pub subpixel_aa_effect_enabled: bool, @@ -73,8 +75,7 @@ impl DemoUI where D: Device { let rotate_texture = device.create_texture_from_png(resources, ROTATE_PNG_NAME); let zoom_in_texture = device.create_texture_from_png(resources, ZOOM_IN_PNG_NAME); let zoom_out_texture = device.create_texture_from_png(resources, ZOOM_OUT_PNG_NAME); - let bg_light_texture = device.create_texture_from_png(resources, BG_LIGHT_PNG_NAME); - let bg_dark_texture = device.create_texture_from_png(resources, BG_DARK_PNG_NAME); + let background_texture = device.create_texture_from_png(resources, BACKGROUND_PNG_NAME); let screenshot_texture = device.create_texture_from_png(resources, SCREENSHOT_PNG_NAME); DemoUI { @@ -83,15 +84,15 @@ impl DemoUI where D: Device { rotate_texture, zoom_in_texture, zoom_out_texture, - bg_light_texture, - bg_dark_texture, + background_texture, screenshot_texture, effects_panel_visible: false, + background_panel_visible: false, rotate_panel_visible: false, mode: options.mode, - dark_background_enabled: false, + background_color: options.background_color, gamma_correction_effect_enabled: false, stem_darkening_effect_enabled: false, subpixel_aa_effect_enabled: false, @@ -166,7 +167,9 @@ impl DemoUI where D: Device { 1 => Mode::ThreeD, _ => Mode::VR, }; + *action = UIAction::ModelChanged; } + let mode_switch_width = debug_ui.ui.measure_switch(3); let mode_switch_size = Point2DI32::new(mode_switch_width, BUTTON_HEIGHT); debug_ui.ui.draw_tooltip(device, @@ -175,17 +178,18 @@ impl DemoUI where D: Device { position += Point2DI32::new(mode_switch_width + PADDING, 0); // Draw background switch. - self.dark_background_enabled = debug_ui.ui.draw_image_switch(device, - position, - &self.bg_light_texture, - &self.bg_dark_texture, - self.dark_background_enabled); - let background_color_switch_width = debug_ui.ui.measure_switch(2); - let background_color_switch_size = Point2DI32::new(background_color_switch_width, - BUTTON_HEIGHT); - let background_color_switch_rect = RectI32::new(position, background_color_switch_size); - debug_ui.ui.draw_tooltip(device, "Background Color", background_color_switch_rect); - position += Point2DI32::new(background_color_switch_width + PADDING, 0); + if debug_ui.ui.draw_button(device, position, &self.background_texture) { + self.background_panel_visible = !self.background_panel_visible; + } + if !self.background_panel_visible { + debug_ui.ui.draw_tooltip(device, + "Background Color", + RectI32::new(position, button_size)); + } + + // Draw background panel, if necessary. + self.draw_background_panel(device, debug_ui, position.x(), action); + position += Point2DI32::new(button_size.x() + PADDING, 0); // Draw effects panel, if necessary. self.draw_effects_panel(device, debug_ui); @@ -268,7 +272,41 @@ impl DemoUI where D: Device { 2, effects_panel_y, self.subpixel_aa_effect_enabled); + } + fn draw_background_panel(&mut self, + device: &D, + debug_ui: &mut DebugUI, + panel_x: i32, + action: &mut UIAction) { + if !self.background_panel_visible { + return; + } + + let bottom = debug_ui.ui.framebuffer_size().y() - PADDING; + let panel_y = bottom - (BUTTON_HEIGHT + PADDING + BACKGROUND_PANEL_HEIGHT); + let panel_position = Point2DI32::new(panel_x, panel_y); + debug_ui.ui.draw_solid_rounded_rect(device, + RectI32::new(panel_position, + Point2DI32::new(BACKGROUND_PANEL_WIDTH, + BACKGROUND_PANEL_HEIGHT)), + WINDOW_COLOR); + + self.draw_background_menu_item(device, + debug_ui, + BackgroundColor::Light, + panel_position, + action); + self.draw_background_menu_item(device, + debug_ui, + BackgroundColor::Dark, + panel_position, + action); + self.draw_background_menu_item(device, + debug_ui, + BackgroundColor::Transparent, + panel_position, + action); } fn draw_rotate_panel(&mut self, @@ -312,6 +350,32 @@ impl DemoUI where D: Device { debug_ui.ui.draw_solid_rect(device, slider_knob_rect, TEXT_COLOR); } + fn draw_background_menu_item(&mut self, + device: &D, + debug_ui: &mut DebugUI, + color: BackgroundColor, + panel_position: Point2DI32, + action: &mut UIAction) { + let (text, index) = (color.as_str(), color as i32); + + let widget_size = Point2DI32::new(BACKGROUND_PANEL_WIDTH, BUTTON_HEIGHT); + let widget_origin = panel_position + Point2DI32::new(0, widget_size.y() * index); + let widget_rect = RectI32::new(widget_origin, widget_size); + + if color == self.background_color { + debug_ui.ui.draw_solid_rounded_rect(device, widget_rect, TEXT_COLOR); + } + + let (text_x, text_y) = (PADDING * 2, BUTTON_TEXT_OFFSET); + let text_position = widget_origin + Point2DI32::new(text_x, text_y); + debug_ui.ui.draw_text(device, text, text_position, color == self.background_color); + + if let Some(_) = debug_ui.ui.event_queue.handle_mouse_down_in_rect(widget_rect) { + self.background_color = color; + *action = UIAction::ModelChanged; + } + } + fn draw_effects_switch(&self, device: &D, debug_ui: &mut DebugUI, @@ -335,8 +399,26 @@ impl DemoUI where D: Device { #[derive(Clone, Debug, PartialEq)] pub enum UIAction { None, + ModelChanged, TakeScreenshot(PathBuf), ZoomIn, ZoomOut, Rotate(f32), } + +#[derive(Clone, Copy, Debug, PartialEq)] +pub enum BackgroundColor { + Light = 0, + Dark = 1, + Transparent = 2, +} + +impl BackgroundColor { + fn as_str(&self) -> &'static str { + match *self { + BackgroundColor::Light => "Light", + BackgroundColor::Dark => "Dark", + BackgroundColor::Transparent => "Transparent", + } + } +} diff --git a/demo/native/src/main.rs b/demo/native/src/main.rs index a1264142..94b1f255 100644 --- a/demo/native/src/main.rs +++ b/demo/native/src/main.rs @@ -39,7 +39,10 @@ fn main() { let mut app = DemoApp::new(window, window_size, options); while !app.should_exit { - let mut events = vec![app.window.get_event()]; + let mut events = vec![]; + if !app.dirty { + events.push(app.window.get_event()); + } while let Some(event) = app.window.try_get_event() { events.push(event); } diff --git a/resources/textures/demo-background.png b/resources/textures/demo-background.png new file mode 100644 index 00000000..c1d06737 Binary files /dev/null and b/resources/textures/demo-background.png differ diff --git a/resources/textures/demo-bg-dark.png b/resources/textures/demo-bg-dark.png deleted file mode 100644 index 82275e92..00000000 Binary files a/resources/textures/demo-bg-dark.png and /dev/null differ diff --git a/resources/textures/demo-bg-light.png b/resources/textures/demo-bg-light.png deleted file mode 100644 index e1540dfe..00000000 Binary files a/resources/textures/demo-bg-light.png and /dev/null differ diff --git a/ui/src/lib.rs b/ui/src/lib.rs index 04332920..f1e92aa4 100644 --- a/ui/src/lib.rs +++ b/ui/src/lib.rs @@ -711,7 +711,7 @@ impl UIEventQueue { mem::replace(&mut self.events, vec![]) } - fn handle_mouse_down_in_rect(&mut self, rect: RectI32) -> Option { + pub fn handle_mouse_down_in_rect(&mut self, rect: RectI32) -> Option { let (mut remaining_events, mut result) = (vec![], None); for event in self.events.drain(..) { match event {