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:
Goffi 2010-08-04 17:57:51 +08:00
commit d1fd1cc04e
4 changed files with 141 additions and 7 deletions

View file

@ -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):

View file

@ -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']

View file

@ -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'))

View file

@ -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))