Dynamic locales, simple dictionary, advanced table

This commit is contained in:
Maximilian Giller 2019-05-06 11:05:10 +02:00
parent 8211b9829e
commit 1e8d02dc41
13 changed files with 246 additions and 62 deletions

View file

@ -32,12 +32,6 @@ fonts = {
defaultfont = fonts[font_boldness]
defaultfontsize = int(font_size)
datetime_locals = {
"de" : "de_DE.UTF-8",
"en" : "en_US.UTF-8",
"zh_TW" : "zh_TW.UTF-8"
}
weathericons = {
'01d': 'wi-day-sunny', '02d':'wi-day-cloudy', '03d': 'wi-cloudy',
'04d': 'wi-cloudy-windy', '09d': 'wi-showers', '10d':'wi-rain',

13
Calendar/DayBoxDesign.py Normal file
View file

@ -0,0 +1,13 @@
from DesignEntity import DesignEntity
class DayBoxDesign (DesignEntity):
"""Represents a day with its events in a box."""
def __init__(self, size, date):
super(DayBoxDesign, self).__init__(size)
self.date = date
def add_calendar(self, calendar):
pass
def __finish_image__(self):
pass

16
Calendar/Dictionary.py Normal file
View file

@ -0,0 +1,16 @@
default_language = "en"
'''Characters following '*' are placeholders and will be replaced by some number/text/etc.'''
more_events = {
'en' : '+ *0 more',
'de' : '+ *0 weitere'
}
multiday_events = {
'en' : 'Multi-day',
'de' : 'Mehrtägig'
}
allday_events = {
'en' : 'All-day',
'de' : 'Ganztägig'
}

View file

@ -0,0 +1,27 @@
from Dictionary import default_language
from settings import language
'''Takes a collection of phrases and outputs the necessary text
according to the language and inserts parameters.'''
def get_text(dictionary, *params):
text = dictionary[default_language]
if language in dictionary.keys():
text = dictionary[language]
return __insert_params__(text, params)
def __insert_params__(text, params):
index = 0
while '*%d' % index in text and index < len(params):
splitted = text.split('*%d' % index)
text = splitted[0] + str(params[index]) + splitted[1]
index += 1
while '*' in text:
splitted = text.split('*%d' % index)
if len(splitted) > 1:
text = splitted[0] + splitted[1].lstrip(' ')
else:
text = splitted[0].rsplit(' ')
index += 1
return text

View file

@ -9,20 +9,25 @@ Copyright by aceisace
"""
from datetime import datetime
from time import sleep
from Assets import datetime_locals, path
from Assets import path
from LoopTimer import LoopTimer
import locale
from DebugConsole import DebugConsole
from settings import language, render_to_display, render_to_file, display_colours, location, api_key, owm_paid_subscription, choosen_design, ical_urls, highlighted_ical_urls, rss_feeds, update_interval, calibrate_hours
from settings import datetime_encoding, language, render_to_display, render_to_file, display_colours, location, api_key, owm_paid_subscription, choosen_design, ical_urls, highlighted_ical_urls, rss_feeds, update_interval, calibrate_hours
from MonthOvPanel import MonthOvPanel
from DayListPanel import DayListPanel
from DayViewPanel import DayViewPanel
from MonthViewPanel import MonthViewPanel
from AgendaListPanel import AgendaListPanel
import OwmForecasts
import IcalEvents
import RssParserPosts
locale.setlocale(locale.LC_ALL, datetime_locals[language])
all_locales = locale.locale_alias
if language not in all_locales.keys():
raise Exception("The locale for \"%s\" is currently not supported! If you need support, please open an issue on github." % language)
locale.setlocale(locale.LC_ALL, "%s.%s" % (all_locales[language].split('.')[0], datetime_encoding))
debug = DebugConsole()
output_adapters = []
@ -45,7 +50,8 @@ available_panels = {
"day-list" : DayListPanel,
"month-overview" : MonthOvPanel,
"day-view" : DayViewPanel,
"agenda-list" : AgendaListPanel
"agenda-list" : AgendaListPanel,
"month-view" : MonthViewPanel
}
loop_timer = LoopTimer(update_interval, run_on_hour=True)

View file

@ -3,6 +3,8 @@ from TableDesign import TableDesign
from settings import language
from Assets import defaultfontsize, colors
from TextFormatter import date_str
from DictionaryMapper import get_text
from Dictionary import more_events
class EventListDesign (DesignEntity):
"""Creates a TableDesign filled with event
@ -30,7 +32,7 @@ class EventListDesign (DesignEntity):
self.__fill_event_matrix__()
col_hori_alignment = [ 'right', 'left' ]
table_design = TableDesign(self.size, background_color = self.background_color, font=self.font_family, line_spacing=self.line_spacing, col_spacing=self.col_spacing, text_matrix=self.__event_matrix__, fontsize = self.text_size, column_horizontal_alignments=col_hori_alignment, mask=False, truncate_cols=False, cell_properties=self.__props_matrix__)
table_design = TableDesign(self.size, background_color = self.background_color, font=self.font_family, line_spacing=self.line_spacing, col_spacing=self.col_spacing, matrix=self.__event_matrix__, fontsize = self.text_size, column_horizontal_alignments=col_hori_alignment, mask=False, truncate_cols=False, cell_properties=self.__props_matrix__)
self.draw_design(table_design)
def __get_formatted_event__ (self, event, index):
@ -51,9 +53,9 @@ class EventListDesign (DesignEntity):
return
additional_events_count = len(self.events) - len(visible_events)
more_text = self.__get_more_text__()
more_text = " " + get_text(more_events, additional_events_count)
if additional_events_count > 0:
self.__event_matrix__.append([ "", " + " + str(additional_events_count) + " " + more_text ])
self.__event_matrix__.append([ "", more_text ])
self.__props_matrix__.append(self.__get_row_props__())
def __get_row_props__ (self, event = None):
@ -65,11 +67,4 @@ class EventListDesign (DesignEntity):
"color" : color,
"background_color" : bg_color
}
return [ cell, cell ]
def __get_more_text__ (self):
more_texts = {
"de" : "weitere",
"en" : "more"
}
return more_texts[language]
return [ cell, cell ]

View file

@ -14,18 +14,13 @@ class IcalEvents(CalendarInterface):
super(IcalEvents, self).__init__()
def is_available(self):
try:
testurl = ""
if self.urls:
testurl = self.urls[0]
elif self.highlighted_urls:
testurl = self.highlighted_urls[0]
else:
return False
urlopen(testurl)
return True
except:
return False
for url in self.urls + self.highlighted_urls:
try:
urlopen(url)
return True
except:
pass
return False
def __get_events__(self):
events = self.__get_events_from_urls__(self.urls)

110
Calendar/MonthViewPanel.py Normal file
View file

@ -0,0 +1,110 @@
from PanelDesign import PanelDesign
from settings import general_settings, week_starts_on
from PIL import ImageDraw
from datetime import date
from Assets import colors
import calendar as callib
from TableDesign import TableDesign
from DayBoxDesign import DayBoxDesign
from RssPostListDesign import RssPostListDesign
from WeatherHeaderDesign import WeatherHeaderDesign
weather_height = 0.113
info_height = 0.25
info_padding = 5
seperator_width = 3
class MonthViewPanel (PanelDesign):
"""Displays a grid of the day of the current month
with detailed event descriptions."""
def __init__(self, size, month = None, year = None):
super(MonthViewPanel, self).__init__(size)
self.day_table = []
self.month = month
if self.month == None:
self.month = date.today().month
self.year = year
if self.year == None:
self.year = date.today().year
self.__init_sizes__()
self.__init_day_boxes__()
def __init_sizes__(self):
self.weather_height = 0
self.info_height = 0
if general_settings["info-area"] in ["events", "rss"]:
self.info_height = info_height
if general_settings["weather-info"]:
self.weather_height = weather_height
self.day_area_height = 1 - self.weather_height - self.info_height
self.day_area_ypos = self.weather_height
area_height = self.size[1] * self.day_area_height
area_width = self.size[0]
self.day_box_size = (area_width / 7, area_height)
def add_weather (self, weather):
if general_settings["weather-info"] == False:
return
size = (self.size[0], self.size[1] * self.weather_height)
header = WeatherHeaderDesign(size, weather)
self.draw_design(header)
self.__draw_seperator__(size[1], colors["hl"])
def add_calendar (self, calendar):
self.__add_calendar_to_days__(calendar)
def __add_calendar_to_days__(self, calendar):
for week in self.day_table:
for day in week:
if day != None:
day.add_calendar(calendar)
def add_rssfeed (self, rss):
if general_settings["info-area"] != "rss":
return
size = (self.size[0], self.size[1] * self.info_height)
pos = (0, self.size[1] - size[1] + info_padding)
rss = RssPostListDesign(size, rss)
rss.pos = pos
self.draw_design(rss)
def add_taks (self, tasks):
pass
def __finish_panel__(self):
self.__draw_days__()
def __draw_days__(self):
size = (self.size[0], self.size[1] * self.day_area_height)
pos = (0, self.size[0] * self.day_area_ypos)
table = TableDesign(size, matrix = self.day_table)
table.pos = pos
self.draw_design(table)
def __draw_seperator__ (self, height, color):
ImageDraw.Draw(self.__image__).line([ (0, height * self.size[1]), (self.size[0], height * self.size[1]) ], fill=color, width=seperator_width)
def __init_day_boxes__(self):
if week_starts_on == "Monday":
callib.setfirstweekday(callib.MONDAY)
elif week_starts_on == "Sunday":
callib.setfirstweekday(callib.SUNDAY)
weeks = callib.monthcalendar(self.year, self.month)
for i, week in enumerate(weeks):
self.day_table.append([])
for day in week:
self.day_table[i].append(self.__create_day__(day))
def __create_day__(self, day):
if day == None or day == 0:
return None
design = DayBoxDesign(self.day_box_size, date(self.year, self.month, int(day)))
return design

View file

@ -14,7 +14,7 @@ class RssPostListDesign (DesignEntity):
def __finish_image__ (self):
self.__fill_post_matrix__()
table_design = TableDesign(self.size, line_spacing=5, col_spacing=3, text_matrix=self.__post_matrix__, fontsize = self.text_size, mask=False, truncate_cols=False, wrap=True)
table_design = TableDesign(self.size, line_spacing=5, col_spacing=3, matrix=self.__post_matrix__, fontsize = self.text_size, mask=False, truncate_cols=False, wrap=True)
self.draw_design(table_design)
def __get_formatted_post__ (self, post):

View file

@ -1,6 +1,7 @@
from TextDesign import TextDesign
from TextWraper import wrap_text_with_font
from Assets import defaultfontsize, colors
from DesignEntity import DesignEntity
default_props = {
@ -11,10 +12,10 @@ default_props = {
class TableDesign (TextDesign):
"""Gets a matrix with text or designs that is than
displayed in a table without borders."""
def __init__ (self, size, text_matrix, max_col_size = None, max_row_size = None, font = None, fontsize = defaultfontsize, column_horizontal_alignments = [], mask = True, line_spacing = 0, col_spacing = 0, truncate_rows = True, truncate_cols = True, wrap = False, truncate_text=True, truncate_suffix="...", cell_properties=None, background_color = colors["bg"]):
def __init__ (self, size, matrix, max_col_size = None, max_row_size = None, font = None, fontsize = defaultfontsize, column_horizontal_alignments = [], mask = True, line_spacing = 0, col_spacing = 0, truncate_rows = True, truncate_cols = True, wrap = False, truncate_text=True, truncate_suffix="...", cell_properties=None, background_color = colors["bg"]):
super(TableDesign, self).__init__(size, font=font, fontsize=fontsize, mask=mask)
self.__init_image__(background_color)
self.matrix = text_matrix
self.matrix = matrix
self.max_col_size = max_col_size
self.max_row_size = max_row_size
self.line_spacing = line_spacing
@ -42,11 +43,10 @@ class TableDesign (TextDesign):
if self.max_col_size is not None:
return
font = self.__get_font__()
col_sizes = []
for c in range(len(self.matrix[0])): #amout of columns
for r in range(len(self.matrix)):
row_col_size = font.getsize(self.matrix[r][c])[0] #get width of text in that row/col
row_col_size = self.__get_cell_size__(r,c)[0]
if len(col_sizes) - 1 < c:
col_sizes.append(row_col_size)
elif row_col_size > col_sizes[c]:
@ -64,14 +64,10 @@ class TableDesign (TextDesign):
if self.max_row_size is not None:
return
font = self.__get_font__()
row_sizes = []
for r in range(len(self.matrix)):
for c in range(len(self.matrix[0])): #amout of columns
cell_text = self.matrix[r][c]
if self.wrap:
cell_text = wrap_text_with_font(cell_text, self.max_col_size[c], font)
col_row_size = font.getsize_multiline(cell_text)[1] #get height of text in that col/row
col_row_size = self.__get_cell_size__(r,c)[1]
if len(row_sizes) - 1 < r:
row_sizes.append(col_row_size)
elif col_row_size > row_sizes[r]:
@ -79,6 +75,24 @@ class TableDesign (TextDesign):
self.max_row_size = row_sizes
def __get_cell_size__(self, r, c):
content = self.matrix[r][c]
size = (0, 0)
if content == None:
return size
elif type(content) == str:
font = self.__get_font__()
width = font.getsize(self.matrix[r][c])[0] #get width of text in that row/col
if self.wrap and self.max_col_size != None:
content = wrap_text_with_font(content, self.max_col_size[c], font)
height = font.getsize_multiline(content)[1] #get height of text in that col/row
size = (width, height)
else: #DesignEntity
size = content.size
return size
def __get_truncated_counts__ (self):
max_col = 0
if self.truncate_cols:
@ -99,9 +113,7 @@ class TableDesign (TextDesign):
def __print_table__ (self, matrix):
for r in range(self.max_row):
for c in range(self.max_col):
size = self.cell_sizes[r][c]
pos = self.__get_cell_pos__(r,c)
self.__draw_text__(pos, size, r, c)
self.__draw_cell__(r,c)
def __draw_text__ (self, pos, size, row, col):
color = self.__get_cell_prop__(row, col, "color")
@ -110,6 +122,30 @@ class TableDesign (TextDesign):
design = TextDesign(size, text=self.matrix[row][col], font=self.font_family, color=color, background_color=bg_color, fontsize=self.font_size, horizontalalignment=self.__get_col_hori_alignment__(col), wrap=self.wrap, truncate=self.truncate_text, truncate_suffix=self.truncate_suffix)
design.pos = pos
self.draw_design(design)
def __draw_design__ (self, pos, size, row, col):
bg_color = self.__get_cell_prop__(row, col, "background_color")
source_design = self.matrix[row][col]
source_design.mask = False
framed_design = DesignEntity(size, mask = False)
framed_design.__init_image__(color=bg_color)
framed_design.draw_design(source_design)
framed_design.pos = pos
self.draw_design(framed_design)
def __draw_cell__ (self, row, col):
size = self.cell_sizes[row][col]
pos = self.__get_cell_pos__(row,col)
if self.matrix[row][col] == None:
return
elif type(self.matrix[row][col]) == str:
self.__draw_text__(pos, size, row, col)
else:
self.__draw_design__(pos, size, row, col)
def __get_cell_pos__ (self, row, col):
xpos, ypos = (0, 0)

View file

@ -1,5 +1,7 @@
from settings import hours, language
from datetime import timedelta, datetime, timezone
from DictionaryMapper import get_text
from Dictionary import multiday_events, allday_events
first_occurrence_char = '['
middle_occurrence_char = '|'
@ -10,18 +12,6 @@ until_character = ' - '
allday_character = ""
multiday_character = allday_character + allday_character
allday_lang = {
"en" : "All day",
"de" : "Ganztägig"
}
allday_detailed = allday_lang[language]
multiday_lang = {
"en" : "Multi-day",
"de" : "Mehrtägig"
}
multiday_detailed = multiday_lang[language]
def time_str (dt):
if hours is "12":
return dt.strftime("%I:%M%p")
@ -57,7 +47,7 @@ def event_prefix_str (event, relative_date=None):
relative_date = event.begin_datetime.date()
if event.multiday:
return multiday_detailed
return get_text(multiday_events)
else:
return event_time_detailed(event)
@ -78,7 +68,7 @@ def event_time_summary (event):
def event_time_detailed (event):
if event.allday:
return allday_detailed
return get_text(allday_events)
else:
return time_str(event.begin_datetime) + until_character + time_str(event.end_datetime)

View file

@ -17,6 +17,7 @@ location = "Julich, DE"
week_starts_on = "Monday"
display_colours = "bwr"
language = "en"
datetime_encoding = "UTF-8" # UTF-8
units = "metric"
hours = "24"
update_interval = 60
@ -25,7 +26,7 @@ update_interval = 60
"""DESIGN"""
font_size = 14 # does not affect every text
font_boldness = "semibold" # extralight, light, regular, semibold, bold, extrabold
choosen_design = "month-overview" # month-overview, day-list, day-view, agenda-list
choosen_design = "month-overview" # month-overview, day-list, day-view, agenda-list, month-view
general_settings = { # General settings that designs may use
"info-area" : "rss", # empty, events, rss
"highlight-event-days" : True,

View file

@ -75,7 +75,8 @@ Once the packages are installed, navigate to the home directory, open 'E-Paper-M
| location | Location refers to the closest weather station from your place. It isn't necessarily the place you live in. To find this location, type your city name in the search box on [openweathermap](https://openweathermap.org/). The output should be in the following format: City Name, Country ISO-Code. Not sure what your ISO code is? Check here: [(find iso-code)](https://countrycode.org/). |
| week_starts_on | When does the work start on your Region? Possible options are `"Monday"` or `"Sunday"`. |
| display_colours | This should normally be set by the installer when you choose the type of your display. Options include `"bw"` if you're using the black and white E-Paper or `"bwr"` when you're using the black-white-red or black-white-yellow E-Paper.|
| language | Choosing the language allows changing the language of the month and week-icons. Possible options are `"en"` for english and `"de"` for german.|
| language | Sets the language and the related locale for datetime-information. Some texts depend on additional translations that can be added to the dictionary-file.|
| datetime_encoding | Sets the encoding that will be used in the datetime-texts (month, weekday, ...). Default is `"UTF-8"`.|
|units| Selecting units allows switching units from km/h (kilometer per hour) and °C (degree Celcius) to mph (miles per hour) and °F (degree Fahrenheit). Possible options are `"metric"` or `"imperial"`. |
|hours | Which time format do you prefer? This will change the sunrise and sunset times from 24-hours format to 12-hours format. Possible options are `"24"` for 24-hours and `"12"` for 12-hours.|
|update_interval | The update delay between two updates in minutes. By default there is always an update on a full hour.|