def __init__(self, parent): gtk.DrawingArea.__init__(self) self.mw = parent self.presenter = parent.presenter self.eventloop = self.presenter.eventloop self.app = self.presenter.app self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color("#ffffff")) self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.SCROLL_MASK) self.connect('button_press_event', self.mousePressEvent) self.connect('motion_notify_event', self.mouseMoveEvent) self.connect('button_release_event', self.mouseReleaseEvent) self.connect('scroll-event', self.wheelEvent) self.connect('expose_event', self.repaint) self.trafo = [1.0, 0.0, 0.0, 1.0, 0.0 , 0.0] self.mw.h_adj.connect('value_changed', self.hscroll) self.mw.v_adj.connect('value_changed', self.vscroll) self.doc = self.presenter.model self.renderer = CairoRenderer(self) self.my_change = False self.ctrls = self.init_controllers() self.eventloop.connect(self.eventloop.DOC_MODIFIED, self.repaint) self.eventloop.connect(self.eventloop.SELECTION_CHANGED, self.selection_repaint)
def __init__(self, filename, width, height): self.filename = filename self.renderer = CairoRenderer(width, height)
class RenderInstance: def __init__(self, filename, width, height): self.filename = filename self.renderer = CairoRenderer(width, height) def draw_rect(self, id: str = "", x: float = 0, y: float = 0, w: float = 100, h: float = 100, color: Color = BLACK, stroke: bool = False, fill: bool = True, radius: float = 0) -> None: self.renderer.set_color(*color) self.renderer.plot_rectangle(x, y, w, h, radius) if stroke: self.renderer.stroke() if fill: self.renderer.fill() def draw_image(self, id: str = "", x: float = 0, y: float = 0, w: float = 100, h: float = 100, file: str = "") -> None: try: width, height = self.renderer.set_image_buffer(file) except FileNotFoundError: warnings.warn("Could not load file: {}".format(file)) return with self.renderer.translate(x, y): with self.renderer.scale(w / width, h / height): self.renderer.paint_image() def draw_text( self, id: str = None, x: float = 0, y: float = 0, w: float = -1.0, # By default, DON'T restrict w/h h: float = -1.0, text: str = "", color: Color = BLACK, font_name: str = "Ubuntu", font_size: int = 16, align: str = "left", line_spacing: int = 0, justify: bool = False, debug: bool = False, ): """Draw the configured text widget on the canvas. """ # First, draw a debug box (if requested) if debug: self.draw_rect(x=x, y=y, w=w, h=h, color=Color(0.0, 1.0, 1.0, 1.0), stroke=True, fill=False) # Process the inputs text = text.replace("\\n", "\n") alignment = { "left": TextAlignment.Left, "center": TextAlignment.Center, "right": TextAlignment.Right, }[align] # TODO: Validate on the parser # Configure the text self.renderer.set_font(font_name, font_size) self.renderer.configure_text_layout( width=w, height=h, line_spacing=line_spacing, alignment=alignment, justify=justify, ) self.renderer.set_color(*color) self.renderer.set_text(text) # Draw the text with self.renderer.translate(x, y): self.renderer.paint_text() def draw_table( self, id: str = None, data: [] = None, x: float = 0, y: float = 0, w: float = 100, padding_x: int = 2, padding_y: int = 2, color: Color = BLACK, border_color: Color = BLACK, font_name: str = "Ubuntu", font_size: int = 16, ): # Load the data if not data: return data = json.loads(data) # TODO: Assert the table data is rectangular # Set the font self.renderer.set_font(font_name, font_size) # First pass to generate the column widths widths = [0] * len(data[0]) for row in data: for i, text in enumerate(row): text = text.replace("\\n", "\n") self.renderer.set_text(text) self.renderer.configure_text_layout(width=w, height=-MAX_TABLE_LINES) this_w, _ = self.renderer.get_text_size() this_w += padding_x * 2 widths[i] = max(this_w, widths[i]) # Make the widths smaller until it fits widths = _scale_column_widths(widths, w) # Second pass to do rendering cursor_y = 0 for i, row in enumerate(data): cursor_x = 0 # calculate the height of this row height = 0 for j, text in enumerate(row): self.renderer.set_text(text) self.renderer.configure_text_layout(width=widths[j], height=-MAX_TABLE_LINES) _, h = self.renderer.get_text_size() height = max(height, h) height += padding_y * 2 for j, text in enumerate(row): # render the table cell self.draw_rect(x=x + cursor_x, y=y + cursor_y, w=widths[j], h=height, stroke=True, fill=False, color=border_color) # then render the text inside it self.draw_text(text=text, x=x + cursor_x + padding_x, y=y + cursor_y + padding_y, w=widths[j], h=height, color=color, font_name=font_name, font_size=font_size) cursor_x += widths[j] cursor_y += height def save(self): self.renderer.save(self.filename)
class RenderInstance: def __init__(self, filename, width, height): self.filename = filename self.renderer = CairoRenderer(width, height) def draw_rect(self, id: str="", x: float=0, y: float=0, w: float=100, h: float=100, color: Color=BLACK, stroke: bool=False, fill: bool=True, radius: float=0) -> None: self.renderer.set_color(*color) self.renderer.plot_rectangle(x, y, w, h, radius) if stroke: self.renderer.stroke() if fill: self.renderer.fill() def draw_image(self, id: str="", x: float=0, y: float=0, w: float=100, h: float=100, file: str="") -> None: try: width, height = self.renderer.set_image_buffer(file) except FileNotFoundError: warnings.warn("Could not load file: {}".format(file)) return with self.renderer.translate(x, y): with self.renderer.scale(w/width, h/height): self.renderer.paint_image() def draw_text(self, id: str=None, x: float=0, y: float=0, w: float=-1.0, # By default, DON'T restrict w/h h: float=-1.0, text: str="", color: Color=BLACK, font_name: str="Ubuntu", font_size: int=16, align: str="left", line_spacing: int=0, justify: bool=False, debug: bool=False, ): """Draw the configured text widget on the canvas. """ # First, draw a debug box (if requested) if debug: self.draw_rect(x=x, y=y, w=w, h=h, color=Color(0.0, 1.0, 1.0, 1.0), stroke=True, fill=False) # Process the inputs text = text.replace("\\n", "\n") alignment = { "left": TextAlignment.Left, "center": TextAlignment.Center, "right": TextAlignment.Right, }[align] # TODO: Validate on the parser # Configure the text self.renderer.set_font(font_name, font_size) self.renderer.configure_text_layout( width=w, height=h, line_spacing=line_spacing, alignment=alignment, justify=justify, ) self.renderer.set_color(*color) self.renderer.set_text(text) # Draw the text with self.renderer.translate(x, y): self.renderer.paint_text() def draw_table(self, id: str=None, data: []=None, x: float=0, y: float=0, w: float=100, padding_x: int=2, padding_y: int=2, color: Color=BLACK, border_color: Color=BLACK, font_name: str="Ubuntu", font_size: int=16, ): # Load the data if not data: return data = json.loads(data) # TODO: Assert the table data is rectangular # Set the font self.renderer.set_font(font_name, font_size) # First pass to generate the column widths widths = [0] * len(data[0]) for row in data: for i, text in enumerate(row): text = text.replace("\\n", "\n") self.renderer.set_text(text) self.renderer.configure_text_layout( width=w, height=-MAX_TABLE_LINES) this_w, _ = self.renderer.get_text_size() this_w += padding_x * 2 widths[i] = max(this_w, widths[i]) # Make the widths smaller until it fits widths = _scale_column_widths(widths, w) # Second pass to do rendering cursor_y = 0 for i, row in enumerate(data): cursor_x = 0 # calculate the height of this row height = 0 for j, text in enumerate(row): self.renderer.set_text(text) self.renderer.configure_text_layout( width=widths[j], height=-MAX_TABLE_LINES) _, h = self.renderer.get_text_size() height = max(height, h) height += padding_y * 2 for j, text in enumerate(row): # render the table cell self.draw_rect(x=x + cursor_x, y=y + cursor_y, w=widths[j], h=height, stroke=True, fill=False, color=border_color) # then render the text inside it self.draw_text(text=text, x=x + cursor_x + padding_x, y=y + cursor_y + padding_y, w=widths[j], h=height, color=color, font_name=font_name, font_size=font_size) cursor_x += widths[j] cursor_y += height def save(self): self.renderer.save(self.filename)
class AppCanvas(gtk.DrawingArea): mw = None matrix = None trafo = [] zoom = 1.0 width = 0 height = 0 mode = None previous_mode = None controller = None ctrls = None orig_cursor = None current_cursor = None resize_marker = 0 stroke_view = False draft_view = False def __init__(self, parent): gtk.DrawingArea.__init__(self) self.mw = parent self.presenter = parent.presenter self.eventloop = self.presenter.eventloop self.app = self.presenter.app self.modify_bg(gtk.STATE_NORMAL, gtk.gdk.Color("#ffffff")) self.add_events(gtk.gdk.BUTTON_PRESS_MASK | gtk.gdk.POINTER_MOTION_MASK | gtk.gdk.BUTTON_RELEASE_MASK | gtk.gdk.SCROLL_MASK) self.connect('button_press_event', self.mousePressEvent) self.connect('motion_notify_event', self.mouseMoveEvent) self.connect('button_release_event', self.mouseReleaseEvent) self.connect('scroll-event', self.wheelEvent) self.connect('expose_event', self.repaint) self.trafo = [1.0, 0.0, 0.0, 1.0, 0.0 , 0.0] self.mw.h_adj.connect('value_changed', self.hscroll) self.mw.v_adj.connect('value_changed', self.vscroll) self.doc = self.presenter.model self.renderer = CairoRenderer(self) self.my_change = False self.ctrls = self.init_controllers() self.eventloop.connect(self.eventloop.DOC_MODIFIED, self.repaint) self.eventloop.connect(self.eventloop.SELECTION_CHANGED, self.selection_repaint) def init_controllers(self): dummy = controllers.AbstractController(self, self.presenter) ctrls = { modes.SELECT_MODE: controllers.SelectController(self, self.presenter), modes.SHAPER_MODE: dummy, modes.ZOOM_MODE: controllers.ZoomController(self, self.presenter), modes.FLEUR_MODE: controllers.FleurController(self, self.presenter), modes.LINE_MODE: dummy, modes.CURVE_MODE: dummy, modes.RECT_MODE: creators.RectangleCreator(self, self.presenter), modes.ELLIPSE_MODE: dummy, modes.TEXT_MODE: dummy, modes.POLYGON_MODE: dummy, modes.MOVE_MODE: controllers.MoveController(self, self.presenter), modes.RESIZE_MODE: controllers.TransformController(self, self.presenter), } return ctrls def set_mode(self, mode=modes.SELECT_MODE): if not mode == self.mode: self.mode = mode # self.set_canvas_cursor(mode) self.controller = self.ctrls[mode] self.controller.set_cursor() events.emit(events.MODE_CHANGED, mode) def set_temp_mode(self, mode=modes.SELECT_MODE): if not mode == self.mode: self.previous_mode = self.mode self.mode = mode # self.set_canvas_cursor(mode) self.controller = self.ctrls[mode] self.controller.set_cursor() def restore_mode(self): if not self.previous_mode is None: self.set_mode(self.previous_mode) self.previous_mode = None def set_canvas_cursor(self, mode): self.current_cursor = self.app.cursors[mode] self.window.set_cursor(self.current_cursor) def set_temp_cursor(self, cursor): self.orig_cursor = self.app.cursors[self.mode] self.current_cursor = cursor self.window.set_cursor(cursor) def restore_cursor(self): if not self.orig_cursor is None: self.window.set_cursor(self.orig_cursor) self.current_cursor = self.orig_cursor self.orig_cursor = None def vscroll(self, *args): if self.my_change: self.my_change = False else: m11, m12, m21, m22, dx, dy = self.trafo val = float(self.mw.v_adj.get_value()) * m11 dy = -val self.trafo = [m11, m12, m21, m22, dx, dy] self.matrix = cairo.Matrix(m11, m12, m21, m22, dx, dy) self.force_redraw() def hscroll(self, *args): m11, m12, m21, m22, dx, dy = self.trafo val = float(self.mw.h_adj.get_value()) * m11 dx = -val self.trafo = [m11, m12, m21, m22, dx, dy] self.matrix = cairo.Matrix(m11, m12, m21, m22, dx, dy) self.force_redraw() def update_scrolls(self): x, y = self.win_to_doc() m11 = self.trafo[0] self.mw.h_adj.set_lower(-WORKSPACE_WIDTH / 2.0) self.mw.h_adj.set_upper(WORKSPACE_WIDTH / 2.0) self.mw.h_adj.set_page_size(self.width / m11) self.mw.h_adj.set_step_increment(self.width / (m11 * 10.0)) self.my_change = True self.mw.h_adj.set_value(x) self.mw.v_adj.set_lower(-WORKSPACE_HEIGHT / 2.0) self.mw.v_adj.set_upper(WORKSPACE_HEIGHT / 2.0) self.mw.v_adj.set_page_size(self.height / m11) self.mw.v_adj.set_step_increment(self.height / (m11 * 10.0)) self.my_change = True self.mw.v_adj.set_value(-y) def _keep_center(self): x, y, w, h = self.allocation w = float(w) h = float(h) if not w == self.width or not h == self.height: _dx = (w - self.width) / 2.0 _dy = (h - self.height) / 2.0 m11, m12, m21, m22, dx, dy = self.trafo dx += _dx dy += _dy self.trafo = [m11, m12, m21, m22, dx, dy] self.matrix = cairo.Matrix(m11, m12, m21, m22, dx, dy) self.width = w self.height = h self.update_scrolls() def _set_center(self, center): x, y = center _dx = self.width / 2.0 - x _dy = self.height / 2.0 - y m11, m12, m21, m22, dx, dy = self.trafo dx += _dx dy += _dy self.trafo = [m11, m12, m21, m22, dx, dy] self.matrix = cairo.Matrix(m11, m12, m21, m22, dx, dy) self.update_scrolls() def doc_to_win(self, point=[0.0, 0.0]): x, y = point m11, m12, m21, m22, dx, dy = self.trafo x_new = m11 * x + dx y_new = m22 * y + dy return [x_new, y_new] def win_to_doc(self, point=[0, 0]): x, y = point x = float(x) y = float(y) m11, m12, m21, m22, dx, dy = self.trafo x_new = (x - dx) / m11 y_new = (y - dy) / m22 return [x_new, y_new] def _fit_to_page(self): width, height = self.presenter.get_page_size() x, y, w, h = self.allocation w = float(w) h = float(h) self.width = w self.height = h zoom = min(w / width, h / height) * PAGEFIT dx = w / 2.0 dy = h / 2.0 self.trafo = [zoom, 0, 0, -zoom, dx, dy] self.matrix = cairo.Matrix(zoom, 0, 0, -zoom, dx, dy) self.zoom = zoom self.update_scrolls() def zoom_fit_to_page(self): self._fit_to_page() self.force_redraw() def _zoom(self, dzoom=1.0): m11, m12, m21, m22, dx, dy = self.trafo m11 *= dzoom _dx = (self.width * dzoom - self.width) / 2.0 _dy = (self.height * dzoom - self.height) / 2.0 dx = dx * dzoom - _dx dy = dy * dzoom - _dy self.trafo = [m11, m12, m21, -m11, dx, dy] self.matrix = cairo.Matrix(m11, m12, m21, -m11, dx, dy) self.zoom = m11 self.update_scrolls() self.force_redraw() def zoom_in(self): self._zoom(ZOOM_IN) def zoom_out(self): self._zoom(ZOOM_OUT) def zoom_100(self): self._zoom(1.0 / self.zoom) def zoom_at_point(self, point, zoom): self._set_center(point) self._zoom(zoom) def zoom_to_rectangle(self, start, end): x, y, w, h = self.allocation w = float(w) h = float(h) self.width = w self.height = h width = abs(end[0] - start[0]) height = abs(end[1] - start[1]) zoom = min(w / width, h / height) center = [start[0] + (end[0] - start[0]) / 2, start[1] + (end[1] - start[1]) / 2] self._set_center(center) self._zoom(zoom) def zoom_selected(self): x0, y0, x1, y1 = self.presenter.selection.frame start = self.doc_to_win([x0, y0]) end = self.doc_to_win([x1, y1]) self.zoom_to_rectangle(start, end) def select_at_point(self, point, flag=False): point = self.win_to_doc(point) self.presenter.selection.select_at_point(point, flag) def select_by_rect(self, start, end, flag=False): start = self.win_to_doc(start) end = self.win_to_doc(end) rect = start + end rect = normalize_bbox(rect) self.presenter.selection.select_by_rect(rect, flag) def force_redraw(self): self.queue_draw() self.eventloop.emit(self.eventloop.VIEW_CHANGED) def repaint(self, *args): if self.matrix is None: self.zoom_fit_to_page() self.set_mode(modes.SELECT_MODE) self._keep_center() self.renderer.paint_document() def selection_repaint(self, *args): self.renderer.paint_selection() #==============EVENT CONTROLLING========================== def mouseDoubleClickEvent(self, widget, event): pass def mouseMoveEvent(self, widget, event): self.controller.mouse_move(event) def mousePressEvent(self, widget, event): self.controller.set_cursor() self.controller.mouse_down(event) def mouseReleaseEvent(self, widget, event): self.controller.mouse_up(event) def wheelEvent(self, widget, event): self.controller.wheel(event) def keyPressEvent(self, widget, event): pass def keyReleaseEvent(self, widget, event): pass