class FormattingBar(ToolBar, NewSkinModule): initover = False def __init__(self, parent, textctrl, skinkey, formatOptions): ToolBar.__init__(self, parent, skinkey = None, alignment = wx.ALIGN_LEFT) self.SetSkinKey(skinkey, FormattingBarSkinDefaults) self.textctrl = textctrl if sys.platform.startswith("win"): textctrl.Bind(EVT_SELECTION_CHANGED, self.OnCursorMove) textctrl.Bind(EVT_TEXT_FORMAT_CHANGED, self.OnCursorMove) self.Bind(wx.EVT_CONTEXT_MENU, self.OnContextMenu) self.fontdd = FontDropDown(self, skinkey = self.skinTB['buttonskin']) self.fontdd.SetMenuSkinKey(self.skinTB["menuskin"]) self.fontdd.Bind(wx.EVT_COMMAND_CHOICE_SELECTED, self.OnFontSelected) icons = self.icons self.msize = SimpleMenu(self, self.skinTB['menuskin'], maxheight = 10) self.msize.SetItems(self.GenSizeItems(DEFAULT_SIZES)) #TODO: None default sizes # self.msize.Bind(wx.EVT_COMMAND_CHOICE_SELECTED, self.OnSizeSelected) self.bsize = UberButton(self, -1, '10', menu = self.msize, type = 'menu') self.bsize.SetStaticWidth(self.skinFB['sizedropdownwidth']) self.msize.SetWidth(self.skinFB['sizedropdownwidth']) self.bbold = UberButton(self, -1, icon = icons['bold'], type = 'toggle') self.bbold.Bind(wx.EVT_TOGGLEBUTTON, self.OnBoldButton) self.bitalic = UberButton(self, -1, icon = icons['italic'], type="toggle") self.bitalic.Bind(wx.EVT_TOGGLEBUTTON, self.OnItalicButton) self.bunderline = UberButton(self, -1, icon = icons['underline'], type="toggle") self.bunderline.Bind(wx.EVT_TOGGLEBUTTON, self.OnUnderlineButton) self.bcolor = UberButton(self, -1, icon = icons['foregroundcolor'] ) self.bcolor.Bind(wx.EVT_BUTTON, self.OnColorButton) self.bbgcolor = UberButton(self,-1, icon = icons['backgroundcolor']) self.bbgcolor.Bind(wx.EVT_BUTTON, self.OnBGColorButton) self.bemote = UberButton(self, -1, icon = icons['emote']) self.bemote.Bind(wx.EVT_BUTTON, self.OnEmoteButton) # import pdb # pdb.set_trace() self.AddMany([self.fontdd, self.bsize, self.bbold, self.bitalic, self.bunderline, self.bcolor, self.bbgcolor, self.bemote]) self.initover = True self.EnableFormattingButtons(formatOptions) self.UpdateDisplay() def OnContextMenu(self, event): from gui.uberwidgets.umenu import UMenu m = UMenu(self) m.AddItem(_('Hide Formatting Bar'), callback = lambda: wx.CallAfter(setpref, 'messaging.show_formatting_bar', False)) m.PopupMenu() def OnFontSelected(self, event): """ Updates the button to the new font and applies it to the selection or calls ApplyStlye """ self.textctrl.ApplyStyle(facename = self.fontdd.GetClientData(self.fontdd.GetSelection()).GetFaceName()) def OnSizeSelected(self, item): """ Updates the Size button to the new size and applies it to the selection or calls ApplyStyle """ self.bsize.label = str(item.id) self.textctrl.ApplyStyle(pointsize = item.id) def OnBoldButton(self, event): self.textctrl.ApplyStyle(bold = event.EventObject.IsActive()) def OnItalicButton(self, event): self.textctrl.ApplyStyle(italic = event.EventObject.IsActive()) def OnUnderlineButton(self, event): self.textctrl.ApplyStyle(underline = event.EventObject.IsActive()) def OnColorButton(self, event): oldtextcolor = self.textctrl.GetFormat().GetTextColour() self.textctrl.ApplyStyle(textcolor = wx.GetColourFromUser(self, oldtextcolor, _('Choose a foreground color'))) def OnBGColorButton(self, event): oldbgcolor = self.textctrl.GetFormat().GetTextColour() self.textctrl.ApplyStyle(bgcolor = wx.GetColourFromUser(self, oldbgcolor, _('Choose a background color'))) def OnEmoteButton(self, event): self.DisplayEmotibox(self.bemote.ScreenRect) def DisplayEmotibox(self, rect): import hooks hooks.notify('digsby.statistics.emoticons.box_viewed') ebox = self.GetEmotibox() # position and display the emotibox ebox.Display(rect) def GetEmotibox(self): 'Shares the emoticon box between all instances of this class.' b = None old_name, new_name = getattr(self, '_emotipack_name', None), pref('appearance.conversations.emoticons.pack', type = unicode, default = u'default') self._emotipack_name = new_name try: b = self.__class__.emotibox if not wx.IsDestroyed(b): if old_name != new_name: b.Destroy() elif b.Parent is not self: b.Reparent(self) except AttributeError: pass if b is None or wx.IsDestroyed(b): from gui.imwin.emoticons import get_emoticon_bitmaps b = self.__class__.emotibox = UberEmotiBox(self, get_emoticon_bitmaps(self._emotipack_name), self.textctrl, maxwidth = 12) else: b.SetTextCtrl(self.textctrl) return b def OnCursorMove(self, event): event.Skip() wx.CallAfter(self.UpdateDisplay) def UpdateDisplay(self): if wx.IsDestroyed(self.textctrl): return selection = self.textctrl.GetSelection() if selection[0] != selection[1]: return textattr = self.textctrl.GetFormat() font = textattr.GetFont() facename = font.GetFaceName() self.fontdd.SetSelection(self.fontdd.FindString(facename, False)) self.bsize.SetLabel(str(font.GetPointSize())) self.bbold.Active(font.GetWeight() == wx.FONTWEIGHT_BOLD) self.bitalic.Active(font.GetStyle() == wx.FONTSTYLE_ITALIC) self.bunderline.Active(font.GetUnderlined()) def EnableFormattingButtons(self, enabledict): if enabledict is None: return default = enabledict['default'] if 'default' in enabledict else True #TODO: fontdd should be disableable buttons = [#('font', self.fontdd), ('size', self.bsize), ('bold', self.bbold), ('italic', self.bitalic), ('underline', self.bunderline), ('color', self.bcolor), ('bgcolor', self.bbgcolor), ('emote', self.bemote)] for key, button in buttons: button.Enable(enabledict[key] if key in enabledict else default) def GenSizeItems(self, sizes = DEFAULT_SIZES): """ Sets the list of selectable sizes If not set sizes default to ['8', '10', '12', '14', '18', '24', '36'] """ return [SimpleMenuItem([str(size)], id=size, method = self.OnSizeSelected) for size in sizes] def DoUpdateSkin(self, skin): self.skinFB = skin ToolBar.DoUpdateSkin(self, SkinProxy(skin['toolbarskin'], ToolBarSkinDefaults)) icons = self.icons = {} icons['bold'] = skin['icons.bold'] icons['italic'] = skin['icons.italic'] icons['underline'] = skin['icons.underline'] icons['foregroundcolor'] = skin['icons.foregroundcolor'] icons['backgroundcolor'] = skin['icons.backgroundcolor'] icons['emote'] = skin['icons.emote'] iconsize = skin['iconsize'] for key in icons: if icons[key] is not None: icons[key] = icons[key].Resized(iconsize) if self.initover: self.bsize.SetStaticWidth(skin['sizedropdownwidth']) self.msize.SetWidth(skin['sizedropdownwidth']) self.bbold.SetIcon(icons['bold']) self.bitalic.SetIcon(icons['italic']) self.bunderline.SetIcon(icons['underline']) self.bcolor.SetIcon(icons['foregroundcolor']) self.bbgcolor.SetIcon(icons['backgroundcolor']) self.bemote.SetIcon(icons['emote']) def GetSkinProxy(self): return self.skinFB if hasattr(self, 'skinFB') else None
class P(wx.Panel): def __init__(self,parent): wx.Panel.__init__(self,parent,-1)#,style = wx.CLIP_CHILDREN|wx.CLIP_SIBLINGS self.Bind(wx.EVT_BUTTON,self.onButton), self.Bind(wx.EVT_LEFT_UP,self.OnMouse), self.Bind(wx.EVT_LEFT_DOWN,self.OnMouse) self.skin = 'button' # print self.skin # self.menu=UMenu(self) # self.menu.Append(wx.NewId(),'item 1') # self.menu.Append(wx.NewId(),'item 2') # self.menu.Append(wx.NewId(),'item 3') content=wx.BoxSizer(wx.VERTICAL) size=None#(200,50)# type=None#'menu'#'toggle'#'toggle'# menu=None#self.menu# icon=wx.Bitmap('../../../../res/skins/default/statusicons/mobile.png',wx.BITMAP_TYPE_PNG)#wx.Bitmap('../../res/skins/default/tinydigsby.png',wx.BITMAP_TYPE_PNG) #label= "button"#"Super wide Button Name of Impending doooooooooooom!!!"#"button"# skin=self.skin#None# self.b1=UberButton(self,wx.NewId(),'&One',skin,icon=icon,style=wx.HORIZONTAL,size=size,type=type,menu=menu) # self.b1.SetStaticWidth(60) self.b2=UberButton(self,wx.NewId(),'&Two',icon=icon,style=wx.HORIZONTAL,size=size,type=type,menu=menu) self.b3=UberButton(self,wx.NewId(),'T&hree',skin,icon=icon,style=wx.VERTICAL,size=size,type=type,menu=menu) self.b4=UberButton(self,wx.NewId(),'&Four',icon=icon,style=wx.VERTICAL,size=size,type=type,menu=menu) self.b5=UberButton(self,wx.NewId(),"",skin,icon=icon,size=size,type=type,menu=menu) self.b6=UberButton(self,wx.NewId(),"",icon=icon,size=size,type=type,menu=menu) self.b7=UberButton(self,wx.NewId(),'Fi&ve',skin,size=size,type=type,menu=menu) self.b8=UberButton(self,wx.NewId(),'&Six',size=size,type=type,menu=menu) self.b9=UberButton(self,wx.NewId(),"",skin,size=size,type=type,menu=menu) self.b10=UberButton(self,wx.NewId(),"",size=size,type=type,menu=menu) self.b11 = wx.Button(self, wx.NewId(), 'Native') self.b12= wx.Button(self, wx.NewId(), ' ') self.b12.Bind(wx.EVT_BUTTON,self.ToggleAlignment) self.b13 = UberButton(self, wx.NewId(), 'active?', self.skin) self.b13.Bind(wx.EVT_BUTTON,self.ToggleSkin) wexp = 0#wx.EXPAND#wx.ALL| hrat = 0#1# pad = 0 content.Add(self.b1,hrat,wexp,pad) content.Add(self.b2,hrat,wexp,pad) content.Add(self.b3,hrat,wexp,pad) content.Add(self.b4,hrat,wexp,pad) content.Add(self.b5,hrat,wexp,pad) content.Add(self.b6,hrat,wexp,pad) content.Add(self.b7,hrat,wexp,pad) content.Add(self.b8,hrat,wexp,pad) content.Add(self.b9,hrat,wexp,pad) content.Add(self.b10,hrat,wexp,pad) content.Add(self.b11,hrat,wexp,pad) content.Add(self.b12,hrat,wexp,pad) content.Add(self.b13, hrat, wexp, pad) self.SetSizer(content) def onButton(self,event): print event.GetEventObject().Label # print "..." # if type(event.EventObject)==wx.Button: # print event.EventObject.Label # else: # print event.EventObject.label # switch= not self.b1.IsEnabled() # self.b1.Enable(switch) # self.b2.Enable(switch) # self.b3.Enable(switch) # self.b4.Enable(switch) # self.b5.Enable(switch) # self.b6.Enable(switch) # self.b7.Enable(switch) # self.b8.Enable(switch) # self.b9.Enable(switch) # self.b10.Enable(switch) # self.b11.Enable(switch) def ToggleSkin(self,event = None): key = None if self.b1.skinkey else 'button' print 'toggleskin to',key self.b1.SetSkinKey(key,1) self.b3.SetSkinKey(key,1) self.b5.SetSkinKey(key,1) self.b7.SetSkinKey(key,1) self.b9.SetSkinKey(key,1) def ToggleAlignment(self,event = None): print "ToggleAlignment DISABLED!!! It can not be!!!" # align = wx.VERTICAL if self.b1.Alignment == wx.HORIZONTAL else wx.HORIZONTAL # self.b1.Alignment = align # self.b3.Alignment = align # self.b5.Alignment = align # self.b7.Alignment = align # self.b9.Alignment = align # self.Layout() def OnMouse(self,event): print "window caught mouse"
class StatusCombo(UberCombo): # number of milliseconds to wait after clicking the status button before the # status is set (if the user hasn't entered any text) set_delay = 3000 def __init__(self, parent, buddylist, statuses, get_status_method=get_profile_status, set_status_method=set_profile_status): ''' StatusCombo constructor. parent - a wx.Window parent window statuses - an observable list of StatusMessage objects ''' self.buddylist = buddylist self.buddylist.Bind(wx.EVT_KEY_DOWN, self.on_buddylist_key) self.searching = False self.searchHintShown = False if not getattr(StatusCombo, 'searchThresholdRegistered', False) and pref('search.buddylist.show_hint', True): def SearchThresholdReached(*a, **k): if pref('search.buddylist.show_hint', True): setpref('search.buddylist.show_hint', False) Hook('digsby.achievements.threshold', 'buddylist.search').register(SearchThresholdReached) StatusCombo.searchThresholdRegistered = True self.offline_item = None self.get_profile_status = get_status_method self.set_profile_status = set_status_method status = self.get_profile_status() UberCombo.__init__(self, parent, skinkey='combobox', typeable=True, valuecallback=self.on_text_lose_focus, empty_text=getattr(status, 'hint', status.title.title()), maxmenuheight=15) self.buttoncallback = self.on_status_button self.cbutton = UberButton(self, -1, skin=self.cbuttonskin) self.cbutton.Bind(wx.EVT_BUTTON, self._on_left_button) self.content.Insert(0, self.cbutton, 0, wx.EXPAND) self.cbutton.BBind(RIGHT_UP=self.on_status_button_right_click, LEFT_DOWN=self.on_status_button_left_click, LEFT_UP=self.on_status_button_left_up) self.display.Bind( wx.EVT_LEFT_DOWN, lambda e: (e.Skip(), setattr(self, 'oldValue', self.Value))) # the on_allow_status_changes method is called when the list of connected # im accounts changes size. if all accounts are offline this control # becomes disabled.. #profile.account_manager.connected_accounts.add_observer(self.on_allow_status_changes) profile.account_manager.connected_accounts.add_observer( self.on_offline_allowed, obj=self) # Listen on status messages (changes, additions, deletes). _obs_link = statuses.add_list_observer(self.on_status_messages_changed, self.on_status_messages_changed) self.Bind( wx.EVT_WINDOW_DESTROY, lambda e: (log.info('status combo removing observers'), e.Skip(), _obs_link.disconnect())) self.on_status_messages_changed(statuses) # when the profile's status changes, update to reflect it profile.add_observer(self.on_profile_status_changed, 'status') # Display the current status. self.show_status(self.get_profile_status()) # Timer for committing status messages after a delay. self.timer = wx.PyTimer(self.SetFocus) self.Bind(wx.EVT_TEXT, self.on_typing) self.button_timer = wx.PyTimer(self.on_status_button_right_click) textbind = self.TextField.Bind textbind(wx.EVT_SET_FOCUS, lambda e: setattr(self, 'skipenter', False)) textbind(wx.EVT_KEY_DOWN, self._on_key_down) textbind(wx.EVT_TEXT_ENTER, self._on_enter) self.DropDownButton.Bind(wx.EVT_LEFT_DOWN, self._dbutton_left) self.OnActivateSearch = Delegate() self.OnDeactivateSearch = Delegate() def UpdateSkin(self): key = 'statuspanel' if not skin.get(key, False) or skin.get(key + '.mode', '') == 'native': s = lambda k, d: None else: s = lambda k, default: skin.get('%s.%s' % (key, k), default) comboskinkey = s('comboboxskin', None) self.cbuttonskin = cbskinkey = s('statusbuttonskin', None) self.SetSkinKey(comboskinkey) UberCombo.UpdateSkin(self) if hasattr(self, 'cbutton'): self.cbutton.SetSkinKey(cbskinkey, True) self.SetButtonIcon(StatusMessage.icon_for(self.status_state)) if hasattr(self, 'menu') and self.menu: self.on_status_messages_changed() def SetButtonIcon(self, icon): """set the icon for the cycle button""" self.cbutton.SetIcon(icon) self._button_icon = icon self.Layout() def SetCallbacks(self, selection=sentinel, value=sentinel, button=sentinel): 'Sets callbacks for this combobox.' UberCombo.SetCallbacks(self, selection, value) if button is not sentinel: self.buttoncallback = button def on_allow_status_changes(self, *a, **k): if self.Show(profile.allow_status_changes): self.Parent.gui_layout() def setandshow(self, statusmsg): 'Immediately sets the status message and shows it.' log.info('setandshow %r', statusmsg) self.oldValue = None self.show_status(statusmsg) self.set_profile_status(statusmsg) def show_status(self, status, force=False): 'Displays the specified status message.' if not force and status is getattr(self, '_shown_status', None): return # make the text area not editable for statuses like "Invisble" and # "Offline", which have the "editable" attribute set to False self.Editable = status.editable self.display.empty_text = getattr(status, 'hint', '') self.ChangeValue(status.message) # change text self.SetButtonIcon(StatusMessage.icon_for(status)) # change icon self.status_state = status.status # store the state self._shown_status = status # # events # def on_typing(self, e): 'Invoked when the user is typing in the textfield.' if self.searching: search.link_prefs(profile.prefs) e.Skip() self.buddylist.search(e.EventObject.Value) else: self.cancel_timer() def on_status_button(self, button): ''' Invoked when the user clicks the state button to the left of the dropdown. ''' # toggle the control's status state isavail = StatusMessage.is_available_state(self.status_state) # do we need to change the shown text? needs_change = self._shown_status in StatusMessage.SpecialStatuses or not self._shown_status.editable self.oldValue = None self.change_state(state='Away' if isavail else 'Available', ) #change_text = needs_change) def change_state(self, state, change_text=False): if not isinstance(state, basestring): raise TypeError('change_state takes a string got a %s' % type(state)) self.status_state = state if change_text: self.ChangeValue(self.status_state, state.title()) else: self.Default = state.title() edit_toggle = getattr(profile.status, 'edit_toggle', True) if getattr(profile.status, 'edit_toggle', True): # update the icon self.SetButtonIcon(StatusMessage.icon_for(self.status_state)) self.cancel_timer() self.timer.StartOneShot(self.set_delay) # select all text in the textfield disp = self.display disp.TypeField() wx.CallAfter(disp.txtfld.SetSelection, -1, -1) else: self.setandshow( profile.status.copy(status=self.status_state, editable=None, edit_toggle=None)) def on_status_button_left_click(self, e=None): if self.searching: return self.TextField.SetFocus() self.skipenter = True self.button_timer.Start(BUTTON_HOLD_TIME, True) if e: e.Skip(True) def on_status_button_left_up(self, e=None): if not self.searching: self.button_timer.Stop() if e: e.Skip(True) def on_status_button_right_click(self, e=None): if not self.searching: self.show_extended_status_menu() def show_extended_status_menu(self): from gui.status import get_state_choices m = SimpleMenu(self, skinkey=skin.get('%s.MenuSkin' % self.skinkey)) for status in get_state_choices(): statusname, statuslabel = status def onclick(item, state=statusname): self.change_state( state ) #, change_text = self.status_state == self.GetValue()) m.AppendItem( SimpleMenuItem( [StatusMessage.icon_for(statusname), statuslabel], method=onclick)) if m.GetCount() > 0: m.Display(self.cbutton) def on_text_lose_focus(self, new_msg): if self.searching: return self.on_search_timer() # Cancel the status button timer if it's running. self.cancel_timer() if getattr(self, 'skipenter', False): wx.CallAfter(lambda: setattr(self, 'skipenter', False)) else: # don't set status if we lost focus because the user is clicking # on the state button if wx.GetMouseState().LeftDown() and wx.FindWindowAtPoint( wx.GetMousePosition()) is self.cbutton: return profile_status = self.get_profile_status() if new_msg == '': self.display.empty_text = profile_status.hint if new_msg != profile_status.message or self.status_state != profile_status.status: # entering a new text value clears all exceptions newmsg = StatusMessage(new_msg, self.status_state, new_msg) self.set_profile_status(newmsg) def on_profile_status_changed(self, *a): "Invoked when the profile's status changes." self.show_status(profile.status) @calllimit(1) def on_offline_allowed(self, *a): if not self: return show_offline = profile.allow_status_changes if not show_offline and self.offline_item: log.info('removing the offline item') self.RemoveItem(self.offline_item) self.offline_item = None elif show_offline and not self.offline_item: log.info('adding the offline item') self.offline_item = self.additem( [skin.get('statusicons.offline'), _('Offline')], self.on_offline) def additem(self, *a, **k): i = SimpleMenuItem(*a, **k) self.AppendItem(i) return i @calllimit(1) def on_status_messages_changed(self, *a): ''' Invoked when a status message changes, or the user status list changes. Rebuilds the status menu items. ''' log.info('on_status_messages_changed, updating menu') self.RemoveAllItems() additem = self.additem def add_status_item(pname, name): additem([skin.get('statusicons.%s' % pname), name], method=getattr(self, 'on_' + pname)) # Available add_status_item('available', _('Available')) # user statuses self.sortedstatuses = msgs = sorted([c for c in profile.statuses], key=lambda msg: msg.away) # Find where to insert the special "Away" status item j = -1 found = False for j, msg in enumerate(msgs): if msg.away: found = True break for i, msg in enumerate(msgs): if found and i == j: add_status_item('away', _('Away')) online_image = skin.get( 'statusicons.away' if msg.away else 'statusicons.available') additem([online_image, msg.title], method=lambda mi, msg=msg: self.setandshow(msg), id=i) if not found or j == -1: add_status_item('away', _('Away')) # Custom... additem(_('Custom...'), method=self.on_custom) self.AppendSeparator() if global_status_enabled(): additem([skin.get('icons.globalstatus'), _('Global Status')], method=self.on_global) log.info('updating status menu with %d extra statuses', len(Hook('digsby.im.statusmessages'))) for msg in Hook('digsby.im.statusmessages'): message = msg() if message is None: continue additem([message.icon, message.title], method=lambda mi, msg=msg: self.setandshow(msg())) if global_status_enabled(): additem([skin.get('statusicons.promote'), _('Promote Digsby!')], method=self.on_promote) # Invisible additem([skin.get('statusicons.invisible'), _('Invisible')], self.on_invisible) # Offline self.offline_item = None self.on_offline_allowed() # # special entries in the status menu. # def on_offline(self, combo_item): self.setandshow(StatusMessage.Offline) def on_available(self, comboitem): self.show_status(StatusMessage.Available) self.display.TypeField() def on_away(self, comboitem): self.show_status(StatusMessage.Away) self.display.TypeField() def on_custom(self, combo_item): edit_custom_status(self) def on_global(self, combo_item): wx.CallAfter(wx.GetApp().SetStatusPrompt) def on_promote(self, combo_item): wx.CallAfter(wx.GetApp().SetStatusPrompt, 'ALL', PROMOTE_STATUS_STRING(), editable=False, edit_toggle=False) def on_nowplaying(self, combo_item): self.setandshow(StatusMessage.NowPlaying) def on_invisible(self, combo_item): sta = self.get_profile_status() cpy = StatusMessage.Invisible.copy(message=sta.message) self.setandshow(cpy) def cancel_timer(self): if self.timer.IsRunning(): self.timer.Stop() # # search functionality # def _on_left_button(self, e): if not self.searching: return self.buttoncallback(self.cbutton) def _on_enter(self, e): if self.searching: self.buddylist.activate_selected_item() self.stop_searching() else: e.Skip() def _on_key_down(self, e): if self.searching: if e.KeyCode == wx.WXK_ESCAPE: self.buddylist.SetFocus() self.stop_searching() elif e.KeyCode in txtcontrol_keys: e.Skip() else: self.buddylist.on_key_down(e) else: e.Skip() def _interpret_char_event(self, e): key = None backspace = False if e is not None: mod = e.Modifiers & ~wx.MOD_SHIFT if e.KeyCode == wx.WXK_BACK: backspace = True elif mod or e.KeyCode <= ord(' ') or e.KeyCode in non_alphanumeric: return key, backspace else: key = unichr(e.UnicodeKey) return key, backspace def ShowSearchHint(self): self.searchHintShown = True def size_like(img, i): img = img.ResizedSmaller(max(i.Width, i.Height)).PIL return img.ResizeCanvas(i.Width, i.Height).WXB self.cbutton.SetIcon( size_like(skin.get('StatusPanel.SearchIcon'), self._button_icon)) self.DropDownButton.SetIcon(skin.get('StatusPanel.CancelSearchIcon')) self.display.DisplayLabel = _("Press 'Ctrl+F' to Search List") def HideSearchHint(self): self.SetButtonIcon(self._button_icon) self.DropDownButton.SetIcon(self.dropdownicon) self.searchHintShown = False self.display.DisplayLabel = None def search(self, e=None): if not pref('search.buddylist.enabled', True): if e is not None: e.Skip() return key, backspace = self._interpret_char_event(e) def size_like(img, i): img = img.ResizedSmaller(max(i.Width, i.Height)).PIL return img.ResizeCanvas(i.Width, i.Height).WXB icon = skin.get('StatusPanel.SearchIcon') self.ForceTextFieldBackground = True self.cbutton.SetIcon(size_like(icon, self._button_icon)) self.DropDownButton.SetIcon(skin.get('StatusPanel.CancelSearchIcon')) self.searching = True if not hasattr(self, 'search_timer'): self.search_timer = wx.PyTimer(self.on_search_timer) self.search_timer.Start(500) self.display.TypeField() # emulate a keypress if one started the search self.TextField.ChangeValue(profile.blist.search_string) if key is not None: self.TextField.AppendText(key) if backspace: # emulate a backspace size = self.TextField.LastPosition self.TextField.Remove(size - 1, size) self.OnActivateSearch() def on_search_timer(self): active = wx.GetActiveWindow() focused = wx.Window.FindFocus() if active is None or not self.searching: self.stop_searching() if not hasattr(self, '_allowed_windows'): # active windows search will stick around for from gui.infobox.infobox import InfoBox from gui.buddylist.buddylistframe import BuddyListFrame from gui.searchgui import SearchEditDialog self._allowed_windows = frozenset( [InfoBox, BuddyListFrame, SearchEditDialog]) self._empty_textfield_cancels = frozenset([BuddyListFrame]) clz = active.__class__ if clz not in self._allowed_windows: self.stop_searching() # if search loses focus to the buddylist and there is no text in the # search field, just cancel the search elif clz in self._empty_textfield_cancels and \ focused is not self.TextField and \ not self.TextField.Value: self.stop_searching() def stop_searching(self): if not self.searching: return log.info('stopping search') self.ForceTextFieldBackground = False self.SetButtonIcon(self._button_icon) self.DropDownButton.SetIcon(self.dropdownicon) self.search_timer.Stop() self.searching = False focused_window = wx.Window.FindFocus() if focused_window is self.TextField: self.buddylist.SetFocus() self.show_status(get_profile_status(), force=True) self.buddylist.clear_search() self.OnDeactivateSearch() hooks.notify('digsby.statistics.buddylist.search') def _dbutton_left(self, e): if self.searching: return self.stop_searching() else: e.Skip() def on_buddylist_key(self, e): if self.searching and e.KeyCode == wx.WXK_ESCAPE: self.stop_searching() else: e.Skip()
class PrefPanel(SimplePanel): def __init__(self, parent, content=None, title='', buttonlabel='', buttoncb=None, titlemaker=None, prefix=''): SimplePanel.__init__(self, parent, wx.FULL_REPAINT_ON_RESIZE) sizer = self.Sizer = BoxSizer(VERTICAL) self.headersizer = BoxSizer(HORIZONTAL) self.bodysizer = BoxSizer(VERTICAL) sizer.Add(self.headersizer, 0, EXPAND | TOP, space_over_header) sizer.Add(self.bodysizer, 1, EXPAND | TOP, space_under_header) self.title = None self.combo = None self.button = None self.content = None self.contents = {} self.titlemaker = titlemaker if wxMac: self.menuitems = {} if title and isinstance(title, basestring): self.title = wx.StaticText(self, -1, ' ' + title + ' ', style=wx.ALIGN_CENTER_VERTICAL) #need grey backgound behind label on mac to hide the line if wxMac: self.title.BackgroundColour = wx.Color(232, 232, 232) self.title.Font = self.HeaderFont self.headersizer.Add(self.title, 0, *header_sizer_flags) if callable(content): content = self.content = content(self, prefix) self.bodysizer.Add(self.content, 1, pref_sizer_style, 7) elif isinstance(content, wx.WindowClass): content.Reparent(self) self.content = content self.bodysizer.Add(self.content, 1, pref_sizer_style, 7) elif isinstance(content, list): self.SetContents(content) if buttoncb: self.SetButton(buttonlabel, buttoncb) Bind = self.Bind Bind(wx.EVT_PAINT, self.OnPaint) #darker border if mac so it is visible for now if not wxMac: self.pen = wx.Pen(wx.Colour(213, 213, 213)) else: self.pen = wx.Pen(wx.Colour(155, 155, 155)) def SetTitle(self, title): self.title.SetLabel(title) @property def HeaderFont(self): try: return self._headerfont except AttributeError: if not wxMac: PrefPanel._headerfont = makeFont('arial 8 bold') else: PrefPanel._headerfont = makeFont('9 bold') return self._headerfont _fg_brush = \ _bg_brush = \ _fg_pen = \ _bg_pen = lambda self: None def get_bg_brush(self): return self._bg_brush() or wx.WHITE_BRUSH def get_fg_brush(self): return self._fg_brush() or wx.TRANSPARENT_BRUSH def get_bg_pen(self): return self._bg_pen() or wx.TRANSPARENT_PEN def get_fg_pen(self): return self._fg_pen() or self.pen bg_brush = property(get_bg_brush) fg_brush = property(get_fg_brush) bg_pen = property(get_bg_pen) fg_pen = property(get_fg_pen) def OnPaint(self, event): size = self.Size dc = AutoDC(self) if not wxMac: # Non mac: white background, rounded rectangle around controls rect = wx.RectS(size) dc.Brush = self.bg_brush #background dc.Pen = self.bg_pen #background border dc.DrawRectangleRect(rect) ypos = self.headersizer.Size.height // 2 + space_over_header gc = wx.GraphicsContext.Create(dc) gc.SetBrush(self.fg_brush) #foreground gc.SetPen(self.fg_pen) #foreground gc.DrawRoundedRectangle(0, ypos, size.width - 1, size.height - ypos - 1, 5) else: # Mac: normal grey background, horizontal line above controls ypos = self.headersizer.Size.height // 2 + space_over_header + 2 dc.Pen = self.fg_pen button_width = 0 if self.button is None else ( self.button.Size.width) dc.DrawLine(10, ypos, self.headersizer.Size.width - 10 - button_width, ypos) content = self.content if isinstance(content, AnyList): # TODO: don't special case crect = wx.Rect(*content.Rect) crect = crect.Inflate(1, 1) dc.SetBrush(wx.TRANSPARENT_BRUSH) dc.SetPen(self.pen) dc.DrawRectangleRect(crect) def ChangeShownContent(self, *a): if self.content: self.content.Show(False) if wxMac: menu_item = self.menuitems[self.combo.GetStringSelection()] else: menu_item = self.combo.Value self.content = self.contents[menu_item] self.content.Show(True) self.Layout() def SetButton(self, label, callback): if self.button: self.headersizer.Detach(self.button) self.button.Destroy() # native button on mac instead of the vista clone button if not wxMac: self.button = UberButton(self, -1, label, skin='AppDefaults.PrefButton') else: self.button = wx.Button(self, -1, label) self.button.SetWindowVariant(wx.WINDOW_VARIANT_SMALL) self.button.Bind(wx.EVT_BUTTON, lambda e: callback(self.button)) self.headersizer.AddStretchSpacer(1) self.headersizer.Add(self.button, 0, wx.ALIGN_CENTER_VERTICAL | RIGHT, 7) @property def MenuItems(self): combo = self.combo if wxMac: return [combo.GetClientData(i) for i in xrange(combo.Count)] else: return combo.menu.spine.items def SetContents(self, content, destroyold=False): if destroyold: if not self.contents: self.content.Destroy() for content in self.contents.values(): content.Destroy() # the currently showing pane in a multiple pane pref panel if self.content: self.content.Show(False) self.content = None self.bodysizer.Clear() contents = self.contents = {} titlemaker = self.titlemaker if self.combo is None: if not wxMac: self.combo = UberCombo(self, value='', skinkey='AppDefaults.PrefCombo', valuecallback=self.ChangeShownContent) else: # use a native ComboBox on mac self.combo = wx.ComboBox(self, style=wx.CB_DROPDOWN | wx.CB_READONLY) self.combo.Bind(wx.EVT_COMBOBOX, self.ChangeShownContent) newcombo = True else: self.combo.RemoveAllItems() newcombo = False for object in content: if isinstance(object, tuple): window, label = object elif isinstance(object, wx.WindowClass): window = object label = titlemaker(window) if titlemaker else object.Label window.Show(False) window.Reparent(self) assert window.Parent is self self.bodysizer.Add(window, 1, pref_sizer_style, 7) menuitem = SimpleMenuItem(label) contents[menuitem] = window if wxMac: itemname = menuitem.GetContentAsString() self.combo.Append(itemname) self.menuitems[itemname] = menuitem else: self.combo.AppendItem(menuitem) if self.combo: if wxMac: self.combo.SetSelection(0) self.ChangeShownContent() else: self.combo.Value = self.combo[0] if self.combo is not None and newcombo: self.headersizer.Add(self.combo, 1, *combo_sizer_flags)