def endElement(self, name): if name == 'object': obj = self.top() self.depth_level -= 1 if not self.depth_level: common.app_tree.auto_expand = True import misc try: # show the first object and update its layout #if self.top_obj.node.parent.widget.is_visible(): # common.app_tree.show_widget(self.top_obj.node) if self.top_obj.node.parent.widget.widget: self.top_obj.create_widgets() except AttributeError: self._logger.exception(_('Exception caused by obj: %s'), self.top_obj) misc.set_focused_widget(self.top_obj) if name == 'label': # if e.g. a button_1 is copied to button_2, also change the label if it was "button_1" obj = self.top() renamed = getattr(obj, "_renamed", None) if renamed: oldname, newname = renamed if obj.obj.name == newname and self._curr_prop_val and self._curr_prop_val[ 0] == oldname: self._curr_prop_val[0] = newname XmlWidgetBuilder.endElement(self, name)
def _show_widget_toplevel(self, node): # creates/shows the widget of the given toplevel node and all its children if not wx.IsBusy(): wx.BeginBusyCursor() if not node.widget.widget: node.widget.create_widget() node.widget.finish_widget_creation() node.widget.drop_target = clipboard.DropTarget(node.widget) node.widget.widget.SetDropTarget(node.widget.drop_target) with node.widget.frozen(): if node.children: for c in node.children: self.create_widgets(c) node.widget.post_load( ) # only edit_sizers.SizerBase has this method implemented and calls it for toplevel node.widget.create() if node.widget.widget.TopLevel: node.widget.widget.Show() else: node.widget.widget.GetParent().Show() misc.set_focused_widget(node.widget) node.widget.widget.Raise() # set the best size for the widget (if no one is given) props = node.widget.properties if 'size' in props and not props['size'].is_active(): if node.widget.sizer: node.widget.sizer.fit_parent() elif getattr(node.widget, "top_sizer", None): wx.Yield( ) # by now, there are probably many EVT_SIZE in the queue node.widget.top_sizer.fit_parent() if wx.IsBusy(): wx.EndBusyCursor()
def on_drop_widget(self, event, reset=None): """replaces self with a widget. This method is called to add every non-toplevel widget or sizer, and in turn calls the appropriate builder function (found in the 'common.widgets' dict).""" if not common.adding_widget: # widget focused/selected misc.set_focused_widget(self) if self.widget: self.widget.Refresh() self.widget.SetFocus() return if not self.check_drop_compatibility()[0]: return if self.widget: self.widget.SetCursor(wx.NullCursor) common.adding_window = event and event.GetEventObject( ).GetTopLevelParent() or None # call the appropriate builder new_widget = common.widgets[common.widget_to_add](self.parent, self.index) if new_widget is None: return misc.rebuild_tree(new_widget) if reset is False: return if event is None or not misc.event_modifier_copy(event): common.adding_widget = common.adding_sizer = False common.widget_to_add = None if event is not None and new_widget.widget: # set focus; required mainly on macOS to receive keys widget = None if new_widget.IS_WINDOW: widget = new_widget.widget elif new_widget.IS_SIZER: widget = new_widget.toplevel_parent_window.widget if hasattr(widget, "SetFocus"): widget.SetFocus() common.history.widget_added(new_widget)
def undo(self): path = self.slot_path or self.path.rsplit("/", 1)[0] # slot or parent widget = common.root.find_widget_from_path(path) if widget.IS_ROOT: # or widget.IS_CONTAINER: widget.clipboard_paste(self.xml_data, self.index) elif self.IS_SLOT: widget.insert_item(None, self.index) # placeholder if self.slot_tab is not None: tabs_p = widget.properties["tabs"] tabs_p.value.insert(self.index, [self.slot_tab]) tabs_p.reset() if widget.IS_SIZER: from edit_sizers import SizerSlot as Slot else: from edit_base import Slot slot = Slot(widget, index=self.index) if widget.widget: slot.create_widget() widget.child_widget_created(slot, 0) # update structure misc.rebuild_tree(widget, focus=False) # update following slots for c in widget.children[self.index + 1:]: if c.IS_SLOT: common.app_tree.refresh(c) misc.set_focused_widget(slot) else: widget.clipboard_paste(self.xml_data)
def undo(self): # identical to HistoryAddedItem.redo, except for the slot_tab part path = self.slot_path or self.path.rsplit("/", 1)[0] # slot or parent widget = common.root.find_widget_from_path(path) if widget is None: # something was pasted/added to e.g. a panel which had a slot as child parent_path, leaf = path.rsplit("/", 1) assert leaf.startswith('SLOT ') widget = common.root.find_widget_from_path(parent_path) if widget.IS_ROOT: # or widget.IS_CONTAINER: widget.clipboard_paste(self.xml_data, self.index) elif self.IS_SLOT: widget.insert_item(None, self.index) # placeholder if self.slot_tab is not None: tabs_p = widget.properties["tabs"] tabs_p.value.insert(self.index, [self.slot_tab]) tabs_p.reset() if widget.IS_SIZER: from edit_sizers import SizerSlot as Slot else: from edit_base import Slot slot = Slot(widget, index=self.index) if widget.widget: slot.create_widget() widget.child_widget_created(slot, 0) # update structure misc.rebuild_tree(widget, focus=False) # update following slots for c in widget.children[self.index + 1:]: if c.IS_SLOT: common.app_tree.refresh(c) misc.set_focused_widget(slot) else: widget.clipboard_paste(self.xml_data)
def _on_set_focus(self, event): # within a short time window, we ignore focus events as these seem due losing focus if not misc.focused_widget is self and time.time( ) - misc.focused_time > 0.05: # don't set focused_widget during event, as this may cause crashes; use delay instead misc.set_focused_widget(self, delayed=True) event.Skip()
def on_drop_widget(self, event, reset=None): """replaces self with a widget in self.sizer. This method is called to add every non-toplevel widget or sizer, and in turn calls the appropriate builder function (found in the ``common.widgets'' dict)""" if not common.adding_widget: # widget focused/selecte misc.set_focused_widget(self) if self.widget: self.widget.Refresh() self.widget.SetFocus() return if common.adding_sizer and self.parent.CHILDREN is not 1 and not self.IS_SLOT: return if self.widget: self.widget.SetCursor(wx.NullCursor) common.adding_window = event and event.GetEventObject( ).GetTopLevelParent() or None # call the appropriate builder new_widget = common.widgets[common.widget_to_add](self.parent, self.pos) if new_widget is None: return misc.rebuild_tree(new_widget) if reset is False: return if event is None or not misc.event_modifier_copy(event): common.adding_widget = common.adding_sizer = False common.widget_to_add = None
def show_toplevel(self, event, widget=None): "Event handler for left double-clicks: if the click is above a toplevel widget and this is hidden, shows it" if widget is None: try: x, y = event.GetPosition() except AttributeError: # if we are here, event is a CommandEvent and not a MouseEvent node = self.GetPyData(self.GetSelection()) self.expand(node) # if we are here, the widget must be shown else: node = self._find_item_by_pos(x, y, True) else: node = widget.node if node is None or node is self.root: return if node.widget.widget: # window widget has been created already; just show it if not node.widget.is_visible(): node.widget.widget.Show() else: node.widget.widget.Hide() return if not node.widget.is_visible(): # added by rlawson to expand node on showing top level widget self.expand(node) self._show_widget_toplevel(node) else: node.widget.create() node.widget.widget.Show() # added by rlawson to collapse only the toplevel node, not collapse back to root node self.select_item(node) misc.set_focused_widget(node.widget) event.Skip()
def destroy_widget(self, detach=True): if self.widget is None: return if misc.currently_under_mouse is self.widget: misc.currently_under_mouse = None if self._dont_destroy: return # on a notebook page self.widget.Hide() if wx.VERSION_STRING != "2.8.12.0": # unbind events to prevent new created (and queued) events self.widget.Bind(wx.EVT_PAINT, None) self.widget.Bind(wx.EVT_RIGHT_DOWN, None) self.widget.Bind(wx.EVT_LEFT_DOWN, None) self.widget.Bind(wx.EVT_MIDDLE_DOWN, None) self.widget.Bind(wx.EVT_ENTER_WINDOW, None) self.widget.Bind(wx.EVT_LEAVE_WINDOW, None) self.widget.Bind(wx.EVT_KEY_DOWN, None) if detach and self.parent.IS_SIZER and self.parent.widget: self.parent.widget.Detach( self.widget) # this will happen during recursive removal only compat.DestroyLater(self.widget) self.widget = None if misc.focused_widget is self: misc.set_focused_widget(None)
def remove(self, *args): self.sizer.free_slot(self.pos) if self.sizer.is_virtual() and not self.sizer.is_fixed(): WindowBase.remove(self) else: # focus the freed slot misc.set_focused_widget(self.sizer.children[self.pos].item)
def on_change_selection(self, event): if self.skip_select: return # triggered by self.SelectItem in self.set_current_widget item = event.GetItem() widget = self._GetItemData(item).widget self._set_cur_widget(widget) misc.set_focused_widget(widget) if not self.IsExpanded(item): self.Expand(item) self.SetFocus()
def on_change_selection(self, event): if self.skip_select: return # triggered by self.SelectItem in self.set_current_widget item = event.GetItem() editor = self._GetItemData(item) self._set_cur_widget(editor) misc.set_focused_widget(editor) if not self.IsExpanded(item) and (not hasattr(self, "HasFocus") or not self.HasFocus()): self.Expand(item) self.SetFocus()
def remove(self): # entry point from GUI i = self.index EditBase.remove(self, focus=False) if i >= len(self.parent.children): i = len(self.parent.children) - 1 # set focused widget if i >= 0: misc.set_focused_widget(self.parent.children[i]) else: misc.set_focused_widget(self.parent)
def new_app(self): "creates a new wxGlade project" if self.ask_save(): common.app_tree.clear() common.app_tree.app.new() common.app_tree.app.filename = None common.app_tree.app.saved = True self.user_message("") common.remove_autosaved() if config.preferences.autosave and self.autosave_timer is not None: self.autosave_timer.Start() misc.set_focused_widget(common.app_tree.root.widget)
def end_drag(self, evt): # move or copy a node including children; re-uses clipboard functionality copy = wx.GetKeyState( wx.WXK_CONTROL) # if Ctrl key is pressed, we will copy src = self._dragged_item # was set in begin_drag dst = evt.GetItem() self._dragged_item = None if src is dst: return # from tree items to nodes to widgets src_node = self.GetPyData(src) dst_node = self.GetPyData(dst) if dst_node is None: return src_widget = src_node.widget dst_widget = dst_node.widget if src_widget == dst_widget: return if not copy and src_widget is misc.focused_widget: if hasattr(src_widget, "parent"): misc.set_focused_widget(src_widget.parent) elif hasattr(src_widget, "window"): # a sizer misc.set_focused_widget(src_widget.window) # do some checks before cutting ################################################################################ # avoid dragging of an item on it's child if dst_node.has_ancestor(src_node): return # possible to paste here? compatible = dst_widget.check_compatibility(src_widget) if not compatible: return if compatible == "AddSlot": # dropped on a sizer -> add slot dst_widget._add_slot() dst_widget.layout() dst_widget = dst_widget.children[-1].item # the slot elif compatible == "Slot": # insert a slot or fill empty slot pos = dst_widget.pos dst_widget.sizer._insert_slot(pos) dst_widget = dst_widget.sizer.children[pos].item # the slot if not hasattr(dst_widget, "clipboard_paste"): return # use cut and paste functionality from clipboard to do the actual work ######################################### import clipboard data = clipboard.get_copy(src_widget) if not copy: src_widget.remove() dst_widget.clipboard_paste(None, data) self.expand(dst_node)
def remove_tab(self, index): # for context menu of an empty page / Slot instance indices = [i for i in range(0, len(self.tabs)) if i != index] old_labels = [tab[0] for tab in self.tabs] del self.properties["tabs"].value[index] self.set_tabs(old_labels, indices) if self.children: if index >= len(self.children): index -= 1 misc.set_focused_widget(self.children[index]) else: misc.set_focused_widget(self)
def OnData(self, x,y,default): compatible, message = self._check_compatibility(x,y) if not compatible: return wx.DragCancel dst_widget = self.window.find_editor_by_pos(x,y) if _current_drag_source: src_widget = _current_drag_source # was set in begin_drag copy = (default==wx.DragCopy) if not copy and _current_drag_source is misc.focused_widget: if hasattr(_current_drag_source, "parent"): misc.set_focused_widget(_current_drag_source.parent) elif hasattr(_current_drag_source, "window"): # a sizer misc.set_focused_widget(_current_drag_source.window) if compatible=="AddSlot": # dropped on a sizer -> add slot dst_widget._add_slot() dst_widget.layout() dst_widget = dst_widget.children[-1] # the slot elif compatible=="Slot": # insert a slot or fill empty slot pos = dst_widget.pos dst_widget.sizer._insert_slot(pos) dst_widget = dst_widget.sizer.children[pos] # the slot elif compatible=="Reorder": # a toplevel dragged onto another toplevel # internal drag: just re-order; external drag: paste before src_index = common.root.children.index(src_widget) dst_index = common.root.children.index(dst_widget) common.root.children.insert(dst_index, src_widget) if src_index>dst_index: del common.root.children[src_index+1] else: del common.root.children[src_index] common.app_tree.SortChildren(common.root.item) # this does sort one level only return default if not hasattr(dst_widget, "clipboard_paste"): return wx.DragCancel # use cut and paste functionality from clipboard to do the actual work ######################################### fmt = self._get_received_format() data = self.data_objects[fmt].GetData() # the data as string self.fmt = None if wx.Platform=="__WXMAC__": # delay action, as otherwise there will be a segmentation fault; 50ms seems to be enough wx.CallLater(50, self._OnData, _current_drag_source, src_widget, dst_widget, data, copy) else: wx.CallAfter(self._OnData, _current_drag_source, src_widget, dst_widget, data, copy) return default
def undo(self): owner = common.root.find_widget_from_path(self.path) p = owner.properties[self.name] self.old.set(p) changed = [self.name] for path, name, old, new in self.dependent: changed.append(name) if path == self.path: old.set(owner.properties[name]) else: owner_ = common.root.find_widget_from_path(self.path) old.set(owner_.properties[name]) owner.properties_changed(changed) misc.set_focused_widget(owner)
def OnData(self, x, y, default): compatible, message = self._check_compatibility(x, y) if not compatible: return wx.DragCancel dst_widget = self.window.find_widget_by_pos(x, y) dst_node = dst_widget.node if _current_drag_source: src_widget = _current_drag_source # was set in begin_drag src_node = src_widget.node copy = (default == wx.DragCopy) if not copy and _current_drag_source is misc.focused_widget: if hasattr(_current_drag_source, "parent"): misc.set_focused_widget(_current_drag_source.parent) elif hasattr(_current_drag_source, "window"): # a sizer misc.set_focused_widget(_current_drag_source.window) if compatible == "AddSlot": # dropped on a sizer -> add slot dst_widget._add_slot() dst_widget.layout() dst_widget = dst_widget.children[-1] # the slot elif compatible == "Slot": # insert a slot or fill empty slot pos = dst_widget.pos dst_widget.sizer._insert_slot(pos) dst_widget = dst_widget.sizer.children[pos] # the slot if not hasattr(dst_widget, "clipboard_paste"): return wx.DragCancel # use cut and paste functionality from clipboard to do the actual work ######################################### fmt = self._get_received_format() data = self.data_objects[fmt].GetData() # the data as string self.fmt = None if _current_drag_source and not copy: with src_widget.frozen(): src_widget.remove() dst_widget.clipboard_paste(data) else: dst_widget.clipboard_paste(data) common.app_tree.expand(dst_node) return default
def show_toplevel(self, event, widget=None): "Event handler for left double-clicks: if the click is above a toplevel widget and this is hidden, shows it" if widget is None: try: x, y = event.GetPosition() except AttributeError: # if we are here, event is a CommandEvent and not a MouseEvent node = self._GetItemData(self.GetSelection()) self.expand(node) # if we are here, the widget must be shown else: node = self._find_node_by_pos(x, y, toplevels_only=True) else: node = widget.node if node is None or node is self.root: return # the actual toplevel widget may be one level higher, e.g. for a Panel, which is embedded in a Frame set_size = None if getattr(node.widget, "_is_toplevel_window", False) or getattr( node.widget, "_is_toplevel", False): # toplevel window or a menu/status bar toplevel_widget = node.widget.widget size_p = node.widget.properties.get("size") toolbar_p = node.widget.properties.get("toolbar") if size_p is not None and size_p.is_active( ) and toolbar_p is not None and toolbar_p.value: # apply workaround for size changes due to a toolbar; this would cause problems with automatic testing set_size = size_p.get_size() else: toplevel_widget = node.widget.widget.GetParent() if not node.widget.is_visible(): # added by rlawson to expand node on showing top level widget self.expand(node) self._show_widget_toplevel(node) if wx.Platform != '__WXMSW__' and set_size is not None: toplevel_widget = node.widget.widget # above it was not yet created wx.CallAfter(toplevel_widget.SetSize, set_size) else: toplevel_widget.GetTopLevelParent().Hide() # added by rlawson to collapse only the toplevel node, not collapse back to root node self.select_item(node) misc.set_focused_widget(node.widget) if event: event.Skip() if "design" in node.widget.properties: node.widget.design.update_label()
def remove(self): # entry point from GUI common.root.saved = False # update the status of the app if self.parent.WX_CLASS in ("wxNotebook", ): self.parent.remove_tab(self.pos) return # set focused widget i = self.pos self._remove() if i >= len(self.parent.children): i = len(self.parent.children) - 1 misc.rebuild_tree(self.parent, recursive=False, focus=False) if i >= 0: misc.set_focused_widget(self.parent.children[i]) else: misc.set_focused_widget(self.parent)
def endElement(self, name): if name == 'object': obj = self.top() self.depth_level -= 1 if not self.depth_level: common.app_tree.auto_expand = True import misc try: # show the first object and update its layout #if self.top_obj.node.parent.widget.is_visible(): # common.app_tree.show_widget(self.top_obj.node) if self.top_obj.node.parent.widget.widget: self.top_obj.create() except AttributeError: self._logger.exception( _('Exception caused by obj: %s'), self.top_obj ) misc.set_focused_widget(self.top_obj) XmlWidgetBuilder.endElement(self, name)
def OnData(self, x, y, default): compatible, message = self._check_compatibility(x, y) if not compatible: return wx.DragCancel dst_widget = self.window.find_widget_by_pos(x, y) if _current_drag_source: src_widget = _current_drag_source # was set in begin_drag src_node = src_widget.node copy = (default == wx.DragCopy) if not copy and _current_drag_source is misc.focused_widget: if hasattr(_current_drag_source, "parent"): misc.set_focused_widget(_current_drag_source.parent) elif hasattr(_current_drag_source, "window"): # a sizer misc.set_focused_widget(_current_drag_source.window) if compatible == "AddSlot": # dropped on a sizer -> add slot dst_widget._add_slot() dst_widget.layout() dst_widget = dst_widget.children[-1] # the slot elif compatible == "Slot": # insert a slot or fill empty slot pos = dst_widget.pos dst_widget.sizer._insert_slot(pos) dst_widget = dst_widget.sizer.children[pos] # the slot if not hasattr(dst_widget, "clipboard_paste"): return wx.DragCancel # use cut and paste functionality from clipboard to do the actual work ######################################### fmt = self._get_received_format() data = self.data_objects[fmt].GetData() # the data as string self.fmt = None if wx.Platform == "__WXMAC__" and compat.IS_CLASSIC: # delay action, as otherwise there will be a segmentation fault; 50ms seems to be enough wx.CallLater(50, self._OnData, _current_drag_source, src_widget, dst_widget, data, copy) else: wx.CallAfter(self._OnData, _current_drag_source, src_widget, dst_widget, data, copy) return default
def _show_widget_toplevel(self, node): # creates/shows the widget of the given toplevel node and all its children if not wx.IsBusy(): wx.BeginBusyCursor() if not node.widget.widget: node.widget.create_widget() node.widget.finish_widget_creation() if node.children: for c in node.children: self.create_widgets(c) node.widget.post_load() node.widget.create() node.widget.widget.Show() misc.set_focused_widget(node.widget) node.widget.widget.Raise() # set the best size for the widget (if no one is given) props = node.widget.properties if 'size' in props and not props['size'].is_active( ) and node.widget.sizer: node.widget.sizer.fit_parent() if wx.IsBusy(): wx.EndBusyCursor()
def destroy_widget(self, level): if self.widget is None: return if misc.currently_under_mouse is self.widget: misc.currently_under_mouse = None self.widget.Hide() if wx.VERSION_STRING != "2.8.12.0": # unbind events to prevent new created (and queued) events self.widget.Bind(wx.EVT_PAINT, None) self.widget.Bind(wx.EVT_RIGHT_DOWN, None) self.widget.Bind(wx.EVT_LEFT_DOWN, None) self.widget.Bind(wx.EVT_MIDDLE_DOWN, None) self.widget.Bind(wx.EVT_ENTER_WINDOW, None) self.widget.Bind(wx.EVT_LEAVE_WINDOW, None) self.widget.Bind(wx.EVT_KEY_DOWN, None) compat.DestroyLater(self.widget) self.widget = None if misc.focused_widget is self: misc.set_focused_widget(None)
def select_item(self, editor): self.skip_select = True self.SelectItem(editor.item) self.skip_select = False self._set_cur_widget(editor) misc.set_focused_widget(self.cur_widget)
def OnData(self, x,y,default): compatible, message = self._check_compatibility(x,y) if not compatible: return wx.DragCancel # workaround for wxPython 4.1 if default == wx.DragNone and hasattr(self, "_last_on_drag_over"): default = self._last_on_drag_over copy = (default==wx.DragCopy) src_widget = None dst_widget = self.window.find_editor_by_pos(x,y) if _current_drag_source: src_widget = _current_drag_source # was set in begin_drag if not copy and _current_drag_source is misc.focused_widget: if hasattr(_current_drag_source, "parent"): misc.set_focused_widget(_current_drag_source.parent) elif hasattr(_current_drag_source, "window"): # a sizer misc.set_focused_widget(_current_drag_source.window) if compatible=="AddSlot": # dropped on a sizer -> add slot dst_widget._add_slot() dst_widget.layout() dst_widget = dst_widget.children[-1] # the slot elif compatible=="Slot": # insert a slot or fill empty slot index = dst_widget.index dst_widget.sizer._insert_slot(index) dst_widget = dst_widget.sizer.children[index] # the slot elif compatible=="Reorder": # a toplevel dragged onto another toplevel # internal drag: just re-order; external drag: paste before src_index = common.root.children.index(src_widget) dst_index = common.root.children.index(dst_widget) common.root.children.insert(dst_index, src_widget) if src_index>dst_index: del common.root.children[src_index+1] else: del common.root.children[src_index] common.app_tree.SortChildren(common.root.item) # this does sort one level only return default fmt = self._get_received_format() self.fmt = None # non-wxglade file dropped ##################################################################################### if fmt=="file.bitmap": bitmap = self.file_data_object.GetFilenames()[0] if not os.path.isfile(bitmap): return wx.DragCancel if dst_widget.IS_SLOT: # fill slot with a StaticBitmap import widgets.static_bitmap.static_bitmap new_widget = widgets.static_bitmap.static_bitmap.builder(dst_widget.parent, dst_widget.index, bitmap) misc.rebuild_tree(new_widget) return default # set attribute value dst_widget.set_attribute(fmt, bitmap) return default # use cut and paste functionality from clipboard to do the actual work ######################################### if not hasattr(dst_widget, "clipboard_paste"): return wx.DragCancel data = self.data_objects[fmt].GetData() # the data as string self.fmt = None if wx.Platform=="__WXMAC__": # delay action, as otherwise there will be a segmentation fault; 50ms were too short sometimes wx.CallLater(100, self._OnData, _current_drag_source, src_widget, dst_widget, data, copy) else: wx.CallAfter(self._OnData, _current_drag_source, src_widget, dst_widget, data, copy) return default
def _on_set_focus(self, event): # don't set focused_widget during event, as this may cause crashes if not misc.focused_widget is self: misc.set_focused_widget(self, delayed=True) event.Skip()
def on_set_focus(self, event): misc.set_focused_widget(self) # here we must call event.Skip() also on Win32 as this we should be able to move the sash event.Skip()
def on_set_focus(self, event): # allow switching of pages misc.set_focused_widget(self) event.Skip()