Package layouts :: Module sparse
[hide private]
[frames] | no frames]

Source Code for Module layouts.sparse

  1  # -*- coding: utf-8 -*- 
  2  #    callirhoe - high quality calendar rendering 
  3  #    Copyright (C) 2012 George M. Tzoumas 
  4   
  5  #    Sparse Layout Module 
  6  #    Copyright (C) 2013 Neels Hofmeyr 
  7   
  8  #    This program is free software: you can redistribute it and/or modify 
  9  #    it under the terms of the GNU General Public License as published by 
 10  #    the Free Software Foundation, either version 3 of the License, or 
 11  #    (at your option) any later version. 
 12  # 
 13  #    This program is distributed in the hope that it will be useful, 
 14  #    but WITHOUT ANY WARRANTY; without even the implied warranty of 
 15  #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 16  #    GNU General Public License for more details. 
 17  # 
 18  #    You should have received a copy of the GNU General Public License 
 19  #    along with this program.  If not, see http://www.gnu.org/licenses/ 
 20   
 21  """sparse layout""" 
 22   
 23  from lib.xcairo import * 
 24  from lib.geom import * 
 25  import calendar 
 26  import optparse 
 27  import sys 
 28  from datetime import date, timedelta 
 29   
 30  import _base 
 31   
32 -def get_parser(layout_name):
33 """get the parser object for the layout command-line arguments 34 35 @param layout_name: corresponding python module (.py file) 36 @rtype: optparse.OptionParser 37 """ 38 lname = layout_name.split(".")[1] 39 parser = optparse.OptionParser(usage="%prog (...) --layout " + lname + " [options] (...)",add_help_option=False) 40 parser.add_option("--rows", type="int", default=1, help="force grid rows [%default]") 41 parser.add_option("--cols", type="int", default=3, 42 help="force grid columns [%default]; if ROWS and COLS are both non-zero, " 43 "calendar will span multiple pages as needed; if one value is zero, it " 44 "will be computed automatically in order to fill exactly 1 page") 45 parser.add_option("--grid-order", choices=["row","column"],default="row", 46 help="either `row' or `column' to set grid placing order row-wise or column-wise [%default]") 47 parser.add_option("--z-order", choices=["auto", "increasing", "decreasing"], default="auto", 48 help="either `increasing' or `decreasing' to set whether next month (in grid order) " 49 "lies above or below the previously drawn month; this affects shadow casting, " 50 "since rendering is always performed in increasing z-order; specifying `auto' " 51 "selects increasing order if and only if sloppy boxes are enabled [%default]") 52 parser.add_option("--month-with-year", action="store_true", default=False, 53 help="displays year together with month name, e.g. January 1980; suppresses year from footer line") 54 parser.add_option("--no-footer", action="store_true", default=False, 55 help="disable footer line (with year and rendered-by message)") 56 parser.add_option("--symmetric", action="store_true", default=False, 57 help="force symmetric mode (equivalent to --geom-var=month.symmetric=1). " 58 "In symmetric mode, day cells are equally sized and all month boxes contain " 59 "the same number of (possibly empty) cells, independently of how many days or " 60 "weeks per month. In asymmetric mode, empty rows are eliminated, by slightly " 61 "resizing day cells, in order to have uniform month boxes.") 62 parser.add_option("--padding", type="float", default=None, 63 help="set month box padding (equivalent to --geom-var=month.padding=PADDING)") 64 parser.add_option("--no-shadow", action="store_true", default=None, 65 help="disable box shadows") 66 parser.add_option("--opaque", action="store_true", default=False, 67 help="make background opaque (white fill)") 68 parser.add_option("--swap-colors", action="store_true", default=None, 69 help="swap month colors for even/odd years") 70 return parser
71 72 parser = get_parser(__name__) 73
74 -def _draw_day_cell(cr, rect, day, header, footer, theme, show_day_name, text_height=None):
75 ds,G,L = theme 76 year, month, day_of_month, day_of_week = day 77 draw_box(cr, rect, ds.bg, ds.bg, mm_to_dots(ds.frame_thickness)) 78 79 if day_of_month > 1: 80 x, y, w, h = rect 81 draw_line(cr, (x, y, w, 0), ds.frame, mm_to_dots(ds.frame_thickness)) 82 83 if (text_height is not None) and (text_height > 0): 84 x, y, w, h = rect 85 h_diff = h - text_height 86 if h_diff > 0: 87 y += h_diff / 2 88 h = text_height 89 rect = (x, y, w, h) 90 91 x, y, w, h = rect 92 ww = h 93 Rleft = (x + 0.1 * h, y + 0.2 * h, ww - 0.2 * h, .6 * h) 94 Rmiddle = (x + h, y, ww, h) 95 Rmiddle_top = (x + h + 0.1 * h, y + 0.2 * h, ww, .18 * h) 96 bottom_h = .8 * h 97 Rmiddle_bottom = (x + h + 0.1 * h, y + h - bottom_h, ww, bottom_h - 0.2 * h) 98 #Rmiddle_top = rect_rel_scale(Rmiddle_top, .8, 0.6) 99 #Rmiddle_bottom = rect_rel_scale(Rmiddle, .8, 0.6) 100 Rright_header = (x + 2*h, y + 0.1 * h, w - 2 * ww - 0.2 * ww, 0.28 * h) 101 Rright_footer = (x + 2*h, y + 0.6 * h, w - 2 * ww - 0.2 * ww, 0.28 * h) 102 x, y, w, h = Rmiddle_bottom 103 hh = h 104 h = float(h) * 0.6 105 y += float(hh) - h 106 Rmiddle_bottom = (x, y, w, h) 107 valign = 0 if show_day_name else 2 108 # draw day of month (number) 109 draw_str(cr, text = str(day_of_month), rect = Rleft, scaling = -1, stroke_rgba = ds.fg, 110 align = (1,valign), font = ds.font, measure = "88") 111 # draw name of day 112 if show_day_name: 113 draw_str(cr, text = L.day_name[day_of_week], rect = Rmiddle_bottom, 114 scaling = -1, stroke_rgba = ds.fg, align = (0,valign), 115 font = ds.font, measure = "Mo") 116 # week number 117 if day_of_week == 0 or (day_of_month == 1 and month == 1): 118 week_nr = date(year, month, day_of_month).isocalendar()[1] 119 draw_str(cr, text = "%s%d" % (L.week_of_year_prefix, week_nr), rect = Rmiddle_top, 120 scaling = -1, stroke_rgba = ds.fg, align = (0,valign), 121 font = ds.header_font, measure = "W88") 122 123 if header: 124 draw_str(cr, text = header, rect = Rright_header, scaling = -1, 125 stroke_rgba = ds.header, align = (1,1), font = ds.header_font, 126 measure='MgMgMgMgMgMgMgMgMg') 127 if footer: 128 draw_str(cr, text = footer, rect = Rright_footer, scaling = -1, 129 stroke_rgba = ds.footer, align = (1,1), font = ds.header_font, 130 measure='MgMgMgMgMgMgMgMgMg')
131
132 -class CalendarRenderer(_base.CalendarRenderer):
133 """sparse layout class"""
134 - def _draw_month(self, cr, rect, month, year):
135 S,G,L = self.Theme 136 make_sloppy_rect(cr, rect, G.month.sloppy_dx, G.month.sloppy_dy, G.month.sloppy_rot) 137 138 day, span = calendar.monthrange(year, month) 139 wmeasure = 'A'*max(map(len,L.day_name)) 140 mmeasure = 'A'*max(map(len,L.month_name)) 141 142 rows = 31 if G.month.symmetric else span 143 grid = VLayout(rect_from_origin(rect), 32) # title bar always symmetric 144 dom_grid = VLayout(grid.item_span(31,1), rows) 145 146 # determine text height 147 tmp_grid = VLayout(grid.item_span(31,1), 31) 148 text_height = tmp_grid.item(0)[3] 149 150 # draw box shadow 151 if S.month.box_shadow: 152 f = S.month.box_shadow_size 153 shad = (f,-f) if G.landscape else (f,f) 154 draw_shadow(cr, rect_from_origin(rect), shad) 155 156 # draw day cells 157 for dom in range(1,span+1): 158 R = dom_grid.item(dom-1) 159 holiday_tuple = self.holiday_provider(year, month, dom, day) 160 day_style = holiday_tuple[2] 161 header = holiday_tuple[0] 162 footer = holiday_tuple[1] 163 _draw_day_cell(cr, rect = R, day = (year, month, dom, day), 164 header = header, footer = footer, 165 theme = (day_style, G.dom, L), show_day_name = True, 166 text_height = text_height) 167 168 day = (day + 1) % 7 169 170 # draw month title (name) 171 mcolor = S.month.color_map_bg[year%2][month] 172 mcolor_fg = S.month.color_map_fg[year%2][month] 173 R_mb = grid.item(0) 174 R_text = rect_rel_scale(R_mb, 1, 0.5) 175 mshad = None 176 if S.month.text_shadow: 177 f = S.month.text_shadow_size 178 mshad = (f,-f) if G.landscape else (f,f) 179 draw_str(cr, text = L.month_name[month], rect = R_text, scaling = -1, stroke_rgba = mcolor_fg, 180 align = (2,0), font = S.month.font, measure = mmeasure, shadow = mshad) 181 cr.restore()
182