[input] widgets must say if they are interested in click or drags
This commit is contained in:
parent
4bea65595c
commit
5c966bdc76
14 changed files with 170 additions and 114 deletions
|
@ -163,7 +163,8 @@ impl Prepared {
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
let move_interact = ctx.interact(layer, clip_rect, rect, interact_id);
|
let move_interact =
|
||||||
|
ctx.interact(layer, clip_rect, rect, interact_id, Sense::click_and_drag());
|
||||||
|
|
||||||
let input = ctx.input();
|
let input = ctx.input();
|
||||||
if move_interact.active {
|
if move_interact.active {
|
||||||
|
|
|
@ -96,7 +96,7 @@ impl State {
|
||||||
&mut self,
|
&mut self,
|
||||||
ui: &mut Ui,
|
ui: &mut Ui,
|
||||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||||
) -> Option<(R, InteractInfo)> {
|
) -> Option<(R, Rect)> {
|
||||||
let openness = self.openness(ui);
|
let openness = self.openness(ui);
|
||||||
let animate = 0.0 < openness && openness < 1.0;
|
let animate = 0.0 < openness && openness < 1.0;
|
||||||
if animate {
|
if animate {
|
||||||
|
@ -132,7 +132,7 @@ impl State {
|
||||||
}))
|
}))
|
||||||
} else if self.open {
|
} else if self.open {
|
||||||
let r_interact = ui.add_custom(add_contents);
|
let r_interact = ui.add_custom(add_contents);
|
||||||
let full_size = r_interact.1.rect.size();
|
let full_size = r_interact.1.size();
|
||||||
self.open_height = Some(full_size.y);
|
self.open_height = Some(full_size.y);
|
||||||
Some(r_interact)
|
Some(r_interact)
|
||||||
} else {
|
} else {
|
||||||
|
@ -190,13 +190,13 @@ impl CollapsingHeader {
|
||||||
let desired_width = text_max_x - available.left();
|
let desired_width = text_max_x - available.left();
|
||||||
let desired_width = desired_width.max(available.width());
|
let desired_width = desired_width.max(available.width());
|
||||||
|
|
||||||
let interact = ui.reserve_space(
|
let size = vec2(
|
||||||
vec2(
|
desired_width,
|
||||||
desired_width,
|
galley.size.y + 2.0 * ui.style().button_padding.y,
|
||||||
galley.size.y + 2.0 * ui.style().button_padding.y,
|
|
||||||
),
|
|
||||||
Some(id),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
|
let rect = ui.allocate_space(size);
|
||||||
|
let interact = ui.interact(rect, id, Sense::click());
|
||||||
let text_pos = pos2(text_pos.x, interact.rect.center().y - galley.size.y / 2.0);
|
let text_pos = pos2(text_pos.x, interact.rect.center().y - galley.size.y / 2.0);
|
||||||
|
|
||||||
let mut state = State::from_memory_with_default_open(ui, id, default_open);
|
let mut state = State::from_memory_with_default_open(ui, id, default_open);
|
||||||
|
|
|
@ -20,7 +20,7 @@ impl Default for BarState {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, InteractInfo) {
|
pub fn bar<R>(ui: &mut Ui, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect) {
|
||||||
ui.inner_layout(Layout::horizontal(Align::Center), |ui| {
|
ui.inner_layout(Layout::horizontal(Align::Center), |ui| {
|
||||||
Frame::menu_bar(ui.style()).show(ui, |ui| {
|
Frame::menu_bar(ui.style()).show(ui, |ui| {
|
||||||
let mut style = ui.style().clone();
|
let mut style = ui.style().clone();
|
||||||
|
|
|
@ -209,7 +209,7 @@ impl Resize {
|
||||||
position + state.size + self.handle_offset - corner_size,
|
position + state.size + self.handle_offset - corner_size,
|
||||||
corner_size,
|
corner_size,
|
||||||
);
|
);
|
||||||
let corner_interact = ui.interact_rect(corner_rect, id.with("corner"));
|
let corner_interact = ui.interact(corner_rect, id.with("corner"), Sense::drag());
|
||||||
|
|
||||||
if corner_interact.active {
|
if corner_interact.active {
|
||||||
if let Some(mouse_pos) = ui.input().mouse.pos {
|
if let Some(mouse_pos) = ui.input().mouse.pos {
|
||||||
|
@ -304,7 +304,7 @@ impl Resize {
|
||||||
// state.size = state.size.clamp(self.min_size..=self.max_size);
|
// state.size = state.size.clamp(self.min_size..=self.max_size);
|
||||||
state.size = state.size.round(); // TODO: round to pixels
|
state.size = state.size.round(); // TODO: round to pixels
|
||||||
|
|
||||||
ui.reserve_space(state.size, None);
|
ui.allocate_space(state.size);
|
||||||
|
|
||||||
// ------------------------------
|
// ------------------------------
|
||||||
|
|
||||||
|
|
|
@ -146,8 +146,8 @@ impl Prepared {
|
||||||
let content_is_too_small = content_size.y > inner_rect.height();
|
let content_is_too_small = content_size.y > inner_rect.height();
|
||||||
|
|
||||||
if content_is_too_small {
|
if content_is_too_small {
|
||||||
// Dragg contents to scroll (for touch screens mostly):
|
// Drag contents to scroll (for touch screens mostly):
|
||||||
let content_interact = ui.interact_rect(inner_rect, id.with("area"));
|
let content_interact = ui.interact(inner_rect, id.with("area"), Sense::drag());
|
||||||
if content_interact.active {
|
if content_interact.active {
|
||||||
state.offset.y -= ui.input().mouse.delta.y;
|
state.offset.y -= ui.input().mouse.delta.y;
|
||||||
}
|
}
|
||||||
|
@ -181,7 +181,7 @@ impl Prepared {
|
||||||
|
|
||||||
// intentionally use same id for inside and outside of handle
|
// intentionally use same id for inside and outside of handle
|
||||||
let interact_id = id.with("vertical");
|
let interact_id = id.with("vertical");
|
||||||
let handle_interact = ui.interact_rect(handle_rect, interact_id);
|
let handle_interact = ui.interact(handle_rect, interact_id, Sense::click_and_drag());
|
||||||
|
|
||||||
if let Some(mouse_pos) = ui.input().mouse.pos {
|
if let Some(mouse_pos) = ui.input().mouse.pos {
|
||||||
if handle_interact.active {
|
if handle_interact.active {
|
||||||
|
@ -191,7 +191,8 @@ impl Prepared {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Check for mouse down outside handle:
|
// Check for mouse down outside handle:
|
||||||
let scroll_bg_interact = ui.interact_rect(outer_scroll_rect, interact_id);
|
let scroll_bg_interact =
|
||||||
|
ui.interact(outer_scroll_rect, interact_id, Sense::click_and_drag());
|
||||||
|
|
||||||
if scroll_bg_interact.active {
|
if scroll_bg_interact.active {
|
||||||
// Center scroll at mouse pos:
|
// Center scroll at mouse pos:
|
||||||
|
@ -235,7 +236,7 @@ impl Prepared {
|
||||||
// content_size.y.min(inner_rect.size().y), // respect vertical height.
|
// content_size.y.min(inner_rect.size().y), // respect vertical height.
|
||||||
// );
|
// );
|
||||||
let size = outer_rect.size();
|
let size = outer_rect.size();
|
||||||
ui.reserve_space(size, None);
|
ui.allocate_space(size);
|
||||||
|
|
||||||
state.offset.y = state.offset.y.min(content_size.y - inner_rect.height());
|
state.offset.y = state.offset.y.min(content_size.y - inner_rect.height());
|
||||||
state.offset.y = state.offset.y.max(0.0);
|
state.offset.y = state.offset.y.max(0.0);
|
||||||
|
|
|
@ -529,10 +529,10 @@ fn show_title_bar(
|
||||||
|
|
||||||
{
|
{
|
||||||
// TODO: make clickable radius larger
|
// TODO: make clickable radius larger
|
||||||
ui.reserve_space(vec2(0.0, 0.0), None); // HACK: will add left spacing
|
ui.allocate_space(vec2(0.0, 0.0)); // HACK: will add left spacing
|
||||||
|
|
||||||
let collapse_button_interact =
|
let rect = ui.allocate_space(Vec2::splat(button_size));
|
||||||
ui.reserve_space(Vec2::splat(button_size), Some(collapsing_id));
|
let collapse_button_interact = ui.interact(rect, collapsing_id, Sense::click());
|
||||||
if collapse_button_interact.clicked {
|
if collapse_button_interact.clicked {
|
||||||
// TODO: also do this when double-clicking window title
|
// TODO: also do this when double-clicking window title
|
||||||
collapsing.toggle(ui);
|
collapsing.toggle(ui);
|
||||||
|
@ -541,7 +541,7 @@ fn show_title_bar(
|
||||||
}
|
}
|
||||||
|
|
||||||
let title_galley = title_label.layout(ui);
|
let title_galley = title_label.layout(ui);
|
||||||
let title_rect = ui.reserve_space(title_galley.size, None).rect;
|
let title_rect = ui.allocate_space(title_galley.size);
|
||||||
|
|
||||||
if show_close_button {
|
if show_close_button {
|
||||||
// Reserve space for close button which will be added later:
|
// Reserve space for close button which will be added later:
|
||||||
|
@ -566,7 +566,7 @@ fn show_title_bar(
|
||||||
});
|
});
|
||||||
|
|
||||||
TitleBar {
|
TitleBar {
|
||||||
rect: tb_interact.1.rect,
|
rect: tb_interact.1,
|
||||||
..tb_interact.0
|
..tb_interact.0
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -577,8 +577,8 @@ impl TitleBar {
|
||||||
.paint_galley(ui, self.title_rect.min, self.title_galley);
|
.paint_galley(ui, self.title_rect.min, self.title_galley);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn close_button_ui(&self, ui: &mut Ui, content: &Option<InteractInfo>) -> InteractInfo {
|
pub fn close_button_ui(&self, ui: &mut Ui, content: &Option<Rect>) -> InteractInfo {
|
||||||
let right = content.map(|c| c.rect.right()).unwrap_or(self.rect.right());
|
let right = content.map(|c| c.right()).unwrap_or(self.rect.right());
|
||||||
|
|
||||||
let button_size = ui.style().start_icon_width;
|
let button_size = ui.style().start_icon_width;
|
||||||
let button_rect = Rect::from_min_size(
|
let button_rect = Rect::from_min_size(
|
||||||
|
@ -595,7 +595,7 @@ impl TitleBar {
|
||||||
|
|
||||||
fn close_button(ui: &mut Ui, rect: Rect) -> InteractInfo {
|
fn close_button(ui: &mut Ui, rect: Rect) -> InteractInfo {
|
||||||
let close_id = ui.make_child_id("window_close_button");
|
let close_id = ui.make_child_id("window_close_button");
|
||||||
let interact = ui.interact_rect(rect, close_id);
|
let interact = ui.interact(rect, close_id, Sense::click());
|
||||||
ui.expand_to_include_child(interact.rect);
|
ui.expand_to_include_child(interact.rect);
|
||||||
|
|
||||||
let stroke_color = ui.style().interact(&interact).stroke_color;
|
let stroke_color = ui.style().interact(&interact).stroke_color;
|
||||||
|
|
|
@ -148,16 +148,19 @@ impl Context {
|
||||||
|
|
||||||
fn begin_frame_mut(&mut self, new_raw_input: RawInput) {
|
fn begin_frame_mut(&mut self, new_raw_input: RawInput) {
|
||||||
if !self.input.mouse.down || self.input.mouse.pos.is_none() {
|
if !self.input.mouse.down || self.input.mouse.pos.is_none() {
|
||||||
|
// mouse was not down last frame
|
||||||
self.memory().active_id = None;
|
self.memory().active_id = None;
|
||||||
|
|
||||||
let window_interaction = self.memory().window_interaction.take();
|
let window_interaction = self.memory().window_interaction.take();
|
||||||
if let Some(window_interaction) = window_interaction {
|
if let Some(window_interaction) = window_interaction {
|
||||||
let area_layer = window_interaction.area_layer;
|
if !window_interaction.is_resize() {
|
||||||
let area_state = self.memory().areas.get(area_layer.id).clone();
|
|
||||||
if let Some(mut area_state) = area_state {
|
|
||||||
// Throw windows because it is fun:
|
// Throw windows because it is fun:
|
||||||
area_state.vel = self.input().mouse.velocity;
|
let area_layer = window_interaction.area_layer;
|
||||||
self.memory().areas.set_state(area_layer, area_state);
|
let area_state = self.memory().areas.get(area_layer.id).clone();
|
||||||
|
if let Some(mut area_state) = area_state {
|
||||||
|
area_state.vel = self.input().mouse.velocity;
|
||||||
|
self.memory().areas.set_state(area_layer, area_state);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -287,15 +290,38 @@ impl Context {
|
||||||
clip_rect: Rect,
|
clip_rect: Rect,
|
||||||
rect: Rect,
|
rect: Rect,
|
||||||
interaction_id: Option<Id>,
|
interaction_id: Option<Id>,
|
||||||
|
sense: Sense,
|
||||||
) -> InteractInfo {
|
) -> InteractInfo {
|
||||||
let interact_rect = rect.expand2(0.5 * self.style().item_spacing); // make it easier to click. TODO: nice way to do this
|
let interact_rect = rect.expand2(0.5 * self.style().item_spacing); // make it easier to click. TODO: nice way to do this
|
||||||
let hovered = self.contains_mouse(layer, clip_rect, interact_rect);
|
let hovered = self.contains_mouse(layer, clip_rect, interact_rect);
|
||||||
|
|
||||||
|
if interaction_id.is_none() || sense == Sense::nothing() {
|
||||||
|
// Not interested in input:
|
||||||
|
return InteractInfo {
|
||||||
|
rect,
|
||||||
|
hovered,
|
||||||
|
clicked: false,
|
||||||
|
active: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
let interaction_id = interaction_id.unwrap();
|
||||||
|
|
||||||
let mut memory = self.memory();
|
let mut memory = self.memory();
|
||||||
let active = interaction_id.is_some() && memory.active_id == interaction_id;
|
let active = memory.active_id == Some(interaction_id);
|
||||||
|
|
||||||
|
if active && !sense.drag && !self.input().mouse.could_be_click {
|
||||||
|
// Aborted click
|
||||||
|
memory.active_id = None;
|
||||||
|
return InteractInfo {
|
||||||
|
rect,
|
||||||
|
hovered: false,
|
||||||
|
clicked: false,
|
||||||
|
active: false,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
if self.input.mouse.pressed {
|
if self.input.mouse.pressed {
|
||||||
if hovered && interaction_id.is_some() {
|
if hovered {
|
||||||
if memory.active_id.is_some() {
|
if memory.active_id.is_some() {
|
||||||
// Already clicked something else this frame
|
// Already clicked something else this frame
|
||||||
InteractInfo {
|
InteractInfo {
|
||||||
|
@ -305,7 +331,8 @@ impl Context {
|
||||||
active: false,
|
active: false,
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
memory.active_id = interaction_id;
|
// start of a click or drag
|
||||||
|
memory.active_id = Some(interaction_id);
|
||||||
InteractInfo {
|
InteractInfo {
|
||||||
rect,
|
rect,
|
||||||
hovered,
|
hovered,
|
||||||
|
@ -314,6 +341,7 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// miss
|
||||||
InteractInfo {
|
InteractInfo {
|
||||||
rect,
|
rect,
|
||||||
hovered,
|
hovered,
|
||||||
|
@ -325,7 +353,7 @@ impl Context {
|
||||||
InteractInfo {
|
InteractInfo {
|
||||||
rect,
|
rect,
|
||||||
hovered,
|
hovered,
|
||||||
clicked: hovered && active && self.input().mouse.could_be_click,
|
clicked: hovered && active,
|
||||||
active,
|
active,
|
||||||
}
|
}
|
||||||
} else if self.input.mouse.down {
|
} else if self.input.mouse.down {
|
||||||
|
|
|
@ -394,11 +394,7 @@ impl BoxPainting {
|
||||||
ui.add(Slider::usize(&mut self.num_boxes, 0..=5).text("num_boxes"));
|
ui.add(Slider::usize(&mut self.num_boxes, 0..=5).text("num_boxes"));
|
||||||
|
|
||||||
let pos = ui
|
let pos = ui
|
||||||
.reserve_space(
|
.allocate_space(vec2(self.size.x * (self.num_boxes as f32), self.size.y))
|
||||||
vec2(self.size.x * (self.num_boxes as f32), self.size.y),
|
|
||||||
None,
|
|
||||||
)
|
|
||||||
.rect
|
|
||||||
.min;
|
.min;
|
||||||
|
|
||||||
let mut cmds = vec![];
|
let mut cmds = vec![];
|
||||||
|
@ -438,7 +434,8 @@ impl Painting {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn content(&mut self, ui: &mut Ui) {
|
fn content(&mut self, ui: &mut Ui) {
|
||||||
let interact = ui.reserve_space(ui.available_finite().size(), Some(ui.id()));
|
let rect = ui.allocate_space(ui.available_finite().size());
|
||||||
|
let interact = ui.interact(rect, ui.id(), Sense::drag());
|
||||||
let rect = interact.rect;
|
let rect = interact.rect;
|
||||||
ui.set_clip_rect(ui.clip_rect().intersect(rect)); // Make sure we don't paint out of bounds
|
ui.set_clip_rect(ui.clip_rect().intersect(rect)); // Make sure we don't paint out of bounds
|
||||||
|
|
||||||
|
|
|
@ -17,8 +17,7 @@ impl Texture {
|
||||||
if size.x > ui.available().width() {
|
if size.x > ui.available().width() {
|
||||||
size *= ui.available().width() / size.x;
|
size *= ui.available().width() / size.x;
|
||||||
}
|
}
|
||||||
let interact = ui.reserve_space(size, None);
|
let rect = ui.allocate_space(size);
|
||||||
let rect = interact.rect;
|
|
||||||
let top_left = Vertex {
|
let top_left = Vertex {
|
||||||
pos: rect.min,
|
pos: rect.min,
|
||||||
uv: (0, 0),
|
uv: (0, 0),
|
||||||
|
@ -33,10 +32,10 @@ impl Texture {
|
||||||
triangles.add_rect(top_left, bottom_right);
|
triangles.add_rect(top_left, bottom_right);
|
||||||
ui.add_paint_cmd(PaintCmd::Triangles(triangles));
|
ui.add_paint_cmd(PaintCmd::Triangles(triangles));
|
||||||
|
|
||||||
if interact.hovered {
|
if ui.hovered(rect) {
|
||||||
show_tooltip(ui.ctx(), |ui| {
|
show_tooltip(ui.ctx(), |ui| {
|
||||||
let pos = ui.top_left();
|
let pos = ui.top_left();
|
||||||
let zoom_rect = ui.reserve_space(vec2(128.0, 128.0), None).rect;
|
let zoom_rect = ui.allocate_space(vec2(128.0, 128.0));
|
||||||
let u = remap_clamp(pos.x, rect.range_x(), 0.0..=self.width as f32 - 1.0).round();
|
let u = remap_clamp(pos.x, rect.range_x(), 0.0..=self.width as f32 - 1.0).round();
|
||||||
let v = remap_clamp(pos.y, rect.range_y(), 0.0..=self.height as f32 - 1.0).round();
|
let v = remap_clamp(pos.y, rect.range_y(), 0.0..=self.height as f32 - 1.0).round();
|
||||||
|
|
||||||
|
|
|
@ -111,3 +111,44 @@ impl GuiResponse {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
/// What sort of interaction is a widget sensitive to?
|
||||||
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
|
pub struct Sense {
|
||||||
|
/// buttons, sliders, windows ...
|
||||||
|
pub click: bool,
|
||||||
|
|
||||||
|
/// sliders, windows, scroll bars, scroll areas ...
|
||||||
|
pub drag: bool,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Sense {
|
||||||
|
pub fn nothing() -> Self {
|
||||||
|
Self {
|
||||||
|
click: false,
|
||||||
|
drag: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn click() -> Self {
|
||||||
|
Self {
|
||||||
|
click: true,
|
||||||
|
drag: false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn drag() -> Self {
|
||||||
|
Self {
|
||||||
|
click: false,
|
||||||
|
drag: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// e.g. a slider or window
|
||||||
|
pub fn click_and_drag() -> Self {
|
||||||
|
Self {
|
||||||
|
click: true,
|
||||||
|
drag: true,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -303,14 +303,18 @@ impl Ui {
|
||||||
// ------------------------------------------------------------------------
|
// ------------------------------------------------------------------------
|
||||||
// Interaction
|
// Interaction
|
||||||
|
|
||||||
/// Check for clicks on this entire ui (rect())
|
pub fn interact(&self, rect: Rect, id: Id, sense: Sense) -> InteractInfo {
|
||||||
pub fn interact_whole(&self) -> InteractInfo {
|
self.ctx
|
||||||
self.interact_rect(self.rect(), self.id)
|
.interact(self.layer, self.clip_rect, rect, Some(id), sense)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn interact_rect(&self, rect: Rect, id: Id) -> InteractInfo {
|
pub fn interact_hover(&self, rect: Rect) -> InteractInfo {
|
||||||
self.ctx
|
self.ctx
|
||||||
.interact(self.layer, self.clip_rect, rect, Some(id))
|
.interact(self.layer, self.clip_rect, rect, None, Sense::nothing())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn hovered(&self, rect: Rect) -> bool {
|
||||||
|
self.interact_hover(rect).hovered
|
||||||
}
|
}
|
||||||
|
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
@ -340,15 +344,6 @@ impl Ui {
|
||||||
/// for `Justified` aligned layouts, like in menus.
|
/// for `Justified` aligned layouts, like in menus.
|
||||||
///
|
///
|
||||||
/// You may get LESS space than you asked for if the current layout won't fit what you asked for.
|
/// You may get LESS space than you asked for if the current layout won't fit what you asked for.
|
||||||
///
|
|
||||||
/// TODO: remove, or redesign or something and start using allocate_space
|
|
||||||
pub fn reserve_space(&mut self, child_size: Vec2, interaction_id: Option<Id>) -> InteractInfo {
|
|
||||||
let rect = self.allocate_space(child_size);
|
|
||||||
|
|
||||||
self.ctx
|
|
||||||
.interact(self.layer, self.clip_rect, rect, interaction_id)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn allocate_space(&mut self, child_size: Vec2) -> Rect {
|
pub fn allocate_space(&mut self, child_size: Vec2) -> Rect {
|
||||||
let child_size = self.round_vec_to_pixels(child_size);
|
let child_size = self.round_vec_to_pixels(child_size);
|
||||||
self.cursor = self.round_pos_to_pixels(self.cursor);
|
self.cursor = self.round_pos_to_pixels(self.cursor);
|
||||||
|
@ -530,25 +525,21 @@ impl Ui {
|
||||||
/// Just because you ask for a lot of space does not mean you have to use it!
|
/// 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`
|
/// After `add_contents` is called the contents of `bounding_size`
|
||||||
/// will decide how much space will be used in the parent ui.
|
/// will decide how much space will be used in the parent ui.
|
||||||
pub fn add_custom_contents(
|
pub fn add_custom_contents(&mut self, size: Vec2, add_contents: impl FnOnce(&mut Ui)) -> Rect {
|
||||||
&mut self,
|
|
||||||
size: Vec2,
|
|
||||||
add_contents: impl FnOnce(&mut Ui),
|
|
||||||
) -> InteractInfo {
|
|
||||||
let size = size.min(self.available().size());
|
let size = size.min(self.available().size());
|
||||||
let child_rect = Rect::from_min_size(self.cursor, size);
|
let child_rect = Rect::from_min_size(self.cursor, size);
|
||||||
let mut child_ui = self.child_ui(child_rect);
|
let mut child_ui = self.child_ui(child_rect);
|
||||||
add_contents(&mut child_ui);
|
add_contents(&mut child_ui);
|
||||||
self.reserve_space(child_ui.bounding_size(), None)
|
self.allocate_space(child_ui.bounding_size())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a child ui
|
/// Create a child ui
|
||||||
pub fn add_custom<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, InteractInfo) {
|
pub fn add_custom<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect) {
|
||||||
let child_rect = self.available();
|
let child_rect = self.available();
|
||||||
let mut child_ui = self.child_ui(child_rect);
|
let mut child_ui = self.child_ui(child_rect);
|
||||||
let r = add_contents(&mut child_ui);
|
let r = add_contents(&mut child_ui);
|
||||||
let size = child_ui.bounding_size();
|
let size = child_ui.bounding_size();
|
||||||
(r, self.reserve_space(size, None))
|
(r, self.allocate_space(size))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a child ui which is indented to the right
|
/// Create a child ui which is indented to the right
|
||||||
|
@ -556,7 +547,7 @@ impl Ui {
|
||||||
&mut self,
|
&mut self,
|
||||||
id_source: impl Hash,
|
id_source: impl Hash,
|
||||||
add_contents: impl FnOnce(&mut Ui) -> R,
|
add_contents: impl FnOnce(&mut Ui) -> R,
|
||||||
) -> (R, InteractInfo) {
|
) -> (R, Rect) {
|
||||||
assert!(
|
assert!(
|
||||||
self.layout().dir() == Direction::Vertical,
|
self.layout().dir() == Direction::Vertical,
|
||||||
"You can only indent vertical layouts"
|
"You can only indent vertical layouts"
|
||||||
|
@ -580,7 +571,7 @@ impl Ui {
|
||||||
self.style.line_width,
|
self.style.line_width,
|
||||||
));
|
));
|
||||||
|
|
||||||
(ret, self.reserve_space(indent + size, None))
|
(ret, self.allocate_space(indent + size))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn left_column(&mut self, width: f32) -> Ui {
|
pub fn left_column(&mut self, width: f32) -> Ui {
|
||||||
|
@ -609,12 +600,12 @@ impl Ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start a ui with horizontal layout
|
/// Start a ui with horizontal layout
|
||||||
pub fn horizontal<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, InteractInfo) {
|
pub fn horizontal<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect) {
|
||||||
self.inner_layout(Layout::horizontal(Align::Min), add_contents)
|
self.inner_layout(Layout::horizontal(Align::Min), add_contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Start a ui with vertical layout
|
/// Start a ui with vertical layout
|
||||||
pub fn vertical<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, InteractInfo) {
|
pub fn vertical<R>(&mut self, add_contents: impl FnOnce(&mut Ui) -> R) -> (R, Rect) {
|
||||||
self.inner_layout(Layout::vertical(Align::Min), add_contents)
|
self.inner_layout(Layout::vertical(Align::Min), add_contents)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -622,7 +613,7 @@ impl Ui {
|
||||||
&mut self,
|
&mut self,
|
||||||
layout: Layout,
|
layout: Layout,
|
||||||
add_contents: impl FnOnce(&mut Self) -> R,
|
add_contents: impl FnOnce(&mut Self) -> R,
|
||||||
) -> (R, InteractInfo) {
|
) -> (R, Rect) {
|
||||||
let child_rect = Rect::from_min_max(self.cursor, self.bottom_right());
|
let child_rect = Rect::from_min_max(self.cursor, self.bottom_right());
|
||||||
let mut child_ui = Self {
|
let mut child_ui = Self {
|
||||||
..self.child_ui(child_rect)
|
..self.child_ui(child_rect)
|
||||||
|
@ -630,8 +621,8 @@ impl Ui {
|
||||||
child_ui.set_layout(layout); // HACK: need a separate call right now
|
child_ui.set_layout(layout); // HACK: need a separate call right now
|
||||||
let ret = add_contents(&mut child_ui);
|
let ret = add_contents(&mut child_ui);
|
||||||
let size = child_ui.bounding_size();
|
let size = child_ui.bounding_size();
|
||||||
let interact = self.reserve_space(size, None);
|
let rect = self.allocate_space(size);
|
||||||
(ret, interact)
|
(ret, rect)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Temporarily split split an Ui into several columns.
|
/// Temporarily split split an Ui into several columns.
|
||||||
|
@ -678,7 +669,7 @@ impl Ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
let size = vec2(self.available().width().max(sum_width), max_height);
|
let size = vec2(self.available().width().max(sum_width), max_height);
|
||||||
self.reserve_space(size, None);
|
self.allocate_space(size);
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -108,9 +108,9 @@ macro_rules! label {
|
||||||
impl Widget for Label {
|
impl Widget for Label {
|
||||||
fn ui(self, ui: &mut Ui) -> GuiResponse {
|
fn ui(self, ui: &mut Ui) -> GuiResponse {
|
||||||
let galley = self.layout(ui);
|
let galley = self.layout(ui);
|
||||||
let interact = ui.reserve_space(galley.size, None);
|
let rect = ui.allocate_space(galley.size);
|
||||||
self.paint_galley(ui, interact.rect.min, galley);
|
self.paint_galley(ui, rect.min, galley);
|
||||||
ui.response(interact)
|
ui.response(ui.interact_hover(rect))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -158,7 +158,8 @@ impl Widget for Hyperlink {
|
||||||
let id = ui.make_child_id(&url);
|
let id = ui.make_child_id(&url);
|
||||||
let font = &ui.fonts()[text_style];
|
let font = &ui.fonts()[text_style];
|
||||||
let galley = font.layout_multiline(text, ui.available().width());
|
let galley = font.layout_multiline(text, ui.available().width());
|
||||||
let interact = ui.reserve_space(galley.size, Some(id));
|
let rect = ui.allocate_space(galley.size);
|
||||||
|
let interact = ui.interact(rect, id, Sense::click());
|
||||||
if interact.hovered {
|
if interact.hovered {
|
||||||
ui.ctx().output().cursor_icon = CursorIcon::PointingHand;
|
ui.ctx().output().cursor_icon = CursorIcon::PointingHand;
|
||||||
}
|
}
|
||||||
|
@ -239,7 +240,8 @@ impl Widget for Button {
|
||||||
let padding = ui.style().button_padding;
|
let padding = ui.style().button_padding;
|
||||||
let mut size = galley.size + 2.0 * padding;
|
let mut size = galley.size + 2.0 * padding;
|
||||||
size.y = size.y.max(ui.style().clickable_diameter);
|
size.y = size.y.max(ui.style().clickable_diameter);
|
||||||
let interact = ui.reserve_space(size, Some(id));
|
let rect = ui.allocate_space(size);
|
||||||
|
let interact = ui.interact(rect, id, Sense::click());
|
||||||
let text_cursor = interact.rect.left_center() + vec2(padding.x, -0.5 * galley.size.y);
|
let text_cursor = interact.rect.left_center() + vec2(padding.x, -0.5 * galley.size.y);
|
||||||
let bg_fill_color = fill_color.or(ui.style().interact(&interact).bg_fill_color);
|
let bg_fill_color = fill_color.or(ui.style().interact(&interact).bg_fill_color);
|
||||||
ui.add_paint_cmd(PaintCmd::Rect {
|
ui.add_paint_cmd(PaintCmd::Rect {
|
||||||
|
@ -291,13 +293,12 @@ impl<'a> Widget for Checkbox<'a> {
|
||||||
let text_style = TextStyle::Button;
|
let text_style = TextStyle::Button;
|
||||||
let font = &ui.fonts()[text_style];
|
let font = &ui.fonts()[text_style];
|
||||||
let galley = font.layout_single_line(text);
|
let galley = font.layout_single_line(text);
|
||||||
let interact = ui.reserve_space(
|
let size = ui.style().button_padding
|
||||||
ui.style().button_padding
|
+ vec2(ui.style().start_icon_width, 0.0)
|
||||||
+ vec2(ui.style().start_icon_width, 0.0)
|
+ galley.size
|
||||||
+ galley.size
|
+ ui.style().button_padding;
|
||||||
+ ui.style().button_padding,
|
let rect = ui.allocate_space(size);
|
||||||
Some(id),
|
let interact = ui.interact(rect, id, Sense::click());
|
||||||
);
|
|
||||||
let text_cursor =
|
let text_cursor =
|
||||||
interact.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0);
|
interact.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0);
|
||||||
if interact.clicked {
|
if interact.clicked {
|
||||||
|
@ -370,13 +371,12 @@ impl Widget for RadioButton {
|
||||||
let text_style = TextStyle::Button;
|
let text_style = TextStyle::Button;
|
||||||
let font = &ui.fonts()[text_style];
|
let font = &ui.fonts()[text_style];
|
||||||
let galley = font.layout_multiline(text, ui.available().width());
|
let galley = font.layout_multiline(text, ui.available().width());
|
||||||
let interact = ui.reserve_space(
|
let size = ui.style().button_padding
|
||||||
ui.style().button_padding
|
+ vec2(ui.style().start_icon_width, 0.0)
|
||||||
+ vec2(ui.style().start_icon_width, 0.0)
|
+ galley.size
|
||||||
+ galley.size
|
+ ui.style().button_padding;
|
||||||
+ ui.style().button_padding,
|
let rect = ui.allocate_space(size);
|
||||||
Some(id),
|
let interact = ui.interact(rect, id, Sense::click());
|
||||||
);
|
|
||||||
let text_cursor =
|
let text_cursor =
|
||||||
interact.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0);
|
interact.rect.min + ui.style().button_padding + vec2(ui.style().start_icon_width, 0.0);
|
||||||
|
|
||||||
|
@ -461,27 +461,25 @@ impl Widget for Separator {
|
||||||
|
|
||||||
let available_space = ui.available_finite().size();
|
let available_space = ui.available_finite().size();
|
||||||
|
|
||||||
let (points, interact) = match ui.layout().dir() {
|
let (points, rect) = match ui.layout().dir() {
|
||||||
Direction::Horizontal => {
|
Direction::Horizontal => {
|
||||||
let interact = ui.reserve_space(vec2(min_spacing, available_space.y), None);
|
let rect = ui.allocate_space(vec2(min_spacing, available_space.y));
|
||||||
let r = &interact.rect;
|
|
||||||
(
|
(
|
||||||
[
|
[
|
||||||
pos2(r.center().x, r.top() - extra),
|
pos2(rect.center().x, rect.top() - extra),
|
||||||
pos2(r.center().x, r.bottom() + extra),
|
pos2(rect.center().x, rect.bottom() + extra),
|
||||||
],
|
],
|
||||||
interact,
|
rect,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
Direction::Vertical => {
|
Direction::Vertical => {
|
||||||
let interact = ui.reserve_space(vec2(available_space.x, min_spacing), None);
|
let rect = ui.allocate_space(vec2(available_space.x, min_spacing));
|
||||||
let r = &interact.rect;
|
|
||||||
(
|
(
|
||||||
[
|
[
|
||||||
pos2(r.left() - extra, r.center().y),
|
pos2(rect.left() - extra, rect.center().y),
|
||||||
pos2(r.right() + extra, r.center().y),
|
pos2(rect.right() + extra, rect.center().y),
|
||||||
],
|
],
|
||||||
interact,
|
rect,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -490,6 +488,6 @@ impl Widget for Separator {
|
||||||
color: color,
|
color: color,
|
||||||
width: line_width,
|
width: line_width,
|
||||||
});
|
});
|
||||||
ui.response(interact)
|
ui.response(ui.interact_hover(rect))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -117,7 +117,7 @@ impl<'a> Widget for Slider<'a> {
|
||||||
|
|
||||||
if text_on_top {
|
if text_on_top {
|
||||||
let galley = font.layout_single_line(full_text);
|
let galley = font.layout_single_line(full_text);
|
||||||
let pos = ui.reserve_space(galley.size, None).rect.min;
|
let pos = ui.allocate_space(galley.size).min;
|
||||||
ui.add_galley(pos, galley, text_style, text_color);
|
ui.add_galley(pos, galley, text_style, text_color);
|
||||||
slider_sans_text.ui(ui)
|
slider_sans_text.ui(ui)
|
||||||
} else {
|
} else {
|
||||||
|
@ -140,13 +140,12 @@ impl<'a> Widget for Slider<'a> {
|
||||||
|
|
||||||
let id = self.id.unwrap_or_else(|| ui.make_position_id());
|
let id = self.id.unwrap_or_else(|| ui.make_position_id());
|
||||||
|
|
||||||
let interact = ui.reserve_space(
|
let size = Vec2 {
|
||||||
Vec2 {
|
x: ui.available().width(),
|
||||||
x: ui.available().width(),
|
y: height,
|
||||||
y: height,
|
};
|
||||||
},
|
let rect = ui.allocate_space(size);
|
||||||
Some(id),
|
let interact = ui.interact(rect, id, Sense::click_and_drag());
|
||||||
);
|
|
||||||
|
|
||||||
let left = interact.rect.left() + handle_radius;
|
let left = interact.rect.left() + handle_radius;
|
||||||
let right = interact.rect.right() - handle_radius;
|
let right = interact.rect.right() - handle_radius;
|
||||||
|
|
|
@ -71,7 +71,8 @@ impl<'t> Widget for TextEdit<'t> {
|
||||||
font.layout_single_line(text.clone())
|
font.layout_single_line(text.clone())
|
||||||
};
|
};
|
||||||
let desired_size = galley.size.max(vec2(available_width, line_spacing));
|
let desired_size = galley.size.max(vec2(available_width, line_spacing));
|
||||||
let interact = ui.reserve_space(desired_size, Some(id));
|
let rect = ui.allocate_space(desired_size);
|
||||||
|
let interact = ui.interact(rect, id, Sense::click_and_drag()); // TODO: implement drag-select
|
||||||
|
|
||||||
if interact.clicked {
|
if interact.clicked {
|
||||||
ui.request_kb_focus(id);
|
ui.request_kb_focus(id);
|
||||||
|
|
Loading…
Reference in a new issue