Packages

Core behaviours, utilities, events, config, accessibility, and plugin infrastructure for Raxol. Zero external runtime dependencies. Provides BaseManager, event system, plugin lifecycle, keyboard/focus management, and accessibility primitives.

Current section

Files

Jump to
raxol_core lib raxol core box.ex
Raw

lib/raxol/core/box.ex

defmodule Raxol.Core.Box do
@moduledoc """
Box drawing and line rendering utilities for terminal UIs.
This module provides functions for drawing boxes, lines, and filled areas
using Unicode box drawing characters.
## Supported Box Styles
- `:single` - Single line box drawing (─│┌┐└┘)
- `:double` - Double line box drawing (═║╔╗╚╝)
- `:rounded` - Rounded corners (─│╭╮╰╯)
- `:heavy` - Heavy/bold lines (━┃┏┓┗┛)
- `:dashed` - Dashed lines (╌╎┌┐└┘)
## Examples
# Draw a simple box
buffer = Raxol.Core.Buffer.create_blank_buffer(80, 24)
buffer = Raxol.Core.Box.draw_box(buffer, 5, 3, 20, 10, :single)
# Draw a double-line box with style
buffer = Raxol.Core.Box.draw_box(buffer, 10, 5, 30, 8, :double)
# Draw horizontal and vertical lines
buffer = Raxol.Core.Box.draw_horizontal_line(buffer, 0, 0, 80)
buffer = Raxol.Core.Box.draw_vertical_line(buffer, 0, 0, 24)
"""
alias Raxol.Core.Buffer
@type box_style :: :single | :double | :rounded | :heavy | :dashed
@doc """
Draws a box at the specified coordinates with the given style.
## Parameters
- `buffer` - The buffer to draw on
- `x` - X coordinate (left edge)
- `y` - Y coordinate (top edge)
- `width` - Width of the box
- `height` - Height of the box
- `style` - Box style (default: `:single`)
## Examples
buffer = Raxol.Core.Box.draw_box(buffer, 5, 3, 20, 10, :double)
"""
@spec draw_box(
Buffer.t(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
box_style()
) :: Buffer.t()
def draw_box(buffer, x, y, width, height, style \\ :single) do
chars = box_chars(style)
buffer
|> draw_corners(x, y, width, height, chars)
|> draw_edges(x, y, width, height, chars)
end
@spec box_chars(box_style()) :: %{
top_left: String.t(),
top_right: String.t(),
bottom_left: String.t(),
bottom_right: String.t(),
horizontal: String.t(),
vertical: String.t()
}
defp box_chars(:single) do
%{
top_left: "┌",
top_right: "┐",
bottom_left: "└",
bottom_right: "┘",
horizontal: "─",
vertical: "│"
}
end
defp box_chars(:double) do
%{
top_left: "╔",
top_right: "╗",
bottom_left: "╚",
bottom_right: "╝",
horizontal: "═",
vertical: "║"
}
end
defp box_chars(:rounded) do
%{
top_left: "╭",
top_right: "╮",
bottom_left: "╰",
bottom_right: "╯",
horizontal: "─",
vertical: "│"
}
end
defp box_chars(:heavy) do
%{
top_left: "┏",
top_right: "┓",
bottom_left: "┗",
bottom_right: "┛",
horizontal: "━",
vertical: "┃"
}
end
defp box_chars(:dashed) do
%{
top_left: "┌",
top_right: "┐",
bottom_left: "└",
bottom_right: "┘",
horizontal: "╌",
vertical: "╎"
}
end
@spec draw_corners(
Buffer.t(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
map()
) :: Buffer.t()
defp draw_corners(buffer, x, y, width, height, chars) do
right_x = x + width - 1
bottom_y = y + height - 1
buffer
|> Buffer.set_cell(x, y, chars.top_left, %{})
|> Buffer.set_cell(right_x, y, chars.top_right, %{})
|> Buffer.set_cell(x, bottom_y, chars.bottom_left, %{})
|> Buffer.set_cell(right_x, bottom_y, chars.bottom_right, %{})
end
@spec draw_edges(
Buffer.t(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
map()
) :: Buffer.t()
defp draw_edges(buffer, x, y, width, height, chars) do
right_x = x + width - 1
bottom_y = y + height - 1
buffer
|> draw_horizontal_edge(x + 1, y, width - 2, chars.horizontal)
|> draw_horizontal_edge(x + 1, bottom_y, width - 2, chars.horizontal)
|> draw_vertical_edge(x, y + 1, height - 2, chars.vertical)
|> draw_vertical_edge(right_x, y + 1, height - 2, chars.vertical)
end
@spec draw_horizontal_edge(
Buffer.t(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
String.t()
) :: Buffer.t()
defp draw_horizontal_edge(buffer, x, y, length, char) do
Enum.reduce(0..(length - 1), buffer, fn offset, acc ->
Buffer.set_cell(acc, x + offset, y, char, %{})
end)
end
@spec draw_vertical_edge(
Buffer.t(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
String.t()
) :: Buffer.t()
defp draw_vertical_edge(buffer, x, y, length, char) do
Enum.reduce(0..(length - 1), buffer, fn offset, acc ->
Buffer.set_cell(acc, x, y + offset, char, %{})
end)
end
@doc """
Draws a horizontal line at the specified position.
## Parameters
- `buffer` - The buffer to draw on
- `x` - X coordinate (starting position)
- `y` - Y coordinate (row)
- `length` - Length of the line
- `char` - Character to use (default: "-")
"""
@spec draw_horizontal_line(
Buffer.t(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
String.t()
) :: Buffer.t()
def draw_horizontal_line(buffer, x, y, length, char \\ "-") do
Enum.reduce(0..(length - 1), buffer, fn offset, acc ->
Buffer.set_cell(acc, x + offset, y, char, %{})
end)
end
@doc """
Draws a vertical line at the specified position.
## Parameters
- `buffer` - The buffer to draw on
- `x` - X coordinate (column)
- `y` - Y coordinate (starting position)
- `length` - Length of the line
- `char` - Character to use (default: "|")
"""
@spec draw_vertical_line(
Buffer.t(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
String.t()
) :: Buffer.t()
def draw_vertical_line(buffer, x, y, length, char \\ "|") do
Enum.reduce(0..(length - 1), buffer, fn offset, acc ->
Buffer.set_cell(acc, x, y + offset, char, %{})
end)
end
@doc """
Fills an area with the specified character and style.
## Parameters
- `buffer` - The buffer to draw on
- `x` - X coordinate (left edge)
- `y` - Y coordinate (top edge)
- `width` - Width of the area
- `height` - Height of the area
- `char` - Character to fill with
- `style` - Style to apply (default: %{})
"""
@spec fill_area(
Buffer.t(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
non_neg_integer(),
String.t(),
map()
) :: Buffer.t()
def fill_area(buffer, x, y, width, height, char, style \\ %{}) do
Enum.reduce(0..(height - 1), buffer, fn row_offset, row_buffer ->
Enum.reduce(0..(width - 1), row_buffer, fn col_offset, col_buffer ->
Buffer.set_cell(col_buffer, x + col_offset, y + row_offset, char, style)
end)
end)
end
end