@@ -44,6 +44,7 @@
import platform
import math
import random
import textwrap
#
# Internal modules
@@ -59,8 +60,7 @@ class PositionHelperBase(ScreenHelperBase):
There are main methods available here:
* `get_terminal_size`: retrieves the current terminal dimensions, width
and height, to be stored in local properties `screen_width` and
`screen_height`.
and height, to be stored in local propertiy `geometry`.
* `center_text_vertically`: centers a specified text in vertical
@@ -74,32 +74,71 @@ class PositionHelperBase(ScreenHelperBase):
If the method `get_terminal_size` is never called, all other functionality,
relying on terminal dimensions, will just based on a default size, set as
80x25.
"""
screen_width = 80
The main properties available are:
* `geometry`: defines the size of the terminal (populated by the
`get_terminal_size` method, whenever called.
* `position`: defines the current position of the text to be printed,
based on usage of other methods that temper with text positioning
(eg. `randomize_text_horizontally`)
* `changed_geometry`: for every call to `get_terminal_size` method,
holds the information if the terminal has changed size or not.
"""
Defines the current terminal width. Its default value is set as 80.
geometry = {
'x' : 0 ,
'y' : 0 ,
}
"""
Defines the current terminal width and height.
Its default value is set as 80x25.
"""
screen_height = 25
__old_geometry = {
'x' : 0 ,
'y' : 0 ,
}
"""
Defines the current terminal height. Its default value is set as 25.
Private property to track changes in the geometry. Refer to
`changed_geometry` to identify any terminal size changes.
"""
pos_y = 1
changed_geometry = False
"""
Stores the latest position Y axis (height) position value after calling
the randomizing methods of this class (useful to allow you to know the
previous location of the text in the window)
A simple boolean that identifies if the terminal has changed size since the
last check with `get_terminal_size`. This is handy to decide what to do
with a particular screen (eg: clear and redraw again?).
"""
pos_x = 1
position = {
'x' : 0 ,
'y' : 0 ,
}
"""
Stores the latest position X axis (width) position value after calling
the randomizing methods of this class (useful to allow you to know the
previous location of the text in the window)
Stores the latest position X-Y axis (width and height ) position value after
calling the randomizing methods of this class (useful to allow you to know
the previous location of the text in the window)
"""
def fix_text_wrap (self , text ):
"""
Wraps the text to the geometry size, maintaining existing new lines.
"""
temp = text .split ("\n " )
longest_line = max ([len (x ) for x in temp ])
new_text = []
for l in temp :
t = "\n " .join (textwrap .wrap (l , width = self .geometry ['x' ]))
# fill in trailing blanks
t += " " * (min (longest_line , self .geometry ['x' ]) - min (len (t ), self .geometry ['x' ]))
new_text .append (t )
return "\n " .join (new_text )
def center_text_vertically (self , text ):
"""
Returns the text argument with additional new lines, calculated to
@@ -109,14 +148,12 @@ def center_text_vertically(self, text):
* text: the text to be vertically centered
"""
line_count = 0
for t in text .split ("\n " ):
line_count += 1 + math .ceil (len (t ) / (self .screen_width - 1 ))
return "\n " * int (math .floor ((self .screen_height - line_count ) / 2 )) \
+ text
temp = self .fix_text_wrap (text ).split ("\n " )
self .position ['y' ] = int (math .floor (
(self .geometry ['y' ] - len (temp )) / 2 ))
return "\n " * self .position ['y' ] + text
def center_text_horizontally (self , text ):
"""
Returns the text argument with additional blank spaces, calculated to
@@ -126,20 +163,16 @@ def center_text_horizontally(self, text):
* text: the text to be horizontally centered
"""
temp = self .fix_text_wrap (text ).split ("\n " )
new_text = ""
for t in text .split ("\n " ):
temp = ["" ]
index = 0
for w in t .split (" " ):
if len (temp [index ] + w ) < self .screen_width - 1 :
temp [index ] = " " .join ([temp [index ], w ])
else :
index += 1
temp .append (w )
for l in temp :
new_text += " " * int (math .ceil (
(self .screen_width - len (l ) - 1 ) / 2 )) + l + "\n "
for t in temp :
self .position ['x' ] = int (math .ceil (
(self .geometry ['x' ] - len (t )) / 2 ))
new_text += " " * self .position ['x' ] + t
if len (temp ) > 1 :
new_text += "\n "
return new_text
def randomize_text_horizontally (self , text ):
@@ -151,10 +184,21 @@ def randomize_text_horizontally(self, text):
* text: the text to be horizontally randomized
"""
self .pos_x = random .randint (0 , self .screen_width - len (text ))
return " " * self .pos_x + text \
+ " " * (self .screen_width - self .pos_x - len (text ))
# find longest line
temp = self .fix_text_wrap (text ).split ("\n " )
longest_line = max ([len (x ) for x in temp ])
self .position ['x' ] = random .randint (0 ,
self .geometry ['x' ] - longest_line )
new_text = ""
for t in temp :
new_text += " " * self .position ['x' ] + t
if len (temp ) > 0 :
new_text += "\n "
return new_text
def randomize_text_vertically (self , text ):
"""
@@ -165,15 +209,17 @@ def randomize_text_vertically(self, text):
* text: the text to be vertically randomized
"""
self .pos_y = random .randint (0 , self .screen_height )
total_lines = len (self .fix_text_wrap (text ).split ("\n " ))
self .position ['y' ] = random .randint (0 ,
max (0 , self .geometry ['y' ] - total_lines ))
return "\n " * self .pos_y + text
return "\n " * self .position [ 'y' ] + text
def get_terminal_size (self ):
"""
Retrieves the screen terminal dimensions, returning a tuple
(width, height), and will also store them in internal properties
`screen_width` and `screen_height `.
(width, height), and will also store them in internal property
`geometry `.
Copyright note:
This code has been adapted from:
@@ -267,7 +313,15 @@ def ioctl_GWINSZ(fd):
if tuple_xy is None :
tuple_xy = (80 , 25 ) # default value
# assign result to
self .screen_width , self .screen_height = tuple_xy
return tuple_xy
self .geometry ['x' ], self .geometry ['y' ] = tuple_xy
# store geometry changes
if self .__old_geometry == {'x' : 0 , 'y' : 0 }:
# first time checking geometry
self .__old_geometry = self .geometry .copy ()
self .changed_geometry = False
elif self .__old_geometry != self .geometry :
self .__old_geometry = self .geometry .copy ()
self .changed_geometry = True
else :
self .changed_geometry = False