Skip to content
Snippets Groups Projects
Unverified Commit 23083ecf authored by MrGVSV's avatar MrGVSV Committed by GitHub
Browse files

Merge pull request #75 from StarArawn/cursor-icon

parents 7b76d319 c4220891
No related branches found
No related tags found
No related merge requests found
use kayak_core::CursorIcon;
pub fn convert_cursor_icon(cursor_icon: CursorIcon) -> bevy::prelude::CursorIcon {
match cursor_icon {
CursorIcon::Default => bevy::prelude::CursorIcon::Default,
CursorIcon::Crosshair => bevy::prelude::CursorIcon::Crosshair,
CursorIcon::Hand => bevy::prelude::CursorIcon::Hand,
CursorIcon::Arrow => bevy::prelude::CursorIcon::Arrow,
CursorIcon::Move => bevy::prelude::CursorIcon::Move,
CursorIcon::Text => bevy::prelude::CursorIcon::Text,
CursorIcon::Wait => bevy::prelude::CursorIcon::Wait,
CursorIcon::Help => bevy::prelude::CursorIcon::Help,
CursorIcon::Progress => bevy::prelude::CursorIcon::Progress,
CursorIcon::NotAllowed => bevy::prelude::CursorIcon::NotAllowed,
CursorIcon::ContextMenu => bevy::prelude::CursorIcon::ContextMenu,
CursorIcon::Cell => bevy::prelude::CursorIcon::Cell,
CursorIcon::VerticalText => bevy::prelude::CursorIcon::VerticalText,
CursorIcon::Alias => bevy::prelude::CursorIcon::Alias,
CursorIcon::Copy => bevy::prelude::CursorIcon::Copy,
CursorIcon::NoDrop => bevy::prelude::CursorIcon::NoDrop,
CursorIcon::Grab => bevy::prelude::CursorIcon::Grab,
CursorIcon::Grabbing => bevy::prelude::CursorIcon::Grabbing,
CursorIcon::AllScroll => bevy::prelude::CursorIcon::AllScroll,
CursorIcon::ZoomIn => bevy::prelude::CursorIcon::ZoomIn,
CursorIcon::ZoomOut => bevy::prelude::CursorIcon::ZoomOut,
CursorIcon::EResize => bevy::prelude::CursorIcon::EResize,
CursorIcon::NResize => bevy::prelude::CursorIcon::NResize,
CursorIcon::NeResize => bevy::prelude::CursorIcon::NeResize,
CursorIcon::NwResize => bevy::prelude::CursorIcon::NwResize,
CursorIcon::SResize => bevy::prelude::CursorIcon::SResize,
CursorIcon::SeResize => bevy::prelude::CursorIcon::SeResize,
CursorIcon::SwResize => bevy::prelude::CursorIcon::SwResize,
CursorIcon::WResize => bevy::prelude::CursorIcon::WResize,
CursorIcon::EwResize => bevy::prelude::CursorIcon::EwResize,
CursorIcon::NsResize => bevy::prelude::CursorIcon::NsResize,
CursorIcon::NeswResize => bevy::prelude::CursorIcon::NeswResize,
CursorIcon::NwseResize => bevy::prelude::CursorIcon::NwseResize,
CursorIcon::ColResize => bevy::prelude::CursorIcon::ColResize,
CursorIcon::RowResize => bevy::prelude::CursorIcon::RowResize,
}
}
......@@ -8,9 +8,11 @@ use bevy::{
mod bevy_context;
mod camera;
mod cursor;
mod key;
mod render;
use crate::cursor::convert_cursor_icon;
pub use bevy_context::BevyContext;
pub use camera::*;
use kayak_core::{bind, Binding, InputEvent, MutableBound};
......@@ -40,8 +42,15 @@ pub fn update(world: &mut World) {
if let Ok(mut context) = bevy_context.kayak_context.write() {
context.set_global_state(std::mem::take(world));
context.render();
*world = context.take_global_state::<World>().unwrap()
*world = context.take_global_state::<World>().unwrap();
if let Some(ref mut windows) = world.get_resource_mut::<Windows>() {
if let Some(window) = windows.get_primary_mut() {
window.set_cursor_icon(convert_cursor_icon(context.cursor_icon()));
}
}
}
world.insert_resource(bevy_context);
}
}
......
use kayak_core::CursorIcon;
use kayak_ui::core::{
color::Color,
render_command::RenderCommand,
......@@ -31,11 +32,17 @@ pub fn AddButton(props: AddButtonProps) {
let background_styles = Some(Style {
border_radius: StyleProp::Value((5.0, 5.0, 5.0, 5.0)),
background_color: StyleProp::Value(color),
cursor: CursorIcon::Hand.into(),
padding_left: StyleProp::Value(Units::Pixels(9.0)),
padding_bottom: StyleProp::Value(Units::Pixels(6.0)),
..Style::default()
});
let text_styles = Some(Style {
cursor: StyleProp::Inherit,
..Style::default()
});
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::MouseIn(..) => {
set_color(Color::new(0.0791, 0.0998, 0.201, 1.0));
......@@ -48,7 +55,7 @@ pub fn AddButton(props: AddButtonProps) {
rsx! {
<Background styles={background_styles} on_event={Some(on_event)}>
<Text content={"+".to_string()} size={20.0} />
<Text content={"+".to_string()} size={20.0} styles={text_styles} />
</Background>
}
}
use kayak_core::CursorIcon;
use kayak_ui::core::{
color::Color,
render_command::RenderCommand,
......@@ -32,10 +33,16 @@ pub fn DeleteButton(props: DeleteButtonProps) {
let background_styles = Some(Style {
border_radius: StyleProp::Value((5.0, 5.0, 5.0, 5.0)),
background_color: StyleProp::Value(color),
cursor: CursorIcon::Hand.into(),
padding_left: StyleProp::Value(Units::Pixels(8.0)),
..Style::default()
});
let text_styles = Some(Style {
cursor: StyleProp::Inherit,
..Style::default()
});
let on_event = OnEvent::new(move |_, event| match event.event_type {
EventType::MouseIn(..) => {
set_color(Color::new(0.0791, 0.0998, 0.201, 1.0));
......@@ -48,7 +55,7 @@ pub fn DeleteButton(props: DeleteButtonProps) {
rsx! {
<Background styles={background_styles} on_event={Some(on_event)}>
<Text content={"X".to_string()} size={20.0} />
<Text content={"X".to_string()} size={20.0} styles={text_styles} />
</Background>
}
}
......@@ -83,7 +83,7 @@ fn TodoApp(props: TodoAppProps) {
});
rsx! {
<Window position={(415.0, 50.0)} size={(450.0, 600.0)} title={"Todo!".to_string()}>
<Window draggable={true} position={(415.0, 50.0)} size={(450.0, 600.0)} title={"Todo!".to_string()}>
<Element styles={Some(top_area_styles)}>
<TextBox
styles={Some(text_box_styles)}
......
use crate::assets::AssetStorage;
use crate::{Binding, Changeable, KayakContextRef};
use crate::{Binding, Changeable, CursorIcon, KayakContextRef};
use std::collections::HashMap;
use std::path::PathBuf;
......@@ -27,6 +27,7 @@ pub struct KayakContext {
widget_state_lifetimes:
HashMap<crate::Index, HashMap<crate::flo_binding::Uuid, Box<dyn crate::Releasable>>>,
widget_states: HashMap<crate::Index, resources::Resources>,
cursor_icon: CursorIcon,
}
impl std::fmt::Debug for KayakContext {
......@@ -42,6 +43,7 @@ impl KayakContext {
assets: resources::Resources::default(),
current_effect_index: 0,
current_state_index: 0,
cursor_icon: CursorIcon::Default,
event_dispatcher: EventDispatcher::new(),
global_bindings: HashMap::new(),
global_state: resources::Resources::default(),
......@@ -394,6 +396,7 @@ impl KayakContext {
// self.widget_manager.dirty_nodes.clear();
self.widget_manager.render();
self.widget_manager.calculate_layout();
self.update_cursor();
}
/// Processes the given input events
......@@ -557,4 +560,27 @@ impl KayakContext {
pub fn force_release_cursor(&mut self) -> Option<Index> {
self.event_dispatcher.force_release_cursor()
}
pub fn cursor_icon(&self) -> CursorIcon {
self.cursor_icon
}
#[allow(dead_code)]
pub(crate) fn set_cursor_icon(&mut self, icon: CursorIcon) {
self.cursor_icon = icon;
}
fn update_cursor(&mut self) {
if self.event_dispatcher.hovered.is_none() {
return;
}
let hovered = self.event_dispatcher.hovered.unwrap();
if let Some(node) = self.widget_manager.nodes.get(hovered) {
if let Some(node) = node {
let icon = node.resolved_styles.cursor.resolve();
self.cursor_icon = icon;
}
}
}
}
#[derive(Debug, Hash, PartialEq, Eq, Clone, Copy)]
pub enum CursorIcon {
Default,
Crosshair,
Hand,
Arrow,
Move,
Text,
Wait,
Help,
Progress,
NotAllowed,
ContextMenu,
Cell,
VerticalText,
Alias,
Copy,
NoDrop,
Grab,
Grabbing,
AllScroll,
ZoomIn,
ZoomOut,
EResize,
NResize,
NeResize,
NwResize,
SResize,
SeResize,
SwResize,
WResize,
EwResize,
NsResize,
NeswResize,
NwseResize,
ColResize,
RowResize,
}
impl Default for CursorIcon {
fn default() -> Self {
CursorIcon::Default
}
}
......@@ -48,6 +48,7 @@ pub(crate) struct EventDispatcher {
wants_cursor: Option<bool>,
has_cursor: Option<Index>,
pub cursor_capture: Option<Index>,
pub hovered: Option<Index>,
}
impl EventDispatcher {
......@@ -64,6 +65,7 @@ impl EventDispatcher {
wants_cursor: None,
has_cursor: None,
cursor_capture: None,
hovered: None,
}
}
......@@ -144,6 +146,12 @@ impl EventDispatcher {
self.has_cursor.is_some()
}
/// The currently hovered node
#[allow(dead_code)]
pub fn hovered(&self) -> Option<Index> {
self.hovered
}
/// Process and dispatch an [InputEvent](crate::InputEvent)
#[allow(dead_code)]
pub fn process_event(&mut self, input_event: InputEvent, context: &mut KayakContext) {
......@@ -252,8 +260,10 @@ impl EventDispatcher {
};
// === Setup Cursor States === //
let old_hovered = self.hovered;
let old_contains_cursor = self.contains_cursor;
let old_wants_cursor = self.wants_cursor;
self.hovered = None;
self.contains_cursor = None;
self.wants_cursor = None;
self.next_mouse_position = self.current_mouse_position;
......@@ -375,6 +385,9 @@ impl EventDispatcher {
}
widget_manager.focus_tree.focus(node);
}
EventType::Hover(..) => {
self.hovered = Some(node);
}
_ => {}
}
}
......@@ -393,6 +406,10 @@ impl EventDispatcher {
self.current_mouse_position = self.next_mouse_position;
self.is_mouse_pressed = self.next_mouse_pressed;
if self.hovered.is_none() {
// No change -> revert
self.hovered = old_hovered;
}
if self.contains_cursor.is_none() {
// No change -> revert
self.contains_cursor = old_contains_cursor;
......@@ -700,6 +717,7 @@ impl EventDispatcher {
self.contains_cursor = from.contains_cursor;
self.wants_cursor = from.wants_cursor;
self.has_cursor = from.has_cursor;
self.hovered = from.hovered;
// Do not include:
// self.cursor_capture = from.cursor_capture;
......
......@@ -5,6 +5,7 @@ pub mod color;
pub mod context;
mod context_ref;
mod cursor;
mod cursor_icon;
pub mod event;
mod event_dispatcher;
mod flo_binding;
......@@ -34,6 +35,7 @@ pub use color::Color;
pub use context::*;
pub use context_ref::KayakContextRef;
pub use cursor::PointerEvents;
pub use cursor_icon::CursorIcon;
pub use event::*;
pub use focus_tree::FocusTree;
pub use fragment::{Fragment, FragmentProps};
......
pub use morphorm::{LayoutType, PositionType, Units};
use crate::cursor::PointerEvents;
use crate::{color::Color, render_command::RenderCommand};
use crate::{color::Color, render_command::RenderCommand, CursorIcon};
#[derive(Debug, Clone, PartialEq)]
pub enum StyleProp<T: Default + Clone> {
......@@ -142,6 +142,7 @@ define_styles! {
pub border: StyleProp<(f32, f32, f32, f32)>,
pub bottom: StyleProp<Units>,
pub color: StyleProp<Color>,
pub cursor: StyleProp<CursorIcon>,
pub height: StyleProp<Units>,
pub layout_type: StyleProp<LayoutType>,
pub left: StyleProp<Units>,
......@@ -179,6 +180,7 @@ impl Style {
border_radius: StyleProp::Default,
bottom: StyleProp::Default,
color: StyleProp::Inherit,
cursor: StyleProp::Inherit,
height: StyleProp::Default,
layout_type: StyleProp::Default,
left: StyleProp::Default,
......
......@@ -4,6 +4,7 @@ use crate::core::{
styles::{Style, StyleProp, Units},
widget, Children, Color, Fragment, OnEvent, WidgetProps,
};
use kayak_core::CursorIcon;
#[derive(Default, Debug, PartialEq, Clone)]
pub struct ButtonProps {
......@@ -51,6 +52,7 @@ pub fn Button(props: ButtonProps) {
height: StyleProp::Value(Units::Pixels(45.0)),
padding_left: StyleProp::Value(Units::Stretch(1.0)),
padding_right: StyleProp::Value(Units::Stretch(1.0)),
cursor: CursorIcon::Hand.into(),
..Default::default()
}),
);
......
use kayak_core::{styles::Units, Binding, Bound};
use kayak_core::{styles::Units, Binding, Bound, CursorIcon};
use kayak_font::{CoordinateSystem, KayakFont};
use crate::core::{
......@@ -73,11 +73,14 @@ pub fn Text(props: TextProps) {
font: font_name.clone().unwrap_or("Roboto".into()),
};
let styles = props.styles.clone().unwrap_or_default();
props.styles = Some(Style {
render_command: StyleProp::Value(render_command),
width: StyleProp::Value(Units::Pixels(layout_size.0)),
height: StyleProp::Value(Units::Pixels(layout_size.1)),
..props.styles.clone().unwrap_or_default()
cursor: StyleProp::select(&[&styles.cursor, &StyleProp::Value(CursorIcon::Text)])
.clone(),
..styles
});
} else {
context.mark_dirty();
......
......@@ -4,6 +4,7 @@ use crate::core::{
styles::{Style, Units},
widget, Bound, Children, Color, EventType, MutableBound, OnEvent, WidgetProps,
};
use kayak_core::CursorIcon;
use std::sync::{Arc, RwLock};
use crate::widgets::{Background, Clip, Text};
......@@ -94,6 +95,7 @@ pub fn TextBox(props: TextBoxProps) {
top: Units::Pixels(0.0).into(),
bottom: Units::Pixels(0.0).into(),
height: Units::Pixels(26.0).into(),
cursor: CursorIcon::Text.into(),
..Default::default()
}),
);
......
......@@ -5,6 +5,7 @@ use crate::core::{
styles::{PositionType, Style, StyleProp, Units},
use_state, widget, Children, EventType, OnEvent, WidgetProps,
};
use kayak_core::CursorIcon;
use crate::widgets::{Background, Clip, Element, Text};
......@@ -88,9 +89,20 @@ pub fn Window(props: WindowProps) {
..Style::default()
};
let cursor = if draggable {
if is_dragging {
CursorIcon::Grabbing
} else {
CursorIcon::Grab
}
} else {
CursorIcon::Default
};
let title_background_styles = Style {
background_color: StyleProp::Value(Color::new(0.0781, 0.0898, 0.101, 1.0)),
border_radius: StyleProp::Value((5.0, 0.0, 0.0, 5.0)),
cursor: cursor.into(),
height: StyleProp::Value(Units::Pixels(24.0)),
width: StyleProp::Value(Units::Stretch(1.0)),
left: StyleProp::Value(Units::Pixels(0.0)),
......@@ -103,6 +115,7 @@ pub fn Window(props: WindowProps) {
let title_text_styles = Style {
height: StyleProp::Value(Units::Pixels(25.0)),
cursor: StyleProp::Inherit,
..Style::default()
};
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment