aboutsummaryrefslogtreecommitdiff
path: root/src/main.rs
diff options
context:
space:
mode:
authorNathan Reiner <nathan@nathanreiner.xyz>2024-01-18 23:20:48 +0100
committerNathan Reiner <nathan@nathanreiner.xyz>2024-01-18 23:20:48 +0100
commit2d8674255a739c99b1d871e7af20480199fb95c8 (patch)
tree24460275f33c3e881bcf993266ab90a06f156309 /src/main.rs
parent1713618d4cc0194674f91fd2d24ef2de88f21784 (diff)
add scrolling to iced demo
Diffstat (limited to 'src/main.rs')
-rw-r--r--src/main.rs151
1 files changed, 107 insertions, 44 deletions
diff --git a/src/main.rs b/src/main.rs
index 8876f16..90fc7ea 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,7 +1,9 @@
pub mod math;
+use iced::event;
use iced::executor;
use iced::mouse;
+use iced::mouse::Interaction;
use iced::widget::canvas::{stroke, Cache, Geometry, LineCap, Path, Stroke};
use iced::widget::column;
use iced::widget::text_input;
@@ -27,9 +29,6 @@ pub fn main() -> iced::Result {
#[derive(Default)]
struct Graph {
graph: Cache,
- center_x: f32,
- center_y: f32,
- scale: f32,
func: ExpressionFunction,
ctx: Context,
input_state: String,
@@ -38,16 +37,7 @@ struct Graph {
#[derive(Debug, Clone)]
enum Message {
InputChanged(String),
- FunctionRun,
-}
-
-impl Graph {
- fn map_coords(&self, x: f32, y: f32) -> Point {
- Point::new(
- (self.center_x + x) * self.scale,
- (self.center_y - y) * self.scale,
- )
- }
+ UpdateScreen,
}
impl Application for Graph {
@@ -62,7 +52,6 @@ impl Application for Graph {
input_state: "f(x) = x^2".to_string(),
func: ExpressionFunction::from_string("f(x) = x^2".to_string()),
ctx: Context::commonsense(),
- scale: 50.0,
..Default::default()
},
Command::none(),
@@ -78,7 +67,7 @@ impl Application for Graph {
Message::InputChanged(s) => {
self.input_state = s;
}
- Message::FunctionRun => {
+ Message::UpdateScreen => {
self.func = ExpressionFunction::from_string(self.input_state.clone());
self.graph.clear();
}
@@ -89,7 +78,7 @@ impl Application for Graph {
fn view(&self) -> Element<Message> {
let input = text_input("x", &self.input_state)
.on_input(Message::InputChanged)
- .on_submit(Message::FunctionRun)
+ .on_submit(Message::UpdateScreen)
.padding(15)
.size(30);
let canvas = canvas(self as &Self)
@@ -105,12 +94,40 @@ impl Application for Graph {
}
}
-impl<Message> canvas::Program<Message, Renderer> for Graph {
- type State = ();
+#[derive(Copy, Clone)]
+struct MouseState {
+ interaction: Interaction,
+ center: Point,
+ last_position: Option<Point>,
+ scale: f32,
+}
+
+impl MouseState {
+ fn map_coords(&self, x: f32, y: f32) -> Point {
+ Point::new(
+ (self.center.x + x) * self.scale,
+ (self.center.y - y) * self.scale,
+ )
+ }
+}
+
+impl Default for MouseState {
+ fn default() -> Self {
+ Self {
+ interaction: Interaction::default(),
+ center: Point::default(),
+ last_position: None,
+ scale: 50.0
+ }
+ }
+}
+
+impl canvas::Program<Message, Renderer> for Graph {
+ type State = MouseState;
fn draw(
&self,
- _state: &Self::State,
+ state: &Self::State,
renderer: &Renderer,
_theme: &Theme,
bounds: Rectangle,
@@ -149,65 +166,65 @@ impl<Message> canvas::Program<Message, Renderer> for Graph {
});
frame.with_save(|frame| {
- let start_y = ((self.center_y - frame.height() / 2.0) / self.scale) as i64
- * self.scale as i64;
+ let start_y = ((state.center.y - frame.height() / 2.0) / state.scale) as i64
+ * state.scale as i64;
let start_x =
- ((self.center_x - frame.width() / 2.0) / self.scale) as i64 * self.scale as i64;
- let end_y = ((self.center_y + frame.height() / 2.0) / self.scale) as i64
- * self.scale as i64;
+ ((state.center.x - frame.width() / 2.0) / state.scale) as i64 * state.scale as i64;
+ let end_y = ((state.center.y + frame.height() / 2.0) / state.scale) as i64
+ * state.scale as i64;
let end_x =
- ((self.center_x + frame.width() / 2.0) / self.scale) as i64 * self.scale as i64;
+ ((state.center.x + frame.width() / 2.0) / state.scale) as i64 * state.scale as i64;
- for y in (start_y..end_y + self.scale as i64).step_by(1) {
+ for y in (start_y..end_y + state.scale as i64).step_by(1) {
let line = Path::line(
- self.map_coords(start_x as f32, y as f32),
- self.map_coords(end_x as f32, y as f32),
+ state.map_coords(start_x as f32, y as f32),
+ state.map_coords(end_x as f32, y as f32),
);
frame.stroke(&line, unitline_whole.clone());
}
- for x in (start_x..end_x + self.scale as i64).step_by(1) {
+ for x in (start_x..end_x + state.scale as i64).step_by(1) {
let line = Path::line(
- self.map_coords(x as f32, start_y as f32),
- self.map_coords(x as f32, end_y as f32),
+ state.map_coords(x as f32, start_y as f32),
+ state.map_coords(x as f32, end_y as f32),
);
frame.stroke(&line, unitline_whole.clone());
}
- let start_y_100 = ((self.center_y - frame.height() / 2.0) / self.scale * 10.0)
+ let start_y_100 = ((state.center.y - frame.height() / 2.0) / state.scale * 10.0)
as i64
* 10
- * self.scale as i64;
- let start_x_100 = ((self.center_x - frame.width() / 2.0) / self.scale * 10.0)
+ * state.scale as i64;
+ let start_x_100 = ((state.center.x - frame.width() / 2.0) / state.scale * 10.0)
as i64
* 10
- * self.scale as i64;
+ * state.scale as i64;
for y in (start_y_100..end_y).step_by(10) {
let line = Path::line(
- self.map_coords(start_x as f32, y as f32),
- self.map_coords(end_x as f32, y as f32),
+ state.map_coords(start_x as f32, y as f32),
+ state.map_coords(end_x as f32, y as f32),
);
frame.stroke(&line, unitline.clone());
}
for x in (start_x_100..end_x).step_by(10) {
let line = Path::line(
- self.map_coords(x as f32, start_y as f32),
- self.map_coords(x as f32, end_y as f32),
+ state.map_coords(x as f32, start_y as f32),
+ state.map_coords(x as f32, end_y as f32),
);
frame.stroke(&line, unitline.clone());
}
let line = Path::line(
- self.map_coords(0.0, start_y as f32),
- self.map_coords(0.0, end_y as f32),
+ state.map_coords(0.0, start_y as f32),
+ state.map_coords(0.0, end_y as f32),
);
frame.stroke(&line, zeroline.clone());
let line = Path::line(
- self.map_coords(start_x as f32, 0.0),
- self.map_coords(end_x as f32, 0.0),
+ state.map_coords(start_x as f32, 0.0),
+ state.map_coords(end_x as f32, 0.0),
);
frame.stroke(&line, zeroline.clone());
@@ -233,7 +250,7 @@ impl<Message> canvas::Program<Message, Renderer> for Graph {
.unwrap()
.real as f32;
if y1.is_finite() && !y1.is_nan() && y2.is_finite() && !y2.is_nan() {
- let line = Path::line(self.map_coords(x1, y1), self.map_coords(x2, y2));
+ let line = Path::line(state.map_coords(x1, y1), state.map_coords(x2, y2));
frame.stroke(&line, graphline.clone())
}
}
@@ -243,4 +260,50 @@ impl<Message> canvas::Program<Message, Renderer> for Graph {
vec![graph]
}
+
+ fn update(
+ &self,
+ state: &mut Self::State,
+ event: canvas::Event,
+ _bounds: Rectangle,
+ cursor: iced::advanced::mouse::Cursor,
+ ) -> (canvas::event::Status, Option<Message>) {
+ if let canvas::Event::Mouse(mouse::Event::ButtonPressed(_)) = event {
+ state.interaction = Interaction::Grabbing;
+ state.last_position = cursor.position();
+ return (event::Status::Captured, Some(Message::UpdateScreen));
+ }
+
+ if let canvas::Event::Mouse(mouse::Event::CursorMoved { position }) = event {
+ if state.interaction == Interaction::Grabbing {
+ if let Some(lp) = state.last_position {
+ state.center.x += (position.x - lp.x) / state.scale;
+ state.center.y += (position.y - lp.y) / state.scale;
+ }
+ state.last_position = Some(position);
+ return (event::Status::Captured, Some(Message::UpdateScreen));
+ }
+ }
+
+ if let canvas::Event::Mouse(mouse::Event::ButtonReleased(_)) = event {
+ state.interaction = Interaction::Pointer;
+ }
+ (event::Status::Ignored, None)
+ }
+
+ fn mouse_interaction(
+ &self,
+ state: &Self::State,
+ _bounds: Rectangle,
+ _cursor: mouse::Cursor,
+ ) -> mouse::Interaction {
+ match state.interaction {
+ Interaction::Grabbing => {
+ mouse::Interaction::Grabbing
+ },
+ _ => {
+ mouse::Interaction::Grab
+ }
+ }
+ }
}