i wanted to do this but they said i need textual and i really dont like how it looks.
i want something like
> start
settings
exit
and being navigatble like
start
> settings
exit
i wanted to do this but they said i need textual and i really dont like how it looks.
i want something like
> start
settings
exit
and being navigatble like
start
> settings
exit
Sounds like what you want is curses.
Try going through a tutorial and see whether it suits your purposes.
i saw something about like clearing the terminal and doing the printing again for it to like change the button. is that in the thing that you sent?
Yep. Youâll end up with some sort of ârepaint, wait for input, act on that inputâ loop.
im going to read it and get back to you
is there any other tutorials for it? this one is kinda outdated i tested the example codes and its not working
i think his gone. is there anyone else with any soulotions?
i think his gone.
This is a web forum for asynchronous discussion, sometimes it takes
hours or even days for people to respond to your posts.
is there anyone else with any soulotions?
All the available solutions Iâm aware of are in the same vein. Keep
in mind that âterminalsâ arenât a standardized technology, so making
software portable even just to a variety of commonly-used terminals
(or more properly âterminal emulatorsâ in this century) requires
quite a lot of code. If you want to be able to do this purely with
modules from CPythonâs standard library then itâs going to be a lot
of work essentially reimplementing the âdownloadable librariesâ you
seem to insist on avoiding.
If thatâs truly your goal, then youâre better off looking at the
source code for libs like Urwid to understand how they drive at
least the specific terminal emulators you want to support. But
thereâs a reason basically everyone who writes âTUIâ applications
relies on one of these popular libraries rather than recreating it
all on their own from scratch.
i know but there were some things like idk c64 or smt. that when you executed the terminal would get cleared. so i was thinking is it possible that like
if a person clicks arrow down. â clear terminal. print those things again but this time put the selected box around the settings tab or smt
You want a program in the terminal that people can navigate with the mouse? That seems ambitious. The standard loop thatâs going to work reliably is âwait for keyboard inputâ â âparse keyboard inputâ â âredraw whole terminalâ. I think you can get that to work relatively easily and reliably.
Not impossible. The curses module (and the underlying ncurses library) does support mouse inputs. The OP will do well to take a tutorial on using curses with Python.
not mouse inputs. wait for keyboard input i want. but idk how to get it to work
For an example of a simple TUI, that relies only on the standardlib:
import sys
import termios
import tty
from dataclasses import dataclass, replace
from typing import Protocol
COLORS: dict[str, str] = {
"black": "30",
"red": "31",
"green": "32",
"yellow": "33",
"blue": "34",
"magenta": "35",
"cyan": "36",
"white": "37",
}
# ---------------------------------------------------------------------------
# Settings
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class Settings:
bold: bool = False
italic: bool = False
color: str = "white"
# ---------------------------------------------------------------------------
# Actions
# ---------------------------------------------------------------------------
class Action(Protocol):
def apply(self, settings: Settings) -> Settings:
...
@dataclass(frozen=True)
class ToggleBold:
def apply(self, settings: Settings) -> Settings:
return replace(
settings,
bold=not settings.bold,
)
@dataclass(frozen=True)
class ToggleItalic:
def apply(self, settings: Settings) -> Settings:
return replace(
settings,
italic=not settings.italic,
)
@dataclass(frozen=True)
class SetColor:
color: str
def apply(self, settings: Settings) -> Settings:
return replace(
settings,
color=self.color,
)
# ---------------------------------------------------------------------------
# Cursors
# ---------------------------------------------------------------------------
class Cursor(Protocol):
def process_key(self, key: str) -> CursorResult:
...
@dataclass(frozen=True)
class CursorResult:
cursor: Cursor
action: Action | None = None
message: str | None = None
@dataclass(frozen=True)
class BoldCursor:
def process_key(self, key: str) -> CursorResult:
if key == "\x1b[A": # Up
return CursorResult(ColorCursor())
if key == "\x1b[B": # Down
return CursorResult(ItalicCursor())
if key in ("\r", "\n"):
return CursorResult(
cursor=self,
action=ToggleBold(),
)
return CursorResult(self)
@dataclass(frozen=True)
class ItalicCursor:
def process_key(self, key: str) -> CursorResult:
if key == "\x1b[A":
return CursorResult(BoldCursor())
if key == "\x1b[B":
return CursorResult(ColorCursor())
if key in ("\r", "\n"):
return CursorResult(
cursor=self,
action=ToggleItalic(),
)
return CursorResult(self)
@dataclass(frozen=True)
class ColorCursor:
text: str = ""
def process_key(self, key: str) -> CursorResult:
if key == "\x1b[A":
return CursorResult(ItalicCursor())
if key == "\x1b[B":
return CursorResult(BoldCursor())
if key in ("\r", "\n"):
if self.text in COLORS:
return CursorResult(
cursor=ColorCursor(),
action=SetColor(self.text),
)
return CursorResult(
cursor=ColorCursor(),
message=f"Invalid color: {self.text!r}",
)
if key in ("\x7f", "\b"):
return CursorResult(
ColorCursor(self.text[:-1]),
)
if key.isprintable():
return CursorResult(
ColorCursor(self.text + key.lower()),
)
return CursorResult(self)
# ---------------------------------------------------------------------------
# Global state
# ---------------------------------------------------------------------------
@dataclass(frozen=True)
class State:
settings: Settings
cursor: Cursor
message: str | None = None
def process_key(self, key: str) -> State:
result = self.cursor.process_key(key)
settings = self.settings
if result.action is not None:
settings = result.action.apply(settings)
return State(
settings=settings,
cursor=result.cursor,
message=result.message,
)
# ---------------------------------------------------------------------------
# Terminal I/O
# ---------------------------------------------------------------------------
def read_key() -> str:
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
key = sys.stdin.read(1)
if key == "\x1b":
key += sys.stdin.read(2)
return key
finally:
termios.tcsetattr(
fd,
termios.TCSADRAIN,
old_settings,
)
def clear_screen() -> None:
print("\033[2J\033[H", end="")
def style_code(settings: Settings) -> str:
codes: list[str] = []
if settings.bold:
codes.append("1")
if settings.italic:
codes.append("3")
codes.append(COLORS[settings.color])
return f"\033[{';'.join(codes)}m"
def draw(state: State) -> None:
clear_screen()
print(style_code(state.settings), end="")
print(
f"{'>' if isinstance(state.cursor, BoldCursor) else ' '}"
"toggle bold"
)
print(
f"{'>' if isinstance(state.cursor, ItalicCursor) else ' '}"
"toggle italic"
)
if isinstance(state.cursor, ColorCursor):
print(f">select color: {state.cursor.text}%")
else:
print(" select color")
if state.message is not None:
print()
print(state.message)
print()
print("â/â: move Enter: select q: quit")
print("\033[0m", end="", flush=True)
# ---------------------------------------------------------------------------
# Main loop
# ---------------------------------------------------------------------------
def main() -> None:
state = State(
settings=Settings(),
cursor=BoldCursor(),
)
while True:
draw(state)
key = read_key()
# q is ordinary text while typing a color.
if key == "q" and not isinstance(state.cursor, ColorCursor):
break
state = state.process_key(key)
clear_screen()
if __name__ == "__main__":
main()
Or if you prefer a more âsimpleâ implementation:
import sys
import termios
import tty
COLORS: dict[str, str] = {
"black": "30",
"red": "31",
"green": "32",
"yellow": "33",
"blue": "34",
"magenta": "35",
"cyan": "36",
"white": "37",
}
def read_key() -> str:
fd = sys.stdin.fileno()
old_settings = termios.tcgetattr(fd)
try:
tty.setraw(fd)
key = sys.stdin.read(1)
if key == "\x1b":
key += sys.stdin.read(2)
return key
finally:
termios.tcsetattr(fd, termios.TCSADRAIN, old_settings)
def clear_screen() -> None:
print("\033[2J\033[H", end="")
def style_code(*, bold: bool, italic: bool, color: str) -> str:
codes: list[str] = []
if bold:
codes.append("1")
if italic:
codes.append("3")
codes.append(COLORS[color])
return f"\033[{';'.join(codes)}m"
def main() -> None:
options = [
"toggle bold",
"toggle italic",
"select color",
]
selected = 0
bold = False
italic = False
color = "white"
color_input = ""
message = ""
while True:
# -------------------------
# REDRAW WHOLE SCREEN
# -------------------------
clear_screen()
style = style_code(
bold=bold,
italic=italic,
color=color,
)
reset = "\033[0m"
# Everything from here is displayed in the selected style.
print(style, end="")
for index, option in enumerate(options):
marker = ">" if index == selected else " "
if index == 2 and selected == 2:
print(f"{marker}{option}: {color_input}", end="")
# A simple visible cursor.
print("%")
else:
print(f"{marker}{option}")
print()
print(f"current color: {color}")
if message:
print(message)
print()
print("â/â: move Enter: select q: quit")
print(reset, end="", flush=True)
# -------------------------
# WAIT FOR KEYBOARD INPUT
# -------------------------
key = read_key()
# -------------------------
# PROCESS INPUT
# -------------------------
message = ""
if key == "q" and not (selected == 2 and color_input):
break
if key == "\x1b[A": # Up
color_input = ""
selected = (selected - 1) % len(options)
elif key == "\x1b[B": # Down
color_input = ""
selected = (selected + 1) % len(options)
elif key in ("\r", "\n"):
if selected == 0:
bold = not bold
elif selected == 1:
italic = not italic
elif selected == 2:
if color_input in COLORS:
color = color_input
color_input = ""
else:
message = f"Invalid color: {color_input!r}"
color_input = ""
elif selected == 2:
if key in ("\x7f", "\b"): # Backspace
color_input = color_input[:-1]
elif key.isprintable():
color_input += key.lower()
clear_screen()
if __name__ == "__main__":
main()
so i dont have termios. and i tried installing it manny times with windows-curses and stuff and it did not working. is there a way to do it without that?. like i dont want screens. i just want the texts in my terminal you know. like a main menu in a video game
Right, itâs windows causing problems again. Termios is included in most Python 3.14 builds, but not Windows.
Iâd recommend installing WSL, and running all your programming projects from WSL. WSL is a linux-emulator that runs on Windows, and is actively being developed by Microsoft (and is for that reason probably not actively being sabotaged by Microsoft
). And it allows you to get on with programming without having to deal with Windows BS.
But I understand other people have different perspectives.[1]
Once youâve got WSL installed, you never need to deal with stuff like windows-curses again.
Instead of getting vague guides about which buttons to press and which websites to go to, guides in the linux system can consist of ârun these lines of code in your terminalâ. This does have itâs own downsides, primarily to do with figuring out what to trust. âŠď¸
If it concerns you that you wouldnât be able to distribute your application to windows users: that is why you should use a downloadable library. They have already solved the (significant) cross-platform compatibility issues.
is there any other things than termios?
i installed arch linux once. and i asked chatgpt how to change my dns it give me the wrong answer it messed up my internet and stuff so i had to switch back to windows
Yes, you can ask ChatGPT to translate the program I gave to use curses instead[1], but then youâve got the same problem that curses is not included in the windows build of Python by default.
Sorry you had bad experience with arch linux. Itâs predictable to me that it would give you trouble, but perhaps you couldnât have known. Ubuntu, Fedora and Linux Mint are some of the linux distros that are relatively âfriendlyâ. Arch Linux is not.
WSL is something else again: Install WSL | Microsoft Learn . I highly recommend giving it a try.
or at least I can âŠď¸
You might want to look in to Textual. Works on Mac, Windows, and Linux.