# -*- coding: utf-8 -*- # # Copyright (C) 2016 by Ihor E. Novikov # # 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 # the Free Software Foundation, either version 3 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program. If not, see <https://www.gnu.org/licenses/>. import cairo import math import wal from sk1 import config from sk1.document.ruler import VFONT, HFONT from uc2 import cms, uc2const CORNER = ((3, 1, 3, 16), (2, 2, 5, 2), (1, 13, 16, 13), (14, 12, 14, 15), (5, 11, 6, 10), (7, 9, 8, 8), (9, 7, 10, 6), (11, 5, 12, 4), (13, 3, 14, 2)) class PreviewCorner(wal.HPanel, wal.DrawableWidget): icon = None def __init__(self, parent): size = config.ruler_size wal.HPanel.__init__(self, parent) wal.DrawableWidget.__init__(self) self.pack((size, size)) self.set_bg(wal.WHITE) self.set_double_buffered() def paint(self): w, h = self.get_size() self.set_stroke() self.set_fill(cms.val_255(config.ruler_bg)) self.draw_rect(0, 0, w, h) stop_clr = cms.val_255(config.ruler_fg) + [255] start_clr = cms.val_255(config.ruler_fg) + [0] rect = (0, h - 1, w * 2, 1) self.gc_draw_linear_gradient(rect, start_clr, stop_clr) rect = (w - 1, 0, 1, h * 2) self.gc_draw_linear_gradient(rect, start_clr, stop_clr, True) shift = (w - 19) / 2 + 1 self.set_stroke(cms.val_255(config.ruler_fg)) for x0, y0, x1, y1 in CORNER: self.draw_line(x0 + shift, y0 + shift, x1 + shift, y1 + shift) class PreviewRuler(wal.HPanel, wal.DrawableWidget): horizontal = True units = uc2const.UNIT_MM canvas = None surface = None ctx = None width = 0 height = 0 def __init__(self, parent, canvas, units=uc2const.UNIT_MM, horizontal=True): self.canvas = canvas self.units = units self.horizontal = horizontal size = config.ruler_size wal.HPanel.__init__(self, parent) wal.DrawableWidget.__init__(self) self.pack((size, size)) self.set_bg(wal.WHITE) self.set_double_buffered() def calc_ruler(self): canvas = self.canvas w, h = self.canvas.get_page_size() x = y = 0 udx = udy = uc2const.unit_dict[self.units] x0, y0 = canvas.point_doc_to_win([-w / 2.0 + x, -h / 2.0 + y]) dx = udx * canvas.zoom dy = udy * canvas.zoom sdist = config.snap_distance i = 0.0 while dx < sdist + 3: i = i + 0.5 dx = dx * 10.0 * i if dx / 2.0 > sdist + 3 and dx / 2.0 > udx * canvas.zoom: dx = dx / 2.0 i = 0.0 while dy < sdist + 3: i = i + 0.5 dy = dy * 10.0 * i if dy / 2.0 > sdist + 3 and dy / 2.0 > udy * canvas.zoom: dy = dy / 2.0 sx = (x0 / dx - math.floor(x0 / dx)) * dx sy = (y0 / dy - math.floor(y0 / dy)) * dy return x0, y0, dx, dy, sx, sy def get_ticks(self): canvas = self.canvas pw, ph = self.canvas.get_page_size() unit = uc2const.unit_dict[self.units] w, h = self.get_size() x0, y0, dx, dy, sx, sy = self.calc_ruler() small_ticks = [] text_ticks = [] if self.horizontal: i = -1 pos = 0 while pos < w: pos = sx + i * dx small_ticks.append(sx + i * dx) if dx > 10: small_ticks.append(pos + dx * .5) i += 1 coef = round(50.0 / dx) if not coef: coef = 1.0 dxt = dx * coef sxt = (x0 / dxt - math.floor(x0 / dxt)) * dxt float_flag = False unit_dx = dxt / (unit * canvas.zoom) if unit_dx < 1.0: float_flag = True i = -1 pos = 0 shift = pw / 2.0 while pos < w: pos = sxt + i * dxt doc_pos = canvas.point_win_to_doc((pos, 0))[0] + shift doc_pos *= uc2const.point_dict[self.units] if float_flag: txt = str(round(doc_pos, 4)) if not doc_pos: txt = '0' else: txt = str(int(round(doc_pos))) text_ticks.append((sxt + i * dxt, txt)) i += 1 else: i = -1 pos = 0 while pos < h: pos = sy + i * dy small_ticks.append(sy + i * dy) if dy > 10: small_ticks.append(pos + dy * .5) i += 1 coef = round(50.0 / dy) if not coef: coef = 1.0 dyt = dy * coef syt = (y0 / dyt - math.floor(y0 / dyt)) * dyt float_flag = False unit_dy = dyt / (unit * canvas.zoom) if unit_dy < 1.0: float_flag = True i = -1 pos = 0 shift = ph / 2.0 while pos < h: pos = syt + i * dyt doc_pos = canvas.point_win_to_doc((0, pos))[1] + shift doc_pos *= uc2const.point_dict[self.units] if float_flag: txt = str(round(doc_pos, 4)) if not doc_pos: txt = '0' else: txt = str(int(round(doc_pos))) text_ticks.append((syt + i * dyt, txt)) i += 1 return small_ticks, text_ticks def paint(self): w, h = self.get_size() if self.surface is None or self.width != w or self.height != h: self.surface = cairo.ImageSurface(cairo.FORMAT_RGB24, w, h) self.width, self.height = w, h self.ctx = cairo.Context(self.surface) self.ctx.set_matrix(cairo.Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)) self.ctx.set_source_rgb(*config.ruler_bg) self.ctx.paint() self.ctx.set_antialias(cairo.ANTIALIAS_NONE) self.ctx.set_line_width(1.0) self.ctx.set_dash([]) self.ctx.set_source_rgb(*config.ruler_fg) if self.horizontal: self.hrender(w, h) else: self.vrender(w, h) self.draw_bitmap(wal.copy_surface_to_bitmap(self.surface)) def hrender(self, w, h): self.ctx.move_to(0, h) self.ctx.line_to(w, h) small_ticks, text_ticks = self.get_ticks() for item in small_ticks: self.ctx.move_to(item, h - config.ruler_small_tick) self.ctx.line_to(item, h - 1) for pos, txt in text_ticks: self.ctx.move_to(pos, h - config.ruler_large_tick) self.ctx.line_to(pos, h - 1) self.ctx.stroke() vshift = config.ruler_text_vshift hshift = config.ruler_text_hshift for pos, txt in text_ticks: for character in txt: data = HFONT[character] position = int(pos) + hshift self.ctx.set_source_surface(data[1], position, vshift) self.ctx.paint() pos += data[0] def vrender(self, w, h): self.ctx.move_to(w, 0) self.ctx.line_to(w, h) small_ticks, text_ticks = self.get_ticks() for item in small_ticks: self.ctx.move_to(w - config.ruler_small_tick, item) self.ctx.line_to(w - 1, item) for item, txt in text_ticks: self.ctx.move_to(w - config.ruler_large_tick, item) self.ctx.line_to(w - 1, item) self.ctx.stroke() vshift = config.ruler_text_vshift hshift = config.ruler_text_hshift for pos, txt in text_ticks: for character in txt: data = VFONT[character] position = int(pos) - data[0] - hshift self.ctx.set_source_surface(data[1], vshift, position) self.ctx.paint() pos -= data[0]