Formatted code
This commit is contained in:
parent
5d881753b8
commit
1e0f59739f
54 changed files with 968 additions and 722 deletions
|
@ -8,9 +8,11 @@ from settings import line_thickness
|
||||||
|
|
||||||
separator_width = line_thickness
|
separator_width = line_thickness
|
||||||
|
|
||||||
|
|
||||||
class AgendaListDesign (DesignEntity):
|
class AgendaListDesign (DesignEntity):
|
||||||
'''Lists upcoming events in chronological order and groups them by days'''
|
'''Lists upcoming events in chronological order and groups them by days'''
|
||||||
def __init__ (self, size, calendar, line_spacing = 0, col_spacing = 8, text_size = defaultfontsize, start_date = date.today(), always_add_start_row = True):
|
|
||||||
|
def __init__(self, size, calendar, line_spacing=0, col_spacing=8, text_size=defaultfontsize, start_date=date.today(), always_add_start_row=True):
|
||||||
super(AgendaListDesign, self).__init__(size)
|
super(AgendaListDesign, self).__init__(size)
|
||||||
self.calendar = calendar
|
self.calendar = calendar
|
||||||
self.line_spacing = line_spacing
|
self.line_spacing = line_spacing
|
||||||
|
@ -19,19 +21,19 @@ class AgendaListDesign (DesignEntity):
|
||||||
self.start_dt = date(start_date.year, start_date.month, start_date.day)
|
self.start_dt = date(start_date.year, start_date.month, start_date.day)
|
||||||
self.always_add_start_row = always_add_start_row
|
self.always_add_start_row = always_add_start_row
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
self.__calculate_parameter__()
|
self.__calculate_parameter__()
|
||||||
self.__create_infos_events__()
|
self.__create_infos_events__()
|
||||||
self.__draw_infos__()
|
self.__draw_infos__()
|
||||||
self.__draw_lines__()
|
self.__draw_lines__()
|
||||||
|
|
||||||
def __calculate_parameter__ (self):
|
def __calculate_parameter__(self):
|
||||||
self.__line_height__ = self.line_spacing + self.__get_text_height__()
|
self.__line_height__ = self.line_spacing + self.__get_text_height__()
|
||||||
self.__event_number__ = int(int(self.size[1]) // self.__line_height__)
|
self.__event_number__ = int(int(self.size[1]) // self.__line_height__)
|
||||||
self.__date_fontsize__ = self.text_size
|
self.__date_fontsize__ = self.text_size
|
||||||
self.__date_linespace__ = self.line_spacing
|
self.__date_linespace__ = self.line_spacing
|
||||||
|
|
||||||
def __create_infos_events__ (self):
|
def __create_infos_events__(self):
|
||||||
self.infos = []
|
self.infos = []
|
||||||
self.cell_props = []
|
self.cell_props = []
|
||||||
fetch_day = self.start_dt
|
fetch_day = self.start_dt
|
||||||
|
@ -39,7 +41,7 @@ class AgendaListDesign (DesignEntity):
|
||||||
day_events = self.calendar.get_day_events(fetch_day)
|
day_events = self.calendar.get_day_events(fetch_day)
|
||||||
fetch_day_added_once = False
|
fetch_day_added_once = False
|
||||||
for event in day_events:
|
for event in day_events:
|
||||||
row = [ "" ]
|
row = [""]
|
||||||
if fetch_day_added_once is False:
|
if fetch_day_added_once is False:
|
||||||
row.append(date_summary_str(fetch_day))
|
row.append(date_summary_str(fetch_day))
|
||||||
fetch_day_added_once = True
|
fetch_day_added_once = True
|
||||||
|
@ -49,46 +51,48 @@ class AgendaListDesign (DesignEntity):
|
||||||
row.append(event_prefix_str(event, fetch_day))
|
row.append(event_prefix_str(event, fetch_day))
|
||||||
row.append(event.title)
|
row.append(event.title)
|
||||||
self.cell_props.append(self.__get_row_props__(event))
|
self.cell_props.append(self.__get_row_props__(event))
|
||||||
|
|
||||||
self.infos.append(row)
|
self.infos.append(row)
|
||||||
fetch_day = fetch_day + timedelta(1)
|
fetch_day = fetch_day + timedelta(1)
|
||||||
|
|
||||||
if self.infos[0][1] != date_summary_str(self.start_dt) and self.always_add_start_row:
|
if self.infos[0][1] != date_summary_str(self.start_dt) and self.always_add_start_row:
|
||||||
row = ["", date_summary_str(self.start_dt), "", ""]
|
row = ["", date_summary_str(self.start_dt), "", ""]
|
||||||
props = self.__get_row_props__()
|
props = self.__get_row_props__()
|
||||||
self.infos.insert(0, row)
|
self.infos.insert(0, row)
|
||||||
self.cell_props.insert(0, props)
|
self.cell_props.insert(0, props)
|
||||||
|
|
||||||
def __draw_infos__ (self):
|
def __draw_infos__(self):
|
||||||
table = TableDesign(self.size, self.infos, fontsize = self.__date_fontsize__, line_spacing=self.__date_linespace__, col_spacing = self.col_spacing, cell_properties=self.cell_props)
|
table = TableDesign(self.size, self.infos, fontsize=self.__date_fontsize__,
|
||||||
|
line_spacing=self.__date_linespace__, col_spacing=self.col_spacing, cell_properties=self.cell_props)
|
||||||
self.draw_design(table)
|
self.draw_design(table)
|
||||||
|
|
||||||
def __draw_lines__ (self):
|
def __draw_lines__(self):
|
||||||
for i, (_, date, _, _) in enumerate(self.infos[1:]):
|
for i, (_, date, _, _) in enumerate(self.infos[1:]):
|
||||||
if date is not "":
|
if date is not "":
|
||||||
self.__draw_line__(i + 1)
|
self.__draw_line__(i + 1)
|
||||||
|
|
||||||
def __draw_line__ (self, index):
|
def __draw_line__(self, index):
|
||||||
ypos = index * self.__line_height__ - self.line_spacing / 2
|
ypos = index * self.__line_height__ - self.line_spacing / 2
|
||||||
pos = (0, ypos)
|
pos = (0, ypos)
|
||||||
positions = [ pos, (self.size[0], ypos) ]
|
positions = [pos, (self.size[0], ypos)]
|
||||||
|
|
||||||
ImageDraw.Draw(self.__image__).line(positions, fill=colors["fg"], width=separator_width)
|
ImageDraw.Draw(self.__image__).line(
|
||||||
|
positions, fill=colors["fg"], width=separator_width)
|
||||||
|
|
||||||
def __get_row_props__ (self, event = None):
|
def __get_row_props__(self, event=None):
|
||||||
color = colors["fg"]
|
color = colors["fg"]
|
||||||
bg_color = colors["bg"]
|
bg_color = colors["bg"]
|
||||||
default_cell = {
|
default_cell = {
|
||||||
"color" : color,
|
"color": color,
|
||||||
"background_color" : bg_color
|
"background_color": bg_color
|
||||||
}
|
}
|
||||||
if event is not None and event.highlight:
|
if event is not None and event.highlight:
|
||||||
color = colors["hl"]
|
color = colors["hl"]
|
||||||
cell = {
|
cell = {
|
||||||
"color" : color,
|
"color": color,
|
||||||
"background_color" : bg_color
|
"background_color": bg_color
|
||||||
}
|
}
|
||||||
return [default_cell, default_cell, cell, cell ]
|
return [default_cell, default_cell, cell, cell]
|
||||||
|
|
||||||
def __get_text_height__(self):
|
def __get_text_height__(self):
|
||||||
return ImageFont.truetype(path + defaultfont, self.text_size).font.height
|
return ImageFont.truetype(path + defaultfont, self.text_size).font.height
|
||||||
|
|
|
@ -13,22 +13,25 @@ seperator_width = line_thickness
|
||||||
infolist_size = (1, 0.24)
|
infolist_size = (1, 0.24)
|
||||||
infolist_padding = 0
|
infolist_padding = 0
|
||||||
|
|
||||||
|
|
||||||
class AgendaListPanel (PanelDesign):
|
class AgendaListPanel (PanelDesign):
|
||||||
'''Lists upcoming events in chronological order and groups them by days'''
|
'''Lists upcoming events in chronological order and groups them by days'''
|
||||||
|
|
||||||
def __init__(self, size):
|
def __init__(self, size):
|
||||||
super(AgendaListPanel, self).__init__(size)
|
super(AgendaListPanel, self).__init__(size)
|
||||||
self.weather_size = (0, 0)
|
self.weather_size = (0, 0)
|
||||||
self.info_size = (0, 0)
|
self.info_size = (0, 0)
|
||||||
if general_settings["weather-info"]:
|
if general_settings["weather-info"]:
|
||||||
self.weather_size = (self.size[0], self.size[1] * weatherheader_height)
|
self.weather_size = (
|
||||||
|
self.size[0], self.size[1] * weatherheader_height)
|
||||||
|
|
||||||
def add_weather (self, weather):
|
def add_weather(self, weather):
|
||||||
self.weather = weather
|
self.weather = weather
|
||||||
|
|
||||||
def add_calendar (self, calendar):
|
def add_calendar(self, calendar):
|
||||||
self.calendar = calendar
|
self.calendar = calendar
|
||||||
|
|
||||||
def add_rssfeed (self, rss):
|
def add_rssfeed(self, rss):
|
||||||
if general_settings["info-area"] != "rss":
|
if general_settings["info-area"] != "rss":
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -41,10 +44,10 @@ class AgendaListPanel (PanelDesign):
|
||||||
|
|
||||||
self.__draw_seperator__(1-infolist_size[1], colors["fg"])
|
self.__draw_seperator__(1-infolist_size[1], colors["fg"])
|
||||||
|
|
||||||
def add_tasks (self, tasks):
|
def add_tasks(self, tasks):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_crypto (self, crypto):
|
def add_crypto(self, crypto):
|
||||||
if general_settings["info-area"] != "crypto":
|
if general_settings["info-area"] != "crypto":
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -64,16 +67,18 @@ class AgendaListPanel (PanelDesign):
|
||||||
if general_settings["weather-info"]:
|
if general_settings["weather-info"]:
|
||||||
self.__draw_weather__()
|
self.__draw_weather__()
|
||||||
|
|
||||||
def __draw_seperator__ (self, height, color):
|
def __draw_seperator__(self, height, color):
|
||||||
ImageDraw.Draw(self.__image__).line([ self.__abs_pos__((0, height)), self.__abs_pos__((1, height)) ], fill=color, width=seperator_width)
|
ImageDraw.Draw(self.__image__).line([self.__abs_pos__(
|
||||||
|
(0, height)), self.__abs_pos__((1, height))], fill=color, width=seperator_width)
|
||||||
|
|
||||||
def __abs_pos__ (self, pos, size = None):
|
def __abs_pos__(self, pos, size=None):
|
||||||
if size is None:
|
if size is None:
|
||||||
size = self.size
|
size = self.size
|
||||||
return (int(pos[0] * size[0]), int(pos[1] * size[1]))
|
return (int(pos[0] * size[0]), int(pos[1] * size[1]))
|
||||||
|
|
||||||
def __draw_calendar__(self):
|
def __draw_calendar__(self):
|
||||||
size = (self.size[0], self.size[1] - self.weather_size[1] - self.info_size[1] - agenda_ypadding)
|
size = (self.size[0], self.size[1] - self.weather_size[1] -
|
||||||
|
self.info_size[1] - agenda_ypadding)
|
||||||
|
|
||||||
agenda = AgendaListDesign(size, self.calendar)
|
agenda = AgendaListDesign(size, self.calendar)
|
||||||
agenda.pos = (0, agenda_ypadding + self.weather_size[1])
|
agenda.pos = (0, agenda_ypadding + self.weather_size[1])
|
||||||
|
@ -82,4 +87,4 @@ class AgendaListPanel (PanelDesign):
|
||||||
def __draw_weather__(self):
|
def __draw_weather__(self):
|
||||||
header = WeatherHeaderDesign(self.weather_size, self.weather)
|
header = WeatherHeaderDesign(self.weather_size, self.weather)
|
||||||
self.draw_design(header)
|
self.draw_design(header)
|
||||||
self.__draw_seperator__(weatherheader_height, colors["hl"])
|
self.__draw_seperator__(weatherheader_height, colors["hl"])
|
||||||
|
|
|
@ -9,43 +9,43 @@ path = os.path.dirname(os.path.abspath(__file__)).replace("\\", "/")
|
||||||
if path != "" and path[-1] != "/":
|
if path != "" and path[-1] != "/":
|
||||||
path += "/"
|
path += "/"
|
||||||
|
|
||||||
wpath = path+'weather-icons/'
|
wpath = path+'weather-icons/'
|
||||||
opath = path+'other/'
|
opath = path+'other/'
|
||||||
fpath = 'fonts/'
|
fpath = 'fonts/'
|
||||||
|
|
||||||
tempicon = im_open(opath+'temperature.jpeg')
|
tempicon = im_open(opath+'temperature.jpeg')
|
||||||
humicon = im_open(opath+'humidity.jpeg')
|
humicon = im_open(opath+'humidity.jpeg')
|
||||||
no_response= im_open(opath+'cloud-no-response.jpeg')
|
no_response = im_open(opath+'cloud-no-response.jpeg')
|
||||||
sunriseicon = im_open(opath+'wi-sunrise.jpeg')
|
sunriseicon = im_open(opath+'wi-sunrise.jpeg')
|
||||||
sunseticon = im_open(opath+'wi-sunset.jpeg')
|
sunseticon = im_open(opath+'wi-sunset.jpeg')
|
||||||
windicon = im_open(opath+'wi-strong-wind.jpeg')
|
windicon = im_open(opath+'wi-strong-wind.jpeg')
|
||||||
|
|
||||||
fonts = {
|
fonts = {
|
||||||
"extralight" : fpath + "Assistant-ExtraLight.otf",
|
"extralight": fpath + "Assistant-ExtraLight.otf",
|
||||||
"light" : fpath + "Assistant-Light.otf",
|
"light": fpath + "Assistant-Light.otf",
|
||||||
"regular" : fpath + "Assistant-Regular.otf",
|
"regular": fpath + "Assistant-Regular.otf",
|
||||||
"semibold" : fpath + "Assistant-SemiBold.otf",
|
"semibold": fpath + "Assistant-SemiBold.otf",
|
||||||
"bold" : fpath + "Assistant-Bold.otf",
|
"bold": fpath + "Assistant-Bold.otf",
|
||||||
"extrabold" : fpath + "Assistant-ExtraBold.otf"
|
"extrabold": fpath + "Assistant-ExtraBold.otf"
|
||||||
}
|
}
|
||||||
|
|
||||||
defaultfont = fonts[font_boldness]
|
defaultfont = fonts[font_boldness]
|
||||||
defaultfontsize = int(font_size)
|
defaultfontsize = int(font_size)
|
||||||
|
|
||||||
weathericons = {
|
weathericons = {
|
||||||
'01d': 'wi-day-sunny', '02d':'wi-day-cloudy', '03d': 'wi-cloudy',
|
'01d': 'wi-day-sunny', '02d': 'wi-day-cloudy', '03d': 'wi-cloudy',
|
||||||
'04d': 'wi-cloudy-windy', '09d': 'wi-showers', '10d':'wi-rain',
|
'04d': 'wi-cloudy-windy', '09d': 'wi-showers', '10d': 'wi-rain',
|
||||||
'11d':'wi-thunderstorm', '13d':'wi-snow', '50d': 'wi-fog',
|
'11d': 'wi-thunderstorm', '13d': 'wi-snow', '50d': 'wi-fog',
|
||||||
'01n': 'wi-night-clear', '02n':'wi-night-cloudy',
|
'01n': 'wi-night-clear', '02n': 'wi-night-cloudy',
|
||||||
'03n': 'wi-night-cloudy', '04n': 'wi-night-cloudy',
|
'03n': 'wi-night-cloudy', '04n': 'wi-night-cloudy',
|
||||||
'09n': 'wi-night-showers', '10n':'wi-night-rain',
|
'09n': 'wi-night-showers', '10n': 'wi-night-rain',
|
||||||
'11n':'wi-night-thunderstorm', '13n':'wi-night-snow',
|
'11n': 'wi-night-thunderstorm', '13n': 'wi-night-snow',
|
||||||
'50n': 'wi-night-alt-cloudy-windy'}
|
'50n': 'wi-night-alt-cloudy-windy'}
|
||||||
|
|
||||||
colors = {
|
colors = {
|
||||||
"hl" : "red",
|
"hl": "red",
|
||||||
"fg" : "black",
|
"fg": "black",
|
||||||
"bg" : "white"
|
"bg": "white"
|
||||||
}
|
}
|
||||||
|
|
||||||
supported_img_formats = [
|
supported_img_formats = [
|
||||||
|
@ -92,4 +92,4 @@ supported_img_formats = [
|
||||||
"PSD",
|
"PSD",
|
||||||
"WAL",
|
"WAL",
|
||||||
"XPM",
|
"XPM",
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
from DesignEntity import DesignEntity
|
from DesignEntity import DesignEntity
|
||||||
from PIL import ImageDraw, ImageOps
|
from PIL import ImageDraw, ImageOps
|
||||||
|
|
||||||
|
|
||||||
class BoxDesign (DesignEntity):
|
class BoxDesign (DesignEntity):
|
||||||
"""Redefinition of ImageDraw.Draw.Rectangle"""
|
"""Redefinition of ImageDraw.Draw.Rectangle"""
|
||||||
|
|
||||||
def __init__(self, size, fill=None, outline=None, width=0):
|
def __init__(self, size, fill=None, outline=None, width=0):
|
||||||
super(BoxDesign, self).__init__((size[0]+1, size[1]+1), mask=True)
|
super(BoxDesign, self).__init__((size[0]+1, size[1]+1), mask=True)
|
||||||
self.size = size
|
self.size = size
|
||||||
|
@ -12,9 +14,10 @@ class BoxDesign (DesignEntity):
|
||||||
self.width = width
|
self.width = width
|
||||||
|
|
||||||
def __define_corners__(self):
|
def __define_corners__(self):
|
||||||
topleft = (0,0)
|
topleft = (0, 0)
|
||||||
bottomright = self.size
|
bottomright = self.size
|
||||||
self.corners = [topleft, bottomright]
|
self.corners = [topleft, bottomright]
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
ImageDraw.Draw(self.__image__).rectangle(self.corners, fill=self.fill, outline=self.outline, width=self.width)
|
ImageDraw.Draw(self.__image__).rectangle(
|
||||||
|
self.corners, fill=self.fill, outline=self.outline, width=self.width)
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
class CalendarEvent (object):
|
class CalendarEvent (object):
|
||||||
"""Defines a calendar event, independent of any implementation"""
|
"""Defines a calendar event, independent of any implementation"""
|
||||||
def __init__ (self):
|
|
||||||
|
def __init__(self):
|
||||||
self.begin_datetime = None
|
self.begin_datetime = None
|
||||||
self.end_datetime = None
|
self.end_datetime = None
|
||||||
self.duration = None
|
self.duration = None
|
||||||
|
@ -19,4 +20,4 @@ class CalendarEvent (object):
|
||||||
self.fetch_datetime = None
|
self.fetch_datetime = None
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
return self.title
|
return self.title
|
||||||
|
|
|
@ -4,31 +4,34 @@ from dateutil.rrule import rrulestr
|
||||||
from dateutil.parser import parse
|
from dateutil.parser import parse
|
||||||
import calendar
|
import calendar
|
||||||
|
|
||||||
|
|
||||||
class CalendarInterface (DataSourceInterface):
|
class CalendarInterface (DataSourceInterface):
|
||||||
"""Interface for fetching and processing calendar event information."""
|
"""Interface for fetching and processing calendar event information."""
|
||||||
def __init__ (self):
|
|
||||||
|
def __init__(self):
|
||||||
self.events = []
|
self.events = []
|
||||||
|
|
||||||
def reload (self):
|
def reload(self):
|
||||||
if self.is_available() == False:
|
if self.is_available() == False:
|
||||||
return
|
return
|
||||||
self.events = self.__get_events__()
|
self.events = self.__get_events__()
|
||||||
self.events = self.__sort_events__(self.events)
|
self.events = self.__sort_events__(self.events)
|
||||||
|
|
||||||
def __sort_events__ (self, events):
|
def __sort_events__(self, events):
|
||||||
events.sort(key=lambda x : x.begin_datetime)
|
events.sort(key=lambda x: x.begin_datetime)
|
||||||
return events
|
return events
|
||||||
|
|
||||||
def __sort_event_types__ (self, events):
|
def __sort_event_types__(self, events):
|
||||||
multiday = [ev for ev in events if ev.multiday]
|
multiday = [ev for ev in events if ev.multiday]
|
||||||
allday = [ev for ev in events if ev.allday and ev.multiday == False]
|
allday = [ev for ev in events if ev.allday and ev.multiday == False]
|
||||||
timed = [ev for ev in events if ev.allday == False and ev.multiday == False]
|
timed = [ev for ev in events if ev.allday ==
|
||||||
|
False and ev.multiday == False]
|
||||||
return multiday + allday + timed
|
return multiday + allday + timed
|
||||||
|
|
||||||
def __get_events__ (self):
|
def __get_events__(self):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
def get_upcoming_events (self, timespan = None, start_time = None):
|
def get_upcoming_events(self, timespan=None, start_time=None):
|
||||||
if timespan is None:
|
if timespan is None:
|
||||||
timespan = timedelta(31)
|
timespan = timedelta(31)
|
||||||
if start_time == None:
|
if start_time == None:
|
||||||
|
@ -36,28 +39,31 @@ class CalendarInterface (DataSourceInterface):
|
||||||
start_time = datetime.now(local_tzinfo)
|
start_time = datetime.now(local_tzinfo)
|
||||||
return self.__get_events_in_range__(start_time, timespan)
|
return self.__get_events_in_range__(start_time, timespan)
|
||||||
|
|
||||||
def get_today_events (self):
|
def get_today_events(self):
|
||||||
return self.get_day_events(date.today())
|
return self.get_day_events(date.today())
|
||||||
|
|
||||||
def get_day_events (self, day):
|
def get_day_events(self, day):
|
||||||
if type(day) is not type(date.today()):
|
if type(day) is not type(date.today()):
|
||||||
raise TypeError("get_day_events only takes date-objects as parameters, not \"%s\"" % str(type(day)))
|
raise TypeError(
|
||||||
|
"get_day_events only takes date-objects as parameters, not \"%s\"" % str(type(day)))
|
||||||
local_tzinfo = datetime.now(timezone.utc).astimezone().tzinfo
|
local_tzinfo = datetime.now(timezone.utc).astimezone().tzinfo
|
||||||
day_start = datetime(day.year, day.month, day.day, 0, 0, 0, 0, local_tzinfo)
|
day_start = datetime(day.year, day.month, day.day,
|
||||||
|
0, 0, 0, 0, local_tzinfo)
|
||||||
return self.__get_events_in_range__(day_start, timedelta(1))
|
return self.__get_events_in_range__(day_start, timedelta(1))
|
||||||
|
|
||||||
def get_month_events (self, month = -1, year = -1):
|
def get_month_events(self, month=-1, year=-1):
|
||||||
if month < 0:
|
if month < 0:
|
||||||
month = datetime.now().month
|
month = datetime.now().month
|
||||||
if year < 0:
|
if year < 0:
|
||||||
year = datetime.now().year
|
year = datetime.now().year
|
||||||
|
|
||||||
local_tzinfo = datetime.now(timezone.utc).astimezone().tzinfo
|
local_tzinfo = datetime.now(timezone.utc).astimezone().tzinfo
|
||||||
month_start = datetime(year, month, 1, 0, 0, 0, 0, local_tzinfo)
|
month_start = datetime(year, month, 1, 0, 0, 0, 0, local_tzinfo)
|
||||||
month_days = calendar.monthrange(month_start.year, month_start.month)[1]
|
month_days = calendar.monthrange(
|
||||||
|
month_start.year, month_start.month)[1]
|
||||||
return self.__get_events_in_range__(month_start, timedelta(month_days))
|
return self.__get_events_in_range__(month_start, timedelta(month_days))
|
||||||
|
|
||||||
def __get_events_in_range__ (self, start, duration):
|
def __get_events_in_range__(self, start, duration):
|
||||||
if self.events is None:
|
if self.events is None:
|
||||||
return []
|
return []
|
||||||
|
|
||||||
|
@ -66,14 +72,15 @@ class CalendarInterface (DataSourceInterface):
|
||||||
|
|
||||||
events_in_range = []
|
events_in_range = []
|
||||||
for event in self.events:
|
for event in self.events:
|
||||||
event_occurrence = self.__get_if_event_in_range__(event, start, duration)
|
event_occurrence = self.__get_if_event_in_range__(
|
||||||
|
event, start, duration)
|
||||||
if event_occurrence:
|
if event_occurrence:
|
||||||
events_in_range.extend(event_occurrence)
|
events_in_range.extend(event_occurrence)
|
||||||
|
|
||||||
events_in_range = self.__sort_events__(events_in_range)
|
events_in_range = self.__sort_events__(events_in_range)
|
||||||
return self.__sort_event_types__(events_in_range)
|
return self.__sort_event_types__(events_in_range)
|
||||||
|
|
||||||
def __get_if_event_in_range__ (self, event, start, duration):
|
def __get_if_event_in_range__(self, event, start, duration):
|
||||||
'''Returns list or None'''
|
'''Returns list or None'''
|
||||||
if event is None:
|
if event is None:
|
||||||
return None
|
return None
|
||||||
|
@ -83,7 +90,7 @@ class CalendarInterface (DataSourceInterface):
|
||||||
else:
|
else:
|
||||||
return self.__is_repeating_in_range__(event, start, duration)
|
return self.__is_repeating_in_range__(event, start, duration)
|
||||||
|
|
||||||
def __is_onetime_in_range__ (self, event, start, duration):
|
def __is_onetime_in_range__(self, event, start, duration):
|
||||||
if event.begin_datetime > start:
|
if event.begin_datetime > start:
|
||||||
first_start = start
|
first_start = start
|
||||||
first_duration = duration
|
first_duration = duration
|
||||||
|
@ -94,37 +101,39 @@ class CalendarInterface (DataSourceInterface):
|
||||||
second_start = start
|
second_start = start
|
||||||
|
|
||||||
if (second_start - first_start) < first_duration:
|
if (second_start - first_start) < first_duration:
|
||||||
return [ event ]
|
return [event]
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __is_repeating_in_range__ (self, event, start, duration):
|
def __is_repeating_in_range__(self, event, start, duration):
|
||||||
end = start + duration
|
end = start + duration
|
||||||
occurrences = []
|
occurrences = []
|
||||||
|
|
||||||
try:
|
try:
|
||||||
r_string=""
|
r_string = ""
|
||||||
r_string=self.__add_timezoneawarness__(event.rrule)
|
r_string = self.__add_timezoneawarness__(event.rrule)
|
||||||
rule=rrulestr(r_string,dtstart=event.begin_datetime)
|
rule = rrulestr(r_string, dtstart=event.begin_datetime)
|
||||||
for occurrence in rule:
|
for occurrence in rule:
|
||||||
if occurrence - end > timedelta(0):
|
if occurrence - end > timedelta(0):
|
||||||
return occurrences
|
return occurrences
|
||||||
merged_event = self.__merge_event_data__(event, start=occurrence)
|
merged_event = self.__merge_event_data__(
|
||||||
|
event, start=occurrence)
|
||||||
if self.__is_onetime_in_range__(merged_event, start, duration):
|
if self.__is_onetime_in_range__(merged_event, start, duration):
|
||||||
occurrences.append(merged_event)
|
occurrences.append(merged_event)
|
||||||
return occurrences
|
return occurrences
|
||||||
except Exception as ex:
|
except Exception as ex:
|
||||||
print("\"is_repeating_in_range\" failed while processing: dtstart="+str(event.begin_datetime)+" dtstart.tzinfo="+str(event.begin_datetime.tzinfo)+" rrule="+r_string)
|
print("\"is_repeating_in_range\" failed while processing: dtstart="+str(event.begin_datetime) +
|
||||||
|
" dtstart.tzinfo="+str(event.begin_datetime.tzinfo)+" rrule="+r_string)
|
||||||
raise ex
|
raise ex
|
||||||
|
|
||||||
def __merge_event_data__ (self, event, start = None):
|
def __merge_event_data__(self, event, start=None):
|
||||||
if start is not None:
|
if start is not None:
|
||||||
event.begin_datetime = start
|
event.begin_datetime = start
|
||||||
event.end_datetime = start + event.duration
|
event.end_datetime = start + event.duration
|
||||||
|
|
||||||
return event
|
return event
|
||||||
|
|
||||||
def __add_timezoneawarness__ (self, rrule):
|
def __add_timezoneawarness__(self, rrule):
|
||||||
"""UNTIL must be specified in UTC when DTSTART is timezone-aware (which it is)"""
|
"""UNTIL must be specified in UTC when DTSTART is timezone-aware (which it is)"""
|
||||||
if "UNTIL" not in rrule:
|
if "UNTIL" not in rrule:
|
||||||
return rrule
|
return rrule
|
||||||
|
@ -137,8 +146,8 @@ class CalendarInterface (DataSourceInterface):
|
||||||
tz_index = until_index + len(until_template)
|
tz_index = until_index + len(until_template)
|
||||||
if until_index < 0 or (tz_index < len(rrule) and rrule[tz_index] is "T"):
|
if until_index < 0 or (tz_index < len(rrule) and rrule[tz_index] is "T"):
|
||||||
return rrule
|
return rrule
|
||||||
|
|
||||||
if tz_index == len(rrule):
|
if tz_index == len(rrule):
|
||||||
return rrule + timezone_str
|
return rrule + timezone_str
|
||||||
else:
|
else:
|
||||||
return rrule[:tz_index] + timezone_str + rrule[tz_index:]
|
return rrule[:tz_index] + timezone_str + rrule[tz_index:]
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
class CryptoCoin(object):
|
class CryptoCoin(object):
|
||||||
def __init__ (self):
|
def __init__(self):
|
||||||
self.name = None
|
self.name = None
|
||||||
self.symbol = None
|
self.symbol = None
|
||||||
self.price = None
|
self.price = None
|
||||||
|
@ -7,4 +7,4 @@ class CryptoCoin(object):
|
||||||
self.currency = None
|
self.currency = None
|
||||||
self.datetime = None
|
self.datetime = None
|
||||||
|
|
||||||
self.fetch_datetime = None
|
self.fetch_datetime = None
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
from DataSourceInterface import DataSourceInterface
|
from DataSourceInterface import DataSourceInterface
|
||||||
|
|
||||||
|
|
||||||
class CryptoInterface(DataSourceInterface):
|
class CryptoInterface(DataSourceInterface):
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.crypto_coins = []
|
self.crypto_coins = []
|
||||||
|
|
|
@ -6,27 +6,30 @@ from settings import crypto_coins
|
||||||
|
|
||||||
xpadding = 5
|
xpadding = 5
|
||||||
|
|
||||||
|
|
||||||
class CryptoListDesign (DesignEntity):
|
class CryptoListDesign (DesignEntity):
|
||||||
def __init__ (self, size, crypto, text_size = defaultfontsize):
|
def __init__(self, size, crypto, text_size=defaultfontsize):
|
||||||
super(CryptoListDesign, self).__init__(size)
|
super(CryptoListDesign, self).__init__(size)
|
||||||
self.crypto = crypto
|
self.crypto = crypto
|
||||||
self.text_size = text_size
|
self.text_size = text_size
|
||||||
self.matrix = self.__get_matrix__()
|
self.matrix = self.__get_matrix__()
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
col_spacing = 10
|
col_spacing = 10
|
||||||
if len(self.matrix) > 0:
|
if len(self.matrix) > 0:
|
||||||
col_spacing = (self.size[0] / len(self.matrix[0])) * 0.5
|
col_spacing = (self.size[0] / len(self.matrix[0])) * 0.5
|
||||||
|
|
||||||
table_design = TableDesign(self.size, matrix=self.matrix, col_spacing=col_spacing, fontsize = self.text_size, mask=False, truncate_rows=True)
|
table_design = TableDesign(self.size, matrix=self.matrix, col_spacing=col_spacing,
|
||||||
table_design.pos = (xpadding, 0)
|
fontsize=self.text_size, mask=False, truncate_rows=True)
|
||||||
|
table_design.pos = (xpadding, 0)
|
||||||
self.draw_design(table_design)
|
self.draw_design(table_design)
|
||||||
|
|
||||||
def __get_matrix__ (self):
|
def __get_matrix__(self):
|
||||||
matrix = []
|
matrix = []
|
||||||
coins = self.crypto.get_coins()
|
coins = self.crypto.get_coins()
|
||||||
for coin in coins:
|
for coin in coins:
|
||||||
row = [ coin.symbol.upper(), coin.name, coin.currency + " " + str(coin.price), "% " + str(coin.day_change) ]
|
row = [coin.symbol.upper(), coin.name, coin.currency + " " +
|
||||||
|
str(coin.price), "% " + str(coin.day_change)]
|
||||||
matrix.append(row)
|
matrix.append(row)
|
||||||
return matrix
|
return matrix
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
class DataSourceInterface (object):
|
class DataSourceInterface (object):
|
||||||
"""Interface for child interfaces that fetch data."""
|
"""Interface for child interfaces that fetch data."""
|
||||||
def is_available (self):
|
|
||||||
|
def is_available(self):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
def reload (self):
|
def reload(self):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
|
@ -4,8 +4,10 @@ from TextDesign import TextDesign
|
||||||
|
|
||||||
header_height = 0.2
|
header_height = 0.2
|
||||||
|
|
||||||
|
|
||||||
class DayBoxDesign (DesignEntity):
|
class DayBoxDesign (DesignEntity):
|
||||||
"""Represents a day with its events in a box."""
|
"""Represents a day with its events in a box."""
|
||||||
|
|
||||||
def __init__(self, size, date):
|
def __init__(self, size, date):
|
||||||
super(DayBoxDesign, self).__init__(size)
|
super(DayBoxDesign, self).__init__(size)
|
||||||
self.date = date
|
self.date = date
|
||||||
|
@ -28,4 +30,4 @@ class DayBoxDesign (DesignEntity):
|
||||||
|
|
||||||
event_list = SingelDayEventListDesign(size, events)
|
event_list = SingelDayEventListDesign(size, events)
|
||||||
event_list.pos = pos
|
event_list.pos = pos
|
||||||
self.draw_design(event_list)
|
self.draw_design(event_list)
|
||||||
|
|
|
@ -27,62 +27,71 @@ numberbox_font_color = colors["bg"]
|
||||||
numberbox_background_color = colors["hl"]
|
numberbox_background_color = colors["hl"]
|
||||||
weekday_font = fonts["bold"]
|
weekday_font = fonts["bold"]
|
||||||
|
|
||||||
|
|
||||||
class DayHeaderDesign (DesignEntity):
|
class DayHeaderDesign (DesignEntity):
|
||||||
"""Detailed and big view of a given date."""
|
"""Detailed and big view of a given date."""
|
||||||
def __init__ (self, size, date):
|
|
||||||
|
def __init__(self, size, date):
|
||||||
super(DayHeaderDesign, self).__init__(size)
|
super(DayHeaderDesign, self).__init__(size)
|
||||||
self.weather_column_width = 0
|
self.weather_column_width = 0
|
||||||
self.date = date
|
self.date = date
|
||||||
|
|
||||||
def add_weather (self, weather):
|
def add_weather(self, weather):
|
||||||
if general_settings["weather-info"] == False:
|
if general_settings["weather-info"] == False:
|
||||||
return
|
return
|
||||||
|
|
||||||
forecast = weather.get_forecast_in_days(self.date.day - date.today().day)
|
forecast = weather.get_forecast_in_days(
|
||||||
|
self.date.day - date.today().day)
|
||||||
self.weather_column_width = weathercolumn_y_size[0] * self.size[1]
|
self.weather_column_width = weathercolumn_y_size[0] * self.size[1]
|
||||||
size = (self.weather_column_width, weathercolumn_y_size[1] * self.size[1])
|
size = (self.weather_column_width,
|
||||||
|
weathercolumn_y_size[1] * self.size[1])
|
||||||
pos = (self.size[0] - size[0], 0)
|
pos = (self.size[0] - size[0], 0)
|
||||||
|
|
||||||
design = WeatherColumnDesign(size, forecast)
|
design = WeatherColumnDesign(size, forecast)
|
||||||
design.pos = pos
|
design.pos = pos
|
||||||
self.draw_design(design)
|
self.draw_design(design)
|
||||||
|
|
||||||
def add_calendar (self, calendar):
|
def add_calendar(self, calendar):
|
||||||
local_tzinfo = datetime.now(timezone.utc).astimezone().tzinfo
|
local_tzinfo = datetime.now(timezone.utc).astimezone().tzinfo
|
||||||
now = datetime.now(local_tzinfo)
|
now = datetime.now(local_tzinfo)
|
||||||
time_until_tomorrow = (datetime(now.year, now.month, now.day, 0, 0, 0, 0, local_tzinfo) + timedelta(1)) - now
|
time_until_tomorrow = (datetime(
|
||||||
self.__draw_event_list__(calendar.get_upcoming_events(time_until_tomorrow, now))
|
now.year, now.month, now.day, 0, 0, 0, 0, local_tzinfo) + timedelta(1)) - now
|
||||||
|
self.__draw_event_list__(
|
||||||
|
calendar.get_upcoming_events(time_until_tomorrow, now))
|
||||||
|
|
||||||
def add_events (self, events):
|
def add_events(self, events):
|
||||||
self.__draw_event_list__(events)
|
self.__draw_event_list__(events)
|
||||||
|
|
||||||
def add_rssfeed (self, rss):
|
def add_rssfeed(self, rss):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_crypto (self, crypto):
|
def add_crypto(self, crypto):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
self.__draw_number_square__()
|
self.__draw_number_square__()
|
||||||
self.__draw_month__()
|
self.__draw_month__()
|
||||||
|
|
||||||
def __draw_event_list__ (self, events):
|
def __draw_event_list__(self, events):
|
||||||
box_ypos = numberbox_ypos * self.size[1]
|
box_ypos = numberbox_ypos * self.size[1]
|
||||||
box_xpos = numberbox_ypos * self.size[1]
|
box_xpos = numberbox_ypos * self.size[1]
|
||||||
box_height = numberbox_height * self.size[1]
|
box_height = numberbox_height * self.size[1]
|
||||||
xpadding = eventlist_xpadding * self.size[0]
|
xpadding = eventlist_xpadding * self.size[0]
|
||||||
ypadding = eventlist_ypadding * self.size[1]
|
ypadding = eventlist_ypadding * self.size[1]
|
||||||
monthbox_height = (monthbox_ypadding + month_height) * self.size[1]
|
monthbox_height = (monthbox_ypadding + month_height) * self.size[1]
|
||||||
pos = (box_xpos + box_height + xpadding, box_ypos + monthbox_height + ypadding)
|
pos = (box_xpos + box_height + xpadding,
|
||||||
size = (self.size[0] - pos[0] - self.weather_column_width, self.size[1] - pos[1] - box_ypos)
|
box_ypos + monthbox_height + ypadding)
|
||||||
|
size = (self.size[0] - pos[0] - self.weather_column_width,
|
||||||
|
self.size[1] - pos[1] - box_ypos)
|
||||||
fontsize = eventlist_static_fontsize
|
fontsize = eventlist_static_fontsize
|
||||||
|
|
||||||
rel_dates = [self.date for _ in range(len(events))]
|
rel_dates = [self.date for _ in range(len(events))]
|
||||||
event_list = SingelDayEventListDesign(size, events, fontsize, event_prefix_rel_dates = rel_dates)
|
event_list = SingelDayEventListDesign(
|
||||||
|
size, events, fontsize, event_prefix_rel_dates=rel_dates)
|
||||||
event_list.pos = pos
|
event_list.pos = pos
|
||||||
self.draw_design(event_list)
|
self.draw_design(event_list)
|
||||||
|
|
||||||
def __draw_month__ (self):
|
def __draw_month__(self):
|
||||||
font_size = int(month_height * self.size[1])
|
font_size = int(month_height * self.size[1])
|
||||||
xpadding = int(monthbox_xpadding * self.size[0])
|
xpadding = int(monthbox_xpadding * self.size[0])
|
||||||
ypadding = int(monthbox_ypadding * self.size[1])
|
ypadding = int(monthbox_ypadding * self.size[1])
|
||||||
|
@ -96,20 +105,20 @@ class DayHeaderDesign (DesignEntity):
|
||||||
month.pos = box_pos
|
month.pos = box_pos
|
||||||
self.draw_design(month)
|
self.draw_design(month)
|
||||||
|
|
||||||
def __draw_number_square__ (self):
|
def __draw_number_square__(self):
|
||||||
box_height = numberbox_height * self.size[1]
|
box_height = numberbox_height * self.size[1]
|
||||||
box_ypos = numberbox_ypos * self.size[1]
|
box_ypos = numberbox_ypos * self.size[1]
|
||||||
box_pos = (box_ypos, box_ypos)
|
box_pos = (box_ypos, box_ypos)
|
||||||
box_size = (box_height, box_height)
|
box_size = (box_height, box_height)
|
||||||
|
|
||||||
box = BoxDesign(box_size, fill = numberbox_background_color)
|
box = BoxDesign(box_size, fill=numberbox_background_color)
|
||||||
box.pos = box_pos
|
box.pos = box_pos
|
||||||
self.draw_design(box)
|
self.draw_design(box)
|
||||||
|
|
||||||
self.__draw_today_number__()
|
self.__draw_today_number__()
|
||||||
self.__draw_weekday__()
|
self.__draw_weekday__()
|
||||||
|
|
||||||
def __draw_today_number__ (self):
|
def __draw_today_number__(self):
|
||||||
font_size = number_height * self.size[1]
|
font_size = number_height * self.size[1]
|
||||||
box_height = numberbox_height * self.size[1]
|
box_height = numberbox_height * self.size[1]
|
||||||
box_ypos = numberbox_ypos * self.size[1]
|
box_ypos = numberbox_ypos * self.size[1]
|
||||||
|
@ -118,12 +127,13 @@ class DayHeaderDesign (DesignEntity):
|
||||||
pos = (box_ypos, box_ypos + ypadding)
|
pos = (box_ypos, box_ypos + ypadding)
|
||||||
|
|
||||||
day_text = self.__get_day_text__()
|
day_text = self.__get_day_text__()
|
||||||
number = TextDesign(size, text=day_text, background_color=numberbox_background_color, color=numberbox_font_color, fontsize=font_size, horizontalalignment="center", verticalalignment="center")
|
number = TextDesign(size, text=day_text, background_color=numberbox_background_color,
|
||||||
|
color=numberbox_font_color, fontsize=font_size, horizontalalignment="center", verticalalignment="center")
|
||||||
number.pos = pos
|
number.pos = pos
|
||||||
number.mask = False
|
number.mask = False
|
||||||
self.draw_design(number)
|
self.draw_design(number)
|
||||||
|
|
||||||
def __draw_weekday__ (self):
|
def __draw_weekday__(self):
|
||||||
font_size = weekday_height * self.size[1]
|
font_size = weekday_height * self.size[1]
|
||||||
box_height = numberbox_height * self.size[1]
|
box_height = numberbox_height * self.size[1]
|
||||||
size = (box_height, weekdaybox_height * box_height)
|
size = (box_height, weekdaybox_height * box_height)
|
||||||
|
@ -131,13 +141,14 @@ class DayHeaderDesign (DesignEntity):
|
||||||
pos = (box_ypos, box_ypos)
|
pos = (box_ypos, box_ypos)
|
||||||
|
|
||||||
week_day_name = self.date.strftime("%A")
|
week_day_name = self.date.strftime("%A")
|
||||||
week_day = TextDesign(size, text=week_day_name, background_color=numberbox_background_color, color=numberbox_font_color, fontsize=font_size, horizontalalignment="center", verticalalignment = "center", font=weekday_font)
|
week_day = TextDesign(size, text=week_day_name, background_color=numberbox_background_color, color=numberbox_font_color,
|
||||||
|
fontsize=font_size, horizontalalignment="center", verticalalignment="center", font=weekday_font)
|
||||||
week_day.pos = pos
|
week_day.pos = pos
|
||||||
week_day.mask = False
|
week_day.mask = False
|
||||||
self.draw_design(week_day)
|
self.draw_design(week_day)
|
||||||
|
|
||||||
def __abs_co__ (self, coordinates):
|
def __abs_co__(self, coordinates):
|
||||||
return (int(coordinates[0] * self.size[0]),int(coordinates[1] * self.size[1]))
|
return (int(coordinates[0] * self.size[0]), int(coordinates[1] * self.size[1]))
|
||||||
|
|
||||||
def __get_day_text__ (self):
|
def __get_day_text__(self):
|
||||||
return str(self.date.day)
|
return str(self.date.day)
|
||||||
|
|
|
@ -12,8 +12,8 @@ from CryptoListDesign import CryptoListDesign
|
||||||
from settings import line_thickness
|
from settings import line_thickness
|
||||||
from math import ceil
|
from math import ceil
|
||||||
|
|
||||||
todayheader_pos = (0,0)
|
todayheader_pos = (0, 0)
|
||||||
todayheader_size = (1,0.25)
|
todayheader_size = (1, 0.25)
|
||||||
lines_thickness = line_thickness
|
lines_thickness = line_thickness
|
||||||
infoarea_replacedrowscount = 3
|
infoarea_replacedrowscount = 3
|
||||||
|
|
||||||
|
@ -24,43 +24,46 @@ dayrow_max_format = 70 / 384
|
||||||
rss_y_padding = 5
|
rss_y_padding = 5
|
||||||
crypto_y_padding = 5
|
crypto_y_padding = 5
|
||||||
|
|
||||||
|
|
||||||
class DayListPanel (PanelDesign):
|
class DayListPanel (PanelDesign):
|
||||||
"""Overview that focuses on the current day and
|
"""Overview that focuses on the current day and
|
||||||
lists following days in a list below."""
|
lists following days in a list below."""
|
||||||
def __init__ (self, size):
|
|
||||||
|
def __init__(self, size):
|
||||||
super(DayListPanel, self).__init__(size)
|
super(DayListPanel, self).__init__(size)
|
||||||
self.__day_rows__ = []
|
self.__day_rows__ = []
|
||||||
self.__calc_dayrow_size__()
|
self.__calc_dayrow_size__()
|
||||||
self.__first_render__()
|
self.__first_render__()
|
||||||
|
|
||||||
def __first_render__ (self):
|
def __first_render__(self):
|
||||||
self.__draw_today_header__()
|
self.__draw_today_header__()
|
||||||
self.__draw_day_rows__()
|
self.__draw_day_rows__()
|
||||||
|
|
||||||
def add_weather (self, weather):
|
def add_weather(self, weather):
|
||||||
for row in self.__day_rows__:
|
for row in self.__day_rows__:
|
||||||
row.add_weather(weather)
|
row.add_weather(weather)
|
||||||
|
|
||||||
def add_calendar (self, calendar):
|
def add_calendar(self, calendar):
|
||||||
for row in self.__day_rows__:
|
for row in self.__day_rows__:
|
||||||
row.add_calendar(calendar)
|
row.add_calendar(calendar)
|
||||||
|
|
||||||
def add_rssfeed (self, rss):
|
def add_rssfeed(self, rss):
|
||||||
for row in self.__day_rows__:
|
for row in self.__day_rows__:
|
||||||
row.add_rssfeed(rss)
|
row.add_rssfeed(rss)
|
||||||
if general_settings["info-area"] is "rss":
|
if general_settings["info-area"] is "rss":
|
||||||
self.__day_rows__ = self.__day_rows__[:-infoarea_replacedrowscount]
|
self.__day_rows__ = self.__day_rows__[:-infoarea_replacedrowscount]
|
||||||
self.__draw_rss_infoarea__(rss)
|
self.__draw_rss_infoarea__(rss)
|
||||||
|
|
||||||
def add_crypto (self, crypto):
|
def add_crypto(self, crypto):
|
||||||
if general_settings["info-area"] is "crypto":
|
if general_settings["info-area"] is "crypto":
|
||||||
self.__draw_crypto_infoarea__(crypto)
|
self.__draw_crypto_infoarea__(crypto)
|
||||||
|
|
||||||
def add_tasks (self, tasks):
|
def add_tasks(self, tasks):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __draw_rss_infoarea__ (self, rss):
|
def __draw_rss_infoarea__(self, rss):
|
||||||
height = infoarea_replacedrowscount * self.dayrow_size[1] * self.size[1] - rss_y_padding
|
height = infoarea_replacedrowscount * \
|
||||||
|
self.dayrow_size[1] * self.size[1] - rss_y_padding
|
||||||
ypos = self.size[1] - height
|
ypos = self.size[1] - height
|
||||||
size = (self.size[0], height)
|
size = (self.size[0], height)
|
||||||
pos = (0, ypos)
|
pos = (0, ypos)
|
||||||
|
@ -69,8 +72,9 @@ class DayListPanel (PanelDesign):
|
||||||
design.pos = pos
|
design.pos = pos
|
||||||
self.draw_design(design)
|
self.draw_design(design)
|
||||||
|
|
||||||
def __draw_crypto_infoarea__ (self, crypto):
|
def __draw_crypto_infoarea__(self, crypto):
|
||||||
height = infoarea_replacedrowscount * self.dayrow_size[1] * self.size[1] - crypto_y_padding
|
height = infoarea_replacedrowscount * \
|
||||||
|
self.dayrow_size[1] * self.size[1] - crypto_y_padding
|
||||||
ypos = self.size[1] - height
|
ypos = self.size[1] - height
|
||||||
size = (self.size[0], height)
|
size = (self.size[0], height)
|
||||||
pos = (0, ypos)
|
pos = (0, ypos)
|
||||||
|
@ -79,23 +83,24 @@ class DayListPanel (PanelDesign):
|
||||||
acutal_height = design.get_estimated_height()
|
acutal_height = design.get_estimated_height()
|
||||||
design.pos = (pos[0], pos[1] + (height - acutal_height))
|
design.pos = (pos[0], pos[1] + (height - acutal_height))
|
||||||
self.draw_design(design)
|
self.draw_design(design)
|
||||||
|
|
||||||
replaced_rows = ceil(acutal_height / (self.dayrow_size[1] * self.size[1]))
|
replaced_rows = ceil(
|
||||||
|
acutal_height / (self.dayrow_size[1] * self.size[1]))
|
||||||
self.__day_rows__ = self.__day_rows__[:-replaced_rows]
|
self.__day_rows__ = self.__day_rows__[:-replaced_rows]
|
||||||
|
|
||||||
def __draw_day_rows__ (self):
|
def __draw_day_rows__(self):
|
||||||
following_days = self.__get_following_days__()
|
following_days = self.__get_following_days__()
|
||||||
for i, date in enumerate(following_days):
|
for i, date in enumerate(following_days):
|
||||||
row = DayRowDesign(self.__abs_co__(self.dayrow_size), date)
|
row = DayRowDesign(self.__abs_co__(self.dayrow_size), date)
|
||||||
row.pos = self.__get_day_row_pos__(i)
|
row.pos = self.__get_day_row_pos__(i)
|
||||||
self.__day_rows__.append(row)
|
self.__day_rows__.append(row)
|
||||||
|
|
||||||
def __get_day_row_pos__ (self, i):
|
def __get_day_row_pos__(self, i):
|
||||||
ypos = self.size[1] * dayrowsarea_ypos
|
ypos = self.size[1] * dayrowsarea_ypos
|
||||||
down_shift = i * self.dayrow_size[1] * self.size[1]
|
down_shift = i * self.dayrow_size[1] * self.size[1]
|
||||||
return (0, int(ypos + down_shift))
|
return (0, int(ypos + down_shift))
|
||||||
|
|
||||||
def __calc_dayrow_size__ (self):
|
def __calc_dayrow_size__(self):
|
||||||
max_area_height = dayrowsarea_height * self.size[1]
|
max_area_height = dayrowsarea_height * self.size[1]
|
||||||
max_row_number = max_area_height / (dayrow_min_format * self.size[0])
|
max_row_number = max_area_height / (dayrow_min_format * self.size[0])
|
||||||
min_row_number = max_area_height / (dayrow_max_format * self.size[0])
|
min_row_number = max_area_height / (dayrow_max_format * self.size[0])
|
||||||
|
@ -110,8 +115,9 @@ class DayListPanel (PanelDesign):
|
||||||
following_days.append(date.today() + timedelta(days=i + 1))
|
following_days.append(date.today() + timedelta(days=i + 1))
|
||||||
return following_days
|
return following_days
|
||||||
|
|
||||||
def __draw_today_header__ (self):
|
def __draw_today_header__(self):
|
||||||
header = DayHeaderDesign(self.__abs_co__(todayheader_size), date.today())
|
header = DayHeaderDesign(self.__abs_co__(
|
||||||
|
todayheader_size), date.today())
|
||||||
header.pos = self.__abs_co__(todayheader_pos)
|
header.pos = self.__abs_co__(todayheader_pos)
|
||||||
self.__day_rows__.append(header)
|
self.__day_rows__.append(header)
|
||||||
|
|
||||||
|
@ -122,7 +128,8 @@ class DayListPanel (PanelDesign):
|
||||||
for ypos in positions:
|
for ypos in positions:
|
||||||
line_start = (0, ypos)
|
line_start = (0, ypos)
|
||||||
line_end = (self.size[0], ypos)
|
line_end = (self.size[0], ypos)
|
||||||
ImageDraw.Draw(self.__image__).line([line_start, line_end], fill=colors["fg"], width=lines_thickness)
|
ImageDraw.Draw(self.__image__).line(
|
||||||
|
[line_start, line_end], fill=colors["fg"], width=lines_thickness)
|
||||||
|
|
||||||
def __finish_panel__(self):
|
def __finish_panel__(self):
|
||||||
for design in self.__day_rows__:
|
for design in self.__day_rows__:
|
||||||
|
@ -130,4 +137,4 @@ class DayListPanel (PanelDesign):
|
||||||
self.__draw_lines__()
|
self.__draw_lines__()
|
||||||
|
|
||||||
def __abs_co__(self, coordinates):
|
def __abs_co__(self, coordinates):
|
||||||
return (int(coordinates[0] * self.size[0]),int(coordinates[1] * self.size[1]))
|
return (int(coordinates[0] * self.size[0]), int(coordinates[1] * self.size[1]))
|
||||||
|
|
|
@ -20,25 +20,27 @@ eventlist_y_fontsize = 0.2
|
||||||
|
|
||||||
font = fonts["light"]
|
font = fonts["light"]
|
||||||
|
|
||||||
|
|
||||||
class DayRowDesign (DesignEntity):
|
class DayRowDesign (DesignEntity):
|
||||||
"""Detailed view of a given date."""
|
"""Detailed view of a given date."""
|
||||||
def __init__ (self, size, date):
|
|
||||||
|
def __init__(self, size, date):
|
||||||
super(DayRowDesign, self).__init__(size)
|
super(DayRowDesign, self).__init__(size)
|
||||||
self.__init_image__()
|
self.__init_image__()
|
||||||
self.date = date
|
self.date = date
|
||||||
|
|
||||||
def add_weather (self, weather):
|
def add_weather(self, weather):
|
||||||
if weather.is_available is False:
|
if weather.is_available is False:
|
||||||
return
|
return
|
||||||
self.__draw_forecast__(weather)
|
self.__draw_forecast__(weather)
|
||||||
|
|
||||||
def add_calendar (self, calendar):
|
def add_calendar(self, calendar):
|
||||||
self.__draw_event_list__(calendar)
|
self.__draw_event_list__(calendar)
|
||||||
|
|
||||||
def add_rssfeed (self, rss):
|
def add_rssfeed(self, rss):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __draw_event_list__ (self, calendar):
|
def __draw_event_list__(self, calendar):
|
||||||
number_width = daynumber_y_size[0] * self.size[1]
|
number_width = daynumber_y_size[0] * self.size[1]
|
||||||
ypos = eventlist_ypos * self.size[1]
|
ypos = eventlist_ypos * self.size[1]
|
||||||
weather_width = 0
|
weather_width = 0
|
||||||
|
@ -50,12 +52,14 @@ class DayRowDesign (DesignEntity):
|
||||||
|
|
||||||
events = calendar.get_day_events(self.date)
|
events = calendar.get_day_events(self.date)
|
||||||
rel_dates = [self.date for _ in range(len(events))]
|
rel_dates = [self.date for _ in range(len(events))]
|
||||||
event_list = SingelDayEventListDesign(size, events, fontsize, event_prefix_rel_dates = rel_dates)
|
event_list = SingelDayEventListDesign(
|
||||||
|
size, events, fontsize, event_prefix_rel_dates=rel_dates)
|
||||||
event_list.pos = pos
|
event_list.pos = pos
|
||||||
self.draw_design(event_list)
|
self.draw_design(event_list)
|
||||||
|
|
||||||
def __draw_forecast__ (self, weather):
|
def __draw_forecast__(self, weather):
|
||||||
forecast = weather.get_forecast_in_days(self.date.day - datetime.today().day)
|
forecast = weather.get_forecast_in_days(
|
||||||
|
self.date.day - datetime.today().day)
|
||||||
|
|
||||||
if forecast is None:
|
if forecast is None:
|
||||||
return
|
return
|
||||||
|
@ -68,44 +72,48 @@ class DayRowDesign (DesignEntity):
|
||||||
resized_icon = icon.resize(size, resample=Image.LANCZOS)
|
resized_icon = icon.resize(size, resample=Image.LANCZOS)
|
||||||
self.draw(resized_icon, pos)
|
self.draw(resized_icon, pos)
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
self.__draw_weekday__()
|
self.__draw_weekday__()
|
||||||
self.__draw_day_number__()
|
self.__draw_day_number__()
|
||||||
|
|
||||||
def __draw_weekday__ (self):
|
def __draw_weekday__(self):
|
||||||
font_size = int(weekday_fontsize * self.size[1])
|
font_size = int(weekday_fontsize * self.size[1])
|
||||||
size = (weekday_y_size[0] * self.size[1], weekday_y_size[1] * self.size[1])
|
size = (weekday_y_size[0] * self.size[1],
|
||||||
|
weekday_y_size[1] * self.size[1])
|
||||||
ypos = weekday_ypos * self.size[1]
|
ypos = weekday_ypos * self.size[1]
|
||||||
pos = (0, ypos)
|
pos = (0, ypos)
|
||||||
|
|
||||||
color = self.__get_day_color__()
|
color = self.__get_day_color__()
|
||||||
week_day_name = self.date.strftime("%a")
|
week_day_name = self.date.strftime("%a")
|
||||||
|
|
||||||
week_day = TextDesign(size, text=week_day_name, font=font, color=color, fontsize=font_size, horizontalalignment="center", verticalalignment="top")
|
week_day = TextDesign(size, text=week_day_name, font=font, color=color,
|
||||||
|
fontsize=font_size, horizontalalignment="center", verticalalignment="top")
|
||||||
week_day.pos = pos
|
week_day.pos = pos
|
||||||
week_day.mask = False
|
week_day.mask = False
|
||||||
self.draw_design(week_day)
|
self.draw_design(week_day)
|
||||||
|
|
||||||
def __draw_day_number__ (self):
|
def __draw_day_number__(self):
|
||||||
font_size = int(daynumber_fontsize * self.size[1])
|
font_size = int(daynumber_fontsize * self.size[1])
|
||||||
ypadding = daynumber_ypadding * self.size[1]
|
ypadding = daynumber_ypadding * self.size[1]
|
||||||
size = (daynumber_y_size[0] * self.size[1], daynumber_y_size[1] * self.size[1])
|
size = (daynumber_y_size[0] * self.size[1],
|
||||||
|
daynumber_y_size[1] * self.size[1])
|
||||||
pos = (0, ypadding)
|
pos = (0, ypadding)
|
||||||
|
|
||||||
day_text = self.__get_day_text__()
|
day_text = self.__get_day_text__()
|
||||||
color = self.__get_day_color__()
|
color = self.__get_day_color__()
|
||||||
|
|
||||||
number = TextDesign(size, text=day_text, font=font, color=color, fontsize=font_size, horizontalalignment="center", verticalalignment="bottom")
|
number = TextDesign(size, text=day_text, font=font, color=color,
|
||||||
|
fontsize=font_size, horizontalalignment="center", verticalalignment="bottom")
|
||||||
number.pos = pos
|
number.pos = pos
|
||||||
self.draw_design(number)
|
self.draw_design(number)
|
||||||
|
|
||||||
def __abs_co__ (self, coordinates):
|
def __abs_co__(self, coordinates):
|
||||||
return (int(coordinates[0] * self.size[0]),int(coordinates[1] * self.size[1]))
|
return (int(coordinates[0] * self.size[0]), int(coordinates[1] * self.size[1]))
|
||||||
|
|
||||||
def __get_day_text__ (self):
|
def __get_day_text__(self):
|
||||||
return str(self.date.day)
|
return str(self.date.day)
|
||||||
|
|
||||||
def __get_day_color__ (self):
|
def __get_day_color__(self):
|
||||||
"""Depending on week_starts_on"""
|
"""Depending on week_starts_on"""
|
||||||
if week_starts_on == "Monday" and self.date.strftime("%w") == "0":
|
if week_starts_on == "Monday" and self.date.strftime("%w") == "0":
|
||||||
return colors["hl"]
|
return colors["hl"]
|
||||||
|
|
|
@ -18,25 +18,28 @@ infoarea_replaced_hours = 4
|
||||||
infoarea_borderline_width = 1
|
infoarea_borderline_width = 1
|
||||||
infoarea_padding = 5
|
infoarea_padding = 5
|
||||||
|
|
||||||
|
|
||||||
class DayViewPanel (PanelDesign):
|
class DayViewPanel (PanelDesign):
|
||||||
"""Overview that focuses on the current day and
|
"""Overview that focuses on the current day and
|
||||||
shows a timeline split into hours."""
|
shows a timeline split into hours."""
|
||||||
def __init__ (self, size):
|
|
||||||
|
def __init__(self, size):
|
||||||
super(DayViewPanel, self).__init__(size)
|
super(DayViewPanel, self).__init__(size)
|
||||||
self.shownhours_count = default_shownhours_count
|
self.shownhours_count = default_shownhours_count
|
||||||
if general_settings["info-area"] not in ["", "empty"]:
|
if general_settings["info-area"] not in ["", "empty"]:
|
||||||
self.shownhours_count -= infoarea_replaced_hours
|
self.shownhours_count -= infoarea_replaced_hours
|
||||||
self.__first_render__()
|
self.__first_render__()
|
||||||
|
|
||||||
def __first_render__ (self):
|
def __first_render__(self):
|
||||||
self.__init_header__()
|
self.__init_header__()
|
||||||
self.__init_hourlist__()
|
self.__init_hourlist__()
|
||||||
|
|
||||||
def add_weather (self, weather):
|
def add_weather(self, weather):
|
||||||
self.__header__.add_weather(weather)
|
self.__header__.add_weather(weather)
|
||||||
|
|
||||||
def add_calendar (self, calendar):
|
def add_calendar(self, calendar):
|
||||||
allday_ev, timed_ev = self.__split_events__(calendar.get_today_events())
|
allday_ev, timed_ev = self.__split_events__(
|
||||||
|
calendar.get_today_events())
|
||||||
self.__header__.add_events(allday_ev)
|
self.__header__.add_events(allday_ev)
|
||||||
self.__hourlist__.add_events(timed_ev)
|
self.__hourlist__.add_events(timed_ev)
|
||||||
|
|
||||||
|
@ -44,12 +47,12 @@ class DayViewPanel (PanelDesign):
|
||||||
self.__draw_event_list__(calendar)
|
self.__draw_event_list__(calendar)
|
||||||
self.__draw_infoarea_line__()
|
self.__draw_infoarea_line__()
|
||||||
|
|
||||||
def add_rssfeed (self, rss):
|
def add_rssfeed(self, rss):
|
||||||
if general_settings["info-area"] == "rss":
|
if general_settings["info-area"] == "rss":
|
||||||
self.__draw_rss_feed__(rss)
|
self.__draw_rss_feed__(rss)
|
||||||
self.__draw_infoarea_line__()
|
self.__draw_infoarea_line__()
|
||||||
|
|
||||||
def add_crypto (self, crypto):
|
def add_crypto(self, crypto):
|
||||||
if general_settings["info-area"] == "crypto":
|
if general_settings["info-area"] == "crypto":
|
||||||
self.__draw_crypto_feed__(crypto)
|
self.__draw_crypto_feed__(crypto)
|
||||||
self.__draw_infoarea_line__()
|
self.__draw_infoarea_line__()
|
||||||
|
@ -60,10 +63,12 @@ class DayViewPanel (PanelDesign):
|
||||||
|
|
||||||
line_start = (0, ypos)
|
line_start = (0, ypos)
|
||||||
line_end = (self.size[0], ypos)
|
line_end = (self.size[0], ypos)
|
||||||
ImageDraw.Draw(self.__image__).line([ line_start, line_end ], fill=colors["fg"], width=infoarea_borderline_width)
|
ImageDraw.Draw(self.__image__).line(
|
||||||
|
[line_start, line_end], fill=colors["fg"], width=infoarea_borderline_width)
|
||||||
|
|
||||||
def __draw_rss_feed__(self, rss):
|
def __draw_rss_feed__(self, rss):
|
||||||
height = infoarea_replaced_hours * self.__hourlist__.row_size[1] - infoarea_padding
|
height = infoarea_replaced_hours * \
|
||||||
|
self.__hourlist__.row_size[1] - infoarea_padding
|
||||||
size = (self.size[0], height)
|
size = (self.size[0], height)
|
||||||
pos = (0, self.size[1] - size[1])
|
pos = (0, self.size[1] - size[1])
|
||||||
|
|
||||||
|
@ -72,7 +77,8 @@ class DayViewPanel (PanelDesign):
|
||||||
self.draw_design(rss)
|
self.draw_design(rss)
|
||||||
|
|
||||||
def __draw_crypto_feed__(self, crypto):
|
def __draw_crypto_feed__(self, crypto):
|
||||||
height = infoarea_replaced_hours * self.__hourlist__.row_size[1] - infoarea_padding
|
height = infoarea_replaced_hours * \
|
||||||
|
self.__hourlist__.row_size[1] - infoarea_padding
|
||||||
size = (self.size[0], height)
|
size = (self.size[0], height)
|
||||||
pos = (0, self.size[1] - size[1])
|
pos = (0, self.size[1] - size[1])
|
||||||
|
|
||||||
|
@ -81,9 +87,9 @@ class DayViewPanel (PanelDesign):
|
||||||
crypto.pos = (pos[0], pos[1] + (height - acutal_height))
|
crypto.pos = (pos[0], pos[1] + (height - acutal_height))
|
||||||
self.draw_design(crypto)
|
self.draw_design(crypto)
|
||||||
|
|
||||||
|
|
||||||
def __draw_event_list__(self, calendar):
|
def __draw_event_list__(self, calendar):
|
||||||
height = infoarea_replaced_hours * self.__hourlist__.row_size[1] - infoarea_padding
|
height = infoarea_replaced_hours * \
|
||||||
|
self.__hourlist__.row_size[1] - infoarea_padding
|
||||||
size = (self.size[0], height)
|
size = (self.size[0], height)
|
||||||
pos = (0, self.size[1] - size[1])
|
pos = (0, self.size[1] - size[1])
|
||||||
|
|
||||||
|
@ -91,21 +97,23 @@ class DayViewPanel (PanelDesign):
|
||||||
events.pos = pos
|
events.pos = pos
|
||||||
self.draw_design(events)
|
self.draw_design(events)
|
||||||
|
|
||||||
def add_tasks (self, tasks):
|
def add_tasks(self, tasks):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __finish_panel__ (self):
|
def __finish_panel__(self):
|
||||||
self.draw_design(self.__header__)
|
self.draw_design(self.__header__)
|
||||||
self.draw_design(self.__hourlist__)
|
self.draw_design(self.__hourlist__)
|
||||||
|
|
||||||
def __init_header__ (self):
|
def __init_header__(self):
|
||||||
self.__header__ = DayHeaderDesign(self.__abs_co__(header_size), date.today())
|
self.__header__ = DayHeaderDesign(
|
||||||
|
self.__abs_co__(header_size), date.today())
|
||||||
self.__header__.pos = (0, 0)
|
self.__header__.pos = (0, 0)
|
||||||
|
|
||||||
def __init_hourlist__ (self):
|
def __init_hourlist__(self):
|
||||||
start, end = self.__get_current_hour_range__()
|
start, end = self.__get_current_hour_range__()
|
||||||
size = self.__abs_co__(hourlist_size)
|
size = self.__abs_co__(hourlist_size)
|
||||||
size = (size[0], size[1] * self.shownhours_count / default_shownhours_count)
|
size = (size[0], size[1] * self.shownhours_count /
|
||||||
|
default_shownhours_count)
|
||||||
|
|
||||||
self.__hourlist__ = HourListDesign(size, start, end)
|
self.__hourlist__ = HourListDesign(size, start, end)
|
||||||
self.__hourlist__.pos = (0, self.__header__.size[1])
|
self.__hourlist__.pos = (0, self.__header__.size[1])
|
||||||
|
@ -119,10 +127,10 @@ class DayViewPanel (PanelDesign):
|
||||||
|
|
||||||
return start_hour, start_hour + additional_hours
|
return start_hour, start_hour + additional_hours
|
||||||
|
|
||||||
def __abs_co__ (self, coordinates):
|
def __abs_co__(self, coordinates):
|
||||||
return (int(coordinates[0] * self.size[0]),int(coordinates[1] * self.size[1]))
|
return (int(coordinates[0] * self.size[0]), int(coordinates[1] * self.size[1]))
|
||||||
|
|
||||||
def __split_events__ (self, events):
|
def __split_events__(self, events):
|
||||||
allday_ev = []
|
allday_ev = []
|
||||||
timed_ev = []
|
timed_ev = []
|
||||||
|
|
||||||
|
@ -140,7 +148,7 @@ class DayViewPanel (PanelDesign):
|
||||||
timed_ev.append(event)
|
timed_ev.append(event)
|
||||||
return allday_ev, timed_ev
|
return allday_ev, timed_ev
|
||||||
|
|
||||||
def __is_today__ (self, dt):
|
def __is_today__(self, dt):
|
||||||
today = date.today()
|
today = date.today()
|
||||||
return dt.day == today.day and \
|
return dt.day == today.day and \
|
||||||
dt.month == today.month and \
|
dt.month == today.month and \
|
||||||
|
|
|
@ -3,9 +3,11 @@ from Assets import weathericons
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
|
|
||||||
class DebugConsole (DebugInterface):
|
class DebugConsole (DebugInterface):
|
||||||
"""Defines concrete console export of debug objects"""
|
"""Defines concrete console export of debug objects"""
|
||||||
def print_event (self, event):
|
|
||||||
|
def print_event(self, event):
|
||||||
print("\nCalendarEvent:")
|
print("\nCalendarEvent:")
|
||||||
print("---------------------")
|
print("---------------------")
|
||||||
print('Begin datetime: ' + str(event.begin_datetime))
|
print('Begin datetime: ' + str(event.begin_datetime))
|
||||||
|
@ -22,7 +24,7 @@ class DebugConsole (DebugInterface):
|
||||||
print('Location: ' + str(event.location))
|
print('Location: ' + str(event.location))
|
||||||
print('Fetch datetime: ' + str(event.fetch_datetime))
|
print('Fetch datetime: ' + str(event.fetch_datetime))
|
||||||
|
|
||||||
def print_forecast (self, forecast):
|
def print_forecast(self, forecast):
|
||||||
print("\nWeatherForecast:")
|
print("\nWeatherForecast:")
|
||||||
print("---------------------")
|
print("---------------------")
|
||||||
print('Air temperature: ' + str(forecast.air_temperature))
|
print('Air temperature: ' + str(forecast.air_temperature))
|
||||||
|
@ -45,12 +47,12 @@ class DebugConsole (DebugInterface):
|
||||||
print('Location: ' + str(forecast.location))
|
print('Location: ' + str(forecast.location))
|
||||||
print('Fetch datetime: ' + str(forecast.fetch_datetime))
|
print('Fetch datetime: ' + str(forecast.fetch_datetime))
|
||||||
|
|
||||||
def print_line (self, content):
|
def print_line(self, content):
|
||||||
if content is None:
|
if content is None:
|
||||||
return
|
return
|
||||||
print(str(content))
|
print(str(content))
|
||||||
|
|
||||||
def print_err (self, exception, msg=""):
|
def print_err(self, exception, msg=""):
|
||||||
if exception is None:
|
if exception is None:
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -60,4 +62,4 @@ class DebugConsole (DebugInterface):
|
||||||
content += "\n" + str(msg) + "\n"
|
content += "\n" + str(msg) + "\n"
|
||||||
traceback.print_exc()
|
traceback.print_exc()
|
||||||
|
|
||||||
self.print_line(str(content))
|
self.print_line(str(content))
|
||||||
|
|
|
@ -1,13 +1,14 @@
|
||||||
class DebugInterface (object):
|
class DebugInterface (object):
|
||||||
"""Defines general interface for debugging operations"""
|
"""Defines general interface for debugging operations"""
|
||||||
def print_event (self, event):
|
|
||||||
|
def print_event(self, event):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
def print_forecast (self, forecast):
|
def print_forecast(self, forecast):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
def print_line (self, content):
|
def print_line(self, content):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
def print_err (self, exception, msg=""):
|
def print_err(self, exception, msg=""):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
|
@ -3,10 +3,12 @@ from Assets import colors
|
||||||
|
|
||||||
masking_threshold = 200
|
masking_threshold = 200
|
||||||
|
|
||||||
|
|
||||||
class DesignEntity (object):
|
class DesignEntity (object):
|
||||||
"""General entity that can be drawn on to a panel design or
|
"""General entity that can be drawn on to a panel design or
|
||||||
other design entities."""
|
other design entities."""
|
||||||
def __init__ (self, size, mask=False, invert_mask=False, color_key=False):
|
|
||||||
|
def __init__(self, size, mask=False, invert_mask=False, color_key=False):
|
||||||
self.size = size
|
self.size = size
|
||||||
self.pos = (0, 0)
|
self.pos = (0, 0)
|
||||||
self.mask = mask
|
self.mask = mask
|
||||||
|
@ -15,36 +17,39 @@ class DesignEntity (object):
|
||||||
self.__finished_image__ = False
|
self.__finished_image__ = False
|
||||||
self.color_key = color_key
|
self.color_key = color_key
|
||||||
|
|
||||||
def __init_image__ (self, color = colors["bg"]):
|
def __init_image__(self, color=colors["bg"]):
|
||||||
rounded_size = (int(self.size[0]),int(self.size[1]))
|
rounded_size = (int(self.size[0]), int(self.size[1]))
|
||||||
self.__image__ = Image.new('RGBA', rounded_size, color=color)
|
self.__image__ = Image.new('RGBA', rounded_size, color=color)
|
||||||
|
|
||||||
def get_image (self):
|
def get_image(self):
|
||||||
if self.__finished_image__ is False:
|
if self.__finished_image__ is False:
|
||||||
self.__finish_image__()
|
self.__finish_image__()
|
||||||
self.__finished_image__ = True
|
self.__finished_image__ = True
|
||||||
return self.__image__
|
return self.__image__
|
||||||
|
|
||||||
def draw (self, subimage, pos, mask=False, invert_mask=False, color_key=False):
|
def draw(self, subimage, pos, mask=False, invert_mask=False, color_key=False):
|
||||||
rounded_pos = (int(pos[0]),int(pos[1]))
|
rounded_pos = (int(pos[0]), int(pos[1]))
|
||||||
img_mask = None
|
img_mask = None
|
||||||
if mask:
|
if mask:
|
||||||
img_mask = self.__get_mask__(subimage, invert_mask=invert_mask, color_key=color_key)
|
img_mask = self.__get_mask__(
|
||||||
|
subimage, invert_mask=invert_mask, color_key=color_key)
|
||||||
self.__image__.paste(subimage, rounded_pos, mask=img_mask)
|
self.__image__.paste(subimage, rounded_pos, mask=img_mask)
|
||||||
|
|
||||||
def draw_design (self, entity):
|
def draw_design(self, entity):
|
||||||
self.draw(entity.get_image(), entity.pos, entity.mask, entity.invert_mask, entity.color_key)
|
self.draw(entity.get_image(), entity.pos, entity.mask,
|
||||||
|
entity.invert_mask, entity.color_key)
|
||||||
|
|
||||||
def draw_image (self, path, pos):
|
def draw_image(self, path, pos):
|
||||||
self.draw(Image.open(path), pos)
|
self.draw(Image.open(path), pos)
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def __get_mask__ (self, image, invert_mask, color_key):
|
def __get_mask__(self, image, invert_mask, color_key):
|
||||||
mask = image.convert('L')
|
mask = image.convert('L')
|
||||||
if color_key:
|
if color_key:
|
||||||
mask = mask.point(lambda p : 0 if p < masking_threshold else 255, '1').convert('L')
|
mask = mask.point(lambda p: 0 if p <
|
||||||
|
masking_threshold else 255, '1').convert('L')
|
||||||
if invert_mask:
|
if invert_mask:
|
||||||
mask = ImageOps.invert(mask)
|
mask = ImageOps.invert(mask)
|
||||||
return ImageOps.invert(mask)
|
return ImageOps.invert(mask)
|
||||||
|
|
|
@ -4,78 +4,78 @@ default_language = "en"
|
||||||
|
|
||||||
'''Events'''
|
'''Events'''
|
||||||
more_events = {
|
more_events = {
|
||||||
'en' : '+ *0 more',
|
'en': '+ *0 more',
|
||||||
'de' : '+ *0 weitere'
|
'de': '+ *0 weitere'
|
||||||
}
|
}
|
||||||
multiday_events = {
|
multiday_events = {
|
||||||
'en' : 'Multi-day',
|
'en': 'Multi-day',
|
||||||
'de' : 'Mehrtägig'
|
'de': 'Mehrtägig'
|
||||||
}
|
}
|
||||||
allday_events = {
|
allday_events = {
|
||||||
'en' : 'All-day',
|
'en': 'All-day',
|
||||||
'de' : 'Ganztägig'
|
'de': 'Ganztägig'
|
||||||
}
|
}
|
||||||
|
|
||||||
'''Weather'''
|
'''Weather'''
|
||||||
rain_weather = {
|
rain_weather = {
|
||||||
'en' : 'Rain',
|
'en': 'Rain',
|
||||||
'de' : 'Regen'
|
'de': 'Regen'
|
||||||
}
|
}
|
||||||
clear_weather = {
|
clear_weather = {
|
||||||
'en' : 'Clear',
|
'en': 'Clear',
|
||||||
'de' : 'Klar'
|
'de': 'Klar'
|
||||||
}
|
}
|
||||||
clouds_weather = {
|
clouds_weather = {
|
||||||
'en' : 'Clouds',
|
'en': 'Clouds',
|
||||||
'de' : 'Wolken'
|
'de': 'Wolken'
|
||||||
}
|
}
|
||||||
thunderstorm_weather = {
|
thunderstorm_weather = {
|
||||||
'en' : 'Thunderstorm',
|
'en': 'Thunderstorm',
|
||||||
'de' : 'Gewitter'
|
'de': 'Gewitter'
|
||||||
}
|
}
|
||||||
drizzle_weather = {
|
drizzle_weather = {
|
||||||
'en' : 'Drizzle',
|
'en': 'Drizzle',
|
||||||
'de' : 'Niesel'
|
'de': 'Niesel'
|
||||||
}
|
}
|
||||||
snow_weather = {
|
snow_weather = {
|
||||||
'en' : 'Snow',
|
'en': 'Snow',
|
||||||
'de' : 'Schnee'
|
'de': 'Schnee'
|
||||||
}
|
}
|
||||||
mist_weather = {
|
mist_weather = {
|
||||||
'en' : 'Mist',
|
'en': 'Mist',
|
||||||
'de' : 'Nebel'
|
'de': 'Nebel'
|
||||||
}
|
}
|
||||||
smoke_weather = {
|
smoke_weather = {
|
||||||
'en' : 'Smoke',
|
'en': 'Smoke',
|
||||||
'de' : 'Rauch'
|
'de': 'Rauch'
|
||||||
}
|
}
|
||||||
haze_weather = {
|
haze_weather = {
|
||||||
'en' : 'Haze',
|
'en': 'Haze',
|
||||||
'de' : 'Nebel'
|
'de': 'Nebel'
|
||||||
}
|
}
|
||||||
dust_weather = {
|
dust_weather = {
|
||||||
'en' : 'Dust',
|
'en': 'Dust',
|
||||||
'de' : 'Staub'
|
'de': 'Staub'
|
||||||
}
|
}
|
||||||
fog_weather = {
|
fog_weather = {
|
||||||
'en' : 'Fog',
|
'en': 'Fog',
|
||||||
'de' : 'Nebel'
|
'de': 'Nebel'
|
||||||
}
|
}
|
||||||
sand_weather = {
|
sand_weather = {
|
||||||
'en' : 'Sand',
|
'en': 'Sand',
|
||||||
'de' : 'Sand'
|
'de': 'Sand'
|
||||||
}
|
}
|
||||||
ash_weather = {
|
ash_weather = {
|
||||||
'en' : 'Ash',
|
'en': 'Ash',
|
||||||
'de' : 'Asche'
|
'de': 'Asche'
|
||||||
}
|
}
|
||||||
squall_weather = {
|
squall_weather = {
|
||||||
'en' : 'Squall',
|
'en': 'Squall',
|
||||||
'de' : 'Sturm'
|
'de': 'Sturm'
|
||||||
}
|
}
|
||||||
tornado_weather = {
|
tornado_weather = {
|
||||||
'en' : 'Tornado',
|
'en': 'Tornado',
|
||||||
'de' : 'Tornado'
|
'de': 'Tornado'
|
||||||
}
|
}
|
||||||
dictionary_collection = [
|
dictionary_collection = [
|
||||||
rain_weather,
|
rain_weather,
|
||||||
|
@ -96,4 +96,4 @@ dictionary_collection = [
|
||||||
more_events,
|
more_events,
|
||||||
allday_events,
|
allday_events,
|
||||||
multiday_events
|
multiday_events
|
||||||
]
|
]
|
||||||
|
|
|
@ -4,13 +4,15 @@ from settings import language
|
||||||
'''Takes a collection of phrases and outputs the necessary text
|
'''Takes a collection of phrases and outputs the necessary text
|
||||||
according to the language and inserts parameters.'''
|
according to the language and inserts parameters.'''
|
||||||
|
|
||||||
|
|
||||||
def get_text(dictionary, *params):
|
def get_text(dictionary, *params):
|
||||||
text = dictionary[default_language]
|
text = dictionary[default_language]
|
||||||
if language in dictionary.keys():
|
if language in dictionary.keys():
|
||||||
text = dictionary[language]
|
text = dictionary[language]
|
||||||
|
|
||||||
return __insert_params__(text, params)
|
return __insert_params__(text, params)
|
||||||
|
|
||||||
|
|
||||||
def __insert_params__(text, params):
|
def __insert_params__(text, params):
|
||||||
index = 0
|
index = 0
|
||||||
while '*%d' % index in text and index < len(params):
|
while '*%d' % index in text and index < len(params):
|
||||||
|
@ -24,4 +26,4 @@ def __insert_params__(text, params):
|
||||||
else:
|
else:
|
||||||
text = splitted[0].rsplit(' ')
|
text = splitted[0].rsplit(' ')
|
||||||
index += 1
|
index += 1
|
||||||
return text
|
return text
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
class DisplayAdapter (object):
|
class DisplayAdapter (object):
|
||||||
"""Interface for CalendarDesign output channels."""
|
"""Interface for CalendarDesign output channels."""
|
||||||
|
|
||||||
def __init__(self, width, height):
|
def __init__(self, width, height):
|
||||||
self.width = width
|
self.width = width
|
||||||
self.height = height
|
self.height = height
|
||||||
|
|
||||||
def render (self, design):
|
def render(self, design):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
def calibrate (self):
|
def calibrate(self):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
|
@ -27,8 +27,10 @@ import GeckoCrypto
|
||||||
|
|
||||||
all_locales = locale.locale_alias
|
all_locales = locale.locale_alias
|
||||||
if language.lower() not in all_locales.keys():
|
if language.lower() 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)
|
raise Exception(
|
||||||
locale.setlocale(locale.LC_ALL, "%s.%s" % (all_locales[language.lower()].split('.')[0], datetime_encoding))
|
"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.lower()].split('.')[0], datetime_encoding))
|
||||||
|
|
||||||
debug = DebugConsole()
|
debug = DebugConsole()
|
||||||
output_adapters = []
|
output_adapters = []
|
||||||
|
@ -49,19 +51,22 @@ if render_to_display:
|
||||||
output_adapters.append(epd)
|
output_adapters.append(epd)
|
||||||
|
|
||||||
available_panels = {
|
available_panels = {
|
||||||
"day-list" : DayListPanel,
|
"day-list": DayListPanel,
|
||||||
"month-overview" : MonthOvPanel,
|
"month-overview": MonthOvPanel,
|
||||||
"day-view" : DayViewPanel,
|
"day-view": DayViewPanel,
|
||||||
"agenda-list" : AgendaListPanel,
|
"agenda-list": AgendaListPanel,
|
||||||
"month-view" : MonthViewPanel,
|
"month-view": MonthViewPanel,
|
||||||
"image-frame" : ImageFramePanel
|
"image-frame": ImageFramePanel
|
||||||
}
|
}
|
||||||
|
|
||||||
loop_timer = LoopTimer(update_interval, run_on_hour=True)
|
loop_timer = LoopTimer(update_interval, run_on_hour=True)
|
||||||
|
|
||||||
"""Main loop starts from here"""
|
"""Main loop starts from here"""
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
owm = OwmForecasts.OwmForecasts(location, api_key, paid_api=owm_paid_subscription)
|
owm = OwmForecasts.OwmForecasts(
|
||||||
|
location, api_key, paid_api=owm_paid_subscription)
|
||||||
events_cal = IcalEvents.IcalEvents(ical_urls, highlighted_ical_urls)
|
events_cal = IcalEvents.IcalEvents(ical_urls, highlighted_ical_urls)
|
||||||
rss = RssParserPosts.RssParserPosts(rss_feeds)
|
rss = RssParserPosts.RssParserPosts(rss_feeds)
|
||||||
crypto = GeckoCrypto.GeckoCrypto(crypto_coins)
|
crypto = GeckoCrypto.GeckoCrypto(crypto_coins)
|
||||||
|
@ -78,7 +83,8 @@ def main():
|
||||||
if choosen_design in available_panels.keys():
|
if choosen_design in available_panels.keys():
|
||||||
design = available_panels[choosen_design]((epd.width, epd.height))
|
design = available_panels[choosen_design]((epd.width, epd.height))
|
||||||
else:
|
else:
|
||||||
raise ImportError("choosen_design must be valid (" + choosen_design + ")")
|
raise ImportError(
|
||||||
|
"choosen_design must be valid (" + choosen_design + ")")
|
||||||
|
|
||||||
debug.print_line("Fetching weather information from open weather map")
|
debug.print_line("Fetching weather information from open weather map")
|
||||||
owm.reload()
|
owm.reload()
|
||||||
|
@ -100,18 +106,22 @@ def main():
|
||||||
for i, output in enumerate(output_adapters):
|
for i, output in enumerate(output_adapters):
|
||||||
try:
|
try:
|
||||||
output.render(design)
|
output.render(design)
|
||||||
debug.print_line(str(i + 1) + " of " + str(len(output_adapters)) + " rendered")
|
debug.print_line(str(i + 1) + " of " +
|
||||||
|
str(len(output_adapters)) + " rendered")
|
||||||
except BaseException as ex:
|
except BaseException as ex:
|
||||||
debug.print_err(ex, "Failed to render output " + str(i + 1) + " of " + str(len(output_adapters)))
|
debug.print_err(ex, "Failed to render output " +
|
||||||
|
str(i + 1) + " of " + str(len(output_adapters)))
|
||||||
|
|
||||||
debug.print_line("=> Finished rendering" + "\n")
|
debug.print_line("=> Finished rendering" + "\n")
|
||||||
|
|
||||||
loop_timer.end_loop()
|
loop_timer.end_loop()
|
||||||
sleep_time = loop_timer.time_until_next()
|
sleep_time = loop_timer.time_until_next()
|
||||||
|
|
||||||
debug.print_line("This loop took " + str(loop_timer.get_last_duration()) + " to execute.")
|
debug.print_line("This loop took " +
|
||||||
|
str(loop_timer.get_last_duration()) + " to execute.")
|
||||||
debug.print_line("Sleeping " + str(sleep_time) + " until next loop.")
|
debug.print_line("Sleeping " + str(sleep_time) + " until next loop.")
|
||||||
sleep(sleep_time.total_seconds())
|
sleep(sleep_time.total_seconds())
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
main()
|
main()
|
||||||
|
|
|
@ -1,10 +1,14 @@
|
||||||
from BoxDesign import BoxDesign
|
from BoxDesign import BoxDesign
|
||||||
from PIL import ImageDraw, ImageOps
|
from PIL import ImageDraw, ImageOps
|
||||||
|
|
||||||
|
|
||||||
class EllipseDesign (BoxDesign):
|
class EllipseDesign (BoxDesign):
|
||||||
"""Redefinition of ImageDraw.Draw.Rectangle"""
|
"""Redefinition of ImageDraw.Draw.Rectangle"""
|
||||||
def __init__(self, size, fill=None, outline=None, width=0):
|
|
||||||
super(EllipseDesign, self).__init__(size, fill=fill, outline=outline, width=width)
|
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __init__(self, size, fill=None, outline=None, width=0):
|
||||||
ImageDraw.Draw(self.__image__).ellipse(self.corners, fill=self.fill, outline=self.outline, width=self.width)
|
super(EllipseDesign, self).__init__(
|
||||||
|
size, fill=fill, outline=outline, width=width)
|
||||||
|
|
||||||
|
def __finish_image__(self):
|
||||||
|
ImageDraw.Draw(self.__image__).ellipse(
|
||||||
|
self.corners, fill=self.fill, outline=self.outline, width=self.width)
|
||||||
|
|
|
@ -2,11 +2,12 @@ from EpdAdapter import EpdAdapter, DISPLAY_REFRESH, DATA_START_TRANSMISSION_1
|
||||||
from settings import display_colours
|
from settings import display_colours
|
||||||
from PIL import Image, ImageDraw
|
from PIL import Image, ImageDraw
|
||||||
|
|
||||||
|
|
||||||
class Epd7in5Adapter (EpdAdapter):
|
class Epd7in5Adapter (EpdAdapter):
|
||||||
def __init__ (self):
|
def __init__(self):
|
||||||
super(Epd7in5Adapter, self).__init__(384, 640)
|
super(Epd7in5Adapter, self).__init__(384, 640)
|
||||||
|
|
||||||
def display_frame (self, frame_buffer):
|
def display_frame(self, frame_buffer):
|
||||||
self.send_command(DATA_START_TRANSMISSION_1)
|
self.send_command(DATA_START_TRANSMISSION_1)
|
||||||
for i in range(0, 30720):
|
for i in range(0, 30720):
|
||||||
temp1 = frame_buffer[i]
|
temp1 = frame_buffer[i]
|
||||||
|
@ -30,11 +31,11 @@ class Epd7in5Adapter (EpdAdapter):
|
||||||
self.delay_ms(100)
|
self.delay_ms(100)
|
||||||
self.wait_until_idle()
|
self.wait_until_idle()
|
||||||
|
|
||||||
def get_frame_buffer (self, image):
|
def get_frame_buffer(self, image):
|
||||||
buf = [0x00] * int(self.height * self.width / 8)
|
buf = [0x00] * int(self.height * self.width / 8)
|
||||||
# Set buffer to value of Python Imaging Library image.
|
# Set buffer to value of Python Imaging Library image.
|
||||||
# Image must be in mode 1.
|
# Image must be in mode 1.
|
||||||
image_monocolor = image.convert('L') #with ot withour dithering?
|
image_monocolor = image.convert('L') # with ot withour dithering?
|
||||||
imwidth, imheight = image_monocolor.size
|
imwidth, imheight = image_monocolor.size
|
||||||
if imwidth != self.height or imheight != self.width:
|
if imwidth != self.height or imheight != self.width:
|
||||||
raise ValueError('Image must be same dimensions as display \
|
raise ValueError('Image must be same dimensions as display \
|
||||||
|
@ -44,11 +45,11 @@ class Epd7in5Adapter (EpdAdapter):
|
||||||
for y in range(self.width):
|
for y in range(self.width):
|
||||||
for x in range(self.height):
|
for x in range(self.height):
|
||||||
# Set the bits for the column of pixels at the current position.
|
# Set the bits for the column of pixels at the current position.
|
||||||
if pixels[x, y] >= 240: #White
|
if pixels[x, y] >= 240: # White
|
||||||
buf[int((x + y * self.height) / 8)] |= 0x80 >> (x % 8)
|
buf[int((x + y * self.height) / 8)] |= 0x80 >> (x % 8)
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def calibrate (self):
|
def calibrate(self):
|
||||||
for _ in range(2):
|
for _ in range(2):
|
||||||
self.init_render()
|
self.init_render()
|
||||||
black = Image.new('1', (self.height, self.width), 'black')
|
black = Image.new('1', (self.height, self.width), 'black')
|
||||||
|
@ -61,4 +62,4 @@ class Epd7in5Adapter (EpdAdapter):
|
||||||
print('calibrating white...')
|
print('calibrating white...')
|
||||||
self.display_frame(self.get_frame_buffer(white))
|
self.display_frame(self.get_frame_buffer(white))
|
||||||
self.sleep()
|
self.sleep()
|
||||||
print('Calibration complete')
|
print('Calibration complete')
|
||||||
|
|
|
@ -4,16 +4,17 @@ from PIL import Image, ImageDraw
|
||||||
from math import sqrt, pow
|
from math import sqrt, pow
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
|
||||||
|
|
||||||
class Epd7in5bAdapter (EpdAdapter):
|
class Epd7in5bAdapter (EpdAdapter):
|
||||||
def __init__ (self):
|
def __init__(self):
|
||||||
super(Epd7in5bAdapter, self).__init__(384, 640)
|
super(Epd7in5bAdapter, self).__init__(384, 640)
|
||||||
|
|
||||||
def display_frame (self, frame_buffer):
|
def display_frame(self, frame_buffer):
|
||||||
self.send_command(DATA_START_TRANSMISSION_1)
|
self.send_command(DATA_START_TRANSMISSION_1)
|
||||||
for i in range(0, int(self.height / 4 * self.width)):
|
for i in range(0, int(self.height / 4 * self.width)):
|
||||||
#the above line had to be modified due to python2 -> python3
|
# the above line had to be modified due to python2 -> python3
|
||||||
#the issue lies in division, which returns integers in python2
|
# the issue lies in division, which returns integers in python2
|
||||||
#but floats in python3
|
# but floats in python3
|
||||||
temp1 = frame_buffer[i]
|
temp1 = frame_buffer[i]
|
||||||
j = 0
|
j = 0
|
||||||
while (j < 4):
|
while (j < 4):
|
||||||
|
@ -39,8 +40,8 @@ class Epd7in5bAdapter (EpdAdapter):
|
||||||
self.delay_ms(100)
|
self.delay_ms(100)
|
||||||
self.wait_until_idle()
|
self.wait_until_idle()
|
||||||
|
|
||||||
def get_frame_buffer (self, image):
|
def get_frame_buffer(self, image):
|
||||||
buf = [ 0x00 ] * int(self.height * self.width / 4)
|
buf = [0x00] * int(self.height * self.width / 4)
|
||||||
imwidth, imheight = image.size
|
imwidth, imheight = image.size
|
||||||
if imwidth != self.height or imheight != self.width:
|
if imwidth != self.height or imheight != self.width:
|
||||||
raise ValueError('Image must be same dimensions as display \
|
raise ValueError('Image must be same dimensions as display \
|
||||||
|
@ -51,24 +52,26 @@ class Epd7in5bAdapter (EpdAdapter):
|
||||||
for y in range(self.height):
|
for y in range(self.height):
|
||||||
# Set the bits for the column of pixels at the current
|
# Set the bits for the column of pixels at the current
|
||||||
# position.
|
# position.
|
||||||
if image_buf[x, y, 1] == 255: #White
|
if image_buf[x, y, 1] == 255: # White
|
||||||
buf[int((y + x * self.height) / 4)] |= 0xC0 >> (y % 4 * 2)
|
buf[int((y + x * self.height) / 4)] |= 0xC0 >> (y % 4 * 2)
|
||||||
elif image_buf[x, y, 0] == 0: #Black
|
elif image_buf[x, y, 0] == 0: # Black
|
||||||
buf[int((y + x * self.height) / 4)] &= ~(0xC0 >> (y % 4 * 2))
|
buf[int((y + x * self.height) / 4)
|
||||||
else: #Red
|
] &= ~(0xC0 >> (y % 4 * 2))
|
||||||
buf[int((y + x * self.height) / 4)] &= ~(0xC0 >> (y % 4 * 2))
|
else: # Red
|
||||||
|
buf[int((y + x * self.height) / 4)
|
||||||
|
] &= ~(0xC0 >> (y % 4 * 2))
|
||||||
buf[int((y + x * self.height) / 4)] |= 0x40 >> (y % 4 * 2)
|
buf[int((y + x * self.height) / 4)] |= 0x40 >> (y % 4 * 2)
|
||||||
return buf
|
return buf
|
||||||
|
|
||||||
def __prepare_image__(self, image):
|
def __prepare_image__(self, image):
|
||||||
buffer = np.array(image)
|
buffer = np.array(image)
|
||||||
r,g = buffer[:,:,0], buffer[:,:,1]
|
r, g = buffer[:, :, 0], buffer[:, :, 1]
|
||||||
buffer[np.logical_and(r > 220, g > 220)] = [255,255,255]
|
buffer[np.logical_and(r > 220, g > 220)] = [255, 255, 255]
|
||||||
buffer[r > g] = [255,0,0]
|
buffer[r > g] = [255, 0, 0]
|
||||||
buffer[r != 255] = [0,0,0]
|
buffer[r != 255] = [0, 0, 0]
|
||||||
return buffer
|
return buffer
|
||||||
|
|
||||||
def calibrate (self):
|
def calibrate(self):
|
||||||
for _ in range(2):
|
for _ in range(2):
|
||||||
self.init_render()
|
self.init_render()
|
||||||
black = Image.new('RGB', (self.height, self.width), 'black')
|
black = Image.new('RGB', (self.height, self.width), 'black')
|
||||||
|
@ -86,4 +89,4 @@ class Epd7in5bAdapter (EpdAdapter):
|
||||||
print('calibrating white...')
|
print('calibrating white...')
|
||||||
self.display_frame(self.get_frame_buffer(white))
|
self.display_frame(self.get_frame_buffer(white))
|
||||||
self.sleep()
|
self.sleep()
|
||||||
print('Calibration complete')
|
print('Calibration complete')
|
||||||
|
|
|
@ -4,53 +4,55 @@ import RPi.GPIO as GPIO
|
||||||
import time
|
import time
|
||||||
from PIL import Image
|
from PIL import Image
|
||||||
|
|
||||||
RST_PIN = 17
|
RST_PIN = 17
|
||||||
DC_PIN = 25
|
DC_PIN = 25
|
||||||
CS_PIN = 8
|
CS_PIN = 8
|
||||||
BUSY_PIN = 24
|
BUSY_PIN = 24
|
||||||
|
|
||||||
# Commands
|
# Commands
|
||||||
PANEL_SETTING = 0x00
|
PANEL_SETTING = 0x00
|
||||||
POWER_SETTING = 0x01
|
POWER_SETTING = 0x01
|
||||||
POWER_OFF = 0x02
|
POWER_OFF = 0x02
|
||||||
POWER_OFF_SEQUENCE_SETTING = 0x03
|
POWER_OFF_SEQUENCE_SETTING = 0x03
|
||||||
POWER_ON = 0x04
|
POWER_ON = 0x04
|
||||||
POWER_ON_MEASURE = 0x05
|
POWER_ON_MEASURE = 0x05
|
||||||
BOOSTER_SOFT_START = 0x06
|
BOOSTER_SOFT_START = 0x06
|
||||||
DEEP_SLEEP = 0x07
|
DEEP_SLEEP = 0x07
|
||||||
DATA_START_TRANSMISSION_1 = 0x10
|
DATA_START_TRANSMISSION_1 = 0x10
|
||||||
DATA_STOP = 0x11
|
DATA_STOP = 0x11
|
||||||
DISPLAY_REFRESH = 0x12
|
DISPLAY_REFRESH = 0x12
|
||||||
IMAGE_PROCESS = 0x13
|
IMAGE_PROCESS = 0x13
|
||||||
LUT_FOR_VCOM = 0x20
|
LUT_FOR_VCOM = 0x20
|
||||||
LUT_BLUE = 0x21
|
LUT_BLUE = 0x21
|
||||||
LUT_WHITE = 0x22
|
LUT_WHITE = 0x22
|
||||||
LUT_GRAY_1 = 0x23
|
LUT_GRAY_1 = 0x23
|
||||||
LUT_GRAY_2 = 0x24
|
LUT_GRAY_2 = 0x24
|
||||||
LUT_RED_0 = 0x25
|
LUT_RED_0 = 0x25
|
||||||
LUT_RED_1 = 0x26
|
LUT_RED_1 = 0x26
|
||||||
LUT_RED_2 = 0x27
|
LUT_RED_2 = 0x27
|
||||||
LUT_RED_3 = 0x28
|
LUT_RED_3 = 0x28
|
||||||
LUT_XON = 0x29
|
LUT_XON = 0x29
|
||||||
PLL_CONTROL = 0x30
|
PLL_CONTROL = 0x30
|
||||||
TEMPERATURE_SENSOR_COMMAND = 0x40
|
TEMPERATURE_SENSOR_COMMAND = 0x40
|
||||||
TEMPERATURE_CALIBRATION = 0x41
|
TEMPERATURE_CALIBRATION = 0x41
|
||||||
TEMPERATURE_SENSOR_WRITE = 0x42
|
TEMPERATURE_SENSOR_WRITE = 0x42
|
||||||
TEMPERATURE_SENSOR_READ = 0x43
|
TEMPERATURE_SENSOR_READ = 0x43
|
||||||
VCOM_AND_DATA_INTERVAL_SETTING = 0x50
|
VCOM_AND_DATA_INTERVAL_SETTING = 0x50
|
||||||
LOW_POWER_DETECTION = 0x51
|
LOW_POWER_DETECTION = 0x51
|
||||||
TCON_SETTING = 0x60
|
TCON_SETTING = 0x60
|
||||||
TCON_RESOLUTION = 0x61
|
TCON_RESOLUTION = 0x61
|
||||||
SPI_FLASH_CONTROL = 0x65
|
SPI_FLASH_CONTROL = 0x65
|
||||||
REVISION = 0x70
|
REVISION = 0x70
|
||||||
GET_STATUS = 0x71
|
GET_STATUS = 0x71
|
||||||
AUTO_MEASUREMENT_VCOM = 0x80
|
AUTO_MEASUREMENT_VCOM = 0x80
|
||||||
READ_VCOM_VALUE = 0x81
|
READ_VCOM_VALUE = 0x81
|
||||||
VCM_DC_SETTING = 0x82
|
VCM_DC_SETTING = 0x82
|
||||||
|
|
||||||
class EpdAdapter (DisplayAdapter):
|
|
||||||
|
class EpdAdapter (DisplayAdapter):
|
||||||
"""Generalized adapter for epd7in5 and epd7in5b"""
|
"""Generalized adapter for epd7in5 and epd7in5b"""
|
||||||
def __init__ (self, width, height):
|
|
||||||
|
def __init__(self, width, height):
|
||||||
super(EpdAdapter, self).__init__(width, height)
|
super(EpdAdapter, self).__init__(width, height)
|
||||||
|
|
||||||
self.reset_pin = RST_PIN
|
self.reset_pin = RST_PIN
|
||||||
|
@ -59,16 +61,16 @@ class EpdAdapter (DisplayAdapter):
|
||||||
|
|
||||||
self.epd_init()
|
self.epd_init()
|
||||||
|
|
||||||
def display_frame (self, frame_buffer):
|
def display_frame(self, frame_buffer):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
def get_frame_buffer (self, image):
|
def get_frame_buffer(self, image):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
def render (self, design):
|
def render(self, design):
|
||||||
self.init_render()
|
self.init_render()
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
|
|
||||||
print('Converting image to data and sending it to the display')
|
print('Converting image to data and sending it to the display')
|
||||||
print('This may take a while...' + '\n')
|
print('This may take a while...' + '\n')
|
||||||
prepared_image = design.get_image().rotate(270, expand=1).convert("RGB")
|
prepared_image = design.get_image().rotate(270, expand=1).convert("RGB")
|
||||||
|
@ -79,7 +81,7 @@ class EpdAdapter (DisplayAdapter):
|
||||||
print('Data sent successfully')
|
print('Data sent successfully')
|
||||||
print('Powering off the E-Paper until the next loop' + '\n')
|
print('Powering off the E-Paper until the next loop' + '\n')
|
||||||
|
|
||||||
def init_render (self):
|
def init_render(self):
|
||||||
if (self.epd_init() != 0):
|
if (self.epd_init() != 0):
|
||||||
return -1
|
return -1
|
||||||
self.reset()
|
self.reset()
|
||||||
|
@ -113,30 +115,30 @@ class EpdAdapter (DisplayAdapter):
|
||||||
self.send_data(0x22)
|
self.send_data(0x22)
|
||||||
|
|
||||||
self.send_command(TCON_RESOLUTION)
|
self.send_command(TCON_RESOLUTION)
|
||||||
self.send_data(0x02) #source 640
|
self.send_data(0x02) # source 640
|
||||||
self.send_data(0x80)
|
self.send_data(0x80)
|
||||||
self.send_data(0x01) #gate 384
|
self.send_data(0x01) # gate 384
|
||||||
self.send_data(0x80)
|
self.send_data(0x80)
|
||||||
|
|
||||||
self.send_command(VCM_DC_SETTING)
|
self.send_command(VCM_DC_SETTING)
|
||||||
self.send_data(0x1E) #decide by LUT file
|
self.send_data(0x1E) # decide by LUT file
|
||||||
|
|
||||||
self.send_command(0xe5) #FLASH MODE
|
self.send_command(0xe5) # FLASH MODE
|
||||||
self.send_data(0x03)
|
self.send_data(0x03)
|
||||||
|
|
||||||
def digital_write (self, pin, value):
|
def digital_write(self, pin, value):
|
||||||
GPIO.output(pin, value)
|
GPIO.output(pin, value)
|
||||||
|
|
||||||
def digital_read (self, pin):
|
def digital_read(self, pin):
|
||||||
return GPIO.input(pin)
|
return GPIO.input(pin)
|
||||||
|
|
||||||
def delay_ms (self, delaytime):
|
def delay_ms(self, delaytime):
|
||||||
time.sleep(delaytime / 1000.0)
|
time.sleep(delaytime / 1000.0)
|
||||||
|
|
||||||
def spi_transfer (self, data):
|
def spi_transfer(self, data):
|
||||||
self.SPI.writebytes(data)
|
self.SPI.writebytes(data)
|
||||||
|
|
||||||
def epd_init (self):
|
def epd_init(self):
|
||||||
# SPI device, bus = 0, device = 0
|
# SPI device, bus = 0, device = 0
|
||||||
self.SPI = spidev.SpiDev(0, 0)
|
self.SPI = spidev.SpiDev(0, 0)
|
||||||
#self.SPI.no_cs = True
|
#self.SPI.no_cs = True
|
||||||
|
@ -151,13 +153,13 @@ class EpdAdapter (DisplayAdapter):
|
||||||
self.SPI.mode = 0b00
|
self.SPI.mode = 0b00
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def sleep (self):
|
def sleep(self):
|
||||||
self.send_command(POWER_OFF)
|
self.send_command(POWER_OFF)
|
||||||
self.wait_until_idle()
|
self.wait_until_idle()
|
||||||
self.send_command(DEEP_SLEEP)
|
self.send_command(DEEP_SLEEP)
|
||||||
self.send_data(0xa5)
|
self.send_data(0xa5)
|
||||||
|
|
||||||
def wait_until_idle (self, max_wait_seconds = 60):
|
def wait_until_idle(self, max_wait_seconds=60):
|
||||||
wait_ms = 100
|
wait_ms = 100
|
||||||
count = 0
|
count = 0
|
||||||
while(self.digital_read(self.busy_pin) == 0 and wait_ms * count < max_wait_seconds * 1000): # 0: busy, 1: idle
|
while(self.digital_read(self.busy_pin) == 0 and wait_ms * count < max_wait_seconds * 1000): # 0: busy, 1: idle
|
||||||
|
@ -166,20 +168,20 @@ class EpdAdapter (DisplayAdapter):
|
||||||
if wait_ms * count >= max_wait_seconds * 1000:
|
if wait_ms * count >= max_wait_seconds * 1000:
|
||||||
print("Skipped idle confirmation")
|
print("Skipped idle confirmation")
|
||||||
|
|
||||||
def reset (self):
|
def reset(self):
|
||||||
self.digital_write(self.reset_pin, GPIO.LOW) # module reset
|
self.digital_write(self.reset_pin, GPIO.LOW) # module reset
|
||||||
self.delay_ms(200)
|
self.delay_ms(200)
|
||||||
self.digital_write(self.reset_pin, GPIO.HIGH)
|
self.digital_write(self.reset_pin, GPIO.HIGH)
|
||||||
self.delay_ms(200)
|
self.delay_ms(200)
|
||||||
|
|
||||||
def send_command (self, command):
|
def send_command(self, command):
|
||||||
self.digital_write(self.dc_pin, GPIO.LOW)
|
self.digital_write(self.dc_pin, GPIO.LOW)
|
||||||
# the parameter type is list but not int
|
# the parameter type is list but not int
|
||||||
# so use [command] instead of command
|
# so use [command] instead of command
|
||||||
self.spi_transfer([ command ])
|
self.spi_transfer([command])
|
||||||
|
|
||||||
def send_data (self, data):
|
def send_data(self, data):
|
||||||
self.digital_write(self.dc_pin, GPIO.HIGH)
|
self.digital_write(self.dc_pin, GPIO.HIGH)
|
||||||
# the parameter type is list but not int
|
# the parameter type is list but not int
|
||||||
# so use [data] instead of data
|
# so use [data] instead of data
|
||||||
self.spi_transfer([ data ])
|
self.spi_transfer([data])
|
||||||
|
|
|
@ -5,10 +5,12 @@ from TextFormatter import date_str
|
||||||
from DictionaryMapper import get_text
|
from DictionaryMapper import get_text
|
||||||
from Dictionary import more_events
|
from Dictionary import more_events
|
||||||
|
|
||||||
|
|
||||||
class EventListDesign (DesignEntity):
|
class EventListDesign (DesignEntity):
|
||||||
"""Creates a TableDesign filled with event
|
"""Creates a TableDesign filled with event
|
||||||
begin date and title"""
|
begin date and title"""
|
||||||
def __init__ (self, size, events, text_size = defaultfontsize, line_spacing = 0, col_spacing = 10, event_prefix_rel_dates = [], event_prefix_func = None, font_family = None, general_color = colors["fg"], background_color = colors["bg"], highlight_color = colors["hl"], show_more_info = False):
|
|
||||||
|
def __init__(self, size, events, text_size=defaultfontsize, line_spacing=0, col_spacing=10, event_prefix_rel_dates=[], event_prefix_func=None, font_family=None, general_color=colors["fg"], background_color=colors["bg"], highlight_color=colors["hl"], show_more_info=False):
|
||||||
super(EventListDesign, self).__init__(size)
|
super(EventListDesign, self).__init__(size)
|
||||||
self.events = events
|
self.events = events
|
||||||
self.__event_matrix__ = []
|
self.__event_matrix__ = []
|
||||||
|
@ -24,22 +26,25 @@ class EventListDesign (DesignEntity):
|
||||||
self.event_prefix_func = event_prefix_func
|
self.event_prefix_func = event_prefix_func
|
||||||
self.event_prefix_rel_dates = event_prefix_rel_dates
|
self.event_prefix_rel_dates = event_prefix_rel_dates
|
||||||
if self.event_prefix_func is None:
|
if self.event_prefix_func is None:
|
||||||
self.event_prefix_func = lambda x, y : date_str(x.begin_datetime)
|
self.event_prefix_func = lambda x, y: date_str(x.begin_datetime)
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
self.visible_event_count = int(int(self.size[1] + self.line_spacing) // (self.line_spacing + int(self.text_size)))
|
self.visible_event_count = int(int(
|
||||||
|
self.size[1] + self.line_spacing) // (self.line_spacing + int(self.text_size)))
|
||||||
self.__fill_event_matrix__()
|
self.__fill_event_matrix__()
|
||||||
|
|
||||||
col_hori_alignment = [ 'right', 'left' ]
|
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, 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)
|
self.draw_design(table_design)
|
||||||
|
|
||||||
def __get_formatted_event__ (self, event, index):
|
def __get_formatted_event__(self, event, index):
|
||||||
rel_date = None if index < 0 or index >= len(self.event_prefix_rel_dates) else self.event_prefix_rel_dates[index]
|
rel_date = None if index < 0 or index >= len(
|
||||||
|
self.event_prefix_rel_dates) else self.event_prefix_rel_dates[index]
|
||||||
prefix = self.event_prefix_func(event, rel_date)
|
prefix = self.event_prefix_func(event, rel_date)
|
||||||
return [ prefix, event.title ]
|
return [prefix, event.title]
|
||||||
|
|
||||||
def __fill_event_matrix__ (self):
|
def __fill_event_matrix__(self):
|
||||||
visible_events = self.events
|
visible_events = self.events
|
||||||
if self.show_more_info and len(visible_events) > self.visible_event_count:
|
if self.show_more_info and len(visible_events) > self.visible_event_count:
|
||||||
visible_events = visible_events[:self.visible_event_count - 1]
|
visible_events = visible_events[:self.visible_event_count - 1]
|
||||||
|
@ -54,16 +59,16 @@ class EventListDesign (DesignEntity):
|
||||||
additional_events_count = len(self.events) - len(visible_events)
|
additional_events_count = len(self.events) - len(visible_events)
|
||||||
more_text = " " + get_text(more_events, additional_events_count)
|
more_text = " " + get_text(more_events, additional_events_count)
|
||||||
if additional_events_count > 0:
|
if additional_events_count > 0:
|
||||||
self.__event_matrix__.append([ "", more_text ])
|
self.__event_matrix__.append(["", more_text])
|
||||||
self.__props_matrix__.append(self.__get_row_props__())
|
self.__props_matrix__.append(self.__get_row_props__())
|
||||||
|
|
||||||
def __get_row_props__ (self, event = None):
|
def __get_row_props__(self, event=None):
|
||||||
color = self.general_color
|
color = self.general_color
|
||||||
bg_color = self.background_color
|
bg_color = self.background_color
|
||||||
if event is not None and event.highlight:
|
if event is not None and event.highlight:
|
||||||
color = self.highlight_color
|
color = self.highlight_color
|
||||||
cell = {
|
cell = {
|
||||||
"color" : color,
|
"color": color,
|
||||||
"background_color" : bg_color
|
"background_color": bg_color
|
||||||
}
|
}
|
||||||
return [ cell, cell ]
|
return [cell, cell]
|
||||||
|
|
|
@ -12,6 +12,7 @@ api_price_url = api_url + "simple/price"
|
||||||
price_currency = "usd"
|
price_currency = "usd"
|
||||||
price_currency_sign = "$"
|
price_currency_sign = "$"
|
||||||
|
|
||||||
|
|
||||||
class GeckoCrypto(CryptoInterface):
|
class GeckoCrypto(CryptoInterface):
|
||||||
def __init__(self, coins):
|
def __init__(self, coins):
|
||||||
self.coin_ids = coins
|
self.coin_ids = coins
|
||||||
|
@ -33,12 +34,13 @@ class GeckoCrypto(CryptoInterface):
|
||||||
coins = []
|
coins = []
|
||||||
for id in self.coin_ids:
|
for id in self.coin_ids:
|
||||||
try:
|
try:
|
||||||
data = urlopen(api_price_url + "?include_24hr_change=true&ids=" + self.metadata[id]['id'] + "&vs_currencies=" + price_currency).read()
|
data = urlopen(api_price_url + "?include_24hr_change=true&ids=" +
|
||||||
|
self.metadata[id]['id'] + "&vs_currencies=" + price_currency).read()
|
||||||
dataJSON = json.loads(data.decode('utf-8'))
|
dataJSON = json.loads(data.decode('utf-8'))
|
||||||
raw = dataJSON[id][price_currency]
|
raw = dataJSON[id][price_currency]
|
||||||
price = math.ceil(raw*100) / 100
|
price = math.ceil(raw*100) / 100
|
||||||
change = dataJSON[id]['usd_24h_change']
|
change = dataJSON[id]['usd_24h_change']
|
||||||
|
|
||||||
coins.append(self.__build_coin__(id, price, change))
|
coins.append(self.__build_coin__(id, price, change))
|
||||||
except:
|
except:
|
||||||
print("Gecko-Error [" + id + "]")
|
print("Gecko-Error [" + id + "]")
|
||||||
|
@ -46,20 +48,21 @@ class GeckoCrypto(CryptoInterface):
|
||||||
|
|
||||||
def __build_coin__(self, id, value, change):
|
def __build_coin__(self, id, value, change):
|
||||||
coin = CryptoCoin()
|
coin = CryptoCoin()
|
||||||
|
|
||||||
coin.name = self.metadata[id]['name']
|
coin.name = self.metadata[id]['name']
|
||||||
coin.day_change = round(change, 2)
|
coin.day_change = round(change, 2)
|
||||||
coin.price = value
|
coin.price = value
|
||||||
|
|
||||||
coin.datetime = datetime.now()
|
coin.datetime = datetime.now()
|
||||||
coin.fetch_datetime = datetime.now()
|
coin.fetch_datetime = datetime.now()
|
||||||
coin.currency = price_currency_sign
|
coin.currency = price_currency_sign
|
||||||
coin.symbol = self.metadata[id]['symbol']
|
coin.symbol = self.metadata[id]['symbol']
|
||||||
|
|
||||||
return coin
|
return coin
|
||||||
|
|
||||||
def __prepare_metadata__(self):
|
def __prepare_metadata__(self):
|
||||||
self.metadata = None
|
self.metadata = None
|
||||||
data = urlopen(api_metadata_url).read()
|
data = urlopen(api_metadata_url).read()
|
||||||
dataJSON = json.loads(data.decode('utf-8'))
|
dataJSON = json.loads(data.decode('utf-8'))
|
||||||
self.metadata = { coin['id'].lower() : coin for coin in dataJSON if coin['id'].lower() in self.coin_ids }
|
self.metadata = {coin['id'].lower(
|
||||||
|
): coin for coin in dataJSON if coin['id'].lower() in self.coin_ids}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
from DesignEntity import DesignEntity
|
from DesignEntity import DesignEntity
|
||||||
from settings import hours, language,line_thickness
|
from settings import hours, language, line_thickness
|
||||||
from TextDesign import TextDesign
|
from TextDesign import TextDesign
|
||||||
from PIL import ImageDraw
|
from PIL import ImageDraw
|
||||||
from Assets import colors, defaultfontsize, fonts
|
from Assets import colors, defaultfontsize, fonts
|
||||||
|
@ -19,54 +19,57 @@ currenttimeline_thickness = line_thickness
|
||||||
|
|
||||||
event_title_font = fonts['bold']
|
event_title_font = fonts['bold']
|
||||||
|
|
||||||
|
|
||||||
class HourListDesign (DesignEntity):
|
class HourListDesign (DesignEntity):
|
||||||
"""Hours of a day are listed vertically and
|
"""Hours of a day are listed vertically and
|
||||||
resemble a timeline."""
|
resemble a timeline."""
|
||||||
def __init__ (self, size, first_hour = 0, last_hour = 23):
|
|
||||||
|
def __init__(self, size, first_hour=0, last_hour=23):
|
||||||
super(HourListDesign, self).__init__(size)
|
super(HourListDesign, self).__init__(size)
|
||||||
self.first_hour = first_hour
|
self.first_hour = first_hour
|
||||||
self.last_hour = last_hour
|
self.last_hour = last_hour
|
||||||
self.__calc_parameters__()
|
self.__calc_parameters__()
|
||||||
self.events = []
|
self.events = []
|
||||||
|
|
||||||
def add_events (self, events):
|
def add_events(self, events):
|
||||||
self.events.extend(events)
|
self.events.extend(events)
|
||||||
self.events.sort(key=lambda x : x.begin_datetime)
|
self.events.sort(key=lambda x: x.begin_datetime)
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
self.number_columns = self.__get_max_num_simultaneous_events__()
|
self.number_columns = self.__get_max_num_simultaneous_events__()
|
||||||
self.__draw_lines__()
|
self.__draw_lines__()
|
||||||
self.__draw_events__()
|
self.__draw_events__()
|
||||||
self.__draw_current_time_line__()
|
self.__draw_current_time_line__()
|
||||||
self.__draw_hour_rows__()
|
self.__draw_hour_rows__()
|
||||||
|
|
||||||
def __calc_parameters__ (self):
|
def __calc_parameters__(self):
|
||||||
self.hour_count = self.last_hour - self.first_hour + 1
|
self.hour_count = self.last_hour - self.first_hour + 1
|
||||||
self.row_size = (self.size[0], self.size[1] / self.hour_count)
|
self.row_size = (self.size[0], self.size[1] / self.hour_count)
|
||||||
|
|
||||||
def __get_hour_text__ (self, hour):
|
def __get_hour_text__(self, hour):
|
||||||
if hour <= 12 or hours is "24":
|
if hour <= 12 or hours is "24":
|
||||||
return str(hour)
|
return str(hour)
|
||||||
else:
|
else:
|
||||||
short = hour - 12
|
short = hour - 12
|
||||||
return str(short) if short > 0 else "12"
|
return str(short) if short > 0 else "12"
|
||||||
|
|
||||||
def __get_ypos_for_time__ (self, hour, minute = 0):
|
def __get_ypos_for_time__(self, hour, minute=0):
|
||||||
return self.__get_height_for_duration__(hour, minute) - self.__get_height_for_duration__(self.first_hour)
|
return self.__get_height_for_duration__(hour, minute) - self.__get_height_for_duration__(self.first_hour)
|
||||||
|
|
||||||
def __get_height_for_duration__ (self, hours, minutes = 0):
|
def __get_height_for_duration__(self, hours, minutes=0):
|
||||||
row_height = self.row_size[1]
|
row_height = self.row_size[1]
|
||||||
return row_height * (hours + minutes / 60)
|
return row_height * (hours + minutes / 60)
|
||||||
|
|
||||||
def __draw_events__ (self):
|
def __draw_events__(self):
|
||||||
column_events = []
|
column_events = []
|
||||||
for _ in range(self.number_columns):
|
for _ in range(self.number_columns):
|
||||||
column_events.append(None)
|
column_events.append(None)
|
||||||
for event in self.events:
|
for event in self.events:
|
||||||
column_events = self.__update_columns_events__(column_events, event)
|
column_events = self.__update_columns_events__(
|
||||||
|
column_events, event)
|
||||||
self.__draw_event__(event, column_events.index(event))
|
self.__draw_event__(event, column_events.index(event))
|
||||||
|
|
||||||
def __update_columns_events__ (self, column_events, new_event):
|
def __update_columns_events__(self, column_events, new_event):
|
||||||
current_time = new_event.begin_datetime
|
current_time = new_event.begin_datetime
|
||||||
new_event_added = False
|
new_event_added = False
|
||||||
for index in range(len(column_events)):
|
for index in range(len(column_events)):
|
||||||
|
@ -77,11 +80,11 @@ class HourListDesign (DesignEntity):
|
||||||
new_event_added = True
|
new_event_added = True
|
||||||
return column_events
|
return column_events
|
||||||
|
|
||||||
def __draw_hour_rows__ (self):
|
def __draw_hour_rows__(self):
|
||||||
for hour in range(self.first_hour, self.last_hour + 1):
|
for hour in range(self.first_hour, self.last_hour + 1):
|
||||||
self.__draw_row__(hour)
|
self.__draw_row__(hour)
|
||||||
|
|
||||||
def __draw_row__ (self, hour):
|
def __draw_row__(self, hour):
|
||||||
subtext_height = self.row_size[1] * hoursubtext_height
|
subtext_height = self.row_size[1] * hoursubtext_height
|
||||||
sub_fontsize = subtext_height * hoursubtext_fontsize
|
sub_fontsize = subtext_height * hoursubtext_fontsize
|
||||||
ypadding = hour_ypadding * self.row_size[1]
|
ypadding = hour_ypadding * self.row_size[1]
|
||||||
|
@ -91,22 +94,25 @@ class HourListDesign (DesignEntity):
|
||||||
pos = (0, self.__get_ypos_for_time__(hour) + ypadding)
|
pos = (0, self.__get_ypos_for_time__(hour) + ypadding)
|
||||||
fontsize = size[1] * hour_box_fontsize
|
fontsize = size[1] * hour_box_fontsize
|
||||||
|
|
||||||
txt = TextDesign(size, text=self.__get_hour_text__(hour), fontsize=fontsize, verticalalignment="bottom", horizontalalignment="center")
|
txt = TextDesign(size, text=self.__get_hour_text__(
|
||||||
|
hour), fontsize=fontsize, verticalalignment="bottom", horizontalalignment="center")
|
||||||
txt.pos = pos
|
txt.pos = pos
|
||||||
self.draw_design(txt)
|
self.draw_design(txt)
|
||||||
|
|
||||||
sub = TextDesign((width, subtext_height), text=self.__get_hour_sub_text__(hour), fontsize=sub_fontsize, verticalalignment="top", horizontalalignment="center")
|
sub = TextDesign((width, subtext_height), text=self.__get_hour_sub_text__(
|
||||||
|
hour), fontsize=sub_fontsize, verticalalignment="top", horizontalalignment="center")
|
||||||
sub.pos = (0, height + self.__get_ypos_for_time__(hour))
|
sub.pos = (0, height + self.__get_ypos_for_time__(hour))
|
||||||
self.draw_design(sub)
|
self.draw_design(sub)
|
||||||
|
|
||||||
def __draw_lines__ (self):
|
def __draw_lines__(self):
|
||||||
for i in range(self.hour_count):
|
for i in range(self.hour_count):
|
||||||
ypos = i * self.row_size[1]
|
ypos = i * self.row_size[1]
|
||||||
line_start = (0, ypos)
|
line_start = (0, ypos)
|
||||||
line_end = (self.size[0], ypos)
|
line_end = (self.size[0], ypos)
|
||||||
ImageDraw.Draw(self.__image__).line([ line_start, line_end ], fill=colors["fg"], width=line_thickness)
|
ImageDraw.Draw(self.__image__).line(
|
||||||
|
[line_start, line_end], fill=colors["fg"], width=line_thickness)
|
||||||
|
|
||||||
def __get_hour_sub_text__ (self, hour):
|
def __get_hour_sub_text__(self, hour):
|
||||||
if hours == "12":
|
if hours == "12":
|
||||||
return "AM" if hour < 12 else "PM"
|
return "AM" if hour < 12 else "PM"
|
||||||
elif language is "de":
|
elif language is "de":
|
||||||
|
@ -115,7 +121,7 @@ class HourListDesign (DesignEntity):
|
||||||
return "o'c"
|
return "o'c"
|
||||||
return ""
|
return ""
|
||||||
|
|
||||||
def __draw_event__ (self, event, column = 0):
|
def __draw_event__(self, event, column=0):
|
||||||
xoffset = hourbox_y_width * self.row_size[1]
|
xoffset = hourbox_y_width * self.row_size[1]
|
||||||
column_width = (self.size[0] - xoffset) / self.number_columns
|
column_width = (self.size[0] - xoffset) / self.number_columns
|
||||||
|
|
||||||
|
@ -132,36 +138,42 @@ class HourListDesign (DesignEntity):
|
||||||
size = (column_width, time_height + yoffset_correction)
|
size = (column_width, time_height + yoffset_correction)
|
||||||
|
|
||||||
if size[1] < 0:
|
if size[1] < 0:
|
||||||
return #Event not in shown time range
|
return # Event not in shown time range
|
||||||
|
|
||||||
self.__draw_event_block__(pos, size, event)
|
self.__draw_event_block__(pos, size, event)
|
||||||
|
|
||||||
def __draw_event_block__ (self, pos, size, event):
|
def __draw_event_block__(self, pos, size, event):
|
||||||
box_color = colors["hl"] if event.highlight else colors["fg"]
|
box_color = colors["hl"] if event.highlight else colors["fg"]
|
||||||
box = BoxDesign(size, fill = box_color)
|
box = BoxDesign(size, fill=box_color)
|
||||||
box.mask = False
|
box.mask = False
|
||||||
box.pos = pos
|
box.pos = pos
|
||||||
self.draw_design(box)
|
self.draw_design(box)
|
||||||
|
|
||||||
text = event.title
|
text = event.title
|
||||||
text_color = colors["bg"]
|
text_color = colors["bg"]
|
||||||
textbox_size = (size[0] - event_title_xpadding, size[1] - event_title_ypadding)
|
textbox_size = (size[0] - event_title_xpadding,
|
||||||
txt = TextDesign(textbox_size, text = text, font=event_title_font, fontsize=event_title_fontsize, color=text_color, background_color=box_color, wrap=True)
|
size[1] - event_title_ypadding)
|
||||||
|
txt = TextDesign(textbox_size, text=text, font=event_title_font,
|
||||||
|
fontsize=event_title_fontsize, color=text_color, background_color=box_color, wrap=True)
|
||||||
txt.mask = False
|
txt.mask = False
|
||||||
txt.pos = (pos[0] + event_title_xpadding, pos[1] + event_title_ypadding)
|
txt.pos = (pos[0] + event_title_xpadding,
|
||||||
|
pos[1] + event_title_ypadding)
|
||||||
self.draw_design(txt)
|
self.draw_design(txt)
|
||||||
|
|
||||||
half_ypadding = int(event_title_ypadding / 2)
|
half_ypadding = int(event_title_ypadding / 2)
|
||||||
line_start = (pos[0] + event_title_xpadding, pos[1] + half_ypadding)
|
line_start = (pos[0] + event_title_xpadding, pos[1] + half_ypadding)
|
||||||
line_end = (pos[0] + size[0] - event_title_xpadding, pos[1] + half_ypadding)
|
line_end = (pos[0] + size[0] - event_title_xpadding,
|
||||||
ImageDraw.Draw(self.__image__).line([ line_start, line_end ], fill=colors["bg"], width=1)
|
pos[1] + half_ypadding)
|
||||||
|
ImageDraw.Draw(self.__image__).line(
|
||||||
|
[line_start, line_end], fill=colors["bg"], width=1)
|
||||||
|
|
||||||
def __get_max_num_simultaneous_events__ (self):
|
def __get_max_num_simultaneous_events__(self):
|
||||||
parallelity_count = 1
|
parallelity_count = 1
|
||||||
|
|
||||||
for index, event in enumerate(self.events):
|
for index, event in enumerate(self.events):
|
||||||
current_parallelity = 1
|
current_parallelity = 1
|
||||||
preceding = self.events[:index] #Assumption: Events are ordered chronologically
|
# Assumption: Events are ordered chronologically
|
||||||
|
preceding = self.events[:index]
|
||||||
for pre_event in preceding:
|
for pre_event in preceding:
|
||||||
if self.__are_simultaneous__(pre_event, event):
|
if self.__are_simultaneous__(pre_event, event):
|
||||||
current_parallelity += 1
|
current_parallelity += 1
|
||||||
|
@ -169,18 +181,19 @@ class HourListDesign (DesignEntity):
|
||||||
parallelity_count = current_parallelity
|
parallelity_count = current_parallelity
|
||||||
return parallelity_count
|
return parallelity_count
|
||||||
|
|
||||||
def __are_simultaneous__ (self, ev_a, ev_b):
|
def __are_simultaneous__(self, ev_a, ev_b):
|
||||||
if ev_a.begin_datetime > ev_b.begin_datetime:
|
if ev_a.begin_datetime > ev_b.begin_datetime:
|
||||||
ev_a, ev_b = ev_b, ev_a
|
ev_a, ev_b = ev_b, ev_a
|
||||||
|
|
||||||
mes_dur = ev_b.begin_datetime - ev_a.begin_datetime
|
mes_dur = ev_b.begin_datetime - ev_a.begin_datetime
|
||||||
|
|
||||||
return mes_dur < ev_a.duration
|
return mes_dur < ev_a.duration
|
||||||
|
|
||||||
def __draw_current_time_line__ (self):
|
def __draw_current_time_line__(self):
|
||||||
now = datetime.now()
|
now = datetime.now()
|
||||||
ypos = self.__get_ypos_for_time__(now.hour, now.minute)
|
ypos = self.__get_ypos_for_time__(now.hour, now.minute)
|
||||||
|
|
||||||
line_start = (0, ypos)
|
line_start = (0, ypos)
|
||||||
line_end = (self.size[0], ypos)
|
line_end = (self.size[0], ypos)
|
||||||
ImageDraw.Draw(self.__image__).line([ line_start, line_end ], fill=colors["hl"], width=currenttimeline_thickness)
|
ImageDraw.Draw(self.__image__).line(
|
||||||
|
[line_start, line_end], fill=colors["hl"], width=currenttimeline_thickness)
|
||||||
|
|
|
@ -6,8 +6,10 @@ import re
|
||||||
from settings import week_starts_on
|
from settings import week_starts_on
|
||||||
from urllib.request import urlopen
|
from urllib.request import urlopen
|
||||||
|
|
||||||
|
|
||||||
class IcalEvents(CalendarInterface):
|
class IcalEvents(CalendarInterface):
|
||||||
"""Fetches events from ical addresses."""
|
"""Fetches events from ical addresses."""
|
||||||
|
|
||||||
def __init__(self, urls, highlighted_urls=None):
|
def __init__(self, urls, highlighted_urls=None):
|
||||||
self.urls = urls
|
self.urls = urls
|
||||||
self.highlighted_urls = highlighted_urls
|
self.highlighted_urls = highlighted_urls
|
||||||
|
@ -60,8 +62,10 @@ class IcalEvents(CalendarInterface):
|
||||||
cal_event.allday = event.all_day
|
cal_event.allday = event.all_day
|
||||||
cal_event.rrule = self.__extract_rrule__(event)
|
cal_event.rrule = self.__extract_rrule__(event)
|
||||||
|
|
||||||
cal_event.begin_datetime = cal_event.begin_datetime.astimezone(None)
|
cal_event.begin_datetime = cal_event.begin_datetime.astimezone(
|
||||||
cal_event.end_datetime = cal_event.end_datetime.astimezone(None)
|
None)
|
||||||
|
cal_event.end_datetime = cal_event.end_datetime.astimezone(
|
||||||
|
None)
|
||||||
|
|
||||||
if cal_event.allday:
|
if cal_event.allday:
|
||||||
cal_event = self.__fix_allday__(cal_event)
|
cal_event = self.__fix_allday__(cal_event)
|
||||||
|
@ -79,8 +83,10 @@ class IcalEvents(CalendarInterface):
|
||||||
begin_utc = event.begin_datetime.astimezone(timezone.utc)
|
begin_utc = event.begin_datetime.astimezone(timezone.utc)
|
||||||
end_utc = event.end_datetime.astimezone(timezone.utc)
|
end_utc = event.end_datetime.astimezone(timezone.utc)
|
||||||
|
|
||||||
event.begin_datetime = datetime(begin_utc.year, begin_utc.month, begin_utc.day, 0, 0, 0, 0, local_tzinfo)
|
event.begin_datetime = datetime(
|
||||||
event.end_datetime = datetime(end_utc.year, end_utc.month, end_utc.day, 0, 0, 0, 0, local_tzinfo) - timedelta(1)
|
begin_utc.year, begin_utc.month, begin_utc.day, 0, 0, 0, 0, local_tzinfo)
|
||||||
|
event.end_datetime = datetime(
|
||||||
|
end_utc.year, end_utc.month, end_utc.day, 0, 0, 0, 0, local_tzinfo) - timedelta(1)
|
||||||
event.duration = event.end_datetime - event.begin_datetime
|
event.duration = event.end_datetime - event.begin_datetime
|
||||||
|
|
||||||
return event
|
return event
|
||||||
|
@ -95,19 +101,21 @@ class IcalEvents(CalendarInterface):
|
||||||
beginAlarmIndex = decode.find(alarm_begin)
|
beginAlarmIndex = decode.find(alarm_begin)
|
||||||
if beginAlarmIndex >= 0:
|
if beginAlarmIndex >= 0:
|
||||||
endAlarmIndex = decode.find(alarm_end, beginAlarmIndex)
|
endAlarmIndex = decode.find(alarm_end, beginAlarmIndex)
|
||||||
decode = decode[:beginAlarmIndex] + decode[endAlarmIndex + len(alarm_end) + len(lineseparation):]
|
decode = decode[:beginAlarmIndex] + \
|
||||||
|
decode[endAlarmIndex +
|
||||||
|
len(alarm_end) + len(lineseparation):]
|
||||||
return decode
|
return decode
|
||||||
|
|
||||||
def __extract_rrule__(self, event):
|
def __extract_rrule__(self, event):
|
||||||
if re.search('RRULE',str(event)) is None:
|
if re.search('RRULE', str(event)) is None:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
return re.search('RRULE:(.+?)\n',str(event)).group(1).rstrip()
|
return re.search('RRULE:(.+?)\n', str(event)).group(1).rstrip()
|
||||||
|
|
||||||
def __is_multiday__ (self, event):
|
def __is_multiday__(self, event):
|
||||||
if event.allday and event.duration == timedelta(1):
|
if event.allday and event.duration == timedelta(1):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
return event.begin_datetime.day != event.end_datetime.day or \
|
return event.begin_datetime.day != event.end_datetime.day or \
|
||||||
event.begin_datetime.month != event.end_datetime.month or \
|
event.begin_datetime.month != event.end_datetime.month or \
|
||||||
event.begin_datetime.year != event.end_datetime.year
|
event.begin_datetime.year != event.end_datetime.year
|
||||||
|
|
|
@ -2,23 +2,26 @@ from DesignEntity import DesignEntity
|
||||||
from Assets import path as application_path
|
from Assets import path as application_path
|
||||||
from PIL import Image, ExifTags
|
from PIL import Image, ExifTags
|
||||||
|
|
||||||
|
|
||||||
class ImageDesign (DesignEntity):
|
class ImageDesign (DesignEntity):
|
||||||
"""Creates a TableDesign filled with rss post
|
"""Creates a TableDesign filled with rss post
|
||||||
date and title"""
|
date and title"""
|
||||||
def __init__ (self, size, path, fill = "none", color="RGBA", dither=None): # fill: "none" : original size, "stretch" : strech to fill, "scale" : scale to fill, "border" : scale until one side touches border
|
|
||||||
|
# fill: "none" : original size, "stretch" : strech to fill, "scale" : scale to fill, "border" : scale until one side touches border
|
||||||
|
def __init__(self, size, path, fill="none", color="RGBA", dither=None):
|
||||||
super(ImageDesign, self).__init__(size)
|
super(ImageDesign, self).__init__(size)
|
||||||
self.set_path(path)
|
self.set_path(path)
|
||||||
self.fill = fill
|
self.fill = fill
|
||||||
self.color = color
|
self.color = color
|
||||||
self.dither = dither
|
self.dither = dither
|
||||||
|
|
||||||
def set_path (self, path):
|
def set_path(self, path):
|
||||||
path = path.replace('\\', '/')
|
path = path.replace('\\', '/')
|
||||||
if path[0] != '/' and ':' not in path[0:3]:
|
if path[0] != '/' and ':' not in path[0:3]:
|
||||||
path = application_path + '/' + path
|
path = application_path + '/' + path
|
||||||
self.path = path
|
self.path = path
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
img = Image.open(self.path)
|
img = Image.open(self.path)
|
||||||
img = img.convert(self.color, dither=self.dither)
|
img = img.convert(self.color, dither=self.dither)
|
||||||
|
|
||||||
|
@ -70,9 +73,9 @@ class ImageDesign (DesignEntity):
|
||||||
return img
|
return img
|
||||||
|
|
||||||
for orientation in ExifTags.TAGS.keys():
|
for orientation in ExifTags.TAGS.keys():
|
||||||
if ExifTags.TAGS[orientation]=='Orientation':
|
if ExifTags.TAGS[orientation] == 'Orientation':
|
||||||
break
|
break
|
||||||
exif=img.info["parsed_exif"]
|
exif = img.info["parsed_exif"]
|
||||||
|
|
||||||
if exif[orientation] == 3:
|
if exif[orientation] == 3:
|
||||||
img = img.rotate(180, expand=True)
|
img = img.rotate(180, expand=True)
|
||||||
|
@ -80,4 +83,4 @@ class ImageDesign (DesignEntity):
|
||||||
img = img.rotate(270, expand=True)
|
img = img.rotate(270, expand=True)
|
||||||
elif exif[orientation] == 8:
|
elif exif[orientation] == 8:
|
||||||
img = img.rotate(90, expand=True)
|
img = img.rotate(90, expand=True)
|
||||||
return img
|
return img
|
||||||
|
|
|
@ -1,16 +1,18 @@
|
||||||
from DisplayAdapter import DisplayAdapter
|
from DisplayAdapter import DisplayAdapter
|
||||||
from Assets import path
|
from Assets import path
|
||||||
|
|
||||||
|
|
||||||
class ImageFileAdapter (DisplayAdapter):
|
class ImageFileAdapter (DisplayAdapter):
|
||||||
"""Saves design to an image file, can be used for debugging"""
|
"""Saves design to an image file, can be used for debugging"""
|
||||||
def __init__ (self, file_path = ""):
|
|
||||||
|
def __init__(self, file_path=""):
|
||||||
super(ImageFileAdapter, self).__init__(384, 640)
|
super(ImageFileAdapter, self).__init__(384, 640)
|
||||||
self.file_path = file_path
|
self.file_path = file_path
|
||||||
if self.file_path == "":
|
if self.file_path == "":
|
||||||
self.file_path = path
|
self.file_path = path
|
||||||
|
|
||||||
def render (self, design):
|
def render(self, design):
|
||||||
design.get_image().save(self.file_path + 'design_exported.png')
|
design.get_image().save(self.file_path + 'design_exported.png')
|
||||||
|
|
||||||
def calibrate (self):
|
def calibrate(self):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -10,14 +10,17 @@ from random import choice
|
||||||
class ImageFramePanel (PanelDesign):
|
class ImageFramePanel (PanelDesign):
|
||||||
"""Converts the display into a digital frame and
|
"""Converts the display into a digital frame and
|
||||||
shows a slide show of images, iterating on each update"""
|
shows a slide show of images, iterating on each update"""
|
||||||
def __init__ (self, size):
|
|
||||||
|
def __init__(self, size):
|
||||||
super(ImageFramePanel, self).__init__(size)
|
super(ImageFramePanel, self).__init__(size)
|
||||||
self.overlay_path = self.__complete_path__(general_settings["overlay-image"])
|
self.overlay_path = self.__complete_path__(
|
||||||
self.image_folder_path = self.__complete_path__(general_settings["image-folder"])
|
general_settings["overlay-image"])
|
||||||
|
self.image_folder_path = self.__complete_path__(
|
||||||
|
general_settings["image-folder"])
|
||||||
self.images = self.__extract_valid_img_paths__()
|
self.images = self.__extract_valid_img_paths__()
|
||||||
self.__first_render__()
|
self.__first_render__()
|
||||||
|
|
||||||
def __extract_valid_img_paths__ (self):
|
def __extract_valid_img_paths__(self):
|
||||||
images = []
|
images = []
|
||||||
for file in listdir(self.image_folder_path):
|
for file in listdir(self.image_folder_path):
|
||||||
file_path = join(self.image_folder_path, file).replace('\\', '/')
|
file_path = join(self.image_folder_path, file).replace('\\', '/')
|
||||||
|
@ -42,17 +45,17 @@ class ImageFramePanel (PanelDesign):
|
||||||
overlay.__finish_image__()
|
overlay.__finish_image__()
|
||||||
self.__image__.alpha_composite(overlay.__image__)
|
self.__image__.alpha_composite(overlay.__image__)
|
||||||
|
|
||||||
def add_weather (self, weather):
|
def add_weather(self, weather):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_calendar (self, calendar):
|
def add_calendar(self, calendar):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_rssfeed (self, rss):
|
def add_rssfeed(self, rss):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_crypto (self, crypto):
|
def add_crypto(self, crypto):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_tasks (self, tasks):
|
def add_tasks(self, tasks):
|
||||||
pass
|
pass
|
||||||
|
|
|
@ -3,39 +3,41 @@ from datetime import datetime, timedelta
|
||||||
min_sleep_minutes = 0
|
min_sleep_minutes = 0
|
||||||
max_history_entries = 25
|
max_history_entries = 25
|
||||||
|
|
||||||
|
|
||||||
class LoopTimer (object):
|
class LoopTimer (object):
|
||||||
"""Manages loop times and sleeps until
|
"""Manages loop times and sleeps until
|
||||||
next loop."""
|
next loop."""
|
||||||
def __init__ (self, loop_interval, run_on_hour = False):
|
|
||||||
|
def __init__(self, loop_interval, run_on_hour=False):
|
||||||
self.interval = int(str(loop_interval))
|
self.interval = int(str(loop_interval))
|
||||||
self.on_hour = run_on_hour
|
self.on_hour = run_on_hour
|
||||||
self.loop_history = []
|
self.loop_history = []
|
||||||
|
|
||||||
def begin_loop (self):
|
def begin_loop(self):
|
||||||
begin_time = datetime.now()
|
begin_time = datetime.now()
|
||||||
print('\n__________Starting new loop__________')
|
print('\n__________Starting new loop__________')
|
||||||
print('Datetime: ' + str(begin_time) + '\n')
|
print('Datetime: ' + str(begin_time) + '\n')
|
||||||
self.__add_beginning__(begin_time)
|
self.__add_beginning__(begin_time)
|
||||||
|
|
||||||
def __add_beginning__ (self, time):
|
def __add_beginning__(self, time):
|
||||||
self.loop_history.append((time,))
|
self.loop_history.append((time,))
|
||||||
|
|
||||||
if len(self.loop_history) > max_history_entries:
|
if len(self.loop_history) > max_history_entries:
|
||||||
dif = len(self.loop_history) - max_history_entries
|
dif = len(self.loop_history) - max_history_entries
|
||||||
self.loop_history = self.loop_history[dif:]
|
self.loop_history = self.loop_history[dif:]
|
||||||
|
|
||||||
def __add_ending__ (self, time):
|
def __add_ending__(self, time):
|
||||||
current = self.get_current()
|
current = self.get_current()
|
||||||
self.loop_history[-1] = (current[0], time)
|
self.loop_history[-1] = (current[0], time)
|
||||||
|
|
||||||
def end_loop (self):
|
def end_loop(self):
|
||||||
end_time = datetime.now()
|
end_time = datetime.now()
|
||||||
self.__add_ending__(end_time)
|
self.__add_ending__(end_time)
|
||||||
|
|
||||||
def get_current (self):
|
def get_current(self):
|
||||||
return self.loop_history[-1]
|
return self.loop_history[-1]
|
||||||
|
|
||||||
def time_until_next (self):
|
def time_until_next(self):
|
||||||
interval_duration = timedelta(minutes=self.interval)
|
interval_duration = timedelta(minutes=self.interval)
|
||||||
loop_duration = self.get_last_duration()
|
loop_duration = self.get_last_duration()
|
||||||
sleep_time = interval_duration - loop_duration
|
sleep_time = interval_duration - loop_duration
|
||||||
|
@ -48,19 +50,19 @@ class LoopTimer (object):
|
||||||
sleep_time = timedelta(0, 0, 0, 0, min_sleep_minutes)
|
sleep_time = timedelta(0, 0, 0, 0, min_sleep_minutes)
|
||||||
return sleep_time
|
return sleep_time
|
||||||
|
|
||||||
def get_last_duration (self):
|
def get_last_duration(self):
|
||||||
if len(self.loop_history) == 0:
|
if len(self.loop_history) == 0:
|
||||||
return
|
return
|
||||||
begin, end = self.loop_history[-1]
|
begin, end = self.loop_history[-1]
|
||||||
return end - begin
|
return end - begin
|
||||||
|
|
||||||
def get_time_to_next_hour (self):
|
def get_time_to_next_hour(self):
|
||||||
cur = datetime.now()
|
cur = datetime.now()
|
||||||
rounded = datetime(cur.year, cur.month, cur.day, cur.hour)
|
rounded = datetime(cur.year, cur.month, cur.day, cur.hour)
|
||||||
next_hour_time = rounded + timedelta(hours=1)
|
next_hour_time = rounded + timedelta(hours=1)
|
||||||
return next_hour_time - datetime.now()
|
return next_hour_time - datetime.now()
|
||||||
|
|
||||||
def is_new_hour_loop (self):
|
def is_new_hour_loop(self):
|
||||||
if len(self.loop_history) < 2:
|
if len(self.loop_history) < 2:
|
||||||
return False
|
return False
|
||||||
previous_loop = self.loop_history[-2]
|
previous_loop = self.loop_history[-2]
|
||||||
|
@ -69,4 +71,4 @@ class LoopTimer (object):
|
||||||
if previous_loop[0].hour != current_loop[0].hour:
|
if previous_loop[0].hour != current_loop[0].hour:
|
||||||
return True
|
return True
|
||||||
else:
|
else:
|
||||||
return False
|
return False
|
||||||
|
|
|
@ -11,10 +11,12 @@ dayhighlightboxsize = (0.143, 0.14)
|
||||||
daynumbersize = daynumberboxsize[0] * 0.45
|
daynumbersize = daynumberboxsize[0] * 0.45
|
||||||
day_number_ypadding = -0.002
|
day_number_ypadding = -0.002
|
||||||
|
|
||||||
|
|
||||||
class MonthBlockDesign (DesignEntity):
|
class MonthBlockDesign (DesignEntity):
|
||||||
"""Creates a view containing one week of the month in
|
"""Creates a view containing one week of the month in
|
||||||
one row"""
|
one row"""
|
||||||
def __init__(self, size, datetime_month, highlight_today = False):
|
|
||||||
|
def __init__(self, size, datetime_month, highlight_today=False):
|
||||||
super(MonthBlockDesign, self).__init__(size, mask=True)
|
super(MonthBlockDesign, self).__init__(size, mask=True)
|
||||||
self.month = datetime_month.month
|
self.month = datetime_month.month
|
||||||
self.year = datetime_month.year
|
self.year = datetime_month.year
|
||||||
|
@ -24,49 +26,53 @@ class MonthBlockDesign (DesignEntity):
|
||||||
def __finish_image__(self):
|
def __finish_image__(self):
|
||||||
self.__draw_month_overview__()
|
self.__draw_month_overview__()
|
||||||
|
|
||||||
def __draw_month_overview__ (self):
|
def __draw_month_overview__(self):
|
||||||
"""Using the built-in calendar function, draw icons for each
|
"""Using the built-in calendar function, draw icons for each
|
||||||
number of the month (1,2,3,...29,30,31)"""
|
number of the month (1,2,3,...29,30,31)"""
|
||||||
cal = callib.monthcalendar(self.year, self.month)
|
cal = callib.monthcalendar(self.year, self.month)
|
||||||
for week in cal:
|
for week in cal:
|
||||||
for numbers in week:
|
for numbers in week:
|
||||||
self.__draw_day_number__(numbers, self.get_day_pos(cal.index(week), week.index(numbers)))
|
self.__draw_day_number__(numbers, self.get_day_pos(
|
||||||
|
cal.index(week), week.index(numbers)))
|
||||||
if self.highlight_today:
|
|
||||||
self.__draw_highlight_box__(self.__abs_pos__(dayhighlightboxsize), self.__get_today_box_pos__(), width=3)
|
|
||||||
|
|
||||||
def __draw_highlight_box__ (self, size, pos, color=colors["fg"], width=1):
|
if self.highlight_today:
|
||||||
design = BoxDesign(size, outline=color, width = width)
|
self.__draw_highlight_box__(self.__abs_pos__(
|
||||||
|
dayhighlightboxsize), self.__get_today_box_pos__(), width=3)
|
||||||
|
|
||||||
|
def __draw_highlight_box__(self, size, pos, color=colors["fg"], width=1):
|
||||||
|
design = BoxDesign(size, outline=color, width=width)
|
||||||
design.pos = pos
|
design.pos = pos
|
||||||
self.draw_design(design)
|
self.draw_design(design)
|
||||||
|
|
||||||
def __draw_day_number__ (self, number, pos):
|
def __draw_day_number__(self, number, pos):
|
||||||
if number <= 0:
|
if number <= 0:
|
||||||
return
|
return
|
||||||
txt = TextDesign(self.__abs_pos__(daynumberboxsize), fontsize=daynumbersize * self.size[0], text=str(number), verticalalignment="center", horizontalalignment="center")
|
txt = TextDesign(self.__abs_pos__(daynumberboxsize), fontsize=daynumbersize *
|
||||||
|
self.size[0], text=str(number), verticalalignment="center", horizontalalignment="center")
|
||||||
txt.pos = (pos[0], pos[1] + day_number_ypadding * self.size[1])
|
txt.pos = (pos[0], pos[1] + day_number_ypadding * self.size[1])
|
||||||
self.draw_design(txt)
|
self.draw_design(txt)
|
||||||
|
|
||||||
def get_day_pos (self, week_in_month, day_of_week, rel_pos=(0,0)):
|
def get_day_pos(self, week_in_month, day_of_week, rel_pos=(0, 0)):
|
||||||
maxwidth, maxheight = self.size
|
maxwidth, maxheight = self.size
|
||||||
partialwidth = maxwidth / 7
|
partialwidth = maxwidth / 7
|
||||||
partialheight = maxheight / 5
|
partialheight = maxheight / 5
|
||||||
return (int(rel_pos[0] + day_of_week * partialwidth), int(rel_pos[1] + week_in_month * partialheight))
|
return (int(rel_pos[0] + day_of_week * partialwidth), int(rel_pos[1] + week_in_month * partialheight))
|
||||||
|
|
||||||
def __get_today_box_pos__ (self):
|
def __get_today_box_pos__(self):
|
||||||
x, y = self.get_day_pos(self.__get_week_of_month__(datetime.now()), self.__get_day_of_week__(datetime.now()))
|
x, y = self.get_day_pos(self.__get_week_of_month__(
|
||||||
|
datetime.now()), self.__get_day_of_week__(datetime.now()))
|
||||||
return (x, int(y + (self.__abs_pos__(daynumberboxsize)[1] - self.__abs_pos__(dayhighlightboxsize)[1]) / 2))
|
return (x, int(y + (self.__abs_pos__(daynumberboxsize)[1] - self.__abs_pos__(dayhighlightboxsize)[1]) / 2))
|
||||||
|
|
||||||
def __get_week_of_month__ (self, date):
|
def __get_week_of_month__(self, date):
|
||||||
for wof, week in enumerate(callib.monthcalendar(date.year, date.month)):
|
for wof, week in enumerate(callib.monthcalendar(date.year, date.month)):
|
||||||
if date.day in week:
|
if date.day in week:
|
||||||
return wof
|
return wof
|
||||||
return 0
|
return 0
|
||||||
|
|
||||||
def __get_day_of_week__ (self, date):
|
def __get_day_of_week__(self, date):
|
||||||
return self.__week_days__.index(date.strftime("%a"))
|
return self.__week_days__.index(date.strftime("%a"))
|
||||||
|
|
||||||
def __get_week_days_ordered__ (self):
|
def __get_week_days_ordered__(self):
|
||||||
cur_weekday = datetime.now().weekday()
|
cur_weekday = datetime.now().weekday()
|
||||||
correction = -cur_weekday
|
correction = -cur_weekday
|
||||||
if week_starts_on == "Sunday":
|
if week_starts_on == "Sunday":
|
||||||
|
@ -74,17 +80,18 @@ class MonthBlockDesign (DesignEntity):
|
||||||
|
|
||||||
weekdays = []
|
weekdays = []
|
||||||
for i in range(7):
|
for i in range(7):
|
||||||
weekdays.append((datetime.now() + timedelta(days=(i + correction))).strftime("%a"))
|
weekdays.append(
|
||||||
|
(datetime.now() + timedelta(days=(i + correction))).strftime("%a"))
|
||||||
|
|
||||||
return weekdays
|
return weekdays
|
||||||
|
|
||||||
def __abs_pos__ (self, pos, size = None):
|
def __abs_pos__(self, pos, size=None):
|
||||||
if size is None:
|
if size is None:
|
||||||
size = self.size
|
size = self.size
|
||||||
return (int(pos[0] * size[0]), int(pos[1] * size[1]))
|
return (int(pos[0] * size[0]), int(pos[1] * size[1]))
|
||||||
|
|
||||||
def get_real_height (self):
|
def get_real_height(self):
|
||||||
weeks_in_month = callib.monthcalendar(self.year, self.month)
|
weeks_in_month = callib.monthcalendar(self.year, self.month)
|
||||||
num_size = self.__abs_pos__(daynumberboxsize)
|
num_size = self.__abs_pos__(daynumberboxsize)
|
||||||
num_pos = self.get_day_pos(len(weeks_in_month) - 1, 6)
|
num_pos = self.get_day_pos(len(weeks_in_month) - 1, 6)
|
||||||
return num_size[1] + num_pos[1]
|
return num_size[1] + num_pos[1]
|
||||||
|
|
|
@ -15,7 +15,7 @@ from settings import general_settings
|
||||||
from CryptoListDesign import CryptoListDesign
|
from CryptoListDesign import CryptoListDesign
|
||||||
|
|
||||||
|
|
||||||
weatherheadersize = (1,0.113)
|
weatherheadersize = (1, 0.113)
|
||||||
monthboxsize = (1, 0.085)
|
monthboxsize = (1, 0.085)
|
||||||
monthtextsize = monthboxsize[1] * 0.75
|
monthtextsize = monthboxsize[1] * 0.75
|
||||||
monthplace = (0, 0.11 - weatherheadersize[1])
|
monthplace = (0, 0.11 - weatherheadersize[1])
|
||||||
|
@ -29,17 +29,19 @@ weekdaytextpadding = -0.001
|
||||||
weekrownameboxsize = (0.143, 0.044)
|
weekrownameboxsize = (0.143, 0.044)
|
||||||
eventcirclehorizontalsize = 0.100
|
eventcirclehorizontalsize = 0.100
|
||||||
|
|
||||||
|
|
||||||
class MonthOvPanel (PanelDesign):
|
class MonthOvPanel (PanelDesign):
|
||||||
"""Overview that focuses on the current month and
|
"""Overview that focuses on the current month and
|
||||||
some additional information in the bottom."""
|
some additional information in the bottom."""
|
||||||
def __init__ (self, size):
|
|
||||||
|
def __init__(self, size):
|
||||||
super(MonthOvPanel, self).__init__(size)
|
super(MonthOvPanel, self).__init__(size)
|
||||||
self.weather_header_height = 0
|
self.weather_header_height = 0
|
||||||
if general_settings["weather-info"]:
|
if general_settings["weather-info"]:
|
||||||
self.weather_header_height = self.size[1] * weatherheadersize[1]
|
self.weather_header_height = self.size[1] * weatherheadersize[1]
|
||||||
self.__first_render__()
|
self.__first_render__()
|
||||||
|
|
||||||
def __first_render__ (self):
|
def __first_render__(self):
|
||||||
if week_starts_on == "Monday":
|
if week_starts_on == "Monday":
|
||||||
callib.setfirstweekday(callib.MONDAY)
|
callib.setfirstweekday(callib.MONDAY)
|
||||||
elif week_starts_on == "Sunday":
|
elif week_starts_on == "Sunday":
|
||||||
|
@ -52,119 +54,135 @@ class MonthOvPanel (PanelDesign):
|
||||||
if general_settings["weather-info"]:
|
if general_settings["weather-info"]:
|
||||||
self.__draw_seperator__()
|
self.__draw_seperator__()
|
||||||
|
|
||||||
self.month_block = MonthBlockDesign(self.__abs_pos__(monthovsize), datetime.now(), highlight_today = True)
|
self.month_block = MonthBlockDesign(self.__abs_pos__(
|
||||||
|
monthovsize), datetime.now(), highlight_today=True)
|
||||||
pos = self.__abs_pos__(monthovposition)
|
pos = self.__abs_pos__(monthovposition)
|
||||||
pos = (pos[0], pos[1] + self.weather_header_height)
|
pos = (pos[0], pos[1] + self.weather_header_height)
|
||||||
self.month_block.pos = pos
|
self.month_block.pos = pos
|
||||||
self.draw_design(self.month_block)
|
self.draw_design(self.month_block)
|
||||||
|
|
||||||
def add_weather (self, weather):
|
def add_weather(self, weather):
|
||||||
if general_settings["weather-info"] == False:
|
if general_settings["weather-info"] == False:
|
||||||
return
|
return
|
||||||
self.draw_design(WeatherHeaderDesign(self.__abs_pos__(weatherheadersize), weather))
|
self.draw_design(WeatherHeaderDesign(
|
||||||
|
self.__abs_pos__(weatherheadersize), weather))
|
||||||
|
|
||||||
def add_rssfeed (self, rss):
|
def add_rssfeed(self, rss):
|
||||||
if general_settings["info-area"] is "rss":
|
if general_settings["info-area"] is "rss":
|
||||||
self.__draw_rss_post_list_to_bottom__(rss)
|
self.__draw_rss_post_list_to_bottom__(rss)
|
||||||
|
|
||||||
def add_crypto (self, crypto):
|
def add_crypto(self, crypto):
|
||||||
if general_settings["info-area"] is "crypto":
|
if general_settings["info-area"] is "crypto":
|
||||||
self.__draw_crypto_post_list_to_bottom__(crypto)
|
self.__draw_crypto_post_list_to_bottom__(crypto)
|
||||||
|
|
||||||
def add_tasks (self, tasks):
|
def add_tasks(self, tasks):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_calendar (self, calendar):
|
def add_calendar(self, calendar):
|
||||||
if general_settings["highlight-event-days"]:
|
if general_settings["highlight-event-days"]:
|
||||||
month_events = list(set([ (event.begin_datetime.day, event.begin_datetime.month, event.begin_datetime.year) for event in calendar.get_month_events()]))
|
month_events = list(set([(event.begin_datetime.day, event.begin_datetime.month,
|
||||||
|
event.begin_datetime.year) for event in calendar.get_month_events()]))
|
||||||
for event in month_events:
|
for event in month_events:
|
||||||
self.__draw_highlight_event_day__(event)
|
self.__draw_highlight_event_day__(event)
|
||||||
|
|
||||||
if general_settings["info-area"] is "events":
|
if general_settings["info-area"] is "events":
|
||||||
self.__draw_event_list_to_bottom__(calendar)
|
self.__draw_event_list_to_bottom__(calendar)
|
||||||
|
|
||||||
def __draw_rss_post_list_to_bottom__ (self, rss):
|
def __draw_rss_post_list_to_bottom__(self, rss):
|
||||||
month_pos = self.__abs_pos__(monthovposition)
|
month_pos = self.__abs_pos__(monthovposition)
|
||||||
month_height = self.month_block.get_real_height()
|
month_height = self.month_block.get_real_height()
|
||||||
size = (self.size[0], self.size[1] - (month_pos[1] + month_height + self.weather_header_height))
|
size = (self.size[0], self.size[1] - (month_pos[1] +
|
||||||
|
month_height + self.weather_header_height))
|
||||||
info_list = RssPostListDesign(size, rss)
|
info_list = RssPostListDesign(size, rss)
|
||||||
info_list.pos = (int(month_pos[0]), month_pos[1] + month_height + self.weather_header_height)
|
info_list.pos = (
|
||||||
|
int(month_pos[0]), month_pos[1] + month_height + self.weather_header_height)
|
||||||
self.draw_design(info_list)
|
self.draw_design(info_list)
|
||||||
|
|
||||||
def __draw_crypto_post_list_to_bottom__ (self, crypto):
|
def __draw_crypto_post_list_to_bottom__(self, crypto):
|
||||||
month_pos = self.__abs_pos__(monthovposition)
|
month_pos = self.__abs_pos__(monthovposition)
|
||||||
month_height = self.month_block.get_real_height()
|
month_height = self.month_block.get_real_height()
|
||||||
size = (self.size[0], self.size[1] - (month_pos[1] + month_height + self.weather_header_height))
|
size = (self.size[0], self.size[1] - (month_pos[1] +
|
||||||
|
month_height + self.weather_header_height))
|
||||||
|
|
||||||
info_list = CryptoListDesign(size, crypto)
|
info_list = CryptoListDesign(size, crypto)
|
||||||
list_height = info_list.get_estimated_height()
|
list_height = info_list.get_estimated_height()
|
||||||
info_list.pos = (int(month_pos[0]), month_pos[1] + month_height + self.weather_header_height + (size[1] - list_height))
|
info_list.pos = (int(month_pos[0]), month_pos[1] + month_height +
|
||||||
|
self.weather_header_height + (size[1] - list_height))
|
||||||
self.draw_design(info_list)
|
self.draw_design(info_list)
|
||||||
|
|
||||||
def __draw_event_list_to_bottom__ (self, calendar):
|
def __draw_event_list_to_bottom__(self, calendar):
|
||||||
month_pos = self.__abs_pos__(monthovposition)
|
month_pos = self.__abs_pos__(monthovposition)
|
||||||
month_height = self.month_block.get_real_height()
|
month_height = self.month_block.get_real_height()
|
||||||
size = (self.size[0], self.size[1] - (month_pos[1] + month_height + self.weather_header_height))
|
size = (self.size[0], self.size[1] - (month_pos[1] +
|
||||||
|
month_height + self.weather_header_height))
|
||||||
|
|
||||||
events = calendar.get_upcoming_events()
|
events = calendar.get_upcoming_events()
|
||||||
info_list = EventListDesign(size, events)
|
info_list = EventListDesign(size, events)
|
||||||
info_list.pos = (int(month_pos[0]), int(month_pos[1] + month_height + self.weather_header_height))
|
info_list.pos = (int(month_pos[0]), int(
|
||||||
|
month_pos[1] + month_height + self.weather_header_height))
|
||||||
self.draw_design(info_list)
|
self.draw_design(info_list)
|
||||||
|
|
||||||
def __draw_highlight_event_day__ (self, date):
|
def __draw_highlight_event_day__(self, date):
|
||||||
first_month_week = datetime(date[2], date[1], 1).isocalendar()[1]
|
first_month_week = datetime(date[2], date[1], 1).isocalendar()[1]
|
||||||
cur_date = datetime(date[2], date[1], date[0])
|
cur_date = datetime(date[2], date[1], date[0])
|
||||||
|
|
||||||
side_length = int(eventcirclehorizontalsize * self.size[0])
|
side_length = int(eventcirclehorizontalsize * self.size[0])
|
||||||
circle_size = (side_length,side_length)
|
circle_size = (side_length, side_length)
|
||||||
pos = self.month_block.get_day_pos(cur_date.isocalendar()[1] - first_month_week, self.__get_day_of_week__(cur_date), rel_pos = self.month_block.pos)
|
pos = self.month_block.get_day_pos(cur_date.isocalendar(
|
||||||
place_size = (self.month_block.size[0] * daynumberboxsize[0], self.month_block.size[1] * daynumberboxsize[1])
|
)[1] - first_month_week, self.__get_day_of_week__(cur_date), rel_pos=self.month_block.pos)
|
||||||
pos = (int(pos[0] + (place_size[0] - circle_size[0]) / 2), int(pos[1] + (place_size[1] - circle_size[1]) / 2))
|
place_size = (self.month_block.size[0] * daynumberboxsize[0],
|
||||||
|
self.month_block.size[1] * daynumberboxsize[1])
|
||||||
|
pos = (int(pos[0] + (place_size[0] - circle_size[0]) / 2),
|
||||||
|
int(pos[1] + (place_size[1] - circle_size[1]) / 2))
|
||||||
self.__draw_highlight_circle__(circle_size, pos, 'red', width=2)
|
self.__draw_highlight_circle__(circle_size, pos, 'red', width=2)
|
||||||
|
|
||||||
def __abs_pos__ (self, pos, size = None):
|
def __abs_pos__(self, pos, size=None):
|
||||||
if size is None:
|
if size is None:
|
||||||
size = self.size
|
size = self.size
|
||||||
return (int(pos[0] * size[0]), int(pos[1] * size[1]))
|
return (int(pos[0] * size[0]), int(pos[1] * size[1]))
|
||||||
|
|
||||||
def __draw_seperator__ (self):
|
def __draw_seperator__(self):
|
||||||
"""Draw a line seperating the weather and Calendar section"""
|
"""Draw a line seperating the weather and Calendar section"""
|
||||||
ImageDraw.Draw(self.__image__).line([ self.__abs_pos__(seperatorplace), self.__abs_pos__((1, seperatorplace[1])) ], fill='red', width=5)
|
ImageDraw.Draw(self.__image__).line([self.__abs_pos__(
|
||||||
|
seperatorplace), self.__abs_pos__((1, seperatorplace[1]))], fill='red', width=5)
|
||||||
|
|
||||||
def __draw_month_name__ (self):
|
def __draw_month_name__(self):
|
||||||
"""Draw the icon with the current month's name"""
|
"""Draw the icon with the current month's name"""
|
||||||
month = datetime.now().strftime("%B")
|
month = datetime.now().strftime("%B")
|
||||||
txt = TextDesign(self.__abs_pos__(monthboxsize), fontsize=monthtextsize * self.size[1], text=month, verticalalignment="center", horizontalalignment="center")
|
txt = TextDesign(self.__abs_pos__(monthboxsize), fontsize=monthtextsize *
|
||||||
|
self.size[1], text=month, verticalalignment="center", horizontalalignment="center")
|
||||||
pos = self.__abs_pos__(monthplace)
|
pos = self.__abs_pos__(monthplace)
|
||||||
txt.pos = (pos[0], pos[1] + self.weather_header_height)
|
txt.pos = (pos[0], pos[1] + self.weather_header_height)
|
||||||
self.draw_design(txt)
|
self.draw_design(txt)
|
||||||
|
|
||||||
def __draw_week_row__ (self):
|
def __draw_week_row__(self):
|
||||||
for day_of_week, day in enumerate(self.__week_days__):
|
for day_of_week, day in enumerate(self.__week_days__):
|
||||||
txt = TextDesign(self.__abs_pos__(weekrownameboxsize), fontsize=weekdaytextsize * self.size[1], text=str(day), verticalalignment="center", horizontalalignment="center")
|
txt = TextDesign(self.__abs_pos__(weekrownameboxsize), fontsize=weekdaytextsize *
|
||||||
|
self.size[1], text=str(day), verticalalignment="center", horizontalalignment="center")
|
||||||
pos = self.__get_week_day_pos__(day_of_week)
|
pos = self.__get_week_day_pos__(day_of_week)
|
||||||
txt.pos = (pos[0], pos[1] + weekdaytextpadding * self.size[1])
|
txt.pos = (pos[0], pos[1] + weekdaytextpadding * self.size[1])
|
||||||
self.draw_design(txt)
|
self.draw_design(txt)
|
||||||
|
|
||||||
self.__draw_highlight_box__(self.__abs_pos__(weekrownameboxsize), self.__get_week_day_pos__(self.__get_day_of_week__(datetime.now())), width=1)
|
self.__draw_highlight_box__(self.__abs_pos__(weekrownameboxsize), self.__get_week_day_pos__(
|
||||||
|
self.__get_day_of_week__(datetime.now())), width=1)
|
||||||
|
|
||||||
def __get_week_day_pos__ (self, day_of_week):
|
def __get_week_day_pos__(self, day_of_week):
|
||||||
maxwidth, _ = self.__abs_pos__(monthovsize)
|
maxwidth, _ = self.__abs_pos__(monthovsize)
|
||||||
partialwidth = maxwidth / 7
|
partialwidth = maxwidth / 7
|
||||||
posx, posy = self.__abs_pos__(weekdayrowpos)
|
posx, posy = self.__abs_pos__(weekdayrowpos)
|
||||||
return (int(posx + day_of_week * partialwidth), int(posy + self.weather_header_height))
|
return (int(posx + day_of_week * partialwidth), int(posy + self.weather_header_height))
|
||||||
|
|
||||||
def __draw_highlight_box__ (self, size, pos, color = colors["fg"], width = 1):
|
def __draw_highlight_box__(self, size, pos, color=colors["fg"], width=1):
|
||||||
design = BoxDesign(size, outline=color, width = width)
|
design = BoxDesign(size, outline=color, width=width)
|
||||||
design.pos = pos
|
design.pos = pos
|
||||||
self.draw_design(design)
|
self.draw_design(design)
|
||||||
|
|
||||||
def __draw_highlight_circle__ (self, size, pos, color = colors["fg"], width = 1):
|
def __draw_highlight_circle__(self, size, pos, color=colors["fg"], width=1):
|
||||||
design = EllipseDesign(size, outline=color, width = width)
|
design = EllipseDesign(size, outline=color, width=width)
|
||||||
design.pos = pos
|
design.pos = pos
|
||||||
self.draw_design(design)
|
self.draw_design(design)
|
||||||
|
|
||||||
def __get_week_days_ordered__ (self):
|
def __get_week_days_ordered__(self):
|
||||||
cur_weekday = datetime.now().weekday()
|
cur_weekday = datetime.now().weekday()
|
||||||
correction = -cur_weekday
|
correction = -cur_weekday
|
||||||
if week_starts_on == "Sunday":
|
if week_starts_on == "Sunday":
|
||||||
|
@ -172,9 +190,10 @@ class MonthOvPanel (PanelDesign):
|
||||||
|
|
||||||
weekdays = []
|
weekdays = []
|
||||||
for i in range(7):
|
for i in range(7):
|
||||||
weekdays.append((datetime.now() + timedelta(days=(i + correction))).strftime("%a"))
|
weekdays.append(
|
||||||
|
(datetime.now() + timedelta(days=(i + correction))).strftime("%a"))
|
||||||
|
|
||||||
return weekdays
|
return weekdays
|
||||||
|
|
||||||
def __get_day_of_week__ (self, date):
|
def __get_day_of_week__(self, date):
|
||||||
return self.__week_days__.index(date.strftime("%a"))
|
return self.__week_days__.index(date.strftime("%a"))
|
||||||
|
|
|
@ -15,10 +15,12 @@ info_height = 0.25
|
||||||
info_padding = 5
|
info_padding = 5
|
||||||
seperator_width = line_thickness
|
seperator_width = line_thickness
|
||||||
|
|
||||||
|
|
||||||
class MonthViewPanel (PanelDesign):
|
class MonthViewPanel (PanelDesign):
|
||||||
"""Displays a grid of the day of the current month
|
"""Displays a grid of the day of the current month
|
||||||
with detailed event descriptions."""
|
with detailed event descriptions."""
|
||||||
def __init__(self, size, month = None, year = None):
|
|
||||||
|
def __init__(self, size, month=None, year=None):
|
||||||
super(MonthViewPanel, self).__init__(size)
|
super(MonthViewPanel, self).__init__(size)
|
||||||
self.day_table = []
|
self.day_table = []
|
||||||
self.month = month
|
self.month = month
|
||||||
|
@ -39,14 +41,14 @@ class MonthViewPanel (PanelDesign):
|
||||||
self.weather_height = weather_height
|
self.weather_height = weather_height
|
||||||
self.day_area_height = 1 - self.weather_height - self.info_height
|
self.day_area_height = 1 - self.weather_height - self.info_height
|
||||||
self.day_area_ypos = self.weather_height
|
self.day_area_ypos = self.weather_height
|
||||||
|
|
||||||
self.week_count = self.__get_week_count__()
|
self.week_count = self.__get_week_count__()
|
||||||
|
|
||||||
area_height = self.size[1] * self.day_area_height
|
area_height = self.size[1] * self.day_area_height
|
||||||
area_width = self.size[0]
|
area_width = self.size[0]
|
||||||
self.day_box_size = (area_width / 7, area_height / self.week_count)
|
self.day_box_size = (area_width / 7, area_height / self.week_count)
|
||||||
|
|
||||||
def add_weather (self, weather):
|
def add_weather(self, weather):
|
||||||
if general_settings["weather-info"] == False:
|
if general_settings["weather-info"] == False:
|
||||||
return
|
return
|
||||||
size = (self.size[0], self.size[1] * self.weather_height)
|
size = (self.size[0], self.size[1] * self.weather_height)
|
||||||
|
@ -55,7 +57,7 @@ class MonthViewPanel (PanelDesign):
|
||||||
self.draw_design(header)
|
self.draw_design(header)
|
||||||
self.__draw_seperator__(size[1], colors["hl"])
|
self.__draw_seperator__(size[1], colors["hl"])
|
||||||
|
|
||||||
def add_calendar (self, calendar):
|
def add_calendar(self, calendar):
|
||||||
self.__add_calendar_to_days__(calendar)
|
self.__add_calendar_to_days__(calendar)
|
||||||
|
|
||||||
def __add_calendar_to_days__(self, calendar):
|
def __add_calendar_to_days__(self, calendar):
|
||||||
|
@ -64,7 +66,7 @@ class MonthViewPanel (PanelDesign):
|
||||||
if day != None:
|
if day != None:
|
||||||
day.add_calendar(calendar)
|
day.add_calendar(calendar)
|
||||||
|
|
||||||
def add_rssfeed (self, rss):
|
def add_rssfeed(self, rss):
|
||||||
if general_settings["info-area"] != "rss":
|
if general_settings["info-area"] != "rss":
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -75,19 +77,20 @@ class MonthViewPanel (PanelDesign):
|
||||||
rss.pos = pos
|
rss.pos = pos
|
||||||
self.draw_design(rss)
|
self.draw_design(rss)
|
||||||
|
|
||||||
def add_tasks (self, tasks):
|
def add_tasks(self, tasks):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def add_crypto (self, crypto):
|
def add_crypto(self, crypto):
|
||||||
if general_settings["info-area"] == "crypto":
|
if general_settings["info-area"] == "crypto":
|
||||||
self.__draw_crypto__(crypto)
|
self.__draw_crypto__(crypto)
|
||||||
|
|
||||||
def __draw_crypto__(self, crypto):
|
def __draw_crypto__(self, crypto):
|
||||||
size = (self.size[0], self.size[1] * self.info_height)
|
size = (self.size[0], self.size[1] * self.info_height)
|
||||||
pos = (0, self.size[1] - size[1])
|
pos = (0, self.size[1] - size[1])
|
||||||
|
|
||||||
crypto = CryptoListDesign(size, crypto)
|
crypto = CryptoListDesign(size, crypto)
|
||||||
crypto.pos = (pos[0],pos[1] + (size[1] - crypto.get_estimated_height()))
|
crypto.pos = (pos[0], pos[1] + (size[1] -
|
||||||
|
crypto.get_estimated_height()))
|
||||||
self.draw_design(crypto)
|
self.draw_design(crypto)
|
||||||
|
|
||||||
def __finish_panel__(self):
|
def __finish_panel__(self):
|
||||||
|
@ -97,12 +100,13 @@ class MonthViewPanel (PanelDesign):
|
||||||
size = (self.size[0], self.size[1] * self.day_area_height)
|
size = (self.size[0], self.size[1] * self.day_area_height)
|
||||||
pos = (0, self.size[1] * self.day_area_ypos)
|
pos = (0, self.size[1] * self.day_area_ypos)
|
||||||
|
|
||||||
table = TableDesign(size, matrix = self.day_table)
|
table = TableDesign(size, matrix=self.day_table)
|
||||||
table.pos = pos
|
table.pos = pos
|
||||||
self.draw_design(table)
|
self.draw_design(table)
|
||||||
|
|
||||||
def __draw_seperator__ (self, height, color):
|
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)
|
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):
|
def __init_day_boxes__(self):
|
||||||
if week_starts_on == "Monday":
|
if week_starts_on == "Monday":
|
||||||
|
@ -120,9 +124,10 @@ class MonthViewPanel (PanelDesign):
|
||||||
if day == None or day == 0:
|
if day == None or day == 0:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
design = DayBoxDesign(self.day_box_size, date(self.year, self.month, int(day)))
|
design = DayBoxDesign(self.day_box_size, date(
|
||||||
|
self.year, self.month, int(day)))
|
||||||
|
|
||||||
return design
|
return design
|
||||||
|
|
||||||
def __get_week_count__(self):
|
def __get_week_count__(self):
|
||||||
return len(callib.monthcalendar(self.year, self.month))
|
return len(callib.monthcalendar(self.year, self.month))
|
||||||
|
|
|
@ -5,16 +5,19 @@ from datetime import datetime
|
||||||
from settings import units, language
|
from settings import units, language
|
||||||
from Translator import translate
|
from Translator import translate
|
||||||
|
|
||||||
|
|
||||||
class OwmForecasts (WeatherInterface):
|
class OwmForecasts (WeatherInterface):
|
||||||
"""Fetches weather through the Openweathermap-api."""
|
"""Fetches weather through the Openweathermap-api."""
|
||||||
def __init__ (self, location, api_key, paid_api=False):
|
|
||||||
|
def __init__(self, location, api_key, paid_api=False):
|
||||||
self.subscription = "pro" if paid_api else None
|
self.subscription = "pro" if paid_api else None
|
||||||
self.api_key = api_key
|
self.api_key = api_key
|
||||||
self.units = units
|
self.units = units
|
||||||
self.location = location
|
self.location = location
|
||||||
self.api = pyowm.OWM(self.api_key, subscription_type=self.subscription, language=language)
|
self.api = pyowm.OWM(
|
||||||
|
self.api_key, subscription_type=self.subscription, language=language)
|
||||||
|
|
||||||
def is_available (self):
|
def is_available(self):
|
||||||
try:
|
try:
|
||||||
return self.api.is_API_online()
|
return self.api.is_API_online()
|
||||||
except:
|
except:
|
||||||
|
@ -23,7 +26,7 @@ class OwmForecasts (WeatherInterface):
|
||||||
def reload(self):
|
def reload(self):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_today_forecast (self, location=None):
|
def get_today_forecast(self, location=None):
|
||||||
if self.is_available() is False:
|
if self.is_available() is False:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@ -37,7 +40,7 @@ class OwmForecasts (WeatherInterface):
|
||||||
except:
|
except:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def get_forecast_in_days (self, offset_by_days, location=None):
|
def get_forecast_in_days(self, offset_by_days, location=None):
|
||||||
if offset_by_days is 0:
|
if offset_by_days is 0:
|
||||||
return self.get_today_forecast(location)
|
return self.get_today_forecast(location)
|
||||||
|
|
||||||
|
@ -50,38 +53,49 @@ class OwmForecasts (WeatherInterface):
|
||||||
target_weather = forecast.get_forecast().get_weathers()[-1]
|
target_weather = forecast.get_forecast().get_weathers()[-1]
|
||||||
|
|
||||||
return self.__get_forecast_from_weather__(target_weather, location=location)
|
return self.__get_forecast_from_weather__(target_weather, location=location)
|
||||||
except: # only allowed for paid membership
|
except: # only allowed for paid membership
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def __get_forecast_from_weather__ (self, weather, location):
|
def __get_forecast_from_weather__(self, weather, location):
|
||||||
forecast_object = WeatherForecast()
|
forecast_object = WeatherForecast()
|
||||||
forecast_object.units = self.units
|
forecast_object.units = self.units
|
||||||
forecast_object.fetch_datetime = datetime.now()
|
forecast_object.fetch_datetime = datetime.now()
|
||||||
forecast_object.location = location
|
forecast_object.location = location
|
||||||
forecast_object.datetime = weather.get_reference_time(timeformat='date')
|
forecast_object.datetime = weather.get_reference_time(
|
||||||
|
timeformat='date')
|
||||||
|
|
||||||
forecast_object.icon = weather.get_weather_icon_name()
|
forecast_object.icon = weather.get_weather_icon_name()
|
||||||
forecast_object.air_humidity = str(weather.get_humidity())
|
forecast_object.air_humidity = str(weather.get_humidity())
|
||||||
forecast_object.clouds = str(weather.get_clouds())
|
forecast_object.clouds = str(weather.get_clouds())
|
||||||
forecast_object.short_description = translate(str(weather.get_status()))
|
forecast_object.short_description = translate(
|
||||||
forecast_object.detailed_description = str(weather.get_detailed_status())
|
str(weather.get_status()))
|
||||||
|
forecast_object.detailed_description = str(
|
||||||
|
weather.get_detailed_status())
|
||||||
forecast_object.air_pressure = str(weather.get_pressure()['press'])
|
forecast_object.air_pressure = str(weather.get_pressure()['press'])
|
||||||
if 'deg' in weather.get_wind().keys():
|
if 'deg' in weather.get_wind().keys():
|
||||||
forecast_object.wind_deg = str(int(weather.get_wind()['deg']))
|
forecast_object.wind_deg = str(int(weather.get_wind()['deg']))
|
||||||
|
|
||||||
if forecast_object.units == "metric":
|
if forecast_object.units == "metric":
|
||||||
forecast_object.air_temperature = str(int(weather.get_temperature(unit='celsius')['temp']))
|
forecast_object.air_temperature = str(
|
||||||
forecast_object.wind_speed = str(int(weather.get_wind()['speed'])) #kmh
|
int(weather.get_temperature(unit='celsius')['temp']))
|
||||||
|
forecast_object.wind_speed = str(
|
||||||
|
int(weather.get_wind()['speed'])) # kmh
|
||||||
|
|
||||||
if forecast_object.units == "aviation":
|
if forecast_object.units == "aviation":
|
||||||
forecast_object.air_temperature = str(int(weather.get_temperature(unit='celsius')['temp']))
|
forecast_object.air_temperature = str(
|
||||||
forecast_object.wind_speed = str(int(weather.get_wind()['speed'] * 1.94384)) #knots
|
int(weather.get_temperature(unit='celsius')['temp']))
|
||||||
|
forecast_object.wind_speed = str(
|
||||||
|
int(weather.get_wind()['speed'] * 1.94384)) # knots
|
||||||
|
|
||||||
if forecast_object.units == "imperial":
|
if forecast_object.units == "imperial":
|
||||||
forecast_object.air_temperature = str(int(weather.get_temperature('fahrenheit')['temp']))
|
forecast_object.air_temperature = str(
|
||||||
forecast_object.wind_speed = str(int(weather.get_wind()['speed'] * 0.621)) #mph
|
int(weather.get_temperature('fahrenheit')['temp']))
|
||||||
|
forecast_object.wind_speed = str(
|
||||||
|
int(weather.get_wind()['speed'] * 0.621)) # mph
|
||||||
|
|
||||||
forecast_object.sunrise = datetime.fromtimestamp(int(weather.get_sunrise_time(timeformat='unix')))
|
forecast_object.sunrise = datetime.fromtimestamp(
|
||||||
forecast_object.sunset = datetime.fromtimestamp(int(weather.get_sunset_time(timeformat='unix')))
|
int(weather.get_sunrise_time(timeformat='unix')))
|
||||||
|
forecast_object.sunset = datetime.fromtimestamp(
|
||||||
|
int(weather.get_sunset_time(timeformat='unix')))
|
||||||
|
|
||||||
return forecast_object
|
return forecast_object
|
||||||
|
|
|
@ -3,25 +3,27 @@ from TechnicalDataDesign import TechnicalDataDesign
|
||||||
from settings import print_technical_data
|
from settings import print_technical_data
|
||||||
from datetime import datetime
|
from datetime import datetime
|
||||||
|
|
||||||
|
|
||||||
class PanelDesign (DesignEntity):
|
class PanelDesign (DesignEntity):
|
||||||
"""Defined general interface for panel designs."""
|
"""Defined general interface for panel designs."""
|
||||||
def __init__ (self, size):
|
|
||||||
|
def __init__(self, size):
|
||||||
super(PanelDesign, self).__init__(size)
|
super(PanelDesign, self).__init__(size)
|
||||||
self.start_timestamp = datetime.now()
|
self.start_timestamp = datetime.now()
|
||||||
|
|
||||||
def add_weather (self, weather):
|
def add_weather(self, weather):
|
||||||
raise NotImplementedError("Function needs to be implemented")
|
raise NotImplementedError("Function needs to be implemented")
|
||||||
|
|
||||||
def add_calendar (self, calendar):
|
def add_calendar(self, calendar):
|
||||||
raise NotImplementedError("Function needs to be implemented")
|
raise NotImplementedError("Function needs to be implemented")
|
||||||
|
|
||||||
def add_rssfeed (self, rss):
|
def add_rssfeed(self, rss):
|
||||||
raise NotImplementedError("Function needs to be implemented")
|
raise NotImplementedError("Function needs to be implemented")
|
||||||
|
|
||||||
def add_tasks (self, tasks):
|
def add_tasks(self, tasks):
|
||||||
raise NotImplementedError("Function needs to be implemented")
|
raise NotImplementedError("Function needs to be implemented")
|
||||||
|
|
||||||
def add_crypto (self, crypto):
|
def add_crypto(self, crypto):
|
||||||
raise NotImplementedError("Function needs to be implemented")
|
raise NotImplementedError("Function needs to be implemented")
|
||||||
|
|
||||||
def __finish_panel__(self):
|
def __finish_panel__(self):
|
||||||
|
@ -31,6 +33,7 @@ class PanelDesign (DesignEntity):
|
||||||
self.__finish_panel__()
|
self.__finish_panel__()
|
||||||
|
|
||||||
if print_technical_data:
|
if print_technical_data:
|
||||||
td = TechnicalDataDesign(self.size, self.start_timestamp, datetime.now())
|
td = TechnicalDataDesign(
|
||||||
|
self.size, self.start_timestamp, datetime.now())
|
||||||
td.mask = True
|
td.mask = True
|
||||||
self.draw_design(td)
|
self.draw_design(td)
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
from DataSourceInterface import DataSourceInterface
|
from DataSourceInterface import DataSourceInterface
|
||||||
from datetime import datetime, timezone, timedelta
|
from datetime import datetime, timezone, timedelta
|
||||||
|
|
||||||
|
|
||||||
class RssInterface(DataSourceInterface):
|
class RssInterface(DataSourceInterface):
|
||||||
"""Interface for fetching and processing rss post information."""
|
"""Interface for fetching and processing rss post information."""
|
||||||
|
|
||||||
def __init__(self):
|
def __init__(self):
|
||||||
self.loaded_posts = []
|
self.loaded_posts = []
|
||||||
|
|
||||||
|
@ -22,7 +24,7 @@ class RssInterface(DataSourceInterface):
|
||||||
return self.get_day_posts(datetime.now())
|
return self.get_day_posts(datetime.now())
|
||||||
|
|
||||||
def get_day_posts(self, day):
|
def get_day_posts(self, day):
|
||||||
return self.__get_posts_to_filter__(lambda x : x.datetime.strftime('%d-%m-%y') == day.strftime('%d-%m-%y'))
|
return self.__get_posts_to_filter__(lambda x: x.datetime.strftime('%d-%m-%y') == day.strftime('%d-%m-%y'))
|
||||||
|
|
||||||
def __get_posts_to_filter__(self, post_filter):
|
def __get_posts_to_filter__(self, post_filter):
|
||||||
if self.loaded_posts is None:
|
if self.loaded_posts is None:
|
||||||
|
@ -30,4 +32,4 @@ class RssInterface(DataSourceInterface):
|
||||||
return [post for post in self.loaded_posts if post_filter(post)]
|
return [post for post in self.loaded_posts if post_filter(post)]
|
||||||
|
|
||||||
def __sort_posts__(self):
|
def __sort_posts__(self):
|
||||||
self.loaded_posts.sort(key=lambda x : x.datetime, reverse=True)
|
self.loaded_posts.sort(key=lambda x: x.datetime, reverse=True)
|
||||||
|
|
|
@ -6,8 +6,10 @@ from urllib.request import urlopen
|
||||||
|
|
||||||
max_range_days = 14
|
max_range_days = 14
|
||||||
|
|
||||||
|
|
||||||
class RssParserPosts (RssInterface):
|
class RssParserPosts (RssInterface):
|
||||||
"""Fetches posts from url-addresses via rss parser."""
|
"""Fetches posts from url-addresses via rss parser."""
|
||||||
|
|
||||||
def __init__(self, urls):
|
def __init__(self, urls):
|
||||||
self.urls = urls
|
self.urls = urls
|
||||||
super(RssParserPosts, self).__init__()
|
super(RssParserPosts, self).__init__()
|
||||||
|
@ -52,5 +54,4 @@ class RssParserPosts (RssInterface):
|
||||||
def __get_webpage__(self, link):
|
def __get_webpage__(self, link):
|
||||||
start_index = link.find('://') + 3
|
start_index = link.find('://') + 3
|
||||||
end_index = link[start_index:].find('/') + start_index
|
end_index = link[start_index:].find('/') + start_index
|
||||||
return link[start_index : end_index]
|
return link[start_index: end_index]
|
||||||
|
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
class RssPost(object):
|
class RssPost(object):
|
||||||
"""Defines a rss post, independent of any implementation"""
|
"""Defines a rss post, independent of any implementation"""
|
||||||
def __init__ (self):
|
|
||||||
|
def __init__(self):
|
||||||
self.title = None
|
self.title = None
|
||||||
self.description = None
|
self.description = None
|
||||||
self.source = None
|
self.source = None
|
||||||
|
|
||||||
self.datetime = None
|
self.datetime = None
|
||||||
self.fetch_datetime = None
|
self.fetch_datetime = None
|
||||||
|
|
|
@ -2,32 +2,35 @@ from DesignEntity import DesignEntity
|
||||||
from TableDesign import TableDesign
|
from TableDesign import TableDesign
|
||||||
from Assets import defaultfontsize
|
from Assets import defaultfontsize
|
||||||
|
|
||||||
|
|
||||||
class RssPostListDesign (DesignEntity):
|
class RssPostListDesign (DesignEntity):
|
||||||
"""Creates a TableDesign filled with rss post
|
"""Creates a TableDesign filled with rss post
|
||||||
date and title"""
|
date and title"""
|
||||||
def __init__ (self, size, rssfeed, text_size = defaultfontsize):
|
|
||||||
|
def __init__(self, size, rssfeed, text_size=defaultfontsize):
|
||||||
super(RssPostListDesign, self).__init__(size)
|
super(RssPostListDesign, self).__init__(size)
|
||||||
self.rssfeed = rssfeed
|
self.rssfeed = rssfeed
|
||||||
self.__post_matrix__ = []
|
self.__post_matrix__ = []
|
||||||
self.text_size = text_size
|
self.text_size = text_size
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
self.__fill_post_matrix__()
|
self.__fill_post_matrix__()
|
||||||
|
|
||||||
table_design = TableDesign(self.size, line_spacing=2, col_spacing=3, matrix=self.__post_matrix__, fontsize = self.text_size, mask=False, wrap=True, truncate_rows=True)
|
table_design = TableDesign(self.size, line_spacing=2, col_spacing=3, matrix=self.__post_matrix__,
|
||||||
|
fontsize=self.text_size, mask=False, wrap=True, truncate_rows=True)
|
||||||
self.draw_design(table_design)
|
self.draw_design(table_design)
|
||||||
|
|
||||||
def __get_formatted_post__ (self, post):
|
def __get_formatted_post__(self, post):
|
||||||
date = post.datetime.strftime('%d %b')
|
date = post.datetime.strftime('%d %b')
|
||||||
date = self.__remove_leading_zero__(date)
|
date = self.__remove_leading_zero__(date)
|
||||||
return [ '', '•', post.title ]
|
return ['', '•', post.title]
|
||||||
|
|
||||||
def __remove_leading_zero__(self, text):
|
def __remove_leading_zero__(self, text):
|
||||||
while text[0] is '0':
|
while text[0] is '0':
|
||||||
text = text[1:]
|
text = text[1:]
|
||||||
return text
|
return text
|
||||||
|
|
||||||
def __fill_post_matrix__ (self):
|
def __fill_post_matrix__(self):
|
||||||
for post in self.rssfeed.get_latest_posts():
|
for post in self.rssfeed.get_latest_posts():
|
||||||
row = self.__get_formatted_post__(post)
|
row = self.__get_formatted_post__(post)
|
||||||
self.__post_matrix__.append(row)
|
self.__post_matrix__.append(row)
|
||||||
|
|
|
@ -5,8 +5,11 @@ from TextFormatter import event_prefix_str_sum
|
||||||
|
|
||||||
font = fonts["regular"]
|
font = fonts["regular"]
|
||||||
|
|
||||||
|
|
||||||
class SingelDayEventListDesign (EventListDesign):
|
class SingelDayEventListDesign (EventListDesign):
|
||||||
"""Specialized event list for day list design."""
|
"""Specialized event list for day list design."""
|
||||||
def __init__ (self, size, events, font_size = defaultfontsize, line_spacing=0, event_prefix_rel_dates = [], col_spacing=5, general_color=colors["fg"], background_color=colors["bg"], highlight_color=colors["hl"]):
|
|
||||||
prefix_func = lambda x, rel_date : event_prefix_str_sum(x, rel_date)
|
def __init__(self, size, events, font_size=defaultfontsize, line_spacing=0, event_prefix_rel_dates=[], col_spacing=5, general_color=colors["fg"], background_color=colors["bg"], highlight_color=colors["hl"]):
|
||||||
super().__init__(size, events, text_size=font_size, line_spacing=line_spacing, col_spacing=col_spacing, event_prefix_rel_dates = event_prefix_rel_dates, event_prefix_func=prefix_func, font_family=font, show_more_info=True, general_color=general_color, background_color=background_color, highlight_color = highlight_color)
|
def prefix_func(x, rel_date): return event_prefix_str_sum(x, rel_date)
|
||||||
|
super().__init__(size, events, text_size=font_size, line_spacing=line_spacing, col_spacing=col_spacing, event_prefix_rel_dates=event_prefix_rel_dates,
|
||||||
|
event_prefix_func=prefix_func, font_family=font, show_more_info=True, general_color=general_color, background_color=background_color, highlight_color=highlight_color)
|
||||||
|
|
|
@ -5,16 +5,19 @@ from DesignEntity import DesignEntity
|
||||||
|
|
||||||
|
|
||||||
default_props = {
|
default_props = {
|
||||||
"color" : colors["fg"],
|
"color": colors["fg"],
|
||||||
"background_color" : colors["bg"],
|
"background_color": colors["bg"],
|
||||||
"font-size" : defaultfontsize
|
"font-size": defaultfontsize
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class TableDesign (TextDesign):
|
class TableDesign (TextDesign):
|
||||||
"""Gets a matrix with text or designs that is than
|
"""Gets a matrix with text or designs that is than
|
||||||
displayed in a table without borders."""
|
displayed in a table without borders."""
|
||||||
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)
|
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.__init_image__(background_color)
|
||||||
self.matrix = matrix
|
self.matrix = matrix
|
||||||
self.max_col_size = max_col_size
|
self.max_col_size = max_col_size
|
||||||
|
@ -32,7 +35,7 @@ class TableDesign (TextDesign):
|
||||||
self.cell_properties = cell_properties
|
self.cell_properties = cell_properties
|
||||||
default_props["font-size"] = fontsize
|
default_props["font-size"] = fontsize
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
if len(self.matrix) is 0:
|
if len(self.matrix) is 0:
|
||||||
return
|
return
|
||||||
self.__reform_col_size__()
|
self.__reform_col_size__()
|
||||||
|
@ -41,19 +44,19 @@ class TableDesign (TextDesign):
|
||||||
self.max_col, self.max_row = self.__get_truncated_counts__()
|
self.max_col, self.max_row = self.__get_truncated_counts__()
|
||||||
self.__print_table__(self.matrix)
|
self.__print_table__(self.matrix)
|
||||||
|
|
||||||
def __reform_col_size__ (self):
|
def __reform_col_size__(self):
|
||||||
if self.max_col_size is not None:
|
if self.max_col_size is not None:
|
||||||
return
|
return
|
||||||
|
|
||||||
col_sizes = []
|
col_sizes = []
|
||||||
for c in range(len(self.matrix[0])): #amout of columns
|
for c in range(len(self.matrix[0])): # amout of columns
|
||||||
for r in range(len(self.matrix)):
|
for r in range(len(self.matrix)):
|
||||||
row_col_size = self.__get_cell_size__(r,c)[0]
|
row_col_size = self.__get_cell_size__(r, c)[0]
|
||||||
if len(col_sizes) - 1 < c:
|
if len(col_sizes) - 1 < c:
|
||||||
col_sizes.append(row_col_size)
|
col_sizes.append(row_col_size)
|
||||||
elif row_col_size > col_sizes[c]:
|
elif row_col_size > col_sizes[c]:
|
||||||
col_sizes[c] = row_col_size
|
col_sizes[c] = row_col_size
|
||||||
|
|
||||||
for index, size in enumerate(col_sizes):
|
for index, size in enumerate(col_sizes):
|
||||||
preceding_size = sum(col_sizes[:index]) + index * self.col_spacing
|
preceding_size = sum(col_sizes[:index]) + index * self.col_spacing
|
||||||
if preceding_size + size > self.size[0]:
|
if preceding_size + size > self.size[0]:
|
||||||
|
@ -62,19 +65,19 @@ class TableDesign (TextDesign):
|
||||||
|
|
||||||
self.max_col_size = col_sizes
|
self.max_col_size = col_sizes
|
||||||
|
|
||||||
def __reform_row_size__ (self):
|
def __reform_row_size__(self):
|
||||||
if self.max_row_size is not None:
|
if self.max_row_size is not None:
|
||||||
return
|
return
|
||||||
|
|
||||||
row_sizes = []
|
row_sizes = []
|
||||||
for r in range(len(self.matrix)):
|
for r in range(len(self.matrix)):
|
||||||
for c in range(len(self.matrix[0])): #amout of columns
|
for c in range(len(self.matrix[0])): # amout of columns
|
||||||
col_row_size = self.__get_cell_size__(r,c)[1]
|
col_row_size = self.__get_cell_size__(r, c)[1]
|
||||||
if len(row_sizes) - 1 < r:
|
if len(row_sizes) - 1 < r:
|
||||||
row_sizes.append(col_row_size)
|
row_sizes.append(col_row_size)
|
||||||
elif col_row_size > row_sizes[r]:
|
elif col_row_size > row_sizes[r]:
|
||||||
row_sizes[r] = col_row_size
|
row_sizes[r] = col_row_size
|
||||||
|
|
||||||
self.max_row_size = row_sizes
|
self.max_row_size = row_sizes
|
||||||
|
|
||||||
def __get_cell_size__(self, r, c):
|
def __get_cell_size__(self, r, c):
|
||||||
|
@ -85,18 +88,20 @@ class TableDesign (TextDesign):
|
||||||
return size
|
return size
|
||||||
elif type(content) == str:
|
elif type(content) == str:
|
||||||
font = self.__get_font__()
|
font = self.__get_font__()
|
||||||
width = font.getsize(self.matrix[r][c])[0] #get width of text in that row/col
|
# get width of text in that row/col
|
||||||
|
width = font.getsize(self.matrix[r][c])[0]
|
||||||
if self.wrap and self.max_col_size != None:
|
if self.wrap and self.max_col_size != None:
|
||||||
content = wrap_text_with_font(content, self.max_col_size[c], font)
|
content = wrap_text_with_font(
|
||||||
|
content, self.max_col_size[c], font)
|
||||||
line_count = content.count('\n') + 1
|
line_count = content.count('\n') + 1
|
||||||
height = font.font.height * line_count #get height of text in that col/row
|
height = font.font.height * line_count # get height of text in that col/row
|
||||||
size = (width, height)
|
size = (width, height)
|
||||||
else: #DesignEntity
|
else: # DesignEntity
|
||||||
size = content.size
|
size = content.size
|
||||||
|
|
||||||
return size
|
return size
|
||||||
|
|
||||||
def __get_truncated_counts__ (self):
|
def __get_truncated_counts__(self):
|
||||||
max_col = 0
|
max_col = 0
|
||||||
if self.truncate_cols:
|
if self.truncate_cols:
|
||||||
while max_col < len(self.matrix[0]) and self.__get_cell_pos__(0, max_col + 1)[0] - self.col_spacing <= self.size[0]:
|
while max_col < len(self.matrix[0]) and self.__get_cell_pos__(0, max_col + 1)[0] - self.col_spacing <= self.size[0]:
|
||||||
|
@ -106,44 +111,45 @@ class TableDesign (TextDesign):
|
||||||
|
|
||||||
max_row = 0
|
max_row = 0
|
||||||
if self.truncate_rows:
|
if self.truncate_rows:
|
||||||
while max_row < len(self.matrix) and self.__get_cell_pos__(max_row + 1,0)[1] - self.line_spacing <= self.size[1]:
|
while max_row < len(self.matrix) and self.__get_cell_pos__(max_row + 1, 0)[1] - self.line_spacing <= self.size[1]:
|
||||||
max_row += 1
|
max_row += 1
|
||||||
else:
|
else:
|
||||||
max_row = len(self.matrix)
|
max_row = len(self.matrix)
|
||||||
|
|
||||||
return (max_col, max_row)
|
return (max_col, max_row)
|
||||||
|
|
||||||
def __print_table__ (self, matrix):
|
def __print_table__(self, matrix):
|
||||||
for r in range(self.max_row):
|
for r in range(self.max_row):
|
||||||
for c in range(self.max_col):
|
for c in range(self.max_col):
|
||||||
self.__draw_cell__(r,c)
|
self.__draw_cell__(r, c)
|
||||||
|
|
||||||
def __draw_text__ (self, pos, size, row, col):
|
def __draw_text__(self, pos, size, row, col):
|
||||||
color = self.__get_cell_prop__(row, col, "color")
|
color = self.__get_cell_prop__(row, col, "color")
|
||||||
bg_color = self.__get_cell_prop__(row, col, "background_color")
|
bg_color = self.__get_cell_prop__(row, col, "background_color")
|
||||||
fontsize = self.__get_cell_prop__(row, col, "font-size")
|
fontsize = self.__get_cell_prop__(row, col, "font-size")
|
||||||
|
|
||||||
design = TextDesign(size, text=self.matrix[row][col], font=self.font_family, color=color, background_color=bg_color, fontsize=fontsize, horizontalalignment=self.__get_col_hori_alignment__(col), wrap=self.wrap, truncate=self.truncate_text, truncate_suffix=self.truncate_suffix)
|
design = TextDesign(size, text=self.matrix[row][col], font=self.font_family, color=color, background_color=bg_color, fontsize=fontsize,
|
||||||
|
horizontalalignment=self.__get_col_hori_alignment__(col), wrap=self.wrap, truncate=self.truncate_text, truncate_suffix=self.truncate_suffix)
|
||||||
design.pos = pos
|
design.pos = pos
|
||||||
design.mask = False
|
design.mask = False
|
||||||
self.draw_design(design)
|
self.draw_design(design)
|
||||||
|
|
||||||
def __draw_design__ (self, pos, size, row, col):
|
def __draw_design__(self, pos, size, row, col):
|
||||||
bg_color = self.__get_cell_prop__(row, col, "background_color")
|
bg_color = self.__get_cell_prop__(row, col, "background_color")
|
||||||
|
|
||||||
source_design = self.matrix[row][col]
|
source_design = self.matrix[row][col]
|
||||||
source_design.mask = False
|
source_design.mask = False
|
||||||
|
|
||||||
framed_design = DesignEntity(size, mask = False)
|
framed_design = DesignEntity(size, mask=False)
|
||||||
framed_design.__init_image__(color=bg_color)
|
framed_design.__init_image__(color=bg_color)
|
||||||
framed_design.draw_design(source_design)
|
framed_design.draw_design(source_design)
|
||||||
|
|
||||||
framed_design.pos = pos
|
framed_design.pos = pos
|
||||||
self.draw_design(framed_design)
|
self.draw_design(framed_design)
|
||||||
|
|
||||||
def __draw_cell__ (self, row, col):
|
def __draw_cell__(self, row, col):
|
||||||
size = self.cell_sizes[row][col]
|
size = self.cell_sizes[row][col]
|
||||||
pos = self.__get_cell_pos__(row,col)
|
pos = self.__get_cell_pos__(row, col)
|
||||||
|
|
||||||
if self.matrix[row][col] == None:
|
if self.matrix[row][col] == None:
|
||||||
return
|
return
|
||||||
|
@ -151,8 +157,8 @@ class TableDesign (TextDesign):
|
||||||
self.__draw_text__(pos, size, row, col)
|
self.__draw_text__(pos, size, row, col)
|
||||||
else:
|
else:
|
||||||
self.__draw_design__(pos, size, row, col)
|
self.__draw_design__(pos, size, row, col)
|
||||||
|
|
||||||
def __get_cell_pos__ (self, row, col):
|
def __get_cell_pos__(self, row, col):
|
||||||
xpos, ypos = (0, 0)
|
xpos, ypos = (0, 0)
|
||||||
for c in range(col):
|
for c in range(col):
|
||||||
xpos += self.cell_sizes[row][c][0]
|
xpos += self.cell_sizes[row][c][0]
|
||||||
|
@ -162,7 +168,7 @@ class TableDesign (TextDesign):
|
||||||
ypos += self.line_spacing
|
ypos += self.line_spacing
|
||||||
return (xpos, ypos)
|
return (xpos, ypos)
|
||||||
|
|
||||||
def __get_cell_sizes__ (self):
|
def __get_cell_sizes__(self):
|
||||||
size_matrix = []
|
size_matrix = []
|
||||||
for r in range(len(self.matrix)):
|
for r in range(len(self.matrix)):
|
||||||
size_matrix.append([])
|
size_matrix.append([])
|
||||||
|
@ -171,7 +177,7 @@ class TableDesign (TextDesign):
|
||||||
size_matrix[r].append(size)
|
size_matrix[r].append(size)
|
||||||
return size_matrix
|
return size_matrix
|
||||||
|
|
||||||
def __get_col_hori_alignment__ (self, c):
|
def __get_col_hori_alignment__(self, c):
|
||||||
if len(self.column_horizontal_alignments) <= c:
|
if len(self.column_horizontal_alignments) <= c:
|
||||||
return "left"
|
return "left"
|
||||||
return self.column_horizontal_alignments[c]
|
return self.column_horizontal_alignments[c]
|
||||||
|
@ -179,8 +185,8 @@ class TableDesign (TextDesign):
|
||||||
def __get_cell_prop__(self, r, c, prop):
|
def __get_cell_prop__(self, r, c, prop):
|
||||||
if self.cell_properties is None:
|
if self.cell_properties is None:
|
||||||
return default_props[prop]
|
return default_props[prop]
|
||||||
|
|
||||||
if r < len(self.cell_properties) and c < len(self.cell_properties[r]) and prop in self.cell_properties[r][c].keys():
|
if r < len(self.cell_properties) and c < len(self.cell_properties[r]) and prop in self.cell_properties[r][c].keys():
|
||||||
return self.cell_properties[r][c][prop]
|
return self.cell_properties[r][c][prop]
|
||||||
else:
|
else:
|
||||||
return default_props[prop]
|
return default_props[prop]
|
||||||
|
|
|
@ -4,10 +4,12 @@ from Assets import colors
|
||||||
|
|
||||||
font_size = 20
|
font_size = 20
|
||||||
|
|
||||||
|
|
||||||
class TechnicalDataDesign(DesignEntity):
|
class TechnicalDataDesign(DesignEntity):
|
||||||
'''Prints data about the current loop ontop of the panel'''
|
'''Prints data about the current loop ontop of the panel'''
|
||||||
|
|
||||||
def __init__(self, size, start, stop):
|
def __init__(self, size, start, stop):
|
||||||
super(TechnicalDataDesign, self).__init__(size, mask = True)
|
super(TechnicalDataDesign, self).__init__(size, mask=True)
|
||||||
self.start = start
|
self.start = start
|
||||||
self.stop = stop
|
self.stop = stop
|
||||||
|
|
||||||
|
@ -37,4 +39,4 @@ class TechnicalDataDesign(DesignEntity):
|
||||||
data += str(dur)
|
data += str(dur)
|
||||||
data += "\nSTOP: "
|
data += "\nSTOP: "
|
||||||
data += str(self.stop)
|
data += str(self.stop)
|
||||||
return data
|
return data
|
||||||
|
|
|
@ -5,11 +5,13 @@ from TextWraper import wrap_text_with_font
|
||||||
|
|
||||||
truncateerror_fontsize = 0.5
|
truncateerror_fontsize = 0.5
|
||||||
|
|
||||||
|
|
||||||
class TextDesign (DesignEntity):
|
class TextDesign (DesignEntity):
|
||||||
"""Object that manages all information relevant to text
|
"""Object that manages all information relevant to text
|
||||||
and prints it to an image"""
|
and prints it to an image"""
|
||||||
def __init__ (self, size, color=colors["fg"], background_color=colors["bg"], font = None, fontsize = defaultfontsize, text = "", horizontalalignment = "left", verticalalignment = "top", mask=True, truncate=False, truncate_suffix = '...', wrap=False):
|
|
||||||
super(TextDesign, self).__init__(size, mask = mask)
|
def __init__(self, size, color=colors["fg"], background_color=colors["bg"], font=None, fontsize=defaultfontsize, text="", horizontalalignment="left", verticalalignment="top", mask=True, truncate=False, truncate_suffix='...', wrap=False):
|
||||||
|
super(TextDesign, self).__init__(size, mask=mask)
|
||||||
if font is None:
|
if font is None:
|
||||||
font = defaultfont
|
font = defaultfont
|
||||||
self.font_family = font
|
self.font_family = font
|
||||||
|
@ -23,7 +25,7 @@ class TextDesign (DesignEntity):
|
||||||
self.color = color
|
self.color = color
|
||||||
self.background_color = background_color
|
self.background_color = background_color
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
if self.color is "white":
|
if self.color is "white":
|
||||||
self.invert_mask = True
|
self.invert_mask = True
|
||||||
if self.background_color not in ["white", "black"] or self.color in ["red"]:
|
if self.background_color not in ["white", "black"] or self.color in ["red"]:
|
||||||
|
@ -36,21 +38,24 @@ class TextDesign (DesignEntity):
|
||||||
if self.wrap:
|
if self.wrap:
|
||||||
self.__wrap_text__()
|
self.__wrap_text__()
|
||||||
pos = self.__pos_from_alignment__()
|
pos = self.__pos_from_alignment__()
|
||||||
ImageDraw.Draw(self.__image__).text(pos, self.text, fill=self.color, font=self.__font__)
|
ImageDraw.Draw(self.__image__).text(
|
||||||
|
pos, self.text, fill=self.color, font=self.__font__)
|
||||||
def __truncate_text__ (self):
|
|
||||||
if self.__font__.getsize_multiline(self.text)[0] <= self.size[0]: #does not need truncating
|
def __truncate_text__(self):
|
||||||
|
# does not need truncating
|
||||||
|
if self.__font__.getsize_multiline(self.text)[0] <= self.size[0]:
|
||||||
return
|
return
|
||||||
suffix_length = self.__font__.getsize_multiline(self.truncate_suffix)[0]
|
suffix_length = self.__font__.getsize_multiline(
|
||||||
|
self.truncate_suffix)[0]
|
||||||
while len(self.text) > 1 and self.__font__.getsize_multiline(self.text)[0] + suffix_length >= self.size[0]:
|
while len(self.text) > 1 and self.__font__.getsize_multiline(self.text)[0] + suffix_length >= self.size[0]:
|
||||||
self.text = self.text[0:-1]
|
self.text = self.text[0:-1]
|
||||||
self.text = self.text.rstrip(' ')
|
self.text = self.text.rstrip(' ')
|
||||||
self.text += self.truncate_suffix
|
self.text += self.truncate_suffix
|
||||||
|
|
||||||
def __pos_from_alignment__ (self):
|
def __pos_from_alignment__(self):
|
||||||
width, height = self.__get_text_size__()
|
width, height = self.__get_text_size__()
|
||||||
x, y = 0, 0
|
x, y = 0, 0
|
||||||
|
|
||||||
if self.vertical_alignment == "center":
|
if self.vertical_alignment == "center":
|
||||||
y = int((self.size[1] / 2) - (height / 2))
|
y = int((self.size[1] / 2) - (height / 2))
|
||||||
elif self.vertical_alignment == "bottom":
|
elif self.vertical_alignment == "bottom":
|
||||||
|
@ -68,8 +73,8 @@ class TextDesign (DesignEntity):
|
||||||
height = (self.text.count('\n') + 1) * self.__font__.font.height
|
height = (self.text.count('\n') + 1) * self.__font__.font.height
|
||||||
return widht, height
|
return widht, height
|
||||||
|
|
||||||
def __wrap_text__ (self):
|
def __wrap_text__(self):
|
||||||
self.text = wrap_text_with_font(self.text, self.size[0], self.__font__)
|
self.text = wrap_text_with_font(self.text, self.size[0], self.__font__)
|
||||||
|
|
||||||
def __get_font__(self):
|
def __get_font__(self):
|
||||||
return ImageFont.truetype(path + self.font_family, int(self.font_size))
|
return ImageFont.truetype(path + self.font_family, int(self.font_size))
|
||||||
|
|
|
@ -12,7 +12,8 @@ until_character = ' - '
|
||||||
allday_character = "•"
|
allday_character = "•"
|
||||||
multiday_character = allday_character + allday_character
|
multiday_character = allday_character + allday_character
|
||||||
|
|
||||||
def time_str (dt):
|
|
||||||
|
def time_str(dt):
|
||||||
if hours is "12":
|
if hours is "12":
|
||||||
return dt.strftime("%I:%M%p")
|
return dt.strftime("%I:%M%p")
|
||||||
elif hours is "24":
|
elif hours is "24":
|
||||||
|
@ -20,29 +21,31 @@ def time_str (dt):
|
||||||
else:
|
else:
|
||||||
return str(dt)
|
return str(dt)
|
||||||
|
|
||||||
def event_prefix_str_md_dif (event, relative_date=None):
|
|
||||||
|
def event_prefix_str_md_dif(event, relative_date=None):
|
||||||
if relative_date is None:
|
if relative_date is None:
|
||||||
relative_date = event.begin_datetime.date()
|
relative_date = event.begin_datetime.date()
|
||||||
|
|
||||||
if event.multiday is False:
|
if event.multiday is False:
|
||||||
return event_time_summary(event)
|
return event_time_summary(event)
|
||||||
|
|
||||||
#Relative to
|
# Relative to
|
||||||
#First day
|
# First day
|
||||||
elif __equal__(event.begin_datetime, relative_date):
|
elif __equal__(event.begin_datetime, relative_date):
|
||||||
return event_time_summary(event) + multiday_begin_character
|
return event_time_summary(event) + multiday_begin_character
|
||||||
|
|
||||||
#Last day
|
# Last day
|
||||||
elif __equal__(event.end_datetime, relative_date) or \
|
elif __equal__(event.end_datetime, relative_date) or \
|
||||||
(__day_duration__(event.end_datetime) == timedelta(0) and __equal__(relative_date + timedelta(1), event.end_datetime)):
|
(__day_duration__(event.end_datetime) == timedelta(0) and __equal__(relative_date + timedelta(1), event.end_datetime)):
|
||||||
return multiday_end_character + event_time_summary(event)
|
return multiday_end_character + event_time_summary(event)
|
||||||
|
|
||||||
#Some day
|
# Some day
|
||||||
else:
|
else:
|
||||||
event.allday = True
|
event.allday = True
|
||||||
return multiday_end_character + event_time_summary(event) + multiday_begin_character
|
return multiday_end_character + event_time_summary(event) + multiday_begin_character
|
||||||
|
|
||||||
def event_prefix_str (event, relative_date=None):
|
|
||||||
|
def event_prefix_str(event, relative_date=None):
|
||||||
if relative_date is None:
|
if relative_date is None:
|
||||||
relative_date = event.begin_datetime.date()
|
relative_date = event.begin_datetime.date()
|
||||||
|
|
||||||
|
@ -51,7 +54,8 @@ def event_prefix_str (event, relative_date=None):
|
||||||
else:
|
else:
|
||||||
return event_time_detailed(event)
|
return event_time_detailed(event)
|
||||||
|
|
||||||
def event_prefix_str_sum (event, relative_date=None):
|
|
||||||
|
def event_prefix_str_sum(event, relative_date=None):
|
||||||
if relative_date is None:
|
if relative_date is None:
|
||||||
relative_date = event.begin_datetime.date()
|
relative_date = event.begin_datetime.date()
|
||||||
|
|
||||||
|
@ -60,25 +64,30 @@ def event_prefix_str_sum (event, relative_date=None):
|
||||||
else:
|
else:
|
||||||
return event_time_summary(event)
|
return event_time_summary(event)
|
||||||
|
|
||||||
def event_time_summary (event):
|
|
||||||
|
def event_time_summary(event):
|
||||||
if event.allday:
|
if event.allday:
|
||||||
return allday_character
|
return allday_character
|
||||||
else:
|
else:
|
||||||
return time_str(event.begin_datetime)
|
return time_str(event.begin_datetime)
|
||||||
|
|
||||||
def event_time_detailed (event):
|
|
||||||
|
def event_time_detailed(event):
|
||||||
if event.allday:
|
if event.allday:
|
||||||
return get_text(allday_events)
|
return get_text(allday_events)
|
||||||
else:
|
else:
|
||||||
return time_str(event.begin_datetime) + until_character + time_str(event.end_datetime)
|
return time_str(event.begin_datetime) + until_character + time_str(event.end_datetime)
|
||||||
|
|
||||||
|
|
||||||
def date_str(dt):
|
def date_str(dt):
|
||||||
return remove_leading_zero(dt.strftime('%d. %b'))
|
return remove_leading_zero(dt.strftime('%d. %b'))
|
||||||
|
|
||||||
def remove_leading_zero (text):
|
|
||||||
while text[0] is '0':
|
def remove_leading_zero(text):
|
||||||
text = text[1:]
|
while text[0] is '0':
|
||||||
return text
|
text = text[1:]
|
||||||
|
return text
|
||||||
|
|
||||||
|
|
||||||
def date_summary_str(dt):
|
def date_summary_str(dt):
|
||||||
day = remove_leading_zero(dt.strftime("%d"))
|
day = remove_leading_zero(dt.strftime("%d"))
|
||||||
|
@ -89,11 +98,13 @@ def date_summary_str(dt):
|
||||||
else:
|
else:
|
||||||
return dt.strftime('%a ' + day + '. %b')
|
return dt.strftime('%a ' + day + '. %b')
|
||||||
|
|
||||||
|
|
||||||
def __equal__(dt1, dt2):
|
def __equal__(dt1, dt2):
|
||||||
return dt1.day == dt2.day and \
|
return dt1.day == dt2.day and \
|
||||||
dt1.month == dt2.month and \
|
dt1.month == dt2.month and \
|
||||||
dt1.year == dt2.year
|
dt1.year == dt2.year
|
||||||
|
|
||||||
|
|
||||||
def __day_duration__(dt):
|
def __day_duration__(dt):
|
||||||
day_begin = datetime(dt.year, dt.month, dt.day, 0, 0, 0, 0, timezone.utc)
|
day_begin = datetime(dt.year, dt.month, dt.day, 0, 0, 0, 0, timezone.utc)
|
||||||
return dt - day_begin
|
return dt - day_begin
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
from Assets import path, defaultfont
|
from Assets import path, defaultfont
|
||||||
from PIL import ImageFont
|
from PIL import ImageFont
|
||||||
|
|
||||||
def wrap_text_with_font (text, width, font):
|
|
||||||
|
def wrap_text_with_font(text, width, font):
|
||||||
words = text.split(' ')
|
words = text.split(' ')
|
||||||
result = ""
|
result = ""
|
||||||
for index, word in enumerate(words):
|
for word in words:
|
||||||
until_current = (result + " " + word).strip()
|
until_current = (result + " " + word).strip()
|
||||||
txt_width, _ = font.getsize_multiline(until_current)
|
txt_width, _ = font.getsize_multiline(until_current)
|
||||||
if txt_width > width:
|
if txt_width > width:
|
||||||
|
@ -14,5 +15,6 @@ def wrap_text_with_font (text, width, font):
|
||||||
result += word
|
result += word
|
||||||
return result.strip()
|
return result.strip()
|
||||||
|
|
||||||
def wrap_text (text, width, font_size, font_family = defaultfont):
|
|
||||||
return wrap_text_with_font(text, width, ImageFont.truetype(path + font_family, int(font_size)))
|
def wrap_text(text, width, font_size, font_family=defaultfont):
|
||||||
|
return wrap_text_with_font(text, width, ImageFont.truetype(path + font_family, int(font_size)))
|
||||||
|
|
|
@ -4,7 +4,8 @@ from settings import language
|
||||||
'''Looks up a phrase in a given dictionary-collection
|
'''Looks up a phrase in a given dictionary-collection
|
||||||
and returns the translated phrase'''
|
and returns the translated phrase'''
|
||||||
|
|
||||||
def translate(phrase, target_lang = language, dictionary_collection = dictionary_collection) :
|
|
||||||
|
def translate(phrase, target_lang=language, dictionary_collection=dictionary_collection):
|
||||||
dictionary = find_dictionary(phrase, dictionary_collection)
|
dictionary = find_dictionary(phrase, dictionary_collection)
|
||||||
|
|
||||||
if dictionary == None:
|
if dictionary == None:
|
||||||
|
@ -17,8 +18,9 @@ def translate(phrase, target_lang = language, dictionary_collection = dictionary
|
||||||
else:
|
else:
|
||||||
return dictionary[default_language]
|
return dictionary[default_language]
|
||||||
|
|
||||||
def find_dictionary(phrase, dictionary_collection = dictionary_collection):
|
|
||||||
|
def find_dictionary(phrase, dictionary_collection=dictionary_collection):
|
||||||
for dictionary in dictionary_collection:
|
for dictionary in dictionary_collection:
|
||||||
if phrase in dictionary.values():
|
if phrase in dictionary.values():
|
||||||
return dictionary
|
return dictionary
|
||||||
return None
|
return None
|
||||||
|
|
|
@ -13,13 +13,15 @@ info_yresize = -0.05
|
||||||
fontsize_static = defaultfontsize
|
fontsize_static = defaultfontsize
|
||||||
max_symbol_y_width = 0.15
|
max_symbol_y_width = 0.15
|
||||||
|
|
||||||
|
|
||||||
class WeatherColumnDesign (DesignEntity):
|
class WeatherColumnDesign (DesignEntity):
|
||||||
"""Displays weather information in a column"""
|
"""Displays weather information in a column"""
|
||||||
def __init__ (self, size, forecast):
|
|
||||||
|
def __init__(self, size, forecast):
|
||||||
super().__init__(size)
|
super().__init__(size)
|
||||||
self.forecast = forecast
|
self.forecast = forecast
|
||||||
|
|
||||||
def __finish_image__ (self):
|
def __finish_image__(self):
|
||||||
if self.forecast is None:
|
if self.forecast is None:
|
||||||
self.__draw_no_response__()
|
self.__draw_no_response__()
|
||||||
return
|
return
|
||||||
|
@ -27,47 +29,56 @@ class WeatherColumnDesign (DesignEntity):
|
||||||
self.__draw_icon__(self.forecast.icon)
|
self.__draw_icon__(self.forecast.icon)
|
||||||
self.__draw_infos__(self.forecast)
|
self.__draw_infos__(self.forecast)
|
||||||
|
|
||||||
def __draw_infos__ (self, forecast):
|
def __draw_infos__(self, forecast):
|
||||||
temperature = forecast.air_temperature + " " + self.__get_unit__(("°C", "°F"))
|
temperature = forecast.air_temperature + \
|
||||||
|
" " + self.__get_unit__(("°C", "°F"))
|
||||||
humidity = forecast.air_humidity + "%"
|
humidity = forecast.air_humidity + "%"
|
||||||
if forecast.units== "aviation":
|
if forecast.units == "aviation":
|
||||||
if forecast.wind_deg == None:
|
if forecast.wind_deg == None:
|
||||||
forecast.wind_deg = ""
|
forecast.wind_deg = ""
|
||||||
elif len(forecast.wind_deg)==1:
|
elif len(forecast.wind_deg) == 1:
|
||||||
forecast.wind_deg = "00" + forecast.wind_deg
|
forecast.wind_deg = "00" + forecast.wind_deg
|
||||||
elif len(forecast.wind_deg)==2:
|
elif len(forecast.wind_deg) == 2:
|
||||||
forecast.wind_deg = "0" + forecast.wind_deg
|
forecast.wind_deg = "0" + forecast.wind_deg
|
||||||
if int(forecast.wind_speed)<10:
|
if int(forecast.wind_speed) < 10:
|
||||||
windspeed = forecast.wind_deg + "@" + "0" + forecast.wind_speed + self.__get_unit__(("", "")) #added degrees, if wind<10 add a 0 to make two digit
|
windspeed = forecast.wind_deg + "@" + "0" + forecast.wind_speed + \
|
||||||
|
self.__get_unit__(
|
||||||
|
("", "")) # added degrees, if wind<10 add a 0 to make two digit
|
||||||
else:
|
else:
|
||||||
windspeed = forecast.wind_deg + "@" + forecast.wind_speed + self.__get_unit__(("", "")) #added degrees
|
windspeed = forecast.wind_deg + "@" + forecast.wind_speed + \
|
||||||
|
self.__get_unit__(("", "")) # added degrees
|
||||||
else:
|
else:
|
||||||
windspeed = forecast.wind_speed + " " + self.__get_unit__(("km/h", "mph"))
|
windspeed = forecast.wind_speed + " " + \
|
||||||
|
self.__get_unit__(("km/h", "mph"))
|
||||||
|
|
||||||
numbers_list = [ [ forecast.short_description ],
|
numbers_list = [[forecast.short_description],
|
||||||
[ temperature ],
|
[temperature],
|
||||||
[ humidity ],
|
[humidity],
|
||||||
[ windspeed ] ]
|
[windspeed]]
|
||||||
|
|
||||||
ypos = info_x_ypos * self.size[0]
|
ypos = info_x_ypos * self.size[0]
|
||||||
pos = (0, ypos)
|
pos = (0, ypos)
|
||||||
size = (self.size[0], self.size[1] + info_yresize * self.size[1] - pos[1])
|
size = (self.size[0], self.size[1] +
|
||||||
line_spacing = (size[1] - len(numbers_list) * fontsize_static) / (len(numbers_list) + 1)
|
info_yresize * self.size[1] - pos[1])
|
||||||
|
line_spacing = (size[1] - len(numbers_list) *
|
||||||
|
fontsize_static) / (len(numbers_list) + 1)
|
||||||
|
|
||||||
table = TableDesign(size, numbers_list, fontsize=fontsize_static, line_spacing=line_spacing, column_horizontal_alignments=[ "center" ], max_col_size=[ size[0] ], truncate_text=False, truncate_rows=False)
|
table = TableDesign(size, numbers_list, fontsize=fontsize_static, line_spacing=line_spacing, column_horizontal_alignments=[
|
||||||
|
"center"], max_col_size=[size[0]], truncate_text=False, truncate_rows=False)
|
||||||
table.pos = pos
|
table.pos = pos
|
||||||
self.draw_design(table)
|
self.draw_design(table)
|
||||||
|
|
||||||
def __draw_icon__ (self, icon_id):
|
def __draw_icon__(self, icon_id):
|
||||||
width = int(icon_width * self.size[0])
|
width = int(icon_width * self.size[0])
|
||||||
size = (width, width)
|
size = (width, width)
|
||||||
xpos = icon_xpos * self.size[0]
|
xpos = icon_xpos * self.size[0]
|
||||||
ypos = icon_x_ypos * self.size[0]
|
ypos = icon_x_ypos * self.size[0]
|
||||||
pos = (xpos, ypos)
|
pos = (xpos, ypos)
|
||||||
|
|
||||||
self.__draw_resized_path_at__(wpath + weathericons[icon_id] + ".jpeg", pos, size)
|
self.__draw_resized_path_at__(
|
||||||
|
wpath + weathericons[icon_id] + ".jpeg", pos, size)
|
||||||
|
|
||||||
def __draw_no_response__ (self):
|
def __draw_no_response__(self):
|
||||||
width = int(icon_width * self.size[0])
|
width = int(icon_width * self.size[0])
|
||||||
size = (width, width)
|
size = (width, width)
|
||||||
xpos = icon_xpos * self.size[0]
|
xpos = icon_xpos * self.size[0]
|
||||||
|
@ -76,26 +87,25 @@ class WeatherColumnDesign (DesignEntity):
|
||||||
|
|
||||||
self.__draw_resized_image_at__(no_response, pos, size)
|
self.__draw_resized_image_at__(no_response, pos, size)
|
||||||
|
|
||||||
def __draw_resized_path_at__ (self, path, pos, size):
|
def __draw_resized_path_at__(self, path, pos, size):
|
||||||
img = Image.open(path)
|
img = Image.open(path)
|
||||||
self.__draw_resized_image_at__(img, pos, size)
|
self.__draw_resized_image_at__(img, pos, size)
|
||||||
|
|
||||||
def __draw_resized_image_at__ (self, img, pos, size):
|
def __draw_resized_image_at__(self, img, pos, size):
|
||||||
size = (int(size[0]), int(size[1]))
|
size = (int(size[0]), int(size[1]))
|
||||||
resized_img = img.resize(size, resample=Image.LANCZOS)
|
resized_img = img.resize(size, resample=Image.LANCZOS)
|
||||||
self.draw(resized_img, pos)
|
self.draw(resized_img, pos)
|
||||||
|
|
||||||
|
def __get_unit__(self, tuple):
|
||||||
def __get_unit__ (self, tuple):
|
|
||||||
if self.forecast.units == "metric" or self.forecast.units == "aviation":
|
if self.forecast.units == "metric" or self.forecast.units == "aviation":
|
||||||
return tuple[0]
|
return tuple[0]
|
||||||
else:
|
else:
|
||||||
return tuple[1]
|
return tuple[1]
|
||||||
|
|
||||||
def __abs_co__ (self, coordinates):
|
def __abs_co__(self, coordinates):
|
||||||
return (coordinates[0] * self.size[0], coordinates[1] * self.size[1])
|
return (coordinates[0] * self.size[0], coordinates[1] * self.size[1])
|
||||||
|
|
||||||
def __get_time__ (self, time):
|
def __get_time__(self, time):
|
||||||
if hours == "24":
|
if hours == "24":
|
||||||
return time.strftime('%H:%M')
|
return time.strftime('%H:%M')
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
class WeatherForecast (object):
|
class WeatherForecast (object):
|
||||||
"""Defines a weather forecast, independent of any implementation"""
|
"""Defines a weather forecast, independent of any implementation"""
|
||||||
def __init__ (self):
|
|
||||||
|
def __init__(self):
|
||||||
self.air_temperature = None
|
self.air_temperature = None
|
||||||
self.air_pressure = None
|
self.air_pressure = None
|
||||||
self.air_humidity = None
|
self.air_humidity = None
|
||||||
|
@ -21,4 +22,4 @@ class WeatherForecast (object):
|
||||||
self.units = None
|
self.units = None
|
||||||
self.datetime = None
|
self.datetime = None
|
||||||
self.location = None
|
self.location = None
|
||||||
self.fetch_datetime = None
|
self.fetch_datetime = None
|
||||||
|
|
|
@ -10,14 +10,16 @@ windiconspace = (0.206, 0)
|
||||||
sunriseplace = (0.55, 0)
|
sunriseplace = (0.55, 0)
|
||||||
sunsetplace = (0.55, 0.486)
|
sunsetplace = (0.55, 0.486)
|
||||||
|
|
||||||
|
|
||||||
class WeatherHeaderDesign (DesignEntity):
|
class WeatherHeaderDesign (DesignEntity):
|
||||||
"""Defines a top area that displays basic weather information"""
|
"""Defines a top area that displays basic weather information"""
|
||||||
def __init__ (self, size, weather):
|
|
||||||
|
def __init__(self, size, weather):
|
||||||
super(WeatherHeaderDesign, self).__init__(size)
|
super(WeatherHeaderDesign, self).__init__(size)
|
||||||
self.__weather__ = weather
|
self.__weather__ = weather
|
||||||
self.__first_render__()
|
self.__first_render__()
|
||||||
|
|
||||||
def __first_render__ (self):
|
def __first_render__(self):
|
||||||
if self.__weather__.is_available() is False:
|
if self.__weather__.is_available() is False:
|
||||||
self.__render_missing_connection__()
|
self.__render_missing_connection__()
|
||||||
return
|
return
|
||||||
|
@ -28,53 +30,65 @@ class WeatherHeaderDesign (DesignEntity):
|
||||||
self.__render_missing_connection__()
|
self.__render_missing_connection__()
|
||||||
return
|
return
|
||||||
|
|
||||||
temperature = cur_weather.air_temperature + " " + self.__get_unit__(("°C", "°F"))
|
temperature = cur_weather.air_temperature + \
|
||||||
if units== "aviation": #pick up aviation
|
" " + self.__get_unit__(("°C", "°F"))
|
||||||
|
if units == "aviation": # pick up aviation
|
||||||
if cur_weather.wind_deg == None:
|
if cur_weather.wind_deg == None:
|
||||||
cur_weather.wind_deg = ""
|
cur_weather.wind_deg = ""
|
||||||
elif len(cur_weather.wind_deg)==1: #if deg is 2, add two zeros for format
|
elif len(cur_weather.wind_deg) == 1: # if deg is 2, add two zeros for format
|
||||||
cur_weather.wind_deg = "00" + cur_weather.wind_deg
|
cur_weather.wind_deg = "00" + cur_weather.wind_deg
|
||||||
elif len(cur_weather.wind_deg)==2:
|
elif len(cur_weather.wind_deg) == 2:
|
||||||
cur_weather.wind_deg = "0" + cur_weather.wind_deg
|
cur_weather.wind_deg = "0" + cur_weather.wind_deg
|
||||||
if int(cur_weather.wind_speed)<10:
|
if int(cur_weather.wind_speed) < 10:
|
||||||
windspeed = cur_weather.wind_deg + "@" + "0" + cur_weather.wind_speed + self.__get_unit__(("", "")) #added degrees, if wind<10 add a 0 to make two digit
|
windspeed = cur_weather.wind_deg + "@" + "0" + cur_weather.wind_speed + \
|
||||||
|
self.__get_unit__(
|
||||||
|
("", "")) # added degrees, if wind<10 add a 0 to make two digit
|
||||||
else:
|
else:
|
||||||
windspeed = cur_weather.wind_deg + "@" + cur_weather.wind_speed + self.__get_unit__(("", "")) #added degrees
|
windspeed = cur_weather.wind_deg + "@" + cur_weather.wind_speed + \
|
||||||
|
self.__get_unit__(("", "")) # added degrees
|
||||||
else:
|
else:
|
||||||
windspeed = cur_weather.wind_speed + " " + self.__get_unit__(("km/h", "mph"))
|
windspeed = cur_weather.wind_speed + " " + \
|
||||||
|
self.__get_unit__(("km/h", "mph"))
|
||||||
|
|
||||||
self.__draw_text__(temperature, self.__abs_pos__((0.87, 0)), (50,35))
|
self.__draw_text__(temperature, self.__abs_pos__((0.87, 0)), (50, 35))
|
||||||
self.__draw_text__(windspeed, self.__abs_pos__((0.297, 0.05)), (100,35))
|
self.__draw_text__(windspeed, self.__abs_pos__(
|
||||||
self.__draw_text__(self.__get_time__(cur_weather.sunrise), self.__abs_pos__((0.64,0)), (50,35))
|
(0.297, 0.05)), (100, 35))
|
||||||
self.__draw_text__(self.__get_time__(cur_weather.sunset), self.__abs_pos__((0.64,0.486)), (50,35))
|
self.__draw_text__(self.__get_time__(cur_weather.sunrise),
|
||||||
self.__draw_text__(cur_weather.air_humidity + " %", self.__abs_pos__((0.87,0.486)), (50,35))
|
self.__abs_pos__((0.64, 0)), (50, 35))
|
||||||
self.__draw_text__(cur_weather.short_description, self.__abs_pos__((0.182,0.486)), (144,35))
|
self.__draw_text__(self.__get_time__(cur_weather.sunset),
|
||||||
|
self.__abs_pos__((0.64, 0.486)), (50, 35))
|
||||||
|
self.__draw_text__(cur_weather.air_humidity + " %",
|
||||||
|
self.__abs_pos__((0.87, 0.486)), (50, 35))
|
||||||
|
self.__draw_text__(cur_weather.short_description,
|
||||||
|
self.__abs_pos__((0.182, 0.486)), (144, 35))
|
||||||
|
|
||||||
self.draw(windicon, self.__abs_pos__(windiconspace))
|
self.draw(windicon, self.__abs_pos__(windiconspace))
|
||||||
self.draw(sunseticon, self.__abs_pos__(sunsetplace))
|
self.draw(sunseticon, self.__abs_pos__(sunsetplace))
|
||||||
self.draw(sunriseicon, self.__abs_pos__(sunriseplace))
|
self.draw(sunriseicon, self.__abs_pos__(sunriseplace))
|
||||||
self.draw(humicon, self.__abs_pos__(humplace))
|
self.draw(humicon, self.__abs_pos__(humplace))
|
||||||
self.draw(tempicon, self.__abs_pos__(tempplace))
|
self.draw(tempicon, self.__abs_pos__(tempplace))
|
||||||
self.draw_image(wpath + weathericons[cur_weather.icon] + '.jpeg', self.__abs_pos__(wiconplace))
|
self.draw_image(
|
||||||
|
wpath + weathericons[cur_weather.icon] + '.jpeg', self.__abs_pos__(wiconplace))
|
||||||
|
|
||||||
def __render_missing_connection__ (self):
|
def __render_missing_connection__(self):
|
||||||
self.draw(no_response, self.__abs_pos__(wiconplace))
|
self.draw(no_response, self.__abs_pos__(wiconplace))
|
||||||
|
|
||||||
def __abs_pos__ (self, pos):
|
def __abs_pos__(self, pos):
|
||||||
return (int(pos[0] * self.size[0]), int(pos[1] * self.size[1]))
|
return (int(pos[0] * self.size[0]), int(pos[1] * self.size[1]))
|
||||||
|
|
||||||
def __draw_text__ (self, text, pos, size):
|
def __draw_text__(self, text, pos, size):
|
||||||
txt = TextDesign(size, fontsize=18, text=text, verticalalignment="center", horizontalalignment="center")
|
txt = TextDesign(size, fontsize=18, text=text,
|
||||||
|
verticalalignment="center", horizontalalignment="center")
|
||||||
txt.pos = pos
|
txt.pos = pos
|
||||||
self.draw_design(txt)
|
self.draw_design(txt)
|
||||||
|
|
||||||
def __get_unit__ (self, tuple):
|
def __get_unit__(self, tuple):
|
||||||
if units == "metric" or units == "aviation":
|
if units == "metric" or units == "aviation":
|
||||||
return tuple[0]
|
return tuple[0]
|
||||||
else:
|
else:
|
||||||
return tuple[1]
|
return tuple[1]
|
||||||
|
|
||||||
def __get_time__ (self, time):
|
def __get_time__(self, time):
|
||||||
if hours == "24":
|
if hours == "24":
|
||||||
return time.strftime('%H:%M')
|
return time.strftime('%H:%M')
|
||||||
else:
|
else:
|
||||||
|
|
|
@ -1,9 +1,11 @@
|
||||||
from DataSourceInterface import DataSourceInterface
|
from DataSourceInterface import DataSourceInterface
|
||||||
|
|
||||||
|
|
||||||
class WeatherInterface (DataSourceInterface):
|
class WeatherInterface (DataSourceInterface):
|
||||||
"""Interface for fetching and processing weather forecast information."""
|
"""Interface for fetching and processing weather forecast information."""
|
||||||
def get_forecast_in_days (self, offset_by_days, location=None):
|
|
||||||
|
def get_forecast_in_days(self, offset_by_days, location=None):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
||||||
def get_today_forecast (self, location=None):
|
def get_today_forecast(self, location=None):
|
||||||
raise NotImplementedError("Functions needs to be implemented")
|
raise NotImplementedError("Functions needs to be implemented")
|
||||||
|
|
Loading…
Reference in a new issue