aboutsummaryrefslogtreecommitdiff
path: root/src/gui
diff options
context:
space:
mode:
authorArne Dußin2020-12-16 18:01:25 +0100
committerArne Dußin2020-12-16 18:01:25 +0100
commitc073618d9773216ab4a2dcd7944589f38b1df751 (patch)
treee57b1ea8f99d9eb4bd3e500b6b56fb7879cabc40 /src/gui
parent82d11b7d3e15d8175accf7579db1fbe528fc6583 (diff)
downloadgraf_karto-c073618d9773216ab4a2dcd7944589f38b1df751.tar.gz
graf_karto-c073618d9773216ab4a2dcd7944589f38b1df751.zip
Add new dimension indicator
Diffstat (limited to 'src/gui')
-rw-r--r--src/gui/dimension_indicator.rs141
-rw-r--r--src/gui/mod.rs2
2 files changed, 97 insertions, 46 deletions
diff --git a/src/gui/dimension_indicator.rs b/src/gui/dimension_indicator.rs
index cc12f0b..3d8313d 100644
--- a/src/gui/dimension_indicator.rs
+++ b/src/gui/dimension_indicator.rs
@@ -1,69 +1,118 @@
-use crate::math::Vec2;
+use crate::math::{self, Vec2, Rect};
use crate::transform::Transform;
use raylib::drawing::RaylibDraw;
-use raylib::ffi::Color;
+use raylib::RaylibHandle;
+use raylib::ffi::{KeyboardKey, Color};
+use crate::map::Map;
+use std::mem;
+/// A state the [DimensionIndicator] is currently in. This determines the behaviour of it and what
+/// inputs it might be waiting for.
+enum State {
+ /// In this state, the indicator is not trying to read any keyboard input, but will instead watch
+ /// for any changes to the dimensions from a different source, updating its display.
+ Watching,
+ /// In this state, the indicator will capture keyboard input and attempt to set the dimensions
+ /// according to whatever was entered. If the dimensions cannot be set, the indicator will use
+ /// the last valid dimensions.
+ Ruling {
+ dim_x: String,
+ dim_y: String,
+ editing_x: bool
+ }
+}
+
+/// Used to render the horizontal and vertical dimensions of whatever is selected on the map and, if
+/// the user so desires edit them directly by entering values into it.
pub struct DimensionIndicator {
- /// The lines that are used to draw the Dimension Indicator. For a rectangle for instance these
- /// would be two. One for width and one for height.
- length_lines: Vec<(Vec2<f64>, Vec2<f64>)>,
+ /// The [State] the dimension indicator is currently in.
+ state: State,
+ /// The last dimensions that were valid.
+ dimensions: Rect<f64>
+}
+
+impl Default for State {
+ fn default() -> Self {
+ Self::Watching
+ }
}
impl DimensionIndicator {
- #[allow(clippy::new_without_default)]
+ /// Create a new dimension indicator. While it is possible to have multiple instances, this is
+ /// not generally recommended, since they will need to be managed carefully or otherwise steal
+ /// keystrokes from each other.
pub fn new() -> Self {
Self {
- length_lines: Vec::new(),
+ state: State::default(),
+ dimensions: Rect::new(0., 0., 0., 0.);
}
}
- pub fn from_corner_points(corner_points: &[Vec2<f64>]) -> Self {
- let mut this = Self::new();
- this.update_dimensions(corner_points);
-
- this
+ /// Update whatever is selected on the map according to the dimension indicator rules and rulers.
+ pub fn update(&mut self, map: &mut Map, rl: &mut RaylibHandle) {
+ match &self.state {
+ &State::Watching => self.update_watching(map, rl),
+ &State::Ruling{ .. } => self.update_ruling(map, rl),
+ };
}
- pub fn clear_dimensions(&mut self) {
- self.length_lines.clear();
- }
+ fn update_watching(&mut self, map: &Map, rl: &RaylibHandle) {
+ let mut min: Vec2<f64> = Vec2::default();
+ let mut max: Vec2<f64> = Vec2::default();
- /// Update the dimensions by analysing a given set of points and adjusting the internal
- /// (measured) dimensions.
- pub fn update_dimensions(&mut self, corner_points: &[Vec2<f64>]) {
- if corner_points.len() < 2 {
- warn!("Cannot discern dimensions when not at least two points are given. The dimensions were not updated.");
- return;
+ /* Try to find selected items. If no items exist, the dimension indicator is set to its
+ * default, otherwise it is adjusted to the size of the combined selection.
+ */
+ let mut selection_exists = false;
+ for e in map.elements() {
+ if e.selected() {
+ let element_bounds = e.bounding_rect();
+ if selection_exists {
+ // Adjust the currently detected selection size.
+ min.x = math::partial_min(min.x, element_bounds.x);
+ min.y = math::partial_min(min.y, element_bounds.y);
+ max.x = math::partial_max(max.x, element_bounds.x + element_bounds.w);
+ max.y = math::partial_max(max.y, element_bounds.y + element_bounds.h);
+ }
+ else {
+ // No selection size detected yet. Set now.
+ min.x = element_bounds.x;
+ min.y = element_bounds.y;
+ max.x = element_bounds.x + element_bounds.w;
+ max.y = element_bounds.y + element_bounds.h;
+ }
+ }
}
- // Discern the bounding box for the given corner points.
- let mut min = corner_points[0];
- let mut max = corner_points[0];
- for point in corner_points.iter().skip(1) {
- if point.x < min.x {
- min.x = point.x;
- }
- if point.x > max.x {
- max.x = point.x;
- }
+ // Set the current selection limits, if any.
+ self.dimensions = if selection_exists {
+ Rect::bounding_rect(min, max)
+ }
+ else {
+ Rect::new(0., 0., 0., 0.)
+ };
- if point.y < min.y {
- min.y = point.y;
- }
- if point.y > max.y {
- max.y = point.y;
- }
+ // Check if the user wants to change into editing mode, which the user can only do if there
+ // is a selection to begin with.
+ if selection_exists && rl.is_key_pressed(KeyboardKey::KEY_TAB) {
+ self.state = State::Ruling {
+ dim_x: self.dimensions.w.to_string(),
+ dim_y: self.dimensions.h.to_string(),
+ editing_x: true
+ };
}
+ }
+
+ fn update_ruling(&mut self, map: &mut Map, rl: &mut RaylibHandle) {
+ /* Capture the current key press and interpret it, if it exists. Otherwise, there is nothing
+ * to update.
+ */
+ let key = match rl.get_key_pressed() {
+ Some(key) => key,
+ None => return,
+ };
+
- // For now, only use the width and height vectors.
- // TODO: Change to a more sophisticated approach.
- self.length_lines.clear();
- // Horizontal dimensions, left to right.
- self.length_lines
- .push((Vec2::new(min.x, max.y), Vec2::new(max.x, max.y)));
- // Vertical dimensions, bottom to top.
- self.length_lines
- .push((Vec2::new(max.x, max.y), Vec2::new(max.x, min.y)));
}
pub fn draw(&self, rld: &mut impl RaylibDraw, transform: &Transform) {
diff --git a/src/gui/mod.rs b/src/gui/mod.rs
index a4a000b..0351ab3 100644
--- a/src/gui/mod.rs
+++ b/src/gui/mod.rs
@@ -1,3 +1,5 @@
pub mod tool_sidebar;
+pub mod dimension_indicator;
pub use self::tool_sidebar::*;
+pub use self::dimension_indicator::*; \ No newline at end of file