def Draw(self, grid, dc, rect, row): rect.y -= 1 if row == grid.actions.cursor[0]: color = get_color(config["selection_color"]) else: color = get_color(config["label_color"]) dc.SetPen(wx.TRANSPARENT_PEN) dc.SetBrush(wx.Brush(color)) dc.DrawRectangleRect(rect) hAlign, vAlign = grid.GetRowLabelAlignment() text = grid.GetRowLabelValue(row) if row != grid.actions.cursor[0]: self.DrawBorder(grid, dc, rect) self.DrawText(grid, dc, rect, text, hAlign, vAlign)
def __init__(self, parent, main_window, *args, **kwargs): wx.Panel.__init__(self, parent, *args, **kwargs) try: self.SetBackgroundColour(get_color(wx.SYS_COLOUR_FRAMEBK)) except AttributeError: # Does not work on wx 2.x pass self.parent = parent self.main_window = main_window style = wx.TE_PROCESS_ENTER | wx.TE_MULTILINE self.entry_line = EntryLine(self, main_window, style=style) self.selection_toggle_button = \ wx.ToggleButton(self, -1, size=(24, -1), label=u"\u25F0") tooltip = wx.ToolTip(_("Toggles link insertion mode.")) self.selection_toggle_button.SetToolTip(tooltip) self.selection_toggle_button.Bind(wx.EVT_TOGGLEBUTTON, self.OnToggle) if not is_gtk(): # TODO: Selections still do not work right on Windows self.selection_toggle_button.Disable() self.__do_layout()
def __init__(self, parent, main_window, no_tabs): self.parent = parent self.main_window = main_window self.no_tabs = no_tabs IntCtrl.__init__(self, parent, allow_long=True, style=wx.NO_BORDER, default_color=get_color(config["text_color"])) self.last_change_s = time.clock() tipmsg = _("For switching tables enter the table number or " "use the mouse wheel.") self.SetToolTip(wx.ToolTip(tipmsg)) # State for preventing to post GridActionTableSwitchMsg self.switching = False self.cursor_pos = 0 self.Bind(EVT_INT, self.OnInt) self.Bind(wx.EVT_MOUSEWHEEL, self.OnMouseWheel) self.Bind(wx.EVT_SET_FOCUS, self.OnFocus) self.main_window.Bind(self.EVT_CMD_RESIZE_GRID, self.OnResizeGrid) self.main_window.Bind(self.EVT_CMD_TABLE_CHANGED, self.OnTableChanged)
def OnDrawBackground(self, dc, rect, item, flags): """Called for drawing the background area of each item Overridden from OwnerDrawnComboBox """ # If the item is selected, or its item is even, # or if we are painting the combo control itself # then use the default rendering. if (item & 1 == 0 or flags & (wx.combo.ODCB_PAINTING_CONTROL | wx.combo.ODCB_PAINTING_SELECTED)): try: wx.combo.OwnerDrawnComboBox.OnDrawBackground( self, dc, rect, item, flags) finally: return # Otherwise, draw every other background with # different color. bg_color = get_color(wx.SYS_COLOUR_BACKGROUND) dc.SetBrush(wx.Brush(bg_color)) dc.SetPen(wx.Pen(bg_color)) dc.DrawRectangleRect(rect)
def OnDrawItem(self, dc, rect, item, flags): if item == wx.NOT_FOUND: return default_font_size = get_default_font().GetPointSize() context = wx.lib.wxcairo.ContextFromDC(dc) context.rectangle(*rect) context.clip() pangocairo_context = pangocairo.CairoContext(context) pangocairo_context.set_antialias(cairo.ANTIALIAS_SUBPIXEL) layout = pangocairo_context.create_layout() fontname = self.GetString(item) font = pango.FontDescription("{} {}".format(fontname, default_font_size)) layout.set_font_description(font) layout.set_text(fontname) color = tuple( [c / 255.0 for c in get_color(config["text_color"]).Get()]) context.set_source_rgb(*color) height = layout.get_pixel_extents()[1][3] y_adjust = int((rect.height - height) / 2.0) context.translate(rect.x + 3, rect.y + y_adjust) pangocairo_context.update_layout(layout) pangocairo_context.show_layout(layout)
def OnDrawBackground(self, dc, rect, item, flags): """Called for drawing the background area of each item Overridden from OwnerDrawnComboBox """ # If the item is selected, or its item is even, # or if we are painting the combo control itself # then use the default rendering. if (item & 1 == 0 or flags & (wx.combo.ODCB_PAINTING_CONTROL | wx.combo.ODCB_PAINTING_SELECTED)): try: wx.combo.OwnerDrawnComboBox.OnDrawBackground(self, dc, rect, item, flags) finally: return # Otherwise, draw every other background with # different color. bg_color = get_color(config["label_color"]) dc.SetBrush(wx.Brush(bg_color)) dc.SetPen(wx.Pen(bg_color)) dc.DrawRectangleRect(rect)
def Draw(self, grid, dc, rect, col): if col == grid.actions.cursor[1]: rect.x += 1 rect.width -= 1 pen_color = get_color(wx.SYS_COLOUR_MENUHILIGHT) pen = wx.Pen(pen_color, 2, wx.SOLID) dc.SetPen(pen) else: dc.SetPen(wx.TRANSPARENT_PEN) color = get_color(wx.SYS_COLOUR_BACKGROUND) dc.SetBrush(wx.Brush(color)) dc.DrawRectangleRect(rect) hAlign, vAlign = grid.GetColLabelAlignment() text = grid.GetColLabelValue(col) self.DrawBorder(grid, dc, rect) self.DrawText(grid, dc, rect, text, hAlign, vAlign)
def Draw(self, grid, dc, rect, col): if col == grid.actions.cursor[1]: rect.x += 1 rect.width -= 1 pen_color = get_color(wx.SYS_COLOUR_MENUHILIGHT) pen = wx.Pen(pen_color, 2, wx.SOLID) dc.SetPen(pen) else: dc.SetPen(wx.TRANSPARENT_PEN) color = get_color(wx.SYS_COLOUR_MENUBAR) dc.SetBrush(wx.Brush(color)) dc.DrawRectangleRect(rect) hAlign, vAlign = grid.GetColLabelAlignment() text = grid.GetColLabelValue(col) self.DrawBorder(grid, dc, rect) self.DrawText(grid, dc, rect, text, hAlign, vAlign)
def Draw(self, grid, dc, rect, row): if row == grid.actions.cursor[0]: rect.y += 1 rect.height -= 1 pen_color = get_color(wx.SYS_COLOUR_MENUHILIGHT) pen = wx.Pen(pen_color, 2, wx.SOLID) dc.SetPen(pen) else: dc.SetPen(wx.TRANSPARENT_PEN) color = get_color(wx.SYS_COLOUR_MENUBAR) dc.SetBrush(wx.Brush(color)) dc.DrawRectangleRect(rect) hAlign, vAlign = grid.GetRowLabelAlignment() text = grid.GetRowLabelValue(row) self.DrawBorder(grid, dc, rect) self.DrawText(grid, dc, rect, text, hAlign, vAlign)
def update_cursor(self, dc, grid, row, col): """Whites out the old cursor and draws the new one""" old_row, old_col = self.old_cursor_row_col bgcolor = get_color(config["background_color"]) self._draw_cursor(dc, grid, old_row, old_col, pen=wx.Pen(bgcolor), brush=wx.Brush(bgcolor)) self._draw_cursor(dc, grid, row, col)
def draw_background(self, dc): """Draws the background of the background""" attr = self.data_array.cell_attributes[self.key] if self.selection: color = get_color(config["selection_color"]) else: rgb = attr["bgcolor"] color = wx.Colour() color.SetRGB(rgb) bgbrush = wx.Brush(color, wx.SOLID) dc.SetBrush(bgbrush) dc.SetPen(wx.TRANSPARENT_PEN) dc.DrawRectangle(0, 0, self.rect.width, self.rect.height) # Draw frozen cell background rect if self.grid._view_frozen and attr['frozen']: style = wx.FDIAGONAL_HATCH freeze_color = get_color(config['freeze_color']) freeze_brush = wx.Brush(freeze_color, style) dc.SetBrush(freeze_brush) dc.DrawRectangle(0, 0, self.rect.width, self.rect.height)
def __init__(self, parent, *args, **kwargs): wx.Panel.__init__(self, parent, *args, **kwargs) try: self.SetBackgroundColour(get_color(wx.SYS_COLOUR_FRAMEBK)) except AttributeError: # Does not work on wx 2.x pass self.parent = parent # Panel with EntryLine and button self.entry_line_panel = EntryLinePanel(self, parent, style=wx.NO_BORDER) # IntCtrl for table choice self.table_choice = TableChoiceIntCtrl(self, parent, config["grid_tables"]) self.__do_layout()
def _get_color_idx(color): """Converts wx.Colour to Excel color index Differs from self.color2idx because it maps the pyspread default grid color to the Excel default color Parameters ---------- color: wx.Colour \tColor to be converted """ if color == get_color(config["grid_color"]): return DEFAULT_COLOR_IDX else: return self.color2idx(*color.Get())
def OnDrawItem(self, dc, rect, item, flags): if item == wx.NOT_FOUND: return default_font_size = get_default_font().GetPointSize() context = wx.lib.wxcairo.ContextFromDC(dc) context.rectangle(*rect) context.clip() pangocairo_context = pangocairo.CairoContext(context) pangocairo_context.set_antialias(cairo.ANTIALIAS_SUBPIXEL) layout = pangocairo_context.create_layout() fontname = self.GetString(item) font = pango.FontDescription("{} {}".format(fontname, default_font_size)) layout.set_font_description(font) layout.set_text(fontname) color = tuple([c / 255.0 for c in get_color(config["text_color"]).Get()]) context.set_source_rgb(*color) height = layout.get_pixel_extents()[1][3] y_adjust = int((rect.height - height) / 2.0) context.save() context.translate(rect.x + 3, rect.y + y_adjust) pangocairo_context.update_layout(layout) pangocairo_context.show_layout(layout) context.restore()
def _do_layout(self): """Adds widgets to the aui manager and controls the layout""" # Set background color for the toolbar via the manager ap = self._mgr.GetArtProvider() ap.SetColour(aui.AUI_DOCKART_BACKGROUND_GRADIENT_COLOUR, get_color(config["background_color"])) # Add the toolbars to the manager self._mgr.AddPane(self.main_toolbar, aui.AuiPaneInfo(). Name("main_window_toolbar"). Caption(_("Main toolbar")). ToolbarPane().Top().Row(0)) self._mgr.AddPane(self.find_toolbar, aui.AuiPaneInfo(). Name("find_toolbar").Caption(_("Find toolbar")). ToolbarPane().Top().Row(0)) self._mgr.AddPane(self.attributes_toolbar, aui.AuiPaneInfo(). Name("attributes_toolbar"). Caption(_("Format toolbar")). ToolbarPane().Top().Row(1)) self._mgr.AddPane(self.macro_toolbar, aui.AuiPaneInfo(). Name("macro_toolbar").Caption(_("Macro toolbar")). Gripper(True).ToolbarPane().Top().Row(1)) self._mgr.AddPane(self.widget_toolbar, aui.AuiPaneInfo(). Name("widget_toolbar").Caption(_("Widget toolbar")). Gripper(True).ToolbarPane().Top().Row(1)) self._mgr.AddPane(self.entry_line_panel, aui.AuiPaneInfo(). Name("entry_line_panel").Caption(_("Entry line")). Gripper(False).CenterPane().Top().Row(2). BestSize(400, 30).PaneBorder(False)) self._mgr.AddPane(self.table_list_panel, aui.AuiPaneInfo(). Name("table_list_panel").Caption(_("Table")). CenterPane().Left().BestSize(50, 300)) self._mgr.AddPane(self.macro_panel, aui.AuiPaneInfo(). Name("macro_panel").Caption(_("Macro panel")). Gripper(False).CenterPane().Right(). BestSize(200, 200)) # Load perspective from config window_layout = config["window_layout"] if window_layout: self._mgr.LoadPerspective(window_layout) # Add the main grid self._mgr.AddPane(self.grid, aui.AuiPaneInfo(). Name("grid").Caption(_("Main grid")).CentrePane()) # Tell the manager to 'commit' all the changes just made self._mgr.Update() self._mgr.GetPane("attributes_toolbar") self._mgr.Update() self._set_menu_toggles() # Set initial size to config value self.SetInitialSize(config["window_size"]) self.SetMinSize((10, 10)) # TODO: Set window position fix --> different positions for # different window managers prevent this self.SetPosition(config["window_position"])
class CellAttributes(list): """Stores cell formatting attributes in a list of 3 - tuples The first element of each tuple is a Selection. The second element is the table The third element is a dict of attributes that are altered. The class provides attribute read access to single cells via __getitem__ Otherwise it behaves similar to a list. The following methods mave been made undoable: * __setitem__ * append List methods that may alter the list have been removed """ def __init__(self, *args, **kwargs): self.__add__ = None self.__delattr__ = None self.__delitem__ = None self.__delslice__ = None self.__iadd__ = None self.__imul__ = None self.__rmul__ = None self.__setattr__ = None self.__setslice__ = None self.insert = None self.pop = None self.remove = None self.reverse = None self.sort = None default_cell_attributes = { "borderwidth_bottom": 1, "borderwidth_right": 1, "bordercolor_bottom": get_color(config["grid_color"]).GetRGB(), "bordercolor_right": get_color(config["grid_color"]).GetRGB(), "bgcolor": get_color(config["background_color"]).GetRGB(), "textfont": get_font_string(config["font"]), "pointsize": 10, "fontweight": wx.NORMAL, "fontstyle": wx.NORMAL, "textcolor": get_color(config["text_color"]).GetRGB(), "underline": False, "strikethrough": False, "locked": False, "angle": 0.0, "column-width": 75, "row-height": 26, "vertical_align": "top", "justification": "left", "frozen": False, "merge_area": None, "markup": False, "button_cell": False, "panel_cell": False, "video_volume": None, } # Cache for __getattr__ maps key to tuple of len and attr_dict _attr_cache = {} _table_cache = {} @undoable def append(self, value): list.append(self, value) self._attr_cache.clear() self._table_cache.clear() yield "append" # Undo actions list.pop(self) self._attr_cache.clear() self._table_cache.clear() def __getitem__(self, key): """Returns attribute dict for a single key""" assert not any(type(key_ele) is SliceType for key_ele in key) if key in self._attr_cache: cache_len, cache_dict = self._attr_cache[key] # Use cache result only if no new attrs have been defined if cache_len == len(self): return cache_dict # Update table cache if it is outdated (e.g. when creating a new grid) if len(self) != self._len_table_cache(): self._update_table_cache() row, col, tab = key result_dict = copy(self.default_cell_attributes) try: for selection, attr_dict in self._table_cache[tab]: if (row, col) in selection: result_dict.update(attr_dict) except KeyError: pass # Upddate cache with current length and dict self._attr_cache[key] = (len(self), result_dict) return result_dict @undoable def __setitem__(self, key, value): """Undoable version of list.__setitem__""" try: old_value = list.__getitem__(self, key) except IndexError: old_value = None list.__setitem__(self, key, value) self._attr_cache.clear() self._table_cache.clear() yield "__setitem__" if old_value is None: self.pop(key) else: list.__setitem__(self, key, old_value) self._attr_cache.clear() self._table_cache.clear() def _len_table_cache(self): """Returns the length of the table cache""" length = 0 for table in self._table_cache: length += len(self._table_cache[table]) return length def _update_table_cache(self): """Clears and updates the table cache to be in sync with self""" self._table_cache.clear() for sel, tab, val in self: try: self._table_cache[tab].append((sel, val)) except KeyError: self._table_cache[tab] = [(sel, val)] assert len(self) == self._len_table_cache() def get_merging_cell(self, key): """Returns key of cell that merges the cell key or None if cell key not merged Parameters ---------- key: 3-tuple of Integer \tThe key of the cell that is merged """ row, col, tab = key # Is cell merged merge_area = self[key]["merge_area"] if merge_area: return merge_area[0], merge_area[1], tab
def __init__(self, main_window, *args, **kwargs): S = kwargs.pop("S") self.main_window = main_window self._states() self.interfaces = GuiInterfaces(self.main_window) if S is None: dimensions = kwargs.pop("dimensions") else: dimensions = S.shape kwargs.pop("dimensions") wx.grid.Grid.__init__(self, main_window, *args, **kwargs) glr.GridWithLabelRenderersMixin.__init__(self) self.SetDefaultCellBackgroundColour( get_color(config["background_color"])) # Cursor position on entering selection mode self.sel_mode_cursor = None # Set multi line editor self.SetDefaultEditor(GridCellEditor(main_window)) # Create new grid if S is None: self.code_array = CodeArray(dimensions) post_command_event(self, self.GridActionNewMsg, shape=dimensions) else: self.code_array = S _grid_table = GridTable(self, self.code_array) self.SetTable(_grid_table, True) # Grid renderer draws the grid self.grid_renderer = GridRenderer(self.code_array) self.SetDefaultRenderer(self.grid_renderer) self.SetDefaultRowLabelRenderer(RowLabelRenderer()) self.SetDefaultColLabelRenderer(ColLabelRenderer()) # Context menu for quick access of important functions self.contextmenu = ContextMenu(parent=self) # Handler classes contain event handler methods self.handlers = GridEventHandlers(self) self.cell_handlers = GridCellEventHandlers(self) # Grid actions self.actions = AllGridActions(self) # Layout and bindings self._layout() self._bind() # Update toolbars self.update_entry_line() self.update_attribute_toolbar() # Focus on grid so that typing can start immediately self.SetFocus()
def _draw_cursor(self, dc, grid, row, col, pen=None, brush=None): """Draws cursor as Rectangle in lower right corner""" # If in full screen mode draw no cursor if grid.main_window.IsFullScreen(): return key = row, col, grid.current_table rect = grid.CellToRect(row, col) rect = self.get_merged_rect(grid, key, rect) # Check if cell is invisible if rect is None: return size = self.get_zoomed_size(1.0) caret_length = int(min([rect.width, rect.height]) / 5.0) color = get_color(config["text_color"]) if pen is None: pen = wx.Pen(color) if brush is None: brush = wx.Brush(color) pen.SetWidth(size) # Inner right and lower borders border_left = rect.x + size - 1 border_right = rect.x + rect.width - size - 1 border_upper = rect.y + size - 1 border_lower = rect.y + rect.height - size - 1 points_lr = [ (border_right, border_lower - caret_length), (border_right, border_lower), (border_right - caret_length, border_lower), (border_right, border_lower), ] points_ur = [ (border_right, border_upper + caret_length), (border_right, border_upper), (border_right - caret_length, border_upper), (border_right, border_upper), ] points_ul = [ (border_left, border_upper + caret_length), (border_left, border_upper), (border_left + caret_length, border_upper), (border_left, border_upper), ] points_ll = [ (border_left, border_lower - caret_length), (border_left, border_lower), (border_left + caret_length, border_lower), (border_left, border_lower), ] point_list = [points_lr, points_ur, points_ul, points_ll] dc.DrawPolygonList(point_list, pens=pen, brushes=brush) self.old_cursor_row_col = row, col
class CellAttributes(list): """Stores cell formatting attributes in a list of 3 - tuples The first element of each tuple is a Selection. The second element is the table The third element is a dict of attributes that are altered. The class provides attribute read access to single cells via __getitem__ Otherwise it behaves similar to a list. Note that for the method undoable_append to work, unredo has to be defined as class attribute. """ default_cell_attributes = { "borderwidth_bottom": 1, "borderwidth_right": 1, "bordercolor_bottom": get_color(config["grid_color"]).GetRGB(), "bordercolor_right": get_color(config["grid_color"]).GetRGB(), "bgcolor": get_color(config["background_color"]).GetRGB(), "textfont": get_font_string(config["font"]), "pointsize": 10, "fontweight": wx.NORMAL, "fontstyle": wx.NORMAL, "textcolor": get_color(config["text_color"]).GetRGB(), "underline": False, "strikethrough": False, "locked": False, "angle": 0.0, "column-width": 150, "row-height": 26, "vertical_align": "top", "justification": "left", "frozen": False, "merge_area": None, } # Cache for __getattr__ maps key to tuple of len and attr_dict _attr_cache = {} def undoable_append(self, value, mark_unredo=True): """Appends item to list and provides undo and redo functionality""" undo_operation = (self.pop, []) redo_operation = (self.undoable_append, [value, mark_unredo]) self.unredo.append(undo_operation, redo_operation) if mark_unredo: self.unredo.mark() self.append(value) self._attr_cache.clear() def __getitem__(self, key): """Returns attribute dict for a single key""" assert not any(type(key_ele) is SliceType for key_ele in key) if key in self._attr_cache: cache_len, cache_dict = self._attr_cache[key] # Use cache result only if no new attrs have been defined if cache_len == len(self): return cache_dict row, col, tab = key result_dict = copy(self.default_cell_attributes) for selection, table, attr_dict in self: if tab == table and (row, col) in selection: result_dict.update(attr_dict) # Upddate cache with current length and dict self._attr_cache[key] = (len(self), result_dict) return result_dict def get_merging_cell(self, key): """Returns key of cell that merges the cell key or None if cell key not merged Parameters ---------- key: 3-tuple of Integer \tThe key of the cell that is merged """ row, col, tab = key merging_cell = None def is_in_merge_area(row, col, merge_area): top, left, bottom, right = merge_area return top <= row <= bottom and left <= col <= right for selection, table, attr_dict in self: try: merge_area = attr_dict["merge_area"] if table == tab and merge_area is not None: # We have a merge area in the cell's table if is_in_merge_area(row, col, merge_area): merging_cell = merge_area[0], merge_area[1], tab except KeyError: pass return merging_cell # Allow getting and setting elements in list get_item = list.__getitem__ set_item = list.__setitem__
class GridRenderer(wx.grid.PyGridCellRenderer, EventMixin): """This renderer draws borders and text at specified font, size, color""" selection_color_tuple = \ tuple([c / 255.0 for c in get_color(config["selection_color"]).Get()] + [0.5]) def __init__(self, data_array): wx.grid.PyGridCellRenderer.__init__(self) self.data_array = data_array # Cache for cell content self.cell_cache = {} # Video cell register, contains keys self.video_cells = {} # Zoom of grid self.zoom = 1.0 # Old cursor position self.old_cursor_row_col = 0, 0 def get_zoomed_size(self, size): """Returns zoomed size as Integer Parameters ---------- font_size: Integer \tOriginal font size """ return max(1.0, round(size * self.zoom)) def _draw_cursor(self, dc, grid, row, col, pen=None, brush=None): """Draws cursor as Rectangle in lower right corner""" # If in full screen mode draw no cursor if grid.main_window.IsFullScreen(): return key = row, col, grid.current_table rect = grid.CellToRect(row, col) rect = self.get_merged_rect(grid, key, rect) # Check if cell is invisible if rect is None: return size = self.get_zoomed_size(1.0) caret_length = int(min([rect.width, rect.height]) / 5.0) color = get_color(config["text_color"]) if pen is None: pen = wx.Pen(color) if brush is None: brush = wx.Brush(color) pen.SetWidth(size) # Inner right and lower borders border_left = rect.x + size - 1 border_right = rect.x + rect.width - size - 1 border_upper = rect.y + size - 1 border_lower = rect.y + rect.height - size - 1 points_lr = [ (border_right, border_lower - caret_length), (border_right, border_lower), (border_right - caret_length, border_lower), (border_right, border_lower), ] points_ur = [ (border_right, border_upper + caret_length), (border_right, border_upper), (border_right - caret_length, border_upper), (border_right, border_upper), ] points_ul = [ (border_left, border_upper + caret_length), (border_left, border_upper), (border_left + caret_length, border_upper), (border_left, border_upper), ] points_ll = [ (border_left, border_lower - caret_length), (border_left, border_lower), (border_left + caret_length, border_lower), (border_left, border_lower), ] point_list = [points_lr, points_ur, points_ul, points_ll] dc.DrawPolygonList(point_list, pens=pen, brushes=brush) self.old_cursor_row_col = row, col def update_cursor(self, dc, grid, row, col): """Whites out the old cursor and draws the new one""" old_row, old_col = self.old_cursor_row_col bgcolor = get_color(config["background_color"]) self._draw_cursor(dc, grid, old_row, old_col, pen=wx.Pen(bgcolor), brush=wx.Brush(bgcolor)) self._draw_cursor(dc, grid, row, col) def get_merging_cell(self, grid, key): """Returns row, col, tab of merging cell if the cell key is merged""" return grid.code_array.cell_attributes.get_merging_cell(key) def get_merged_rect(self, grid, key, rect): """Returns cell rect for normal or merged cells and None for merged""" row, col, tab = key # Check if cell is merged: cell_attributes = grid.code_array.cell_attributes merge_area = cell_attributes[(row, col, tab)]["merge_area"] if merge_area is None: return rect else: # We have a merged cell top, left, bottom, right = merge_area # Are we drawing the top left cell? if top == row and left == col: # Set rect to merge area ul_rect = grid.CellToRect(row, col) br_rect = grid.CellToRect(bottom, right) width = br_rect.x - ul_rect.x + br_rect.width height = br_rect.y - ul_rect.y + br_rect.height rect = wx.Rect(ul_rect.x, ul_rect.y, width, height) return rect def _get_drawn_rect(self, grid, key, rect): """Replaces drawn rect if the one provided by wx is incorrect This handles merged rects including those that are partly off screen. """ rect = self.get_merged_rect(grid, key, rect) if rect is None: # Merged cell is drawn if grid.is_merged_cell_drawn(key): # Merging cell is outside view row, col, __ = key = self.get_merging_cell(grid, key) rect = grid.CellToRect(row, col) rect = self.get_merged_rect(grid, key, rect) else: return return rect def _get_draw_cache_key(self, grid, key, drawn_rect, is_selected): """Returns key for the screen draw cache""" row, col, tab = key cell_attributes = grid.code_array.cell_attributes zoomed_width = drawn_rect.width / self.zoom zoomed_height = drawn_rect.height / self.zoom # Button cells shall not be executed for preview if grid.code_array.cell_attributes[key]["button_cell"]: cell_preview = repr(grid.code_array(key))[:100] else: cell_preview = repr(grid.code_array[key])[:100] sorted_keys = sorted(grid.code_array.cell_attributes[key].iteritems()) key_above_left = row - 1, col - 1, tab key_above = row - 1, col, tab key_above_right = row - 1, col + 1, tab key_left = row, col - 1, tab key_right = row, col + 1, tab key_below_left = row + 1, col - 1, tab key_below = row + 1, col, tab borders = [] for k in [ key, key_above_left, key_above, key_above_right, key_left, key_right, key_below_left, key_below ]: borders.append(cell_attributes[k]["borderwidth_bottom"]) borders.append(cell_attributes[k]["borderwidth_right"]) borders.append(cell_attributes[k]["bordercolor_bottom"]) borders.append(cell_attributes[k]["bordercolor_right"]) return (zoomed_width, zoomed_height, is_selected, cell_preview, tuple(sorted_keys), tuple(borders)) def _get_cairo_bmp(self, mdc, key, rect, is_selected, view_frozen): """Returns a wx.Bitmap of cell key in size rect""" bmp = wx.EmptyBitmap(rect.width, rect.height) mdc.SelectObject(bmp) mdc.SetBackgroundMode(wx.SOLID) mdc.SetBackground(wx.WHITE_BRUSH) mdc.Clear() mdc.SetDeviceOrigin(0, 0) context = wx.lib.wxcairo.ContextFromDC(mdc) context.save() # Zoom context zoom = self.zoom context.scale(zoom, zoom) # Set off cell renderer by 1/2 a pixel to avoid blurry lines rect_tuple = \ -0.5, -0.5, rect.width / zoom + 0.5, rect.height / zoom + 0.5 spell_check = config["check_spelling"] cell_renderer = GridCellCairoRenderer(context, self.data_array, key, rect_tuple, view_frozen, spell_check=spell_check) # Draw cell cell_renderer.draw() # Draw selection if present if is_selected: context.set_source_rgba(*self.selection_color_tuple) context.rectangle(*rect_tuple) context.fill() context.restore() return bmp def Draw(self, grid, attr, dc, rect, row, col, isSelected): """Draws the cell border and content using pycairo""" key = row, col, grid.current_table # If cell is merge draw the merging cell if invisibile if grid.code_array.cell_attributes[key]["merge_area"]: key = self.get_merging_cell(grid, key) drawn_rect = self._get_drawn_rect(grid, key, rect) if drawn_rect is None: return cell_cache_key = self._get_draw_cache_key(grid, key, drawn_rect, isSelected) mdc = wx.MemoryDC() if vlc is not None and key in self.video_cells and \ grid.code_array.cell_attributes[key]["panel_cell"]: # Update video position of previously created video panel self.video_cells[key].SetClientRect(drawn_rect) elif cell_cache_key in self.cell_cache: mdc.SelectObject(self.cell_cache[cell_cache_key]) else: code = grid.code_array(key) if vlc is not None and code is not None and \ grid.code_array.cell_attributes[key]["panel_cell"]: try: # A panel is to be displayed panel_cls = grid.code_array[key] # Assert that we have a subclass of a wxPanel that we # can instantiate assert issubclass(panel_cls, wx.Panel) video_panel = panel_cls(grid) video_panel.SetClientRect(drawn_rect) # Register video cell self.video_cells[key] = video_panel return except Exception, err: # Someting is wrong with the panel to be displayed post_command_event(grid.main_window, self.StatusBarMsg, text=unicode(err)) bmp = self._get_cairo_bmp(mdc, key, drawn_rect, isSelected, grid._view_frozen) else: