Skip to content

feat: add a tool that can fix line joints #24

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added assets/joint-fixer-icon.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
254 changes: 254 additions & 0 deletions src/tools/joint_fixer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,254 @@
use druid::EventCtx;

use crate::{
consts::{
CHAR_CORNER_BL_L, CHAR_CORNER_BR_L, CHAR_CORNER_TL_L, CHAR_CORNER_TR_L, CHAR_CROSS,
CHAR_HOR_DOWN_L, CHAR_HOR_L, CHAR_HOR_UP_L, CHAR_SPACE, CHAR_VER_L, CHAR_VER_LEFT_L,
CHAR_VER_RIGHT_L,
},
data::{
grid_list::GridList,
history::{Version, HISTORY_MANAGER},
shape_list::ShapeList,
},
};

use super::ToolControl;

pub struct JointFixerTool {
version: Version,
last_cursor_position: Option<usize>,
}

macro_rules! idx_to_opt_char {
($var:ident,$input:ident,$g:ident) => {
let $var = if let Some(i) = $input {
match $g.get(i).read_content() {
CHAR_SPACE => None,
c => Some(c),
}
} else {
None
};
};
}

macro_rules! UP_CHARS {
() => {
CHAR_VER_L
| CHAR_CORNER_TR_L
| CHAR_CORNER_TL_L
| CHAR_HOR_DOWN_L
| CHAR_VER_RIGHT_L
| CHAR_VER_LEFT_L
| CHAR_CROSS
};
}

macro_rules! DOWN_CHARS {
() => {
CHAR_VER_L
| CHAR_CORNER_BL_L
| CHAR_CORNER_BR_L
| CHAR_HOR_UP_L
| CHAR_VER_RIGHT_L
| CHAR_VER_LEFT_L
| CHAR_CROSS
};
}

macro_rules! LEFT_CHARS {
() => {
CHAR_HOR_L
| CHAR_CORNER_TL_L
| CHAR_CORNER_BL_L
| CHAR_HOR_UP_L
| CHAR_HOR_DOWN_L
| CHAR_VER_RIGHT_L
| CHAR_CROSS
};
}

macro_rules! RIGHT_CHARS {
() => {
CHAR_HOR_L
| CHAR_CORNER_TR_L
| CHAR_CORNER_BR_L
| CHAR_HOR_UP_L
| CHAR_HOR_DOWN_L
| CHAR_VER_LEFT_L
| CHAR_CROSS
};
}

impl JointFixerTool {
pub fn new() -> Self {
Self {
version: Version::new(),
last_cursor_position: None,
}
}

fn calculate_content(
&self,
grid_list: &mut GridList,
u: Option<usize>,
d: Option<usize>,
l: Option<usize>,
r: Option<usize>,
) -> Option<char> {
idx_to_opt_char!(uc, u, grid_list);
idx_to_opt_char!(dc, d, grid_list);
idx_to_opt_char!(lc, l, grid_list);
idx_to_opt_char!(rc, r, grid_list);

match (uc, dc, lc, rc) {
(None, None, None, None) => None,
// Vertical
// (Some(UP_CHARS!()), None, None, None) => Some(CHAR_VER_L),
// (None, Some(DOWN_CHARS!()), None, None) => Some(CHAR_VER_L),
(Some(UP_CHARS!()), Some(DOWN_CHARS!()), l, r)
if !matches!((l, r), (Some(LEFT_CHARS!()), _) | (_, Some(RIGHT_CHARS!()))) =>
{
Some(CHAR_VER_L)
}
// Horizontal
// (None, None, Some(LEFT_CHARS!()), None) => Some(CHAR_HOR_L),
// (None, None, None, Some(RIGHT_CHARS!())) => Some(CHAR_HOR_L),
(u, d, Some(LEFT_CHARS!()), Some(RIGHT_CHARS!()))
if !matches!((u, d), (Some(UP_CHARS!()), _) | (_, Some(DOWN_CHARS!()))) =>
{
Some(CHAR_HOR_L)
}
// Two joint
(Some(UP_CHARS!()), d, Some(LEFT_CHARS!()), r)
if !matches!((d, r), (Some(DOWN_CHARS!()), _) | (_, Some(RIGHT_CHARS!()))) =>
{
Some(CHAR_CORNER_BR_L)
}
(Some(UP_CHARS!()), d, l, Some(RIGHT_CHARS!()))
if !matches!((d, l), (Some(DOWN_CHARS!()), _) | (_, Some(LEFT_CHARS!()))) =>
{
Some(CHAR_CORNER_BL_L)
}
(u, Some(DOWN_CHARS!()), Some(LEFT_CHARS!()), r)
if !matches!((u, r), (Some(UP_CHARS!()), _) | (_, Some(RIGHT_CHARS!()))) =>
{
Some(CHAR_CORNER_TR_L)
}
(u, Some(DOWN_CHARS!()), l, Some(RIGHT_CHARS!()))
if !matches!((u, l), (Some(UP_CHARS!()), _) | (_, Some(LEFT_CHARS!()))) =>
{
Some(CHAR_CORNER_TL_L)
}
// Three joint
(Some(UP_CHARS!()), Some(DOWN_CHARS!()), Some(LEFT_CHARS!()), r)
if !matches!(r, Some(RIGHT_CHARS!())) =>
{
Some(CHAR_VER_LEFT_L)
}
(Some(UP_CHARS!()), Some(DOWN_CHARS!()), l, Some(RIGHT_CHARS!()))
if !matches!(l, Some(LEFT_CHARS!())) =>
{
Some(CHAR_VER_RIGHT_L)
}
(Some(UP_CHARS!()), d, Some(LEFT_CHARS!()), Some(RIGHT_CHARS!()))
if !matches!(d, Some(DOWN_CHARS!())) =>
{
Some(CHAR_HOR_UP_L)
}
(u, Some(DOWN_CHARS!()), Some(LEFT_CHARS!()), Some(RIGHT_CHARS!()))
if !matches!(u, Some(UP_CHARS!())) =>
{
Some(CHAR_HOR_DOWN_L)
}
// Four joint
(Some(UP_CHARS!()), Some(DOWN_CHARS!()), Some(LEFT_CHARS!()), Some(RIGHT_CHARS!())) => {
Some(CHAR_CROSS)
}
_ => None,
}
}
}

impl ToolControl for JointFixerTool {
fn start(
&mut self,
_ctx: &mut EventCtx,
_event: &druid::MouseEvent,
_shape_list: &mut ShapeList,
_grid_list: &mut GridList,
) {
self.last_cursor_position = None;
}

fn draw(
&mut self,
_ctx: &mut EventCtx,
event: &druid::MouseEvent,
_shape_list: &mut ShapeList,
grid_list: &mut GridList,
) {
let (cell_width, cell_height) = grid_list.cell_size;
let row = (event.pos.y / cell_height) as usize;
let col = (event.pos.x / cell_width) as usize;
let (rows, cols) = grid_list.grid_size;
let i = row * cols + col;

if let Some(last_cursor_pos) = self.last_cursor_position {
if i == last_cursor_pos {
return;
}
}

let up_i = match row {
0 => None,
_ => Some((row - 1) * cols + col),
};

let down_i = match row {
r if r >= rows - 1 => None,
_ => Some((row + 1) * cols + col),
};

let left_i = match col {
0 => None,
_ => Some(i - 1),
};

let right_i = match col {
c if c >= cols - 1 => None,
_ => Some(i + 1),
};

if let Some(content) = self.calculate_content(grid_list, up_i, down_i, left_i, right_i) {
self.last_cursor_position = Some(i);
let cell = grid_list.get(i);
let from_content = cell.read_content();
self.version.push(i, from_content, content);
cell.set_content(content);
}
}

fn end(
&mut self,
_ctx: &mut EventCtx,
_event: &druid::MouseEvent,
_shape_list: &mut ShapeList,
_grid_list: &mut GridList,
) {
unsafe {
HISTORY_MANAGER.save_version(self.version.clone());
self.version.clear();
}
}

fn input(
&mut self,
_ctx: &mut EventCtx,
_event: &druid::KeyEvent,
_shape_list: &mut ShapeList,
_grid_list: &mut GridList,
) {
}
}
6 changes: 5 additions & 1 deletion src/tools/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ use crate::{
tools::{line::LineTool, text::TextTool},
};

use self::{eraser::EraserTool, rect::RectTool, select::SelectTool};
use self::{eraser::EraserTool, joint_fixer::JointFixerTool, rect::RectTool, select::SelectTool};

pub mod eraser;
pub mod joint_fixer;
pub mod line;
pub mod rect;
pub mod select;
Expand All @@ -25,6 +26,7 @@ pub enum DrawingTools {
Text = 2,
Eraser = 3,
Rect = 4,
JointFixer = 5,
}

impl Display for DrawingTools {
Expand All @@ -35,6 +37,7 @@ impl Display for DrawingTools {
DrawingTools::Text => "TEXT",
DrawingTools::Eraser => "ERASER",
DrawingTools::Rect => "RECTANGLE",
DrawingTools::JointFixer => "JOINTFIXER",
};
write!(f, "{}", op)
}
Expand Down Expand Up @@ -99,6 +102,7 @@ impl ToolManager {
Box::new(TextTool::new()),
Box::new(EraserTool::new()),
Box::new(RectTool::new()),
Box::new(JointFixerTool::new()),
],
current: DrawingTools::Select,
}
Expand Down
4 changes: 4 additions & 0 deletions src/widgets/grid.rs
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ impl Widget<ApplicationState> for CanvasGrid {
Code::Digit4 | Code::KeyE => {
win_data.mode = DrawingTools::Eraser;
}
Code::Digit5 => {
win_data.mode = DrawingTools::JointFixer;
}
Code::Delete | Code::Backspace => {
self.grid_list.erase_highlighted();
self.grid_list.clear_all_highlight();
Expand Down Expand Up @@ -286,6 +289,7 @@ impl Widget<ApplicationState> for CanvasGrid {
DrawingTools::Rect => ctx.set_cursor(&Cursor::Crosshair),
DrawingTools::Text => ctx.set_cursor(&Cursor::IBeam),
DrawingTools::Eraser => ctx.set_cursor(&Cursor::Crosshair),
DrawingTools::JointFixer => ctx.set_cursor(&Cursor::Crosshair),
}
}
}
Expand Down
20 changes: 20 additions & 0 deletions src/widgets/toolbar.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ impl ToolBarWidget {
let rect_icon = ImageBuf::from_data(include_bytes!("../../assets/rect-icon.png")).unwrap();
let eraser_icon =
ImageBuf::from_data(include_bytes!("../../assets/eraser-icon.png")).unwrap();
let joint_fixer_icon =
ImageBuf::from_data(include_bytes!("../../assets/joint-fixer-icon.png")).unwrap();
let save_icon = ImageBuf::from_data(include_bytes!("../../assets/save-icon.png")).unwrap();
let open_icon = ImageBuf::from_data(include_bytes!("../../assets/open-icon.png")).unwrap();

Expand Down Expand Up @@ -117,6 +119,24 @@ impl ToolBarWidget {
ctx.set_handled();
}),
)
.with_spacer(4.0)
.with_child(
ImageButton::new(
joint_fixer_icon,
Size::new(26.0, 26.0),
DrawingTools::JointFixer.to_string(),
)
.on_click(|ctx, data: &mut ApplicationState, _env| {
let win_data = data
.windows
.get_mut(&ctx.window_id())
.expect("Invalid WindowID");
let tool = DrawingTools::JointFixer;
win_data.mode = tool;
ctx.submit_notification(BUTTON_HIGHLIGHT_COMMAND.with(tool.to_string()));
ctx.set_handled();
}),
)
.cross_axis_alignment(CrossAxisAlignment::End)
.main_axis_alignment(MainAxisAlignment::Start),
);
Expand Down