mirror of
https://github.com/ankitects/anki.git
synced 2025-09-18 14:02:21 -04:00
Revamp Preferences, implement Minimalist Mode and Qt widget gallery to test GUI changes (#2289)
* Create widget gallery dialog
* Add WidgetGallery to debug dialog
* Use enum for its intended purpose
* Rename "reduced-motion" to "reduce-motion"
* Add another border-radius value
and make former large radius a bit smaller.
* Revamp preferences, add minimalist mode
Also:
- create additional and missing widget styles and tweak existing ones
- use single profile entry to set widget styles and reduce choices to Anki and Native
* Indent QTabBar style definitions
* Add missing styles for QPushButton states
* Fix QTableView background
* Remove unused layout from Preferences
* Fix QTabView focused tab style
* Highlight QCheckBox and QRadioButton when focused
* Fix toolbar styles
* Reorder preferences
* Add setting to hide bottom toolbar
* Move toolbar settings above minimalist modes
* Remove unused lines
* Implement proper full-screen mode
* Sort imports
* Tweak deck overview appearance in minimalist mode
* Undo TitledContainer changes
since nobody asked for that
* Remove dynamic toolbar background from minimalist mode
* Tweak buttons in minimalist mode
* Fix some issues
* Reduce theme check interval to 5s on Linux
* Increase hide timer interval to 2s
* Collapse toolbars with slight delay when moving to review state
This should ensure the bottom toolbar collapses too.
* Allow users to make hiding exclusive to full screen
* Rename full screen option
* Fix hide mode dropdown ignoring checkbox state on startup
* Fix typing issue
* Refine background image handling
Giving the toolbar body the main webview height ensures background-size: cover behaves exactly the same.
To prevent an override of other background properties, users are advised to only set background-images via the background-image property, not the background shorthand.
* Fix top toolbar getting huge when switching modes
The issue was caused by the min-height hack to align the background images. A call to web.adjustHeightToFit would set the toolbar to the same height as the main webview, as the function makes use of document.offsetHeight.
* Prevent scrollbar from appearing on bottom toolbar resize
* Cleanup
* Put review tab before editing; fix some tab orders
* Rename 'network' to 'syncing'
* Fix bottom toolbar disappearing on UI > 100
* Improve Preferences layout by adding vertical spacers to the bottom
also make the hiding of video_driver and its label more obvious in preferences.py.
* Fix bottom toolbar animating on startup
Also fix bottom toolbar not appearing when unchecking hide mode in reviewer.
* Hide/Show menubar in fullscreen mode along with toolbar
* Attempt to fix broken native theme on macOS
* Format
* Improve native theme on other systems by not forcing palette
with the caveat that theme switching can get weird.
* Fix theme switching in native style
* Remove redundant condition
* Add back check for Qt5 to prevent theme issues
* Add check for macOS before setting fusion theme
* Do not force scrollbar styles on macOS
* Remove all of that crazy theme logic
* Use canvas instead of button-bg for ColorRole.Button
* Make sure Anki style is always based on Fusion
otherwise we can't guarantee the same look on all systems.
* Explicitly apply default style when Anki style is not selected
This should fix the style not switching back after it was selected.
* Remove reduncant default_palette
* Revert 8af4c1cc2
On Mac with native theme, both Qt5 and Qt6 look correct already. On
the Anki theme, without this change, we get the fusion-style scrollbars
instead of the rounded ones.
* Rename AnkiStyles enum to WidgetStyle
* Fix theme switching shades on same theme
* Format
* Remove unused placeholderText
that caused an error when opening the widget gallery on Qt5.
* Check for full screen windowState using bitwise operator
to prevent error in Qt5.
Credit: https://stackoverflow.com/a/65425151
* Hide style option on Windows
also exclude native option from dropdown just in case.
* Format
* Minor naming tweak
This commit is contained in:
parent
c923553a53
commit
f169ee0933
33 changed files with 2495 additions and 1204 deletions
|
@ -4,13 +4,13 @@ preferences-basic = Basic
|
|||
preferences-change-deck-depending-on-note-type = Change deck depending on note type
|
||||
preferences-changes-will-take-effect-when-you = Changes will take effect when you restart Anki.
|
||||
preferences-hours-past-midnight = hours past midnight
|
||||
preferences-interface-language = Interface language:
|
||||
preferences-language = Language
|
||||
preferences-interrupt-current-audio-when-answering = Interrupt current audio when answering
|
||||
preferences-learn-ahead-limit = Learn ahead limit
|
||||
preferences-mins = mins
|
||||
preferences-network = Syncing
|
||||
preferences-next-day-starts-at = Next day starts at
|
||||
preferences-note-media-is-not-backed-up = Note: Media is not backed up. Please create a periodic backup of your Anki folder to be safe.
|
||||
preferences-note-media-is-not-backed-up = Media is not backed up. Please create a periodic backup of your Anki folder to be safe.
|
||||
preferences-on-next-sync-force-changes-in = On next sync, force changes in one direction
|
||||
preferences-paste-clipboard-images-as-png = Paste clipboard images as PNG
|
||||
preferences-paste-without-shift-key-strips-formatting = Paste without shift key strips formatting
|
||||
|
@ -21,19 +21,19 @@ preferences-scheduling = Scheduling
|
|||
preferences-show-learning-cards-with-larger-steps = Show learning cards with larger steps before reviews
|
||||
preferences-show-next-review-time-above-answer = Show next review time above answer buttons
|
||||
preferences-show-play-buttons-on-cards-with = Show play buttons on cards with audio
|
||||
preferences-show-remaining-card-count-during-review = Show remaining card count during review
|
||||
preferences-show-remaining-card-count-during-review = Show remaining card count
|
||||
preferences-some-settings-will-take-effect-after = Some settings will take effect after you restart Anki.
|
||||
preferences-synchronisation = <b>Synchronisation</b>
|
||||
preferences-synchronisation = Synchronisation
|
||||
preferences-synchronizationnot-currently-enabled-click-the-sync = <b>Synchronization</b><br> Not currently enabled; click the sync button in the main window to enable.
|
||||
preferences-synchronize-audio-and-images-too = Synchronize audio and images too
|
||||
preferences-timebox-time-limit = Timebox time limit
|
||||
preferences-user-interface-size = User interface size
|
||||
preferences-when-adding-default-to-current-deck = When adding, default to current deck
|
||||
preferences-you-can-restore-backups-via-fileswitch = You can restore backups via File>Switch Profile.
|
||||
preferences-you-can-restore-backups-via-fileswitch = You can restore backups via File > Switch Profile.
|
||||
preferences-legacy-timezone-handling = Legacy timezone handling (buggy, but required for AnkiDroid <= 2.14)
|
||||
preferences-default-search-text = Default search text
|
||||
preferences-default-search-text-example = eg. 'deck:current '
|
||||
preferences-theme-label = Theme: { $theme }
|
||||
preferences-theme = Theme
|
||||
preferences-theme-follow-system = Follow System
|
||||
preferences-theme-light = Light
|
||||
preferences-theme-dark = Dark
|
||||
|
@ -48,6 +48,25 @@ preferences-monthly-backups = Monthly backups to keep:
|
|||
preferences-minutes-between-backups = Minutes between automatic backups:
|
||||
preferences-reduce-motion = Reduce motion
|
||||
preferences-reduce-motion-tooltip = Disable various animations and transitions of the user interface
|
||||
preferences-collapse-toolbar = Hide top bar during review
|
||||
preferences-custom-sync-url = Self-hosted sync server
|
||||
preferences-custom-sync-url-disclaimer = For advanced users - please see the manual
|
||||
preferences-hide-top-bar-during-review = Hide top bar during review
|
||||
preferences-hide-bottom-bar-during-review = Hide bottom bar during review
|
||||
preferences-always = Always
|
||||
preferences-full-screen-only = Full screen only
|
||||
preferences-appearance = Appearance
|
||||
preferences-general = General
|
||||
preferences-style = Style
|
||||
preferences-review = Review
|
||||
preferences-reviewer = Reviewer
|
||||
preferences-distractions = Distractions
|
||||
preferences-minimalist-mode = Minimalist mode
|
||||
preferences-editing = Editing
|
||||
preferences-browsing = Browsing
|
||||
preferences-default-deck = Default deck
|
||||
preferences-account = AnkiWeb Account
|
||||
preferences-media = Media
|
||||
preferences-note = Note
|
||||
preferences-scheduler = Scheduler
|
||||
preferences-user-interface = User Interface
|
||||
preferences-import-export = Import/Export
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
## Video drivers/hardware acceleration. Please avoid translating 'OpenGL' and 'ANGLE'.
|
||||
|
||||
preferences-video-driver = Video driver: { $driver }
|
||||
preferences-video-driver = Video driver
|
||||
preferences-video-driver-opengl-mac = OpenGL (recommended on Macs)
|
||||
preferences-video-driver-software-mac = Software (not recommended)
|
||||
preferences-video-driver-opengl-other = OpenGL (faster, may cause issues)
|
||||
|
|
|
@ -350,6 +350,7 @@ class AnkiApp(QApplication):
|
|||
QCheckBox,
|
||||
QRadioButton,
|
||||
QMenu,
|
||||
QSlider,
|
||||
# classes with PyQt5 compatibility proxy
|
||||
without_qt5_compat_wrapper(QToolButton),
|
||||
without_qt5_compat_wrapper(QTabBar),
|
||||
|
|
|
@ -7,17 +7,19 @@
|
|||
|
||||
table {
|
||||
padding: 1rem;
|
||||
background: var(--canvas-elevated);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--border-radius-large);
|
||||
|
||||
@include elevation(1, $opacity-boost: -0.08);
|
||||
&:hover {
|
||||
@include elevation(2);
|
||||
.fancy & {
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--border-radius-medium);
|
||||
|
||||
@include elevation(1, $opacity-boost: -0.08);
|
||||
&:hover {
|
||||
@include elevation(2);
|
||||
}
|
||||
transition: box-shadow var(--transition) ease-in-out;
|
||||
background: var(--canvas-glass);
|
||||
backdrop-filter: blur(var(--blur));
|
||||
}
|
||||
transition: box-shadow var(--transition) ease-in-out;
|
||||
background: var(--canvas-glass);
|
||||
backdrop-filter: blur(var(--blur));
|
||||
}
|
||||
|
||||
a.deck {
|
||||
|
@ -37,7 +39,13 @@ th {
|
|||
}
|
||||
|
||||
tr.deck td {
|
||||
padding: 4px 12px;
|
||||
padding: 1px 12px;
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
|
||||
.fancy & {
|
||||
border: unset;
|
||||
padding: 4px 12px;
|
||||
}
|
||||
}
|
||||
|
||||
tr.top-level-drag-row td {
|
||||
|
@ -62,12 +70,12 @@ tr:hover:not(.top-level-drag-row) {
|
|||
td {
|
||||
background: color(border-subtle);
|
||||
&:first-child {
|
||||
border-top-left-radius: prop(border-radius-large);
|
||||
border-bottom-left-radius: prop(border-radius-large);
|
||||
border-top-left-radius: prop(border-radius-medium);
|
||||
border-bottom-left-radius: prop(border-radius-medium);
|
||||
}
|
||||
&:last-child {
|
||||
border-top-right-radius: prop(border-radius-large);
|
||||
border-bottom-right-radius: prop(border-radius-large);
|
||||
border-top-right-radius: prop(border-radius-medium);
|
||||
border-bottom-right-radius: prop(border-radius-medium);
|
||||
}
|
||||
.gears {
|
||||
visibility: visible;
|
||||
|
@ -82,14 +90,14 @@ tr:hover:not(.top-level-drag-row) {
|
|||
&:first-child {
|
||||
border-top-left-radius: 0;
|
||||
border-bottom-left-radius: 0;
|
||||
border-top-right-radius: prop(border-radius-large);
|
||||
border-bottom-right-radius: prop(border-radius-large);
|
||||
border-top-right-radius: prop(border-radius-medium);
|
||||
border-bottom-right-radius: prop(border-radius-medium);
|
||||
}
|
||||
&:last-child {
|
||||
border-top-right-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
border-top-left-radius: prop(border-radius-large);
|
||||
border-bottom-left-radius: prop(border-radius-large);
|
||||
border-top-left-radius: prop(border-radius-medium);
|
||||
border-bottom-left-radius: prop(border-radius-medium);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,6 +1,10 @@
|
|||
/* Copyright: Ankitects Pty Ltd and contributors
|
||||
* License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */
|
||||
|
||||
body {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#header {
|
||||
border-bottom: 0;
|
||||
margin-top: 0;
|
||||
|
|
|
@ -7,11 +7,13 @@
|
|||
@use "sass/button-mixins" as button;
|
||||
|
||||
.header {
|
||||
height: 41px;
|
||||
display: grid;
|
||||
grid-template-columns: repeat(3, 1fr);
|
||||
align-items: start;
|
||||
align-content: space-between;
|
||||
body:not(.fancy) & {
|
||||
border-bottom: 1px solid var(--border-subtle);
|
||||
}
|
||||
}
|
||||
|
||||
.left-tray {
|
||||
|
@ -31,65 +33,89 @@
|
|||
}
|
||||
|
||||
.toolbar {
|
||||
height: 31px;
|
||||
justify-self: center;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
border-bottom-left-radius: prop(border-radius-large);
|
||||
border-bottom-right-radius: prop(border-radius-large);
|
||||
@include elevation(1, $opacity-boost: -0.1);
|
||||
|
||||
// elevated state (deck browser, overview)
|
||||
body:not(.flat) & {
|
||||
background: var(--canvas-elevated);
|
||||
@include elevation(1);
|
||||
&:hover {
|
||||
@include elevation(2);
|
||||
}
|
||||
}
|
||||
// glass effect
|
||||
background: var(--canvas-glass);backdrop-filter: unset;
|
||||
backdrop-filter: blur(var(--blur));
|
||||
|
||||
transition: all var(--transition) ease-in-out;
|
||||
}
|
||||
|
||||
.hitem {
|
||||
font-weight: bold;
|
||||
padding: 5px 12px;
|
||||
color: color(fg);
|
||||
display: inline-block;
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
}
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
-webkit-user-select: none;
|
||||
overflow: hidden;
|
||||
|
||||
&.collapsed {
|
||||
transform: translateY(-100vh);
|
||||
&:not(.fancy).hidden {
|
||||
opacity: 0;
|
||||
}
|
||||
transition: opacity var(--transition) ease-in-out;
|
||||
|
||||
&.fancy {
|
||||
margin-bottom: 5px;
|
||||
|
||||
&.hidden {
|
||||
transform: translateY(-100vh);
|
||||
}
|
||||
transition: transform var(--transition) ease-in-out;
|
||||
|
||||
.toolbar {
|
||||
overflow: hidden;
|
||||
border-bottom-left-radius: prop(border-radius-medium);
|
||||
border-bottom-right-radius: prop(border-radius-medium);
|
||||
@include elevation(1, $opacity-boost: -0.1);
|
||||
|
||||
// glass effect
|
||||
background: var(--canvas-glass);
|
||||
backdrop-filter: blur(var(--blur));
|
||||
}
|
||||
|
||||
// elevated state (deck browser, overview)
|
||||
&:not(.flat) .toolbar {
|
||||
background: var(--canvas-elevated);
|
||||
@include elevation(1);
|
||||
&:hover {
|
||||
@include elevation(2);
|
||||
}
|
||||
}
|
||||
|
||||
&:not(.flat) .hitem {
|
||||
@include button.base($border: false, $with-hover: false);
|
||||
background: var(--canvas-glass);
|
||||
border: 1px solid transparent;
|
||||
}
|
||||
.hitem {
|
||||
text-decoration: none;
|
||||
border: 1px solid transparent;
|
||||
|
||||
&:hover {
|
||||
border: 1px solid var(--border-subtle);
|
||||
}
|
||||
&:active {
|
||||
background: var(--canvas-inset);
|
||||
}
|
||||
&:first-child {
|
||||
padding-left: 18px;
|
||||
}
|
||||
&:last-child {
|
||||
padding-right: 18px;
|
||||
}
|
||||
}
|
||||
}
|
||||
transition: transform var(--transition) ease-in-out;
|
||||
}
|
||||
|
||||
* {
|
||||
-webkit-user-drag: none;
|
||||
}
|
||||
|
||||
.hitem {
|
||||
font-weight: bold;
|
||||
padding: 5px 12px;
|
||||
text-decoration: none;
|
||||
color: color(fg);
|
||||
display: inline-block;
|
||||
|
||||
body:not(.flat) &,
|
||||
&:hover {
|
||||
@include button.base($border: false);
|
||||
background: var(--canvas-elevated);
|
||||
}
|
||||
&:first-child {
|
||||
padding-left: 18px;
|
||||
}
|
||||
&:last-child {
|
||||
padding-right: 18px;
|
||||
}
|
||||
}
|
||||
|
||||
.hitem:focus {
|
||||
outline: 0;
|
||||
}
|
||||
|
|
|
@ -22,14 +22,19 @@ body {
|
|||
&:not(.isMac) * {
|
||||
@include scrollbar.custom;
|
||||
}
|
||||
&.reduced-motion,
|
||||
&.reduced-motion * {
|
||||
&.reduce-motion,
|
||||
&.reduce-motion * {
|
||||
transition: none !important;
|
||||
animation: none !important;
|
||||
}
|
||||
&.no-blur * {
|
||||
backdrop-filter: none !important;
|
||||
}
|
||||
&:not(.fancy),
|
||||
&:not(.fancy) * {
|
||||
box-shadow: none !important;
|
||||
backdrop-filter: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
|
|
|
@ -42,4 +42,5 @@ from . import (
|
|||
synclog,
|
||||
taglimit,
|
||||
template,
|
||||
widgets,
|
||||
)
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>643</width>
|
||||
<height>580</height>
|
||||
<height>582</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
|
@ -48,6 +48,9 @@
|
|||
<property name="lineWrapMode">
|
||||
<enum>QPlainTextEdit::NoWrap</enum>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true">Type commands here (Enter to submit)</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QPlainTextEdit" name="log">
|
||||
<property name="sizePolicy">
|
||||
|
@ -68,9 +71,28 @@
|
|||
<property name="readOnly">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true">Output</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QGroupBox" name="groupBox">
|
||||
<property name="title">
|
||||
<string notr="true">Styling</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QPushButton" name="widgetsButton">
|
||||
<property name="text">
|
||||
<string notr="true">Qt Widget Gallery</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,7 @@
|
|||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string>preferences_interface_language</string>
|
||||
<string>preferences_language</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
|
6
qt/aqt/forms/widgets.py
Normal file
6
qt/aqt/forms/widgets.py
Normal file
|
@ -0,0 +1,6 @@
|
|||
from aqt.qt import qtmajor
|
||||
|
||||
if qtmajor > 5:
|
||||
from _aqt.forms.widgets_qt6 import *
|
||||
else:
|
||||
from _aqt.forms.widgets_qt5 import * # type: ignore
|
375
qt/aqt/forms/widgets.ui
Normal file
375
qt/aqt/forms/widgets.ui
Normal file
|
@ -0,0 +1,375 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>Dialog</class>
|
||||
<widget class="QDialog" name="Dialog">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>925</width>
|
||||
<height>822</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string notr="true">Qt Widget Gallery</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="topLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="styleLabel">
|
||||
<property name="text">
|
||||
<string notr="true">Style</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="styleComboBox">
|
||||
<property name="currentText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="horizontalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>40</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="disableCheckBox">
|
||||
<property name="text">
|
||||
<string notr="true">Disable Widgets</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QWidget" name="testGrid" native="true">
|
||||
<layout class="QGridLayout" name="gridLayout">
|
||||
<item row="0" column="0">
|
||||
<widget class="QGroupBox" name="checkButtonsGroup">
|
||||
<property name="title">
|
||||
<string notr="true">Check Buttons</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButtonNotCheckable">
|
||||
<property name="text">
|
||||
<string notr="true">RadioButton (not checkable)</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButtonChecked">
|
||||
<property name="text">
|
||||
<string notr="true">RadioButton (checked)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="radioButtonUnchecked">
|
||||
<property name="text">
|
||||
<string notr="true">RadioButton (unchecked)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="checkBoxTristate">
|
||||
<property name="text">
|
||||
<string notr="true">CheckBox (tristate)</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="tristate">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QGroupBox" name="buttonsGroup">
|
||||
<property name="title">
|
||||
<string notr="true">Buttons</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButton">
|
||||
<property name="text">
|
||||
<string notr="true">PushButton</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButtonCheckable">
|
||||
<property name="text">
|
||||
<string notr="true">PushButton (checkable)</string>
|
||||
</property>
|
||||
<property name="checkable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QPushButton" name="pushButtonFlat">
|
||||
<property name="text">
|
||||
<string notr="true">PushButton (flat)</string>
|
||||
</property>
|
||||
<property name="autoDefault">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="flat">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QGroupBox" name="calendarGroup">
|
||||
<property name="title">
|
||||
<string notr="true">CalendarWidget</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QCalendarWidget" name="calendarWidget"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QGroupBox" name="textInputsGroup">
|
||||
<property name="title">
|
||||
<string notr="true">Text Inputs</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_8">
|
||||
<item>
|
||||
<widget class="QComboBox" name="comboBox">
|
||||
<property name="editable">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="currentText">
|
||||
<string notr="true">ComboBox (editable)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="lineEdit">
|
||||
<property name="text">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true">LineEdit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSplitter" name="splitter">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
<widget class="QPlainTextEdit" name="plainTextEdit">
|
||||
<property name="plainText">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true">PlainTextEdit</string>
|
||||
</property>
|
||||
</widget>
|
||||
<widget class="QTextEdit" name="textEdit">
|
||||
<property name="documentTitle">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="placeholderText">
|
||||
<string notr="true">TextEdit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QGroupBox" name="otherInputsGroup">
|
||||
<property name="title">
|
||||
<string notr="true">Other Inputs</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="2" column="1" colspan="2">
|
||||
<widget class="QKeySequenceEdit" name="keySequenceEdit">
|
||||
<property name="keySequence">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1" colspan="2">
|
||||
<widget class="QSpinBox" name="spinBox">
|
||||
<property name="suffix">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="prefix">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>1</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="keySequenceLabel">
|
||||
<property name="text">
|
||||
<string notr="true">KeySequenceEdit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="dateTimeLabel">
|
||||
<property name="text">
|
||||
<string notr="true">DateTimeEdit</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="spinBoxLabel">
|
||||
<property name="text">
|
||||
<string notr="true">SpinBox</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="3">
|
||||
<layout class="QHBoxLayout" name="horizontalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="sliderLabel">
|
||||
<property name="text">
|
||||
<string notr="true">Slider</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSlider" name="horizontalSlider">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label">
|
||||
<property name="text">
|
||||
<string notr="true">Dial</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDial" name="dial"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item row="1" column="1" colspan="2">
|
||||
<widget class="QDateTimeEdit" name="dateTimeEdit"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QTabWidget" name="tabWidget">
|
||||
<property name="currentIndex">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<widget class="QWidget" name="listTab">
|
||||
<attribute name="title">
|
||||
<string notr="true">ListWidget</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_6">
|
||||
<item>
|
||||
<widget class="QListWidget" name="listWidget"/>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="treeTab">
|
||||
<attribute name="title">
|
||||
<string notr="true">TreeWidget</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_7">
|
||||
<item>
|
||||
<widget class="QTreeWidget" name="treeWidget">
|
||||
<column>
|
||||
<property name="text">
|
||||
<string notr="true">1</string>
|
||||
</property>
|
||||
</column>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWidget" name="tableTab">
|
||||
<attribute name="title">
|
||||
<string notr="true">TableWidget</string>
|
||||
</attribute>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_5">
|
||||
<item>
|
||||
<widget class="QTableWidget" name="tableWidget">
|
||||
<property name="rowCount">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="columnCount">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0" colspan="2">
|
||||
<layout class="QHBoxLayout" name="progressBarLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="progressBarLabel">
|
||||
<property name="text">
|
||||
<string notr="true">ProgressBar</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QProgressBar" name="progressBar">
|
||||
<property name="value">
|
||||
<number>24</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
|
@ -66,7 +66,7 @@ from aqt.qt import sip
|
|||
from aqt.sync import sync_collection, sync_login
|
||||
from aqt.taskman import TaskManager
|
||||
from aqt.theme import Theme, theme_manager
|
||||
from aqt.toolbar import Toolbar, ToolbarWebView
|
||||
from aqt.toolbar import BottomWebView, Toolbar, TopWebView
|
||||
from aqt.undo import UndoActionsInfo
|
||||
from aqt.utils import (
|
||||
HelpPage,
|
||||
|
@ -150,18 +150,17 @@ class MainWebView(AnkiWebView):
|
|||
return handled
|
||||
|
||||
if evt.type() == QEvent.Type.Leave:
|
||||
if self.mw.pm.collapse_toolbar():
|
||||
# Expand toolbar when mouse moves above main webview
|
||||
# and automatically collapse it with delay after mouse leaves
|
||||
if self.mapFromGlobal(QCursor.pos()).y() < self.geometry().y():
|
||||
if self.mw.toolbarWeb.collapsed:
|
||||
self.mw.toolbarWeb.expand()
|
||||
# Show toolbar when mouse moves outside main webview
|
||||
# and automatically hide it with delay after mouse has entered again
|
||||
if self.mw.pm.hide_top_bar() or self.mw.pm.hide_bottom_bar():
|
||||
self.mw.toolbarWeb.show()
|
||||
self.mw.bottomWeb.show()
|
||||
return True
|
||||
|
||||
if evt.type() == QEvent.Type.Enter:
|
||||
if self.mw.pm.collapse_toolbar():
|
||||
self.mw.toolbarWeb.hide_timer.start()
|
||||
return True
|
||||
self.mw.toolbarWeb.hide_timer.start()
|
||||
self.mw.bottomWeb.hide_timer.start()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
|
@ -170,7 +169,7 @@ class AnkiQt(QMainWindow):
|
|||
col: Collection
|
||||
pm: ProfileManagerType
|
||||
web: MainWebView
|
||||
bottomWeb: AnkiWebView
|
||||
bottomWeb: BottomWebView
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
|
@ -190,6 +189,7 @@ class AnkiQt(QMainWindow):
|
|||
aqt.mw = self
|
||||
self.app = app
|
||||
self.pm = profileManager
|
||||
self.fullscreen = False
|
||||
# init rest of app
|
||||
self.safeMode = (
|
||||
bool(self.app.queryKeyboardModifiers() & Qt.KeyboardModifier.ShiftModifier)
|
||||
|
@ -709,7 +709,7 @@ class AnkiQt(QMainWindow):
|
|||
gui_hooks.state_will_change(state, oldState)
|
||||
getattr(self, f"_{state}State", lambda *_: None)(oldState, *args)
|
||||
if state != "resetRequired":
|
||||
self.bottomWeb.show()
|
||||
self.bottomWeb.adjustHeightToFit()
|
||||
gui_hooks.state_did_change(state, oldState)
|
||||
|
||||
def _deckBrowserState(self, oldState: MainWindowState) -> None:
|
||||
|
@ -729,16 +729,23 @@ class AnkiQt(QMainWindow):
|
|||
|
||||
def _reviewState(self, oldState: MainWindowState) -> None:
|
||||
self.reviewer.show()
|
||||
if self.pm.collapse_toolbar():
|
||||
self.toolbarWeb.collapse()
|
||||
|
||||
if self.pm.hide_top_bar():
|
||||
self.toolbarWeb.hide_timer.setInterval(500)
|
||||
self.toolbarWeb.hide_timer.start()
|
||||
else:
|
||||
self.toolbarWeb.flatten()
|
||||
|
||||
if self.pm.hide_bottom_bar():
|
||||
self.bottomWeb.hide_timer.setInterval(500)
|
||||
self.bottomWeb.hide_timer.start()
|
||||
|
||||
def _reviewCleanup(self, newState: MainWindowState) -> None:
|
||||
if newState != "resetRequired" and newState != "review":
|
||||
self.reviewer.cleanup()
|
||||
self.toolbarWeb.elevate()
|
||||
self.toolbarWeb.expand()
|
||||
self.toolbarWeb.show()
|
||||
self.bottomWeb.show()
|
||||
|
||||
# Resetting state
|
||||
##########################################################################
|
||||
|
@ -872,12 +879,12 @@ title="{}" {}>{}</button>""".format(
|
|||
self.form = aqt.forms.main.Ui_MainWindow()
|
||||
self.form.setupUi(self)
|
||||
# toolbar
|
||||
tweb = self.toolbarWeb = ToolbarWebView(self, title="top toolbar")
|
||||
tweb = self.toolbarWeb = TopWebView(self, title="top toolbar")
|
||||
self.toolbar = Toolbar(self, tweb)
|
||||
# main area
|
||||
self.web = MainWebView(self)
|
||||
# bottom area
|
||||
sweb = self.bottomWeb = AnkiWebView(title="bottom toolbar")
|
||||
sweb = self.bottomWeb = BottomWebView(self, title="bottom toolbar")
|
||||
sweb.setFocusPolicy(Qt.FocusPolicy.WheelFocus)
|
||||
sweb.disable_zoom()
|
||||
# add in a layout
|
||||
|
@ -1068,12 +1075,12 @@ title="{}" {}>{}</button>""".format(
|
|||
if is_lin:
|
||||
# On Linux, the check requires invoking an external binary,
|
||||
# which we don't want to be doing frequently
|
||||
interval_secs = 300
|
||||
else:
|
||||
interval_secs = 5
|
||||
else:
|
||||
interval_secs = 2
|
||||
self.progress.timer(
|
||||
interval_secs * 1000,
|
||||
theme_manager.apply_style_if_system_style_changed,
|
||||
theme_manager.apply_style,
|
||||
True,
|
||||
False,
|
||||
parent=self,
|
||||
|
@ -1358,9 +1365,24 @@ title="{}" {}>{}</button>""".format(
|
|||
window.windowState() ^ Qt.WindowState.WindowFullScreen
|
||||
)
|
||||
|
||||
def collapse_toolbar_if_allowed(self) -> None:
|
||||
if self.pm.collapse_toolbar() and self.state == "review":
|
||||
self.toolbarWeb.collapse()
|
||||
# Hide Menubar on Windows and Linux
|
||||
if window.windowState() & Qt.WindowState.WindowFullScreen and not is_mac:
|
||||
self.fullscreen = True
|
||||
self.hide_menubar()
|
||||
else:
|
||||
self.fullscreen = False
|
||||
self.show_menubar()
|
||||
|
||||
# Update Toolbar states
|
||||
self.toolbarWeb.hide_if_allowed()
|
||||
self.bottomWeb.hide_if_allowed()
|
||||
|
||||
def hide_menubar(self) -> None:
|
||||
self.form.menubar.setFixedHeight(0)
|
||||
|
||||
def show_menubar(self) -> None:
|
||||
self.form.menubar.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX)
|
||||
self.form.menubar.setMinimumSize(0, 0)
|
||||
|
||||
# Auto update
|
||||
##########################################################################
|
||||
|
@ -1633,6 +1655,8 @@ title="{}" {}>{}</button>""".format(
|
|||
s = self.debugDiagShort = QShortcut(QKeySequence("ctrl+shift+l"), d)
|
||||
qconnect(s.activated, frm.text.clear)
|
||||
|
||||
qconnect(frm.widgetsButton.clicked, self._on_widgetGallery)
|
||||
|
||||
def addContextMenu(
|
||||
ev: Union[QCloseEvent, QContextMenuEvent], name: str
|
||||
) -> None:
|
||||
|
@ -1654,6 +1678,12 @@ title="{}" {}>{}</button>""".format(
|
|||
gui_hooks.debug_console_will_show(d)
|
||||
d.show()
|
||||
|
||||
def _on_widgetGallery(self) -> None:
|
||||
from aqt.widgetgallery import WidgetGallery
|
||||
|
||||
self.widgetGallery = WidgetGallery(self)
|
||||
self.widgetGallery.show()
|
||||
|
||||
def _captureOutput(self, on: bool) -> None:
|
||||
mw2 = self
|
||||
|
||||
|
|
|
@ -14,7 +14,15 @@ from aqt.operations.collection import set_preferences
|
|||
from aqt.profiles import VideoDriver
|
||||
from aqt.qt import *
|
||||
from aqt.theme import Theme
|
||||
from aqt.utils import HelpPage, disable_help_button, openHelp, showInfo, showWarning, tr
|
||||
from aqt.utils import (
|
||||
HelpPage,
|
||||
disable_help_button,
|
||||
is_win,
|
||||
openHelp,
|
||||
showInfo,
|
||||
showWarning,
|
||||
tr,
|
||||
)
|
||||
|
||||
|
||||
class Preferences(QDialog):
|
||||
|
@ -209,20 +217,61 @@ class Preferences(QDialog):
|
|||
|
||||
def setup_global(self) -> None:
|
||||
"Setup options global to all profiles."
|
||||
self.form.reduce_motion.setChecked(self.mw.pm.reduced_motion())
|
||||
self.form.collapse_toolbar.setChecked(self.mw.pm.collapse_toolbar())
|
||||
self.form.reduce_motion.setChecked(self.mw.pm.reduce_motion())
|
||||
qconnect(self.form.reduce_motion.stateChanged, self.mw.pm.set_reduce_motion)
|
||||
|
||||
self.form.minimalist_mode.setChecked(self.mw.pm.minimalist_mode())
|
||||
qconnect(self.form.minimalist_mode.stateChanged, self.mw.pm.set_minimalist_mode)
|
||||
|
||||
hide_choices = [tr.preferences_full_screen_only(), tr.preferences_always()]
|
||||
|
||||
self.form.hide_top_bar.setChecked(self.mw.pm.hide_top_bar())
|
||||
qconnect(self.form.hide_top_bar.stateChanged, self.mw.pm.set_hide_top_bar)
|
||||
qconnect(
|
||||
self.form.hide_top_bar.stateChanged,
|
||||
self.form.topBarComboBox.setVisible,
|
||||
)
|
||||
self.form.topBarComboBox.addItems(hide_choices)
|
||||
self.form.topBarComboBox.setCurrentIndex(self.mw.pm.top_bar_hide_mode())
|
||||
self.form.topBarComboBox.setVisible(self.form.hide_top_bar.isChecked())
|
||||
|
||||
qconnect(
|
||||
self.form.topBarComboBox.currentIndexChanged,
|
||||
self.mw.pm.set_top_bar_hide_mode,
|
||||
)
|
||||
|
||||
self.form.hide_bottom_bar.setChecked(self.mw.pm.hide_bottom_bar())
|
||||
qconnect(self.form.hide_bottom_bar.stateChanged, self.mw.pm.set_hide_bottom_bar)
|
||||
qconnect(
|
||||
self.form.hide_bottom_bar.stateChanged,
|
||||
self.form.bottomBarComboBox.setVisible,
|
||||
)
|
||||
self.form.bottomBarComboBox.addItems(hide_choices)
|
||||
self.form.bottomBarComboBox.setCurrentIndex(self.mw.pm.bottom_bar_hide_mode())
|
||||
self.form.bottomBarComboBox.setVisible(self.form.hide_bottom_bar.isChecked())
|
||||
|
||||
qconnect(
|
||||
self.form.bottomBarComboBox.currentIndexChanged,
|
||||
self.mw.pm.set_bottom_bar_hide_mode,
|
||||
)
|
||||
|
||||
self.form.uiScale.setValue(int(self.mw.pm.uiScale() * 100))
|
||||
themes = [
|
||||
tr.preferences_theme_label(theme=theme)
|
||||
for theme in (
|
||||
tr.preferences_theme_follow_system(),
|
||||
tr.preferences_theme_light(),
|
||||
tr.preferences_theme_dark(),
|
||||
)
|
||||
tr.preferences_theme_follow_system(),
|
||||
tr.preferences_theme_light(),
|
||||
tr.preferences_theme_dark(),
|
||||
]
|
||||
self.form.theme.addItems(themes)
|
||||
self.form.theme.setCurrentIndex(self.mw.pm.theme().value)
|
||||
qconnect(self.form.theme.currentIndexChanged, self.on_theme_changed)
|
||||
|
||||
self.form.styleComboBox.addItems(["Anki"] + (["Native"] if not is_win else []))
|
||||
self.form.styleComboBox.setCurrentIndex(self.mw.pm.get_widget_style())
|
||||
qconnect(
|
||||
self.form.styleComboBox.currentIndexChanged,
|
||||
self.mw.pm.set_widget_style,
|
||||
)
|
||||
self.form.styleComboBox.setVisible(not is_win)
|
||||
self.form.legacy_import_export.setChecked(self.mw.pm.legacy_import_export())
|
||||
|
||||
self.setup_language()
|
||||
|
@ -240,8 +289,6 @@ class Preferences(QDialog):
|
|||
self.mw.pm.setUiScale(newScale)
|
||||
restart_required = True
|
||||
|
||||
self.mw.pm.set_reduced_motion(self.form.reduce_motion.isChecked())
|
||||
self.mw.pm.set_collapse_toolbar(self.form.collapse_toolbar.isChecked())
|
||||
self.mw.pm.set_legacy_import_export(self.form.legacy_import_export.isChecked())
|
||||
|
||||
if restart_required:
|
||||
|
@ -291,15 +338,14 @@ class Preferences(QDialog):
|
|||
|
||||
def setup_video_driver(self) -> None:
|
||||
self.video_drivers = VideoDriver.all_for_platform()
|
||||
names = [
|
||||
tr.preferences_video_driver(driver=video_driver_name_for_platform(d))
|
||||
for d in self.video_drivers
|
||||
]
|
||||
names = [video_driver_name_for_platform(d) for d in self.video_drivers]
|
||||
self.form.video_driver.addItems(names)
|
||||
self.form.video_driver.setCurrentIndex(
|
||||
self.video_drivers.index(self.mw.pm.video_driver())
|
||||
)
|
||||
self.form.video_driver.setVisible(qtmajor == 5)
|
||||
if qtmajor > 5:
|
||||
self.form.video_driver_label.setVisible(False)
|
||||
self.form.video_driver.setVisible(False)
|
||||
|
||||
def update_video_driver(self) -> None:
|
||||
new_driver = self.video_drivers[self.form.video_driver.currentIndex()]
|
||||
|
|
|
@ -21,9 +21,10 @@ from anki.db import DB
|
|||
from anki.lang import without_unicode_isolation
|
||||
from anki.sync import SyncAuth
|
||||
from anki.utils import int_time, is_mac, is_win, point_version
|
||||
from aqt import appHelpSite
|
||||
from aqt import appHelpSite, gui_hooks
|
||||
from aqt.qt import *
|
||||
from aqt.theme import Theme, theme_manager
|
||||
from aqt.theme import Theme, WidgetStyle, theme_manager
|
||||
from aqt.toolbar import HideMode
|
||||
from aqt.utils import disable_help_button, send_to_trash, showWarning, tr
|
||||
|
||||
if TYPE_CHECKING:
|
||||
|
@ -518,17 +519,47 @@ create table if not exists profiles
|
|||
def setUiScale(self, scale: float) -> None:
|
||||
self.meta["uiScale"] = scale
|
||||
|
||||
def reduced_motion(self) -> bool:
|
||||
return self.meta.get("reduced_motion", False)
|
||||
def reduce_motion(self) -> bool:
|
||||
return self.meta.get("reduce_motion", False)
|
||||
|
||||
def set_reduced_motion(self, on: bool) -> None:
|
||||
self.meta["reduced_motion"] = on
|
||||
def set_reduce_motion(self, on: bool) -> None:
|
||||
self.meta["reduce_motion"] = on
|
||||
gui_hooks.body_classes_need_update()
|
||||
|
||||
def collapse_toolbar(self) -> bool:
|
||||
return self.meta.get("collapse_toolbar", False)
|
||||
def minimalist_mode(self) -> bool:
|
||||
return self.meta.get("minimalist_mode", False)
|
||||
|
||||
def set_collapse_toolbar(self, on: bool) -> None:
|
||||
self.meta["collapse_toolbar"] = on
|
||||
def set_minimalist_mode(self, on: bool) -> None:
|
||||
self.meta["minimalist_mode"] = on
|
||||
gui_hooks.body_classes_need_update()
|
||||
|
||||
def hide_top_bar(self) -> bool:
|
||||
return self.meta.get("hide_top_bar", False)
|
||||
|
||||
def set_hide_top_bar(self, on: bool) -> None:
|
||||
self.meta["hide_top_bar"] = on
|
||||
gui_hooks.body_classes_need_update()
|
||||
|
||||
def top_bar_hide_mode(self) -> HideMode:
|
||||
return self.meta.get("top_bar_hide_mode", HideMode.FULLSCREEN)
|
||||
|
||||
def set_top_bar_hide_mode(self, mode: HideMode) -> None:
|
||||
self.meta["top_bar_hide_mode"] = mode
|
||||
gui_hooks.body_classes_need_update()
|
||||
|
||||
def hide_bottom_bar(self) -> bool:
|
||||
return self.meta.get("hide_bottom_bar", False)
|
||||
|
||||
def set_hide_bottom_bar(self, on: bool) -> None:
|
||||
self.meta["hide_bottom_bar"] = on
|
||||
gui_hooks.body_classes_need_update()
|
||||
|
||||
def bottom_bar_hide_mode(self) -> HideMode:
|
||||
return self.meta.get("bottom_bar_hide_mode", HideMode.FULLSCREEN)
|
||||
|
||||
def set_bottom_bar_hide_mode(self, mode: HideMode) -> None:
|
||||
self.meta["bottom_bar_hide_mode"] = mode
|
||||
gui_hooks.body_classes_need_update()
|
||||
|
||||
def last_addon_update_check(self) -> int:
|
||||
return self.meta.get("last_addon_update_check", 0)
|
||||
|
@ -546,11 +577,14 @@ create table if not exists profiles
|
|||
def set_theme(self, theme: Theme) -> None:
|
||||
self.meta["theme"] = theme.value
|
||||
|
||||
def force_custom_styles(self) -> bool:
|
||||
return self.meta.get("force_custom_styles", False)
|
||||
def set_widget_style(self, style: WidgetStyle) -> None:
|
||||
self.meta["widget_style"] = style
|
||||
theme_manager.apply_style()
|
||||
|
||||
def set_force_custom_styles(self, enabled: bool) -> None:
|
||||
self.meta["force_custom_styles"] = enabled
|
||||
def get_widget_style(self) -> WidgetStyle:
|
||||
return self.meta.get(
|
||||
"widget_style", WidgetStyle.NATIVE if is_mac else WidgetStyle.ANKI
|
||||
)
|
||||
|
||||
def browser_layout(self) -> BrowserLayout:
|
||||
from aqt.browser.layout import BrowserLayout
|
||||
|
|
|
@ -325,7 +325,6 @@ class Reviewer:
|
|||
self.web.allow_drops = True
|
||||
self.web.eval("_blockDefaultDragDropBehavior();")
|
||||
# show answer / ease buttons
|
||||
self.bottom.web.show()
|
||||
self.bottom.web.stdHtml(
|
||||
self._bottomHTML(),
|
||||
css=["css/toolbar-bottom.css", "css/reviewer-bottom.css"],
|
||||
|
@ -706,7 +705,6 @@ time = %(time)d;
|
|||
else:
|
||||
maxTime = 0
|
||||
self.bottom.web.eval("showQuestion(%s,%d);" % (json.dumps(middle), maxTime))
|
||||
self.bottom.web.adjustHeightToFit()
|
||||
|
||||
def _showEaseButtons(self) -> None:
|
||||
middle = self._answerButtons()
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,6 @@ from anki.utils import is_lin, is_mac, is_win
|
|||
from aqt import QApplication, colors, gui_hooks
|
||||
from aqt.qt import (
|
||||
QColor,
|
||||
QGuiApplication,
|
||||
QIcon,
|
||||
QPainter,
|
||||
QPalette,
|
||||
|
@ -44,6 +43,11 @@ class ColoredIcon:
|
|||
return ColoredIcon(path=self.path, color=color)
|
||||
|
||||
|
||||
class WidgetStyle(enum.IntEnum):
|
||||
ANKI = 0
|
||||
NATIVE = 1
|
||||
|
||||
|
||||
class Theme(enum.IntEnum):
|
||||
FOLLOW_SYSTEM = 0
|
||||
LIGHT = 1
|
||||
|
@ -56,8 +60,8 @@ class ThemeManager:
|
|||
_icon_cache_dark: dict[str, QIcon] = {}
|
||||
_icon_size = 128
|
||||
_dark_mode_available: bool | None = None
|
||||
default_palette: QPalette | None = None
|
||||
_default_style: str | None = None
|
||||
_current_widget_style: WidgetStyle | None = None
|
||||
|
||||
def rtl(self) -> bool:
|
||||
return is_rtl(anki.lang.current_lang)
|
||||
|
@ -168,8 +172,10 @@ class ThemeManager:
|
|||
classes.extend(["nightMode", "night_mode"])
|
||||
if self.macos_dark_mode():
|
||||
classes.append("macos-dark-mode")
|
||||
if aqt.mw.pm.reduced_motion():
|
||||
classes.append("reduced-motion")
|
||||
if aqt.mw.pm.reduce_motion():
|
||||
classes.append("reduce-motion")
|
||||
if not aqt.mw.pm.minimalist_mode():
|
||||
classes.append("fancy")
|
||||
if qtmajor == 5 and qtminor < 15:
|
||||
classes.append("no-blur")
|
||||
return " ".join(classes)
|
||||
|
@ -212,56 +218,50 @@ class ThemeManager:
|
|||
else:
|
||||
return get_linux_dark_mode()
|
||||
|
||||
def apply_style_if_system_style_changed(self) -> None:
|
||||
theme = aqt.mw.pm.theme()
|
||||
if theme != Theme.FOLLOW_SYSTEM:
|
||||
return
|
||||
if self._determine_night_mode() != self.night_mode:
|
||||
self.apply_style()
|
||||
|
||||
def apply_style(self) -> None:
|
||||
"Apply currently configured style."
|
||||
new_theme = self._determine_night_mode()
|
||||
theme_changed = self.night_mode != new_theme
|
||||
new_widget_style = aqt.mw.pm.get_widget_style()
|
||||
style_changed = self._current_widget_style != new_widget_style
|
||||
if not theme_changed and not style_changed:
|
||||
return
|
||||
self.night_mode = new_theme
|
||||
self._current_widget_style = new_widget_style
|
||||
app = aqt.mw.app
|
||||
self.night_mode = self._determine_night_mode()
|
||||
if not self.default_palette:
|
||||
self.default_palette = QGuiApplication.palette()
|
||||
if not self._default_style:
|
||||
self._default_style = app.style().objectName()
|
||||
self._apply_palette(app)
|
||||
self._apply_style(app)
|
||||
gui_hooks.theme_did_change()
|
||||
|
||||
def _apply_style(self, app: QApplication) -> None:
|
||||
from aqt.stylesheets import splitter_styles
|
||||
buf = ""
|
||||
|
||||
buf = splitter_styles(self)
|
||||
if aqt.mw.pm.get_widget_style() == WidgetStyle.ANKI:
|
||||
from aqt.stylesheets import custom_styles
|
||||
|
||||
if not is_mac or aqt.mw.pm.force_custom_styles():
|
||||
from aqt.stylesheets import (
|
||||
button_styles,
|
||||
checkbox_styles,
|
||||
combobox_styles,
|
||||
general_styles,
|
||||
menu_styles,
|
||||
scrollbar_styles,
|
||||
spinbox_styles,
|
||||
table_styles,
|
||||
tabwidget_styles,
|
||||
)
|
||||
app.setStyle(QStyleFactory.create("fusion")) # type: ignore
|
||||
|
||||
buf += "".join(
|
||||
[
|
||||
general_styles(self),
|
||||
button_styles(self),
|
||||
checkbox_styles(self),
|
||||
menu_styles(self),
|
||||
combobox_styles(self),
|
||||
tabwidget_styles(self),
|
||||
table_styles(self),
|
||||
spinbox_styles(self),
|
||||
scrollbar_styles(self),
|
||||
custom_styles.general(self),
|
||||
custom_styles.button(self),
|
||||
custom_styles.checkbox(self),
|
||||
custom_styles.menu(self),
|
||||
custom_styles.combobox(self),
|
||||
custom_styles.tabwidget(self),
|
||||
custom_styles.table(self),
|
||||
custom_styles.spinbox(self),
|
||||
custom_styles.scrollbar(self),
|
||||
custom_styles.slider(self),
|
||||
custom_styles.splitter(self),
|
||||
]
|
||||
)
|
||||
|
||||
else:
|
||||
app.setStyle(QStyleFactory.create(self._default_style)) # type: ignore
|
||||
|
||||
# allow addons to modify the styling
|
||||
buf = gui_hooks.style_did_init(buf)
|
||||
|
||||
|
@ -270,19 +270,6 @@ class ThemeManager:
|
|||
def _apply_palette(self, app: QApplication) -> None:
|
||||
set_macos_dark_mode(self.night_mode)
|
||||
|
||||
if is_mac and not (qtmajor == 5 or aqt.mw.pm.force_custom_styles()):
|
||||
app.setStyle(QStyleFactory.create(self._default_style)) # type: ignore
|
||||
self.default_palette.setColor(
|
||||
QPalette.ColorRole.Window, self.qcolor(colors.CANVAS)
|
||||
)
|
||||
self.default_palette.setColor(
|
||||
QPalette.ColorRole.AlternateBase, self.qcolor(colors.CANVAS)
|
||||
)
|
||||
app.setPalette(self.default_palette)
|
||||
return
|
||||
|
||||
app.setStyle(QStyleFactory.create("fusion")) # type: ignore
|
||||
|
||||
palette = QPalette()
|
||||
text = self.qcolor(colors.FG)
|
||||
palette.setColor(QPalette.ColorRole.WindowText, text)
|
||||
|
@ -300,7 +287,7 @@ class ThemeManager:
|
|||
palette.setColor(QPalette.ColorRole.Window, canvas)
|
||||
palette.setColor(QPalette.ColorRole.AlternateBase, canvas)
|
||||
|
||||
palette.setColor(QPalette.ColorRole.Button, self.qcolor(colors.BUTTON_BG))
|
||||
palette.setColor(QPalette.ColorRole.Button, canvas)
|
||||
|
||||
input_base = self.qcolor(colors.CANVAS_CODE)
|
||||
palette.setColor(QPalette.ColorRole.Base, input_base)
|
||||
|
|
|
@ -2,18 +2,25 @@
|
|||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
from __future__ import annotations
|
||||
|
||||
import enum
|
||||
import re
|
||||
from typing import Any, Optional
|
||||
from typing import Any, Callable, Optional, cast
|
||||
|
||||
import aqt
|
||||
from anki.sync import SyncStatus
|
||||
from aqt import gui_hooks
|
||||
from aqt import gui_hooks, props
|
||||
from aqt.qt import *
|
||||
from aqt.sync import get_sync_status
|
||||
from aqt.theme import theme_manager
|
||||
from aqt.utils import tr
|
||||
from aqt.webview import AnkiWebView
|
||||
|
||||
|
||||
class HideMode(enum.IntEnum):
|
||||
FULLSCREEN = 0
|
||||
ALWAYS = 1
|
||||
|
||||
|
||||
# wrapper class for set_bridge_command()
|
||||
class TopToolbar:
|
||||
def __init__(self, toolbar: Toolbar) -> None:
|
||||
|
@ -27,45 +34,94 @@ class BottomToolbar:
|
|||
|
||||
|
||||
class ToolbarWebView(AnkiWebView):
|
||||
hide_condition: Callable[..., bool]
|
||||
|
||||
def __init__(self, mw: aqt.AnkiQt, title: str) -> None:
|
||||
AnkiWebView.__init__(self, mw, title=title)
|
||||
self.mw = mw
|
||||
self.setFocusPolicy(Qt.FocusPolicy.WheelFocus)
|
||||
self.disable_zoom()
|
||||
self.collapsed = False
|
||||
self.web_height = 0
|
||||
# collapse timer
|
||||
self.hidden = False
|
||||
self.hide_timer = QTimer()
|
||||
self.hide_timer.setSingleShot(True)
|
||||
self.hide_timer.setInterval(1000)
|
||||
qconnect(self.hide_timer.timeout, self.mw.collapse_toolbar_if_allowed)
|
||||
self.reset_timer()
|
||||
|
||||
def reset_timer(self) -> None:
|
||||
self.hide_timer.stop()
|
||||
self.hide_timer.setInterval(2000)
|
||||
|
||||
def hide(self) -> None:
|
||||
self.hidden = True
|
||||
|
||||
def show(self) -> None:
|
||||
self.hidden = False
|
||||
|
||||
|
||||
class TopWebView(ToolbarWebView):
|
||||
def __init__(self, mw: aqt.AnkiQt, title: str) -> None:
|
||||
super().__init__(mw, title=title)
|
||||
self.web_height = 0
|
||||
qconnect(self.hide_timer.timeout, self.hide_if_allowed)
|
||||
|
||||
def eventFilter(self, obj, evt):
|
||||
if handled := super().eventFilter(obj, evt):
|
||||
return handled
|
||||
|
||||
# prevent collapse if pointer inside
|
||||
# prevent collapse of both toolbars if pointer is inside one of them
|
||||
if evt.type() == QEvent.Type.Enter:
|
||||
self.hide_timer.stop()
|
||||
self.hide_timer.setInterval(1000)
|
||||
self.reset_timer()
|
||||
self.mw.bottomWeb.reset_timer()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def on_body_classes_need_update(self) -> None:
|
||||
super().on_body_classes_need_update()
|
||||
|
||||
if self.mw.state == "review":
|
||||
if self.mw.pm.hide_top_bar():
|
||||
self.eval("""document.body.classList.remove("flat"); """)
|
||||
else:
|
||||
self.flatten()
|
||||
|
||||
self.show()
|
||||
|
||||
def _onHeight(self, qvar: Optional[int]) -> None:
|
||||
super()._onHeight(qvar)
|
||||
self.web_height = int(qvar)
|
||||
|
||||
def collapse(self) -> None:
|
||||
self.collapsed = True
|
||||
self.eval("""document.body.classList.add("collapsed"); """)
|
||||
def hide_if_allowed(self) -> None:
|
||||
if self.mw.state != "review":
|
||||
return
|
||||
|
||||
def expand(self) -> None:
|
||||
self.collapsed = False
|
||||
self.eval("""document.body.classList.remove("collapsed"); """)
|
||||
if self.mw.pm.hide_top_bar():
|
||||
if (
|
||||
self.mw.pm.top_bar_hide_mode() == HideMode.FULLSCREEN
|
||||
and not self.mw.windowState() & Qt.WindowState.WindowFullScreen
|
||||
):
|
||||
self.show()
|
||||
return
|
||||
|
||||
self.hide()
|
||||
|
||||
def hide(self) -> None:
|
||||
super().hide()
|
||||
|
||||
self.hidden = True
|
||||
self.eval(
|
||||
"""document.body.classList.add("hidden"); """,
|
||||
)
|
||||
if self.mw.fullscreen:
|
||||
self.mw.hide_menubar()
|
||||
|
||||
def show(self) -> None:
|
||||
super().show()
|
||||
|
||||
self.eval("""document.body.classList.remove("hidden"); """)
|
||||
self.mw.show_menubar()
|
||||
|
||||
def flatten(self) -> None:
|
||||
self.eval("document.body.classList.add('flat'); ")
|
||||
self.eval("""document.body.classList.add("flat"); """)
|
||||
|
||||
def elevate(self) -> None:
|
||||
self.eval(
|
||||
|
@ -76,15 +132,24 @@ class ToolbarWebView(AnkiWebView):
|
|||
)
|
||||
|
||||
def update_background_image(self) -> None:
|
||||
def set_background(val: str) -> None:
|
||||
if self.mw.pm.minimalist_mode():
|
||||
return
|
||||
|
||||
def set_background(computed: str) -> None:
|
||||
# remove offset from copy
|
||||
background = re.sub(r"-\d+px ", "0%", val)
|
||||
background = re.sub(r"-\d+px ", "0%", computed)
|
||||
# ensure alignment with main webview
|
||||
background = re.sub(r"\sfixed", "", background)
|
||||
# change computedStyle px value back to 100vw
|
||||
background = re.sub(r"\d+px", "100vw", background)
|
||||
|
||||
self.eval(
|
||||
f"""document.body.style.setProperty("background", '{background}'); """
|
||||
f"""
|
||||
document.body.style.setProperty("background", '{background}');
|
||||
"""
|
||||
)
|
||||
self.set_body_height(self.mw.web.height())
|
||||
|
||||
# offset reviewer background by toolbar height
|
||||
self.mw.web.eval(
|
||||
f"""document.body.style.setProperty("background-position-y", "-{self.web_height}px"); """
|
||||
|
@ -95,6 +160,93 @@ class ToolbarWebView(AnkiWebView):
|
|||
set_background,
|
||||
)
|
||||
|
||||
def set_body_height(self, height: int) -> None:
|
||||
self.eval(
|
||||
f"""document.body.style.setProperty("min-height", "{self.mw.web.height()}px"); """
|
||||
)
|
||||
|
||||
def adjustHeightToFit(self) -> None:
|
||||
self.eval("""document.body.style.setProperty("min-height", "0px"); """)
|
||||
self.evalWithCallback("document.documentElement.offsetHeight", self._onHeight)
|
||||
|
||||
def resizeEvent(self, event: QResizeEvent) -> None:
|
||||
super().resizeEvent(event)
|
||||
|
||||
self.mw.web.evalWithCallback(
|
||||
"""window.innerHeight; """,
|
||||
self.set_body_height,
|
||||
)
|
||||
|
||||
|
||||
class BottomWebView(ToolbarWebView):
|
||||
def __init__(self, mw: aqt.AnkiQt, title: str) -> None:
|
||||
super().__init__(mw, title=title)
|
||||
qconnect(self.hide_timer.timeout, self.hide_if_allowed)
|
||||
|
||||
def eventFilter(self, obj, evt):
|
||||
if handled := super().eventFilter(obj, evt):
|
||||
return handled
|
||||
|
||||
if evt.type() == QEvent.Type.Enter:
|
||||
self.reset_timer()
|
||||
self.mw.toolbarWeb.reset_timer()
|
||||
return True
|
||||
|
||||
return False
|
||||
|
||||
def on_body_classes_need_update(self) -> None:
|
||||
super().on_body_classes_need_update()
|
||||
if self.mw.state == "review":
|
||||
self.show()
|
||||
|
||||
def animate_height(self, height: int) -> None:
|
||||
self.web_height = height
|
||||
|
||||
if self.mw.pm.reduce_motion():
|
||||
self.setFixedHeight(height)
|
||||
else:
|
||||
# Collapse/Expand animation
|
||||
self.setMinimumHeight(0)
|
||||
self.animation = QPropertyAnimation(
|
||||
self, cast(QByteArray, b"maximumHeight")
|
||||
)
|
||||
self.animation.setDuration(int(theme_manager.var(props.TRANSITION)))
|
||||
self.animation.setStartValue(self.height())
|
||||
self.animation.setEndValue(height)
|
||||
qconnect(self.animation.finished, lambda: self.setFixedHeight(height))
|
||||
self.animation.start()
|
||||
|
||||
def hide_if_allowed(self) -> None:
|
||||
if self.mw.state != "review":
|
||||
return
|
||||
|
||||
if self.mw.pm.hide_bottom_bar():
|
||||
if (
|
||||
self.mw.pm.bottom_bar_hide_mode() == HideMode.FULLSCREEN
|
||||
and not self.mw.windowState() & Qt.WindowState.WindowFullScreen
|
||||
):
|
||||
self.show()
|
||||
return
|
||||
|
||||
self.hide()
|
||||
|
||||
def hide(self) -> None:
|
||||
super().hide()
|
||||
|
||||
self.hidden = True
|
||||
self.animate_height(1)
|
||||
|
||||
def show(self) -> None:
|
||||
super().show()
|
||||
|
||||
self.hidden = False
|
||||
if self.mw.state == "review":
|
||||
self.evalWithCallback(
|
||||
"document.documentElement.offsetHeight", self.animate_height
|
||||
)
|
||||
else:
|
||||
self.adjustHeightToFit()
|
||||
|
||||
|
||||
class Toolbar:
|
||||
def __init__(self, mw: aqt.AnkiQt, web: AnkiWebView) -> None:
|
||||
|
|
|
@ -248,6 +248,7 @@ class AnkiWebView(QWebEngineView):
|
|||
self.resetHandlers()
|
||||
self._filterSet = False
|
||||
gui_hooks.theme_did_change.append(self.on_theme_did_change)
|
||||
gui_hooks.body_classes_need_update.append(self.on_body_classes_need_update)
|
||||
|
||||
qconnect(self.loadFinished, self._on_load_finished)
|
||||
|
||||
|
@ -410,8 +411,7 @@ class AnkiWebView(QWebEngineView):
|
|||
return 3
|
||||
|
||||
def standard_css(self) -> str:
|
||||
palette = theme_manager.default_palette
|
||||
color_hl = palette.color(QPalette.ColorRole.Highlight).name()
|
||||
color_hl = theme_manager.var(colors.BORDER_FOCUS)
|
||||
|
||||
if is_win:
|
||||
# T: include a font for your language on Windows, eg: "Segoe UI", "MS Mincho"
|
||||
|
@ -706,6 +706,7 @@ html {{ {font} }}
|
|||
return
|
||||
|
||||
gui_hooks.theme_did_change.remove(self.on_theme_did_change)
|
||||
gui_hooks.body_classes_need_update.remove(self.on_body_classes_need_update)
|
||||
mw.mediaServer.clear_page_html(id(self))
|
||||
self._page.deleteLater()
|
||||
|
||||
|
@ -733,6 +734,16 @@ html {{ {font} }}
|
|||
"""
|
||||
)
|
||||
|
||||
def on_body_classes_need_update(self) -> None:
|
||||
from aqt import mw
|
||||
|
||||
self.eval(
|
||||
f"""document.body.classList.toggle("fancy", {json.dumps(not mw.pm.minimalist_mode())}); """
|
||||
)
|
||||
self.eval(
|
||||
f"""document.body.classList.toggle("reduce-motion", {json.dumps(mw.pm.minimalist_mode())}); """
|
||||
)
|
||||
|
||||
@deprecated(info="use theme_manager.qcolor() instead")
|
||||
def get_window_bg_color(self, night_mode: Optional[bool] = None) -> QColor:
|
||||
return theme_manager.qcolor(colors.CANVAS)
|
||||
|
|
40
qt/aqt/widgetgallery.py
Normal file
40
qt/aqt/widgetgallery.py
Normal file
|
@ -0,0 +1,40 @@
|
|||
# Copyright: Ankitects Pty Ltd and contributors
|
||||
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||
|
||||
import aqt
|
||||
import aqt.main
|
||||
from aqt.qt import QDialog, qconnect
|
||||
from aqt.theme import WidgetStyle
|
||||
from aqt.utils import restoreGeom, saveGeom
|
||||
|
||||
|
||||
class WidgetGallery(QDialog):
|
||||
silentlyClose = True
|
||||
|
||||
def __init__(self, mw: aqt.main.AnkiQt) -> None:
|
||||
super().__init__(mw)
|
||||
self.mw = mw.weakref()
|
||||
|
||||
self.form = aqt.forms.widgets.Ui_Dialog()
|
||||
self.form.setupUi(self)
|
||||
restoreGeom(self, "WidgetGallery")
|
||||
|
||||
qconnect(
|
||||
self.form.disableCheckBox.stateChanged,
|
||||
lambda: self.form.testGrid.setEnabled(
|
||||
not self.form.disableCheckBox.isChecked()
|
||||
),
|
||||
)
|
||||
|
||||
self.form.styleComboBox.addItems(
|
||||
[member.name.lower().capitalize() for member in WidgetStyle]
|
||||
)
|
||||
self.form.styleComboBox.setCurrentIndex(self.mw.pm.get_widget_style())
|
||||
qconnect(
|
||||
self.form.styleComboBox.currentIndexChanged,
|
||||
self.mw.pm.set_widget_style,
|
||||
)
|
||||
|
||||
def reject(self) -> None:
|
||||
super().reject()
|
||||
saveGeom(self, "WidgetGallery")
|
|
@ -613,6 +613,10 @@ hooks = [
|
|||
name="theme_did_change",
|
||||
doc="Called after night mode is toggled.",
|
||||
),
|
||||
Hook(
|
||||
name="body_classes_need_update",
|
||||
doc="Called when a setting involving a webview body class is toggled.",
|
||||
),
|
||||
# Webview
|
||||
###################
|
||||
Hook(
|
||||
|
|
|
@ -25,8 +25,14 @@ $vars: (
|
|||
default: 5px,
|
||||
),
|
||||
),
|
||||
medium: (
|
||||
"Used for container corners",
|
||||
(
|
||||
default: 12px,
|
||||
),
|
||||
),
|
||||
large: (
|
||||
"Used for big centered buttons",
|
||||
"Used for pill-shaped buttons",
|
||||
(
|
||||
default: 15px,
|
||||
),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
@use "vars" as *;
|
||||
@use "root-vars";
|
||||
@use "button-mixins" as button;
|
||||
@use "sass/scrollbar";
|
||||
|
||||
$body-color: color(fg);
|
||||
$body-bg: color(canvas);
|
||||
|
@ -43,6 +44,26 @@ html {
|
|||
overscroll-behavior: none;
|
||||
}
|
||||
|
||||
body {
|
||||
&:not(.isMac),
|
||||
&:not(.isMac) * {
|
||||
@include scrollbar.custom;
|
||||
}
|
||||
&.reduce-motion,
|
||||
&.reduce-motion * {
|
||||
transition: none !important;
|
||||
animation: none !important;
|
||||
}
|
||||
&.no-blur * {
|
||||
backdrop-filter: none !important;
|
||||
}
|
||||
&:not(.fancy),
|
||||
&:not(.fancy) * {
|
||||
box-shadow: none !important;
|
||||
backdrop-filter: none !important;
|
||||
}
|
||||
}
|
||||
|
||||
button {
|
||||
/* override transition for instant hover response */
|
||||
transition: color var(--transition) ease-in-out, box-shadow var(--transition) ease-in-out !important;
|
||||
|
@ -57,7 +78,7 @@ samp {
|
|||
unicode-bidi: normal !important;
|
||||
}
|
||||
|
||||
.reduced-motion * {
|
||||
.reduce-motion * {
|
||||
transition: none !important;
|
||||
animation: none !important;
|
||||
}
|
||||
|
|
|
@ -24,15 +24,24 @@
|
|||
|
||||
button {
|
||||
outline: none !important;
|
||||
@include button.base;
|
||||
border-radius: var(--border-radius-large);
|
||||
padding: 8px 10px;
|
||||
background: var(--button-bg);
|
||||
border-radius: var(--border-radius);
|
||||
border: 1px solid var(--border-subtle);
|
||||
&:hover {
|
||||
background: var(--button-gradient-start);
|
||||
border: 1px solid var(--border);
|
||||
}
|
||||
font-weight: 500;
|
||||
padding: 8px 10px;
|
||||
margin: 0 4px;
|
||||
|
||||
@include elevation(1, $opacity-boost: -0.08);
|
||||
&:hover {
|
||||
@include elevation(2);
|
||||
transition: box-shadow var(--transition) linear;
|
||||
.fancy & {
|
||||
@include button.base;
|
||||
border-radius: var(--border-radius-large);
|
||||
@include elevation(1, $opacity-boost: -0.08);
|
||||
&:hover {
|
||||
@include elevation(2);
|
||||
transition: box-shadow var(--transition) linear;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
|
||||
export let collapse = false;
|
||||
export let toggleDisplay = false;
|
||||
export let animated = !document.body.classList.contains("reduced-motion");
|
||||
export let animated = !document.body.classList.contains("reduce-motion");
|
||||
|
||||
let contentHeight = 0;
|
||||
|
||||
|
|
|
@ -38,17 +38,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
width: 100%;
|
||||
background: var(--canvas-elevated);
|
||||
border: 1px solid var(--border-subtle);
|
||||
border-radius: var(--border-radius-large, 10px);
|
||||
padding: 1rem 1.75rem 0.75rem 1.25rem;
|
||||
&.rtl {
|
||||
padding: 1rem 1.25rem 0.75rem 1.75rem;
|
||||
}
|
||||
&:hover,
|
||||
&:focus-within {
|
||||
.help-badge {
|
||||
color: var(--fg-subtle);
|
||||
}
|
||||
}
|
||||
border-radius: var(--border-radius-medium, 10px);
|
||||
|
||||
&.light {
|
||||
@include elevation(2, $opacity-boost: -0.08);
|
||||
&:hover,
|
||||
|
@ -63,6 +54,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
@include elevation(4);
|
||||
}
|
||||
}
|
||||
|
||||
padding: 1rem 1.75rem 0.75rem 1.25rem;
|
||||
&.rtl {
|
||||
padding: 1rem 1.25rem 0.75rem 1.75rem;
|
||||
}
|
||||
&:hover,
|
||||
&:focus-within {
|
||||
.help-badge {
|
||||
color: var(--fg-subtle);
|
||||
}
|
||||
}
|
||||
transition: box-shadow var(--transition) ease-in-out;
|
||||
page-break-inside: avoid;
|
||||
}
|
||||
|
|
|
@ -158,7 +158,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
.modal-content {
|
||||
background-color: var(--canvas);
|
||||
color: var(--fg);
|
||||
border-radius: var(--border-radius-large, 10px);
|
||||
border-radius: var(--border-radius-medium, 10px);
|
||||
}
|
||||
|
||||
.invert {
|
||||
|
|
|
@ -11,7 +11,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
import { context as editorFieldContext } from "./EditorField.svelte";
|
||||
import { plainTextIcon } from "./icons";
|
||||
|
||||
const animated = !document.body.classList.contains("reduced-motion");
|
||||
const animated = !document.body.classList.contains("reduce-motion");
|
||||
|
||||
const editorField = editorFieldContext.get();
|
||||
const keyCombination = "Control+Shift+X";
|
||||
|
|
|
@ -11,7 +11,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
import { context as editorFieldContext } from "./EditorField.svelte";
|
||||
import { richTextIcon } from "./icons";
|
||||
|
||||
const animated = !document.body.classList.contains("reduced-motion");
|
||||
const animated = !document.body.classList.contains("reduce-motion");
|
||||
|
||||
const editorField = editorFieldContext.get();
|
||||
const keyCombination = "Control+Shift+X";
|
||||
|
|
|
@ -12,7 +12,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
|||
import { context as editorFieldContext } from "./EditorField.svelte";
|
||||
import { stickyIcon } from "./icons";
|
||||
|
||||
const animated = !document.body.classList.contains("reduced-motion");
|
||||
const animated = !document.body.classList.contains("reduce-motion");
|
||||
|
||||
export let active: boolean;
|
||||
export let show: boolean;
|
||||
|
|
|
@ -11,8 +11,9 @@ body {
|
|||
margin: 20px;
|
||||
overflow-wrap: break-word;
|
||||
// default background setting to fit with toolbar
|
||||
background-size: 100vw;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
background-position: top;
|
||||
background-attachment: fixed;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in a new issue