Primitivus: notification bar, first draft
- popup queue is now managed - notifications can auto-hide when nothing to show - ctrl-n show next notification Primitivus: ctrl-s allow to temporarily hide a popup Primitivus: cards in card_game now answer to mouse click Primitivus: notification is shown when invalid card is played in card_game Primitivus: SelectableText has now methods get_text and set_text
This commit is contained in:
parent
4977887e9a
commit
d1fd1cc04e
4 changed files with 141 additions and 7 deletions
|
|
@ -43,6 +43,14 @@ class CardDisplayer(urwid.Text):
|
|||
self._emit('click')
|
||||
return key
|
||||
|
||||
def mouse_event(self, size, event, button, x, y, focus):
|
||||
if urwid.is_mouse_press(event) and button == 1:
|
||||
self.select(not self.__selected)
|
||||
self._emit('click')
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def select(self, state=True):
|
||||
self.__selected = state
|
||||
attr,txt = self.card.getAttrText()
|
||||
|
|
@ -275,6 +283,7 @@ class CardGame(QuickCardGame,urwid.WidgetWrap):
|
|||
@param invalid_cards: cards which are invalid"""
|
||||
QuickCardGame.invalidCards(self, phase, played_cards, invalid_cards)
|
||||
self.hand_wid.update(self.hand)
|
||||
self.parent.host.notify(_('Cards played are invalid !'))
|
||||
self.parent.host.redraw()
|
||||
|
||||
def cardsPlayed(self, player, cards):
|
||||
|
|
|
|||
|
|
@ -115,6 +115,14 @@ class SelectableText(urwid.FlowWidget):
|
|||
def getValue(self):
|
||||
return self.text
|
||||
|
||||
def get_text(self):
|
||||
"""for compatibility with urwid.Text"""
|
||||
return self.getValue()
|
||||
|
||||
def set_text(self, text):
|
||||
self.text=unicode(text)
|
||||
self._invalidate()
|
||||
|
||||
def setAttribute(self, name, value):
|
||||
"""Change attribut used for rendering widget
|
||||
@param name: one of
|
||||
|
|
@ -358,6 +366,74 @@ class List(urwid.FlowWidget):
|
|||
|
||||
## MISC ##
|
||||
|
||||
class NotificationBar(urwid.WidgetWrap):
|
||||
"""Bar used to show misc information to user"""
|
||||
signals = ['change']
|
||||
|
||||
def __init__(self):
|
||||
self.waitNotifs = urwid.Text('')
|
||||
self.message = ClickableText('', default_attr='notifs')
|
||||
urwid.connect_signal(self.message, 'click', lambda wid: self.showNext())
|
||||
self.columns = urwid.Columns([('fixed',6,self.waitNotifs),self.message])
|
||||
urwid.WidgetWrap.__init__(self, urwid.AttrMap(self.columns,'notifs'))
|
||||
self.notifs = []
|
||||
|
||||
def __modQueue(self):
|
||||
"""must be called each time the notifications queue is changed"""
|
||||
self.waitNotifs.set_text("(%i)" % len(self.notifs) if self.notifs else '')
|
||||
self._emit('change')
|
||||
|
||||
def addPopUp(self, pop_up_widget):
|
||||
"""Add a popup to the waiting queue"""
|
||||
self.notifs.append(('popup',pop_up_widget))
|
||||
self.__modQueue()
|
||||
|
||||
def addMessage(self, message):
|
||||
"Add a message to the notificatio bar"
|
||||
if not self.message.get_text():
|
||||
self.message.set_text(message)
|
||||
self._invalidate()
|
||||
self._emit('change')
|
||||
else:
|
||||
self.notifs.append(('message',message))
|
||||
self.__modQueue()
|
||||
|
||||
def showNext(self):
|
||||
"""Show next message if any, else delete current message"""
|
||||
found = None
|
||||
for notif in self.notifs:
|
||||
if notif[0] == "message":
|
||||
found = notif
|
||||
break
|
||||
if found:
|
||||
self.notifs.remove(found)
|
||||
self.message.set_text(found[1])
|
||||
self.__modQueue()
|
||||
else:
|
||||
self.message.set_text('')
|
||||
self._emit('change')
|
||||
|
||||
def getNextPopup(self):
|
||||
"""Return next pop-up and remove it from the queue
|
||||
@return: pop-up or None if there is no more in the queue"""
|
||||
ret = None
|
||||
for notif in self.notifs:
|
||||
if notif[0] == 'popup':
|
||||
ret = notif[1]
|
||||
break
|
||||
if ret:
|
||||
self.notifs.remove(notif)
|
||||
self.__modQueue()
|
||||
return ret
|
||||
|
||||
def isQueueEmpty(self):
|
||||
return not bool(self.notifs)
|
||||
|
||||
def canHide(self):
|
||||
"""Return True if there is now important information to show"""
|
||||
return self.isQueueEmpty() and not self.message.get_text()
|
||||
|
||||
|
||||
class MenuBox(urwid.WidgetWrap):
|
||||
"""Show menu items of a category in a box"""
|
||||
signals = ['click']
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ const_PALETTE = [('title', 'black', 'light gray', 'standout,underline'),
|
|||
('selected_menu', 'light gray,bold', 'dark green'),
|
||||
('menuitem', 'light gray,bold', 'dark red'),
|
||||
('menuitem_focus', 'light gray,bold', 'dark green'),
|
||||
('notifs', 'black,bold', 'yellow'),
|
||||
('card_neutral', 'dark gray', 'white', 'standout,underline'),
|
||||
('card_neutral_selected', 'dark gray', 'dark green', 'standout,underline'),
|
||||
('card_special', 'brown', 'white', 'standout,underline'),
|
||||
|
|
@ -80,7 +81,7 @@ class PrimitivusApp(QuickApp):
|
|||
|
||||
def __init__(self):
|
||||
self.CM = QuickContactManagement() #FIXME: not the best place
|
||||
QuickApp.__init__(self) #XXX: yes it's an unusual place for the constructor of a parent class, but the init order is important
|
||||
QuickApp.__init__(self)
|
||||
|
||||
## main loop setup ##
|
||||
self.main_widget = ProfileManager(self)
|
||||
|
|
@ -88,6 +89,9 @@ class PrimitivusApp(QuickApp):
|
|||
|
||||
##misc setup##
|
||||
self.chat_wins=ChatList(self)
|
||||
self.notBar = custom_widgets.NotificationBar()
|
||||
urwid.connect_signal(self.notBar,'change',self.onNotification)
|
||||
self.__saved_overlay = None
|
||||
|
||||
def debug(self):
|
||||
"""convenient method to reset screen and launch pdb"""
|
||||
|
|
@ -111,6 +115,8 @@ class PrimitivusApp(QuickApp):
|
|||
self.loop.run()
|
||||
|
||||
def inputFilter(self, input, raw):
|
||||
if self.__saved_overlay and input != ['ctrl s']:
|
||||
return
|
||||
for i in input:
|
||||
if isinstance(i,tuple):
|
||||
if i[0] == 'mouse press':
|
||||
|
|
@ -129,6 +135,19 @@ class PrimitivusApp(QuickApp):
|
|||
self.main_widget.header = None
|
||||
except AttributeError:
|
||||
pass
|
||||
elif input == 'ctrl n':
|
||||
"""User wants to see next notification"""
|
||||
self.notBar.showNext()
|
||||
elif input == 'ctrl s':
|
||||
"""User wants to (un)hide overlay window"""
|
||||
if isinstance(self.loop.widget,urwid.Overlay):
|
||||
self.__saved_overlay = self.loop.widget
|
||||
self.loop.widget = self.main_widget
|
||||
else:
|
||||
if self.__saved_overlay:
|
||||
self.loop.widget = self.__saved_overlay
|
||||
self.__saved_overlay = None
|
||||
|
||||
elif input == 'ctrl d' and 'D' in self.bridge.getVersion(): #Debug only for dev versions
|
||||
self.debug()
|
||||
elif input == 'f2': #user wants to (un)hide the contact_list
|
||||
|
|
@ -190,10 +209,10 @@ class PrimitivusApp(QuickApp):
|
|||
self.contactList = ContactList(self, self.CM, on_click = self.contactSelected, on_change=lambda w: self.redraw())
|
||||
#self.center_part = urwid.Columns([('weight',2,self.contactList),('weight',8,Chat('',self))])
|
||||
self.center_part = urwid.Columns([('weight',2,self.contactList), ('weight',8,urwid.Filler(urwid.Text('')))])
|
||||
editBar = custom_widgets.AdvancedEdit('> ')
|
||||
urwid.connect_signal(editBar,'click',self.onTextEntered)
|
||||
self.editBar = custom_widgets.AdvancedEdit('> ')
|
||||
urwid.connect_signal(self.editBar,'click',self.onTextEntered)
|
||||
self.menu_roller = self.__buildMenuRoller()
|
||||
self.main_widget = custom_widgets.FocusFrame(self.center_part, header=self.menu_roller, footer=editBar, focus_part='footer')
|
||||
self.main_widget = custom_widgets.FocusFrame(self.center_part, header=self.menu_roller, footer=self.editBar, focus_part='footer')
|
||||
return self.main_widget
|
||||
|
||||
def plug_profile(self, profile_key='@DEFAULT@'):
|
||||
|
|
@ -201,11 +220,23 @@ class PrimitivusApp(QuickApp):
|
|||
QuickApp.plug_profile(self, profile_key)
|
||||
|
||||
def removePopUp(self, widget=None):
|
||||
"Remove current pop-up, and if there is other in queue, show it"
|
||||
self.loop.widget = self.main_widget
|
||||
next_popup = self.notBar.getNextPopup()
|
||||
if next_popup:
|
||||
#we still have popup to show, we display it
|
||||
self.showPopUp(next_popup)
|
||||
|
||||
def showPopUp(self, pop_up_widget):
|
||||
display_widget = urwid.Overlay(pop_up_widget, self.main_widget, 'center', ('relative', 40), 'middle', ('relative', 40))
|
||||
self.loop.widget = display_widget
|
||||
"Show a pop-up window if possible, else put it in queue"
|
||||
if not isinstance(self.loop.widget,urwid.Overlay):
|
||||
display_widget = urwid.Overlay(pop_up_widget, self.main_widget, 'center', ('relative', 40), 'middle', ('relative', 40))
|
||||
self.loop.widget = display_widget
|
||||
else:
|
||||
self.notBar.addPopUp(pop_up_widget)
|
||||
|
||||
def notify(self, message):
|
||||
self.notBar.addMessage(message)
|
||||
|
||||
def contactSelected(self, contact_list):
|
||||
contact = contact_list.get_contact()
|
||||
|
|
@ -233,6 +264,24 @@ class PrimitivusApp(QuickApp):
|
|||
if JID(self.contactList.selected).short != sender.short:
|
||||
self.contactList.putAlert(sender)
|
||||
|
||||
def onNotification(self, notBar):
|
||||
"""Called when a new notification has been received"""
|
||||
if not isinstance(self.main_widget, custom_widgets.FocusFrame):
|
||||
#if we are not in the main configuration, we ignore the notifications bar
|
||||
return
|
||||
if isinstance(self.main_widget.footer,custom_widgets.AdvancedEdit):
|
||||
if not self.notBar.canHide():
|
||||
#the notification bar is not visible and has usefull informations, we show it
|
||||
pile = urwid.Pile([self.notBar, self.editBar])
|
||||
self.main_widget.footer = pile
|
||||
else:
|
||||
if not isinstance(self.main_widget.footer, urwid.Pile):
|
||||
error(_("INTERNAL ERROR: Unexpected class for main widget's footer"))
|
||||
assert(False)
|
||||
if self.notBar.canHide():
|
||||
#No notification left, we can hide the bar
|
||||
self.main_widget.footer = self.editBar
|
||||
|
||||
def actionResult(self, type, id, data):
|
||||
if not id in self.current_action_ids:
|
||||
debug (_('unknown id, ignoring'))
|
||||
|
|
|
|||
|
|
@ -72,7 +72,7 @@ class QuickApp():
|
|||
return profile in self.profiles.keys()
|
||||
|
||||
def postInit(self):
|
||||
"""Must be called after __init__, do all automatic task (auto plug profile)"""
|
||||
"""Must be called after initialization is done, do all automatic task (auto plug profile)"""
|
||||
if self.options.profile:
|
||||
if not self.bridge.getProfileName(self.options.profile):
|
||||
error(_("Trying to plug an unknown profile (%s)" % self.options.profile))
|
||||
|
|
|
|||
Loading…
Reference in a new issue