mirror of
https://github.com/danbulant/cushy
synced 2026-07-06 03:30:38 +00:00
CursorIcon + disabled refactoring
Input can now accept focus while disabled, and all controls should do the right thing with regard to cursor icons now.
This commit is contained in:
parent
00cb29d261
commit
3e651c2964
11 changed files with 208 additions and 60 deletions
25
examples/cursor-icon.rs
Normal file
25
examples/cursor-icon.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
use gooey::value::Dynamic;
|
||||||
|
use gooey::widget::MakeWidget;
|
||||||
|
use gooey::widgets::input::InputValue;
|
||||||
|
use gooey::widgets::Custom;
|
||||||
|
use gooey::Run;
|
||||||
|
use kludgine::app::winit::window::CursorIcon;
|
||||||
|
|
||||||
|
fn main() -> gooey::Result {
|
||||||
|
Custom::new(
|
||||||
|
"Try hovering the mouse cursor around this window"
|
||||||
|
.and(
|
||||||
|
Dynamic::new(String::from("Input fields show the text selection cursor"))
|
||||||
|
.into_input(),
|
||||||
|
)
|
||||||
|
.into_rows()
|
||||||
|
.pad()
|
||||||
|
.centered(),
|
||||||
|
)
|
||||||
|
.on_hover(|_location, _context| Some(CursorIcon::Help))
|
||||||
|
.on_hit_test(|_location, _context| true)
|
||||||
|
.contain()
|
||||||
|
.centered()
|
||||||
|
.expand()
|
||||||
|
.run()
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@ fn main() -> gooey::Result {
|
||||||
.and("Allow Custom Widget to Lose Focus".into_checkbox(allow_blur.clone()))
|
.and("Allow Custom Widget to Lose Focus".into_checkbox(allow_blur.clone()))
|
||||||
.and(
|
.and(
|
||||||
Custom::empty()
|
Custom::empty()
|
||||||
.on_accept_focus(|_| true)
|
.on_accept_focus(|context| context.enabled())
|
||||||
.on_redraw(|context| {
|
.on_redraw(|context| {
|
||||||
context.fill(context.theme().secondary.color);
|
context.fill(context.theme().secondary.color);
|
||||||
if context.focused() {
|
if context.focused() {
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use gooey::animation::{LinearInterpolate, PercentBetween};
|
use gooey::animation::{LinearInterpolate, PercentBetween};
|
||||||
use gooey::value::{Dynamic, ForEach};
|
use gooey::value::{Dynamic, ForEach};
|
||||||
use gooey::widget::MakeWidget;
|
use gooey::widget::MakeWidget;
|
||||||
|
use gooey::widgets::checkbox::Checkable;
|
||||||
use gooey::widgets::input::InputValue;
|
use gooey::widgets::input::InputValue;
|
||||||
use gooey::widgets::slider::Slidable;
|
use gooey::widgets::slider::Slidable;
|
||||||
use gooey::Run;
|
use gooey::Run;
|
||||||
|
|
@ -8,10 +9,14 @@ use kludgine::figures::units::Lp;
|
||||||
use kludgine::figures::Ranged;
|
use kludgine::figures::Ranged;
|
||||||
|
|
||||||
fn main() -> gooey::Result {
|
fn main() -> gooey::Result {
|
||||||
|
let enabled = Dynamic::new(true);
|
||||||
u8_slider()
|
u8_slider()
|
||||||
.and(u8_range_slider())
|
.and(u8_range_slider())
|
||||||
.and(enum_slider())
|
.and(enum_slider())
|
||||||
.into_rows()
|
.into_rows()
|
||||||
|
.with_enabled(enabled.clone())
|
||||||
|
.and(enabled.into_checkbox("Enabled"))
|
||||||
|
.into_rows()
|
||||||
.expand_horizontally()
|
.expand_horizontally()
|
||||||
.contain()
|
.contain()
|
||||||
.width(..Lp::points(800))
|
.width(..Lp::points(800))
|
||||||
|
|
|
||||||
|
|
@ -8,6 +8,7 @@ use kempt::Set;
|
||||||
use kludgine::app::winit::event::{
|
use kludgine::app::winit::event::{
|
||||||
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||||
};
|
};
|
||||||
|
use kludgine::app::winit::window::CursorIcon;
|
||||||
use kludgine::figures::units::{Lp, Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{IntoSigned, Point, Px2D, Rect, Round, ScreenScale, Size, Zero};
|
use kludgine::figures::{IntoSigned, Point, Px2D, Rect, Round, ScreenScale, Size, Zero};
|
||||||
use kludgine::shapes::{Shape, StrokeOptions};
|
use kludgine::shapes::{Shape, StrokeOptions};
|
||||||
|
|
@ -163,10 +164,17 @@ impl<'context, 'window> EventContext<'context, 'window> {
|
||||||
let mut context = self.for_other(&unhovered);
|
let mut context = self.for_other(&unhovered);
|
||||||
unhovered.lock().as_widget().unhover(&mut context);
|
unhovered.lock().as_widget().unhover(&mut context);
|
||||||
}
|
}
|
||||||
for hover in changes.hovered {
|
|
||||||
|
let mut cursor = None;
|
||||||
|
for hover in changes.hovered.into_iter().rev() {
|
||||||
let mut context = self.for_other(&hover);
|
let mut context = self.for_other(&hover);
|
||||||
hover.lock().as_widget().hover(location, &mut context);
|
let widget_cursor = hover.lock().as_widget().hover(location, &mut context);
|
||||||
|
|
||||||
|
if cursor.is_none() {
|
||||||
|
cursor = widget_cursor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
self.winit().set_cursor_icon(cursor.unwrap_or_default());
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn clear_hover(&mut self) {
|
pub(crate) fn clear_hover(&mut self) {
|
||||||
|
|
@ -177,6 +185,8 @@ impl<'context, 'window> EventContext<'context, 'window> {
|
||||||
let mut old_hover_context = self.for_other(&old_hover);
|
let mut old_hover_context = self.for_other(&old_hover);
|
||||||
old_hover.lock().as_widget().unhover(&mut old_hover_context);
|
old_hover.lock().as_widget().unhover(&mut old_hover_context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.winit().set_cursor_icon(CursorIcon::Default);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn apply_pending_activation(&mut self) {
|
fn apply_pending_activation(&mut self) {
|
||||||
|
|
@ -227,14 +237,10 @@ impl<'context, 'window> EventContext<'context, 'window> {
|
||||||
fn apply_pending_focus(&mut self) {
|
fn apply_pending_focus(&mut self) {
|
||||||
let mut focus_changes = 0;
|
let mut focus_changes = 0;
|
||||||
while focus_changes < Self::MAX_PENDING_CHANGE_CYCLES {
|
while focus_changes < Self::MAX_PENDING_CHANGE_CYCLES {
|
||||||
let focus = match self
|
let focus = self
|
||||||
.pending_state
|
.pending_state
|
||||||
.focus
|
.focus
|
||||||
.and_then(|w| self.current_node.tree.widget(w))
|
.and_then(|w| self.current_node.tree.widget(w));
|
||||||
{
|
|
||||||
Some(focus) => self.for_other(&focus).enabled().then_some(focus),
|
|
||||||
None => None,
|
|
||||||
};
|
|
||||||
if self.current_node.tree.focused_widget() == focus.as_ref().map(|w| w.node_id) {
|
if self.current_node.tree.focused_widget() == focus.as_ref().map(|w| w.node_id) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -242,8 +248,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
|
||||||
|
|
||||||
self.pending_state.focus = focus.and_then(|mut focus| loop {
|
self.pending_state.focus = focus.and_then(|mut focus| loop {
|
||||||
let mut focus_context = self.for_other(&focus);
|
let mut focus_context = self.for_other(&focus);
|
||||||
let accept_focus = focus_context.enabled()
|
let accept_focus = focus.lock().as_widget().accept_focus(&mut focus_context);
|
||||||
&& focus.lock().as_widget().accept_focus(&mut focus_context);
|
|
||||||
drop(focus_context);
|
drop(focus_context);
|
||||||
|
|
||||||
if accept_focus {
|
if accept_focus {
|
||||||
|
|
@ -402,8 +407,7 @@ impl<'context, 'window> EventContext<'context, 'window> {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut child_context = self.for_other(&child);
|
let mut child_context = self.for_other(&child);
|
||||||
let accept_focus = child_context.enabled()
|
let accept_focus = child.lock().as_widget().accept_focus(&mut child_context);
|
||||||
&& child.lock().as_widget().accept_focus(&mut child_context);
|
|
||||||
drop(child_context);
|
drop(child_context);
|
||||||
if accept_focus {
|
if accept_focus {
|
||||||
return Some(child.id());
|
return Some(child.id());
|
||||||
|
|
|
||||||
|
|
@ -129,6 +129,8 @@ define_components! {
|
||||||
WidgetBackground(Color, "widget_backgrond_color", Color::CLEAR_WHITE)
|
WidgetBackground(Color, "widget_backgrond_color", Color::CLEAR_WHITE)
|
||||||
/// A [`Color`] to be used to accent a widget.
|
/// A [`Color`] to be used to accent a widget.
|
||||||
WidgetAccentColor(Color, "widget_accent_color", .primary.color)
|
WidgetAccentColor(Color, "widget_accent_color", .primary.color)
|
||||||
|
/// A [`Color`] to be used to accent a disabled widget.
|
||||||
|
DisabledWidgetAccentColor(Color, "disabled_widget_accent_color", .primary.color_dim)
|
||||||
/// A [`Color`] to be used as an outline color.
|
/// A [`Color`] to be used as an outline color.
|
||||||
OutlineColor(Color, "outline_color", .surface.outline)
|
OutlineColor(Color, "outline_color", .surface.outline)
|
||||||
/// A [`Color`] to be used as an outline color.
|
/// A [`Color`] to be used as an outline color.
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ use alot::LotId;
|
||||||
use kludgine::app::winit::event::{
|
use kludgine::app::winit::event::{
|
||||||
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||||
};
|
};
|
||||||
|
use kludgine::app::winit::window::CursorIcon;
|
||||||
use kludgine::figures::units::{Px, UPx};
|
use kludgine::figures::units::{Px, UPx};
|
||||||
use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, Size};
|
use kludgine::figures::{IntoSigned, IntoUnsigned, Point, Rect, Size};
|
||||||
use kludgine::Color;
|
use kludgine::Color;
|
||||||
|
|
@ -68,7 +69,13 @@ pub trait Widget: Send + UnwindSafe + Debug + 'static {
|
||||||
|
|
||||||
/// The widget is currently has a cursor hovering it at `location`.
|
/// The widget is currently has a cursor hovering it at `location`.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) {}
|
fn hover(
|
||||||
|
&mut self,
|
||||||
|
location: Point<Px>,
|
||||||
|
context: &mut EventContext<'_, '_>,
|
||||||
|
) -> Option<CursorIcon> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// The widget is no longer being hovered.
|
/// The widget is no longer being hovered.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
|
|
@ -333,7 +340,13 @@ pub trait WrapperWidget: Debug + Send + UnwindSafe + 'static {
|
||||||
|
|
||||||
/// The widget is currently has a cursor hovering it at `location`.
|
/// The widget is currently has a cursor hovering it at `location`.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) {}
|
fn hover(
|
||||||
|
&mut self,
|
||||||
|
location: Point<Px>,
|
||||||
|
context: &mut EventContext<'_, '_>,
|
||||||
|
) -> Option<CursorIcon> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
/// The widget is no longer being hovered.
|
/// The widget is no longer being hovered.
|
||||||
#[allow(unused_variables)]
|
#[allow(unused_variables)]
|
||||||
|
|
@ -500,8 +513,12 @@ where
|
||||||
T::hit_test(self, location, context)
|
T::hit_test(self, location, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) {
|
fn hover(
|
||||||
T::hover(self, location, context);
|
&mut self,
|
||||||
|
location: Point<Px>,
|
||||||
|
context: &mut EventContext<'_, '_>,
|
||||||
|
) -> Option<CursorIcon> {
|
||||||
|
T::hover(self, location, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unhover(&mut self, context: &mut EventContext<'_, '_>) {
|
fn unhover(&mut self, context: &mut EventContext<'_, '_>) {
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use std::panic::UnwindSafe;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use kludgine::app::winit::event::{DeviceId, ElementState, KeyEvent, MouseButton};
|
use kludgine::app::winit::event::{DeviceId, ElementState, KeyEvent, MouseButton};
|
||||||
|
use kludgine::app::winit::window::CursorIcon;
|
||||||
use kludgine::figures::units::{Lp, Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{IntoSigned, Point, Rect, ScreenScale, Size};
|
use kludgine::figures::{IntoSigned, Point, Rect, ScreenScale, Size};
|
||||||
use kludgine::shapes::{Shape, StrokeOptions};
|
use kludgine::shapes::{Shape, StrokeOptions};
|
||||||
|
|
@ -383,7 +384,7 @@ impl Widget for Button {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn accept_focus(&mut self, context: &mut EventContext<'_, '_>) -> bool {
|
fn accept_focus(&mut self, context: &mut EventContext<'_, '_>) -> bool {
|
||||||
context.get(&AutoFocusableControls).is_all()
|
context.enabled() && context.get(&AutoFocusableControls).is_all()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_down(
|
fn mouse_down(
|
||||||
|
|
@ -492,8 +493,18 @@ impl Widget for Button {
|
||||||
self.update_colors(context, false);
|
self.update_colors(context, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hover(&mut self, _location: Point<Px>, context: &mut EventContext<'_, '_>) {
|
fn hover(
|
||||||
|
&mut self,
|
||||||
|
_location: Point<Px>,
|
||||||
|
context: &mut EventContext<'_, '_>,
|
||||||
|
) -> Option<CursorIcon> {
|
||||||
self.update_colors(context, false);
|
self.update_colors(context, false);
|
||||||
|
|
||||||
|
if context.enabled() {
|
||||||
|
Some(CursorIcon::Pointer)
|
||||||
|
} else {
|
||||||
|
Some(CursorIcon::NotAllowed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus(&mut self, context: &mut EventContext<'_, '_>) {
|
fn focus(&mut self, context: &mut EventContext<'_, '_>) {
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ use std::panic::UnwindSafe;
|
||||||
use kludgine::app::winit::event::{
|
use kludgine::app::winit::event::{
|
||||||
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||||
};
|
};
|
||||||
|
use kludgine::app::winit::window::CursorIcon;
|
||||||
use kludgine::figures::units::Px;
|
use kludgine::figures::units::Px;
|
||||||
use kludgine::figures::{Point, Size};
|
use kludgine::figures::{Point, Size};
|
||||||
use kludgine::Color;
|
use kludgine::Color;
|
||||||
|
|
@ -36,7 +37,7 @@ pub struct Custom {
|
||||||
adjust_child: Option<Box<dyn AdjustChildConstraintsFunc>>,
|
adjust_child: Option<Box<dyn AdjustChildConstraintsFunc>>,
|
||||||
position_child: Option<Box<dyn PositionChildFunc>>,
|
position_child: Option<Box<dyn PositionChildFunc>>,
|
||||||
hit_test: Option<Box<dyn OneParamEventFunc<Point<Px>, bool>>>,
|
hit_test: Option<Box<dyn OneParamEventFunc<Point<Px>, bool>>>,
|
||||||
hover: Option<Box<dyn OneParamEventFunc<Point<Px>>>>,
|
hover: Option<Box<dyn OneParamEventFunc<Point<Px>, Option<CursorIcon>>>>,
|
||||||
mouse_down:
|
mouse_down:
|
||||||
Option<Box<dyn ThreeParamEventFunc<Point<Px>, DeviceId, MouseButton, EventHandling>>>,
|
Option<Box<dyn ThreeParamEventFunc<Point<Px>, DeviceId, MouseButton, EventHandling>>>,
|
||||||
mouse_drag: Option<Box<dyn ThreeParamEventFunc<Point<Px>, DeviceId, MouseButton>>>,
|
mouse_drag: Option<Box<dyn ThreeParamEventFunc<Point<Px>, DeviceId, MouseButton>>>,
|
||||||
|
|
@ -366,7 +367,10 @@ impl Custom {
|
||||||
Hover: Send
|
Hover: Send
|
||||||
+ UnwindSafe
|
+ UnwindSafe
|
||||||
+ 'static
|
+ 'static
|
||||||
+ for<'context, 'window> FnMut(Point<Px>, &mut EventContext<'context, 'window>),
|
+ for<'context, 'window> FnMut(
|
||||||
|
Point<Px>,
|
||||||
|
&mut EventContext<'context, 'window>,
|
||||||
|
) -> Option<CursorIcon>,
|
||||||
{
|
{
|
||||||
self.hover = Some(Box::new(hover));
|
self.hover = Some(Box::new(hover));
|
||||||
self
|
self
|
||||||
|
|
@ -563,10 +567,13 @@ impl WrapperWidget for Custom {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hover(&mut self, location: Point<Px>, context: &mut EventContext<'_, '_>) {
|
fn hover(
|
||||||
if let Some(hover) = &mut self.hover {
|
&mut self,
|
||||||
hover.invoke(location, context);
|
location: Point<Px>,
|
||||||
}
|
context: &mut EventContext<'_, '_>,
|
||||||
|
) -> Option<CursorIcon> {
|
||||||
|
let hover = self.hover.as_mut()?;
|
||||||
|
hover.invoke(location, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unhover(&mut self, context: &mut EventContext<'_, '_>) {
|
fn unhover(&mut self, context: &mut EventContext<'_, '_>) {
|
||||||
|
|
|
||||||
|
|
@ -12,7 +12,7 @@ use std::time::Duration;
|
||||||
use intentional::Cast;
|
use intentional::Cast;
|
||||||
use kludgine::app::winit::event::{ElementState, Ime, KeyEvent};
|
use kludgine::app::winit::event::{ElementState, Ime, KeyEvent};
|
||||||
use kludgine::app::winit::keyboard::{Key, NamedKey};
|
use kludgine::app::winit::keyboard::{Key, NamedKey};
|
||||||
use kludgine::app::winit::window::ImePurpose;
|
use kludgine::app::winit::window::{CursorIcon, ImePurpose};
|
||||||
use kludgine::figures::units::{Lp, Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{
|
use kludgine::figures::{
|
||||||
FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size,
|
FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size,
|
||||||
|
|
@ -163,7 +163,11 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn forward_delete(&mut self) {
|
fn forward_delete(&mut self, context: &mut EventContext<'_, '_>) {
|
||||||
|
if !context.enabled() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let (cursor, selection) = self.selected_range();
|
let (cursor, selection) = self.selected_range();
|
||||||
if let Some(selection) = selection {
|
if let Some(selection) = selection {
|
||||||
self.replace_range(cursor, selection, "");
|
self.replace_range(cursor, selection, "");
|
||||||
|
|
@ -193,7 +197,11 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn delete(&mut self) {
|
fn delete(&mut self, context: &mut EventContext<'_, '_>) {
|
||||||
|
if !context.enabled() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let (cursor, selection) = self.selected_range();
|
let (cursor, selection) = self.selected_range();
|
||||||
if let Some(selection) = selection {
|
if let Some(selection) = selection {
|
||||||
self.replace_range(cursor, selection, "");
|
self.replace_range(cursor, selection, "");
|
||||||
|
|
@ -395,7 +403,11 @@ where
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn replace_selection(&mut self, new_text: &str) {
|
fn replace_selection(&mut self, new_text: &str, context: &mut EventContext<'_, '_>) {
|
||||||
|
if !context.enabled() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
let selected_range = self.selected_range();
|
let selected_range = self.selected_range();
|
||||||
match selected_range {
|
match selected_range {
|
||||||
(start, Some(end)) => {
|
(start, Some(end)) => {
|
||||||
|
|
@ -415,12 +427,16 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paste_from_clipboard(&mut self, context: &mut EventContext<'_, '_>) -> bool {
|
fn paste_from_clipboard(&mut self, context: &mut EventContext<'_, '_>) -> bool {
|
||||||
|
if !context.enabled() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
match context
|
match context
|
||||||
.clipboard_guard()
|
.clipboard_guard()
|
||||||
.map(|mut clipboard| clipboard.get_text())
|
.map(|mut clipboard| clipboard.get_text())
|
||||||
{
|
{
|
||||||
Some(Ok(text)) => {
|
Some(Ok(text)) => {
|
||||||
self.replace_selection(&text);
|
self.replace_selection(&text, context);
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
None | Some(Err(arboard::Error::ConversionFailure)) => false,
|
None | Some(Err(arboard::Error::ConversionFailure)) => false,
|
||||||
|
|
@ -435,8 +451,8 @@ where
|
||||||
match (input.state, input.logical_key, input.text.as_deref()) {
|
match (input.state, input.logical_key, input.text.as_deref()) {
|
||||||
(ElementState::Pressed, Key::Named(key @ (NamedKey::Backspace| NamedKey::Delete)), _) => {
|
(ElementState::Pressed, Key::Named(key @ (NamedKey::Backspace| NamedKey::Delete)), _) => {
|
||||||
match key {
|
match key {
|
||||||
NamedKey::Backspace => self.delete(),
|
NamedKey::Backspace => self.delete(context),
|
||||||
NamedKey::Delete => self.forward_delete(),
|
NamedKey::Delete => self.forward_delete(context),
|
||||||
_ => unreachable!("previously matched"),
|
_ => unreachable!("previously matched"),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -505,7 +521,7 @@ where
|
||||||
=>
|
=>
|
||||||
{
|
{
|
||||||
if state.is_pressed() {
|
if state.is_pressed() {
|
||||||
self.replace_selection(text);
|
self.replace_selection(text, context);
|
||||||
}
|
}
|
||||||
HANDLED
|
HANDLED
|
||||||
}
|
}
|
||||||
|
|
@ -914,6 +930,14 @@ where
|
||||||
HANDLED
|
HANDLED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hover(
|
||||||
|
&mut self,
|
||||||
|
_location: Point<Px>,
|
||||||
|
_context: &mut EventContext<'_, '_>,
|
||||||
|
) -> Option<CursorIcon> {
|
||||||
|
Some(CursorIcon::Text)
|
||||||
|
}
|
||||||
|
|
||||||
fn mouse_drag(
|
fn mouse_drag(
|
||||||
&mut self,
|
&mut self,
|
||||||
location: Point<Px>,
|
location: Point<Px>,
|
||||||
|
|
@ -963,6 +987,7 @@ where
|
||||||
} else {
|
} else {
|
||||||
ImePurpose::Normal
|
ImePurpose::Normal
|
||||||
});
|
});
|
||||||
|
|
||||||
if let Some(selection) = cache.selection {
|
if let Some(selection) = cache.selection {
|
||||||
let (start, end) = if selection < cache.cursor {
|
let (start, end) = if selection < cache.cursor {
|
||||||
(selection, cache.cursor)
|
(selection, cache.cursor)
|
||||||
|
|
@ -1098,7 +1123,7 @@ where
|
||||||
tracing::warn!("TODO: preview IME input {text}, cursor: {cursor:?}");
|
tracing::warn!("TODO: preview IME input {text}, cursor: {cursor:?}");
|
||||||
}
|
}
|
||||||
Ime::Commit(text) => {
|
Ime::Commit(text) => {
|
||||||
self.replace_selection(&text);
|
self.replace_selection(&text, context);
|
||||||
context.set_needs_redraw();
|
context.set_needs_redraw();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ use std::time::Duration;
|
||||||
|
|
||||||
use intentional::Cast;
|
use intentional::Cast;
|
||||||
use kludgine::app::winit::event::{DeviceId, MouseScrollDelta, TouchPhase};
|
use kludgine::app::winit::event::{DeviceId, MouseScrollDelta, TouchPhase};
|
||||||
|
use kludgine::app::winit::window::CursorIcon;
|
||||||
use kludgine::figures::units::{Lp, Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{
|
use kludgine::figures::{
|
||||||
FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size,
|
FloatConversion, IntoSigned, IntoUnsigned, Point, Rect, ScreenScale, Size,
|
||||||
|
|
@ -107,8 +108,14 @@ impl Widget for Scroll {
|
||||||
true
|
true
|
||||||
}
|
}
|
||||||
|
|
||||||
fn hover(&mut self, _location: Point<Px>, context: &mut EventContext<'_, '_>) {
|
fn hover(
|
||||||
|
&mut self,
|
||||||
|
_location: Point<Px>,
|
||||||
|
context: &mut EventContext<'_, '_>,
|
||||||
|
) -> Option<CursorIcon> {
|
||||||
self.show_scrollbars(context);
|
self.show_scrollbars(context);
|
||||||
|
|
||||||
|
None
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unhover(&mut self, context: &mut EventContext<'_, '_>) {
|
fn unhover(&mut self, context: &mut EventContext<'_, '_>) {
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ use std::panic::UnwindSafe;
|
||||||
use intentional::{Assert, Cast as _};
|
use intentional::{Assert, Cast as _};
|
||||||
use kludgine::app::winit::event::{DeviceId, MouseButton, MouseScrollDelta, TouchPhase};
|
use kludgine::app::winit::event::{DeviceId, MouseButton, MouseScrollDelta, TouchPhase};
|
||||||
use kludgine::app::winit::keyboard::{Key, NamedKey};
|
use kludgine::app::winit::keyboard::{Key, NamedKey};
|
||||||
|
use kludgine::app::winit::window::CursorIcon;
|
||||||
use kludgine::figures::units::{Lp, Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{
|
use kludgine::figures::{
|
||||||
FloatConversion, IntoSigned, Point, Ranged, Rect, Round, ScreenScale, Size,
|
FloatConversion, IntoSigned, Point, Ranged, Rect, Round, ScreenScale, Size,
|
||||||
|
|
@ -17,7 +18,8 @@ use kludgine::{Color, DrawableExt, Origin};
|
||||||
use crate::animation::{LinearInterpolate, PercentBetween, ZeroToOne};
|
use crate::animation::{LinearInterpolate, PercentBetween, ZeroToOne};
|
||||||
use crate::context::{EventContext, GraphicsContext, LayoutContext};
|
use crate::context::{EventContext, GraphicsContext, LayoutContext};
|
||||||
use crate::styles::components::{
|
use crate::styles::components::{
|
||||||
AutoFocusableControls, OpaqueWidgetColor, OutlineColor, WidgetAccentColor,
|
AutoFocusableControls, DisabledWidgetAccentColor, OpaqueWidgetColor, OutlineColor,
|
||||||
|
WidgetAccentColor,
|
||||||
};
|
};
|
||||||
use crate::styles::{Dimension, HorizontalOrder, VerticalOrder, VisualOrder};
|
use crate::styles::{Dimension, HorizontalOrder, VerticalOrder, VisualOrder};
|
||||||
use crate::value::{Dynamic, IntoDynamic, IntoValue, Value};
|
use crate::value::{Dynamic, IntoDynamic, IntoValue, Value};
|
||||||
|
|
@ -420,9 +422,19 @@ where
|
||||||
T: SliderValue,
|
T: SliderValue,
|
||||||
{
|
{
|
||||||
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
fn redraw(&mut self, context: &mut GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||||
let track_color = context.get(&TrackColor);
|
let (track_color, inactive_track_color, knob_color) = if context.enabled() {
|
||||||
let inactive_track_color = context.get(&InactiveTrackColor);
|
(
|
||||||
let knob_color = context.get(&KnobColor);
|
context.get(&TrackColor),
|
||||||
|
context.get(&InactiveTrackColor),
|
||||||
|
context.get(&KnobColor),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(
|
||||||
|
context.get(&DisabledTrackColor),
|
||||||
|
context.get(&DisabledInactiveTrackColor),
|
||||||
|
context.get(&DisabledKnobColor),
|
||||||
|
)
|
||||||
|
};
|
||||||
let knob_size = self.knob_size.into_signed();
|
let knob_size = self.knob_size.into_signed();
|
||||||
let mut track_size = context.get(&TrackSize).into_px(context.gfx.scale());
|
let mut track_size = context.get(&TrackSize).into_px(context.gfx.scale());
|
||||||
if knob_size > 0 {
|
if knob_size > 0 {
|
||||||
|
|
@ -548,8 +560,29 @@ where
|
||||||
self.interactive
|
self.interactive
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn hover(
|
||||||
|
&mut self,
|
||||||
|
_location: Point<Px>,
|
||||||
|
context: &mut EventContext<'_, '_>,
|
||||||
|
) -> Option<CursorIcon> {
|
||||||
|
(self.interactive && self.knob_visible).then_some({
|
||||||
|
if context.enabled() {
|
||||||
|
if self.mouse_buttons_down > 0 {
|
||||||
|
CursorIcon::Grabbing
|
||||||
|
} else {
|
||||||
|
CursorIcon::Grab
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
CursorIcon::NotAllowed
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn accept_focus(&mut self, context: &mut EventContext<'_, '_>) -> bool {
|
fn accept_focus(&mut self, context: &mut EventContext<'_, '_>) -> bool {
|
||||||
self.interactive && self.knob_visible && context.get(&AutoFocusableControls).is_all()
|
context.enabled()
|
||||||
|
&& self.interactive
|
||||||
|
&& self.knob_visible
|
||||||
|
&& context.get(&AutoFocusableControls).is_all()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus(&mut self, context: &mut EventContext<'_, '_>) {
|
fn focus(&mut self, context: &mut EventContext<'_, '_>) {
|
||||||
|
|
@ -606,13 +639,15 @@ where
|
||||||
return IGNORED;
|
return IGNORED;
|
||||||
};
|
};
|
||||||
|
|
||||||
let previous_focus = match (self.previous_focus.take(), self.focused_knob.take()) {
|
if context.enabled() {
|
||||||
(None | Some(_), Some(focus)) | (Some(focus), None) => Some(focus),
|
let previous_focus = match (self.previous_focus.take(), self.focused_knob.take()) {
|
||||||
(None, None) => None,
|
(None | Some(_), Some(focus)) | (Some(focus), None) => Some(focus),
|
||||||
};
|
(None, None) => None,
|
||||||
self.update_from_click(location, previous_focus);
|
};
|
||||||
|
self.update_from_click(location, previous_focus);
|
||||||
|
context.focus();
|
||||||
|
}
|
||||||
self.mouse_buttons_down += 1;
|
self.mouse_buttons_down += 1;
|
||||||
context.focus();
|
|
||||||
HANDLED
|
HANDLED
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -621,9 +656,11 @@ where
|
||||||
location: Point<Px>,
|
location: Point<Px>,
|
||||||
_device_id: DeviceId,
|
_device_id: DeviceId,
|
||||||
_button: MouseButton,
|
_button: MouseButton,
|
||||||
_context: &mut EventContext<'_, '_>,
|
context: &mut EventContext<'_, '_>,
|
||||||
) {
|
) {
|
||||||
self.update_from_click(location, None);
|
if context.enabled() {
|
||||||
|
self.update_from_click(location, None);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn mouse_up(
|
fn mouse_up(
|
||||||
|
|
@ -666,24 +703,26 @@ where
|
||||||
_device_id: DeviceId,
|
_device_id: DeviceId,
|
||||||
delta: MouseScrollDelta,
|
delta: MouseScrollDelta,
|
||||||
_phase: TouchPhase,
|
_phase: TouchPhase,
|
||||||
_context: &mut EventContext<'_, '_>,
|
context: &mut EventContext<'_, '_>,
|
||||||
) -> EventHandling {
|
) -> EventHandling {
|
||||||
let true = self.interactive else {
|
let true = self.interactive else {
|
||||||
return IGNORED;
|
return IGNORED;
|
||||||
};
|
};
|
||||||
|
|
||||||
let factor: f32 = match delta {
|
if context.enabled() {
|
||||||
MouseScrollDelta::LineDelta(_, y) => y,
|
let factor: f32 = match delta {
|
||||||
MouseScrollDelta::PixelDelta(pt) => pt.y.cast(),
|
MouseScrollDelta::LineDelta(_, y) => y,
|
||||||
};
|
MouseScrollDelta::PixelDelta(pt) => pt.y.cast(),
|
||||||
|
};
|
||||||
|
|
||||||
let (forwards, factor) = if factor.is_sign_negative() {
|
let (forwards, factor) = if factor.is_sign_negative() {
|
||||||
(false, -factor)
|
(false, -factor)
|
||||||
} else {
|
} else {
|
||||||
(true, factor)
|
(true, factor)
|
||||||
};
|
};
|
||||||
|
|
||||||
self.step(forwards, factor);
|
self.step(forwards, factor);
|
||||||
|
}
|
||||||
|
|
||||||
// @ecton: Unlike scroll alreas cascasing, I feel like scrolling while
|
// @ecton: Unlike scroll alreas cascasing, I feel like scrolling while
|
||||||
// using a mouse wheel as an input is annoying.
|
// using a mouse wheel as an input is annoying.
|
||||||
|
|
@ -726,10 +765,16 @@ define_components! {
|
||||||
MinimumSliderSize(Dimension, "minimum_size", |context| context.get(&KnobSize) * 2)
|
MinimumSliderSize(Dimension, "minimum_size", |context| context.get(&KnobSize) * 2)
|
||||||
/// The color of the draggable portion of the knob.
|
/// The color of the draggable portion of the knob.
|
||||||
KnobColor(Color, "knob_color", @WidgetAccentColor)
|
KnobColor(Color, "knob_color", @WidgetAccentColor)
|
||||||
|
/// The color of the draggable portion of the knob.
|
||||||
|
DisabledKnobColor(Color, "disabled_knob_color", @DisabledWidgetAccentColor)
|
||||||
/// The color of the track that the knob rests on.
|
/// The color of the track that the knob rests on.
|
||||||
TrackColor(Color,"track_color", |context| context.get(&KnobColor))
|
TrackColor(Color,"track_color", |context| context.get(&KnobColor))
|
||||||
/// The color of the track that the knob rests on.
|
/// The color of the track that the knob rests on when the widget is disabled.
|
||||||
|
DisabledTrackColor(Color,"track_color", |context| context.get(&DisabledKnobColor))
|
||||||
|
/// The color of the track that the knob rests.
|
||||||
InactiveTrackColor(Color, "inactive_track_color", |context| context.get(&OpaqueWidgetColor))
|
InactiveTrackColor(Color, "inactive_track_color", |context| context.get(&OpaqueWidgetColor))
|
||||||
|
/// The color of the track that the knob rests.
|
||||||
|
DisabledInactiveTrackColor(Color, "disabled_inactive_track_color", |context| context.get(&OpaqueWidgetColor))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue