Skip to content

Commit

Permalink
Merge pull request #466 from Sharktheone/rendering/hover
Browse files Browse the repository at this point in the history
Search for hovered element and print it to the console
  • Loading branch information
Sharktheone authored May 7, 2024
2 parents 08926e1 + a303a2d commit 6e34034
Show file tree
Hide file tree
Showing 23 changed files with 260 additions and 28 deletions.
54 changes: 49 additions & 5 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ gosub_css3 = { path = "./crates/gosub_css3", features = [] }
gosub_styling = { path = "./crates/gosub_styling", features = [] }
gosub_jsapi = { path = "./crates/gosub_jsapi", features = [] }
gosub_testing = { path = "./crates/gosub_testing", features = [] }
gosub_rendering = { path = "./crates/gosub_rendering", features = [] }
gosub_rendering = { path = "crates/gosub_render_utils", features = [] }
gosub_renderer = { path = "./crates/gosub_renderer", features = [] }
serde = { version = "1.0", features = ["derive"] }
serde_derive = "1.0"
Expand Down
2 changes: 1 addition & 1 deletion crates/gosub_bindings/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ license = "MIT"

[dependencies]
gosub_shared = { path = "../gosub_shared" }
gosub_rendering = { path = "../gosub_rendering" }
gosub_rendering = { path = "../gosub_render_utils" }
gosub_html5 = { path = "../gosub_html5" }

[lib]
Expand Down
2 changes: 1 addition & 1 deletion crates/gosub_bindings/src/wrapper/text.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use gosub_rendering::render_tree::text::TextNode;
use std::ffi::c_char;
use std::ffi::CString;

/// This is a C-friendly wrapper around gosub_rendering::rendertree::text::TextNode
/// This is a C-friendly wrapper around gosub_render_utils::rendertree::text::TextNode
/// that converts Rust Strings to owned pointers to pass to the C API.
#[repr(C)]
pub struct CTextNode {
Expand Down
4 changes: 4 additions & 0 deletions crates/gosub_html5/src/node/data/element.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ pub struct ElementData {
impl Debug for ElementData {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
let mut debug = f.debug_struct("ElementData");
debug.field("node_id", &self.node_id);
debug.field("name", &self.name);
debug.field("attributes", &self.attributes);
debug.field("classes", &self.classes);
debug.finish()
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,4 @@ gosub_styling = { path = "../gosub_styling" }
taffy = "0.4.3"
anyhow = "1.0.82"
regex = "1.10.4"
rstar = "0.12.0"
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use taffy::prelude::*;

use gosub_html5::node::NodeId as GosubID;
use gosub_styling::render_tree::{RenderNodeData, RenderTree};
use gosub_styling::render_tree::RenderTree;

use crate::style::get_style_from_node;

Expand Down Expand Up @@ -40,22 +40,10 @@ fn add_children_to_tree(

let style = get_style_from_node(node);

let node = rt.get_node(node_id).unwrap();
let mut is_text = false;
if let RenderNodeData::Text(text) = &node.data {
println!("Text: {:?}", text.text);
println!("Style: {:?}", style.size);
is_text = true;
}

let node = tree
.new_with_children(style, &children)
.map_err(|e| anyhow::anyhow!(e.to_string()))?;

if is_text {
println!("Node: {:?}", node);
}

tree.set_node_context(node, Some(node_id))?;

Ok(node)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,5 +4,6 @@
//!

pub mod layout;
pub mod position;
pub mod render_tree;
pub mod style;
151 changes: 151 additions & 0 deletions crates/gosub_render_utils/src/position.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
use std::cmp::Ordering;

use rstar::{RTree, RTreeObject, AABB};
use taffy::{NodeId, PrintTree, TaffyTree};

struct Element {
id: NodeId,
x: f32,
y: f32,
width: f32,
height: f32,
radius: Option<(f32, f32, f32, f32)>,
z_index: i32,
}

impl RTreeObject for Element {
type Envelope = AABB<(f32, f32)>;
fn envelope(&self) -> Self::Envelope {
let lower = (self.x, self.y);
let upper = (self.x + self.width, self.y + self.height);
AABB::from_corners(lower, upper)
}
}

pub struct PositionTree {
tree: RTree<Element>,
}

impl PositionTree {
pub fn from_taffy<T>(taffy: &TaffyTree<T>, root: NodeId) -> Self {
let mut tree = RTree::new();

//TODO: we somehow need to get the border radius and a potential stacking context of the element here

Self::add_node_to_tree(taffy, root, 0, &mut tree, (0.0, 0.0));

Self { tree }
}

fn add_node_to_tree<T>(
taffy: &TaffyTree<T>,
id: NodeId,
z_index: i32,
tree: &mut RTree<Element>,
mut pos: (f32, f32),
) {
let layout = taffy.get_final_layout(id);

pos.0 += layout.location.x;
pos.1 += layout.location.y;

let element = Element {
id,
x: pos.0,
y: pos.1,
width: layout.size.width,
height: layout.size.height,
radius: None, //TODO: border radius
z_index,
};

tree.insert(element);

for child in taffy.children(id).unwrap_or_default() {
Self::add_node_to_tree(taffy, child, z_index + 1, tree, pos);
}
}

pub fn find(&self, x: f32, y: f32) -> Option<NodeId> {
let envelope = AABB::from_point((x, y));

self.tree
.locate_in_envelope_intersecting(&envelope)
.filter(|e| {
let Some(radi) = e.radius else {
return true;
};

let middle = (e.x + e.width / 2.0, e.y + e.height / 2.0);

match middle.0.total_cmp(&x) {
Ordering::Equal => true,
Ordering::Less => {
match middle.1.total_cmp(&y) {
Ordering::Equal => true,
// top left
Ordering::Less => {
if (e.x + radi.0) > x && (e.y + radi.0) > y {
return is_point_in_circle(
(e.x + radi.0, e.y + radi.0),
radi.0,
(x, y),
);
}
false
}
// top right
Ordering::Greater => {
if (e.x + e.width - radi.1) < x && (e.y + radi.1) < y {
return is_point_in_circle(
(e.x + radi.1, e.y + radi.1),
radi.1,
(x, y),
);
}

false
}
}
}
Ordering::Greater => {
match middle.1.total_cmp(&y) {
Ordering::Equal => true,
// bottom left
Ordering::Less => {
if (e.x + radi.2) > x && (e.y + e.height - radi.2) < y {
return is_point_in_circle(
(e.x + radi.2, e.y + e.height - radi.2),
radi.2,
(x, y),
);
}
false
}
// bottom right
Ordering::Greater => {
if (e.x + e.width - radi.3) < x && (e.y + e.height - radi.3) < y {
return is_point_in_circle(
(e.x + radi.3, e.y + radi.3),
radi.3,
(x, y),
);
}
false
}
}
}
}
})
.reduce(|a, b| if a.z_index >= b.z_index { a } else { b }) // >= because we just hope that the last-drawn element is last in the list
.map(|e| e.id)
}
}

fn is_point_in_circle(circle_center: (f32, f32), circle_radius: f32, point: (f32, f32)) -> bool {
let dx = circle_center.0 - point.0;
let dy = circle_center.1 - point.1;
let distance = (dx * dx + dy * dy).sqrt();

distance <= circle_radius
}
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion crates/gosub_renderer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ license = "MIT"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
gosub_rendering = { path = "../gosub_rendering" }
gosub_rendering = { path = "../gosub_render_utils" }
gosub_html5 = { path = "../gosub_html5" }
gosub_shared = { path = "../gosub_shared" }
gosub_styling = { path = "../gosub_styling" }
Expand Down
Loading

0 comments on commit 6e34034

Please sign in to comment.