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-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-changes-will-take-effect-when-you = Changes will take effect when you restart Anki.
|
||||||
preferences-hours-past-midnight = hours past midnight
|
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-interrupt-current-audio-when-answering = Interrupt current audio when answering
|
||||||
preferences-learn-ahead-limit = Learn ahead limit
|
preferences-learn-ahead-limit = Learn ahead limit
|
||||||
preferences-mins = mins
|
preferences-mins = mins
|
||||||
preferences-network = Syncing
|
preferences-network = Syncing
|
||||||
preferences-next-day-starts-at = Next day starts at
|
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-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-clipboard-images-as-png = Paste clipboard images as PNG
|
||||||
preferences-paste-without-shift-key-strips-formatting = Paste without shift key strips formatting
|
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-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-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-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-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-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-synchronize-audio-and-images-too = Synchronize audio and images too
|
||||||
preferences-timebox-time-limit = Timebox time limit
|
preferences-timebox-time-limit = Timebox time limit
|
||||||
preferences-user-interface-size = User interface size
|
preferences-user-interface-size = User interface size
|
||||||
preferences-when-adding-default-to-current-deck = When adding, default to current deck
|
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-legacy-timezone-handling = Legacy timezone handling (buggy, but required for AnkiDroid <= 2.14)
|
||||||
preferences-default-search-text = Default search text
|
preferences-default-search-text = Default search text
|
||||||
preferences-default-search-text-example = eg. 'deck:current '
|
preferences-default-search-text-example = eg. 'deck:current '
|
||||||
preferences-theme-label = Theme: { $theme }
|
preferences-theme = Theme
|
||||||
preferences-theme-follow-system = Follow System
|
preferences-theme-follow-system = Follow System
|
||||||
preferences-theme-light = Light
|
preferences-theme-light = Light
|
||||||
preferences-theme-dark = Dark
|
preferences-theme-dark = Dark
|
||||||
|
@ -48,6 +48,25 @@ preferences-monthly-backups = Monthly backups to keep:
|
||||||
preferences-minutes-between-backups = Minutes between automatic backups:
|
preferences-minutes-between-backups = Minutes between automatic backups:
|
||||||
preferences-reduce-motion = Reduce motion
|
preferences-reduce-motion = Reduce motion
|
||||||
preferences-reduce-motion-tooltip = Disable various animations and transitions of the user interface
|
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 = Self-hosted sync server
|
||||||
preferences-custom-sync-url-disclaimer = For advanced users - please see the manual
|
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'.
|
## 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-opengl-mac = OpenGL (recommended on Macs)
|
||||||
preferences-video-driver-software-mac = Software (not recommended)
|
preferences-video-driver-software-mac = Software (not recommended)
|
||||||
preferences-video-driver-opengl-other = OpenGL (faster, may cause issues)
|
preferences-video-driver-opengl-other = OpenGL (faster, may cause issues)
|
||||||
|
|
|
@ -350,6 +350,7 @@ class AnkiApp(QApplication):
|
||||||
QCheckBox,
|
QCheckBox,
|
||||||
QRadioButton,
|
QRadioButton,
|
||||||
QMenu,
|
QMenu,
|
||||||
|
QSlider,
|
||||||
# classes with PyQt5 compatibility proxy
|
# classes with PyQt5 compatibility proxy
|
||||||
without_qt5_compat_wrapper(QToolButton),
|
without_qt5_compat_wrapper(QToolButton),
|
||||||
without_qt5_compat_wrapper(QTabBar),
|
without_qt5_compat_wrapper(QTabBar),
|
||||||
|
|
|
@ -7,17 +7,19 @@
|
||||||
|
|
||||||
table {
|
table {
|
||||||
padding: 1rem;
|
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);
|
.fancy & {
|
||||||
&:hover {
|
border: 1px solid var(--border-subtle);
|
||||||
@include elevation(2);
|
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 {
|
a.deck {
|
||||||
|
@ -37,7 +39,13 @@ th {
|
||||||
}
|
}
|
||||||
|
|
||||||
tr.deck td {
|
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 {
|
tr.top-level-drag-row td {
|
||||||
|
@ -62,12 +70,12 @@ tr:hover:not(.top-level-drag-row) {
|
||||||
td {
|
td {
|
||||||
background: color(border-subtle);
|
background: color(border-subtle);
|
||||||
&:first-child {
|
&:first-child {
|
||||||
border-top-left-radius: prop(border-radius-large);
|
border-top-left-radius: prop(border-radius-medium);
|
||||||
border-bottom-left-radius: prop(border-radius-large);
|
border-bottom-left-radius: prop(border-radius-medium);
|
||||||
}
|
}
|
||||||
&:last-child {
|
&:last-child {
|
||||||
border-top-right-radius: prop(border-radius-large);
|
border-top-right-radius: prop(border-radius-medium);
|
||||||
border-bottom-right-radius: prop(border-radius-large);
|
border-bottom-right-radius: prop(border-radius-medium);
|
||||||
}
|
}
|
||||||
.gears {
|
.gears {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
|
@ -82,14 +90,14 @@ tr:hover:not(.top-level-drag-row) {
|
||||||
&:first-child {
|
&:first-child {
|
||||||
border-top-left-radius: 0;
|
border-top-left-radius: 0;
|
||||||
border-bottom-left-radius: 0;
|
border-bottom-left-radius: 0;
|
||||||
border-top-right-radius: prop(border-radius-large);
|
border-top-right-radius: prop(border-radius-medium);
|
||||||
border-bottom-right-radius: prop(border-radius-large);
|
border-bottom-right-radius: prop(border-radius-medium);
|
||||||
}
|
}
|
||||||
&:last-child {
|
&:last-child {
|
||||||
border-top-right-radius: 0;
|
border-top-right-radius: 0;
|
||||||
border-bottom-right-radius: 0;
|
border-bottom-right-radius: 0;
|
||||||
border-top-left-radius: prop(border-radius-large);
|
border-top-left-radius: prop(border-radius-medium);
|
||||||
border-bottom-left-radius: prop(border-radius-large);
|
border-bottom-left-radius: prop(border-radius-medium);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
/* Copyright: Ankitects Pty Ltd and contributors
|
/* Copyright: Ankitects Pty Ltd and contributors
|
||||||
* License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */
|
* License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html */
|
||||||
|
|
||||||
|
body {
|
||||||
|
overflow: hidden;
|
||||||
|
}
|
||||||
|
|
||||||
#header {
|
#header {
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
|
|
|
@ -7,11 +7,13 @@
|
||||||
@use "sass/button-mixins" as button;
|
@use "sass/button-mixins" as button;
|
||||||
|
|
||||||
.header {
|
.header {
|
||||||
height: 41px;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: repeat(3, 1fr);
|
grid-template-columns: repeat(3, 1fr);
|
||||||
align-items: start;
|
align-items: start;
|
||||||
align-content: space-between;
|
align-content: space-between;
|
||||||
|
body:not(.fancy) & {
|
||||||
|
border-bottom: 1px solid var(--border-subtle);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.left-tray {
|
.left-tray {
|
||||||
|
@ -31,65 +33,89 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.toolbar {
|
.toolbar {
|
||||||
height: 31px;
|
|
||||||
justify-self: center;
|
justify-self: center;
|
||||||
white-space: nowrap;
|
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;
|
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 {
|
body {
|
||||||
margin: 0;
|
margin: 0;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
&.collapsed {
|
&:not(.fancy).hidden {
|
||||||
transform: translateY(-100vh);
|
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;
|
-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 {
|
.hitem:focus {
|
||||||
outline: 0;
|
outline: 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -22,14 +22,19 @@ body {
|
||||||
&:not(.isMac) * {
|
&:not(.isMac) * {
|
||||||
@include scrollbar.custom;
|
@include scrollbar.custom;
|
||||||
}
|
}
|
||||||
&.reduced-motion,
|
&.reduce-motion,
|
||||||
&.reduced-motion * {
|
&.reduce-motion * {
|
||||||
transition: none !important;
|
transition: none !important;
|
||||||
animation: none !important;
|
animation: none !important;
|
||||||
}
|
}
|
||||||
&.no-blur * {
|
&.no-blur * {
|
||||||
backdrop-filter: none !important;
|
backdrop-filter: none !important;
|
||||||
}
|
}
|
||||||
|
&:not(.fancy),
|
||||||
|
&:not(.fancy) * {
|
||||||
|
box-shadow: none !important;
|
||||||
|
backdrop-filter: none !important;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
a {
|
a {
|
||||||
|
|
|
@ -42,4 +42,5 @@ from . import (
|
||||||
synclog,
|
synclog,
|
||||||
taglimit,
|
taglimit,
|
||||||
template,
|
template,
|
||||||
|
widgets,
|
||||||
)
|
)
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
<x>0</x>
|
<x>0</x>
|
||||||
<y>0</y>
|
<y>0</y>
|
||||||
<width>643</width>
|
<width>643</width>
|
||||||
<height>580</height>
|
<height>582</height>
|
||||||
</rect>
|
</rect>
|
||||||
</property>
|
</property>
|
||||||
<property name="windowTitle">
|
<property name="windowTitle">
|
||||||
|
@ -48,6 +48,9 @@
|
||||||
<property name="lineWrapMode">
|
<property name="lineWrapMode">
|
||||||
<enum>QPlainTextEdit::NoWrap</enum>
|
<enum>QPlainTextEdit::NoWrap</enum>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string notr="true">Type commands here (Enter to submit)</string>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
<widget class="QPlainTextEdit" name="log">
|
<widget class="QPlainTextEdit" name="log">
|
||||||
<property name="sizePolicy">
|
<property name="sizePolicy">
|
||||||
|
@ -68,9 +71,28 @@
|
||||||
<property name="readOnly">
|
<property name="readOnly">
|
||||||
<bool>true</bool>
|
<bool>true</bool>
|
||||||
</property>
|
</property>
|
||||||
|
<property name="placeholderText">
|
||||||
|
<string notr="true">Output</string>
|
||||||
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -17,7 +17,7 @@
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="label">
|
<widget class="QLabel" name="label">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>preferences_interface_language</string>
|
<string>preferences_language</string>
|
||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</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.sync import sync_collection, sync_login
|
||||||
from aqt.taskman import TaskManager
|
from aqt.taskman import TaskManager
|
||||||
from aqt.theme import Theme, theme_manager
|
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.undo import UndoActionsInfo
|
||||||
from aqt.utils import (
|
from aqt.utils import (
|
||||||
HelpPage,
|
HelpPage,
|
||||||
|
@ -150,18 +150,17 @@ class MainWebView(AnkiWebView):
|
||||||
return handled
|
return handled
|
||||||
|
|
||||||
if evt.type() == QEvent.Type.Leave:
|
if evt.type() == QEvent.Type.Leave:
|
||||||
if self.mw.pm.collapse_toolbar():
|
# Show toolbar when mouse moves outside main webview
|
||||||
# Expand toolbar when mouse moves above main webview
|
# and automatically hide it with delay after mouse has entered again
|
||||||
# and automatically collapse it with delay after mouse leaves
|
if self.mw.pm.hide_top_bar() or self.mw.pm.hide_bottom_bar():
|
||||||
if self.mapFromGlobal(QCursor.pos()).y() < self.geometry().y():
|
self.mw.toolbarWeb.show()
|
||||||
if self.mw.toolbarWeb.collapsed:
|
self.mw.bottomWeb.show()
|
||||||
self.mw.toolbarWeb.expand()
|
|
||||||
return True
|
return True
|
||||||
|
|
||||||
if evt.type() == QEvent.Type.Enter:
|
if evt.type() == QEvent.Type.Enter:
|
||||||
if self.mw.pm.collapse_toolbar():
|
self.mw.toolbarWeb.hide_timer.start()
|
||||||
self.mw.toolbarWeb.hide_timer.start()
|
self.mw.bottomWeb.hide_timer.start()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
return False
|
||||||
|
|
||||||
|
@ -170,7 +169,7 @@ class AnkiQt(QMainWindow):
|
||||||
col: Collection
|
col: Collection
|
||||||
pm: ProfileManagerType
|
pm: ProfileManagerType
|
||||||
web: MainWebView
|
web: MainWebView
|
||||||
bottomWeb: AnkiWebView
|
bottomWeb: BottomWebView
|
||||||
|
|
||||||
def __init__(
|
def __init__(
|
||||||
self,
|
self,
|
||||||
|
@ -190,6 +189,7 @@ class AnkiQt(QMainWindow):
|
||||||
aqt.mw = self
|
aqt.mw = self
|
||||||
self.app = app
|
self.app = app
|
||||||
self.pm = profileManager
|
self.pm = profileManager
|
||||||
|
self.fullscreen = False
|
||||||
# init rest of app
|
# init rest of app
|
||||||
self.safeMode = (
|
self.safeMode = (
|
||||||
bool(self.app.queryKeyboardModifiers() & Qt.KeyboardModifier.ShiftModifier)
|
bool(self.app.queryKeyboardModifiers() & Qt.KeyboardModifier.ShiftModifier)
|
||||||
|
@ -709,7 +709,7 @@ class AnkiQt(QMainWindow):
|
||||||
gui_hooks.state_will_change(state, oldState)
|
gui_hooks.state_will_change(state, oldState)
|
||||||
getattr(self, f"_{state}State", lambda *_: None)(oldState, *args)
|
getattr(self, f"_{state}State", lambda *_: None)(oldState, *args)
|
||||||
if state != "resetRequired":
|
if state != "resetRequired":
|
||||||
self.bottomWeb.show()
|
self.bottomWeb.adjustHeightToFit()
|
||||||
gui_hooks.state_did_change(state, oldState)
|
gui_hooks.state_did_change(state, oldState)
|
||||||
|
|
||||||
def _deckBrowserState(self, oldState: MainWindowState) -> None:
|
def _deckBrowserState(self, oldState: MainWindowState) -> None:
|
||||||
|
@ -729,16 +729,23 @@ class AnkiQt(QMainWindow):
|
||||||
|
|
||||||
def _reviewState(self, oldState: MainWindowState) -> None:
|
def _reviewState(self, oldState: MainWindowState) -> None:
|
||||||
self.reviewer.show()
|
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:
|
else:
|
||||||
self.toolbarWeb.flatten()
|
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:
|
def _reviewCleanup(self, newState: MainWindowState) -> None:
|
||||||
if newState != "resetRequired" and newState != "review":
|
if newState != "resetRequired" and newState != "review":
|
||||||
self.reviewer.cleanup()
|
self.reviewer.cleanup()
|
||||||
self.toolbarWeb.elevate()
|
self.toolbarWeb.elevate()
|
||||||
self.toolbarWeb.expand()
|
self.toolbarWeb.show()
|
||||||
|
self.bottomWeb.show()
|
||||||
|
|
||||||
# Resetting state
|
# Resetting state
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
@ -872,12 +879,12 @@ title="{}" {}>{}</button>""".format(
|
||||||
self.form = aqt.forms.main.Ui_MainWindow()
|
self.form = aqt.forms.main.Ui_MainWindow()
|
||||||
self.form.setupUi(self)
|
self.form.setupUi(self)
|
||||||
# toolbar
|
# toolbar
|
||||||
tweb = self.toolbarWeb = ToolbarWebView(self, title="top toolbar")
|
tweb = self.toolbarWeb = TopWebView(self, title="top toolbar")
|
||||||
self.toolbar = Toolbar(self, tweb)
|
self.toolbar = Toolbar(self, tweb)
|
||||||
# main area
|
# main area
|
||||||
self.web = MainWebView(self)
|
self.web = MainWebView(self)
|
||||||
# bottom area
|
# bottom area
|
||||||
sweb = self.bottomWeb = AnkiWebView(title="bottom toolbar")
|
sweb = self.bottomWeb = BottomWebView(self, title="bottom toolbar")
|
||||||
sweb.setFocusPolicy(Qt.FocusPolicy.WheelFocus)
|
sweb.setFocusPolicy(Qt.FocusPolicy.WheelFocus)
|
||||||
sweb.disable_zoom()
|
sweb.disable_zoom()
|
||||||
# add in a layout
|
# add in a layout
|
||||||
|
@ -1068,12 +1075,12 @@ title="{}" {}>{}</button>""".format(
|
||||||
if is_lin:
|
if is_lin:
|
||||||
# On Linux, the check requires invoking an external binary,
|
# On Linux, the check requires invoking an external binary,
|
||||||
# which we don't want to be doing frequently
|
# which we don't want to be doing frequently
|
||||||
interval_secs = 300
|
|
||||||
else:
|
|
||||||
interval_secs = 5
|
interval_secs = 5
|
||||||
|
else:
|
||||||
|
interval_secs = 2
|
||||||
self.progress.timer(
|
self.progress.timer(
|
||||||
interval_secs * 1000,
|
interval_secs * 1000,
|
||||||
theme_manager.apply_style_if_system_style_changed,
|
theme_manager.apply_style,
|
||||||
True,
|
True,
|
||||||
False,
|
False,
|
||||||
parent=self,
|
parent=self,
|
||||||
|
@ -1358,9 +1365,24 @@ title="{}" {}>{}</button>""".format(
|
||||||
window.windowState() ^ Qt.WindowState.WindowFullScreen
|
window.windowState() ^ Qt.WindowState.WindowFullScreen
|
||||||
)
|
)
|
||||||
|
|
||||||
def collapse_toolbar_if_allowed(self) -> None:
|
# Hide Menubar on Windows and Linux
|
||||||
if self.pm.collapse_toolbar() and self.state == "review":
|
if window.windowState() & Qt.WindowState.WindowFullScreen and not is_mac:
|
||||||
self.toolbarWeb.collapse()
|
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
|
# Auto update
|
||||||
##########################################################################
|
##########################################################################
|
||||||
|
@ -1633,6 +1655,8 @@ title="{}" {}>{}</button>""".format(
|
||||||
s = self.debugDiagShort = QShortcut(QKeySequence("ctrl+shift+l"), d)
|
s = self.debugDiagShort = QShortcut(QKeySequence("ctrl+shift+l"), d)
|
||||||
qconnect(s.activated, frm.text.clear)
|
qconnect(s.activated, frm.text.clear)
|
||||||
|
|
||||||
|
qconnect(frm.widgetsButton.clicked, self._on_widgetGallery)
|
||||||
|
|
||||||
def addContextMenu(
|
def addContextMenu(
|
||||||
ev: Union[QCloseEvent, QContextMenuEvent], name: str
|
ev: Union[QCloseEvent, QContextMenuEvent], name: str
|
||||||
) -> None:
|
) -> None:
|
||||||
|
@ -1654,6 +1678,12 @@ title="{}" {}>{}</button>""".format(
|
||||||
gui_hooks.debug_console_will_show(d)
|
gui_hooks.debug_console_will_show(d)
|
||||||
d.show()
|
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:
|
def _captureOutput(self, on: bool) -> None:
|
||||||
mw2 = self
|
mw2 = self
|
||||||
|
|
||||||
|
|
|
@ -14,7 +14,15 @@ from aqt.operations.collection import set_preferences
|
||||||
from aqt.profiles import VideoDriver
|
from aqt.profiles import VideoDriver
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.theme import Theme
|
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):
|
class Preferences(QDialog):
|
||||||
|
@ -209,20 +217,61 @@ class Preferences(QDialog):
|
||||||
|
|
||||||
def setup_global(self) -> None:
|
def setup_global(self) -> None:
|
||||||
"Setup options global to all profiles."
|
"Setup options global to all profiles."
|
||||||
self.form.reduce_motion.setChecked(self.mw.pm.reduced_motion())
|
self.form.reduce_motion.setChecked(self.mw.pm.reduce_motion())
|
||||||
self.form.collapse_toolbar.setChecked(self.mw.pm.collapse_toolbar())
|
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))
|
self.form.uiScale.setValue(int(self.mw.pm.uiScale() * 100))
|
||||||
themes = [
|
themes = [
|
||||||
tr.preferences_theme_label(theme=theme)
|
tr.preferences_theme_follow_system(),
|
||||||
for theme in (
|
tr.preferences_theme_light(),
|
||||||
tr.preferences_theme_follow_system(),
|
tr.preferences_theme_dark(),
|
||||||
tr.preferences_theme_light(),
|
|
||||||
tr.preferences_theme_dark(),
|
|
||||||
)
|
|
||||||
]
|
]
|
||||||
self.form.theme.addItems(themes)
|
self.form.theme.addItems(themes)
|
||||||
self.form.theme.setCurrentIndex(self.mw.pm.theme().value)
|
self.form.theme.setCurrentIndex(self.mw.pm.theme().value)
|
||||||
qconnect(self.form.theme.currentIndexChanged, self.on_theme_changed)
|
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.form.legacy_import_export.setChecked(self.mw.pm.legacy_import_export())
|
||||||
|
|
||||||
self.setup_language()
|
self.setup_language()
|
||||||
|
@ -240,8 +289,6 @@ class Preferences(QDialog):
|
||||||
self.mw.pm.setUiScale(newScale)
|
self.mw.pm.setUiScale(newScale)
|
||||||
restart_required = True
|
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())
|
self.mw.pm.set_legacy_import_export(self.form.legacy_import_export.isChecked())
|
||||||
|
|
||||||
if restart_required:
|
if restart_required:
|
||||||
|
@ -291,15 +338,14 @@ class Preferences(QDialog):
|
||||||
|
|
||||||
def setup_video_driver(self) -> None:
|
def setup_video_driver(self) -> None:
|
||||||
self.video_drivers = VideoDriver.all_for_platform()
|
self.video_drivers = VideoDriver.all_for_platform()
|
||||||
names = [
|
names = [video_driver_name_for_platform(d) for d in self.video_drivers]
|
||||||
tr.preferences_video_driver(driver=video_driver_name_for_platform(d))
|
|
||||||
for d in self.video_drivers
|
|
||||||
]
|
|
||||||
self.form.video_driver.addItems(names)
|
self.form.video_driver.addItems(names)
|
||||||
self.form.video_driver.setCurrentIndex(
|
self.form.video_driver.setCurrentIndex(
|
||||||
self.video_drivers.index(self.mw.pm.video_driver())
|
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:
|
def update_video_driver(self) -> None:
|
||||||
new_driver = self.video_drivers[self.form.video_driver.currentIndex()]
|
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.lang import without_unicode_isolation
|
||||||
from anki.sync import SyncAuth
|
from anki.sync import SyncAuth
|
||||||
from anki.utils import int_time, is_mac, is_win, point_version
|
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.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
|
from aqt.utils import disable_help_button, send_to_trash, showWarning, tr
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
|
@ -518,17 +519,47 @@ create table if not exists profiles
|
||||||
def setUiScale(self, scale: float) -> None:
|
def setUiScale(self, scale: float) -> None:
|
||||||
self.meta["uiScale"] = scale
|
self.meta["uiScale"] = scale
|
||||||
|
|
||||||
def reduced_motion(self) -> bool:
|
def reduce_motion(self) -> bool:
|
||||||
return self.meta.get("reduced_motion", False)
|
return self.meta.get("reduce_motion", False)
|
||||||
|
|
||||||
def set_reduced_motion(self, on: bool) -> None:
|
def set_reduce_motion(self, on: bool) -> None:
|
||||||
self.meta["reduced_motion"] = on
|
self.meta["reduce_motion"] = on
|
||||||
|
gui_hooks.body_classes_need_update()
|
||||||
|
|
||||||
def collapse_toolbar(self) -> bool:
|
def minimalist_mode(self) -> bool:
|
||||||
return self.meta.get("collapse_toolbar", False)
|
return self.meta.get("minimalist_mode", False)
|
||||||
|
|
||||||
def set_collapse_toolbar(self, on: bool) -> None:
|
def set_minimalist_mode(self, on: bool) -> None:
|
||||||
self.meta["collapse_toolbar"] = on
|
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:
|
def last_addon_update_check(self) -> int:
|
||||||
return self.meta.get("last_addon_update_check", 0)
|
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:
|
def set_theme(self, theme: Theme) -> None:
|
||||||
self.meta["theme"] = theme.value
|
self.meta["theme"] = theme.value
|
||||||
|
|
||||||
def force_custom_styles(self) -> bool:
|
def set_widget_style(self, style: WidgetStyle) -> None:
|
||||||
return self.meta.get("force_custom_styles", False)
|
self.meta["widget_style"] = style
|
||||||
|
theme_manager.apply_style()
|
||||||
|
|
||||||
def set_force_custom_styles(self, enabled: bool) -> None:
|
def get_widget_style(self) -> WidgetStyle:
|
||||||
self.meta["force_custom_styles"] = enabled
|
return self.meta.get(
|
||||||
|
"widget_style", WidgetStyle.NATIVE if is_mac else WidgetStyle.ANKI
|
||||||
|
)
|
||||||
|
|
||||||
def browser_layout(self) -> BrowserLayout:
|
def browser_layout(self) -> BrowserLayout:
|
||||||
from aqt.browser.layout import BrowserLayout
|
from aqt.browser.layout import BrowserLayout
|
||||||
|
|
|
@ -325,7 +325,6 @@ class Reviewer:
|
||||||
self.web.allow_drops = True
|
self.web.allow_drops = True
|
||||||
self.web.eval("_blockDefaultDragDropBehavior();")
|
self.web.eval("_blockDefaultDragDropBehavior();")
|
||||||
# show answer / ease buttons
|
# show answer / ease buttons
|
||||||
self.bottom.web.show()
|
|
||||||
self.bottom.web.stdHtml(
|
self.bottom.web.stdHtml(
|
||||||
self._bottomHTML(),
|
self._bottomHTML(),
|
||||||
css=["css/toolbar-bottom.css", "css/reviewer-bottom.css"],
|
css=["css/toolbar-bottom.css", "css/reviewer-bottom.css"],
|
||||||
|
@ -706,7 +705,6 @@ time = %(time)d;
|
||||||
else:
|
else:
|
||||||
maxTime = 0
|
maxTime = 0
|
||||||
self.bottom.web.eval("showQuestion(%s,%d);" % (json.dumps(middle), maxTime))
|
self.bottom.web.eval("showQuestion(%s,%d);" % (json.dumps(middle), maxTime))
|
||||||
self.bottom.web.adjustHeightToFit()
|
|
||||||
|
|
||||||
def _showEaseButtons(self) -> None:
|
def _showEaseButtons(self) -> None:
|
||||||
middle = self._answerButtons()
|
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 import QApplication, colors, gui_hooks
|
||||||
from aqt.qt import (
|
from aqt.qt import (
|
||||||
QColor,
|
QColor,
|
||||||
QGuiApplication,
|
|
||||||
QIcon,
|
QIcon,
|
||||||
QPainter,
|
QPainter,
|
||||||
QPalette,
|
QPalette,
|
||||||
|
@ -44,6 +43,11 @@ class ColoredIcon:
|
||||||
return ColoredIcon(path=self.path, color=color)
|
return ColoredIcon(path=self.path, color=color)
|
||||||
|
|
||||||
|
|
||||||
|
class WidgetStyle(enum.IntEnum):
|
||||||
|
ANKI = 0
|
||||||
|
NATIVE = 1
|
||||||
|
|
||||||
|
|
||||||
class Theme(enum.IntEnum):
|
class Theme(enum.IntEnum):
|
||||||
FOLLOW_SYSTEM = 0
|
FOLLOW_SYSTEM = 0
|
||||||
LIGHT = 1
|
LIGHT = 1
|
||||||
|
@ -56,8 +60,8 @@ class ThemeManager:
|
||||||
_icon_cache_dark: dict[str, QIcon] = {}
|
_icon_cache_dark: dict[str, QIcon] = {}
|
||||||
_icon_size = 128
|
_icon_size = 128
|
||||||
_dark_mode_available: bool | None = None
|
_dark_mode_available: bool | None = None
|
||||||
default_palette: QPalette | None = None
|
|
||||||
_default_style: str | None = None
|
_default_style: str | None = None
|
||||||
|
_current_widget_style: WidgetStyle | None = None
|
||||||
|
|
||||||
def rtl(self) -> bool:
|
def rtl(self) -> bool:
|
||||||
return is_rtl(anki.lang.current_lang)
|
return is_rtl(anki.lang.current_lang)
|
||||||
|
@ -168,8 +172,10 @@ class ThemeManager:
|
||||||
classes.extend(["nightMode", "night_mode"])
|
classes.extend(["nightMode", "night_mode"])
|
||||||
if self.macos_dark_mode():
|
if self.macos_dark_mode():
|
||||||
classes.append("macos-dark-mode")
|
classes.append("macos-dark-mode")
|
||||||
if aqt.mw.pm.reduced_motion():
|
if aqt.mw.pm.reduce_motion():
|
||||||
classes.append("reduced-motion")
|
classes.append("reduce-motion")
|
||||||
|
if not aqt.mw.pm.minimalist_mode():
|
||||||
|
classes.append("fancy")
|
||||||
if qtmajor == 5 and qtminor < 15:
|
if qtmajor == 5 and qtminor < 15:
|
||||||
classes.append("no-blur")
|
classes.append("no-blur")
|
||||||
return " ".join(classes)
|
return " ".join(classes)
|
||||||
|
@ -212,56 +218,50 @@ class ThemeManager:
|
||||||
else:
|
else:
|
||||||
return get_linux_dark_mode()
|
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:
|
def apply_style(self) -> None:
|
||||||
"Apply currently configured style."
|
"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
|
app = aqt.mw.app
|
||||||
self.night_mode = self._determine_night_mode()
|
if not self._default_style:
|
||||||
if not self.default_palette:
|
|
||||||
self.default_palette = QGuiApplication.palette()
|
|
||||||
self._default_style = app.style().objectName()
|
self._default_style = app.style().objectName()
|
||||||
self._apply_palette(app)
|
self._apply_palette(app)
|
||||||
self._apply_style(app)
|
self._apply_style(app)
|
||||||
gui_hooks.theme_did_change()
|
gui_hooks.theme_did_change()
|
||||||
|
|
||||||
def _apply_style(self, app: QApplication) -> None:
|
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():
|
app.setStyle(QStyleFactory.create("fusion")) # type: ignore
|
||||||
from aqt.stylesheets import (
|
|
||||||
button_styles,
|
|
||||||
checkbox_styles,
|
|
||||||
combobox_styles,
|
|
||||||
general_styles,
|
|
||||||
menu_styles,
|
|
||||||
scrollbar_styles,
|
|
||||||
spinbox_styles,
|
|
||||||
table_styles,
|
|
||||||
tabwidget_styles,
|
|
||||||
)
|
|
||||||
|
|
||||||
buf += "".join(
|
buf += "".join(
|
||||||
[
|
[
|
||||||
general_styles(self),
|
custom_styles.general(self),
|
||||||
button_styles(self),
|
custom_styles.button(self),
|
||||||
checkbox_styles(self),
|
custom_styles.checkbox(self),
|
||||||
menu_styles(self),
|
custom_styles.menu(self),
|
||||||
combobox_styles(self),
|
custom_styles.combobox(self),
|
||||||
tabwidget_styles(self),
|
custom_styles.tabwidget(self),
|
||||||
table_styles(self),
|
custom_styles.table(self),
|
||||||
spinbox_styles(self),
|
custom_styles.spinbox(self),
|
||||||
scrollbar_styles(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
|
# allow addons to modify the styling
|
||||||
buf = gui_hooks.style_did_init(buf)
|
buf = gui_hooks.style_did_init(buf)
|
||||||
|
|
||||||
|
@ -270,19 +270,6 @@ class ThemeManager:
|
||||||
def _apply_palette(self, app: QApplication) -> None:
|
def _apply_palette(self, app: QApplication) -> None:
|
||||||
set_macos_dark_mode(self.night_mode)
|
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()
|
palette = QPalette()
|
||||||
text = self.qcolor(colors.FG)
|
text = self.qcolor(colors.FG)
|
||||||
palette.setColor(QPalette.ColorRole.WindowText, text)
|
palette.setColor(QPalette.ColorRole.WindowText, text)
|
||||||
|
@ -300,7 +287,7 @@ class ThemeManager:
|
||||||
palette.setColor(QPalette.ColorRole.Window, canvas)
|
palette.setColor(QPalette.ColorRole.Window, canvas)
|
||||||
palette.setColor(QPalette.ColorRole.AlternateBase, 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)
|
input_base = self.qcolor(colors.CANVAS_CODE)
|
||||||
palette.setColor(QPalette.ColorRole.Base, input_base)
|
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
|
# License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
from __future__ import annotations
|
from __future__ import annotations
|
||||||
|
|
||||||
|
import enum
|
||||||
import re
|
import re
|
||||||
from typing import Any, Optional
|
from typing import Any, Callable, Optional, cast
|
||||||
|
|
||||||
import aqt
|
import aqt
|
||||||
from anki.sync import SyncStatus
|
from anki.sync import SyncStatus
|
||||||
from aqt import gui_hooks
|
from aqt import gui_hooks, props
|
||||||
from aqt.qt import *
|
from aqt.qt import *
|
||||||
from aqt.sync import get_sync_status
|
from aqt.sync import get_sync_status
|
||||||
|
from aqt.theme import theme_manager
|
||||||
from aqt.utils import tr
|
from aqt.utils import tr
|
||||||
from aqt.webview import AnkiWebView
|
from aqt.webview import AnkiWebView
|
||||||
|
|
||||||
|
|
||||||
|
class HideMode(enum.IntEnum):
|
||||||
|
FULLSCREEN = 0
|
||||||
|
ALWAYS = 1
|
||||||
|
|
||||||
|
|
||||||
# wrapper class for set_bridge_command()
|
# wrapper class for set_bridge_command()
|
||||||
class TopToolbar:
|
class TopToolbar:
|
||||||
def __init__(self, toolbar: Toolbar) -> None:
|
def __init__(self, toolbar: Toolbar) -> None:
|
||||||
|
@ -27,45 +34,94 @@ class BottomToolbar:
|
||||||
|
|
||||||
|
|
||||||
class ToolbarWebView(AnkiWebView):
|
class ToolbarWebView(AnkiWebView):
|
||||||
|
hide_condition: Callable[..., bool]
|
||||||
|
|
||||||
def __init__(self, mw: aqt.AnkiQt, title: str) -> None:
|
def __init__(self, mw: aqt.AnkiQt, title: str) -> None:
|
||||||
AnkiWebView.__init__(self, mw, title=title)
|
AnkiWebView.__init__(self, mw, title=title)
|
||||||
self.mw = mw
|
self.mw = mw
|
||||||
self.setFocusPolicy(Qt.FocusPolicy.WheelFocus)
|
self.setFocusPolicy(Qt.FocusPolicy.WheelFocus)
|
||||||
self.disable_zoom()
|
self.disable_zoom()
|
||||||
self.collapsed = False
|
self.hidden = False
|
||||||
self.web_height = 0
|
|
||||||
# collapse timer
|
|
||||||
self.hide_timer = QTimer()
|
self.hide_timer = QTimer()
|
||||||
self.hide_timer.setSingleShot(True)
|
self.hide_timer.setSingleShot(True)
|
||||||
self.hide_timer.setInterval(1000)
|
self.reset_timer()
|
||||||
qconnect(self.hide_timer.timeout, self.mw.collapse_toolbar_if_allowed)
|
|
||||||
|
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):
|
def eventFilter(self, obj, evt):
|
||||||
if handled := super().eventFilter(obj, evt):
|
if handled := super().eventFilter(obj, evt):
|
||||||
return handled
|
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:
|
if evt.type() == QEvent.Type.Enter:
|
||||||
self.hide_timer.stop()
|
self.reset_timer()
|
||||||
self.hide_timer.setInterval(1000)
|
self.mw.bottomWeb.reset_timer()
|
||||||
return True
|
return True
|
||||||
|
|
||||||
return False
|
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:
|
def _onHeight(self, qvar: Optional[int]) -> None:
|
||||||
super()._onHeight(qvar)
|
super()._onHeight(qvar)
|
||||||
self.web_height = int(qvar)
|
self.web_height = int(qvar)
|
||||||
|
|
||||||
def collapse(self) -> None:
|
def hide_if_allowed(self) -> None:
|
||||||
self.collapsed = True
|
if self.mw.state != "review":
|
||||||
self.eval("""document.body.classList.add("collapsed"); """)
|
return
|
||||||
|
|
||||||
def expand(self) -> None:
|
if self.mw.pm.hide_top_bar():
|
||||||
self.collapsed = False
|
if (
|
||||||
self.eval("""document.body.classList.remove("collapsed"); """)
|
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:
|
def flatten(self) -> None:
|
||||||
self.eval("document.body.classList.add('flat'); ")
|
self.eval("""document.body.classList.add("flat"); """)
|
||||||
|
|
||||||
def elevate(self) -> None:
|
def elevate(self) -> None:
|
||||||
self.eval(
|
self.eval(
|
||||||
|
@ -76,15 +132,24 @@ class ToolbarWebView(AnkiWebView):
|
||||||
)
|
)
|
||||||
|
|
||||||
def update_background_image(self) -> None:
|
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
|
# 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
|
# change computedStyle px value back to 100vw
|
||||||
background = re.sub(r"\d+px", "100vw", background)
|
background = re.sub(r"\d+px", "100vw", background)
|
||||||
|
|
||||||
self.eval(
|
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
|
# offset reviewer background by toolbar height
|
||||||
self.mw.web.eval(
|
self.mw.web.eval(
|
||||||
f"""document.body.style.setProperty("background-position-y", "-{self.web_height}px"); """
|
f"""document.body.style.setProperty("background-position-y", "-{self.web_height}px"); """
|
||||||
|
@ -95,6 +160,93 @@ class ToolbarWebView(AnkiWebView):
|
||||||
set_background,
|
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:
|
class Toolbar:
|
||||||
def __init__(self, mw: aqt.AnkiQt, web: AnkiWebView) -> None:
|
def __init__(self, mw: aqt.AnkiQt, web: AnkiWebView) -> None:
|
||||||
|
|
|
@ -248,6 +248,7 @@ class AnkiWebView(QWebEngineView):
|
||||||
self.resetHandlers()
|
self.resetHandlers()
|
||||||
self._filterSet = False
|
self._filterSet = False
|
||||||
gui_hooks.theme_did_change.append(self.on_theme_did_change)
|
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)
|
qconnect(self.loadFinished, self._on_load_finished)
|
||||||
|
|
||||||
|
@ -410,8 +411,7 @@ class AnkiWebView(QWebEngineView):
|
||||||
return 3
|
return 3
|
||||||
|
|
||||||
def standard_css(self) -> str:
|
def standard_css(self) -> str:
|
||||||
palette = theme_manager.default_palette
|
color_hl = theme_manager.var(colors.BORDER_FOCUS)
|
||||||
color_hl = palette.color(QPalette.ColorRole.Highlight).name()
|
|
||||||
|
|
||||||
if is_win:
|
if is_win:
|
||||||
# T: include a font for your language on Windows, eg: "Segoe UI", "MS Mincho"
|
# T: include a font for your language on Windows, eg: "Segoe UI", "MS Mincho"
|
||||||
|
@ -706,6 +706,7 @@ html {{ {font} }}
|
||||||
return
|
return
|
||||||
|
|
||||||
gui_hooks.theme_did_change.remove(self.on_theme_did_change)
|
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))
|
mw.mediaServer.clear_page_html(id(self))
|
||||||
self._page.deleteLater()
|
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")
|
@deprecated(info="use theme_manager.qcolor() instead")
|
||||||
def get_window_bg_color(self, night_mode: Optional[bool] = None) -> QColor:
|
def get_window_bg_color(self, night_mode: Optional[bool] = None) -> QColor:
|
||||||
return theme_manager.qcolor(colors.CANVAS)
|
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",
|
name="theme_did_change",
|
||||||
doc="Called after night mode is toggled.",
|
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
|
# Webview
|
||||||
###################
|
###################
|
||||||
Hook(
|
Hook(
|
||||||
|
|
|
@ -25,8 +25,14 @@ $vars: (
|
||||||
default: 5px,
|
default: 5px,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
medium: (
|
||||||
|
"Used for container corners",
|
||||||
|
(
|
||||||
|
default: 12px,
|
||||||
|
),
|
||||||
|
),
|
||||||
large: (
|
large: (
|
||||||
"Used for big centered buttons",
|
"Used for pill-shaped buttons",
|
||||||
(
|
(
|
||||||
default: 15px,
|
default: 15px,
|
||||||
),
|
),
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
@use "vars" as *;
|
@use "vars" as *;
|
||||||
@use "root-vars";
|
@use "root-vars";
|
||||||
@use "button-mixins" as button;
|
@use "button-mixins" as button;
|
||||||
|
@use "sass/scrollbar";
|
||||||
|
|
||||||
$body-color: color(fg);
|
$body-color: color(fg);
|
||||||
$body-bg: color(canvas);
|
$body-bg: color(canvas);
|
||||||
|
@ -43,6 +44,26 @@ html {
|
||||||
overscroll-behavior: none;
|
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 {
|
button {
|
||||||
/* override transition for instant hover response */
|
/* override transition for instant hover response */
|
||||||
transition: color var(--transition) ease-in-out, box-shadow var(--transition) ease-in-out !important;
|
transition: color var(--transition) ease-in-out, box-shadow var(--transition) ease-in-out !important;
|
||||||
|
@ -57,7 +78,7 @@ samp {
|
||||||
unicode-bidi: normal !important;
|
unicode-bidi: normal !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.reduced-motion * {
|
.reduce-motion * {
|
||||||
transition: none !important;
|
transition: none !important;
|
||||||
animation: none !important;
|
animation: none !important;
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,15 +24,24 @@
|
||||||
|
|
||||||
button {
|
button {
|
||||||
outline: none !important;
|
outline: none !important;
|
||||||
@include button.base;
|
background: var(--button-bg);
|
||||||
border-radius: var(--border-radius-large);
|
border-radius: var(--border-radius);
|
||||||
padding: 8px 10px;
|
border: 1px solid var(--border-subtle);
|
||||||
|
&:hover {
|
||||||
|
background: var(--button-gradient-start);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
}
|
||||||
font-weight: 500;
|
font-weight: 500;
|
||||||
|
padding: 8px 10px;
|
||||||
margin: 0 4px;
|
margin: 0 4px;
|
||||||
|
|
||||||
@include elevation(1, $opacity-boost: -0.08);
|
.fancy & {
|
||||||
&:hover {
|
@include button.base;
|
||||||
@include elevation(2);
|
border-radius: var(--border-radius-large);
|
||||||
transition: box-shadow var(--transition) linear;
|
@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 collapse = false;
|
||||||
export let toggleDisplay = 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;
|
let contentHeight = 0;
|
||||||
|
|
||||||
|
|
|
@ -38,17 +38,8 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
width: 100%;
|
width: 100%;
|
||||||
background: var(--canvas-elevated);
|
background: var(--canvas-elevated);
|
||||||
border: 1px solid var(--border-subtle);
|
border: 1px solid var(--border-subtle);
|
||||||
border-radius: var(--border-radius-large, 10px);
|
border-radius: var(--border-radius-medium, 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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
&.light {
|
&.light {
|
||||||
@include elevation(2, $opacity-boost: -0.08);
|
@include elevation(2, $opacity-boost: -0.08);
|
||||||
&:hover,
|
&:hover,
|
||||||
|
@ -63,6 +54,17 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
@include elevation(4);
|
@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;
|
transition: box-shadow var(--transition) ease-in-out;
|
||||||
page-break-inside: avoid;
|
page-break-inside: avoid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -158,7 +158,7 @@ License: GNU AGPL, version 3 or later; http://www.gnu.org/licenses/agpl.html
|
||||||
.modal-content {
|
.modal-content {
|
||||||
background-color: var(--canvas);
|
background-color: var(--canvas);
|
||||||
color: var(--fg);
|
color: var(--fg);
|
||||||
border-radius: var(--border-radius-large, 10px);
|
border-radius: var(--border-radius-medium, 10px);
|
||||||
}
|
}
|
||||||
|
|
||||||
.invert {
|
.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 { context as editorFieldContext } from "./EditorField.svelte";
|
||||||
import { plainTextIcon } from "./icons";
|
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 editorField = editorFieldContext.get();
|
||||||
const keyCombination = "Control+Shift+X";
|
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 { context as editorFieldContext } from "./EditorField.svelte";
|
||||||
import { richTextIcon } from "./icons";
|
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 editorField = editorFieldContext.get();
|
||||||
const keyCombination = "Control+Shift+X";
|
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 { context as editorFieldContext } from "./EditorField.svelte";
|
||||||
import { stickyIcon } from "./icons";
|
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 active: boolean;
|
||||||
export let show: boolean;
|
export let show: boolean;
|
||||||
|
|
|
@ -11,8 +11,9 @@ body {
|
||||||
margin: 20px;
|
margin: 20px;
|
||||||
overflow-wrap: break-word;
|
overflow-wrap: break-word;
|
||||||
// default background setting to fit with toolbar
|
// default background setting to fit with toolbar
|
||||||
background-size: 100vw;
|
background-size: cover;
|
||||||
background-repeat: no-repeat;
|
background-repeat: no-repeat;
|
||||||
|
background-position: top;
|
||||||
background-attachment: fixed;
|
background-attachment: fixed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue