Update various UI aspects

Minor menu/UI tweaks, with the addition of some shortcuts.
Reconnecting in the middle of typing shouldn't kill the whole client
now.
It still needs to account for the "reconnecting" window (this will
likely be made to loop back into the query window for now).
This commit is contained in:
karxi 2017-01-09 01:18:59 -05:00
parent c7755899a3
commit c1d03887b4
6 changed files with 124 additions and 52 deletions

View file

@ -59,8 +59,6 @@
* Save commonly-used times on a per-handle basis! * Save commonly-used times on a per-handle basis!
* Make the memo list highlight/recolor the names of channels you're in * Make the memo list highlight/recolor the names of channels you're in
(including secret ones) (including secret ones)
* Make right-clicking on a tab open up the right-click menu one would get on
right-clicking the title (frame??)
* Add an option to Cycle (for log separation) * Add an option to Cycle (for log separation)
* Add a separate 'Tweaks' section in Options * Add a separate 'Tweaks' section in Options
@ -80,15 +78,10 @@
* Enable/Disable toggle (Firefox style option sheet-esque? Seems okay.) * Enable/Disable toggle (Firefox style option sheet-esque? Seems okay.)
* Ctrl+W closes tab * Ctrl+W closes tab
* Ctrl+Shift+PGUP/PGDN moves tab * Ctrl+Shift+PGUP/PGDN moves tab
* Make Ctrl+J/K usable for tab changing
* Option to disable Ctrl+Tab's jump to newest * Option to disable Ctrl+Tab's jump to newest
* Ctrl+Shift+V "Mass Paste" option (parse lines in sequence)? * Ctrl+Shift+V "Mass Paste" option (parse lines in sequence)?
* Make system messages use timestamps like everything else * Make system messages use timestamps like everything else
* Offer option for timestamps in memos * Offer option for timestamps in memos
* Make certain dialogues start on the safer of the two options
* Make the Reconnect dialog start on reconnect
* Make the Rejoin dialog start on rejoin
* Make the Invite dialog start on decline
* Make a status window/popup to contain logs of information like invites * Make a status window/popup to contain logs of information like invites
### "Security" ### "Security"
@ -98,7 +91,7 @@ design.**
If you want Pesterchum to be more secure, either get ghostDunk to make changes If you want Pesterchum to be more secure, either get ghostDunk to make changes
to the server and its administration policies, or get everyone to switch to this to the server and its administration policies, or get everyone to switch to this
version of the client. There aren't really any other choices. version of the client. There aren't really any other options.
* Flood protection (don't send because of the same target too many times in a * Flood protection (don't send because of the same target too many times in a
row) row)
@ -144,13 +137,23 @@ version of the client. There aren't really any other choices.
## Todo/Done ## Todo/Done
**Everything in this section has already been completed.** **Everything in this section has already been completed.**
### GUI
* Toggle individual tab flash / alert sounds (from the same right-click memo
that lets us toggle OOC)
* Make CTRL+PGUP/PGDN switch memo/pester tabs
* Make Ctrl+J/K usable for tab changing
* Make right-clicking on a tab open up the right-click menu one would get on
right-clicking the title (frame??)
* Right-click in userlist offers option to Pester
* Make certain dialogues start on the safer of the two options
* Make the Reconnect dialog start on Reconnect
* Make the Rejoin dialog start on Rejoin
* Make the Invite dialog start on Decline
### Usability ### Usability
* Fix parser text-loss bug that plagues everyone (especially Chumdroid users) * Fix parser text-loss bug that plagues everyone (especially Chumdroid users)
* Make /me messages that cut continue into more /me messages * Make /me messages that cut continue into more /me messages
* Make sound work on Windows through QSound (disables volume control) * Make sound work on Windows through QSound (disables volume control)
* Toggle individual tab flash / alert sounds (from the same right-click memo
that lets us toggle OOC)
* Make CTRL+PGUP/PGDN switch memo/pester tabs
* Color tags are now posted as their shorter hexadecimal forms, if applicable * Color tags are now posted as their shorter hexadecimal forms, if applicable
(255,255,255 -> #FFFFFF, for example) (255,255,255 -> #FFFFFF, for example)
* Separate auto-idle and checkbox idle so they don't share a state (and make * Separate auto-idle and checkbox idle so they don't share a state (and make

View file

@ -9,6 +9,7 @@ import dataobjs, generic, memos, parsetools, ostools
from version import _pcVersion from version import _pcVersion
from pnc.dep.attrdict import AttrDict from pnc.dep.attrdict import AttrDict
#~from styling import styler
_datadir = ostools.getDataDir() _datadir = ostools.getDataDir()
@ -19,6 +20,7 @@ logging.basicConfig(level=logging.WARNING)
class ConsoleWindow(QtGui.QDialog): class ConsoleWindow(QtGui.QDialog):
#~class ConsoleWindow(styler.PesterBaseWindow):
# A simple console class, cobbled together from the corpse of another. # A simple console class, cobbled together from the corpse of another.
# This is a holder for our text inputs. # This is a holder for our text inputs.
@ -110,6 +112,10 @@ class ConsoleWindow(QtGui.QDialog):
parent.console.is_open = False parent.console.is_open = False
parent.console.window = None parent.console.window = None
def hideEvent(self, event):
parent = self.parent()
parent.console.is_open = False
# Actual console stuff. # Actual console stuff.
def execInConsole(self, scriptstr, env=None): def execInConsole(self, scriptstr, env=None):
# Since that's what imports *us*, this should be okay # Since that's what imports *us*, this should be okay

View file

@ -15,10 +15,11 @@ from parsetools import convertTags, lexMessage, splitMessage, mecmd, colorBegin,
import parsetools import parsetools
import pnc.lexercon as lexercon import pnc.lexercon as lexercon
from pnc.dep.attrdict import AttrDict
class PesterTabWindow(QtGui.QFrame): class PesterTabWindow(QtGui.QFrame):
def __init__(self, mainwindow, parent=None, convo="convo"): def __init__(self, mainwindow, parent=None, convo="convo"):
QtGui.QFrame.__init__(self, parent) super(PesterTabWindow, self).__init__(parent)
self.setAttribute(QtCore.Qt.WA_QuitOnClose, False) self.setAttribute(QtCore.Qt.WA_QuitOnClose, False)
self.setFocusPolicy(QtCore.Qt.ClickFocus) self.setFocusPolicy(QtCore.Qt.ClickFocus)
self.mainwindow = mainwindow self.mainwindow = mainwindow
@ -33,6 +34,30 @@ class PesterTabWindow(QtGui.QFrame):
self.connect(self.tabs, QtCore.SIGNAL('tabMoved(int, int)'), self.connect(self.tabs, QtCore.SIGNAL('tabMoved(int, int)'),
self, QtCore.SLOT('tabMoved(int, int)')) self, QtCore.SLOT('tabMoved(int, int)'))
self.shortcuts = AttrDict()
self.shortcuts.tabNext = QtGui.QShortcut(
QtGui.QKeySequence('Ctrl+j'), self,
context=QtCore.Qt.WidgetWithChildrenShortcut)
self.shortcuts.tabLast = QtGui.QShortcut(
QtGui.QKeySequence('Ctrl+k'), self,
context=QtCore.Qt.WidgetWithChildrenShortcut)
# Note that we use reversed keys here.
self.shortcuts.tabUp = QtGui.QShortcut(
QtGui.QKeySequence('Ctrl+PgDown'), self,
context=QtCore.Qt.WidgetWithChildrenShortcut)
self.shortcuts.tabDn = QtGui.QShortcut(
QtGui.QKeySequence('Ctrl+PgUp'), self,
context=QtCore.Qt.WidgetWithChildrenShortcut)
self.connect(self.shortcuts.tabNext, QtCore.SIGNAL('activated()'),
self, QtCore.SLOT('nudgeTabNext()'))
self.connect(self.shortcuts.tabUp, QtCore.SIGNAL('activated()'),
self, QtCore.SLOT('nudgeTabNext()'))
self.connect(self.shortcuts.tabLast, QtCore.SIGNAL('activated()'),
self, QtCore.SLOT('nudgeTabLast()'))
self.connect(self.shortcuts.tabDn, QtCore.SIGNAL('activated()'),
self, QtCore.SLOT('nudgeTabLast()'))
self.initTheme(self.mainwindow.theme) self.initTheme(self.mainwindow.theme)
self.layout = QtGui.QVBoxLayout() self.layout = QtGui.QVBoxLayout()
self.layout.setContentsMargins(0,0,0,0) self.layout.setContentsMargins(0,0,0,0)
@ -96,38 +121,39 @@ class PesterTabWindow(QtGui.QFrame):
nexti = (self.tabIndices[self.currentConvo.title()] + 1) % self.tabs.count() nexti = (self.tabIndices[self.currentConvo.title()] + 1) % self.tabs.count()
self.tabs.setCurrentIndex(nexti) self.tabs.setCurrentIndex(nexti)
elif (mods == QtCore.Qt.ControlModifier and @QtCore.pyqtSlot()
keypress in (QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown)): def nudgeTabNext(self): return self.nudgeTabIndex(+1)
# Inverted controls. Might add an option for this if people want @QtCore.pyqtSlot()
# it. def nudgeTabLast(self): return self.nudgeTabIndex(-1)
if keypress == QtCore.Qt.Key_PageDown:
direction = 1 def nudgeTabIndex(self, direction):
elif keypress == QtCore.Qt.Key_PageUp: # Inverted controls. Might add an option for this if people want
direction = -1 # it.
# ...Processing... #~if keypress == QtCore.Qt.Key_PageDown:
tabs = self.tabs #~ direction = 1
# Pick our new index by sliding up or down the tab range. #~elif keypress == QtCore.Qt.Key_PageUp:
# NOTE: This feels like it could error. In fact, it /will/ if #~ direction = -1
# there are no tabs, but...that shouldn't happen, should it? # ...Processing...
# There are probably other scenarios, too, so we'll have to tabs = self.tabs
# check on this later. # Pick our new index by sliding up or down the tab range.
# # NOTE: This feels like it could error. In fact, it /will/ if
# Calculate the new index. # there are no tabs, but...that shouldn't happen, should it?
ct = tabs.count() # There are probably other scenarios, too, so we'll have to
cind = tabs.currentIndex() # check on this later.
nind = cind + direction #
if nind > (ct - 1): # Calculate the new index.
# The new index would be higher than the maximum; loop. ct = tabs.count()
nind = nind % ct cind = tabs.currentIndex()
# Otherwise, negative syntax should get it for us. nind = cind + direction
nind = range(ct)[nind] if nind > (ct - 1):
# Change to the selected tab. # The new index would be higher than the maximum; loop.
# Note that this will send out the usual callbacks that handle nind = nind % ct
# focusing and such. # Otherwise, negative syntax should get it for us.
tabs.setCurrentIndex(nind) nind = range(ct)[nind]
# Ensure this doesn't fall through normally. # Change to the selected tab.
# (Not an issue here, but this used to be on a TextArea.) # Note that this will send out the usual callbacks that handle
return # focusing and such.
tabs.setCurrentIndex(nind)
def contextMenuEvent(self, event): def contextMenuEvent(self, event):
#~if event.reason() == QtGui.QContextMenuEvent.Mouse: #~if event.reason() == QtGui.QContextMenuEvent.Mouse:
@ -450,8 +476,7 @@ class PesterText(QtGui.QTextEdit):
def keyPressEvent(self, event): def keyPressEvent(self, event):
# First parent is the PesterConvo containing this. # First parent is the PesterConvo containing this.
# Second parent is the PesterTabWindow containing *it*. # Second parent is the PesterTabWindow containing *it*.
pass_to_super = (QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown, pass_to_super = (QtCore.Qt.Key_Up, QtCore.Qt.Key_Down)
QtCore.Qt.Key_Up, QtCore.Qt.Key_Down)
parent = self.parent() parent = self.parent()
key = event.key() key = event.key()
keymods = event.modifiers() keymods = event.modifiers()
@ -554,8 +579,6 @@ class PesterInput(QtGui.QLineEdit):
prev = self.parent().history.prev() prev = self.parent().history.prev()
if prev is not None: if prev is not None:
self.setText(prev) self.setText(prev)
elif event.key() in [QtCore.Qt.Key_PageUp, QtCore.Qt.Key_PageDown]:
self.parent().textArea.keyPressEvent(event)
self.parent().mainwindow.idler.time = 0 self.parent().mainwindow.idler.time = 0
super(PesterInput, self).keyPressEvent(event) super(PesterInput, self).keyPressEvent(event)

View file

@ -375,6 +375,9 @@ class PesterMemo(PesterConvo):
self.userlist = RightClickList(self) self.userlist = RightClickList(self)
self.userlist.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding)) self.userlist.setSizePolicy(QtGui.QSizePolicy(QtGui.QSizePolicy.Fixed, QtGui.QSizePolicy.Expanding))
self.userlist.optionsMenu = QtGui.QMenu(self) self.userlist.optionsMenu = QtGui.QMenu(self)
self.pesterChumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/pester"], self)
self.connect(self.pesterChumAction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('newPesterSlot()'))
self.addchumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self) self.addchumAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/addchum"], self)
self.connect(self.addchumAction, QtCore.SIGNAL('triggered()'), self.connect(self.addchumAction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('addChumSlot()')) self, QtCore.SLOT('addChumSlot()'))
@ -390,6 +393,7 @@ class PesterMemo(PesterConvo):
self.quirkDisableAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirkkill"], self) self.quirkDisableAction = QtGui.QAction(self.mainwindow.theme["main/menus/rclickchumlist/quirkkill"], self)
self.connect(self.quirkDisableAction, QtCore.SIGNAL('triggered()'), self.connect(self.quirkDisableAction, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('killQuirkUser()')) self, QtCore.SLOT('killQuirkUser()'))
self.userlist.optionsMenu.addAction(self.pesterChumAction)
self.userlist.optionsMenu.addAction(self.addchumAction) self.userlist.optionsMenu.addAction(self.addchumAction)
# ban & op list added if we are op # ban & op list added if we are op
@ -1024,6 +1028,12 @@ class PesterMemo(PesterConvo):
msgbox.setText(self.mainwindow.theme["convo/text/kickedmemo"]) msgbox.setText(self.mainwindow.theme["convo/text/kickedmemo"])
msgbox.setInformativeText("press 0k to rec0nnect or cancel to absc0nd") msgbox.setInformativeText("press 0k to rec0nnect or cancel to absc0nd")
msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
# Find the OK button and make it default
for b in msgbox.buttons():
if msgbox.buttonRole(b) == QtGui.QMessageBox.AcceptRole:
# We found the 'OK' button, set it as the default
b.setAutoDefault(True)
break
ret = msgbox.exec_() ret = msgbox.exec_()
if ret == QtGui.QMessageBox.Ok: if ret == QtGui.QMessageBox.Ok:
self.userlist.clear() self.userlist.clear()
@ -1160,6 +1170,15 @@ class PesterMemo(PesterConvo):
elif c.lower() == self.channel.lower() and h == "" and update[0] in ["+","-"]: elif c.lower() == self.channel.lower() and h == "" and update[0] in ["+","-"]:
self.updateChanModes(update, op) self.updateChanModes(update, op)
@QtCore.pyqtSlot()
def newPesterSlot(self):
# We're opening a pester with someone in our user list.
user = self.userlist.currentItem()
if not user:
return
user = unicode(user.text())
self.mainwindow.newConversation(user)
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def addChumSlot(self): def addChumSlot(self):
if not self.userlist.currentItem(): if not self.userlist.currentItem():

View file

@ -1730,6 +1730,9 @@ class LoadingScreen(QtGui.QDialog):
self.loadinglabel = QtGui.QLabel("CONN3CT1NG", self) self.loadinglabel = QtGui.QLabel("CONN3CT1NG", self)
self.cancel = QtGui.QPushButton("QU1T >:?", self) self.cancel = QtGui.QPushButton("QU1T >:?", self)
self.ok = QtGui.QPushButton("R3CONN3CT >:]", self) self.ok = QtGui.QPushButton("R3CONN3CT >:]", self)
# Help reduce the number of accidental Pesterchum closures... :|
self.cancel.setAutoDefault(False)
self.ok.setAutoDefault(True)
self.connect(self.cancel, QtCore.SIGNAL('clicked()'), self.connect(self.cancel, QtCore.SIGNAL('clicked()'),
self, QtCore.SLOT('reject()')) self, QtCore.SLOT('reject()'))
self.connect(self.ok, QtCore.SIGNAL('clicked()'), self.connect(self.ok, QtCore.SIGNAL('clicked()'),

View file

@ -1085,6 +1085,7 @@ class PesterWindow(MovingWindow):
self.memos = CaseInsensitiveDict() self.memos = CaseInsensitiveDict()
self.tabconvo = None self.tabconvo = None
self.tabmemo = None self.tabmemo = None
self.shortcuts = AttrDict()
if "advanced" in options: if "advanced" in options:
self.advanced = options["advanced"] self.advanced = options["advanced"]
else: self.advanced = False else: self.advanced = False
@ -1179,6 +1180,16 @@ class PesterWindow(MovingWindow):
self.console.action = QtGui.QAction("Console", self) self.console.action = QtGui.QAction("Console", self)
self.connect(self.console.action, QtCore.SIGNAL('triggered()'), self.connect(self.console.action, QtCore.SIGNAL('triggered()'),
self, QtCore.SLOT('showConsole()')) self, QtCore.SLOT('showConsole()'))
self.console.shortcut = QtGui.QShortcut(
QtGui.QKeySequence("Ctrl+`"), self)
# Make sure the shortcut works anywhere.
# karxi: There's something wrong with the inheritance scheme here.
self.console.shortcut.setContext(QtCore.Qt.ApplicationShortcut)
self.connect(self.console.shortcut, QtCore.SIGNAL('activated()'),
self, QtCore.SLOT('showConsole()'))
#~# Use new-style connections
#~self.console.shortcut.activated.connect(self.showConsole)
# Apparently those can crash sometimes...c'est la vie. Can't use 'em.
self.console.is_open = False self.console.is_open = False
filemenu = self.menu.addMenu(self.theme["main/menus/client/_name"]) filemenu = self.menu.addMenu(self.theme["main/menus/client/_name"])
@ -2002,6 +2013,12 @@ class PesterWindow(MovingWindow):
msgbox.setText("You're invited!") msgbox.setText("You're invited!")
msgbox.setInformativeText("%s has invited you to the memo: %s\nWould you like to join them?" % (handle, channel)) msgbox.setInformativeText("%s has invited you to the memo: %s\nWould you like to join them?" % (handle, channel))
msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel) msgbox.setStandardButtons(QtGui.QMessageBox.Ok | QtGui.QMessageBox.Cancel)
# Find the Cancel button and make it default
for b in msgbox.buttons():
if msgbox.buttonRole(b) == QtGui.QMessageBox.RejectRole:
# We found the 'Cancel' button, set it as the default
b.setAutoDefault(True)
break
ret = msgbox.exec_() ret = msgbox.exec_()
if ret == QtGui.QMessageBox.Ok: if ret == QtGui.QMessageBox.Ok:
self.newMemo(unicode(channel), "+0:00") self.newMemo(unicode(channel), "+0:00")
@ -2299,6 +2316,11 @@ class PesterWindow(MovingWindow):
secret = self.memochooser.secretChannel.isChecked() secret = self.memochooser.secretChannel.isChecked()
invite = self.memochooser.inviteChannel.isChecked() invite = self.memochooser.inviteChannel.isChecked()
# Join the ones on the list first
for SelectedMemo in self.memochooser.SelectedMemos():
channel = "#"+unicode(SelectedMemo.target)
self.newMemo(channel, time)
if self.memochooser.newmemoname(): if self.memochooser.newmemoname():
newmemo = self.memochooser.newmemoname() newmemo = self.memochooser.newmemoname()
channel = unicode(newmemo).replace(" ", "_") channel = unicode(newmemo).replace(" ", "_")
@ -2313,10 +2335,6 @@ class PesterWindow(MovingWindow):
# the server has confirmed that we've joined.... # the server has confirmed that we've joined....
self.newMemo(c, time, secret=secret, invite=invite) self.newMemo(c, time, secret=secret, invite=invite)
for SelectedMemo in self.memochooser.SelectedMemos():
channel = "#"+unicode(SelectedMemo.target)
self.newMemo(channel, time)
self.memochooser = None self.memochooser = None
@QtCore.pyqtSlot() @QtCore.pyqtSlot()
def memoChooserClose(self): def memoChooserClose(self):