diff options
Diffstat (limited to 'src/tool')
| -rw-r--r-- | src/tool/deletion_tool.rs | 75 | ||||
| -rw-r--r-- | src/tool/icon_tool.rs | 76 | ||||
| -rw-r--r-- | src/tool/mod.rs | 86 | ||||
| -rw-r--r-- | src/tool/polygon_room_tool.rs | 134 | ||||
| -rw-r--r-- | src/tool/rect_room_tool.rs | 80 | ||||
| -rw-r--r-- | src/tool/selection_tool.rs | 68 | ||||
| -rw-r--r-- | src/tool/wall_tool.rs | 69 |
7 files changed, 0 insertions, 588 deletions
diff --git a/src/tool/deletion_tool.rs b/src/tool/deletion_tool.rs deleted file mode 100644 index da2090b..0000000 --- a/src/tool/deletion_tool.rs +++ /dev/null @@ -1,75 +0,0 @@ -//! A meta tool for selecting parts of a map and removing them in a single operation. -//! -//! The user can draw a rectangle, which currently must have it's side parallel to the x and y-axes -//! of the world. With the first node placement, the mode is started, while the second placement would -//! finish the process and delete all elements that are *completely* contained in the rectangle -//! (partially contained items are not deleted) or abort it, in which case the selection is removed -//! and nothing is deleted. - -use super::Tool; -use crate::colours::DEFAULT_COLOURS; -use crate::map::Map; -use crate::math::{ExactSurface, Rect, Vec2}; -use crate::transform::Transform; -use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; - -/// The deletion tool itself. -pub struct DeletionTool { - deletion_rect: Option<(Vec2<f64>, Vec2<f64>)>, -} - -impl DeletionTool { - /// Create a new deletion tool, there should only be one deletion tool and it should be created - /// by the editor. - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self { - deletion_rect: None, - } - } -} - -fn delete_rect((pos1, pos2): (&Vec2<f64>, &Vec2<f64>), map: &mut Map) { - let bounds = Rect::bounding_rect(*pos1, *pos2); - map.retain(|e| !bounds.contains_rect(&e.bounding_rect())); -} - -impl Tool for DeletionTool { - fn deactivate(&mut self) { - self.deletion_rect = None; - } - - fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) { - if let Some((_, ref mut pos2)) = &mut self.deletion_rect { - *pos2 = *mouse_pos_m; - } - } - - fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) { - if let Some((pos1, pos2)) = self.deletion_rect { - let rect_px = transform.rect_m_to_px(&Rect::bounding_rect(pos1, pos2)); - rld.draw_rectangle_rec(rect_px, DEFAULT_COLOURS.deletion_rect); - rld.draw_rectangle_lines_ex(rect_px, 4, DEFAULT_COLOURS.deletion_rect_outline); - } - } - - fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2<f64>) { - if let Some((pos1, pos2)) = self.deletion_rect { - delete_rect((&pos1, &pos2), map); - self.deletion_rect = None; - } else { - self.deletion_rect = Some((*mouse_pos_m, *mouse_pos_m)); - } - } - - fn finish(&mut self, map: &mut Map) { - if let Some((pos1, pos2)) = self.deletion_rect { - delete_rect((&pos1, &pos2), map); - self.deletion_rect = None; - } - } - - fn abort(&mut self) { - self.deletion_rect = None; - } -} diff --git a/src/tool/icon_tool.rs b/src/tool/icon_tool.rs deleted file mode 100644 index 8b4afc0..0000000 --- a/src/tool/icon_tool.rs +++ /dev/null @@ -1,76 +0,0 @@ -//! Tool for creating icons. For explanation of icons, please see -//! [the icon module](crate::map::icon). - -use crate::config::IconToolBinds; -use crate::input::Input; -use crate::map::icon_renderer::IconRenderer; -use crate::map::{Icon, Map, Mappable}; -use crate::math::Vec2; -use crate::tool::Tool; -use crate::transform::Transform; -use raylib::core::drawing::RaylibDrawHandle; -use std::rc::Rc; - -/// The icon tool itself. -pub struct IconTool { - keybindings: IconToolBinds, - /// Saves whether the IconTool is the currently active tool or not. - active: bool, - /// The information of the icon that should be placed / is currently being placed, if it - /// exists. - current_icon: Icon, - renderer: Rc<IconRenderer>, -} - -impl IconTool { - /// Create a new icon tool that renders icons with the provided icon renderer. There should only - /// be one instance of the tool for the program, which should be created in the editor. - pub fn new(keybindings: IconToolBinds, renderer: Rc<IconRenderer>) -> Self { - Self { - keybindings, - active: false, - current_icon: Icon::new(0, Vec2::default(), 0., renderer.clone()), - renderer, - } - } -} - -impl Tool for IconTool { - fn activate(&mut self) { - self.active = true; - } - - fn deactivate(&mut self) { - self.active = false; - } - - fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) { - self.current_icon.position = *mouse_pos_m; - } - - fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) { - if self.active { - self.current_icon.draw(rld, transform); - } - } - - fn place_single(&mut self, map: &mut Map, _mouse_pos_m: &Vec2<f64>) { - map.push_icon(self.current_icon.clone()); - } - - fn handle_custom_bindings(&mut self, _map: &mut Map, input: &mut Input) { - if input.poll_global(&self.keybindings.next) { - self.current_icon.id = (self.current_icon.id + 1) % self.renderer.num_icons(); - } - if input.poll_global(&self.keybindings.previous) { - self.current_icon.id = - (self.current_icon.id + self.renderer.num_icons() - 1) % self.renderer.num_icons(); - } - if input.poll_global(&self.keybindings.rotate_clockwise) { - self.current_icon.rotation += 45.; - } - if input.poll_global(&self.keybindings.rotate_counterclockwise) { - self.current_icon.rotation -= 45.; - } - } -} diff --git a/src/tool/mod.rs b/src/tool/mod.rs deleted file mode 100644 index b3fae80..0000000 --- a/src/tool/mod.rs +++ /dev/null @@ -1,86 +0,0 @@ -//! Tools, which are user interfaces that must be specifically selected in order to do something. -//! -//! As stated, a tool is not simply everything that helps a user do something, think of it more as a -//! mode which must be elected by the user to perform a task on a specific object type or a class of -//! objects. If instead the operation is defined by the state of the program, it is not a tool, since -//! the user didn't explicitly ask for this function to be performed, but it is rather an option -//! that's inherent to the situation the user finds themselves in. - -pub mod deletion_tool; -pub mod icon_tool; -pub mod polygon_room_tool; -pub mod rect_room_tool; -pub mod selection_tool; -pub mod wall_tool; - -pub use deletion_tool::DeletionTool; -pub use icon_tool::IconTool; -pub use polygon_room_tool::PolygonRoomTool; -pub use rect_room_tool::RectRoomTool; -pub use selection_tool::SelectionTool; -pub use wall_tool::WallTool; - -use crate::input::Input; -use crate::map::Map; -use crate::math::Vec2; -use crate::transform::Transform; -use raylib::core::drawing::RaylibDrawHandle; - -#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)] -#[repr(u8)] -/// The types of tools available in graf karto. For information about the tool itself, please see the -/// referenced Tool's documentation. -pub enum ToolType { - /// See [RectRoomTool] for information on this tool. - RectRoomTool, - /// See [PolygonRoomTool] for information on this tool. - PolygonRoomTool, - /// See [WallTool] for information on this tool. - WallTool, - /// See [IconTool] for information on this tool. - IconTool, - /// See [DeletionTool] for information on this tool. - DeletionTool, - /// See [SelectionTool] for information on this tool. - SelectionTool, - /// Not a real tool but used to know how many tools are available. New tools must be added - /// above this variant. - // TODO: Since we now use a hash map in the editor, check if this is still necessary at all. - NumTools, -} - -/// Base trait for tools. A tool is something that performs a specific action on one or more types of -/// elements. It must be selected in order to be active. For this reason, the selection tool is a -/// tool (it must be selected from the toolbox), but the dimension indicator for instance is not, -/// since it is automatically updated when applicable. -pub trait Tool { - /// Code that needs to be called when this Tool is activated or reactivated goes here. - fn activate(&mut self) {} - /// Cleanup that needs to be done when the user switches from this tool to something else goes here. - fn deactivate(&mut self) {} - - /// Called on each frame when this tool is active. - fn update(&mut self, map: &Map, mouse_pos_m: &Vec2<f64>); - - /// Draw the contents of this tool. - // TODO: Maybe make this tool mappable? This might make it easier to make things resizable while - // it's still being drawn. - fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform); - - /// Generic keybinding. - /// Code to place a single node for this tool. - fn place_single(&mut self, _map: &mut Map, _mouse_pos_m: &Vec2<f64>) {} - - /// Generic keybinding. - /// Code to finish whatever one is doing with this tool currently and trying to apply the - /// changes to the map data. - fn finish(&mut self, _map: &mut Map) {} - - /// Generic keybinding. - /// Stop whatever one is doing with this tool and do not apply any changes to the map data. - fn abort(&mut self) {} - - /// If there are any additional keybindings that need to be handled by this tool, these can be - /// handled here. - fn handle_custom_bindings(&mut self, _map: &mut Map, _input: &mut Input) {} -} diff --git a/src/tool/polygon_room_tool.rs b/src/tool/polygon_room_tool.rs deleted file mode 100644 index d7c188f..0000000 --- a/src/tool/polygon_room_tool.rs +++ /dev/null @@ -1,134 +0,0 @@ -//! Tool to create rooms in the shape of generic polygons. - -use super::Tool; -use crate::colours::DEFAULT_COLOURS; -use crate::map::Map; -use crate::math::{self, PolygonGraph, Vec2}; -use crate::transform::Transform; -use crate::FLOAT_MARGIN; -use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; - -/// The tool itself. -pub struct PolygonRoomTool { - unfinished_room: Option<(PolygonGraph<f64>, Vec2<f64>)>, - last_mouse_pos_m: Vec2<f64>, -} - -impl PolygonRoomTool { - /// Create a new polygon room tool. There should be only one instance and it should be created - /// in the editor. - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self { - unfinished_room: None, - last_mouse_pos_m: Vec2::new(0., 0.), - } - } - - /* Helper function to try and finish the currently drawn polygon. If successful, it will add it - * to the map, clear the currently drawn polygon and return bool. Otherwise it will leave the - * unfinished polygon as is and return false without pushing anything. - */ - fn try_push(&mut self, map: &mut Map) -> bool { - if self.unfinished_room.is_none() { - return false; - } - - match self - .unfinished_room - .as_ref() - .unwrap() - .0 - .clone() - .bounding_polygon(FLOAT_MARGIN) - { - Some(polygon) => { - map.push_room(polygon); - self.unfinished_room = None; - true - } - None => false, - } - } -} - -impl Tool for PolygonRoomTool { - fn deactivate(&mut self) { - self.unfinished_room = None; - } - - fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) { - // Update the last mouse position that was seen for later use. - self.last_mouse_pos_m = *mouse_pos_m; - } - - fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) { - if let Some((graph, last_node)) = &self.unfinished_room { - /* To turn the graph into a polygon, we need a copy, might as well do - * it now, so we can add the working corner to it. - */ - let mut graph = graph.clone(); - - // Add the current mouse position as the next position if possible. - graph.add_edge(&last_node, &self.last_mouse_pos_m); - - if graph.num_nodes() <= 1 { - // Only able to draw a point - rld.draw_circle_v( - transform.point_m_to_px(&self.last_mouse_pos_m), - transform.length_m_to_px(0.1) as f32, - DEFAULT_COLOURS.room_selected, - ); - } else if let Some(polygon) = graph.clone().bounding_polygon(FLOAT_MARGIN) { - let triangles = math::triangulate(polygon, FLOAT_MARGIN); - for triangle in triangles { - let triangle: [Vec2<f64>; 3] = triangle.into(); - rld.draw_triangle( - transform.point_m_to_px(&triangle[0]), - transform.point_m_to_px(&triangle[1]), - transform.point_m_to_px(&triangle[2]), - DEFAULT_COLOURS.room_selected, - ) - } - } else { - // For some reason the polygon creation failed. Draw lines for the edges instead. - for edge in graph.edge_iter() { - rld.draw_line_ex( - transform.point_m_to_px(&edge.start), - transform.point_m_to_px(&edge.end), - transform.length_m_to_px(0.1) as f32, - DEFAULT_COLOURS.room_selected, - ); - } - } - } - } - - fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2<f64>) { - if let Some((ref mut graph, ref mut last_placed)) = &mut self.unfinished_room { - // If the corner already exists in the polygon, try to finish and push it after adding the - // next edge. - let try_finish = graph.has_node(&mouse_pos_m); - - // Add an edge from the last corner to the currently active position if possible. - if graph.add_edge(last_placed, &mouse_pos_m) { - *last_placed = *mouse_pos_m; - } - - if try_finish { - self.try_push(map); - } - } else { - // Start a new unfinished polygon - self.unfinished_room = Some((PolygonGraph::new(), *mouse_pos_m)); - } - } - - fn finish(&mut self, map: &mut Map) { - self.try_push(map); - } - - fn abort(&mut self) { - self.unfinished_room = None; - } -} diff --git a/src/tool/rect_room_tool.rs b/src/tool/rect_room_tool.rs deleted file mode 100644 index ec0f0ec..0000000 --- a/src/tool/rect_room_tool.rs +++ /dev/null @@ -1,80 +0,0 @@ -//! The rectangle room tool is a specialised tool to create rooms of rectangular shape and with the -//! sides of the room parallel to the x and y-axes. This is often useful, when a quick room creation -//! is necessary and the shape of the room does not have to be very special. - -use super::Tool; -use crate::colours::DEFAULT_COLOURS; -use crate::map::Map; -use crate::math::{Rect, Vec2}; -use crate::transform::Transform; -use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; - -/// The tool to create simple, rectangular rooms. -pub struct RectRoomTool { - /// The rectangle that is currently being drawn by the user. Once it is finished, it will be - /// pushed into the room_rects. - unfinished_rect: Option<(Vec2<f64>, Vec2<f64>)>, -} - -impl RectRoomTool { - /// Create a new room tool where no rooms have been drawn yet. Should be created only once per - /// program instance and by the editor. - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self { - unfinished_rect: None, - } - } -} - -impl Tool for RectRoomTool { - fn deactivate(&mut self) { - self.unfinished_rect = None; - } - - fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) { - if let Some((_, ref mut pos2)) = &mut self.unfinished_rect { - *pos2 = *mouse_pos_m; - } - } - - fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) { - if let Some((pos1, pos2)) = self.unfinished_rect { - rld.draw_rectangle_rec( - transform.rect_m_to_px(&Rect::bounding_rect(pos1, pos2)), - DEFAULT_COLOURS.room_selected, - ); - } - } - - fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2<f64>) { - // Try to finish the rectangle if it has been started. - if let Some((pos1, pos2)) = self.unfinished_rect { - if pos1 == pos2 { - warn!("Cannot place rectangle with start and endpoint being the same"); - return; - } - - map.push_room(Rect::bounding_rect(pos1, pos2).into()); - self.unfinished_rect = None; - } else { - self.unfinished_rect = Some((*mouse_pos_m, *mouse_pos_m)); - } - } - - fn finish(&mut self, map: &mut Map) { - if let Some((pos1, pos2)) = self.unfinished_rect { - if pos1 == pos2 { - warn!("Cannot place rectangle with start and endpoint being the same"); - return; - } - - map.push_room(Rect::bounding_rect(pos1, pos2).into()); - self.unfinished_rect = None; - } - } - - fn abort(&mut self) { - self.unfinished_rect = None; - } -} diff --git a/src/tool/selection_tool.rs b/src/tool/selection_tool.rs deleted file mode 100644 index 4850a28..0000000 --- a/src/tool/selection_tool.rs +++ /dev/null @@ -1,68 +0,0 @@ -//! Selection of items on the map. -//! -//! When selecting items on the map, the editor goes into a different mode than when editing a -//! specific kind of item. Actions that are available for specific types of items become -//! unavailable, while other actions that make use of the properties to a wide range of items -//! become available instead. -//! For this reason, the selection tool can be thought of as a kind of meta tool over tools. - -use super::Tool; -use crate::colours::DEFAULT_COLOURS; -use crate::map::Map; -use crate::math::{ExactSurface, Rect, Vec2}; -use crate::transform::Transform; -use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; - -/// The selection tool makes it possible to select any item on the map when activated. -pub struct SelectionTool { - selection_rect: Option<(Vec2<f64>, Vec2<f64>)>, -} - -impl SelectionTool { - /// Create a new selection tool. There should be only one such tool per program instance and it - /// should be created in the editor. - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self { - selection_rect: None, - } - } -} - -impl Tool for SelectionTool { - fn deactivate(&mut self) { - self.selection_rect = None; - } - - fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) { - if let Some((_, ref mut pos2)) = &mut self.selection_rect { - *pos2 = *mouse_pos_m; - } - } - - fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) { - if let Some((pos1, pos2)) = self.selection_rect { - let rect_px = transform.rect_m_to_px(&Rect::bounding_rect(pos1, pos2)); - rld.draw_rectangle_rec(rect_px, DEFAULT_COLOURS.selection_rect); - rld.draw_rectangle_lines_ex(rect_px, 4, DEFAULT_COLOURS.selection_rect_outline); - } - } - - fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2<f64>) { - if let Some((pos1, pos2)) = self.selection_rect { - // Select all items on the map that are inside of the selection rectangle - let bounds = Rect::bounding_rect(pos1, pos2); - for element in map.elements_mut() { - // TODO: Make it possible to do this additively by custom keybinding. - element.set_selected(bounds.contains_rect(&element.bounding_rect())); - } - self.selection_rect = None; - } else { - self.selection_rect = Some((*mouse_pos_m, *mouse_pos_m)); - } - } - - fn abort(&mut self) { - self.selection_rect = None; - } -} diff --git a/src/tool/wall_tool.rs b/src/tool/wall_tool.rs deleted file mode 100644 index e79d815..0000000 --- a/src/tool/wall_tool.rs +++ /dev/null @@ -1,69 +0,0 @@ -//! Tool to create walls. For information about walls, see also -//! [the wall module](crate::map::wall). - -use super::Tool; -use crate::map::Map; -use crate::math::{LineSegment, Vec2}; -use crate::transform::Transform; -use raylib::core::drawing::{RaylibDraw, RaylibDrawHandle}; -use raylib::ffi::{Color, Vector2}; - -/// The wall tool to create solid barriers a player usually cannot cross. -pub struct WallTool { - unfinished_wall: Option<LineSegment<f64>>, -} - -impl WallTool { - /// Create a new wall tool. There should only be one wall tool per program instance, which should - /// be created inside of the editor. - #[allow(clippy::new_without_default)] - pub fn new() -> Self { - Self { - unfinished_wall: None, - } - } -} - -impl Tool for WallTool { - fn deactivate(&mut self) { - self.unfinished_wall = None; - } - - fn update(&mut self, _map: &Map, mouse_pos_m: &Vec2<f64>) { - if let Some(ref mut wall) = &mut self.unfinished_wall { - wall.end = *mouse_pos_m; - } - } - - fn draw(&self, rld: &mut RaylibDrawHandle, transform: &Transform) { - if let Some(ref wall) = self.unfinished_wall { - let start: Vector2 = transform.point_m_to_px(&wall.start).into(); - let end: Vector2 = transform.point_m_to_px(&wall.end).into(); - rld.draw_line_ex( - start, - end, - transform.length_m_to_px(0.1) as f32, - Color { - r: 150, - g: 200, - b: 150, - a: 255, - }, - ); - } - } - - fn place_single(&mut self, map: &mut Map, mouse_pos_m: &Vec2<f64>) { - if let Some(wall) = self.unfinished_wall.take() { - // Continue with the next wall straight away. - self.unfinished_wall = Some(LineSegment::new(wall.end, wall.end)); - map.push_wall(wall); - } else { - self.unfinished_wall = Some(LineSegment::new(*mouse_pos_m, *mouse_pos_m)); - } - } - - fn abort(&mut self) { - self.unfinished_wall = None; - } -} |
