mirror of
https://github.com/danbulant/cushy
synced 2026-07-08 04:30:34 +00:00
Button/input outline, Input select all
This commit is contained in:
parent
d844a44b33
commit
972a1c1c13
4 changed files with 169 additions and 47 deletions
|
|
@ -7,10 +7,10 @@ use kludgine::app::winit::event::{
|
||||||
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
DeviceId, Ime, KeyEvent, MouseButton, MouseScrollDelta, TouchPhase,
|
||||||
};
|
};
|
||||||
use kludgine::app::winit::window;
|
use kludgine::app::winit::window;
|
||||||
use kludgine::figures::units::{Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{IntoSigned, Point, Rect, Size};
|
use kludgine::figures::{IntoSigned, Point, Rect, ScreenScale, Size};
|
||||||
use kludgine::shapes::{Shape, StrokeOptions};
|
use kludgine::shapes::{Shape, StrokeOptions};
|
||||||
use kludgine::Kludgine;
|
use kludgine::{Color, Kludgine};
|
||||||
|
|
||||||
use crate::graphics::Graphics;
|
use crate::graphics::Graphics;
|
||||||
use crate::styles::components::{HighlightColor, VisualOrder, WidgetBackground};
|
use crate::styles::components::{HighlightColor, VisualOrder, WidgetBackground};
|
||||||
|
|
@ -450,6 +450,18 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Strokes an outline around this widget's contents.
|
||||||
|
pub fn stroke_outline<Unit>(&mut self, color: Color, options: StrokeOptions<Unit>)
|
||||||
|
where
|
||||||
|
Unit: ScreenScale<Px = Px, Lp = Lp>,
|
||||||
|
{
|
||||||
|
let visible_rect = Rect::from(self.gfx.region().size - (Px(1), Px(1)));
|
||||||
|
let focus_ring =
|
||||||
|
Shape::stroked_rect(visible_rect, color, options.into_px(self.gfx.scale()));
|
||||||
|
self.gfx
|
||||||
|
.draw_shape(&focus_ring, Point::default(), None, None);
|
||||||
|
}
|
||||||
|
|
||||||
/// Renders the default focus ring for this widget.
|
/// Renders the default focus ring for this widget.
|
||||||
///
|
///
|
||||||
/// To ensure the correct color is used, include [`HighlightColor`] in the
|
/// To ensure the correct color is used, include [`HighlightColor`] in the
|
||||||
|
|
@ -460,14 +472,8 @@ impl<'context, 'window, 'clip, 'gfx, 'pass> GraphicsContext<'context, 'window, '
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
let visible_rect = Rect::from(self.gfx.region().size - (Px(1), Px(1)));
|
let color = styles.get(&HighlightColor, self);
|
||||||
let focus_ring = Shape::stroked_rect(
|
self.stroke_outline::<Lp>(color, StrokeOptions::default());
|
||||||
visible_rect,
|
|
||||||
styles.get(&HighlightColor, self),
|
|
||||||
StrokeOptions::default(),
|
|
||||||
);
|
|
||||||
self.gfx
|
|
||||||
.draw_shape(&focus_ring, Point::default(), None, None);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Renders the default focus ring for this widget.
|
/// Renders the default focus ring for this widget.
|
||||||
|
|
|
||||||
|
|
@ -394,3 +394,39 @@ impl ComponentDefinition for WidgetBackground {
|
||||||
Color::CLEAR_WHITE
|
Color::CLEAR_WHITE
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// A [`Color`] to be used as an outline color.
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||||
|
pub struct OutlineColor;
|
||||||
|
|
||||||
|
impl NamedComponent for OutlineColor {
|
||||||
|
fn name(&self) -> Cow<'_, ComponentName> {
|
||||||
|
Cow::Owned(ComponentName::named::<Global>("outline_color"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentDefinition for OutlineColor {
|
||||||
|
type ComponentType = Color;
|
||||||
|
|
||||||
|
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Color {
|
||||||
|
context.theme().surface.outline
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A [`Color`] to be used as an outline color.
|
||||||
|
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
|
||||||
|
pub struct DisabledOutlineColor;
|
||||||
|
|
||||||
|
impl NamedComponent for DisabledOutlineColor {
|
||||||
|
fn name(&self) -> Cow<'_, ComponentName> {
|
||||||
|
Cow::Owned(ComponentName::named::<Global>("disabled_outline_color"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ComponentDefinition for DisabledOutlineColor {
|
||||||
|
type ComponentType = Color;
|
||||||
|
|
||||||
|
fn default_value(&self, context: &WidgetContext<'_, '_>) -> Color {
|
||||||
|
context.theme().surface.outline_variant
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,18 @@ 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::figures::units::{Px, UPx};
|
use kludgine::figures::units::{Lp, Px, UPx};
|
||||||
use kludgine::figures::{IntoUnsigned, Point, Rect, ScreenScale, Size};
|
use kludgine::figures::{IntoUnsigned, Point, Rect, ScreenScale, Size};
|
||||||
|
use kludgine::shapes::StrokeOptions;
|
||||||
use kludgine::text::Text;
|
use kludgine::text::Text;
|
||||||
use kludgine::Color;
|
use kludgine::Color;
|
||||||
|
|
||||||
use crate::animation::{AnimationHandle, AnimationTarget, Spawn};
|
use crate::animation::{AnimationHandle, AnimationTarget, LinearInterpolate, Spawn};
|
||||||
use crate::context::{EventContext, GraphicsContext, LayoutContext, WidgetContext};
|
use crate::context::{EventContext, GraphicsContext, LayoutContext, WidgetContext};
|
||||||
use crate::names::Name;
|
use crate::names::Name;
|
||||||
use crate::styles::components::{
|
use crate::styles::components::{
|
||||||
AutoFocusableControls, Easing, IntrinsicPadding, SurfaceColor, TextColor,
|
AutoFocusableControls, DisabledOutlineColor, Easing, IntrinsicPadding, OutlineColor,
|
||||||
|
SurfaceColor, TextColor,
|
||||||
};
|
};
|
||||||
use crate::styles::{ColorExt, ComponentDefinition, ComponentGroup, ComponentName, NamedComponent};
|
use crate::styles::{ColorExt, ComponentDefinition, ComponentGroup, ComponentName, NamedComponent};
|
||||||
use crate::utils::ModifiersExt;
|
use crate::utils::ModifiersExt;
|
||||||
|
|
@ -31,8 +33,8 @@ pub struct Button {
|
||||||
pub enabled: Value<bool>,
|
pub enabled: Value<bool>,
|
||||||
currently_enabled: bool,
|
currently_enabled: bool,
|
||||||
buttons_pressed: usize,
|
buttons_pressed: usize,
|
||||||
background_color: Option<Dynamic<Color>>,
|
colors: Option<Dynamic<Colors>>,
|
||||||
text_color: Option<Dynamic<Color>>,
|
|
||||||
color_animation: AnimationHandle,
|
color_animation: AnimationHandle,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -45,8 +47,7 @@ impl Button {
|
||||||
enabled: Value::Constant(true),
|
enabled: Value::Constant(true),
|
||||||
currently_enabled: true,
|
currently_enabled: true,
|
||||||
buttons_pressed: 0,
|
buttons_pressed: 0,
|
||||||
background_color: None,
|
colors: None,
|
||||||
text_color: None,
|
|
||||||
color_animation: AnimationHandle::default(),
|
color_animation: AnimationHandle::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -88,18 +89,23 @@ impl Button {
|
||||||
&Easing,
|
&Easing,
|
||||||
&TextColor,
|
&TextColor,
|
||||||
&SurfaceColor,
|
&SurfaceColor,
|
||||||
|
&OutlineColor,
|
||||||
|
&DisabledOutlineColor,
|
||||||
]);
|
]);
|
||||||
let text_color = styles.get(&TextColor, context);
|
let text_color = styles.get(&TextColor, context);
|
||||||
let surface_color = styles.get(&SurfaceColor, context);
|
let surface_color = styles.get(&SurfaceColor, context);
|
||||||
let (background_color, text_color, surface_color) = if !self.enabled.get() {
|
let outline_color = styles.get(&OutlineColor, context);
|
||||||
|
let (background, outline, text_color, surface_color) = if !self.enabled.get() {
|
||||||
(
|
(
|
||||||
styles.get(&ButtonDisabledBackground, context),
|
styles.get(&ButtonDisabledBackground, context),
|
||||||
|
styles.get(&DisabledOutlineColor, context),
|
||||||
text_color,
|
text_color,
|
||||||
surface_color,
|
surface_color,
|
||||||
)
|
)
|
||||||
} else if context.is_default() {
|
} else if context.is_default() {
|
||||||
// TODO this probably should be de-prioritized if ButtonBackground is explicitly set.
|
// TODO this probably should be de-prioritized if ButtonBackground is explicitly set.
|
||||||
(
|
(
|
||||||
|
context.theme().primary.color,
|
||||||
context.theme().primary.color,
|
context.theme().primary.color,
|
||||||
context.theme().primary.on_color,
|
context.theme().primary.on_color,
|
||||||
context.theme().primary.color,
|
context.theme().primary.color,
|
||||||
|
|
@ -107,56 +113,77 @@ impl Button {
|
||||||
} else if context.active() {
|
} else if context.active() {
|
||||||
(
|
(
|
||||||
styles.get(&ButtonActiveBackground, context),
|
styles.get(&ButtonActiveBackground, context),
|
||||||
|
outline_color,
|
||||||
text_color,
|
text_color,
|
||||||
surface_color,
|
surface_color,
|
||||||
)
|
)
|
||||||
} else if context.hovered() {
|
} else if context.hovered() {
|
||||||
(
|
(
|
||||||
styles.get(&ButtonHoverBackground, context),
|
styles.get(&ButtonHoverBackground, context),
|
||||||
|
outline_color,
|
||||||
text_color,
|
text_color,
|
||||||
surface_color,
|
surface_color,
|
||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
(
|
(
|
||||||
styles.get(&ButtonBackground, context),
|
styles.get(&ButtonBackground, context),
|
||||||
|
outline_color,
|
||||||
text_color,
|
text_color,
|
||||||
surface_color,
|
surface_color,
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
let text_color = background_color.most_contrasting(&[text_color, surface_color]);
|
let text = background.most_contrasting(&[text_color, surface_color]);
|
||||||
|
|
||||||
match (immediate, &self.background_color, &self.text_color) {
|
let new_colors = Colors {
|
||||||
(false, Some(bg), Some(text)) => {
|
background,
|
||||||
self.color_animation = (
|
text,
|
||||||
bg.transition_to(background_color),
|
outline,
|
||||||
text.transition_to(text_color),
|
};
|
||||||
)
|
|
||||||
|
match (immediate, &self.colors) {
|
||||||
|
(false, Some(colors)) => {
|
||||||
|
self.color_animation = colors
|
||||||
|
.transition_to(new_colors)
|
||||||
.over(Duration::from_millis(150))
|
.over(Duration::from_millis(150))
|
||||||
.with_easing(styles.get(&Easing, context))
|
.with_easing(styles.get(&Easing, context))
|
||||||
.spawn();
|
.spawn();
|
||||||
}
|
}
|
||||||
(true, Some(bg), Some(text)) => {
|
(true, Some(colors)) => {
|
||||||
bg.update(background_color);
|
colors.update(new_colors);
|
||||||
text.update(text_color);
|
|
||||||
self.color_animation.clear();
|
self.color_animation.clear();
|
||||||
}
|
}
|
||||||
_ => {
|
_ => {
|
||||||
self.background_color = Some(Dynamic::new(background_color));
|
self.colors = Some(Dynamic::new(new_colors));
|
||||||
self.text_color = Some(Dynamic::new(text_color));
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn current_colors(&mut self, context: &WidgetContext<'_, '_>) -> (Color, Color) {
|
fn current_colors(&mut self, context: &WidgetContext<'_, '_>) -> Colors {
|
||||||
if self.background_color.is_none() {
|
if self.colors.is_none() {
|
||||||
self.update_colors(context, false);
|
self.update_colors(context, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let background_color = self.background_color.as_ref().expect("always initialized");
|
let colors = self.colors.as_ref().expect("always initialized");
|
||||||
let text_color = self.text_color.as_ref().expect("always initialized"); // TODO combine these into a single option
|
context.redraw_when_changed(colors);
|
||||||
context.redraw_when_changed(background_color);
|
colors.get()
|
||||||
(background_color.get(), text_color.get())
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, Clone, Copy)]
|
||||||
|
struct Colors {
|
||||||
|
background: Color,
|
||||||
|
text: Color,
|
||||||
|
outline: Color,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl LinearInterpolate for Colors {
|
||||||
|
fn lerp(&self, target: &Self, percent: f32) -> Self {
|
||||||
|
Self {
|
||||||
|
background: self.background.lerp(&target.background, percent),
|
||||||
|
text: self.text.lerp(&target.text, percent),
|
||||||
|
outline: self.outline.lerp(&target.outline, percent),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -175,16 +202,18 @@ impl Widget for Button {
|
||||||
self.label.redraw_when_changed(context);
|
self.label.redraw_when_changed(context);
|
||||||
self.enabled.redraw_when_changed(context);
|
self.enabled.redraw_when_changed(context);
|
||||||
|
|
||||||
let (background_color, text_color) = self.current_colors(context);
|
let colors = self.current_colors(context);
|
||||||
context.gfx.fill(background_color);
|
context.gfx.fill(colors.background);
|
||||||
|
|
||||||
if context.focused() {
|
if context.focused() {
|
||||||
context.draw_focus_ring();
|
context.draw_focus_ring();
|
||||||
|
} else {
|
||||||
|
context.stroke_outline::<Lp>(colors.outline, StrokeOptions::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
self.label.map(|label| {
|
self.label.map(|label| {
|
||||||
context.gfx.draw_text(
|
context.gfx.draw_text(
|
||||||
Text::new(label, text_color)
|
Text::new(label, colors.text)
|
||||||
.origin(kludgine::text::TextOrigin::Center)
|
.origin(kludgine::text::TextOrigin::Center)
|
||||||
.wrap_at(size.width),
|
.wrap_at(size.width),
|
||||||
center,
|
center,
|
||||||
|
|
|
||||||
|
|
@ -5,17 +5,19 @@ use std::time::Duration;
|
||||||
|
|
||||||
use kludgine::app::winit::event::{ElementState, Ime, KeyEvent};
|
use kludgine::app::winit::event::{ElementState, Ime, KeyEvent};
|
||||||
use kludgine::app::winit::keyboard::Key;
|
use kludgine::app::winit::keyboard::Key;
|
||||||
use kludgine::cosmic_text::{Action, Attrs, Buffer, Cursor, Edit, Editor, Metrics, Shaping};
|
use kludgine::cosmic_text::{
|
||||||
use kludgine::figures::units::{Px, UPx};
|
Action, Affinity, Attrs, Buffer, Cursor, Edit, Editor, Metrics, Shaping,
|
||||||
|
};
|
||||||
|
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,
|
||||||
};
|
};
|
||||||
use kludgine::shapes::Shape;
|
use kludgine::shapes::{Shape, StrokeOptions};
|
||||||
use kludgine::text::TextOrigin;
|
use kludgine::text::TextOrigin;
|
||||||
use kludgine::{Color, Kludgine};
|
use kludgine::{Color, Kludgine};
|
||||||
|
|
||||||
use crate::context::{EventContext, LayoutContext, WidgetContext};
|
use crate::context::{EventContext, LayoutContext, WidgetContext};
|
||||||
use crate::styles::components::{HighlightColor, LineHeight, TextColor, TextSize};
|
use crate::styles::components::{HighlightColor, LineHeight, OutlineColor, TextColor, TextSize};
|
||||||
use crate::styles::Styles;
|
use crate::styles::Styles;
|
||||||
use crate::utils::ModifiersExt;
|
use crate::utils::ModifiersExt;
|
||||||
use crate::value::{Generation, IntoValue, Value};
|
use crate::value::{Generation, IntoValue, Value};
|
||||||
|
|
@ -32,6 +34,8 @@ pub struct Input {
|
||||||
on_key: Option<Callback<KeyEvent, EventHandling>>,
|
on_key: Option<Callback<KeyEvent, EventHandling>>,
|
||||||
editor: Option<LiveEditor>,
|
editor: Option<LiveEditor>,
|
||||||
cursor_state: CursorState,
|
cursor_state: CursorState,
|
||||||
|
needs_to_select_all: bool,
|
||||||
|
mouse_buttons_down: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Input {
|
impl Input {
|
||||||
|
|
@ -47,6 +51,8 @@ impl Input {
|
||||||
editor: None,
|
editor: None,
|
||||||
cursor_state: CursorState::default(),
|
cursor_state: CursorState::default(),
|
||||||
on_key: None,
|
on_key: None,
|
||||||
|
mouse_buttons_down: 0,
|
||||||
|
needs_to_select_all: true,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -100,6 +106,22 @@ impl Input {
|
||||||
fn styles(context: &WidgetContext<'_, '_>) -> Styles {
|
fn styles(context: &WidgetContext<'_, '_>) -> Styles {
|
||||||
context.query_styles(&[&TextColor, &TextSize, &LineHeight])
|
context.query_styles(&[&TextColor, &TextSize, &LineHeight])
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn select_all(&mut self) {
|
||||||
|
let Some(editor) = self.editor.as_mut().map(|editor| &mut editor.editor) else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
if !editor.buffer().lines.is_empty() {
|
||||||
|
let line = editor.buffer().lines.len() - 1;
|
||||||
|
let end = Cursor::new_with_affinity(
|
||||||
|
line,
|
||||||
|
editor.buffer().lines[line].text().len(),
|
||||||
|
Affinity::After,
|
||||||
|
);
|
||||||
|
editor.set_cursor(end);
|
||||||
|
editor.set_select_opt(Some(Cursor::new_with_affinity(0, 0, Affinity::Before)));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Input {
|
impl Default for Input {
|
||||||
|
|
@ -132,7 +154,9 @@ impl Widget for Input {
|
||||||
_button: kludgine::app::winit::event::MouseButton,
|
_button: kludgine::app::winit::event::MouseButton,
|
||||||
context: &mut EventContext<'_, '_>,
|
context: &mut EventContext<'_, '_>,
|
||||||
) -> EventHandling {
|
) -> EventHandling {
|
||||||
|
self.mouse_buttons_down += 1;
|
||||||
context.focus();
|
context.focus();
|
||||||
|
self.needs_to_select_all = false;
|
||||||
let styles = context.query_styles(&[&TextColor]);
|
let styles = context.query_styles(&[&TextColor]);
|
||||||
self.editor_mut(context.kludgine, &styles, &context.widget)
|
self.editor_mut(context.kludgine, &styles, &context.widget)
|
||||||
.action(
|
.action(
|
||||||
|
|
@ -166,12 +190,22 @@ impl Widget for Input {
|
||||||
context.set_needs_redraw();
|
context.set_needs_redraw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn mouse_up(
|
||||||
|
&mut self,
|
||||||
|
_location: Option<Point<Px>>,
|
||||||
|
_device_id: kludgine::app::winit::event::DeviceId,
|
||||||
|
_button: kludgine::app::winit::event::MouseButton,
|
||||||
|
_context: &mut EventContext<'_, '_>,
|
||||||
|
) {
|
||||||
|
self.mouse_buttons_down -= 1;
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(clippy::too_many_lines)]
|
#[allow(clippy::too_many_lines)]
|
||||||
fn redraw(&mut self, context: &mut crate::context::GraphicsContext<'_, '_, '_, '_, '_>) {
|
fn redraw(&mut self, context: &mut crate::context::GraphicsContext<'_, '_, '_, '_, '_>) {
|
||||||
self.cursor_state.update(context.elapsed());
|
self.cursor_state.update(context.elapsed());
|
||||||
let cursor_state = self.cursor_state;
|
let cursor_state = self.cursor_state;
|
||||||
let size = context.gfx.size();
|
let size = context.gfx.size();
|
||||||
let styles = context.query_styles(&[&TextColor, &HighlightColor]);
|
let styles = context.query_styles(&[&TextColor, &HighlightColor, &OutlineColor]);
|
||||||
let highlight = styles.get(&HighlightColor, context);
|
let highlight = styles.get(&HighlightColor, context);
|
||||||
let editor = self.editor_mut(&mut context.gfx, &styles, &context.widget);
|
let editor = self.editor_mut(&mut context.gfx, &styles, &context.widget);
|
||||||
let cursor = editor.cursor();
|
let cursor = editor.cursor();
|
||||||
|
|
@ -311,6 +345,9 @@ impl Widget for Input {
|
||||||
context.redraw_when_changed(context.window().focused());
|
context.redraw_when_changed(context.window().focused());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
let outline_color = styles.get(&OutlineColor, context);
|
||||||
|
context.stroke_outline::<Lp>(outline_color, StrokeOptions::default());
|
||||||
}
|
}
|
||||||
|
|
||||||
let text_color = styles.get(&TextColor, context);
|
let text_color = styles.get(&TextColor, context);
|
||||||
|
|
@ -330,6 +367,10 @@ impl Widget for Input {
|
||||||
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
context: &mut LayoutContext<'_, '_, '_, '_, '_>,
|
||||||
) -> Size<UPx> {
|
) -> Size<UPx> {
|
||||||
let styles = context.query_styles(&[&TextColor]);
|
let styles = context.query_styles(&[&TextColor]);
|
||||||
|
if self.needs_to_select_all {
|
||||||
|
self.needs_to_select_all = false;
|
||||||
|
self.select_all();
|
||||||
|
}
|
||||||
let editor = self.editor_mut(&mut context.graphics.gfx, &styles, &context.graphics.widget);
|
let editor = self.editor_mut(&mut context.graphics.gfx, &styles, &context.graphics.widget);
|
||||||
let buffer = editor.buffer_mut();
|
let buffer = editor.buffer_mut();
|
||||||
buffer.set_size(
|
buffer.set_size(
|
||||||
|
|
@ -362,7 +403,7 @@ impl Widget for Input {
|
||||||
// "Keyboard input: {:?}. {:?}, {:?}",
|
// "Keyboard input: {:?}. {:?}, {:?}",
|
||||||
// input.logical_key, input.text, input.physical_key
|
// input.logical_key, input.text, input.physical_key
|
||||||
// );
|
// );
|
||||||
let (text_changed, handled) = match (input.state, input.logical_key, input.text) {
|
let (text_changed, handled) = match (input.state, input.logical_key, input.text.as_deref()) {
|
||||||
(ElementState::Pressed, key @ (Key::Backspace | Key::Delete), _) => {
|
(ElementState::Pressed, key @ (Key::Backspace | Key::Delete), _) => {
|
||||||
editor.action(
|
editor.action(
|
||||||
context.kludgine.font_system(),
|
context.kludgine.font_system(),
|
||||||
|
|
@ -400,6 +441,12 @@ impl Widget for Input {
|
||||||
);
|
);
|
||||||
(false, HANDLED)
|
(false, HANDLED)
|
||||||
}
|
}
|
||||||
|
(state, _, Some("a")) if context.modifiers().primary() => {
|
||||||
|
if state.is_pressed() {
|
||||||
|
self.select_all();
|
||||||
|
}
|
||||||
|
(false, HANDLED)
|
||||||
|
}
|
||||||
(state, _, Some(text))
|
(state, _, Some(text))
|
||||||
if !context.modifiers().primary()
|
if !context.modifiers().primary()
|
||||||
&& text != "\t" // tab
|
&& text != "\t" // tab
|
||||||
|
|
@ -408,7 +455,7 @@ impl Widget for Input {
|
||||||
=>
|
=>
|
||||||
{
|
{
|
||||||
if state.is_pressed() {
|
if state.is_pressed() {
|
||||||
editor.insert_string(&text, None);
|
editor.insert_string(text, None);
|
||||||
}
|
}
|
||||||
(state.is_pressed(), HANDLED)
|
(state.is_pressed(), HANDLED)
|
||||||
}
|
}
|
||||||
|
|
@ -456,6 +503,10 @@ impl Widget for Input {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn focus(&mut self, context: &mut EventContext<'_, '_>) {
|
fn focus(&mut self, context: &mut EventContext<'_, '_>) {
|
||||||
|
if self.mouse_buttons_down == 0 {
|
||||||
|
self.needs_to_select_all = true;
|
||||||
|
}
|
||||||
|
|
||||||
context.set_ime_allowed(true);
|
context.set_ime_allowed(true);
|
||||||
context.set_needs_redraw();
|
context.set_needs_redraw();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue