# maolan-widgets

[![crates.io](https://img.shields.io/crates/v/maolan-widgets.svg)](https://crates.io/crates/maolan-widgets)

`maolan-widgets` is the reusable UI widget crate for the Maolan DAW project.
It contains the custom `iced` components that the main application uses for
timeline clips, piano-roll editing, mixer controls, meters, and related MIDI UI.

This repository directory is not the whole DAW. It is the focused widget package
that the main app imports as `maolan_widgets`.

## What is in this crate

The crate exposes these public modules from [`src/lib.rs`](./src/lib.rs):

- `clip`: audio and MIDI clip widgets, plus clip data types and interaction
  payloads.
- `controller`: helpers for MIDI controller lanes, CC naming, RPN/NRPN mapping,
  and SysEx previews.
- `horizontal_scrollbar`: a custom horizontal scrollbar widget.
- `horizontal_slider`: a compact horizontal slider widget.
- `meters`: canvas-based audio level meters for mixer-style UIs.
- `midi`: shared MIDI constants and data types used across the widgets.
- `note_area`: piano-roll background/grid composition and synchronized
  scroller helpers.
- `numeric_input`: a spinner-style number input built from `iced` controls.
- `piano`: piano keyboard rendering, note coloring, and an interactive octave
  keyboard canvas.
- `piano_roll`: note block rendering for MIDI clips and editors.
- `slider`: a vertical slider widget used for faders and similar controls.
- `ticks`: tick-mark and label rendering for slider scales.
- `vertical_scrollbar`: a custom vertical scrollbar widget.

## Main building blocks

### MIDI primitives

[`src/midi.rs`](./src/midi.rs) defines the shared data structures that the rest
of the crate builds on:

- `PianoNote`: a note event with `start_sample`, `length_samples`, `pitch`,
  `velocity`, and `channel`.
- `PianoControllerPoint`: a controller event with sample position, CC number,
  value, and channel.
- `PianoSysExPoint`: a SysEx event with sample position and raw bytes.
- `PianoControllerLane`, `PianoRpnKind`, `PianoNrpnKind`: enums used by the
  controller UI.

It also exports layout constants such as keyboard width, note count, scroll IDs,
zoom limits, and MIDI-related limits used by the piano-roll widgets.

### Clip widgets

[`src/clip.rs`](./src/clip.rs) provides:

- `AudioClipData` and `MIDIClipData`: lightweight clip models used to render
  track clips.
- `AudioClip<Message>` and `MIDIClip<Message>`: builder-style widgets that can
  be configured with size, labels, selection state, hover state, colors, and
  interaction messages before converting into an `iced::Element`.
- `AudioClipInteraction<Message>` and `MIDIClipInteraction<Message>`: message
  bundles for selection, opening, dragging, resizing, and fade-handle actions.

Audio clips can render waveform previews from peak data and an optional session
root path. MIDI clips can render note previews from `PianoNote` data.

### Piano and piano-roll UI

These modules support Maolan's MIDI editing surfaces:

- [`src/piano.rs`](./src/piano.rs): keyboard drawing helpers, note color logic,
  octave math, and `OctaveKeyboard`, an interactive canvas widget that emits
  note press/release messages.
- [`src/piano_roll.rs`](./src/piano_roll.rs): `PianoRoll`, which turns
  `PianoNote` data into positioned note blocks over an arbitrary interaction
  layer.
- [`src/note_area.rs`](./src/note_area.rs): `NoteArea`, which composes the
  piano-roll background, beat/bar guides, playhead overlay, and arbitrary note
  content; plus `piano_grid_scrollers`, which wires the keyboard area, note
  area, and custom scrollbars together.

### Mixer and control widgets

- [`src/slider.rs`](./src/slider.rs): vertical slider/fader widget with optional
  quantized stepping.
- [`src/horizontal_slider.rs`](./src/horizontal_slider.rs): horizontal variant
  for compact controls such as pan or zoom.
- [`src/ticks.rs`](./src/ticks.rs): scale labels and tick marks for vertical
  faders.
- [`src/meters.rs`](./src/meters.rs): compact multichannel meter bars for mixer
  strips.
- [`src/numeric_input.rs`](./src/numeric_input.rs): generic spinner input for
  bounded numeric values.
- [`src/horizontal_scrollbar.rs`](./src/horizontal_scrollbar.rs) and
  [`src/vertical_scrollbar.rs`](./src/vertical_scrollbar.rs): custom scrollbar
  widgets sized for the editor surfaces in the DAW.

### MIDI controller helpers

[`src/controller.rs`](./src/controller.rs) contains pure helper logic for:

- choosing colors for controller lanes,
- mapping controller events into visible rows,
- decoding RPN/NRPN parameter combinations,
- collecting populated controller rows and CCs,
- generating short SysEx previews,
- resolving standard MIDI CC names.

This is the logic used by the main application when it builds controller-lane
views on top of the widget crate.

## How the crate is used

This crate is consumed by the parent Maolan application in the repository root.
Examples in the main app include:

- `src/workspace/mixer.rs`: uses `slider`, `horizontal_slider`, `meters`, and
  `ticks` for mixer strips.
- `src/workspace/editor.rs`: uses `clip::AudioClip` and `clip::MIDIClip` for
  arrangement clips.
- `src/widget/midi_edit.rs`: uses `PianoRoll`, `OctaveKeyboard`,
  `VerticalScrollbar`, and other MIDI editing widgets.
- `src/add_track.rs`: uses `numeric_input::number_input`.

That usage pattern is the intended one: this crate supplies composable widgets
and helper types, while higher-level editor behavior stays in the main app.

## Dependencies

The crate currently depends on:

- `iced` for widget, canvas, and event handling infrastructure.
- `iced_fonts` for icon glyphs used by the numeric spinner.
- `wavers` for reading waveform data used by audio clip previews.

## Development

From this directory, standard Cargo commands are:

```bash
cargo build
cargo test
cargo fmt
cargo clippy
```

When working as part of the full Maolan repository, also run the engine tests
from the repository root:

```bash
cargo test -p maolan-engine
```

## Testing

The crate includes unit tests in widget modules such as:

- [`src/meters.rs`](./src/meters.rs)
- [`src/ticks.rs`](./src/ticks.rs)
- [`src/horizontal_scrollbar.rs`](./src/horizontal_scrollbar.rs)
- [`src/vertical_scrollbar.rs`](./src/vertical_scrollbar.rs)
- [`src/piano.rs`](./src/piano.rs)

Tests focus on the pure math and interaction logic behind rendering and input
handling, which keeps the widget behavior verifiable without a full running UI.
