class PatternSample(PyWidget): def __init__(self, master=None, **kw): apply(PyWidget.__init__, (self, master), kw) self.gc_initialized = 0 self.gc = GraphicsDevice() self.pattern = EmptyPattern self.properties = PropertyStack() self.properties.AddStyle(EmptyLineStyle) self.properties.SetProperty(fill_pattern = self.pattern) self.gc.SetProperties(self.properties) self.fill_rect = None def MapMethod(self): self.fill_rect = Rect(0, 0, self.tkwin.width, self.tkwin.height) if not self.gc_initialized: self.init_gc() self.gc_initialized = 1 def init_gc(self): self.gc.init_gc(self.tkwin) self.compute_trafo() def compute_trafo(self): height = self.tkwin.height doc_to_win = Trafo(1, 0, 0, -1, 0, height) win_to_doc = doc_to_win.inverse() self.gc.SetViewportTransform(1.0, doc_to_win, win_to_doc) self.fill_rect = Rect(0, 0, self.tkwin.width, self.tkwin.height) self.gc.SetProperties(self.properties, self.fill_rect) def SetPattern(self, pattern): if pattern != self.pattern: self.pattern = pattern self.UpdateWhenIdle() self.properties.SetProperty(fill_pattern = pattern) self.gc.SetProperties(self.properties, self.fill_rect) def RedrawMethod(self, region = None): win = self.tkwin self.gc.StartDblBuffer() self.gc.SetFillColor(StandardColors.white) self.gc.FillRectangle(0, 0, win.width, win.height) if self.properties.HasFill(): self.gc.Rectangle(Trafo(win.width, 0, 0, win.height, 0, 0)) else: self.gc.SetLineColor(StandardColors.black) self.gc.DrawLineXY(0, win.height, win.width, 0) self.gc.EndDblBuffer() def ResizedMethod(self, width, height): self.gc.WindowResized(width, height) self.UpdateWhenIdle() self.compute_trafo()
class PaletteWidget(PyWidget, Publisher): def __init__(self, master=None, palette=None, cell_size=16, **kw): if not kw.has_key('height'): kw['height'] = cell_size apply(PyWidget.__init__, (self, master), kw) self.cell_size = cell_size self.num_cells = 0 self.gc_initialized = 0 self.gc = GraphicsDevice() self.gc.SetViewportTransform(1.0, Identity, Identity) self.start_idx = 0 self.palette = None if palette is None: palette = RGBPalette() self.SetPalette(palette) self.dragging = 0 self.bind('<ButtonPress-1>', self.press_1) self.bind('<Motion>', self.move_1) self.bind('<ButtonRelease-1>', self.release_1) self.bind('<ButtonRelease-3>', self.apply_color_2) def DestroyMethod(self): self.palette.Unsubscribe(CHANGED, self.palette_changed) Publisher.Destroy(self) def compute_num_cells(self): self.num_cells = self.tkwin.width / self.cell_size + 1 def MapMethod(self): self.compute_num_cells() self.issue(VIEW) if not self.gc_initialized: self.init_gc() self.gc_initialized = 1 def init_gc(self): self.gc.init_gc(self.tkwin) def get_color(self, x, y): if 0 <= x < self.tkwin.width and 0 <= y < self.tkwin.height: i = self.start_idx + x / self.cell_size if i < len(self.palette): return apply(CreateRGBColor, self.palette.GetRGB(i)) def release_1(self, event): try: if self.dragging: self.drop_color(event) else: self.apply_color_1(event) finally: self.dragging = 0 def drop_color(self, event): self['cursor'] = self.drag_old_cursor w = self.winfo_containing(event.x_root, event.y_root) while w and w != self: if __debug__: pdebug('DND', 'trying to drop on', w) try: accepts = w.accept_drop except AttributeError: accepts = () if DROP_COLOR in accepts: x = event.x_root - w.winfo_rootx() y = event.y_root - w.winfo_rooty() w.DropAt(x, y, DROP_COLOR, self.drag_start) break if w != w.winfo_toplevel(): parent = self.tk.call('winfo', 'parent', w._w) w = self.nametowidget(parent) else: break def apply_color_1(self, event): c = self.get_color(event.x, event.y) if c: self.issue(COLOR1, c) def apply_color_2(self, event): c = self.get_color(event.x, event.y) if c: self.issue(COLOR2, c) drag_start = (0, 0, 0) def press_1(self, event): self.drag_start = self.get_color(event.x, event.y) def move_1(self, event): if event.state & X.Button1Mask: if not self.dragging: self.dragging = 1 self.drag_old_cursor = self['cursor'] self['cursor'] = CurDragColor w = self.winfo_containing(event.x_root, event.y_root) def Palette(self): return self.palette def SetPalette(self, palette): if self.palette is not None: self.palette.Unsubscribe(CHANGED, self.palette_changed) self.palette = palette self.palette.Subscribe(CHANGED, self.palette_changed) self.palette_changed() def palette_changed(self): self.compute_num_cells() self.normalize_start() self.issue(VIEW) self.UpdateWhenIdle() def RedrawMethod(self, region=None): win = self.tkwin width = win.width height = win.height self.gc.StartDblBuffer() self.gc.SetFillColor(StandardColors.white) self.gc.FillRectangle(0, 0, width, height) x = 0 FillRectangle = self.gc.FillRectangle SetFillColor = self.gc.SetFillColor create_color = CreateRGBColor rgbs = self.palette.Colors() rgbs = rgbs[self.start_idx:self.start_idx + self.num_cells] for rgb in rgbs: SetFillColor(apply(create_color, rgb)) FillRectangle(x, 0, x + height, height) x = x + height self.gc.EndDblBuffer() def ResizedMethod(self, width, height): self.compute_num_cells() self.gc.WindowResized(width, height) self.normalize_start() self.UpdateWhenIdle() def normalize_start(self): length = len(self.palette) if self.start_idx < 0: self.start_idx = 0 if length < self.num_cells: self.start_idx = 0 elif length - self.start_idx < self.num_cells: self.start_idx = length - self.num_cells def CanScrollLeft(self): return self.start_idx > 0 def CanScrollRight(self): return len(self.palette) - self.start_idx > self.num_cells def ScrollXPages(self, count): length = self.tkwin.width / self.cell_size start = self.start_idx self.start_idx = self.start_idx + count * length self.normalize_start() if start != self.start_idx: self.UpdateWhenIdle() self.issue(VIEW) def ScrollXUnits(self, count): start = self.start_idx self.start_idx = self.start_idx + count self.normalize_start() if start != self.start_idx: self.UpdateWhenIdle() self.issue(VIEW)
class SketchView(PyWidget, Viewport, QueueingPublisher): document = None def __init__(self, master=None, toplevel=None, document=None, show_visible=0, show_printable=1, resolution=None, **kw): apply(PyWidget.__init__, (self, master), kw) Viewport.__init__(self, resolution) QueueingPublisher.__init__(self) self.toplevel = toplevel self.move_window_count = 0 self.show_page_outline = 1 self.show_visible = show_visible self.show_printable = show_printable self.gcs_initialized = 0 self.gc = GraphicsDevice() self.init_transactions() if document is not None: self.SetDocument(document) else: self.SetDocument(Document(create_layer=1)) def destroy(self): self.unsubscribe_doc() PyWidget.destroy(self) QueueingPublisher.Destroy(self) def MapMethod(self): # when being mapped the first time, initialise the gcs. this cannot be # done earlier, because the hitgc creates a pixmap which currently # only works after the window (id) has been created. In Xt this can be # done in the Realize widget method (after calling the superclass' # method), but Tk doesn't seem to offer any similar thing. if not self.gcs_initialized: self.init_gcs() self.issue_state() def DestroyMethod(self): # make sure that gc is deleted. gc may have a shared memory ximage # which is not freed if the gc is not destroyed leaving unused shared # memory segments in the system even after the process has finished. self.gc = None PyWidget.DestroyMethod(self) def init_gcs(self): self.gc.init_gc(self.tkwin, graphics_exposures=1) self.gc.draw_visible = self.show_visible self.gc.draw_printable = self.show_printable self.gc.allow_outline = 0 self.gcs_initialized = 1 self.default_view() self.set_gc_transforms() def default_view(self): self.FitPageToWindow() def set_gc_transforms(self): self.gc.SetViewportTransform(self.scale, self.doc_to_win, self.win_to_doc) # # Channels # def issue_state(self): self.queue_message(STATE) def issue_view(self): self.queue_message(VIEW) def issue_document(self): self.doc_changed = 1 def queue_message(self, Publisher): if self.transaction: QueueingPublisher.queue_message(self, Publisher) else: self.issue(Publisher) def init_transactions(self): self.sb_update_pending = 0 self.doc_changed = 0 self.transaction = 0 def begin_transaction(self): self.transaction = self.transaction + 1 def end_transaction(self): self.transaction = self.transaction - 1 if self.transaction == 0: if self.doc_changed: self.issue(DOCUMENT, self.document) self.sb_update_pending = 0 self.doc_changed = 0 self.flush_message_queue() elif self.transaction < 0: raise SketchInternalError('transaction count < 0') # # receivers # def redraw_doc(self, all, rects=None): if all: self.clear_window() else: map(self.clear_area_doc, rects) def layout_changed(self): self.SetPageSize(self.document.Layout().Size()) self.set_gc_transforms() self.update_scrollbars() self.update_rulers() if self.show_page_outline: self.clear_window() def layer_changed(self, *args): if args: redraw = EmptyRect if args[0] == LAYER_STATE: layer, visible_changed, printable_changed, outlined_changed \ = args[1] rect = layer.bounding_rect if rect is not EmptyRect: if self.show_printable and printable_changed: redraw = rect if self.show_visible: if visible_changed: redraw = rect if outlined_changed and layer.Visible(): redraw = rect elif args[0] == LAYER_ORDER: layer = args[1] if (self.show_printable and layer.Printable() or self.show_visible and layer.Visible()): redraw = layer.bounding_rect if len(args) > 2: other = args[2] if (self.show_printable and other.Printable() or self.show_visible and other.Visible()): redraw = IntersectRects(redraw, other.bounding_rect) else: redraw = EmptyRect elif args[0] == LAYER_COLOR: layer = args[1] rect = layer.bounding_rect if self.show_visible and rect is not EmptyRect \ and layer.Visible(): redraw = rect self.clear_area_doc(redraw) # # Widget Methods (Redraw, ... ) # time_redraw = 0 def RedrawMethod(self, region=None): # draw the document if __debug__: if self.time_redraw: import time start = time.clock() if self.move_window_count >= 2: self.clear_window(update=0) self.move_window_count = 0 region = self.do_clear(region) # draw document self.gc.InitClip() self.gc.ResetFontCache() if region: self.gc.PushClip() self.gc.ClipRegion(region) tkwin = self.tkwin if region: x, y, w, h = region.ClipBox() if x < 0: w = w - x x = 0 if y < 0: h = h - y y = 0 if w > tkwin.width: w = tkwin.width if h > tkwin.height: h = tkwin.height else: x = y = 0 w = tkwin.width h = tkwin.height p1 = self.WinToDoc(x - 1, y - 1) p2 = self.WinToDoc(x + w + 1, y + h + 1) rect = Rect(p1, p2) self.gc.SetFillColor(StandardColors.white) self.gc.gc.FillRectangle(x, y, w, h) # XXX ugly to access gc.gc # draw paper if self.show_page_outline: w, h = self.document.PageSize() self.gc.DrawPageOutline(w, h) self.document.Draw(self.gc, rect) if region: self.gc.PopClip() if __debug__: if self.time_redraw: pdebug('timing', 'redraw', time.clock() - start) return region def ResizedMethod(self, width, height): Viewport.ResizedMethod(self, width, height) self.gc.WindowResized(width, height) # # Viewport- and related methods # # extend some Viewport methods to issue VIEW whenever # the displayed area changes # def ForceRedraw(self): # Force a redraw of the whole window self.clear_window() if __debug__: #self.time_redraw = 1 pass # def SetScrollbars(self, hbar, vbar): # Viewport.SetScrollbars(self, hbar, vbar) # hbar.configure(jump = 1) # vbar.configure(jump = 1) def set_origin(self, xorg, yorg, move_contents=1): self.begin_transaction() try: Viewport.set_origin(self, xorg, yorg, move_contents=move_contents) self.set_gc_transforms() self.issue_view() finally: self.end_transaction() def move_window_contents(self, offx, offy): # implement the method needed by Viewport.set_origin w = self.tkwin width = w.width height = w.height if abs(offx) < width and abs(offy) < height: w.CopyArea(w, self.gc.gc, offx, offy, width, height, 0, 0) self.move_window_count = self.move_window_count + 1 else: self.clear_window() def SetScale(self, scale, do_center=1): # Set current scale self.begin_transaction() try: Viewport.SetScale(self, scale, do_center=do_center) self.set_gc_transforms() finally: self.end_transaction() def zoom_fit_rect(self, rect, save_viewport=0): if save_viewport: self.save_viewport() Viewport.zoom_fit_rect(self, rect) # # other view related methods # def FitToWindow(self, selected_only=0, save_viewport=1): self.begin_transaction() try: if selected_only: rect = self.document.SelectionBoundingRect() else: rect = self.document.BoundingRect() if rect: self.zoom_fit_rect(rect, save_viewport=save_viewport) finally: self.end_transaction() def FitPageToWindow(self, save_viewport=1): self.begin_transaction() try: w, h = self.document.PageSize() self.zoom_fit_rect(Rect(0 - w * .03, 0 - h * .03, w * 1.03, h * 1.03).grown(10), save_viewport=save_viewport) finally: self.end_transaction() # # Outline Mode # # Although not directly related to the viewport methods (the outline # mode doesn't change the displayed area) the outline mode changes the # way the drawing is displayed and thus issues VIEW. def SetOutlineMode(self, on=1): self.begin_transaction() try: if on: if self.gc.IsOutlineActive(): return else: self.gc.StartOutlineMode() self.hitgc.StartOutlineMode() else: if self.gc.IsOutlineActive(): self.gc.EndOutlineMode() self.hitgc.EndOutlineMode() else: return self.issue_view() self.clear_window() finally: self.end_transaction() def ToggleOutlineMode(self): self.SetOutlineMode(not self.IsOutlineMode()) def IsOutlineMode(self): return self.gc and self.gc.IsOutlineActive() # # Show page outline on/off # def SetPageOutlineMode(self, on=1): self.begin_transaction() try: self.show_page_outline = on self.issue_view() self.clear_window() finally: self.end_transaction() def TogglePageOutlineMode(self): self.SetPageOutlineMode(not self.IsPageOutlineMode()) def IsPageOutlineMode(self): return self.show_page_outline # # # def unsubscribe_doc(self): if self.document is not None: self.document.Unsubscribe(REDRAW, self.redraw_doc) self.document.Unsubscribe(LAYOUT, self.layout_changed) self.document.Unsubscribe(LAYER, self.layer_changed) def subscribe_doc(self): self.document.Subscribe(REDRAW, self.redraw_doc) self.document.Subscribe(LAYOUT, self.layout_changed) self.document.Subscribe(LAYER, self.layer_changed) def SetDocument(self, doc): self.begin_transaction() try: self.unsubscribe_doc() self.document = doc self.subscribe_doc() self.clear_window() self.SetPageSize(self.document.Layout().Size()) self.FitPageToWindow(save_viewport=0) self.issue_document() self.issue_state() self.issue_view() finally: self.end_transaction()