clayout refactor

- tabs became difficult to read when users had a lot of templates, so we
use a combobox instead
- move the More button to the top and integrate adding/removing
templates
- start with no focus to avoid accidental modifications
- display confirmation before adding template
- remove 'edit to customize' text that some users had trouble editing
This commit is contained in:
Damien Elmes 2017-08-08 19:45:31 +10:00
parent 23f8e15816
commit d55318d83f
2 changed files with 157 additions and 50 deletions

View file

@ -38,43 +38,65 @@ class CardLayout(QDialog):
self.emptyFields.append(name) self.emptyFields.append(name)
note[name] = "(%s)" % name note[name] = "(%s)" % name
note.flush() note.flush()
self.setupTabs() self.setupTopArea()
self.setupMainArea() self.setupMainArea()
self.setupButtons() self.setupButtons()
self.setWindowTitle(_("Card Types for %s") % self.model['name']) self.setWindowTitle(_("Card Types for %s") % self.model['name'])
v1 = QVBoxLayout() v1 = QVBoxLayout()
v1.addWidget(self.tabs) v1.addWidget(self.topArea)
v1.addWidget(self.mainArea) v1.addWidget(self.mainArea)
v1.addLayout(self.buttons) v1.addLayout(self.buttons)
v1.setContentsMargins(12,12,12,12)
self.setLayout(v1) self.setLayout(v1)
self.redraw() self.redraw()
restoreGeom(self, "CardLayout") restoreGeom(self, "CardLayout")
self.setWindowModality(Qt.ApplicationModal) self.setWindowModality(Qt.ApplicationModal)
self.show() self.show()
# take the focus away from the first input area when starting up,
# as users tend to accidentally type into the template
self.setFocus()
def redraw(self): def redraw(self):
self.cards = self.col.previewCards(self.note, 2) self.cards = self.col.previewCards(self.note, 2)
self.redrawing = True
self.updateMainArea()
self.redrawing = False
idx = self.ord idx = self.ord
if idx >= len(self.cards): if idx >= len(self.cards):
idx = len(self.cards) - 1 self.ord = len(self.cards) - 1
self.selectCard(idx)
def setupTabs(self): self.redrawing = True
cloze = self.model['type'] == MODEL_CLOZE self.updateTopArea()
self.tabs = QTabWidget() self.updateMainArea()
self.tabs.setTabsClosable(not cloze) self.redrawing = False
self.tabs.setUsesScrollButtons(True) self.onCardSelected(self.ord)
if not cloze:
add = QPushButton("+") def setupTopArea(self):
add.setFixedWidth(30) self.topArea = QWidget()
add.setToolTip(_("Add new card")) self.topAreaForm = aqt.forms.clayout_top.Ui_Form()
add.clicked.connect(self.onAddCard) self.topAreaForm.setupUi(self.topArea)
self.tabs.setCornerWidget(add) self.topAreaForm.templateOptions.setText(_("Options") + " "+downArrow())
self.tabs.currentChanged.connect(self.onCardSelected) self.topAreaForm.templateOptions.clicked.connect(self.onMore)
self.tabs.tabCloseRequested.connect(self.onRemoveTab) self.topAreaForm.templatesBox.currentIndexChanged.connect(self.onCardSelected)
def updateTopArea(self):
cnt = self.mw.col.models.useCount(self.model)
self.topAreaForm.changesLabel.setText(ngettext(
"Changes below will affect the %(cnt)d note that uses this card type.",
"Changes below will affect the %(cnt)d notes that use this card type.",
cnt) % dict(cnt=cnt))
combo = self.topAreaForm.templatesBox
combo.clear()
combo.addItems(self._templateNameIncludingOrdinal(t) for t in self.model['tmpls'])
combo.setCurrentIndex(self.ord)
combo.setVisible(not self._isCloze())
def _templateNameIncludingOrdinal(self, tmpl):
return _("Card Type %(n)d of %(total)d: %(name)s") % dict(
n=tmpl['ord']+1,
total=len(self.model['tmpls']),
name=tmpl['name'],
)
def _isCloze(self):
return self.model['type'] == MODEL_CLOZE
def setupMainArea(self): def setupMainArea(self):
w = self.mainArea = QWidget() w = self.mainArea = QWidget()
@ -132,20 +154,16 @@ class CardLayout(QDialog):
head=base, js=jsinc) head=base, js=jsinc)
def updateMainArea(self): def updateMainArea(self):
self.tabs.clear() if self._isCloze():
for t in self.model['tmpls']:
# dummy widget for now
self.tabs.addTab(QWidget(), t['name'])
if self.model['type'] == MODEL_CLOZE:
cnt = len(self.mm.availOrds( cnt = len(self.mm.availOrds(
self.model, joinFields(self.note.fields))) self.model, joinFields(self.note.fields)))
for g in self.pform.groupBox, self.pform.groupBox_2: for g in self.pform.groupBox, self.pform.groupBox_2:
g.setTitle(g.title() + _(" (1 of %d)") % max(cnt, 1)) g.setTitle(g.title() + _(" (1 of %d)") % max(cnt, 1))
def onRemoveTab(self, idx): def onRemove(self):
if len(self.model['tmpls']) < 2: if len(self.model['tmpls']) < 2:
return showInfo(_("At least one card type is required.")) return showInfo(_("At least one card type is required."))
idx = self.ord
cards = self.mm.tmplUseCount(self.model, idx) cards = self.mm.tmplUseCount(self.model, idx)
cards = ngettext("%d card", "%d cards", cards) % cards cards = ngettext("%d card", "%d cards", cards) % cards
msg = (_("Delete the '%(a)s' card type, and its %(b)s?") % msg = (_("Delete the '%(a)s' card type, and its %(b)s?") %
@ -172,15 +190,11 @@ Please create a new card type first."""))
addField.setAutoDefault(False) addField.setAutoDefault(False)
l.addWidget(addField) l.addWidget(addField)
addField.clicked.connect(self.onAddField) addField.clicked.connect(self.onAddField)
if self.model['type'] != MODEL_CLOZE: if not self._isCloze():
flip = QPushButton(_("Flip")) flip = QPushButton(_("Flip"))
flip.setAutoDefault(False) flip.setAutoDefault(False)
l.addWidget(flip) l.addWidget(flip)
flip.clicked.connect(self.onFlip) flip.clicked.connect(self.onFlip)
more = QPushButton(_("More") + " "+downArrow())
more.setAutoDefault(False)
l.addWidget(more)
more.clicked.connect(lambda: self.onMore(more))
l.addStretch() l.addStretch()
close = QPushButton(_("Close")) close = QPushButton(_("Close"))
close.setAutoDefault(False) close.setAutoDefault(False)
@ -190,19 +204,11 @@ Please create a new card type first."""))
# Cards # Cards
########################################################################## ##########################################################################
def selectCard(self, idx):
if self.tabs.currentIndex() == idx:
# trigger a re-read
self.onCardSelected(idx)
else:
self.tabs.setCurrentIndex(idx)
def onCardSelected(self, idx): def onCardSelected(self, idx):
if self.redrawing: if self.redrawing:
return return
self.card = self.cards[idx] self.card = self.cards[idx]
self.ord = idx self.ord = idx
self.tabs.setCurrentIndex(idx)
self.playedAudio = {} self.playedAudio = {}
self.readCard() self.readCard()
self.renderPreview() self.renderPreview()
@ -295,7 +301,7 @@ Please create a new card type first."""))
if c.template()['ord'] != self.ord]: if c.template()['ord'] != self.ord]:
return showWarning(_("That name is already used.")) return showWarning(_("That name is already used."))
self.card.template()['name'] = name self.card.template()['name'] = name
self.tabs.setTabText(self.tabs.currentIndex(), name) self.redraw()
def onReorder(self): def onReorder(self):
n = len(self.cards) n = len(self.cards)
@ -328,10 +334,15 @@ Please create a new card type first."""))
return name return name
def onAddCard(self): def onAddCard(self):
cnt = self.mw.col.models.useCount(self.model)
txt = ngettext("This will create %d card. Proceed?",
"This will create %d cards. Proceed?", cnt) % cnt
if not askUser(txt):
return
name = self._newCardName() name = self._newCardName()
t = self.mm.newTemplate(name) t = self.mm.newTemplate(name)
old = self.card.template() old = self.card.template()
t['qfmt'] = "%s<br>\n%s" % (_("Edit to customize"), old['qfmt']) t['qfmt'] = old['qfmt']
t['afmt'] = old['afmt'] t['afmt'] = old['afmt']
self.mm.addTemplate(self.model, t) self.mm.addTemplate(self.model, t)
self.ord = len(self.cards) self.ord = len(self.cards)
@ -353,23 +364,36 @@ adjust the template manually to switch the question and answer."""))
dst['qfmt'] = m.group(2).strip() dst['qfmt'] = m.group(2).strip()
return True return True
def onMore(self, button): def onMore(self):
m = QMenu(self) m = QMenu(self)
a = m.addAction(_("Rename"))
if not self._isCloze():
a = m.addAction(_("Add Card Type..."))
a.triggered.connect(self.onAddCard)
a = m.addAction(_("Remove Card Type..."))
a.triggered.connect(self.onRemove)
a = m.addAction(_("Rename Card Type..."))
a.triggered.connect(self.onRename) a.triggered.connect(self.onRename)
if self.model['type'] != MODEL_CLOZE:
a = m.addAction(_("Reposition")) a = m.addAction(_("Reposition Card Type..."))
a.triggered.connect(self.onReorder) a.triggered.connect(self.onReorder)
m.addSeparator()
t = self.card.template() t = self.card.template()
if t['did']: if t['did']:
s = _(" (on)") s = _(" (on)")
else: else:
s = _(" (off)") s = _(" (off)")
a = m.addAction(_("Deck Override") + s) a = m.addAction(_("Deck Override...") + s)
a.triggered.connect(self.onTargetDeck) a.triggered.connect(self.onTargetDeck)
a = m.addAction(_("Browser Appearance"))
a = m.addAction(_("Browser Appearance..."))
a.triggered.connect(self.onBrowserDisplay) a.triggered.connect(self.onBrowserDisplay)
m.exec_(button.mapToGlobal(QPoint(0,0)))
m.exec_(self.topAreaForm.templateOptions.mapToGlobal(QPoint(0,0)))
def onBrowserDisplay(self): def onBrowserDisplay(self):
d = QDialog() d = QDialog()

83
designer/clayout_top.ui Normal file
View file

@ -0,0 +1,83 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>Form</class>
<widget class="QWidget" name="Form">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>400</width>
<height>300</height>
</rect>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<property name="spacing">
<number>3</number>
</property>
<property name="margin">
<number>0</number>
</property>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<property name="spacing">
<number>-1</number>
</property>
<item>
<widget class="QComboBox" name="templatesBox">
<property name="sizePolicy">
<sizepolicy hsizetype="Expanding" vsizetype="Fixed">
<horstretch>10</horstretch>
<verstretch>0</verstretch>
</sizepolicy>
</property>
</widget>
</item>
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeType">
<enum>QSizePolicy::MinimumExpanding</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>1</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="templateOptions">
<property name="text">
<string/>
</property>
<property name="autoDefault">
<bool>false</bool>
</property>
<property name="default">
<bool>false</bool>
</property>
</widget>
</item>
</layout>
</item>
<item>
<widget class="QLabel" name="changesLabel">
<property name="text">
<string/>
</property>
<property name="alignment">
<set>Qt::AlignCenter</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections/>
</ui>