Move to a new state when menu option selected
This commit is contained in:
parent
93ae544684
commit
1536d0192f
@ -1,6 +1,6 @@
|
|||||||
defmodule Chessh.SSH.Client do
|
defmodule Chessh.SSH.Client do
|
||||||
alias IO.ANSI
|
alias IO.ANSI
|
||||||
alias Chessh.SSH.Client.Menu
|
alias Chessh.SSH.Client.{Menu, Board}
|
||||||
require Logger
|
require Logger
|
||||||
|
|
||||||
use GenServer
|
use GenServer
|
||||||
@ -98,6 +98,7 @@ defmodule Chessh.SSH.Client do
|
|||||||
"\e[B" -> :down
|
"\e[B" -> :down
|
||||||
"\e[D" -> :left
|
"\e[D" -> :left
|
||||||
"\e[C" -> :right
|
"\e[C" -> :right
|
||||||
|
"\r" -> :return
|
||||||
x -> x
|
x -> x
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@ -107,8 +108,8 @@ defmodule Chessh.SSH.Client do
|
|||||||
Enum.member?(@min_terminal_height..@max_terminal_height, height)
|
Enum.member?(@min_terminal_height..@max_terminal_height, height)
|
||||||
end
|
end
|
||||||
|
|
||||||
defp render(
|
def render(
|
||||||
%State{width: width, height: height, state_stack: [{module, _screen_state}]} = state
|
%State{width: width, height: height, state_stack: [{module, _screen_state} | _]} = state
|
||||||
) do
|
) do
|
||||||
if terminal_size_allowed(width, height) do
|
if terminal_size_allowed(width, height) do
|
||||||
[
|
[
|
||||||
|
@ -1,14 +1,30 @@
|
|||||||
defmodule Chessh.SSH.Client.Board do
|
defmodule Chessh.SSH.Client.Board do
|
||||||
use Chessh.SSH.Client.Screen
|
alias Chessh.SSH.Client
|
||||||
alias Chessh.SSH.Client.State
|
alias IO.ANSI
|
||||||
|
|
||||||
def render(%State{} = _state) do
|
require Logger
|
||||||
@ascii_chars["pieces"]["white"]["knight"]
|
|
||||||
|
defmodule State do
|
||||||
|
defstruct cursor_x: 0,
|
||||||
|
cursor_y: 0
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_input(action, state) do
|
use Chessh.SSH.Client.Screen
|
||||||
|
|
||||||
|
def render(%Client.State{} = _state) do
|
||||||
|
knight = @ascii_chars["pieces"]["white"]["knight"]
|
||||||
|
|
||||||
|
[ANSI.home()] ++
|
||||||
|
Enum.map(
|
||||||
|
Enum.zip(0..(length(knight) - 1), knight),
|
||||||
|
fn {i, line} ->
|
||||||
|
[ANSI.cursor(i, 0), line]
|
||||||
|
end
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def handle_input(action, %Client.State{} = state) do
|
||||||
case action do
|
case action do
|
||||||
"q" -> state
|
|
||||||
_ -> state
|
_ -> state
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -7,13 +7,13 @@ defmodule Chessh.SSH.Client.Menu do
|
|||||||
|
|
||||||
defmodule State do
|
defmodule State do
|
||||||
defstruct y: 0,
|
defstruct y: 0,
|
||||||
x: 0
|
x: 0,
|
||||||
|
selected: 0
|
||||||
end
|
end
|
||||||
|
|
||||||
use Chessh.SSH.Client.Screen
|
use Chessh.SSH.Client.Screen
|
||||||
|
|
||||||
@logo " Simponic's
|
@logo " Simponic's
|
||||||
|
|
||||||
dP MP\"\"\"\"\"\"`MM MP\"\"\"\"\"\"`MM M\"\"MMMMM\"\"MM
|
dP MP\"\"\"\"\"\"`MM MP\"\"\"\"\"\"`MM M\"\"MMMMM\"\"MM
|
||||||
88 M mmmmm..M M mmmmm..M M MMMMM MM
|
88 M mmmmm..M M mmmmm..M M MMMMM MM
|
||||||
.d8888b. 88d888b. .d8888b. M. `YM M. `YM M `M
|
.d8888b. 88d888b. .d8888b. M. `YM M. `YM M `M
|
||||||
@ -22,54 +22,80 @@ defmodule Chessh.SSH.Client.Menu do
|
|||||||
`88888P' dP dP `88888P' Mb. .dM Mb. .dM M MMMMM MM
|
`88888P' dP dP `88888P' Mb. .dM Mb. .dM M MMMMM MM
|
||||||
MMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMMM"
|
MMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMMM"
|
||||||
|
|
||||||
|
@options [
|
||||||
|
{"Option 1", {Chessh.SSH.Client.Board, %{}}},
|
||||||
|
{"Option 2", {Chessh.SSH.Client.Board, %{}}},
|
||||||
|
{"Option 3", {Chessh.SSH.Client.Board, %{}}}
|
||||||
|
]
|
||||||
|
|
||||||
def render(%Client.State{
|
def render(%Client.State{
|
||||||
width: width,
|
width: width,
|
||||||
height: height,
|
height: height,
|
||||||
state_stack: [{_this_module, %State{y: y, x: x}} | _tail]
|
state_stack: [{_this_module, %State{selected: selected, y: dy, x: dx}} | _tail]
|
||||||
}) do
|
}) do
|
||||||
|
text = String.split(@logo, "\n")
|
||||||
{logo_width, logo_height} = Utils.text_dim(@logo)
|
{logo_width, logo_height} = Utils.text_dim(@logo)
|
||||||
|
{y, x} = center_rect({logo_width, logo_height + length(text)}, {width, height})
|
||||||
split = String.split(@logo, "\n")
|
|
||||||
|
|
||||||
Enum.flat_map(
|
Enum.flat_map(
|
||||||
Enum.zip(0..(length(split) - 1), split),
|
Enum.zip(0..(length(text) - 1), text),
|
||||||
fn {i, line} ->
|
fn {i, line} ->
|
||||||
[
|
[
|
||||||
ANSI.cursor(div(height - logo_height, 2) + i + y, div(width - logo_width, 2) + x),
|
ANSI.cursor(y + i + dy, x + dx),
|
||||||
"#{line}\n"
|
line
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
)
|
) ++
|
||||||
|
Enum.flat_map(
|
||||||
|
Enum.zip(0..(length(@options) - 1), @options),
|
||||||
|
fn {i, {option, _}} ->
|
||||||
|
[
|
||||||
|
ANSI.cursor(y + length(text) + i + dy, x + dx),
|
||||||
|
if(i == selected, do: ANSI.format([:light_cyan, "* #{option}"]), else: option)
|
||||||
|
]
|
||||||
|
end
|
||||||
|
) ++ [ANSI.home()]
|
||||||
|
end
|
||||||
|
|
||||||
|
def wrap_around(index, delta, length) do
|
||||||
|
calc = index + delta
|
||||||
|
if(calc < 0, do: length, else: 0) + rem(calc, length)
|
||||||
end
|
end
|
||||||
|
|
||||||
def handle_input(
|
def handle_input(
|
||||||
data,
|
data,
|
||||||
%Client.State{state_stack: [{this_module, %State{y: y, x: x} = screen_state} | tail]} =
|
%Client.State{
|
||||||
state
|
state_stack:
|
||||||
|
[{this_module, %State{selected: selected} = screen_state} | tail] = state_stack
|
||||||
|
} = state
|
||||||
) do
|
) do
|
||||||
case data do
|
case(data) do
|
||||||
:left ->
|
|
||||||
%Client.State{
|
|
||||||
state
|
|
||||||
| state_stack: [{this_module, %State{screen_state | x: x - 1}} | tail]
|
|
||||||
}
|
|
||||||
|
|
||||||
:right ->
|
|
||||||
%Client.State{
|
|
||||||
state
|
|
||||||
| state_stack: [{this_module, %State{screen_state | x: x + 1}} | tail]
|
|
||||||
}
|
|
||||||
|
|
||||||
:up ->
|
:up ->
|
||||||
%Client.State{
|
%Client.State{
|
||||||
state
|
state
|
||||||
| state_stack: [{this_module, %State{screen_state | y: y - 1}} | tail]
|
| state_stack: [
|
||||||
|
{this_module,
|
||||||
|
%State{screen_state | selected: wrap_around(selected, -1, length(@options))}}
|
||||||
|
| tail
|
||||||
|
]
|
||||||
}
|
}
|
||||||
|
|
||||||
:down ->
|
:down ->
|
||||||
%Client.State{
|
%Client.State{
|
||||||
state
|
state
|
||||||
| state_stack: [{this_module, %State{screen_state | y: y + 1}} | tail]
|
| state_stack: [
|
||||||
|
{this_module,
|
||||||
|
%State{screen_state | selected: wrap_around(selected, 1, length(@options))}}
|
||||||
|
| tail
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
|
:return ->
|
||||||
|
{_, new_state} = Enum.at(@options, selected)
|
||||||
|
|
||||||
|
%Client.State{
|
||||||
|
state
|
||||||
|
| state_stack: [new_state] ++ state_stack
|
||||||
}
|
}
|
||||||
|
|
||||||
_ ->
|
_ ->
|
||||||
|
@ -10,6 +10,13 @@ defmodule Chessh.SSH.Client.Screen do
|
|||||||
@ascii_chars Application.compile_env!(:chessh, :ascii_chars_json_file)
|
@ascii_chars Application.compile_env!(:chessh, :ascii_chars_json_file)
|
||||||
|> File.read!()
|
|> File.read!()
|
||||||
|> Jason.decode!()
|
|> Jason.decode!()
|
||||||
|
|
||||||
|
def center_rect({rect_width, rect_height}, {parent_width, parent_height}) do
|
||||||
|
{
|
||||||
|
div(parent_height - rect_height, 2),
|
||||||
|
div(parent_width - rect_width, 2)
|
||||||
|
}
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
Reference in New Issue
Block a user