Skip to content

Commit

Permalink
Merge pull request #211 from StaffEngineer/drawing
Browse files Browse the repository at this point in the history
Enhance drawing mode
  • Loading branch information
Dimchikkk authored Jul 24, 2023
2 parents 4014f82 + 1b527ba commit 187c60d
Show file tree
Hide file tree
Showing 8 changed files with 165 additions and 12 deletions.
2 changes: 1 addition & 1 deletion 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 @@ -4,7 +4,7 @@ license = "MIT OR Apache-2.0"
description = "App for brainstorming & sharing ideas 🦀 Learning Project"
repository = "https://github.com/StaffEngineer/velo.git"
readme = "Readme.md"
version = "0.8.11"
version = "0.8.12"
edition = "2021"

exclude = ["assets/fonts/*", "velo.gif", "velo.png"]
Expand Down
3 changes: 3 additions & 0 deletions src/themes.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ pub struct Theme {
pub celebrate_btn: Color,
pub drawing_pencil_btn_bg: Color,
pub drawing_pencil_btn: Color,
pub drawing_selected: Color,
pub clipboard_image_bg: Color,
pub code_default_lang: String,
pub code_theme: String,
Expand Down Expand Up @@ -119,6 +120,7 @@ pub fn velo_light() -> Theme {
text_pos_btn_bg: Color::rgb(207.0 / 255.0, 216.0 / 255.0, 220.0 / 255.0),
tooltip_bg: Color::rgb(1., 1., 1.),
max_camera_space: 1_000_000_000_000_000_000.,
drawing_selected: Color::BLUE,
}
}

Expand Down Expand Up @@ -180,6 +182,7 @@ pub fn velo_dark() -> Theme {
text_pos_btn_bg: Color::rgb(0.9, 0.9, 0.9),
tooltip_bg: Color::rgb(0.2, 0.2, 0.2),
max_camera_space: 1_000_000_000_000_000_000.,
drawing_selected: Color::BLUE,
}
}

Expand Down
9 changes: 8 additions & 1 deletion src/ui_plugin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,6 +182,8 @@ pub struct UiState {
pub hold_entity: Option<ReflectableUuid>,
pub entity_to_resize: Option<ReflectableUuid>,
pub entity_to_draw: Option<ReflectableUuid>,
pub entity_to_draw_selected: Option<ReflectableUuid>,
pub entity_to_draw_hold: Option<ReflectableUuid>,
pub draw_color_pair: Option<(String, Color)>,
pub arrow_to_draw_start: Option<ArrowConnect>,
pub drawing_mode: bool,
Expand Down Expand Up @@ -295,12 +297,17 @@ impl Plugin for UiPlugin {
save_to_store.after(save_tab),
canvas_click,
active_editor_changed,
interactive_sprite.before(canvas_click),
interactive_node.before(canvas_click),
change_theme,
enable_drawing_mode,
drawing,
update_drawing_position,
),
);
app.add_systems(
Update,
(set_focus_drawing, entity_to_draw_selected_changed).chain(),
);
app.add_systems(Update, (set_focused_entity, clickable_links).chain());

app.add_systems(
Expand Down
11 changes: 7 additions & 4 deletions src/ui_plugin/systems/button_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ pub fn rec_button_handlers(
border_query: Query<&Parent, With<VeloShape>>,
mut velo_node_query: Query<(Entity, &VeloNode, &mut Transform), With<VeloNode>>,
mut arrows: Query<(Entity, &ArrowMeta), (With<ArrowMeta>, Without<Tooltip>)>,
mut drawings: Query<Entity, With<Drawing<(String, Color)>>>,
mut drawings: Query<(Entity, &Drawing<(String, Color)>), With<Drawing<(String, Color)>>>,
mut ui_state: ResMut<UiState>,
mut app_state: ResMut<AppState>,
mut camera_proj_query: Query<
Expand Down Expand Up @@ -121,9 +121,12 @@ pub fn rec_button_handlers(
});
}
super::ui_helpers::ButtonTypes::Del => {
if ui_state.drawing_mode {
for entity in &mut drawings.iter_mut() {
commands.entity(entity).despawn_recursive();
if let Some(id) = ui_state.entity_to_draw_selected {
ui_state.entity_to_draw_selected = None;
for (entity, drawing) in &mut drawings.iter_mut() {
if drawing.id == id {
commands.entity(entity).despawn_recursive();
}
}
}
if let Some(id) = ui_state.entity_to_edit {
Expand Down
107 changes: 105 additions & 2 deletions src/ui_plugin/systems/drawing.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,14 +11,69 @@ use crate::{
};

use super::{
ui_helpers::{Drawing, MainPanel},
UiState,
ui_helpers::{Drawing, InteractiveNode, MainPanel},
NodeInteraction, NodeInteractionType, UiState,
};

#[path = "../../macros.rs"]
#[macro_use]
mod macros;

pub fn entity_to_draw_selected_changed(
ui_state: Res<UiState>,
theme: Res<Theme>,
mut last_entity_to_draw: Local<Option<ReflectableUuid>>,
mut drawing_q: Query<(&mut Stroke, &Drawing<(String, Color)>), With<Drawing<(String, Color)>>>,
) {
if ui_state.is_changed() && ui_state.entity_to_draw_selected != *last_entity_to_draw {
match ui_state.entity_to_draw_selected {
Some(entity_to_draw_selected) => {
for (mut stroke, drawing) in &mut drawing_q.iter_mut() {
if drawing.id == entity_to_draw_selected {
stroke.color = theme.drawing_selected;
} else {
stroke.color = drawing.drawing_color.1;
}
}
}
None => {
for (mut stroke, drawing) in &mut drawing_q.iter_mut() {
stroke.color = drawing.drawing_color.1;
}
}
};
*last_entity_to_draw = ui_state.entity_to_draw_selected;
}
}

pub fn set_focus_drawing(
mut node_interaction_events: EventReader<NodeInteraction>,
mut ui_state: ResMut<UiState>,
drawing_container_q: Query<&Drawing<(String, Color)>, With<Drawing<(String, Color)>>>,
) {
for event in node_interaction_events.iter() {
if let Ok(drawing) = drawing_container_q.get(event.entity) {
if event.node_interaction_type == NodeInteractionType::LeftDoubleClick {
if let Some(entity_to_draw_selected) = ui_state.entity_to_draw_selected {
if entity_to_draw_selected == drawing.id {
ui_state.entity_to_draw_selected = None;
continue;
}
}
ui_state.entity_to_draw_selected = Some(drawing.id);
}
if event.node_interaction_type == NodeInteractionType::LeftMouseHoldAndDrag
&& ui_state.entity_to_draw_selected == Some(drawing.id)
{
ui_state.entity_to_draw_hold = Some(drawing.id);
}
}
if event.node_interaction_type == NodeInteractionType::LeftMouseRelease {
ui_state.entity_to_draw_hold = None;
}
}
}

pub fn drawing(
mut commands: Commands,
interaction_query: Query<&Interaction, (Changed<Interaction>, With<MainPanel>)>,
Expand All @@ -35,6 +90,10 @@ pub fn drawing(
mut app_state: ResMut<AppState>,
mut z_index_local: Local<f32>,
) {
if ui_state.entity_to_draw_hold.is_some() || ui_state.entity_to_draw_selected.is_some() {
*holding_state = None;
return;
}
let (camera, camera_transform) = camera_q.single();
let mut primary_window = windows.single_mut();
let now_ms = get_timestamp();
Expand Down Expand Up @@ -111,6 +170,7 @@ pub fn drawing(
drawing_color: pair_color,
id,
},
InteractiveNode,
));
ui_state.entity_to_draw = Some(id);
}
Expand All @@ -120,3 +180,46 @@ pub fn drawing(
}
}
}

pub fn update_drawing_position(
mut cursor_moved_events: EventReader<CursorMoved>,
camera_q: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
ui_state: Res<UiState>,
mut previous_position: Local<Option<Vec2>>,
mut drawing_q: Query<
(&mut Transform, &Drawing<(String, Color)>),
With<Drawing<(String, Color)>>,
>,
) {
let (camera, camera_transform) = camera_q.single();

if ui_state.entity_to_draw_hold.is_none() {
*previous_position = None;
return;
}

if previous_position.is_none() && !cursor_moved_events.is_empty() {
if let Some(pos) = camera.viewport_to_world_2d(
camera_transform,
cursor_moved_events.iter().next().unwrap().position,
) {
*previous_position = Some(pos.round());
}
}

if previous_position.is_some() {
for (mut transform, drawing) in &mut drawing_q.iter_mut() {
if ui_state.modal_id.is_none() && Some(drawing.id) == ui_state.entity_to_draw_hold {
let event = cursor_moved_events.iter().last();
if let Some(pos) = event
.and_then(|event| camera.viewport_to_world_2d(camera_transform, event.position))
{
transform.translation.x += (pos.x - previous_position.unwrap().x).round();
transform.translation.y += (pos.y - previous_position.unwrap().y).round();
*previous_position = Some(pos.round());
break;
}
}
}
}
}
39 changes: 37 additions & 2 deletions src/ui_plugin/systems/interactive_sprites.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ use crate::{components::MainCamera, utils::get_timestamp};

use std::time::Duration;

use super::{ui_helpers::InteractiveNode, NodeInteraction, NodeInteractionType};
use super::{
ui_helpers::{Drawing, InteractiveNode},
NodeInteraction, NodeInteractionType,
};

#[derive(Default, Debug)]
pub struct HoldingState {
Expand All @@ -13,14 +16,18 @@ pub struct HoldingState {
is_holding: bool,
}

pub fn interactive_sprite(
pub fn interactive_node(
windows: Query<&Window, With<PrimaryWindow>>,
buttons: Res<Input<MouseButton>>,
res_images: Res<Assets<Image>>,
mut sprite_query: Query<
(&Sprite, &Handle<Image>, &GlobalTransform, Entity),
With<InteractiveNode>,
>,
drawing_query: Query<
(&Drawing<(String, Color)>, &GlobalTransform, Entity),
With<InteractiveNode>,
>,
camera_q: Query<(&Camera, &GlobalTransform), With<MainCamera>>,
mut node_interaction_events: EventWriter<NodeInteraction>,
mut double_click: Local<(Duration, Option<Entity>)>,
Expand All @@ -30,6 +37,34 @@ pub fn interactive_sprite(
let primary_window = windows.single();
let scale_factor = primary_window.scale_factor() as f32;
let mut active_entity = None;
for (drawing, node_transform, entity) in drawing_query.iter() {
let (mut x_min, mut x_max, mut y_min, mut y_max) = (f32::MAX, f32::MIN, f32::MAX, f32::MIN);
for point in &drawing.points {
x_min = x_min.min(point.x);
x_max = x_max.max(point.x);
y_min = y_min.min(point.y);
y_max = y_max.max(point.y);
}
x_min += node_transform.affine().translation.x;
x_max += node_transform.affine().translation.x;
y_min += node_transform.affine().translation.y;
y_max += node_transform.affine().translation.y;
let z_current = node_transform.affine().translation.z;

if let Some(pos) = primary_window.cursor_position() {
if let Some(pos) = camera.viewport_to_world_2d(camera_transform, pos) {
if x_min < pos.x && pos.x < x_max && y_min < pos.y && pos.y < y_max {
if let Some((_, z)) = active_entity {
if z < z_current {
active_entity = Some((entity, z_current));
}
} else {
active_entity = Some((entity, node_transform.affine().translation.z));
}
}
};
}
}
for (sprite, handle, node_transform, entity) in &mut sprite_query.iter_mut() {
let size = match sprite.custom_size {
Some(size) => (size.x, size.y),
Expand Down
4 changes: 3 additions & 1 deletion src/ui_plugin/systems/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,8 @@ use bevy_prototype_lyon::prelude::{PathBuilder, ShapeBundle, Stroke};

use super::{
ui_helpers::{
add_tab, spawn_sprite_node, BottomPanel, Drawing, NodeMeta, TabContainer, VeloNode,
add_tab, spawn_sprite_node, BottomPanel, Drawing, InteractiveNode, NodeMeta, TabContainer,
VeloNode,
},
DeleteDoc, DeleteTab, DrawingJsonNode,
};
Expand Down Expand Up @@ -261,6 +262,7 @@ pub fn load_tab(
points: drawing_json_node.points.clone(),
drawing_color: pair_color,
},
InteractiveNode,
));
}
break;
Expand Down

0 comments on commit 187c60d

Please sign in to comment.