# `Easel.WX`
[🔗](https://github.com/jasonstiebs/easel/blob/v0.3.4/lib/easel/wx.ex#L1)

A wx (wxWidgets) backend for Easel that renders draw operations
to a native window using wxGraphicsContext.

Uses `:wx_object` for proper OTP lifecycle management and
double buffering via `wxBitmap` + `wxMemoryDC` for flicker-free rendering.

Requires Erlang compiled with wx support. When wx is not available,
`render/2` and `animate/5` will raise at runtime.

## Usage

    canvas =
      Easel.new(400, 300)
      |> Easel.set_fill_style("blue")
      |> Easel.fill_rect(50, 50, 100, 100)
      |> Easel.set_stroke_style("red")
      |> Easel.set_line_width(3)
      |> Easel.stroke_rect(50, 50, 100, 100)
      |> Easel.render()

    # Opens a wx window and draws the operations
    Easel.WX.render(canvas)

## Animation

    Easel.WX.animate(600, 400, initial_state, fn state ->
      {canvas, new_state} = MyApp.tick(state)
      {canvas, new_state}
    end, title: "Animation")

## Supported operations

Drawing: `fillRect`, `strokeRect`, `clearRect`, `fillText`, `strokeText`

Paths: `beginPath`, `closePath`, `moveTo`, `lineTo`, `arc`, `ellipse`,
`rect`, `bezierCurveTo`, `quadraticCurveTo`, `arcTo`, `fill`, `stroke`

Styles: `fillStyle`, `strokeStyle`, `lineWidth`, `lineCap`, `lineJoin`,
`font`, `globalAlpha`

Transforms: `save`, `restore`, `translate`, `rotate`, `scale`,
`setTransform`, `resetTransform`, `transform`

## Unsupported operations

Operations that have no wx equivalent will raise `Easel.WX.UnsupportedOpError`.
These include: shadows, filters, compositing modes, image data, patterns,
gradients, clipping, and text measurement.

# `animate`

Runs an animation loop in a wx window.

Takes a width, height, initial state, and a function that receives
the current state and returns `{%Easel{}, new_state}`. The function
is called every `interval` milliseconds (default 16, ~60fps).

The loop runs until the window is closed, then returns `:ok`.

## Options

  * `:title` - window title (default `"Easel"`)
  * `:interval` - milliseconds between frames (default `16`)
  * `:on_click` - `fn x, y, state -> new_state end` called on mouse click
  * `:on_mouse_down` - `fn x, y, state -> new_state end`
  * `:on_mouse_up` - `fn x, y, state -> new_state end`
  * `:on_mouse_move` - `fn x, y, state -> new_state end`
  * `:on_key_down` - `fn key_event, state -> new_state end`

Event handlers for `animate` receive the current state and must return
the new state. The updated state will be used by the next tick.

## Example

    Easel.WX.animate(600, 400, initial_state, fn state ->
      {canvas, new_state} = MyApp.tick(state)
      {canvas, new_state}
    end, title: "Animation", on_click: fn x, y, state ->
      %{state | target: {x, y}}
    end)

# `available?`

Returns true if wx is available in the current Erlang runtime.

# `parse_color`

Parses a CSS color string into an `{r, g, b, a}` tuple.

Supports named colors, hex (`#rgb`, `#rrggbb`, `#rrggbbaa`),
`rgb()`, and `rgba()`.

# `parse_font`

Parses a CSS font shorthand string into `{size, face, style, weight}`.

Returns a tuple of `{integer, charlist, wx_style_atom, wx_weight_atom}`.

# `rasterize`

Rasterizes a canvas off-screen and returns raw RGB pixel data.

Useful for experimental non-window renderers (for example terminal/ASCII).

Returns `%{width: w, height: h, rgb: binary}` where `rgb` is row-major
24-bit color (`<<r, g, b, ...>>`).

## Options

  * `:width` - logical canvas width (default `canvas.width || 400`)
  * `:height` - logical canvas height (default `canvas.height || 300`)
  * `:dpr` - device pixel ratio multiplier (default `1.0`)

# `render`

Renders an Easel struct to a wx window.

Opens a native window, draws all operations, and blocks until
the window is closed by the user.

## Options

  * `:title` - window title (default `"Easel"`)
  * `:on_click` - `fn x, y -> ... end` called on mouse click
  * `:on_mouse_down` - `fn x, y -> ... end` called on mouse button press
  * `:on_mouse_up` - `fn x, y -> ... end` called on mouse button release
  * `:on_mouse_move` - `fn x, y -> ... end` called on mouse movement
  * `:on_key_down` - `fn key_event -> ... end` called on key press

---

*Consult [api-reference.md](api-reference.md) for complete listing*
