Overview

16 partial files under Calendar/BeepCalendar.Interactions.*.cs handle all pointer/touch/mouse events. The system uses view-mode-specific hit testing, drag mode resolution driven by the hit-test result, event creation proposals during drag, and a commitment pipeline that integrates with the undo/redo history stack. The ResolveDragMode() method returns a CalendarInteractionMode enum that determines subsequent behavior. Four interaction events (InteractionStarted, InteractionUpdated, InteractionCompleted, InteractionCancelled) provide hooks for external observers.

Pointer Events (4 Files)

FileEventsResponsibility
Interactions.Pointer.csMouseDown, MouseUp, MouseMovePointer dispatch, modifier key tracking (Ctrl for copy, Shift for range)
Interactions.Pointer.DownUp.csMouseDown + MouseUpClick detection, drag threshold (minimum pixels before drag mode activates)
Interactions.Pointer.MoveCancel.csMouseMove + CancelDrag tracking with delta calculation, Escape key to cancel current interaction
Interactions.Pointer.Up.csMouseUpDrag completion trigger, passes location + delta to commitment pipeline

Drag Modes

ResolveDragMode(CalendarInteractionHitTestResult) determines the CalendarInteractionMode:

ModeHit TargetEnabled ViewsBehavior
MoveEventEvent block bodyDay, Week, WorkWeek, TimelineDrag event to a new time slot. Original position cleared, new position shown as ghost
ResizeStartEvent block top edgeDay, Week, WorkWeekDrag upward to move start time earlier. Bottom anchor fixed.
ResizeEndEvent block bottom edgeDay, Week, WorkWeekDrag downward to move end time later. Top anchor fixed.
SelectEventEvent block in non-drag viewsMonth, Agenda, ListClick to select the event. Fires EventSelected. Double-click opens editor.
RangeSelectDate cellDay, Week, WorkWeekClick-drag over time slots to select a time range
CreateEventEmpty surface / date cellMonth, Agenda, ListClick-drag to define and create a new event at that time
SelectDateDate cell (any view)All viewsClick to navigate to that date

Hit Testing (8 Files, 7 Views)

private CalendarInteractionHitTestResult ResolveInteractionTarget(Point loc)
{
    switch (_state.ViewMode)
    {
        case CalendarViewMode.Month:    return ResolveMonthInteraction(loc);
        case CalendarViewMode.Week:
        case CalendarViewMode.WorkWeek: return ResolveWeekInteraction(loc);
        case CalendarViewMode.Day:      return ResolveDayInteraction(loc);
        case CalendarViewMode.Agenda:   return ResolveAgendaInteraction(loc);
        case CalendarViewMode.Timeline: return ResolveTimelineInteraction(loc);
        case CalendarViewMode.List:     return ResolveListInteraction(loc);
        default: return new CalendarInteractionHitTestResult
            { TargetKind = EmptySurface, RequestedMode = SelectDate };
    }
}

8 specialized hit-testing files: HitTesting.cs (dispatcher above), HitTesting.Views.cs, HitTesting.MonthView.cs, HitTesting.WeekView.cs, HitTesting.DayView.cs, HitTesting.TimelineView.cs, HitTesting.TimedView.cs, HitTesting.Helpers.cs. Each resolves whether the click hit an event block (EventBlock), a date cell (DateCell), or empty space (EmptySurface). Returns a CalendarInteractionHitTestResult with TargetKind, RequestedMode, Location, and Date properties.

Timing & Snapping

InteractionSnapIntervalMinutes (default 15) causes event start/end times to snap to the nearest N-minute interval during drag operations. The snapping logic spans three files: Interactions.Timing.cs (base timing), Timing.Snap.cs (snap calculation), Timing.Snap.Location.cs (pixel-to-time conversion with snap). For ResizeStart/ResizeEnd modes, only the affected edge snaps; the opposite anchor remains fixed.

Creation Proposals

During drag-to-create operations, a visual "ghost" rectangle is rendered showing the proposed event at the snapped time interval. The ghost updates in real-time as the user drags, giving live visual feedback of the event that will be created on mouse-up. Two files: Interactions.Proposals.cs (proposal lifecycle management — create, update, clear) and Proposals.CreationRange.cs (calculates proposal start/end times from drag rectangle extents).

Commitment Pipeline (4 Files)

On mouse-up, CommitInteractionMutation(Point location, Point delta) dispatches:

  • Commit.cs — Dispatch hub: routes to NewEvent, Copy, or ExistingEvent handler based on drag mode and modifier state
  • Commit.NewEvent.cs — Creates event from proposal, routes through EventMutating → CRUD → EventMutated → History push
  • Commit.Copy.cs — Clones the source event and creates the copy at the drop location (activated by Ctrl+drag of existing event)
  • Commit.ExistingEvent.cs — Mutates an existing event's properties (start, end, date) in place. Routes through EventMutating/EventMutated with modification kind

Copy-Modifier (Ctrl+Drag)

IsCopyModifierDown() checks whether Ctrl or Ctrl+Shift is pressed. When true, dragging an existing event creates a copy at the drop location instead of moving the original. This enables quick event duplication workflows common in modern calendar applications.

CalendarViewStateHelper

Internal static helper in Calendar/Helpers/CalendarViewStateHelper.cs. Builds and returns a populated DayCellState data object:

internal static DayCellState BuildDayCellState(
    DateTime cellDate,
    DateTime currentMonthAnchor,
    DateTime selectedDate,
    DateTime? hoveredDate,
    DateTime focusedDate,
    bool isKeyboardFocusVisible,
    int eventCount,
    int maxEventsPerCell)
// Returns DayCellState with computed flags:
//   IsCurrentMonth, IsToday, IsSelected, IsHovered,
//   IsWeekend (Saturday/Sunday), IsFocused,
//   EventCount, HasMoreEvents (eventCount > maxEventsPerCell)

File Inventory

GroupFilesPurpose
CoreInteractions.csDispatcher, drag mode resolution, copy-modifier detection, interaction start/update/complete/cancel events
Hit TestingHitTesting.cs + 7 sub-filesView-mode-specific hit test resolution returning CalendarInteractionHitTestResult
PointerPointer.cs + 3 sub-filesMouse down/up/move/cancel event handling with modifier key tracking
TimingTiming.cs + 2 sub-filesTime snapping to configurable interval (default 15 min) during drag
ProposalsProposals.cs + 1 sub-fileVisual ghost rectangle creation during drag-to-create
CommitCommit.cs + 3 sub-filesInteraction completion: new event creation, copy-on-drag, existing event mutation

Code Examples

// Interaction events
cal.InteractionStarted += (s, e) =>
    Console.WriteLine($"Started: {e.Mode} at {e.Location}");

cal.InteractionUpdated += (s, e) =>
    Console.WriteLine($"Updated: dragged to {e.Location}");

cal.InteractionCompleted += (s, e) =>
    Console.WriteLine($"Completed: {e.Mode}");

// Snap interval
cal.InteractionSnapIntervalMinutes = 30;  // Snap to :00 and :30

// Create event on drop
cal.CreateEventRequested += (s, e) =>
{
    e.CreatedEvent = new CalendarEvent
    {
        Title = "New Event",
        Start = e.RequestedStart,
        End = e.RequestedStart.AddHours(1)
    };
};