From 41a365a9c13d06a18b080625c88cc557a70567b4 Mon Sep 17 00:00:00 2001 From: fluffy Date: Thu, 7 Dec 2023 16:35:16 +0100 Subject: [PATCH] V 1.2 Added inputs, Modified Readme and added getch functions that is (hopefully) os independend --- README.md | 58 ++++++++++++++++++++++++++++++++++++++---- flyconsole/__init__.py | 3 ++- flyconsole/console.py | 39 ++++++++++++++++++++++++++++ flyconsole/input.py | 58 ++++++++++++++++++++++++++++++++++++++++++ pyproject.toml | 5 +++- 5 files changed, 156 insertions(+), 7 deletions(-) create mode 100644 flyconsole/input.py diff --git a/README.md b/README.md index 09e174f..3e8bb39 100644 --- a/README.md +++ b/README.md @@ -1,15 +1,15 @@ # Fly Console ---- - -Fly Console is build to easy manipulate the terminal xonsole in multiple aspects It is possible to change the color, clear the terminal or manipulate the position and visibility of the cursor. +Fly Console is build to easy manipulate the terminal xonsole in multiple aspects It is possible to change the color, clear the terminal or manipulate the position, visibility of the cursor and use custom input methods. -With that all said, lets get into the documentations `:D` +You can install it for python via pip [here](https://pypi.org/project/flyconsole/) and you can view the source code on github [here](https://github.com/fluffeliger/fly-console). ## Documenation Welcome to the documentation about the fly console package c: +The Documentation is based on the newest Version. + With this package it is possible to change the foreground and background color of the text in the terminal, write with or without line breaks, set the cursor position with different modes, show and hide the cursor or clear the console on specific parts. Lets get right into it! @@ -237,4 +237,52 @@ And you can also clear the whole current line with the following ```py from flyconsole import Console Console.Clear.current_line() -``` \ No newline at end of file +``` + +--- + +### Inputs + +There are also some inputs you can use. In later updates there are coming more! + +#### List Menu (Since V1.2) + +A List Menu uses for its fields a `Menuitem`. You can also customize the key events with a `KeyConfiguration`. + +To setup a List menu you can write the following + +```py +from flyconsole import ListMenu + +menu = Menu(0) # 0 Defines the y coordinate of the menu +menu.add_item('Item A') +menu.add_item('Item B') +menu.add_item('Item C') +menu.enable() # Shows the menu and enables the Key Events + +# After the menu is done you can get its result with +menu.result +# The result will return a MenuItem +``` + +When we look at the `ListMenu` init arguments + +```py +ListMenu(y:int=0, can_cancel:bool=1, can_escape:bool=1, key_configuration:KeyConfiguration=KeyConfiguration()) +``` + +we can see, we can disable the `[CTRl] + [C]` cancel and the `[ESC]` key. The cancel and escape keys can also be modified in a `KeyConfiguration` + +The Keyconfiguration looks like this + +```py +@dataclass +class KeyConfiguration: + up: tuple = (72, 1) + down: tuple = (80, 1) + select: tuple = (13, 0) + escape: tuple = (27, 0) + cancel: tuple = (3, 0) +``` + +Foreach tuple the first argument is the keycode and the second argument defines if the key means something else. For example if you press an arrow key it will return `(72, 1)` and if u press `[H]` it will return `(72, 0)`. \ No newline at end of file diff --git a/flyconsole/__init__.py b/flyconsole/__init__.py index cb72c70..5f2ecdd 100644 --- a/flyconsole/__init__.py +++ b/flyconsole/__init__.py @@ -1 +1,2 @@ -from .console import Console, Color \ No newline at end of file +from .console import Console, Color +from .input import ListMenu, MenuItem, KeyConfiguration \ No newline at end of file diff --git a/flyconsole/console.py b/flyconsole/console.py index 28b01c8..22598de 100644 --- a/flyconsole/console.py +++ b/flyconsole/console.py @@ -1,5 +1,9 @@ import sys import os +if os.name == 'nt': # Windows + import msvcrt +else: # Unix + import tty class Color: # NOTE: Colors range from 0 - 255 @@ -44,6 +48,41 @@ def set_color(foreground:Color=None, background:Color=None) -> None: def reset_color() -> None: _Console.escape(f'0m') + @staticmethod + def get_width() -> int: + return os.get_terminal_size().columns + + @staticmethod + def get_height() -> int: + return os.get_terminal_size().lines + + @staticmethod + def get_dimensions() -> tuple[int, int]: + return Console.get_height(), Console.get_width() + + @staticmethod + def getch() -> int: + if os.name == 'nt': + char = msvcrt.getch() + if char == b'\xe0': + arrow_key = msvcrt.getch() + return ord(arrow_key), 1 + else: + return ord(char), 0 + else: + fd = sys.stdin.fileno() + old_settings = tty.tcgetattr(fd) + try: + tty.setcbreak(fd) + char = sys.stdin.read(1) + if char == '\x1b': + special_key = sys.stdin.read(2) + return ord(special_key[-1]), 1 + else: + return ord(char), 0 + finally: + tty.tcsetattr(fd, tty.TCSADRAIN, old_settings) + class Cursor: @staticmethod def go_to(line:int, column:int) -> None: diff --git a/flyconsole/input.py b/flyconsole/input.py new file mode 100644 index 0000000..949ce4b --- /dev/null +++ b/flyconsole/input.py @@ -0,0 +1,58 @@ +from dataclasses import dataclass +from console import Console, Color + +@dataclass +class MenuItem: + master: any + title: str + _id: int + +@dataclass +class KeyConfiguration: + up: tuple = (72, 1) + down: tuple = (80, 1) + select: tuple = (13, 0) + escape: tuple = (27, 0) + cancel: tuple = (3, 0) + +class ListMenu: + def __init__(self, y:int=0, can_cancel:bool=1, can_escape:bool=1, key_configuration:KeyConfiguration=KeyConfiguration()) -> None: + self._items = [] + self._menu_index = 0 + self._y = y + self._key_configuration = key_configuration + self._running = 0 + self._can_cancel = can_cancel + self._can_escape = can_escape + + def add_item(self, title) -> None: + if self._running: return + self._items.append(MenuItem(self, title, len(self._items))) + + def _render(self) -> None: + for i in range(len(self._items)): + item = self._items[i] + Console.Cursor.go_to(self._y+i, 0) + Console.set_color(Color.BLACK, Color.LIGHT_BLUE if self.get_active() == item else Color.WHITE) + Console.write(item.title + ' '*(Console.get_width() - len(item.title))) + Console.reset_color() + + def get_active(self) -> None: + return self._items[self._menu_index] + + def enable(self) -> None: + if len(self._items) <= 0: return + self._running = 1 + Console.Cursor.Private.hide() + while self._running: + self._render() + k = Console.getch() + if self._can_cancel and k == self._key_configuration.cancel: break + if self._can_escape and k == self._key_configuration.escape: break + if k == self._key_configuration.select: + self.result = self.get_active() + break + if k == self._key_configuration.down and self._menu_index < len(self._items)-1: self._menu_index += 1 + if k == self._key_configuration.up and self._menu_index > 0: self._menu_index -= 1 + Console.Cursor.Private.show() + self._running = 0 \ No newline at end of file diff --git a/pyproject.toml b/pyproject.toml index a8df60d..6d5d05b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta" [project] name = "flyconsole" -version = "1.1.1" +version = "1.2" authors = [ { name="fluffy" }, ] @@ -17,6 +17,9 @@ classifiers = [ "Operating System :: OS Independent", ] +[project.optional-dependencies] +PDF = ["msvcrt", "tty"] + [project.urls] Homepage = "https://github.com/fluffeliger/fly-console" Issues = "https://github.com/fluffeliger/fly-console/issues" \ No newline at end of file