mirror of
https://github.com/oDinZu/callirhoe.git
synced 2025-02-22 00:04:52 -05:00
full code documentation with epydoc
git-svn-id: https://callirhoe.googlecode.com/svn/branches/next@47 81c8bb96-aa45-f2e2-0eef-c4fa4a15c6df
This commit is contained in:
parent
e31fa29316
commit
d7ec93602d
@ -16,7 +16,10 @@
|
||||
|
||||
# --- geom.default ---
|
||||
|
||||
"""module defining the default geometry"""
|
||||
|
||||
class dom:
|
||||
"""day of month geometry"""
|
||||
size = (0.5,0.5,0.8,0.5) # short 0-1, long 2-3
|
||||
mw_split = (0.7,0.2)
|
||||
|
||||
@ -27,6 +30,7 @@ class dom:
|
||||
hf_vsplit = (0.5,0.4)
|
||||
|
||||
class month:
|
||||
"""month geometry"""
|
||||
symmetric = False
|
||||
sloppy_rot = 0
|
||||
sloppy_dx = 0
|
||||
|
@ -16,6 +16,8 @@
|
||||
|
||||
# --- geom.sloppy ---
|
||||
|
||||
"""module defining the sloppy geometry"""
|
||||
|
||||
import default
|
||||
|
||||
class dom(default.dom): pass
|
||||
|
@ -30,4 +30,4 @@ ce|39||Ascension|off
|
||||
ce|50||Whit Monday|off
|
||||
|
||||
d|20130223-20130310|winter vacations (B)||multi
|
||||
f|20140222-20140309|winter vacations (B)||multi
|
||||
d|20140222-20140309|winter vacations (B)||multi
|
||||
|
@ -3,7 +3,7 @@
|
||||
# callirhoe - high quality calendar rendering
|
||||
# Copyright (C) 2012 George M. Tzoumas
|
||||
|
||||
# German language data
|
||||
""" German language definition file"""
|
||||
# Copyright (C) 2013 Neels Hofmeyr
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
|
@ -16,6 +16,8 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/
|
||||
|
||||
"""Greek language definition file"""
|
||||
|
||||
long_day_name = [ u'Δευτέρα', u'Τρίτη', u'Τετάρτη',
|
||||
u'Πέμπτη', u'Παρασκευή', u'Σάββατο', u'Κυριακή' ]
|
||||
|
||||
|
@ -16,8 +16,10 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/
|
||||
|
||||
"""English language definition file"""
|
||||
|
||||
long_day_name = [ u'Monday', u'Tuesday', u'Wednesday',
|
||||
u'Thursday', u'Friday', u'Saturday', u'Sunday' ]
|
||||
u'Thursday', u'Friday', u'Saturday', u'Sunday' ]
|
||||
|
||||
short_day_name = [ u'Mo', u'Tu', u'We', u'Th', u'Fr', u'Sa', u'Su' ]
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/
|
||||
|
||||
"""French language definition file"""
|
||||
|
||||
long_day_name = [ u'Lundi', u'Mardi', u'Mercredi',
|
||||
u'Jeudi', u'Vendredi', u'Samedi', u'Dimanche' ]
|
||||
|
||||
|
@ -3,7 +3,7 @@
|
||||
# callirhoe - high quality calendar rendering
|
||||
# Copyright (C) 2012 George M. Tzoumas
|
||||
|
||||
# Turkish language data
|
||||
""" Turkish language definition file"""
|
||||
# Copyright (C) 2013 Ece Neslihan Aybeke
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
@ -24,7 +24,7 @@ long_day_name = [ u'Pazartesi', u'Salı', u' Çarşamba ',
|
||||
|
||||
short_day_name = [ u'Pt', u'Sa', u'Ça', u'Pe', u'Cu', u'Ct', u'Pa' ]
|
||||
|
||||
long_month_name = [ '', u'Ocak', 'Şubat', u'Mart', u'Nisan',
|
||||
long_month_name = [ '', u'Ocak', u'Şubat', u'Mart', u'Nisan',
|
||||
u'Mayıs', u'Haziran', u'Temmuz', u'Ağustos',
|
||||
u'Eylül', u'Ekim', u'Kasım', u'Aralık' ]
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/
|
||||
|
||||
# --- layouts._base ---
|
||||
"""base layout module -- others may inherit from this one"""
|
||||
|
||||
import optparse
|
||||
from lib.xcairo import *
|
||||
@ -23,6 +23,10 @@ from lib.geom import *
|
||||
from math import floor, ceil, sqrt
|
||||
|
||||
def get_parser(layout_name):
|
||||
"""get the parser object for the layout command-line arguments
|
||||
|
||||
@param layout_name: corresponding python module (.py file)
|
||||
"""
|
||||
lname = layout_name.split(".")[1]
|
||||
parser = optparse.OptionParser(usage="%prog (...) --layout " + lname + " [options] (...)",add_help_option=False)
|
||||
parser.add_option("--rows", type="int", default=0, help="force grid rows [%default]")
|
||||
@ -67,6 +71,16 @@ def get_parser(layout_name):
|
||||
|
||||
|
||||
class DayCell(object):
|
||||
"""class Holding a day cell to be drawn
|
||||
|
||||
@type day: int
|
||||
@ivar day: day of week
|
||||
@ivar header: header string
|
||||
@ivar footer: footer string
|
||||
@ivar theme: (Style,Geometry,Language) tuple
|
||||
@type show_day_name: bool
|
||||
@ivar show_day_name: whether day name is displayed
|
||||
"""
|
||||
def __init__(self, day, header, footer, theme, show_day_name):
|
||||
self.day = day
|
||||
self.header = header
|
||||
@ -75,6 +89,7 @@ class DayCell(object):
|
||||
self.show_day_name = show_day_name
|
||||
|
||||
def _draw_short(self, cr, rect):
|
||||
"""render the day cell in short mode"""
|
||||
S,G,L = self.theme
|
||||
x, y, w, h = rect
|
||||
day_of_month, day_of_week = self.day
|
||||
@ -86,24 +101,25 @@ class DayCell(object):
|
||||
Rdom = R
|
||||
valign = 0 if self.show_day_name else 2
|
||||
# draw day of month (number)
|
||||
draw_str(cr, text = str(day_of_month), rect = Rdom, stretch = -1, stroke_rgba = S.fg,
|
||||
draw_str(cr, text = str(day_of_month), rect = Rdom, scaling = -1, stroke_rgba = S.fg,
|
||||
align = (2,valign), font = S.font, measure = "88")
|
||||
# draw name of day
|
||||
if self.show_day_name:
|
||||
draw_str(cr, text = L.day_name[day_of_week][0], rect = Rdow, stretch = -1, stroke_rgba = S.fg,
|
||||
draw_str(cr, text = L.day_name[day_of_week][0], rect = Rdow, scaling = -1, stroke_rgba = S.fg,
|
||||
align = (2,valign), font = S.font, measure = "88")
|
||||
# draw header
|
||||
if self.header:
|
||||
R = rect_rel_scale(rect, G.header_size[0], G.header_size[1], 0, -1.0 + G.header_align)
|
||||
draw_str(cr, text = self.header, rect = R, stretch = -1, stroke_rgba = S.header,
|
||||
draw_str(cr, text = self.header, rect = R, scaling = -1, stroke_rgba = S.header,
|
||||
font = S.header_font) # , measure = "MgMgMgMgMgMg"
|
||||
# draw footer
|
||||
if self.footer:
|
||||
R = rect_rel_scale(rect, G.footer_size[0], G.footer_size[1], 0, 1.0 - G.footer_align)
|
||||
draw_str(cr, text = self.footer, rect = R, stretch = -1, stroke_rgba = S.footer,
|
||||
draw_str(cr, text = self.footer, rect = R, scaling = -1, stroke_rgba = S.footer,
|
||||
font = S.footer_font)
|
||||
|
||||
def _draw_long(self, cr, rect):
|
||||
"""render the day cell in long mode"""
|
||||
S,G,L = self.theme
|
||||
x, y, w, h = rect
|
||||
day_of_month, day_of_week = self.day
|
||||
@ -116,23 +132,27 @@ class DayCell(object):
|
||||
Rdom = rect_rel_scale(R1, G.size[0], G.size[1])
|
||||
valign = 0 if self.show_day_name else 2
|
||||
# draw day of month (number)
|
||||
draw_str(cr, text = str(day_of_month), rect = Rdom, stretch = -1, stroke_rgba = S.fg,
|
||||
draw_str(cr, text = str(day_of_month), rect = Rdom, scaling = -1, stroke_rgba = S.fg,
|
||||
align = (2,valign), font = S.font, measure = "88")
|
||||
# draw name of day
|
||||
if self.show_day_name:
|
||||
draw_str(cr, text = L.day_name[day_of_week], rect = Rdow, stretch = -1, stroke_rgba = S.fg,
|
||||
draw_str(cr, text = L.day_name[day_of_week], rect = Rdow, scaling = -1, stroke_rgba = S.fg,
|
||||
align = (0,valign), font = S.font, measure = "M")
|
||||
Rh, Rf = rect_vsplit(Rhf, *G.hf_vsplit)
|
||||
# draw header
|
||||
if self.header:
|
||||
draw_str(cr, text = self.header, rect = Rh, stretch = -1, stroke_rgba = S.header, align = (1,2),
|
||||
draw_str(cr, text = self.header, rect = Rh, scaling = -1, stroke_rgba = S.header, align = (1,2),
|
||||
font = S.header_font)
|
||||
# draw footer
|
||||
if self.footer:
|
||||
draw_str(cr, text = self.footer, rect = Rf, stretch = -1, stroke_rgba = S.footer, align = (1,2),
|
||||
draw_str(cr, text = self.footer, rect = Rf, scaling = -1, stroke_rgba = S.footer, align = (1,2),
|
||||
font = S.footer_font)
|
||||
|
||||
def draw(self, cr, rect, short_thres):
|
||||
"""automatically render a short or long day cell depending on threshold I{short_thres}
|
||||
|
||||
If C{rect} ratio is less than C{short_thres} then short mode is chosen, otherwise long mode.
|
||||
"""
|
||||
if rect_ratio(rect) < short_thres:
|
||||
self._draw_short(cr, rect)
|
||||
else:
|
||||
@ -140,6 +160,17 @@ class DayCell(object):
|
||||
|
||||
|
||||
class CalendarRenderer(object):
|
||||
"""base monthly calendar renderer - others inherit from this
|
||||
|
||||
@ivar Outfile: output file
|
||||
@ivar Year: year of first month
|
||||
@ivar Month: first month
|
||||
@ivar MonthSpan: month span
|
||||
@ivar Theme: (Style,Geometry,Language) tuple
|
||||
@ivar holiday_provider: L{HolidayProvider} object
|
||||
@ivar version_string: callirhoe version string
|
||||
@ivar options: parser options object
|
||||
"""
|
||||
def __init__(self, Outfile, Year, Month, MonthSpan, Theme, holiday_provider, version_string, options):
|
||||
self.Outfile = Outfile
|
||||
self.Year = Year
|
||||
@ -151,6 +182,14 @@ class CalendarRenderer(object):
|
||||
self.options = options
|
||||
|
||||
def _draw_month(self, cr, rect, month, year, daycell_thres):
|
||||
"""this method renders a calendar month, it B{should be overridden} in any subclass
|
||||
|
||||
@param cr: cairo context
|
||||
@param rect: rendering rect
|
||||
@param month: month
|
||||
@param year: year
|
||||
@param daycell_thres: short/long day cell threshold
|
||||
"""
|
||||
raise NotImplementedError("base _draw_month() should be overridden")
|
||||
|
||||
#1 1 1
|
||||
@ -171,6 +210,7 @@ class CalendarRenderer(object):
|
||||
#rows = 0
|
||||
#cols = 0
|
||||
def render(self):
|
||||
"""main calendar rendering routine"""
|
||||
S,G,L = self.Theme
|
||||
rows, cols = self.options.rows, self.options.cols
|
||||
|
||||
@ -186,7 +226,7 @@ class CalendarRenderer(object):
|
||||
S.month.color_map_fg = (S.month.color_map_fg[1], S.month.color_map_fg[0])
|
||||
|
||||
try:
|
||||
page = PageWriter(self.Outfile, G.landscape, G.pagespec, G.border, not self.options.opaque)
|
||||
page = PageWriter(self.Outfile, G.pagespec, not self.options.opaque, G.landscape, G.border)
|
||||
except InvalidFormat as e:
|
||||
print >> sys.stderr, "invalid output format", e.args[0]
|
||||
sys.exit(1)
|
||||
@ -253,11 +293,11 @@ class CalendarRenderer(object):
|
||||
if (y > yy[-1]): yy.append(y)
|
||||
if not self.options.month_with_year and not self.options.no_footer:
|
||||
year_str = str(yy[0]) if yy[0] == yy[-1] else "%s – %s" % (yy[0],yy[-1])
|
||||
draw_str(page.cr, text = year_str, rect = Rc, stroke_rgba = (0,0,0,0.5), stretch = -1,
|
||||
draw_str(page.cr, text = year_str, rect = Rc, stroke_rgba = (0,0,0,0.5), scaling = -1,
|
||||
align = (0,0), font = (extract_font_name(S.month.font),0,0))
|
||||
if not self.options.no_footer:
|
||||
draw_str(page.cr, text = "rendered by Callirhoe ver. %s" % self.version_string,
|
||||
rect = Rc, stroke_rgba = (0,0,0,0.5), stretch = -1, align = (1,0),
|
||||
rect = Rc, stroke_rgba = (0,0,0,0.5), scaling = -1, align = (1,0),
|
||||
font = (extract_font_name(S.month.font),1,0))
|
||||
num_pages_written += 1
|
||||
page.end_page()
|
||||
|
@ -1,6 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# callirhoe - high quality calendar rendering
|
||||
# Copyright (C) 2012-2013 George M. Tzoumas
|
||||
# Copyright (C) 2012-2014 George M. Tzoumas
|
||||
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
@ -15,7 +15,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/
|
||||
|
||||
# --- layouts.bars ---
|
||||
"""bars layout"""
|
||||
|
||||
from lib.xcairo import *
|
||||
from lib.geom import *
|
||||
@ -29,10 +29,11 @@ import _base
|
||||
parser = _base.get_parser(__name__)
|
||||
|
||||
class CalendarRenderer(_base.CalendarRenderer):
|
||||
"""bars layout class"""
|
||||
#default thres = 2.5
|
||||
def _draw_month(self, cr, rect, month, year, daycell_thres):
|
||||
S,G,L = self.Theme
|
||||
apply_rect(cr, rect, G.month.sloppy_dx, G.month.sloppy_dy, G.month.sloppy_rot)
|
||||
make_sloppy_rect(cr, rect, G.month.sloppy_dx, G.month.sloppy_dy, G.month.sloppy_rot)
|
||||
|
||||
day, span = calendar.monthrange(year, month)
|
||||
mmeasure = 'A'*max(map(len,L.month_name))
|
||||
@ -79,7 +80,7 @@ class CalendarRenderer(_base.CalendarRenderer):
|
||||
mshad = (f,-f) if G.landscape else (f,f)
|
||||
title_str = L.month_name[month]
|
||||
if self.options.month_with_year: title_str += ' ' + str(year)
|
||||
draw_str(cr, text = title_str, rect = R_text, stretch = -1, stroke_rgba = mcolor_fg,
|
||||
draw_str(cr, text = title_str, rect = R_text, scaling = -1, stroke_rgba = mcolor_fg,
|
||||
align = (2,0), font = S.month.font, measure = mmeasure, shadow = mshad)
|
||||
cr.restore()
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/
|
||||
|
||||
# --- layouts.classic ---
|
||||
"""classic layout"""
|
||||
|
||||
from lib.xcairo import *
|
||||
from lib.geom import *
|
||||
@ -28,6 +28,7 @@ import _base
|
||||
parser = _base.get_parser(__name__)
|
||||
|
||||
def _weekrows_of_month(year, month):
|
||||
"""returns the number of Monday-Sunday ranges (or subsets of) that a month contains, which are 4, 5 or 6"""
|
||||
day,span = calendar.monthrange(year, month)
|
||||
if day == 0 and span == 28: return 4
|
||||
if day == 5 and span == 31: return 6
|
||||
@ -35,10 +36,11 @@ def _weekrows_of_month(year, month):
|
||||
return 5
|
||||
|
||||
class CalendarRenderer(_base.CalendarRenderer):
|
||||
"""classic tiles layout class"""
|
||||
#default thres = 2.5
|
||||
def _draw_month(self, cr, rect, month, year, daycell_thres):
|
||||
S,G,L = self.Theme
|
||||
apply_rect(cr, rect, G.month.sloppy_dx, G.month.sloppy_dy, G.month.sloppy_rot)
|
||||
make_sloppy_rect(cr, rect, G.month.sloppy_dx, G.month.sloppy_dy, G.month.sloppy_rot)
|
||||
|
||||
day, span = calendar.monthrange(year, month)
|
||||
weekrows = 6 if G.month.symmetric else _weekrows_of_month(year, month)
|
||||
@ -67,7 +69,7 @@ class CalendarRenderer(_base.CalendarRenderer):
|
||||
fill_rgba = S.dom.bg if col < 5 else S.dom_weekend.bg,
|
||||
stroke_width = mm_to_dots(S.dow.frame_thickness))
|
||||
R_text = rect_rel_scale(R, 1, 0.5)
|
||||
draw_str(cr, text = L.day_name[col], rect = R_text, stretch = -1, stroke_rgba = S.dow.fg,
|
||||
draw_str(cr, text = L.day_name[col], rect = R_text, scaling = -1, stroke_rgba = S.dow.fg,
|
||||
align = (2,0), font = S.dow.font, measure = wmeasure)
|
||||
|
||||
# draw day cells
|
||||
@ -100,7 +102,7 @@ class CalendarRenderer(_base.CalendarRenderer):
|
||||
mshad = (f,-f) if G.landscape else (f,f)
|
||||
title_str = L.month_name[month]
|
||||
if self.options.month_with_year: title_str += ' ' + str(year)
|
||||
draw_str(cr, text = title_str, rect = R_text, stretch = -1, stroke_rgba = mcolor_fg,
|
||||
draw_str(cr, text = title_str, rect = R_text, scaling = -1, stroke_rgba = mcolor_fg,
|
||||
align = (2,0), font = S.month.font, measure = mmeasure, shadow = mshad)
|
||||
cr.restore()
|
||||
|
||||
|
@ -170,7 +170,7 @@ class HLayout(VLayout):
|
||||
t = super(HLayout,self).item(i)
|
||||
return (t[1], t[0], t[3], t[2])
|
||||
|
||||
class GLayout:
|
||||
class GLayout(object):
|
||||
"""grid layout manager
|
||||
|
||||
@ivar vrep: internal L{VLayout} for row computations
|
||||
|
178
lib/holiday.py
178
lib/holiday.py
@ -25,7 +25,7 @@
|
||||
from datetime import date, timedelta
|
||||
|
||||
def _get_orthodox_easter(year):
|
||||
"""Compute date of orthodox easter."""
|
||||
"""compute date of orthodox easter"""
|
||||
y1, y2, y3 = year % 4 , year % 7, year % 19
|
||||
a = 19*y3 + 15
|
||||
y4 = a % 30
|
||||
@ -37,7 +37,7 @@ def _get_orthodox_easter(year):
|
||||
# return res
|
||||
|
||||
def _get_catholic_easter(year):
|
||||
"""Compute date of catholic easter."""
|
||||
"""compute date of catholic easter"""
|
||||
a, b, c = year % 19, year // 100, year % 100
|
||||
d, e = divmod(b,4)
|
||||
f = (b + 8) // 25
|
||||
@ -49,11 +49,23 @@ def _get_catholic_easter(year):
|
||||
emonth,edate = divmod(h + l - 7*m + 114,31)
|
||||
return date(year, emonth, edate+1)
|
||||
|
||||
class Holiday(object):
|
||||
"""class holding a Holiday object (date is I{not} stored!)
|
||||
def _strip_empty(sl):
|
||||
"""strip empty strings from list I{sl}"""
|
||||
return filter(lambda z: z, sl) if sl else []
|
||||
|
||||
@ivar header: string for header (primary text)
|
||||
@ivar footer: string for footer (secondary text)
|
||||
def _flatten(sl):
|
||||
"""join list I{sl} into a comma-separated string"""
|
||||
if not sl: return None
|
||||
res = sl[0]
|
||||
for s in sl[1:]:
|
||||
res += ', ' + s
|
||||
return res
|
||||
|
||||
class Holiday(object):
|
||||
"""class holding a Holiday object (date is I{not} stored, use L{HolidayProvider} for that)
|
||||
|
||||
@ivar header_list: string list for header (primary text)
|
||||
@ivar footer_list: string list for footer (secondary text)
|
||||
@ivar flags: bit combination of {OFF=1, MULTI=2, REMINDER=4}
|
||||
|
||||
I{OFF}: day off (real holiday)
|
||||
@ -73,27 +85,31 @@ class Holiday(object):
|
||||
MULTI = 2
|
||||
REMINDER = 4
|
||||
def __init__(self, header = [], footer = [], flags_str = None):
|
||||
self.header_list = self._strip_empty(header)
|
||||
self.footer_list = self._strip_empty(footer)
|
||||
self.header_list = _strip_empty(header)
|
||||
self.footer_list = _strip_empty(footer)
|
||||
self.flags = self._parse_flags(flags_str)
|
||||
|
||||
def merge_with(self, hol_list):
|
||||
"""Merge a list of holiday objects into this object."""
|
||||
"""merge a list of holiday objects into this object"""
|
||||
for hol in hol_list:
|
||||
self.header_list.extend(hol.header_list)
|
||||
self.footer_list.extend(hol.footer_list)
|
||||
self.flags |= hol.flags
|
||||
|
||||
def header(self):
|
||||
return self._flatten(self.header_list)
|
||||
"""return a comma-separated string for L{header_list}"""
|
||||
return _flatten(self.header_list)
|
||||
|
||||
def footer(self):
|
||||
return self._flatten(self.footer_list)
|
||||
"""return a comma-separated string for L{footer_list}"""
|
||||
return _flatten(self.footer_list)
|
||||
|
||||
def __repr__(self):
|
||||
def __str__(self):
|
||||
"""string representation for debugging purposes"""
|
||||
return str(self.footer()) + ':' + str(self.header()) + ':' + str(self.flags)
|
||||
|
||||
def _parse_flags(self, fstr):
|
||||
"""return a bit combination of flags, from a comma-separated string list"""
|
||||
if not fstr: return 0
|
||||
fs = fstr.split(',')
|
||||
val = 0
|
||||
@ -104,18 +120,20 @@ class Holiday(object):
|
||||
elif 'reminder'.startswith(s): val |= Holiday.REMINDER
|
||||
return val
|
||||
|
||||
def _strip_empty(self, sl):
|
||||
return filter(lambda z: z, sl) if sl else []
|
||||
|
||||
def _flatten(self, sl):
|
||||
if not sl: return None
|
||||
res = sl[0]
|
||||
for s in sl[1:]:
|
||||
res += ', ' + s
|
||||
return res
|
||||
|
||||
|
||||
def _decode_date_str(ddef):
|
||||
"""decode a date definition string into a I{(year,month,day)} tuple
|
||||
|
||||
@param ddef: date definition string of length 2, 4 or 8
|
||||
|
||||
If C{ddef} is of the form "DD" then tuple (0,0,DD) is returned, which
|
||||
stands for any year - any month - day DD.
|
||||
|
||||
If C{ddef} is of the form "MMDD" then tuple (0,MM,DD) is returned, which
|
||||
stands for any year - month MM - day DD.
|
||||
|
||||
If C{ddef} is of the form "YYYYMMDD" then tuple (YYYY,MM,DD) is returned, which
|
||||
stands for year YYYY - month MM - day DD.
|
||||
"""
|
||||
if len(ddef) == 2:
|
||||
return (0,0,int(ddef))
|
||||
if len(ddef) == 4:
|
||||
@ -125,7 +143,36 @@ def _decode_date_str(ddef):
|
||||
raise ValueError("invalid date definition '%s'" % ddef)
|
||||
|
||||
class HolidayProvider(object):
|
||||
def __init__(self, s_normal, s_weekend, s_holiday, s_weekend_holiday, s_multi, s_weekend_multi, verbose=True):
|
||||
"""class holding the holidays throught the year(s)
|
||||
|
||||
@ivar annual: dict of events occuring annually, indexed by tuple I{(day,month)}. Note
|
||||
each dict entry is actually a list of L{Holiday} objects. This is also true for the other
|
||||
instance variables: L{monthly}, L{fixed}, L{orth_easter}, L{george}, L{cath_easter}.
|
||||
@ivar monthly: event occuring monthly, indexed by int I{day}
|
||||
@ivar fixed: fixed date events, indexed by a C{date()} object
|
||||
@ivar orth_easter: dict of events relative to the orthodox easter Sunday, indexed by
|
||||
an integer days offset
|
||||
@ivar george: events occuring on St George's day (orthodox calendar special computation)
|
||||
@ivar cath_easter: dict of events relative to the catholic easter Sunday, indexed by
|
||||
an integer days offset
|
||||
@ivar cache: for each year requested, all holidays occuring
|
||||
within that year (annual, monthly, easter-based etc.) are precomputed and stored into
|
||||
dict C{cache}, indexed by a C{date()} object
|
||||
@ivar ycache: set holding cached years; each new year requested, triggers a cache-fill
|
||||
operation
|
||||
"""
|
||||
def __init__(self, s_normal, s_weekend, s_holiday, s_weekend_holiday, s_multi, s_weekend_multi, multiday_markers=True):
|
||||
"""initialize a C{HolidayProvider} object
|
||||
|
||||
@param s_normal: style class object for normal (weekday) day cells
|
||||
@param s_weekend: style for weekend day cells
|
||||
@param s_holiday: style for holiday day cells
|
||||
@param s_weekend_holiday: style for holiday cells on weekends
|
||||
@param s_multi: style for multi-day holiday weekday cells
|
||||
@param s_weekend_multi: style for multi-day holiday weekend cells
|
||||
@param multiday_markers: if C{True}, then use end-of-multiday-holiday markers and range markers (with dots),
|
||||
otherwise only first day and first-day-of-month are marked
|
||||
"""
|
||||
self.annual = dict() # key = (d,m)
|
||||
self.monthly = dict() # key = d
|
||||
self.fixed = dict() # key = date()
|
||||
@ -140,9 +187,9 @@ class HolidayProvider(object):
|
||||
self.s_weekend_holiday = s_weekend_holiday
|
||||
self.s_multi = s_multi
|
||||
self.s_weekend_multi = s_weekend_multi
|
||||
self.verbose = verbose
|
||||
self.multiday_markers = multiday_markers
|
||||
|
||||
def parse_day_record(self, fields):
|
||||
def _parse_day_record(self, fields):
|
||||
"""return tuple (etype,ddef,footer,header,flags)
|
||||
|
||||
@note: I{ddef} is one of the following:
|
||||
@ -189,17 +236,22 @@ class HolidayProvider(object):
|
||||
res = int(fields[1])
|
||||
return (fields[0],res,fields[2],fields[3],fields[4])
|
||||
|
||||
def multi_holiday_tuple(self, date1, date2, header, footer, flags):
|
||||
"""Returns Holiday objects for (beginning, end, first_dom, rest)"""
|
||||
def _multi_holiday_tuple(self, header, footer, flags):
|
||||
"""returns a 4-tuple of L{Holiday} objects representing (beginning, end, first-day-of-month, rest)
|
||||
|
||||
@param header: passed as C{[header]} of the generated L{Holiday} object
|
||||
@param footer: passed as C{[footer]} of the generated L{Holiday} object
|
||||
@param flags: C{flags} of the generated L{Holiday} object
|
||||
"""
|
||||
if header:
|
||||
if self.verbose:
|
||||
if self.multiday_markers:
|
||||
header_tuple = (header+'..', '..'+header, '..'+header+'..', None)
|
||||
else:
|
||||
header_tuple = (header, None, header, None)
|
||||
else:
|
||||
header_tuple = (None, None, None, None)
|
||||
if footer:
|
||||
if self.verbose:
|
||||
if self.multiday_markers:
|
||||
footer_tuple = (footer+'..', '..'+footer, '..'+footer+'..', None)
|
||||
else:
|
||||
footer_tuple = (footer, None, footer, None)
|
||||
@ -208,29 +260,47 @@ class HolidayProvider(object):
|
||||
return tuple(map(lambda k: Holiday([header_tuple[k]], [footer_tuple[k]], flags),
|
||||
range(4)))
|
||||
|
||||
# File Format:
|
||||
# type|DATE*span|footer|header|flags
|
||||
# type|DATE1-DATE2|footer|header|flags
|
||||
# type|DATE|footer|header|flags
|
||||
#
|
||||
# type:
|
||||
# d: event occurs annually fixed day/month: MMDD
|
||||
# d: event occurs monthly, fixed day: DD
|
||||
# d: fixed day/month/year combination (e.g. deadline, trip, etc.): YYYYMMDD
|
||||
# oe: Orthodox Easter-dependent holiday, annually
|
||||
# ge: Georgios' name day, Orthodox Easter dependent holiday, annually
|
||||
# ce: Catholic Easter holiday
|
||||
#
|
||||
# DATE*span and DATE1-DATE2 supported only for YYYYMMDD
|
||||
# flags = {off, multi}
|
||||
def load_holiday_file(self, filename):
|
||||
"""load a holiday file into the C{HolidayProvider} object
|
||||
|
||||
B{File Format:}
|
||||
- C{type|date*span|footer|header|flags}
|
||||
- C{type|date1-date2|footer|header|flags}
|
||||
- C{type|date|footer|header|flags}
|
||||
|
||||
I{type:}
|
||||
- C{d}: event occurs annually fixed day/month; I{date}=MMDD
|
||||
- C{d}: event occurs monthly, fixed day; I{date}=DD
|
||||
- C{d}: fixed day/month/year combination (e.g. deadline, trip, etc.); I{date}=YYYYMMDD
|
||||
- C{oe}: Orthodox Easter-dependent holiday, annually; I{date}=integer offset in days
|
||||
- C{ge}: Georgios' name day, Orthodox Easter dependent holiday, annually; I{date} field is ignored
|
||||
- C{ce}: Catholic Easter holiday; I{date}=integer offset in days
|
||||
|
||||
I{date*span} and range I{date1-date2} supported only for I{date}=YYYYMMDD (fixed) events
|
||||
|
||||
I{flags:} comma-separated list of the following:
|
||||
1. off
|
||||
2. multi
|
||||
3. reminder (or any prefix of it)
|
||||
|
||||
B{Example}::
|
||||
|
||||
d|0101||New year's|off
|
||||
d|0501||Labour day|off
|
||||
ce|-2||Good Friday|
|
||||
ce|0||Easter|off
|
||||
ce|1||Easter Monday|off
|
||||
d|20130223-20130310|winter vacations (B)||multi
|
||||
|
||||
@param filename: file to be loaded
|
||||
"""
|
||||
with open(filename, 'r') as f:
|
||||
for line in f:
|
||||
line = line.strip()
|
||||
if not line: continue
|
||||
if line[0] == '#': continue
|
||||
fields = line.split('|')
|
||||
etype,ddef,footer,header,flags = self.parse_day_record(fields)
|
||||
etype,ddef,footer,header,flags = self._parse_day_record(fields)
|
||||
hol = Holiday([header], [footer], flags)
|
||||
if etype == 'd':
|
||||
if len(ddef) == 1:
|
||||
@ -249,7 +319,7 @@ class HolidayProvider(object):
|
||||
self.fixed[dt1].append(hol)
|
||||
else:
|
||||
# properly annotate multi-day events
|
||||
hols = self.multi_holiday_tuple(dt1, dt2, header, footer, flags)
|
||||
hols = self._multi_holiday_tuple(header, footer, flags)
|
||||
dt = dt1
|
||||
while dt <= dt2:
|
||||
if dt not in self.fixed: self.fixed[dt] = []
|
||||
@ -273,6 +343,11 @@ class HolidayProvider(object):
|
||||
self.cath_easter[d].append(hol)
|
||||
|
||||
def get_holiday(self, y, m, d):
|
||||
"""return a L{Holiday} object for the specified date (y,m,d) or C{None} if no holiday is defined
|
||||
|
||||
@note: If year I{y} has not been requested before, the cache is updated first
|
||||
with all holidays that belong in I{y}, indexed by C{date()} objects.
|
||||
"""
|
||||
if y not in self.ycache:
|
||||
# fill-in events for year y
|
||||
# annual
|
||||
@ -315,6 +390,11 @@ class HolidayProvider(object):
|
||||
return self.cache[dt] if dt in self.cache else None
|
||||
|
||||
def get_style(self, flags, dow):
|
||||
"""return appropriate style object, depending on I{flags} and I{dow}
|
||||
|
||||
@param flags: bit combination of holiday flags
|
||||
@param dow: day of week
|
||||
"""
|
||||
if flags & Holiday.OFF:
|
||||
return self.s_weekend_holiday if dow >= 5 else self.s_holiday
|
||||
if flags & Holiday.MULTI:
|
||||
@ -322,7 +402,7 @@ class HolidayProvider(object):
|
||||
return self.s_weekend if dow >= 5 else self.s_normal
|
||||
|
||||
def __call__(self, year, month, dom, dow):
|
||||
"""Returns (header,footer,day_style)
|
||||
"""returns (header,footer,day_style)
|
||||
|
||||
@param month: month (0-12)
|
||||
@param dom: day of month (1-31)
|
||||
@ -337,6 +417,8 @@ class HolidayProvider(object):
|
||||
if __name__ == '__main__':
|
||||
import sys
|
||||
hp = HolidayProvider('n', 'w', 'h', 'wh', 'm', 'wm')
|
||||
if len(sys.argv) < 3:
|
||||
raise SystemExit("Usage: %s YEAR holiday_file ..." % sys.argv[0]);
|
||||
y = int(sys.argv[1])
|
||||
for f in sys.argv[2:]:
|
||||
hp.load_holiday_file(f)
|
||||
|
169
lib/xcairo.py
169
lib/xcairo.py
@ -29,16 +29,30 @@ from os.path import splitext
|
||||
from geom import *
|
||||
|
||||
XDPI = 72.0
|
||||
"""dots per inch of output device"""
|
||||
|
||||
# decreasing order
|
||||
# [1188, 840, 594, 420, 297, 210, 148, 105, 74, 52, 37]
|
||||
ISOPAGE = map(lambda x: int(210*math.sqrt(2)**x+0.5), range(5,-6,-1))
|
||||
"""ISO page height list, index k for height of Ak paper"""
|
||||
|
||||
def page_spec(spec = None):
|
||||
"""return tuple of page dimensions (width,height) in mm for I{spec}
|
||||
|
||||
@param spec: paper type.
|
||||
Paper type can be an ISO paper type (a0..a9 or a0w..a9w) or of the
|
||||
form W:H; positive values correspond to W or H mm, negative values correspond to
|
||||
-W or -H pixels; 'w' suffix swaps width & height; None defaults to A4 paper
|
||||
"""
|
||||
if not spec:
|
||||
return (ISOPAGE[5], ISOPAGE[4])
|
||||
if len(spec) == 2 and spec[0].lower() == 'a':
|
||||
k = int(spec[1])
|
||||
if k > 9: k = 9
|
||||
return (ISOPAGE[k+1], ISOPAGE[k])
|
||||
if len(spec) == 3 and spec[0].lower() == 'a' and spec[2].lower() == 'w':
|
||||
k = int(spec[1])
|
||||
if k > 9: k = 9
|
||||
return (ISOPAGE[k], ISOPAGE[k+1])
|
||||
if ':' in spec:
|
||||
s = spec.split(':')
|
||||
@ -48,13 +62,38 @@ def page_spec(spec = None):
|
||||
return (w,h)
|
||||
|
||||
def mm_to_dots(mm):
|
||||
"""convert millimeters to dots"""
|
||||
return mm/25.4 * XDPI
|
||||
|
||||
def dots_to_mm(dots):
|
||||
"""convert dots to millimeters"""
|
||||
return dots*25.4/XDPI
|
||||
|
||||
class Page(object):
|
||||
"""class holding Page properties
|
||||
|
||||
@type Size_mm: tuple (width,height)
|
||||
@ivar Size_mm: page dimensions in mm
|
||||
@type landscape: bool
|
||||
@ivar landscape: landscape mode (for landscape, Size_mm will have swapped elements)
|
||||
@type Size: tuple (width,height)
|
||||
@ivar Size: page size in dots/pixels
|
||||
@type Margins: tuple (top,left,bottom,right)
|
||||
@ivar Margins: page margins in pixels
|
||||
@type Text_rect: tuple (x,y,w,h)
|
||||
@ivar Text_rect: text rectangle
|
||||
"""
|
||||
def __init__(self, landscape, w, h, b, raster):
|
||||
"""initialize Page properties object
|
||||
|
||||
@type landscape: bool
|
||||
@param landscape: landscape mode
|
||||
@param w: page physical width in mm
|
||||
@param h: page physical height in mm, M{h>w}, even in landscape mode
|
||||
@param b: page border in mm (uniform)
|
||||
@type raster: bool
|
||||
@param raster: raster mode (not vector)
|
||||
"""
|
||||
if not landscape:
|
||||
self.Size_mm = (w, h) # (width, height) in mm
|
||||
else:
|
||||
@ -67,12 +106,37 @@ class Page(object):
|
||||
self.Size[1] - self.Margins[0] - self.Margins[2])
|
||||
self.Text_rect = (self.Margins[1], self.Margins[0], txs[0], txs[1])
|
||||
|
||||
class InvalidFormat(Exception): pass
|
||||
class InvalidFormat(Exception):
|
||||
"""exception thrown when an invalid output format is requested"""
|
||||
pass
|
||||
|
||||
class PageWriter(Page):
|
||||
"""class to output multiple pages in raster (png) or vector (pdf) format
|
||||
|
||||
|
||||
@ivar base: out filename (without extension)
|
||||
@ivar ext: filename extension (with dot)
|
||||
@type curpage: int
|
||||
@ivar curpage: current page
|
||||
@ivar format: output format: L{PDF} or L{PNG}
|
||||
@type keep_transparency: bool
|
||||
@ivar keep_transparency: C{True} to use transparent instead of white fill color
|
||||
@ivar img_format: C{cairo.FORMAT_ARGB32} or C{cairo.FORMAT_RGB24} depending on
|
||||
L{keep_transparency}
|
||||
@ivar Surface: cairo surface (set by L{_setup_surface_and_context})
|
||||
@ivar cr: cairo context (set by L{_setup_surface_and_context})
|
||||
"""
|
||||
|
||||
PDF = 0
|
||||
PNG = 1
|
||||
def __init__(self, filename, landscape = False, pagespec = None, b = 0.0, keep_transparency = True):
|
||||
def __init__(self, filename, pagespec = None, keep_transparency = True, landscape = False, b = 0.0):
|
||||
"""initialize PageWriter object
|
||||
|
||||
see also L{Page.__init__}
|
||||
@param filename: output filename (extension determines format PDF or PNG)
|
||||
@param pagespec: iso page spec, see L{page_spec}
|
||||
@param keep_transparency: see L{keep_transparency}
|
||||
"""
|
||||
self.base,self.ext = splitext(filename)
|
||||
self.filename = filename
|
||||
self.curpage = 1
|
||||
@ -90,19 +154,15 @@ class PageWriter(Page):
|
||||
w, h = h, w
|
||||
landscape = False
|
||||
super(PageWriter,self).__init__(landscape, w, h, b, self.format == PageWriter.PNG)
|
||||
self.setup_surface_and_context()
|
||||
self._setup_surface_and_context()
|
||||
|
||||
def setup_surface_and_context(self):
|
||||
if not self.landscape:
|
||||
if self.format == PageWriter.PDF:
|
||||
self.Surface = cairo.PDFSurface(self.filename, self.Size[0], self.Size[1])
|
||||
else:
|
||||
self.Surface = cairo.ImageSurface(self.img_format, int(self.Size[0]), int(self.Size[1]))
|
||||
def _setup_surface_and_context(self):
|
||||
"""setup cairo surface taking into account raster mode, transparency and landscape mode"""
|
||||
z = int(self.landscape)
|
||||
if self.format == PageWriter.PDF:
|
||||
self.Surface = cairo.PDFSurface(self.filename, self.Size[z], self.Size[1-z])
|
||||
else:
|
||||
if self.format == PageWriter.PDF:
|
||||
self.Surface = cairo.PDFSurface(self.filename, self.Size[1], self.Size[0])
|
||||
else:
|
||||
self.Surface = cairo.ImageSurface(self.img_format, int(self.Size[1]), int(self.Size[0]))
|
||||
self.Surface = cairo.ImageSurface(self.img_format, int(self.Size[z]), int(self.Size[1-z]))
|
||||
|
||||
self.cr = cairo.Context(self.Surface)
|
||||
if self.landscape:
|
||||
@ -118,11 +178,13 @@ class PageWriter(Page):
|
||||
self.cr.fill()
|
||||
|
||||
def end_page(self):
|
||||
"""in PNG mode, output a separate file for each page"""
|
||||
if self.format == PageWriter.PNG:
|
||||
outfile = self.filename if self.curpage < 2 else self.base + "%02d" % (self.curpage) + self.ext
|
||||
self.Surface.write_to_png(outfile)
|
||||
|
||||
def new_page(self):
|
||||
"""setup next page"""
|
||||
if self.format == PageWriter.PDF:
|
||||
self.cr.show_page()
|
||||
else:
|
||||
@ -131,15 +193,29 @@ class PageWriter(Page):
|
||||
|
||||
|
||||
def set_color(cr, rgba):
|
||||
"""set stroke color
|
||||
|
||||
@param cr: cairo context
|
||||
@type rgba: tuple
|
||||
@param rgba: (r,g,b) or (r,g,b,a)
|
||||
"""
|
||||
if len(rgba) == 3:
|
||||
cr.set_source_rgb(*rgba)
|
||||
else:
|
||||
cr.set_source_rgba(*rgba)
|
||||
|
||||
def extract_font_name(f):
|
||||
"extract the font name from a string or from a tuple (fontname, slant, weight)"""
|
||||
return f if type(f) is str else f[0]
|
||||
|
||||
def apply_rect(cr, rect, sdx = 0.0, sdy = 0.0, srot = 0.0):
|
||||
def make_sloppy_rect(cr, rect, sdx = 0.0, sdy = 0.0, srot = 0.0):
|
||||
"""slightly rotate and translate a rect to give it a sloppy look
|
||||
|
||||
@param cr: cairo context
|
||||
@param sdx: maximum x-offset, true offset will be uniformly distibuted
|
||||
@param sdy: maximum y-offset
|
||||
@param sdy: maximum rotation
|
||||
"""
|
||||
x, y, w, h = rect
|
||||
cr.save()
|
||||
cr.translate(x,y)
|
||||
@ -150,6 +226,15 @@ def apply_rect(cr, rect, sdx = 0.0, sdy = 0.0, srot = 0.0):
|
||||
cr.translate(-w/2.0, -h/2.0)
|
||||
|
||||
def draw_shadow(cr, rect, thickness = None, shadow_color = (0,0,0,0.3)):
|
||||
"""draw a shadow at the bottom-right corner of a rect
|
||||
|
||||
@param cr: cairo context
|
||||
@param rect: tuple (x,y,w,h)
|
||||
@param thickness: if C{None} nothing is drawn
|
||||
@param shadow_color: shadow color
|
||||
"""
|
||||
|
||||
|
||||
if thickness is None: return
|
||||
fx = mm_to_dots(thickness[0])
|
||||
fy = mm_to_dots(thickness[1])
|
||||
@ -172,6 +257,13 @@ def draw_shadow(cr, rect, thickness = None, shadow_color = (0,0,0,0.3)):
|
||||
cr.close_path(); cr.fill();
|
||||
|
||||
def draw_line(cr, rect, stroke_rgba = None, stroke_width = 1.0):
|
||||
"""draw a line from (x,y) to (x+w,y+h), where rect=(x,y,w,h)
|
||||
|
||||
@param cr: cairo context
|
||||
@param rect: tuple (x,y,w,h)
|
||||
@param stroke_rgba: stroke color
|
||||
@param stroke_width: stroke width, if <= 0 nothing is drawn
|
||||
"""
|
||||
if (stroke_width <= 0): return
|
||||
x, y, w, h = rect
|
||||
cr.move_to(x, y)
|
||||
@ -183,6 +275,15 @@ def draw_line(cr, rect, stroke_rgba = None, stroke_width = 1.0):
|
||||
cr.stroke()
|
||||
|
||||
def draw_box(cr, rect, stroke_rgba = None, fill_rgba = None, stroke_width = 1.0, shadow = None):
|
||||
"""draw a box (rectangle) with optional shadow
|
||||
|
||||
@param cr: cairo context
|
||||
@param rect: box rectangle as tuple (x,y,w,h)
|
||||
@param stroke_rgba: stroke color (set if not C{None})
|
||||
@param fill_rgba: fill color (set if not C{None})
|
||||
@param stroke_width: stroke width
|
||||
@param shadow: shadow thickness
|
||||
"""
|
||||
if (stroke_width <= 0): return
|
||||
draw_shadow(cr, rect, shadow)
|
||||
x, y, w, h = rect
|
||||
@ -199,8 +300,34 @@ def draw_box(cr, rect, stroke_rgba = None, fill_rgba = None, stroke_width = 1.0,
|
||||
cr.set_line_width(stroke_width)
|
||||
cr.stroke()
|
||||
|
||||
def draw_str(cr, text, rect, stretch = -1, stroke_rgba = None, align = (2,0), bbox = False,
|
||||
def draw_str(cr, text, rect, scaling = -1, stroke_rgba = None, align = (2,0), bbox = False,
|
||||
font = "Times", measure = None, shadow = None):
|
||||
"""draw text
|
||||
|
||||
@param cr: cairo context
|
||||
@param text: text string to be drawn
|
||||
@type scaling: int
|
||||
@param scaling: text scaling mode
|
||||
|
||||
- -1: auto select x-scaling or y-scaling (whatever fills the rect)
|
||||
- 0: no scaling
|
||||
- 1: x-scaling, scale so that text fills rect horizontally, preserving ratio
|
||||
- 2: y-scaling, scale so that text fills rect vertically, preserving ratio
|
||||
- 3: xy-scaling, stretch so that text fills rect completely, does not preserve ratio
|
||||
|
||||
@param stroke_rgba: stroke color
|
||||
@type align: tuple
|
||||
@param align: alignment mode as (int,int) tuple for horizontal/vertical alignment
|
||||
|
||||
- 0: left/top alignment
|
||||
- 1: right/bottom alignment
|
||||
- 2: center/middle alignment
|
||||
|
||||
@param bbox: draw text bounding box (for debugging)
|
||||
@param font: font name as string or (font,slant,weight) tuple
|
||||
@param measure: use this string for measurement instead of C{text}
|
||||
@param shadow: draw text shadow as tuple (dx,dy)
|
||||
"""
|
||||
x, y, w, h = rect
|
||||
cr.save()
|
||||
slant = weight = 0
|
||||
@ -216,13 +343,13 @@ def draw_str(cr, text, rect, stretch = -1, stroke_rgba = None, align = (2,0), bb
|
||||
mw = 5.
|
||||
if mh < 5:
|
||||
mh = 5.
|
||||
ratio, tratio = w*1.0/h, mw*1.0/mh;
|
||||
#ratio, tratio = w*1.0/h, mw*1.0/mh;
|
||||
xratio, yratio = mw*1.0/w, mh*1.0/h;
|
||||
if stretch < 0: stretch = 1 if xratio >= yratio else 2
|
||||
if stretch == 0: crs = (1,1)
|
||||
elif stretch == 1: crs = (1.0/xratio, 1.0/xratio)
|
||||
elif stretch == 2: crs = (1.0/yratio, 1.0/yratio)
|
||||
elif stretch == 3: crs = (1.0/xratio, 1.0/yratio)
|
||||
if scaling < 0: scaling = 1 if xratio >= yratio else 2
|
||||
if scaling == 0: crs = (1,1)
|
||||
elif scaling == 1: crs = (1.0/xratio, 1.0/xratio)
|
||||
elif scaling == 2: crs = (1.0/yratio, 1.0/yratio)
|
||||
elif scaling == 3: crs = (1.0/xratio, 1.0/yratio)
|
||||
te = cr.text_extents(text)
|
||||
tw,th = te[2], te[3]
|
||||
tw *= crs[0]
|
||||
|
12
style/bw.py
12
style/bw.py
@ -16,15 +16,17 @@
|
||||
|
||||
# --- style.bw ---
|
||||
|
||||
# day of week
|
||||
"""module defining the black-& white style"""
|
||||
|
||||
class dow:
|
||||
"""day of week style"""
|
||||
fg = (.33,.33,.33)
|
||||
frame_thickness = 0.1
|
||||
frame = (0.8,0.8,0.8)
|
||||
font = "Arial"
|
||||
|
||||
# day of month
|
||||
class dom:
|
||||
"""day of month style"""
|
||||
bg = (1,1,1)
|
||||
frame = (0.8,0.8,0.8)
|
||||
frame_thickness = 0.1
|
||||
@ -35,27 +37,33 @@ class dom:
|
||||
header_font = footer_font = "Arial"
|
||||
|
||||
class dom_weekend(dom):
|
||||
"""day of month style (weekend)"""
|
||||
bg = (0.95,0.95,0.95)
|
||||
fg = (0,0,0)
|
||||
font = ("Times New Roman", 0, 1)
|
||||
|
||||
class dom_holiday(dom):
|
||||
"""day of month (holiday, indicated by the OFF flag in the holiday file)"""
|
||||
fg = (0,0,0)
|
||||
bg = (0.95,0.95,0.95)
|
||||
header = (0,0,0)
|
||||
font = ("Times New Roman", 0, 1)
|
||||
|
||||
class dom_weekend_holiday(dom_holiday):
|
||||
"""day of month (weekend & holiday)"""
|
||||
fg = (0,0,0)
|
||||
bg = (0.95,0.95,0.95)
|
||||
|
||||
class dom_multi(dom_holiday):
|
||||
"""day of month (multi-day holiday)"""
|
||||
pass
|
||||
|
||||
class dom_weekend_multi(dom_weekend_holiday):
|
||||
"""day of month (weekend in multi-day holiday)"""
|
||||
pass
|
||||
|
||||
class month:
|
||||
"""month style"""
|
||||
font = ("Times New Roman", 0, 1)
|
||||
frame = (0,0,0)
|
||||
frame_thickness = 0.2
|
||||
|
@ -16,15 +16,17 @@
|
||||
|
||||
# --- style.default ---
|
||||
|
||||
# day of week
|
||||
"""module defining the default style"""
|
||||
|
||||
class dow:
|
||||
"""day of week style"""
|
||||
fg = (0,0,1)
|
||||
frame_thickness = 0.1
|
||||
frame = (0.75,0.75,0.75)
|
||||
font = "Arial"
|
||||
|
||||
# day of month
|
||||
class dom:
|
||||
"""day of month style"""
|
||||
bg = (1,1,1)
|
||||
frame = (0.75,0.75,0.75)
|
||||
frame_thickness = 0.1
|
||||
@ -35,25 +37,30 @@ class dom:
|
||||
header_font = footer_font = "Arial"
|
||||
|
||||
class dom_weekend(dom):
|
||||
"""day of month style (weekend)"""
|
||||
bg = (0.7,1,1)
|
||||
fg = (0,0,1)
|
||||
|
||||
# OFF flag
|
||||
class dom_holiday(dom):
|
||||
"""day of month (holiday, indicated by the OFF flag in the holiday file)"""
|
||||
bg = (0.7,1,1)
|
||||
fg = (1,0,0)
|
||||
header = (1,0,0)
|
||||
|
||||
class dom_weekend_holiday(dom_holiday):
|
||||
"""day of month (weekend & holiday)"""
|
||||
pass
|
||||
|
||||
class dom_multi(dom):
|
||||
"""day of month (multi-day holiday)"""
|
||||
bg = (0.7,1,1)
|
||||
|
||||
class dom_weekend_multi(dom_multi):
|
||||
"""day of month (weekend in multi-day holiday)"""
|
||||
pass
|
||||
|
||||
class month:
|
||||
"""month style"""
|
||||
font = ("Times New Roman", 0, 1)
|
||||
frame = (0,0,0)
|
||||
frame_thickness = 0.2
|
||||
|
@ -14,7 +14,9 @@
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see http://www.gnu.org/licenses/
|
||||
|
||||
# --- style.gfs (Greek Font Society fonts) ---
|
||||
# --- style.gfs ---
|
||||
|
||||
"""module defining Greek Font Society fonts for default style"""
|
||||
|
||||
import default
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
# --- style.rainbow ---
|
||||
|
||||
"""module defining rainbow color & gfs style"""
|
||||
|
||||
import gfs
|
||||
|
||||
|
@ -16,6 +16,7 @@
|
||||
|
||||
# --- style.rainbow ---
|
||||
|
||||
"""module defining rainbow color style"""
|
||||
|
||||
import default
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user