Dynamic locales, simple dictionary, advanced table
This commit is contained in:
parent
8211b9829e
commit
1e8d02dc41
13 changed files with 246 additions and 62 deletions
|
@ -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
13
Calendar/DayBoxDesign.py
Normal 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
16
Calendar/Dictionary.py
Normal 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'
|
||||
}
|
27
Calendar/DictionaryMapper.py
Normal file
27
Calendar/DictionaryMapper.py
Normal 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
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
@ -66,10 +68,3 @@ class EventListDesign (DesignEntity):
|
|||
"background_color" : bg_color
|
||||
}
|
||||
return [ cell, cell ]
|
||||
|
||||
def __get_more_text__ (self):
|
||||
more_texts = {
|
||||
"de" : "weitere",
|
||||
"en" : "more"
|
||||
}
|
||||
return more_texts[language]
|
|
@ -14,17 +14,12 @@ class IcalEvents(CalendarInterface):
|
|||
super(IcalEvents, self).__init__()
|
||||
|
||||
def is_available(self):
|
||||
for url in self.urls + self.highlighted_urls:
|
||||
try:
|
||||
testurl = ""
|
||||
if self.urls:
|
||||
testurl = self.urls[0]
|
||||
elif self.highlighted_urls:
|
||||
testurl = self.highlighted_urls[0]
|
||||
else:
|
||||
return False
|
||||
urlopen(testurl)
|
||||
urlopen(url)
|
||||
return True
|
||||
except:
|
||||
pass
|
||||
return False
|
||||
|
||||
def __get_events__(self):
|
||||
|
|
110
Calendar/MonthViewPanel.py
Normal file
110
Calendar/MonthViewPanel.py
Normal 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
|
|
@ -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):
|
||||
|
|
|
@ -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")
|
||||
|
@ -111,6 +123,30 @@ class TableDesign (TextDesign):
|
|||
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)
|
||||
for c in range(col):
|
||||
|
|
|
@ -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)
|
||||
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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.|
|
||||
|
|
Loading…
Reference in a new issue