You've already forked pygconsole
very first commit
This commit is contained in:
152
.gitignore
vendored
Normal file
152
.gitignore
vendored
Normal file
@@ -0,0 +1,152 @@
|
||||
# Byte-compiled / optimized / DLL files
|
||||
__pycache__/
|
||||
*.py[cod]
|
||||
*$py.class
|
||||
|
||||
# C extensions
|
||||
*.so
|
||||
|
||||
# Distribution / packaging
|
||||
.Python
|
||||
build/
|
||||
develop-eggs/
|
||||
dist/
|
||||
downloads/
|
||||
eggs/
|
||||
.eggs/
|
||||
lib/
|
||||
lib64/
|
||||
parts/
|
||||
sdist/
|
||||
var/
|
||||
wheels/
|
||||
share/python-wheels/
|
||||
*.egg-info/
|
||||
.installed.cfg
|
||||
*.egg
|
||||
MANIFEST
|
||||
|
||||
# PyInstaller
|
||||
# Usually these files are written by a python script from a template
|
||||
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
||||
*.manifest
|
||||
*.spec
|
||||
|
||||
# Installer logs
|
||||
pip-log.txt
|
||||
pip-delete-this-directory.txt
|
||||
|
||||
# Unit test / coverage reports
|
||||
htmlcov/
|
||||
.tox/
|
||||
.nox/
|
||||
.coverage
|
||||
.coverage.*
|
||||
.cache
|
||||
nosetests.xml
|
||||
coverage.xml
|
||||
*.cover
|
||||
*.py,cover
|
||||
.hypothesis/
|
||||
.pytest_cache/
|
||||
cover/
|
||||
|
||||
# Translations
|
||||
*.mo
|
||||
*.pot
|
||||
|
||||
# Django stuff:
|
||||
*.log
|
||||
local_settings.py
|
||||
db.sqlite3
|
||||
db.sqlite3-journal
|
||||
|
||||
# Flask stuff:
|
||||
instance/
|
||||
.webassets-cache
|
||||
|
||||
# Scrapy stuff:
|
||||
.scrapy
|
||||
|
||||
# Sphinx documentation
|
||||
docs/_build/
|
||||
|
||||
# PyBuilder
|
||||
.pybuilder/
|
||||
target/
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
# IPython
|
||||
profile_default/
|
||||
ipython_config.py
|
||||
|
||||
# pyenv
|
||||
# For a library or package, you might want to ignore these files since the code is
|
||||
# intended to run in multiple environments; otherwise, check them in:
|
||||
.python-version
|
||||
|
||||
# pipenv
|
||||
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
||||
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
||||
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
||||
# install all needed dependencies.
|
||||
#Pipfile.lock
|
||||
|
||||
# poetry
|
||||
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
||||
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
||||
# commonly ignored for libraries.
|
||||
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
||||
#poetry.lock
|
||||
|
||||
# PEP 582; used by e.g. github.com/David-OConnor/pyflow
|
||||
__pypackages__/
|
||||
|
||||
# Celery stuff
|
||||
celerybeat-schedule
|
||||
celerybeat.pid
|
||||
|
||||
# SageMath parsed files
|
||||
*.sage.py
|
||||
|
||||
# Environments
|
||||
.env
|
||||
.venv
|
||||
env/
|
||||
venv/
|
||||
ENV/
|
||||
env.bak/
|
||||
venv.bak/
|
||||
|
||||
# Spyder project settings
|
||||
.spyderproject
|
||||
.spyproject
|
||||
|
||||
# Rope project settings
|
||||
.ropeproject
|
||||
|
||||
# mkdocs documentation
|
||||
/site
|
||||
|
||||
# mypy
|
||||
.mypy_cache/
|
||||
.dmypy.json
|
||||
dmypy.json
|
||||
|
||||
# Pyre type checker
|
||||
.pyre/
|
||||
|
||||
# pytype static type analyzer
|
||||
.pytype/
|
||||
|
||||
# Cython debug symbols
|
||||
cython_debug/
|
||||
|
||||
# PyCharm
|
||||
# JetBrains specific template is maintainted in a separate JetBrains.gitignore that can
|
||||
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
||||
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||
#.idea/
|
21
LICENSE.md
Normal file
21
LICENSE.md
Normal file
@@ -0,0 +1,21 @@
|
||||
# MIT License
|
||||
|
||||
Copyright (c) 2022 [devfred78](https://github.com/devfred78)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
276
README.md
Normal file
276
README.md
Normal file
@@ -0,0 +1,276 @@
|
||||
# pygconsole
|
||||
|
||||
ANSI terminal emulation for Pygame.
|
||||
|
||||
## About the project
|
||||
|
||||
This package provides a way to emulate a terminal onto a Pygame display, compliant with a subset of the [ECMA-48 standard](https://www.ecma-international.org/publications-and-standards/standards/ecma-48/) (aka **ANSI escape codes**). Once correctly implemented, it can replace entirely `sys.stdout` if you desire, or at least be used with `print()` built-in function, as simply as displaying a string on a legacy terminal.
|
||||
|
||||
## Getting started
|
||||
|
||||
### Prerequisites
|
||||
|
||||
Of course, pygconsole cannot run without Python ! More precisely, it requires at least the 3.8 version of our beloved language.
|
||||
|
||||
pygconsole depends on the following packages. The installation of pygconsole should install automatically those packages if they are missing on your system. If it fails, you can install them individually:
|
||||
|
||||
* pygame: version 2.1.0 or above
|
||||
|
||||
```sh
|
||||
pip install pygame
|
||||
```
|
||||
|
||||
* colorlog: version 6.4.1 or above
|
||||
|
||||
```sh
|
||||
pip install colorlog
|
||||
```
|
||||
|
||||
### Installation
|
||||
|
||||
Install from PyPi with:
|
||||
|
||||
```sh
|
||||
pip install pygconsole
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
First, import the package with the following command:
|
||||
|
||||
```python
|
||||
import pygconsole
|
||||
```
|
||||
|
||||
pygconsole is used in close coordination with pygame. So you have to import and initialize pygame for instance with the following lines:
|
||||
|
||||
```python
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
|
||||
DISPLAY_SIZE = (1920,1080)
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
|
||||
pygame.init()
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
```
|
||||
|
||||
Those lines initalize a full HD, fullscreen display, with a background image named `background.jpg`. For deeper information about pygame, read the [official site](https://www.pygame.org/docs/).
|
||||
|
||||
Initialize an I/O text, buffered stream with:
|
||||
|
||||
```python
|
||||
iotextstreaam = pygconsole.io.TextIOConsoleWrapper(console_name="pygame_console", newline='\r\n', line_buffering=True)
|
||||
```
|
||||
|
||||
Retrieve the console created "under the hoods" with this I/O stream:
|
||||
|
||||
```python
|
||||
console = pygconsole.console.Console.get_console(name="pygame_console")
|
||||
```
|
||||
|
||||
Finally, retrieve the pygame.Surface object used for displaying the console on screen:
|
||||
|
||||
```python
|
||||
surface = console.surface
|
||||
```
|
||||
|
||||
It is now possible to enter the display loop ! A possible example of display loop can be (take care to previously import the builtin module `sys` otherwise the `sys.exit()` command will raise an exception !) :
|
||||
|
||||
```python
|
||||
while True:
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE:
|
||||
sys.exit() # Exit when hitting the ESCAPE key
|
||||
elif event.key == K_RETURN:
|
||||
print("", file=iotextstreaam, flush=True) # New line
|
||||
if event.type == TEXTINPUT: # When typing a key with a writable character...
|
||||
print(event.text, end='', file=iotextstreaam, flush=True) # Display the character
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Console display at coordinates (1000,620)
|
||||
screen_surface.blit(console.surface,(1000,620))
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
```
|
||||
|
||||
If you wish to custom the console, you can initialize it independantly, and assign it to an I/O stream in a second step.
|
||||
|
||||
```python
|
||||
my_console = pygconsole.console.get_console(name="custom_console",width=120,height=50)
|
||||
|
||||
iotextstreaam = pygconsole.io.TextIOConsoleWrapper(console_name="custom_console", newline='\r\n', line_buffering=True)
|
||||
```
|
||||
|
||||
A console is identified by its name, 2 consoles with the same name are in reality the same instance of the Console class.
|
||||
|
||||
### Recognised ECMA-48 controls
|
||||
|
||||
Apart from recognising the main displayable unicode characters, pygconsole supports also the following non-displayable values in the byte stream sent to the console:
|
||||
|
||||
```
|
||||
'\x0a' # LF (Line Field): move cursor to the corresponding character position of the following line
|
||||
'\x0d' # CR (Carriage Return): move cursor to the first position of the current line
|
||||
'\x1b' # ESC (Escape): start an escape sequence (see below)
|
||||
```
|
||||
|
||||
Escape sequences supported by pygconsole take the form:
|
||||
|
||||
```
|
||||
ESC [ <param> ; <param> ... <command>
|
||||
```
|
||||
|
||||
Where `<param>` is an integer, and `<command>` is a single letter. Zero or more params are passed to a `<command>`. If no params are passed, it is generally synonymous with passing a single zero. No spaces exist in the sequence; they have been inserted here simply to read more easily.
|
||||
|
||||
The exhaustive list of escape sequences supported by pygconsole is the following:
|
||||
|
||||
```
|
||||
# Erase in Display
|
||||
ESC [ 0 J # clear from cursor to end of screen
|
||||
ESC [ 1 J # clear from cursor to beginning of the screen
|
||||
ESC [ 2 J # clear entire screen
|
||||
ESC [ 3 J # clear entire screen and delete all lines saved in the scrollback buffer
|
||||
|
||||
# Screen scrolling
|
||||
ESC [ n S # Scroll up of n lines. New lines are added at the bottom of the screen
|
||||
ESC [ n T # Scroll down of n lines. New lines are added at the top of the screen
|
||||
|
||||
# general graphic rendition commands
|
||||
ESC [ 0 m # default rendition, cancels the effect of any preceding occurrence of SGR sequence ("m" command)
|
||||
ESC [ 1 m # bold characters
|
||||
ESC [ 3 m # italicized characters
|
||||
ESC [ 4 m # singly underlined characters
|
||||
ESC [ 7 m # negative image, swaps foreground and background colours
|
||||
ESC [ 22 m # normal intensity characters (not bold)
|
||||
ESC [ 23 m # not italicized characters
|
||||
ESC [ 24 m # not underlined characters
|
||||
ESC [ 27 m # positive image, colours are no more reversed
|
||||
|
||||
# Foreground
|
||||
ESC [ 30 m # black
|
||||
ESC [ 31 m # red
|
||||
ESC [ 32 m # green
|
||||
ESC [ 33 m # yellow
|
||||
ESC [ 34 m # blue
|
||||
ESC [ 35 m # magenta
|
||||
ESC [ 36 m # cyan
|
||||
ESC [ 37 m # white
|
||||
ESC [ 90 m # bright black (grey)
|
||||
ESC [ 91 m # bright red
|
||||
ESC [ 92 m # bright green
|
||||
ESC [ 93 m # bright yellow
|
||||
ESC [ 94 m # bright blue
|
||||
ESC [ 95 m # bright magenta
|
||||
ESC [ 96 m # bright cyan
|
||||
ESC [ 97 m # bright white
|
||||
|
||||
# Background
|
||||
ESC [ 40 m # black
|
||||
ESC [ 41 m # red
|
||||
ESC [ 42 m # green
|
||||
ESC [ 43 m # yellow
|
||||
ESC [ 44 m # blue
|
||||
ESC [ 45 m # magenta
|
||||
ESC [ 46 m # cyan
|
||||
ESC [ 47 m # white
|
||||
ESC [ 100 m # bright black (grey)
|
||||
ESC [ 101 m # bright red
|
||||
ESC [ 102 m # bright green
|
||||
ESC [ 103 m # bright yellow
|
||||
ESC [ 104 m # bright blue
|
||||
ESC [ 105 m # bright magenta
|
||||
ESC [ 106 m # bright cyan
|
||||
ESC [ 107 m # bright white
|
||||
|
||||
```
|
||||
|
||||
For instance, to display "Hello world !" in red:
|
||||
|
||||
```python
|
||||
print("\x1b[31mHello world !", file=iotextstreaam, flush=True)
|
||||
```
|
||||
|
||||
Multiple numeric params to the 'm' command can be combined into a single sequence:
|
||||
|
||||
```
|
||||
ESC [ 1 ; 92 ; 41 m # bold, bright green characters on red background
|
||||
```
|
||||
|
||||
The colon character `:` is also recognised as a separator (like the semicolon `;`).
|
||||
|
||||
All other escape sequences of the form `ESC [ <param> ; <param> ... <command>`, and, more generally, all other ECMA-48 controls, are silently stripped from the output.
|
||||
|
||||
### API documentation
|
||||
|
||||
The API documentation is not yet implemented, sorry for the inconvenience :-(. Until the completion of this chapter, you can refer to the source files, they are self-documented enough to understand how the package proceeds.
|
||||
|
||||
The most two important classes are:
|
||||
|
||||
```python
|
||||
pygconsole.io.TextIOConsoleWrapper()
|
||||
```
|
||||
|
||||
A buffered text stream providing higher-level access to a BufferedIOConsole buffered binary stream. It inherits io.TextIOWrapper in the `ìo` Python built-in library. For further details about inherited elements, see <https://docs.python.org/3/library/io.html> . This class is generally used directly to write characters on the console, by objects using I/O streams (like `print()`).
|
||||
|
||||
```python
|
||||
pygconsole.console.Console()
|
||||
```
|
||||
Console objects represent terminals that can be displayed onto any `pygame.Surface` object (in particular the display surface given by the `pygame.display.get_surface()` method).
|
||||
|
||||
Note that this class should never be instantiated directly, but always through the `get_console()` static method. Multiple calls to `get_console()` with the same name will always return a reference to the same Console object.
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are **greatly appreciated**.
|
||||
|
||||
If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement" or "bug", according to whether you want to share a proposal of a new function, or to record an anomaly.
|
||||
|
||||
Don't forget to give the project a star! Thanks again!
|
||||
|
||||
1. Fork the Project
|
||||
2. Create your Feature Branch (`git checkout -b feature/AmazingFeature`)
|
||||
3. Commit your Changes (`git commit -m 'Add some AmazingFeature'`)
|
||||
4. Push to the Branch (`git push origin feature/AmazingFeature`)
|
||||
5. Open a Pull Request
|
||||
|
||||
## License
|
||||
|
||||
Distributed under the MIT License. See `LICENSE.md` file for more information.
|
||||
|
||||
## Acknowledgments
|
||||
|
||||
I would like greatfully to thank:
|
||||
|
||||
[DejaVU](https://dejavu-fonts.github.io/) authors for their astounding work on that famous font family I chose as the default font on pygconsole.
|
||||
|
||||
[Karl MPhotography](https://www.pexels.com/fr-fr/photo/paysage-nature-ciel-sable-8092914/) for the great picture I chose for the background of the testing set.
|
||||
|
||||
[Make a README](https://www.makeareadme.com/), [Sayan Mondal](https://medium.com/swlh/how-to-make-the-perfect-readme-md-on-github-92ed5771c061), [Hillary Nyakundi](https://www.freecodecamp.org/news/how-to-write-a-good-readme-file/) and [othneildrew](https://github.com/othneildrew/Best-README-Template) for providing very interesting materials to write good README files (far better than I can write by myself !).
|
||||
|
||||
[Choose an open source license](https://choosealicense.com/) for helping to choose the best suitable license for this project.
|
||||
|
||||
[pygame](https://www.pygame.org) for their wonderful library.
|
||||
|
||||
[colorama](https://github.com/tartley/colorama) for their inspiring description regarding ANSI escape sequences.
|
||||
|
||||
[python-colorlog](https://github.com/borntyping/python-colorlog) for adding joyful colors to the logging outputs.
|
||||
|
||||
[ECMA International](https://www.ecma-international.org/) for maintaining over years the [ECMA-48 standard](https://www.ecma-international.org/publications-and-standards/standards/ecma-48/)
|
||||
|
||||
[Semantic Versioning](https://semver.org/) for providing clear specifications for versioning projects.
|
||||
|
||||
[Real Python](https://realpython.com/) for contributing really increasing skills in Python for everyone, novices or veterans.
|
||||
|
||||
[GitHub](https://github.com/) for hosting this project, and helping to share it.
|
||||
|
||||
[Pypi](https://pypi.org/) for providing a very convenient way to share modules and package to the entire Python community.
|
||||
|
||||
And, of course, all the former, current and further contributors of this project !
|
4
pygconsole/__init__.py
Normal file
4
pygconsole/__init__.py
Normal file
@@ -0,0 +1,4 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
__VERSION__ = "0.1.0"
|
||||
RESOURCE_LOCATION = "resources"
|
||||
import pygconsole.console, pygconsole.io
|
909
pygconsole/console.py
Normal file
909
pygconsole/console.py
Normal file
@@ -0,0 +1,909 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Module console : Terminal emulation onto a pygame display.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#------------------
|
||||
import sys
|
||||
import logging
|
||||
import threading
|
||||
from collections import namedtuple, deque
|
||||
from dataclasses import dataclass
|
||||
import io
|
||||
import pkgutil
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
from pygconsole import RESOURCE_LOCATION
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
@dataclass
|
||||
class CharArgs:
|
||||
"""
|
||||
Character caracteristics
|
||||
"""
|
||||
foreground_colour: Colour = Colour(255,255,255,255) # Font colour
|
||||
background_colour: Colour = Colour(0,0,0,255) # Background colour
|
||||
italic: bool = False # If True, character is italic (default is False)
|
||||
bold: bool = False # If True, character is bold (default is False)
|
||||
underline: bool = False # If True, character is underlined (default is False)
|
||||
str: str = " " # Character representation
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
class Console():
|
||||
"""
|
||||
Console objects represent terminals that can be displayed onto any `pygame.Surface` object (in particular the display surface given by the `pygame.display.get_surface()` method).
|
||||
|
||||
Note that this class should never be instantiated directly, but always through the `get_console()` static method. Multiple calls to `get_console()` with the same name will always return a reference to the same Console object.
|
||||
|
||||
Once instantiated, a typical cycling use-case of the object is:
|
||||
- If necessary, modify attributes `italic`, `bold`, `underline`, `foreground_colour` or `background_colour` in accordance with the desired format to be rendered
|
||||
- Call the `add_char()` method to add a string onto the console display
|
||||
- Render the console screen onto the display by the use of the `surface` attribute in the Pygame display loop.
|
||||
|
||||
In addition to this cycle, several other methods can be called for specific commands to the console, like `clear()` or `scroll()`.
|
||||
|
||||
At last, a `logging.logger` object can be applied to facilitate status monitoring or fault investigation. In this case, the `create_log()` static method can be used to create a colorized, well-formed logger before calling `get_console()`. CAUTION: To prevent infinite loops, NEVER use the Console object to display its proper logger's outputs !
|
||||
|
||||
Attributes
|
||||
----------
|
||||
log : logging.logger object
|
||||
logger used to track events that append when the instance is running (default is None).
|
||||
name : str
|
||||
the name of the console. Read-only attribute (default is the module name (eg: "pygconsole")).
|
||||
surface : pygame.Surface object
|
||||
represents the console rendering. Should be applied in the display loop. Read-only attribute.
|
||||
foreground_colour : namedtuple(red,green,blue,alpha)
|
||||
font colour that will be applied to the next printed character (default is `bright_white` (255,255,255,255)).
|
||||
background_colour : namedtuple(red,green,blue,alpha)
|
||||
background colour that will be applied to the next printed character (default is `black` (0,0,0,255)).
|
||||
font_transparency : int
|
||||
font transparency, using a value range of 0 (invisible) to 255 (opaque) inclusive (default 255).
|
||||
background_transparency : int
|
||||
Background transparency, using a value range of 0 (invisible) to 255 (opaque) inclusive (default 255).
|
||||
italic : bool
|
||||
gets or sets whether the font should be rendered in italics (default False).
|
||||
bold : bool
|
||||
gets or sets whether the font should be rendered in bold (default False).
|
||||
underline : bool
|
||||
gets or sets whether the font should be rendered with an underline (default False).
|
||||
memory_size : int
|
||||
amount of memorized characters (default 19200).
|
||||
width : int
|
||||
console width, in characters (default 80).
|
||||
height : int
|
||||
console height, in characters (default 24).
|
||||
|
||||
Static methods
|
||||
--------------
|
||||
get_console(name = __name__, width = 80, height = 24, font_size = 10, font_transparency = 255, background_transparency = 255, logger = None)
|
||||
Return a Console instance.
|
||||
create_log(name, level = logging.DEBUG, writestream = sys.stdout)
|
||||
Return a logger with the specified name, level and output stream.
|
||||
|
||||
Methods
|
||||
-------
|
||||
add_char(char)
|
||||
Display one or several characters on the console, at the current cursor position.
|
||||
clear(mode = "all")
|
||||
Clear full or part of screen.
|
||||
scroll(nb_lines = 1, up = True)
|
||||
Vertical scrolling of the display.
|
||||
carriage_return()
|
||||
Move cursor to the first position of the current line.
|
||||
line_field()
|
||||
Move cursor to the corresponding character position of the following line.
|
||||
"""
|
||||
|
||||
#############################################################
|
||||
# Class attributes
|
||||
|
||||
DEFAULT_NORMAL_FONT = RESOURCE_LOCATION + "/fonts/DejaVu/DejaVuSansMono.ttf"
|
||||
DEFAULT_BOLD_FONT = RESOURCE_LOCATION + "/fonts/DejaVu/DejaVuSansMono-Bold.ttf"
|
||||
DEFAULT_ITALIC_FONT = RESOURCE_LOCATION + "/fonts/DejaVu/DejaVuSansMono-Oblique.ttf"
|
||||
DEFAULT_BOLDITALIC_FONT = RESOURCE_LOCATION + "/fonts/DejaVu/DejaVuSansMono-BoldOblique.ttf"
|
||||
DEFAULT_LICENCE_FONT = RESOURCE_LOCATION + "/fonts/DejaVu/LICENSE"
|
||||
DEFAULT_AUTHOR_FONT = RESOURCE_LOCATION + "/fonts/DejaVu/AUTHORS"
|
||||
# Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is a trademark of Bitstream, Inc.
|
||||
# https://dejavu-fonts.github.io/
|
||||
DEFAULT_ALPHA = 255 # Default console transparency (0=invisible, 255=opaque)
|
||||
DEFAULT_FOREGROUND_COLOUR = Colour(255,255,255,DEFAULT_ALPHA) # Default font colour
|
||||
DEFAULT_BACKGROUND_COLOUR = Colour(0,0,0,DEFAULT_ALPHA) # Default background colour
|
||||
DEFAULT_CHAR_MEMORY_SIZE = 80*24*10 # Default amount of memorized characters
|
||||
|
||||
STANDARD_COLOURS = {
|
||||
'black': Colour(0,0,0,DEFAULT_ALPHA),
|
||||
'red': Colour(170,0,0,DEFAULT_ALPHA),
|
||||
'green': Colour(0,170,0,DEFAULT_ALPHA),
|
||||
'yellow': Colour(170,85,0,DEFAULT_ALPHA),
|
||||
'blue': Colour(0,0,170,DEFAULT_ALPHA),
|
||||
'magenta': Colour(170,0,170,DEFAULT_ALPHA),
|
||||
'cyan': Colour(0,170,170,DEFAULT_ALPHA),
|
||||
'white': Colour(170,170,170,DEFAULT_ALPHA),
|
||||
'bright_black': Colour(85,85,85,DEFAULT_ALPHA),
|
||||
'bright_red': Colour(255,85,85,DEFAULT_ALPHA),
|
||||
'bright_green': Colour(85,255,85,DEFAULT_ALPHA),
|
||||
'bright_yellow': Colour(255,255,85,DEFAULT_ALPHA),
|
||||
'bright_blue': Colour(85,85,255,DEFAULT_ALPHA),
|
||||
'bright_magenta': Colour(255,85,255,DEFAULT_ALPHA),
|
||||
'bright_cyan': Colour(85,255,255,DEFAULT_ALPHA),
|
||||
'bright_white': Colour(255,255,255,DEFAULT_ALPHA)
|
||||
}
|
||||
|
||||
_instances = dict()
|
||||
|
||||
#############################################################
|
||||
# Static methods
|
||||
|
||||
@staticmethod
|
||||
def get_console(name = __name__, width = 80, height = 24, font_size = 10, font_transparency = DEFAULT_ALPHA, background_transparency = DEFAULT_ALPHA, logger = None):
|
||||
"""
|
||||
Return a Console instance.
|
||||
|
||||
If a new name is given, a new instance is created. All calls to this method with a given name return the same Console instance. in this case, other parameters are ignored.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str, optional
|
||||
The name of the console. Default is the module name (eg: "pygconsole")
|
||||
width : int, optional
|
||||
The width of the console, in characters (default is 80).
|
||||
height : int, optional
|
||||
The height of the console, in characters (default is 24).
|
||||
font_size : int, optional
|
||||
The height of the font, in pixels (default is 10).
|
||||
font_transparency : int, optional
|
||||
The transparency of the font, using a value range of 0 to 255 inclusive. 0 means invisible, 255 means fully opaque (default is 255).
|
||||
background_transparency : int, optional
|
||||
The transparency of the background, using a value range of 0 to 255 inclusive. 0 means invisible, 255 means fully opaque (default is 255).
|
||||
logger : logging.Logger object, optional
|
||||
The parent logger used to track events that append when the instance is running. Mainly for status monitoring or fault investigation purposes. If None (the default), no event is tracked.
|
||||
"""
|
||||
if name not in Console._instances:
|
||||
with threading.Lock():
|
||||
if name not in Console._instances:
|
||||
if logger is None:
|
||||
log = Console.create_log(name, writestream = None)
|
||||
else:
|
||||
log = logger.getChild(name)
|
||||
|
||||
Console(name,width,height,font_size,font_transparency,background_transparency,log)
|
||||
log.info("------------------------------")
|
||||
log.info(f"Creation of a new Console instance with the name '{name}'")
|
||||
log.info("Characteristics:")
|
||||
log.info(f"- dimensions (in chars) : {width}x{height}")
|
||||
log.info(f"- font size : {font_size}")
|
||||
log.info(f"- font transparency : {font_transparency}")
|
||||
log.info(f"- background transparency : {background_transparency}")
|
||||
log.info("------------------------------")
|
||||
log.debug(f"List of Console instances: {Console._instances}")
|
||||
else:
|
||||
Console._instances[name].log.info(f"Usage of the already instanciated console '{name}'")
|
||||
Console._instances[name].log.debug(f"List of Console instances: {Console._instances}")
|
||||
else:
|
||||
Console._instances[name].log.info(f"Usage of the already instanciated console '{name}'")
|
||||
Console._instances[name].log.debug(f"List of Console instances: {Console._instances}")
|
||||
|
||||
return Console._instances[name]
|
||||
|
||||
@staticmethod
|
||||
def create_log(name, level = logging.DEBUG, writestream = sys.stdout):
|
||||
"""
|
||||
Return a logger with the specified name, level and output stream.
|
||||
|
||||
This method wraps the logging.getLogger() function, adding colorization for ECMA-48 compliant terminals (almost all modern terminals are concerned). Hence, all calls to this method with a given name return the same logger instance.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name : str
|
||||
The name of the logger
|
||||
level : int, optional
|
||||
The threshold of the logger. Logging messages which are less severe than level will be ignored; logging messages which have severity level or higher will be emitted. See https://docs.python.org/3/library/logging.html#levels for the possible values (default is logging.DEBUG)
|
||||
writestream : writable text file-like object with buffering implementation, optional
|
||||
Output stream where logging messages should be printed. For instance, all subclasses of io.TextIOBase should be available. Can also be None. In this case, no logging messages will be printed. (default is sys.stdout).
|
||||
"""
|
||||
# Colorized formatter
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
|
||||
# Handler to specified output
|
||||
if writestream is None:
|
||||
handler = logging.NullHandler()
|
||||
else:
|
||||
handler = logging.StreamHandler(writestream)
|
||||
handler.setLevel(level)
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
# logging
|
||||
log = logging.getLogger(name)
|
||||
log.setLevel(level)
|
||||
log.addHandler(handler)
|
||||
|
||||
return log
|
||||
|
||||
#############################################################
|
||||
# Initialization
|
||||
|
||||
def __init__(self, name = __name__, width = 80, height = 24, font_size = 10, font_transparency = DEFAULT_ALPHA, background_transparency = DEFAULT_ALPHA, logger = None):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
See get_console() method.
|
||||
"""
|
||||
if logger is None:
|
||||
self.log = self.create_log(name, writestream = None)
|
||||
else:
|
||||
self.log = logger
|
||||
|
||||
if name not in Console._instances:
|
||||
# New instance recording
|
||||
Console._instances[name] = self
|
||||
|
||||
# console carateristics recording
|
||||
self._width = width
|
||||
self._height = height
|
||||
self._font_size = font_size
|
||||
self._name = name
|
||||
self._font_transparency = font_transparency
|
||||
self._background_transparency = background_transparency
|
||||
|
||||
# Console initialization
|
||||
self._init_console()
|
||||
|
||||
def _init_console(self):
|
||||
"""
|
||||
Console initialization, with associated internal variables.
|
||||
"""
|
||||
# Pygame initialization
|
||||
if not pygame.get_init(): pygame.init()
|
||||
|
||||
# Fonts initialization
|
||||
self._init_font(self._font_size)
|
||||
self._italic = False
|
||||
self._bold = False
|
||||
self._underline = False
|
||||
|
||||
# Default colours initialization
|
||||
self._default_foreground_colour = Console.DEFAULT_FOREGROUND_COLOUR._replace(alpha = self.font_transparency)
|
||||
self._default_background_colour = Console.DEFAULT_BACKGROUND_COLOUR._replace(alpha = self.background_transparency)
|
||||
|
||||
# Current colours initialization
|
||||
self._current_foreground_colour = Console.DEFAULT_FOREGROUND_COLOUR._replace(alpha = self.font_transparency)
|
||||
self._current_background_colour = Console.DEFAULT_BACKGROUND_COLOUR._replace(alpha = self.background_transparency)
|
||||
|
||||
# pygame.Surface objects initialization
|
||||
char_width, char_height = self._normal_font.size(" ") # Works only with fixed-width fonts !
|
||||
surf_width = char_width * self._width
|
||||
surf_height = char_height * self._height
|
||||
self._current_surface = pygame.Surface((surf_width, surf_height), flags=SRCALPHA)
|
||||
with pygame.PixelArray(self._current_surface) as currentpxarray:
|
||||
currentpxarray[:] = pygame.Color(0, 0, 0, 0) # invisible surface by default
|
||||
self._previous_surface = self._current_surface.copy()
|
||||
|
||||
# Presentation stream initialization
|
||||
self._char_memory_size = Console.DEFAULT_CHAR_MEMORY_SIZE
|
||||
self._presentation_stream = deque([None] * self._width * self._height, self._char_memory_size)
|
||||
|
||||
# Other initializations
|
||||
self._cursor = 0 # Cursor position in the presentation stream (ie: the index where the next character will be added)
|
||||
self._start_window = 0 # First rendered character position in the presentation stream
|
||||
self._end_window = self._width * self._height - 1 # Last rendered character position in the presentation stream
|
||||
self._update_surface_lock = threading.Lock() # Protect the _current_surface object during its update
|
||||
|
||||
# Initial surfaces populating
|
||||
self._render_all()
|
||||
|
||||
def _init_font(self, font_size):
|
||||
"""
|
||||
Fonts initialization.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
font_size: int
|
||||
size of initialized fonts
|
||||
"""
|
||||
# get binary resources
|
||||
normal_font_bin = pkgutil.get_data(__name__, Console.DEFAULT_NORMAL_FONT)
|
||||
bold_font_bin = pkgutil.get_data(__name__, Console.DEFAULT_BOLD_FONT)
|
||||
italic_font_bin = pkgutil.get_data(__name__, Console.DEFAULT_ITALIC_FONT)
|
||||
bolditalic_font_bin = pkgutil.get_data(__name__, Console.DEFAULT_BOLDITALIC_FONT)
|
||||
|
||||
# translate binaries into file-like objects
|
||||
normal_font_file = io.BytesIO(normal_font_bin)
|
||||
bold_font_file = io.BytesIO(bold_font_bin)
|
||||
italic_font_file = io.BytesIO(italic_font_bin)
|
||||
bolditalic_font_file = io.BytesIO(bolditalic_font_bin)
|
||||
|
||||
# Creation of pygame.font.Font objects
|
||||
self._normal_font = pygame.font.Font(normal_font_file, font_size)
|
||||
self._bold_font = pygame.font.Font(bold_font_file, font_size)
|
||||
self._italic_font = pygame.font.Font(italic_font_file, font_size)
|
||||
self._bolditalic_font = pygame.font.Font(bolditalic_font_file, font_size)
|
||||
|
||||
|
||||
#############################################################
|
||||
# Private attributes
|
||||
|
||||
def __repr__(self):
|
||||
"""
|
||||
"Official" String representation of the instance.
|
||||
"""
|
||||
return f"<Console '{self.name}' with dimensions {self.width}x{self.height}>"
|
||||
|
||||
def __str__(self):
|
||||
"""
|
||||
"Informal" String representation of the instance.
|
||||
"""
|
||||
return f"Console instance called '{self.name}'"
|
||||
|
||||
#############################################################
|
||||
# Public attributes
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
"""
|
||||
Name of the instance. Read-only attribute.
|
||||
"""
|
||||
return self._name
|
||||
|
||||
@property
|
||||
def surface(self):
|
||||
"""
|
||||
pygame.Surface object representing the console rendering. Should be applied in the display loop. Read-only attribute.
|
||||
"""
|
||||
if self._update_surface_lock.locked(): return self._previous_surface
|
||||
else: return self._current_surface
|
||||
|
||||
@property
|
||||
def foreground_colour(self):
|
||||
"""
|
||||
Font colour that will be applied to the next printed character.
|
||||
|
||||
The return value is a namedtuple Colour "red green blue alpha".
|
||||
The value can be set using one of the following formats:
|
||||
- namedtuple Colour
|
||||
- tuple (red, green, blue, alpha) (each element is an int in the range of 0 to 255 inclusive)
|
||||
- tuple (red, green, blue) (each element is an int in the range of 0 to 255 inclusive)
|
||||
- string 'default': font default colour
|
||||
- string among the following: 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'bright_black', 'bright_red', 'bright_green', 'bright_yellow', 'bright_blue', 'bright_magenta', 'bright_cyan', 'bright_white'
|
||||
if none of these formats is used, the attribute remains unchanged.
|
||||
"""
|
||||
return self._current_foreground_colour
|
||||
|
||||
@foreground_colour.setter
|
||||
def foreground_colour(self, value):
|
||||
if isinstance(value, str):
|
||||
if value in Console.STANDARD_COLOURS:
|
||||
self._current_foreground_colour = Console.STANDARD_COLOURS[value]._replace(alpha = self.font_transparency)
|
||||
self.log.debug(f"The font colour is set to {value}.")
|
||||
elif value == 'default':
|
||||
self._current_foreground_colour = self._default_foreground_colour._replace(alpha = self.font_transparency)
|
||||
self.log.debug(f"The font colour is set to {value}.")
|
||||
elif len(value) == 4:
|
||||
if -1 < value[0] < 256 and -1 < value[1] < 256 and -1 < value[2] < 256 and -1 < value[3] < 256:
|
||||
self._current_foreground_colour = Colour._make(value)
|
||||
self.font_transparency = value[3]
|
||||
self.log.debug(f"The font colour is set to {value}.")
|
||||
else: self.log.warning(f"{value} cannot be applied to a foreground colour. The previous value is kept: {self._current_foreground_colour}")
|
||||
elif len(value) == 3:
|
||||
if -1 < value[0] < 256 and -1 < value[1] < 256 and -1 < value[2] < 256:
|
||||
self._current_foreground_colour = Colour._make(list(value) + [self.font_transparency])
|
||||
self.log.debug(f"The font colour is set to {value}.")
|
||||
else: self.log.warning(f"{value} cannot be applied to a foreground colour. The previous value is kept: {self._current_foreground_colour}")
|
||||
else: self.log.warning(f"{value} cannot be applied to a foreground colour. The previous value is kept: {self._current_foreground_colour}")
|
||||
|
||||
@property
|
||||
def background_colour(self):
|
||||
"""
|
||||
Background colour that will be applied to the next printed character.
|
||||
|
||||
The return value is a namedtuple Colour "red green blue alpha".
|
||||
The value can be set using one of the following formats:
|
||||
- namedtuple Colour
|
||||
- tuple (red, green, blue, alpha) (each element is an int in the range of 0 to 255 inclusive)
|
||||
- tuple (red, green, blue) (each element is an int in the range of 0 to 255 inclusive)
|
||||
- string 'default': background default colour
|
||||
- string among the following: 'black', 'red', 'green', 'yellow', 'blue', 'magenta', 'cyan', 'white', 'bright_black', 'bright_red', 'bright_green', 'bright_yellow', 'bright_blue', 'bright_magenta', 'bright_cyan', 'bright_white'
|
||||
if none of these formats is used, the attribute remains unchanged.
|
||||
"""
|
||||
return self._current_background_colour
|
||||
|
||||
@background_colour.setter
|
||||
def background_colour(self, value):
|
||||
if isinstance(value, str):
|
||||
if value in Console.STANDARD_COLOURS:
|
||||
self._current_background_colour = Console.STANDARD_COLOURS[value]._replace(alpha = self.background_transparency)
|
||||
self.log.debug(f"The background colour is set to {value}.")
|
||||
elif value == 'default':
|
||||
self._current_background_colour = self._default_background_colour._replace(alpha = self.background_transparency)
|
||||
self.log.debug(f"The background colour is set to {value}.")
|
||||
elif len(value) == 4:
|
||||
if -1 < value[0] < 256 and -1 < value[1] < 256 and -1 < value[2] < 256 and -1 < value[3] < 256:
|
||||
self._current_background_colour = Colour._make(value)
|
||||
self.background_transparency = value[3]
|
||||
self.log.debug(f"The background colour is set to {value}.")
|
||||
else: self.log.warning(f"{value} cannot be applied to a background colour. The previous value is kept: {self._current_background_colour}")
|
||||
elif len(value) == 3:
|
||||
if -1 < value[0] < 256 and -1 < value[1] < 256 and -1 < value[2] < 256:
|
||||
self._current_background_colour = Colour._make(list(value) + [self.background_transparency])
|
||||
self.log.debug(f"The background colour is set to {value}.")
|
||||
else: self.log.warning(f"{value} cannot be applied to a background colour. The previous value is kept: {self._current_background_colour}")
|
||||
else: self.log.warning(f"{value} cannot be applied to a background colour. The previous value is kept: {self._current_background_colour}")
|
||||
|
||||
@property
|
||||
def font_transparency(self):
|
||||
"""
|
||||
Font transparency, using a value range of 0 (invisible) to 255 (opaque) inclusive.
|
||||
"""
|
||||
return self._font_transparency
|
||||
|
||||
@font_transparency.setter
|
||||
def font_transparency(self, value):
|
||||
try:
|
||||
value_int = int(value)
|
||||
except ValueError:
|
||||
self.log.warning(f"{value} cannot be applied to a transparency value. The default value is kept: {self.Console.DEFAULT_ALPHA}")
|
||||
value_int = Console.DEFAULT_ALPHA
|
||||
finally:
|
||||
self._font_transparency = value_int
|
||||
self.log.debug(f"The font transparency is set to {value_int}.")
|
||||
|
||||
@property
|
||||
def background_transparency(self):
|
||||
"""
|
||||
Background transparency, using a value range of 0 (invisible) to 255 (opaque) inclusive.
|
||||
"""
|
||||
return self._background_transparency
|
||||
|
||||
@background_transparency.setter
|
||||
def background_transparency(self, value):
|
||||
try:
|
||||
value_int = int(value)
|
||||
except ValueError:
|
||||
self.log.warning(f"{value} cannot be applied to a transparency value. The default value is kept: {self.Console.DEFAULT_ALPHA}")
|
||||
value_int = Console.DEFAULT_ALPHA
|
||||
finally:
|
||||
self._background_transparency = value_int
|
||||
self.log.debug(f"The background transparency is set to {value_int}.")
|
||||
|
||||
@property
|
||||
def italic(self):
|
||||
"""
|
||||
Gets or sets whether the font should be rendered in italics.
|
||||
|
||||
If the set value is not a boolean, the attribute remains unchanged.
|
||||
"""
|
||||
return self._italic
|
||||
|
||||
@italic.setter
|
||||
def italic(self, value):
|
||||
if isinstance(value, bool):
|
||||
self._italic = value
|
||||
else: self.log.warning(f"{value} cannot be applied to 'italic' attribute. The previous value is kept: {self._italic}")
|
||||
|
||||
@property
|
||||
def bold(self):
|
||||
"""
|
||||
Gets or sets whether the font should be rendered in bold.
|
||||
|
||||
If the set value is not a boolean, the attribute remains unchanged.
|
||||
"""
|
||||
return self._bold
|
||||
|
||||
@bold.setter
|
||||
def bold(self, value):
|
||||
if isinstance(value, bool):
|
||||
self._bold = value
|
||||
else: self.log.warning(f"{value} cannot be applied to 'bold' attribute. The previous value is kept: {self._bold}")
|
||||
|
||||
@property
|
||||
def underline(self):
|
||||
"""
|
||||
Gets or sets whether the font should be rendered with an underline.
|
||||
|
||||
If the set value is not a boolean, the attribute remains unchanged.
|
||||
"""
|
||||
return self._underline
|
||||
|
||||
@underline.setter
|
||||
def underline(self, value):
|
||||
if isinstance(value, bool):
|
||||
self._underline = value
|
||||
else: self.log.warning(f"{value} cannot be applied to 'underline' attribute. The previous value is kept: {self._underline}")
|
||||
|
||||
@property
|
||||
def memory_size(self):
|
||||
"""
|
||||
Amount of memorized characters.
|
||||
|
||||
If modified, the console is re-initialized, and all memorized characters are lost. Its value must be higher or equal to the amount of displayable characters on the console surface. If not, the set value is ignored, and the attribute remains unchanged.
|
||||
"""
|
||||
return self._char_memory_size
|
||||
|
||||
@memory_size.setter
|
||||
def memory_size(self, value):
|
||||
if value >= self._width * self._height:
|
||||
self._char_memory_size = value
|
||||
# Console re-init
|
||||
self._presentation_stream = deque([None] * self._width * self._height, self._char_memory_size)
|
||||
self._cursor = 0
|
||||
self._start_window = 0
|
||||
self._end_window = self._width * self._height - 1
|
||||
else: self.log.warning(f"Memory cannot be less than {self._width * self._height}. The previous value is kept: {self._char_memory_size}")
|
||||
|
||||
@property
|
||||
def width(self):
|
||||
"""
|
||||
Console width, in characters.
|
||||
|
||||
If modified, the console is re-initialized, and all memorized characters are lost. If the set value is negative or null, it is ignored, and the attribute remains unchanged.
|
||||
"""
|
||||
return self._width
|
||||
|
||||
@width.setter
|
||||
def width(self, value):
|
||||
if value > 0:
|
||||
self._width = value
|
||||
# Console re-init
|
||||
self._presentation_stream = deque([None] * self._width * self._height, self._char_memory_size)
|
||||
self._cursor = 0
|
||||
self._start_window = 0
|
||||
self._end_window = self._width * self._height - 1
|
||||
else: self.log.warning(f"Console width cannot be negative. The previous value is kept: {self._width}")
|
||||
|
||||
@property
|
||||
def height(self):
|
||||
"""
|
||||
Console height, in characters.
|
||||
|
||||
If modified, the console is re-initialized, and all memorized characters are lost. If the set value is negative or null, it is ignored, and the attribute remains unchanged.
|
||||
"""
|
||||
return self._height
|
||||
|
||||
@height.setter
|
||||
def height(self, value):
|
||||
if value > 0:
|
||||
self._height = value
|
||||
# Console re-init
|
||||
self._presentation_stream = deque([None] * self._width * self._height, self._char_memory_size)
|
||||
self._cursor = 0
|
||||
self._start_window = 0
|
||||
self._end_window = self._width * self._height - 1
|
||||
else: self.log.warning(f"Console height cannot be negative. The previous value is kept: {self._height}")
|
||||
|
||||
#############################################################
|
||||
# Public methods
|
||||
|
||||
def add_char(self, char):
|
||||
"""
|
||||
Display one or several characters on the console, at the current cursor position.
|
||||
|
||||
The rendered surface is updated. The cursor moves to the position just after the last character printed. If `char` is empty, nothing is modified, and the cursor remains at the same place. All characters included in `char` share the same caracteristics (foregroung and background colours, italic, bold and underline) from the corresponding attributes.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
char: string
|
||||
Characters that will be displayed.
|
||||
"""
|
||||
if len(char) == 0:
|
||||
self.log.debug("An empty string is displayed: nothing is done.")
|
||||
elif len(char) == 1:
|
||||
self.log.debug(f"Position: {self._cursor} - displayed character: '{char}'")
|
||||
render_all = False
|
||||
|
||||
# Caracteristics of the character
|
||||
char_args = CharArgs()
|
||||
char_args.foreground_colour = self.foreground_colour
|
||||
char_args.background_colour = self.background_colour
|
||||
char_args.italic = self.italic
|
||||
char_args.bold = self.bold
|
||||
char_args.underline = self.underline
|
||||
char_args.str = char
|
||||
|
||||
# Adding a new line in the presentation stream if needed
|
||||
if self._cursor >= len(self._presentation_stream):
|
||||
self._presentation_stream.extend([None] * self.width)
|
||||
# rendered window move
|
||||
self._start_window += self.width
|
||||
self._end_window += self.width
|
||||
# The complete rendered surface must be updated
|
||||
render_all = True
|
||||
|
||||
# Adding character in the presentation stream
|
||||
self._presentation_stream[self._cursor] = char_args
|
||||
|
||||
# Surface rendering
|
||||
if render_all:
|
||||
self._render_all()
|
||||
else:
|
||||
self._render_char(self._cursor)
|
||||
|
||||
# Increasing cursor position
|
||||
self._cursor += 1
|
||||
|
||||
else: # More than 1 character to display
|
||||
self.log.debug(f"Position: {self._cursor} - displayed string: '{char}'")
|
||||
render_all = False
|
||||
list_of_indexes = []
|
||||
for single_char in char:
|
||||
# Caracteristics of the character
|
||||
char_args = CharArgs()
|
||||
char_args.foreground_colour = self.foreground_colour
|
||||
char_args.background_colour = self.background_colour
|
||||
char_args.italic = self.italic
|
||||
char_args.bold = self.bold
|
||||
char_args.underline = self.underline
|
||||
char_args.str = single_char
|
||||
# Adding a new line in the presentation stream if needed
|
||||
if self._cursor >= len(self._presentation_stream):
|
||||
self._presentation_stream.extend([None] * self.width)
|
||||
# rendered window move
|
||||
self._start_window += self.width
|
||||
self._end_window += self.width
|
||||
# The complete rendered surface must be updated
|
||||
render_all = True
|
||||
# Adding character in the presentation stream
|
||||
self._presentation_stream[self._cursor] = char_args
|
||||
# Adding cursor position in the characters list to display
|
||||
list_of_indexes.append(self._cursor)
|
||||
# Increasing cursor position
|
||||
self._cursor += 1
|
||||
# Surface rendering
|
||||
if render_all:
|
||||
self._render_all()
|
||||
else:
|
||||
self._render_chars(list_of_indexes)
|
||||
|
||||
def clear(self, mode = "all"):
|
||||
"""
|
||||
Clear full or part of screen.
|
||||
|
||||
According to the value of `mode`, this function has one of the follwing behaviours:
|
||||
"all" (the default): all character positions of the page are cleared, and the cursor is moved to the upper left position. All memorized characters are lost.
|
||||
"before": the character positions from the beginning of the page up to the cursor are cleared.
|
||||
"after": the cursor position and the character positions up to the end of the page are cleared.
|
||||
"all_without_memory": all character positions of the page are cleared, but cursor position and memorized characters are preserved
|
||||
|
||||
Parameters
|
||||
----------
|
||||
mode: string
|
||||
type of clearing
|
||||
"""
|
||||
if mode == "before":
|
||||
self.log.debug("All characters before the cursor are cleared.")
|
||||
for index_char in range(self._start_window,self._cursor):
|
||||
self._presentation_stream[index_char] = None
|
||||
elif mode == "after":
|
||||
self.log.debug("All characters after the cursor are cleared.")
|
||||
for index_char in range(self._cursor,self._end_window+1):
|
||||
self._presentation_stream[index_char] = None
|
||||
elif mode == "all_without_memory":
|
||||
self.log.debug("All characters of the page are cleared, preserving memorized characters.")
|
||||
for index_char in range(self._start_window,self._end_window+1):
|
||||
self._presentation_stream[index_char] = None
|
||||
else:
|
||||
self.log.debug("Clear full screen and memory.")
|
||||
# Console re-init
|
||||
self._presentation_stream = deque([None] * self._width * self._height, self._char_memory_size)
|
||||
self._cursor = 0
|
||||
self._start_window = 0
|
||||
self._end_window = self._width * self._height - 1
|
||||
|
||||
# Surface rendering
|
||||
self._render_all()
|
||||
|
||||
def scroll(self, nb_lines = 1, up = True):
|
||||
"""
|
||||
Vertical scrolling of the display.
|
||||
|
||||
The rendered characters are moved down or up by `nb_lines`, depending on the value of `up`.
|
||||
|
||||
PARAMETERS
|
||||
----------
|
||||
nb_lines: int, optional
|
||||
number of lines the display is moved of (default is 1).
|
||||
up: bool, optional
|
||||
direction of the move. `True` for moving up (the default), `False` for moving down.
|
||||
"""
|
||||
# Rendered window update
|
||||
if up:
|
||||
if nb_lines == 1:
|
||||
self.log.debug(f"Display moving up of 1 line.")
|
||||
else:
|
||||
self.log.debug(f"Display moving up of {nb_lines} lines.")
|
||||
if self._start_window - self._width * nb_lines < 0:
|
||||
self._start_window = 0
|
||||
else:
|
||||
self._start_window -= self._width * nb_lines
|
||||
self._end_window = self._start_window + self._width * self._height - 1
|
||||
else:
|
||||
if nb_lines == 1:
|
||||
self.log.debug(f"Display moving down of 1 line.")
|
||||
else:
|
||||
self.log.debug(f"Display moving down of {nb_lines} lines.")
|
||||
if self._end_window + self._width * nb_lines > len(self._presentation_stream):
|
||||
self._end_window = len(self._presentation_stream) - 1
|
||||
else:
|
||||
self._end_window += self._width * nb_lines
|
||||
self._start_window = self._end_window - self._width * self._height + 1
|
||||
|
||||
# Surface rendering
|
||||
self._render_all()
|
||||
|
||||
def carriage_return(self):
|
||||
"""
|
||||
Carriage return.
|
||||
|
||||
The cursor is moved to the first position of the current line.
|
||||
"""
|
||||
self.log.debug(f"Carriage return at the line n° {self._cursor // self._width}")
|
||||
self._cursor = (self._cursor // self._width) * self._width
|
||||
|
||||
def line_field(self):
|
||||
"""
|
||||
Line field.
|
||||
|
||||
The cursor is moved to the corresponding character position of the following line.
|
||||
"""
|
||||
self.log.debug(f"Cursor move to the line n° {self._cursor // self._width + 1}")
|
||||
self._cursor += self._width
|
||||
|
||||
#############################################################
|
||||
# Private methods
|
||||
|
||||
def _chartopixcoord(self, index_char = 0):
|
||||
"""
|
||||
Return coordinates of a specific character on the rendered surface.
|
||||
|
||||
This function returns a Coordinates namedtuple object, corresponding to the coordinates of the upper left pixel of the displayed character, on the rendered surface where the upper left pixel is (0,0).
|
||||
Return `None`if the character is out of the rendered surface.
|
||||
|
||||
PARAMETERS
|
||||
----------
|
||||
index_char: int, optional
|
||||
character index in the presentation stream (default is 0).
|
||||
"""
|
||||
if index_char < self._start_window: return None
|
||||
if index_char > self._end_window: return None
|
||||
|
||||
# Calculing column and row
|
||||
column = (index_char - self._start_window) % self._width
|
||||
row = (index_char - self._start_window) // self._width
|
||||
|
||||
# Figuring out character dimensions
|
||||
char_width, char_height = self._normal_font.size(" ") # Works only with fixed-width fonts !
|
||||
|
||||
# Calculing abscissa and ordinate
|
||||
x = column * char_width
|
||||
y = row * char_height
|
||||
|
||||
# Returning calculated coordinates
|
||||
return Coordinates(x, y)
|
||||
|
||||
def _render_char(self, index):
|
||||
"""
|
||||
Update the rendered surface with a specified character.
|
||||
|
||||
The image of the character is drawn onto the rendered surface at the appropriate coordinates, and the rest of the surface remains unchanged.
|
||||
|
||||
PARAMETERS
|
||||
----------
|
||||
index: int
|
||||
character index in the presentation stream.
|
||||
"""
|
||||
coord_char = self._chartopixcoord(index)
|
||||
if self._presentation_stream[index] is None:
|
||||
font_surf = self._normal_font.render(" ", True, self.foreground_colour, self.background_colour)
|
||||
else:
|
||||
if self._presentation_stream[index].bold and self._presentation_stream[index].italic:
|
||||
local_font = self._bolditalic_font
|
||||
elif self._presentation_stream[index].bold and not self._presentation_stream[index].italic:
|
||||
local_font = self._bold_font
|
||||
elif self._presentation_stream[index].italic and not self._presentation_stream[index].bold:
|
||||
local_font = self._italic_font
|
||||
else:
|
||||
local_font = self._normal_font
|
||||
local_font.underline = self._presentation_stream[index].underline
|
||||
font_surf = local_font.render(self._presentation_stream[index].str, True, self._presentation_stream[index].foreground_colour, self._presentation_stream[index].background_colour)
|
||||
|
||||
with self._update_surface_lock:
|
||||
self._current_surface.blit(font_surf,coord_char)
|
||||
# self._current_surface = self._current_surface.convert_alpha()
|
||||
|
||||
self._previous_surface = self._current_surface.copy()
|
||||
|
||||
def _render_chars(self, list_of_indexes):
|
||||
"""
|
||||
Update the rendered surface with several specified characters.
|
||||
|
||||
The images of the characters are drawn onto the rendered surface at the appropriate coordinates, and the rest of the surface remains unchanged.
|
||||
|
||||
PARAMETERS
|
||||
----------
|
||||
list_of_indexes: iterable of integers
|
||||
list of character indexes to be drawn onto the rendered surface
|
||||
"""
|
||||
surf_to_blit = []
|
||||
for index in list_of_indexes:
|
||||
coord_char = self._chartopixcoord(index)
|
||||
if self._presentation_stream[index] is None:
|
||||
font_surf = self._normal_font.render(" ", True, self.foreground_colour, self.background_colour)
|
||||
else:
|
||||
if self._presentation_stream[index].bold and self._presentation_stream[index].italic:
|
||||
local_font = self._bolditalic_font
|
||||
elif self._presentation_stream[index].bold and not self._presentation_stream[index].italic:
|
||||
local_font = self._bold_font
|
||||
elif self._presentation_stream[index].italic and not self._presentation_stream[index].bold:
|
||||
local_font = self._italic_font
|
||||
else:
|
||||
local_font = self._normal_font
|
||||
local_font.underline = self._presentation_stream[index].underline
|
||||
font_surf = local_font.render(self._presentation_stream[index].str, True, self._presentation_stream[index].foreground_colour, self._presentation_stream[index].background_colour)
|
||||
|
||||
surf_to_blit.append((font_surf,coord_char))
|
||||
|
||||
with self._update_surface_lock:
|
||||
self._current_surface.blits(surf_to_blit,doreturn=False)
|
||||
# self._current_surface = self._current_surface.convert_alpha()
|
||||
|
||||
self._previous_surface = self._current_surface.copy()
|
||||
|
||||
def _render_all(self):
|
||||
"""
|
||||
Update the complete rendered surface.
|
||||
"""
|
||||
surf_to_blit = []
|
||||
for index in range(self._start_window, self._end_window + 1):
|
||||
coord_char = self._chartopixcoord(index)
|
||||
if self._presentation_stream[index] is None:
|
||||
font_surf = self._normal_font.render(" ", True, self.foreground_colour, self.background_colour)
|
||||
else:
|
||||
if self._presentation_stream[index].bold and self._presentation_stream[index].italic:
|
||||
local_font = self._bolditalic_font
|
||||
elif self._presentation_stream[index].bold and not self._presentation_stream[index].italic:
|
||||
local_font = self._bold_font
|
||||
elif self._presentation_stream[index].italic and not self._presentation_stream[index].bold:
|
||||
local_font = self._italic_font
|
||||
else:
|
||||
local_font = self._normal_font
|
||||
local_font.underline = self._presentation_stream[index].underline
|
||||
font_surf = local_font.render(self._presentation_stream[index].str, True, self._presentation_stream[index].foreground_colour, self._presentation_stream[index].background_colour)
|
||||
|
||||
surf_to_blit.append((font_surf,coord_char))
|
||||
|
||||
with self._update_surface_lock:
|
||||
self._current_surface.blits(surf_to_blit,doreturn=False)
|
||||
# self._current_surface = self._current_surface.convert_alpha()
|
||||
|
||||
self._previous_surface = self._current_surface.copy()
|
493
pygconsole/io.py
Normal file
493
pygconsole/io.py
Normal file
@@ -0,0 +1,493 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
Module io : I/O interfaces to the terminal emulation provided by the console module.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#------------------
|
||||
import logging
|
||||
import io
|
||||
import codecs
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
from pygconsole.console import Console as Console
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
class RawIOConsole(io.RawIOBase):
|
||||
"""
|
||||
RawIOConsole class provides the lower-level binary access to an underlying Console object, without buffering. It inherits io.RawIOBase. For further details about inherited elements, see https://docs.python.org/3/library/io.html . In normal cases, RawIOConsole objects do not have to be used directly to write characters on the console (use TextIOConsoleWrapper objects instead).
|
||||
|
||||
Attributes
|
||||
----------
|
||||
console: pygconsole.console.Console object
|
||||
Underlying Console object associated to this API.
|
||||
log : logging.logger object
|
||||
logger used to track events that append when the instance is running (default is None).
|
||||
|
||||
Inherited attributes remain unchanged.
|
||||
|
||||
Overriden methods
|
||||
-----------------
|
||||
isatty()
|
||||
As the stream is not interactive, return always `False` in the current implementation of the RawIOConsole class.
|
||||
readable()
|
||||
As the stream cannot be read from, return always `False` in the current implementation of the RawIOConsole class.
|
||||
seekable()
|
||||
As the stream does not support random access, return always `False` in the current implementation of the RawIOConsole class.
|
||||
writable()
|
||||
As the stream supports writing, return always `True` in the current implementation of the RawIOConsole class.
|
||||
write(bytes_str)
|
||||
Write the given bytes-like object `bytes_str` to the underlying console, and return the number of bytes written.
|
||||
|
||||
Other inherited methods remain unchanged.
|
||||
"""
|
||||
#############################################################
|
||||
# Class constants
|
||||
|
||||
# ECMA-48 standard implementation (aka 'ANSI escape codes')
|
||||
# C0 control code set
|
||||
CTRL_RANGE = range(0x1f+1) # Range of possible values for the C0 control byte
|
||||
SUPPORTED_C0_CTRL = {
|
||||
0x0a: 'LF', # LINE FIELD
|
||||
0x0d: 'CR', # CARRIAGE RETURN
|
||||
0x1b: 'ESC' # ESCAPE
|
||||
}
|
||||
# C1 control code set
|
||||
Fe_RANGE = range(0x40,0x5f+1) # Range of possible values for the Fe byte (byte following ESC in a C1 control code)
|
||||
SUPPORTED_C1_CTRL = {
|
||||
0x5b: 'CSI' # '[' : CONTROL SEQUENCE INTRODUCER
|
||||
}
|
||||
# Control sequences
|
||||
FINAL_RANGE = range(0x40,0x7e+1) # Range of possibles values for the final byte in control sequences
|
||||
SUPPORTED_FINAL_CTRL = {
|
||||
0x4a: 'ED', # 'J' : Erase in Display (Erase in Page in ECMA-48 standard): CSI n J (n=0:clear from cursor to end of screen,n=1:clear from cursor to beginning of the screen,n=2:clear entire screen,n=3:clear entire screen and delete all lines saved in the scrollback buffer (not part of the ECMA-48 standard, but introduced for xterm and supported now by all terminal applications))
|
||||
0x53: 'SU', # 'S' : Scroll Up: CSI n S (n = nb of lines). New lines are added at the bottom.
|
||||
0x54: 'SD', # 'T': Scroll Down CSI n T (n = nb of lines). New lines are added at the top.
|
||||
0x6d: 'SGR' # 'm': Select Graphic Rendition: CSI n m (n = colour or style identifiers - see below)
|
||||
}
|
||||
# SGR parameters
|
||||
SEPARATORS = ";:" # Possible separators between parameters
|
||||
SUPPORTED_SGR_PARAMETERS = {
|
||||
'0': 'reset', # default rendition, cancels the effect of any preceding occurrence of SGR
|
||||
'1': 'bold', # bold characters
|
||||
'3': 'italic', # italicized characters
|
||||
'4': 'underline', # singly underlined characters
|
||||
'7': 'negative', # negative image, swaps foreground and background colours
|
||||
'22': 'not_bold', # normal intensity characters (not bold)
|
||||
'23': 'not_italic', # not italicized characters
|
||||
'24': 'not_underline', # not underlined characters
|
||||
'27': 'positive' # positive image, colours are no more reversed
|
||||
}
|
||||
STANDARD_FOREGROUND_COLOURS = {
|
||||
'30': 'black',
|
||||
'31': 'red',
|
||||
'32': 'green',
|
||||
'33': 'yellow',
|
||||
'34': 'blue',
|
||||
'35': 'magenta',
|
||||
'36': 'cyan',
|
||||
'37': 'white',
|
||||
'90': 'bright_black', # grey
|
||||
'91': 'bright_red',
|
||||
'92': 'bright_green',
|
||||
'93': 'bright_yellow',
|
||||
'94': 'bright_blue',
|
||||
'95': 'bright_magenta',
|
||||
'96': 'bright_cyan',
|
||||
'97': 'bright_white'
|
||||
}
|
||||
STANDARD_BACKGROUND_COLOURS = {
|
||||
'40': 'black',
|
||||
'41': 'red',
|
||||
'42': 'green',
|
||||
'43': 'yellow',
|
||||
'44': 'blue',
|
||||
'45': 'magenta',
|
||||
'46': 'cyan',
|
||||
'47': 'white',
|
||||
'100': 'bright_black', # grey
|
||||
'101': 'bright_red',
|
||||
'102': 'bright_green',
|
||||
'103': 'bright_yellow',
|
||||
'104': 'bright_blue',
|
||||
'105': 'bright_magenta',
|
||||
'106': 'bright_cyan',
|
||||
'107': 'bright_white'
|
||||
}
|
||||
BRIGHT_SHIFT = 60 # shift between normal and bright colours
|
||||
|
||||
#############################################################
|
||||
# Initialization
|
||||
|
||||
def __init__(self, console_name = "pygame_console", logger = None):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
console_name: str
|
||||
Name of theuUnderlying pygconsole.console.Console object associated to this API (default is "pygame_console")
|
||||
logger: logging.Logger object, optional
|
||||
The parent logger used to track events that append when the instance is running. Mainly for status monitoring or fault investigation purposes. If None (the default), no event is tracked.
|
||||
"""
|
||||
|
||||
|
||||
if logger is None:
|
||||
handler = logging.NullHandler()
|
||||
self.log = logging.getLogger('RawIOConsole')
|
||||
self.log.addHandler(handler)
|
||||
else:
|
||||
self.log = logger.getChild('RawIOConsole')
|
||||
|
||||
self._console = Console.get_console(console_name, logger = self.log)
|
||||
self._byte_esc_seq = bytearray() # undecoded escape sequence
|
||||
self._byte_displaying_char = bytearray() # undecoded displayable characters
|
||||
|
||||
|
||||
#############################################################
|
||||
# Public attributes
|
||||
|
||||
@property
|
||||
def console(self):
|
||||
"""
|
||||
Underlying pygconsole.console.Console object associated to this API.
|
||||
|
||||
If the set value is not a Console object, the attribute remains silently unchanged.
|
||||
"""
|
||||
return self._console
|
||||
|
||||
@console.setter
|
||||
def console(self, value):
|
||||
if isinstance(value, Console):
|
||||
self._console = value
|
||||
else:
|
||||
self.log.warning(f"{value} is not a Console object. The previous value is kept: {self.console}")
|
||||
pass
|
||||
|
||||
|
||||
#############################################################
|
||||
# Public methods
|
||||
|
||||
def isatty(self):
|
||||
"""
|
||||
Return True if the stream is interactive (i.e., connected to a terminal/tty device).
|
||||
"""
|
||||
return False
|
||||
|
||||
def readable(self):
|
||||
"""
|
||||
Return True if the stream can be read from. If False, read() will raise OSError.
|
||||
"""
|
||||
return False
|
||||
|
||||
def seekable(self):
|
||||
"""
|
||||
Return True if the stream supports random access. If False, seek(), tell() and truncate() will raise OSError.
|
||||
"""
|
||||
return False
|
||||
|
||||
def writable(self):
|
||||
"""
|
||||
Return True if the stream supports writing. If False, write() and truncate() will raise OSError.
|
||||
"""
|
||||
return True
|
||||
|
||||
def write(self, bytestream):
|
||||
"""
|
||||
Write the given bytes-like object, bytestream, to the underlying console, and return the number of bytes written.
|
||||
|
||||
Only encoded utf-8 characters in bytestream are accepted. If a decoding error occurs, then only bytes before the undecoded byte are taken into account. The supported escape sequences are translated.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
bytestream: bytes, bytearray or memoryview object
|
||||
bytes sequence, that is, succession of positive integers less or equal to 255
|
||||
"""
|
||||
# bytestream translation into bytearray object
|
||||
byte_sequence = bytearray(bytestream)
|
||||
|
||||
# utf-8 check
|
||||
try:
|
||||
codecs.decode(byte_sequence,encoding='utf-8',errors='strict')
|
||||
except UnicodeDecodeError as err:
|
||||
byte_sequence = byte_sequence[:err.start]
|
||||
finally:
|
||||
nb_decoded_bytes = len(byte_sequence)
|
||||
|
||||
# byte treatment
|
||||
for byte in byte_sequence:
|
||||
if len(self._byte_esc_seq) > 0: # proceeding escape sequence
|
||||
self._byte_esc_seq.append(byte)
|
||||
decoded_esc_seq = self._esc_seq_decode(self._byte_esc_seq)
|
||||
if decoded_esc_seq == 'error':
|
||||
self.log.warning(f"The following escape sequence encountered an error: {list(self._byte_esc_seq)}")
|
||||
self._byte_esc_seq = bytearray()
|
||||
elif decoded_esc_seq == 'successful':
|
||||
self.log.debug(f"The follwing escape sequence was treated successfully: {list(self._byte_esc_seq)}")
|
||||
self._byte_esc_seq = bytearray()
|
||||
elif decoded_esc_seq == 'incomplete':
|
||||
pass
|
||||
elif byte in RawIOConsole.CTRL_RANGE: # Beginning of an escape sequence
|
||||
if len(self._byte_displaying_char) > 0:
|
||||
self.console.add_char(self._byte_displaying_char.decode(encoding='utf-8'))
|
||||
self._byte_displaying_char = bytearray()
|
||||
self._byte_esc_seq.append(byte)
|
||||
# 1-byte escape sequence
|
||||
decoded_esc_seq = self._esc_seq_decode(self._byte_esc_seq)
|
||||
if decoded_esc_seq == 'error':
|
||||
self.log.warning(f"The following escape sequence encountered an error: {list(self._byte_esc_seq)}")
|
||||
self._byte_esc_seq = bytearray()
|
||||
elif decoded_esc_seq == 'successful':
|
||||
self.log.debug(f"The follwing escape sequence was treated successfully: {list(self._byte_esc_seq)}")
|
||||
self._byte_esc_seq = bytearray()
|
||||
elif decoded_esc_seq == 'incomplete':
|
||||
pass
|
||||
else: # Displayable character (or part of)
|
||||
self._byte_displaying_char.append(byte)
|
||||
|
||||
# Final treatment of displayable characters
|
||||
if len(self._byte_displaying_char) > 0:
|
||||
self.console.add_char(self._byte_displaying_char.decode(encoding='utf-8'))
|
||||
self._byte_displaying_char = bytearray()
|
||||
|
||||
return nb_decoded_bytes
|
||||
|
||||
|
||||
#############################################################
|
||||
# Private methods
|
||||
|
||||
def _esc_seq_decode(self, sequence):
|
||||
"""
|
||||
Decode an escape sequence conforming to ECMA-48 standard (ANSI escape codes).
|
||||
|
||||
Supported commands are sent to the console. Return 'successful' if the sequence is supported and successfully proceeded, 'error' if an error is encountered, or 'incomplete' if the sequence is recognized as the beginning of a supported sequence, but not yet complete.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
sequence: bytearray
|
||||
Escape sequence encoded using utf-8 codec
|
||||
"""
|
||||
if len(sequence) == 0:
|
||||
return 'incomplete'
|
||||
elif sequence[0] in RawIOConsole.CTRL_RANGE:
|
||||
if sequence[0] in RawIOConsole.SUPPORTED_C0_CTRL:
|
||||
if RawIOConsole.SUPPORTED_C0_CTRL[sequence[0]] == 'ESC': # Beginning of the escape sequence
|
||||
if len(sequence) > 1:
|
||||
if sequence[1] in RawIOConsole.Fe_RANGE:
|
||||
if sequence[1] in RawIOConsole.SUPPORTED_C1_CTRL:
|
||||
if RawIOConsole.SUPPORTED_C1_CTRL[sequence[1]] == 'CSI': # CONTROL SEQUENCE INTRODUCER
|
||||
if len(sequence) > 2:
|
||||
if sequence[-1] in RawIOConsole.FINAL_RANGE:
|
||||
if sequence[-1] in RawIOConsole.SUPPORTED_FINAL_CTRL:
|
||||
if RawIOConsole.SUPPORTED_FINAL_CTRL[sequence[-1]] == 'ED': # Erase in Display
|
||||
try:
|
||||
mode = int(sequence[2:len(sequence)-1].decode(encoding='utf-8'))
|
||||
except ValueError:
|
||||
mode = 3
|
||||
finally:
|
||||
if mode == 0:
|
||||
self.console.clear("after")
|
||||
return 'successful'
|
||||
elif mode == 1:
|
||||
self.console.clear("before")
|
||||
return 'successful'
|
||||
elif mode == 2:
|
||||
self.console.clear("all_without_memory")
|
||||
return 'successful'
|
||||
elif mode == 3:
|
||||
self.console.clear()
|
||||
return 'successful'
|
||||
else:
|
||||
return 'error'
|
||||
elif RawIOConsole.SUPPORTED_FINAL_CTRL[sequence[-1]] == 'SU': # Scroll Up
|
||||
try:
|
||||
nb_lines = int(sequence[2:len(sequence)-1].decode(encoding='utf-8'))
|
||||
except ValueError:
|
||||
nb_lines = 1
|
||||
finally:
|
||||
self.console.scroll(nb_lines, True)
|
||||
return 'successful'
|
||||
elif RawIOConsole.SUPPORTED_FINAL_CTRL[sequence[-1]] == 'SD': # Scroll Down
|
||||
try:
|
||||
nb_lines = int(sequence[2:len(sequence)-1].decode(encoding='utf-8'))
|
||||
except ValueError:
|
||||
nb_lines = 1
|
||||
finally:
|
||||
self.console.scroll(nb_lines, False)
|
||||
return 'successful'
|
||||
elif RawIOConsole.SUPPORTED_FINAL_CTRL[sequence[-1]] == 'SGR': # Select Graphic Rendition
|
||||
# All separators are replaced by the same character
|
||||
sep = RawIOConsole.SEPARATORS[0]
|
||||
formatted_sequence = sequence[2:len(sequence)-1].decode(encoding='utf-8')
|
||||
for any_sep in RawIOConsole.SEPARATORS:
|
||||
formatted_sequence = formatted_sequence.replace(any_sep,sep)
|
||||
|
||||
# All parameters in a list
|
||||
seq_list = formatted_sequence.split(sep)
|
||||
|
||||
# Empty list: equivalent to '0'
|
||||
if len(seq_list) == 0: seq_list = ['0']
|
||||
|
||||
# Processing of each parameter
|
||||
for param in seq_list:
|
||||
if param in RawIOConsole.SUPPORTED_SGR_PARAMETERS:
|
||||
if RawIOConsole.SUPPORTED_SGR_PARAMETERS[param] == 'reset':
|
||||
self.console.bold = False
|
||||
self.console.italic = False
|
||||
self.console.underline = False
|
||||
self.console.foreground_colour = 'default'
|
||||
self.console.background_colour = 'default'
|
||||
elif RawIOConsole.SUPPORTED_SGR_PARAMETERS[param] == 'bold':
|
||||
self.console.bold = True
|
||||
elif RawIOConsole.SUPPORTED_SGR_PARAMETERS[param] == 'italic':
|
||||
self.console.italic = True
|
||||
elif RawIOConsole.SUPPORTED_SGR_PARAMETERS[param] == 'underline':
|
||||
self.console.underline = True
|
||||
elif RawIOConsole.SUPPORTED_SGR_PARAMETERS[param] == 'negative':
|
||||
temp_colour = self.console.foreground_colour
|
||||
self.console.foreground_colour = self.console.background_colour
|
||||
self.console.background_colour = temp_colour
|
||||
elif RawIOConsole.SUPPORTED_SGR_PARAMETERS[param] == 'not_bold':
|
||||
self.console.bold = False
|
||||
elif RawIOConsole.SUPPORTED_SGR_PARAMETERS[param] == 'not_italic':
|
||||
self.console.italic = False
|
||||
elif RawIOConsole.SUPPORTED_SGR_PARAMETERS[param] == 'not_underline':
|
||||
self.console.underline = False
|
||||
elif RawIOConsole.SUPPORTED_SGR_PARAMETERS[param] == 'positive':
|
||||
temp_colour = self.console.foreground_colour
|
||||
self.console.foreground_colour = self.console.background_colour
|
||||
self.console.background_colour = temp_colour
|
||||
else: # SGR parameter supported but not (yet) treated
|
||||
pass
|
||||
elif param in RawIOConsole.STANDARD_FOREGROUND_COLOURS:
|
||||
self.console.foreground_colour = RawIOConsole.STANDARD_FOREGROUND_COLOURS[param]
|
||||
elif param in RawIOConsole.STANDARD_BACKGROUND_COLOURS:
|
||||
self.console.background_colour = RawIOConsole.STANDARD_BACKGROUND_COLOURS[param]
|
||||
else: # valid but not supported SGR parameter
|
||||
pass
|
||||
return 'successful'
|
||||
else: # Final byte supported but not (yet) treated
|
||||
return 'error'
|
||||
else: # Valid but not supported final byte
|
||||
return 'error'
|
||||
else: # Invalid final byte
|
||||
return 'incomplete'
|
||||
else: # incomplete control sequence
|
||||
return 'incomplete'
|
||||
else: # C1 control byte supported but not (yet) treated
|
||||
return 'error'
|
||||
else: # Valid but not supported C1 control byte
|
||||
return 'error'
|
||||
else: # Escape sequence not recognized
|
||||
return 'error'
|
||||
else: # Incomplete escape sequence
|
||||
return 'incomplete'
|
||||
elif RawIOConsole.SUPPORTED_C0_CTRL[sequence[0]] == 'LF': # Line Field (cursor moves to the following line)
|
||||
self.console.line_field()
|
||||
return 'successful'
|
||||
elif RawIOConsole.SUPPORTED_C0_CTRL[sequence[0]] == 'CR': # Carriage Return (cursor moves to the beginning of the current line)
|
||||
self.console.carriage_return()
|
||||
return 'successful'
|
||||
else: # C0 control byte supported but not (yet) treated
|
||||
return 'error'
|
||||
else: # Valid bu not supported C0 control byte
|
||||
return 'error'
|
||||
else: # Invalid C0 control byte
|
||||
return 'error'
|
||||
|
||||
class BufferedIOConsole(io.BufferedWriter):
|
||||
"""
|
||||
BufferedIOConsole class provides the mid-level binary access to an underlying Console object, with buffering. It inherits io.BufferedWriter. For further details about inherited elements, see https://docs.python.org/3/library/io.html . In normal cases (except if the direct usage of binary sequences is required), BufferedIOConsole objects do not have to be used directly to write characters on the console (use TextIOConsoleWrapper objects instead).
|
||||
|
||||
Attributes
|
||||
----------
|
||||
console: pygconsole.console.Console object
|
||||
Underlying Console object associated to this API.
|
||||
|
||||
Methods
|
||||
-------
|
||||
All inherited methods remain unchanged. No new method added.
|
||||
|
||||
"""
|
||||
|
||||
#############################################################
|
||||
# Initialization
|
||||
|
||||
def __init__(self, console_name = "pygame_console"):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
console_name: str
|
||||
Name of theuUnderlying pygconsole.console.Console object associated to this API (default is "pygame_console")
|
||||
"""
|
||||
raw = RawIOConsole(console_name)
|
||||
super().__init__(raw = raw)
|
||||
|
||||
#############################################################
|
||||
# Public attributes
|
||||
|
||||
@property
|
||||
def console(self):
|
||||
"""
|
||||
Underlying pygconsole.console.Console object associated to this API.
|
||||
|
||||
If the set value is not a Console object, the attribute remains silently unchanged.
|
||||
"""
|
||||
return self.raw.console
|
||||
|
||||
@console.setter
|
||||
def console(self, value):
|
||||
if isinstance(value, Console):
|
||||
self.raw.console = value
|
||||
else:
|
||||
pass
|
||||
|
||||
class TextIOConsoleWrapper(io.TextIOWrapper):
|
||||
"""
|
||||
A buffered text stream providing higher-level access to a BufferedIOConsole buffered binary stream. It inherits io.TextIOWrapper. For further details about inherited elements, see https://docs.python.org/3/library/io.html . This class is generally used directly to write characters on the console, by objects using I/O streams (like `print()`).
|
||||
|
||||
Attributes
|
||||
----------
|
||||
All inherited attributes remain unchanged. No new attribute added.
|
||||
|
||||
Methods
|
||||
-------
|
||||
All inherited methods remain unchanged. No new method added.
|
||||
"""
|
||||
|
||||
#############################################################
|
||||
# Initialisation
|
||||
|
||||
def __init__(self, console_name = "pygame_console", errors=None, newline=None, line_buffering=False, write_through=False):
|
||||
"""
|
||||
Parameters
|
||||
----------
|
||||
console_name: str
|
||||
Name of theuUnderlying pygconsole.console.Console object associated to this API (default is "pygame_console")
|
||||
error: str
|
||||
optional string that specifies how encoding and decoding errors are to be handled.
|
||||
newline: str
|
||||
controls how line endings are handled. It can be None, '', '\n', '\r', and '\r\n'.
|
||||
line_buffering: bool
|
||||
If True, flush() is implied when a call to write contains a newline character or a carriage return. Default is False.
|
||||
write_through: bool
|
||||
If True, calls to write() are guaranteed not to be buffered. Default is False.
|
||||
"""
|
||||
buffer = BufferedIOConsole(console_name)
|
||||
# To be compliant with RawIOConsole, encoding must be utf-8.
|
||||
encoding = 'utf-8'
|
||||
super().__init__(buffer, encoding, errors, newline, line_buffering, write_through)
|
57
pygconsole/resources/fonts/DejaVu/AUTHORS
Normal file
57
pygconsole/resources/fonts/DejaVu/AUTHORS
Normal file
@@ -0,0 +1,57 @@
|
||||
abysta at yandex.ru
|
||||
Adrian Schroeter
|
||||
Aleksey Chalabyan
|
||||
Andrey Valentinovich Panov
|
||||
Ben Laenen
|
||||
Besarion Gugushvili
|
||||
Bhikkhu Pesala
|
||||
Clayborne Arevalo
|
||||
Dafydd Harries
|
||||
Danilo Segan
|
||||
Davide Viti
|
||||
David Jez
|
||||
David Lawrence Ramsey
|
||||
Denis Jacquerye
|
||||
Dwayne Bailey
|
||||
Eugeniy Meshcheryakov
|
||||
Frédéric Wang
|
||||
Gee Fung Sit
|
||||
Heikki Lindroos
|
||||
James Cloos
|
||||
James Crippen
|
||||
John Karp
|
||||
Keenan Pepper
|
||||
Lars Næsbye Christensen
|
||||
Lior Halphon
|
||||
MaEr
|
||||
Mashrab Kuvatov
|
||||
Max Berger
|
||||
Mederic Boquien
|
||||
Michael Everson
|
||||
MihailJP
|
||||
Misu Moldovan
|
||||
Nguyen Thai Ngoc Duy
|
||||
Nicolas Mailhot
|
||||
Norayr Chilingarian
|
||||
Olleg Samoylov
|
||||
Ognyan Kulev
|
||||
Ondrej Koala Vacha
|
||||
Peter Cernak
|
||||
Remy Oudompheng
|
||||
Roozbeh Pournader
|
||||
Rouben Hakobian
|
||||
Sahak Petrosyan
|
||||
Sami Tarazi
|
||||
Sander Vesik
|
||||
Stepan Roh
|
||||
Stephen Hartke
|
||||
Steve Tinney
|
||||
Tavmjong Bah
|
||||
Thomas Henlich
|
||||
Tim May
|
||||
Valentin Stoykov
|
||||
Vasek Stodulka
|
||||
Wesley Transue
|
||||
Yoshiki Ohshima
|
||||
|
||||
$Id$
|
BIN
pygconsole/resources/fonts/DejaVu/DejaVuSansMono-Bold.ttf
Normal file
BIN
pygconsole/resources/fonts/DejaVu/DejaVuSansMono-Bold.ttf
Normal file
Binary file not shown.
BIN
pygconsole/resources/fonts/DejaVu/DejaVuSansMono-BoldOblique.ttf
Normal file
BIN
pygconsole/resources/fonts/DejaVu/DejaVuSansMono-BoldOblique.ttf
Normal file
Binary file not shown.
BIN
pygconsole/resources/fonts/DejaVu/DejaVuSansMono-Oblique.ttf
Normal file
BIN
pygconsole/resources/fonts/DejaVu/DejaVuSansMono-Oblique.ttf
Normal file
Binary file not shown.
BIN
pygconsole/resources/fonts/DejaVu/DejaVuSansMono.ttf
Normal file
BIN
pygconsole/resources/fonts/DejaVu/DejaVuSansMono.ttf
Normal file
Binary file not shown.
187
pygconsole/resources/fonts/DejaVu/LICENSE
Normal file
187
pygconsole/resources/fonts/DejaVu/LICENSE
Normal file
@@ -0,0 +1,187 @@
|
||||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||
Glyphs imported from Arev fonts are (c) Tavmjong Bah (see below)
|
||||
|
||||
|
||||
Bitstream Vera Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera is
|
||||
a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of the fonts accompanying this license ("Fonts") and associated
|
||||
documentation files (the "Font Software"), to reproduce and distribute the
|
||||
Font Software, including without limitation the rights to use, copy, merge,
|
||||
publish, distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to the
|
||||
following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice shall
|
||||
be included in all copies of one or more of the Font Software typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in particular
|
||||
the designs of glyphs or characters in the Fonts may be modified and
|
||||
additional glyphs or characters may be added to the Fonts, only if the fonts
|
||||
are renamed to names not containing either the words "Bitstream" or the word
|
||||
"Vera".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts or Font
|
||||
Software that has been modified and is distributed under the "Bitstream
|
||||
Vera" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but no
|
||||
copy of one or more of the Font Software typefaces may be sold by itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
|
||||
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
|
||||
FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING
|
||||
ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES,
|
||||
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
|
||||
THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE
|
||||
FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the names of Gnome, the Gnome
|
||||
Foundation, and Bitstream Inc., shall not be used in advertising or
|
||||
otherwise to promote the sale, use or other dealings in this Font Software
|
||||
without prior written authorization from the Gnome Foundation or Bitstream
|
||||
Inc., respectively. For further information, contact: fonts at gnome dot
|
||||
org.
|
||||
|
||||
Arev Fonts Copyright
|
||||
------------------------------
|
||||
|
||||
Copyright (c) 2006 by Tavmjong Bah. All Rights Reserved.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of the fonts accompanying this license ("Fonts") and
|
||||
associated documentation files (the "Font Software"), to reproduce
|
||||
and distribute the modifications to the Bitstream Vera Font Software,
|
||||
including without limitation the rights to use, copy, merge, publish,
|
||||
distribute, and/or sell copies of the Font Software, and to permit
|
||||
persons to whom the Font Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be included in all copies of one or more of the Font Software
|
||||
typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in
|
||||
particular the designs of glyphs or characters in the Fonts may be
|
||||
modified and additional glyphs or characters may be added to the
|
||||
Fonts, only if the fonts are renamed to names not containing either
|
||||
the words "Tavmjong Bah" or the word "Arev".
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts
|
||||
or Font Software that has been modified and is distributed under the
|
||||
"Tavmjong Bah Arev" names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy of one or more of the Font Software typefaces may be sold by
|
||||
itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
|
||||
OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
|
||||
TAVMJONG BAH BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
|
||||
INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
|
||||
DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
|
||||
OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
|
||||
Except as contained in this notice, the name of Tavmjong Bah shall not
|
||||
be used in advertising or otherwise to promote the sale, use or other
|
||||
dealings in this Font Software without prior written authorization
|
||||
from Tavmjong Bah. For further information, contact: tavmjong @ free
|
||||
. fr.
|
||||
|
||||
TeX Gyre DJV Math
|
||||
-----------------
|
||||
Fonts are (c) Bitstream (see below). DejaVu changes are in public domain.
|
||||
|
||||
Math extensions done by B. Jackowski, P. Strzelczyk and P. Pianowski
|
||||
(on behalf of TeX users groups) are in public domain.
|
||||
|
||||
Letters imported from Euler Fraktur from AMSfonts are (c) American
|
||||
Mathematical Society (see below).
|
||||
Bitstream Vera Fonts Copyright
|
||||
Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream Vera
|
||||
is a trademark of Bitstream, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of the fonts accompanying this license (“Fonts”) and associated
|
||||
documentation
|
||||
files (the “Font Software”), to reproduce and distribute the Font Software,
|
||||
including without limitation the rights to use, copy, merge, publish,
|
||||
distribute,
|
||||
and/or sell copies of the Font Software, and to permit persons to whom
|
||||
the Font Software is furnished to do so, subject to the following
|
||||
conditions:
|
||||
|
||||
The above copyright and trademark notices and this permission notice
|
||||
shall be
|
||||
included in all copies of one or more of the Font Software typefaces.
|
||||
|
||||
The Font Software may be modified, altered, or added to, and in particular
|
||||
the designs of glyphs or characters in the Fonts may be modified and
|
||||
additional
|
||||
glyphs or characters may be added to the Fonts, only if the fonts are
|
||||
renamed
|
||||
to names not containing either the words “Bitstream” or the word “Vera”.
|
||||
|
||||
This License becomes null and void to the extent applicable to Fonts or
|
||||
Font Software
|
||||
that has been modified and is distributed under the “Bitstream Vera”
|
||||
names.
|
||||
|
||||
The Font Software may be sold as part of a larger software package but
|
||||
no copy
|
||||
of one or more of the Font Software typefaces may be sold by itself.
|
||||
|
||||
THE FONT SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT OF COPYRIGHT, PATENT,
|
||||
TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL BITSTREAM OR THE GNOME
|
||||
FOUNDATION
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, INCLUDING ANY GENERAL,
|
||||
SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, WHETHER IN AN
|
||||
ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF THE USE OR
|
||||
INABILITY TO USE
|
||||
THE FONT SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
|
||||
Except as contained in this notice, the names of GNOME, the GNOME
|
||||
Foundation,
|
||||
and Bitstream Inc., shall not be used in advertising or otherwise to promote
|
||||
the sale, use or other dealings in this Font Software without prior written
|
||||
authorization from the GNOME Foundation or Bitstream Inc., respectively.
|
||||
For further information, contact: fonts at gnome dot org.
|
||||
|
||||
AMSFonts (v. 2.2) copyright
|
||||
|
||||
The PostScript Type 1 implementation of the AMSFonts produced by and
|
||||
previously distributed by Blue Sky Research and Y&Y, Inc. are now freely
|
||||
available for general use. This has been accomplished through the
|
||||
cooperation
|
||||
of a consortium of scientific publishers with Blue Sky Research and Y&Y.
|
||||
Members of this consortium include:
|
||||
|
||||
Elsevier Science IBM Corporation Society for Industrial and Applied
|
||||
Mathematics (SIAM) Springer-Verlag American Mathematical Society (AMS)
|
||||
|
||||
In order to assure the authenticity of these fonts, copyright will be
|
||||
held by
|
||||
the American Mathematical Society. This is not meant to restrict in any way
|
||||
the legitimate use of the fonts, such as (but not limited to) electronic
|
||||
distribution of documents containing these fonts, inclusion of these fonts
|
||||
into other public domain or commercial font collections or computer
|
||||
applications, use of the outline data to create derivative fonts and/or
|
||||
faces, etc. However, the AMS does require that the AMS copyright notice be
|
||||
removed from any derivative versions of the fonts which have been altered in
|
||||
any way. In addition, to ensure the fidelity of TeX documents using Computer
|
||||
Modern fonts, Professor Donald Knuth, creator of the Computer Modern faces,
|
||||
has requested that any alterations which yield different font metrics be
|
||||
given a different name.
|
||||
|
||||
$Id$
|
3
pyproject.toml
Normal file
3
pyproject.toml
Normal file
@@ -0,0 +1,3 @@
|
||||
[build-system]
|
||||
requires = ["setuptools"]
|
||||
build-backend = "setuptools.build_meta"
|
39
setup.cfg
Normal file
39
setup.cfg
Normal file
@@ -0,0 +1,39 @@
|
||||
[metadata]
|
||||
name = pygconsole
|
||||
version = attr: pygconsole.__VERSION__
|
||||
author = devfred78
|
||||
author_email = devfred78@gmail.com
|
||||
description = ANSI terminal emulation for Pygame
|
||||
long_description = file: README.md
|
||||
long_decription_content_type = text/markdown
|
||||
url = https://github.com/devfred78/pygconsole
|
||||
project_urls =
|
||||
Bug Tracker = https://github.com/devfred78/pygconsole/issues
|
||||
Sources = https://github.com/devfred78/pygconsole
|
||||
classifiers =
|
||||
Development Status :: 3 - Alpha
|
||||
Intended Audience :: Developers
|
||||
Programming Language :: Python :: 3
|
||||
Programming Language :: Python :: 3.8
|
||||
Programming Language :: Python :: 3.9
|
||||
Programming Language :: Python :: 3.10
|
||||
License :: OSI Approved :: MIT License
|
||||
Operating System :: OS Independent
|
||||
Topic :: Software Development :: Libraries :: Python Modules
|
||||
Topic :: Terminals
|
||||
|
||||
[options]
|
||||
package_dir =
|
||||
pygconsole = pygconsole
|
||||
packages = pygconsole
|
||||
install_requires =
|
||||
pygame >= 2.1.0
|
||||
colorlog >= 6.4.1
|
||||
python_requires = >= 3.8
|
||||
|
||||
[options.packages.find]
|
||||
where = pygconsole
|
||||
include = pygconsole
|
||||
|
||||
[options.package_data]
|
||||
pygconsole = resources/fonts/DejaVu/*
|
7
tests/resources/LICENCES.txt
Normal file
7
tests/resources/LICENCES.txt
Normal file
@@ -0,0 +1,7 @@
|
||||
Background image
|
||||
----------------
|
||||
Licence: Free
|
||||
https://www.pexels.com/fr-fr/photo/paysage-nature-ciel-sable-8092914/
|
||||
Location: Oljato-Monument Valley, United States
|
||||
Date: 13th May 2014
|
||||
Photographer: Karl MPhotography
|
BIN
tests/resources/background.jpg
Normal file
BIN
tests/resources/background.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 469 KiB |
140
tests/test0.py
Normal file
140
tests/test0.py
Normal file
@@ -0,0 +1,140 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 0 : import pygconsole module and display a blank console (with default parameters)
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 0: display a blank console with default parameters.",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
142
tests/test1.py
Normal file
142
tests/test1.py
Normal file
@@ -0,0 +1,142 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 1 : import pygconsole module and display a console with `Hello world !` written (with default parameters)
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 1: display a console with default parameters.",
|
||||
"press 'A' to write `Hello world !` at the cursor position.",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a: console.add_char("Hello world !")
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
161
tests/test10.py
Normal file
161
tests/test10.py
Normal file
@@ -0,0 +1,161 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 10 : Write a long text on the console with normal characters colorized randomly (foreground / background).
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
import random
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 10 : Write a long text on the console with normal characters colorized randomly",
|
||||
"(foreground / background).",
|
||||
"Press 'A' to write the 'Lorem ipsum' text",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae nunc dictum, sagittis elit venenatis, efficitur justo. Etiam suscipit, ipsum accumsan aliquam elementum, massa tellus pellentesque lacus, ut porttitor ligula tortor at urna. Duis eu felis non tortor bibendum ultrices. Aliquam tortor velit, suscipit faucibus nunc quis, blandit posuere leo. Donec dignissim aliquam lectus, vitae lacinia risus feugiat non. Curabitur dapibus, massa quis eleifend lobortis, nulla sem ullamcorper turpis, vel sodales risus orci non velit. Nam ac neque faucibus, consequat eros eu, viverra neque. Nulla vel blandit lorem. Nam interdum nisl non sem pretium dictum. Phasellus id sapien vitae ipsum efficitur fringilla. Quisque suscipit consequat erat quis commodo. Aenean tristique felis libero, et ultrices justo porttitor eget. Vivamus sit amet urna nibh. Ut ultrices nulla et dui eleifend, ut sagittis ipsum condimentum. Mauris nec dolor eget augue gravida lacinia. "
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# random initialization
|
||||
random.seed()
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a:
|
||||
for word in LONG_TEXT.split():
|
||||
console.background_colour = random.choice(list(console.STANDARD_COLOURS.keys()))
|
||||
console.foreground_colour = random.choice(list(console.STANDARD_COLOURS.keys()))
|
||||
if console.background_colour == console.foreground_colour:
|
||||
if console.background_colour in ('black','red','green','yellow','blue','magenta','cyan','white'):
|
||||
console.foreground_colour = 'bright_white'
|
||||
else:
|
||||
console.foreground_colour = 'black'
|
||||
console.add_char(word)
|
||||
console.background_colour = 'black'
|
||||
console.foreground_colour = 'bright_white'
|
||||
console.add_char(' ')
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
147
tests/test100.py
Normal file
147
tests/test100.py
Normal file
@@ -0,0 +1,147 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'io' test set : tests regarding the pygconsole.io submodule
|
||||
Test 100 : Print characters typed on the keyboard, on a console initialized with the default parameters.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 100: Print characters typed on the keyboard,",
|
||||
"on a console initialized with the default parameters.",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(name="pygame_console",logger = log)
|
||||
iotextstream = pygconsole.io.TextIOConsoleWrapper(console_name="pygame_console", newline='\r\n', line_buffering=True)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE:
|
||||
sys.exit()
|
||||
elif event.key == K_RETURN:
|
||||
print("", file=iotextstream, flush=True) # New line
|
||||
if event.type == TEXTINPUT: # When typing a key with a writable character...
|
||||
print(event.text, end='', file=iotextstream, flush=True) # Display the character
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
147
tests/test101.py
Normal file
147
tests/test101.py
Normal file
@@ -0,0 +1,147 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'io' test set : tests regarding the pygconsole.io submodule
|
||||
Test 101 : Display a message in red coloured characters.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 101: Display a message in red coloured characters.",
|
||||
"press 'A' to write `Hello world !` at the cursor position.",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(name="pygame_console",logger = log)
|
||||
iotextstream = pygconsole.io.TextIOConsoleWrapper(console_name="pygame_console", newline='\r\n', line_buffering=True)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE:
|
||||
sys.exit()
|
||||
elif event.key == K_RETURN:
|
||||
print("", file=iotextstream, flush=True) # New line
|
||||
elif event.key == K_a:
|
||||
print("\x1b[31mHello world !", file=iotextstream, flush=True) # Print 'Hello World !' in red
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
155
tests/test102.py
Normal file
155
tests/test102.py
Normal file
@@ -0,0 +1,155 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'io' test set : tests regarding the pygconsole.io submodule
|
||||
Test 102 : Display a message in all supported colours.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 102: Display a message in coloured characters.",
|
||||
"press 'A' to write `Hello world !` at the cursor position,",
|
||||
"with a colour changing cyclicly.",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
COLOUR_LIST = ['\x1b[30m','\x1b[31m','\x1b[32m','\x1b[33m','\x1b[34m','\x1b[35m','\x1b[36m','\x1b[37m',
|
||||
'\x1b[90m','\x1b[91m','\x1b[92m','\x1b[93m','\x1b[94m','\x1b[95m','\x1b[96m','\x1b[97m']
|
||||
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(name="pygame_console",logger = log)
|
||||
iotextstream = pygconsole.io.TextIOConsoleWrapper(console_name="pygame_console", newline='\r\n', line_buffering=True)
|
||||
coloured_index = 0
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE:
|
||||
sys.exit()
|
||||
elif event.key == K_RETURN:
|
||||
print("", file=iotextstream, flush=True) # New line
|
||||
elif event.key == K_a:
|
||||
print(COLOUR_LIST[coloured_index] + "Hello world !", file=iotextstream, flush=True) # Print 'Hello World !' in colour
|
||||
coloured_index += 1
|
||||
if coloured_index >= len(COLOUR_LIST): coloured_index = 0
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
155
tests/test103.py
Normal file
155
tests/test103.py
Normal file
@@ -0,0 +1,155 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'io' test set : tests regarding the pygconsole.io submodule
|
||||
Test 103 : Display a message with a background in all supported colours.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 103: Display a message in coloured background.",
|
||||
"press 'A' to write `Hello world !` at the cursor position,",
|
||||
"with a colour background changing cyclicly.",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
COLOUR_LIST = ['\x1b[40m','\x1b[41m','\x1b[42m','\x1b[43m','\x1b[44m','\x1b[45m','\x1b[46m','\x1b[47m',
|
||||
'\x1b[100m','\x1b[101m','\x1b[102m','\x1b[103m','\x1b[104m','\x1b[105m','\x1b[106m','\x1b[107m']
|
||||
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(name="pygame_console",logger = log)
|
||||
iotextstream = pygconsole.io.TextIOConsoleWrapper(console_name="pygame_console", newline='\r\n', line_buffering=True)
|
||||
coloured_index = 0
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE:
|
||||
sys.exit()
|
||||
elif event.key == K_RETURN:
|
||||
print("", file=iotextstream, flush=True) # New line
|
||||
elif event.key == K_a:
|
||||
print(COLOUR_LIST[coloured_index] + "Hello world !", file=iotextstream, flush=True) # Print 'Hello World !' in colour
|
||||
coloured_index += 1
|
||||
if coloured_index >= len(COLOUR_LIST): coloured_index = 0
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
163
tests/test10_bis.py
Normal file
163
tests/test10_bis.py
Normal file
@@ -0,0 +1,163 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 10_bis : Write a long text on the console with normal characters colorized randomly (foreground / background).
|
||||
ESCAPE Key to exit.
|
||||
** USE the pygconsole package installed with `pip` **
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
import random
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
# if __name__ == '__main__':
|
||||
# sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
# import pygconsole
|
||||
# else:
|
||||
# from .. import pygconsole
|
||||
import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 10 : Write a long text on the console with normal characters colorized randomly",
|
||||
"(foreground / background).",
|
||||
"Press 'A' to write the 'Lorem ipsum' text",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae nunc dictum, sagittis elit venenatis, efficitur justo. Etiam suscipit, ipsum accumsan aliquam elementum, massa tellus pellentesque lacus, ut porttitor ligula tortor at urna. Duis eu felis non tortor bibendum ultrices. Aliquam tortor velit, suscipit faucibus nunc quis, blandit posuere leo. Donec dignissim aliquam lectus, vitae lacinia risus feugiat non. Curabitur dapibus, massa quis eleifend lobortis, nulla sem ullamcorper turpis, vel sodales risus orci non velit. Nam ac neque faucibus, consequat eros eu, viverra neque. Nulla vel blandit lorem. Nam interdum nisl non sem pretium dictum. Phasellus id sapien vitae ipsum efficitur fringilla. Quisque suscipit consequat erat quis commodo. Aenean tristique felis libero, et ultrices justo porttitor eget. Vivamus sit amet urna nibh. Ut ultrices nulla et dui eleifend, ut sagittis ipsum condimentum. Mauris nec dolor eget augue gravida lacinia. "
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# random initialization
|
||||
random.seed()
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a:
|
||||
for word in LONG_TEXT.split():
|
||||
console.background_colour = random.choice(list(console.STANDARD_COLOURS.keys()))
|
||||
console.foreground_colour = random.choice(list(console.STANDARD_COLOURS.keys()))
|
||||
if console.background_colour == console.foreground_colour:
|
||||
if console.background_colour in ('black','red','green','yellow','blue','magenta','cyan','white'):
|
||||
console.foreground_colour = 'bright_white'
|
||||
else:
|
||||
console.foreground_colour = 'black'
|
||||
console.add_char(word)
|
||||
console.background_colour = 'black'
|
||||
console.foreground_colour = 'bright_white'
|
||||
console.add_char(' ')
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
146
tests/test1_1.py
Normal file
146
tests/test1_1.py
Normal file
@@ -0,0 +1,146 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 1_1 : display a console with `Hello world !` written (with default parameters), and test the carriage return and the line field functions.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 1_1: display a console with default parameters.",
|
||||
"press 'A' to write `Hello world !` at the cursor position.",
|
||||
"press 'ENTER' to move the cursor to the first position of the next line.",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a: console.add_char("Hello world !")
|
||||
elif event.key == K_RETURN:
|
||||
console.carriage_return()
|
||||
console.line_field()
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
154
tests/test2.py
Normal file
154
tests/test2.py
Normal file
@@ -0,0 +1,154 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 2 : Write several 'Hello world !' on a console with the different standard colours.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 2: Write several `Hello world !` on a console with the 16 different standard colours.",
|
||||
"Press 'A' to write the 16 lines at the cursor position.",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a:
|
||||
for font_colour in console.STANDARD_COLOURS:
|
||||
console.foreground_colour = 'bright_white'
|
||||
console.background_colour = 'black'
|
||||
console.add_char(f"{font_colour}: ")
|
||||
console.foreground_colour = font_colour
|
||||
if font_colour == 'black':
|
||||
console.background_colour = 'bright_white'
|
||||
else:
|
||||
console.background_colour = 'black'
|
||||
console.add_char("Hello world !")
|
||||
console.line_field()
|
||||
console.carriage_return()
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
154
tests/test3.py
Normal file
154
tests/test3.py
Normal file
@@ -0,0 +1,154 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 3 : Write several 'Hello world !' on a console with a background of the different standard colours.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 3: Write several `Hello world !` on a console with a background of the 16 different standard colours.",
|
||||
"Press 'A' to write the 16 lines at the cursor position.",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a:
|
||||
for background_colour in console.STANDARD_COLOURS:
|
||||
console.foreground_colour = 'bright_white'
|
||||
console.background_colour = 'black'
|
||||
console.add_char(f"{background_colour}: ")
|
||||
console.background_colour = background_colour
|
||||
if background_colour == 'bright_white':
|
||||
console.foreground_colour = 'black'
|
||||
else:
|
||||
console.foreground_colour = 'bright_white'
|
||||
console.add_char("Hello world !")
|
||||
console.line_field()
|
||||
console.carriage_return()
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
144
tests/test4.py
Normal file
144
tests/test4.py
Normal file
@@ -0,0 +1,144 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 4 : Write a long text on the console with the default parameters.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 4: Write a long text on the console with the default parameters.",
|
||||
"Press 'A' to write the 'Lorem ipsum' text",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae nunc dictum, sagittis elit venenatis, efficitur justo. Etiam suscipit, ipsum accumsan aliquam elementum, massa tellus pellentesque lacus, ut porttitor ligula tortor at urna. Duis eu felis non tortor bibendum ultrices. Aliquam tortor velit, suscipit faucibus nunc quis, blandit posuere leo. Donec dignissim aliquam lectus, vitae lacinia risus feugiat non. Curabitur dapibus, massa quis eleifend lobortis, nulla sem ullamcorper turpis, vel sodales risus orci non velit. Nam ac neque faucibus, consequat eros eu, viverra neque. Nulla vel blandit lorem. Nam interdum nisl non sem pretium dictum. Phasellus id sapien vitae ipsum efficitur fringilla. Quisque suscipit consequat erat quis commodo. Aenean tristique felis libero, et ultrices justo porttitor eget. Vivamus sit amet urna nibh. Ut ultrices nulla et dui eleifend, ut sagittis ipsum condimentum. Mauris nec dolor eget augue gravida lacinia. "
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a: console.add_char(LONG_TEXT)
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
146
tests/test4_1.py
Normal file
146
tests/test4_1.py
Normal file
@@ -0,0 +1,146 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 4_1 : Write a long text on the console with the default parameters, and test the clear function.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 4: Write a long text on the console with the default parameters.",
|
||||
"Press 'A' to write the 'Lorem ipsum' text.",
|
||||
"Press 'ENTER' to clear the console.",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae nunc dictum, sagittis elit venenatis, efficitur justo. Etiam suscipit, ipsum accumsan aliquam elementum, massa tellus pellentesque lacus, ut porttitor ligula tortor at urna. Duis eu felis non tortor bibendum ultrices. Aliquam tortor velit, suscipit faucibus nunc quis, blandit posuere leo. Donec dignissim aliquam lectus, vitae lacinia risus feugiat non. Curabitur dapibus, massa quis eleifend lobortis, nulla sem ullamcorper turpis, vel sodales risus orci non velit. Nam ac neque faucibus, consequat eros eu, viverra neque. Nulla vel blandit lorem. Nam interdum nisl non sem pretium dictum. Phasellus id sapien vitae ipsum efficitur fringilla. Quisque suscipit consequat erat quis commodo. Aenean tristique felis libero, et ultrices justo porttitor eget. Vivamus sit amet urna nibh. Ut ultrices nulla et dui eleifend, ut sagittis ipsum condimentum. Mauris nec dolor eget augue gravida lacinia. "
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a: console.add_char(LONG_TEXT)
|
||||
elif event.key == K_RETURN: console.clear()
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
146
tests/test5.py
Normal file
146
tests/test5.py
Normal file
@@ -0,0 +1,146 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 5 : Write a long text on the console in bold characters.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 5: Write a long text on the console in bold characters.",
|
||||
"Press 'A' to write the 'Lorem ipsum' text",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae nunc dictum, sagittis elit venenatis, efficitur justo. Etiam suscipit, ipsum accumsan aliquam elementum, massa tellus pellentesque lacus, ut porttitor ligula tortor at urna. Duis eu felis non tortor bibendum ultrices. Aliquam tortor velit, suscipit faucibus nunc quis, blandit posuere leo. Donec dignissim aliquam lectus, vitae lacinia risus feugiat non. Curabitur dapibus, massa quis eleifend lobortis, nulla sem ullamcorper turpis, vel sodales risus orci non velit. Nam ac neque faucibus, consequat eros eu, viverra neque. Nulla vel blandit lorem. Nam interdum nisl non sem pretium dictum. Phasellus id sapien vitae ipsum efficitur fringilla. Quisque suscipit consequat erat quis commodo. Aenean tristique felis libero, et ultrices justo porttitor eget. Vivamus sit amet urna nibh. Ut ultrices nulla et dui eleifend, ut sagittis ipsum condimentum. Mauris nec dolor eget augue gravida lacinia. "
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a:
|
||||
console.bold = True
|
||||
console.add_char(LONG_TEXT)
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
146
tests/test6.py
Normal file
146
tests/test6.py
Normal file
@@ -0,0 +1,146 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 6 : Write a long text on the console in underlined, normal characters.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 6: Write a long text on the console in underlined, normal characters.",
|
||||
"Press 'A' to write the 'Lorem ipsum' text",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae nunc dictum, sagittis elit venenatis, efficitur justo. Etiam suscipit, ipsum accumsan aliquam elementum, massa tellus pellentesque lacus, ut porttitor ligula tortor at urna. Duis eu felis non tortor bibendum ultrices. Aliquam tortor velit, suscipit faucibus nunc quis, blandit posuere leo. Donec dignissim aliquam lectus, vitae lacinia risus feugiat non. Curabitur dapibus, massa quis eleifend lobortis, nulla sem ullamcorper turpis, vel sodales risus orci non velit. Nam ac neque faucibus, consequat eros eu, viverra neque. Nulla vel blandit lorem. Nam interdum nisl non sem pretium dictum. Phasellus id sapien vitae ipsum efficitur fringilla. Quisque suscipit consequat erat quis commodo. Aenean tristique felis libero, et ultrices justo porttitor eget. Vivamus sit amet urna nibh. Ut ultrices nulla et dui eleifend, ut sagittis ipsum condimentum. Mauris nec dolor eget augue gravida lacinia. "
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a:
|
||||
console.underline = True
|
||||
console.add_char(LONG_TEXT)
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
146
tests/test7.py
Normal file
146
tests/test7.py
Normal file
@@ -0,0 +1,146 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 7 : Write a long text on the console in italic characters.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 7: Write a long text on the console in italic characters.",
|
||||
"Press 'A' to write the 'Lorem ipsum' text",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae nunc dictum, sagittis elit venenatis, efficitur justo. Etiam suscipit, ipsum accumsan aliquam elementum, massa tellus pellentesque lacus, ut porttitor ligula tortor at urna. Duis eu felis non tortor bibendum ultrices. Aliquam tortor velit, suscipit faucibus nunc quis, blandit posuere leo. Donec dignissim aliquam lectus, vitae lacinia risus feugiat non. Curabitur dapibus, massa quis eleifend lobortis, nulla sem ullamcorper turpis, vel sodales risus orci non velit. Nam ac neque faucibus, consequat eros eu, viverra neque. Nulla vel blandit lorem. Nam interdum nisl non sem pretium dictum. Phasellus id sapien vitae ipsum efficitur fringilla. Quisque suscipit consequat erat quis commodo. Aenean tristique felis libero, et ultrices justo porttitor eget. Vivamus sit amet urna nibh. Ut ultrices nulla et dui eleifend, ut sagittis ipsum condimentum. Mauris nec dolor eget augue gravida lacinia. "
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a:
|
||||
console.italic = True
|
||||
console.add_char(LONG_TEXT)
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
147
tests/test8.py
Normal file
147
tests/test8.py
Normal file
@@ -0,0 +1,147 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 8 : Write a long text on the console in bold, italic characters.
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 8: Write a long text on the console in bold, italic characters.",
|
||||
"Press 'A' to write the 'Lorem ipsum' text",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae nunc dictum, sagittis elit venenatis, efficitur justo. Etiam suscipit, ipsum accumsan aliquam elementum, massa tellus pellentesque lacus, ut porttitor ligula tortor at urna. Duis eu felis non tortor bibendum ultrices. Aliquam tortor velit, suscipit faucibus nunc quis, blandit posuere leo. Donec dignissim aliquam lectus, vitae lacinia risus feugiat non. Curabitur dapibus, massa quis eleifend lobortis, nulla sem ullamcorper turpis, vel sodales risus orci non velit. Nam ac neque faucibus, consequat eros eu, viverra neque. Nulla vel blandit lorem. Nam interdum nisl non sem pretium dictum. Phasellus id sapien vitae ipsum efficitur fringilla. Quisque suscipit consequat erat quis commodo. Aenean tristique felis libero, et ultrices justo porttitor eget. Vivamus sit amet urna nibh. Ut ultrices nulla et dui eleifend, ut sagittis ipsum condimentum. Mauris nec dolor eget augue gravida lacinia. "
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a:
|
||||
console.bold = True
|
||||
console.italic = True
|
||||
console.add_char(LONG_TEXT)
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
154
tests/test9.py
Normal file
154
tests/test9.py
Normal file
@@ -0,0 +1,154 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
"""
|
||||
'console' test set : tests regarding only the pygconsole.console submodule
|
||||
Test 9 : Write a long text on the console in characters parametered randomly (bold / underline / italic), but with the default colours (foreground in bright white, background in black).
|
||||
ESCAPE Key to exit.
|
||||
"""
|
||||
|
||||
|
||||
# Standard modules
|
||||
#-----------------
|
||||
import sys
|
||||
import os
|
||||
from collections import namedtuple
|
||||
import logging
|
||||
import random
|
||||
|
||||
# Third party modules
|
||||
#--------------------
|
||||
import pygame
|
||||
from pygame.locals import *
|
||||
from colorlog import ColoredFormatter
|
||||
|
||||
# Internal modules
|
||||
#-----------------
|
||||
if __name__ == '__main__':
|
||||
sys.path.append(os.path.join(os.path.dirname(__file__),'..'))
|
||||
import pygconsole
|
||||
else:
|
||||
from .. import pygconsole
|
||||
|
||||
# namedtuples
|
||||
#------------
|
||||
Coordinates = namedtuple("Coordinates", "x y")
|
||||
Colour = namedtuple("Colour", "red green blue alpha")
|
||||
|
||||
# Global constants
|
||||
#-----------------
|
||||
RESOURCE_DIR = os.path.join(os.path.dirname(__file__),"resources") # directory where graphical resources are stored
|
||||
BACKGROUND_IMAGE = os.path.join(RESOURCE_DIR,"background.jpg") # Background image
|
||||
FONT = None # Font displayed outside of the console (None = default pygame font)
|
||||
|
||||
DISPLAY_SIZE = Coordinates(1920,1080) # screen resolution
|
||||
CONSOLE_COORDINATES = Coordinates(1000,620) # upper left corner coordinates of the console
|
||||
FRAMERATE = 50 # Maximum number of displaying loops per second
|
||||
|
||||
FONT_SIZE = 40 # size of the font displayed on the screen, but out of the console
|
||||
FONT_COLOUR = Colour(255,0,0,255) # Colour of the font displayed outside of the console
|
||||
TEXT_COORDINATES = Coordinates(50,50) # Coordinates of the first line of the text displayed outside of the console
|
||||
|
||||
TEXT_LIST = [
|
||||
"Test 9 : Write a long text on the console in characters parametered randomly (bold / underline / italic), but with the default colours (foreground in bright white, background in black).",
|
||||
"Press 'A' to write the 'Lorem ipsum' text",
|
||||
"ESCAPE key to exit."
|
||||
]
|
||||
|
||||
LONG_TEXT = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Quisque vitae nunc dictum, sagittis elit venenatis, efficitur justo. Etiam suscipit, ipsum accumsan aliquam elementum, massa tellus pellentesque lacus, ut porttitor ligula tortor at urna. Duis eu felis non tortor bibendum ultrices. Aliquam tortor velit, suscipit faucibus nunc quis, blandit posuere leo. Donec dignissim aliquam lectus, vitae lacinia risus feugiat non. Curabitur dapibus, massa quis eleifend lobortis, nulla sem ullamcorper turpis, vel sodales risus orci non velit. Nam ac neque faucibus, consequat eros eu, viverra neque. Nulla vel blandit lorem. Nam interdum nisl non sem pretium dictum. Phasellus id sapien vitae ipsum efficitur fringilla. Quisque suscipit consequat erat quis commodo. Aenean tristique felis libero, et ultrices justo porttitor eget. Vivamus sit amet urna nibh. Ut ultrices nulla et dui eleifend, ut sagittis ipsum condimentum. Mauris nec dolor eget augue gravida lacinia. "
|
||||
|
||||
# Dataclasses
|
||||
#------------
|
||||
|
||||
# Classes
|
||||
#--------
|
||||
|
||||
|
||||
# Functions
|
||||
#----------
|
||||
|
||||
|
||||
# Main function
|
||||
#--------------
|
||||
def main():
|
||||
""" Main program execution"""
|
||||
|
||||
# random initialization
|
||||
random.seed()
|
||||
|
||||
# Logging initialization
|
||||
formatter = ColoredFormatter(
|
||||
'%(log_color)s[%(asctime)s][%(levelname)s][%(name)s]:%(message)s',
|
||||
datefmt='%Y-%m-%d %H:%M:%S',
|
||||
reset=True,
|
||||
log_colors={
|
||||
'DEBUG': 'cyan',
|
||||
'INFO': 'green',
|
||||
'WARNING': 'yellow',
|
||||
'ERROR': 'red',
|
||||
'CRITICAL': 'red,bg_white'
|
||||
},
|
||||
secondary_log_colors={},
|
||||
style='%'
|
||||
)
|
||||
handler = logging.StreamHandler()
|
||||
handler.setLevel(logging.DEBUG)
|
||||
handler.setFormatter(formatter)
|
||||
log = logging.getLogger('display')
|
||||
log.setLevel(logging.DEBUG)
|
||||
log.addHandler(handler)
|
||||
|
||||
|
||||
# screen initialization
|
||||
pygame.init()
|
||||
clock = pygame.time.Clock() # timer to control framerate
|
||||
flags = FULLSCREEN|SCALED|DOUBLEBUF
|
||||
screen_surface = pygame.display.set_mode(size=DISPLAY_SIZE,flags=flags)
|
||||
background_surface = pygame.image.load(BACKGROUND_IMAGE)
|
||||
|
||||
# Font initialization
|
||||
font = pygame.font.Font(FONT,FONT_SIZE)
|
||||
line_space = font.get_linesize()
|
||||
|
||||
# console initialization
|
||||
console = pygconsole.console.Console.get_console(logger = log)
|
||||
|
||||
# Displaying loop
|
||||
while True:
|
||||
clock.tick(FRAMERATE)
|
||||
|
||||
# Events
|
||||
for event in pygame.event.get():
|
||||
if event.type == QUIT: sys.exit()
|
||||
if event.type == KEYDOWN:
|
||||
if event.key == K_ESCAPE: sys.exit()
|
||||
elif event.key == K_a:
|
||||
for word in LONG_TEXT.split():
|
||||
console.bold = random.choice((True, False))
|
||||
console.italic = random.choice((True, False))
|
||||
console.underline = random.choice((True, False))
|
||||
console.add_char(word)
|
||||
console.add_char(' ')
|
||||
|
||||
# Background display
|
||||
screen_surface.blit(background_surface,(0,0))
|
||||
|
||||
# Text display
|
||||
text_line_coordinates = TEXT_COORDINATES
|
||||
for text_line in TEXT_LIST:
|
||||
text_surface = font.render(text_line,True,FONT_COLOUR)
|
||||
screen_surface.blit(text_surface,text_line_coordinates)
|
||||
text_line_coordinates = text_line_coordinates._replace(y=text_line_coordinates.y+line_space)
|
||||
|
||||
# Console display
|
||||
screen_surface.blit(console.surface,CONSOLE_COORDINATES)
|
||||
|
||||
# Screen rendering
|
||||
pygame.display.flip()
|
||||
|
||||
|
||||
# Main program,
|
||||
# running only if the module is NOT imported (but directly executed)
|
||||
#-------------------------------------------------------------------
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
|
Reference in New Issue
Block a user