Search code examples
pythonwindowscmd

Editable terminal border in cmd


How can I create a simple terminal border that can easily be printed in?

Something like this is perfect

┌──────────┐
│  text    │
│  text    │
├──────────┤
│ input    │
└──────────┘

I've seen modules like Npyscreen and a UI like this would be perfect although this is not what my requirements need. It needs to be way easier for my purpose (Text based RPG game). If someone can recommend me a module or give me a simple way on how to replicate this then that'd be great!


Solution

  • Here is a solution using curses :

    import curses
    screen = curses.initscr()
    curses.noecho()
    curses.cbreak()
    screen.keypad(True)
    left_border = '│'
    right_border = '│'
    top_border = '─'
    bottom_border = '─'
    separator = '─'
    top_left = "┌"
    top_right = "┐"
    bottom_left = "└"
    bottom_right = "┘"
    left_junction = "├"
    right_junction = '┤'
    
    
    def refresh_screen(current_text, info):
        screen.clear()  # clear
        rows, cols = screen.getmaxyx()  # get screen rows and columns
        screen.addstr(0, 0, top_left)  # top left corner
        screen.addstr(0, 1, top_border * (cols - 3))  # top border
        screen.addstr(0, cols - 2, top_right)  # top right corner
        for i in range(1, rows - 1):
            screen.addstr(i, 0, left_border)  # left border
        for i in range(1, rows - 1):
            screen.addstr(i, cols - 2, right_border)  # right border
        screen.addstr(rows - 1, 0, bottom_left)  # bottom left corner
        screen.addstr(rows - 1, 1, bottom_border * (cols - 3))  # bottom border
        screen.addstr(rows - 1, cols - 2, bottom_right)  # bottom right corner
        screen.addstr(rows - 3, 0, left_junction)  # left junction
        screen.addstr(rows - 3, 1, separator * (cols - 3))  # separator
        screen.addstr(rows - 3, cols - 2, right_junction)  # right junction
        cursorx = 1
        cursory = 1
        # write the info text
        for char in info:
            if char == '\n': # deal with newlines
                cursorx = 1
                cursory += 1
            else:
                screen.addstr(cursory, cursorx, char)  # add character
            cursorx += 1  # increment cursor position
            if cursorx >= cols - 3:  # if cursor x is over right border, carriage return
                cursorx = 1
                cursory += 1
        # write the current user input
        screen.addstr(rows - 2, 1, " " + current_text)
        screen.refresh()
    
    
    info = "lorem ipsum dolor sit amet " * 10
    user_input = ""
    refresh_screen(user_input, info)
    while True:
        key = screen.getkey()
        if ord(key) == 127: # backspace
            user_input = user_input[:-1]
        else:
            user_input += key
        if key == '\n':
            # user entered something
            # do_something(user_input)
            user_input = ""
        refresh_screen(user_input, info)
    
    
    

    However, this does not handle the Backspace key or a text overflow (info text larger than the text zone).

    EDIT: I added support for deleting with backspace.

    info is the variable containing the text in the top zone (here lorem ipsum ten times) and user_input contains the current user input. You can change the variable declarations at the top to change the type of the border.

    It gives something like this :

    ┌─────────────────────────────────────────────────────────────────────┐
    │lorem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum do │
    │lor sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet l │
    │orem ipsum dolor sit amet lorem ipsum dolor sit amet lorem ipsum dol │
    │or sit amet lorem ipsum dolor sit amet lorem ipsum dolor sit amet    │
    │                                                                     │
    │                                                                     │
    │                                                                     │
    │                                                                     │
    │                                                                     │
    │                                                                     │
    ├─────────────────────────────────────────────────────────────────────┤
    │ user input here                                                     │
    └─────────────────────────────────────────────────────────────────────┘