def reset_hotkey(self): """Reset the system for the next stream of hotkey up/down events""" self.hotkey_pressed = False if not self.canvas.selected: return self.canvas.selected.end_select_action(0) pub.sendMessage('update_shape_viewer')
def redraw_all(self, update_thumb=False, dc=None, resizing=False): """ Redraws all shapes that have been drawn. self.text is used to show text characters as they're being typed, as new Text/Note objects have not been added to self.shapes at this point. dc is used as the DC for printing. """ if not dc: dc = wx.BufferedDC(None, self.buffer) dc.Clear() for s in self.shapes: if not resizing: s.draw(dc, True) else: if not isinstance(s, Highlighter): s.draw(dc, True) if self.text: self.text.draw(dc, True) if self.copy: self.copy.draw(dc, True) self.Refresh() if update_thumb: pub.sendMessage('thumbs.update_current')
def change_tool(self, new=None, canvas=None): if not canvas: canvas = self.canvas self.util.change_tool(canvas, new) canvas.change_tool() pub.sendMessage('gui.preview.refresh')
def add_undo(self): """Creates an undo point. NEED to change this for memory improvements""" l = self.clone_shapes() self.undo_list.append(l) if self.redo_list: self.redo_list = [] pub.sendMessage('gui.mark_unsaved')
def paste_text(self, text, x, y, colour): """Pastes a string onto the canvas, as a Text object""" self.shape = Text(self, colour, 1) self.shape.text = text self.shape.left_down(x, y) self.shape.left_up(x, y) self.text = None pub.sendMessage('canvas.change_tool') self.redraw_all(True)
def on_swap(self, event): """Swaps foreground/background colours""" background, colour = self.get_background_colour(), self.get_colour() self.background.SetColour(colour) self.colour.SetColour(background) self.gui.util.colour = background if not self.transparent.IsChecked(): self.gui.util.background = background pub.sendMessage('canvas.change_tool')
def on_transparency(self, event): """Toggles transparency in the shapes' background""" self.gui.util.transparent = False if event.Checked() and not self.gui.canvas.selected: self.gui.util.transparent = True if self.gui.canvas.selected: self.gui.canvas.toggle_transparent() pub.sendMessage('canvas.change_tool')
def load_image(path, canvas, image_class): """ Loads an image into the given Whyteboard tab. bitmap is the path to an image file to create a bitmap from. image_class = tools.Image *CLASS ITSELF* """ logger.debug("Loading [%s] and creating an Image object", path) image = wx.Bitmap(path) shape = image_class(canvas, image, path) shape.left_down(0, 0) # renders, updates scrollbars pub.sendMessage("thumbs.update_current")
def add_shape(self, shape): """ Adds a shape to the shape list managed by the canvas. """ self.add_undo() self.shapes.append(shape) if self.selected: self.deselect_shape() self.redraw_all() if self.text: self.text = None if self.copy: self.copy = None self.redraw_all() pub.sendMessage('update_shape_viewer')
def on_rename(self, event=None, sheet=None): if sheet is None: sheet = self.current_tab current_name = self.tabs.GetPageText(sheet) dlg = wx.TextEntryDialog(self, _("Rename this sheet to:"), _("Rename sheet")) dlg.SetValue(current_name) if dlg.ShowModal() == wx.ID_CANCEL: dlg.Destroy() else: val = dlg.GetValue() if val: logger.debug("Renaming sheet [%s] to [%s]", current_name, val) self.tabs.SetPageText(sheet, val) pub.sendMessage('sheet.rename', _id=sheet, text=val)
def on_change_tab(self, event=None): """Updates tab vars, scrolls thumbnails and selects tree node""" self.canvas = self.tabs.GetCurrentPage() self.update_panels(False) self.current_tab = self.tabs.GetSelection() self.update_panels(True) self.thumbs.thumbs[self.current_tab].update() self.thumbs.ScrollChildIntoView(self.thumbs.thumbs[self.current_tab]) self.control.change_tool() # updates canvas' shape if self.notes.tabs: tree_id = self.notes.tabs[self.current_tab] self.notes.tree.SelectItem(tree_id, True) pub.sendMessage('update_shape_viewer')
def change_tool(self, event=None, _id=None): """ Toggles the tool buttons on/off """ new = self.gui.util.tool if event and not _id: new = int(event.GetId()) elif _id: new = _id for button in self.tools.values(): button.SetValue(False) self.tools[new].SetValue(True) pub.sendMessage('canvas.change_tool', new=new)
def delete_selected(self): """Deletes the selected shape""" if not self.selected: return if isinstance(self.selected, Media): self.selected.remove_panel() else: if isinstance(self.selected, Note): self.gui.notes.tree.Delete(self.selected.tree_id) self.add_undo() self.shapes.remove(self.selected) pub.sendMessage('update_shape_viewer') self.selected = None self.redraw_all(True)
def update(self, value, var_name, add_undo=True): """Updates the given utility variable and the selected shape""" setattr(self.gui.util, var_name, value) if self.gui.canvas.selected: if add_undo: self.gui.canvas.add_undo() if var_name == u"background" and not self.transparent.IsChecked(): self.gui.canvas.selected.background = value elif var_name != u"background": setattr(self.gui.canvas.selected, var_name, value) self.gui.canvas.redraw_all(True) pub.sendMessage('update_shape_viewer') pub.sendMessage('canvas.change_tool') self.preview.Refresh()
def on_drop_tab(self, event): """ Update the thumbs/notes so that they're poiting to the new tab position. Show a progress dialog, as all thumbnails must be updated. """ if event.GetSelection() == event.GetOldSelection(): return self.show_progress_dialog(_("Loading...")) self.dialog.Show() self.on_change_tab() pub.sendMessage('sheet.move', event=event, tab_count=self.tab_count) self.on_done_load() wx.MilliSleep(100) # try and stop user dragging too many tabs quickly wx.SafeYield() pub.sendMessage('update_shape_viewer')
def on_undo_tab(self, event=None, tab=None): """ Undoes the last closed tab from the list. Re-creates the canvas from the saved shapes/undo/redo lists """ if not self.closed_tabs: return if not tab: tab = self.closed_tabs.pop() else: tab = self.closed_tabs.pop(self.closed_tabs.index(tab)) self.on_new_tab(name=tab['name'], wb=True) self.canvas.restore_sheet(tab['shapes'], tab['undo'], tab['redo'], tab['size'], tab['medias'], tab['viewport']) pub.sendMessage('update_shape_viewer') self.menu.make_closed_tabs_menu()
def clear(self, keep_images=False): """Removes all shapes. Images can be specified to not be removed.""" if not self.medias and not self.shapes: return for m in self.medias: m.remove_panel() self.medias = [] images = [] if self.shapes: self.add_undo() if keep_images: for x in self.shapes: if isinstance(x, Image): images.append(x) self.shapes = images pub.sendMessage('update_shape_viewer') self.redraw_all(update_thumb=True)
def perform(self, list_a, list_b): """ Perform undo/redo. list_a: to remove from / list b: append to """ if not list_a: return list_b.append(list(self.shapes)) self.shapes = list_a.pop() self.deselect_shape() self.redraw_all(True) pub.sendMessage('note.delete_sheet_items') # lazy way of doing things... for x in self.shapes: if isinstance(x, Note): pub.sendMessage('note.add', note=x) pub.sendMessage('gui.mark_unsaved') pub.sendMessage('update_shape_viewer')
def update_config(self, new_config): old_config = Config().config if new_config['language'] != old_config['language']: wx.MessageBox(_("Whyteboard will be translated into %s when restarted") % _(new_config['language']), u"Whyteboard") if 'default_font' in new_config: if new_config['default_font'] and not self.util.font: self.util.font = wx.FFont(1, wx.FONTFAMILY_DEFAULT) self.util.font.SetNativeFontInfoFromString(new_config['default_font']) # Toggles the items under "View" menu. Ignore the colour grid for now for menu_item in ['statusbar', 'toolbar', 'tool_preview']: method = getattr(self, "on_" + menu_item) if new_config[menu_item]: method(None, True) else: method(None, False) new_config.write() Config().config = new_config if new_config['bmp_select_transparent'] != old_config['bmp_select_transparent']: self.canvas.copy = None if not new_config['tool_preview']: self.control.preview.Hide() else: self.control.preview.Show() pub.sendMessage('gui.preview.refresh') wx.CallAfter(self.on_colour_grid, None, new_config['colour_grid']) # too lazy to check if each colour has changed - just remake it self.canvas.redraw_all() self.control.grid.Clear(True) self.control.make_colour_grid() self.control.grid.Layout()
def restore_sheet(self, shapes, undo_list, redo_list, size, medias, viewport): """ Restores itself (e.g. from undoing closing a sheet.) """ self.shapes = shapes self.undo_list = undo_list self.redo_list = redo_list self.medias = medias for media in medias: media.canvas = self media.make_panel() for shape in shapes: shape.canvas = self if isinstance(shape, Note): pub.sendMessage('note.add', note=shape) wx.Yield() self.resize(size) self.Scroll(viewport[0], viewport[1]) self.redraw_all() pub.sendMessage('thumbs.update_current')
def make_tools(self): # create some shapes self.rect = whyteboard.tools.Rectangle(self.canvas, (0, 0, 0), 1) self.rect.x = 150 self.rect.y = 150 self.rect.width, self.rect.height = 50, 50 self.text = whyteboard.tools.Text(self.canvas, (0, 0, 0), 3) self.text.x = 150 self.text.y = 150 self.text.text = "blah blah" # 'x' extent of 58 self.text.find_extent() self.circle = whyteboard.tools.Circle(self.canvas, (0, 0, 0), 1) self.circle.radius = 25 self.circle.x = 250 self.circle.y = 250 # add shapes to canvas, update the shapes for hit testing shapes = [self.rect, self.text, self.circle] for shape in shapes: pub.sendMessage('shape.add', shape=shape) shape.sort_handles()
def left_up(self, event): """ Called when the left mouse button is released. """ if os.name == "nt" and not self.shape.drawing: if self.HasCapture(): self.ReleaseMouse() if self.resizing: logger.debug("End resizing.") self.resizing = False self.redraw_all(True) # update thumb for new canvas size self.Layout() if self.copy: self.draw_shape(self.copy) # draw back the GCDC return if self.drawing or isinstance(self.shape, Text): before = len(self.shapes) self.shape.left_up(*self.convert_coords(event)) if not isinstance(self.shape, Media): if len(self.shapes) - before: pub.sendMessage('canvas.change_tool') pub.sendMessage('thumbs.update_current') self.drawing = False
def OnData(self, x, y, d): """ Handles drag/dropping files, text or bitmap items """ if self.GetData(): df = self.do.GetReceivedFormat().GetType() if df in [wx.DF_UNICODETEXT, wx.DF_TEXT]: pub.sendMessage('canvas.paste_text', text=self.textdo.GetText(), x=x, y=y) elif df == wx.DF_FILENAME: for x, name in enumerate(self.filedo.GetFilenames()): pub.sendMessage('gui.open_file', filename=name) elif df == wx.DF_BITMAP: pub.sendMessage('canvas.paste_image', image=self.bmpdo.GetBitmap(), x=x, y=y, ignore=True) return d
def on_colour_grid(self, event=None, force=None): val = self.get_toggle_value(ID_COLOUR_GRID, force) self.control.toggle_colour_grid(val) self.menu.check(ID_COLOUR_GRID, val) pub.sendMessage('gui.preview.refresh')
def recreate_save(self, filename, save_data): """ Recreates the saved .wtbd file's state """ logger.debug("Recreating save file") self.filename = filename self.gui.show_progress_dialog(_("Loading...")) self.gui.remove_all_sheets() # change program settings and update the Preview window self.colour = save_data[0][0] self.thickness = save_data[0][1] self.tool = save_data[0][2] self.gui.control.change_tool(_id=self.tool) # toggle button self.gui.control.colour.SetColour(self.colour) self.gui.control.thickness.SetSelection(self.thickness - 1) # re-create tabs and its saved drawings for x in save_data[1]: self.gui.on_new_tab(name=save_data[3][x]) size = (Config().default_width(), Config().default_height()) try: size = save_data[4][x] except KeyError: pass self.gui.canvas.resize(size) try: media = save_data[5][x] for m in media: m.canvas = self.gui.canvas m.load() self.gui.canvas.medias.append(m) except KeyError: break for shape in save_data[1][x]: try: shape.canvas = self.gui.canvas # restore canvas shape.load() # restore unpickleable settings self.gui.canvas.add_shape(shape) except Exception: break self.gui.canvas.redraw_all(True) # close progress bar, handle older file versions gracefully wx.PostEvent(self.gui, self.gui.LoadEvent()) self.mark_saved() self.saved_version = save_data[0][4] pub.sendMessage("canvas.change_tool") self.gui.tabs.SetSelection(save_data[0][3]) self.gui.on_change_tab() self.gui.SetTitle(u"%s - %s" % (os.path.basename(filename), self.gui.title)) self.gui.closed_tabs = list() try: if save_data[0][5]: logger.debug("Setting default font from save file: [%s]", save_data[0][5]) font = wx.FFont(1, wx.FONTFAMILY_DEFAULT) font.SetNativeFontInfoFromString(save_data[0][5]) self.font = font except IndexError: pass # Don't save .wtbd file of future versions as current, older version if version_is_greater(self.saved_version, meta.version): self.update_version = False
def update_panels(self, select): """Updates thumbnail panel's text""" pub.sendMessage('thumbs.text.highlight', tab=self.current_tab, select=select)
def wrapper(self, shape, x=None, item=None): x, item = self.do_move(shape) fn(self, shape, x, item) pub.sendMessage('update_shape_viewer') self.redraw_all(True)
def __init__(self): """ Initialise utility, status/menu/tool bar, tabs, ctrl panel + bindings. """ wx.Frame.__init__(self, None, title=_("Untitled") + u" - %s" % self.title) self.util = Utility(self) meta.find_transparent() # important logger.info("Transparency supported: %s", meta.transparent) if meta.transparent: try: x = self.util.items.index(Highlighter) except ValueError: self.util.items.insert(1, Highlighter) self.can_paste = check_clipboard() self.process = None self.pid = None self.dialog = None self.convert_cancelled = False self.shape_viewer_open = False self.help = None self.hotkey_pressed = False # for hotkey timer self.hotkey_timer = None self.tab_count = 1 self.tab_total = 1 self.current_tab = 0 self.closed_tabs = [] self.hotkeys = [] style = (fnb.FNB_X_ON_TAB | fnb.FNB_NO_X_BUTTON | fnb.FNB_VC8 | fnb.FNB_DROPDOWN_TABS_LIST | fnb.FNB_MOUSE_MIDDLE_CLOSES_TABS | fnb.FNB_NO_NAV_BUTTONS) self.control = ControlPanel(self) self.tabs = fnb.FlatNotebook(self, agwStyle=style) self.canvas = Canvas(self.tabs, self, (Config().default_width(), Config().default_height())) self.panel = SidePanel(self) self.thumbs = self.panel.thumbs self.notes = self.panel.notes self.tabs.AddPage(self.canvas, _("Sheet") + u" 1") box = wx.BoxSizer(wx.HORIZONTAL) # position windows side-by-side box.Add(self.control, 0, wx.EXPAND) box.Add(self.tabs, 1, wx.EXPAND) box.Add(self.panel, 0, wx.EXPAND) self.SetSizer(box) self.SetSizeWH(800, 600) if os.name == "posix": self.canvas.SetFocus() # makes EVT_CHAR_HOOK trigger if 'mac' != os.name: self.Maximize(True) self.paste_check_count = PASTE_CHECK_COUNT - 1 wx.UpdateUIEvent.SetUpdateInterval(75) #wx.UpdateUIEvent.SetMode(wx.UPDATE_UI_PROCESS_SPECIFIED) self.SetIcon(icon.getIcon()) self.SetExtraStyle(wx.WS_EX_PROCESS_UI_UPDATES) self.SetDropTarget(CanvasDropTarget()) self.statusbar = self.CreateStatusBar() self._print = Print(self) self.filehistory = wx.FileHistory(8) self.config = wx.Config() self.load_history_file() self.filehistory.Load(self.config) self.menu = Menu(self) self.toolbar = self.CreateToolBar() Toolbar.configure(self.toolbar, self.can_paste) self.SetMenuBar(self.menu.menu) self.set_menu_from_config() self.do_bindings() self.find_help() pub.sendMessage('thumbs.update_current') self.update_panels(True) wx.CallAfter(self.UpdateWindowUI)