Add partial support for transparent background colors.

This commit is contained in:
Patrick Walton 2019-04-10 14:42:24 -07:00
parent 12b3b1cd9a
commit c5ccd0f6e0
7 changed files with 145 additions and 31 deletions

View File

@ -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<W> where W: Window {
frame_counter: u32,
pending_screenshot_path: Option<PathBuf>,
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<W> DemoApp<W> where W: Window {
}
pub fn prepare_frame(&mut self, events: Vec<Event>) -> u32 {
// Clear dirty flag.
self.dirty = false;
// Handle events.
let ui_events = self.handle_events(events);
@ -595,6 +600,7 @@ impl<W> DemoApp<W> 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<W> DemoApp<W> 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);
}

View File

@ -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<D> where D: Device {
@ -47,17 +49,17 @@ pub struct DemoUI<D> 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<D> DemoUI<D> 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<D> DemoUI<D> 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<D> DemoUI<D> 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<D> DemoUI<D> 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<D> DemoUI<D> where D: Device {
2,
effects_panel_y,
self.subpixel_aa_effect_enabled);
}
fn draw_background_panel(&mut self,
device: &D,
debug_ui: &mut DebugUI<D>,
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<D> DemoUI<D> 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<D>,
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<D>,
@ -335,8 +399,26 @@ impl<D> DemoUI<D> 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",
}
}
}

View File

@ -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);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 954 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 780 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 448 B

View File

@ -711,7 +711,7 @@ impl UIEventQueue {
mem::replace(&mut self.events, vec![])
}
fn handle_mouse_down_in_rect(&mut self, rect: RectI32) -> Option<Point2DI32> {
pub fn handle_mouse_down_in_rect(&mut self, rect: RectI32) -> Option<Point2DI32> {
let (mut remaining_events, mut result) = (vec![], None);
for event in self.events.drain(..) {
match event {