~vpzom/savg

b46616209d42a30e58d91edd7d89c8e9b6c5672b — Colin Reeder 5 years ago af37b98
Rescaling
3 files changed, 126 insertions(+), 20 deletions(-)

M src/document.rs
M src/main.rs
M src/types.rs
M src/document.rs => src/document.rs +5 -0
@@ 67,6 67,11 @@ impl Element {
            Element::Rect(rect) => Some(rect),
        }
    }
    pub fn as_scalable(&self) -> Option<&ScalableElement> {
        match self {
            Element::Rect(rect) => Some(rect),
        }
    }
}

pub trait ScalableElement {

M src/main.rs => src/main.rs +98 -19
@@ 21,6 21,8 @@ use std::sync::Arc;
use std::sync::RwLock;
use std::sync::atomic::AtomicBool;

const HANDLE_SIZE: f64 = 8.0;

fn main() {
    gtk::init().expect("Failed to init GTK");



@@ 121,26 123,69 @@ fn main() {
                let last_mouse_pos = instance.last_mouse_pos.read().unwrap();

                for elem in &document.content {
                    let selected = if let Some(selection) = selection {
                        selection.id() == elem.id()
                    } else {
                        false
                    };
                    draw::draw_elem(elem.as_ref(), ctx, DrawContext {
                        mouse_pos: &last_mouse_pos,
                    }, if let Some(selection) = selection {
                        if selection.id() == elem.id() {
                            &drag_state
                        }
                        else {
                            &None
                        }
                        selected,
                    }, if selected {
                        &drag_state
                    } else {
                        &None
                    });
                }

                if let Some(selection) = selection {
                    let bbox = selection.as_ref().get_aabb();
                    ctx.set_source_rgb(0.0, 0.0, 0.0);
                    ctx.set_dash(&mut [5.0], 0.0);
                    ctx.rectangle(bbox.position.x, bbox.position.y, bbox.size.width, bbox.size.height);
                    ctx.stroke();
                if drag_state.is_none() {
                    if let Some(selection) = selection {
                        let bbox = selection.as_ref().get_aabb();
                        ctx.set_source_rgb(0.0, 0.0, 0.0);
                        ctx.set_dash(&mut [5.0], 0.0);
                        ctx.rectangle(bbox.position.x, bbox.position.y, bbox.size.width, bbox.size.height);
                        ctx.stroke();

                        ctx.set_dash(&mut [], 0.0);

                        let tool = instance.tool.read().unwrap();
                        let tool: &ToolMode = &tool;
                        if tool == &ToolMode::Select {
                            if selection.as_ref().as_scalable().is_some() {
                                println!("scalable");
                                let scale_handle_pos = &bbox.position + &bbox.size - Size2 {
                                    width: HANDLE_SIZE / 2.0,
                                    height: HANDLE_SIZE / 2.0,
                                };
                                let handle_box = AABB {
                                    position: scale_handle_pos,
                                    size: Size2 {
                                        width: HANDLE_SIZE,
                                        height: HANDLE_SIZE,
                                    }
                                };

                                let hovered = handle_box.contains(&instance.last_mouse_pos.read().unwrap());

                                if hovered {
                                    ctx.set_source_rgb(0.0, 0.0, 0.0);
                                }
                                else {
                                    ctx.set_source_rgb(1.0, 1.0, 1.0);
                                }
                                ctx.rectangle(handle_box.position.x, handle_box.position.y, handle_box.size.width, handle_box.size.height);
                                ctx.fill();
                                if hovered {
                                    ctx.set_source_rgb(1.0, 1.0, 1.0);
                                }
                                else {
                                    ctx.set_source_rgb(0.0, 0.0, 0.0);
                                }
                                ctx.rectangle(handle_box.position.x, handle_box.position.y, handle_box.size.width, handle_box.size.height);
                                ctx.stroke();
                            }
                        }
                    }
                }
            }



@@ 195,10 240,45 @@ fn main() {
                ToolMode::Select => {
                    let document = instance.document.read().unwrap();

                    let new_selection = document.content.iter().find(|elem| elem.as_ref().get_aabb().contains(Point2 {
                    let mouse_pos = Point2 {
                        x: pos_x,
                        y: pos_y,
                    }));
                    };

                    {
                        let current_selection = instance.selection.read().unwrap();
                        let current_selection = document.content.iter().find(|elem| Some(elem.id()) == *current_selection);
                        if let Some(selection) = current_selection {
                            let bbox = selection.as_ref().get_aabb();

                            let scale_box_pos = &bbox.position + &bbox.size - Size2 {
                                width: HANDLE_SIZE / 2.0,
                                height: HANDLE_SIZE / 2.0,
                            };
                            let scale_box = AABB {
                                position: scale_box_pos,
                                size: Size2 {
                                    width: HANDLE_SIZE,
                                    height: HANDLE_SIZE,
                                }
                            };

                            if scale_box.contains(&mouse_pos) {
                                *instance.drag_state.write().unwrap() = Some(DragState::ScaleBoth {
                                    start_pos: mouse_pos,
                                });
                                return Inhibit(true);
                            }

                            if bbox.contains(&mouse_pos) {
                                // already selected

                                return Inhibit(true);
                            }
                        }
                    }

                    let new_selection = document.content.iter().find(|elem| elem.as_ref().get_aabb().contains(&mouse_pos));

                    *instance.selection.write().unwrap() = match new_selection {
                        Some(e) => Some(e.id()),


@@ 269,9 349,7 @@ fn main() {
            last_mouse_pos.x = x;
            last_mouse_pos.y = y;

            if instance.drag_state.read().unwrap().is_some() {
                instance.queue_repaint();
            }
            instance.queue_repaint();

            Inhibit(true)
        });


@@ 381,7 459,7 @@ impl EditInstance {
    }
}

#[derive(Clone, Copy)]
#[derive(Clone, Copy, PartialEq, Eq)]
enum ToolMode {
    Select,
    Rectangle,


@@ 395,4 473,5 @@ pub enum DragState {

pub struct DrawContext<'a> {
    pub mouse_pos: &'a Point2,
    pub selected: bool,
}

M src/types.rs => src/types.rs +23 -1
@@ 4,6 4,17 @@ pub struct Point2 {
    pub y: f64,
}

impl<'a> std::ops::Add<&'a Size2> for &'a Point2 {
    type Output = Point2;

    fn add(self, other: &Size2) -> Point2 {
        Point2 {
            x: self.x + other.width,
            y: self.y + other.height,
        }
    }
}

impl<'a> std::ops::Sub for &'a Point2 {
    type Output = Size2;



@@ 15,6 26,17 @@ impl<'a> std::ops::Sub for &'a Point2 {
    }
}

impl std::ops::Sub<Size2> for Point2 {
    type Output = Point2;

    fn sub(mut self, other: Size2) -> Point2 {
        self.x -= other.width;
        self.y -= other.height;

        self
    }
}

#[derive(Clone)]
pub struct Size2 {
    pub width: f64,


@@ 47,7 69,7 @@ pub struct AABB {
}

impl AABB {
    pub fn contains(&self, point: Point2) -> bool {
    pub fn contains(&self, point: &Point2) -> bool {
        return point.x > self.position.x && point.y > self.position.y && point.x < self.position.x + self.size.width && point.y < self.position.y + self.size.height;
    }
}