Completed Toast Notifications. Includes all options, working custom toast
This commit is contained in:
parent
26f6b2a2f4
commit
d9a742d90c
7 changed files with 342 additions and 76 deletions
|
@ -28,6 +28,8 @@ CHANGELOG
|
|||
* Customizable name alerts - Kiooeht [evacipatedBox]
|
||||
* Update bug reporter - Kiooeht [evacipatedBox]
|
||||
* Explain why a chumhandle is invalid - Kiooeht [evacipatedBox] (Idea: Lexi [lexicalNuance])
|
||||
* Netsplit notification in memos - Kiooeht [evacipatedBox]
|
||||
* Toast Notifications - Kiooeht [evacipatedBox]
|
||||
* Bug fixes
|
||||
* Don't delete random chum when blocking someone not on chumroll - Kiooeht [evacipatedBox]
|
||||
* Openning global userlist doesn't reset OP status of memo users - Kiooeht [evacipatedBox]
|
||||
|
|
|
@ -18,6 +18,7 @@ Features
|
|||
* Fully working Toasts
|
||||
* Auto download/install updates via Windows installer
|
||||
* Turn memo notifications on/off from right-click menu on memos (Idea: lostGash)
|
||||
* Gray out random encounter option when RE is offline
|
||||
|
||||
Bugs
|
||||
----
|
||||
|
|
57
menus.py
57
menus.py
|
@ -996,7 +996,7 @@ class PesterOptions(QtGui.QDialog):
|
|||
self.tabs = QtGui.QButtonGroup(self)
|
||||
self.connect(self.tabs, QtCore.SIGNAL('buttonClicked(int)'),
|
||||
self, QtCore.SLOT('changePage(int)'))
|
||||
tabNames = ["Chum List", "Conversations", "Interface", "Sound", "Logging", "Idle/Updates", "Theme"]
|
||||
tabNames = ["Chum List", "Conversations", "Interface", "Sound", "Notifications", "Logging", "Idle/Updates", "Theme"]
|
||||
if parent.advanced: tabNames.append("Advanced")
|
||||
for t in tabNames:
|
||||
button = QtGui.QPushButton(t)
|
||||
|
@ -1038,6 +1038,9 @@ class PesterOptions(QtGui.QDialog):
|
|||
self.editMentions = QtGui.QPushButton("Edit Mentions", self)
|
||||
self.connect(self.editMentions, QtCore.SIGNAL('clicked()'),
|
||||
self, QtCore.SLOT('openMentions()'))
|
||||
self.editMentions2 = QtGui.QPushButton("Edit Mentions", self)
|
||||
self.connect(self.editMentions2, QtCore.SIGNAL('clicked()'),
|
||||
self, QtCore.SLOT('openMentions()'))
|
||||
|
||||
self.volume = QtGui.QSlider(QtCore.Qt.Horizontal, self)
|
||||
self.volume.setMinimum(0)
|
||||
|
@ -1186,6 +1189,21 @@ class PesterOptions(QtGui.QDialog):
|
|||
layout_type = QtGui.QHBoxLayout()
|
||||
layout_type.addWidget(self.notifyTypeLabel)
|
||||
layout_type.addWidget(self.notifyOptions)
|
||||
self.notifySigninCheck = QtGui.QCheckBox("Chum signs in", self)
|
||||
if self.config.notifyOptions() & self.config.SIGNIN:
|
||||
self.notifySigninCheck.setChecked(True)
|
||||
self.notifySignoutCheck = QtGui.QCheckBox("Chum signs out", self)
|
||||
if self.config.notifyOptions() & self.config.SIGNOUT:
|
||||
self.notifySignoutCheck.setChecked(True)
|
||||
self.notifyNewMsgCheck = QtGui.QCheckBox("New messages", self)
|
||||
if self.config.notifyOptions() & self.config.NEWMSG:
|
||||
self.notifyNewMsgCheck.setChecked(True)
|
||||
self.notifyNewConvoCheck = QtGui.QCheckBox("Only new conversations", self)
|
||||
if self.config.notifyOptions() & self.config.NEWCONVO:
|
||||
self.notifyNewConvoCheck.setChecked(True)
|
||||
self.notifyMentionsCheck = QtGui.QCheckBox("Memo Mentions (initials)", self)
|
||||
if self.config.notifyOptions() & self.config.INITIALS:
|
||||
self.notifyMentionsCheck.setChecked(True)
|
||||
self.notifyChange(self.notifycheck.checkState())
|
||||
|
||||
if parent.advanced:
|
||||
|
@ -1245,13 +1263,6 @@ class PesterOptions(QtGui.QDialog):
|
|||
layout_interface.addLayout(layout_close)
|
||||
layout_interface.addWidget(self.pesterBlink)
|
||||
layout_interface.addWidget(self.memoBlink)
|
||||
layout_interface.addSpacing(16)
|
||||
layout_interface.addWidget(QtGui.QLabel("NOT FULLY COMPLETE YET:"))
|
||||
layout_interface.addWidget(self.notifycheck)
|
||||
layout_indent = QtGui.QVBoxLayout()
|
||||
layout_indent.addLayout(layout_type)
|
||||
layout_indent.setContentsMargins(22,0,0,0)
|
||||
layout_interface.addLayout(layout_indent)
|
||||
self.pages.addWidget(widget)
|
||||
|
||||
# Sound
|
||||
|
@ -1276,6 +1287,26 @@ class PesterOptions(QtGui.QDialog):
|
|||
layout_sound.addWidget(self.currentVol)
|
||||
self.pages.addWidget(widget)
|
||||
|
||||
# Notifications
|
||||
widget = QtGui.QWidget()
|
||||
layout_notify = QtGui.QVBoxLayout(widget)
|
||||
layout_notify.setAlignment(QtCore.Qt.AlignTop)
|
||||
layout_notify.addWidget(self.notifycheck)
|
||||
layout_indent = QtGui.QVBoxLayout()
|
||||
layout_indent.addLayout(layout_type)
|
||||
layout_indent.setContentsMargins(22,0,0,0)
|
||||
layout_indent.addWidget(self.notifySigninCheck)
|
||||
layout_indent.addWidget(self.notifySignoutCheck)
|
||||
layout_indent.addWidget(self.notifyNewMsgCheck)
|
||||
layout_doubleindent = QtGui.QVBoxLayout()
|
||||
layout_doubleindent.addWidget(self.notifyNewConvoCheck)
|
||||
layout_doubleindent.setContentsMargins(22,0,0,0)
|
||||
layout_indent.addLayout(layout_doubleindent)
|
||||
layout_indent.addWidget(self.notifyMentionsCheck)
|
||||
layout_indent.addWidget(self.editMentions2)
|
||||
layout_notify.addLayout(layout_indent)
|
||||
self.pages.addWidget(widget)
|
||||
|
||||
# Logging
|
||||
widget = QtGui.QWidget()
|
||||
layout_logs = QtGui.QVBoxLayout(widget)
|
||||
|
@ -1335,9 +1366,19 @@ class PesterOptions(QtGui.QDialog):
|
|||
if state == 0:
|
||||
self.notifyTypeLabel.setEnabled(False)
|
||||
self.notifyOptions.setEnabled(False)
|
||||
self.notifySigninCheck.setEnabled(False)
|
||||
self.notifySignoutCheck.setEnabled(False)
|
||||
self.notifyNewMsgCheck.setEnabled(False)
|
||||
self.notifyNewConvoCheck.setEnabled(False)
|
||||
self.notifyMentionsCheck.setEnabled(False)
|
||||
else:
|
||||
self.notifyTypeLabel.setEnabled(True)
|
||||
self.notifyOptions.setEnabled(True)
|
||||
self.notifySigninCheck.setEnabled(True)
|
||||
self.notifySignoutCheck.setEnabled(True)
|
||||
self.notifyNewMsgCheck.setEnabled(True)
|
||||
self.notifyNewConvoCheck.setEnabled(True)
|
||||
self.notifyMentionsCheck.setEnabled(True)
|
||||
|
||||
@QtCore.pyqtSlot(int)
|
||||
def soundChange(self, state):
|
||||
|
|
|
@ -328,6 +328,12 @@ class userConfig(object):
|
|||
# Use for bit flag blink
|
||||
self.PBLINK = 1
|
||||
self.MBLINK = 2
|
||||
# Use for bit flag notfications
|
||||
self.SIGNIN = 1
|
||||
self.SIGNOUT = 2
|
||||
self.NEWMSG = 4
|
||||
self.NEWCONVO = 8
|
||||
self.INITIALS = 16
|
||||
self.filename = _datadir+"pesterchum.js"
|
||||
fp = open(self.filename)
|
||||
self.config = json.load(fp)
|
||||
|
@ -435,6 +441,8 @@ class userConfig(object):
|
|||
return self.config.get('notify', True)
|
||||
def notifyType(self):
|
||||
return self.config.get('notifyType', "default")
|
||||
def notifyOptions(self):
|
||||
return self.config.get('notifyOptions', self.SIGNIN | self.NEWMSG | self.NEWCONVO | self.INITIALS)
|
||||
def addChum(self, chum):
|
||||
if chum.handle not in self.chums():
|
||||
fp = open(self.filename) # what if we have two clients open??
|
||||
|
@ -689,18 +697,20 @@ class chumListing(QtGui.QTreeWidgetItem):
|
|||
def setMood(self, mood):
|
||||
if hasattr(self.mainwindow, "chumList") and self.mainwindow.chumList.notify:
|
||||
#print "%s -> %s" % (self.chum.mood.name(), mood.name())
|
||||
if mood.name() == "offline" and self.chum.mood.name() != "offline":
|
||||
if self.mainwindow.config.notifyOptions() & self.mainwindow.config.SIGNOUT and \
|
||||
mood.name() == "offline" and self.chum.mood.name() != "offline":
|
||||
#print "OFFLINE NOTIFY: " + self.handle
|
||||
uri = "file://" + os.path.abspath(os.path.curdir) + "/themes/enamel/distraught2.gif"
|
||||
uri = self.mainwindow.theme["toasts/icon/signout"]
|
||||
n = self.mainwindow.tm.Toast(self.mainwindow.tm.appName,
|
||||
"%s is Offline" % (self.handle), uri)
|
||||
#n.show()
|
||||
elif mood.name() != "offline" and self.chum.mood.name() == "offline":
|
||||
n.show()
|
||||
elif self.mainwindow.config.notifyOptions() & self.mainwindow.config.SIGNIN and \
|
||||
mood.name() != "offline" and self.chum.mood.name() == "offline":
|
||||
#print "ONLINE NOTIFY: " + self.handle
|
||||
uri = "file://" + os.path.abspath(os.path.curdir) + "/themes/enamel/chummy2.gif"
|
||||
uri = self.mainwindow.theme["toasts/icon/signin"]
|
||||
n = self.mainwindow.tm.Toast(self.mainwindow.tm.appName,
|
||||
"%s is Online" % (self.handle), uri)
|
||||
#n.show()
|
||||
n.show()
|
||||
login = False
|
||||
logout = False
|
||||
if mood.name() == "offline" and self.chum.mood.name() != "offline":
|
||||
|
@ -1596,11 +1606,12 @@ class PesterWindow(MovingWindow):
|
|||
themeWarning.exec_()
|
||||
self.theme = pesterTheme("pesterchum")
|
||||
|
||||
extraToasts = {'default': PesterToast}
|
||||
if pytwmn.confExists():
|
||||
extraToasts['twmn'] = pytwmn.Notification
|
||||
self.tm = PesterToastMachine(self, lambda: self.theme["main/windowtitle"], on=self.config.notify(),
|
||||
type=self.config.notifyType(), extras={'pester': PesterToast, 'twmn': pytwmn.Notification})
|
||||
type=self.config.notifyType(), extras=extraToasts)
|
||||
self.tm.run()
|
||||
t = self.tm.Toast(self.tm.appName, "!!---Started up ToastMachine---!!")
|
||||
t.show()
|
||||
|
||||
self.chatlog = PesterLog(self.profile().handle, self)
|
||||
|
||||
|
@ -1856,6 +1867,25 @@ class PesterWindow(MovingWindow):
|
|||
#yeah suck on this
|
||||
self.sendMessage.emit("PESTERCHUM:BLOCKED", handle)
|
||||
return
|
||||
# notify
|
||||
if self.config.notifyOptions() & self.config.NEWMSG:
|
||||
if not self.convos.has_key(handle):
|
||||
t = self.tm.Toast("New Conversation", "From: %s" % handle)
|
||||
t.show()
|
||||
elif not self.config.notifyOptions() & self.config.NEWCONVO:
|
||||
if msg[:11] != "PESTERCHUM:":
|
||||
t = self.tm.Toast("From: %s" % handle, re.sub("</?c(=.*?)?>", "", msg))
|
||||
t.show()
|
||||
else:
|
||||
if msg == "PESTERCHUM:CEASE":
|
||||
t = self.tm.Toast("Closed Conversation", handle)
|
||||
t.show()
|
||||
elif msg == "PESTERCHUM:BLOCK":
|
||||
t = self.tm.Toast("Blocked", handle)
|
||||
t.show()
|
||||
elif msg == "PESTERCHUM:UNBLOCK":
|
||||
t = self.tm.Toast("Unblocked", handle)
|
||||
t.show()
|
||||
if not self.convos.has_key(handle):
|
||||
if msg == "PESTERCHUM:CEASE": # ignore cease after we hang up
|
||||
return
|
||||
|
@ -1902,6 +1932,9 @@ class PesterWindow(MovingWindow):
|
|||
m = m[m.find(":"):]
|
||||
for search in self.userprofile.getMentions():
|
||||
if re.search(search, m):
|
||||
if self.config.notifyOptions() & self.config.INITIALS:
|
||||
t = self.tm.Toast(chan, re.sub("</?c(=.*?)?>", "", msg))
|
||||
t.show()
|
||||
self.namesound.play()
|
||||
return
|
||||
if self.honk and re.search(r"\bhonk\b", convertTags(msg, "text"), re.I):
|
||||
|
@ -2869,15 +2902,29 @@ class PesterWindow(MovingWindow):
|
|||
# Taskbar blink
|
||||
blinksetting = 0
|
||||
if self.optionmenu.pesterBlink.isChecked():
|
||||
blinksetting = blinksetting | self.config.PBLINK
|
||||
blinksetting |= self.config.PBLINK
|
||||
if self.optionmenu.memoBlink.isChecked():
|
||||
blinksetting = blinksetting | self.config.MBLINK
|
||||
blinksetting |= self.config.MBLINK
|
||||
curblink = self.config.blink()
|
||||
if blinksetting != curblink:
|
||||
self.config.set('blink', blinksetting)
|
||||
# toast notifications
|
||||
self.tm.setEnabled(self.optionmenu.notifycheck.isChecked())
|
||||
self.tm.setCurrentType(str(self.optionmenu.notifyOptions.currentText()))
|
||||
notifysetting = 0
|
||||
if self.optionmenu.notifySigninCheck.isChecked():
|
||||
notifysetting |= self.config.SIGNIN
|
||||
if self.optionmenu.notifySignoutCheck.isChecked():
|
||||
notifysetting |= self.config.SIGNOUT
|
||||
if self.optionmenu.notifyNewMsgCheck.isChecked():
|
||||
notifysetting |= self.config.NEWMSG
|
||||
if self.optionmenu.notifyNewConvoCheck.isChecked():
|
||||
notifysetting |= self.config.NEWCONVO
|
||||
if self.optionmenu.notifyMentionsCheck.isChecked():
|
||||
notifysetting |= self.config.INITIALS
|
||||
curnotify = self.config.notifyOptions()
|
||||
if notifysetting != curnotify:
|
||||
self.config.set('notifyOptions', notifysetting)
|
||||
# advanced
|
||||
## user mode
|
||||
if self.advanced:
|
||||
|
|
|
@ -319,5 +319,18 @@
|
|||
"voice": { "icon": "$path/voice.png" },
|
||||
"founder": { "icon": "$path/founder.png" },
|
||||
"admin": { "icon": "$path/admin.png" }
|
||||
},
|
||||
"toasts":
|
||||
{
|
||||
"width": 210,
|
||||
"height": 100,
|
||||
"style": "background: white;",
|
||||
"icon": { "signin": "$path/../enamel/chummy2.gif",
|
||||
"signout": "$path/../enamel/distraught2.gif",
|
||||
"style": "border: 2px solid black; border-width: 2px 0px 0px 2px;" },
|
||||
"title": { "minimumheight": 50,
|
||||
"style": "border: 2px solid black; border-width: 2px 2px 0px 0px; padding: 5px; font-weight:bold;"
|
||||
},
|
||||
"content": { "style": "background: black; color: white; padding: 5px;" }
|
||||
}
|
||||
}
|
||||
|
|
|
@ -349,5 +349,18 @@
|
|||
"op": { "icon": "$path/op.png" },
|
||||
"halfop": { "icon": "$path/halfop.png" },
|
||||
"voice": { "icon": "$path/voice.png" }
|
||||
},
|
||||
"toasts":
|
||||
{
|
||||
"width": 210,
|
||||
"height": 100,
|
||||
"style": "background: white;",
|
||||
"icon": { "signin": "$path/../enamel/ecstatic2.gif",
|
||||
"signout": "$path/../enamel/discontent2.gif",
|
||||
"style": "border: 2px solid black; border-width: 2px 0px 0px 2px;" },
|
||||
"title": { "minimumheight": 50,
|
||||
"style": "border: 2px solid black; border-width: 2px 2px 0px 0px; padding: 5px; font-weight:bold;"
|
||||
},
|
||||
"content": { "style": "background: black; color: white; padding: 5px;" }
|
||||
}
|
||||
}
|
||||
|
|
253
toast.py
253
toast.py
|
@ -1,6 +1,6 @@
|
|||
import inspect
|
||||
import threading
|
||||
import time
|
||||
import time, os
|
||||
from PyQt4 import QtGui, QtCore
|
||||
|
||||
try:
|
||||
|
@ -9,12 +9,20 @@ except:
|
|||
pynotify = None
|
||||
|
||||
class DefaultToast(object):
|
||||
def __init__(self, title, msg, icon):
|
||||
def __init__(self, machine, title, msg, icon):
|
||||
self.machine = machine
|
||||
self.title = title
|
||||
self.msg = msg
|
||||
self.icon = icon
|
||||
def show(self):
|
||||
print self.title, self.msg, self.icon
|
||||
self.done()
|
||||
def done(self):
|
||||
t = self.machine.toasts[0]
|
||||
if t.title == self.title and t.msg == self.msg and t.icon == self.icon:
|
||||
self.machine.toasts.pop(0)
|
||||
self.machine.displaying = False
|
||||
print "Done"
|
||||
|
||||
class ToastMachine(object):
|
||||
class __Toast__(object):
|
||||
|
@ -23,6 +31,8 @@ class ToastMachine(object):
|
|||
self.title = title
|
||||
self.msg = msg
|
||||
self.time = time
|
||||
if icon:
|
||||
icon = os.path.abspath(icon)
|
||||
self.icon = icon
|
||||
self.importance = importance
|
||||
if inspect.ismethod(self.title) or inspect.isfunction(self.title):
|
||||
|
@ -59,10 +69,20 @@ class ToastMachine(object):
|
|||
self.realShow()
|
||||
|
||||
def realShow(self):
|
||||
self.machine.displaying = True
|
||||
t = None
|
||||
for (k,v) in self.machine.types.iteritems():
|
||||
if self.machine.type == k:
|
||||
t = v(self.title, self.msg, self.icon)
|
||||
args = inspect.getargspec(v.__init__).args
|
||||
extras = {}
|
||||
if 'parent' in args:
|
||||
extras['parent'] = self.machine.parent
|
||||
if 'time' in args:
|
||||
extras['time'] = self.time
|
||||
if k == "libnotify" or k == "twmn":
|
||||
t = v(self.title, self.msg, self.icon, **extras)
|
||||
else:
|
||||
t = v(self.machine, self.title, self.msg, self.icon, **extras)
|
||||
# Use libnotify's urgency setting
|
||||
if k == "libnotify":
|
||||
if self.importance < 0:
|
||||
|
@ -74,17 +94,13 @@ class ToastMachine(object):
|
|||
break
|
||||
if not t:
|
||||
if 'default' in self.machine.types:
|
||||
if 'parent' in inspect.getargspec(self.machine.types['default']).args:
|
||||
t = self.machine.types['default'](self.title, self.msg, self.icon, self.machine.parent)
|
||||
if 'parent' in inspect.getargspec(self.machine.types['default'].__init__).args:
|
||||
t = self.machine.types['default'](self.machine, self.title, self.msg, self.icon, self.machine.parent)
|
||||
else:
|
||||
t = self.machine.types['default'](self.title, self.msg, self.icon)
|
||||
t = self.machine.types['default'](self.machine, self.title, self.msg, self.icon)
|
||||
else:
|
||||
t = DefaultToast(self.title, self.msg, self.icon)
|
||||
t.show()
|
||||
print "SLEEPING"
|
||||
#time.sleep(self.time/1000)
|
||||
if self in self.machine.toasts:
|
||||
self.machine.toasts.remove(self)
|
||||
|
||||
def __init__(self, parent, name, on=True, type="default",
|
||||
types=({'default' : DefaultToast,
|
||||
|
@ -99,13 +115,14 @@ class ToastMachine(object):
|
|||
self.types = types
|
||||
self.type = "default"
|
||||
self.quit = False
|
||||
self.displaying = False
|
||||
|
||||
self.setCurrentType(type)
|
||||
|
||||
self.toasts = []
|
||||
|
||||
def Toast(self, title, msg, icon=""):
|
||||
return self.__Toast__(self, title, msg, time=0, icon=icon)
|
||||
def Toast(self, title, msg, icon="", time=3000):
|
||||
return self.__Toast__(self, title, msg, time=time, icon=icon)
|
||||
|
||||
def setEnabled(self, on):
|
||||
self.on = (on is True)
|
||||
|
@ -140,18 +157,9 @@ class ToastMachine(object):
|
|||
return self.name
|
||||
|
||||
def showNext(self):
|
||||
high = filter(lambda x: x.importance < 0, self.toasts)
|
||||
normal = filter(lambda x: x.importance == 0, self.toasts)
|
||||
low = filter(lambda x: x.importance > 0, self.toasts)
|
||||
|
||||
if high:
|
||||
high.sort(key=lambda x: x.importance)
|
||||
high[0].realShow()
|
||||
elif normal:
|
||||
normal[0].realShow()
|
||||
elif low:
|
||||
low.sort(key=lambda x: x.importance)
|
||||
low[0].realShow()
|
||||
if not self.displaying and self.toasts:
|
||||
self.toasts.sort(key=lambda x: x.importance)
|
||||
self.toasts[0].realShow()
|
||||
|
||||
def showAll(self):
|
||||
while self.toasts:
|
||||
|
@ -163,40 +171,180 @@ class ToastMachine(object):
|
|||
self.showNext()
|
||||
|
||||
|
||||
class PesterToast(QtGui.QFrame, DefaultToast):
|
||||
def __init__(self, title, msg, icon, parent=None):
|
||||
QtGui.QFrame.__init__(self, parent,
|
||||
(QtCore.Qt.CustomizeWindowHint |
|
||||
QtCore.Qt.FramelessWindowHint))
|
||||
#self.setAttribute(QtCore.Qt.WA_QuitOnClose, False)
|
||||
#self.setAttribute(QtCore.Qt.WA_TranslucentBackground, True)
|
||||
#self.setAttribute(QtCore.Qt.WA_NoSystemBackground, True)
|
||||
self.setObjectName("toast")
|
||||
self.setWindowTitle("toast")
|
||||
#self.setFocusPolicy(QtCore.Qt.ClickFocus)
|
||||
class PesterToast(QtGui.QWidget, DefaultToast):
|
||||
def __init__(self, machine, title, msg, icon, time=3000, parent=None):
|
||||
QtGui.QWidget.__init__(self, parent)
|
||||
|
||||
self.machine = machine
|
||||
self.time = time
|
||||
|
||||
self.setWindowFlags(QtCore.Qt.ToolTip)
|
||||
|
||||
self.m_animation = QtCore.QParallelAnimationGroup()
|
||||
anim = QtCore.QPropertyAnimation(self)
|
||||
anim.setTargetObject(self)
|
||||
self.m_animation.addAnimation(anim)
|
||||
anim.setEasingCurve(QtCore.QEasingCurve.OutBounce)
|
||||
anim.setDuration(1000)
|
||||
self.connect(anim, QtCore.SIGNAL('finished()'),
|
||||
self, QtCore.SLOT('reverseTrigger()'))
|
||||
|
||||
self.m_animation.setDirection(QtCore.QAnimationGroup.Forward)
|
||||
|
||||
self.title = QtGui.QLabel(title, self)
|
||||
self.msg = QtGui.QLabel(msg, self)
|
||||
|
||||
self.btn = QtGui.QPushButton("Push Me", self)
|
||||
self.connect(self.btn, QtCore.SIGNAL('clicked()'),
|
||||
self, QtCore.SLOT('close()'))
|
||||
self.content = msg
|
||||
if icon:
|
||||
self.icon = QtGui.QLabel("")
|
||||
self.icon.setPixmap(QtGui.QPixmap(icon).scaledToWidth(30))
|
||||
else:
|
||||
self.icon = QtGui.QLabel("")
|
||||
self.icon.setPixmap(QtGui.QPixmap(30, 30))
|
||||
self.icon.pixmap().fill(QtGui.QColor(0,0,0,0))
|
||||
|
||||
layout_0 = QtGui.QVBoxLayout()
|
||||
layout_0.setMargin(0)
|
||||
layout_0.setContentsMargins(0, 0, 0, 0)
|
||||
|
||||
if self.icon:
|
||||
layout_1 = QtGui.QGridLayout()
|
||||
layout_1.addWidget(self.icon, 0,0, 1,1)
|
||||
layout_1.addWidget(self.title, 0,1, 1,7)
|
||||
layout_1.setAlignment(self.msg, QtCore.Qt.AlignTop)
|
||||
layout_0.addLayout(layout_1)
|
||||
else:
|
||||
layout_0.addWidget(self.title)
|
||||
layout_0.addWidget(self.btn)
|
||||
layout_0.addWidget(self.msg)
|
||||
|
||||
self.setMaximumWidth(self.parent().theme["toasts/width"])
|
||||
self.msg.setMaximumWidth(self.parent().theme["toasts/width"])
|
||||
self.title.setMinimumHeight(self.parent().theme["toasts/title/minimumheight"])
|
||||
|
||||
self.setLayout(layout_0)
|
||||
|
||||
print self.isWindow()
|
||||
self.setGeometry(0,0, self.parent().theme["toasts/width"], self.parent().theme["toasts/height"])
|
||||
self.setStyleSheet(self.parent().theme["toasts/style"])
|
||||
self.title.setStyleSheet(self.parent().theme["toasts/title/style"])
|
||||
if self.icon:
|
||||
self.icon.setStyleSheet(self.parent().theme["toasts/icon/style"])
|
||||
self.msg.setStyleSheet(self.parent().theme["toasts/content/style"])
|
||||
self.layout().setSpacing(0)
|
||||
|
||||
self.msg.setText(PesterToast.wrapText(self.msg.font(), str(self.msg.text()), self.parent().theme["toasts/width"], self.parent().theme["toasts/content/style"]))
|
||||
|
||||
anim.setStartValue(0)
|
||||
anim.setEndValue(100)
|
||||
self.connect(anim, QtCore.SIGNAL('valueChanged(QVariant)'),
|
||||
self, QtCore.SLOT('updateBottomLeftAnimation(QVariant)'))
|
||||
|
||||
self.byebye = False
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def show(self):
|
||||
QtGui.QFrame.setVisible(self, True)
|
||||
print "SHOWING"
|
||||
#~ themeWarning = QtGui.QMessageBox(self)
|
||||
#~ themeWarning.setText("ASDFASD")
|
||||
#~ themeWarning.exec_()
|
||||
self.m_animation.start()
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def done(self):
|
||||
QtGui.QWidget.hide(self)
|
||||
t = self.machine.toasts[0]
|
||||
if t.title == str(self.title.text()) and \
|
||||
t.msg == str(self.content):
|
||||
self.machine.toasts.pop(0)
|
||||
self.machine.displaying = False
|
||||
if self.machine.on:
|
||||
self.machine.showNext()
|
||||
del self
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def reverseTrigger(self):
|
||||
if self.time >= 0:
|
||||
QtCore.QTimer.singleShot(self.time, self, QtCore.SLOT('reverseStart()'))
|
||||
|
||||
@QtCore.pyqtSlot()
|
||||
def reverseStart(self):
|
||||
if not self.byebye:
|
||||
self.byebye = True
|
||||
anim = self.m_animation.animationAt(0)
|
||||
self.m_animation.setDirection(QtCore.QAnimationGroup.Backward)
|
||||
anim.setEasingCurve(QtCore.QEasingCurve.InCubic)
|
||||
self.disconnect(anim, QtCore.SIGNAL('finished()'),
|
||||
self, QtCore.SLOT('reverseTrigger()'))
|
||||
self.connect(anim, QtCore.SIGNAL('finished()'),
|
||||
self, QtCore.SLOT('done()'))
|
||||
self.m_animation.start()
|
||||
|
||||
@QtCore.pyqtSlot(QtCore.QVariant)
|
||||
def updateBottomLeftAnimation(self, value):
|
||||
p = QtGui.QApplication.desktop().availableGeometry(self).bottomRight()
|
||||
val = float(self.height())/100
|
||||
self.move(p.x()-self.width(), p.y() - (value.toInt()[0] * val) +1)
|
||||
self.layout().setSpacing(0)
|
||||
self.raise_()
|
||||
QtGui.QWidget.show(self)
|
||||
|
||||
def mousePressEvent(self, event):
|
||||
if event.button() == QtCore.Qt.RightButton:
|
||||
self.reverseStart()
|
||||
elif event.button() == QtCore.Qt.LeftButton:
|
||||
pass
|
||||
|
||||
@staticmethod
|
||||
def wrapText(font, text, maxwidth, css=""):
|
||||
ret = []
|
||||
metric = QtGui.QFontMetrics(font)
|
||||
if "padding" in css:
|
||||
if css[css.find("padding")+7] != "-":
|
||||
colon = css.find(":", css.find("padding"))
|
||||
semicolon = css.find(";", css.find("padding"))
|
||||
if semicolon < 0:
|
||||
stuff = css[colon+1:]
|
||||
else:
|
||||
stuff = css[colon+1:semicolon]
|
||||
stuff = stuff.replace("px", "").lstrip().rstrip()
|
||||
stuff = stuff.split(" ")
|
||||
if len(stuff) == 1:
|
||||
maxwidth -= int(stuff[0])*2
|
||||
elif len(stuff) == 2:
|
||||
maxwidth -= int(stuff[1])*2
|
||||
elif len(stuff) == 3:
|
||||
maxwidth -= int(stuff[1])*2
|
||||
elif len(stuff) == 4:
|
||||
maxwidth -= int(stuff[1]) + int(stuff[3])
|
||||
else:
|
||||
if "padding-left" in css:
|
||||
colon = css.find(":", css.find("padding-left"))
|
||||
semicolon = css.find(";", css.find("padding-left"))
|
||||
if semicolon < 0:
|
||||
stuff = css[colon+1:]
|
||||
else:
|
||||
stuff = css[colon+1:semicolon]
|
||||
stuff = stuff.replace("px", "").lstrip().rstrip()
|
||||
if stuff.isdigit():
|
||||
maxwidth -= int(stuff)
|
||||
if "padding-right" in css:
|
||||
colon = css.find(":", css.find("padding-right"))
|
||||
semicolon = css.find(";", css.find("padding-right"))
|
||||
if semicolon < 0:
|
||||
stuff = css[colon+1:]
|
||||
else:
|
||||
stuff = css[colon+1:semicolon]
|
||||
stuff = stuff.replace("px", "").lstrip().rstrip()
|
||||
if stuff.isdigit():
|
||||
maxwidth -= int(stuff)
|
||||
|
||||
if metric.width(text) < maxwidth:
|
||||
return text
|
||||
while metric.width(text) > maxwidth:
|
||||
lastspace = text.find(" ")
|
||||
curspace = lastspace
|
||||
while metric.width(text, curspace) < maxwidth:
|
||||
lastspace = curspace
|
||||
curspace = text.find(" ", lastspace+1)
|
||||
ret.append(text[:lastspace])
|
||||
text = text[lastspace+1:]
|
||||
ret.append(text)
|
||||
return "\n".join(ret)
|
||||
|
||||
|
||||
class PesterToastMachine(ToastMachine, QtCore.QObject):
|
||||
def __init__(self, parent, name, on=True, type="default",
|
||||
|
@ -229,9 +377,10 @@ class PesterToastMachine(ToastMachine, QtCore.QObject):
|
|||
ToastMachine.showNext(self)
|
||||
|
||||
def run(self):
|
||||
self.timer = QtCore.QTimer(self)
|
||||
self.timer.setInterval(1000)
|
||||
self.connect(self.timer, QtCore.SIGNAL('timeout()'),
|
||||
self, QtCore.SLOT('showNext()'))
|
||||
if self.on:
|
||||
pass#self.timer.start()
|
||||
pass
|
||||
#~ self.timer = QtCore.QTimer(self)
|
||||
#~ self.timer.setInterval(1000)
|
||||
#~ self.connect(self.timer, QtCore.SIGNAL('timeout()'),
|
||||
#~ self, QtCore.SLOT('showNext()'))
|
||||
#~ if self.on:
|
||||
#~ self.timer.start()
|
||||
|
|
Loading…
Reference in a new issue