diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/chessh/ssh/client.ex | 43 | ||||
-rw-r--r-- | lib/chessh/ssh/renderers/menu.ex | 35 | ||||
-rw-r--r-- | lib/chessh/ssh/screens/board.ex | 15 | ||||
-rw-r--r-- | lib/chessh/ssh/screens/menu.ex | 79 | ||||
-rw-r--r-- | lib/chessh/ssh/screens/screen.ex | 15 |
5 files changed, 129 insertions, 58 deletions
diff --git a/lib/chessh/ssh/client.ex b/lib/chessh/ssh/client.ex index 4eceb38..dfa222c 100644 --- a/lib/chessh/ssh/client.ex +++ b/lib/chessh/ssh/client.ex @@ -1,6 +1,6 @@ defmodule Chessh.SSH.Client do alias IO.ANSI - + alias Chessh.SSH.Client.Menu require Logger use GenServer @@ -26,7 +26,7 @@ defmodule Chessh.SSH.Client do height: 0, player_session: nil, buffer: [], - state_stack: [{&Chessh.SSH.Client.Menu.render/2, []}] + state_stack: [{Menu, %Menu.State{}}] end @impl true @@ -61,13 +61,21 @@ defmodule Chessh.SSH.Client do end end - def handle({:data, data}, %State{tui_pid: tui_pid} = state) do - new_state = - keymap(data) - |> keypress(state) + def handle( + {:data, data}, + %State{tui_pid: tui_pid, state_stack: [{module, _screen_state} | _tail]} = state + ) do + action = keymap(data) - send(tui_pid, {:send_data, render(new_state)}) - {:noreply, new_state} + if action == :quit do + {:stop, :normal, state} + else + new_state = module.handle_input(action, state) + + send(tui_pid, {:send_data, render(new_state)}) + + {:noreply, new_state} + end end def handle({:resize, {width, height}}, %State{tui_pid: tui_pid} = state) do @@ -80,18 +88,6 @@ defmodule Chessh.SSH.Client do {:noreply, new_state} end - def keypress(:up, state), do: state - def keypress(:right, state), do: state - def keypress(:down, state), do: state - def keypress(:left, state), do: state - - def keypress(:quit, state) do - send(self(), :quit) - state - end - - def keypress(_, state), do: state - def keymap(key) do case key do # Exit keys - C-c and C-d @@ -106,17 +102,18 @@ defmodule Chessh.SSH.Client do end end - @spec terminal_size_allowed(any, any) :: boolean def terminal_size_allowed(width, height) do Enum.member?(@min_terminal_width..@max_terminal_width, width) && Enum.member?(@min_terminal_height..@max_terminal_height, height) end - defp render(%{width: width, height: height, state_stack: [{render_fn, args} | _tail]} = state) do + defp render( + %State{width: width, height: height, state_stack: [{module, _screen_state}]} = state + ) do if terminal_size_allowed(width, height) do [ @clear_codes ++ - render_fn.(state, args) + module.render(state) ] else @terminal_bad_dim_msg diff --git a/lib/chessh/ssh/renderers/menu.ex b/lib/chessh/ssh/renderers/menu.ex deleted file mode 100644 index c3c3646..0000000 --- a/lib/chessh/ssh/renderers/menu.ex +++ /dev/null @@ -1,35 +0,0 @@ -defmodule Chessh.SSH.Client.Menu do - alias Chessh.SSH.Client.State - alias Chessh.Utils - - alias IO.ANSI - - @logo " Simponic's - - dP MP\"\"\"\"\"\"`MM MP\"\"\"\"\"\"`MM M\"\"MMMMM\"\"MM - 88 M mmmmm..M M mmmmm..M M MMMMM MM -.d8888b. 88d888b. .d8888b. M. `YM M. `YM M `M -88' `\"\" 88' `88 88ooood8 MMMMMMM. M MMMMMMM. M M MMMMM MM -88. ... 88 88 88. ... M. .MMM' M M. .MMM' M M MMMMM MM -`88888P' dP dP `88888P' Mb. .dM Mb. .dM M MMMMM MM - MMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMMM" - - def render( - %State{width: width, height: height, state_stack: [_current_state | _tail]} = _state, - _args - ) do - {logo_width, logo_height} = Utils.text_dim(@logo) - - split = String.split(@logo, "\n") - - Enum.flat_map( - Enum.zip(0..(length(split) - 1), split), - fn {i, x} -> - [ - ANSI.cursor(div(height - logo_height, 2) + i, div(width - logo_width, 2)), - "#{x}\n" - ] - end - ) - end -end diff --git a/lib/chessh/ssh/screens/board.ex b/lib/chessh/ssh/screens/board.ex new file mode 100644 index 0000000..7b22052 --- /dev/null +++ b/lib/chessh/ssh/screens/board.ex @@ -0,0 +1,15 @@ +defmodule Chessh.SSH.Client.Board do + use Chessh.SSH.Client.Screen + alias Chessh.SSH.Client.State + + def render(%State{} = _state) do + @ascii_chars["pieces"]["white"]["knight"] + end + + def handle_input(action, state) do + case action do + "q" -> state + _ -> state + end + end +end diff --git a/lib/chessh/ssh/screens/menu.ex b/lib/chessh/ssh/screens/menu.ex new file mode 100644 index 0000000..22aba85 --- /dev/null +++ b/lib/chessh/ssh/screens/menu.ex @@ -0,0 +1,79 @@ +defmodule Chessh.SSH.Client.Menu do + alias Chessh.SSH.Client + alias Chessh.Utils + alias IO.ANSI + + require Logger + + defmodule State do + defstruct y: 0, + x: 0 + end + + use Chessh.SSH.Client.Screen + + @logo " Simponic's + + dP MP\"\"\"\"\"\"`MM MP\"\"\"\"\"\"`MM M\"\"MMMMM\"\"MM + 88 M mmmmm..M M mmmmm..M M MMMMM MM +.d8888b. 88d888b. .d8888b. M. `YM M. `YM M `M +88' `\"\" 88' `88 88ooood8 MMMMMMM. M MMMMMMM. M M MMMMM MM +88. ... 88 88 88. ... M. .MMM' M M. .MMM' M M MMMMM MM +`88888P' dP dP `88888P' Mb. .dM Mb. .dM M MMMMM MM + MMMMMMMMMMM MMMMMMMMMMM MMMMMMMMMMMM" + + def render(%Client.State{ + width: width, + height: height, + state_stack: [{_this_module, %State{y: y, x: x}} | _tail] + }) do + {logo_width, logo_height} = Utils.text_dim(@logo) + + split = String.split(@logo, "\n") + + Enum.flat_map( + Enum.zip(0..(length(split) - 1), split), + fn {i, line} -> + [ + ANSI.cursor(div(height - logo_height, 2) + i + y, div(width - logo_width, 2) + x), + "#{line}\n" + ] + end + ) + end + + def handle_input( + data, + %Client.State{state_stack: [{this_module, %State{y: y, x: x} = screen_state} | tail]} = + state + ) 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 -> + %Client.State{ + state + | state_stack: [{this_module, %State{screen_state | y: y - 1}} | tail] + } + + :down -> + %Client.State{ + state + | state_stack: [{this_module, %State{screen_state | y: y + 1}} | tail] + } + + _ -> + state + end + end +end diff --git a/lib/chessh/ssh/screens/screen.ex b/lib/chessh/ssh/screens/screen.ex new file mode 100644 index 0000000..be6e00e --- /dev/null +++ b/lib/chessh/ssh/screens/screen.ex @@ -0,0 +1,15 @@ +defmodule Chessh.SSH.Client.Screen do + @callback render(state :: Chessh.SSH.Client.State.t() | any()) :: any() + @callback handle_input(action :: any(), state :: Chessh.SSH.Client.State.t()) :: + Chessh.SSH.Client.State.t() + + defmacro __using__(_) do + quote do + @behaviour Chessh.SSH.Client.Screen + + @ascii_chars Application.compile_env!(:chessh, :ascii_chars_json_file) + |> File.read!() + |> Jason.decode!() + end + end +end |