def __init__(self, filename, id_, item, text): self.filename = filename self.id_ = id_ self.item = item self.original = text self.mtimer = None self.tmrunning = False config = coreaux_api.get_interface_configuration('wxgui') self.DELAY = config.get_int('text_min_upd_time') # Do not set the text now, otherwise for example URLs won't be # highlighted in blue # wx.TE_PROCESS_TAB seems to have no effect... self.area = TextUrlCtrl(editor.tabs[item].panel, value='', style=wx.TE_MULTILINE | wx.TE_DONTWRAP | wx.TE_NOHIDESEL) font = self.area.GetFont() font = wx.Font(font.GetPointSize(), wx.FONTFAMILY_TELETYPE, font.GetStyle(), font.GetWeight(), font.GetUnderlined()) self.area.SetFont(font) # Set the text after setting the font, so for example URLs will be # correctly highlighted in blue self.area.SetValue(text) wx.GetApp().root.accmanager.register_text_ctrl(self.area) self.textctrl_nav_keys = { # The Ctrl+Enter in the menu isn't processed when the TextCtrl is # focused; wx.TE_PROCESS_ENTER seems to have no effect either... wx.WXK_RETURN: self._handle_enter_on_textctrl, wx.WXK_ESCAPE: self._navigate_textctrl_backward, } # wx.TE_PROCESS_TAB seems to have no effect... if not config.get_bool('text_process_tab'): # Note that this natively still lets Ctrl+(Shift+)Tab navigate as # expected self.textctrl_nav_keys[wx.WXK_TAB] = self._handle_tab_on_textctrl self.area.Bind(wx.EVT_KEY_DOWN, self._handle_key_down) self.area.Bind(wx.EVT_TEXT, self._handle_text) editor.apply_editor_event.bind(self._handle_apply) editor.check_modified_state_event.bind( self._handle_check_editor_modified) editor.close_editor_event.bind(self._handle_close)
def __init__(self, parent): wx.SplitterWindow.__init__(self, parent, style=wx.SP_LIVE_UPDATE) self.tree = wx.TreeCtrl(self, style=wx.TR_HAS_BUTTONS | wx.TR_HIDE_ROOT | wx.TR_SINGLE | wx.TR_FULL_ROW_HIGHLIGHT) self.STYLE_HEAD = wx.TextAttr( font=wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) self.STYLE_NORMAL = wx.TextAttr( font=wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.STYLE_BOLD = wx.TextAttr( font=wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) self.STYLE_ITALIC = wx.TextAttr( font=wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_ITALIC, wx.FONTWEIGHT_NORMAL)) self.tree.AddRoot(text='root') self.init_info() self.textw = TextUrlCtrl(self, value='', style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP) self.SplitVertically(self.tree, self.textw) # Prevent the window from unsplitting when dragging the sash to the # border self.SetMinimumPaneSize(20) self.SetSashPosition(120) self.Bind(wx.EVT_SPLITTER_DCLICK, self.veto_dclick) self.tree.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.veto_label_edit) self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.retrieve_info) self.tree.SelectItem( self.tree.GetFirstChild(self.tree.GetRootItem())[0])
class TextArea(object): def __init__(self, filename, id_, item, text): self.filename = filename self.id_ = id_ self.item = item self.original = text self.mtimer = None self.tmrunning = False config = coreaux_api.get_interface_configuration('wxgui') self.DELAY = config.get_int('text_min_upd_time') # Do not set the text now, otherwise for example URLs won't be # highlighted in blue # wx.TE_PROCESS_TAB seems to have no effect... self.area = TextUrlCtrl(editor.tabs[item].panel, value='', style=wx.TE_MULTILINE | wx.TE_DONTWRAP | wx.TE_NOHIDESEL) font = self.area.GetFont() font = wx.Font(font.GetPointSize(), wx.FONTFAMILY_TELETYPE, font.GetStyle(), font.GetWeight(), font.GetUnderlined()) self.area.SetFont(font) # Set the text after setting the font, so for example URLs will be # correctly highlighted in blue self.area.SetValue(text) wx.GetApp().root.accmanager.register_text_ctrl(self.area) self.textctrl_nav_keys = { # The Ctrl+Enter in the menu isn't processed when the TextCtrl is # focused; wx.TE_PROCESS_ENTER seems to have no effect either... wx.WXK_RETURN: self._handle_enter_on_textctrl, wx.WXK_ESCAPE: self._navigate_textctrl_backward, } # wx.TE_PROCESS_TAB seems to have no effect... if not config.get_bool('text_process_tab'): # Note that this natively still lets Ctrl+(Shift+)Tab navigate as # expected self.textctrl_nav_keys[wx.WXK_TAB] = self._handle_tab_on_textctrl self.area.Bind(wx.EVT_KEY_DOWN, self._handle_key_down) self.area.Bind(wx.EVT_TEXT, self._handle_text) editor.apply_editor_event.bind(self._handle_apply) editor.check_modified_state_event.bind( self._handle_check_editor_modified) editor.close_editor_event.bind(self._handle_close) def _handle_key_down(self, event): try: self.textctrl_nav_keys[event.GetKeyCode()](event) except KeyError: event.Skip() # Don't skip the event if the navigation is done #event.Skip() def _handle_enter_on_textctrl(self, event): # This method must get the same arguments as # _navigate_textctrl_backward if event.ControlDown(): if event.ShiftDown(): for item in editor.tabs: editor.tabs[item].apply() else: editor.tabs[self.item].apply() else: event.Skip() def _handle_tab_on_textctrl(self, event): # This method must get the same arguments as # _navigate_textctrl_backward # Note that this natively still lets Ctrl+(Shift+)Tab navigate as # expected if event.ShiftDown(): self._navigate_textctrl_backward(event) else: self.area.Navigate(flags=wx.NavigationKeyEvent.IsForward) def _navigate_textctrl_backward(self, event): # This method must get the same arguments as _handle_tab_on_textctrl try: captionbar = editor.tabs[self.item].get_plugin_captionbars()[-1] except IndexError: # No plugins installed/enabled self.area.Navigate(flags=wx.NavigationKeyEvent.IsBackward) else: if captionbar.IsCollapsed(): captionbar.SetFocus() else: self.area.Navigate(flags=wx.NavigationKeyEvent.IsBackward) def _handle_text(self, event): if not (self.tmrunning): # Always set modified when (re)starting the timer, in fact it's not # possible that the textarea can be unmodified, except for the # only case where the original state is actually restored, but in # that case the modified state will be restored to False anyway if # and when the timer executes its action self.area.SetModified(True) else: self.mtimer.cancel() self.tmrunning = True self.mtimer = Timer(self.DELAY, self._reset_timer) self.mtimer.name = "wxtextarea" self.mtimer.start() event.Skip() def _reset_timer(self): self.tmrunning = False self._set_modified() def _set_modified(self): if self.area.GetValue() == self.original: self.area.SetModified(False) else: self.area.SetModified(True) def _reset_modified(self): self.original = self.area.GetValue() self.area.SetModified(False) def _is_modified(self): self._set_modified() return self.area.IsModified() def _handle_apply(self, kwargs): if kwargs['filename'] == self.filename and kwargs['id_'] == self.id_ \ and self._is_modified(): core_api.update_item_text(self.filename, self.id_, self.area.GetValue(), kwargs['group'], kwargs['description']) self._refresh_mod_state() def _refresh_mod_state(self): treedb = tree.dbs[self.filename] tabtitle = editor.Editor.make_title(self.area.GetLineText(0)) wx.GetApp().nb_right.set_editor_title(self.item, tabtitle) self._reset_modified() def _handle_check_editor_modified(self, kwargs): if kwargs['filename'] == self.filename and kwargs['id_'] == self.id_ \ and self._is_modified(): editor.tabs[self.item].set_modified() def _handle_close(self, kwargs): if kwargs['filename'] == self.filename and kwargs['id_'] == self.id_: if self.mtimer: self.mtimer.cancel() # It's necessary to explicitly unbind the handlers, otherwise this # object will never be garbage-collected due to circular # references, and the automatic unbinding won't work editor.apply_editor_event.bind(self._handle_apply, False) editor.check_modified_state_event.bind( self._handle_check_editor_modified, False) editor.close_editor_event.bind(self._handle_close, False) def cut(self): self.area.Cut() def copy(self): self.area.Copy() def paste(self): self.area.Paste() def select_all(self): self.area.SetSelection(-1, -1) def can_cut(self): return self.area.CanCut() def can_copy(self): return self.area.CanCopy() def can_paste(self): return self.area.CanPaste()
class InfoBox(wx.SplitterWindow): tree = None textw = None STYLE_HEAD = None STYLE_NORMAL = None STYLE_BOLD = None STYLE_ITALIC = None def __init__(self, parent): wx.SplitterWindow.__init__(self, parent, style=wx.SP_LIVE_UPDATE) self.tree = wx.TreeCtrl(self, style=wx.TR_HAS_BUTTONS | wx.TR_HIDE_ROOT | wx.TR_SINGLE | wx.TR_FULL_ROW_HIGHLIGHT) self.STYLE_HEAD = wx.TextAttr( font=wx.Font(14, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) self.STYLE_NORMAL = wx.TextAttr( font=wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_NORMAL)) self.STYLE_BOLD = wx.TextAttr( font=wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_NORMAL, wx.FONTWEIGHT_BOLD)) self.STYLE_ITALIC = wx.TextAttr( font=wx.Font(10, wx.FONTFAMILY_DEFAULT, wx.FONTSTYLE_ITALIC, wx.FONTWEIGHT_NORMAL)) self.tree.AddRoot(text='root') self.init_info() self.textw = TextUrlCtrl(self, value='', style=wx.TE_MULTILINE | wx.TE_READONLY | wx.TE_DONTWRAP) self.SplitVertically(self.tree, self.textw) # Prevent the window from unsplitting when dragging the sash to the # border self.SetMinimumPaneSize(20) self.SetSashPosition(120) self.Bind(wx.EVT_SPLITTER_DCLICK, self.veto_dclick) self.tree.Bind(wx.EVT_TREE_BEGIN_LABEL_EDIT, self.veto_label_edit) self.tree.Bind(wx.EVT_TREE_SEL_CHANGED, self.retrieve_info) self.tree.SelectItem( self.tree.GetFirstChild(self.tree.GetRootItem())[0]) def init_info(self): self.tree.AppendItem(self.tree.GetRootItem(), text='License', data=wx.TreeItemData({'req': 'lic'})) self.tree.AppendItem(self.tree.GetRootItem(), text='Info', data=wx.TreeItemData({'req': 'cor'})) # Do not use the configuration because it could have entries about # addons that aren't actually installed addons = coreaux_api.get_components_info()["addons"] for type_ in ('Extensions', 'Interfaces', 'Plugins'): typeitem = self.tree.AppendItem(self.tree.GetRootItem(), text=type_, data=wx.TreeItemData({ 'req': 'lst', 'type_': type_ })) for addon in addons[type_]: self.tree.AppendItem(typeitem, text=addon, data=wx.TreeItemData({ 'req': 'inf', 'type_': type_, 'addon': addon })) def compose_license(self): self.textw.AppendText(coreaux_api.get_license()) def compose_main_info(self): coreinfo = coreaux_api.get_core_info() self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('Core version: ') self.textw.SetDefaultStyle(self.STYLE_NORMAL) self.textw.AppendText(coreinfo.version) self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\nWebsite: ') self.textw.SetDefaultStyle(self.STYLE_NORMAL) self.textw.AppendText(coreinfo.website) self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\nAuthor: ') self.textw.SetDefaultStyle(self.STYLE_NORMAL) self.textw.AppendText('Dario Giovannetti <*****@*****.**>') self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\nContributors: ') self.textw.SetDefaultStyle(self.STYLE_NORMAL) try: contributors = coreinfo.contributors except AttributeError: pass else: for c in contributors: self.textw.AppendText('\n\t{}'.format(c)) self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\n\nInstalled components:') self.textw.SetDefaultStyle(self.STYLE_NORMAL) cinfo = coreaux_api.get_components_info()["info"] for cname in cinfo: self.textw.AppendText('\n\t{} {} ({})'.format( cname, cinfo[cname].version, cinfo[cname].release_date)) def compose_addon_info(self, type_, addon): info = { "Extensions": coreaux_api.import_extension_info, "Interfaces": coreaux_api.import_interface_info, "Plugins": coreaux_api.import_plugin_info, }[type_](addon) config = coreaux_api.get_configuration()(type_)(addon) self.textw.SetDefaultStyle(self.STYLE_HEAD) self.textw.AppendText('{}\n'.format(addon)) self.textw.SetDefaultStyle(self.STYLE_NORMAL) self.textw.AppendText('{}\n'.format(info.description)) self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\nEnabled: ') self.textw.SetDefaultStyle(self.STYLE_NORMAL) self.textw.AppendText('yes' if config.get_bool('enabled') else 'no') self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\nVersion: ') self.textw.SetDefaultStyle(self.STYLE_NORMAL) self.textw.AppendText(info.version) self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\nWebsite: ') self.textw.SetDefaultStyle(self.STYLE_NORMAL) self.textw.AppendText(info.website) self.textw.SetDefaultStyle(self.STYLE_BOLD) if len(info.authors) > 1: self.textw.AppendText('\nAuthors:') self.textw.SetDefaultStyle(self.STYLE_NORMAL) for a in info.authors: self.textw.AppendText('\n\t{}'.format(a)) else: self.textw.AppendText('\nAuthor: ') self.textw.SetDefaultStyle(self.STYLE_NORMAL) self.textw.AppendText(info.authors[0]) self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\nContributors:') self.textw.SetDefaultStyle(self.STYLE_NORMAL) try: contributors = info.contributors except AttributeError: pass else: for c in contributors: self.textw.AppendText('\n\t{}'.format(c)) self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\nComponent: ') self.textw.SetDefaultStyle(self.STYLE_NORMAL) cinfo = coreaux_api.get_components_info() cname = cinfo["addons"][type_][addon] component = cinfo["info"][cname] self.textw.AppendText('{} {} ({})'.format(cname, component.version, component.release_date)) self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\nDependencies:') self.textw.SetDefaultStyle(self.STYLE_NORMAL) try: deps = info.dependencies except AttributeError: pass else: for d in deps: self.textw.AppendText('\n\t{} {}.x'.format(*d)) self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('\nOptional dependencies:') self.textw.SetDefaultStyle(self.STYLE_NORMAL) try: opts = info.optional_dependencies except AttributeError: pass else: for o in opts: self.textw.AppendText('\n\t{} {}.x'.format(*o)) def compose_list(self, type_): # Do not use the configuration because it could have entries about # addons that aren't actually installed info = coreaux_api.get_components_info()["addons"] self.textw.SetDefaultStyle(self.STYLE_BOLD) self.textw.AppendText('{}:\n'.format(type_)) for addon in info[type_]: config = coreaux_api.get_configuration()(type_)(addon) if config.get_bool('enabled'): self.textw.SetDefaultStyle(self.STYLE_NORMAL) self.textw.AppendText('\t{}\n'.format(addon)) else: self.textw.SetDefaultStyle(self.STYLE_ITALIC) self.textw.AppendText('\t{} [disabled]\n'.format(addon)) def veto_dclick(self, event): event.Veto() def veto_label_edit(self, event): event.Veto() def retrieve_info(self, event): self.textw.Clear() self.textw.SetDefaultStyle(self.STYLE_NORMAL) data = self.tree.GetPyData(event.GetItem()) if data['req'] == 'lic': self.compose_license() elif data['req'] == 'cor': self.compose_main_info() elif data['req'] == 'lst': self.compose_list(data['type_']) elif data['req'] == 'inf': self.compose_addon_info(data['type_'], data['addon']) # Scroll back to top self.textw.ShowPosition(0)