Add button to collapse windows
This commit is contained in:
parent
c79b28e3b0
commit
f9bb9f71c4
8 changed files with 276 additions and 152 deletions
|
@ -16,6 +16,7 @@ This is the core library crate Emigui. It is fully platform independent without
|
|||
* [ ] Windows should open from `UI`s and be boxed by parent ui.
|
||||
* Then we could open the example app inside a window in the example app, recursively.
|
||||
* [ ] Resize any side and corner on windows
|
||||
* [ ] Fix autoshrink
|
||||
* [ ] Scroll areas
|
||||
* [x] Vertical scrolling
|
||||
* [ ] Horizontal scrolling
|
||||
|
@ -29,7 +30,7 @@ This is the core library crate Emigui. It is fully platform independent without
|
|||
* [ ] Text input
|
||||
* [x] Input events (key presses)
|
||||
* [x] Text focus
|
||||
* [ ] Cursor movement
|
||||
* [x] Cursor movement
|
||||
* [ ] Text selection
|
||||
* [ ] Clipboard copy/paste
|
||||
* [ ] Move focus with tab
|
||||
|
@ -41,6 +42,7 @@ This is the core library crate Emigui. It is fully platform independent without
|
|||
* [ ] Generalize Layout (separate from Ui)
|
||||
* [ ] Cascading layout: same lite if it fits, else next line. Like text.
|
||||
* [ ] Grid layout
|
||||
* [ ] Point list
|
||||
* [ ] Image support
|
||||
|
||||
### Web version:
|
||||
|
@ -49,10 +51,12 @@ This is the core library crate Emigui. It is fully platform independent without
|
|||
* [ ] Make it a JS library for easily creating your own stuff
|
||||
* [ ] Read url fragment and redirect to a subpage (e.g. different examples apps)
|
||||
|
||||
### Painting
|
||||
* [ ] Pixel-perfect painting (round positions to nearest pixel).
|
||||
### Visuals
|
||||
* [ ] Simplify button style to make for nicer collapsible headers. Maybe weak outline? Or just subtle different text color?
|
||||
* [/] Pixel-perfect painting (round positions to nearest pixel).
|
||||
* [ ] Make sure alpha blending is correct (different between web and glium)
|
||||
* [ ] sRGBA correct colors
|
||||
* [ ] Color picker widgets
|
||||
* [ ] Fix thin rounded corners rendering bug (too bright)
|
||||
|
||||
### Animations
|
||||
Add extremely quick animations for some things, maybe 2-3 frames. For instance:
|
||||
|
@ -94,6 +98,7 @@ Add extremely quick animations for some things, maybe 2-3 frames. For instance:
|
|||
* [x] Combine Emigui and Context?
|
||||
* [x] Solve which parts of Context are behind a mutex
|
||||
* [x] Rename Region to Ui
|
||||
* [ ] Move Path and Mesh to own crate
|
||||
* [ ] Maybe find a shorter name for the library like `egui`?
|
||||
|
||||
### Global widget search
|
||||
|
|
|
@ -22,6 +22,111 @@ impl Default for State {
|
|||
}
|
||||
}
|
||||
|
||||
impl State {
|
||||
pub fn from_memory_with_default_open(ui: &Ui, id: Id, default_open: bool) -> Self {
|
||||
ui.memory()
|
||||
.collapsing_headers
|
||||
.entry(id)
|
||||
.or_insert(State {
|
||||
open: default_open,
|
||||
..Default::default()
|
||||
})
|
||||
.clone()
|
||||
}
|
||||
|
||||
pub fn toggle(&mut self, ui: &Ui) {
|
||||
self.open = !self.open;
|
||||
self.toggle_time = ui.input().time;
|
||||
}
|
||||
|
||||
/// 0 for closed, 1 for open, with tweening
|
||||
pub fn openness(&self, ui: &Ui) -> f32 {
|
||||
let animation_time = ui.style().animation_time;
|
||||
let time_since_toggle = (ui.input().time - self.toggle_time) as f32;
|
||||
let time_since_toggle = time_since_toggle + ui.input().dt; // Instant feedback
|
||||
if self.open {
|
||||
remap_clamp(time_since_toggle, 0.0..=animation_time, 0.0..=1.0)
|
||||
} else {
|
||||
remap_clamp(time_since_toggle, 0.0..=animation_time, 1.0..=0.0)
|
||||
}
|
||||
}
|
||||
|
||||
/// Paint the arrow icon that indicated if the region is open or not
|
||||
pub fn paint_icon(&self, ui: &mut Ui, interact: &InteractInfo) {
|
||||
let stroke_color = ui.style().interact(interact).stroke_color;
|
||||
let stroke_width = ui.style().interact(interact).stroke_width;
|
||||
|
||||
let rect = interact.rect;
|
||||
|
||||
let openness = self.openness(ui);
|
||||
|
||||
// Draw a pointy triangle arrow:
|
||||
let rect = Rect::from_center_size(rect.center(), vec2(rect.width(), rect.height()) * 0.75);
|
||||
let mut points = [rect.left_top(), rect.right_top(), rect.center_bottom()];
|
||||
let rotation = Vec2::angled(remap(openness, 0.0..=1.0, -TAU / 4.0..=0.0));
|
||||
for p in &mut points {
|
||||
let v = *p - rect.center();
|
||||
let v = rotation.rotate_other(v);
|
||||
*p = rect.center() + v;
|
||||
}
|
||||
|
||||
ui.add_paint_cmd(PaintCmd::Path {
|
||||
path: mesher::Path::from_point_loop(&points),
|
||||
closed: true,
|
||||
fill_color: None,
|
||||
outline: Some(Outline::new(stroke_width, stroke_color)),
|
||||
});
|
||||
}
|
||||
|
||||
/// Show contents if we are open, with a nice animation between closed and open
|
||||
pub fn add_contents(
|
||||
&mut self,
|
||||
ui: &mut Ui,
|
||||
add_contents: impl FnOnce(&mut Ui),
|
||||
) -> Option<InteractInfo> {
|
||||
let openness = self.openness(ui);
|
||||
let animate = 0.0 < openness && openness < 1.0;
|
||||
if animate {
|
||||
Some(ui.add_custom(|child_ui| {
|
||||
let max_height = if self.open {
|
||||
if let Some(full_height) = self.open_height {
|
||||
remap_clamp(openness, 0.0..=1.0, 0.0..=full_height)
|
||||
} else {
|
||||
// First frame of expansion.
|
||||
// We don't know full height yet, but we will next frame.
|
||||
// Just use a placehodler value that shows some movement:
|
||||
10.0
|
||||
}
|
||||
} else {
|
||||
let full_height = self.open_height.unwrap_or_default();
|
||||
remap_clamp(openness, 0.0..=1.0, 0.0..=full_height)
|
||||
};
|
||||
|
||||
let mut clip_rect = child_ui.clip_rect();
|
||||
clip_rect.max.y = clip_rect.max.y.min(child_ui.rect().top() + max_height);
|
||||
child_ui.set_clip_rect(clip_rect);
|
||||
|
||||
let top_left = child_ui.top_left();
|
||||
add_contents(child_ui);
|
||||
|
||||
self.open_height = Some(child_ui.bounding_size().y);
|
||||
|
||||
// Pretend children took up less space:
|
||||
let mut child_bounds = child_ui.child_bounds();
|
||||
child_bounds.max.y = child_bounds.max.y.min(top_left.y + max_height);
|
||||
child_ui.force_set_child_bounds(child_bounds);
|
||||
}))
|
||||
} else if self.open {
|
||||
let interact = ui.add_custom(add_contents);
|
||||
let full_size = interact.rect.size();
|
||||
self.open_height = Some(full_size.y);
|
||||
Some(interact)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CollapsingHeader {
|
||||
label: Label,
|
||||
default_open: bool,
|
||||
|
@ -75,32 +180,25 @@ impl CollapsingHeader {
|
|||
);
|
||||
let text_pos = pos2(text_pos.x, interact.rect.center().y - galley.size.y / 2.0);
|
||||
|
||||
let mut state = {
|
||||
let mut memory = ui.memory();
|
||||
let mut state = memory.collapsing_headers.entry(id).or_insert(State {
|
||||
open: default_open,
|
||||
..Default::default()
|
||||
});
|
||||
let mut state = State::from_memory_with_default_open(ui, id, default_open);
|
||||
if interact.clicked {
|
||||
state.open = !state.open;
|
||||
state.toggle_time = ui.input().time;
|
||||
state.toggle(ui);
|
||||
}
|
||||
*state
|
||||
};
|
||||
|
||||
let animation_time = ui.style().animation_time;
|
||||
let time_since_toggle = (ui.input().time - state.toggle_time) as f32;
|
||||
let time_since_toggle = time_since_toggle + ui.input().dt; // Instant feedback
|
||||
let openness = if state.open {
|
||||
remap_clamp(time_since_toggle, 0.0..=animation_time, 0.0..=1.0)
|
||||
} else {
|
||||
remap_clamp(time_since_toggle, 0.0..=animation_time, 1.0..=0.0)
|
||||
};
|
||||
let animate = time_since_toggle < animation_time;
|
||||
|
||||
let where_to_put_background = ui.paint_list_len();
|
||||
|
||||
paint_icon(ui, &interact, openness);
|
||||
{
|
||||
let (mut icon_rect, _) = ui.style().icon_rectangles(interact.rect);
|
||||
icon_rect.set_center(pos2(
|
||||
interact.rect.left() + ui.style().indent / 2.0,
|
||||
interact.rect.center().y,
|
||||
));
|
||||
let icon_interact = InteractInfo {
|
||||
rect: icon_rect,
|
||||
..interact
|
||||
};
|
||||
state.paint_icon(ui, &icon_interact);
|
||||
}
|
||||
|
||||
ui.add_galley(
|
||||
text_pos,
|
||||
|
@ -121,74 +219,11 @@ impl CollapsingHeader {
|
|||
|
||||
ui.expand_to_include_child(interact.rect); // TODO: remove, just a test
|
||||
|
||||
if animate {
|
||||
ui.indent(id, |child_ui| {
|
||||
let max_height = if state.open {
|
||||
if let Some(full_height) = state.open_height {
|
||||
remap(time_since_toggle, 0.0..=animation_time, 0.0..=full_height)
|
||||
} else {
|
||||
// First frame of expansion.
|
||||
// We don't know full height yet, but we will next frame.
|
||||
// Just use a placehodler value that shows some movement:
|
||||
10.0
|
||||
}
|
||||
} else {
|
||||
let full_height = state.open_height.unwrap_or_default();
|
||||
remap_clamp(time_since_toggle, 0.0..=animation_time, full_height..=0.0)
|
||||
};
|
||||
|
||||
let mut clip_rect = child_ui.clip_rect();
|
||||
clip_rect.max.y = clip_rect.max.y.min(child_ui.rect().top() + max_height);
|
||||
child_ui.set_clip_rect(clip_rect);
|
||||
|
||||
let top_left = child_ui.top_left();
|
||||
add_contents(child_ui);
|
||||
|
||||
state.open_height = Some(child_ui.bounding_size().y);
|
||||
|
||||
// Pretend children took up less space:
|
||||
let mut child_bounds = child_ui.child_bounds();
|
||||
child_bounds.max.y = child_bounds.max.y.min(top_left.y + max_height);
|
||||
child_ui.force_set_child_bounds(child_bounds);
|
||||
state.add_contents(ui, |ui| {
|
||||
ui.indent(id, add_contents);
|
||||
});
|
||||
} else if state.open {
|
||||
let full_size = ui.indent(id, add_contents).rect.size();
|
||||
state.open_height = Some(full_size.y);
|
||||
}
|
||||
|
||||
ui.memory().collapsing_headers.insert(id, state);
|
||||
ui.response(interact)
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_icon(ui: &mut Ui, interact: &InteractInfo, openness: f32) {
|
||||
let stroke_color = ui.style().interact(interact).stroke_color;
|
||||
let stroke_width = ui.style().interact(interact).stroke_width;
|
||||
|
||||
let (mut small_icon_rect, _) = ui.style().icon_rectangles(interact.rect);
|
||||
small_icon_rect.set_center(pos2(
|
||||
interact.rect.left() + ui.style().indent / 2.0,
|
||||
interact.rect.center().y,
|
||||
));
|
||||
|
||||
// Draw a pointy triangle arrow:
|
||||
let rect = Rect::from_center_size(
|
||||
small_icon_rect.center(),
|
||||
vec2(small_icon_rect.width(), small_icon_rect.height()) * 0.75,
|
||||
);
|
||||
let mut points = [rect.left_top(), rect.right_top(), rect.center_bottom()];
|
||||
let rotation = Vec2::angled(remap(openness, 0.0..=1.0, -TAU / 4.0..=0.0));
|
||||
for p in &mut points {
|
||||
let v = *p - rect.center();
|
||||
let v = rotation.rotate_other(v);
|
||||
*p = rect.center() + v;
|
||||
}
|
||||
// }
|
||||
|
||||
ui.add_paint_cmd(PaintCmd::Path {
|
||||
path: mesher::Path::from_point_loop(&points),
|
||||
closed: true,
|
||||
fill_color: None,
|
||||
outline: Some(Outline::new(stroke_width, stroke_color)),
|
||||
});
|
||||
}
|
||||
|
|
|
@ -122,7 +122,11 @@ impl<'open> Window<'open> {
|
|||
}
|
||||
|
||||
impl<'open> Window<'open> {
|
||||
pub fn show(self, ctx: &Arc<Context>, add_contents: impl FnOnce(&mut Ui)) -> InteractInfo {
|
||||
pub fn show(
|
||||
self,
|
||||
ctx: &Arc<Context>,
|
||||
add_contents: impl FnOnce(&mut Ui),
|
||||
) -> Option<InteractInfo> {
|
||||
let Window {
|
||||
title_label,
|
||||
open,
|
||||
|
@ -133,31 +137,35 @@ impl<'open> Window<'open> {
|
|||
} = self;
|
||||
|
||||
if matches!(open, Some(false)) {
|
||||
return Default::default();
|
||||
return None;
|
||||
}
|
||||
|
||||
let frame = frame.unwrap_or_else(|| Frame::window(&ctx.style()));
|
||||
|
||||
if true {
|
||||
// TODO: easier way to compose these
|
||||
area.show(ctx, |ui| {
|
||||
Some(area.show(ctx, |ui| {
|
||||
frame.show(ui, |ui| {
|
||||
let collapsing_id = ui.make_child_id("collapsing");
|
||||
let default_expanded = true;
|
||||
let mut collapsing = collapsing_header::State::from_memory_with_default_open(
|
||||
ui,
|
||||
collapsing_id,
|
||||
default_expanded,
|
||||
);
|
||||
let show_close_button = open.is_some();
|
||||
let title_bar = show_title_bar(
|
||||
ui,
|
||||
title_label,
|
||||
show_close_button,
|
||||
collapsing_id,
|
||||
&mut collapsing,
|
||||
);
|
||||
ui.memory()
|
||||
.collapsing_headers
|
||||
.insert(collapsing_id, collapsing);
|
||||
|
||||
let content = collapsing.add_contents(ui, |ui| {
|
||||
resize.show(ui, |ui| {
|
||||
show_title_bar(ui, title_label, open);
|
||||
if let Some(scroll) = scroll {
|
||||
scroll.show(ui, add_contents)
|
||||
} else {
|
||||
add_contents(ui)
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
} else {
|
||||
// TODO: something like this, with collapsing contents
|
||||
area.show(ctx, |ui| {
|
||||
frame.show(ui, |ui| {
|
||||
CollapsingHeader::new(title_label.text()).show(ui, |ui| {
|
||||
resize.show(ui, |ui| {
|
||||
ui.add(Separator::new().line_width(1.0)); // TODO: nicer way to split window title from contents
|
||||
if let Some(scroll) = scroll {
|
||||
scroll.show(ui, add_contents)
|
||||
} else {
|
||||
|
@ -165,21 +173,63 @@ impl<'open> Window<'open> {
|
|||
}
|
||||
})
|
||||
});
|
||||
})
|
||||
})
|
||||
|
||||
if let Some(open) = open {
|
||||
// Add close button now that we know our full width:
|
||||
|
||||
let right = content
|
||||
.map(|c| c.rect.right())
|
||||
.unwrap_or(title_bar.rect.right());
|
||||
|
||||
let button_size = ui.style().start_icon_width;
|
||||
let button_rect = Rect::from_min_size(
|
||||
pos2(
|
||||
right - ui.style().item_spacing.x - button_size,
|
||||
title_bar.rect.center().y - 0.5 * button_size,
|
||||
),
|
||||
Vec2::splat(button_size),
|
||||
);
|
||||
|
||||
if close_button(ui, button_rect).clicked {
|
||||
*open = false;
|
||||
}
|
||||
}
|
||||
})
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
fn show_title_bar(ui: &mut Ui, title_label: Label, open: Option<&mut bool>) {
|
||||
let button_size = ui.style().clickable_diameter;
|
||||
fn show_title_bar(
|
||||
ui: &mut Ui,
|
||||
title_label: Label,
|
||||
show_close_button: bool,
|
||||
collapsing_id: Id,
|
||||
collapsing: &mut collapsing_header::State,
|
||||
) -> InteractInfo {
|
||||
ui.inner_layout(Layout::horizontal(Align::Center), |ui| {
|
||||
ui.set_desired_height(title_label.font_height(ui));
|
||||
|
||||
// TODO: show collapse button
|
||||
let item_spacing = ui.style().item_spacing;
|
||||
let button_size = ui.style().start_icon_width;
|
||||
|
||||
{
|
||||
// TODO: make clickable radius larger
|
||||
ui.reserve_space(vec2(0.0, 0.0), None); // HACK: will add left spacing
|
||||
|
||||
let collapse_button_interact =
|
||||
ui.reserve_space(Vec2::splat(button_size), Some(collapsing_id));
|
||||
if collapse_button_interact.clicked {
|
||||
// TODO: also do this when double-clicking window title
|
||||
collapsing.toggle(ui);
|
||||
}
|
||||
collapsing.paint_icon(ui, &collapse_button_interact);
|
||||
}
|
||||
|
||||
let title_rect = ui.add(title_label).rect;
|
||||
|
||||
if let Some(open) = open {
|
||||
let close_max_x = title_rect.right() + ui.style().item_spacing.x + button_size;
|
||||
if show_close_button {
|
||||
// Reserve space for close button which will be added later:
|
||||
let close_max_x = title_rect.right() + item_spacing.x + button_size + item_spacing.x;
|
||||
let close_max_x = close_max_x.max(ui.rect_finite().right());
|
||||
let close_rect = Rect::from_min_size(
|
||||
pos2(
|
||||
|
@ -188,12 +238,9 @@ fn show_title_bar(ui: &mut Ui, title_label: Label, open: Option<&mut bool>) {
|
|||
),
|
||||
Vec2::splat(button_size),
|
||||
);
|
||||
if close_button(ui, close_rect).clicked {
|
||||
*open = false;
|
||||
ui.expand_to_include_child(close_rect);
|
||||
}
|
||||
}
|
||||
|
||||
ui.add(Separator::new().line_width(1.0)); // TODO: nicer way to split window title from contents
|
||||
})
|
||||
}
|
||||
|
||||
fn close_button(ui: &mut Ui, rect: Rect) -> InteractInfo {
|
||||
|
@ -201,15 +248,6 @@ fn close_button(ui: &mut Ui, rect: Rect) -> InteractInfo {
|
|||
let interact = ui.interact_rect(rect, close_id);
|
||||
ui.expand_to_include_child(interact.rect);
|
||||
|
||||
// ui.add_paint_cmd(PaintCmd::Rect {
|
||||
// corner_radius: ui.style().interact(&interact).corner_radius,
|
||||
// fill_color: ui.style().interact(&interact).bg_fill_color,
|
||||
// outline: ui.style().interact(&interact).rect_outline,
|
||||
// rect: interact.rect,
|
||||
// });
|
||||
|
||||
let rect = rect.expand(-4.0);
|
||||
|
||||
let stroke_color = ui.style().interact(&interact).stroke_color;
|
||||
let stroke_width = ui.style().interact(&interact).stroke_width;
|
||||
ui.add_paint_cmd(PaintCmd::line_segment(
|
||||
|
|
|
@ -297,7 +297,8 @@ impl Context {
|
|||
rect: Rect,
|
||||
interaction_id: Option<Id>,
|
||||
) -> InteractInfo {
|
||||
let hovered = self.contains_mouse(layer, clip_rect, rect);
|
||||
let interact_rect = rect.expand2(0.5 * self.style().item_spacing); // make it easier to click. TODO: nice way to do this
|
||||
let hovered = self.contains_mouse(layer, clip_rect, interact_rect);
|
||||
|
||||
let mut memory = self.memory();
|
||||
let active = interaction_id.is_some() && memory.active_id == interaction_id;
|
||||
|
|
|
@ -42,7 +42,7 @@ impl Default for CursorIcon {
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, Serialize)]
|
||||
#[derive(Clone, Copy, Debug, Serialize)]
|
||||
pub struct InteractInfo {
|
||||
/// The mouse is hovering above this thing
|
||||
pub hovered: bool,
|
||||
|
@ -58,6 +58,15 @@ pub struct InteractInfo {
|
|||
}
|
||||
|
||||
impl InteractInfo {
|
||||
pub fn nothing() -> Self {
|
||||
Self {
|
||||
hovered: false,
|
||||
clicked: false,
|
||||
active: false,
|
||||
rect: Rect::nothing(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn union(self, other: Self) -> Self {
|
||||
Self {
|
||||
hovered: self.hovered || other.hovered,
|
||||
|
|
|
@ -339,7 +339,16 @@ impl Ui {
|
|||
/// for `Justified` aligned layouts, like in menus.
|
||||
///
|
||||
/// You may get LESS space than you asked for if the current layout won't fit what you asked for.
|
||||
///
|
||||
/// TODO: remove, or redesign or something and start using allocate_space
|
||||
pub fn reserve_space(&mut self, child_size: Vec2, interaction_id: Option<Id>) -> InteractInfo {
|
||||
let rect = self.allocate_space(child_size);
|
||||
|
||||
self.ctx
|
||||
.interact(self.layer, self.clip_rect, rect, interaction_id)
|
||||
}
|
||||
|
||||
pub fn allocate_space(&mut self, child_size: Vec2) -> Rect {
|
||||
let child_size = self.round_vec_to_pixels(child_size);
|
||||
self.cursor = self.round_pos_to_pixels(self.cursor);
|
||||
|
||||
|
@ -376,8 +385,7 @@ impl Ui {
|
|||
}
|
||||
}
|
||||
|
||||
self.ctx
|
||||
.interact(self.layer, self.clip_rect, rect, interaction_id)
|
||||
rect
|
||||
}
|
||||
|
||||
/// Reserve this much space and move the cursor.
|
||||
|
@ -517,12 +525,25 @@ impl Ui {
|
|||
/// Just because you ask for a lot of space does not mean you have to use it!
|
||||
/// After `add_contents` is called the contents of `bounding_size`
|
||||
/// will decide how much space will be used in the parent ui.
|
||||
pub fn add_custom_contents(&mut self, size: Vec2, add_contents: impl FnOnce(&mut Ui)) {
|
||||
pub fn add_custom_contents(
|
||||
&mut self,
|
||||
size: Vec2,
|
||||
add_contents: impl FnOnce(&mut Ui),
|
||||
) -> InteractInfo {
|
||||
let size = size.min(self.available().size());
|
||||
let child_rect = Rect::from_min_size(self.cursor, size);
|
||||
let mut child_ui = self.child_ui(child_rect);
|
||||
add_contents(&mut child_ui);
|
||||
self.reserve_space(child_ui.bounding_size(), None);
|
||||
self.reserve_space(child_ui.bounding_size(), None)
|
||||
}
|
||||
|
||||
/// Create a child ui
|
||||
pub fn add_custom(&mut self, add_contents: impl FnOnce(&mut Ui)) -> InteractInfo {
|
||||
let child_rect = self.available();
|
||||
let mut child_ui = self.child_ui(child_rect);
|
||||
add_contents(&mut child_ui);
|
||||
let size = child_ui.bounding_size();
|
||||
self.reserve_space(size, None)
|
||||
}
|
||||
|
||||
/// Create a child ui which is indented to the right
|
||||
|
|
|
@ -72,6 +72,10 @@ impl Label {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn font_height(&self, ui: &Ui) -> f32 {
|
||||
ui.fonts()[self.text_style].height()
|
||||
}
|
||||
|
||||
// TODO: this should return a LabelLayout which has a paint method.
|
||||
// We can then split Widget::Ui in two: layout + allocating space, and painting.
|
||||
// this allows us to assemble lables, THEN detect interaction, THEN chose color style based on that.
|
||||
|
|
|
@ -62,8 +62,10 @@ fn main() {
|
|||
|
||||
let pixels_per_point = display.gl_window().get_hidpi_factor() as f32;
|
||||
|
||||
let mut ctx = Context::new(pixels_per_point);
|
||||
let mut painter = emigui_glium::Painter::new(&display);
|
||||
let mut ctx = profile("initializing emilib", || Context::new(pixels_per_point));
|
||||
let mut painter = profile("initializing painter", || {
|
||||
emigui_glium::Painter::new(&display)
|
||||
});
|
||||
|
||||
let mut raw_input = emigui::RawInput {
|
||||
screen_size: {
|
||||
|
@ -143,6 +145,7 @@ fn main() {
|
|||
emigui_glium::handle_output(output, &display, clipboard.as_mut());
|
||||
}
|
||||
|
||||
// Save state to disk:
|
||||
window_settings.pos = display
|
||||
.gl_window()
|
||||
.get_position()
|
||||
|
@ -162,3 +165,11 @@ fn main() {
|
|||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
fn profile<R>(name: &str, action: impl FnOnce() -> R) -> R {
|
||||
let start = Instant::now();
|
||||
let r = action();
|
||||
let elapsed = start.elapsed();
|
||||
eprintln!("{}: {} ms", name, elapsed.as_millis());
|
||||
r
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue