Enable colored text (and other misc fixes)

This commit is contained in:
Emil Ernerfeldt 2019-01-16 09:28:43 -06:00
parent 4dab7a1504
commit 7f83876005
9 changed files with 104 additions and 82 deletions

View file

@ -6,7 +6,7 @@ use crate::{
style,
types::GuiInput,
widgets::*,
Frame, Painter, RawInput,
Frame, RawInput,
};
#[derive(Clone, Copy, Default)]
@ -42,19 +42,15 @@ pub struct Emigui {
pub last_input: RawInput,
pub data: Arc<layout::Data>,
pub style: style::Style,
pub painter: Painter,
stats: Stats,
}
impl Emigui {
pub fn new() -> Emigui {
let data = Arc::new(layout::Data::new());
let fonts = data.fonts.clone();
Emigui {
last_input: Default::default(),
data,
data: Arc::new(layout::Data::new()),
style: Default::default(),
painter: Painter::new(fonts),
stats: Default::default(),
}
}
@ -90,7 +86,7 @@ impl Emigui {
pub fn paint(&mut self) -> Frame {
let gui_commands = self.data.graphics.lock().unwrap().drain();
let paint_commands = style::into_paint_commands(gui_commands, &self.style);
let frame = self.painter.paint(&paint_commands);
let frame = Frame::paint(&self.data.fonts, &paint_commands);
self.stats.num_vertices = frame.vertices.len();
self.stats.num_triangles = frame.indices.len() / 3;
frame

View file

@ -51,7 +51,7 @@ impl Default for LayoutOptions {
// ----------------------------------------------------------------------------
// TODO: rename
// TODO: rename GuiResponse
pub struct GuiResponse {
/// The mouse is hovering above this
pub hovered: bool,
@ -181,7 +181,7 @@ impl Clone for Data {
Data {
options: Mutex::new(self.options()),
fonts: self.fonts.clone(),
input: self.input.clone(),
input: self.input,
memory: Mutex::new(self.memory.lock().unwrap().clone()),
graphics: Mutex::new(self.graphics.lock().unwrap().clone()),
}
@ -358,6 +358,7 @@ impl Region {
text_cursor + vec2(self.options().start_icon_width, 0.0),
text_style,
text,
None,
);
if open {
@ -475,13 +476,15 @@ impl Region {
pub fn reserve_space(&mut self, size: Vec2, interaction_id: Option<Id>) -> InteractInfo {
let pos = self.reserve_space_without_padding(size + self.options().item_spacing);
let rect = Rect::from_min_size(pos, size);
let mut memory = self.data.memory.lock().unwrap();
let hovered = rect.contains(self.input().mouse_pos);
let is_something_else_active =
memory.active_id.is_some() && memory.active_id != interaction_id;
let hovered = !is_something_else_active && rect.contains(self.input().mouse_pos);
let clicked = hovered && self.input().mouse_clicked;
let active = if interaction_id.is_some() {
let mut memory = self.data.memory.lock().unwrap();
if clicked {
memory.active_id = interaction_id;
}
@ -543,12 +546,19 @@ impl Region {
})
}
pub fn add_text(&mut self, pos: Vec2, text_style: TextStyle, text: Vec<TextFragment>) {
pub fn add_text(
&mut self,
pos: Vec2,
text_style: TextStyle,
text: Vec<TextFragment>,
color: Option<Color>,
) {
for fragment in text {
self.add_graphic(GuiCmd::Text {
color,
pos: pos + vec2(0.0, fragment.y_offset),
text_style,
text: fragment.text,
text_style,
x_offsets: fragment.x_offsets,
});
}

View file

@ -11,7 +11,7 @@ mod font;
mod fonts;
mod layout;
pub mod math;
mod painter;
mod mesher;
mod style;
mod texture_atlas;
pub mod types;
@ -21,7 +21,7 @@ pub use crate::{
emigui::Emigui,
fonts::TextStyle,
layout::{Align, LayoutOptions, Region},
painter::{Frame, Painter, Vertex},
mesher::{Frame, Vertex},
style::Style,
types::RawInput,
};

View file

@ -1,5 +1,3 @@
use std::sync::Arc;
const ANTI_ALIAS: bool = true;
const AA_SIZE: f32 = 1.0;
@ -22,7 +20,6 @@ pub struct Vertex {
#[derive(Clone, Debug, Default)]
pub struct Frame {
pub clear_color: Option<Color>,
/// Draw as triangles (i.e. the length is a multiple of three)
pub indices: Vec<u32>,
pub vertices: Vec<Vertex>,
@ -189,19 +186,8 @@ impl Frame {
}
}
}
}
#[derive(Clone)]
pub struct Painter {
fonts: Arc<Fonts>,
}
impl Painter {
pub fn new(fonts: Arc<Fonts>) -> Painter {
Painter { fonts }
}
pub fn paint(&self, commands: &[PaintCmd]) -> Frame {
pub fn paint(fonts: &Fonts, commands: &[PaintCmd]) -> Frame {
let mut path_points = Vec::new();
let mut path_normals = Vec::new();
@ -238,9 +224,6 @@ impl Painter {
);
}
}
PaintCmd::Clear { fill_color } => {
frame.clear_color = Some(*fill_color);
}
PaintCmd::Line {
points,
color,
@ -338,7 +321,7 @@ impl Painter {
text_style,
x_offsets,
} => {
let font = &self.fonts[*text_style];
let font = &fonts[*text_style];
for (c, x_offset) in text.chars().zip(x_offsets.iter()) {
if let Some(glyph) = font.uv_rect(c) {
let mut top_left = Vertex {

View file

@ -129,8 +129,6 @@ fn translate_cmd(out_commands: &mut Vec<PaintCmd>, style: &Style, cmd: GuiCmd) {
rect: interact.rect,
});
// TODO: paint a little triangle or arrow or something instead of this
let (small_icon_rect, _) = style.icon_rectangles(&interact.rect);
// Draw a minus:
out_commands.push(PaintCmd::Line {
@ -215,12 +213,13 @@ fn translate_cmd(out_commands: &mut Vec<PaintCmd>, style: &Style, cmd: GuiCmd) {
}
}
GuiCmd::Text {
color,
pos,
text_style,
text,
text_style,
x_offsets,
} => {
let color = style.text_color();
let color = color.unwrap_or_else(|| style.text_color());
out_commands.push(PaintCmd::Text {
color,
text_style,
@ -237,7 +236,7 @@ fn translate_cmd(out_commands: &mut Vec<PaintCmd>, style: &Style, cmd: GuiCmd) {
color: srgba(255, 255, 255, 255), // TODO
width: 1.0,
}),
rect: rect,
rect,
});
}
}

View file

@ -13,8 +13,8 @@ pub struct TextureAtlas {
impl TextureAtlas {
pub fn new(width: usize, height: usize) -> Self {
TextureAtlas {
width: width,
height: height,
width,
height,
pixels: vec![0; width * height],
..Default::default()
}

View file

@ -120,13 +120,12 @@ pub enum GuiCmd {
min: f32,
value: f32,
},
/// Paint a single line of mono-space text.
/// The text should start at the given position and flow to the right.
/// The text should be vertically centered at the given position.
/// A string of text with a position for each character.
Text {
color: Option<Color>,
pos: Vec2,
text_style: TextStyle,
text: String,
text_style: TextStyle,
/// Start each character in the text, as offset from pos.
x_offsets: Vec<f32>,
},
@ -153,9 +152,6 @@ pub enum PaintCmd {
outline: Option<Outline>,
radius: f32,
},
Clear {
fill_color: Color,
},
Line {
points: Vec<Vec2>,
color: Color,

View file

@ -17,6 +17,7 @@ pub trait Widget {
pub struct Label {
text: String,
text_style: TextStyle,
text_color: Option<Color>,
}
impl Label {
@ -24,6 +25,7 @@ impl Label {
Label {
text: text.into(),
text_style: TextStyle::Body,
text_color: None,
}
}
@ -31,6 +33,11 @@ impl Label {
self.text_style = text_style;
self
}
pub fn text_color(mut self, text_color: Color) -> Self {
self.text_color = Some(text_color);
self
}
}
pub fn label<S: Into<String>>(text: S) -> Label {
@ -42,7 +49,7 @@ impl Widget for Label {
let font = &region.fonts()[self.text_style];
let (text, text_size) = font.layout_multiline(&self.text, region.width());
let interact = region.reserve_space(text_size, None);
region.add_text(interact.rect.min(), self.text_style, text);
region.add_text(interact.rect.min(), self.text_style, text, self.text_color);
region.response(interact)
}
}
@ -51,11 +58,20 @@ impl Widget for Label {
pub struct Button {
text: String,
text_color: Option<Color>,
}
impl Button {
pub fn new<S: Into<String>>(text: S) -> Self {
Button { text: text.into() }
Button {
text: text.into(),
text_color: None,
}
}
pub fn text_color(mut self, text_color: Color) -> Self {
self.text_color = Some(text_color);
self
}
}
@ -69,7 +85,7 @@ impl Widget for Button {
region.reserve_space(text_size + 2.0 * region.options().button_padding, Some(id));
let text_cursor = interact.rect.min() + region.options().button_padding;
region.add_graphic(GuiCmd::Button { interact });
region.add_text(text_cursor, text_style, text);
region.add_text(text_cursor, text_style, text, self.text_color);
region.response(interact)
}
}
@ -80,6 +96,7 @@ impl Widget for Button {
pub struct Checkbox<'a> {
checked: &'a mut bool,
text: String,
text_color: Option<Color>,
}
impl<'a> Checkbox<'a> {
@ -87,8 +104,14 @@ impl<'a> Checkbox<'a> {
Checkbox {
checked,
text: text.into(),
text_color: None,
}
}
pub fn text_color(mut self, text_color: Color) -> Self {
self.text_color = Some(text_color);
self
}
}
impl<'a> Widget for Checkbox<'a> {
@ -114,7 +137,7 @@ impl<'a> Widget for Checkbox<'a> {
checked: *self.checked,
interact,
});
region.add_text(text_cursor, text_style, text);
region.add_text(text_cursor, text_style, text, self.text_color);
region.response(interact)
}
}
@ -125,6 +148,7 @@ impl<'a> Widget for Checkbox<'a> {
pub struct RadioButton {
checked: bool,
text: String,
text_color: Option<Color>,
}
impl RadioButton {
@ -132,8 +156,14 @@ impl RadioButton {
RadioButton {
checked,
text: text.into(),
text_color: None,
}
}
pub fn text_color(mut self, text_color: Color) -> Self {
self.text_color = Some(text_color);
self
}
}
pub fn radio<S: Into<String>>(checked: bool, text: S) -> RadioButton {
@ -160,7 +190,7 @@ impl Widget for RadioButton {
checked: self.checked,
interact,
});
region.add_text(text_cursor, text_style, text);
region.add_text(text_cursor, text_style, text, self.text_color);
region.response(interact)
}
}
@ -174,6 +204,7 @@ pub struct Slider<'a> {
max: f32,
id: Option<Id>,
text: Option<String>,
text_color: Option<Color>,
text_on_top: Option<bool>,
}
@ -186,6 +217,7 @@ impl<'a> Slider<'a> {
id: None,
text: None,
text_on_top: None,
text_color: None,
}
}
@ -198,6 +230,11 @@ impl<'a> Slider<'a> {
self.text = Some(text.into());
self
}
pub fn text_color(mut self, text_color: Color) -> Self {
self.text_color = Some(text_color);
self
}
}
impl<'a> Widget for Slider<'a> {
@ -207,8 +244,9 @@ impl<'a> Widget for Slider<'a> {
if let Some(text) = &self.text {
let text_on_top = self.text_on_top.unwrap_or_default();
let text_color = self.text_color;
let full_text = format!("{}: {:.3}", text, self.value);
let id = Some(self.id.unwrap_or(make_id(text)));
let id = Some(self.id.unwrap_or_else(|| make_id(text)));
let mut naked = self;
naked.id = id;
naked.text = None;
@ -216,7 +254,7 @@ impl<'a> Widget for Slider<'a> {
if text_on_top {
let (text, text_size) = font.layout_multiline(&full_text, region.width());
let pos = region.reserve_space_without_padding(text_size);
region.add_text(pos, text_style, text);
region.add_text(pos, text_style, text, text_color);
naked.add_to(region)
} else {
region.columns(2, |columns| {

View file

@ -3,7 +3,7 @@ use emigui::{math::*, types::*, widgets::*, Align, Region, TextStyle};
pub struct App {
checked: bool,
count: i32,
selected_alternative: i32,
radio: i32,
size: Vec2,
corner_radius: f32,
@ -14,7 +14,7 @@ impl Default for App {
fn default() -> App {
App {
checked: true,
selected_alternative: 0,
radio: 0,
count: 0,
size: vec2(100.0, 50.0),
corner_radius: 5.0,
@ -35,6 +35,11 @@ impl App {
gui.input().screen_size.y,
)));
gui.horizontal(Align::Min, |gui| {
gui.add(label("Text can have").text_color(srgba(110, 255, 110, 255)));
gui.add(label("color").text_color(srgba(128, 140, 255, 255)));
});
gui.add(label("Hover me")).tooltip_text(
"This is a multiline tooltip that demonstrates that you can easily add tooltips to any element.\nThis is the second line.\nThis is the third.",
);
@ -42,26 +47,18 @@ impl App {
gui.add(Checkbox::new(&mut self.checked, "checkbox"));
gui.horizontal(Align::Min, |gui| {
if gui
.add(radio(self.selected_alternative == 0, "First"))
.clicked
{
self.selected_alternative = 0;
if gui.add(radio(self.radio == 0, "First")).clicked {
self.radio = 0;
}
if gui
.add(radio(self.selected_alternative == 1, "Second"))
.clicked
{
self.selected_alternative = 1;
if gui.add(radio(self.radio == 1, "Second")).clicked {
self.radio = 1;
}
if gui
.add(radio(self.selected_alternative == 2, "Final"))
.clicked
{
self.selected_alternative = 2;
if gui.add(radio(self.radio == 2, "Final")).clicked {
self.radio = 2;
}
});
gui.horizontal(Align::Min, |gui| {
if gui
.add(Button::new("Click me"))
.tooltip_text("This will just increase a counter.")
@ -69,8 +66,11 @@ impl App {
{
self.count += 1;
}
gui.add(label(format!("This is a multiline label.\nThe button have been clicked {} times.\nBelow are more options.", self.count)));
gui.add(label(format!(
"The button have been clicked {} times",
self.count
)));
});
gui.foldable("Test box rendering", |gui| {
gui.add(Slider::new(&mut self.size.x, 0.0, 500.0).text("width"));