Improve the regions with available_width
This commit is contained in:
parent
56da7f40e8
commit
ae40b617ad
8 changed files with 186 additions and 73 deletions
|
@ -1,3 +1,5 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crate::{font::Font, layout, style, types::GuiInput, Frame, Painter, RawInput};
|
use crate::{font::Font, layout, style, types::GuiInput, Frame, Painter, RawInput};
|
||||||
|
|
||||||
/// Encapsulates input, layout and painting for ease of use.
|
/// Encapsulates input, layout and painting for ease of use.
|
||||||
|
@ -10,7 +12,7 @@ pub struct Emgui {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Emgui {
|
impl Emgui {
|
||||||
pub fn new(font: Font) -> Emgui {
|
pub fn new(font: Arc<Font>) -> Emgui {
|
||||||
Emgui {
|
Emgui {
|
||||||
last_input: Default::default(),
|
last_input: Default::default(),
|
||||||
data: layout::Data::new(font.clone()),
|
data: layout::Data::new(font.clone()),
|
||||||
|
@ -30,12 +32,14 @@ impl Emgui {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn whole_screen_region(&mut self) -> layout::Region {
|
pub fn whole_screen_region(&mut self) -> layout::Region {
|
||||||
|
let size = self.data.input.screen_size;
|
||||||
layout::Region {
|
layout::Region {
|
||||||
data: &mut self.data,
|
data: &mut self.data,
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
dir: layout::Direction::Vertical,
|
dir: layout::Direction::Vertical,
|
||||||
cursor: Default::default(),
|
cursor: Default::default(),
|
||||||
size: Default::default(),
|
bounding_size: Default::default(),
|
||||||
|
available_space: size,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -44,7 +48,7 @@ impl Emgui {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn paint(&mut self) -> Frame {
|
pub fn paint(&mut self) -> Frame {
|
||||||
let gui_commands = self.data.gui_commands();
|
let gui_commands = self.data.drain_gui_commands();
|
||||||
let paint_commands = style::into_paint_commands(gui_commands, &self.style);
|
let paint_commands = style::into_paint_commands(gui_commands, &self.style);
|
||||||
self.painter.paint(&paint_commands)
|
self.painter.paint(&paint_commands)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#![allow(unused)] // TODO
|
|
||||||
|
|
||||||
use rusttype::{point, Scale};
|
use rusttype::{point, Scale};
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||||
|
@ -27,7 +25,6 @@ pub struct GlyphInfo {
|
||||||
/// Printable ASCII characters [32, 126], which excludes control codes.
|
/// Printable ASCII characters [32, 126], which excludes control codes.
|
||||||
const FIRST_ASCII: usize = 32; // 32 == space
|
const FIRST_ASCII: usize = 32; // 32 == space
|
||||||
const LAST_ASCII: usize = 126;
|
const LAST_ASCII: usize = 126;
|
||||||
const NUM_CHARS: usize = LAST_ASCII - FIRST_ASCII + 1;
|
|
||||||
|
|
||||||
// TODO: break out texture atlas into separate struct, and fill it dynamically, potentially from multiple fonts.
|
// TODO: break out texture atlas into separate struct, and fill it dynamically, potentially from multiple fonts.
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -116,7 +113,7 @@ impl Font {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
let offset_y = scale as i16 + bb.min.y as i16 - 3; // TODO: use font.v_metrics
|
let offset_y = scale as i16 + bb.min.y as i16 - 4; // TODO: use font.v_metrics
|
||||||
glyph_infos.push(GlyphInfo {
|
glyph_infos.push(GlyphInfo {
|
||||||
id: glyph.id(),
|
id: glyph.id(),
|
||||||
advance_width: glyph.unpositioned().h_metrics().advance_width,
|
advance_width: glyph.unpositioned().h_metrics().advance_width,
|
||||||
|
@ -230,7 +227,7 @@ impl Font {
|
||||||
let scale = Scale::uniform(self.scale as f32);
|
let scale = Scale::uniform(self.scale as f32);
|
||||||
let mut pixel_rows = vec![vec![0; max_width]; self.scale];
|
let mut pixel_rows = vec![vec![0; max_width]; self.scale];
|
||||||
let mut cursor_x = 0.0;
|
let mut cursor_x = 0.0;
|
||||||
let mut cursor_y = 0;
|
let cursor_y = 0;
|
||||||
let mut last_glyph_id = None;
|
let mut last_glyph_id = None;
|
||||||
for c in Self::supported_characters() {
|
for c in Self::supported_characters() {
|
||||||
if let Some(glyph) = self.glyph_info(c) {
|
if let Some(glyph) = self.glyph_info(c) {
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::collections::HashSet;
|
use std::{collections::HashSet, sync::Arc};
|
||||||
|
|
||||||
use crate::{font::Font, math::*, types::*};
|
use crate::{font::Font, math::*, types::*};
|
||||||
|
|
||||||
|
@ -15,9 +15,6 @@ pub struct LayoutOptions {
|
||||||
/// Indent foldable regions etc by this much.
|
/// Indent foldable regions etc by this much.
|
||||||
pub indent: f32,
|
pub indent: f32,
|
||||||
|
|
||||||
/// Default width of sliders, foldout categories etc. TODO: percentage of parent?
|
|
||||||
pub width: f32,
|
|
||||||
|
|
||||||
/// Button size is text size plus this on each side
|
/// Button size is text size plus this on each side
|
||||||
pub button_padding: Vec2,
|
pub button_padding: Vec2,
|
||||||
|
|
||||||
|
@ -32,7 +29,6 @@ impl Default for LayoutOptions {
|
||||||
item_spacing: vec2(8.0, 4.0),
|
item_spacing: vec2(8.0, 4.0),
|
||||||
window_padding: vec2(6.0, 6.0),
|
window_padding: vec2(6.0, 6.0),
|
||||||
indent: 21.0,
|
indent: 21.0,
|
||||||
width: 250.0,
|
|
||||||
button_padding: vec2(5.0, 3.0),
|
button_padding: vec2(5.0, 3.0),
|
||||||
start_icon_width: 20.0,
|
start_icon_width: 20.0,
|
||||||
}
|
}
|
||||||
|
@ -123,7 +119,7 @@ type Id = u64;
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Data {
|
pub struct Data {
|
||||||
pub(crate) options: LayoutOptions,
|
pub(crate) options: LayoutOptions,
|
||||||
pub(crate) font: Font, // TODO: Arc?. TODO: move to options.
|
pub(crate) font: Arc<Font>,
|
||||||
pub(crate) input: GuiInput,
|
pub(crate) input: GuiInput,
|
||||||
pub(crate) memory: Memory,
|
pub(crate) memory: Memory,
|
||||||
pub(crate) graphics: Vec<GuiCmd>,
|
pub(crate) graphics: Vec<GuiCmd>,
|
||||||
|
@ -131,7 +127,7 @@ pub struct Data {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Data {
|
impl Data {
|
||||||
pub fn new(font: Font) -> Data {
|
pub fn new(font: Arc<Font>) -> Data {
|
||||||
Data {
|
Data {
|
||||||
options: Default::default(),
|
options: Default::default(),
|
||||||
font,
|
font,
|
||||||
|
@ -146,10 +142,6 @@ impl Data {
|
||||||
&self.input
|
&self.input
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn gui_commands(&self) -> impl Iterator<Item = &GuiCmd> {
|
|
||||||
self.graphics.iter().chain(self.hovering_graphics.iter())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn options(&self) -> &LayoutOptions {
|
pub fn options(&self) -> &LayoutOptions {
|
||||||
&self.options
|
&self.options
|
||||||
}
|
}
|
||||||
|
@ -160,14 +152,19 @@ impl Data {
|
||||||
|
|
||||||
// TODO: move
|
// TODO: move
|
||||||
pub fn new_frame(&mut self, gui_input: GuiInput) {
|
pub fn new_frame(&mut self, gui_input: GuiInput) {
|
||||||
self.graphics.clear();
|
|
||||||
self.hovering_graphics.clear();
|
|
||||||
self.input = gui_input;
|
self.input = gui_input;
|
||||||
if !gui_input.mouse_down {
|
if !gui_input.mouse_down {
|
||||||
self.memory.active_id = None;
|
self.memory.active_id = None;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn drain_gui_commands(&mut self) -> impl ExactSizeIterator<Item = GuiCmd> {
|
||||||
|
// TODO: there must be a nicer way to do this?
|
||||||
|
let mut all_commands: Vec<_> = self.graphics.drain(..).collect();
|
||||||
|
all_commands.extend(self.hovering_graphics.drain(..));
|
||||||
|
all_commands.into_iter()
|
||||||
|
}
|
||||||
|
|
||||||
/// Show a pop-over window
|
/// Show a pop-over window
|
||||||
pub fn show_popup<F>(&mut self, window_pos: Vec2, add_contents: F)
|
pub fn show_popup<F>(&mut self, window_pos: Vec2, add_contents: F)
|
||||||
where
|
where
|
||||||
|
@ -183,13 +180,14 @@ impl Data {
|
||||||
id: Default::default(),
|
id: Default::default(),
|
||||||
dir: Direction::Vertical,
|
dir: Direction::Vertical,
|
||||||
cursor: window_pos + window_padding,
|
cursor: window_pos + window_padding,
|
||||||
size: vec2(0.0, 0.0),
|
bounding_size: vec2(0.0, 0.0),
|
||||||
|
available_space: vec2(400.0, std::f32::INFINITY), // TODO
|
||||||
};
|
};
|
||||||
|
|
||||||
add_contents(&mut popup_region);
|
add_contents(&mut popup_region);
|
||||||
|
|
||||||
// TODO: handle the last item_spacing in a nicer way
|
// TODO: handle the last item_spacing in a nicer way
|
||||||
let inner_size = popup_region.size - self.options.item_spacing;
|
let inner_size = popup_region.bounding_size - self.options.item_spacing;
|
||||||
let outer_size = inner_size + 2.0 * window_padding;
|
let outer_size = inner_size + 2.0 * window_padding;
|
||||||
|
|
||||||
let rect = Rect::from_min_size(window_pos, outer_size);
|
let rect = Rect::from_min_size(window_pos, outer_size);
|
||||||
|
@ -204,10 +202,11 @@ impl Data {
|
||||||
|
|
||||||
/// Represents a region of the screen
|
/// Represents a region of the screen
|
||||||
/// with a type of layout (horizontal or vertical).
|
/// with a type of layout (horizontal or vertical).
|
||||||
|
/// TODO: make Region a trait so we can have type-safe HorizontalRegion etc?
|
||||||
pub struct Region<'a> {
|
pub struct Region<'a> {
|
||||||
|
// TODO: Arc<StaticDat> + Arc<Mutex<MutableData>> for a lot less hassle.
|
||||||
pub(crate) data: &'a mut Data,
|
pub(crate) data: &'a mut Data,
|
||||||
|
|
||||||
// TODO: add min_size and max_size
|
|
||||||
/// Unique ID of this region.
|
/// Unique ID of this region.
|
||||||
pub(crate) id: Id,
|
pub(crate) id: Id,
|
||||||
|
|
||||||
|
@ -217,8 +216,13 @@ pub struct Region<'a> {
|
||||||
/// Changes only along self.dir
|
/// Changes only along self.dir
|
||||||
pub(crate) cursor: Vec2,
|
pub(crate) cursor: Vec2,
|
||||||
|
|
||||||
|
/// Bounding box children.
|
||||||
/// We keep track of our max-size along the orthogonal to self.dir
|
/// We keep track of our max-size along the orthogonal to self.dir
|
||||||
pub(crate) size: Vec2,
|
pub(crate) bounding_size: Vec2,
|
||||||
|
|
||||||
|
/// This how much space we can take up without overflowing our parent.
|
||||||
|
/// Shrinks as cursor increments.
|
||||||
|
pub(crate) available_space: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Region<'a> {
|
impl<'a> Region<'a> {
|
||||||
|
@ -233,6 +237,7 @@ impl<'a> Region<'a> {
|
||||||
self.data.options()
|
self.data.options()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: remove
|
||||||
pub fn set_options(&mut self, options: LayoutOptions) {
|
pub fn set_options(&mut self, options: LayoutOptions) {
|
||||||
self.data.set_options(options)
|
self.data.set_options(options)
|
||||||
}
|
}
|
||||||
|
@ -241,6 +246,10 @@ impl<'a> Region<'a> {
|
||||||
self.data.input()
|
self.data.input()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn cursor(&self) -> Vec2 {
|
||||||
|
self.cursor
|
||||||
|
}
|
||||||
|
|
||||||
pub fn button<S: Into<String>>(&mut self, text: S) -> GuiResponse {
|
pub fn button<S: Into<String>>(&mut self, text: S) -> GuiResponse {
|
||||||
let text: String = text.into();
|
let text: String = text.into();
|
||||||
let id = self.get_id(&text);
|
let id = self.get_id(&text);
|
||||||
|
@ -326,7 +335,7 @@ impl<'a> Region<'a> {
|
||||||
self.reserve_space_inner(text_size);
|
self.reserve_space_inner(text_size);
|
||||||
let (slider_rect, interact) = self.reserve_space(
|
let (slider_rect, interact) = self.reserve_space(
|
||||||
Vec2 {
|
Vec2 {
|
||||||
x: self.options().width,
|
x: self.available_space.x,
|
||||||
y: self.data.font.line_spacing(),
|
y: self.data.font.line_spacing(),
|
||||||
},
|
},
|
||||||
Some(id),
|
Some(id),
|
||||||
|
@ -354,7 +363,7 @@ impl<'a> Region<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Areas:
|
// Sub-regions:
|
||||||
|
|
||||||
pub fn foldable<S, F>(&mut self, text: S, add_contents: F) -> GuiResponse
|
pub fn foldable<S, F>(&mut self, text: S, add_contents: F) -> GuiResponse
|
||||||
where
|
where
|
||||||
|
@ -371,7 +380,7 @@ impl<'a> Region<'a> {
|
||||||
let text_cursor = self.cursor + self.options().button_padding;
|
let text_cursor = self.cursor + self.options().button_padding;
|
||||||
let (rect, interact) = self.reserve_space(
|
let (rect, interact) = self.reserve_space(
|
||||||
vec2(
|
vec2(
|
||||||
self.options().width,
|
self.available_space.x,
|
||||||
text_size.y + 2.0 * self.options().button_padding.y,
|
text_size.y + 2.0 * self.options().button_padding.y,
|
||||||
),
|
),
|
||||||
Some(id),
|
Some(id),
|
||||||
|
@ -397,39 +406,115 @@ impl<'a> Region<'a> {
|
||||||
);
|
);
|
||||||
|
|
||||||
if open {
|
if open {
|
||||||
// TODO: new region
|
|
||||||
let old_id = self.id;
|
let old_id = self.id;
|
||||||
self.id = id;
|
self.id = id;
|
||||||
let old_x = self.cursor.x;
|
self.indent(add_contents);
|
||||||
self.cursor.x += self.options().indent;
|
|
||||||
add_contents(self);
|
|
||||||
self.cursor.x = old_x;
|
|
||||||
self.id = old_id;
|
self.id = old_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
self.response(interact)
|
self.response(interact)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Create a child region which is indented to the right
|
||||||
|
pub fn indent<F>(&mut self, add_contents: F)
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Region),
|
||||||
|
{
|
||||||
|
let indent = vec2(self.options().indent, 0.0);
|
||||||
|
let mut child_region = Region {
|
||||||
|
data: self.data,
|
||||||
|
id: self.id,
|
||||||
|
dir: self.dir,
|
||||||
|
cursor: self.cursor + indent,
|
||||||
|
bounding_size: vec2(0.0, 0.0),
|
||||||
|
available_space: self.available_space - indent,
|
||||||
|
};
|
||||||
|
add_contents(&mut child_region);
|
||||||
|
let size = child_region.bounding_size;
|
||||||
|
self.reserve_space_inner(indent + size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A horizontally centered region of the given width.
|
||||||
|
pub fn centered_column(&mut self, width: f32) -> Region {
|
||||||
|
Region {
|
||||||
|
data: self.data,
|
||||||
|
id: self.id,
|
||||||
|
dir: self.dir,
|
||||||
|
cursor: vec2((self.available_space.x - width) / 2.0, self.cursor.y),
|
||||||
|
bounding_size: vec2(0.0, 0.0),
|
||||||
|
available_space: vec2(width, self.available_space.y),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Start a region with horizontal layout
|
/// Start a region with horizontal layout
|
||||||
pub fn horizontal<F>(&mut self, add_contents: F)
|
pub fn horizontal<F>(&mut self, add_contents: F)
|
||||||
where
|
where
|
||||||
F: FnOnce(&mut Region),
|
F: FnOnce(&mut Region),
|
||||||
{
|
{
|
||||||
let mut horizontal_region = Region {
|
let mut child_region = Region {
|
||||||
data: self.data,
|
data: self.data,
|
||||||
id: self.id,
|
id: self.id,
|
||||||
dir: Direction::Horizontal,
|
dir: Direction::Horizontal,
|
||||||
cursor: self.cursor,
|
cursor: self.cursor,
|
||||||
size: vec2(0.0, 0.0),
|
bounding_size: vec2(0.0, 0.0),
|
||||||
|
available_space: self.available_space,
|
||||||
};
|
};
|
||||||
add_contents(&mut horizontal_region);
|
add_contents(&mut child_region);
|
||||||
let size = horizontal_region.size;
|
let size = child_region.bounding_size;
|
||||||
self.reserve_space_inner(size);
|
self.reserve_space_inner(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: we need to rethink this a lot. Passing closures have problems with borrow checker.
|
||||||
|
// Much better with temporary regions that register the final size in Drop ?
|
||||||
|
|
||||||
|
// pub fn columns_2<F0, F1>(&mut self, col0: F0, col1: F1)
|
||||||
|
// where
|
||||||
|
// F0: FnOnce(&mut Region),
|
||||||
|
// F1: FnOnce(&mut Region),
|
||||||
|
// {
|
||||||
|
// let mut max_height = 0.0;
|
||||||
|
// let num_columns = 2;
|
||||||
|
// // TODO: ensure there is space
|
||||||
|
// let padding = self.options().item_spacing.x;
|
||||||
|
// let total_padding = padding * (num_columns as f32 - 1.0);
|
||||||
|
// let column_width = (self.available_space.x - total_padding) / (num_columns as f32);
|
||||||
|
|
||||||
|
// let col_idx = 0;
|
||||||
|
// let mut child_region = Region {
|
||||||
|
// data: self.data,
|
||||||
|
// id: self.id,
|
||||||
|
// dir: Direction::Vertical,
|
||||||
|
// cursor: self.cursor + vec2((col_idx as f32) * (column_width + padding), 0.0),
|
||||||
|
// bounding_size: vec2(0.0, 0.0),
|
||||||
|
// available_space: vec2(column_width, self.available_space.y),
|
||||||
|
// };
|
||||||
|
// col0(&mut child_region);
|
||||||
|
// let size = child_region.bounding_size;
|
||||||
|
// max_height = size.y.max(max_height);
|
||||||
|
|
||||||
|
// let col_idx = 1;
|
||||||
|
// let mut child_region = Region {
|
||||||
|
// data: self.data,
|
||||||
|
// id: self.id,
|
||||||
|
// dir: Direction::Vertical,
|
||||||
|
// cursor: self.cursor + vec2((col_idx as f32) * (column_width + padding), 0.0),
|
||||||
|
// bounding_size: vec2(0.0, 0.0),
|
||||||
|
// available_space: vec2(column_width, self.available_space.y),
|
||||||
|
// };
|
||||||
|
// col1(&mut child_region);
|
||||||
|
// let size = child_region.bounding_size;
|
||||||
|
// max_height = size.y.max(max_height);
|
||||||
|
|
||||||
|
// self.reserve_space_inner(vec2(self.available_space.x, max_height));
|
||||||
|
// }
|
||||||
|
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
|
|
||||||
fn reserve_space(&mut self, size: Vec2, interaction_id: Option<Id>) -> (Rect, InteractInfo) {
|
pub fn reserve_space(
|
||||||
|
&mut self,
|
||||||
|
size: Vec2,
|
||||||
|
interaction_id: Option<Id>,
|
||||||
|
) -> (Rect, InteractInfo) {
|
||||||
let rect = Rect {
|
let rect = Rect {
|
||||||
pos: self.cursor,
|
pos: self.cursor,
|
||||||
size,
|
size,
|
||||||
|
@ -458,12 +543,14 @@ impl<'a> Region<'a> {
|
||||||
fn reserve_space_inner(&mut self, size: Vec2) {
|
fn reserve_space_inner(&mut self, size: Vec2) {
|
||||||
if self.dir == Direction::Horizontal {
|
if self.dir == Direction::Horizontal {
|
||||||
self.cursor.x += size.x;
|
self.cursor.x += size.x;
|
||||||
self.size.x += size.x;
|
self.available_space.x -= size.x;
|
||||||
self.size.y = self.size.y.max(size.y);
|
self.bounding_size.x += size.x;
|
||||||
|
self.bounding_size.y = self.bounding_size.y.max(size.y);
|
||||||
} else {
|
} else {
|
||||||
self.cursor.y += size.y;
|
self.cursor.y += size.y;
|
||||||
self.size.y += size.y;
|
self.available_space.y -= size.x;
|
||||||
self.size.x = self.size.x.max(size.x);
|
self.bounding_size.y += size.y;
|
||||||
|
self.bounding_size.x = self.bounding_size.x.max(size.x);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#![allow(unused_variables)]
|
use std::sync::Arc;
|
||||||
|
|
||||||
const ANTI_ALIAS: bool = true;
|
const ANTI_ALIAS: bool = true;
|
||||||
const AA_SIZE: f32 = 1.0;
|
const AA_SIZE: f32 = 1.0;
|
||||||
|
@ -131,7 +131,6 @@ impl Frame {
|
||||||
for i1 in 0..n {
|
for i1 in 0..n {
|
||||||
let connect_with_previous = path_type == PathType::Closed || i1 > 0;
|
let connect_with_previous = path_type == PathType::Closed || i1 > 0;
|
||||||
if thin_line {
|
if thin_line {
|
||||||
let hw = (width - AA_SIZE) * 0.5;
|
|
||||||
let p = points[i1 as usize];
|
let p = points[i1 as usize];
|
||||||
let n = normals[i1 as usize];
|
let n = normals[i1 as usize];
|
||||||
self.vertices.push(vert(p + n * AA_SIZE, color_outer));
|
self.vertices.push(vert(p + n * AA_SIZE, color_outer));
|
||||||
|
@ -194,11 +193,11 @@ impl Frame {
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Painter {
|
pub struct Painter {
|
||||||
font: Font,
|
font: Arc<Font>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Painter {
|
impl Painter {
|
||||||
pub fn new(font: Font) -> Painter {
|
pub fn new(font: Arc<Font>) -> Painter {
|
||||||
Painter { font }
|
Painter { font }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -289,7 +288,7 @@ impl Painter {
|
||||||
|
|
||||||
let cr = corner_radius.min(size.x * 0.5).min(size.y * 0.5);
|
let cr = corner_radius.min(size.x * 0.5).min(size.y * 0.5);
|
||||||
|
|
||||||
if cr < 1.0 {
|
if cr <= 0.0 {
|
||||||
path_points.push(vec2(min.x, min.y));
|
path_points.push(vec2(min.x, min.y));
|
||||||
path_normals.push(vec2(-1.0, -1.0));
|
path_normals.push(vec2(-1.0, -1.0));
|
||||||
path_points.push(vec2(max.x, min.y));
|
path_points.push(vec2(max.x, min.y));
|
||||||
|
|
|
@ -275,11 +275,11 @@ pub fn into_paint_commands<'a, GuiCmdIterator>(
|
||||||
style: &Style,
|
style: &Style,
|
||||||
) -> Vec<PaintCmd>
|
) -> Vec<PaintCmd>
|
||||||
where
|
where
|
||||||
GuiCmdIterator: Iterator<Item = &'a GuiCmd>,
|
GuiCmdIterator: Iterator<Item = GuiCmd>,
|
||||||
{
|
{
|
||||||
let mut paint_commands = vec![];
|
let mut paint_commands = vec![];
|
||||||
for gui_cmd in gui_commands {
|
for gui_cmd in gui_commands {
|
||||||
translate_cmd(&mut paint_commands, style, gui_cmd.clone())
|
translate_cmd(&mut paint_commands, style, gui_cmd)
|
||||||
}
|
}
|
||||||
paint_commands
|
paint_commands
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,8 +9,7 @@ pub struct App {
|
||||||
count: i32,
|
count: i32,
|
||||||
selected_alternative: i32,
|
selected_alternative: i32,
|
||||||
|
|
||||||
width: f32,
|
size: Vec2,
|
||||||
height: f32,
|
|
||||||
corner_radius: f32,
|
corner_radius: f32,
|
||||||
stroke_width: f32,
|
stroke_width: f32,
|
||||||
}
|
}
|
||||||
|
@ -21,8 +20,7 @@ impl Default for App {
|
||||||
checked: true,
|
checked: true,
|
||||||
selected_alternative: 0,
|
selected_alternative: 0,
|
||||||
count: 0,
|
count: 0,
|
||||||
width: 100.0,
|
size: vec2(100.0, 50.0),
|
||||||
height: 50.0,
|
|
||||||
corner_radius: 5.0,
|
corner_radius: 5.0,
|
||||||
stroke_width: 2.0,
|
stroke_width: 2.0,
|
||||||
}
|
}
|
||||||
|
@ -65,23 +63,25 @@ impl GuiSettings for App {
|
||||||
|
|
||||||
gui.label(format!("This is a multiline label.\nThe button have been clicked {} times.\nBelow are more options.", self.count));
|
gui.label(format!("This is a multiline label.\nThe button have been clicked {} times.\nBelow are more options.", self.count));
|
||||||
|
|
||||||
gui.foldable("Box rendering options", |gui| {
|
gui.foldable("Test box rendering", |gui| {
|
||||||
gui.slider_f32("width", &mut self.width, 0.0, 500.0);
|
gui.slider_f32("width", &mut self.size.x, 0.0, 500.0);
|
||||||
gui.slider_f32("height", &mut self.height, 0.0, 500.0);
|
gui.slider_f32("height", &mut self.size.y, 0.0, 500.0);
|
||||||
gui.slider_f32("corner_radius", &mut self.corner_radius, 0.0, 50.0);
|
gui.slider_f32("corner_radius", &mut self.corner_radius, 0.0, 50.0);
|
||||||
gui.slider_f32("stroke_width", &mut self.stroke_width, 0.0, 10.0);
|
gui.slider_f32("stroke_width", &mut self.stroke_width, 0.0, 10.0);
|
||||||
});
|
|
||||||
|
|
||||||
|
let pos = gui.cursor();
|
||||||
gui.add_graphic(GuiCmd::PaintCommands(vec![PaintCmd::Rect {
|
gui.add_graphic(GuiCmd::PaintCommands(vec![PaintCmd::Rect {
|
||||||
corner_radius: self.corner_radius,
|
corner_radius: self.corner_radius,
|
||||||
fill_color: Some(srgba(136, 136, 136, 255)),
|
fill_color: Some(srgba(136, 136, 136, 255)),
|
||||||
pos: vec2(300.0, 100.0),
|
pos,
|
||||||
size: vec2(self.width, self.height),
|
size: self.size,
|
||||||
outline: Some(Outline {
|
outline: Some(Outline {
|
||||||
width: self.stroke_width,
|
width: self.stroke_width,
|
||||||
color: srgba(255, 255, 255, 255),
|
color: srgba(255, 255, 255, 255),
|
||||||
}),
|
}),
|
||||||
}]));
|
}]));
|
||||||
|
gui.reserve_space(self.size, None);
|
||||||
|
});
|
||||||
|
|
||||||
gui.foldable("LayoutOptions", |gui| {
|
gui.foldable("LayoutOptions", |gui| {
|
||||||
let mut options = gui.options().clone();
|
let mut options = gui.options().clone();
|
||||||
|
@ -101,7 +101,6 @@ impl GuiSettings for emgui::LayoutOptions {
|
||||||
gui.slider_f32("window_padding.x", &mut self.window_padding.x, 0.0, 10.0);
|
gui.slider_f32("window_padding.x", &mut self.window_padding.x, 0.0, 10.0);
|
||||||
gui.slider_f32("window_padding.y", &mut self.window_padding.y, 0.0, 10.0);
|
gui.slider_f32("window_padding.y", &mut self.window_padding.y, 0.0, 10.0);
|
||||||
gui.slider_f32("indent", &mut self.indent, 0.0, 100.0);
|
gui.slider_f32("indent", &mut self.indent, 0.0, 100.0);
|
||||||
gui.slider_f32("width", &mut self.width, 0.0, 1000.0);
|
|
||||||
gui.slider_f32("button_padding.x", &mut self.button_padding.x, 0.0, 20.0);
|
gui.slider_f32("button_padding.x", &mut self.button_padding.x, 0.0, 20.0);
|
||||||
gui.slider_f32("button_padding.y", &mut self.button_padding.y, 0.0, 20.0);
|
gui.slider_f32("button_padding.y", &mut self.button_padding.y, 0.0, 20.0);
|
||||||
gui.slider_f32("start_icon_width", &mut self.start_icon_width, 0.0, 60.0);
|
gui.slider_f32("start_icon_width", &mut self.start_icon_width, 0.0, 60.0);
|
||||||
|
|
|
@ -5,6 +5,8 @@ extern crate wasm_bindgen;
|
||||||
|
|
||||||
extern crate emgui;
|
extern crate emgui;
|
||||||
|
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
use emgui::{Emgui, Font, RawInput};
|
use emgui::{Emgui, Font, RawInput};
|
||||||
|
|
||||||
use wasm_bindgen::prelude::*;
|
use wasm_bindgen::prelude::*;
|
||||||
|
@ -38,7 +40,7 @@ pub struct State {
|
||||||
|
|
||||||
impl State {
|
impl State {
|
||||||
fn new(canvas_id: &str) -> Result<State, JsValue> {
|
fn new(canvas_id: &str) -> Result<State, JsValue> {
|
||||||
let font = Font::new(20); // TODO: Arc to avoid cloning
|
let font = Arc::new(Font::new(20));
|
||||||
let emgui = Emgui::new(font);
|
let emgui = Emgui::new(font);
|
||||||
let webgl_painter = webgl::Painter::new(canvas_id, emgui.texture())?;
|
let webgl_painter = webgl::Painter::new(canvas_id, emgui.texture())?;
|
||||||
Ok(State {
|
Ok(State {
|
||||||
|
@ -58,21 +60,31 @@ impl State {
|
||||||
|
|
||||||
let mut style = self.emgui.style.clone();
|
let mut style = self.emgui.style.clone();
|
||||||
let mut region = self.emgui.whole_screen_region();
|
let mut region = self.emgui.whole_screen_region();
|
||||||
|
let mut region = region.centered_column(300.0);
|
||||||
self.app.show_gui(&mut region);
|
self.app.show_gui(&mut region);
|
||||||
|
|
||||||
|
// TODO: move this to some emgui::example module
|
||||||
region.foldable("Style", |gui| {
|
region.foldable("Style", |gui| {
|
||||||
style.show_gui(gui);
|
style.show_gui(gui);
|
||||||
});
|
});
|
||||||
|
|
||||||
let stats = self.stats; // TODO: avoid
|
let stats = self.stats; // TODO: avoid
|
||||||
|
let webgl_info = self.webgl_painter.debug_info(); // TODO: avoid
|
||||||
region.foldable("Stats", |gui| {
|
region.foldable("Stats", |gui| {
|
||||||
gui.label(format!("num_vertices: {}", stats.num_vertices));
|
gui.label(format!("num_vertices: {}", stats.num_vertices));
|
||||||
gui.label(format!("num_triangles: {}", stats.num_triangles));
|
gui.label(format!("num_triangles: {}", stats.num_triangles));
|
||||||
|
|
||||||
|
gui.label("WebGl painter info:");
|
||||||
|
gui.indent(|gui| {
|
||||||
|
gui.label(webgl_info);
|
||||||
|
});
|
||||||
|
|
||||||
gui.label("Timings:");
|
gui.label("Timings:");
|
||||||
|
gui.indent(|gui| {
|
||||||
gui.label(format!("Everything: {:.1} ms", stats.everything_ms));
|
gui.label(format!("Everything: {:.1} ms", stats.everything_ms));
|
||||||
gui.label(format!("WebGL: {:.1} ms", stats.webgl_ms));
|
gui.label(format!("WebGL: {:.1} ms", stats.webgl_ms));
|
||||||
});
|
});
|
||||||
|
});
|
||||||
|
|
||||||
self.emgui.style = style;
|
self.emgui.style = style;
|
||||||
let frame = self.emgui.paint();
|
let frame = self.emgui.paint();
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
#![allow(dead_code)]
|
|
||||||
|
|
||||||
use {
|
use {
|
||||||
js_sys::WebAssembly,
|
js_sys::WebAssembly,
|
||||||
wasm_bindgen::{prelude::*, JsCast},
|
wasm_bindgen::{prelude::*, JsCast},
|
||||||
|
@ -23,6 +21,17 @@ pub struct Painter {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Painter {
|
impl Painter {
|
||||||
|
pub fn debug_info(&self) -> String {
|
||||||
|
format!(
|
||||||
|
"Stored canvas size: {} x {}\n\
|
||||||
|
gl context size: {} x {}",
|
||||||
|
self.canvas.width(),
|
||||||
|
self.canvas.height(),
|
||||||
|
self.gl.drawing_buffer_width(),
|
||||||
|
self.gl.drawing_buffer_height(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
canvas_id: &str,
|
canvas_id: &str,
|
||||||
(tex_width, tex_height, pixels): (u16, u16, &[u8]),
|
(tex_width, tex_height, pixels): (u16, u16, &[u8]),
|
||||||
|
@ -274,6 +283,12 @@ impl Painter {
|
||||||
let u_sampler_loc = gl.get_uniform_location(&self.program, "u_sampler").unwrap();
|
let u_sampler_loc = gl.get_uniform_location(&self.program, "u_sampler").unwrap();
|
||||||
gl.uniform1i(Some(&u_sampler_loc), 0);
|
gl.uniform1i(Some(&u_sampler_loc), 0);
|
||||||
|
|
||||||
|
gl.viewport(
|
||||||
|
0,
|
||||||
|
0,
|
||||||
|
self.canvas.width() as i32,
|
||||||
|
self.canvas.height() as i32,
|
||||||
|
);
|
||||||
gl.clear_color(0.05, 0.05, 0.05, 1.0);
|
gl.clear_color(0.05, 0.05, 0.05, 1.0);
|
||||||
gl.clear(Gl::COLOR_BUFFER_BIT);
|
gl.clear(Gl::COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue