Rename Region to Ui (shorter, sweeter)
This commit is contained in:
parent
cbd51c3f43
commit
fa82e8d806
22 changed files with 508 additions and 524 deletions
|
@ -88,10 +88,7 @@ Add extremely quick animations for some things, maybe 2-3 frames. For instance:
|
|||
* [ ] Solve which parts of Context are behind a mutex
|
||||
* [ ] All of Context behind one mutex?
|
||||
* [ } Break up Context into Input, State, Output ?
|
||||
* [ ] Rename Region to something shorter?
|
||||
* `region: &Region` `region.add(...)` :/
|
||||
* `gui: &Gui` `gui.add(...)` :)
|
||||
* `ui: &Ui` `ui.add(...)` :)
|
||||
* [x] Rename Region to Ui
|
||||
* [ ] Maybe find a shorter name for the library like `egui`?
|
||||
|
||||
### Global widget search
|
||||
|
|
|
@ -12,10 +12,10 @@ pub use {
|
|||
|
||||
// TODO
|
||||
// pub trait Container {
|
||||
// fn show(self, region: &mut Region, add_contents: impl FnOnce(&mut Region));
|
||||
// fn show(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui));
|
||||
// }
|
||||
|
||||
// pub trait Container {
|
||||
// fn begin(&mut self, parent: &mut Region) -> Region;
|
||||
// fn end(self, parent: &mut Region, content: Region);
|
||||
// fn begin(&mut self, parent: &mut Ui) -> Ui;
|
||||
// fn end(self, parent: &mut Ui, content: Ui);
|
||||
// }
|
||||
|
|
|
@ -8,7 +8,7 @@ pub(crate) struct State {
|
|||
#[serde(skip)] // Times are relative, and we don't want to continue animations anyway
|
||||
toggle_time: f64,
|
||||
|
||||
/// Height open the region when open. Used for animations
|
||||
/// Height of the region when open. Used for animations
|
||||
open_height: Option<f32>,
|
||||
}
|
||||
|
||||
|
@ -44,9 +44,9 @@ impl CollapsingHeader {
|
|||
}
|
||||
|
||||
impl CollapsingHeader {
|
||||
pub fn show(self, region: &mut Region, add_contents: impl FnOnce(&mut Region)) -> GuiResponse {
|
||||
pub fn show(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui)) -> GuiResponse {
|
||||
assert!(
|
||||
region.direction() == Direction::Vertical,
|
||||
ui.direction() == Direction::Vertical,
|
||||
"Horizontal collapsing is unimplemented"
|
||||
);
|
||||
let Self {
|
||||
|
@ -57,63 +57,63 @@ impl CollapsingHeader {
|
|||
// TODO: horizontal layout, with icon and text as labels. Inser background behind using Frame.
|
||||
|
||||
let title = &label.text; // TODO: not this
|
||||
let id = region.make_unique_id(title);
|
||||
let text_pos = region.cursor() + vec2(region.style().indent, 0.0);
|
||||
let (title, text_size) = label.layout(text_pos, region);
|
||||
let id = ui.make_unique_id(title);
|
||||
let text_pos = ui.cursor() + vec2(ui.style().indent, 0.0);
|
||||
let (title, text_size) = label.layout(text_pos, ui);
|
||||
let text_max_x = text_pos.x + text_size.x;
|
||||
let desired_width = region.available_width().max(text_max_x - region.cursor().x);
|
||||
let desired_width = ui.available_width().max(text_max_x - ui.cursor().x);
|
||||
|
||||
let interact = region.reserve_space(
|
||||
let interact = ui.reserve_space(
|
||||
vec2(
|
||||
desired_width,
|
||||
text_size.y + 2.0 * region.style().button_padding.y,
|
||||
text_size.y + 2.0 * ui.style().button_padding.y,
|
||||
),
|
||||
Some(id),
|
||||
);
|
||||
let text_pos = pos2(text_pos.x, interact.rect.center().y - text_size.y / 2.0);
|
||||
|
||||
let mut state = {
|
||||
let mut memory = region.memory();
|
||||
let mut memory = ui.memory();
|
||||
let mut state = memory.collapsing_headers.entry(id).or_insert(State {
|
||||
open: default_open,
|
||||
..Default::default()
|
||||
});
|
||||
if interact.clicked {
|
||||
state.open = !state.open;
|
||||
state.toggle_time = region.input().time;
|
||||
state.toggle_time = ui.input().time;
|
||||
}
|
||||
*state
|
||||
};
|
||||
|
||||
let where_to_put_background = region.paint_list_len();
|
||||
let where_to_put_background = ui.paint_list_len();
|
||||
|
||||
paint_icon(region, &state, &interact);
|
||||
paint_icon(ui, &state, &interact);
|
||||
|
||||
region.add_text(
|
||||
ui.add_text(
|
||||
text_pos,
|
||||
label.text_style,
|
||||
title,
|
||||
Some(region.style().interact_stroke_color(&interact)),
|
||||
Some(ui.style().interact_stroke_color(&interact)),
|
||||
);
|
||||
|
||||
region.insert_paint_cmd(
|
||||
ui.insert_paint_cmd(
|
||||
where_to_put_background,
|
||||
PaintCmd::Rect {
|
||||
corner_radius: region.style().interact_corner_radius(&interact),
|
||||
fill_color: region.style().interact_fill_color(&interact),
|
||||
outline: region.style().interact_outline(&interact),
|
||||
corner_radius: ui.style().interact_corner_radius(&interact),
|
||||
fill_color: ui.style().interact_fill_color(&interact),
|
||||
outline: ui.style().interact_outline(&interact),
|
||||
rect: interact.rect,
|
||||
},
|
||||
);
|
||||
|
||||
region.expand_to_include_child(interact.rect); // TODO: remove, just a test
|
||||
ui.expand_to_include_child(interact.rect); // TODO: remove, just a test
|
||||
|
||||
let animation_time = region.style().animation_time;
|
||||
let time_since_toggle = (region.input().time - state.toggle_time) as f32;
|
||||
let time_since_toggle = time_since_toggle + region.input().dt; // Instant feedback
|
||||
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 animate = time_since_toggle < animation_time;
|
||||
if animate {
|
||||
region.indent(id, |child_region| {
|
||||
ui.indent(id, |child_ui| {
|
||||
let max_height = if state.open {
|
||||
let full_height = state.open_height.unwrap_or(1000.0);
|
||||
remap(time_since_toggle, 0.0..=animation_time, 0.0..=full_height)
|
||||
|
@ -122,42 +122,42 @@ impl CollapsingHeader {
|
|||
remap_clamp(time_since_toggle, 0.0..=animation_time, full_height..=0.0)
|
||||
};
|
||||
|
||||
let mut clip_rect = child_region.clip_rect();
|
||||
clip_rect.max.y = clip_rect.max.y.min(child_region.cursor().y + max_height);
|
||||
child_region.set_clip_rect(clip_rect);
|
||||
let mut clip_rect = child_ui.clip_rect();
|
||||
clip_rect.max.y = clip_rect.max.y.min(child_ui.cursor().y + max_height);
|
||||
child_ui.set_clip_rect(clip_rect);
|
||||
|
||||
let top_left = child_region.top_left();
|
||||
add_contents(child_region);
|
||||
let top_left = child_ui.top_left();
|
||||
add_contents(child_ui);
|
||||
|
||||
state.open_height = Some(child_region.bounding_size().y);
|
||||
state.open_height = Some(child_ui.bounding_size().y);
|
||||
|
||||
// Pretend children took up less space:
|
||||
let mut child_bounds = child_region.child_bounds();
|
||||
let mut child_bounds = child_ui.child_bounds();
|
||||
child_bounds.max.y = child_bounds.max.y.min(top_left.y + max_height);
|
||||
child_region.force_set_child_bounds(child_bounds);
|
||||
child_ui.force_set_child_bounds(child_bounds);
|
||||
});
|
||||
} else if state.open {
|
||||
let full_size = region.indent(id, add_contents).rect.size();
|
||||
let full_size = ui.indent(id, add_contents).rect.size();
|
||||
state.open_height = Some(full_size.y);
|
||||
}
|
||||
|
||||
region.memory().collapsing_headers.insert(id, state);
|
||||
region.response(interact)
|
||||
ui.memory().collapsing_headers.insert(id, state);
|
||||
ui.response(interact)
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_icon(region: &mut Region, state: &State, interact: &InteractInfo) {
|
||||
let stroke_color = region.style().interact_stroke_color(interact);
|
||||
let stroke_width = region.style().interact_stroke_width(interact);
|
||||
fn paint_icon(ui: &mut Ui, state: &State, interact: &InteractInfo) {
|
||||
let stroke_color = ui.style().interact_stroke_color(interact);
|
||||
let stroke_width = ui.style().interact_stroke_width(interact);
|
||||
|
||||
let (mut small_icon_rect, _) = region.style().icon_rectangles(interact.rect);
|
||||
let (mut small_icon_rect, _) = ui.style().icon_rectangles(interact.rect);
|
||||
small_icon_rect.set_center(pos2(
|
||||
interact.rect.left() + region.style().indent / 2.0,
|
||||
interact.rect.left() + ui.style().indent / 2.0,
|
||||
interact.rect.center().y,
|
||||
));
|
||||
|
||||
// Draw a minus:
|
||||
region.add_paint_cmd(PaintCmd::Line {
|
||||
ui.add_paint_cmd(PaintCmd::Line {
|
||||
points: vec![
|
||||
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
||||
pos2(small_icon_rect.right(), small_icon_rect.center().y),
|
||||
|
@ -168,7 +168,7 @@ fn paint_icon(region: &mut Region, state: &State, interact: &InteractInfo) {
|
|||
|
||||
if !state.open {
|
||||
// Draw it as a plus:
|
||||
region.add_paint_cmd(PaintCmd::Line {
|
||||
ui.add_paint_cmd(PaintCmd::Line {
|
||||
points: vec![
|
||||
pos2(small_icon_rect.center().x, small_icon_rect.top()),
|
||||
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
//! A Floating is a region that has no parent, it floats on the background.
|
||||
//! A Floating is an Ui that has no parent, it floats on the background.
|
||||
//! It is potentioally movable.
|
||||
//! It has no frame or own size.
|
||||
//! It is the foundation for a window
|
||||
|
@ -49,7 +49,7 @@ impl Floating {
|
|||
}
|
||||
|
||||
impl Floating {
|
||||
pub fn show(self, ctx: &Arc<Context>, add_contents: impl FnOnce(&mut Region)) {
|
||||
pub fn show(self, ctx: &Arc<Context>, add_contents: impl FnOnce(&mut Ui)) {
|
||||
let default_pos = self.default_pos.unwrap_or_else(|| pos2(100.0, 100.0)); // TODO
|
||||
let id = ctx.register_unique_id(self.id, "Floating", default_pos);
|
||||
let layer = Layer::Window(id);
|
||||
|
@ -67,14 +67,14 @@ impl Floating {
|
|||
};
|
||||
state.pos = state.pos.round();
|
||||
|
||||
let mut region = Region::new(
|
||||
let mut ui = Ui::new(
|
||||
ctx.clone(),
|
||||
layer,
|
||||
id,
|
||||
Rect::from_min_size(state.pos, Vec2::infinity()),
|
||||
);
|
||||
add_contents(&mut region);
|
||||
state.size = region.bounding_size().ceil();
|
||||
add_contents(&mut ui);
|
||||
state.size = ui.bounding_size().ceil();
|
||||
|
||||
let rect = Rect::from_min_size(state.pos, state.size);
|
||||
let clip_rect = Rect::everything();
|
||||
|
|
|
@ -15,26 +15,26 @@ impl Frame {
|
|||
}
|
||||
|
||||
impl Frame {
|
||||
pub fn show(self, region: &mut Region, add_contents: impl FnOnce(&mut Region)) {
|
||||
let style = region.style();
|
||||
pub fn show(self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui)) {
|
||||
let style = ui.style();
|
||||
let margin = self.margin.unwrap_or_default();
|
||||
|
||||
let outer_pos = region.cursor();
|
||||
let outer_pos = ui.cursor();
|
||||
let inner_rect =
|
||||
Rect::from_min_size(outer_pos + margin, region.available_space() - 2.0 * margin);
|
||||
let where_to_put_background = region.paint_list_len();
|
||||
Rect::from_min_size(outer_pos + margin, ui.available_space() - 2.0 * margin);
|
||||
let where_to_put_background = ui.paint_list_len();
|
||||
|
||||
let mut child_region = region.child_region(inner_rect);
|
||||
add_contents(&mut child_region);
|
||||
let mut child_ui = ui.child_ui(inner_rect);
|
||||
add_contents(&mut child_ui);
|
||||
|
||||
let inner_size = child_region.bounding_size();
|
||||
let inner_size = child_ui.bounding_size();
|
||||
let inner_size = inner_size.ceil(); // TODO: round to pixel
|
||||
|
||||
let outer_rect = Rect::from_min_size(outer_pos, margin + inner_size + margin);
|
||||
|
||||
let corner_radius = style.window.corner_radius;
|
||||
let fill_color = style.background_fill_color();
|
||||
region.insert_paint_cmd(
|
||||
ui.insert_paint_cmd(
|
||||
where_to_put_background,
|
||||
PaintCmd::Rect {
|
||||
corner_radius,
|
||||
|
@ -44,7 +44,7 @@ impl Frame {
|
|||
},
|
||||
);
|
||||
|
||||
region.expand_to_include_child(child_region.child_bounds().expand2(margin));
|
||||
ui.expand_to_include_child(child_ui.child_bounds().expand2(margin));
|
||||
// TODO: move up cursor?
|
||||
}
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ pub struct Resize {
|
|||
/// If false, we are no enabled
|
||||
resizable: bool,
|
||||
|
||||
// Will still try to stay within parent region bounds
|
||||
// Will still try to stay within parent ui bounds
|
||||
min_size: Vec2,
|
||||
max_size: Vec2,
|
||||
|
||||
|
@ -132,17 +132,17 @@ impl Resize {
|
|||
|
||||
// TODO: a common trait for Things that follow this pattern
|
||||
impl Resize {
|
||||
pub fn show(mut self, region: &mut Region, add_contents: impl FnOnce(&mut Region)) {
|
||||
pub fn show(mut self, ui: &mut Ui, add_contents: impl FnOnce(&mut Ui)) {
|
||||
if !self.resizable {
|
||||
return add_contents(region);
|
||||
return add_contents(ui);
|
||||
}
|
||||
|
||||
let id = region.make_child_id("scroll");
|
||||
self.min_size = self.min_size.min(region.available_space());
|
||||
self.max_size = self.max_size.min(region.available_space());
|
||||
let id = ui.make_child_id("scroll");
|
||||
self.min_size = self.min_size.min(ui.available_space());
|
||||
self.max_size = self.max_size.min(ui.available_space());
|
||||
self.max_size = self.max_size.max(self.min_size);
|
||||
|
||||
let (is_new, mut state) = match region.memory().resize.get(&id) {
|
||||
let (is_new, mut state) = match ui.memory().resize.get(&id) {
|
||||
Some(state) => (false, *state),
|
||||
None => {
|
||||
let default_size = self.default_size.clamp(self.min_size..=self.max_size);
|
||||
|
@ -153,7 +153,7 @@ impl Resize {
|
|||
state.size = state.size.clamp(self.min_size..=self.max_size);
|
||||
let last_frame_size = state.size;
|
||||
|
||||
let position = region.cursor();
|
||||
let position = ui.cursor();
|
||||
|
||||
// Resize-corner:
|
||||
let corner_size = Vec2::splat(16.0); // TODO: style
|
||||
|
@ -161,10 +161,10 @@ impl Resize {
|
|||
position + state.size + self.handle_offset - corner_size,
|
||||
corner_size,
|
||||
);
|
||||
let corner_interact = region.interact_rect(corner_rect, id.with("corner"));
|
||||
let corner_interact = ui.interact_rect(corner_rect, id.with("corner"));
|
||||
|
||||
if corner_interact.active {
|
||||
if let Some(mouse_pos) = region.input().mouse_pos {
|
||||
if let Some(mouse_pos) = ui.input().mouse_pos {
|
||||
// This is the desired size. We may not be able to achieve it.
|
||||
|
||||
state.size =
|
||||
|
@ -178,11 +178,11 @@ impl Resize {
|
|||
|
||||
// ------------------------------
|
||||
|
||||
let inner_rect = Rect::from_min_size(region.cursor(), state.size);
|
||||
let inner_rect = Rect::from_min_size(ui.cursor(), state.size);
|
||||
let desired_size = {
|
||||
let mut content_clip_rect = region
|
||||
let mut content_clip_rect = ui
|
||||
.clip_rect()
|
||||
.intersect(inner_rect.expand(region.style().clip_rect_margin));
|
||||
.intersect(inner_rect.expand(ui.style().clip_rect_margin));
|
||||
|
||||
// If we pull the resize handle to shrink, we want to TRY to shink it.
|
||||
// After laying out the contents, we might be much bigger.
|
||||
|
@ -192,12 +192,12 @@ impl Resize {
|
|||
content_clip_rect.max = content_clip_rect
|
||||
.max
|
||||
.max(content_clip_rect.min + last_frame_size)
|
||||
.min(region.clip_rect().max); // Respect parent region
|
||||
.min(ui.clip_rect().max); // Respect parent region
|
||||
|
||||
let mut contents_region = region.child_region(inner_rect);
|
||||
contents_region.set_clip_rect(content_clip_rect);
|
||||
add_contents(&mut contents_region);
|
||||
contents_region.bounding_size()
|
||||
let mut contents_ui = ui.child_ui(inner_rect);
|
||||
contents_ui.set_clip_rect(content_clip_rect);
|
||||
add_contents(&mut contents_ui);
|
||||
contents_ui.bounding_size()
|
||||
};
|
||||
let desired_size = desired_size.ceil(); // Avoid rounding errors in math
|
||||
|
||||
|
@ -220,29 +220,29 @@ impl Resize {
|
|||
// state.size = state.size.clamp(self.min_size..=self.max_size);
|
||||
state.size = state.size.round(); // TODO: round to pixels
|
||||
|
||||
region.reserve_space(state.size, None);
|
||||
ui.reserve_space(state.size, None);
|
||||
|
||||
// ------------------------------
|
||||
|
||||
paint_resize_corner(region, &corner_interact);
|
||||
paint_resize_corner(ui, &corner_interact);
|
||||
|
||||
if corner_interact.hovered || corner_interact.active {
|
||||
region.ctx().output().cursor_icon = CursorIcon::ResizeNwSe;
|
||||
ui.ctx().output().cursor_icon = CursorIcon::ResizeNwSe;
|
||||
}
|
||||
|
||||
region.memory().resize.insert(id, state);
|
||||
ui.memory().resize.insert(id, state);
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_resize_corner(region: &mut Region, interact: &InteractInfo) {
|
||||
let color = region.style().interact_stroke_color(interact);
|
||||
let width = region.style().interact_stroke_width(interact);
|
||||
fn paint_resize_corner(ui: &mut Ui, interact: &InteractInfo) {
|
||||
let color = ui.style().interact_stroke_color(interact);
|
||||
let width = ui.style().interact_stroke_width(interact);
|
||||
|
||||
let corner = interact.rect.right_bottom().round(); // TODO: round to pixels
|
||||
let mut w = 2.0;
|
||||
|
||||
while w < 12.0 {
|
||||
region.add_paint_cmd(PaintCmd::line_segment(
|
||||
ui.add_paint_cmd(PaintCmd::line_segment(
|
||||
(pos2(corner.x - w, corner.y), pos2(corner.x, corner.y - w)),
|
||||
color,
|
||||
width,
|
||||
|
|
|
@ -45,10 +45,10 @@ impl ScrollArea {
|
|||
}
|
||||
|
||||
impl ScrollArea {
|
||||
pub fn show(self, outer_region: &mut Region, add_contents: impl FnOnce(&mut Region)) {
|
||||
let ctx = outer_region.ctx().clone();
|
||||
pub fn show(self, outer_ui: &mut Ui, add_contents: impl FnOnce(&mut Ui)) {
|
||||
let ctx = outer_ui.ctx().clone();
|
||||
|
||||
let scroll_area_id = outer_region.make_child_id("scroll_area");
|
||||
let scroll_area_id = outer_ui.make_child_id("scroll_area");
|
||||
let mut state = ctx
|
||||
.memory()
|
||||
.scroll_areas
|
||||
|
@ -69,23 +69,23 @@ impl ScrollArea {
|
|||
};
|
||||
|
||||
let outer_size = vec2(
|
||||
outer_region.available_width(),
|
||||
outer_region.available_height().min(self.max_height),
|
||||
outer_ui.available_width(),
|
||||
outer_ui.available_height().min(self.max_height),
|
||||
);
|
||||
|
||||
let inner_size = outer_size - vec2(current_scroll_bar_width, 0.0);
|
||||
let inner_rect = Rect::from_min_size(outer_region.cursor(), inner_size);
|
||||
let inner_rect = Rect::from_min_size(outer_ui.cursor(), inner_size);
|
||||
|
||||
let mut content_region = outer_region.child_region(Rect::from_min_size(
|
||||
outer_region.cursor() - state.offset,
|
||||
let mut content_ui = outer_ui.child_ui(Rect::from_min_size(
|
||||
outer_ui.cursor() - state.offset,
|
||||
vec2(inner_size.x, f32::INFINITY),
|
||||
));
|
||||
let mut content_clip_rect = outer_region.clip_rect().intersect(inner_rect);
|
||||
content_clip_rect.max.x = outer_region.clip_rect().max.x - current_scroll_bar_width; // Nice handling of forced resizing beyond the possible
|
||||
content_region.set_clip_rect(content_clip_rect);
|
||||
let mut content_clip_rect = outer_ui.clip_rect().intersect(inner_rect);
|
||||
content_clip_rect.max.x = outer_ui.clip_rect().max.x - current_scroll_bar_width; // Nice handling of forced resizing beyond the possible
|
||||
content_ui.set_clip_rect(content_clip_rect);
|
||||
|
||||
add_contents(&mut content_region);
|
||||
let content_size = content_region.bounding_size();
|
||||
add_contents(&mut content_ui);
|
||||
let content_size = content_ui.bounding_size();
|
||||
|
||||
let inner_rect = Rect::from_min_size(
|
||||
inner_rect.min,
|
||||
|
@ -100,14 +100,14 @@ impl ScrollArea {
|
|||
inner_rect.size() + vec2(current_scroll_bar_width, 0.0),
|
||||
);
|
||||
|
||||
let content_interact = outer_region.interact_rect(inner_rect, scroll_area_id.with("area"));
|
||||
let content_interact = outer_ui.interact_rect(inner_rect, scroll_area_id.with("area"));
|
||||
if content_interact.active {
|
||||
// Dragging scroll area to scroll:
|
||||
state.offset.y -= ctx.input().mouse_move.y;
|
||||
}
|
||||
|
||||
// TODO: check that nothing else is being inteacted with
|
||||
if outer_region.contains_mouse(outer_rect) && ctx.memory().active_id.is_none() {
|
||||
if outer_ui.contains_mouse(outer_rect) && ctx.memory().active_id.is_none() {
|
||||
state.offset.y -= ctx.input().scroll_delta.y;
|
||||
}
|
||||
|
||||
|
@ -134,7 +134,7 @@ impl ScrollArea {
|
|||
|
||||
// intentionally use same id for inside and outside of handle
|
||||
let interact_id = scroll_area_id.with("vertical");
|
||||
let handle_interact = outer_region.interact_rect(handle_rect, interact_id);
|
||||
let handle_interact = outer_ui.interact_rect(handle_rect, interact_id);
|
||||
|
||||
if let Some(mouse_pos) = ctx.input().mouse_pos {
|
||||
if handle_interact.active {
|
||||
|
@ -144,8 +144,7 @@ impl ScrollArea {
|
|||
}
|
||||
} else {
|
||||
// Check for mouse down outside handle:
|
||||
let scroll_bg_interact =
|
||||
outer_region.interact_rect(outer_scroll_rect, interact_id);
|
||||
let scroll_bg_interact = outer_ui.interact_rect(outer_scroll_rect, interact_id);
|
||||
|
||||
if scroll_bg_interact.active {
|
||||
// Center scroll at mouse pos:
|
||||
|
@ -164,18 +163,18 @@ impl ScrollArea {
|
|||
pos2(right, from_content(state.offset.y + inner_rect.height())),
|
||||
);
|
||||
|
||||
let style = outer_region.style();
|
||||
let style = outer_ui.style();
|
||||
let handle_fill_color = style.interact_fill_color(&handle_interact);
|
||||
let handle_outline = style.interact_outline(&handle_interact);
|
||||
|
||||
outer_region.add_paint_cmd(PaintCmd::Rect {
|
||||
outer_ui.add_paint_cmd(PaintCmd::Rect {
|
||||
rect: outer_scroll_rect,
|
||||
corner_radius,
|
||||
fill_color: Some(color::gray(0, 196)), // TODO style
|
||||
outline: None,
|
||||
});
|
||||
|
||||
outer_region.add_paint_cmd(PaintCmd::Rect {
|
||||
outer_ui.add_paint_cmd(PaintCmd::Rect {
|
||||
rect: handle_rect.expand(-2.0),
|
||||
corner_radius,
|
||||
fill_color: handle_fill_color,
|
||||
|
@ -189,15 +188,12 @@ impl ScrollArea {
|
|||
// content_size.y.min(inner_rect.size().y), // respect vertical height.
|
||||
// );
|
||||
let size = outer_rect.size();
|
||||
outer_region.reserve_space(size, None);
|
||||
outer_ui.reserve_space(size, None);
|
||||
|
||||
state.offset.y = state.offset.y.min(content_size.y - inner_rect.height());
|
||||
state.offset.y = state.offset.y.max(0.0);
|
||||
state.show_scroll = show_scroll_this_frame;
|
||||
|
||||
outer_region
|
||||
.memory()
|
||||
.scroll_areas
|
||||
.insert(scroll_area_id, state);
|
||||
outer_ui.memory().scroll_areas.insert(scroll_area_id, state);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -85,7 +85,7 @@ impl Window {
|
|||
}
|
||||
|
||||
impl Window {
|
||||
pub fn show(self, ctx: &Arc<Context>, add_contents: impl FnOnce(&mut Region)) {
|
||||
pub fn show(self, ctx: &Arc<Context>, add_contents: impl FnOnce(&mut Ui)) {
|
||||
let Window {
|
||||
title_label,
|
||||
floating,
|
||||
|
@ -96,12 +96,12 @@ impl Window {
|
|||
frame.margin = Some(frame.margin.unwrap_or_else(|| ctx.style().window_padding));
|
||||
|
||||
// TODO: easier way to compose these
|
||||
floating.show(ctx, |region| {
|
||||
frame.show(region, |region| {
|
||||
resize.show(region, |region| {
|
||||
region.add(title_label);
|
||||
region.add(Separator::new().line_width(1.0)); // TODO: nicer way to split window title from contents
|
||||
scroll.show(region, |region| add_contents(region))
|
||||
floating.show(ctx, |ui| {
|
||||
frame.show(ui, |ui| {
|
||||
resize.show(ui, |ui| {
|
||||
ui.add(title_label);
|
||||
ui.add(Separator::new().line_width(1.0)); // TODO: nicer way to split window title from contents
|
||||
scroll.show(ui, |ui| add_contents(ui))
|
||||
})
|
||||
})
|
||||
})
|
||||
|
|
|
@ -13,11 +13,11 @@ struct PaintStats {
|
|||
}
|
||||
|
||||
/// Contains the input, style and output of all GUI commands.
|
||||
/// Regions keep an Arc pointer to this.
|
||||
/// This allows us to create several child regions at once,
|
||||
/// `Ui`:s keep an Arc pointer to this.
|
||||
/// This allows us to create several child `Ui`:s at once,
|
||||
/// all working against the same shared Context.
|
||||
pub struct Context {
|
||||
/// The default style for new regions
|
||||
/// The default style for new `Ui`:s
|
||||
style: Mutex<Style>,
|
||||
mesher_options: Mutex<mesher::MesherOptions>,
|
||||
fonts: Arc<Fonts>,
|
||||
|
@ -207,10 +207,10 @@ impl Context {
|
|||
|
||||
// ---------------------------------------------------------------------
|
||||
|
||||
/// A region for the entire screen, behind any windows.
|
||||
pub fn background_region(self: &Arc<Self>) -> Region {
|
||||
/// An ui for the entire screen, behind any windows.
|
||||
pub fn fullscreen_ui(self: &Arc<Self>) -> Ui {
|
||||
let rect = Rect::from_min_size(Default::default(), self.input().screen_size);
|
||||
Region::new(self.clone(), Layer::Background, Id::background(), rect)
|
||||
Ui::new(self.clone(), Layer::Background, Id::background(), rect)
|
||||
}
|
||||
|
||||
// ---------------------------------------------------------------------
|
||||
|
@ -428,19 +428,19 @@ impl Context {
|
|||
}
|
||||
|
||||
impl Context {
|
||||
pub fn ui(&self, region: &mut Region) {
|
||||
pub fn ui(&self, ui: &mut Ui) {
|
||||
use crate::containers::*;
|
||||
|
||||
region.collapsing("Style", |region| {
|
||||
self.mesher_options.lock().ui(region);
|
||||
self.style_ui(region);
|
||||
ui.collapsing("Style", |ui| {
|
||||
self.mesher_options.lock().ui(ui);
|
||||
self.style_ui(ui);
|
||||
});
|
||||
|
||||
region.collapsing("Fonts", |region| {
|
||||
ui.collapsing("Fonts", |ui| {
|
||||
let old_font_definitions = self.fonts().definitions();
|
||||
let mut new_font_definitions = old_font_definitions.clone();
|
||||
font_definitions_ui(&mut new_font_definitions, region);
|
||||
self.fonts().texture().ui(region);
|
||||
font_definitions_ui(&mut new_font_definitions, ui);
|
||||
self.fonts().texture().ui(ui);
|
||||
if *old_font_definitions != new_font_definitions {
|
||||
let fonts =
|
||||
Fonts::from_definitions(new_font_definitions, self.input().pixels_per_point);
|
||||
|
@ -448,64 +448,62 @@ impl Context {
|
|||
}
|
||||
});
|
||||
|
||||
region.collapsing("Input", |region| {
|
||||
ui.collapsing("Input", |ui| {
|
||||
CollapsingHeader::new("Raw Input")
|
||||
.default_open()
|
||||
.show(region, |region| {
|
||||
region.ctx().last_raw_input().clone().ui(region)
|
||||
});
|
||||
.show(ui, |ui| ui.ctx().last_raw_input().clone().ui(ui));
|
||||
CollapsingHeader::new("Input")
|
||||
.default_open()
|
||||
.show(region, |region| region.input().clone().ui(region));
|
||||
.show(ui, |ui| ui.input().clone().ui(ui));
|
||||
});
|
||||
|
||||
region.collapsing("Stats", |region| {
|
||||
region.add(label!(
|
||||
ui.collapsing("Stats", |ui| {
|
||||
ui.add(label!(
|
||||
"Screen size: {} x {} points, pixels_per_point: {}",
|
||||
region.input().screen_size.x,
|
||||
region.input().screen_size.y,
|
||||
region.input().pixels_per_point,
|
||||
ui.input().screen_size.x,
|
||||
ui.input().screen_size.y,
|
||||
ui.input().pixels_per_point,
|
||||
));
|
||||
if let Some(mouse_pos) = region.input().mouse_pos {
|
||||
region.add(label!("mouse_pos: {:.2} x {:.2}", mouse_pos.x, mouse_pos.y,));
|
||||
if let Some(mouse_pos) = ui.input().mouse_pos {
|
||||
ui.add(label!("mouse_pos: {:.2} x {:.2}", mouse_pos.x, mouse_pos.y,));
|
||||
} else {
|
||||
region.add_label("mouse_pos: None");
|
||||
ui.add_label("mouse_pos: None");
|
||||
}
|
||||
|
||||
region.add(label!("Painting:").text_style(TextStyle::Heading));
|
||||
self.paint_stats.lock().ui(region);
|
||||
ui.add(label!("Painting:").text_style(TextStyle::Heading));
|
||||
self.paint_stats.lock().ui(ui);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
fn font_definitions_ui(font_definitions: &mut FontDefinitions, region: &mut Region) {
|
||||
fn font_definitions_ui(font_definitions: &mut FontDefinitions, ui: &mut Ui) {
|
||||
use crate::widgets::*;
|
||||
for (text_style, (_family, size)) in font_definitions.iter_mut() {
|
||||
// TODO: radiobutton for family
|
||||
region.add(
|
||||
ui.add(
|
||||
Slider::f32(size, 4.0..=40.0)
|
||||
.precision(0)
|
||||
.text(format!("{:?}", text_style)),
|
||||
);
|
||||
}
|
||||
if region.add(Button::new("Reset fonts")).clicked {
|
||||
if ui.add(Button::new("Reset fonts")).clicked {
|
||||
*font_definitions = crate::fonts::default_font_definitions();
|
||||
}
|
||||
}
|
||||
|
||||
impl Context {
|
||||
pub fn style_ui(&self, region: &mut Region) {
|
||||
pub fn style_ui(&self, ui: &mut Ui) {
|
||||
let mut style = self.style();
|
||||
style.ui(region);
|
||||
style.ui(ui);
|
||||
self.set_style(style);
|
||||
}
|
||||
}
|
||||
|
||||
impl mesher::MesherOptions {
|
||||
pub fn ui(&mut self, region: &mut Region) {
|
||||
pub fn ui(&mut self, ui: &mut Ui) {
|
||||
use crate::widgets::*;
|
||||
region.add(Checkbox::new(&mut self.anti_alias, "Antialias"));
|
||||
region.add(Checkbox::new(
|
||||
ui.add(Checkbox::new(&mut self.anti_alias, "Antialias"));
|
||||
ui.add(Checkbox::new(
|
||||
&mut self.debug_paint_clip_rects,
|
||||
"Paint Clip Rects (debug)",
|
||||
));
|
||||
|
@ -513,14 +511,12 @@ impl mesher::MesherOptions {
|
|||
}
|
||||
|
||||
impl PaintStats {
|
||||
pub fn ui(&self, region: &mut Region) {
|
||||
region
|
||||
.add(label!("Batches: {}", self.num_batches))
|
||||
pub fn ui(&self, ui: &mut Ui) {
|
||||
ui.add(label!("Batches: {}", self.num_batches))
|
||||
.tooltip_text("Number of separate clip rectanlges");
|
||||
region
|
||||
.add(label!("Primitives: {}", self.num_primitives))
|
||||
ui.add(label!("Primitives: {}", self.num_primitives))
|
||||
.tooltip_text("Boxes, circles, text areas etc");
|
||||
region.add(label!("Vertices: {}", self.num_vertices));
|
||||
region.add(label!("Triangles: {}", self.num_triangles));
|
||||
ui.add(label!("Vertices: {}", self.num_vertices));
|
||||
ui.add(label!("Triangles: {}", self.num_triangles));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
use crate::{color::*, containers::*, widgets::*, *};
|
||||
|
||||
/// Showcase some region code
|
||||
/// Showcase some ui code
|
||||
pub struct ExampleWindow {
|
||||
checked: bool,
|
||||
count: usize,
|
||||
|
@ -44,73 +44,73 @@ impl Default for ExampleWindow {
|
|||
}
|
||||
|
||||
impl ExampleWindow {
|
||||
pub fn ui(&mut self, region: &mut Region) {
|
||||
region.collapsing("About Emigui", |region| {
|
||||
region.add(label!(
|
||||
pub fn ui(&mut self, ui: &mut Ui) {
|
||||
ui.collapsing("About Emigui", |ui| {
|
||||
ui.add(label!(
|
||||
"Emigui is an experimental immediate mode GUI written in Rust."
|
||||
));
|
||||
|
||||
region.horizontal(|region| {
|
||||
region.add_label("Project home page:");
|
||||
region.add_hyperlink("https://github.com/emilk/emigui/");
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_label("Project home page:");
|
||||
ui.add_hyperlink("https://github.com/emilk/emigui/");
|
||||
});
|
||||
});
|
||||
|
||||
CollapsingHeader::new("Widgets")
|
||||
.default_open()
|
||||
.show(region, |region| {
|
||||
region.horizontal(|region| {
|
||||
region.add(label!("Text can have").text_color(srgba(110, 255, 110, 255)));
|
||||
region.add(label!("color").text_color(srgba(128, 140, 255, 255)));
|
||||
region.add(label!("and tooltips (hover me)")).tooltip_text(
|
||||
.show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.add(label!("Text can have").text_color(srgba(110, 255, 110, 255)));
|
||||
ui.add(label!("color").text_color(srgba(128, 140, 255, 255)));
|
||||
ui.add(label!("and tooltips (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.",
|
||||
);
|
||||
});
|
||||
|
||||
region.add(Checkbox::new(&mut self.checked, "checkbox"));
|
||||
ui.add(Checkbox::new(&mut self.checked, "checkbox"));
|
||||
|
||||
region.horizontal(|region| {
|
||||
if region.add(radio(self.radio == 0, "First")).clicked {
|
||||
ui.horizontal(|ui| {
|
||||
if ui.add(radio(self.radio == 0, "First")).clicked {
|
||||
self.radio = 0;
|
||||
}
|
||||
if region.add(radio(self.radio == 1, "Second")).clicked {
|
||||
if ui.add(radio(self.radio == 1, "Second")).clicked {
|
||||
self.radio = 1;
|
||||
}
|
||||
if region.add(radio(self.radio == 2, "Final")).clicked {
|
||||
if ui.add(radio(self.radio == 2, "Final")).clicked {
|
||||
self.radio = 2;
|
||||
}
|
||||
});
|
||||
|
||||
region.horizontal(|region| {
|
||||
if region
|
||||
ui.horizontal(|ui| {
|
||||
if ui
|
||||
.add(Button::new("Click me"))
|
||||
.tooltip_text("This will just increase a counter.")
|
||||
.clicked
|
||||
{
|
||||
self.count += 1;
|
||||
}
|
||||
region.add(label!(
|
||||
ui.add(label!(
|
||||
"The button has been clicked {} times",
|
||||
self.count
|
||||
));
|
||||
});
|
||||
|
||||
region.add(Slider::usize(&mut self.slider_value, 1..=1000).text("value"));
|
||||
if region.add(Button::new("Double it")).clicked {
|
||||
ui.add(Slider::usize(&mut self.slider_value, 1..=1000).text("value"));
|
||||
if ui.add(Button::new("Double it")).clicked {
|
||||
self.slider_value *= 2;
|
||||
}
|
||||
|
||||
for (i, text) in self.text_inputs.iter_mut().enumerate() {
|
||||
region.horizontal(|region|{
|
||||
region.add(label!("Text input {}: ", i));
|
||||
region.add(TextEdit::new(text).id(i));
|
||||
ui.horizontal(|ui|{
|
||||
ui.add(label!("Text input {}: ", i));
|
||||
ui.add(TextEdit::new(text).id(i));
|
||||
}); // TODO: .tooltip_text("Enter text to edit me")
|
||||
}
|
||||
});
|
||||
|
||||
region.collapsing("Layouts", |region| {
|
||||
region.add(Slider::usize(&mut self.num_columns, 1..=10).text("Columns"));
|
||||
region.columns(self.num_columns, |cols| {
|
||||
ui.collapsing("Layouts", |ui| {
|
||||
ui.add(Slider::usize(&mut self.num_columns, 1..=10).text("Columns"));
|
||||
ui.columns(self.num_columns, |cols| {
|
||||
for (i, col) in cols.iter_mut().enumerate() {
|
||||
col.add(label!("Column {} out of {}", i + 1, self.num_columns));
|
||||
if i + 1 == self.num_columns && col.add(Button::new("Delete this")).clicked {
|
||||
|
@ -120,14 +120,14 @@ impl ExampleWindow {
|
|||
});
|
||||
});
|
||||
|
||||
region.collapsing("Test box rendering", |region| {
|
||||
region.add(Slider::f32(&mut self.size.x, 0.0..=500.0).text("width"));
|
||||
region.add(Slider::f32(&mut self.size.y, 0.0..=500.0).text("height"));
|
||||
region.add(Slider::f32(&mut self.corner_radius, 0.0..=50.0).text("corner_radius"));
|
||||
region.add(Slider::f32(&mut self.stroke_width, 0.0..=10.0).text("stroke_width"));
|
||||
region.add(Slider::usize(&mut self.num_boxes, 0..=5).text("num_boxes"));
|
||||
ui.collapsing("Test box rendering", |ui| {
|
||||
ui.add(Slider::f32(&mut self.size.x, 0.0..=500.0).text("width"));
|
||||
ui.add(Slider::f32(&mut self.size.y, 0.0..=500.0).text("height"));
|
||||
ui.add(Slider::f32(&mut self.corner_radius, 0.0..=50.0).text("corner_radius"));
|
||||
ui.add(Slider::f32(&mut self.stroke_width, 0.0..=10.0).text("stroke_width"));
|
||||
ui.add(Slider::usize(&mut self.num_boxes, 0..=5).text("num_boxes"));
|
||||
|
||||
let pos = region
|
||||
let pos = ui
|
||||
.reserve_space(
|
||||
vec2(self.size.x * (self.num_boxes as f32), self.size.y),
|
||||
None,
|
||||
|
@ -147,56 +147,56 @@ impl ExampleWindow {
|
|||
outline: Some(Outline::new(self.stroke_width, gray(255, 255))),
|
||||
});
|
||||
}
|
||||
region.add_paint_cmds(cmds);
|
||||
ui.add_paint_cmds(cmds);
|
||||
});
|
||||
|
||||
CollapsingHeader::new("Scroll area")
|
||||
// .default_open()
|
||||
.show(region, |region| {
|
||||
ScrollArea::default().show(region, |region| {
|
||||
region.add_label(LOREM_IPSUM);
|
||||
.show(ui, |ui| {
|
||||
ScrollArea::default().show(ui, |ui| {
|
||||
ui.add_label(LOREM_IPSUM);
|
||||
});
|
||||
});
|
||||
|
||||
CollapsingHeader::new("Painting")
|
||||
// .default_open()
|
||||
.show(region, |region| self.painting.ui(region));
|
||||
.show(ui, |ui| self.painting.ui(ui));
|
||||
|
||||
CollapsingHeader::new("Resize")
|
||||
// .default_open()
|
||||
.show(region, |region| {
|
||||
.show(ui, |ui| {
|
||||
Resize::default()
|
||||
.default_height(200.0)
|
||||
// .as_wide_as_possible()
|
||||
.auto_shrink_height(false)
|
||||
.show(region, |region| {
|
||||
region.add(label!("This region can be resized!"));
|
||||
region.add(label!("Just pull the handle on the bottom right"));
|
||||
.show(ui, |ui| {
|
||||
ui.add(label!("This ui can be resized!"));
|
||||
ui.add(label!("Just pull the handle on the bottom right"));
|
||||
});
|
||||
});
|
||||
|
||||
region.collapsing("Name clash example", |region| {
|
||||
region.add_label("\
|
||||
Regions that store state require unique identifiers so we can track their state between frames. \
|
||||
ui.collapsing("Name clash example", |ui| {
|
||||
ui.add_label("\
|
||||
Widgets that store state require unique identifiers so we can track their state between frames. \
|
||||
Identifiers are normally derived from the titles of the widget.");
|
||||
|
||||
region.add_label("\
|
||||
For instance, collapsing regions needs to store wether or not they are open. \
|
||||
ui.add_label("\
|
||||
For instance, collapsable headers needs to store wether or not they are open. \
|
||||
If you fail to give them unique names then clicking one will open both. \
|
||||
To help you debug this, an error message is printed on screen:");
|
||||
|
||||
region.collapsing("Collapsing header", |region| {
|
||||
region.add_label("Contents of first folddable region");
|
||||
ui.collapsing("Collapsing header", |ui| {
|
||||
ui.add_label("Contents of first folddable ui");
|
||||
});
|
||||
region.collapsing("Collapsing header", |region| {
|
||||
region.add_label("Contents of second folddable region");
|
||||
ui.collapsing("Collapsing header", |ui| {
|
||||
ui.add_label("Contents of second folddable ui");
|
||||
});
|
||||
|
||||
region.add_label("\
|
||||
ui.add_label("\
|
||||
Most widgets don't need unique names, but are tracked \
|
||||
based on their position on screen. For instance, buttons:");
|
||||
region.add(Button::new("Button"));
|
||||
region.add(Button::new("Button"));
|
||||
ui.add(Button::new("Button"));
|
||||
ui.add(Button::new("Button"));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -207,16 +207,16 @@ struct Painting {
|
|||
}
|
||||
|
||||
impl Painting {
|
||||
pub fn ui(&mut self, region: &mut Region) {
|
||||
region.add_label("Draw with your mouse to paint");
|
||||
if region.add(Button::new("Clear")).clicked {
|
||||
pub fn ui(&mut self, ui: &mut Ui) {
|
||||
ui.add_label("Draw with your mouse to paint");
|
||||
if ui.add(Button::new("Clear")).clicked {
|
||||
self.lines.clear();
|
||||
}
|
||||
|
||||
region.add_custom_contents(vec2(f32::INFINITY, 200.0), |region| {
|
||||
let canvas_corner = region.cursor();
|
||||
let interact = region.reserve_space(region.available_space(), Some(region.id()));
|
||||
region.set_clip_rect(region.clip_rect().intersect(interact.rect)); // Make sure we don't paint out of bounds
|
||||
ui.add_custom_contents(vec2(f32::INFINITY, 200.0), |ui| {
|
||||
let canvas_corner = ui.cursor();
|
||||
let interact = ui.reserve_space(ui.available_space(), Some(ui.id()));
|
||||
ui.set_clip_rect(ui.clip_rect().intersect(interact.rect)); // Make sure we don't paint out of bounds
|
||||
|
||||
if self.lines.is_empty() {
|
||||
self.lines.push(vec![]);
|
||||
|
@ -225,7 +225,7 @@ impl Painting {
|
|||
let current_line = self.lines.last_mut().unwrap();
|
||||
|
||||
if interact.active {
|
||||
if let Some(mouse_pos) = region.input().mouse_pos {
|
||||
if let Some(mouse_pos) = ui.input().mouse_pos {
|
||||
let canvas_pos = mouse_pos - canvas_corner;
|
||||
if current_line.last() != Some(&canvas_pos) {
|
||||
current_line.push(canvas_pos);
|
||||
|
@ -237,7 +237,7 @@ impl Painting {
|
|||
|
||||
for line in &self.lines {
|
||||
if line.len() >= 2 {
|
||||
region.add_paint_cmd(PaintCmd::Line {
|
||||
ui.add_paint_cmd(PaintCmd::Line {
|
||||
points: line.iter().map(|p| canvas_corner + *p).collect(),
|
||||
color: LIGHT_GRAY,
|
||||
width: 2.0,
|
||||
|
@ -246,8 +246,8 @@ impl Painting {
|
|||
}
|
||||
|
||||
// Frame it:
|
||||
region.add_paint_cmd(PaintCmd::Rect {
|
||||
rect: region.rect(),
|
||||
ui.add_paint_cmd(PaintCmd::Rect {
|
||||
rect: ui.rect(),
|
||||
corner_radius: 0.0,
|
||||
fill_color: None,
|
||||
outline: Some(Outline::new(1.0, WHITE)),
|
||||
|
|
|
@ -17,7 +17,7 @@
|
|||
//!
|
||||
//! For things that need to persist state even after moving (windows, collapsing headers)
|
||||
//! the location of the widgets is obviously not good enough. For instance,
|
||||
//! a fodlable region needs to remember wether or not it is open even
|
||||
//! a collapsing region needs to remember wether or not it is open even
|
||||
//! if the layout next frame is different and the collapsing is not lower down
|
||||
//! on the screen.
|
||||
//!
|
||||
|
|
|
@ -153,41 +153,41 @@ impl GuiInput {
|
|||
}
|
||||
|
||||
impl RawInput {
|
||||
pub fn ui(&self, region: &mut crate::Region) {
|
||||
pub fn ui(&self, ui: &mut crate::Ui) {
|
||||
use crate::label;
|
||||
// TODO: simpler way to show values, e.g. `region.value("Mouse Pos:", self.mouse_pos);
|
||||
// TODO: simpler way to show values, e.g. `ui.value("Mouse Pos:", self.mouse_pos);
|
||||
// TODO: easily change default font!
|
||||
region.add(label!("mouse_down: {}", self.mouse_down));
|
||||
region.add(label!("mouse_pos: {:.1?}", self.mouse_pos));
|
||||
region.add(label!("scroll_delta: {:?}", self.scroll_delta));
|
||||
region.add(label!("screen_size: {:?}", self.screen_size));
|
||||
region.add(label!("pixels_per_point: {}", self.pixels_per_point));
|
||||
region.add(label!("time: {:.3} s", self.time));
|
||||
region.add(label!("events: {:?}", self.events));
|
||||
region.add(label!("dropped_files: {:?}", self.dropped_files));
|
||||
region.add(label!("hovered_files: {:?}", self.hovered_files));
|
||||
ui.add(label!("mouse_down: {}", self.mouse_down));
|
||||
ui.add(label!("mouse_pos: {:.1?}", self.mouse_pos));
|
||||
ui.add(label!("scroll_delta: {:?}", self.scroll_delta));
|
||||
ui.add(label!("screen_size: {:?}", self.screen_size));
|
||||
ui.add(label!("pixels_per_point: {}", self.pixels_per_point));
|
||||
ui.add(label!("time: {:.3} s", self.time));
|
||||
ui.add(label!("events: {:?}", self.events));
|
||||
ui.add(label!("dropped_files: {:?}", self.dropped_files));
|
||||
ui.add(label!("hovered_files: {:?}", self.hovered_files));
|
||||
}
|
||||
}
|
||||
|
||||
impl GuiInput {
|
||||
pub fn ui(&self, region: &mut crate::Region) {
|
||||
pub fn ui(&self, ui: &mut crate::Ui) {
|
||||
use crate::label;
|
||||
region.add(label!("mouse_down: {}", self.mouse_down));
|
||||
region.add(label!("mouse_pressed: {}", self.mouse_pressed));
|
||||
region.add(label!("mouse_released: {}", self.mouse_released));
|
||||
region.add(label!("mouse_pos: {:?}", self.mouse_pos));
|
||||
region.add(label!("mouse_move: {:?}", self.mouse_move));
|
||||
region.add(label!(
|
||||
ui.add(label!("mouse_down: {}", self.mouse_down));
|
||||
ui.add(label!("mouse_pressed: {}", self.mouse_pressed));
|
||||
ui.add(label!("mouse_released: {}", self.mouse_released));
|
||||
ui.add(label!("mouse_pos: {:?}", self.mouse_pos));
|
||||
ui.add(label!("mouse_move: {:?}", self.mouse_move));
|
||||
ui.add(label!(
|
||||
"mouse_velocity: [{:3.0} {:3.0}] points/sec",
|
||||
self.mouse_velocity.x,
|
||||
self.mouse_velocity.y
|
||||
));
|
||||
region.add(label!("scroll_delta: {:?}", self.scroll_delta));
|
||||
region.add(label!("screen_size: {:?}", self.screen_size));
|
||||
region.add(label!("pixels_per_point: {}", self.pixels_per_point));
|
||||
region.add(label!("time: {:.3} s", self.time));
|
||||
region.add(label!("events: {:?}", self.events));
|
||||
region.add(label!("dropped_files: {:?}", self.dropped_files));
|
||||
region.add(label!("hovered_files: {:?}", self.hovered_files));
|
||||
ui.add(label!("scroll_delta: {:?}", self.scroll_delta));
|
||||
ui.add(label!("screen_size: {:?}", self.screen_size));
|
||||
ui.add(label!("pixels_per_point: {}", self.pixels_per_point));
|
||||
ui.add(label!("time: {:.3} s", self.time));
|
||||
ui.add(label!("events: {:?}", self.events));
|
||||
ui.add(label!("dropped_files: {:?}", self.dropped_files));
|
||||
ui.add(label!("hovered_files: {:?}", self.hovered_files));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ pub struct GuiResponse {
|
|||
/// The mouse is interacting with this thing (e.g. dragging it)
|
||||
pub active: bool,
|
||||
|
||||
/// The region of the screen we are talking about
|
||||
/// The area of the screen we are talking about
|
||||
pub rect: Rect,
|
||||
|
||||
/// Used for optionally showing a tooltip
|
||||
|
@ -24,7 +24,7 @@ pub struct GuiResponse {
|
|||
|
||||
impl GuiResponse {
|
||||
/// Show some stuff if the item was hovered
|
||||
pub fn tooltip(&mut self, add_contents: impl FnOnce(&mut Region)) -> &mut Self {
|
||||
pub fn tooltip(&mut self, add_contents: impl FnOnce(&mut Ui)) -> &mut Self {
|
||||
if self.hovered {
|
||||
if let Some(mouse_pos) = self.ctx.input().mouse_pos {
|
||||
let window_pos = mouse_pos + vec2(16.0, 16.0);
|
||||
|
@ -94,7 +94,7 @@ pub fn align_rect(rect: Rect, align: (Align, Align)) -> Rect {
|
|||
|
||||
// TODO: move show_popup, and expand its features (default size, autosize, etc)
|
||||
/// Show a pop-over window
|
||||
pub fn show_popup(ctx: &Arc<Context>, window_pos: Pos2, add_contents: impl FnOnce(&mut Region)) {
|
||||
pub fn show_popup(ctx: &Arc<Context>, window_pos: Pos2, add_contents: impl FnOnce(&mut Ui)) {
|
||||
let layer = Layer::Popup;
|
||||
let where_to_put_background = ctx.graphics().layer(layer).len();
|
||||
|
||||
|
@ -103,13 +103,13 @@ pub fn show_popup(ctx: &Arc<Context>, window_pos: Pos2, add_contents: impl FnOnc
|
|||
|
||||
let size = vec2(ctx.input().screen_size.x.min(350.0), f32::INFINITY); // TODO: popup/tooltip width
|
||||
let inner_rect = Rect::from_min_size(window_pos + window_padding, size);
|
||||
let mut contents_region = Region::new(ctx.clone(), layer, Id::popup(), inner_rect);
|
||||
let mut contents_ui = Ui::new(ctx.clone(), layer, Id::popup(), inner_rect);
|
||||
|
||||
add_contents(&mut contents_region);
|
||||
add_contents(&mut contents_ui);
|
||||
|
||||
// Now insert popup background:
|
||||
|
||||
let inner_size = contents_region.bounding_size();
|
||||
let inner_size = contents_ui.bounding_size();
|
||||
let outer_size = inner_size + 2.0 * window_padding;
|
||||
|
||||
let rect = Rect::from_min_size(window_pos, outer_size);
|
||||
|
|
|
@ -36,10 +36,10 @@ pub mod math;
|
|||
mod memory;
|
||||
pub mod mesher;
|
||||
mod movement_tracker;
|
||||
mod region;
|
||||
mod style;
|
||||
mod texture_atlas;
|
||||
mod types;
|
||||
mod ui;
|
||||
pub mod widgets;
|
||||
|
||||
pub use {
|
||||
|
@ -54,9 +54,9 @@ pub use {
|
|||
memory::Memory,
|
||||
mesher::{Mesh, PaintBatches, Vertex},
|
||||
movement_tracker::MovementTracker,
|
||||
region::Region,
|
||||
style::Style,
|
||||
texture_atlas::Texture,
|
||||
types::*,
|
||||
ui::Ui,
|
||||
widgets::Widget,
|
||||
};
|
||||
|
|
|
@ -44,7 +44,7 @@ pub struct Style {
|
|||
|
||||
// -----------------------------------------------
|
||||
// Debug rendering:
|
||||
pub debug_regions: bool,
|
||||
pub debug_uis: bool,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
|
||||
|
@ -67,7 +67,7 @@ impl Default for Style {
|
|||
animation_time: 1.0 / 20.0,
|
||||
window: Window::default(),
|
||||
clip_rect_margin: 3.0,
|
||||
debug_regions: false,
|
||||
debug_uis: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -164,33 +164,33 @@ impl Style {
|
|||
|
||||
impl Style {
|
||||
#[rustfmt::skip]
|
||||
pub fn ui(&mut self, region: &mut crate::Region) {
|
||||
pub fn ui(&mut self, ui: &mut crate::Ui) {
|
||||
use crate::{widgets::*, *};
|
||||
if region.add(Button::new("Reset style")).clicked {
|
||||
if ui.add(Button::new("Reset style")).clicked {
|
||||
*self = Default::default();
|
||||
}
|
||||
|
||||
region.add(label!("Debug:").text_style(TextStyle::Heading));
|
||||
region.add(Checkbox::new(&mut self.debug_regions, "debug_regions"));
|
||||
region.add(Separator::new());
|
||||
// TODO: region.section("Heading", |ui| ui.add(contents))
|
||||
ui.add(label!("Debug:").text_style(TextStyle::Heading));
|
||||
ui.add(Checkbox::new(&mut self.debug_uis, "debug_uis"));
|
||||
ui.add(Separator::new());
|
||||
// TODO: ui.section("Heading", |ui| ui.add(contents))
|
||||
|
||||
region.add(Slider::f32(&mut self.item_spacing.x, 0.0..=10.0).text("item_spacing.x").precision(0));
|
||||
region.add(Slider::f32(&mut self.item_spacing.y, 0.0..=10.0).text("item_spacing.y").precision(0));
|
||||
region.add(Slider::f32(&mut self.window_padding.x, 0.0..=10.0).text("window_padding.x").precision(0));
|
||||
region.add(Slider::f32(&mut self.window_padding.y, 0.0..=10.0).text("window_padding.y").precision(0));
|
||||
region.add(Slider::f32(&mut self.indent, 0.0..=100.0).text("indent").precision(0));
|
||||
region.add(Slider::f32(&mut self.button_padding.x, 0.0..=20.0).text("button_padding.x").precision(0));
|
||||
region.add(Slider::f32(&mut self.button_padding.y, 0.0..=20.0).text("button_padding.y").precision(0));
|
||||
region.add(Slider::f32(&mut self.clickable_diameter, 0.0..=60.0).text("clickable_diameter").precision(0));
|
||||
region.add(Slider::f32(&mut self.start_icon_width, 0.0..=60.0).text("start_icon_width").precision(0));
|
||||
region.add(Slider::f32(&mut self.line_width, 0.0..=10.0).text("line_width").precision(0));
|
||||
region.add(Slider::f32(&mut self.animation_time, 0.0..=1.0).text("animation_time").precision(2));
|
||||
ui.add(Slider::f32(&mut self.item_spacing.x, 0.0..=10.0).text("item_spacing.x").precision(0));
|
||||
ui.add(Slider::f32(&mut self.item_spacing.y, 0.0..=10.0).text("item_spacing.y").precision(0));
|
||||
ui.add(Slider::f32(&mut self.window_padding.x, 0.0..=10.0).text("window_padding.x").precision(0));
|
||||
ui.add(Slider::f32(&mut self.window_padding.y, 0.0..=10.0).text("window_padding.y").precision(0));
|
||||
ui.add(Slider::f32(&mut self.indent, 0.0..=100.0).text("indent").precision(0));
|
||||
ui.add(Slider::f32(&mut self.button_padding.x, 0.0..=20.0).text("button_padding.x").precision(0));
|
||||
ui.add(Slider::f32(&mut self.button_padding.y, 0.0..=20.0).text("button_padding.y").precision(0));
|
||||
ui.add(Slider::f32(&mut self.clickable_diameter, 0.0..=60.0).text("clickable_diameter").precision(0));
|
||||
ui.add(Slider::f32(&mut self.start_icon_width, 0.0..=60.0).text("start_icon_width").precision(0));
|
||||
ui.add(Slider::f32(&mut self.line_width, 0.0..=10.0).text("line_width").precision(0));
|
||||
ui.add(Slider::f32(&mut self.animation_time, 0.0..=1.0).text("animation_time").precision(2));
|
||||
|
||||
|
||||
// TODO: region.section("Heading", |ui| ui.add(contents))
|
||||
region.add(Separator::new());
|
||||
region.add(label!("Debug:").text_style(TextStyle::Heading));
|
||||
region.add(Checkbox::new(&mut self.debug_regions, "debug_regions"));
|
||||
// TODO: ui.section("Heading", |ui| ui.add(contents))
|
||||
ui.add(Separator::new());
|
||||
ui.add(label!("Debug:").text_style(TextStyle::Heading));
|
||||
ui.add(Checkbox::new(&mut self.debug_uis, "debug_uis"));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -91,19 +91,19 @@ impl TextureAtlas {
|
|||
}
|
||||
|
||||
impl Texture {
|
||||
pub fn ui(&self, region: &mut crate::Region) {
|
||||
pub fn ui(&self, ui: &mut crate::Ui) {
|
||||
use crate::{color::WHITE, label, layout::show_popup, math::*, Mesh, PaintCmd, Vertex};
|
||||
|
||||
region.add(label!(
|
||||
ui.add(label!(
|
||||
"Texture size: {} x {} (hover to zoom)",
|
||||
self.width,
|
||||
self.height
|
||||
));
|
||||
let mut size = vec2(self.width as f32, self.height as f32);
|
||||
if size.x > region.available_width() {
|
||||
size *= region.available_width() / size.x;
|
||||
if size.x > ui.available_width() {
|
||||
size *= ui.available_width() / size.x;
|
||||
}
|
||||
let interact = region.reserve_space(size, None);
|
||||
let interact = ui.reserve_space(size, None);
|
||||
let rect = interact.rect;
|
||||
let top_left = Vertex {
|
||||
pos: rect.min,
|
||||
|
@ -117,12 +117,12 @@ impl Texture {
|
|||
};
|
||||
let mut mesh = Mesh::default();
|
||||
mesh.add_rect(top_left, bottom_right);
|
||||
region.add_paint_cmd(PaintCmd::Mesh(mesh));
|
||||
ui.add_paint_cmd(PaintCmd::Mesh(mesh));
|
||||
|
||||
if let Some(mouse_pos) = region.input().mouse_pos {
|
||||
if let Some(mouse_pos) = ui.input().mouse_pos {
|
||||
if interact.hovered {
|
||||
show_popup(region.ctx(), mouse_pos, |region| {
|
||||
let zoom_rect = region.reserve_space(vec2(128.0, 128.0), None).rect;
|
||||
show_popup(ui.ctx(), mouse_pos, |ui| {
|
||||
let zoom_rect = ui.reserve_space(vec2(128.0, 128.0), None).rect;
|
||||
let u = remap_clamp(mouse_pos.x, rect.range_x(), 0.0..=self.width as f32 - 1.0)
|
||||
.round();
|
||||
let v =
|
||||
|
@ -145,7 +145,7 @@ impl Texture {
|
|||
};
|
||||
let mut mesh = Mesh::default();
|
||||
mesh.add_rect(top_left, bottom_right);
|
||||
region.add_paint_cmd(PaintCmd::Mesh(mesh));
|
||||
ui.add_paint_cmd(PaintCmd::Mesh(mesh));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,40 +4,39 @@ use crate::{color::*, containers::*, font::TextFragment, layout::*, widgets::*,
|
|||
|
||||
/// Represents a region of the screen
|
||||
/// with a type of layout (horizontal or vertical).
|
||||
/// TODO: make Region a trait so we can have type-safe `HorizontalRegion` etc?
|
||||
pub struct Region {
|
||||
pub struct Ui {
|
||||
/// How we access input, output and memory
|
||||
ctx: Arc<Context>,
|
||||
|
||||
/// ID of this region.
|
||||
/// Generated based on id of parent region together with
|
||||
/// ID of this ui.
|
||||
/// Generated based on id of parent ui together with
|
||||
/// another source of child identity (e.g. window title).
|
||||
/// Acts like a namespace for child regions.
|
||||
/// Acts like a namespace for child uis.
|
||||
/// Hopefully unique.
|
||||
id: Id,
|
||||
|
||||
/// Where to put the graphics output of this Region
|
||||
/// Where to put the graphics output of this Ui
|
||||
layer: Layer,
|
||||
|
||||
/// Everything painted in this region will be clipped against this.
|
||||
/// Everything painted in this ui will be clipped against this.
|
||||
/// This means nothing outside of this rectangle will be visible on screen.
|
||||
clip_rect: Rect,
|
||||
|
||||
/// The `rect` represents where in space the region is
|
||||
/// The `rect` represents where in screen-space the ui is
|
||||
/// and its max size (original available_space).
|
||||
/// Note that the size may be infinite in one or both dimensions.
|
||||
/// The widgets will TRY to fit within the rect,
|
||||
/// but may overflow (which you will see in child_bounds).
|
||||
/// Some widgets (like separator lines) will try to fill the full desired width of the region.
|
||||
/// Some widgets (like separator lines) will try to fill the full desired width of the ui.
|
||||
desired_rect: Rect, // TODO: rename as max_rect ?
|
||||
|
||||
/// Bounding box of all children.
|
||||
/// This is used to see how large a region actually
|
||||
/// This is used to see how large a ui actually
|
||||
/// needs to be after all children has been added.
|
||||
/// You can think of this as the minimum size.
|
||||
child_bounds: Rect, // TODO: rename as min_rect ?
|
||||
|
||||
/// Overide default style in this region
|
||||
/// Overide default style in this ui
|
||||
style: Style,
|
||||
|
||||
// Layout stuff follows. TODO: move to own type and abstract.
|
||||
|
@ -54,13 +53,13 @@ pub struct Region {
|
|||
cursor: Pos2,
|
||||
}
|
||||
|
||||
impl Region {
|
||||
impl Ui {
|
||||
// ------------------------------------------------------------------------
|
||||
// Creation:
|
||||
|
||||
pub fn new(ctx: Arc<Context>, layer: Layer, id: Id, rect: Rect) -> Self {
|
||||
let style = ctx.style();
|
||||
Region {
|
||||
Ui {
|
||||
ctx,
|
||||
id,
|
||||
layer,
|
||||
|
@ -74,12 +73,12 @@ impl Region {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn child_region(&self, child_rect: Rect) -> Self {
|
||||
pub fn child_ui(&self, child_rect: Rect) -> Self {
|
||||
// let clip_rect = self
|
||||
// .clip_rect
|
||||
// .intersect(&child_rect.expand(self.style().clip_rect_margin));
|
||||
let clip_rect = self.clip_rect(); // Keep it unless the child explciitly desires differently
|
||||
Region {
|
||||
Ui {
|
||||
ctx: self.ctx.clone(),
|
||||
layer: self.layer,
|
||||
style: self.style,
|
||||
|
@ -111,7 +110,7 @@ impl Region {
|
|||
self.id
|
||||
}
|
||||
|
||||
/// Options for this region, and any child regions we may spawn.
|
||||
/// Options for this ui, and any child uis we may spawn.
|
||||
pub fn style(&self) -> &Style {
|
||||
&self.style
|
||||
}
|
||||
|
@ -136,7 +135,7 @@ impl Region {
|
|||
self.ctx.fonts()
|
||||
}
|
||||
|
||||
/// Screen-space rectangle for clipping what we paint in this region.
|
||||
/// Screen-space rectangle for clipping what we paint in this ui.
|
||||
/// This is used, for instance, to avoid painting outside a window that is smaller
|
||||
/// than its contents.
|
||||
pub fn clip_rect(&self) -> Rect {
|
||||
|
@ -149,28 +148,28 @@ impl Region {
|
|||
|
||||
// ------------------------------------------------------------------------
|
||||
|
||||
/// Screen-space position of this Region.
|
||||
/// Screen-space position of this Ui.
|
||||
/// This may have moved from its original if a child overflowed to the left or up (rare).
|
||||
pub fn top_left(&self) -> Pos2 {
|
||||
// If a child doesn't fit in desired_rect, we have effectively expanded:
|
||||
self.desired_rect.min.min(self.child_bounds.min)
|
||||
}
|
||||
|
||||
/// Screen-space position of the current bottom right corner of this Region.
|
||||
/// Screen-space position of the current bottom right corner of this Ui.
|
||||
/// This may move when we add children that overflow our desired rectangle bounds.
|
||||
pub fn bottom_right(&self) -> Pos2 {
|
||||
// If a child doesn't fit in desired_rect, we have effectively expanded:
|
||||
self.desired_rect.max.max(self.child_bounds.max)
|
||||
}
|
||||
|
||||
/// Position and current size of the region.
|
||||
/// Position and current size of the ui.
|
||||
/// The size is the maximum of the origional (minimum/desired) size and
|
||||
/// the size of the containted children.
|
||||
pub fn rect(&self) -> Rect {
|
||||
Rect::from_min_max(self.top_left(), self.bottom_right())
|
||||
}
|
||||
|
||||
/// Set the width of the region.
|
||||
/// Set the width of the ui.
|
||||
/// You won't be able to shrink it beyond its current child bounds.
|
||||
pub fn set_desired_width(&mut self, width: f32) {
|
||||
let min_width = self.child_bounds.max.x - self.top_left().x;
|
||||
|
@ -178,7 +177,7 @@ impl Region {
|
|||
self.desired_rect.max.x = self.top_left().x + width;
|
||||
}
|
||||
|
||||
/// Set the height of the region.
|
||||
/// Set the height of the ui.
|
||||
/// You won't be able to shrink it beyond its current child bounds.
|
||||
pub fn set_desired_height(&mut self, height: f32) {
|
||||
let min_height = self.child_bounds.max.y - self.top_left().y;
|
||||
|
@ -191,7 +190,7 @@ impl Region {
|
|||
self.child_bounds.max - self.top_left()
|
||||
}
|
||||
|
||||
/// Expand the bounding rect of this region to include a child at the given rect.
|
||||
/// Expand the bounding rect of this ui to include a child at the given rect.
|
||||
pub fn expand_to_include_child(&mut self, rect: Rect) {
|
||||
self.child_bounds.extend_with(rect.min);
|
||||
self.child_bounds.extend_with(rect.max);
|
||||
|
@ -257,7 +256,7 @@ impl Region {
|
|||
|
||||
/// Will warn if the returned id is not guaranteed unique.
|
||||
/// Use this to generate widget ids for widgets that have persistent state in Memory.
|
||||
/// If the `id_source` is not unique within this region
|
||||
/// If the `id_source` is not unique within this ui
|
||||
/// then an error will be printed at the current cursor position.
|
||||
pub fn make_unique_id<IdSource>(&self, id_source: &IdSource) -> Id
|
||||
where
|
||||
|
@ -282,7 +281,7 @@ impl Region {
|
|||
// ------------------------------------------------------------------------
|
||||
// Interaction
|
||||
|
||||
/// Check for clicks on this entire region (rect())
|
||||
/// Check for clicks on this entire ui (rect())
|
||||
pub fn interact_whole(&self) -> InteractInfo {
|
||||
self.interact_rect(self.rect(), self.id)
|
||||
}
|
||||
|
@ -304,7 +303,7 @@ impl Region {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Stuff that moves the cursor, i.e. allocates space in this region!
|
||||
// Stuff that moves the cursor, i.e. allocates space in this ui!
|
||||
|
||||
/// Reserve this much space and move the cursor.
|
||||
/// Returns where to put the widget.
|
||||
|
@ -324,7 +323,7 @@ impl Region {
|
|||
let child_pos = self.reserve_space_impl(child_size);
|
||||
let rect = Rect::from_min_size(child_pos, child_size);
|
||||
|
||||
if self.style().debug_regions {
|
||||
if self.style().debug_uis {
|
||||
self.add_paint_cmd(PaintCmd::Rect {
|
||||
rect,
|
||||
corner_radius: 0.0,
|
||||
|
@ -446,7 +445,7 @@ impl Region {
|
|||
self.ctx.debug_text(pos, text);
|
||||
}
|
||||
|
||||
/// Show some text anywhere in the region.
|
||||
/// Show some text anywhere in the ui.
|
||||
/// To center the text at the given position, use `align: (Center, Center)`.
|
||||
/// If you want to draw text floating on top of everything,
|
||||
/// consider using `Context.floating_text` instead.
|
||||
|
@ -503,38 +502,38 @@ impl Region {
|
|||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
// Addding Containers / Sub-Regions:
|
||||
// Addding Containers / Sub-uis:
|
||||
|
||||
pub fn collapsing(
|
||||
&mut self,
|
||||
text: impl Into<String>,
|
||||
add_contents: impl FnOnce(&mut Region),
|
||||
add_contents: impl FnOnce(&mut Ui),
|
||||
) -> GuiResponse {
|
||||
CollapsingHeader::new(text).show(self, add_contents)
|
||||
}
|
||||
|
||||
/// Create a child region at the current cursor.
|
||||
/// Create a child ui at the current cursor.
|
||||
/// `size` is the desired size.
|
||||
/// Actual size may be much smaller if `avilable_size()` is not enough.
|
||||
/// Set `size` to `Vec::infinity()` to get as much space as possible.
|
||||
/// 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 region.
|
||||
pub fn add_custom_contents(&mut self, size: Vec2, add_contents: impl FnOnce(&mut Region)) {
|
||||
/// 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)) {
|
||||
let size = size.min(self.available_space());
|
||||
let child_rect = Rect::from_min_size(self.cursor, size);
|
||||
let mut child_region = Region {
|
||||
..self.child_region(child_rect)
|
||||
let mut child_ui = Ui {
|
||||
..self.child_ui(child_rect)
|
||||
};
|
||||
add_contents(&mut child_region);
|
||||
self.reserve_space(child_region.bounding_size(), None);
|
||||
add_contents(&mut child_ui);
|
||||
self.reserve_space(child_ui.bounding_size(), None);
|
||||
}
|
||||
|
||||
/// Create a child region which is indented to the right
|
||||
/// Create a child ui which is indented to the right
|
||||
pub fn indent(
|
||||
&mut self,
|
||||
id_source: impl Hash,
|
||||
add_contents: impl FnOnce(&mut Region),
|
||||
add_contents: impl FnOnce(&mut Ui),
|
||||
) -> InteractInfo {
|
||||
assert!(
|
||||
self.dir == Direction::Vertical,
|
||||
|
@ -542,15 +541,15 @@ impl Region {
|
|||
);
|
||||
let indent = vec2(self.style.indent, 0.0);
|
||||
let child_rect = Rect::from_min_max(self.cursor + indent, self.bottom_right());
|
||||
let mut child_region = Region {
|
||||
let mut child_ui = Ui {
|
||||
id: self.id.with(id_source),
|
||||
align: Align::Min,
|
||||
..self.child_region(child_rect)
|
||||
..self.child_ui(child_rect)
|
||||
};
|
||||
add_contents(&mut child_region);
|
||||
let size = child_region.bounding_size();
|
||||
add_contents(&mut child_ui);
|
||||
let size = child_ui.bounding_size();
|
||||
|
||||
// draw a grey line on the left to mark the region
|
||||
// draw a grey line on the left to mark the indented section
|
||||
let line_start = child_rect.min - indent * 0.5;
|
||||
let line_start = line_start.round(); // TODO: round to pixel instead
|
||||
let line_end = pos2(line_start.x, line_start.y + size.y - 8.0);
|
||||
|
@ -563,38 +562,38 @@ impl Region {
|
|||
self.reserve_space(indent + size, None)
|
||||
}
|
||||
|
||||
pub fn left_column(&mut self, width: f32) -> Region {
|
||||
pub fn left_column(&mut self, width: f32) -> Ui {
|
||||
self.column(Align::Min, width)
|
||||
}
|
||||
|
||||
pub fn centered_column(&mut self, width: f32) -> Region {
|
||||
pub fn centered_column(&mut self, width: f32) -> Ui {
|
||||
self.column(Align::Center, width)
|
||||
}
|
||||
|
||||
pub fn right_column(&mut self, width: f32) -> Region {
|
||||
pub fn right_column(&mut self, width: f32) -> Ui {
|
||||
self.column(Align::Max, width)
|
||||
}
|
||||
|
||||
/// A column region with a given width.
|
||||
pub fn column(&mut self, column_position: Align, width: f32) -> Region {
|
||||
/// A column ui with a given width.
|
||||
pub fn column(&mut self, column_position: Align, width: f32) -> Ui {
|
||||
let x = match column_position {
|
||||
Align::Min => 0.0,
|
||||
Align::Center => self.available_width() / 2.0 - width / 2.0,
|
||||
Align::Max => self.available_width() - width,
|
||||
};
|
||||
self.child_region(Rect::from_min_size(
|
||||
self.child_ui(Rect::from_min_size(
|
||||
self.cursor + vec2(x, 0.0),
|
||||
vec2(width, self.available_height()),
|
||||
))
|
||||
}
|
||||
|
||||
/// Start a region with horizontal layout
|
||||
pub fn horizontal(&mut self, add_contents: impl FnOnce(&mut Region)) {
|
||||
/// Start a ui with horizontal layout
|
||||
pub fn horizontal(&mut self, add_contents: impl FnOnce(&mut Ui)) {
|
||||
self.inner_layout(Direction::Horizontal, Align::Min, add_contents)
|
||||
}
|
||||
|
||||
/// Start a region with vertical layout
|
||||
pub fn vertical(&mut self, add_contents: impl FnOnce(&mut Region)) {
|
||||
/// Start a ui with vertical layout
|
||||
pub fn vertical(&mut self, add_contents: impl FnOnce(&mut Ui)) {
|
||||
self.inner_layout(Direction::Vertical, Align::Min, add_contents)
|
||||
}
|
||||
|
||||
|
@ -605,20 +604,20 @@ impl Region {
|
|||
add_contents: impl FnOnce(&mut Self),
|
||||
) {
|
||||
let child_rect = Rect::from_min_max(self.cursor, self.bottom_right());
|
||||
let mut child_region = Self {
|
||||
let mut child_ui = Self {
|
||||
dir,
|
||||
align,
|
||||
..self.child_region(child_rect)
|
||||
..self.child_ui(child_rect)
|
||||
};
|
||||
add_contents(&mut child_region);
|
||||
let size = child_region.bounding_size();
|
||||
add_contents(&mut child_ui);
|
||||
let size = child_ui.bounding_size();
|
||||
self.reserve_space(size, None);
|
||||
}
|
||||
|
||||
/// Temporarily split split a vertical layout into several columns.
|
||||
///
|
||||
/// ``` ignore
|
||||
/// region.columns(2, |columns| {
|
||||
/// ui.columns(2, |columns| {
|
||||
/// columns[0].add(emigui::widgets::label!("First column"));
|
||||
/// columns[1].add(emigui::widgets::label!("Second column"));
|
||||
/// });
|
||||
|
@ -641,7 +640,7 @@ impl Region {
|
|||
Self {
|
||||
id: self.make_child_id(&("column", col_idx)),
|
||||
dir: Direction::Vertical,
|
||||
..self.child_region(child_rect)
|
||||
..self.child_ui(child_rect)
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
@ -654,8 +653,8 @@ impl Region {
|
|||
}
|
||||
|
||||
let mut max_height = 0.0;
|
||||
for region in columns {
|
||||
let size = region.bounding_size();
|
||||
for ui in columns {
|
||||
let size = ui.bounding_size();
|
||||
max_height = size.y.max(max_height);
|
||||
}
|
||||
|
|
@ -12,9 +12,9 @@ pub use {slider::*, text_edit::*};
|
|||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
||||
/// Anything implementing Widget can be added to a Region with `Region::add`
|
||||
/// Anything implementing Widget can be added to a Ui with `Ui::add`
|
||||
pub trait Widget {
|
||||
fn ui(self, region: &mut Region) -> GuiResponse;
|
||||
fn ui(self, ui: &mut Ui) -> GuiResponse;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------
|
||||
|
@ -23,7 +23,7 @@ pub struct Label {
|
|||
// TODO: not pub
|
||||
pub(crate) text: String,
|
||||
pub(crate) multiline: bool,
|
||||
pub(crate) text_style: TextStyle, // TODO: Option<TextStyle>, where None means "use the default for the region"
|
||||
pub(crate) text_style: TextStyle, // TODO: Option<TextStyle>, where None means "use the default for the ui"
|
||||
pub(crate) text_color: Option<Color>,
|
||||
}
|
||||
|
||||
|
@ -52,9 +52,9 @@ impl Label {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn layout(&self, pos: Pos2, region: &Region) -> (Vec<font::TextFragment>, Vec2) {
|
||||
let font = ®ion.fonts()[self.text_style];
|
||||
let max_width = region.rect().right() - pos.x;
|
||||
pub fn layout(&self, pos: Pos2, ui: &Ui) -> (Vec<font::TextFragment>, Vec2) {
|
||||
let font = &ui.fonts()[self.text_style];
|
||||
let max_width = ui.rect().right() - pos.x;
|
||||
if self.multiline {
|
||||
font.layout_multiline(&self.text, max_width)
|
||||
} else {
|
||||
|
@ -65,9 +65,9 @@ impl Label {
|
|||
// 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.
|
||||
// pub fn layout(self, region: &mut region) -> LabelLayout { }
|
||||
// pub fn layout(self, ui: &mut ui) -> LabelLayout { }
|
||||
|
||||
// TODO: a paint method for painting anywhere in a region.
|
||||
// TODO: a paint method for painting anywhere in a ui.
|
||||
// This should be the easiest method of putting text anywhere.
|
||||
}
|
||||
|
||||
|
@ -79,11 +79,11 @@ macro_rules! label {
|
|||
}
|
||||
|
||||
impl Widget for Label {
|
||||
fn ui(self, region: &mut Region) -> GuiResponse {
|
||||
let (text, text_size) = self.layout(region.cursor(), region);
|
||||
let interact = region.reserve_space(text_size, None);
|
||||
region.add_text(interact.rect.min, self.text_style, text, self.text_color);
|
||||
region.response(interact)
|
||||
fn ui(self, ui: &mut Ui) -> GuiResponse {
|
||||
let (text, text_size) = self.layout(ui.cursor(), ui);
|
||||
let interact = ui.reserve_space(text_size, None);
|
||||
ui.add_text(interact.rect.min, self.text_style, text, self.text_color);
|
||||
ui.response(interact)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -117,20 +117,20 @@ impl Hyperlink {
|
|||
}
|
||||
|
||||
impl Widget for Hyperlink {
|
||||
fn ui(self, region: &mut Region) -> GuiResponse {
|
||||
fn ui(self, ui: &mut Ui) -> GuiResponse {
|
||||
let color = color::LIGHT_BLUE;
|
||||
let text_style = TextStyle::Body;
|
||||
let id = region.make_child_id(&self.url);
|
||||
let font = ®ion.fonts()[text_style];
|
||||
let id = ui.make_child_id(&self.url);
|
||||
let font = &ui.fonts()[text_style];
|
||||
let line_spacing = font.line_spacing();
|
||||
// TODO: underline
|
||||
let (text, text_size) = font.layout_multiline(&self.text, region.available_width());
|
||||
let interact = region.reserve_space(text_size, Some(id));
|
||||
let (text, text_size) = font.layout_multiline(&self.text, ui.available_width());
|
||||
let interact = ui.reserve_space(text_size, Some(id));
|
||||
if interact.hovered {
|
||||
region.ctx().output().cursor_icon = CursorIcon::PointingHand;
|
||||
ui.ctx().output().cursor_icon = CursorIcon::PointingHand;
|
||||
}
|
||||
if interact.clicked {
|
||||
region.ctx().output().open_url = Some(self.url);
|
||||
ui.ctx().output().open_url = Some(self.url);
|
||||
}
|
||||
|
||||
if interact.hovered {
|
||||
|
@ -138,20 +138,20 @@ impl Widget for Hyperlink {
|
|||
for fragment in &text {
|
||||
let pos = interact.rect.min;
|
||||
let y = pos.y + fragment.y_offset + line_spacing;
|
||||
let y = region.round_to_pixel(y);
|
||||
let y = ui.round_to_pixel(y);
|
||||
let min_x = pos.x + fragment.min_x();
|
||||
let max_x = pos.x + fragment.max_x();
|
||||
region.add_paint_cmd(PaintCmd::Line {
|
||||
ui.add_paint_cmd(PaintCmd::Line {
|
||||
points: vec![pos2(min_x, y), pos2(max_x, y)],
|
||||
color,
|
||||
width: region.style().line_width,
|
||||
width: ui.style().line_width,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
region.add_text(interact.rect.min, text_style, text, Some(color));
|
||||
ui.add_text(interact.rect.min, text_style, text, Some(color));
|
||||
|
||||
region.response(interact)
|
||||
ui.response(interact)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -177,27 +177,27 @@ impl Button {
|
|||
}
|
||||
|
||||
impl Widget for Button {
|
||||
fn ui(self, region: &mut Region) -> GuiResponse {
|
||||
let id = region.make_position_id();
|
||||
fn ui(self, ui: &mut Ui) -> GuiResponse {
|
||||
let id = ui.make_position_id();
|
||||
let text_style = TextStyle::Button;
|
||||
let font = ®ion.fonts()[text_style];
|
||||
let (text, text_size) = font.layout_multiline(&self.text, region.available_width());
|
||||
let padding = region.style().button_padding;
|
||||
let font = &ui.fonts()[text_style];
|
||||
let (text, text_size) = font.layout_multiline(&self.text, ui.available_width());
|
||||
let padding = ui.style().button_padding;
|
||||
let mut size = text_size + 2.0 * padding;
|
||||
size.y = size.y.max(region.style().clickable_diameter);
|
||||
let interact = region.reserve_space(size, Some(id));
|
||||
size.y = size.y.max(ui.style().clickable_diameter);
|
||||
let interact = ui.reserve_space(size, Some(id));
|
||||
let mut text_cursor = interact.rect.left_center() + vec2(padding.x, -0.5 * text_size.y);
|
||||
text_cursor.y += 2.0; // TODO: why is this needed?
|
||||
region.add_paint_cmd(PaintCmd::Rect {
|
||||
corner_radius: region.style().interact_corner_radius(&interact),
|
||||
fill_color: region.style().interact_fill_color(&interact),
|
||||
outline: region.style().interact_outline(&interact),
|
||||
ui.add_paint_cmd(PaintCmd::Rect {
|
||||
corner_radius: ui.style().interact_corner_radius(&interact),
|
||||
fill_color: ui.style().interact_fill_color(&interact),
|
||||
outline: ui.style().interact_outline(&interact),
|
||||
rect: interact.rect,
|
||||
});
|
||||
let stroke_color = region.style().interact_stroke_color(&interact);
|
||||
let stroke_color = ui.style().interact_stroke_color(&interact);
|
||||
let text_color = self.text_color.unwrap_or(stroke_color);
|
||||
region.add_text(text_cursor, text_style, text, Some(text_color));
|
||||
region.response(interact)
|
||||
ui.add_text(text_cursor, text_style, text, Some(text_color));
|
||||
ui.response(interact)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -226,49 +226,48 @@ impl<'a> Checkbox<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Widget for Checkbox<'a> {
|
||||
fn ui(self, region: &mut Region) -> GuiResponse {
|
||||
let id = region.make_position_id();
|
||||
fn ui(self, ui: &mut Ui) -> GuiResponse {
|
||||
let id = ui.make_position_id();
|
||||
let text_style = TextStyle::Button;
|
||||
let font = ®ion.fonts()[text_style];
|
||||
let (text, text_size) = font.layout_multiline(&self.text, region.available_width());
|
||||
let interact = region.reserve_space(
|
||||
region.style().button_padding
|
||||
+ vec2(region.style().start_icon_width, 0.0)
|
||||
let font = &ui.fonts()[text_style];
|
||||
let (text, text_size) = font.layout_multiline(&self.text, ui.available_width());
|
||||
let interact = ui.reserve_space(
|
||||
ui.style().button_padding
|
||||
+ vec2(ui.style().start_icon_width, 0.0)
|
||||
+ text_size
|
||||
+ region.style().button_padding,
|
||||
+ ui.style().button_padding,
|
||||
Some(id),
|
||||
);
|
||||
let text_cursor = interact.rect.min
|
||||
+ region.style().button_padding
|
||||
+ vec2(region.style().start_icon_width, 0.0);
|
||||
let text_cursor =
|
||||
interact.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0);
|
||||
if interact.clicked {
|
||||
*self.checked = !*self.checked;
|
||||
}
|
||||
let (small_icon_rect, big_icon_rect) = region.style().icon_rectangles(interact.rect);
|
||||
region.add_paint_cmd(PaintCmd::Rect {
|
||||
let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect);
|
||||
ui.add_paint_cmd(PaintCmd::Rect {
|
||||
corner_radius: 3.0,
|
||||
fill_color: region.style().interact_fill_color(&interact),
|
||||
fill_color: ui.style().interact_fill_color(&interact),
|
||||
outline: None,
|
||||
rect: big_icon_rect,
|
||||
});
|
||||
|
||||
let stroke_color = region.style().interact_stroke_color(&interact);
|
||||
let stroke_color = ui.style().interact_stroke_color(&interact);
|
||||
|
||||
if *self.checked {
|
||||
region.add_paint_cmd(PaintCmd::Line {
|
||||
ui.add_paint_cmd(PaintCmd::Line {
|
||||
points: vec![
|
||||
pos2(small_icon_rect.left(), small_icon_rect.center().y),
|
||||
pos2(small_icon_rect.center().x, small_icon_rect.bottom()),
|
||||
pos2(small_icon_rect.right(), small_icon_rect.top()),
|
||||
],
|
||||
color: stroke_color,
|
||||
width: region.style().line_width,
|
||||
width: ui.style().line_width,
|
||||
});
|
||||
}
|
||||
|
||||
let text_color = self.text_color.unwrap_or(stroke_color);
|
||||
region.add_text(text_cursor, text_style, text, Some(text_color));
|
||||
region.response(interact)
|
||||
ui.add_text(text_cursor, text_style, text, Some(text_color));
|
||||
ui.response(interact)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -301,28 +300,27 @@ pub fn radio(checked: bool, text: impl Into<String>) -> RadioButton {
|
|||
}
|
||||
|
||||
impl Widget for RadioButton {
|
||||
fn ui(self, region: &mut Region) -> GuiResponse {
|
||||
let id = region.make_position_id();
|
||||
fn ui(self, ui: &mut Ui) -> GuiResponse {
|
||||
let id = ui.make_position_id();
|
||||
let text_style = TextStyle::Button;
|
||||
let font = ®ion.fonts()[text_style];
|
||||
let (text, text_size) = font.layout_multiline(&self.text, region.available_width());
|
||||
let interact = region.reserve_space(
|
||||
region.style().button_padding
|
||||
+ vec2(region.style().start_icon_width, 0.0)
|
||||
let font = &ui.fonts()[text_style];
|
||||
let (text, text_size) = font.layout_multiline(&self.text, ui.available_width());
|
||||
let interact = ui.reserve_space(
|
||||
ui.style().button_padding
|
||||
+ vec2(ui.style().start_icon_width, 0.0)
|
||||
+ text_size
|
||||
+ region.style().button_padding,
|
||||
+ ui.style().button_padding,
|
||||
Some(id),
|
||||
);
|
||||
let text_cursor = interact.rect.min
|
||||
+ region.style().button_padding
|
||||
+ vec2(region.style().start_icon_width, 0.0);
|
||||
let text_cursor =
|
||||
interact.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0);
|
||||
|
||||
let fill_color = region.style().interact_fill_color(&interact);
|
||||
let stroke_color = region.style().interact_stroke_color(&interact);
|
||||
let fill_color = ui.style().interact_fill_color(&interact);
|
||||
let stroke_color = ui.style().interact_stroke_color(&interact);
|
||||
|
||||
let (small_icon_rect, big_icon_rect) = region.style().icon_rectangles(interact.rect);
|
||||
let (small_icon_rect, big_icon_rect) = ui.style().icon_rectangles(interact.rect);
|
||||
|
||||
region.add_paint_cmd(PaintCmd::Circle {
|
||||
ui.add_paint_cmd(PaintCmd::Circle {
|
||||
center: big_icon_rect.center(),
|
||||
fill_color,
|
||||
outline: None,
|
||||
|
@ -330,7 +328,7 @@ impl Widget for RadioButton {
|
|||
});
|
||||
|
||||
if self.checked {
|
||||
region.add_paint_cmd(PaintCmd::Circle {
|
||||
ui.add_paint_cmd(PaintCmd::Circle {
|
||||
center: small_icon_rect.center(),
|
||||
fill_color: Some(stroke_color),
|
||||
outline: None,
|
||||
|
@ -339,8 +337,8 @@ impl Widget for RadioButton {
|
|||
}
|
||||
|
||||
let text_color = self.text_color.unwrap_or(stroke_color);
|
||||
region.add_text(text_cursor, text_style, text, Some(text_color));
|
||||
region.response(interact)
|
||||
ui.add_text(text_cursor, text_style, text, Some(text_color));
|
||||
ui.response(interact)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -386,13 +384,12 @@ impl Separator {
|
|||
}
|
||||
|
||||
impl Widget for Separator {
|
||||
fn ui(self, region: &mut Region) -> GuiResponse {
|
||||
let available_space = region.available_space();
|
||||
fn ui(self, ui: &mut Ui) -> GuiResponse {
|
||||
let available_space = ui.available_space();
|
||||
let extra = self.extra;
|
||||
let (points, interact) = match region.direction() {
|
||||
let (points, interact) = match ui.direction() {
|
||||
Direction::Horizontal => {
|
||||
let interact =
|
||||
region.reserve_space(vec2(self.min_spacing, available_space.y), None);
|
||||
let interact = ui.reserve_space(vec2(self.min_spacing, available_space.y), None);
|
||||
(
|
||||
vec![
|
||||
pos2(interact.rect.center().x, interact.rect.top() - extra),
|
||||
|
@ -402,8 +399,7 @@ impl Widget for Separator {
|
|||
)
|
||||
}
|
||||
Direction::Vertical => {
|
||||
let interact =
|
||||
region.reserve_space(vec2(available_space.x, self.min_spacing), None);
|
||||
let interact = ui.reserve_space(vec2(available_space.x, self.min_spacing), None);
|
||||
(
|
||||
vec![
|
||||
pos2(interact.rect.left() - extra, interact.rect.center().y),
|
||||
|
@ -413,11 +409,11 @@ impl Widget for Separator {
|
|||
)
|
||||
}
|
||||
};
|
||||
region.add_paint_cmd(PaintCmd::Line {
|
||||
ui.add_paint_cmd(PaintCmd::Line {
|
||||
points,
|
||||
color: self.color,
|
||||
width: self.line_width,
|
||||
});
|
||||
region.response(interact)
|
||||
ui.response(interact)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,9 +99,9 @@ impl<'a> Slider<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Widget for Slider<'a> {
|
||||
fn ui(mut self, region: &mut Region) -> GuiResponse {
|
||||
fn ui(mut self, ui: &mut Ui) -> GuiResponse {
|
||||
let text_style = TextStyle::Button;
|
||||
let font = ®ion.fonts()[text_style];
|
||||
let font = &ui.fonts()[text_style];
|
||||
|
||||
if let Some(text) = &self.text {
|
||||
if self.id.is_none() {
|
||||
|
@ -116,35 +116,35 @@ impl<'a> Widget for Slider<'a> {
|
|||
let slider_sans_text = Slider { text: None, ..self };
|
||||
|
||||
if text_on_top {
|
||||
// let (text, text_size) = font.layout_multiline(&full_text, region.available_width());
|
||||
// let (text, text_size) = font.layout_multiline(&full_text, ui.available_width());
|
||||
let (text, text_size) = font.layout_single_line(&full_text);
|
||||
let pos = region.reserve_space(text_size, None).rect.min;
|
||||
region.add_text(pos, text_style, text, text_color);
|
||||
slider_sans_text.ui(region)
|
||||
let pos = ui.reserve_space(text_size, None).rect.min;
|
||||
ui.add_text(pos, text_style, text, text_color);
|
||||
slider_sans_text.ui(ui)
|
||||
} else {
|
||||
region.columns(2, |columns| {
|
||||
ui.columns(2, |columns| {
|
||||
// Slider on the left:
|
||||
let slider_response = columns[0].add(slider_sans_text);
|
||||
|
||||
// Place the text in line with the slider on the left:
|
||||
columns[1].set_desired_height(slider_response.rect.height());
|
||||
columns[1].horizontal(|region| {
|
||||
region.set_align(Align::Center);
|
||||
region.add(Label::new(full_text).multiline(false));
|
||||
columns[1].horizontal(|ui| {
|
||||
ui.set_align(Align::Center);
|
||||
ui.add(Label::new(full_text).multiline(false));
|
||||
});
|
||||
|
||||
slider_response
|
||||
})
|
||||
}
|
||||
} else {
|
||||
let height = font.line_spacing().max(region.style().clickable_diameter);
|
||||
let height = font.line_spacing().max(ui.style().clickable_diameter);
|
||||
let handle_radius = height / 2.5;
|
||||
|
||||
let id = self.id.unwrap_or_else(|| region.make_position_id());
|
||||
let id = self.id.unwrap_or_else(|| ui.make_position_id());
|
||||
|
||||
let interact = region.reserve_space(
|
||||
let interact = ui.reserve_space(
|
||||
Vec2 {
|
||||
x: region.available_width(),
|
||||
x: ui.available_width(),
|
||||
y: height,
|
||||
},
|
||||
Some(id),
|
||||
|
@ -156,7 +156,7 @@ impl<'a> Widget for Slider<'a> {
|
|||
let range = self.range.clone();
|
||||
debug_assert!(range.start() <= range.end());
|
||||
|
||||
if let Some(mouse_pos) = region.input().mouse_pos {
|
||||
if let Some(mouse_pos) = ui.input().mouse_pos {
|
||||
if interact.active {
|
||||
self.set_value_f32(remap_clamp(mouse_pos.x, left..=right, range.clone()));
|
||||
}
|
||||
|
@ -167,32 +167,32 @@ impl<'a> Widget for Slider<'a> {
|
|||
let value = self.get_value_f32();
|
||||
|
||||
let rect = interact.rect;
|
||||
let rail_radius = region.round_to_pixel((height / 8.0).max(2.0));
|
||||
let rail_radius = ui.round_to_pixel((height / 8.0).max(2.0));
|
||||
let rail_rect = Rect::from_min_max(
|
||||
pos2(interact.rect.left(), rect.center().y - rail_radius),
|
||||
pos2(interact.rect.right(), rect.center().y + rail_radius),
|
||||
);
|
||||
let marker_center_x = remap_clamp(value, range, left..=right);
|
||||
|
||||
region.add_paint_cmd(PaintCmd::Rect {
|
||||
ui.add_paint_cmd(PaintCmd::Rect {
|
||||
rect: rail_rect,
|
||||
corner_radius: rail_radius,
|
||||
fill_color: Some(region.style().background_fill_color()),
|
||||
fill_color: Some(ui.style().background_fill_color()),
|
||||
outline: Some(Outline::new(1.0, color::gray(200, 255))), // TODO
|
||||
});
|
||||
|
||||
region.add_paint_cmd(PaintCmd::Circle {
|
||||
ui.add_paint_cmd(PaintCmd::Circle {
|
||||
center: pos2(marker_center_x, rail_rect.center().y),
|
||||
radius: handle_radius,
|
||||
fill_color: region.style().interact_fill_color(&interact),
|
||||
fill_color: ui.style().interact_fill_color(&interact),
|
||||
outline: Some(Outline::new(
|
||||
region.style().interact_stroke_width(&interact),
|
||||
region.style().interact_stroke_color(&interact),
|
||||
ui.style().interact_stroke_width(&interact),
|
||||
ui.style().interact_stroke_color(&interact),
|
||||
)),
|
||||
});
|
||||
}
|
||||
|
||||
region.response(interact)
|
||||
ui.response(interact)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,7 +4,7 @@ use crate::*;
|
|||
pub struct TextEdit<'t> {
|
||||
text: &'t mut String,
|
||||
id: Option<Id>,
|
||||
text_style: TextStyle, // TODO: Option<TextStyle>, where None means "use the default for the region"
|
||||
text_style: TextStyle, // TODO: Option<TextStyle>, where None means "use the default for the current Ui"
|
||||
text_color: Option<Color>,
|
||||
}
|
||||
|
||||
|
@ -35,29 +35,29 @@ impl<'t> TextEdit<'t> {
|
|||
}
|
||||
|
||||
impl<'t> Widget for TextEdit<'t> {
|
||||
fn ui(self, region: &mut Region) -> GuiResponse {
|
||||
let id = region.make_child_id(self.id);
|
||||
fn ui(self, ui: &mut Ui) -> GuiResponse {
|
||||
let id = ui.make_child_id(self.id);
|
||||
|
||||
let font = ®ion.fonts()[self.text_style];
|
||||
let font = &ui.fonts()[self.text_style];
|
||||
let line_spacing = font.line_spacing();
|
||||
let (text, text_size) = font.layout_multiline(self.text.as_str(), region.available_width());
|
||||
let desired_size = text_size.max(vec2(region.available_width(), line_spacing));
|
||||
let interact = region.reserve_space(desired_size, Some(id));
|
||||
let (text, text_size) = font.layout_multiline(self.text.as_str(), ui.available_width());
|
||||
let desired_size = text_size.max(vec2(ui.available_width(), line_spacing));
|
||||
let interact = ui.reserve_space(desired_size, Some(id));
|
||||
|
||||
if interact.clicked {
|
||||
region.request_kb_focus(id);
|
||||
ui.request_kb_focus(id);
|
||||
}
|
||||
if interact.hovered {
|
||||
region.output().cursor_icon = CursorIcon::Text;
|
||||
ui.output().cursor_icon = CursorIcon::Text;
|
||||
}
|
||||
let has_kb_focus = region.has_kb_focus(id);
|
||||
let has_kb_focus = ui.has_kb_focus(id);
|
||||
|
||||
if has_kb_focus {
|
||||
for event in ®ion.input().events {
|
||||
for event in &ui.input().events {
|
||||
match event {
|
||||
Event::Copy | Event::Cut => {
|
||||
// TODO: cut
|
||||
region.ctx().output().copied_text = self.text.clone();
|
||||
ui.ctx().output().copied_text = self.text.clone();
|
||||
}
|
||||
Event::Text(text) => {
|
||||
if text == "\u{7f}" {
|
||||
|
@ -76,35 +76,35 @@ impl<'t> Widget for TextEdit<'t> {
|
|||
}
|
||||
}
|
||||
|
||||
region.add_paint_cmd(PaintCmd::Rect {
|
||||
ui.add_paint_cmd(PaintCmd::Rect {
|
||||
rect: interact.rect,
|
||||
corner_radius: 0.0,
|
||||
// fill_color: Some(color::BLACK),
|
||||
fill_color: region.style().interact_fill_color(&interact),
|
||||
// fill_color: Some(region.style().background_fill_color()),
|
||||
fill_color: ui.style().interact_fill_color(&interact),
|
||||
// fill_color: Some(ui.style().background_fill_color()),
|
||||
outline: None, //Some(Outline::new(1.0, color::WHITE)),
|
||||
});
|
||||
|
||||
if has_kb_focus {
|
||||
let cursor_blink_hz = region.style().cursor_blink_hz;
|
||||
let cursor_blink_hz = ui.style().cursor_blink_hz;
|
||||
let show_cursor =
|
||||
(region.input().time * cursor_blink_hz as f64 * 3.0).floor() as i64 % 3 != 0;
|
||||
(ui.input().time * cursor_blink_hz as f64 * 3.0).floor() as i64 % 3 != 0;
|
||||
if show_cursor {
|
||||
let cursor_pos = if let Some(last) = text.last() {
|
||||
interact.rect.min + vec2(last.max_x(), last.y_offset)
|
||||
} else {
|
||||
interact.rect.min
|
||||
};
|
||||
region.add_paint_cmd(PaintCmd::line_segment(
|
||||
ui.add_paint_cmd(PaintCmd::line_segment(
|
||||
(cursor_pos, cursor_pos + vec2(0.0, line_spacing)),
|
||||
color::WHITE,
|
||||
region.style().text_cursor_width,
|
||||
ui.style().text_cursor_width,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
region.add_text(interact.rect.min, self.text_style, text, self.text_color);
|
||||
ui.add_text(interact.rect.min, self.text_style, text, self.text_color);
|
||||
|
||||
region.response(interact)
|
||||
ui.response(interact)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -68,22 +68,22 @@ fn main() {
|
|||
|
||||
let emigui_start = Instant::now();
|
||||
ctx.begin_frame(raw_input.clone()); // TODO: avoid clone
|
||||
let mut region = ctx.background_region();
|
||||
let mut region = region.centered_column(region.available_width().min(480.0));
|
||||
region.set_align(Align::Min);
|
||||
region.add(label!("Emigui running inside of Glium").text_style(emigui::TextStyle::Heading));
|
||||
if region.add(Button::new("Quit")).clicked {
|
||||
let mut ui = ctx.fullscreen_ui();
|
||||
let mut ui = ui.centered_column(ui.available_width().min(480.0));
|
||||
ui.set_align(Align::Min);
|
||||
ui.add(label!("Emigui running inside of Glium").text_style(emigui::TextStyle::Heading));
|
||||
if ui.add(Button::new("Quit")).clicked {
|
||||
running = false;
|
||||
}
|
||||
|
||||
region.add(
|
||||
ui.add(
|
||||
label!(
|
||||
"CPU usage: {:.2} ms (excludes painting)",
|
||||
1e3 * frame_times.average().unwrap_or_default()
|
||||
)
|
||||
.text_style(TextStyle::Monospace),
|
||||
);
|
||||
region.add(
|
||||
ui.add(
|
||||
label!(
|
||||
"FPS: {:.1}",
|
||||
1.0 / frame_times.mean_time_interval().unwrap_or_default()
|
||||
|
@ -98,15 +98,15 @@ fn main() {
|
|||
.default_size(vec2(300.0, 600.0))
|
||||
// .mutate(|w| w.resize = w.resize.auto_expand_width(true))
|
||||
// .resize(|r| r.auto_expand_width(true))
|
||||
.show(region.ctx(), |region| {
|
||||
example_app.ui(region);
|
||||
.show(ui.ctx(), |ui| {
|
||||
example_app.ui(ui);
|
||||
});
|
||||
|
||||
Window::new("Emigui settings")
|
||||
.default_pos(pos2(450.0, 100.0))
|
||||
.default_size(vec2(450.0, 500.0))
|
||||
.show(region.ctx(), |region| {
|
||||
ctx.ui(region);
|
||||
.show(ui.ctx(), |ui| {
|
||||
ctx.ui(ui);
|
||||
});
|
||||
|
||||
let (output, paint_batches) = ctx.end_frame();
|
||||
|
|
|
@ -38,36 +38,36 @@ impl State {
|
|||
let pixels_per_point = raw_input.pixels_per_point;
|
||||
self.ctx.begin_frame(raw_input);
|
||||
|
||||
let mut region = self.ctx.background_region();
|
||||
let mut region = region.centered_column(region.available_width().min(480.0));
|
||||
region.set_align(Align::Min);
|
||||
region.add(label!("Emigui!").text_style(TextStyle::Heading));
|
||||
region.add_label("Emigui is an immediate mode GUI written in Rust, compiled to WebAssembly, rendered with WebGL.");
|
||||
region.add_label(
|
||||
let mut ui = self.ctx.fullscreen_ui();
|
||||
let mut ui = ui.centered_column(ui.available_width().min(480.0));
|
||||
ui.set_align(Align::Min);
|
||||
ui.add(label!("Emigui!").text_style(TextStyle::Heading));
|
||||
ui.add_label("Emigui is an immediate mode GUI written in Rust, compiled to WebAssembly, rendered with WebGL.");
|
||||
ui.add_label(
|
||||
"Everything you see is rendered as textured triangles. There is no DOM. There are no HTML elements."
|
||||
);
|
||||
region.add_label("This is not JavaScript. This is Rust, running at 60 FPS. This is the web page, reinvented with game tech.");
|
||||
region.add_label("This is also work in progress, and not ready for production... yet :)");
|
||||
region.horizontal(|region| {
|
||||
region.add_label("Project home page:");
|
||||
region.add_hyperlink("https://github.com/emilk/emigui/");
|
||||
ui.add_label("This is not JavaScript. This is Rust, running at 60 FPS. This is the web page, reinvented with game tech.");
|
||||
ui.add_label("This is also work in progress, and not ready for production... yet :)");
|
||||
ui.horizontal(|ui| {
|
||||
ui.add_label("Project home page:");
|
||||
ui.add_hyperlink("https://github.com/emilk/emigui/");
|
||||
});
|
||||
region.add(Separator::new());
|
||||
ui.add(Separator::new());
|
||||
|
||||
region.set_align(Align::Min);
|
||||
region.add_label("WebGl painter info:");
|
||||
region.indent("webgl region", |region| {
|
||||
region.add_label(self.webgl_painter.debug_info());
|
||||
ui.set_align(Align::Min);
|
||||
ui.add_label("WebGl painter info:");
|
||||
ui.indent("webgl region id", |ui| {
|
||||
ui.add_label(self.webgl_painter.debug_info());
|
||||
});
|
||||
|
||||
region.add(
|
||||
ui.add(
|
||||
label!(
|
||||
"CPU usage: {:.2} ms (excludes painting)",
|
||||
1e3 * self.frame_times.average().unwrap_or_default()
|
||||
)
|
||||
.text_style(TextStyle::Monospace),
|
||||
);
|
||||
region.add(
|
||||
ui.add(
|
||||
label!(
|
||||
"FPS: {:.1}",
|
||||
1.0 / self.frame_times.mean_time_interval().unwrap_or_default()
|
||||
|
@ -80,15 +80,15 @@ impl State {
|
|||
Window::new("Examples")
|
||||
.default_pos(pos2(32.0, 300.0))
|
||||
.default_size(vec2(300.0, 400.0))
|
||||
.show(region.ctx(), |region| {
|
||||
self.example_app.ui(region);
|
||||
.show(ui.ctx(), |ui| {
|
||||
self.example_app.ui(ui);
|
||||
});
|
||||
|
||||
Window::new("Emigui settings")
|
||||
.default_pos(pos2(400.0, 300.0))
|
||||
.default_size(vec2(400.0, 400.0))
|
||||
.show(region.ctx(), |region| {
|
||||
self.ctx.ui(region);
|
||||
.show(ui.ctx(), |ui| {
|
||||
self.ctx.ui(ui);
|
||||
});
|
||||
|
||||
let bg_color = srgba(0, 0, 0, 0); // Use background css color.
|
||||
|
|
Loading…
Reference in a new issue