├── .github
├── FUNDING.yml
├── ISSUE_TEMPLATE
│ ├── bug-issue-report.md
│ ├── feature-request.md
│ └── question.md
├── options_advanced.png
├── options_general.png
├── options_macros.png
└── ui_main.png
├── .gitignore
├── LICENSE
├── README.md
├── __init__.py
├── meta.json
├── res
├── img
│ ├── add_icon.svg
│ ├── anki_like.png
│ ├── chevron_down.svg
│ ├── code_icon.svg
│ ├── heart_icon.svg
│ ├── horiz_lines.svg
│ ├── kofilogo_blue.PNG
│ ├── patreon.png
│ ├── remove_icon.svg
│ ├── stats_icon.svg
│ ├── vert_grip.svg
│ └── vert_lines.svg
└── ui
│ ├── Qt5
│ ├── cell_item.py
│ ├── macro_dialog.py
│ └── options_dialog.py
│ ├── Qt6
│ ├── cell_item.py
│ ├── macro_dialog.py
│ └── options_dialog.py
│ ├── cell_item.ui
│ ├── forms.py
│ ├── macro_dialog.ui
│ └── options_dialog.ui
└── src
├── config.py
├── consts.py
├── options.py
├── overview.py
└── toolbar.py
/.github/FUNDING.yml:
--------------------------------------------------------------------------------
1 | # These are supported funding model platforms
2 |
3 | github: # Replace with up to 4 GitHub Sponsors-enabled usernames e.g., [user1, user2]
4 | patreon: iamjustkoi
5 | open_collective: # Replace with a single Open Collective username
6 | ko_fi: iamjustkoi
7 | tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel
8 | community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry
9 | liberapay: # Replace with a single Liberapay username
10 | issuehunt: # Replace with a single IssueHunt username
11 | otechie: # Replace with a single Otechie username
12 | lfx_crowdfunding: # Replace with a single LFX Crowdfunding project-name e.g., cloud-foundry
13 | custom: # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2']
14 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/bug-issue-report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug/Issue Report
3 | about: Create a report to help improve the add-on
4 | title: ''
5 | labels: issue
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Bug/Issue Description**
11 | A short description of the issue.
12 |
13 | **To Reproduce**
14 | Steps to reproduce:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Screenshots/Visuals**
21 | If necessary/applicable, add some screenshots to help explain the issue.
22 |
23 | **System/Debug Info**
24 | You can get this from Anki in Help -> About -> Copy Debug Info,
25 |
26 | **Additional Context**
27 | Any other context that might seem important.
28 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature-request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature Request
3 | about: Ask about implementing a change or idea for the add-on
4 | title: ''
5 | labels: feature
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Potential Issues**
11 | Any issues you've run into that could be resolved.
12 |
13 | **Feature Description**
14 | Description of the feature and how you might want it to work.
15 |
16 | **Alternatives Considered**
17 | Any other alternatives or different features you might've also considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request you think might be useful.
21 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/question.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Question
3 | about: Ask about the add-on
4 | title: ''
5 | labels: question
6 | assignees: ''
7 |
8 | ---
9 |
10 |
11 |
--------------------------------------------------------------------------------
/.github/options_advanced.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamjustkoi/StudyTimeStats/40753916b59d1664950f0bef2414fd7900edad92/.github/options_advanced.png
--------------------------------------------------------------------------------
/.github/options_general.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamjustkoi/StudyTimeStats/40753916b59d1664950f0bef2414fd7900edad92/.github/options_general.png
--------------------------------------------------------------------------------
/.github/options_macros.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamjustkoi/StudyTimeStats/40753916b59d1664950f0bef2414fd7900edad92/.github/options_macros.png
--------------------------------------------------------------------------------
/.github/ui_main.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamjustkoi/StudyTimeStats/40753916b59d1664950f0bef2414fd7900edad92/.github/ui_main.png
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | /.idea/*
2 | /.ignored/
3 | /.build/
4 | manifest.json
5 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022-2023 JustKoi (iamjustkoi)
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #
Study Time Stats
2 |
3 | Add some customizable study time and review count statistics to Anki's main window!
4 |
5 |
6 | ## Installation
7 |
8 | Install from [Anki-Web](https://ankiweb.net/shared/info/1247171202)
9 | Or through Anki via: Tools -> Add-ons -> Get Add-ons...
10 | > 1247171202
11 |
12 | ## Options
13 |
14 | ### General
15 |
16 | Customize the style, column count, range, text, code, and output for all rendered statistics!
17 |
18 |
19 | ### Advanced
20 |
21 | Exclude decks, change time formats, and other miscellaneous options!
22 |
23 |
24 | ## Macros
25 |
26 | Custom text macros can be used for all stat outputs!
27 |
28 | These can be accessed via the "Add Text Macro" button (or the little "+" to the right of the text inputs).
29 |
30 |
31 | #### Bugs/Issues:
32 |
33 | Please post any issues/feedback you might have over the project's
34 | on [GitHub](https://github.com/iamjustkoi/StudyTimeStats/issues).
35 |
36 |
37 | Wish you the best! -koi
38 |
39 | MIT License ©2022-2023 JustKoi (iamjustkoi)
40 |
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | # MIT License: Copyright (c) 2022-2023 JustKoi (iamjustkoi)
2 | # Full license text available in the "LICENSE" file, packaged with the add-on.
3 |
4 | """
5 | Shows total study time and a ranged amount of study time in Anki's main window.
6 | """
7 | from .src import overview
8 | from .src import toolbar
9 |
10 |
11 | def initialize():
12 | """
13 | Initializer for the add-on. Called at the start for finer execution order and a bit of readability.
14 | """
15 | overview.build_hooks()
16 | toolbar.build_toolbar_actions()
17 |
18 |
19 | initialize()
20 |
--------------------------------------------------------------------------------
/meta.json:
--------------------------------------------------------------------------------
1 | {"name": "Study Time Stats", "branch_index": 0}
--------------------------------------------------------------------------------
/res/img/add_icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
8 |
9 |
--------------------------------------------------------------------------------
/res/img/anki_like.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamjustkoi/StudyTimeStats/40753916b59d1664950f0bef2414fd7900edad92/res/img/anki_like.png
--------------------------------------------------------------------------------
/res/img/chevron_down.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/res/img/code_icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
12 |
13 |
--------------------------------------------------------------------------------
/res/img/heart_icon.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/res/img/horiz_lines.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
7 |
9 |
10 |
--------------------------------------------------------------------------------
/res/img/kofilogo_blue.PNG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamjustkoi/StudyTimeStats/40753916b59d1664950f0bef2414fd7900edad92/res/img/kofilogo_blue.PNG
--------------------------------------------------------------------------------
/res/img/patreon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/iamjustkoi/StudyTimeStats/40753916b59d1664950f0bef2414fd7900edad92/res/img/patreon.png
--------------------------------------------------------------------------------
/res/img/remove_icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/res/img/stats_icon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
6 |
7 |
8 |
10 |
11 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
--------------------------------------------------------------------------------
/res/img/vert_grip.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/res/img/vert_lines.svg:
--------------------------------------------------------------------------------
1 |
3 |
4 |
--------------------------------------------------------------------------------
/res/ui/Qt5/macro_dialog.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'macro_dialog.ui'
4 | #
5 | # Created by: PyQt6 UI code generator 5.15.7
6 | #
7 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8 | # run again. Do not edit this file unless you know what you are doing.
9 |
10 |
11 | from PyQt5 import QtCore, QtWidgets
12 |
13 |
14 | class Ui_MacroDialog(object):
15 | def setupUi(self, MacroDialog):
16 | MacroDialog.setObjectName("MacroDialog")
17 | MacroDialog.resize(528, 362)
18 | self.verticalLayout = QtWidgets.QVBoxLayout(MacroDialog)
19 | self.verticalLayout.setObjectName("verticalLayout")
20 | self.macroGroupBox = QtWidgets.QGroupBox(MacroDialog)
21 | sizePolicy = QtWidgets.QSizePolicy(
22 | QtWidgets.QSizePolicy.Policy.Preferred,
23 | QtWidgets.QSizePolicy.Policy.Expanding
24 | )
25 | sizePolicy.setHorizontalStretch(0)
26 | sizePolicy.setVerticalStretch(0)
27 | sizePolicy.setHeightForWidth(self.macroGroupBox.sizePolicy().hasHeightForWidth())
28 | self.macroGroupBox.setSizePolicy(sizePolicy)
29 | self.macroGroupBox.setObjectName("macroGroupBox")
30 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.macroGroupBox)
31 | self.verticalLayout_2.setContentsMargins(6, 0, 6, 6)
32 | self.verticalLayout_2.setObjectName("verticalLayout_2")
33 | self.filterLineEdit = QtWidgets.QLineEdit(self.macroGroupBox)
34 | self.filterLineEdit.setClearButtonEnabled(True)
35 | self.filterLineEdit.setObjectName("filterLineEdit")
36 | self.verticalLayout_2.addWidget(self.filterLineEdit)
37 | self.listView = QtWidgets.QListView(self.macroGroupBox)
38 | self.listView.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
39 | self.listView.setFrameShadow(QtWidgets.QFrame.Shadow.Plain)
40 | self.listView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
41 | self.listView.setTabKeyNavigation(True)
42 | self.listView.setProperty("showDropIndicator", False)
43 | self.listView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
44 | self.listView.setObjectName("listView")
45 | self.verticalLayout_2.addWidget(self.listView)
46 | self.verticalLayout.addWidget(self.macroGroupBox)
47 | self.previewGroupBox = QtWidgets.QGroupBox(MacroDialog)
48 | self.previewGroupBox.setMinimumSize(QtCore.QSize(0, 42))
49 | self.previewGroupBox.setObjectName("previewGroupBox")
50 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.previewGroupBox)
51 | self.verticalLayout_3.setContentsMargins(6, 6, 6, 6)
52 | self.verticalLayout_3.setObjectName("verticalLayout_3")
53 | self.previewLabel = QtWidgets.QLabel(self.previewGroupBox)
54 | self.previewLabel.setObjectName("previewLabel")
55 | self.verticalLayout_3.addWidget(self.previewLabel)
56 | self.verticalLayout.addWidget(self.previewGroupBox)
57 | self.buttonBox = QtWidgets.QDialogButtonBox(MacroDialog)
58 | self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
59 | self.buttonBox.setStandardButtons(
60 | QtWidgets.QDialogButtonBox.StandardButton.Cancel | QtWidgets.QDialogButtonBox.StandardButton.Ok
61 | )
62 | self.buttonBox.setObjectName("buttonBox")
63 | self.verticalLayout.addWidget(self.buttonBox)
64 |
65 | self.retranslateUi(MacroDialog)
66 | self.buttonBox.accepted.connect(MacroDialog.accept) # type: ignore
67 | self.buttonBox.rejected.connect(MacroDialog.reject) # type: ignore
68 | QtCore.QMetaObject.connectSlotsByName(MacroDialog)
69 |
70 | def retranslateUi(self, MacroDialog):
71 | _translate = QtCore.QCoreApplication.translate
72 | MacroDialog.setWindowTitle(_translate("MacroDialog", "Macros"))
73 | self.macroGroupBox.setTitle(_translate("MacroDialog", "Macros"))
74 | self.filterLineEdit.setPlaceholderText(_translate("MacroDialog", "Filter..."))
75 | self.previewGroupBox.setTitle(_translate("MacroDialog", "Preview"))
76 | self.previewLabel.setText(_translate("MacroDialog", "test"))
77 |
78 |
79 | if __name__ == "__main__":
80 | import sys
81 |
82 | app = QtWidgets.QApplication(sys.argv)
83 | MacroDialog = QtWidgets.QDialog()
84 | ui = Ui_MacroDialog()
85 | ui.setupUi(MacroDialog)
86 | MacroDialog.show()
87 | sys.exit(app.exec_())
88 |
--------------------------------------------------------------------------------
/res/ui/Qt5/options_dialog.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'options_dialog.ui'
4 | #
5 | # Created by: PyQt5 UI code generator 5.15.7
6 | #
7 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8 | # run again. Do not edit this file unless you know what you are doing.
9 |
10 |
11 | from PyQt5 import QtCore, QtGui, QtWidgets
12 |
13 |
14 | class Ui_OptionsDialog(object):
15 | def setupUi(self, OptionsDialog):
16 | OptionsDialog.setObjectName("OptionsDialog")
17 | OptionsDialog.setWindowModality(QtCore.Qt.WindowModal)
18 | OptionsDialog.resize(517, 620)
19 | OptionsDialog.setSizeGripEnabled(True)
20 | OptionsDialog.setModal(True)
21 | self.verticalLayout_4 = QtWidgets.QVBoxLayout(OptionsDialog)
22 | self.verticalLayout_4.setObjectName("verticalLayout_4")
23 | self.tabs_widget = QtWidgets.QTabWidget(OptionsDialog)
24 | self.tabs_widget.setEnabled(True)
25 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
26 | sizePolicy.setHorizontalStretch(0)
27 | sizePolicy.setVerticalStretch(0)
28 | sizePolicy.setHeightForWidth(self.tabs_widget.sizePolicy().hasHeightForWidth())
29 | self.tabs_widget.setSizePolicy(sizePolicy)
30 | self.tabs_widget.setTabPosition(QtWidgets.QTabWidget.North)
31 | self.tabs_widget.setTabShape(QtWidgets.QTabWidget.Rounded)
32 | self.tabs_widget.setObjectName("tabs_widget")
33 | self.appearance_tab = QtWidgets.QWidget()
34 | self.appearance_tab.setEnabled(True)
35 | self.appearance_tab.setObjectName("appearance_tab")
36 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.appearance_tab)
37 | self.verticalLayout_3.setObjectName("verticalLayout_3")
38 | self.frame = QtWidgets.QFrame(self.appearance_tab)
39 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
40 | sizePolicy.setHorizontalStretch(0)
41 | sizePolicy.setVerticalStretch(0)
42 | sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth())
43 | self.frame.setSizePolicy(sizePolicy)
44 | self.frame.setObjectName("frame")
45 | self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.frame)
46 | self.verticalLayout_8.setObjectName("verticalLayout_8")
47 | self.pages_group = QtWidgets.QGroupBox(self.frame)
48 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Maximum)
49 | sizePolicy.setHorizontalStretch(0)
50 | sizePolicy.setVerticalStretch(0)
51 | sizePolicy.setHeightForWidth(self.pages_group.sizePolicy().hasHeightForWidth())
52 | self.pages_group.setSizePolicy(sizePolicy)
53 | self.pages_group.setObjectName("pages_group")
54 | self.horizontalLayout = QtWidgets.QHBoxLayout(self.pages_group)
55 | self.horizontalLayout.setObjectName("horizontalLayout")
56 | self.browser_checkbox = QtWidgets.QCheckBox(self.pages_group)
57 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
58 | sizePolicy.setHorizontalStretch(0)
59 | sizePolicy.setVerticalStretch(0)
60 | sizePolicy.setHeightForWidth(self.browser_checkbox.sizePolicy().hasHeightForWidth())
61 | self.browser_checkbox.setSizePolicy(sizePolicy)
62 | self.browser_checkbox.setChecked(True)
63 | self.browser_checkbox.setObjectName("browser_checkbox")
64 | self.horizontalLayout.addWidget(self.browser_checkbox)
65 | self.overview_checkbox = QtWidgets.QCheckBox(self.pages_group)
66 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Fixed)
67 | sizePolicy.setHorizontalStretch(0)
68 | sizePolicy.setVerticalStretch(0)
69 | sizePolicy.setHeightForWidth(self.overview_checkbox.sizePolicy().hasHeightForWidth())
70 | self.overview_checkbox.setSizePolicy(sizePolicy)
71 | self.overview_checkbox.setChecked(True)
72 | self.overview_checkbox.setObjectName("overview_checkbox")
73 | self.horizontalLayout.addWidget(self.overview_checkbox)
74 | self.congrats_checkbox = QtWidgets.QCheckBox(self.pages_group)
75 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Maximum, QtWidgets.QSizePolicy.Fixed)
76 | sizePolicy.setHorizontalStretch(0)
77 | sizePolicy.setVerticalStretch(0)
78 | sizePolicy.setHeightForWidth(self.congrats_checkbox.sizePolicy().hasHeightForWidth())
79 | self.congrats_checkbox.setSizePolicy(sizePolicy)
80 | self.congrats_checkbox.setChecked(True)
81 | self.congrats_checkbox.setObjectName("congrats_checkbox")
82 | self.horizontalLayout.addWidget(self.congrats_checkbox)
83 | self.verticalLayout_8.addWidget(self.pages_group)
84 | self.mainViewGroupbox = QtWidgets.QGroupBox(self.frame)
85 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
86 | sizePolicy.setHorizontalStretch(0)
87 | sizePolicy.setVerticalStretch(0)
88 | sizePolicy.setHeightForWidth(self.mainViewGroupbox.sizePolicy().hasHeightForWidth())
89 | self.mainViewGroupbox.setSizePolicy(sizePolicy)
90 | self.mainViewGroupbox.setAlignment(QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
91 | self.mainViewGroupbox.setObjectName("mainViewGroupbox")
92 | self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.mainViewGroupbox)
93 | self.verticalLayout_5.setObjectName("verticalLayout_5")
94 | self.cellListWidget = QtWidgets.QListWidget(self.mainViewGroupbox)
95 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
96 | sizePolicy.setHorizontalStretch(0)
97 | sizePolicy.setVerticalStretch(0)
98 | sizePolicy.setHeightForWidth(self.cellListWidget.sizePolicy().hasHeightForWidth())
99 | self.cellListWidget.setSizePolicy(sizePolicy)
100 | self.cellListWidget.setMinimumSize(QtCore.QSize(0, 64))
101 | self.cellListWidget.setFrameShape(QtWidgets.QFrame.NoFrame)
102 | self.cellListWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
103 | self.cellListWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustIgnored)
104 | self.cellListWidget.setEditTriggers(QtWidgets.QAbstractItemView.NoEditTriggers)
105 | self.cellListWidget.setProperty("showDropIndicator", False)
106 | self.cellListWidget.setDragEnabled(True)
107 | self.cellListWidget.setDragDropMode(QtWidgets.QAbstractItemView.InternalMove)
108 | self.cellListWidget.setSelectionMode(QtWidgets.QAbstractItemView.NoSelection)
109 | self.cellListWidget.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
110 | self.cellListWidget.setObjectName("cellListWidget")
111 | self.verticalLayout_5.addWidget(self.cellListWidget)
112 | self.verticalLayout_8.addWidget(self.mainViewGroupbox)
113 | self.verticalLayout_3.addWidget(self.frame)
114 | self.tabs_widget.addTab(self.appearance_tab, "")
115 | self.decks_tab = QtWidgets.QWidget()
116 | self.decks_tab.setObjectName("decks_tab")
117 | self.verticalLayout = QtWidgets.QVBoxLayout(self.decks_tab)
118 | self.verticalLayout.setObjectName("verticalLayout")
119 | self.toolbar_checkbox = QtWidgets.QCheckBox(self.decks_tab)
120 | self.toolbar_checkbox.setChecked(True)
121 | self.toolbar_checkbox.setObjectName("toolbar_checkbox")
122 | self.verticalLayout.addWidget(self.toolbar_checkbox)
123 | self.include_deleted_checkbox = QtWidgets.QCheckBox(self.decks_tab)
124 | self.include_deleted_checkbox.setChecked(True)
125 | self.include_deleted_checkbox.setObjectName("include_deleted_checkbox")
126 | self.verticalLayout.addWidget(self.include_deleted_checkbox)
127 | self.useRolloverCheckbox = QtWidgets.QCheckBox(self.decks_tab)
128 | self.useRolloverCheckbox.setChecked(True)
129 | self.useRolloverCheckbox.setObjectName("useRolloverCheckbox")
130 | self.verticalLayout.addWidget(self.useRolloverCheckbox)
131 | self.useDecimalCheckbox = QtWidgets.QCheckBox(self.decks_tab)
132 | self.useDecimalCheckbox.setChecked(True)
133 | self.useDecimalCheckbox.setObjectName("useDecimalCheckbox")
134 | self.verticalLayout.addWidget(self.useDecimalCheckbox)
135 | self.enabled_decks_group = QtWidgets.QGroupBox(self.decks_tab)
136 | self.enabled_decks_group.setMinimumSize(QtCore.QSize(0, 100))
137 | self.enabled_decks_group.setObjectName("enabled_decks_group")
138 | self.enabled_decks_layout = QtWidgets.QVBoxLayout(self.enabled_decks_group)
139 | self.enabled_decks_layout.setObjectName("enabled_decks_layout")
140 | self.exclude_layout = QtWidgets.QHBoxLayout()
141 | self.exclude_layout.setObjectName("exclude_layout")
142 | self.deck_enable_button = QtWidgets.QPushButton(self.enabled_decks_group)
143 | self.deck_enable_button.setFocusPolicy(QtCore.Qt.TabFocus)
144 | self.deck_enable_button.setObjectName("deck_enable_button")
145 | self.exclude_layout.addWidget(self.deck_enable_button)
146 | self.deck_disable_button = QtWidgets.QPushButton(self.enabled_decks_group)
147 | self.deck_disable_button.setFocusPolicy(QtCore.Qt.TabFocus)
148 | self.deck_disable_button.setObjectName("deck_disable_button")
149 | self.exclude_layout.addWidget(self.deck_disable_button)
150 | spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum)
151 | self.exclude_layout.addItem(spacerItem)
152 | self.enabled_decks_layout.addLayout(self.exclude_layout)
153 | self.excluded_decks_list = QtWidgets.QListWidget(self.enabled_decks_group)
154 | self.excluded_decks_list.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
155 | self.excluded_decks_list.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectRows)
156 | self.excluded_decks_list.setObjectName("excluded_decks_list")
157 | self.enabled_decks_layout.addWidget(self.excluded_decks_list)
158 | self.verticalLayout.addWidget(self.enabled_decks_group)
159 | self.tabs_widget.addTab(self.decks_tab, "")
160 | self.about_tab = QtWidgets.QWidget()
161 | self.about_tab.setObjectName("about_tab")
162 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.about_tab)
163 | self.verticalLayout_2.setSizeConstraint(QtWidgets.QLayout.SetNoConstraint)
164 | self.verticalLayout_2.setObjectName("verticalLayout_2")
165 | self.scroll_area = QtWidgets.QScrollArea(self.about_tab)
166 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
167 | sizePolicy.setHorizontalStretch(0)
168 | sizePolicy.setVerticalStretch(0)
169 | sizePolicy.setHeightForWidth(self.scroll_area.sizePolicy().hasHeightForWidth())
170 | self.scroll_area.setSizePolicy(sizePolicy)
171 | self.scroll_area.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.AdjustToContents)
172 | self.scroll_area.setWidgetResizable(True)
173 | self.scroll_area.setObjectName("scroll_area")
174 | self.about_scroll = QtWidgets.QWidget()
175 | self.about_scroll.setGeometry(QtCore.QRect(0, 0, 456, 555))
176 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Expanding)
177 | sizePolicy.setHorizontalStretch(0)
178 | sizePolicy.setVerticalStretch(0)
179 | sizePolicy.setHeightForWidth(self.about_scroll.sizePolicy().hasHeightForWidth())
180 | self.about_scroll.setSizePolicy(sizePolicy)
181 | self.about_scroll.setObjectName("about_scroll")
182 | self.scroll_layout = QtWidgets.QVBoxLayout(self.about_scroll)
183 | self.scroll_layout.setObjectName("scroll_layout")
184 | self.about_label_header = QtWidgets.QLabel(self.about_scroll)
185 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
186 | sizePolicy.setHorizontalStretch(0)
187 | sizePolicy.setVerticalStretch(0)
188 | sizePolicy.setHeightForWidth(self.about_label_header.sizePolicy().hasHeightForWidth())
189 | self.about_label_header.setSizePolicy(sizePolicy)
190 | self.about_label_header.setTextFormat(QtCore.Qt.AutoText)
191 | self.about_label_header.setAlignment(QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
192 | self.about_label_header.setWordWrap(True)
193 | self.about_label_header.setOpenExternalLinks(True)
194 | self.about_label_header.setTextInteractionFlags(
195 | QtCore.Qt.LinksAccessibleByKeyboard | QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextBrowserInteraction
196 | | QtCore.Qt.TextSelectableByKeyboard | QtCore.Qt.TextSelectableByMouse
197 | )
198 | self.about_label_header.setObjectName("about_label_header")
199 | self.scroll_layout.addWidget(self.about_label_header)
200 | self.supportButtonHolder = QtWidgets.QFrame(self.about_scroll)
201 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Maximum)
202 | sizePolicy.setHorizontalStretch(0)
203 | sizePolicy.setVerticalStretch(0)
204 | sizePolicy.setHeightForWidth(self.supportButtonHolder.sizePolicy().hasHeightForWidth())
205 | self.supportButtonHolder.setSizePolicy(sizePolicy)
206 | self.supportButtonHolder.setObjectName("supportButtonHolder")
207 | self.support_buttons = QtWidgets.QHBoxLayout(self.supportButtonHolder)
208 | self.support_buttons.setContentsMargins(6, 6, 6, 6)
209 | self.support_buttons.setObjectName("support_buttons")
210 | self.like_button = QtWidgets.QPushButton(self.supportButtonHolder)
211 | self.like_button.setMinimumSize(QtCore.QSize(0, 42))
212 | self.like_button.setMaximumSize(QtCore.QSize(200, 16777215))
213 | self.like_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
214 | self.like_button.setFocusPolicy(QtCore.Qt.NoFocus)
215 | self.like_button.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
216 | icon = QtGui.QIcon()
217 | icon.addPixmap(QtGui.QPixmap("res/img/anki_like.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
218 | self.like_button.setIcon(icon)
219 | self.like_button.setIconSize(QtCore.QSize(32, 32))
220 | self.like_button.setObjectName("like_button")
221 | self.support_buttons.addWidget(self.like_button)
222 | self.patreon_button = QtWidgets.QPushButton(self.supportButtonHolder)
223 | self.patreon_button.setMinimumSize(QtCore.QSize(0, 42))
224 | self.patreon_button.setMaximumSize(QtCore.QSize(200, 16777215))
225 | self.patreon_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
226 | self.patreon_button.setFocusPolicy(QtCore.Qt.NoFocus)
227 | self.patreon_button.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
228 | icon1 = QtGui.QIcon()
229 | icon1.addPixmap(QtGui.QPixmap("res/img/patreon.png"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
230 | self.patreon_button.setIcon(icon1)
231 | self.patreon_button.setIconSize(QtCore.QSize(32, 32))
232 | self.patreon_button.setObjectName("patreon_button")
233 | self.support_buttons.addWidget(self.patreon_button)
234 | self.kofi_button = QtWidgets.QPushButton(self.supportButtonHolder)
235 | self.kofi_button.setMinimumSize(QtCore.QSize(0, 42))
236 | self.kofi_button.setMaximumSize(QtCore.QSize(200, 16777215))
237 | self.kofi_button.setCursor(QtGui.QCursor(QtCore.Qt.PointingHandCursor))
238 | self.kofi_button.setFocusPolicy(QtCore.Qt.NoFocus)
239 | self.kofi_button.setContextMenuPolicy(QtCore.Qt.CustomContextMenu)
240 | icon2 = QtGui.QIcon()
241 | icon2.addPixmap(QtGui.QPixmap("res/img/kofilogo_blue.PNG"), QtGui.QIcon.Normal, QtGui.QIcon.Off)
242 | self.kofi_button.setIcon(icon2)
243 | self.kofi_button.setIconSize(QtCore.QSize(32, 32))
244 | self.kofi_button.setObjectName("kofi_button")
245 | self.support_buttons.addWidget(self.kofi_button)
246 | self.scroll_layout.addWidget(self.supportButtonHolder)
247 | self.about_label_body = QtWidgets.QLabel(self.about_scroll)
248 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Expanding)
249 | sizePolicy.setHorizontalStretch(0)
250 | sizePolicy.setVerticalStretch(0)
251 | sizePolicy.setHeightForWidth(self.about_label_body.sizePolicy().hasHeightForWidth())
252 | self.about_label_body.setSizePolicy(sizePolicy)
253 | self.about_label_body.setTextFormat(QtCore.Qt.AutoText)
254 | self.about_label_body.setAlignment(QtCore.Qt.AlignLeading | QtCore.Qt.AlignLeft | QtCore.Qt.AlignTop)
255 | self.about_label_body.setWordWrap(True)
256 | self.about_label_body.setOpenExternalLinks(True)
257 | self.about_label_body.setTextInteractionFlags(
258 | QtCore.Qt.LinksAccessibleByKeyboard | QtCore.Qt.LinksAccessibleByMouse | QtCore.Qt.TextBrowserInteraction
259 | | QtCore.Qt.TextSelectableByKeyboard | QtCore.Qt.TextSelectableByMouse
260 | )
261 | self.about_label_body.setObjectName("about_label_body")
262 | self.scroll_layout.addWidget(self.about_label_body)
263 | self.scroll_area.setWidget(self.about_scroll)
264 | self.verticalLayout_2.addWidget(self.scroll_area)
265 | self.tabs_widget.addTab(self.about_tab, "")
266 | self.verticalLayout_4.addWidget(self.tabs_widget)
267 | self.frame_2 = QtWidgets.QFrame(OptionsDialog)
268 | self.frame_2.setObjectName("frame_2")
269 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_2)
270 | self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
271 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
272 | self.confirm_button_box = QtWidgets.QDialogButtonBox(self.frame_2)
273 | self.confirm_button_box.setOrientation(QtCore.Qt.Horizontal)
274 | self.confirm_button_box.setStandardButtons(
275 | QtWidgets.QDialogButtonBox.Apply | QtWidgets.QDialogButtonBox.Cancel | QtWidgets.QDialogButtonBox.Ok |
276 | QtWidgets.QDialogButtonBox.RestoreDefaults
277 | )
278 | self.confirm_button_box.setObjectName("confirm_button_box")
279 | self.horizontalLayout_2.addWidget(self.confirm_button_box)
280 | self.supportButton = HoverButton(self.frame_2)
281 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
282 | sizePolicy.setHorizontalStretch(0)
283 | sizePolicy.setVerticalStretch(0)
284 | sizePolicy.setHeightForWidth(self.supportButton.sizePolicy().hasHeightForWidth())
285 | self.supportButton.setSizePolicy(sizePolicy)
286 | self.supportButton.setObjectName("supportButton")
287 | self.horizontalLayout_2.addWidget(self.supportButton)
288 | self.verticalLayout_4.addWidget(self.frame_2)
289 |
290 | self.retranslateUi(OptionsDialog)
291 | self.tabs_widget.setCurrentIndex(0)
292 | self.confirm_button_box.accepted.connect(OptionsDialog.accept) # type: ignore
293 | self.confirm_button_box.rejected.connect(OptionsDialog.reject) # type: ignore
294 | QtCore.QMetaObject.connectSlotsByName(OptionsDialog)
295 |
296 | def retranslateUi(self, OptionsDialog):
297 | _translate = QtCore.QCoreApplication.translate
298 | OptionsDialog.setWindowTitle(_translate("OptionsDialog", "Study Time Stats Options"))
299 | self.pages_group.setTitle(_translate("OptionsDialog", "Enabled Pages"))
300 | self.browser_checkbox.setToolTip(_translate("OptionsDialog", "The main page for browsing decks."))
301 | self.browser_checkbox.setText(_translate("OptionsDialog", "Deck Browser"))
302 | self.overview_checkbox.setToolTip(_translate("OptionsDialog", "The page that shows when viewing a deck."))
303 | self.overview_checkbox.setText(_translate("OptionsDialog", "Overview"))
304 | self.congrats_checkbox.setToolTip(
305 | _translate(
306 | "OptionsDialog",
307 | "The page that shows when viewing a deck that has its reviews done for the day."
308 | )
309 | )
310 | self.congrats_checkbox.setText(_translate("OptionsDialog", "Congrats"))
311 | self.mainViewGroupbox.setTitle(_translate("OptionsDialog", "Stats View"))
312 | self.cellListWidget.setSortingEnabled(True)
313 | self.tabs_widget.setTabText(
314 | self.tabs_widget.indexOf(self.appearance_tab),
315 | _translate("OptionsDialog", "General")
316 | )
317 | self.toolbar_checkbox.setToolTip(
318 | _translate(
319 | "OptionsDialog", "Enable the Tools Menu shortcut for these options. \n"
320 | "(Can also be accessed via Tools>Add-ons>Study Time Stats>Config)"
321 | )
322 | )
323 | self.toolbar_checkbox.setText(_translate("OptionsDialog", "Show options shortcut in the Tools Menu"))
324 | self.include_deleted_checkbox.setToolTip(
325 | _translate("OptionsDialog", "Include review/time stats for cards that\'ve been deleted.")
326 | )
327 | self.include_deleted_checkbox.setText(_translate("OptionsDialog", "Include reviews from deleted cards"))
328 | self.useRolloverCheckbox.setToolTip(
329 | _translate(
330 | "OptionsDialog",
331 | "Use Anki\'s rollover (next-day) hour when considering the time days are cut off."
332 | )
333 | )
334 | self.useRolloverCheckbox.setText(
335 | _translate("OptionsDialog", "Use the next-day hour when calculating ranged times")
336 | )
337 | self.useDecimalCheckbox.setToolTip(
338 | _translate(
339 | "OptionsDialog", "Shows an \"hour.min\" format for all time outputs. \n"
340 | "(Otherwise uses \"hh:mm\")"
341 | )
342 | )
343 | self.useDecimalCheckbox.setText(_translate("OptionsDialog", "Use decimal format time outputs"))
344 | self.enabled_decks_group.setTitle(_translate("OptionsDialog", "Enabled Decks"))
345 | self.deck_enable_button.setToolTip(_translate("OptionsDialog", "Enable stats for the selected deck(s)."))
346 | self.deck_enable_button.setText(_translate("OptionsDialog", "Enable"))
347 | self.deck_disable_button.setToolTip(_translate("OptionsDialog", "Disable stats for the selected deck(s)."))
348 | self.deck_disable_button.setText(_translate("OptionsDialog", "Disable"))
349 | self.tabs_widget.setTabText(self.tabs_widget.indexOf(self.decks_tab), _translate("OptionsDialog", "Advanced"))
350 | self.about_label_header.setText(
351 | _translate(
352 | "OptionsDialog", "## Study Time Stats
\n"
353 | "Adds a total and ranged study time statistic to Anki\'s main window. \n"
354 | "\n"
355 | "Version: {version} \n"
356 | "Have any issues or feedback? Feel free to post on the project\'s issue section on ["
357 | "GitHub](https://github.com/iamjustkoi/StudyTimeStats/issues)! \n"
358 | "\n"
359 | "[Releases/Changelog](https://github.com/iamjustkoi/StudyTimeStats/releases) \n"
360 | "[Source Code](https://github.com/iamjustkoi/StudyTimeStats) \n"
361 | "\n"
362 | "If you like the add-on and want to consider supporting me in anyway:"
363 | )
364 | )
365 | self.like_button.setToolTip(_translate("OptionsDialog", "Leave a review over at AnkiWeb!"))
366 | self.like_button.setText(_translate("OptionsDialog", "AnkiWeb "))
367 | self.patreon_button.setToolTip(_translate("OptionsDialog", "Follow/support me on Patreon!"))
368 | self.patreon_button.setText(_translate("OptionsDialog", " Patreon "))
369 | self.kofi_button.setToolTip(_translate("OptionsDialog", "Buy me a coffee with Ko-Fi!"))
370 | self.kofi_button.setText(_translate("OptionsDialog", "Ko-Fi"))
371 | self.about_label_body.setText(
372 | _translate(
373 | "OptionsDialog", "Every bit helps and is greatly appreciated! <3\n"
374 | "\n"
375 | "### Text Macros\n"
376 | "All output text can also be filtered to show some more customized information (e.g. "
377 | "\"Past %range\" to \"Past Week\"). These can be used multiple times and will update "
378 | "whenever Anki\'s main window reloads. \n"
379 | "\n"
380 | "`%%` - can be used to return a single % symbol and disable filtering for any macro "
381 | "text (e.g. `%%` -> %, `%%range` -> %range)\n"
382 | "\n"
383 | "*Small warning: as a general rule, the more stats used/the larger the range of the "
384 | "stat, the longer it might take to load them all (some caching is also done on the "
385 | "side, too though).\n"
386 | "\n"
387 | " \n"
388 | " \n"
389 | "Thanks for downloading and hope you enjoy!\n"
390 | "\n"
391 | "-koi \n"
392 | "\n"
393 | "\n"
394 | " \n"
395 | " \n"
396 | "MIT License \n"
397 | "\n"
398 | "©2022-2023 JustKoi (iamjustkoi)"
399 | )
400 | )
401 | self.tabs_widget.setTabText(self.tabs_widget.indexOf(self.about_tab), _translate("OptionsDialog", "About"))
402 | self.supportButton.setText(_translate("OptionsDialog", "<3"))
403 |
404 |
405 | from ..forms import HoverButton
406 |
407 | if __name__ == "__main__":
408 | import sys
409 |
410 | app = QtWidgets.QApplication(sys.argv)
411 | OptionsDialog = QtWidgets.QDialog()
412 | ui = Ui_OptionsDialog()
413 | ui.setupUi(OptionsDialog)
414 | OptionsDialog.show()
415 | sys.exit(app.exec_())
416 |
--------------------------------------------------------------------------------
/res/ui/Qt6/cell_item.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'cell_item.ui'
4 | #
5 | # Created by: PyQt6 UI code generator 5.15.7
6 | #
7 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8 | # run again. Do not edit this file unless you know what you are doing.
9 |
10 |
11 | from PyQt6 import QtCore, QtGui, QtWidgets
12 |
13 |
14 | class Ui_CellWidget(object):
15 | def setupUi(self, CellWidget):
16 | CellWidget.setObjectName("CellWidget")
17 | CellWidget.resize(460, 329)
18 | sizePolicy = QtWidgets.QSizePolicy(
19 | QtWidgets.QSizePolicy.Policy.Preferred,
20 | QtWidgets.QSizePolicy.Policy.Maximum
21 | )
22 | sizePolicy.setHorizontalStretch(0)
23 | sizePolicy.setVerticalStretch(0)
24 | sizePolicy.setHeightForWidth(CellWidget.sizePolicy().hasHeightForWidth())
25 | CellWidget.setSizePolicy(sizePolicy)
26 | self.verticalLayout = QtWidgets.QVBoxLayout(CellWidget)
27 | self.verticalLayout.setContentsMargins(6, 0, 6, 6)
28 | self.verticalLayout.setSpacing(0)
29 | self.verticalLayout.setObjectName("verticalLayout")
30 | self.addButton = HoverButton(CellWidget)
31 | sizePolicy = QtWidgets.QSizePolicy(
32 | QtWidgets.QSizePolicy.Policy.Preferred,
33 | QtWidgets.QSizePolicy.Policy.Fixed
34 | )
35 | sizePolicy.setHorizontalStretch(0)
36 | sizePolicy.setVerticalStretch(0)
37 | sizePolicy.setHeightForWidth(self.addButton.sizePolicy().hasHeightForWidth())
38 | self.addButton.setSizePolicy(sizePolicy)
39 | self.addButton.setMinimumSize(QtCore.QSize(0, 64))
40 | self.addButton.setStyleSheet(
41 | "#addButton {\n"
42 | " border: 1px solid rgba(134, 134, 134, 128);\n"
43 | " border-radius: 2px;\n"
44 | " background: transparent;\n"
45 | "}"
46 | )
47 | icon = QtGui.QIcon()
48 | icon.addPixmap(QtGui.QPixmap("../../img/add_icon.svg"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
49 | self.addButton.setIcon(icon)
50 | self.addButton.setIconSize(QtCore.QSize(20, 20))
51 | self.addButton.setObjectName("addButton")
52 | self.verticalLayout.addWidget(self.addButton)
53 | self.mainFrame = QtWidgets.QFrame(CellWidget)
54 | sizePolicy = QtWidgets.QSizePolicy(
55 | QtWidgets.QSizePolicy.Policy.Ignored,
56 | QtWidgets.QSizePolicy.Policy.Maximum
57 | )
58 | sizePolicy.setHorizontalStretch(0)
59 | sizePolicy.setVerticalStretch(0)
60 | sizePolicy.setHeightForWidth(self.mainFrame.sizePolicy().hasHeightForWidth())
61 | self.mainFrame.setSizePolicy(sizePolicy)
62 | self.mainFrame.setStyleSheet(
63 | "#mainFrame {\n"
64 | " background: rgba(163, 163, 163, 5%);\n"
65 | " border-radius: 6px;\n"
66 | "}"
67 | )
68 | self.mainFrame.setObjectName("mainFrame")
69 | self.gridLayout = QtWidgets.QGridLayout(self.mainFrame)
70 | self.gridLayout.setObjectName("gridLayout")
71 | self.titleColorButton = QtWidgets.QToolButton(self.mainFrame)
72 | sizePolicy = QtWidgets.QSizePolicy(
73 | QtWidgets.QSizePolicy.Policy.Fixed,
74 | QtWidgets.QSizePolicy.Policy.Fixed
75 | )
76 | sizePolicy.setHorizontalStretch(0)
77 | sizePolicy.setVerticalStretch(0)
78 | sizePolicy.setHeightForWidth(self.titleColorButton.sizePolicy().hasHeightForWidth())
79 | self.titleColorButton.setSizePolicy(sizePolicy)
80 | self.titleColorButton.setMaximumSize(QtCore.QSize(20, 20))
81 | self.titleColorButton.setStyleSheet(
82 | "#titleColorButton {\n"
83 | " border-radius: 10px;\n"
84 | " background-color: #76bfb4;\n"
85 | " width: 20px;\n"
86 | "}"
87 | )
88 | self.titleColorButton.setObjectName("titleColorButton")
89 | self.gridLayout.addWidget(self.titleColorButton, 0, 2, 1, 1)
90 | self.titleLineEdit = QtWidgets.QLineEdit(self.mainFrame)
91 | self.titleLineEdit.setObjectName("titleLineEdit")
92 | self.gridLayout.addWidget(self.titleLineEdit, 0, 1, 1, 1)
93 | self.titleLabel = QtWidgets.QLabel(self.mainFrame)
94 | sizePolicy = QtWidgets.QSizePolicy(
95 | QtWidgets.QSizePolicy.Policy.Fixed,
96 | QtWidgets.QSizePolicy.Policy.Maximum
97 | )
98 | sizePolicy.setHorizontalStretch(0)
99 | sizePolicy.setVerticalStretch(0)
100 | sizePolicy.setHeightForWidth(self.titleLabel.sizePolicy().hasHeightForWidth())
101 | self.titleLabel.setSizePolicy(sizePolicy)
102 | self.titleLabel.setMinimumSize(QtCore.QSize(82, 0))
103 | self.titleLabel.setStyleSheet(
104 | "#mainFrame {\n"
105 | " background: rgba(163, 163, 163, 5%);\n"
106 | " border-radius: 6px;\n"
107 | "}"
108 | )
109 | self.titleLabel.setObjectName("titleLabel")
110 | self.gridLayout.addWidget(self.titleLabel, 0, 0, 1, 1)
111 | self.dragHandle = DragHandle(self.mainFrame)
112 | sizePolicy = QtWidgets.QSizePolicy(
113 | QtWidgets.QSizePolicy.Policy.Fixed,
114 | QtWidgets.QSizePolicy.Policy.Fixed
115 | )
116 | sizePolicy.setHorizontalStretch(0)
117 | sizePolicy.setVerticalStretch(0)
118 | sizePolicy.setHeightForWidth(self.dragHandle.sizePolicy().hasHeightForWidth())
119 | self.dragHandle.setSizePolicy(sizePolicy)
120 | self.dragHandle.setMaximumSize(QtCore.QSize(20, 20))
121 | self.dragHandle.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.OpenHandCursor))
122 | self.dragHandle.setMouseTracking(True)
123 | icon1 = QtGui.QIcon()
124 | icon1.addPixmap(
125 | QtGui.QPixmap("../../img/vert_grip.svg"),
126 | QtGui.QIcon.Mode.Normal,
127 | QtGui.QIcon.State.Off
128 | )
129 | self.dragHandle.setIcon(icon1)
130 | self.dragHandle.setObjectName("dragHandle")
131 | self.gridLayout.addWidget(self.dragHandle, 0, 4, 1, 1)
132 | self.expandoButton = RotateButton(self.mainFrame)
133 | sizePolicy = QtWidgets.QSizePolicy(
134 | QtWidgets.QSizePolicy.Policy.Fixed,
135 | QtWidgets.QSizePolicy.Policy.Fixed
136 | )
137 | sizePolicy.setHorizontalStretch(0)
138 | sizePolicy.setVerticalStretch(0)
139 | sizePolicy.setHeightForWidth(self.expandoButton.sizePolicy().hasHeightForWidth())
140 | self.expandoButton.setSizePolicy(sizePolicy)
141 | self.expandoButton.setMaximumSize(QtCore.QSize(20, 20))
142 | icon2 = QtGui.QIcon()
143 | icon2.addPixmap(
144 | QtGui.QPixmap("../../img/chevron_down.svg"),
145 | QtGui.QIcon.Mode.Normal,
146 | QtGui.QIcon.State.Off
147 | )
148 | self.expandoButton.setIcon(icon2)
149 | self.expandoButton.setIconSize(QtCore.QSize(20, 20))
150 | self.expandoButton.setObjectName("expandoButton")
151 | self.gridLayout.addWidget(self.expandoButton, 0, 3, 1, 1)
152 | self.expandFrame = QtWidgets.QFrame(self.mainFrame)
153 | sizePolicy = QtWidgets.QSizePolicy(
154 | QtWidgets.QSizePolicy.Policy.Ignored,
155 | QtWidgets.QSizePolicy.Policy.Maximum
156 | )
157 | sizePolicy.setHorizontalStretch(0)
158 | sizePolicy.setVerticalStretch(0)
159 | sizePolicy.setHeightForWidth(self.expandFrame.sizePolicy().hasHeightForWidth())
160 | self.expandFrame.setSizePolicy(sizePolicy)
161 | self.expandFrame.setObjectName("expandFrame")
162 | self.gridLayout_2 = QtWidgets.QGridLayout(self.expandFrame)
163 | self.gridLayout_2.setContentsMargins(0, 0, 0, 0)
164 | self.gridLayout_2.setObjectName("gridLayout_2")
165 | self.startDayDropdown = QtWidgets.QComboBox(self.expandFrame)
166 | sizePolicy = QtWidgets.QSizePolicy(
167 | QtWidgets.QSizePolicy.Policy.Expanding,
168 | QtWidgets.QSizePolicy.Policy.Fixed
169 | )
170 | sizePolicy.setHorizontalStretch(0)
171 | sizePolicy.setVerticalStretch(0)
172 | sizePolicy.setHeightForWidth(self.startDayDropdown.sizePolicy().hasHeightForWidth())
173 | self.startDayDropdown.setSizePolicy(sizePolicy)
174 | self.startDayDropdown.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
175 | self.startDayDropdown.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents)
176 | self.startDayDropdown.setObjectName("startDayDropdown")
177 | self.startDayDropdown.addItem("")
178 | self.startDayDropdown.addItem("")
179 | self.startDayDropdown.addItem("")
180 | self.startDayDropdown.addItem("")
181 | self.startDayDropdown.addItem("")
182 | self.startDayDropdown.addItem("")
183 | self.startDayDropdown.addItem("")
184 | self.gridLayout_2.addWidget(self.startDayDropdown, 3, 1, 1, 1)
185 | self.outputLineEdit = QtWidgets.QLineEdit(self.expandFrame)
186 | self.outputLineEdit.setObjectName("outputLineEdit")
187 | self.gridLayout_2.addWidget(self.outputLineEdit, 0, 1, 1, 1)
188 | self.outputColorButton = QtWidgets.QToolButton(self.expandFrame)
189 | sizePolicy = QtWidgets.QSizePolicy(
190 | QtWidgets.QSizePolicy.Policy.Fixed,
191 | QtWidgets.QSizePolicy.Policy.Fixed
192 | )
193 | sizePolicy.setHorizontalStretch(0)
194 | sizePolicy.setVerticalStretch(0)
195 | sizePolicy.setHeightForWidth(self.outputColorButton.sizePolicy().hasHeightForWidth())
196 | self.outputColorButton.setSizePolicy(sizePolicy)
197 | self.outputColorButton.setMaximumSize(QtCore.QSize(20, 20))
198 | self.outputColorButton.setStyleSheet(
199 | "#outputColorButton {\n"
200 | " border-radius: 10px;\n"
201 | " background-color: #FFF;\n"
202 | " width: 20px;\n"
203 | "}"
204 | )
205 | self.outputColorButton.setObjectName("outputColorButton")
206 | self.gridLayout_2.addWidget(self.outputColorButton, 0, 2, 1, 1)
207 | self.frame = QtWidgets.QFrame(self.expandFrame)
208 | sizePolicy = QtWidgets.QSizePolicy(
209 | QtWidgets.QSizePolicy.Policy.Expanding,
210 | QtWidgets.QSizePolicy.Policy.Preferred
211 | )
212 | sizePolicy.setHorizontalStretch(0)
213 | sizePolicy.setVerticalStretch(0)
214 | sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth())
215 | self.frame.setSizePolicy(sizePolicy)
216 | self.frame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
217 | self.frame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
218 | self.frame.setObjectName("frame")
219 | self.horizontalLayout = QtWidgets.QHBoxLayout(self.frame)
220 | self.horizontalLayout.setContentsMargins(0, 0, 0, 0)
221 | self.horizontalLayout.setObjectName("horizontalLayout")
222 | self.rangeDropdown = QtWidgets.QComboBox(self.frame)
223 | sizePolicy = QtWidgets.QSizePolicy(
224 | QtWidgets.QSizePolicy.Policy.Expanding,
225 | QtWidgets.QSizePolicy.Policy.Fixed
226 | )
227 | sizePolicy.setHorizontalStretch(0)
228 | sizePolicy.setVerticalStretch(0)
229 | sizePolicy.setHeightForWidth(self.rangeDropdown.sizePolicy().hasHeightForWidth())
230 | self.rangeDropdown.setSizePolicy(sizePolicy)
231 | self.rangeDropdown.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
232 | self.rangeDropdown.setSizeAdjustPolicy(QtWidgets.QComboBox.SizeAdjustPolicy.AdjustToContents)
233 | self.rangeDropdown.setObjectName("rangeDropdown")
234 | self.rangeDropdown.addItem("")
235 | self.rangeDropdown.addItem("")
236 | self.rangeDropdown.addItem("")
237 | self.rangeDropdown.addItem("")
238 | self.rangeDropdown.addItem("")
239 | self.rangeDropdown.addItem("")
240 | self.horizontalLayout.addWidget(self.rangeDropdown)
241 | self.rangeExtraFrame = QtWidgets.QFrame(self.frame)
242 | sizePolicy = QtWidgets.QSizePolicy(
243 | QtWidgets.QSizePolicy.Policy.Expanding,
244 | QtWidgets.QSizePolicy.Policy.Maximum
245 | )
246 | sizePolicy.setHorizontalStretch(0)
247 | sizePolicy.setVerticalStretch(0)
248 | sizePolicy.setHeightForWidth(self.rangeExtraFrame.sizePolicy().hasHeightForWidth())
249 | self.rangeExtraFrame.setSizePolicy(sizePolicy)
250 | self.rangeExtraFrame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
251 | self.rangeExtraFrame.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
252 | self.rangeExtraFrame.setObjectName("rangeExtraFrame")
253 | self.horizontalLayout_4 = QtWidgets.QHBoxLayout(self.rangeExtraFrame)
254 | self.horizontalLayout_4.setContentsMargins(0, 0, 0, 0)
255 | self.horizontalLayout_4.setSpacing(0)
256 | self.horizontalLayout_4.setObjectName("horizontalLayout_4")
257 | self.calendarCheckbox = QtWidgets.QCheckBox(self.rangeExtraFrame)
258 | sizePolicy = QtWidgets.QSizePolicy(
259 | QtWidgets.QSizePolicy.Policy.Maximum,
260 | QtWidgets.QSizePolicy.Policy.Fixed
261 | )
262 | sizePolicy.setHorizontalStretch(0)
263 | sizePolicy.setVerticalStretch(0)
264 | sizePolicy.setHeightForWidth(self.calendarCheckbox.sizePolicy().hasHeightForWidth())
265 | self.calendarCheckbox.setSizePolicy(sizePolicy)
266 | self.calendarCheckbox.setChecked(True)
267 | self.calendarCheckbox.setObjectName("calendarCheckbox")
268 | self.horizontalLayout_4.addWidget(self.calendarCheckbox)
269 | self.customRangeSpinbox = QtWidgets.QSpinBox(self.rangeExtraFrame)
270 | sizePolicy = QtWidgets.QSizePolicy(
271 | QtWidgets.QSizePolicy.Policy.Maximum,
272 | QtWidgets.QSizePolicy.Policy.Fixed
273 | )
274 | sizePolicy.setHorizontalStretch(0)
275 | sizePolicy.setVerticalStretch(0)
276 | sizePolicy.setHeightForWidth(self.customRangeSpinbox.sizePolicy().hasHeightForWidth())
277 | self.customRangeSpinbox.setSizePolicy(sizePolicy)
278 | self.customRangeSpinbox.setFocusPolicy(QtCore.Qt.FocusPolicy.StrongFocus)
279 | self.customRangeSpinbox.setMaximum(5690)
280 | self.customRangeSpinbox.setProperty("value", 7)
281 | self.customRangeSpinbox.setObjectName("customRangeSpinbox")
282 | self.horizontalLayout_4.addWidget(self.customRangeSpinbox)
283 | self.horizontalLayout.addWidget(self.rangeExtraFrame)
284 | self.gridLayout_2.addWidget(self.frame, 2, 1, 1, 1)
285 | self.directionFrame = QtWidgets.QFrame(self.expandFrame)
286 | sizePolicy = QtWidgets.QSizePolicy(
287 | QtWidgets.QSizePolicy.Policy.Maximum,
288 | QtWidgets.QSizePolicy.Policy.Maximum
289 | )
290 | sizePolicy.setHorizontalStretch(0)
291 | sizePolicy.setVerticalStretch(0)
292 | sizePolicy.setHeightForWidth(self.directionFrame.sizePolicy().hasHeightForWidth())
293 | self.directionFrame.setSizePolicy(sizePolicy)
294 | self.directionFrame.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
295 | self.directionFrame.setFrameShadow(QtWidgets.QFrame.Shadow.Plain)
296 | self.directionFrame.setObjectName("directionFrame")
297 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.directionFrame)
298 | self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
299 | self.horizontalLayout_2.setSpacing(0)
300 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
301 | self.directionVerticalButton = QtWidgets.QPushButton(self.directionFrame)
302 | self.directionVerticalButton.setEnabled(False)
303 | sizePolicy = QtWidgets.QSizePolicy(
304 | QtWidgets.QSizePolicy.Policy.Expanding,
305 | QtWidgets.QSizePolicy.Policy.Fixed
306 | )
307 | sizePolicy.setHorizontalStretch(0)
308 | sizePolicy.setVerticalStretch(0)
309 | sizePolicy.setHeightForWidth(self.directionVerticalButton.sizePolicy().hasHeightForWidth())
310 | self.directionVerticalButton.setSizePolicy(sizePolicy)
311 | self.directionVerticalButton.setMaximumSize(QtCore.QSize(42, 16777215))
312 | icon3 = QtGui.QIcon()
313 | icon3.addPixmap(
314 | QtGui.QPixmap("../../img/vert_lines.svg"),
315 | QtGui.QIcon.Mode.Normal,
316 | QtGui.QIcon.State.Off
317 | )
318 | self.directionVerticalButton.setIcon(icon3)
319 | self.directionVerticalButton.setObjectName("directionVerticalButton")
320 | self.horizontalLayout_2.addWidget(self.directionVerticalButton)
321 | self.directionHorizontalButton = QtWidgets.QPushButton(self.directionFrame)
322 | sizePolicy = QtWidgets.QSizePolicy(
323 | QtWidgets.QSizePolicy.Policy.Expanding,
324 | QtWidgets.QSizePolicy.Policy.Fixed
325 | )
326 | sizePolicy.setHorizontalStretch(0)
327 | sizePolicy.setVerticalStretch(0)
328 | sizePolicy.setHeightForWidth(self.directionHorizontalButton.sizePolicy().hasHeightForWidth())
329 | self.directionHorizontalButton.setSizePolicy(sizePolicy)
330 | self.directionHorizontalButton.setMaximumSize(QtCore.QSize(42, 16777215))
331 | icon4 = QtGui.QIcon()
332 | icon4.addPixmap(
333 | QtGui.QPixmap("../../img/horiz_lines.svg"),
334 | QtGui.QIcon.Mode.Normal,
335 | QtGui.QIcon.State.Off
336 | )
337 | self.directionHorizontalButton.setIcon(icon4)
338 | self.directionHorizontalButton.setObjectName("directionHorizontalButton")
339 | self.horizontalLayout_2.addWidget(self.directionHorizontalButton)
340 | self.gridLayout_2.addWidget(self.directionFrame, 4, 1, 1, 1)
341 | self.frame_3 = QtWidgets.QFrame(self.expandFrame)
342 | sizePolicy = QtWidgets.QSizePolicy(
343 | QtWidgets.QSizePolicy.Policy.Expanding,
344 | QtWidgets.QSizePolicy.Policy.Preferred
345 | )
346 | sizePolicy.setHorizontalStretch(0)
347 | sizePolicy.setVerticalStretch(0)
348 | sizePolicy.setHeightForWidth(self.frame_3.sizePolicy().hasHeightForWidth())
349 | self.frame_3.setSizePolicy(sizePolicy)
350 | self.frame_3.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
351 | self.frame_3.setFrameShadow(QtWidgets.QFrame.Shadow.Raised)
352 | self.frame_3.setObjectName("frame_3")
353 | self.horizontalLayout_3 = QtWidgets.QHBoxLayout(self.frame_3)
354 | self.horizontalLayout_3.setContentsMargins(0, 0, 0, 0)
355 | self.horizontalLayout_3.setObjectName("horizontalLayout_3")
356 | self.hourLabel = QtWidgets.QLabel(self.frame_3)
357 | self.hourLabel.setObjectName("hourLabel")
358 | self.horizontalLayout_3.addWidget(self.hourLabel)
359 | self.hourEdit = QtWidgets.QLineEdit(self.frame_3)
360 | sizePolicy = QtWidgets.QSizePolicy(
361 | QtWidgets.QSizePolicy.Policy.Expanding,
362 | QtWidgets.QSizePolicy.Policy.Fixed
363 | )
364 | sizePolicy.setHorizontalStretch(0)
365 | sizePolicy.setVerticalStretch(0)
366 | sizePolicy.setHeightForWidth(self.hourEdit.sizePolicy().hasHeightForWidth())
367 | self.hourEdit.setSizePolicy(sizePolicy)
368 | self.hourEdit.setObjectName("hourEdit")
369 | self.horizontalLayout_3.addWidget(self.hourEdit)
370 | self.minuteLabel = QtWidgets.QLabel(self.frame_3)
371 | self.minuteLabel.setObjectName("minuteLabel")
372 | self.horizontalLayout_3.addWidget(self.minuteLabel)
373 | self.minEdit = QtWidgets.QLineEdit(self.frame_3)
374 | sizePolicy = QtWidgets.QSizePolicy(
375 | QtWidgets.QSizePolicy.Policy.Expanding,
376 | QtWidgets.QSizePolicy.Policy.Fixed
377 | )
378 | sizePolicy.setHorizontalStretch(0)
379 | sizePolicy.setVerticalStretch(0)
380 | sizePolicy.setHeightForWidth(self.minEdit.sizePolicy().hasHeightForWidth())
381 | self.minEdit.setSizePolicy(sizePolicy)
382 | self.minEdit.setObjectName("minEdit")
383 | self.horizontalLayout_3.addWidget(self.minEdit)
384 | self.gridLayout_2.addWidget(self.frame_3, 1, 1, 1, 1)
385 | self.directionLabel = QtWidgets.QLabel(self.expandFrame)
386 | sizePolicy = QtWidgets.QSizePolicy(
387 | QtWidgets.QSizePolicy.Policy.Fixed,
388 | QtWidgets.QSizePolicy.Policy.Maximum
389 | )
390 | sizePolicy.setHorizontalStretch(0)
391 | sizePolicy.setVerticalStretch(0)
392 | sizePolicy.setHeightForWidth(self.directionLabel.sizePolicy().hasHeightForWidth())
393 | self.directionLabel.setSizePolicy(sizePolicy)
394 | self.directionLabel.setObjectName("directionLabel")
395 | self.gridLayout_2.addWidget(self.directionLabel, 4, 0, 1, 1)
396 | self.startDayLabel = QtWidgets.QLabel(self.expandFrame)
397 | sizePolicy = QtWidgets.QSizePolicy(
398 | QtWidgets.QSizePolicy.Policy.Fixed,
399 | QtWidgets.QSizePolicy.Policy.Maximum
400 | )
401 | sizePolicy.setHorizontalStretch(0)
402 | sizePolicy.setVerticalStretch(0)
403 | sizePolicy.setHeightForWidth(self.startDayLabel.sizePolicy().hasHeightForWidth())
404 | self.startDayLabel.setSizePolicy(sizePolicy)
405 | self.startDayLabel.setObjectName("startDayLabel")
406 | self.gridLayout_2.addWidget(self.startDayLabel, 3, 0, 1, 1)
407 | self.rangeLabel = QtWidgets.QLabel(self.expandFrame)
408 | sizePolicy = QtWidgets.QSizePolicy(
409 | QtWidgets.QSizePolicy.Policy.Fixed,
410 | QtWidgets.QSizePolicy.Policy.Maximum
411 | )
412 | sizePolicy.setHorizontalStretch(0)
413 | sizePolicy.setVerticalStretch(0)
414 | sizePolicy.setHeightForWidth(self.rangeLabel.sizePolicy().hasHeightForWidth())
415 | self.rangeLabel.setSizePolicy(sizePolicy)
416 | self.rangeLabel.setObjectName("rangeLabel")
417 | self.gridLayout_2.addWidget(self.rangeLabel, 2, 0, 1, 1)
418 | self.unitLabel = QtWidgets.QLabel(self.expandFrame)
419 | sizePolicy = QtWidgets.QSizePolicy(
420 | QtWidgets.QSizePolicy.Policy.Fixed,
421 | QtWidgets.QSizePolicy.Policy.Maximum
422 | )
423 | sizePolicy.setHorizontalStretch(0)
424 | sizePolicy.setVerticalStretch(0)
425 | sizePolicy.setHeightForWidth(self.unitLabel.sizePolicy().hasHeightForWidth())
426 | self.unitLabel.setSizePolicy(sizePolicy)
427 | self.unitLabel.setObjectName("unitLabel")
428 | self.gridLayout_2.addWidget(self.unitLabel, 1, 0, 1, 1)
429 | self.outputLabel = QtWidgets.QLabel(self.expandFrame)
430 | sizePolicy = QtWidgets.QSizePolicy(
431 | QtWidgets.QSizePolicy.Policy.Fixed,
432 | QtWidgets.QSizePolicy.Policy.Maximum
433 | )
434 | sizePolicy.setHorizontalStretch(0)
435 | sizePolicy.setVerticalStretch(0)
436 | sizePolicy.setHeightForWidth(self.outputLabel.sizePolicy().hasHeightForWidth())
437 | self.outputLabel.setSizePolicy(sizePolicy)
438 | self.outputLabel.setMinimumSize(QtCore.QSize(82, 0))
439 | self.outputLabel.setObjectName("outputLabel")
440 | self.gridLayout_2.addWidget(self.outputLabel, 0, 0, 1, 1)
441 | spacerItem = QtWidgets.QSpacerItem(
442 | 24,
443 | 0,
444 | QtWidgets.QSizePolicy.Policy.Fixed,
445 | QtWidgets.QSizePolicy.Policy.Minimum
446 | )
447 | self.gridLayout_2.addItem(spacerItem, 0, 3, 1, 1)
448 | self.removeButton = HoverButton(self.expandFrame)
449 | sizePolicy = QtWidgets.QSizePolicy(
450 | QtWidgets.QSizePolicy.Policy.Fixed,
451 | QtWidgets.QSizePolicy.Policy.Fixed
452 | )
453 | sizePolicy.setHorizontalStretch(0)
454 | sizePolicy.setVerticalStretch(0)
455 | sizePolicy.setHeightForWidth(self.removeButton.sizePolicy().hasHeightForWidth())
456 | self.removeButton.setSizePolicy(sizePolicy)
457 | self.removeButton.setMinimumSize(QtCore.QSize(0, 0))
458 | self.removeButton.setMaximumSize(QtCore.QSize(20, 20))
459 | icon5 = QtGui.QIcon()
460 | icon5.addPixmap(
461 | QtGui.QPixmap("../../img/remove_icon.svg"),
462 | QtGui.QIcon.Mode.Normal,
463 | QtGui.QIcon.State.Off
464 | )
465 | self.removeButton.setIcon(icon5)
466 | self.removeButton.setIconSize(QtCore.QSize(20, 20))
467 | self.removeButton.setObjectName("removeButton")
468 | self.gridLayout_2.addWidget(self.removeButton, 0, 4, 1, 1)
469 | self.codeButton = HoverButton(self.expandFrame)
470 | sizePolicy = QtWidgets.QSizePolicy(
471 | QtWidgets.QSizePolicy.Policy.Fixed,
472 | QtWidgets.QSizePolicy.Policy.Fixed
473 | )
474 | sizePolicy.setHorizontalStretch(0)
475 | sizePolicy.setVerticalStretch(0)
476 | sizePolicy.setHeightForWidth(self.codeButton.sizePolicy().hasHeightForWidth())
477 | self.codeButton.setSizePolicy(sizePolicy)
478 | self.codeButton.setMinimumSize(QtCore.QSize(0, 0))
479 | self.codeButton.setMaximumSize(QtCore.QSize(20, 20))
480 | icon6 = QtGui.QIcon()
481 | icon6.addPixmap(
482 | QtGui.QPixmap("../../img/code_icon.svg"),
483 | QtGui.QIcon.Mode.Normal,
484 | QtGui.QIcon.State.Off
485 | )
486 | self.codeButton.setIcon(icon6)
487 | self.codeButton.setIconSize(QtCore.QSize(20, 20))
488 | self.codeButton.setObjectName("codeButton")
489 | self.gridLayout_2.addWidget(self.codeButton, 4, 4, 1, 1)
490 | self.codeTextEdit = QtWidgets.QPlainTextEdit(self.expandFrame)
491 | sizePolicy = QtWidgets.QSizePolicy(
492 | QtWidgets.QSizePolicy.Policy.Expanding,
493 | QtWidgets.QSizePolicy.Policy.Preferred
494 | )
495 | sizePolicy.setHorizontalStretch(0)
496 | sizePolicy.setVerticalStretch(0)
497 | sizePolicy.setHeightForWidth(self.codeTextEdit.sizePolicy().hasHeightForWidth())
498 | self.codeTextEdit.setSizePolicy(sizePolicy)
499 | self.codeTextEdit.setMaximumSize(QtCore.QSize(16777215, 128))
500 | self.codeTextEdit.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored)
501 | self.codeTextEdit.setTabChangesFocus(False)
502 | self.codeTextEdit.setObjectName("codeTextEdit")
503 | self.gridLayout_2.addWidget(self.codeTextEdit, 5, 0, 1, 5)
504 | self.gridLayout.addWidget(self.expandFrame, 1, 0, 1, 5)
505 | self.verticalLayout.addWidget(self.mainFrame)
506 |
507 | self.retranslateUi(CellWidget)
508 | QtCore.QMetaObject.connectSlotsByName(CellWidget)
509 |
510 | def retranslateUi(self, CellWidget):
511 | _translate = QtCore.QCoreApplication.translate
512 | CellWidget.setWindowTitle(_translate("CellWidget", "Form"))
513 | self.titleColorButton.setToolTip(_translate("CellWidget", "Set a custom title text color."))
514 | self.titleLabel.setToolTip(
515 | _translate("CellWidget", "Text that appears above or to-the-left-of the output.")
516 | )
517 | self.titleLabel.setText(_translate("CellWidget", "Title"))
518 | self.startDayDropdown.setToolTip(_translate("CellWidget", "The day a new week should start on."))
519 | self.startDayDropdown.setCurrentText(_translate("CellWidget", "Sunday"))
520 | self.startDayDropdown.setItemText(0, _translate("CellWidget", "Sunday"))
521 | self.startDayDropdown.setItemText(1, _translate("CellWidget", "Monday"))
522 | self.startDayDropdown.setItemText(2, _translate("CellWidget", "Tuesday"))
523 | self.startDayDropdown.setItemText(3, _translate("CellWidget", "Wednesday"))
524 | self.startDayDropdown.setItemText(4, _translate("CellWidget", "Thursday"))
525 | self.startDayDropdown.setItemText(5, _translate("CellWidget", "Friday"))
526 | self.startDayDropdown.setItemText(6, _translate("CellWidget", "Saturday"))
527 | self.outputColorButton.setToolTip(_translate("CellWidget", "Set a custom output text color."))
528 | self.rangeDropdown.setToolTip(
529 | _translate("CellWidget", "Time range to filter through for the ranged total stat.")
530 | )
531 | self.rangeDropdown.setItemText(0, _translate("CellWidget", "Total"))
532 | self.rangeDropdown.setItemText(1, _translate("CellWidget", "Past Week"))
533 | self.rangeDropdown.setItemText(2, _translate("CellWidget", "Past 2 Weeks"))
534 | self.rangeDropdown.setItemText(3, _translate("CellWidget", "Past Month"))
535 | self.rangeDropdown.setItemText(4, _translate("CellWidget", "Past Year"))
536 | self.rangeDropdown.setItemText(5, _translate("CellWidget", "Custom"))
537 | self.calendarCheckbox.setToolTip(
538 | _translate("CellWidget", "Use the start of the selected range instead of using its timespan.")
539 | )
540 | self.calendarCheckbox.setText(_translate("CellWidget", "Use Calendar Week"))
541 | self.customRangeSpinbox.setToolTip(
542 | _translate("CellWidget", "Amount of days to filter the custom range.")
543 | )
544 | self.customRangeSpinbox.setSuffix(_translate("CellWidget", " days"))
545 | self.hourLabel.setText(_translate("CellWidget", "Hour"))
546 | self.hourEdit.setText(_translate("CellWidget", "hrs"))
547 | self.minuteLabel.setText(_translate("CellWidget", "Minute"))
548 | self.minEdit.setText(_translate("CellWidget", "min"))
549 | self.directionLabel.setToolTip(
550 | _translate("CellWidget", "Set text-stacking direction to either vertical/horizontal.")
551 | )
552 | self.directionLabel.setText(_translate("CellWidget", "Direction"))
553 | self.startDayLabel.setToolTip(
554 | _translate("CellWidget", "Day to consider the first day of a calendar week.")
555 | )
556 | self.startDayLabel.setText(_translate("CellWidget", "Week-Start Day"))
557 | self.rangeLabel.setToolTip(
558 | _translate("CellWidget", "Preset range to use for macros with an expected range.")
559 | )
560 | self.rangeLabel.setText(_translate("CellWidget", "Selected Range"))
561 | self.unitLabel.setToolTip(
562 | _translate(
563 | "CellWidget",
564 | "Text to be appended to any time-related measurements for all output text."
565 | )
566 | )
567 | self.unitLabel.setText(_translate("CellWidget", "Units"))
568 | self.outputLabel.setToolTip(
569 | _translate("CellWidget", "Text that appears below or to-the-right-of the title.")
570 | )
571 | self.outputLabel.setText(_translate("CellWidget", "Output"))
572 |
573 |
574 | from ..forms import DragHandle, HoverButton, RotateButton
575 |
576 | if __name__ == "__main__":
577 | import sys
578 |
579 | app = QtWidgets.QApplication(sys.argv)
580 | CellWidget = QtWidgets.QWidget()
581 | ui = Ui_CellWidget()
582 | ui.setupUi(CellWidget)
583 | CellWidget.show()
584 | sys.exit(app.exec_())
585 |
--------------------------------------------------------------------------------
/res/ui/Qt6/macro_dialog.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'macro_dialog.ui'
4 | #
5 | # Created by: PyQt6 UI code generator 5.15.7
6 | #
7 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8 | # run again. Do not edit this file unless you know what you are doing.
9 |
10 |
11 | from PyQt6 import QtCore, QtGui, QtWidgets
12 |
13 |
14 | class Ui_MacroDialog(object):
15 | def setupUi(self, MacroDialog):
16 | MacroDialog.setObjectName("MacroDialog")
17 | MacroDialog.resize(528, 362)
18 | self.verticalLayout = QtWidgets.QVBoxLayout(MacroDialog)
19 | self.verticalLayout.setObjectName("verticalLayout")
20 | self.macroGroupBox = QtWidgets.QGroupBox(MacroDialog)
21 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding)
22 | sizePolicy.setHorizontalStretch(0)
23 | sizePolicy.setVerticalStretch(0)
24 | sizePolicy.setHeightForWidth(self.macroGroupBox.sizePolicy().hasHeightForWidth())
25 | self.macroGroupBox.setSizePolicy(sizePolicy)
26 | self.macroGroupBox.setObjectName("macroGroupBox")
27 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.macroGroupBox)
28 | self.verticalLayout_2.setContentsMargins(6, 0, 6, 6)
29 | self.verticalLayout_2.setObjectName("verticalLayout_2")
30 | self.filterLineEdit = QtWidgets.QLineEdit(self.macroGroupBox)
31 | self.filterLineEdit.setClearButtonEnabled(True)
32 | self.filterLineEdit.setObjectName("filterLineEdit")
33 | self.verticalLayout_2.addWidget(self.filterLineEdit)
34 | self.listView = QtWidgets.QListView(self.macroGroupBox)
35 | self.listView.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
36 | self.listView.setFrameShadow(QtWidgets.QFrame.Shadow.Plain)
37 | self.listView.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
38 | self.listView.setTabKeyNavigation(True)
39 | self.listView.setProperty("showDropIndicator", False)
40 | self.listView.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
41 | self.listView.setObjectName("listView")
42 | self.verticalLayout_2.addWidget(self.listView)
43 | self.verticalLayout.addWidget(self.macroGroupBox)
44 | self.previewGroupBox = QtWidgets.QGroupBox(MacroDialog)
45 | self.previewGroupBox.setMinimumSize(QtCore.QSize(0, 42))
46 | self.previewGroupBox.setObjectName("previewGroupBox")
47 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.previewGroupBox)
48 | self.verticalLayout_3.setContentsMargins(6, 6, 6, 6)
49 | self.verticalLayout_3.setObjectName("verticalLayout_3")
50 | self.previewLabel = QtWidgets.QLabel(self.previewGroupBox)
51 | self.previewLabel.setObjectName("previewLabel")
52 | self.verticalLayout_3.addWidget(self.previewLabel)
53 | self.verticalLayout.addWidget(self.previewGroupBox)
54 | self.buttonBox = QtWidgets.QDialogButtonBox(MacroDialog)
55 | self.buttonBox.setOrientation(QtCore.Qt.Orientation.Horizontal)
56 | self.buttonBox.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok)
57 | self.buttonBox.setObjectName("buttonBox")
58 | self.verticalLayout.addWidget(self.buttonBox)
59 |
60 | self.retranslateUi(MacroDialog)
61 | self.buttonBox.accepted.connect(MacroDialog.accept) # type: ignore
62 | self.buttonBox.rejected.connect(MacroDialog.reject) # type: ignore
63 | QtCore.QMetaObject.connectSlotsByName(MacroDialog)
64 |
65 | def retranslateUi(self, MacroDialog):
66 | _translate = QtCore.QCoreApplication.translate
67 | MacroDialog.setWindowTitle(_translate("MacroDialog", "Macros"))
68 | self.macroGroupBox.setTitle(_translate("MacroDialog", "Macros"))
69 | self.filterLineEdit.setPlaceholderText(_translate("MacroDialog", "Filter..."))
70 | self.previewGroupBox.setTitle(_translate("MacroDialog", "Preview"))
71 | self.previewLabel.setText(_translate("MacroDialog", "test"))
72 |
73 |
74 | if __name__ == "__main__":
75 | import sys
76 | app = QtWidgets.QApplication(sys.argv)
77 | MacroDialog = QtWidgets.QDialog()
78 | ui = Ui_MacroDialog()
79 | ui.setupUi(MacroDialog)
80 | MacroDialog.show()
81 | sys.exit(app.exec_())
82 |
--------------------------------------------------------------------------------
/res/ui/Qt6/options_dialog.py:
--------------------------------------------------------------------------------
1 | # -*- coding: utf-8 -*-
2 |
3 | # Form implementation generated from reading ui file 'options_dialog.ui'
4 | #
5 | # Created by: PyQt6 UI code generator 5.15.7
6 | #
7 | # WARNING: Any manual changes made to this file will be lost when pyuic5 is
8 | # run again. Do not edit this file unless you know what you are doing.
9 |
10 |
11 | from PyQt6 import QtCore, QtGui, QtWidgets
12 |
13 |
14 | class Ui_OptionsDialog(object):
15 | def setupUi(self, OptionsDialog):
16 | OptionsDialog.setObjectName("OptionsDialog")
17 | OptionsDialog.setWindowModality(QtCore.Qt.WindowModality.WindowModal)
18 | OptionsDialog.resize(517, 620)
19 | OptionsDialog.setSizeGripEnabled(True)
20 | OptionsDialog.setModal(True)
21 | self.verticalLayout_4 = QtWidgets.QVBoxLayout(OptionsDialog)
22 | self.verticalLayout_4.setObjectName("verticalLayout_4")
23 | self.tabs_widget = QtWidgets.QTabWidget(OptionsDialog)
24 | self.tabs_widget.setEnabled(True)
25 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding)
26 | sizePolicy.setHorizontalStretch(0)
27 | sizePolicy.setVerticalStretch(0)
28 | sizePolicy.setHeightForWidth(self.tabs_widget.sizePolicy().hasHeightForWidth())
29 | self.tabs_widget.setSizePolicy(sizePolicy)
30 | self.tabs_widget.setTabPosition(QtWidgets.QTabWidget.TabPosition.North)
31 | self.tabs_widget.setTabShape(QtWidgets.QTabWidget.TabShape.Rounded)
32 | self.tabs_widget.setObjectName("tabs_widget")
33 | self.appearance_tab = QtWidgets.QWidget()
34 | self.appearance_tab.setEnabled(True)
35 | self.appearance_tab.setObjectName("appearance_tab")
36 | self.verticalLayout_3 = QtWidgets.QVBoxLayout(self.appearance_tab)
37 | self.verticalLayout_3.setObjectName("verticalLayout_3")
38 | self.frame = QtWidgets.QFrame(self.appearance_tab)
39 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
40 | sizePolicy.setHorizontalStretch(0)
41 | sizePolicy.setVerticalStretch(0)
42 | sizePolicy.setHeightForWidth(self.frame.sizePolicy().hasHeightForWidth())
43 | self.frame.setSizePolicy(sizePolicy)
44 | self.frame.setObjectName("frame")
45 | self.verticalLayout_8 = QtWidgets.QVBoxLayout(self.frame)
46 | self.verticalLayout_8.setObjectName("verticalLayout_8")
47 | self.pages_group = QtWidgets.QGroupBox(self.frame)
48 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Maximum)
49 | sizePolicy.setHorizontalStretch(0)
50 | sizePolicy.setVerticalStretch(0)
51 | sizePolicy.setHeightForWidth(self.pages_group.sizePolicy().hasHeightForWidth())
52 | self.pages_group.setSizePolicy(sizePolicy)
53 | self.pages_group.setObjectName("pages_group")
54 | self.horizontalLayout = QtWidgets.QHBoxLayout(self.pages_group)
55 | self.horizontalLayout.setObjectName("horizontalLayout")
56 | self.browser_checkbox = QtWidgets.QCheckBox(self.pages_group)
57 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
58 | sizePolicy.setHorizontalStretch(0)
59 | sizePolicy.setVerticalStretch(0)
60 | sizePolicy.setHeightForWidth(self.browser_checkbox.sizePolicy().hasHeightForWidth())
61 | self.browser_checkbox.setSizePolicy(sizePolicy)
62 | self.browser_checkbox.setChecked(True)
63 | self.browser_checkbox.setObjectName("browser_checkbox")
64 | self.horizontalLayout.addWidget(self.browser_checkbox)
65 | self.overview_checkbox = QtWidgets.QCheckBox(self.pages_group)
66 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Fixed)
67 | sizePolicy.setHorizontalStretch(0)
68 | sizePolicy.setVerticalStretch(0)
69 | sizePolicy.setHeightForWidth(self.overview_checkbox.sizePolicy().hasHeightForWidth())
70 | self.overview_checkbox.setSizePolicy(sizePolicy)
71 | self.overview_checkbox.setChecked(True)
72 | self.overview_checkbox.setObjectName("overview_checkbox")
73 | self.horizontalLayout.addWidget(self.overview_checkbox)
74 | self.congrats_checkbox = QtWidgets.QCheckBox(self.pages_group)
75 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Maximum, QtWidgets.QSizePolicy.Policy.Fixed)
76 | sizePolicy.setHorizontalStretch(0)
77 | sizePolicy.setVerticalStretch(0)
78 | sizePolicy.setHeightForWidth(self.congrats_checkbox.sizePolicy().hasHeightForWidth())
79 | self.congrats_checkbox.setSizePolicy(sizePolicy)
80 | self.congrats_checkbox.setChecked(True)
81 | self.congrats_checkbox.setObjectName("congrats_checkbox")
82 | self.horizontalLayout.addWidget(self.congrats_checkbox)
83 | self.verticalLayout_8.addWidget(self.pages_group)
84 | self.mainViewGroupbox = QtWidgets.QGroupBox(self.frame)
85 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
86 | sizePolicy.setHorizontalStretch(0)
87 | sizePolicy.setVerticalStretch(0)
88 | sizePolicy.setHeightForWidth(self.mainViewGroupbox.sizePolicy().hasHeightForWidth())
89 | self.mainViewGroupbox.setSizePolicy(sizePolicy)
90 | self.mainViewGroupbox.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading | QtCore.Qt.AlignmentFlag.AlignLeft | QtCore.Qt.AlignmentFlag.AlignTop)
91 | self.mainViewGroupbox.setObjectName("mainViewGroupbox")
92 | self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.mainViewGroupbox)
93 | self.verticalLayout_5.setObjectName("verticalLayout_5")
94 | self.cellListWidget = QtWidgets.QListWidget(self.mainViewGroupbox)
95 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
96 | sizePolicy.setHorizontalStretch(0)
97 | sizePolicy.setVerticalStretch(0)
98 | sizePolicy.setHeightForWidth(self.cellListWidget.sizePolicy().hasHeightForWidth())
99 | self.cellListWidget.setSizePolicy(sizePolicy)
100 | self.cellListWidget.setMinimumSize(QtCore.QSize(0, 64))
101 | self.cellListWidget.setFrameShape(QtWidgets.QFrame.Shape.NoFrame)
102 | self.cellListWidget.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarPolicy.ScrollBarAlwaysOff)
103 | self.cellListWidget.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustIgnored)
104 | self.cellListWidget.setEditTriggers(QtWidgets.QAbstractItemView.EditTrigger.NoEditTriggers)
105 | self.cellListWidget.setProperty("showDropIndicator", False)
106 | self.cellListWidget.setDragEnabled(True)
107 | self.cellListWidget.setDragDropMode(QtWidgets.QAbstractItemView.DragDropMode.InternalMove)
108 | self.cellListWidget.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.NoSelection)
109 | self.cellListWidget.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollMode.ScrollPerPixel)
110 | self.cellListWidget.setObjectName("cellListWidget")
111 | self.verticalLayout_5.addWidget(self.cellListWidget)
112 | self.verticalLayout_8.addWidget(self.mainViewGroupbox)
113 | self.verticalLayout_3.addWidget(self.frame)
114 | self.tabs_widget.addTab(self.appearance_tab, "")
115 | self.decks_tab = QtWidgets.QWidget()
116 | self.decks_tab.setObjectName("decks_tab")
117 | self.verticalLayout = QtWidgets.QVBoxLayout(self.decks_tab)
118 | self.verticalLayout.setObjectName("verticalLayout")
119 | self.toolbar_checkbox = QtWidgets.QCheckBox(self.decks_tab)
120 | self.toolbar_checkbox.setChecked(True)
121 | self.toolbar_checkbox.setObjectName("toolbar_checkbox")
122 | self.verticalLayout.addWidget(self.toolbar_checkbox)
123 | self.include_deleted_checkbox = QtWidgets.QCheckBox(self.decks_tab)
124 | self.include_deleted_checkbox.setChecked(True)
125 | self.include_deleted_checkbox.setObjectName("include_deleted_checkbox")
126 | self.verticalLayout.addWidget(self.include_deleted_checkbox)
127 | self.useRolloverCheckbox = QtWidgets.QCheckBox(self.decks_tab)
128 | self.useRolloverCheckbox.setChecked(True)
129 | self.useRolloverCheckbox.setObjectName("useRolloverCheckbox")
130 | self.verticalLayout.addWidget(self.useRolloverCheckbox)
131 | self.useDecimalCheckbox = QtWidgets.QCheckBox(self.decks_tab)
132 | self.useDecimalCheckbox.setChecked(True)
133 | self.useDecimalCheckbox.setObjectName("useDecimalCheckbox")
134 | self.verticalLayout.addWidget(self.useDecimalCheckbox)
135 | self.enabled_decks_group = QtWidgets.QGroupBox(self.decks_tab)
136 | self.enabled_decks_group.setMinimumSize(QtCore.QSize(0, 100))
137 | self.enabled_decks_group.setObjectName("enabled_decks_group")
138 | self.enabled_decks_layout = QtWidgets.QVBoxLayout(self.enabled_decks_group)
139 | self.enabled_decks_layout.setObjectName("enabled_decks_layout")
140 | self.exclude_layout = QtWidgets.QHBoxLayout()
141 | self.exclude_layout.setObjectName("exclude_layout")
142 | self.deck_enable_button = QtWidgets.QPushButton(self.enabled_decks_group)
143 | self.deck_enable_button.setFocusPolicy(QtCore.Qt.FocusPolicy.TabFocus)
144 | self.deck_enable_button.setObjectName("deck_enable_button")
145 | self.exclude_layout.addWidget(self.deck_enable_button)
146 | self.deck_disable_button = QtWidgets.QPushButton(self.enabled_decks_group)
147 | self.deck_disable_button.setFocusPolicy(QtCore.Qt.FocusPolicy.TabFocus)
148 | self.deck_disable_button.setObjectName("deck_disable_button")
149 | self.exclude_layout.addWidget(self.deck_disable_button)
150 | spacerItem = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Minimum)
151 | self.exclude_layout.addItem(spacerItem)
152 | self.enabled_decks_layout.addLayout(self.exclude_layout)
153 | self.excluded_decks_list = QtWidgets.QListWidget(self.enabled_decks_group)
154 | self.excluded_decks_list.setSelectionMode(QtWidgets.QAbstractItemView.SelectionMode.ExtendedSelection)
155 | self.excluded_decks_list.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectionBehavior.SelectRows)
156 | self.excluded_decks_list.setObjectName("excluded_decks_list")
157 | self.enabled_decks_layout.addWidget(self.excluded_decks_list)
158 | self.verticalLayout.addWidget(self.enabled_decks_group)
159 | self.tabs_widget.addTab(self.decks_tab, "")
160 | self.about_tab = QtWidgets.QWidget()
161 | self.about_tab.setObjectName("about_tab")
162 | self.verticalLayout_2 = QtWidgets.QVBoxLayout(self.about_tab)
163 | self.verticalLayout_2.setSizeConstraint(QtWidgets.QLayout.SizeConstraint.SetNoConstraint)
164 | self.verticalLayout_2.setObjectName("verticalLayout_2")
165 | self.scroll_area = QtWidgets.QScrollArea(self.about_tab)
166 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
167 | sizePolicy.setHorizontalStretch(0)
168 | sizePolicy.setVerticalStretch(0)
169 | sizePolicy.setHeightForWidth(self.scroll_area.sizePolicy().hasHeightForWidth())
170 | self.scroll_area.setSizePolicy(sizePolicy)
171 | self.scroll_area.setSizeAdjustPolicy(QtWidgets.QAbstractScrollArea.SizeAdjustPolicy.AdjustToContents)
172 | self.scroll_area.setWidgetResizable(True)
173 | self.scroll_area.setObjectName("scroll_area")
174 | self.about_scroll = QtWidgets.QWidget()
175 | self.about_scroll.setGeometry(QtCore.QRect(0, 0, 456, 555))
176 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Expanding)
177 | sizePolicy.setHorizontalStretch(0)
178 | sizePolicy.setVerticalStretch(0)
179 | sizePolicy.setHeightForWidth(self.about_scroll.sizePolicy().hasHeightForWidth())
180 | self.about_scroll.setSizePolicy(sizePolicy)
181 | self.about_scroll.setObjectName("about_scroll")
182 | self.scroll_layout = QtWidgets.QVBoxLayout(self.about_scroll)
183 | self.scroll_layout.setObjectName("scroll_layout")
184 | self.about_label_header = QtWidgets.QLabel(self.about_scroll)
185 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Preferred)
186 | sizePolicy.setHorizontalStretch(0)
187 | sizePolicy.setVerticalStretch(0)
188 | sizePolicy.setHeightForWidth(self.about_label_header.sizePolicy().hasHeightForWidth())
189 | self.about_label_header.setSizePolicy(sizePolicy)
190 | self.about_label_header.setTextFormat(QtCore.Qt.TextFormat.AutoText)
191 | self.about_label_header.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
192 | self.about_label_header.setWordWrap(True)
193 | self.about_label_header.setOpenExternalLinks(True)
194 | self.about_label_header.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByKeyboard|QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextBrowserInteraction|QtCore.Qt.TextInteractionFlag.TextSelectableByKeyboard|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse)
195 | self.about_label_header.setObjectName("about_label_header")
196 | self.scroll_layout.addWidget(self.about_label_header)
197 | self.supportButtonHolder = QtWidgets.QFrame(self.about_scroll)
198 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Expanding, QtWidgets.QSizePolicy.Policy.Maximum)
199 | sizePolicy.setHorizontalStretch(0)
200 | sizePolicy.setVerticalStretch(0)
201 | sizePolicy.setHeightForWidth(self.supportButtonHolder.sizePolicy().hasHeightForWidth())
202 | self.supportButtonHolder.setSizePolicy(sizePolicy)
203 | self.supportButtonHolder.setObjectName("supportButtonHolder")
204 | self.support_buttons = QtWidgets.QHBoxLayout(self.supportButtonHolder)
205 | self.support_buttons.setContentsMargins(6, 6, 6, 6)
206 | self.support_buttons.setObjectName("support_buttons")
207 | self.like_button = QtWidgets.QPushButton(self.supportButtonHolder)
208 | self.like_button.setMinimumSize(QtCore.QSize(0, 42))
209 | self.like_button.setMaximumSize(QtCore.QSize(200, 16777215))
210 | self.like_button.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.PointingHandCursor))
211 | self.like_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
212 | self.like_button.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
213 | icon = QtGui.QIcon()
214 | icon.addPixmap(QtGui.QPixmap("res/img/anki_like.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
215 | self.like_button.setIcon(icon)
216 | self.like_button.setIconSize(QtCore.QSize(32, 32))
217 | self.like_button.setObjectName("like_button")
218 | self.support_buttons.addWidget(self.like_button)
219 | self.patreon_button = QtWidgets.QPushButton(self.supportButtonHolder)
220 | self.patreon_button.setMinimumSize(QtCore.QSize(0, 42))
221 | self.patreon_button.setMaximumSize(QtCore.QSize(200, 16777215))
222 | self.patreon_button.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.PointingHandCursor))
223 | self.patreon_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
224 | self.patreon_button.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
225 | icon1 = QtGui.QIcon()
226 | icon1.addPixmap(QtGui.QPixmap("res/img/patreon.png"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
227 | self.patreon_button.setIcon(icon1)
228 | self.patreon_button.setIconSize(QtCore.QSize(32, 32))
229 | self.patreon_button.setObjectName("patreon_button")
230 | self.support_buttons.addWidget(self.patreon_button)
231 | self.kofi_button = QtWidgets.QPushButton(self.supportButtonHolder)
232 | self.kofi_button.setMinimumSize(QtCore.QSize(0, 42))
233 | self.kofi_button.setMaximumSize(QtCore.QSize(200, 16777215))
234 | self.kofi_button.setCursor(QtGui.QCursor(QtCore.Qt.CursorShape.PointingHandCursor))
235 | self.kofi_button.setFocusPolicy(QtCore.Qt.FocusPolicy.NoFocus)
236 | self.kofi_button.setContextMenuPolicy(QtCore.Qt.ContextMenuPolicy.CustomContextMenu)
237 | icon2 = QtGui.QIcon()
238 | icon2.addPixmap(QtGui.QPixmap("res/img/kofilogo_blue.PNG"), QtGui.QIcon.Mode.Normal, QtGui.QIcon.State.Off)
239 | self.kofi_button.setIcon(icon2)
240 | self.kofi_button.setIconSize(QtCore.QSize(32, 32))
241 | self.kofi_button.setObjectName("kofi_button")
242 | self.support_buttons.addWidget(self.kofi_button)
243 | self.scroll_layout.addWidget(self.supportButtonHolder)
244 | self.about_label_body = QtWidgets.QLabel(self.about_scroll)
245 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding)
246 | sizePolicy.setHorizontalStretch(0)
247 | sizePolicy.setVerticalStretch(0)
248 | sizePolicy.setHeightForWidth(self.about_label_body.sizePolicy().hasHeightForWidth())
249 | self.about_label_body.setSizePolicy(sizePolicy)
250 | self.about_label_body.setTextFormat(QtCore.Qt.TextFormat.AutoText)
251 | self.about_label_body.setAlignment(QtCore.Qt.AlignmentFlag.AlignLeading|QtCore.Qt.AlignmentFlag.AlignLeft|QtCore.Qt.AlignmentFlag.AlignTop)
252 | self.about_label_body.setWordWrap(True)
253 | self.about_label_body.setOpenExternalLinks(True)
254 | self.about_label_body.setTextInteractionFlags(QtCore.Qt.TextInteractionFlag.LinksAccessibleByKeyboard|QtCore.Qt.TextInteractionFlag.LinksAccessibleByMouse|QtCore.Qt.TextInteractionFlag.TextBrowserInteraction|QtCore.Qt.TextInteractionFlag.TextSelectableByKeyboard|QtCore.Qt.TextInteractionFlag.TextSelectableByMouse)
255 | self.about_label_body.setObjectName("about_label_body")
256 | self.scroll_layout.addWidget(self.about_label_body)
257 | self.scroll_area.setWidget(self.about_scroll)
258 | self.verticalLayout_2.addWidget(self.scroll_area)
259 | self.tabs_widget.addTab(self.about_tab, "")
260 | self.verticalLayout_4.addWidget(self.tabs_widget)
261 | self.frame_2 = QtWidgets.QFrame(OptionsDialog)
262 | self.frame_2.setObjectName("frame_2")
263 | self.horizontalLayout_2 = QtWidgets.QHBoxLayout(self.frame_2)
264 | self.horizontalLayout_2.setContentsMargins(0, 0, 0, 0)
265 | self.horizontalLayout_2.setObjectName("horizontalLayout_2")
266 | self.confirm_button_box = QtWidgets.QDialogButtonBox(self.frame_2)
267 | self.confirm_button_box.setOrientation(QtCore.Qt.Orientation.Horizontal)
268 | self.confirm_button_box.setStandardButtons(QtWidgets.QDialogButtonBox.StandardButton.Apply|QtWidgets.QDialogButtonBox.StandardButton.Cancel|QtWidgets.QDialogButtonBox.StandardButton.Ok|QtWidgets.QDialogButtonBox.StandardButton.RestoreDefaults)
269 | self.confirm_button_box.setObjectName("confirm_button_box")
270 | self.horizontalLayout_2.addWidget(self.confirm_button_box)
271 | self.supportButton = HoverButton(self.frame_2)
272 | sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Policy.Fixed, QtWidgets.QSizePolicy.Policy.Fixed)
273 | sizePolicy.setHorizontalStretch(0)
274 | sizePolicy.setVerticalStretch(0)
275 | sizePolicy.setHeightForWidth(self.supportButton.sizePolicy().hasHeightForWidth())
276 | self.supportButton.setSizePolicy(sizePolicy)
277 | self.supportButton.setObjectName("supportButton")
278 | self.horizontalLayout_2.addWidget(self.supportButton)
279 | self.verticalLayout_4.addWidget(self.frame_2)
280 |
281 | self.retranslateUi(OptionsDialog)
282 | self.tabs_widget.setCurrentIndex(0)
283 | self.confirm_button_box.accepted.connect(OptionsDialog.accept) # type: ignore
284 | self.confirm_button_box.rejected.connect(OptionsDialog.reject) # type: ignore
285 | QtCore.QMetaObject.connectSlotsByName(OptionsDialog)
286 |
287 | def retranslateUi(self, OptionsDialog):
288 | _translate = QtCore.QCoreApplication.translate
289 | OptionsDialog.setWindowTitle(_translate("OptionsDialog", "Study Time Stats Options"))
290 | self.pages_group.setTitle(_translate("OptionsDialog", "Enabled Pages"))
291 | self.browser_checkbox.setToolTip(_translate("OptionsDialog", "The main page for browsing decks."))
292 | self.browser_checkbox.setText(_translate("OptionsDialog", "Deck Browser"))
293 | self.overview_checkbox.setToolTip(_translate("OptionsDialog", "The page that shows when viewing a deck."))
294 | self.overview_checkbox.setText(_translate("OptionsDialog", "Overview"))
295 | self.congrats_checkbox.setToolTip(_translate("OptionsDialog", "The page that shows when viewing a deck that has its reviews done for the day."))
296 | self.congrats_checkbox.setText(_translate("OptionsDialog", "Congrats"))
297 | self.mainViewGroupbox.setTitle(_translate("OptionsDialog", "Stats View"))
298 | self.cellListWidget.setSortingEnabled(True)
299 | self.tabs_widget.setTabText(self.tabs_widget.indexOf(self.appearance_tab), _translate("OptionsDialog", "General"))
300 | self.toolbar_checkbox.setToolTip(_translate("OptionsDialog", "Enable the Tools Menu shortcut for these options. \n"
301 | "(Can also be accessed via Tools>Add-ons>Study Time Stats>Config)"))
302 | self.toolbar_checkbox.setText(_translate("OptionsDialog", "Show options shortcut in the Tools Menu"))
303 | self.include_deleted_checkbox.setToolTip(_translate("OptionsDialog", "Include review/time stats for cards that\'ve been deleted."))
304 | self.include_deleted_checkbox.setText(_translate("OptionsDialog", "Include reviews from deleted cards"))
305 | self.useRolloverCheckbox.setToolTip(_translate("OptionsDialog", "Use Anki\'s rollover (next-day) hour when considering the time days are cut off."))
306 | self.useRolloverCheckbox.setText(_translate("OptionsDialog", "Use the next-day hour when calculating ranged times"))
307 | self.useDecimalCheckbox.setToolTip(_translate("OptionsDialog", "Shows an \"hour.min\" format for all time outputs. \n"
308 | "(Otherwise uses \"hh:mm\")"))
309 | self.useDecimalCheckbox.setText(_translate("OptionsDialog", "Use decimal format time outputs"))
310 | self.enabled_decks_group.setTitle(_translate("OptionsDialog", "Enabled Decks"))
311 | self.deck_enable_button.setToolTip(_translate("OptionsDialog", "Enable stats for the selected deck(s)."))
312 | self.deck_enable_button.setText(_translate("OptionsDialog", "Enable"))
313 | self.deck_disable_button.setToolTip(_translate("OptionsDialog", "Disable stats for the selected deck(s)."))
314 | self.deck_disable_button.setText(_translate("OptionsDialog", "Disable"))
315 | self.tabs_widget.setTabText(self.tabs_widget.indexOf(self.decks_tab), _translate("OptionsDialog", "Advanced"))
316 | self.about_label_header.setText(_translate("OptionsDialog", "## Study Time Stats
\n"
317 | "Adds a total and ranged study time statistic to Anki\'s main window. \n"
318 | "\n"
319 | "Version: {version} \n"
320 | "Have any issues or feedback? Feel free to post on the project\'s issue section on [GitHub](https://github.com/iamjustkoi/StudyTimeStats/issues)! \n"
321 | "\n"
322 | "[Releases/Changelog](https://github.com/iamjustkoi/StudyTimeStats/releases) \n"
323 | "[Source Code](https://github.com/iamjustkoi/StudyTimeStats) \n"
324 | "\n"
325 | "If you like the add-on and want to consider supporting me in anyway:"))
326 | self.like_button.setToolTip(_translate("OptionsDialog", "Leave a review over at AnkiWeb!"))
327 | self.like_button.setText(_translate("OptionsDialog", "AnkiWeb "))
328 | self.patreon_button.setToolTip(_translate("OptionsDialog", "Follow/support me on Patreon!"))
329 | self.patreon_button.setText(_translate("OptionsDialog", " Patreon "))
330 | self.kofi_button.setToolTip(_translate("OptionsDialog", "Buy me a coffee with Ko-Fi!"))
331 | self.kofi_button.setText(_translate("OptionsDialog", "Ko-Fi"))
332 | self.about_label_body.setText(_translate("OptionsDialog", "Every bit helps and is greatly appreciated! <3\n"
333 | "\n"
334 | "### Text Macros\n"
335 | "All output text can also be filtered to show some more customized information (e.g. \"Past %range\" to \"Past Week\"). These can be used multiple times and will update whenever Anki\'s main window reloads. \n"
336 | "\n"
337 | "`%%` - can be used to return a single % symbol and disable filtering for any macro text (e.g. `%%` -> %, `%%range` -> %range)\n"
338 | "\n"
339 | "*Small warning: as a general rule, the more stats used/the larger the range of the stat, the longer it might take to load them all (some caching is also done on the side, too though).\n"
340 | "\n"
341 | " \n"
342 | " \n"
343 | "Thanks for downloading and hope you enjoy!\n"
344 | "\n"
345 | "-koi \n"
346 | "\n"
347 | "\n"
348 | " \n"
349 | " \n"
350 | "MIT License \n"
351 | "\n"
352 | "©2022-2023 JustKoi (iamjustkoi)"
353 | )
354 | )
355 | self.tabs_widget.setTabText(self.tabs_widget.indexOf(self.about_tab), _translate("OptionsDialog", "About"))
356 | self.supportButton.setText(_translate("OptionsDialog", "<3"))
357 |
358 |
359 | from ..forms import HoverButton
360 |
361 | if __name__ == "__main__":
362 | import sys
363 |
364 | app = QtWidgets.QApplication(sys.argv)
365 | OptionsDialog = QtWidgets.QDialog()
366 | ui = Ui_OptionsDialog()
367 | ui.setupUi(OptionsDialog)
368 | OptionsDialog.show()
369 | sys.exit(app.exec_())
370 |
--------------------------------------------------------------------------------
/res/ui/cell_item.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | CellWidget
4 |
5 |
6 |
7 | 0
8 | 0
9 | 460
10 | 329
11 |
12 |
13 |
14 |
15 | 0
16 | 0
17 |
18 |
19 |
20 | Form
21 |
22 |
23 |
24 | 0
25 |
26 |
27 | 6
28 |
29 |
30 | 0
31 |
32 |
33 | 6
34 |
35 |
36 | 6
37 |
38 | -
39 |
40 |
41 |
42 | 0
43 | 0
44 |
45 |
46 |
47 |
48 | 0
49 | 64
50 |
51 |
52 |
53 | #addButton {
54 | border: 1px solid rgba(134, 134, 134, 128);
55 | border-radius: 2px;
56 | background: transparent;
57 | }
58 |
59 |
60 |
61 | ../img/add_icon.svg ../img/add_icon.svg
62 |
63 |
64 |
65 | 20
66 | 20
67 |
68 |
69 |
70 |
71 | -
72 |
73 |
74 |
75 | 0
76 | 0
77 |
78 |
79 |
80 | #mainFrame {
81 | background: rgba(163, 163, 163, 5%);
82 | border-radius: 6px;
83 | }
84 |
85 |
86 | -
87 |
88 |
89 |
90 | 0
91 | 0
92 |
93 |
94 |
95 |
96 | 20
97 | 20
98 |
99 |
100 |
101 | Set a custom title text color.
102 |
103 |
104 | #titleColorButton {
105 | border-radius: 10px;
106 | background-color: #76bfb4;
107 | width: 20px;
108 | }
109 |
110 |
111 |
112 | -
113 |
114 |
115 | -
116 |
117 |
118 |
119 | 0
120 | 0
121 |
122 |
123 |
124 |
125 | 82
126 | 0
127 |
128 |
129 |
130 | Text that appears above or to-the-left-of the output.
131 |
132 |
133 | #mainFrame {
134 | background: rgba(163, 163, 163, 5%);
135 | border-radius: 6px;
136 | }
137 |
138 |
139 | Title
140 |
141 |
142 |
143 | -
144 |
145 |
146 |
147 | 0
148 | 0
149 |
150 |
151 |
152 |
153 | 20
154 | 20
155 |
156 |
157 |
158 | OpenHandCursor
159 |
160 |
161 | true
162 |
163 |
164 |
165 | ../img/vert_grip.svg ../img/vert_grip.svg
166 |
167 |
168 |
169 | -
170 |
171 |
172 |
173 | 0
174 | 0
175 |
176 |
177 |
178 |
179 | 20
180 | 20
181 |
182 |
183 |
184 |
185 | ../img/chevron_down.svg ../img/chevron_down.svg
186 |
187 |
188 |
189 | 20
190 | 20
191 |
192 |
193 |
194 |
195 | -
196 |
197 |
198 |
199 | 0
200 | 0
201 |
202 |
203 |
204 |
205 | 0
206 |
207 |
208 | 0
209 |
210 |
211 | 0
212 |
213 |
214 | 0
215 |
216 | -
217 |
218 |
219 |
220 | 0
221 | 0
222 |
223 |
224 |
225 | Qt::StrongFocus
226 |
227 |
228 | The day a new week should start on.
229 |
230 |
231 | Sunday
232 |
233 |
234 | QComboBox::AdjustToContents
235 |
236 | -
237 |
238 | Sunday
239 |
240 |
241 | -
242 |
243 | Monday
244 |
245 |
246 | -
247 |
248 | Tuesday
249 |
250 |
251 | -
252 |
253 | Wednesday
254 |
255 |
256 | -
257 |
258 | Thursday
259 |
260 |
261 | -
262 |
263 | Friday
264 |
265 |
266 | -
267 |
268 | Saturday
269 |
270 |
271 |
272 |
273 | -
274 |
275 |
276 | -
277 |
278 |
279 |
280 | 0
281 | 0
282 |
283 |
284 |
285 |
286 | 20
287 | 20
288 |
289 |
290 |
291 | Set a custom output text color.
292 |
293 |
294 | #outputColorButton {
295 | border-radius: 10px;
296 | background-color: #FFF;
297 | width: 20px;
298 | }
299 |
300 |
301 |
302 | -
303 |
304 |
305 |
306 | 0
307 | 0
308 |
309 |
310 |
311 | QFrame::NoFrame
312 |
313 |
314 | QFrame::Raised
315 |
316 |
317 |
318 | 0
319 |
320 |
321 | 0
322 |
323 |
324 | 0
325 |
326 |
327 | 0
328 |
329 | -
330 |
331 |
332 |
333 | 0
334 | 0
335 |
336 |
337 |
338 | Qt::StrongFocus
339 |
340 |
341 | Time range to filter through for the ranged total stat.
342 |
343 |
344 | QComboBox::AdjustToContents
345 |
346 | -
347 |
348 | Total
349 |
350 |
351 | -
352 |
353 | Past Week
354 |
355 |
356 | -
357 |
358 | Past 2 Weeks
359 |
360 |
361 | -
362 |
363 | Past Month
364 |
365 |
366 | -
367 |
368 | Past Year
369 |
370 |
371 | -
372 |
373 | Custom
374 |
375 |
376 |
377 |
378 | -
379 |
380 |
381 |
382 | 0
383 | 0
384 |
385 |
386 |
387 | QFrame::NoFrame
388 |
389 |
390 | QFrame::Raised
391 |
392 |
393 |
394 | 0
395 |
396 |
397 | 0
398 |
399 |
400 | 0
401 |
402 |
403 | 0
404 |
405 |
406 | 0
407 |
408 | -
409 |
410 |
411 |
412 | 0
413 | 0
414 |
415 |
416 |
417 | Use the start of the selected range instead of using its timespan.
418 |
419 |
420 | Use Calendar Week
421 |
422 |
423 | true
424 |
425 |
426 |
427 | -
428 |
429 |
430 |
431 | 0
432 | 0
433 |
434 |
435 |
436 | Qt::StrongFocus
437 |
438 |
439 | Amount of days to filter the custom range.
440 |
441 |
442 | days
443 |
444 |
445 | 5690
446 |
447 |
448 | 7
449 |
450 |
451 |
452 |
453 |
454 |
455 |
456 |
457 |
458 | -
459 |
460 |
461 |
462 | 0
463 | 0
464 |
465 |
466 |
467 | QFrame::NoFrame
468 |
469 |
470 | QFrame::Plain
471 |
472 |
473 |
474 | 0
475 |
476 |
477 | 0
478 |
479 |
480 | 0
481 |
482 |
483 | 0
484 |
485 |
486 | 0
487 |
488 | -
489 |
490 |
491 | false
492 |
493 |
494 |
495 | 0
496 | 0
497 |
498 |
499 |
500 |
501 | 42
502 | 16777215
503 |
504 |
505 |
506 |
507 | ../img/vert_lines.svg ../img/vert_lines.svg
508 |
509 |
510 |
511 | -
512 |
513 |
514 |
515 | 0
516 | 0
517 |
518 |
519 |
520 |
521 | 42
522 | 16777215
523 |
524 |
525 |
526 |
527 | ../img/horiz_lines.svg ../img/horiz_lines.svg
528 |
529 |
530 |
531 |
532 |
533 |
534 | -
535 |
536 |
537 |
538 | 0
539 | 0
540 |
541 |
542 |
543 | QFrame::NoFrame
544 |
545 |
546 | QFrame::Raised
547 |
548 |
549 |
550 | 0
551 |
552 |
553 | 0
554 |
555 |
556 | 0
557 |
558 |
559 | 0
560 |
561 | -
562 |
563 |
564 | Hour
565 |
566 |
567 |
568 | -
569 |
570 |
571 |
572 | 0
573 | 0
574 |
575 |
576 |
577 | hrs
578 |
579 |
580 |
581 | -
582 |
583 |
584 | Minute
585 |
586 |
587 |
588 | -
589 |
590 |
591 |
592 | 0
593 | 0
594 |
595 |
596 |
597 | min
598 |
599 |
600 |
601 |
602 |
603 |
604 | -
605 |
606 |
607 |
608 | 0
609 | 0
610 |
611 |
612 |
613 | Set text-stacking direction to either vertical/horizontal.
614 |
615 |
616 | Direction
617 |
618 |
619 |
620 | -
621 |
622 |
623 |
624 | 0
625 | 0
626 |
627 |
628 |
629 | Day to consider the first day of a calendar week.
630 |
631 |
632 | Week-Start Day
633 |
634 |
635 |
636 | -
637 |
638 |
639 |
640 | 0
641 | 0
642 |
643 |
644 |
645 | Preset range to use for macros with an expected range.
646 |
647 |
648 | Selected Range
649 |
650 |
651 |
652 | -
653 |
654 |
655 |
656 | 0
657 | 0
658 |
659 |
660 |
661 | Text to be appended to any time-related measurements for all output text.
662 |
663 |
664 | Units
665 |
666 |
667 |
668 | -
669 |
670 |
671 |
672 | 0
673 | 0
674 |
675 |
676 |
677 |
678 | 82
679 | 0
680 |
681 |
682 |
683 | Text that appears below or to-the-right-of the title.
684 |
685 |
686 | Output
687 |
688 |
689 |
690 | -
691 |
692 |
693 | Qt::Horizontal
694 |
695 |
696 | QSizePolicy::Fixed
697 |
698 |
699 |
700 | 24
701 | 0
702 |
703 |
704 |
705 |
706 | -
707 |
708 |
709 |
710 | 0
711 | 0
712 |
713 |
714 |
715 |
716 | 0
717 | 0
718 |
719 |
720 |
721 |
722 | 20
723 | 20
724 |
725 |
726 |
727 |
728 | ../img/remove_icon.svg ../img/remove_icon.svg
729 |
730 |
731 |
732 | 20
733 | 20
734 |
735 |
736 |
737 |
738 | -
739 |
740 |
741 |
742 | 0
743 | 0
744 |
745 |
746 |
747 |
748 | 0
749 | 0
750 |
751 |
752 |
753 |
754 | 20
755 | 20
756 |
757 |
758 |
759 |
760 | ../img/code_icon.svg ../img/code_icon.svg
761 |
762 |
763 |
764 | 20
765 | 20
766 |
767 |
768 |
769 |
770 | -
771 |
772 |
773 |
774 | 0
775 | 0
776 |
777 |
778 |
779 |
780 | 16777215
781 | 128
782 |
783 |
784 |
785 | QAbstractScrollArea::AdjustIgnored
786 |
787 |
788 | false
789 |
790 |
791 |
792 |
793 |
794 |
795 |
796 |
797 |
798 |
799 |
800 |
801 |
802 | HoverButton
803 | QPushButton
804 |
805 |
806 |
807 | DragHandle
808 | QPushButton
809 |
810 |
811 |
812 | RotateButton
813 | QPushButton
814 |
815 |
816 |
817 |
818 |
819 |
820 |
--------------------------------------------------------------------------------
/res/ui/forms.py:
--------------------------------------------------------------------------------
1 | from aqt import Qt
2 | from aqt.qt import (
3 | QToolButton,
4 | QColor,
5 | QShowEvent,
6 | QIcon,
7 | QTransform,
8 | QMouseEvent,
9 | QListWidget,
10 | QT_VERSION_STR,
11 | )
12 |
13 | ANKI_QT_VER = int(QT_VERSION_STR.split('.')[0])
14 |
15 | if ANKI_QT_VER == 5:
16 | MaskOutColor = Qt.MaskMode.MaskOutColor
17 | ClosedHandCursor = Qt.CursorShape.ClosedHandCursor
18 | OpenHandCursor = Qt.CursorShape.OpenHandCursor
19 | SmoothTransformation = Qt.TransformationMode.SmoothTransformation
20 | else:
21 | MaskOutColor = Qt.MaskMode.MaskOutColor
22 | ClosedHandCursor = Qt.CursorShape.ClosedHandCursor
23 | OpenHandCursor = Qt.CursorShape.OpenHandCursor
24 | SmoothTransformation = Qt.TransformationMode.SmoothTransformation
25 |
26 |
27 | class HoverButton(QToolButton):
28 | """
29 | Custom button for handling button icon tinting during hover events with QPushButtons.
30 | """
31 |
32 | tint = "#FFFFFF"
33 | hover_tint = "#8a8a8a"
34 | mask_color = "black"
35 | raw_icon = None
36 | locked = False
37 |
38 | def setMaskColor(self, color: str):
39 | self.mask_color = color
40 |
41 | def setTint(self, tint: str):
42 | self.tint = tint
43 |
44 | def setHoverTint(self, tint: str):
45 | """
46 | Set the color of the icon when the mouse is hovering over the button.
47 | :param tint: a string representation of the color
48 | """
49 | self.hover_tint = tint
50 |
51 | def setRawIcon(self, icon: QIcon) -> None:
52 | self.raw_icon = icon
53 |
54 | def showEvent(self, a0: QShowEvent) -> None:
55 | super().showEvent(a0)
56 | self._updateIcon(False)
57 |
58 | def enterEvent(self, *args, **kwargs):
59 | super().enterEvent(*args, *kwargs)
60 | self._updateIcon(True)
61 |
62 | def leaveEvent(self, *args, **kwargs):
63 | super().leaveEvent(*args, *kwargs)
64 | if not self.locked:
65 | self._updateIcon(False)
66 |
67 | def lockHoverTint(self, locked: bool = True):
68 | self.locked = locked
69 |
70 | def _updateIcon(self, is_hovered: bool):
71 | """
72 | Updates the icon of the HoverButton to a tinted color if the mouse is currently hovering over it.
73 |
74 | :param is_hovered: whether the mouse is currently hovered over the HoverButton
75 | """
76 |
77 | pixmap = self.raw_icon.pixmap(self.size(), QIcon.Mode.Normal, QIcon.State.On)
78 |
79 | if is_hovered:
80 | mask = pixmap.createMaskFromColor(QColor(self.mask_color), MaskOutColor)
81 | pixmap.fill(QColor(self.hover_tint))
82 | pixmap.setMask(mask)
83 | self.setIcon(QIcon(pixmap))
84 |
85 | else:
86 | mask = pixmap.createMaskFromColor(QColor(self.mask_color), MaskOutColor)
87 | pixmap.fill(QColor(self.tint))
88 | pixmap.setMask(mask)
89 | self.setIcon(QIcon(pixmap))
90 |
91 | self.adjustSize()
92 | self.setMinimumSize(self.sizeHint())
93 |
94 |
95 | class RotateButton(QToolButton):
96 | rotation = 0
97 | tint = "#FFFFFF"
98 | mask_color = "black"
99 | raw_icon = None
100 |
101 | def setRotation(self, degrees: float):
102 | self.rotation = degrees
103 | self._updateIcon()
104 |
105 | def setRawIcon(self, icon: QIcon) -> None:
106 | self.raw_icon = icon
107 |
108 | def showEvent(self, evt: QShowEvent) -> None:
109 | super().showEvent(evt)
110 | self._updateIcon()
111 |
112 | def setMaskColor(self, color: str):
113 | self.mask_color = color
114 |
115 | def setTint(self, tint: str):
116 | self.tint = tint
117 |
118 | def _updateIcon(self):
119 | """
120 | Updates the icon of the RotateButton to the tinted color, using the stored mask color.
121 | """
122 | pixmap = self.raw_icon.pixmap(self.size(), QIcon.Mode.Normal, QIcon.State.On)\
123 | .transformed(QTransform().rotate(self.rotation), SmoothTransformation)
124 | mask = pixmap.createMaskFromColor(QColor(self.mask_color), MaskOutColor)
125 | pixmap.fill(QColor(self.tint))
126 | pixmap.setMask(mask)
127 |
128 | self.setIcon(QIcon(pixmap))
129 |
130 | self.adjustSize()
131 | self.setMinimumSize(self.sizeHint())
132 |
133 |
134 | class DragHandle(QToolButton):
135 | start_pos = None
136 | last_drag_global_pos = None
137 | list_widget: QListWidget = None
138 | is_dragging = False
139 | list_item = None
140 | icon_color = '#FFFFFF'
141 | last_target_idx = -1
142 | padding = 4
143 |
144 | def __init__(self, *args):
145 | super().__init__(*args)
146 | self.setCursor(OpenHandCursor)
147 |
148 | def setIcon(self, icon: QIcon) -> None:
149 | pixmap = icon.pixmap(self.size(), QIcon.Mode.Normal, QIcon.State.On)
150 | mask = pixmap.createMaskFromColor(QColor('black'), MaskOutColor)
151 | pixmap.fill(QColor(self.icon_color))
152 | pixmap.setMask(mask)
153 | super().setIcon(QIcon(pixmap))
154 |
155 | self.adjustSize()
156 | self.setMinimumSize(self.sizeHint())
157 |
158 | def mousePressEvent(self, event: QMouseEvent) -> None:
159 | self.start_pos = event.pos()
160 |
161 | def mouseMoveEvent(self, event: QMouseEvent) -> None:
162 | offset = self.start_pos.y() - event.pos().y() if self.start_pos else 0
163 |
164 | if abs(offset) > 5:
165 | # Moved beyond range (enough to consider a drag check/updates)
166 | self.drag(offset)
167 |
168 | def mouseReleaseEvent(self, event: QMouseEvent) -> None:
169 | self.is_dragging = False
170 | self.start_pos = None
171 | self.setCursor(OpenHandCursor)
172 |
173 | def drag(self, offset: int):
174 | if not self.is_dragging:
175 | self.is_dragging = True
176 | self.setCursor(ClosedHandCursor)
177 |
178 | # Offset greater than half of the currently dragged cell item's height (plus padding)
179 | if self.list_widget and self.list_item and abs(offset) > ((self.parentWidget().height() / 2) + self.padding):
180 | drag_idx = self.list_widget.row(self.list_item)
181 | target_idx = drag_idx + (-1 if offset > 0 else 1)
182 |
183 | move_dir = target_idx - drag_idx
184 |
185 | if target_idx != self.list_widget.count() - 1:
186 | # Target index isn't the last cell item (empty cell)
187 | target_item = self.list_widget.item(target_idx)
188 |
189 | if target_item:
190 | did_switch_dir = False
191 | if self.last_drag_global_pos:
192 | current_drag_global_pos = self.parentWidget().cursor().pos()
193 | global_dir_y = current_drag_global_pos.y() - self.last_drag_global_pos.y()
194 |
195 | # Moving in the opposite direction from the last drag event
196 | did_switch_dir = (global_dir_y < 0 < -move_dir) or (global_dir_y > 0 > -move_dir)
197 |
198 | # noinspection PyUnresolvedReferences
199 | target_cell = target_item.cell_item
200 |
201 | # Not the same target, or the same target and moving in the opposite direction
202 | if target_cell.index != self.last_target_idx or did_switch_dir:
203 | # Swap indices
204 | self.list_item.cell_item.index = target_idx
205 | target_cell.index = drag_idx
206 |
207 | # Re-sort post index swap
208 | self.list_widget.sortItems()
209 |
210 | # Broadcast change
211 | self.list_widget.currentRowChanged.emit(self.list_item.cell_item.index)
212 |
213 | # Cache values
214 | self.last_target_idx = drag_idx
215 | self.last_drag_global_pos = self.parentWidget().cursor().pos()
216 |
--------------------------------------------------------------------------------
/res/ui/macro_dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | MacroDialog
4 |
5 |
6 |
7 | 0
8 | 0
9 | 528
10 | 362
11 |
12 |
13 |
14 | Macros
15 |
16 |
17 | -
18 |
19 |
20 |
21 | 0
22 | 0
23 |
24 |
25 |
26 | Macros
27 |
28 |
29 |
30 | 6
31 |
32 |
33 | 0
34 |
35 |
36 | 6
37 |
38 |
39 | 6
40 |
41 | -
42 |
43 |
44 | Filter...
45 |
46 |
47 | true
48 |
49 |
50 |
51 | -
52 |
53 |
54 | QFrame::NoFrame
55 |
56 |
57 | QFrame::Plain
58 |
59 |
60 | Qt::ScrollBarAlwaysOff
61 |
62 |
63 | true
64 |
65 |
66 | false
67 |
68 |
69 | QAbstractItemView::SelectRows
70 |
71 |
72 |
73 |
74 |
75 |
76 | -
77 |
78 |
79 |
80 | 0
81 | 42
82 |
83 |
84 |
85 | Preview
86 |
87 |
88 |
89 | 6
90 |
91 |
92 | 6
93 |
94 |
95 | 6
96 |
97 |
98 | 6
99 |
100 | -
101 |
102 |
103 | test
104 |
105 |
106 |
107 |
108 |
109 |
110 | -
111 |
112 |
113 | Qt::Horizontal
114 |
115 |
116 | QDialogButtonBox::Cancel|QDialogButtonBox::Ok
117 |
118 |
119 |
120 |
121 |
122 |
123 |
124 |
125 | buttonBox
126 | accepted()
127 | MacroDialog
128 | accept()
129 |
130 |
131 | 248
132 | 254
133 |
134 |
135 | 157
136 | 274
137 |
138 |
139 |
140 |
141 | buttonBox
142 | rejected()
143 | MacroDialog
144 | reject()
145 |
146 |
147 | 316
148 | 260
149 |
150 |
151 | 286
152 | 274
153 |
154 |
155 |
156 |
157 |
158 |
--------------------------------------------------------------------------------
/res/ui/options_dialog.ui:
--------------------------------------------------------------------------------
1 |
2 |
3 | JustKoi
4 | OptionsDialog
5 |
6 |
7 | Qt::WindowModal
8 |
9 |
10 |
11 | 0
12 | 0
13 | 517
14 | 620
15 |
16 |
17 |
18 | Study Time Stats Options
19 |
20 |
21 | true
22 |
23 |
24 | true
25 |
26 |
27 | -
28 |
29 |
30 | true
31 |
32 |
33 |
34 | 0
35 | 0
36 |
37 |
38 |
39 | QTabWidget::North
40 |
41 |
42 | QTabWidget::Rounded
43 |
44 |
45 | 0
46 |
47 |
48 |
49 | true
50 |
51 |
52 | General
53 |
54 |
55 | -
56 |
57 |
58 |
59 | 0
60 | 0
61 |
62 |
63 |
64 | -
65 |
66 |
67 |
68 | 0
69 | 0
70 |
71 |
72 |
73 | Enabled Pages
74 |
75 |
76 | -
77 |
78 |
79 |
80 | 0
81 | 0
82 |
83 |
84 |
85 | The main page for browsing decks.
86 |
87 |
88 | Deck Browser
89 |
90 |
91 | true
92 |
93 |
94 |
95 | -
96 |
97 |
98 |
99 | 0
100 | 0
101 |
102 |
103 |
104 | The page that shows when viewing a deck.
105 |
106 |
107 | Overview
108 |
109 |
110 | true
111 |
112 |
113 |
114 | -
115 |
116 |
117 |
118 | 0
119 | 0
120 |
121 |
122 |
123 | The page that shows when viewing a deck that has its reviews done for the day.
124 |
125 |
126 | Congrats
127 |
128 |
129 | true
130 |
131 |
132 |
133 |
134 |
135 |
136 | -
137 |
138 |
139 |
140 | 0
141 | 0
142 |
143 |
144 |
145 | Stats View
146 |
147 |
148 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
149 |
150 |
151 | -
152 |
153 |
154 |
155 | 0
156 | 0
157 |
158 |
159 |
160 |
161 | 0
162 | 64
163 |
164 |
165 |
166 | QFrame::NoFrame
167 |
168 |
169 | Qt::ScrollBarAlwaysOff
170 |
171 |
172 | QAbstractScrollArea::AdjustIgnored
173 |
174 |
175 | QAbstractItemView::NoEditTriggers
176 |
177 |
178 | false
179 |
180 |
181 | true
182 |
183 |
184 | QAbstractItemView::InternalMove
185 |
186 |
187 | QAbstractItemView::NoSelection
188 |
189 |
190 | QAbstractItemView::ScrollPerPixel
191 |
192 |
193 | true
194 |
195 |
196 |
197 |
198 |
199 |
200 |
201 |
202 |
203 |
204 |
205 |
206 |
207 | Advanced
208 |
209 |
210 | -
211 |
212 |
213 | Enable the Tools Menu shortcut for these options.
214 | (Can also be accessed via Tools>Add-ons>Study Time Stats>Config)
215 |
216 |
217 | Show options shortcut in the Tools Menu
218 |
219 |
220 | true
221 |
222 |
223 |
224 | -
225 |
226 |
227 | Include review/time stats for cards that've been deleted.
228 |
229 |
230 | Include reviews from deleted cards
231 |
232 |
233 | true
234 |
235 |
236 |
237 | -
238 |
239 |
240 | Use Anki's rollover (next-day) hour when considering the time days are cut off.
241 |
242 |
243 | Use the next-day hour when calculating ranged times
244 |
245 |
246 | true
247 |
248 |
249 |
250 | -
251 |
252 |
253 | Shows an "hour.min" format for all time outputs.
254 | (Otherwise uses "hh:mm")
255 |
256 |
257 | Use decimal format time outputs
258 |
259 |
260 | true
261 |
262 |
263 |
264 | -
265 |
266 |
267 |
268 | 0
269 | 100
270 |
271 |
272 |
273 | Enabled Decks
274 |
275 |
276 | -
277 |
278 | -
279 |
280 |
281 | Qt::TabFocus
282 |
283 |
284 | Enable stats for the selected deck(s).
285 |
286 |
287 | Enable
288 |
289 |
290 |
291 | -
292 |
293 |
294 | Qt::TabFocus
295 |
296 |
297 | Disable stats for the selected deck(s).
298 |
299 |
300 | Disable
301 |
302 |
303 |
304 | -
305 |
306 |
307 | Qt::Horizontal
308 |
309 |
310 |
311 | 40
312 | 20
313 |
314 |
315 |
316 |
317 |
318 |
319 | -
320 |
321 |
322 | QAbstractItemView::ExtendedSelection
323 |
324 |
325 | QAbstractItemView::SelectRows
326 |
327 |
328 |
329 |
330 |
331 |
332 |
333 |
334 |
335 |
336 | About
337 |
338 |
339 |
340 | QLayout::SetNoConstraint
341 |
342 | -
343 |
344 |
345 |
346 | 0
347 | 0
348 |
349 |
350 |
351 | QAbstractScrollArea::AdjustToContents
352 |
353 |
354 | true
355 |
356 |
357 |
358 |
359 | 0
360 | 0
361 | 456
362 | 555
363 |
364 |
365 |
366 |
367 | 0
368 | 0
369 |
370 |
371 |
372 | -
373 |
374 |
375 |
376 | 0
377 | 0
378 |
379 |
380 |
381 | ## <p align="center">Study Time Stats<img src="{img_path}"></p>
382 | Adds a total and ranged study time statistic to Anki's main window.
383 |
384 | Version: {version}
385 | Have any issues or feedback? Feel free to post on the project's issue section on [GitHub](https://github.com/iamjustkoi/StudyTimeStats/issues)!
386 |
387 | [Releases/Changelog](https://github.com/iamjustkoi/StudyTimeStats/releases)
388 | [Source Code](https://github.com/iamjustkoi/StudyTimeStats)
389 |
390 | If you like the add-on and want to consider supporting me in anyway:
391 |
392 |
393 | Qt::AutoText
394 |
395 |
396 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
397 |
398 |
399 | true
400 |
401 |
402 | true
403 |
404 |
405 | Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
406 |
407 |
408 |
409 | -
410 |
411 |
412 |
413 | 0
414 | 0
415 |
416 |
417 |
418 |
419 | 6
420 |
421 |
422 | 6
423 |
424 |
425 | 6
426 |
427 |
428 | 6
429 |
430 | -
431 |
432 |
433 |
434 | 0
435 | 42
436 |
437 |
438 |
439 |
440 | 200
441 | 16777215
442 |
443 |
444 |
445 | PointingHandCursor
446 |
447 |
448 | Qt::NoFocus
449 |
450 |
451 | Qt::CustomContextMenu
452 |
453 |
454 | Leave a review over at AnkiWeb!
455 |
456 |
457 | AnkiWeb
458 |
459 |
460 |
461 | res/img/anki_like.png res/img/anki_like.png
462 |
463 |
464 |
465 | 32
466 | 32
467 |
468 |
469 |
470 |
471 | -
472 |
473 |
474 |
475 | 0
476 | 42
477 |
478 |
479 |
480 |
481 | 200
482 | 16777215
483 |
484 |
485 |
486 | PointingHandCursor
487 |
488 |
489 | Qt::NoFocus
490 |
491 |
492 | Qt::CustomContextMenu
493 |
494 |
495 | Follow/support me on Patreon!
496 |
497 |
498 | Patreon
499 |
500 |
501 |
502 | res/img/patreon.png res/img/patreon.png
503 |
504 |
505 |
506 | 32
507 | 32
508 |
509 |
510 |
511 |
512 | -
513 |
514 |
515 |
516 | 0
517 | 42
518 |
519 |
520 |
521 |
522 | 200
523 | 16777215
524 |
525 |
526 |
527 | PointingHandCursor
528 |
529 |
530 | Qt::NoFocus
531 |
532 |
533 | Qt::CustomContextMenu
534 |
535 |
536 | Buy me a coffee with Ko-Fi!
537 |
538 |
539 | Ko-Fi
540 |
541 |
542 |
543 | res/img/kofilogo_blue.PNG res/img/kofilogo_blue.PNG
544 |
545 |
546 |
547 | 32
548 | 32
549 |
550 |
551 |
552 |
553 |
554 |
555 |
556 | -
557 |
558 |
559 |
560 | 0
561 | 0
562 |
563 |
564 |
565 | Every bit helps and is greatly appreciated! <3
566 |
567 | ### Text Macros
568 | All output text can also be filtered to show some more customized information (e.g. "Past %range" to "Past Week"). These can be used multiple times and will update whenever Anki's main window reloads.
569 |
570 | `%%` - can be used to return a single % symbol and disable filtering for any macro text (e.g. `%%` -> %, `%%range` -> %range)
571 |
572 | *Small warning: as a general rule, the more stats used/the larger the range of the stat, the longer it might take to load them all (some caching is also done on the side, too though).
573 |
574 | <br></br>
575 | <br></br>
576 | Thanks for downloading and hope you enjoy!
577 |
578 | -koi
579 |
580 |
581 | <br></br>
582 | <br></br>
583 | MIT License
584 |
585 | ©2022-2023 JustKoi (iamjustkoi)
586 |
587 |
588 | Qt::AutoText
589 |
590 |
591 | Qt::AlignLeading|Qt::AlignLeft|Qt::AlignTop
592 |
593 |
594 | true
595 |
596 |
597 | true
598 |
599 |
600 | Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse
601 |
602 |
603 |
604 |
605 |
606 |
607 |
608 |
609 |
610 |
611 |
612 | -
613 |
614 |
615 |
616 | 0
617 |
618 |
619 | 0
620 |
621 |
622 | 0
623 |
624 |
625 | 0
626 |
627 | -
628 |
629 |
630 | Qt::Horizontal
631 |
632 |
633 | QDialogButtonBox::Apply|QDialogButtonBox::Cancel|QDialogButtonBox::Ok|QDialogButtonBox::RestoreDefaults
634 |
635 |
636 |
637 | -
638 |
639 |
640 |
641 | 0
642 | 0
643 |
644 |
645 |
646 | <3
647 |
648 |
649 |
650 |
651 |
652 |
653 |
654 |
655 |
656 |
657 | HoverButton
658 | QPushButton
659 |
660 |
661 |
662 |
663 |
664 |
665 | confirm_button_box
666 | accepted()
667 | OptionsDialog
668 | accept()
669 |
670 |
671 | 248
672 | 254
673 |
674 |
675 | 157
676 | 274
677 |
678 |
679 |
680 |
681 | confirm_button_box
682 | rejected()
683 | OptionsDialog
684 | reject()
685 |
686 |
687 | 316
688 | 260
689 |
690 |
691 | 286
692 | 274
693 |
694 |
695 |
696 |
697 |
698 |
--------------------------------------------------------------------------------
/src/config.py:
--------------------------------------------------------------------------------
1 | # MIT License: Copyright (c) 2022-2023 JustKoi (iamjustkoi)
2 | # Full license text available in the "LICENSE" file, packaged with the add-on.
3 |
4 | import re
5 | from typing import List
6 |
7 | from anki.buildinfo import version
8 | from aqt import AnkiQt
9 |
10 | from .consts import CELL_HTML_SHELL, CURRENT_VERSION, Config, Direction, Macro, Range, String
11 |
12 | try:
13 | # from anki.utils import pointVersion
14 | from anki.utils import pointVersion
15 | except ImportError:
16 | def pointVersion():
17 | return int(version.replace('2.1.', ''))
18 |
19 | try:
20 | ANKI_VERSION = int(version.replace('2.1.', ''))
21 | except ValueError:
22 | ANKI_VERSION = pointVersion()
23 |
24 |
25 | class TimeStatsConfigManager:
26 |
27 | def __init__(self, mw: AnkiQt):
28 | """
29 | Generic config manager for accessing and writing addon config values.
30 |
31 | :param mw: Anki window to retrieve addon and other data from
32 | """
33 | super().__init__()
34 | self.mw = mw
35 | self._addon = self.mw.addonManager.addonFromModule(__name__)
36 | self._meta = self.mw.addonManager.addonMeta(self._addon)
37 |
38 | self.config = self._init_config()
39 |
40 | self.decks = self.mw.col.decks if self.mw.col is not None else None
41 |
42 | # Add a constant key to meta
43 | self._meta['config'] = self.config
44 |
45 | def write_config(self):
46 | """
47 | Writes the config manager's current values to the addon meta file.
48 | """
49 | self.mw.addonManager.writeAddonMeta(self._addon, self._meta)
50 |
51 | def write_config_val(self, key: str, val):
52 | """
53 | Creates a shallow copy of the current config and writes a single value to the addon meta file
54 | using the shallow copy as a template.
55 | """
56 | config = self._init_config(deep=False)
57 | config[key] = val
58 | meta = self.mw.addonManager.addonMeta(self._addon)
59 | meta['config'] = config
60 | self.mw.addonManager.writeAddonMeta(self._addon, meta)
61 |
62 | def _init_config(self, deep=True):
63 | meta = self._meta if deep else self.mw.addonManager.addonMeta(self._addon)
64 | config = meta.get('config', Config.DEFAULT_CONFIG.copy())
65 | config = _reformat_conf(config) if deep else config
66 | for field in Config.DEFAULT_CONFIG:
67 | if field not in config:
68 | # load temp defaults
69 | config[field] = Config.DEFAULT_CONFIG[field]
70 |
71 | return config
72 |
73 |
74 | def _reformat_conf(config: dict):
75 | """
76 | Handles the addon's config updates/patching pipeline.
77 |
78 | :param config: The current config for the addon.
79 | :return: An updated addon config with updated formatting/patched changes.
80 | """
81 | addon_ver = config.get(Config.VERSION, '0.0.0')
82 | formatted_addon_ver = re.sub('-.*', '', addon_ver)
83 | ver_numbers: List[int] = [int(n) for n in formatted_addon_ver.split('.')]
84 |
85 | # v1.3.5
86 | # Replaces "%from_custom_date" with the updated, custom-date-range hours macro.
87 | if ver_numbers[0] <= 1 and ver_numbers[1] <= 3 and ver_numbers[2] <= 5:
88 | def replace_macro(outer_conf: dict):
89 | for field in outer_conf:
90 | data = outer_conf[field]
91 | if isinstance(data, str) and re.match(fr'.*(?
2 | # Full license text available in the "LICENSE" file, packaged with the add-on.
3 |
4 | from aqt.qt import QT_VERSION_STR
5 | from aqt.theme import theme_manager
6 |
7 | CURRENT_VERSION = '2.1.4'
8 |
9 | ANKI_LEGACY_VER = 35
10 | ANKI_DEFAULT_ROLLOVER = 4
11 | ANKI_QT_VER = int(QT_VERSION_STR.split('.')[0])
12 |
13 | UNIQUE_DATE = '2006-10-05'
14 |
15 | ADDON_ICON_PATH = '../res/img/stats_icon.svg'
16 | HEART_ICON_PATH = '../res/img/heart_icon.svg'
17 | KOFI_ICON_PATH = '../res/img/kofilogo_blue.PNG'
18 | PATREON_ICON_PATH = '../res/img/patreon.png'
19 | ANKI_LIKE_ICON_PATH = '../res/img/anki_like.png'
20 |
21 | REMOVE_ICON_PATH = '../res/img/remove_icon.svg'
22 | ADD_ICON_PATH = '../res/img/add_icon.svg'
23 | CODE_ICON_PATH = '../res/img/code_icon.svg'
24 | CHEVRON_ICON_PATH = '../res/img/chevron_down.svg'
25 | VERT_LINES_PATH = '../res/img/vert_lines.svg'
26 | HORIZ_LINES_PATH = '../res/img/horiz_lines.svg'
27 | HANDLES_PATH = '../res/img/vert_grip.svg'
28 |
29 | PATREON_URL = 'https://www.patreon.com/iamjustkoi'
30 | KOFI_URL = 'https://ko-fi.com/iamjustkoi'
31 | ANKI_URL = 'https://ankiweb.net/shared/info/1247171202'
32 |
33 | TABLE_ID = 'sts-table'
34 | COL_CLASS = 'sts-col'
35 | HORIZ_CELL_CLASS = 'flow-horizontal'
36 | VERT_CELL_CLASS = 'flow-vertical'
37 | HTML_SHELL = '''
38 |
66 |
67 |
68 | {cell_data}
69 |
70 |
71 | '''
72 |
73 | CELL_HTML_SHELL = '''
74 |
{{Title}}
75 |
{{Output}}
76 |
77 | '''
78 |
79 | SUSPENDED = 'suspended'
80 | LEARN = 'learn'
81 | RELEARN = 'relearn'
82 | REVIEW = 'review'
83 | NEW = 'new'
84 | SIB_BURIED = 'sib_buried'
85 | MAN_BURIED = 'man_buried'
86 | BURIED = 'buried'
87 |
88 |
89 | class Macro:
90 | # Text
91 | CMD_RANGE = '%range'
92 | CMD_DATE = '%from_date'
93 | CMD_YEAR = '%from_year'
94 | CMD_FULL_DAY = '%from_full_day'
95 | CMD_DAY = '%from_day'
96 | CMD_DAYS = '%days'
97 | CMD_DATE_FORMATTED = r'%from_date:strf\{".*\"}'
98 |
99 | CMD_MONTH = '%from_month'
100 | CMD_FULL_MONTH = '%from_full_month'
101 |
102 | # Time
103 | CMD_TOTAL_HOURS = '%total_hrs'
104 |
105 | CMD_RANGE_HOURS = '%range_hrs'
106 | CMD_DAY_HOURS = '%day_hrs'
107 | CMD_WEEK_HOURS = '%week_hrs'
108 | CMD_TWO_WEEKS_HOURS = '%two_week_hrs'
109 | CMD_MONTH_HOURS = '%month_hrs'
110 | CMD_YEAR_HOURS = '%year_hrs'
111 |
112 | CMD_ETA_HOURS = '%eta_hrs'
113 |
114 | CMD_HIGHEST_DAY_HOURS = '%highest_day_hrs'
115 | CMD_HIGHEST_WEEK_HOURS = '%highest_week_hrs'
116 | CMD_HIGHEST_MONTH_HOURS = '%highest_month_hrs'
117 | CMD_HIGHEST_YEAR_HOURS = '%highest_year_hrs'
118 |
119 | # Avg
120 | CMD_CARD_AVERAGE_HOURS = '%card_avg_hrs'
121 | CMD_CARD_AVERAGE_REVIEWS = '%card_avg_rev'
122 | CMD_DAY_AVERAGE_HOURS = '%day_avg_hrs'
123 | CMD_DAY_AVERAGE_REVIEWS = '%day_avg_rev'
124 |
125 | # Previous Time
126 | CMD_PREVIOUS_RANGE_HOURS = '%prev_range_hrs'
127 | CMD_PREVIOUS_DAY_HOURS = '%prev_day_hrs'
128 | CMD_PREVIOUS_WEEK_HOURS = '%prev_week_hrs'
129 | CMD_PREVIOUS_TWO_WEEKS_HOURS = '%prev_two_week_hrs'
130 | CMD_PREVIOUS_MONTH_HOURS = '%prev_month_hrs'
131 | CMD_PREVIOUS_YEAR_HOURS = '%prev_year_hrs'
132 | CMD_FROM_DATE_HOURS = '%from_custom_hrs'
133 |
134 | # Reviews
135 | CMD_TOTAL_REVIEWS = '%total_rev'
136 | CMD_RANGE_REVIEWS = '%range_rev'
137 | CMD_DAY_REVIEWS = '%day_rev'
138 | CMD_WEEK_REVIEWS = '%week_rev'
139 | CMD_TWO_WEEKS_REVIEWS = '%two_week_rev'
140 | CMD_MONTH_REVIEWS = '%month_rev'
141 | CMD_YEAR_REVIEWS = '%year_rev'
142 |
143 | CMD_PREVIOUS_RANGE_REVIEWS = '%prev_range_rev'
144 | CMD_PREVIOUS_DAY_REVIEWS = '%prev_day_rev'
145 | CMD_PREVIOUS_WEEK_REVIEWS = '%prev_week_rev'
146 | CMD_PREVIOUS_TWO_WEEKS_REVIEWS = '%prev_two_week_rev'
147 | CMD_PREVIOUS_MONTH_REVIEWS = '%prev_month_rev'
148 | CMD_PREVIOUS_YEAR_REVIEWS = '%prev_year_rev'
149 | CMD_FROM_DATE_REVIEWS = '%from_custom_rev'
150 |
151 | CMD_HIGHEST_DAY_REVIEWS = '%highest_day_rev'
152 | CMD_HIGHEST_WEEK_REVIEWS = '%highest_week_rev'
153 | CMD_HIGHEST_MONTH_REVIEWS = '%highest_month_rev'
154 | CMD_HIGHEST_YEAR_REVIEWS = '%highest_year_rev'
155 |
156 | # Misc
157 | CMD_EVAL = '%eval{'
158 |
159 | CMD_PRECISION = r':p'
160 | PRECISION_EXTRA = r'\d*'
161 |
162 | CMD_STATE = r':state'
163 | STATE_EXTRA = r'[\w,]*'
164 |
165 | # Definitions for all macros
166 | DEFINITIONS = {
167 | # Text
168 | CMD_RANGE:
169 | '''label for the currently selected range''',
170 | CMD_DATE:
171 | '''current range's start date using the system's locale''',
172 | CMD_YEAR:
173 | '''current range's year''',
174 | CMD_FULL_DAY:
175 | '''range filter's full start day''',
176 | CMD_DAY:
177 | '''range filter's starting day using a compact format''',
178 | CMD_DAYS:
179 | '''total days the range filter checks against''',
180 | CMD_DATE_FORMATTED:
181 | '''formatted date string using the current range's from-date (e.g. %from_date:strf{"%x"} -> 2022-01-01)''',
182 | CMD_MONTH:
183 | '''range filter's month name using a compact format''',
184 | CMD_FULL_MONTH:
185 | '''range filter's full month name''',
186 |
187 | # Time
188 | CMD_TOTAL_HOURS:
189 | '''total study time''',
190 | CMD_RANGE_HOURS:
191 | '''total study time for the current range''',
192 |
193 | CMD_DAY_HOURS:
194 | '''total study time for the past day''',
195 | CMD_WEEK_HOURS:
196 | '''total study time for the past week''',
197 | CMD_TWO_WEEKS_HOURS:
198 | '''total study time for the past two weeks''',
199 | CMD_MONTH_HOURS:
200 | '''total study time for the past month''',
201 | CMD_YEAR_HOURS:
202 | '''total study time for the past year''',
203 |
204 | CMD_ETA_HOURS:
205 | '''estimated study time for the current card queue''',
206 |
207 | CMD_HIGHEST_DAY_HOURS:
208 | '''highest total study time for all days in the current range''',
209 | CMD_HIGHEST_WEEK_HOURS:
210 | '''highest total study time for all weeks in the current range''',
211 | CMD_HIGHEST_MONTH_HOURS:
212 | '''highest total study time for all months in the current range''',
213 | CMD_HIGHEST_YEAR_HOURS:
214 | '''highest total study time for all years in the current range''',
215 |
216 | # Avg
217 | CMD_CARD_AVERAGE_HOURS:
218 | '''average study time per card for the current range''',
219 | CMD_CARD_AVERAGE_REVIEWS:
220 | '''average reviews per card for the current range''',
221 | CMD_DAY_AVERAGE_HOURS:
222 | '''average study time per day for the current range''',
223 | CMD_DAY_AVERAGE_REVIEWS:
224 | '''average reviews per day for the current range''',
225 |
226 | # Previous Time
227 | CMD_PREVIOUS_RANGE_HOURS:
228 | '''total study time for the previous range''',
229 | CMD_PREVIOUS_DAY_HOURS:
230 | '''total study time for the previous day''',
231 | CMD_PREVIOUS_WEEK_HOURS:
232 | '''total study time for the previous week''',
233 | CMD_PREVIOUS_TWO_WEEKS_HOURS:
234 | '''total study time for the previous two weeks''',
235 | CMD_PREVIOUS_MONTH_HOURS:
236 | '''total study time for the previous month''',
237 | CMD_PREVIOUS_YEAR_HOURS:
238 | '''total study time for the previous year''',
239 |
240 | CMD_FROM_DATE_HOURS:
241 | '''total study time for a custom date range (%from_custom_hrs:: (YYYY-MM-DD))''',
242 |
243 | # Reviews
244 | CMD_TOTAL_REVIEWS:
245 | '''total reviews''',
246 | CMD_RANGE_REVIEWS:
247 | '''total reviews for the current range''',
248 |
249 | CMD_DAY_REVIEWS:
250 | '''total reviews for the past day''',
251 | CMD_WEEK_REVIEWS:
252 | '''total reviews for the past week''',
253 | CMD_TWO_WEEKS_REVIEWS:
254 | '''total reviews for the past two weeks''',
255 | CMD_MONTH_REVIEWS:
256 | '''total reviews for the past month''',
257 | CMD_YEAR_REVIEWS:
258 | '''total reviews for the past year''',
259 |
260 | CMD_PREVIOUS_RANGE_REVIEWS:
261 | '''total reviews for the previous range''',
262 | CMD_PREVIOUS_DAY_REVIEWS:
263 | '''total reviews for the previous day''',
264 | CMD_PREVIOUS_WEEK_REVIEWS:
265 | '''total reviews for the previous week''',
266 | CMD_PREVIOUS_TWO_WEEKS_REVIEWS:
267 | '''total reviews for the previous two weeks''',
268 | CMD_PREVIOUS_MONTH_REVIEWS:
269 | '''total reviews for the previous month''',
270 | CMD_PREVIOUS_YEAR_REVIEWS:
271 | '''total reviews for the previous year''',
272 |
273 | CMD_FROM_DATE_REVIEWS:
274 | '''total reviews for a custom date range (%from_custom_hrs:: (YYYY-MM-DD))''',
275 |
276 | CMD_HIGHEST_DAY_REVIEWS:
277 | '''highest total reviews for all days in the current range''',
278 | CMD_HIGHEST_WEEK_REVIEWS:
279 | '''highest total reviews for all weeks in the current range''',
280 | CMD_HIGHEST_MONTH_REVIEWS:
281 | '''highest total reviews for all months in the current range''',
282 | CMD_HIGHEST_YEAR_REVIEWS:
283 | '''highest total reviews for all years in the current range''',
284 |
285 | # Misc
286 | CMD_EVAL:
287 | '''customized output that accepts any macros, math, or python as input (warning: unsafe implementation)''',
288 |
289 | CMD_PRECISION:
290 | '''filters an output's precision for time-based, decimal macros (%range_hrs:p{<0-4>})''',
291 |
292 | CMD_STATE:
293 | '''filters an output to the current state of a card, separated by commas'''
294 | f''' (%range_hrs:state{{<{NEW}/{LEARN}/{REVIEW}/{SUSPENDED}/{BURIED}>}},'''
295 | f''' e.g. %range_hrs:state{{{LEARN},{REVIEW}}})''',
296 | }
297 |
298 |
299 | class String:
300 | TOTAL = 'Total'
301 | PAST_RANGE = 'Past %range'
302 | HRS = 'hrs'
303 | MIN = 'min'
304 | OPTIONS_ACTION = 'Study &Time Stats Options...'
305 | USE_CALENDAR = 'Use Calendar'
306 | DAYS = 'Days'
307 | WEEK = 'Week'
308 | TWO_WEEKS = '2 Weeks'
309 | MONTH = 'Month'
310 | YEAR = 'Year'
311 | COPY_LINK_ACTION = 'Copy &Link Location'
312 | ENABLE_ACTION = '&Enable'
313 | DISABLE_ACTION = '&Disable'
314 | INSERT = 'Insert'
315 | ERR = 'ERR'
316 | DELETE_CELL = 'Delete view?'
317 |
318 |
319 | class Range:
320 | TOTAL, WEEK, TWO_WEEKS, MONTH, YEAR, CUSTOM = -1, 0, 1, 2, 3, 4
321 | DAYS_IN = {WEEK: 7, TWO_WEEKS: 14, MONTH: 30, YEAR: 365, CUSTOM: 1}
322 | LABEL = {WEEK: String.WEEK, TWO_WEEKS: String.TWO_WEEKS, MONTH: String.MONTH, YEAR: String.YEAR}
323 |
324 |
325 | class Weekday:
326 | SUNDAY, MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY = 0, 1, 2, 3, 4, 5, 6
327 |
328 |
329 | class Direction:
330 | VERTICAL = 'vertical'
331 | HORIZONTAL = 'horizontal'
332 |
333 |
334 | class Color:
335 | # [Light, Dark]
336 | HOVER = ['#040404', '#b0b0b0']
337 | BUTTON_ICON = ['#808080', '#8a8a8a']
338 | TITLE_DEFAULT = ['#000000', '#FFFFFF']
339 | OUTPUT_DEFAULT = ['#76bfb4', '#76bfb4']
340 | BUTTON_ACTIVE = ['#cacaca', '#5b5b5b']
341 |
342 |
343 | class Config:
344 | TOOLBAR_ENABLED = 'Use_Toolbar_Options'
345 | CUSTOM_DAYS = 'Custom_Days'
346 | CUSTOM_TOTAL_TEXT = 'Custom_Total_Text'
347 | CUSTOM_RANGE_TEXT = 'Custom_Range_Text'
348 | CUSTOM_TOTAL_HOURS = 'Custom_Total_Hrs'
349 | CUSTOM_RANGE_HOURS = 'Custom_Range_Hrs'
350 | CUSTOM_HOURS_TEXT = 'Custom_Hrs_Text'
351 | CUSTOM_MIN_TEXT = 'Custom_Min_Text'
352 | BROWSER_ENABLED = 'Browser_Enabled'
353 | OVERVIEW_ENABLED = 'Overview_Enabled'
354 | CONGRATS_ENABLED = 'Congrats_Enabled'
355 | INCLUDE_DELETED = 'Include_Deleted_Reviews'
356 | USE_ROLLOVER = 'Use_Rollover_Hour'
357 | USE_DECIMAL = 'Use_Decimal_Format'
358 | EXCLUDED_DIDS = "Excluded_Deck_IDs"
359 | CELLS_DATA = "cellsData"
360 | WIN_SIZE = 'winSize'
361 | VERSION = 'version'
362 |
363 | TITLE = 'title'
364 | OUTPUT = 'output'
365 | TITLE_COLOR = 'titleColor'
366 | OUTPUT_COLOR = 'outputColor'
367 | DIRECTION = 'direction'
368 | RANGE = 'range'
369 | USE_CALENDAR = 'useCalendar'
370 | WEEK_START = 'weekStart'
371 | DAYS = 'days'
372 | HRS_UNIT = 'hrsUnit'
373 | MIN_UNIT = 'minUnit'
374 | HTML = 'html'
375 | DEFAULT_CELL_DATA = {
376 | TITLE: String.PAST_RANGE,
377 | OUTPUT: Macro.CMD_RANGE_HOURS,
378 | TITLE_COLOR: Color.TITLE_DEFAULT[theme_manager.get_night_mode()],
379 | OUTPUT_COLOR: Color.OUTPUT_DEFAULT[theme_manager.get_night_mode()],
380 | DIRECTION: Direction.VERTICAL,
381 | RANGE: Range.WEEK,
382 | USE_CALENDAR: True,
383 | WEEK_START: Weekday.SUNDAY,
384 | DAYS: 7,
385 | HRS_UNIT: String.HRS,
386 | MIN_UNIT: String.MIN,
387 | HTML: CELL_HTML_SHELL,
388 | }
389 |
390 | DEFAULT_CONFIG = {
391 | TOOLBAR_ENABLED: True,
392 | BROWSER_ENABLED: True,
393 | OVERVIEW_ENABLED: True,
394 | CONGRATS_ENABLED: True,
395 | INCLUDE_DELETED: True,
396 | USE_ROLLOVER: True,
397 | USE_DECIMAL: True,
398 | EXCLUDED_DIDS: [1],
399 | CELLS_DATA: [
400 | {
401 | TITLE: String.TOTAL,
402 | OUTPUT: Macro.CMD_RANGE_HOURS,
403 | TITLE_COLOR: Color.TITLE_DEFAULT[theme_manager.get_night_mode()],
404 | OUTPUT_COLOR: Color.OUTPUT_DEFAULT[theme_manager.get_night_mode()],
405 | DIRECTION: Direction.VERTICAL,
406 | RANGE: Range.TOTAL,
407 | USE_CALENDAR: True,
408 | WEEK_START: Weekday.SUNDAY,
409 | DAYS: 7,
410 | HRS_UNIT: String.HRS,
411 | MIN_UNIT: String.MIN,
412 | HTML: CELL_HTML_SHELL,
413 | },
414 | {
415 | TITLE: String.PAST_RANGE,
416 | OUTPUT: Macro.CMD_RANGE_HOURS,
417 | TITLE_COLOR: Color.TITLE_DEFAULT[theme_manager.get_night_mode()],
418 | OUTPUT_COLOR: Color.OUTPUT_DEFAULT[theme_manager.get_night_mode()],
419 | DIRECTION: Direction.VERTICAL,
420 | RANGE: Range.WEEK,
421 | USE_CALENDAR: True,
422 | WEEK_START: Weekday.SUNDAY,
423 | DAYS: 7,
424 | HRS_UNIT: String.HRS,
425 | MIN_UNIT: String.MIN,
426 | HTML: CELL_HTML_SHELL,
427 | }
428 | ]
429 | }
430 |
--------------------------------------------------------------------------------
/src/toolbar.py:
--------------------------------------------------------------------------------
1 | # MIT License: Copyright (c) 2022-2023 JustKoi (iamjustkoi)
2 | # Full license text available in the "LICENSE" file, packaged with the add-on.
3 |
4 | from aqt import mw
5 | from aqt.qt import QAction
6 |
7 | from .config import TimeStatsConfigManager
8 | from .consts import (
9 | Config,
10 | String,
11 | )
12 | from .options import TimeStatsOptionsDialog
13 |
14 |
15 | def build_toolbar_actions():
16 | refresh_tools_menu_action()
17 | mw.addonManager.setConfigAction(__name__, on_options_called)
18 |
19 |
20 | def refresh_tools_menu_action(__changes=None, __obj=None):
21 | """
22 | Updates the toolbar actions menu with the options shortcut. Expects an Operation Change hook call,
23 | but can also be used as a general update push, too.
24 |
25 | :param __changes: unused OpChanges object
26 | :param __obj: unused options object
27 | """
28 | if TimeStatsConfigManager(mw).config[Config.TOOLBAR_ENABLED]:
29 | options_action = QAction(String.OPTIONS_ACTION, mw)
30 | options_action.triggered.connect(on_options_called)
31 | # Handles edge cases where toolbar action already exists in the tools menu
32 | if options_action.text() not in [action.text() for action in mw.form.menuTools.actions()]:
33 | mw.form.menuTools.addAction(options_action)
34 | else:
35 | for action in mw.form.menuTools.actions():
36 | if action.text() == String.OPTIONS_ACTION:
37 | mw.form.menuTools.removeAction(action)
38 |
39 |
40 | def on_options_called():
41 | """
42 | Initializes and opens the options dialog.
43 | """
44 | dialog = TimeStatsOptionsDialog(TimeStatsConfigManager(mw))
45 | dialog.exec()
46 |
--------------------------------------------------------------------------------