editbox keyboard input, scrollbars fix (scissoring broken atm), clippy

This commit is contained in:
Aleksander 2026-02-14 22:20:51 +01:00
parent 841241a7e6
commit 2ddb419676
14 changed files with 264 additions and 132 deletions

View File

@ -93,19 +93,18 @@
position="absolute" width="100%" height="100%"
gradient="radial" color="#44BBFF11" color2="#00000000" />
<div
id="content"
flex_direction="column"
overflow_x="scroll"
overflow_y="scroll"
padding="16"
gap="8"
width="100%"
min_height="100%"
>
<!-- filled-in at runtime -->
<div overflow_x="scroll" overflow_y="scroll" width="100%" height="100%">
<div
id="content"
flex_direction="column"
padding="16"
gap="8"
width="100%"
height="100%"
>
<!-- filled-in at runtime -->
</div>
</div>
<div position="absolute" id="popup_manager" width="100%" height="100%" />
</rectangle>
<!-- BOTTOM PANEL -->

View File

@ -1,6 +1,6 @@
<layout>
<elements>
<div id="running_games_list_parent" align_self="center" />
<div id="game_list_parent" align_items="center" flex_direction="column" gap="8" overflow_y="scroll" />
<div id="game_list_parent" align_items="center" flex_direction="column" gap="8" />
</elements>
</layout>

View File

@ -50,7 +50,6 @@ enum CompositorMode {
enum Task {
SetCompositor(CompositorMode),
SetRes(ResMode),
SetPos(PosMode), // TODO?
SetOrientation(OrientationMode),
SetAutoStart(bool),
Launch,
@ -295,7 +294,6 @@ impl View {
match task {
Task::SetCompositor(mode) => self.compositor_mode = mode,
Task::SetRes(mode) => self.res_mode = mode,
Task::SetPos(mode) => self.pos_mode = mode,
Task::SetOrientation(mode) => self.orientation_mode = mode,
Task::SetAutoStart(auto_start) => self.auto_start = auto_start,
Task::Launch => self.action_launch(interface, data),

View File

@ -66,8 +66,9 @@
</rectangle>
<rectangle macro="rect">
<label text="Editbox test" />
<EditBox text="Initial text. Test, abcdef." />
<EditBox />
<EditBox text="Initial text. Test, abcdef." width="400" />
<EditBox margin_left="42" margin_top="42" margin_bottom="40" width="200" />
</rectangle>
</div>

View File

@ -1,25 +1,25 @@
use glam::{vec2, Vec2};
use std::sync::Arc;
use testbed::{testbed_any::TestbedAny, Testbed};
use glam::{Vec2, vec2};
use std::{rc::Rc, sync::Arc};
use testbed::{Testbed, testbed_any::TestbedAny};
use tracing_subscriber::EnvFilter;
use tracing_subscriber::filter::LevelFilter;
use tracing_subscriber::layer::SubscriberExt;
use tracing_subscriber::util::SubscriberInitExt;
use tracing_subscriber::EnvFilter;
use vulkan::init_window;
use vulkano::{
Validated, VulkanError,
command_buffer::CommandBufferUsage,
format::Format,
image::{view::ImageView, ImageUsage},
image::{ImageUsage, view::ImageView},
swapchain::{
acquire_next_image, ColorSpace, CompositeAlpha, PresentMode, Surface, SurfaceInfo, Swapchain,
SwapchainCreateInfo, SwapchainPresentInfo,
ColorSpace, CompositeAlpha, PresentMode, Surface, SurfaceInfo, Swapchain, SwapchainCreateInfo,
SwapchainPresentInfo, acquire_next_image,
},
sync::GpuFuture,
Validated, VulkanError,
};
use wgui::{
event::{MouseButtonIndex, MouseDownEvent, MouseMotionEvent, MouseUpEvent, MouseWheelEvent},
gfx::{cmd::WGfxClearMode, WGfx},
event::{MouseButtonEvent, MouseButtonIndex, MouseMotionEvent, MouseWheelEvent},
gfx::{WGfx, cmd::WGfxClearMode},
renderer_vk::{self},
};
use winit::{
@ -32,7 +32,7 @@ use wlx_common::{audio, timestep::Timestep};
use crate::{
rate_limiter::RateLimiter,
testbed::{
testbed_dashboard::TestbedDashboard, testbed_generic::TestbedGeneric, TestbedUpdateParams,
TestbedUpdateParams, testbed_dashboard::TestbedDashboard, testbed_generic::TestbedGeneric,
},
};
@ -174,7 +174,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
testbed
.layout()
.push_event(
&wgui::event::Event::MouseDown(MouseDownEvent {
&wgui::event::Event::MouseDown(MouseButtonEvent {
pos: mouse / scale,
index: MouseButtonIndex::Left,
device: 0,
@ -187,7 +187,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
testbed
.layout()
.push_event(
&wgui::event::Event::MouseUp(MouseUpEvent {
&wgui::event::Event::MouseUp(MouseButtonEvent {
pos: mouse / scale,
index: MouseButtonIndex::Left,
device: 0,
@ -221,33 +221,46 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
..
} => {
if event.state == ElementState::Pressed {
if event.physical_key == PhysicalKey::Code(KeyCode::F10) {
debug_draw_enabled = !debug_draw_enabled;
if debug_draw_enabled {
log::info!(
"Debug draw enabled\n\tAqua: widget boundary\n\tMagenta: Scissoring (separate render pass)"
);
if !event.repeat {
if event.physical_key == PhysicalKey::Code(KeyCode::F10) {
debug_draw_enabled = !debug_draw_enabled;
if debug_draw_enabled {
log::info!(
"Debug draw enabled\n\tAqua: widget boundary\n\tMagenta: Scissoring (separate render pass)"
);
}
testbed.layout().mark_redraw();
}
if event.physical_key == PhysicalKey::Code(KeyCode::F11) {
testbed.layout().print_tree();
}
if event.physical_key == PhysicalKey::Code(KeyCode::Equal) {
scale *= 1.25;
render_context
.update_viewport(&mut shared_context, swapchain_size, scale)
.unwrap();
}
if event.physical_key == PhysicalKey::Code(KeyCode::Minus) {
scale *= 0.75;
render_context
.update_viewport(&mut shared_context, swapchain_size, scale)
.unwrap();
}
testbed.layout().mark_redraw();
}
if event.physical_key == PhysicalKey::Code(KeyCode::F11) {
testbed.layout().print_tree();
}
if event.physical_key == PhysicalKey::Code(KeyCode::Equal) {
scale *= 1.25;
render_context
.update_viewport(&mut shared_context, swapchain_size, scale)
.unwrap();
}
if event.physical_key == PhysicalKey::Code(KeyCode::Minus) {
scale *= 0.75;
render_context
.update_viewport(&mut shared_context, swapchain_size, scale)
.unwrap();
}
testbed
.layout()
.push_event(
&wgui::event::Event::TextInput(wgui::event::TextInputEvent {
text: event.text.map(|text| Rc::from(text.as_str())),
}),
&mut (),
&mut (),
)
.unwrap();
}
}
Event::WindowEvent {

View File

@ -14,8 +14,8 @@ use wgui::{
drawing,
event::{
CallbackDataCommon, Event as WguiEvent, EventAlterables, EventCallback, EventListenerID,
EventListenerKind, InternalStateChangeEvent, MouseButtonIndex, MouseDownEvent,
MouseLeaveEvent, MouseMotionEvent, MouseUpEvent, MouseWheelEvent,
EventListenerKind, InternalStateChangeEvent, MouseButtonEvent, MouseButtonIndex,
MouseLeaveEvent, MouseMotionEvent, MouseWheelEvent,
},
gfx::cmd::WGfxClearMode,
i18n::Translation,
@ -416,13 +416,13 @@ impl<S: 'static> OverlayBackend for GuiPanel<S> {
};
let e = if pressed {
WguiEvent::MouseDown(MouseDownEvent {
WguiEvent::MouseDown(MouseButtonEvent {
pos: hit.uv * self.layout.content_size,
index,
device: hit.pointer,
})
} else {
WguiEvent::MouseUp(MouseUpEvent {
WguiEvent::MouseUp(MouseButtonEvent {
pos: hit.uv * self.layout.content_size,
index,
device: hit.pointer,

View File

@ -8,8 +8,8 @@ use wayvr_ipc::{
};
use wgui::{
event::{
Event as WguiEvent, MouseButtonIndex, MouseDownEvent, MouseLeaveEvent, MouseMotionEvent,
MouseUpEvent, MouseWheelEvent,
Event as WguiEvent, MouseButtonEvent, MouseButtonIndex, MouseLeaveEvent, MouseMotionEvent,
MouseWheelEvent,
},
gfx::cmd::WGfxClearMode,
renderer_vk::context::Context as WguiContext,
@ -247,13 +247,13 @@ impl OverlayBackend for DashFrontend {
};
let e = if pressed {
WguiEvent::MouseDown(MouseDownEvent {
WguiEvent::MouseDown(MouseButtonEvent {
pos: hit.uv * self.inner.layout.content_size,
index,
device: hit.pointer,
})
} else {
WguiEvent::MouseUp(MouseUpEvent {
WguiEvent::MouseUp(MouseButtonEvent {
pos: hit.uv * self.inner.layout.content_size,
index,
device: hit.pointer,

View File

@ -32,7 +32,7 @@ use regex::Regex;
use slotmap::{SlotMap, new_key_type};
use wgui::{
drawing,
event::{InternalStateChangeEvent, MouseButton, MouseButtonIndex},
event::{InternalStateChangeEvent, MouseButtonEvent, MouseButtonIndex},
};
use wlx_common::windowing::{OverlayWindowState, Positioning};
use wlx_common::{
@ -390,7 +390,7 @@ fn handle_press(
app: &mut AppState,
key: &KeyState,
keyboard: &mut KeyboardState,
button: MouseButton,
button: MouseButtonEvent,
) {
match &key.button_state {
KeyButtonData::Key { vk, pressed } => {

View File

@ -6,7 +6,7 @@
## [Built-in components](#components)
[Button](#button-component), [Slider](#slider-component), [CheckBox](#checkbox-component), [Tabs](#tabs-component) ([Tab](#tab-component))
[Button](#button-component), [Slider](#slider-component), [CheckBox](#checkbox-component), [Tabs](#tabs-component) ([Tab](#tab-component)), [EditBox](#editbox-component)
## [Examples](#examples)
@ -408,6 +408,20 @@ _Image path (see [sprite](#sprite-widget)) for src descriptions_
---
## EditBox component
### `<EditBox>`
### A single-line text input field.
#### Parameters
`text`: **string**
_Initial text content_
---
# Examples
## Simple layout

View File

@ -10,7 +10,7 @@ use crate::{
animation::{Animation, AnimationEasing},
components::{Component, ComponentBase, ComponentTrait, FocusChangeData, RefreshData},
drawing::{self, Color},
event::{self, CallbackDataCommon, EventListenerCollection, EventListenerKind, StyleSetRequest},
event::{self, CallbackDataCommon, CallbackMetadata, EventListenerCollection, EventListenerKind, StyleSetRequest},
i18n::Translation,
layout::{WidgetID, WidgetPair},
renderer_vk::text::{TextShadow, TextStyle},
@ -41,8 +41,9 @@ struct State {
#[allow(clippy::struct_field_names)]
struct Data {
#[allow(dead_code)]
id_rect_container: WidgetID, // Rectangle
id_rect_bottom: WidgetID, // Rectangle
id_rect_container: WidgetID,
id_rect_bottom: WidgetID,
id_rect_cursor: WidgetID,
id_label: WidgetID,
}
@ -76,15 +77,15 @@ fn anim_bottom_rect(
common.alterables.set_style(
data.widget_id,
StyleSetRequest::Size(taffy::Size {
width: percent(0.9.lerp(1.0, pos_bidir)),
height: length(2.0 + pos_bidir * 2.0),
width: percent(0.95.lerp(1.0, pos_bidir)),
height: length(1.0 + pos_bidir),
}),
);
common.alterables.set_style(
data.widget_id,
StyleSetRequest::Margin(taffy::Rect {
bottom: length(0.0),
bottom: length(pos_bidir),
left: auto(),
right: auto(),
top: auto(),
@ -105,7 +106,7 @@ fn refresh_all(common: &mut CallbackDataCommon, data: &Data, state: &mut State)
drop(defaults);
let (rect_color, border_color) = if state.focused {
(editbox_color.add_rgb(0.1), editbox_color.add_rgb(0.75))
(editbox_color.add_rgb(0.15), editbox_color.add_rgb(0.15 + 0.25))
} else if state.hovered {
(editbox_color.add_rgb(0.1), editbox_color.add_rgb(0.1 + 0.15))
} else {
@ -122,6 +123,16 @@ fn refresh_all(common: &mut CallbackDataCommon, data: &Data, state: &mut State)
state.focused_prev = state.focused;
}
// Cursor
common.alterables.set_style(
data.id_rect_cursor,
StyleSetRequest::Display(if state.focused {
taffy::Display::Flex
} else {
taffy::Display::None
}),
);
state.first_refresh = false;
Some(())
@ -149,13 +160,22 @@ impl ComponentTrait for ComponentEditBox {
}
}
impl ComponentEditBox {
pub fn set_text(&self, common: &mut CallbackDataCommon, text: Translation) {
let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(self.data.id_label) else {
return;
};
fn update_text(common: &mut CallbackDataCommon, state: &mut State, data: &Data, text: String) {
let Some(mut label) = common.state.widgets.get_as::<WidgetLabel>(data.id_label) else {
return;
};
label.set_text(common, text);
label.set_text(common, Translation::from_raw_text(&text));
common.alterables.refresh_component_once(&state.self_ref);
state.text = text;
}
impl ComponentEditBox {
pub fn set_text(&self, common: &mut CallbackDataCommon, text: &str) {
let mut state = self.state.borrow_mut();
update_text(common, &mut state, &self.data, String::from(text));
}
pub fn get_text(&self) -> Ref<'_, String> {
@ -163,6 +183,50 @@ impl ComponentEditBox {
}
}
fn register_event_text_input(
state: Rc<RefCell<State>>,
data: Rc<Data>,
listeners: &mut EventListenerCollection,
) -> event::EventListenerID {
listeners.register(
EventListenerKind::TextInput,
Box::new(move |common, evt, (), ()| {
let mut state = state.borrow_mut();
if !state.focused {
return Ok(EventResult::Pass);
}
let CallbackMetadata::TextInput(input) = &evt.metadata else {
unreachable!();
};
let Some(input_text) = &input.text else {
return Ok(EventResult::Pass); // nothing to do
};
let Some(ch) = input_text.chars().next() else {
return Ok(EventResult::Pass); // ???
};
let mut new_text = std::mem::take(&mut state.text);
if ch == '\x08' {
// Backspace
new_text.pop();
} else {
let printable = !input_text.chars().any(char::is_control);
if printable {
new_text.push_str(input_text);
}
}
update_text(common, &mut state, &data, new_text);
Ok(EventResult::Consumed)
}),
)
}
fn register_event_mouse_enter(
state: Rc<RefCell<State>>,
listeners: &mut EventListenerCollection,
@ -217,6 +281,7 @@ pub fn construct(
) -> anyhow::Result<(WidgetPair, Rc<ComponentEditBox>)> {
let globals = ess.layout.state.globals.clone();
let defaults = globals.defaults();
let text_color = defaults.text_color;
drop(defaults);
if params.style.size.width.is_auto() {
@ -232,7 +297,7 @@ pub fn construct(
params.style.position = taffy::Position::Relative;
params.style.overflow = taffy::Point {
x: taffy::Overflow::Scroll,
y: taffy::Overflow::Scroll,
y: taffy::Overflow::Visible,
};
params.style.min_size = params.style.max_size;
@ -296,13 +361,34 @@ pub fn construct(
},
},
),
Default::default(),
taffy::Style {
position: taffy::Position::Relative,
..Default::default()
},
)?;
let (rect_cursor, _) = ess.layout.add_child(
label_parent.id,
WidgetRectangle::create(WidgetRectangleParams {
color: text_color.with_alpha(0.75),
..Default::default()
}),
taffy::Style {
align_self: Some(taffy::AlignSelf::Center),
justify_self: Some(taffy::JustifySelf::End),
min_size: taffy::Size {
width: length(2.0),
height: length(16.0),
},
..Default::default()
},
)?;
let data = Rc::new(Data {
id_rect_container: id_container,
id_label: label.id,
id_rect_bottom: rect_bottom.id,
id_rect_cursor: rect_cursor.id,
});
let state = Rc::new(RefCell::new(State {
@ -322,6 +408,7 @@ pub fn construct(
register_event_mouse_enter(state.clone(), &mut root_state.event_listeners),
register_event_mouse_leave(state.clone(), &mut root_state.event_listeners),
register_event_mouse_press(state.clone(), &mut root_state.event_listeners),
register_event_text_input(state.clone(), data.clone(), &mut root_state.event_listeners),
]
},
};

View File

@ -19,10 +19,6 @@ use crate::{
use super::{layout::Layout, widget::DrawState};
pub struct ImageHandle {
// to be implemented, will contain pixel data (RGB or RGBA) loaded via "ImageBank" or something by the gui
}
#[derive(Debug, Default, Clone, Copy, PartialEq)]
pub struct Boundary {
pub pos: Vec2,
@ -254,14 +250,19 @@ pub fn has_overflow_clip(style: &taffy::Style) -> bool {
style.overflow.x != taffy::Overflow::Visible || style.overflow.y != taffy::Overflow::Visible
}
fn primitive_debug_rect(boundary: &Boundary, transform: &Mat4, color: drawing::Color) -> drawing::RenderPrimitive {
fn primitive_debug_rect(
boundary: &Boundary,
transform: &Mat4,
color: drawing::Color,
border: f32,
) -> drawing::RenderPrimitive {
drawing::RenderPrimitive::Rectangle(
PrimitiveExtent {
boundary: *boundary,
transform: *transform,
},
Rectangle {
border: 1.0,
border,
border_color: color,
color: Color::new(0.0, 0.0, 0.0, 0.0),
..Default::default()
@ -277,12 +278,16 @@ pub fn push_transform_stack(
) {
let raw_dim = Vec2::new(l.size.width, l.size.height);
let visual_dim = raw_dim + scroll_shift;
let content_dim = Vec2::new(l.content_box_width(), l.content_box_height());
let content_rel_pos = Vec2::new(l.content_box_x(), l.content_box_y());
transform_stack.push(stack::Transform {
rel_pos: Vec2::new(l.location.x, l.location.y) - scroll_shift,
transform: widget_state.data.transform,
raw_dim,
visual_dim,
content_dim,
content_rel_pos,
abs_pos: Default::default(),
transform_rel: Default::default(),
});
@ -368,11 +373,11 @@ fn draw_widget(
&boundary,
&state.transform_stack.get().transform,
Color::new(0.0, 1.0, 1.0, 0.5),
1.0,
));
}
let starting_scissor_set_count = internal.scissor_set_count;
let scissor_result = push_scissor_stack(state.transform_stack, state.scissor_stack, scroll_shift, &info, style);
if scissor_result == PushScissorStackResult::VisibleAndClip {
@ -383,6 +388,7 @@ fn draw_widget(
&boundary_relative,
&state.transform_stack.get().transform,
Color::new(1.0, 0.0, 1.0, 1.0),
3.0,
));
}
state
@ -412,12 +418,12 @@ fn draw_widget(
.push(drawing::RenderPrimitive::ScissorSet(*state.scissor_stack.get()));
}
state.transform_stack.pop();
if let Some(info) = &info {
widget_state.draw_scrollbars(state, &draw_params, info);
}
state.transform_stack.pop();
if wants_redraw {
state.alterables.mark_redraw();
}

View File

@ -2,7 +2,7 @@ use std::{
any::{Any, TypeId},
cell::{Ref, RefMut},
collections::HashSet,
rc::Weak,
rc::{Rc, Weak},
};
use glam::Vec2;
@ -10,7 +10,7 @@ use slotmap::{DenseSlotMap, new_key_type};
use crate::{
animation::{self, Animation},
components::{Component, ComponentTrait, ComponentWeak},
components::{ComponentTrait, ComponentWeak},
globals,
i18n::I18n,
layout::{LayoutDispatchFunc, LayoutState, LayoutTask, WidgetID},
@ -27,7 +27,7 @@ pub enum MouseButtonIndex {
}
#[derive(Debug, Clone, Copy)]
pub struct MouseButton {
pub struct MouseButtonEvent {
pub index: MouseButtonIndex,
pub pos: Vec2,
pub device: usize,
@ -39,12 +39,6 @@ pub struct MousePosition {
pub device: usize,
}
pub struct MouseDownEvent {
pub pos: Vec2,
pub index: MouseButtonIndex,
pub device: usize,
}
pub struct MouseLeaveEvent {
pub device: usize,
}
@ -54,29 +48,29 @@ pub struct MouseMotionEvent {
pub device: usize,
}
pub struct MouseUpEvent {
pub pos: Vec2,
pub index: MouseButtonIndex,
pub device: usize,
}
pub struct MouseWheelEvent {
pub pos: Vec2, /* mouse position */
pub delta: Vec2, /* wheel delta */
pub device: usize,
}
#[derive(Clone)]
pub struct TextInputEvent {
pub text: Option<Rc<str>>,
}
pub struct InternalStateChangeEvent {
pub metadata: usize,
}
pub enum Event {
InternalStateChange(InternalStateChangeEvent),
MouseDown(MouseDownEvent),
MouseDown(MouseButtonEvent),
MouseLeave(MouseLeaveEvent),
MouseMotion(MouseMotionEvent),
MouseUp(MouseUpEvent),
MouseUp(MouseButtonEvent),
MouseWheel(MouseWheelEvent),
TextInput(TextInputEvent),
}
impl Event {
@ -203,8 +197,9 @@ pub struct CallbackData<'a> {
pub enum CallbackMetadata {
None,
MouseButton(MouseButton),
MouseButton(MouseButtonEvent),
MousePosition(MousePosition),
TextInput(TextInputEvent),
Custom(usize),
}
@ -213,9 +208,10 @@ impl CallbackMetadata {
pub const fn get_mouse_pos_absolute(&self) -> Option<Vec2> {
match *self {
Self::MouseButton(b) => Some(b.pos),
Self::MousePosition(b) => Some(b.pos),
Self::Custom(_) | Self::None => None,
CallbackMetadata::MouseButton(b) => Some(b.pos),
CallbackMetadata::MousePosition(b) => Some(b.pos),
CallbackMetadata::Custom(_) | CallbackMetadata::None => None,
CallbackMetadata::TextInput(_) => None,
}
}
@ -232,6 +228,7 @@ pub enum EventListenerKind {
MouseEnter,
MouseMotion,
MouseLeave,
TextInput,
InternalStateChange,
}

View File

@ -39,6 +39,11 @@ impl<T: StackItem<T>, const STACK_MAX: usize> GenericStack<T, STACK_MAX> {
pub const fn get(&self) -> &T {
&self.stack[(self.top - 1) as usize]
}
pub const fn parent(&self) -> &T {
debug_assert!(self.top >= 2);
&self.stack[(self.top - 2) as usize]
}
}
impl<T: StackItem<T>, const STACK_MAX: usize> Default for GenericStack<T, STACK_MAX> {
@ -54,9 +59,11 @@ impl<T: StackItem<T>, const STACK_MAX: usize> Default for GenericStack<T, STACK_
#[derive(Debug, Copy, Clone)]
pub struct Transform {
pub rel_pos: Vec2,
pub visual_dim: Vec2, // for convenience
pub raw_dim: Vec2, // for convenience
pub abs_pos: Vec2, // for convenience, will be set after pushing
pub visual_dim: Vec2,
pub raw_dim: Vec2,
pub content_rel_pos: Vec2,
pub content_dim: Vec2,
pub abs_pos: Vec2, // for convenience, will be set after pushing
pub transform: glam::Mat4,
pub transform_rel: glam::Mat4,
}
@ -68,6 +75,8 @@ impl Default for Transform {
rel_pos: Default::default(),
visual_dim: Default::default(),
raw_dim: Default::default(),
content_dim: Default::default(),
content_rel_pos: Default::default(),
transform: Mat4::IDENTITY,
transform_rel: Default::default(),
}

View File

@ -311,6 +311,8 @@ impl WidgetState {
}
pub fn get_scroll_shift_smooth(&self, info: &ScrollbarInfo, l: &taffy::Layout, timestep_alpha: f32) -> (Vec2, bool) {
//return (self.get_scroll_shift_raw(info, l), false);
let currently_animating = self.data.scrolling_cur != self.data.scrolling_cur_prev;
let scrolling = self
@ -368,7 +370,8 @@ impl WidgetState {
return;
}
let transform = state.transform_stack.get();
let transform_widget = state.transform_stack.get();
let transform_parent = state.transform_stack.parent();
let thickness = 6.0;
let margin = 6.0;
@ -385,12 +388,15 @@ impl WidgetState {
PrimitiveExtent {
boundary: drawing::Boundary::from_pos_size(
Vec2::new(
transform.rel_pos.x + transform.raw_dim.x * (1.0 - info.handle_size.x) * self.data.scrolling_cur.x,
transform.rel_pos.y + transform.raw_dim.y - thickness - margin,
// X
transform_widget.content_rel_pos.x
+ transform_parent.raw_dim.x * (1.0 - info.handle_size.x) * self.data.scrolling_cur.x,
// Y
transform_widget.content_rel_pos.y + transform_widget.raw_dim.y - thickness - margin,
),
Vec2::new(transform.raw_dim.x * info.handle_size.x, thickness),
Vec2::new(transform_widget.raw_dim.x * info.handle_size.x, thickness),
),
transform: transform.transform,
transform: transform_parent.transform,
},
rect_params,
));
@ -402,12 +408,15 @@ impl WidgetState {
PrimitiveExtent {
boundary: drawing::Boundary::from_pos_size(
Vec2::new(
transform.rel_pos.x + transform.raw_dim.x - thickness - margin,
transform.rel_pos.y + transform.raw_dim.y * (1.0 - info.handle_size.y) * self.data.scrolling_cur.y,
// X
transform_widget.content_rel_pos.x + transform_widget.raw_dim.x - thickness - margin,
// Y
transform_widget.content_rel_pos.y
+ transform_parent.raw_dim.y * (1.0 - info.handle_size.y) * self.data.scrolling_cur.y,
),
Vec2::new(thickness, transform.raw_dim.y * info.handle_size.y),
Vec2::new(thickness, transform_widget.raw_dim.y * info.handle_size.y),
),
transform: transform.transform,
transform: transform_parent.transform,
},
rect_params,
));
@ -489,16 +498,19 @@ impl WidgetState {
let mut res: Option<InvokeListenersResult> = None;
match &event {
Event::TextInput(e) => {
res = Some(self.invoke_listeners(
&mut invoke_data,
EventListenerKind::TextInput,
CallbackMetadata::TextInput(e.clone()),
)?);
}
Event::MouseDown(e) => {
if hovered && self.data.set_device_pressed(e.device, true) {
res = Some(self.invoke_listeners(
&mut invoke_data,
EventListenerKind::MousePress,
CallbackMetadata::MouseButton(event::MouseButton {
index: e.index,
pos: e.pos,
device: e.device,
}),
CallbackMetadata::MouseButton(*e),
)?);
}
}
@ -507,11 +519,7 @@ impl WidgetState {
res = Some(self.invoke_listeners(
&mut invoke_data,
EventListenerKind::MouseRelease,
CallbackMetadata::MouseButton(event::MouseButton {
index: e.index,
pos: e.pos,
device: e.device,
}),
CallbackMetadata::MouseButton(*e),
)?);
}
}