mirror of
https://github.com/emilk/egui.git
synced 2026-09-02 06:40:06 -04:00
Use a lot more let-else (#7582)
This commit is contained in:
@@ -20,10 +20,10 @@ pub fn capture() -> String {
|
||||
backtrace::resolve_frame(frame, |symbol| {
|
||||
let mut file_and_line = symbol.filename().map(shorten_source_file_path);
|
||||
|
||||
if let Some(file_and_line) = &mut file_and_line {
|
||||
if let Some(line_nr) = symbol.lineno() {
|
||||
file_and_line.push_str(&format!(":{line_nr}"));
|
||||
}
|
||||
if let Some(file_and_line) = &mut file_and_line
|
||||
&& let Some(line_nr) = symbol.lineno()
|
||||
{
|
||||
file_and_line.push_str(&format!(":{line_nr}"));
|
||||
}
|
||||
let file_and_line = file_and_line.unwrap_or_default();
|
||||
|
||||
|
||||
@@ -525,10 +525,11 @@ impl Area {
|
||||
true,
|
||||
);
|
||||
|
||||
if movable && move_response.dragged() {
|
||||
if let Some(pivot_pos) = &mut state.pivot_pos {
|
||||
*pivot_pos += move_response.drag_delta();
|
||||
}
|
||||
if movable
|
||||
&& move_response.dragged()
|
||||
&& let Some(pivot_pos) = &mut state.pivot_pos
|
||||
{
|
||||
*pivot_pos += move_response.drag_delta();
|
||||
}
|
||||
|
||||
if (move_response.dragged() || move_response.clicked())
|
||||
@@ -606,16 +607,16 @@ impl Prepared {
|
||||
let mut ui = Ui::new(ctx.clone(), self.layer_id.id, ui_builder);
|
||||
ui.set_clip_rect(self.constrain_rect); // Don't paint outside our bounds
|
||||
|
||||
if self.fade_in {
|
||||
if let Some(last_became_visible_at) = self.state.last_became_visible_at {
|
||||
let age =
|
||||
ctx.input(|i| (i.time - last_became_visible_at) as f32 + i.predicted_dt / 2.0);
|
||||
let opacity = crate::remap_clamp(age, 0.0..=ctx.style().animation_time, 0.0..=1.0);
|
||||
let opacity = emath::easing::quadratic_out(opacity); // slow fade-out = quick fade-in
|
||||
ui.multiply_opacity(opacity);
|
||||
if opacity < 1.0 {
|
||||
ctx.request_repaint();
|
||||
}
|
||||
if self.fade_in
|
||||
&& let Some(last_became_visible_at) = self.state.last_became_visible_at
|
||||
{
|
||||
let age =
|
||||
ctx.input(|i| (i.time - last_became_visible_at) as f32 + i.predicted_dt / 2.0);
|
||||
let opacity = crate::remap_clamp(age, 0.0..=ctx.style().animation_time, 0.0..=1.0);
|
||||
let opacity = emath::easing::quadratic_out(opacity); // slow fade-out = quick fade-in
|
||||
ui.multiply_opacity(opacity);
|
||||
if opacity < 1.0 {
|
||||
ctx.request_repaint();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -266,12 +266,10 @@ impl SidePanel {
|
||||
resize_hover = resize_response.hovered();
|
||||
is_resizing = resize_response.dragged();
|
||||
|
||||
if is_resizing {
|
||||
if let Some(pointer) = resize_response.interact_pointer_pos() {
|
||||
width = (pointer.x - side.side_x(panel_rect)).abs();
|
||||
width = clamp_to_range(width, width_range).at_most(available_rect.width());
|
||||
side.set_rect_width(&mut panel_rect, width);
|
||||
}
|
||||
if is_resizing && let Some(pointer) = resize_response.interact_pointer_pos() {
|
||||
width = (pointer.x - side.side_x(panel_rect)).abs();
|
||||
width = clamp_to_range(width, width_range).at_most(available_rect.width());
|
||||
side.set_rect_width(&mut panel_rect, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -765,13 +763,10 @@ impl TopBottomPanel {
|
||||
resize_hover = resize_response.hovered();
|
||||
is_resizing = resize_response.dragged();
|
||||
|
||||
if is_resizing {
|
||||
if let Some(pointer) = resize_response.interact_pointer_pos() {
|
||||
height = (pointer.y - side.side_y(panel_rect)).abs();
|
||||
height =
|
||||
clamp_to_range(height, height_range).at_most(available_rect.height());
|
||||
side.set_rect_height(&mut panel_rect, height);
|
||||
}
|
||||
if is_resizing && let Some(pointer) = resize_response.interact_pointer_pos() {
|
||||
height = (pointer.y - side.side_y(panel_rect)).abs();
|
||||
height = clamp_to_range(height, height_range).at_most(available_rect.height());
|
||||
side.set_rect_height(&mut panel_rect, height);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -241,14 +241,12 @@ impl Resize {
|
||||
|
||||
let corner_id = self.resizable.any().then(|| id.with("__resize_corner"));
|
||||
|
||||
if let Some(corner_id) = corner_id {
|
||||
if let Some(corner_response) = ui.ctx().read_response(corner_id) {
|
||||
if let Some(pointer_pos) = corner_response.interact_pointer_pos() {
|
||||
// Respond to the interaction early to avoid frame delay.
|
||||
user_requested_size =
|
||||
Some(pointer_pos - position + 0.5 * corner_response.rect.size());
|
||||
}
|
||||
}
|
||||
if let Some(corner_id) = corner_id
|
||||
&& let Some(corner_response) = ui.ctx().read_response(corner_id)
|
||||
&& let Some(pointer_pos) = corner_response.interact_pointer_pos()
|
||||
{
|
||||
// Respond to the interaction early to avoid frame delay.
|
||||
user_requested_size = Some(pointer_pos - position + 0.5 * corner_response.rect.size());
|
||||
}
|
||||
|
||||
if let Some(user_requested_size) = user_requested_size {
|
||||
|
||||
@@ -240,38 +240,38 @@ impl Scene {
|
||||
resp.mark_changed();
|
||||
}
|
||||
|
||||
if let Some(mouse_pos) = ui.input(|i| i.pointer.latest_pos()) {
|
||||
if resp.contains_pointer() {
|
||||
let pointer_in_scene = to_global.inverse() * mouse_pos;
|
||||
let zoom_delta = ui.ctx().input(|i| i.zoom_delta());
|
||||
let pan_delta = ui.ctx().input(|i| i.smooth_scroll_delta);
|
||||
if let Some(mouse_pos) = ui.input(|i| i.pointer.latest_pos())
|
||||
&& resp.contains_pointer()
|
||||
{
|
||||
let pointer_in_scene = to_global.inverse() * mouse_pos;
|
||||
let zoom_delta = ui.ctx().input(|i| i.zoom_delta());
|
||||
let pan_delta = ui.ctx().input(|i| i.smooth_scroll_delta);
|
||||
|
||||
// Most of the time we can return early. This is also important to
|
||||
// avoid `ui_from_scene` to change slightly due to floating point errors.
|
||||
if zoom_delta == 1.0 && pan_delta == Vec2::ZERO {
|
||||
return;
|
||||
}
|
||||
|
||||
if zoom_delta != 1.0 {
|
||||
// Zoom in on pointer, but only if we are not zoomed in or out too far.
|
||||
let zoom_delta = zoom_delta.clamp(
|
||||
self.zoom_range.min / to_global.scaling,
|
||||
self.zoom_range.max / to_global.scaling,
|
||||
);
|
||||
|
||||
*to_global = *to_global
|
||||
* TSTransform::from_translation(pointer_in_scene.to_vec2())
|
||||
* TSTransform::from_scaling(zoom_delta)
|
||||
* TSTransform::from_translation(-pointer_in_scene.to_vec2());
|
||||
|
||||
// Clamp to exact zoom range.
|
||||
to_global.scaling = self.zoom_range.clamp(to_global.scaling);
|
||||
}
|
||||
|
||||
// Pan:
|
||||
*to_global = TSTransform::from_translation(pan_delta) * *to_global;
|
||||
resp.mark_changed();
|
||||
// Most of the time we can return early. This is also important to
|
||||
// avoid `ui_from_scene` to change slightly due to floating point errors.
|
||||
if zoom_delta == 1.0 && pan_delta == Vec2::ZERO {
|
||||
return;
|
||||
}
|
||||
|
||||
if zoom_delta != 1.0 {
|
||||
// Zoom in on pointer, but only if we are not zoomed in or out too far.
|
||||
let zoom_delta = zoom_delta.clamp(
|
||||
self.zoom_range.min / to_global.scaling,
|
||||
self.zoom_range.max / to_global.scaling,
|
||||
);
|
||||
|
||||
*to_global = *to_global
|
||||
* TSTransform::from_translation(pointer_in_scene.to_vec2())
|
||||
* TSTransform::from_scaling(zoom_delta)
|
||||
* TSTransform::from_translation(-pointer_in_scene.to_vec2());
|
||||
|
||||
// Clamp to exact zoom range.
|
||||
to_global.scaling = self.zoom_range.clamp(to_global.scaling);
|
||||
}
|
||||
|
||||
// Pan:
|
||||
*to_global = TSTransform::from_translation(pan_delta) * *to_global;
|
||||
resp.mark_changed();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -829,10 +829,10 @@ impl ScrollArea {
|
||||
if let Some(cursor) = on_drag_cursor {
|
||||
response.on_hover_cursor(cursor);
|
||||
}
|
||||
} else if response.hovered() {
|
||||
if let Some(cursor) = on_hover_cursor {
|
||||
response.on_hover_cursor(cursor);
|
||||
}
|
||||
} else if response.hovered()
|
||||
&& let Some(cursor) = on_hover_cursor
|
||||
{
|
||||
response.on_hover_cursor(cursor);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -645,10 +645,10 @@ impl Window<'_> {
|
||||
|
||||
let full_response = area.end(ctx, area_content_ui);
|
||||
|
||||
if full_response.should_close() {
|
||||
if let Some(open) = open {
|
||||
*open = false;
|
||||
}
|
||||
if full_response.should_close()
|
||||
&& let Some(open) = open
|
||||
{
|
||||
*open = false;
|
||||
}
|
||||
|
||||
let inner_response = InnerResponse {
|
||||
@@ -839,11 +839,11 @@ fn resize_response(
|
||||
// TODO(emilk): add this to a Window state instead as a command "move here next frame"
|
||||
area.state_mut().set_left_top_pos(new_rect.left_top());
|
||||
|
||||
if resize_interaction.any_dragged() {
|
||||
if let Some(mut state) = resize::State::load(ctx, resize_id) {
|
||||
state.requested_size = Some(new_rect.size() - margins);
|
||||
state.store(ctx, resize_id);
|
||||
}
|
||||
if resize_interaction.any_dragged()
|
||||
&& let Some(mut state) = resize::State::load(ctx, resize_id)
|
||||
{
|
||||
state.requested_size = Some(new_rect.size() - margins);
|
||||
state.store(ctx, resize_id);
|
||||
}
|
||||
|
||||
ctx.memory_mut(|mem| mem.areas_mut().move_to_top(area_layer_id));
|
||||
|
||||
@@ -426,20 +426,18 @@ impl ContextImpl {
|
||||
|
||||
let viewport = self.viewports.entry(viewport_id).or_default();
|
||||
|
||||
if is_outermost_viewport {
|
||||
if let Some(new_zoom_factor) = self.new_zoom_factor.take() {
|
||||
let ratio = self.memory.options.zoom_factor / new_zoom_factor;
|
||||
self.memory.options.zoom_factor = new_zoom_factor;
|
||||
if is_outermost_viewport && let Some(new_zoom_factor) = self.new_zoom_factor.take() {
|
||||
let ratio = self.memory.options.zoom_factor / new_zoom_factor;
|
||||
self.memory.options.zoom_factor = new_zoom_factor;
|
||||
|
||||
let input = &viewport.input;
|
||||
// This is a bit hacky, but is required to avoid jitter:
|
||||
let mut rect = input.screen_rect;
|
||||
rect.min = (ratio * rect.min.to_vec2()).to_pos2();
|
||||
rect.max = (ratio * rect.max.to_vec2()).to_pos2();
|
||||
new_raw_input.screen_rect = Some(rect);
|
||||
// We should really scale everything else in the input too,
|
||||
// but the `screen_rect` is the most important part.
|
||||
}
|
||||
let input = &viewport.input;
|
||||
// This is a bit hacky, but is required to avoid jitter:
|
||||
let mut rect = input.screen_rect;
|
||||
rect.min = (ratio * rect.min.to_vec2()).to_pos2();
|
||||
rect.max = (ratio * rect.max.to_vec2()).to_pos2();
|
||||
new_raw_input.screen_rect = Some(rect);
|
||||
// We should really scale everything else in the input too,
|
||||
// but the `screen_rect` is the most important part.
|
||||
}
|
||||
let native_pixels_per_point = new_raw_input
|
||||
.viewport()
|
||||
@@ -1105,15 +1103,16 @@ impl Context {
|
||||
)
|
||||
};
|
||||
|
||||
if let Some(pointer_pos) = self.pointer_hover_pos() {
|
||||
if text_rect.contains(pointer_pos) {
|
||||
let tooltip_pos = if below {
|
||||
text_rect.left_bottom() + vec2(2.0, 4.0)
|
||||
} else {
|
||||
text_rect.left_top() + vec2(2.0, -4.0)
|
||||
};
|
||||
if let Some(pointer_pos) = self.pointer_hover_pos()
|
||||
&& text_rect.contains(pointer_pos)
|
||||
{
|
||||
let tooltip_pos = if below {
|
||||
text_rect.left_bottom() + vec2(2.0, 4.0)
|
||||
} else {
|
||||
text_rect.left_top() + vec2(2.0, -4.0)
|
||||
};
|
||||
|
||||
painter.error(
|
||||
painter.error(
|
||||
tooltip_pos,
|
||||
format!("Widget is {} this text.\n\n\
|
||||
ID clashes happens when things like Windows or CollapsingHeaders share names,\n\
|
||||
@@ -1121,7 +1120,6 @@ impl Context {
|
||||
Sometimes the solution is to use ui.push_id.",
|
||||
if below { "above" } else { "below" }),
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -1253,10 +1251,10 @@ impl Context {
|
||||
widget_rect.map(|mut rect| {
|
||||
// If the Rect is invalid the Ui hasn't registered its final Rect yet.
|
||||
// We return the Rect from last frame instead.
|
||||
if !(rect.rect.is_positive() && rect.rect.is_finite()) {
|
||||
if let Some(prev_rect) = viewport.prev_pass.widgets.get(id) {
|
||||
rect.rect = prev_rect.rect;
|
||||
}
|
||||
if !(rect.rect.is_positive() && rect.rect.is_finite())
|
||||
&& let Some(prev_rect) = viewport.prev_pass.widgets.get(id)
|
||||
{
|
||||
rect.rect = prev_rect.rect;
|
||||
}
|
||||
rect
|
||||
})
|
||||
@@ -1961,14 +1959,13 @@ impl Context {
|
||||
let mut update_fonts = true;
|
||||
|
||||
self.read(|ctx| {
|
||||
if let Some(current_fonts) = ctx.fonts.as_ref() {
|
||||
if current_fonts
|
||||
if let Some(current_fonts) = ctx.fonts.as_ref()
|
||||
&& current_fonts
|
||||
.definitions()
|
||||
.font_data
|
||||
.contains_key(&new_font.name)
|
||||
{
|
||||
update_fonts = false; // no need to update
|
||||
}
|
||||
{
|
||||
update_fonts = false; // no need to update
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
@@ -317,19 +317,18 @@ fn hit_test_on_close(close: &[WidgetRect], pos: Pos2) -> WidgetHits {
|
||||
pos,
|
||||
);
|
||||
|
||||
if let Some(closest_drag) = closest_drag {
|
||||
if hit_drag
|
||||
if let Some(closest_drag) = closest_drag
|
||||
&& hit_drag
|
||||
.interact_rect
|
||||
.contains_rect(closest_drag.interact_rect)
|
||||
{
|
||||
// `hit_drag` is a big background thing and `closest_drag` is something small on top of it.
|
||||
// Be helpful and return the small things:
|
||||
return WidgetHits {
|
||||
click: None,
|
||||
drag: Some(closest_drag),
|
||||
..Default::default()
|
||||
};
|
||||
}
|
||||
{
|
||||
// `hit_drag` is a big background thing and `closest_drag` is something small on top of it.
|
||||
// Be helpful and return the small things:
|
||||
return WidgetHits {
|
||||
click: None,
|
||||
drag: Some(closest_drag),
|
||||
..Default::default()
|
||||
};
|
||||
}
|
||||
|
||||
WidgetHits {
|
||||
@@ -425,13 +424,13 @@ fn find_closest_within(
|
||||
|
||||
let dist_sq = widget.interact_rect.distance_sq_to_pos(pos);
|
||||
|
||||
if let Some(closest) = closest {
|
||||
if dist_sq == closest_dist_sq {
|
||||
// It's a tie! Pick the thin candidate over the thick one.
|
||||
// This makes it easier to hit a thin resize-handle, for instance:
|
||||
if should_prioritize_hits_on_back(closest.interact_rect, widget.interact_rect) {
|
||||
continue;
|
||||
}
|
||||
if let Some(closest) = closest
|
||||
&& dist_sq == closest_dist_sq
|
||||
{
|
||||
// It's a tie! Pick the thin candidate over the thick one.
|
||||
// This makes it easier to hit a thin resize-handle, for instance:
|
||||
if should_prioritize_hits_on_back(closest.interact_rect, widget.interact_rect) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -884,10 +884,11 @@ impl InputState {
|
||||
) -> impl Iterator<Item = &accesskit::ActionRequest> {
|
||||
let accesskit_id = id.accesskit_id();
|
||||
self.events.iter().filter_map(move |event| {
|
||||
if let Event::AccessKitActionRequest(request) = event {
|
||||
if request.target == accesskit_id && request.action == action {
|
||||
return Some(request);
|
||||
}
|
||||
if let Event::AccessKitActionRequest(request) = event
|
||||
&& request.target == accesskit_id
|
||||
&& request.action == action
|
||||
{
|
||||
return Some(request);
|
||||
}
|
||||
None
|
||||
})
|
||||
@@ -901,10 +902,10 @@ impl InputState {
|
||||
) {
|
||||
let accesskit_id = id.accesskit_id();
|
||||
self.events.retain(|event| {
|
||||
if let Event::AccessKitActionRequest(request) = event {
|
||||
if request.target == accesskit_id {
|
||||
return !consume(request);
|
||||
}
|
||||
if let Event::AccessKitActionRequest(request) = event
|
||||
&& request.target == accesskit_id
|
||||
{
|
||||
return !consume(request);
|
||||
}
|
||||
true
|
||||
});
|
||||
@@ -1468,10 +1469,10 @@ impl PointerState {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(press_start_time) = self.press_start_time {
|
||||
if self.time - press_start_time > self.options.max_click_duration {
|
||||
return false;
|
||||
}
|
||||
if let Some(press_start_time) = self.press_start_time
|
||||
&& self.time - press_start_time > self.options.max_click_duration
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
true
|
||||
|
||||
@@ -115,19 +115,19 @@ pub(crate) fn interact(
|
||||
) -> InteractionSnapshot {
|
||||
profiling::function_scope!();
|
||||
|
||||
if let Some(id) = interaction.potential_click_id {
|
||||
if !widgets.contains(id) {
|
||||
// The widget we were interested in clicking is gone.
|
||||
interaction.potential_click_id = None;
|
||||
}
|
||||
if let Some(id) = interaction.potential_click_id
|
||||
&& !widgets.contains(id)
|
||||
{
|
||||
// The widget we were interested in clicking is gone.
|
||||
interaction.potential_click_id = None;
|
||||
}
|
||||
if let Some(id) = interaction.potential_drag_id {
|
||||
if !widgets.contains(id) {
|
||||
// The widget we were interested in dragging is gone.
|
||||
// This is fine! This could be drag-and-drop,
|
||||
// and the widget being dragged is now "in the air" and thus
|
||||
// not registered in the new frame.
|
||||
}
|
||||
if let Some(id) = interaction.potential_drag_id
|
||||
&& !widgets.contains(id)
|
||||
{
|
||||
// The widget we were interested in dragging is gone.
|
||||
// This is fine! This could be drag-and-drop,
|
||||
// and the widget being dragged is now "in the air" and thus
|
||||
// not registered in the new frame.
|
||||
}
|
||||
|
||||
let mut clicked = None;
|
||||
@@ -172,13 +172,13 @@ pub(crate) fn interact(
|
||||
}
|
||||
|
||||
PointerEvent::Released { click, button: _ } => {
|
||||
if click.is_some() && !input.pointer.is_decidedly_dragging() {
|
||||
if let Some(widget) = interaction
|
||||
if click.is_some()
|
||||
&& !input.pointer.is_decidedly_dragging()
|
||||
&& let Some(widget) = interaction
|
||||
.potential_click_id
|
||||
.and_then(|id| widgets.get(id))
|
||||
{
|
||||
clicked = Some(widget.id);
|
||||
}
|
||||
{
|
||||
clicked = Some(widget.id);
|
||||
}
|
||||
|
||||
interaction.potential_drag_id = None;
|
||||
@@ -190,21 +190,21 @@ pub(crate) fn interact(
|
||||
|
||||
if dragged.is_none() {
|
||||
// Check if we started dragging something new:
|
||||
if let Some(widget) = interaction.potential_drag_id.and_then(|id| widgets.get(id)) {
|
||||
if widget.enabled {
|
||||
let is_dragged = if widget.sense.senses_click() && widget.sense.senses_drag() {
|
||||
// This widget is sensitive to both clicks and drags.
|
||||
// When the mouse first is pressed, it could be either,
|
||||
// so we postpone the decision until we know.
|
||||
input.pointer.is_decidedly_dragging()
|
||||
} else {
|
||||
// This widget is just sensitive to drags, so we can mark it as dragged right away:
|
||||
widget.sense.senses_drag()
|
||||
};
|
||||
if let Some(widget) = interaction.potential_drag_id.and_then(|id| widgets.get(id))
|
||||
&& widget.enabled
|
||||
{
|
||||
let is_dragged = if widget.sense.senses_click() && widget.sense.senses_drag() {
|
||||
// This widget is sensitive to both clicks and drags.
|
||||
// When the mouse first is pressed, it could be either,
|
||||
// so we postpone the decision until we know.
|
||||
input.pointer.is_decidedly_dragging()
|
||||
} else {
|
||||
// This widget is just sensitive to drags, so we can mark it as dragged right away:
|
||||
widget.sense.senses_drag()
|
||||
};
|
||||
|
||||
if is_dragged {
|
||||
dragged = Some(widget.id);
|
||||
}
|
||||
if is_dragged {
|
||||
dragged = Some(widget.id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,15 +236,15 @@ impl GraphicLayers {
|
||||
|
||||
// First do the layers part of area_order:
|
||||
for layer_id in area_order {
|
||||
if layer_id.order == order {
|
||||
if let Some(list) = order_map.get_mut(&layer_id.id) {
|
||||
if let Some(to_global) = to_global.get(layer_id) {
|
||||
for clipped_shape in &mut list.0 {
|
||||
clipped_shape.transform(*to_global);
|
||||
}
|
||||
if layer_id.order == order
|
||||
&& let Some(list) = order_map.get_mut(&layer_id.id)
|
||||
{
|
||||
if let Some(to_global) = to_global.get(layer_id) {
|
||||
for clipped_shape in &mut list.0 {
|
||||
clipped_shape.transform(*to_global);
|
||||
}
|
||||
all_shapes.append(&mut list.0);
|
||||
}
|
||||
all_shapes.append(&mut list.0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -535,36 +535,34 @@ impl Focus {
|
||||
self.focus_direction = FocusDirection::None;
|
||||
|
||||
for event in &new_input.events {
|
||||
if !event_filter.matches(event) {
|
||||
if let crate::Event::Key {
|
||||
if !event_filter.matches(event)
|
||||
&& let crate::Event::Key {
|
||||
key,
|
||||
pressed: true,
|
||||
modifiers,
|
||||
..
|
||||
} = event
|
||||
{
|
||||
if let Some(cardinality) = match key {
|
||||
crate::Key::ArrowUp => Some(FocusDirection::Up),
|
||||
crate::Key::ArrowRight => Some(FocusDirection::Right),
|
||||
crate::Key::ArrowDown => Some(FocusDirection::Down),
|
||||
crate::Key::ArrowLeft => Some(FocusDirection::Left),
|
||||
&& let Some(cardinality) = match key {
|
||||
crate::Key::ArrowUp => Some(FocusDirection::Up),
|
||||
crate::Key::ArrowRight => Some(FocusDirection::Right),
|
||||
crate::Key::ArrowDown => Some(FocusDirection::Down),
|
||||
crate::Key::ArrowLeft => Some(FocusDirection::Left),
|
||||
|
||||
crate::Key::Tab => {
|
||||
if modifiers.shift {
|
||||
Some(FocusDirection::Previous)
|
||||
} else {
|
||||
Some(FocusDirection::Next)
|
||||
}
|
||||
crate::Key::Tab => {
|
||||
if modifiers.shift {
|
||||
Some(FocusDirection::Previous)
|
||||
} else {
|
||||
Some(FocusDirection::Next)
|
||||
}
|
||||
crate::Key::Escape => {
|
||||
self.focused_widget = None;
|
||||
Some(FocusDirection::None)
|
||||
}
|
||||
_ => None,
|
||||
} {
|
||||
self.focus_direction = cardinality;
|
||||
}
|
||||
crate::Key::Escape => {
|
||||
self.focused_widget = None;
|
||||
Some(FocusDirection::None)
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
{
|
||||
self.focus_direction = cardinality;
|
||||
}
|
||||
|
||||
#[cfg(feature = "accesskit")]
|
||||
@@ -582,10 +580,10 @@ impl Focus {
|
||||
}
|
||||
|
||||
pub(crate) fn end_pass(&mut self, used_ids: &IdMap<Rect>) {
|
||||
if self.focus_direction.is_cardinal() {
|
||||
if let Some(found_widget) = self.find_widget_in_direction(used_ids) {
|
||||
self.focused_widget = Some(FocusWidget::new(found_widget));
|
||||
}
|
||||
if self.focus_direction.is_cardinal()
|
||||
&& let Some(found_widget) = self.find_widget_in_direction(used_ids)
|
||||
{
|
||||
self.focused_widget = Some(FocusWidget::new(found_widget));
|
||||
}
|
||||
|
||||
if let Some(focused_widget) = self.focused_widget {
|
||||
@@ -858,12 +856,12 @@ impl Memory {
|
||||
///
|
||||
/// You must first give focus to the widget before calling this.
|
||||
pub fn set_focus_lock_filter(&mut self, id: Id, event_filter: EventFilter) {
|
||||
if self.had_focus_last_frame(id) && self.has_focus(id) {
|
||||
if let Some(focused) = &mut self.focus_mut().focused_widget {
|
||||
if focused.id == id {
|
||||
focused.filter = event_filter;
|
||||
}
|
||||
}
|
||||
if self.had_focus_last_frame(id)
|
||||
&& self.has_focus(id)
|
||||
&& let Some(focused) = &mut self.focus_mut().focused_widget
|
||||
&& focused.id == id
|
||||
{
|
||||
focused.filter = event_filter;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -933,13 +931,13 @@ impl Memory {
|
||||
/// Limit focus to widgets on the given layer and above.
|
||||
/// If this is called multiple times per frame, the top layer wins.
|
||||
pub fn set_modal_layer(&mut self, layer_id: LayerId) {
|
||||
if let Some(current) = self.focus().and_then(|f| f.top_modal_layer_current_frame) {
|
||||
if matches!(
|
||||
if let Some(current) = self.focus().and_then(|f| f.top_modal_layer_current_frame)
|
||||
&& matches!(
|
||||
self.areas().compare_order(layer_id, current),
|
||||
std::cmp::Ordering::Less
|
||||
) {
|
||||
return;
|
||||
}
|
||||
)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
self.focus_mut().set_modal_layer(layer_id);
|
||||
@@ -1047,10 +1045,10 @@ impl Memory {
|
||||
/// being rendered.
|
||||
#[deprecated = "Use Popup::show instead"]
|
||||
pub fn keep_popup_open(&mut self, popup_id: Id) {
|
||||
if let Some(state) = self.popups.get_mut(&self.viewport_id) {
|
||||
if state.id == popup_id {
|
||||
state.open_this_frame = true;
|
||||
}
|
||||
if let Some(state) = self.popups.get_mut(&self.viewport_id)
|
||||
&& state.id == popup_id
|
||||
{
|
||||
state.open_this_frame = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1200,17 +1198,17 @@ impl Areas {
|
||||
layer_to_global: &HashMap<LayerId, TSTransform>,
|
||||
) -> Option<LayerId> {
|
||||
for layer in self.order.iter().rev() {
|
||||
if self.is_visible(layer) {
|
||||
if let Some(state) = self.areas.get(&layer.id) {
|
||||
let mut rect = state.rect();
|
||||
if state.interactable {
|
||||
if let Some(to_global) = layer_to_global.get(layer) {
|
||||
rect = *to_global * rect;
|
||||
}
|
||||
if self.is_visible(layer)
|
||||
&& let Some(state) = self.areas.get(&layer.id)
|
||||
{
|
||||
let mut rect = state.rect();
|
||||
if state.interactable {
|
||||
if let Some(to_global) = layer_to_global.get(layer) {
|
||||
rect = *to_global * rect;
|
||||
}
|
||||
|
||||
if rect.contains(pos) {
|
||||
return Some(*layer);
|
||||
}
|
||||
if rect.contains(pos) {
|
||||
return Some(*layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -420,17 +420,14 @@ impl MenuRoot {
|
||||
} else if button
|
||||
.ctx
|
||||
.input(|i| i.pointer.any_pressed() && i.pointer.primary_down())
|
||||
&& let Some(pos) = button.ctx.input(|i| i.pointer.interact_pos())
|
||||
&& let Some(root) = root.inner.as_mut()
|
||||
&& root.id == id
|
||||
{
|
||||
if let Some(pos) = button.ctx.input(|i| i.pointer.interact_pos()) {
|
||||
if let Some(root) = root.inner.as_mut() {
|
||||
if root.id == id {
|
||||
// pressed somewhere while this menu is open
|
||||
let in_menu = root.menu_state.read().area_contains(pos);
|
||||
if !in_menu {
|
||||
return MenuResponse::Close;
|
||||
}
|
||||
}
|
||||
}
|
||||
// pressed somewhere while this menu is open
|
||||
let in_menu = root.menu_state.read().area_contains(pos);
|
||||
if !in_menu {
|
||||
return MenuResponse::Close;
|
||||
}
|
||||
}
|
||||
MenuResponse::Stay
|
||||
@@ -728,21 +725,21 @@ impl MenuState {
|
||||
return false;
|
||||
}
|
||||
|
||||
if let Some(sub_menu) = self.current_submenu() {
|
||||
if let Some(pos) = pointer.hover_pos() {
|
||||
let rect = sub_menu.read().rect;
|
||||
return rect.intersects_ray(pos, pointer.direction().normalized());
|
||||
}
|
||||
if let Some(sub_menu) = self.current_submenu()
|
||||
&& let Some(pos) = pointer.hover_pos()
|
||||
{
|
||||
let rect = sub_menu.read().rect;
|
||||
return rect.intersects_ray(pos, pointer.direction().normalized());
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
/// Check if pointer is hovering current submenu.
|
||||
fn hovering_current_submenu(&self, pointer: &PointerState) -> bool {
|
||||
if let Some(sub_menu) = self.current_submenu() {
|
||||
if let Some(pos) = pointer.hover_pos() {
|
||||
return sub_menu.read().area_contains(pos);
|
||||
}
|
||||
if let Some(sub_menu) = self.current_submenu()
|
||||
&& let Some(pos) = pointer.hover_pos()
|
||||
{
|
||||
return sub_menu.read().area_contains(pos);
|
||||
}
|
||||
false
|
||||
}
|
||||
|
||||
@@ -316,74 +316,74 @@ impl LabelSelectionState {
|
||||
let may_select_widget =
|
||||
multi_widget_text_select || selection.primary.widget_id == response.id;
|
||||
|
||||
if self.is_dragging && may_select_widget {
|
||||
if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() {
|
||||
let galley_rect =
|
||||
global_from_galley * Rect::from_min_size(Pos2::ZERO, galley.size());
|
||||
let galley_rect = galley_rect.intersect(ui.clip_rect());
|
||||
if self.is_dragging
|
||||
&& may_select_widget
|
||||
&& let Some(pointer_pos) = ui.ctx().pointer_interact_pos()
|
||||
{
|
||||
let galley_rect = global_from_galley * Rect::from_min_size(Pos2::ZERO, galley.size());
|
||||
let galley_rect = galley_rect.intersect(ui.clip_rect());
|
||||
|
||||
let is_in_same_column = galley_rect
|
||||
.x_range()
|
||||
.intersects(self.selection_bbox_last_frame.x_range());
|
||||
let is_in_same_column = galley_rect
|
||||
.x_range()
|
||||
.intersects(self.selection_bbox_last_frame.x_range());
|
||||
|
||||
let has_reached_primary =
|
||||
self.has_reached_primary || response.id == selection.primary.widget_id;
|
||||
let has_reached_secondary =
|
||||
self.has_reached_secondary || response.id == selection.secondary.widget_id;
|
||||
let has_reached_primary =
|
||||
self.has_reached_primary || response.id == selection.primary.widget_id;
|
||||
let has_reached_secondary =
|
||||
self.has_reached_secondary || response.id == selection.secondary.widget_id;
|
||||
|
||||
let new_primary = if response.contains_pointer() {
|
||||
// Dragging into this widget - easy case:
|
||||
Some(galley.cursor_from_pos((galley_from_global * pointer_pos).to_vec2()))
|
||||
} else if is_in_same_column
|
||||
&& !self.has_reached_primary
|
||||
&& selection.primary.pos.y <= selection.secondary.pos.y
|
||||
&& pointer_pos.y <= galley_rect.top()
|
||||
&& galley_rect.top() <= selection.secondary.pos.y
|
||||
{
|
||||
// The user is dragging the text selection upwards, above the first selected widget (this one):
|
||||
if DEBUG {
|
||||
ui.ctx()
|
||||
.debug_text(format!("Upwards drag; include {:?}", response.id));
|
||||
}
|
||||
Some(galley.begin())
|
||||
} else if is_in_same_column
|
||||
&& has_reached_secondary
|
||||
&& has_reached_primary
|
||||
&& selection.secondary.pos.y <= selection.primary.pos.y
|
||||
&& selection.secondary.pos.y <= galley_rect.bottom()
|
||||
&& galley_rect.bottom() <= pointer_pos.y
|
||||
{
|
||||
// The user is dragging the text selection downwards, below this widget.
|
||||
// We move the cursor to the end of this widget,
|
||||
// (and we may do the same for the next widget too).
|
||||
if DEBUG {
|
||||
ui.ctx()
|
||||
.debug_text(format!("Downwards drag; include {:?}", response.id));
|
||||
}
|
||||
Some(galley.end())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let new_primary = if response.contains_pointer() {
|
||||
// Dragging into this widget - easy case:
|
||||
Some(galley.cursor_from_pos((galley_from_global * pointer_pos).to_vec2()))
|
||||
} else if is_in_same_column
|
||||
&& !self.has_reached_primary
|
||||
&& selection.primary.pos.y <= selection.secondary.pos.y
|
||||
&& pointer_pos.y <= galley_rect.top()
|
||||
&& galley_rect.top() <= selection.secondary.pos.y
|
||||
{
|
||||
// The user is dragging the text selection upwards, above the first selected widget (this one):
|
||||
if DEBUG {
|
||||
ui.ctx()
|
||||
.debug_text(format!("Upwards drag; include {:?}", response.id));
|
||||
}
|
||||
Some(galley.begin())
|
||||
} else if is_in_same_column
|
||||
&& has_reached_secondary
|
||||
&& has_reached_primary
|
||||
&& selection.secondary.pos.y <= selection.primary.pos.y
|
||||
&& selection.secondary.pos.y <= galley_rect.bottom()
|
||||
&& galley_rect.bottom() <= pointer_pos.y
|
||||
{
|
||||
// The user is dragging the text selection downwards, below this widget.
|
||||
// We move the cursor to the end of this widget,
|
||||
// (and we may do the same for the next widget too).
|
||||
if DEBUG {
|
||||
ui.ctx()
|
||||
.debug_text(format!("Downwards drag; include {:?}", response.id));
|
||||
}
|
||||
Some(galley.end())
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(new_primary) = new_primary {
|
||||
selection.primary =
|
||||
WidgetTextCursor::new(response.id, new_primary, global_from_galley, galley);
|
||||
if let Some(new_primary) = new_primary {
|
||||
selection.primary =
|
||||
WidgetTextCursor::new(response.id, new_primary, global_from_galley, galley);
|
||||
|
||||
// We don't want the latency of `drag_started`.
|
||||
let drag_started = ui.input(|i| i.pointer.any_pressed());
|
||||
if drag_started {
|
||||
if selection.layer_id == response.layer_id {
|
||||
if ui.input(|i| i.modifiers.shift) {
|
||||
// A continuation of a previous selection.
|
||||
} else {
|
||||
// A new selection in the same layer.
|
||||
selection.secondary = selection.primary;
|
||||
}
|
||||
// We don't want the latency of `drag_started`.
|
||||
let drag_started = ui.input(|i| i.pointer.any_pressed());
|
||||
if drag_started {
|
||||
if selection.layer_id == response.layer_id {
|
||||
if ui.input(|i| i.modifiers.shift) {
|
||||
// A continuation of a previous selection.
|
||||
} else {
|
||||
// A new selection in a new layer.
|
||||
selection.layer_id = response.layer_id;
|
||||
// A new selection in the same layer.
|
||||
selection.secondary = selection.primary;
|
||||
}
|
||||
} else {
|
||||
// A new selection in a new layer.
|
||||
selection.layer_id = response.layer_id;
|
||||
selection.secondary = selection.primary;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -511,26 +511,26 @@ impl LabelSelectionState {
|
||||
|
||||
let old_range = cursor_state.range(galley);
|
||||
|
||||
if let Some(pointer_pos) = ui.ctx().pointer_interact_pos() {
|
||||
if response.contains_pointer() {
|
||||
let cursor_at_pointer =
|
||||
galley.cursor_from_pos((galley_from_global * pointer_pos).to_vec2());
|
||||
if let Some(pointer_pos) = ui.ctx().pointer_interact_pos()
|
||||
&& response.contains_pointer()
|
||||
{
|
||||
let cursor_at_pointer =
|
||||
galley.cursor_from_pos((galley_from_global * pointer_pos).to_vec2());
|
||||
|
||||
// This is where we handle start-of-drag and double-click-to-select.
|
||||
// Actual drag-to-select happens elsewhere.
|
||||
let dragged = false;
|
||||
cursor_state.pointer_interaction(ui, response, cursor_at_pointer, galley, dragged);
|
||||
}
|
||||
// This is where we handle start-of-drag and double-click-to-select.
|
||||
// Actual drag-to-select happens elsewhere.
|
||||
let dragged = false;
|
||||
cursor_state.pointer_interaction(ui, response, cursor_at_pointer, galley, dragged);
|
||||
}
|
||||
|
||||
if let Some(mut cursor_range) = cursor_state.range(galley) {
|
||||
let galley_rect = global_from_galley * Rect::from_min_size(Pos2::ZERO, galley.size());
|
||||
self.selection_bbox_this_frame |= galley_rect;
|
||||
|
||||
if let Some(selection) = &self.selection {
|
||||
if selection.primary.widget_id == response.id {
|
||||
process_selection_key_events(ui.ctx(), galley, response.id, &mut cursor_range);
|
||||
}
|
||||
if let Some(selection) = &self.selection
|
||||
&& selection.primary.widget_id == response.id
|
||||
{
|
||||
process_selection_key_events(ui.ctx(), galley, response.id, &mut cursor_range);
|
||||
}
|
||||
|
||||
if got_copy_event(ui.ctx()) {
|
||||
|
||||
@@ -705,74 +705,74 @@ impl ViewportBuilder {
|
||||
|
||||
let mut commands = Vec::new();
|
||||
|
||||
if let Some(new_title) = new_title {
|
||||
if Some(&new_title) != self.title.as_ref() {
|
||||
self.title = Some(new_title.clone());
|
||||
commands.push(ViewportCommand::Title(new_title));
|
||||
}
|
||||
if let Some(new_title) = new_title
|
||||
&& Some(&new_title) != self.title.as_ref()
|
||||
{
|
||||
self.title = Some(new_title.clone());
|
||||
commands.push(ViewportCommand::Title(new_title));
|
||||
}
|
||||
|
||||
if let Some(new_position) = new_position {
|
||||
if Some(new_position) != self.position {
|
||||
self.position = Some(new_position);
|
||||
commands.push(ViewportCommand::OuterPosition(new_position));
|
||||
}
|
||||
if let Some(new_position) = new_position
|
||||
&& Some(new_position) != self.position
|
||||
{
|
||||
self.position = Some(new_position);
|
||||
commands.push(ViewportCommand::OuterPosition(new_position));
|
||||
}
|
||||
|
||||
if let Some(new_inner_size) = new_inner_size {
|
||||
if Some(new_inner_size) != self.inner_size {
|
||||
self.inner_size = Some(new_inner_size);
|
||||
commands.push(ViewportCommand::InnerSize(new_inner_size));
|
||||
}
|
||||
if let Some(new_inner_size) = new_inner_size
|
||||
&& Some(new_inner_size) != self.inner_size
|
||||
{
|
||||
self.inner_size = Some(new_inner_size);
|
||||
commands.push(ViewportCommand::InnerSize(new_inner_size));
|
||||
}
|
||||
|
||||
if let Some(new_min_inner_size) = new_min_inner_size {
|
||||
if Some(new_min_inner_size) != self.min_inner_size {
|
||||
self.min_inner_size = Some(new_min_inner_size);
|
||||
commands.push(ViewportCommand::MinInnerSize(new_min_inner_size));
|
||||
}
|
||||
if let Some(new_min_inner_size) = new_min_inner_size
|
||||
&& Some(new_min_inner_size) != self.min_inner_size
|
||||
{
|
||||
self.min_inner_size = Some(new_min_inner_size);
|
||||
commands.push(ViewportCommand::MinInnerSize(new_min_inner_size));
|
||||
}
|
||||
|
||||
if let Some(new_max_inner_size) = new_max_inner_size {
|
||||
if Some(new_max_inner_size) != self.max_inner_size {
|
||||
self.max_inner_size = Some(new_max_inner_size);
|
||||
commands.push(ViewportCommand::MaxInnerSize(new_max_inner_size));
|
||||
}
|
||||
if let Some(new_max_inner_size) = new_max_inner_size
|
||||
&& Some(new_max_inner_size) != self.max_inner_size
|
||||
{
|
||||
self.max_inner_size = Some(new_max_inner_size);
|
||||
commands.push(ViewportCommand::MaxInnerSize(new_max_inner_size));
|
||||
}
|
||||
|
||||
if let Some(new_fullscreen) = new_fullscreen {
|
||||
if Some(new_fullscreen) != self.fullscreen {
|
||||
self.fullscreen = Some(new_fullscreen);
|
||||
commands.push(ViewportCommand::Fullscreen(new_fullscreen));
|
||||
}
|
||||
if let Some(new_fullscreen) = new_fullscreen
|
||||
&& Some(new_fullscreen) != self.fullscreen
|
||||
{
|
||||
self.fullscreen = Some(new_fullscreen);
|
||||
commands.push(ViewportCommand::Fullscreen(new_fullscreen));
|
||||
}
|
||||
|
||||
if let Some(new_maximized) = new_maximized {
|
||||
if Some(new_maximized) != self.maximized {
|
||||
self.maximized = Some(new_maximized);
|
||||
commands.push(ViewportCommand::Maximized(new_maximized));
|
||||
}
|
||||
if let Some(new_maximized) = new_maximized
|
||||
&& Some(new_maximized) != self.maximized
|
||||
{
|
||||
self.maximized = Some(new_maximized);
|
||||
commands.push(ViewportCommand::Maximized(new_maximized));
|
||||
}
|
||||
|
||||
if let Some(new_resizable) = new_resizable {
|
||||
if Some(new_resizable) != self.resizable {
|
||||
self.resizable = Some(new_resizable);
|
||||
commands.push(ViewportCommand::Resizable(new_resizable));
|
||||
}
|
||||
if let Some(new_resizable) = new_resizable
|
||||
&& Some(new_resizable) != self.resizable
|
||||
{
|
||||
self.resizable = Some(new_resizable);
|
||||
commands.push(ViewportCommand::Resizable(new_resizable));
|
||||
}
|
||||
|
||||
if let Some(new_transparent) = new_transparent {
|
||||
if Some(new_transparent) != self.transparent {
|
||||
self.transparent = Some(new_transparent);
|
||||
commands.push(ViewportCommand::Transparent(new_transparent));
|
||||
}
|
||||
if let Some(new_transparent) = new_transparent
|
||||
&& Some(new_transparent) != self.transparent
|
||||
{
|
||||
self.transparent = Some(new_transparent);
|
||||
commands.push(ViewportCommand::Transparent(new_transparent));
|
||||
}
|
||||
|
||||
if let Some(new_decorations) = new_decorations {
|
||||
if Some(new_decorations) != self.decorations {
|
||||
self.decorations = Some(new_decorations);
|
||||
commands.push(ViewportCommand::Decorations(new_decorations));
|
||||
}
|
||||
if let Some(new_decorations) = new_decorations
|
||||
&& Some(new_decorations) != self.decorations
|
||||
{
|
||||
self.decorations = Some(new_decorations);
|
||||
commands.push(ViewportCommand::Decorations(new_decorations));
|
||||
}
|
||||
|
||||
if let Some(new_icon) = new_icon {
|
||||
@@ -787,25 +787,25 @@ impl ViewportBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(new_visible) = new_visible {
|
||||
if Some(new_visible) != self.visible {
|
||||
self.visible = Some(new_visible);
|
||||
commands.push(ViewportCommand::Visible(new_visible));
|
||||
}
|
||||
if let Some(new_visible) = new_visible
|
||||
&& Some(new_visible) != self.visible
|
||||
{
|
||||
self.visible = Some(new_visible);
|
||||
commands.push(ViewportCommand::Visible(new_visible));
|
||||
}
|
||||
|
||||
if let Some(new_mouse_passthrough) = new_mouse_passthrough {
|
||||
if Some(new_mouse_passthrough) != self.mouse_passthrough {
|
||||
self.mouse_passthrough = Some(new_mouse_passthrough);
|
||||
commands.push(ViewportCommand::MousePassthrough(new_mouse_passthrough));
|
||||
}
|
||||
if let Some(new_mouse_passthrough) = new_mouse_passthrough
|
||||
&& Some(new_mouse_passthrough) != self.mouse_passthrough
|
||||
{
|
||||
self.mouse_passthrough = Some(new_mouse_passthrough);
|
||||
commands.push(ViewportCommand::MousePassthrough(new_mouse_passthrough));
|
||||
}
|
||||
|
||||
if let Some(new_window_level) = new_window_level {
|
||||
if Some(new_window_level) != self.window_level {
|
||||
self.window_level = Some(new_window_level);
|
||||
commands.push(ViewportCommand::WindowLevel(new_window_level));
|
||||
}
|
||||
if let Some(new_window_level) = new_window_level
|
||||
&& Some(new_window_level) != self.window_level
|
||||
{
|
||||
self.window_level = Some(new_window_level);
|
||||
commands.push(ViewportCommand::WindowLevel(new_window_level));
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------
|
||||
|
||||
@@ -573,41 +573,39 @@ impl TextEdit<'_> {
|
||||
let text_clip_rect = rect;
|
||||
let painter = ui.painter_at(text_clip_rect.expand(1.0)); // expand to avoid clipping cursor
|
||||
|
||||
if interactive {
|
||||
if let Some(pointer_pos) = response.interact_pointer_pos() {
|
||||
if response.hovered() && text.is_mutable() {
|
||||
ui.output_mut(|o| o.mutable_text_under_cursor = true);
|
||||
}
|
||||
if interactive && let Some(pointer_pos) = response.interact_pointer_pos() {
|
||||
if response.hovered() && text.is_mutable() {
|
||||
ui.output_mut(|o| o.mutable_text_under_cursor = true);
|
||||
}
|
||||
|
||||
// TODO(emilk): drag selected text to either move or clone (ctrl on windows, alt on mac)
|
||||
// TODO(emilk): drag selected text to either move or clone (ctrl on windows, alt on mac)
|
||||
|
||||
let cursor_at_pointer =
|
||||
galley.cursor_from_pos(pointer_pos - rect.min + state.text_offset);
|
||||
let cursor_at_pointer =
|
||||
galley.cursor_from_pos(pointer_pos - rect.min + state.text_offset);
|
||||
|
||||
if ui.visuals().text_cursor.preview
|
||||
&& response.hovered()
|
||||
&& ui.input(|i| i.pointer.is_moving())
|
||||
{
|
||||
// text cursor preview:
|
||||
let cursor_rect = TSTransform::from_translation(rect.min.to_vec2())
|
||||
* cursor_rect(&galley, &cursor_at_pointer, row_height);
|
||||
text_selection::visuals::paint_cursor_end(&painter, ui.visuals(), cursor_rect);
|
||||
}
|
||||
if ui.visuals().text_cursor.preview
|
||||
&& response.hovered()
|
||||
&& ui.input(|i| i.pointer.is_moving())
|
||||
{
|
||||
// text cursor preview:
|
||||
let cursor_rect = TSTransform::from_translation(rect.min.to_vec2())
|
||||
* cursor_rect(&galley, &cursor_at_pointer, row_height);
|
||||
text_selection::visuals::paint_cursor_end(&painter, ui.visuals(), cursor_rect);
|
||||
}
|
||||
|
||||
let is_being_dragged = ui.ctx().is_being_dragged(response.id);
|
||||
let did_interact = state.cursor.pointer_interaction(
|
||||
ui,
|
||||
&response,
|
||||
cursor_at_pointer,
|
||||
&galley,
|
||||
is_being_dragged,
|
||||
);
|
||||
let is_being_dragged = ui.ctx().is_being_dragged(response.id);
|
||||
let did_interact = state.cursor.pointer_interaction(
|
||||
ui,
|
||||
&response,
|
||||
cursor_at_pointer,
|
||||
&galley,
|
||||
is_being_dragged,
|
||||
);
|
||||
|
||||
if did_interact || response.clicked() {
|
||||
ui.memory_mut(|mem| mem.request_focus(response.id));
|
||||
if did_interact || response.clicked() {
|
||||
ui.memory_mut(|mem| mem.request_focus(response.id));
|
||||
|
||||
state.last_interaction_time = ui.ctx().input(|i| i.time);
|
||||
}
|
||||
state.last_interaction_time = ui.ctx().input(|i| i.time);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -718,11 +716,9 @@ impl TextEdit<'_> {
|
||||
|
||||
let has_focus = ui.memory(|mem| mem.has_focus(id));
|
||||
|
||||
if has_focus {
|
||||
if let Some(cursor_range) = state.cursor.range(&galley) {
|
||||
// Add text selection rectangles to the galley:
|
||||
paint_text_selection(&mut galley, ui.visuals(), &cursor_range, None);
|
||||
}
|
||||
if has_focus && let Some(cursor_range) = state.cursor.range(&galley) {
|
||||
// Add text selection rectangles to the galley:
|
||||
paint_text_selection(&mut galley, ui.visuals(), &cursor_range, None);
|
||||
}
|
||||
|
||||
if !clip_text {
|
||||
@@ -762,50 +758,47 @@ impl TextEdit<'_> {
|
||||
|
||||
painter.galley(galley_pos, galley.clone(), text_color);
|
||||
|
||||
if has_focus {
|
||||
if let Some(cursor_range) = state.cursor.range(&galley) {
|
||||
let primary_cursor_rect =
|
||||
cursor_rect(&galley, &cursor_range.primary, row_height)
|
||||
.translate(galley_pos.to_vec2());
|
||||
if has_focus && let Some(cursor_range) = state.cursor.range(&galley) {
|
||||
let primary_cursor_rect = cursor_rect(&galley, &cursor_range.primary, row_height)
|
||||
.translate(galley_pos.to_vec2());
|
||||
|
||||
if response.changed() || selection_changed {
|
||||
// Scroll to keep primary cursor in view:
|
||||
ui.scroll_to_rect(primary_cursor_rect + margin, None);
|
||||
}
|
||||
|
||||
if text.is_mutable() && interactive {
|
||||
let now = ui.ctx().input(|i| i.time);
|
||||
if response.changed() || selection_changed {
|
||||
// Scroll to keep primary cursor in view:
|
||||
ui.scroll_to_rect(primary_cursor_rect + margin, None);
|
||||
state.last_interaction_time = now;
|
||||
}
|
||||
|
||||
if text.is_mutable() && interactive {
|
||||
let now = ui.ctx().input(|i| i.time);
|
||||
if response.changed() || selection_changed {
|
||||
state.last_interaction_time = now;
|
||||
}
|
||||
// Only show (and blink) cursor if the egui viewport has focus.
|
||||
// This is for two reasons:
|
||||
// * Don't give the impression that the user can type into a window without focus
|
||||
// * Don't repaint the ui because of a blinking cursor in an app that is not in focus
|
||||
let viewport_has_focus = ui.ctx().input(|i| i.focused);
|
||||
if viewport_has_focus {
|
||||
text_selection::visuals::paint_text_cursor(
|
||||
ui,
|
||||
&painter,
|
||||
primary_cursor_rect,
|
||||
now - state.last_interaction_time,
|
||||
);
|
||||
}
|
||||
|
||||
// Only show (and blink) cursor if the egui viewport has focus.
|
||||
// This is for two reasons:
|
||||
// * Don't give the impression that the user can type into a window without focus
|
||||
// * Don't repaint the ui because of a blinking cursor in an app that is not in focus
|
||||
let viewport_has_focus = ui.ctx().input(|i| i.focused);
|
||||
if viewport_has_focus {
|
||||
text_selection::visuals::paint_text_cursor(
|
||||
ui,
|
||||
&painter,
|
||||
primary_cursor_rect,
|
||||
now - state.last_interaction_time,
|
||||
);
|
||||
}
|
||||
// Set IME output (in screen coords) when text is editable and visible
|
||||
let to_global = ui
|
||||
.ctx()
|
||||
.layer_transform_to_global(ui.layer_id())
|
||||
.unwrap_or_default();
|
||||
|
||||
// Set IME output (in screen coords) when text is editable and visible
|
||||
let to_global = ui
|
||||
.ctx()
|
||||
.layer_transform_to_global(ui.layer_id())
|
||||
.unwrap_or_default();
|
||||
|
||||
ui.ctx().output_mut(|o| {
|
||||
o.ime = Some(crate::output::IMEOutput {
|
||||
rect: to_global * rect,
|
||||
cursor_rect: to_global * primary_cursor_rect,
|
||||
});
|
||||
ui.ctx().output_mut(|o| {
|
||||
o.ime = Some(crate::output::IMEOutput {
|
||||
rect: to_global * rect,
|
||||
cursor_rect: to_global * primary_cursor_rect,
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user