mirror of
https://github.com/slint-ui/slint.git
synced 2025-10-01 06:11:16 +00:00
Add a FocusScope
C++ part not working because the Callback with arguments are not yet supported with C++
This commit is contained in:
parent
340e8f0d5a
commit
094287697a
8 changed files with 159 additions and 12 deletions
|
@ -37,6 +37,7 @@ extern const cbindgen_private::ItemVTable RectangleVTable;
|
|||
extern const cbindgen_private::ItemVTable BorderRectangleVTable;
|
||||
extern const cbindgen_private::ItemVTable TextVTable;
|
||||
extern const cbindgen_private::ItemVTable TouchAreaVTable;
|
||||
extern const cbindgen_private::ItemVTable FocusScopeVTable;
|
||||
extern const cbindgen_private::ItemVTable ImageVTable;
|
||||
extern const cbindgen_private::ItemVTable ClippedImageVTable;
|
||||
extern const cbindgen_private::ItemVTable PathVTable;
|
||||
|
@ -139,6 +140,7 @@ using cbindgen_private::BorderRectangle;
|
|||
using cbindgen_private::Clip;
|
||||
using cbindgen_private::ClippedImage;
|
||||
using cbindgen_private::Flickable;
|
||||
using cbindgen_private::FocusScope;
|
||||
using cbindgen_private::Image;
|
||||
using cbindgen_private::Path;
|
||||
using cbindgen_private::Rectangle;
|
||||
|
|
|
@ -84,6 +84,17 @@ export TouchArea := _ {
|
|||
//-default_size_binding:expands_to_parent_geometry
|
||||
}
|
||||
|
||||
export FocusScope := _ {
|
||||
property <length> x;
|
||||
property <length> y;
|
||||
property <length> width;
|
||||
property <length> height;
|
||||
property <bool> has_focus;
|
||||
callback key_pressed(string);
|
||||
callback key_released(string);
|
||||
//-default_size_binding:expands_to_parent_geometry
|
||||
}
|
||||
|
||||
export Flickable := _ {
|
||||
property <length> x;
|
||||
property <length> y;
|
||||
|
|
|
@ -372,6 +372,97 @@ ItemVTable_static! {
|
|||
pub static TouchAreaVTable for TouchArea
|
||||
}
|
||||
|
||||
/// A runtime item that exposes key
|
||||
#[repr(C)]
|
||||
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
||||
#[pin]
|
||||
pub struct FocusScope {
|
||||
pub x: Property<f32>,
|
||||
pub y: Property<f32>,
|
||||
pub width: Property<f32>,
|
||||
pub height: Property<f32>,
|
||||
pub has_focus: Property<bool>,
|
||||
pub key_pressed: Callback<(SharedString,)>,
|
||||
pub key_released: Callback<(SharedString,)>,
|
||||
/// FIXME: remove this
|
||||
pub cached_rendering_data: CachedRenderingData,
|
||||
}
|
||||
|
||||
impl Item for FocusScope {
|
||||
fn init(self: Pin<&Self>, _window: &ComponentWindow) {}
|
||||
|
||||
fn geometry(self: Pin<&Self>) -> Rect {
|
||||
euclid::rect(self.x(), self.y(), self.width(), self.height())
|
||||
}
|
||||
|
||||
fn layouting_info(self: Pin<&Self>, _window: &ComponentWindow) -> LayoutInfo {
|
||||
LayoutInfo::default()
|
||||
}
|
||||
|
||||
fn implicit_size(self: Pin<&Self>, _window: &ComponentWindow) -> Size {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
fn input_event(
|
||||
self: Pin<&Self>,
|
||||
event: MouseEvent,
|
||||
window: &ComponentWindow,
|
||||
self_rc: &ItemRc,
|
||||
) -> InputEventResult {
|
||||
/*if !self.enabled() {
|
||||
return InputEventResult::EventIgnored;
|
||||
}*/
|
||||
if matches!(event.what, MouseEventType::MousePressed) {
|
||||
if !self.has_focus() {
|
||||
window.set_focus_item(self_rc);
|
||||
}
|
||||
}
|
||||
InputEventResult::EventAccepted
|
||||
}
|
||||
|
||||
fn key_event(self: Pin<&Self>, event: &KeyEvent, _window: &ComponentWindow) -> KeyEventResult {
|
||||
match event {
|
||||
KeyEvent::KeyPressed { .. } => {}
|
||||
KeyEvent::KeyReleased { .. } => {}
|
||||
KeyEvent::CharacterInput { unicode_scalar, .. } => {
|
||||
if let Some(char) = std::char::from_u32(*unicode_scalar) {
|
||||
let key = SharedString::from(char.to_string().as_str());
|
||||
// FIXME: handle pressed and release in their event
|
||||
Self::FIELD_OFFSETS.key_pressed.apply_pin(self).emit(&(key.clone(),));
|
||||
Self::FIELD_OFFSETS.key_released.apply_pin(self).emit(&(key,));
|
||||
}
|
||||
}
|
||||
};
|
||||
KeyEventResult::EventAccepted
|
||||
}
|
||||
|
||||
fn focus_event(self: Pin<&Self>, event: &FocusEvent, _window: &ComponentWindow) {
|
||||
match event {
|
||||
FocusEvent::FocusIn | FocusEvent::WindowReceivedFocus => {
|
||||
self.has_focus.set(true);
|
||||
}
|
||||
FocusEvent::FocusOut | FocusEvent::WindowLostFocus => {
|
||||
self.has_focus.set(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn render(self: Pin<&Self>, _pos: Point, _backend: &mut ItemRendererRef) {}
|
||||
}
|
||||
|
||||
impl ItemConsts for FocusScope {
|
||||
const cached_rendering_data_offset: const_field_offset::FieldOffset<
|
||||
FocusScope,
|
||||
CachedRenderingData,
|
||||
> = FocusScope::FIELD_OFFSETS.cached_rendering_data.as_unpinned_projection();
|
||||
}
|
||||
|
||||
ItemVTable_static! {
|
||||
/// The VTable for `FocusScope`
|
||||
#[no_mangle]
|
||||
pub static FocusScopeVTable for FocusScope
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(FieldOffsets, Default, SixtyFPSElement)]
|
||||
#[pin]
|
||||
|
|
|
@ -19,7 +19,7 @@ use core::pin::Pin;
|
|||
|
||||
macro_rules! declare_ValueType {
|
||||
($($ty:ty,)*) => {
|
||||
pub trait ValueType: 'static + Default $(+ TryInto<$ty> + TryFrom<$ty>)* {}
|
||||
pub trait ValueType: 'static + Default + Clone $(+ TryInto<$ty> + TryFrom<$ty>)* {}
|
||||
};
|
||||
}
|
||||
declare_ValueType![
|
||||
|
@ -225,10 +225,6 @@ pub trait CallbackInfo<Item, Value> {
|
|||
item: Pin<&Item>,
|
||||
handler: Box<dyn Fn(&[Value]) -> Value>,
|
||||
) -> Result<(), ()>;
|
||||
|
||||
/// The offset of the Callback<> in the item.
|
||||
/// The use of this is unsafe
|
||||
fn offset(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<Item, Value: Default + 'static> CallbackInfo<Item, Value>
|
||||
|
@ -249,9 +245,32 @@ impl<Item, Value: Default + 'static> CallbackInfo<Item, Value>
|
|||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
todo!()
|
||||
impl<Item, Value: Clone + Default + 'static, T: Clone> CallbackInfo<Item, Value>
|
||||
for FieldOffset<Item, crate::Callback<(T,)>>
|
||||
where
|
||||
Value: TryInto<T>,
|
||||
T: TryInto<Value>,
|
||||
{
|
||||
fn emit(&self, item: Pin<&Item>, args: &[Value]) -> Result<Value, ()> {
|
||||
let value = args.first().ok_or(())?;
|
||||
let value = value.clone().try_into().map_err(|_| ())?;
|
||||
self.apply_pin(item).emit(&(value,));
|
||||
Ok(Value::default())
|
||||
}
|
||||
|
||||
fn set_handler(
|
||||
&self,
|
||||
item: Pin<&Item>,
|
||||
handler: Box<dyn Fn(&[Value]) -> Value>,
|
||||
) -> Result<(), ()> {
|
||||
self.apply_pin(item).set_handler(move |(val,)| {
|
||||
let val: Value = val.clone().try_into().ok().unwrap();
|
||||
handler(&[val]);
|
||||
Value::default();
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -478,6 +478,7 @@ fn generate_component<'id>(
|
|||
rtti_for::<Rectangle>(),
|
||||
rtti_for::<BorderRectangle>(),
|
||||
rtti_for::<TouchArea>(),
|
||||
rtti_for::<FocusScope>(),
|
||||
rtti_for::<Path>(),
|
||||
rtti_for_flickable(),
|
||||
rtti_for::<Window>(),
|
||||
|
|
|
@ -71,7 +71,6 @@ impl<Item: vtable::HasStaticVTable<corelib::items::ItemVTable>> ErasedPropertyIn
|
|||
pub trait ErasedCallbackInfo {
|
||||
fn emit(&self, item: Pin<ItemRef>, args: &[Value]) -> Value;
|
||||
fn set_handler(&self, item: Pin<ItemRef>, handler: Box<dyn Fn(&[Value]) -> Value>);
|
||||
fn offset(&self) -> usize;
|
||||
}
|
||||
|
||||
impl<Item: vtable::HasStaticVTable<corelib::items::ItemVTable>> ErasedCallbackInfo
|
||||
|
@ -84,10 +83,6 @@ impl<Item: vtable::HasStaticVTable<corelib::items::ItemVTable>> ErasedCallbackIn
|
|||
fn set_handler(&self, item: Pin<ItemRef>, handler: Box<dyn Fn(&[Value]) -> Value>) {
|
||||
(*self).set_handler(ItemRef::downcast_pin(item).unwrap(), handler).unwrap()
|
||||
}
|
||||
|
||||
fn offset(&self) -> usize {
|
||||
(*self).offset()
|
||||
}
|
||||
}
|
||||
|
||||
/// A Pointer to a model
|
||||
|
|
27
tests/cases/examples/key_press.60
Normal file
27
tests/cases/examples/key_press.60
Normal file
|
@ -0,0 +1,27 @@
|
|||
/* LICENSE BEGIN
|
||||
This file is part of the SixtyFPS Project -- https://sixtyfps.io
|
||||
Copyright (c) 2020 Olivier Goffart <olivier.goffart@sixtyfps.io>
|
||||
Copyright (c) 2020 Simon Hausmann <simon.hausmann@sixtyfps.io>
|
||||
|
||||
SPDX-License-Identifier: GPL-3.0-only
|
||||
This file is also available under commercial licensing terms.
|
||||
Please contact info@sixtyfps.io for more information.
|
||||
LICENSE END */
|
||||
|
||||
W := Window {
|
||||
VerticalLayout {
|
||||
Rectangle { color: field.has_focus ? blue: red; }
|
||||
field := FocusScope {
|
||||
vertical_stretch: 1;
|
||||
key-pressed(key) => {
|
||||
debug(key);
|
||||
t.text += key;
|
||||
}
|
||||
Rectangle { color: yellow; }
|
||||
}
|
||||
t:= Text {
|
||||
text: "> ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -47,6 +47,7 @@ fn gen_corelib(include_dir: &Path) -> anyhow::Result<()> {
|
|||
"Image",
|
||||
"ClippedImage",
|
||||
"TouchArea",
|
||||
"FocusScope",
|
||||
"Flickable",
|
||||
"Text",
|
||||
"Path",
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue