package gui import rl "vendor:raylib" editor_update :: proc(app: ^GUI_App_State) { ed := &app.editor if !ed.active { return } pen := &app.pen mouse := rl.GetMousePosition() cr := ed.canvas_rect mx := vec2_x(mouse) my := vec2_y(mouse) in_canvas := mx >= cr.x && mx <= cr.x + cr.width && my >= cr.y && my <= cr.y + cr.height space_down := rl.IsKeyDown(.SPACE) pan_pressed := (rl.IsMouseButtonPressed(.RIGHT) || (space_down && rl.IsMouseButtonPressed(.LEFT))) && in_canvas pan_down := rl.IsMouseButtonDown(.RIGHT) || (space_down && rl.IsMouseButtonDown(.LEFT)) if pan_pressed { ed.is_panning = true ed.pan_start = mouse ed.pan_offset_start = ed.pan_offset } if ed.is_panning { if pan_down { _, fit_scale := editor_image_dest_rect(ed) if fit_scale <= 0 { fit_scale = 1.0 } dx := vec2_x(mouse) - vec2_x(ed.pan_start) dy := vec2_y(mouse) - vec2_y(ed.pan_start) ed.pan_offset = rl.Vector2{vec2_x(ed.pan_offset_start) + dx / fit_scale, vec2_y(ed.pan_offset_start) + dy / fit_scale} ed.needs_redraw = true } else { ed.is_panning = false } } wheel := rl.GetMouseWheelMove() shift_down := rl.IsKeyDown(.LEFT_SHIFT) || rl.IsKeyDown(.RIGHT_SHIFT) if wheel != 0 && in_canvas { if shift_down { ed.brush_size += wheel * 2.0 if ed.brush_size < 1.0 { ed.brush_size = 1.0 } if ed.brush_size > 80.0 { ed.brush_size = 80.0 } } else { editor_zoom_at_mouse(ed, mouse, wheel * 0.1) } } image_rect, _ := editor_image_dest_rect(ed) in_image := mx >= image_rect.x && mx <= image_rect.x + image_rect.width && my >= image_rect.y && my <= image_rect.y + image_rect.height if ed.current_tool == .Move && !ed.is_panning && !space_down { canvas_pos := editor_clamp_canvas_pos(ed, editor_screen_to_canvas(ed, mouse)) if rl.IsMouseButtonPressed(.LEFT) && in_image { handle := editor_selection_handle_at_screen_pos(ed, mouse) if ed.selection_active && handle != .None { ed.is_resizing_selection = true ed.active_selection_handle = handle ed.selection_drag_origin = ed.selection_rect ed.selection_resize_anchor = editor_selection_opposite_corner(ed.selection_rect, handle) } else if ed.selection_active && editor_rect_contains_point(ed.selection_rect, canvas_pos) { ed.is_moving_selection = true ed.selection_drag_start = canvas_pos ed.selection_drag_origin = ed.selection_rect } else { ed.selection_active = false ed.is_moving_selection = false ed.is_resizing_selection = false ed.active_selection_handle = .None ed.is_drawing = true ed.draw_start = canvas_pos clear(&ed.current_stroke.points) append(&ed.current_stroke.points, canvas_pos) ed.current_stroke.tool = .Move } } if ed.is_resizing_selection && rl.IsMouseButtonDown(.LEFT) { end_pos := editor_constrain_shape_point(.Crop, ed.selection_resize_anchor, canvas_pos, shift_down) ed.selection_rect = editor_clamp_rect_to_image(ed, editor_make_rect_from_points(ed.selection_resize_anchor, end_pos)) } if ed.is_moving_selection && rl.IsMouseButtonDown(.LEFT) { dx := vec2_x(canvas_pos) - vec2_x(ed.selection_drag_start) dy := vec2_y(canvas_pos) - vec2_y(ed.selection_drag_start) ed.selection_rect = editor_move_rect_within_image(ed, rl.Rectangle{ed.selection_drag_origin.x + dx, ed.selection_drag_origin.y + dy, ed.selection_drag_origin.width, ed.selection_drag_origin.height}) } if ed.is_drawing && rl.IsMouseButtonDown(.LEFT) { end_pos := editor_constrain_shape_point(.Crop, ed.draw_start, canvas_pos, shift_down) if len(ed.current_stroke.points) > 1 { ed.current_stroke.points[len(ed.current_stroke.points)-1] = end_pos } else { append(&ed.current_stroke.points, end_pos) } } if ed.is_resizing_selection && rl.IsMouseButtonReleased(.LEFT) { ed.is_resizing_selection = false ed.active_selection_handle = .None return } if ed.is_moving_selection && rl.IsMouseButtonReleased(.LEFT) { ed.is_moving_selection = false if ed.selection_rect.x != ed.selection_drag_origin.x || ed.selection_rect.y != ed.selection_drag_origin.y { push_status(&app.status_msg, &app.action_log, editor_apply_move_selection(ed, ed.selection_drag_origin, ed.selection_rect)) } } if ed.is_drawing && rl.IsMouseButtonReleased(.LEFT) { ed.is_drawing = false if len(ed.current_stroke.points) >= 2 { ed.selection_rect = editor_clamp_rect_to_image(ed, editor_make_rect_from_points(ed.current_stroke.points[0], ed.current_stroke.points[len(ed.current_stroke.points)-1])) ed.selection_active = ed.selection_rect.width >= 2 && ed.selection_rect.height >= 2 } clear(&ed.current_stroke.points) return } } if ed.current_tool == .Move { return } if !ed.is_panning && !space_down && (in_image || ed.is_drawing) { if rl.IsMouseButtonPressed(.LEFT) { canvas_pos := editor_clamp_canvas_pos(ed, editor_screen_to_canvas(ed, mouse)) if ed.current_tool == .Color_Pick { picked, ok := editor_sample_composited_color(ed, canvas_pos) if ok { ed.brush_color = picked editor_push_recent_color(ed, picked) } } else if ed.current_tool == .Fill { push_status(&app.status_msg, &app.action_log, editor_apply_fill(ed, canvas_pos)) return } else { ed.is_drawing = true ed.draw_start = canvas_pos clear(&ed.current_stroke.points) append(&ed.current_stroke.points, canvas_pos) ed.current_stroke.color = ed.brush_color effective_size := ed.brush_size * pen_tablet_pressure_for_stroke(pen) ed.current_stroke.thickness = effective_size ed.current_stroke.tool = ed.current_tool ed.current_stroke.filled = !ed.shape_outline_only if ed.current_tool == .Eraser || pen.eraser { ed.current_stroke.color = rl.Color{0, 0, 0, 0} ed.current_stroke.thickness = effective_size * 2 } } } if ed.is_drawing && rl.IsMouseButtonDown(.LEFT) { canvas_pos := editor_clamp_canvas_pos(ed, editor_screen_to_canvas(ed, mouse)) canvas_pos = editor_constrain_shape_point(ed.current_tool, ed.draw_start, canvas_pos, shift_down) if ed.current_tool == .Pen || ed.current_tool == .Eraser { append(&ed.current_stroke.points, canvas_pos) } else { if len(ed.current_stroke.points) > 1 { ed.current_stroke.points[len(ed.current_stroke.points)-1] = canvas_pos } else { append(&ed.current_stroke.points, canvas_pos) } } } } if ed.is_drawing && rl.IsMouseButtonReleased(.LEFT) { ed.is_drawing = false if ed.current_tool == .Crop { if len(ed.current_stroke.points) >= 2 { p0 := ed.current_stroke.points[0] p1 := ed.current_stroke.points[len(ed.current_stroke.points)-1] crop_rect := rl.Rectangle{min(vec2_x(p0), vec2_x(p1)), min(vec2_y(p0), vec2_y(p1)), abs(vec2_x(p1) - vec2_x(p0)), abs(vec2_y(p1) - vec2_y(p0))} push_status(&app.status_msg, &app.action_log, editor_apply_crop(ed, crop_rect)) } ed.current_stroke = Brush_Stroke{} ed.current_stroke.points = make([dynamic]rl.Vector2) ed.current_stroke.color = ed.brush_color ed.current_stroke.thickness = ed.brush_size ed.current_stroke.tool = ed.current_tool ed.current_stroke.filled = !ed.shape_outline_only return } editor_push_undo(ed) rl.BeginTextureMode(ed.drawing_rt) if ed.current_tool == .Eraser { rl.BeginBlendMode(.ALPHA) } editor_render_stroke(ed.current_stroke) if ed.current_tool == .Eraser { rl.EndBlendMode() } rl.EndTextureMode() append(&ed.committed_strokes, ed.current_stroke) ed.current_stroke = Brush_Stroke{} ed.current_stroke.points = make([dynamic]rl.Vector2) ed.current_stroke.color = ed.brush_color ed.current_stroke.thickness = ed.brush_size ed.current_stroke.tool = ed.current_tool ed.current_stroke.filled = !ed.shape_outline_only ed.needs_redraw = true } }