diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index d27e564..5ab7ea9 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -33,6 +33,8 @@ jobs: - name: qmake and nmake run: | + echo $(git rev-parse --short "$GITHUB_SHA") > text\\REVISION.txt + type text\\REVISION.txt qmake theoreticaldiary.pro CONFIG+=release set CL=/MP nmake qmake_all @@ -85,6 +87,8 @@ jobs: - name: qmake and make run: | + echo $(git rev-parse --short "$GITHUB_SHA") > text/REVISION.txt + cat text/REVISION.txt sudo xcode-select -s /Applications/Xcode_12.1.1.app/Contents/Developer qmake QMAKE_CC="/usr/local/opt/llvm/bin/clang" QMAKE_CXX="/usr/local/opt/llvm/bin/clang++" CONFIG+=release QMAKE_LIBS+="-L/usr/local/opt/llvm/lib -L/usr/local/lib" INCLUDEPATH+="-I/usr/local/opt/llvm/include" make -j$(sysctl -n hw.logicalcpu) @@ -129,6 +133,8 @@ jobs: - name: qmake and make run: | + echo $(git rev-parse --short "$GITHUB_SHA") > text/REVISION.txt + cat text/REVISION.txt qmake CONFIG+=release make -j$(nproc) make install INSTALL_ROOT=TheoreticalDiary.AppDir diff --git a/.gitmodules b/.gitmodules index 8b28099..fe09c50 100644 --- a/.gitmodules +++ b/.gitmodules @@ -10,7 +10,4 @@ url = https://github.com/someretical/o2.git [submodule "external-libs/asyncfuture"] path = external-libs/asyncfuture - url = https://github.com/benlau/asyncfuture.git -[submodule "external-libs/phantomstyle"] - path = external-libs/phantomstyle - url = https://github.com/randrew/phantomstyle.git + url = https://github.com/benlau/asyncfuture.git \ No newline at end of file diff --git a/external-libs/phantomstyle b/external-libs/phantomstyle deleted file mode 160000 index 309c97a..0000000 --- a/external-libs/phantomstyle +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 309c97a955f6cdfb1987d1dd04c34d667e4bfce1 diff --git a/fonts/Roboto/Roboto-Black.ttf b/fonts/Roboto/Roboto-Black.ttf deleted file mode 100644 index 689fe5c..0000000 Binary files a/fonts/Roboto/Roboto-Black.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-BlackItalic.ttf b/fonts/Roboto/Roboto-BlackItalic.ttf deleted file mode 100644 index 0b4e0ee..0000000 Binary files a/fonts/Roboto/Roboto-BlackItalic.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-Bold.ttf b/fonts/Roboto/Roboto-Bold.ttf deleted file mode 100644 index d3f01ad..0000000 Binary files a/fonts/Roboto/Roboto-Bold.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-BoldItalic.ttf b/fonts/Roboto/Roboto-BoldItalic.ttf deleted file mode 100644 index 41cc1e7..0000000 Binary files a/fonts/Roboto/Roboto-BoldItalic.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-Italic.ttf b/fonts/Roboto/Roboto-Italic.ttf deleted file mode 100644 index 6a1cee5..0000000 Binary files a/fonts/Roboto/Roboto-Italic.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-Light.ttf b/fonts/Roboto/Roboto-Light.ttf deleted file mode 100644 index 219063a..0000000 Binary files a/fonts/Roboto/Roboto-Light.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-LightItalic.ttf b/fonts/Roboto/Roboto-LightItalic.ttf deleted file mode 100644 index 0e81e87..0000000 Binary files a/fonts/Roboto/Roboto-LightItalic.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-Medium.ttf b/fonts/Roboto/Roboto-Medium.ttf deleted file mode 100644 index 1a7f3b0..0000000 Binary files a/fonts/Roboto/Roboto-Medium.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-MediumItalic.ttf b/fonts/Roboto/Roboto-MediumItalic.ttf deleted file mode 100644 index 0030295..0000000 Binary files a/fonts/Roboto/Roboto-MediumItalic.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-Regular.ttf b/fonts/Roboto/Roboto-Regular.ttf deleted file mode 100644 index 2c97eea..0000000 Binary files a/fonts/Roboto/Roboto-Regular.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-Thin.ttf b/fonts/Roboto/Roboto-Thin.ttf deleted file mode 100644 index b74a4fd..0000000 Binary files a/fonts/Roboto/Roboto-Thin.ttf and /dev/null differ diff --git a/fonts/Roboto/Roboto-ThinItalic.ttf b/fonts/Roboto/Roboto-ThinItalic.ttf deleted file mode 100644 index dd0ddb8..0000000 Binary files a/fonts/Roboto/Roboto-ThinItalic.ttf and /dev/null differ diff --git a/fonts/Roboto/RobotoCondensed-Bold.ttf b/fonts/Roboto/RobotoCondensed-Bold.ttf deleted file mode 100644 index 48dd635..0000000 Binary files a/fonts/Roboto/RobotoCondensed-Bold.ttf and /dev/null differ diff --git a/fonts/Roboto/RobotoCondensed-BoldItalic.ttf b/fonts/Roboto/RobotoCondensed-BoldItalic.ttf deleted file mode 100644 index ad72864..0000000 Binary files a/fonts/Roboto/RobotoCondensed-BoldItalic.ttf and /dev/null differ diff --git a/fonts/Roboto/RobotoCondensed-Italic.ttf b/fonts/Roboto/RobotoCondensed-Italic.ttf deleted file mode 100644 index a232513..0000000 Binary files a/fonts/Roboto/RobotoCondensed-Italic.ttf and /dev/null differ diff --git a/fonts/Roboto/RobotoCondensed-Light.ttf b/fonts/Roboto/RobotoCondensed-Light.ttf deleted file mode 100644 index a6e368d..0000000 Binary files a/fonts/Roboto/RobotoCondensed-Light.ttf and /dev/null differ diff --git a/fonts/Roboto/RobotoCondensed-LightItalic.ttf b/fonts/Roboto/RobotoCondensed-LightItalic.ttf deleted file mode 100644 index 5b2b6ae..0000000 Binary files a/fonts/Roboto/RobotoCondensed-LightItalic.ttf and /dev/null differ diff --git a/fonts/Roboto/RobotoCondensed-Regular.ttf b/fonts/Roboto/RobotoCondensed-Regular.ttf deleted file mode 100644 index 65bf32a..0000000 Binary files a/fonts/Roboto/RobotoCondensed-Regular.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-Bold.ttf b/fonts/RobotoMono/RobotoMono-Bold.ttf deleted file mode 100644 index 900fce6..0000000 Binary files a/fonts/RobotoMono/RobotoMono-Bold.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-BoldItalic.ttf b/fonts/RobotoMono/RobotoMono-BoldItalic.ttf deleted file mode 100644 index 4bfe29a..0000000 Binary files a/fonts/RobotoMono/RobotoMono-BoldItalic.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-ExtraLight.ttf b/fonts/RobotoMono/RobotoMono-ExtraLight.ttf deleted file mode 100644 index d535884..0000000 Binary files a/fonts/RobotoMono/RobotoMono-ExtraLight.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-ExtraLightItalic.ttf b/fonts/RobotoMono/RobotoMono-ExtraLightItalic.ttf deleted file mode 100644 index b28960a..0000000 Binary files a/fonts/RobotoMono/RobotoMono-ExtraLightItalic.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-Italic.ttf b/fonts/RobotoMono/RobotoMono-Italic.ttf deleted file mode 100644 index 4ee4dc4..0000000 Binary files a/fonts/RobotoMono/RobotoMono-Italic.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-Light.ttf b/fonts/RobotoMono/RobotoMono-Light.ttf deleted file mode 100644 index 276af4c..0000000 Binary files a/fonts/RobotoMono/RobotoMono-Light.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-LightItalic.ttf b/fonts/RobotoMono/RobotoMono-LightItalic.ttf deleted file mode 100644 index a2801c2..0000000 Binary files a/fonts/RobotoMono/RobotoMono-LightItalic.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-Medium.ttf b/fonts/RobotoMono/RobotoMono-Medium.ttf deleted file mode 100644 index 8461be7..0000000 Binary files a/fonts/RobotoMono/RobotoMono-Medium.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-MediumItalic.ttf b/fonts/RobotoMono/RobotoMono-MediumItalic.ttf deleted file mode 100644 index a3bfaa1..0000000 Binary files a/fonts/RobotoMono/RobotoMono-MediumItalic.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-Regular.ttf b/fonts/RobotoMono/RobotoMono-Regular.ttf deleted file mode 100644 index 7c4ce36..0000000 Binary files a/fonts/RobotoMono/RobotoMono-Regular.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-SemiBold.ttf b/fonts/RobotoMono/RobotoMono-SemiBold.ttf deleted file mode 100644 index 15ee6c6..0000000 Binary files a/fonts/RobotoMono/RobotoMono-SemiBold.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-SemiBoldItalic.ttf b/fonts/RobotoMono/RobotoMono-SemiBoldItalic.ttf deleted file mode 100644 index 8e21497..0000000 Binary files a/fonts/RobotoMono/RobotoMono-SemiBoldItalic.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-Thin.ttf b/fonts/RobotoMono/RobotoMono-Thin.ttf deleted file mode 100644 index ee8a3fd..0000000 Binary files a/fonts/RobotoMono/RobotoMono-Thin.ttf and /dev/null differ diff --git a/fonts/RobotoMono/RobotoMono-ThinItalic.ttf b/fonts/RobotoMono/RobotoMono-ThinItalic.ttf deleted file mode 100644 index 40b01e4..0000000 Binary files a/fonts/RobotoMono/RobotoMono-ThinItalic.ttf and /dev/null differ diff --git a/fonts/fonts.qrc b/fonts/fonts.qrc deleted file mode 100644 index 28f2627..0000000 --- a/fonts/fonts.qrc +++ /dev/null @@ -1,36 +0,0 @@ - - - Roboto/Roboto-Black.ttf - Roboto/Roboto-BlackItalic.ttf - Roboto/Roboto-Bold.ttf - Roboto/Roboto-BoldItalic.ttf - Roboto/Roboto-Italic.ttf - Roboto/Roboto-Light.ttf - Roboto/Roboto-LightItalic.ttf - Roboto/Roboto-Medium.ttf - Roboto/Roboto-MediumItalic.ttf - Roboto/Roboto-Regular.ttf - Roboto/Roboto-Thin.ttf - Roboto/Roboto-ThinItalic.ttf - Roboto/RobotoCondensed-Bold.ttf - Roboto/RobotoCondensed-BoldItalic.ttf - Roboto/RobotoCondensed-Italic.ttf - Roboto/RobotoCondensed-Light.ttf - Roboto/RobotoCondensed-LightItalic.ttf - Roboto/RobotoCondensed-Regular.ttf - RobotoMono/RobotoMono-Bold.ttf - RobotoMono/RobotoMono-BoldItalic.ttf - RobotoMono/RobotoMono-ExtraLight.ttf - RobotoMono/RobotoMono-ExtraLightItalic.ttf - RobotoMono/RobotoMono-Italic.ttf - RobotoMono/RobotoMono-Light.ttf - RobotoMono/RobotoMono-LightItalic.ttf - RobotoMono/RobotoMono-Medium.ttf - RobotoMono/RobotoMono-MediumItalic.ttf - RobotoMono/RobotoMono-Regular.ttf - RobotoMono/RobotoMono-SemiBold.ttf - RobotoMono/RobotoMono-SemiBoldItalic.ttf - RobotoMono/RobotoMono-Thin.ttf - RobotoMono/RobotoMono-ThinItalic.ttf - - diff --git a/images/images.qrc b/images/images.qrc index 4cb81ca..20f6550 100644 --- a/images/images.qrc +++ b/images/images.qrc @@ -2,158 +2,13 @@ linux_icons/256x256/theoreticaldiary.png linux_icons/scalable/theoreticaldiary.svg - themes/dark/disabled/base.svg - themes/dark/disabled/branch-closed.svg - themes/dark/disabled/branch-end.svg - themes/dark/disabled/branch-more.svg - themes/dark/disabled/branch-open.svg - themes/dark/disabled/checkbox_checked.svg - themes/dark/disabled/checkbox_checked_invert.svg - themes/dark/disabled/checkbox_indeterminate.svg - themes/dark/disabled/checkbox_indeterminate_invert.svg - themes/dark/disabled/checkbox_unchecked.svg - themes/dark/disabled/checkbox_unchecked_invert.svg - themes/dark/disabled/checklist.svg - themes/dark/disabled/checklist_indeterminate.svg - themes/dark/disabled/checklist_indeterminate_invert.svg - themes/dark/disabled/checklist_invert.svg - themes/dark/disabled/close.svg - themes/dark/disabled/downarrow.svg - themes/dark/disabled/downarrow2.svg - themes/dark/disabled/float.svg - themes/dark/disabled/leftarrow.svg - themes/dark/disabled/leftarrow2.svg - themes/dark/disabled/radiobutton_checked.svg - themes/dark/disabled/radiobutton_unchecked.svg - themes/dark/disabled/rightarrow.svg - themes/dark/disabled/rightarrow2.svg - themes/dark/disabled/sizegrip.svg - themes/dark/disabled/slider.svg - themes/dark/disabled/splitter-horizontal.svg - themes/dark/disabled/splitter-vertical.svg - themes/dark/disabled/tab_close.svg - themes/dark/disabled/toolbar-handle-horizontal.svg - themes/dark/disabled/toolbar-handle-vertical.svg - themes/dark/disabled/uparrow.svg - themes/dark/disabled/uparrow2.svg - themes/dark/disabled/vline.svg - themes/dark/primary/base.svg - themes/dark/primary/branch-closed.svg - themes/dark/primary/branch-end.svg - themes/dark/primary/branch-more.svg - themes/dark/primary/branch-open.svg - themes/dark/primary/checkbox_checked.svg - themes/dark/primary/checkbox_checked_invert.svg - themes/dark/primary/checkbox_indeterminate.svg - themes/dark/primary/checkbox_indeterminate_invert.svg - themes/dark/primary/checkbox_unchecked.svg - themes/dark/primary/checkbox_unchecked_invert.svg - themes/dark/primary/checklist.svg - themes/dark/primary/checklist_indeterminate.svg - themes/dark/primary/checklist_indeterminate_invert.svg - themes/dark/primary/checklist_invert.svg - themes/dark/primary/close.svg - themes/dark/primary/downarrow.svg - themes/dark/primary/downarrow2.svg - themes/dark/primary/float.svg - themes/dark/primary/leftarrow.svg - themes/dark/primary/leftarrow2.svg - themes/dark/primary/radiobutton_checked.svg - themes/dark/primary/radiobutton_unchecked.svg - themes/dark/primary/rightarrow.svg - themes/dark/primary/rightarrow2.svg - themes/dark/primary/sizegrip.svg - themes/dark/primary/slider.svg - themes/dark/primary/splitter-horizontal.svg - themes/dark/primary/splitter-vertical.svg - themes/dark/primary/tab_close.svg - themes/dark/primary/toolbar-handle-horizontal.svg - themes/dark/primary/toolbar-handle-vertical.svg - themes/dark/primary/uparrow.svg - themes/dark/primary/uparrow2.svg - themes/dark/primary/vline.svg - themes/global/star_black.svg - themes/global/star_white.svg windows_icons/icon.ico - themes/global/small_star_white.svg - themes/global/small_star_black.svg - themes/light/passwordlineedit/eye_on.svg - themes/light/passwordlineedit/eye_off.svg - themes/dark/passwordlineedit/eye_on.svg - themes/dark/passwordlineedit/eye_off.svg - themes/light/disabled/base.svg - themes/light/disabled/branch-closed.svg - themes/light/disabled/branch-end.svg - themes/light/disabled/branch-more.svg - themes/light/disabled/branch-open.svg - themes/light/disabled/checkbox_checked.svg - themes/light/disabled/checkbox_checked_invert.svg - themes/light/disabled/checkbox_indeterminate.svg - themes/light/disabled/checkbox_indeterminate_invert.svg - themes/light/disabled/checkbox_unchecked.svg - themes/light/disabled/checkbox_unchecked_invert.svg - themes/light/disabled/checklist.svg - themes/light/disabled/checklist_indeterminate.svg - themes/light/disabled/checklist_indeterminate_invert.svg - themes/light/disabled/checklist_invert.svg - themes/light/disabled/close.svg - themes/light/disabled/downarrow.svg - themes/light/disabled/downarrow2.svg - themes/light/disabled/float.svg - themes/light/disabled/leftarrow.svg - themes/light/disabled/leftarrow2.svg - themes/light/disabled/radiobutton_checked.svg - themes/light/disabled/radiobutton_checked_invert.svg - themes/light/disabled/radiobutton_unchecked.svg - themes/light/disabled/radiobutton_unchecked_invert.svg - themes/light/disabled/rightarrow.svg - themes/light/disabled/rightarrow2.svg - themes/light/disabled/sizegrip.svg - themes/light/disabled/slider.svg - themes/light/disabled/splitter-horizontal.svg - themes/light/disabled/splitter-vertical.svg - themes/light/disabled/tab_close.svg - themes/light/disabled/toolbar-handle-horizontal.svg - themes/light/disabled/toolbar-handle-vertical.svg - themes/light/disabled/uparrow.svg - themes/light/disabled/uparrow2.svg - themes/light/disabled/vline.svg - themes/light/primary/base.svg - themes/light/primary/branch-closed.svg - themes/light/primary/branch-end.svg - themes/light/primary/branch-more.svg - themes/light/primary/branch-open.svg - themes/light/primary/checkbox_checked.svg - themes/light/primary/checkbox_checked_invert.svg - themes/light/primary/checkbox_indeterminate.svg - themes/light/primary/checkbox_indeterminate_invert.svg - themes/light/primary/checkbox_unchecked.svg - themes/light/primary/checkbox_unchecked_invert.svg - themes/light/primary/checklist.svg - themes/light/primary/checklist_indeterminate.svg - themes/light/primary/checklist_indeterminate_invert.svg - themes/light/primary/checklist_invert.svg - themes/light/primary/close.svg - themes/light/primary/downarrow.svg - themes/light/primary/downarrow2.svg - themes/light/primary/float.svg - themes/light/primary/leftarrow.svg - themes/light/primary/leftarrow2.svg - themes/light/primary/radiobutton_checked.svg - themes/light/primary/radiobutton_checked_invert.svg - themes/light/primary/radiobutton_unchecked.svg - themes/light/primary/radiobutton_unchecked_invert.svg - themes/light/primary/rightarrow.svg - themes/light/primary/rightarrow2.svg - themes/light/primary/sizegrip.svg - themes/light/primary/slider.svg - themes/light/primary/splitter-horizontal.svg - themes/light/primary/splitter-vertical.svg - themes/light/primary/tab_close.svg - themes/light/primary/toolbar-handle-horizontal.svg - themes/light/primary/toolbar-handle-vertical.svg - themes/light/primary/uparrow.svg - themes/light/primary/uparrow2.svg - themes/light/primary/vline.svg + osx_icons/icons.icns + themes/dark/eye_off.svg + themes/dark/eye_on.svg + themes/dark/star.svg + themes/light/eye_off.svg + themes/light/eye_on.svg + themes/light/star.svg diff --git a/images/themes/dark/disabled/base.svg b/images/themes/dark/disabled/base.svg deleted file mode 100644 index 6a78c16..0000000 --- a/images/themes/dark/disabled/base.svg +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/branch-closed.svg b/images/themes/dark/disabled/branch-closed.svg deleted file mode 100644 index 9bb6044..0000000 --- a/images/themes/dark/disabled/branch-closed.svg +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/branch-end.svg b/images/themes/dark/disabled/branch-end.svg deleted file mode 100644 index 87f1f21..0000000 --- a/images/themes/dark/disabled/branch-end.svg +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/branch-more.svg b/images/themes/dark/disabled/branch-more.svg deleted file mode 100644 index d450b0e..0000000 --- a/images/themes/dark/disabled/branch-more.svg +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/branch-open.svg b/images/themes/dark/disabled/branch-open.svg deleted file mode 100644 index 7e63923..0000000 --- a/images/themes/dark/disabled/branch-open.svg +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/checkbox_checked.svg b/images/themes/dark/disabled/checkbox_checked.svg deleted file mode 100644 index da1f539..0000000 --- a/images/themes/dark/disabled/checkbox_checked.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/checkbox_checked_invert.svg b/images/themes/dark/disabled/checkbox_checked_invert.svg deleted file mode 100644 index f55a847..0000000 --- a/images/themes/dark/disabled/checkbox_checked_invert.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/checkbox_indeterminate.svg b/images/themes/dark/disabled/checkbox_indeterminate.svg deleted file mode 100644 index 4c4e600..0000000 --- a/images/themes/dark/disabled/checkbox_indeterminate.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/checkbox_indeterminate_invert.svg b/images/themes/dark/disabled/checkbox_indeterminate_invert.svg deleted file mode 100644 index 824e0fe..0000000 --- a/images/themes/dark/disabled/checkbox_indeterminate_invert.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/checkbox_unchecked.svg b/images/themes/dark/disabled/checkbox_unchecked.svg deleted file mode 100644 index 50dc034..0000000 --- a/images/themes/dark/disabled/checkbox_unchecked.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/checkbox_unchecked_invert.svg b/images/themes/dark/disabled/checkbox_unchecked_invert.svg deleted file mode 100644 index ef8777f..0000000 --- a/images/themes/dark/disabled/checkbox_unchecked_invert.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/checklist.svg b/images/themes/dark/disabled/checklist.svg deleted file mode 100644 index 9237832..0000000 --- a/images/themes/dark/disabled/checklist.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/checklist_indeterminate.svg b/images/themes/dark/disabled/checklist_indeterminate.svg deleted file mode 100644 index 616d813..0000000 --- a/images/themes/dark/disabled/checklist_indeterminate.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/checklist_indeterminate_invert.svg b/images/themes/dark/disabled/checklist_indeterminate_invert.svg deleted file mode 100644 index 09b8573..0000000 --- a/images/themes/dark/disabled/checklist_indeterminate_invert.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/checklist_invert.svg b/images/themes/dark/disabled/checklist_invert.svg deleted file mode 100644 index 35e996a..0000000 --- a/images/themes/dark/disabled/checklist_invert.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/close.svg b/images/themes/dark/disabled/close.svg deleted file mode 100644 index 5db1bfe..0000000 --- a/images/themes/dark/disabled/close.svg +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/downarrow.svg b/images/themes/dark/disabled/downarrow.svg deleted file mode 100644 index 1ad458e..0000000 --- a/images/themes/dark/disabled/downarrow.svg +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/downarrow2.svg b/images/themes/dark/disabled/downarrow2.svg deleted file mode 100644 index b2630ca..0000000 --- a/images/themes/dark/disabled/downarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/dark/disabled/float.svg b/images/themes/dark/disabled/float.svg deleted file mode 100644 index 375216a..0000000 --- a/images/themes/dark/disabled/float.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/leftarrow.svg b/images/themes/dark/disabled/leftarrow.svg deleted file mode 100644 index 2ccdb33..0000000 --- a/images/themes/dark/disabled/leftarrow.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/leftarrow2.svg b/images/themes/dark/disabled/leftarrow2.svg deleted file mode 100644 index a3632af..0000000 --- a/images/themes/dark/disabled/leftarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/dark/disabled/radiobutton_checked.svg b/images/themes/dark/disabled/radiobutton_checked.svg deleted file mode 100644 index 98df5c2..0000000 --- a/images/themes/dark/disabled/radiobutton_checked.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/radiobutton_unchecked.svg b/images/themes/dark/disabled/radiobutton_unchecked.svg deleted file mode 100644 index c514898..0000000 --- a/images/themes/dark/disabled/radiobutton_unchecked.svg +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/rightarrow.svg b/images/themes/dark/disabled/rightarrow.svg deleted file mode 100644 index d55ef7a..0000000 --- a/images/themes/dark/disabled/rightarrow.svg +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/rightarrow2.svg b/images/themes/dark/disabled/rightarrow2.svg deleted file mode 100644 index 626eef4..0000000 --- a/images/themes/dark/disabled/rightarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/dark/disabled/sizegrip.svg b/images/themes/dark/disabled/sizegrip.svg deleted file mode 100644 index f7aa315..0000000 --- a/images/themes/dark/disabled/sizegrip.svg +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/slider.svg b/images/themes/dark/disabled/slider.svg deleted file mode 100644 index f79582e..0000000 --- a/images/themes/dark/disabled/slider.svg +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/splitter-horizontal.svg b/images/themes/dark/disabled/splitter-horizontal.svg deleted file mode 100644 index f9344f6..0000000 --- a/images/themes/dark/disabled/splitter-horizontal.svg +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/splitter-vertical.svg b/images/themes/dark/disabled/splitter-vertical.svg deleted file mode 100644 index 3185121..0000000 --- a/images/themes/dark/disabled/splitter-vertical.svg +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/tab_close.svg b/images/themes/dark/disabled/tab_close.svg deleted file mode 100644 index 086ce9f..0000000 --- a/images/themes/dark/disabled/tab_close.svg +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/toolbar-handle-horizontal.svg b/images/themes/dark/disabled/toolbar-handle-horizontal.svg deleted file mode 100644 index f010f3e..0000000 --- a/images/themes/dark/disabled/toolbar-handle-horizontal.svg +++ /dev/null @@ -1,255 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/toolbar-handle-vertical.svg b/images/themes/dark/disabled/toolbar-handle-vertical.svg deleted file mode 100644 index a7bf02e..0000000 --- a/images/themes/dark/disabled/toolbar-handle-vertical.svg +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/uparrow.svg b/images/themes/dark/disabled/uparrow.svg deleted file mode 100644 index ee36753..0000000 --- a/images/themes/dark/disabled/uparrow.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/disabled/uparrow2.svg b/images/themes/dark/disabled/uparrow2.svg deleted file mode 100644 index dce9947..0000000 --- a/images/themes/dark/disabled/uparrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/dark/disabled/vline.svg b/images/themes/dark/disabled/vline.svg deleted file mode 100644 index f50c1cc..0000000 --- a/images/themes/dark/disabled/vline.svg +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/passwordlineedit/eye_off.svg b/images/themes/dark/eye_off.svg similarity index 100% rename from images/themes/dark/passwordlineedit/eye_off.svg rename to images/themes/dark/eye_off.svg diff --git a/images/themes/dark/passwordlineedit/eye_on.svg b/images/themes/dark/eye_on.svg similarity index 100% rename from images/themes/dark/passwordlineedit/eye_on.svg rename to images/themes/dark/eye_on.svg diff --git a/images/themes/dark/primary/base.svg b/images/themes/dark/primary/base.svg deleted file mode 100644 index 6a78c16..0000000 --- a/images/themes/dark/primary/base.svg +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/branch-closed.svg b/images/themes/dark/primary/branch-closed.svg deleted file mode 100644 index ee8a26d..0000000 --- a/images/themes/dark/primary/branch-closed.svg +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/branch-end.svg b/images/themes/dark/primary/branch-end.svg deleted file mode 100644 index b4e6230..0000000 --- a/images/themes/dark/primary/branch-end.svg +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/branch-more.svg b/images/themes/dark/primary/branch-more.svg deleted file mode 100644 index 41c5f9f..0000000 --- a/images/themes/dark/primary/branch-more.svg +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/branch-open.svg b/images/themes/dark/primary/branch-open.svg deleted file mode 100644 index 7cef9a6..0000000 --- a/images/themes/dark/primary/branch-open.svg +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/checkbox_checked.svg b/images/themes/dark/primary/checkbox_checked.svg deleted file mode 100644 index 2fa786b..0000000 --- a/images/themes/dark/primary/checkbox_checked.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/checkbox_checked_invert.svg b/images/themes/dark/primary/checkbox_checked_invert.svg deleted file mode 100644 index 5cdf79a..0000000 --- a/images/themes/dark/primary/checkbox_checked_invert.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/checkbox_indeterminate.svg b/images/themes/dark/primary/checkbox_indeterminate.svg deleted file mode 100644 index 6519e7a..0000000 --- a/images/themes/dark/primary/checkbox_indeterminate.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/checkbox_indeterminate_invert.svg b/images/themes/dark/primary/checkbox_indeterminate_invert.svg deleted file mode 100644 index c836424..0000000 --- a/images/themes/dark/primary/checkbox_indeterminate_invert.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/checkbox_unchecked.svg b/images/themes/dark/primary/checkbox_unchecked.svg deleted file mode 100644 index a1c14fd..0000000 --- a/images/themes/dark/primary/checkbox_unchecked.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/checkbox_unchecked_invert.svg b/images/themes/dark/primary/checkbox_unchecked_invert.svg deleted file mode 100644 index 9e74467..0000000 --- a/images/themes/dark/primary/checkbox_unchecked_invert.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/checklist.svg b/images/themes/dark/primary/checklist.svg deleted file mode 100644 index 087852c..0000000 --- a/images/themes/dark/primary/checklist.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/checklist_indeterminate.svg b/images/themes/dark/primary/checklist_indeterminate.svg deleted file mode 100644 index 1588414..0000000 --- a/images/themes/dark/primary/checklist_indeterminate.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/checklist_indeterminate_invert.svg b/images/themes/dark/primary/checklist_indeterminate_invert.svg deleted file mode 100644 index 09b8573..0000000 --- a/images/themes/dark/primary/checklist_indeterminate_invert.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/checklist_invert.svg b/images/themes/dark/primary/checklist_invert.svg deleted file mode 100644 index 35e996a..0000000 --- a/images/themes/dark/primary/checklist_invert.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/close.svg b/images/themes/dark/primary/close.svg deleted file mode 100644 index 51c25d4..0000000 --- a/images/themes/dark/primary/close.svg +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/downarrow.svg b/images/themes/dark/primary/downarrow.svg deleted file mode 100644 index 9cda7fa..0000000 --- a/images/themes/dark/primary/downarrow.svg +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/downarrow2.svg b/images/themes/dark/primary/downarrow2.svg deleted file mode 100644 index b21208a..0000000 --- a/images/themes/dark/primary/downarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/dark/primary/float.svg b/images/themes/dark/primary/float.svg deleted file mode 100644 index a94995f..0000000 --- a/images/themes/dark/primary/float.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/leftarrow.svg b/images/themes/dark/primary/leftarrow.svg deleted file mode 100644 index aa38ce7..0000000 --- a/images/themes/dark/primary/leftarrow.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/leftarrow2.svg b/images/themes/dark/primary/leftarrow2.svg deleted file mode 100644 index d195308..0000000 --- a/images/themes/dark/primary/leftarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/dark/primary/radiobutton_checked.svg b/images/themes/dark/primary/radiobutton_checked.svg deleted file mode 100644 index 51f116a..0000000 --- a/images/themes/dark/primary/radiobutton_checked.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/radiobutton_unchecked.svg b/images/themes/dark/primary/radiobutton_unchecked.svg deleted file mode 100644 index fbc97bb..0000000 --- a/images/themes/dark/primary/radiobutton_unchecked.svg +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/rightarrow.svg b/images/themes/dark/primary/rightarrow.svg deleted file mode 100644 index 7f78cab..0000000 --- a/images/themes/dark/primary/rightarrow.svg +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/rightarrow2.svg b/images/themes/dark/primary/rightarrow2.svg deleted file mode 100644 index 4e4c0b5..0000000 --- a/images/themes/dark/primary/rightarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/dark/primary/sizegrip.svg b/images/themes/dark/primary/sizegrip.svg deleted file mode 100644 index cf08dd5..0000000 --- a/images/themes/dark/primary/sizegrip.svg +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/slider.svg b/images/themes/dark/primary/slider.svg deleted file mode 100644 index 0a58946..0000000 --- a/images/themes/dark/primary/slider.svg +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/splitter-horizontal.svg b/images/themes/dark/primary/splitter-horizontal.svg deleted file mode 100644 index 3ec2fcb..0000000 --- a/images/themes/dark/primary/splitter-horizontal.svg +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/splitter-vertical.svg b/images/themes/dark/primary/splitter-vertical.svg deleted file mode 100644 index c7476ae..0000000 --- a/images/themes/dark/primary/splitter-vertical.svg +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/tab_close.svg b/images/themes/dark/primary/tab_close.svg deleted file mode 100644 index 4ee3a05..0000000 --- a/images/themes/dark/primary/tab_close.svg +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/toolbar-handle-horizontal.svg b/images/themes/dark/primary/toolbar-handle-horizontal.svg deleted file mode 100644 index f0e986a..0000000 --- a/images/themes/dark/primary/toolbar-handle-horizontal.svg +++ /dev/null @@ -1,255 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/toolbar-handle-vertical.svg b/images/themes/dark/primary/toolbar-handle-vertical.svg deleted file mode 100644 index 7145f8b..0000000 --- a/images/themes/dark/primary/toolbar-handle-vertical.svg +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/uparrow.svg b/images/themes/dark/primary/uparrow.svg deleted file mode 100644 index bb0bbf9..0000000 --- a/images/themes/dark/primary/uparrow.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/primary/uparrow2.svg b/images/themes/dark/primary/uparrow2.svg deleted file mode 100644 index ced2a29..0000000 --- a/images/themes/dark/primary/uparrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/dark/primary/vline.svg b/images/themes/dark/primary/vline.svg deleted file mode 100644 index 04d24b0..0000000 --- a/images/themes/dark/primary/vline.svg +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/dark/star.svg b/images/themes/dark/star.svg new file mode 100644 index 0000000..4e6ed3a --- /dev/null +++ b/images/themes/dark/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/images/themes/global/small_star_black.svg b/images/themes/global/small_star_black.svg deleted file mode 100644 index e8c3c39..0000000 --- a/images/themes/global/small_star_black.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - diff --git a/images/themes/global/small_star_white.svg b/images/themes/global/small_star_white.svg deleted file mode 100644 index 319269c..0000000 --- a/images/themes/global/small_star_white.svg +++ /dev/null @@ -1,49 +0,0 @@ - - - - - - - - diff --git a/images/themes/global/star_black.svg b/images/themes/global/star_black.svg deleted file mode 100644 index 0d063a1..0000000 --- a/images/themes/global/star_black.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - diff --git a/images/themes/global/star_white.svg b/images/themes/global/star_white.svg deleted file mode 100644 index ab24766..0000000 --- a/images/themes/global/star_white.svg +++ /dev/null @@ -1,48 +0,0 @@ - - - - - - - - diff --git a/images/themes/light/disabled/base.svg b/images/themes/light/disabled/base.svg deleted file mode 100644 index 6a78c16..0000000 --- a/images/themes/light/disabled/base.svg +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/branch-closed.svg b/images/themes/light/disabled/branch-closed.svg deleted file mode 100644 index 18896ca..0000000 --- a/images/themes/light/disabled/branch-closed.svg +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/branch-end.svg b/images/themes/light/disabled/branch-end.svg deleted file mode 100644 index e4cf937..0000000 --- a/images/themes/light/disabled/branch-end.svg +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/branch-more.svg b/images/themes/light/disabled/branch-more.svg deleted file mode 100644 index 59056a0..0000000 --- a/images/themes/light/disabled/branch-more.svg +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/branch-open.svg b/images/themes/light/disabled/branch-open.svg deleted file mode 100644 index 1f0f2e9..0000000 --- a/images/themes/light/disabled/branch-open.svg +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/checkbox_checked.svg b/images/themes/light/disabled/checkbox_checked.svg deleted file mode 100644 index 5afbb67..0000000 --- a/images/themes/light/disabled/checkbox_checked.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/checkbox_checked_invert.svg b/images/themes/light/disabled/checkbox_checked_invert.svg deleted file mode 100644 index e84fc7f..0000000 --- a/images/themes/light/disabled/checkbox_checked_invert.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/checkbox_indeterminate.svg b/images/themes/light/disabled/checkbox_indeterminate.svg deleted file mode 100644 index 7ed4f7e..0000000 --- a/images/themes/light/disabled/checkbox_indeterminate.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/checkbox_indeterminate_invert.svg b/images/themes/light/disabled/checkbox_indeterminate_invert.svg deleted file mode 100644 index 62a1b52..0000000 --- a/images/themes/light/disabled/checkbox_indeterminate_invert.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/checkbox_unchecked.svg b/images/themes/light/disabled/checkbox_unchecked.svg deleted file mode 100644 index 1e49fdd..0000000 --- a/images/themes/light/disabled/checkbox_unchecked.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/checkbox_unchecked_invert.svg b/images/themes/light/disabled/checkbox_unchecked_invert.svg deleted file mode 100644 index f198afd..0000000 --- a/images/themes/light/disabled/checkbox_unchecked_invert.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/checklist.svg b/images/themes/light/disabled/checklist.svg deleted file mode 100644 index a171475..0000000 --- a/images/themes/light/disabled/checklist.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/checklist_indeterminate.svg b/images/themes/light/disabled/checklist_indeterminate.svg deleted file mode 100644 index d126ba1..0000000 --- a/images/themes/light/disabled/checklist_indeterminate.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/checklist_indeterminate_invert.svg b/images/themes/light/disabled/checklist_indeterminate_invert.svg deleted file mode 100644 index 56a5197..0000000 --- a/images/themes/light/disabled/checklist_indeterminate_invert.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/checklist_invert.svg b/images/themes/light/disabled/checklist_invert.svg deleted file mode 100644 index bfff96f..0000000 --- a/images/themes/light/disabled/checklist_invert.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/close.svg b/images/themes/light/disabled/close.svg deleted file mode 100644 index 97100fa..0000000 --- a/images/themes/light/disabled/close.svg +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/downarrow.svg b/images/themes/light/disabled/downarrow.svg deleted file mode 100644 index 753c423..0000000 --- a/images/themes/light/disabled/downarrow.svg +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/downarrow2.svg b/images/themes/light/disabled/downarrow2.svg deleted file mode 100644 index 093f732..0000000 --- a/images/themes/light/disabled/downarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/light/disabled/float.svg b/images/themes/light/disabled/float.svg deleted file mode 100644 index 47a4bdf..0000000 --- a/images/themes/light/disabled/float.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/leftarrow.svg b/images/themes/light/disabled/leftarrow.svg deleted file mode 100644 index 1235642..0000000 --- a/images/themes/light/disabled/leftarrow.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/leftarrow2.svg b/images/themes/light/disabled/leftarrow2.svg deleted file mode 100644 index 8c463dd..0000000 --- a/images/themes/light/disabled/leftarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/light/disabled/radiobutton_checked.svg b/images/themes/light/disabled/radiobutton_checked.svg deleted file mode 100644 index 2055b2b..0000000 --- a/images/themes/light/disabled/radiobutton_checked.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/radiobutton_checked_invert.svg b/images/themes/light/disabled/radiobutton_checked_invert.svg deleted file mode 100644 index 6268346..0000000 --- a/images/themes/light/disabled/radiobutton_checked_invert.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/radiobutton_unchecked.svg b/images/themes/light/disabled/radiobutton_unchecked.svg deleted file mode 100644 index 73d0c90..0000000 --- a/images/themes/light/disabled/radiobutton_unchecked.svg +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/radiobutton_unchecked_invert.svg b/images/themes/light/disabled/radiobutton_unchecked_invert.svg deleted file mode 100644 index 45409c0..0000000 --- a/images/themes/light/disabled/radiobutton_unchecked_invert.svg +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/rightarrow.svg b/images/themes/light/disabled/rightarrow.svg deleted file mode 100644 index 57c1bcd..0000000 --- a/images/themes/light/disabled/rightarrow.svg +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/rightarrow2.svg b/images/themes/light/disabled/rightarrow2.svg deleted file mode 100644 index 54d1b60..0000000 --- a/images/themes/light/disabled/rightarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/light/disabled/sizegrip.svg b/images/themes/light/disabled/sizegrip.svg deleted file mode 100644 index ed3aad5..0000000 --- a/images/themes/light/disabled/sizegrip.svg +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/slider.svg b/images/themes/light/disabled/slider.svg deleted file mode 100644 index 13d319a..0000000 --- a/images/themes/light/disabled/slider.svg +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/splitter-horizontal.svg b/images/themes/light/disabled/splitter-horizontal.svg deleted file mode 100644 index dba2984..0000000 --- a/images/themes/light/disabled/splitter-horizontal.svg +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/splitter-vertical.svg b/images/themes/light/disabled/splitter-vertical.svg deleted file mode 100644 index 6f74035..0000000 --- a/images/themes/light/disabled/splitter-vertical.svg +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/tab_close.svg b/images/themes/light/disabled/tab_close.svg deleted file mode 100644 index bcaf667..0000000 --- a/images/themes/light/disabled/tab_close.svg +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/toolbar-handle-horizontal.svg b/images/themes/light/disabled/toolbar-handle-horizontal.svg deleted file mode 100644 index cf10252..0000000 --- a/images/themes/light/disabled/toolbar-handle-horizontal.svg +++ /dev/null @@ -1,255 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/toolbar-handle-vertical.svg b/images/themes/light/disabled/toolbar-handle-vertical.svg deleted file mode 100644 index 9dc64cb..0000000 --- a/images/themes/light/disabled/toolbar-handle-vertical.svg +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/uparrow.svg b/images/themes/light/disabled/uparrow.svg deleted file mode 100644 index 303a817..0000000 --- a/images/themes/light/disabled/uparrow.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/disabled/uparrow2.svg b/images/themes/light/disabled/uparrow2.svg deleted file mode 100644 index 10e4597..0000000 --- a/images/themes/light/disabled/uparrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/light/disabled/vline.svg b/images/themes/light/disabled/vline.svg deleted file mode 100644 index 5b7d609..0000000 --- a/images/themes/light/disabled/vline.svg +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/passwordlineedit/eye_off.svg b/images/themes/light/eye_off.svg similarity index 100% rename from images/themes/light/passwordlineedit/eye_off.svg rename to images/themes/light/eye_off.svg diff --git a/images/themes/light/passwordlineedit/eye_on.svg b/images/themes/light/eye_on.svg similarity index 100% rename from images/themes/light/passwordlineedit/eye_on.svg rename to images/themes/light/eye_on.svg diff --git a/images/themes/light/primary/base.svg b/images/themes/light/primary/base.svg deleted file mode 100644 index 6a78c16..0000000 --- a/images/themes/light/primary/base.svg +++ /dev/null @@ -1,175 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/branch-closed.svg b/images/themes/light/primary/branch-closed.svg deleted file mode 100644 index ce73577..0000000 --- a/images/themes/light/primary/branch-closed.svg +++ /dev/null @@ -1,219 +0,0 @@ - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/branch-end.svg b/images/themes/light/primary/branch-end.svg deleted file mode 100644 index 2c34f69..0000000 --- a/images/themes/light/primary/branch-end.svg +++ /dev/null @@ -1,197 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/branch-more.svg b/images/themes/light/primary/branch-more.svg deleted file mode 100644 index 7d5c69a..0000000 --- a/images/themes/light/primary/branch-more.svg +++ /dev/null @@ -1,203 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/branch-open.svg b/images/themes/light/primary/branch-open.svg deleted file mode 100644 index b24518d..0000000 --- a/images/themes/light/primary/branch-open.svg +++ /dev/null @@ -1,230 +0,0 @@ - - - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/checkbox_checked.svg b/images/themes/light/primary/checkbox_checked.svg deleted file mode 100644 index 608c4ac..0000000 --- a/images/themes/light/primary/checkbox_checked.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/checkbox_checked_invert.svg b/images/themes/light/primary/checkbox_checked_invert.svg deleted file mode 100644 index cd3b20c..0000000 --- a/images/themes/light/primary/checkbox_checked_invert.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/checkbox_indeterminate.svg b/images/themes/light/primary/checkbox_indeterminate.svg deleted file mode 100644 index 1965324..0000000 --- a/images/themes/light/primary/checkbox_indeterminate.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/checkbox_indeterminate_invert.svg b/images/themes/light/primary/checkbox_indeterminate_invert.svg deleted file mode 100644 index 21e5300..0000000 --- a/images/themes/light/primary/checkbox_indeterminate_invert.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/checkbox_unchecked.svg b/images/themes/light/primary/checkbox_unchecked.svg deleted file mode 100644 index 670dd67..0000000 --- a/images/themes/light/primary/checkbox_unchecked.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/checkbox_unchecked_invert.svg b/images/themes/light/primary/checkbox_unchecked_invert.svg deleted file mode 100644 index 2e9a8ee..0000000 --- a/images/themes/light/primary/checkbox_unchecked_invert.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/checklist.svg b/images/themes/light/primary/checklist.svg deleted file mode 100644 index 9cf2f22..0000000 --- a/images/themes/light/primary/checklist.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/checklist_indeterminate.svg b/images/themes/light/primary/checklist_indeterminate.svg deleted file mode 100644 index c349cf8..0000000 --- a/images/themes/light/primary/checklist_indeterminate.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/checklist_indeterminate_invert.svg b/images/themes/light/primary/checklist_indeterminate_invert.svg deleted file mode 100644 index 56a5197..0000000 --- a/images/themes/light/primary/checklist_indeterminate_invert.svg +++ /dev/null @@ -1,188 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/checklist_invert.svg b/images/themes/light/primary/checklist_invert.svg deleted file mode 100644 index bfff96f..0000000 --- a/images/themes/light/primary/checklist_invert.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/close.svg b/images/themes/light/primary/close.svg deleted file mode 100644 index 595bcc3..0000000 --- a/images/themes/light/primary/close.svg +++ /dev/null @@ -1,186 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/downarrow.svg b/images/themes/light/primary/downarrow.svg deleted file mode 100644 index 162a271..0000000 --- a/images/themes/light/primary/downarrow.svg +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/downarrow2.svg b/images/themes/light/primary/downarrow2.svg deleted file mode 100644 index 50f48d3..0000000 --- a/images/themes/light/primary/downarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/light/primary/float.svg b/images/themes/light/primary/float.svg deleted file mode 100644 index adb6592..0000000 --- a/images/themes/light/primary/float.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/leftarrow.svg b/images/themes/light/primary/leftarrow.svg deleted file mode 100644 index 227fe1c..0000000 --- a/images/themes/light/primary/leftarrow.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/leftarrow2.svg b/images/themes/light/primary/leftarrow2.svg deleted file mode 100644 index 8594008..0000000 --- a/images/themes/light/primary/leftarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/light/primary/radiobutton_checked.svg b/images/themes/light/primary/radiobutton_checked.svg deleted file mode 100644 index c5c7a11..0000000 --- a/images/themes/light/primary/radiobutton_checked.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/radiobutton_checked_invert.svg b/images/themes/light/primary/radiobutton_checked_invert.svg deleted file mode 100644 index 6268346..0000000 --- a/images/themes/light/primary/radiobutton_checked_invert.svg +++ /dev/null @@ -1,187 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/radiobutton_unchecked.svg b/images/themes/light/primary/radiobutton_unchecked.svg deleted file mode 100644 index 1f75ed1..0000000 --- a/images/themes/light/primary/radiobutton_unchecked.svg +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/radiobutton_unchecked_invert.svg b/images/themes/light/primary/radiobutton_unchecked_invert.svg deleted file mode 100644 index 45409c0..0000000 --- a/images/themes/light/primary/radiobutton_unchecked_invert.svg +++ /dev/null @@ -1,180 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/rightarrow.svg b/images/themes/light/primary/rightarrow.svg deleted file mode 100644 index 1fe968d..0000000 --- a/images/themes/light/primary/rightarrow.svg +++ /dev/null @@ -1,192 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/rightarrow2.svg b/images/themes/light/primary/rightarrow2.svg deleted file mode 100644 index ced2746..0000000 --- a/images/themes/light/primary/rightarrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/light/primary/sizegrip.svg b/images/themes/light/primary/sizegrip.svg deleted file mode 100644 index c67ef51..0000000 --- a/images/themes/light/primary/sizegrip.svg +++ /dev/null @@ -1,238 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/slider.svg b/images/themes/light/primary/slider.svg deleted file mode 100644 index 54d382c..0000000 --- a/images/themes/light/primary/slider.svg +++ /dev/null @@ -1,182 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/splitter-horizontal.svg b/images/themes/light/primary/splitter-horizontal.svg deleted file mode 100644 index 6db982d..0000000 --- a/images/themes/light/primary/splitter-horizontal.svg +++ /dev/null @@ -1,213 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/splitter-vertical.svg b/images/themes/light/primary/splitter-vertical.svg deleted file mode 100644 index b73f102..0000000 --- a/images/themes/light/primary/splitter-vertical.svg +++ /dev/null @@ -1,214 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/tab_close.svg b/images/themes/light/primary/tab_close.svg deleted file mode 100644 index e21b3bc..0000000 --- a/images/themes/light/primary/tab_close.svg +++ /dev/null @@ -1,185 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/toolbar-handle-horizontal.svg b/images/themes/light/primary/toolbar-handle-horizontal.svg deleted file mode 100644 index 8e63b19..0000000 --- a/images/themes/light/primary/toolbar-handle-horizontal.svg +++ /dev/null @@ -1,255 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/toolbar-handle-vertical.svg b/images/themes/light/primary/toolbar-handle-vertical.svg deleted file mode 100644 index 481d9a8..0000000 --- a/images/themes/light/primary/toolbar-handle-vertical.svg +++ /dev/null @@ -1,259 +0,0 @@ - - - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/uparrow.svg b/images/themes/light/primary/uparrow.svg deleted file mode 100644 index c119df8..0000000 --- a/images/themes/light/primary/uparrow.svg +++ /dev/null @@ -1,191 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/primary/uparrow2.svg b/images/themes/light/primary/uparrow2.svg deleted file mode 100644 index fc3a122..0000000 --- a/images/themes/light/primary/uparrow2.svg +++ /dev/null @@ -1,103 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - diff --git a/images/themes/light/primary/vline.svg b/images/themes/light/primary/vline.svg deleted file mode 100644 index d1173e8..0000000 --- a/images/themes/light/primary/vline.svg +++ /dev/null @@ -1,190 +0,0 @@ - - - - - - - - - - image/svg+xml - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/images/themes/light/star.svg b/images/themes/light/star.svg new file mode 100644 index 0000000..ee43c24 --- /dev/null +++ b/images/themes/light/star.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/core/internalmanager.cpp b/src/core/internalmanager.cpp index 63d548d..b7a4027 100644 --- a/src/core/internalmanager.cpp +++ b/src/core/internalmanager.cpp @@ -17,6 +17,8 @@ */ #include "internalmanager.h" +#include "../gui/styles/dark/darkstyle.h" +#include "../gui/styles/light/lightstyle.h" InternalManager *i_m_ptr; @@ -32,6 +34,8 @@ InternalManager::InternalManager() inactive_filter = new InactiveFilter(settings->value("lock_timeout").toLongLong(), this); QApplication::instance()->installEventFilter(inactive_filter); + + start_update_theme(); } InternalManager::~InternalManager() @@ -96,3 +100,24 @@ void InternalManager::end_busy_mode(int const line, std::string const &func, std app_busy = false; QGuiApplication::restoreOverrideCursor(); } + +void InternalManager::start_update_theme() +{ + QPixmapCache::clear(); + state_color_palette = StateColorPalette(); + + if (get_theme() == td::Theme::Dark) { + state_color_palette.initDefaultPaletteDark(); + auto s = new DarkStyle; + QApplication::setPalette(s->standardPalette()); + QApplication::setStyle(s); + } + else { + state_color_palette.initDefaultPaletteLight(); + auto s = new LightStyle; + QApplication::setPalette(s->standardPalette()); + QApplication::setStyle(s); + } + + emit update_theme(); +} diff --git a/src/core/internalmanager.h b/src/core/internalmanager.h index 78b921b..19fd440 100644 --- a/src/core/internalmanager.h +++ b/src/core/internalmanager.h @@ -24,6 +24,7 @@ #include #include +#include "../gui/styles/statecolorpalette.h" #include "../util/eventfilters.h" #include "asyncfuture.h" #include "json.hpp" @@ -154,10 +155,12 @@ class InternalManager : public QObject { void start_busy_mode(int const line, std::string const &func, std::string const &file); void end_busy_mode(int const line, std::string const &func, std::string const &file); void init_settings(bool const force_reset); + void start_update_theme(); QSettings *settings; InactiveFilter *inactive_filter; BusyFilter busy_filter; + StateColorPalette state_color_palette; bool app_busy; bool internal_diary_changed; bool diary_file_changed; diff --git a/src/core/theoreticaldiary.cpp b/src/core/theoreticaldiary.cpp index a57b32c..45cc9cb 100644 --- a/src/core/theoreticaldiary.cpp +++ b/src/core/theoreticaldiary.cpp @@ -24,42 +24,6 @@ TheoreticalDiary::TheoreticalDiary(int &argc, char *argv[]) : QApplication(argc, argv) { - // Load main font. - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Black.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-BlackItalic.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Bold.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-BoldItalic.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Italic.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Light.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-LightItalic.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Medium.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-MediumItalic.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Regular.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Thin.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-ThinItalic.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Condensed-Bold.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Condensed-BoldItalic.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Condensed-Italic.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Condensed-Light.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Condensed-LightItalic.ttf"); - QFontDatabase::addApplicationFont(":/Roboto/Roboto-Condensed-Regular.ttf"); - - // Load monospace font. - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-Thin.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-ExtraLight.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-Light.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-Regular.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-Medium.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-SemiBold.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-Bold.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-ThinItalic.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-ExtraLightItalic.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-LightItalic.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-Italic.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-MediumItalic.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-SemiBoldItalic.ttf"); - QFontDatabase::addApplicationFont(":/RobotoMono/RobotoMono-BoldItalic.ttf"); - // Set app version. QFile file(":/VERSION.txt"); file.open(QIODevice::ReadOnly); diff --git a/src/gui/aboutdialog.cpp b/src/gui/aboutdialog.cpp index ce642f0..c13826d 100644 --- a/src/gui/aboutdialog.cpp +++ b/src/gui/aboutdialog.cpp @@ -19,25 +19,67 @@ #include "aboutdialog.h" #include "ui_aboutdialog.h" +// clang-format off +QString const DESCRIPTION = R"( +

%APPNAME% is a desktop GUI application for keeping a digital diary.

+

Please provide the info below when reporting a bug.

+)"; + +QString const ABOUT = R"( +

Version %VERSION%

+

Revision %REVISION%

+

OS %OS%

+

CPU %CPU%

+

Kernel %KERNEL%

+)"; + +// Shhhhhh ;) +QString const CONTRIBUTORS = R"( +

+)"; + +QString const LIBRARIES = R"( + +)"; +// clang-format on + AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent), ui(new Ui::AboutDialog) { ui->setupUi(this); - ui->version_placeholder->setText(QApplication::applicationVersion()); - ui->version_placeholder->update(); - - auto description = ui->description->text(); - ui->description->setText(description.replace("%APPNAME%", QApplication::applicationName())); - ui->description->update(); + ui->description->setText(QString(DESCRIPTION).replace("%APPNAME%", QApplication::applicationName())); + ui->contributors->setText(CONTRIBUTORS); + ui->licenses->setText(LIBRARIES); - QFile file(":/CONTRIBUTORS.txt"); + QFile file(":/REVISION.txt"); file.open(QIODevice::ReadOnly); - ui->contributors->setPlainText(file.readAll()); + + ui->about->setText(QString(ABOUT) + .replace("%VERSION%", QApplication::applicationVersion()) + .replace("%REVISION%", file.readAll()) + .replace("%OS%", QSysInfo::prettyProductName()) + .replace("%CPU%", QSysInfo::currentCpuArchitecture()) + .replace("%KERNEL%", QSysInfo::kernelType() + " " + QSysInfo::kernelVersion())); connect(ui->ok_button, &QPushButton::clicked, this, &AboutDialog::accept, Qt::QueuedConnection); + connect(ui->clipboard, &QPushButton::clicked, + [this]() { QGuiApplication::clipboard()->setText(ui->about->toPlainText()); }); // connect(InternalManager::instance(), &InternalManager::update_theme, this, &AboutDialog::update_theme, // Qt::QueuedConnection); - update_theme(); + // update_theme(); } AboutDialog::~AboutDialog() @@ -45,9 +87,4 @@ AboutDialog::~AboutDialog() delete ui; } -void AboutDialog::update_theme() -{ - QFile file(":/global/aboutdialog.qss"); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); -} +void AboutDialog::update_theme() {} diff --git a/src/gui/aboutdialog.ui b/src/gui/aboutdialog.ui index 3202f3e..8faae63 100644 --- a/src/gui/aboutdialog.ui +++ b/src/gui/aboutdialog.ui @@ -6,239 +6,157 @@ 0 0 - 640 - 480 + 400 + 500 About - - - 15 - - - 15 - - - 15 - - - 15 - - - 15 - - - - - - 200 - 200 - - - - QFrame::StyledPanel - - - QFrame::Raised - - - - 0 - - - 0 - - - 0 - - - 0 - - - 15 - - - 0 - - - - - 0 - - - 15 - - - - - - 16 - - - - Version - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - 11 - - - - version placeholder - - - - - - - - 11 - - - - %APPNAME% is a desktop GUI application for keeping a digital diary. - - - true - - - - - - - Qt::Vertical - - - - 20 - 0 - - - - - - - - - 16 - - - - About - - - - - - - - - - 200 - 200 - - - - - - - :/linux_icons/scalable/theoreticaldiary.svg - - - true - - - - - + + + + + + + + 50 + 50 + + + + + + + :/linux_icons/scalable/theoreticaldiary.svg + + + true + + + + + + + + 26 + + + + <b>Theoretical Diary</b> + + + + - - - - QFrame::StyledPanel - - - QFrame::Raised + + + + 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 0 - - - 15 - - - - - - 16 - - - - Contributors - - - - - - - - 11 - - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - + + + About + + + + + + Copy to clipboard + + + true + + + false + + + + + + + Qt::TextSelectableByMouse + + + + + + + TextLabel + + + true + + + + + + + + Contributors + + + + + + TextLabel + + + true + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse + + + + + + + + Libraries + + + + + + TextLabel + + + true + + + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse + + + + + - + - - - 11 - + + + 100 + 0 + - OK + Close + + + true + + tabWidget + about + clipboard + ok_button + diff --git a/src/gui/apiresponse.cpp b/src/gui/apiresponse.cpp index ef5f486..c71f2a9 100644 --- a/src/gui/apiresponse.cpp +++ b/src/gui/apiresponse.cpp @@ -24,11 +24,15 @@ APIResponse::APIResponse(QByteArray const &res, QWidget *parent) : QDialog(paren ui->setupUi(this); ui->res->setPlainText(res); + auto monospaced = QFontDatabase::systemFont(QFontDatabase::FixedFont); + monospaced.setLetterSpacing(QFont::PercentageSpacing, 110); + ui->res->setFont(monospaced); + connect(ui->ok_button, &QPushButton::clicked, this, &APIResponse::accept, Qt::QueuedConnection); // connect(InternalManager::instance(), &InternalManager::update_theme, this, &AboutDialog::update_theme, // Qt::QueuedConnection); - update_theme(); + // update_theme(); } APIResponse::~APIResponse() @@ -36,9 +40,4 @@ APIResponse::~APIResponse() delete ui; } -void APIResponse::update_theme() -{ - QFile file(":/global/apiresponse.qss"); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); -} +void APIResponse::update_theme() {} diff --git a/src/gui/apiresponse.ui b/src/gui/apiresponse.ui index 5c2ba0e..df36918 100644 --- a/src/gui/apiresponse.ui +++ b/src/gui/apiresponse.ui @@ -2,65 +2,30 @@ APIResponse - - - 0 - 0 - 640 - 640 - - - 640 - 640 + 600 + 600 API response - - 15 - - - 15 - - - 15 - - - 15 - - - 15 - - - - - - 16 - - + + - Response + OK - + Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextEditable|Qt::TextEditorInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - OK - - - diff --git a/src/gui/calendarbutton.cpp b/src/gui/calendarbutton.cpp index b0938c0..30a2205 100644 --- a/src/gui/calendarbutton.cpp +++ b/src/gui/calendarbutton.cpp @@ -51,47 +51,49 @@ CalendarButton::~CalendarButton() {} // - Whether it is selected or not void CalendarButton::re_render(td::CalendarButtonData const &d) { - // Set stylesheet (determines colours). - QString stylesheet((*data.parent)->base_stylesheet); - - // Set background star if necessary. - // If the provided 'd' object does not have the 'important' property set, use the 'important' property from 'data' - // instead. If the provided 'd' object DOES contain an 'important' property, update the 'important' property of - // 'data'. - data.important = std::optional(d.important.value_or(*data.important)); - data.rating = std::optional(d.rating.value_or(*data.rating)); - - if (*data.important) { - switch (*data.rating) { - case td::Rating::Unknown: - // Fall through - case td::Rating::VeryBad: - // Fall through - case td::Rating::Bad: - // Fall through - case td::Rating::Ok: - stylesheet.append((*data.parent)->white_star); - break; - case td::Rating::Good: - // Fall through - case td::Rating::VeryGood: - stylesheet.append((*data.parent)->black_star); - break; - } - } - - // Set colour scheme. - auto const r = d.rating.value_or(*data.rating); - data.rating = std::optional(r); - stylesheet.append(*(((*data.parent)->rating_stylesheets)[static_cast(r)])); - - // Give border if selected. - data.selected = std::optional(d.selected.value_or(*data.selected)); - if (*data.selected) { - stylesheet.append((*data.parent)->selected_stylesheet); - } - - setStyleSheet(stylesheet); + // // Set stylesheet (determines colours). + // QString stylesheet((*data.parent)->base_stylesheet); + + // // Set background star if necessary. + // // If the provided 'd' object does not have the 'important' property set, use the 'important' property from + // 'data' + // // instead. If the provided 'd' object DOES contain an 'important' property, update the 'important' property + // of + // // 'data'. + // data.important = std::optional(d.important.value_or(*data.important)); + // data.rating = std::optional(d.rating.value_or(*data.rating)); + + // if (*data.important) { + // switch (*data.rating) { + // case td::Rating::Unknown: + // // Fall through + // case td::Rating::VeryBad: + // // Fall through + // case td::Rating::Bad: + // // Fall through + // case td::Rating::Ok: + // stylesheet.append((*data.parent)->white_star); + // break; + // case td::Rating::Good: + // // Fall through + // case td::Rating::VeryGood: + // stylesheet.append((*data.parent)->black_star); + // break; + // } + // } + + // // Set colour scheme. + // auto const r = d.rating.value_or(*data.rating); + // data.rating = std::optional(r); + // stylesheet.append(*(((*data.parent)->rating_stylesheets)[static_cast(r)])); + + // // Give border if selected. + // data.selected = std::optional(d.selected.value_or(*data.selected)); + // if (*data.selected) { + // stylesheet.append((*data.parent)->selected_stylesheet); + // } + + // setStylesheet\(stylesheet); } void CalendarButton::clicked_on() diff --git a/src/gui/diaryeditor.cpp b/src/gui/diaryeditor.cpp index abc4b39..e73decb 100644 --- a/src/gui/diaryeditor.cpp +++ b/src/gui/diaryeditor.cpp @@ -85,48 +85,48 @@ DiaryEditor::~DiaryEditor() void DiaryEditor::update_theme() { - auto const &theme = InternalManager::instance()->get_theme_str(); - - QFile file(QString(":/%1/diaryeditor.qss").arg(theme)); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); - file.close(); - - file.setFileName(QString(":/%1/theoretical_calendar/base.qss").arg(theme)); - file.open(QIODevice::ReadOnly); - base_stylesheet = file.readAll(); - file.close(); - - file.setFileName(QString(":/%1/theoretical_calendar/selected.qss").arg(theme)); - file.open(QIODevice::ReadOnly); - selected_stylesheet = file.readAll(); - file.close(); - - file.setFileName(":/global/white_star.qss"); - file.open(QIODevice::ReadOnly); - white_star = file.readAll(); - file.close(); - - file.setFileName(":/global/black_star.qss"); - file.open(QIODevice::ReadOnly); - black_star = file.readAll(); - file.close(); - - for (auto &ss_ptr : rating_stylesheets) - ss_ptr.reset(); - - rating_stylesheets.clear(); - - for (int i = 0; i < 6; ++i) { - file.setFileName(QString(":/%1/theoretical_calendar/%2.qss").arg(theme, QString::number(i))); - file.open(QIODevice::ReadOnly); - rating_stylesheets.push_back(std::make_unique(file.readAll())); - file.close(); - } - - // When this function is run in the constructor, no buttons should exist yet. - emit sig_re_render_buttons( - td::CalendarButtonData{std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}); + // auto const &theme = InternalManager::instance()->get_theme_str(); + + // QFile file(QString(":/%1/diaryeditor.qss").arg(theme)); + // file.open(QIODevice::ReadOnly); + // // setStylesheet\(file.readAll()); + // file.close(); + + // file.setFileName(QString(":/%1/theoretical_calendar/base.qss").arg(theme)); + // file.open(QIODevice::ReadOnly); + // base_stylesheet = file.readAll(); + // file.close(); + + // file.setFileName(QString(":/%1/theoretical_calendar/selected.qss").arg(theme)); + // file.open(QIODevice::ReadOnly); + // selected_stylesheet = file.readAll(); + // file.close(); + + // file.setFileName(":/global/white_star.qss"); + // file.open(QIODevice::ReadOnly); + // white_star = file.readAll(); + // file.close(); + + // file.setFileName(":/global/black_star.qss"); + // file.open(QIODevice::ReadOnly); + // black_star = file.readAll(); + // file.close(); + + // for (auto &ss_ptr : rating_stylesheets) + // ss_ptr.reset(); + + // rating_stylesheets.clear(); + + // for (int i = 0; i < 6; ++i) { + // file.setFileName(QString(":/%1/theoretical_calendar/%2.qss").arg(theme, QString::number(i))); + // file.open(QIODevice::ReadOnly); + // rating_stylesheets.push_back(std::make_unique(file.readAll())); + // file.close(); + // } + + // // When this function is run in the constructor, no buttons should exist yet. + // emit sig_re_render_buttons( + // td::CalendarButtonData{std::nullopt, std::nullopt, std::nullopt, std::nullopt, std::nullopt}); } // Note for future me and any other readers: @@ -217,6 +217,9 @@ void DiaryEditor::change_month(QDate const &date, bool const suppress_confirm) if (QMessageBox::RejectRole == res) return; + if (QMessageBox::AcceptRole) + update_day(true); + // Remove everything from current grid. QLayoutItem *child; while ((child = ui->dates->takeAt(0)) != 0) { @@ -254,7 +257,7 @@ void DiaryEditor::change_month(QDate const &date, bool const suppress_confirm) if (InternalManager::instance()->internal_diary_changed && !suppress_confirm) return cmb::confirm_switch_date(this, cb); - cb(QMessageBox::AcceptRole); + cb(QMessageBox::DestructiveRole); } void DiaryEditor::render_day(td::CalendarButtonData const &d, bool const set_info_pane) @@ -315,7 +318,7 @@ void DiaryEditor::date_clicked(int const day) if (QMessageBox::RejectRole == res) return; - if (QMessageBox::YesRole == res) + if (QMessageBox::AcceptRole == res) update_day(true); // Suppress entry saved message so it doesn't appear on new date. td::CalendarButtonData const old{ @@ -334,7 +337,7 @@ void DiaryEditor::date_clicked(int const day) if (InternalManager::instance()->internal_diary_changed) cmb::confirm_switch_date(this, cb); else - cb(QMessageBox::NoRole); + cb(QMessageBox::DestructiveRole); } void DiaryEditor::update_info_pane(QDate const &date, td::Entry const &entry) diff --git a/src/gui/diaryeditor.ui b/src/gui/diaryeditor.ui index 4a7954e..cc0755f 100644 --- a/src/gui/diaryeditor.ui +++ b/src/gui/diaryeditor.ui @@ -55,12 +55,6 @@ 0 - - QFrame::StyledPanel - - - QFrame::Raised - 15 @@ -305,7 +299,7 @@ - 40 + 50 16777215 @@ -318,10 +312,7 @@ Next month. - - - - true + > @@ -329,7 +320,7 @@ - 40 + 50 16777215 @@ -342,10 +333,7 @@ Previous month. - - - - true + < @@ -545,11 +533,6 @@ - - - 11 - - Entry message @@ -560,11 +543,6 @@ - - - 11 - - Special? @@ -572,23 +550,13 @@ - - - 11 - - Rating - + - - - 11 - - Entry @@ -604,11 +572,6 @@ - - - 11 - - CrossCursor @@ -648,11 +611,6 @@ 0 - - - 11 - - Rating dropdown @@ -732,55 +690,34 @@ - - - 11 - - Jump to today. Jump to today - - true - - - - 11 - - Delete entry. Delete - - true - - - - 11 - - Update entry. Update - - false + + true @@ -875,7 +812,12 @@ month_dropdown year_edit next_month + rating_dropdown + special_box entry_edit + update_button + delete_button + reset_button diff --git a/src/gui/diaryentryviewer.cpp b/src/gui/diaryentryviewer.cpp index 3bc8d93..86d4e00 100644 --- a/src/gui/diaryentryviewer.cpp +++ b/src/gui/diaryentryviewer.cpp @@ -62,41 +62,41 @@ DiaryEntryViewer::~DiaryEntryViewer() void DiaryEntryViewer::update_theme() { - auto const &theme = InternalManager::instance()->get_theme_str(); - - QFile file(QString(":/%1/diary_entry_list/base.qss").arg(theme)); - file.open(QIODevice::ReadOnly); - ui->scrollArea->setStyleSheet(file.readAll()); - file.close(); - - file.setFileName(QString(":/%1/diaryentryviewer.qss").arg(theme)); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); - file.close(); - - file.setFileName(":/global/white_star.qss"); - file.open(QIODevice::ReadOnly); - white_star = file.readAll(); - file.close(); - - file.setFileName(":/global/black_star.qss"); - file.open(QIODevice::ReadOnly); - black_star = file.readAll(); - file.close(); - - for (auto &ss_ptr : rating_stylesheets) - ss_ptr.reset(); - - rating_stylesheets.clear(); - - for (int i = 0; i < 6; ++i) { - file.setFileName(QString(":/%1/diary_entry_list/%2.qss").arg(theme, QString::number(i))); - file.open(QIODevice::ReadOnly); - rating_stylesheets.push_back(std::make_unique(file.readAll())); - file.close(); - } + // auto const &theme = InternalManager::instance()->get_theme_str(); + + // QFile file(QString(":/%1/diary_entry_list/base.qss").arg(theme)); + // file.open(QIODevice::ReadOnly); + // // ui->scrollArea->setStyleSheet(file.readAll()); + // file.close(); + + // file.setFileName(QString(":/%1/diaryentryviewer.qss").arg(theme)); + // file.open(QIODevice::ReadOnly); + // // setStylesheet\(file.readAll()); + // file.close(); + + // file.setFileName(":/global/white_star.qss"); + // file.open(QIODevice::ReadOnly); + // white_star = file.readAll(); + // file.close(); + + // file.setFileName(":/global/black_star.qss"); + // file.open(QIODevice::ReadOnly); + // black_star = file.readAll(); + // file.close(); - emit sig_update_labels(); + // for (auto &ss_ptr : rating_stylesheets) + // ss_ptr.reset(); + + // rating_stylesheets.clear(); + + // for (int i = 0; i < 6; ++i) { + // file.setFileName(QString(":/%1/diary_entry_list/%2.qss").arg(theme, QString::number(i))); + // file.open(QIODevice::ReadOnly); + // rating_stylesheets.push_back(std::make_unique(file.readAll())); + // file.close(); + // } + + // emit sig_update_labels(); } void DiaryEntryViewer::change_month(QDate const &date) @@ -241,30 +241,30 @@ DiaryEntryDayLabel::~DiaryEntryDayLabel() {} void DiaryEntryDayLabel::update_theme() { - // Set colour theme. - QString stylesheet(*(data.parent->rating_stylesheets)[static_cast(data.rating)]); - - // Set background star if necessary. - if (data.special) { - switch (data.rating) { - case td::Rating::Unknown: - // Fall through - case td::Rating::VeryBad: - // Fall through - case td::Rating::Bad: - // Fall through - case td::Rating::Ok: - stylesheet.append(data.parent->white_star); - break; - case td::Rating::Good: - // Fall through - case td::Rating::VeryGood: - stylesheet.append(data.parent->black_star); - break; - } - } - - setStyleSheet(stylesheet); + // // Set colour theme. + // QString stylesheet(*(data.parent->rating_stylesheets)[static_cast(data.rating)]); + + // // Set background star if necessary. + // if (data.special) { + // switch (data.rating) { + // case td::Rating::Unknown: + // // Fall through + // case td::Rating::VeryBad: + // // Fall through + // case td::Rating::Bad: + // // Fall through + // case td::Rating::Ok: + // stylesheet.append(data.parent->white_star); + // break; + // case td::Rating::Good: + // // Fall through + // case td::Rating::VeryGood: + // stylesheet.append(data.parent->black_star); + // break; + // } + // } + + // setStylesheet\(stylesheet); } /* diff --git a/src/gui/diaryentryviewer.ui b/src/gui/diaryentryviewer.ui index 0979265..560b239 100644 --- a/src/gui/diaryentryviewer.ui +++ b/src/gui/diaryentryviewer.ui @@ -61,12 +61,6 @@ 16777215 - - QFrame::StyledPanel - - - QFrame::Raised - 15 @@ -105,8 +99,8 @@ 0 0 - 1216 - 543 + 1218 + 545 @@ -179,7 +173,7 @@ - 40 + 50 16777215 @@ -192,10 +186,7 @@ Next month. - - - - true + > @@ -218,7 +209,7 @@ - 40 + 50 16777215 @@ -231,10 +222,7 @@ Previous month. - - - - true + < @@ -381,6 +369,13 @@ + + scrollArea + prev_month + month_dropdown + year_edit + next_month + diff --git a/src/gui/diarymenu.cpp b/src/gui/diarymenu.cpp index 4132b89..43f38de 100644 --- a/src/gui/diarymenu.cpp +++ b/src/gui/diarymenu.cpp @@ -37,11 +37,11 @@ DiaryMenu::DiaryMenu(QWidget *parent) : QWidget(parent), ui(new Ui::DiaryMenu) ui->editor->layout()->addWidget(new DiaryEditor(date, this)); ui->settings_tab->layout()->addWidget(new OptionsMenu(true, this)); - connect(ui->tabWidget, &QTabWidget::currentChanged, this, &DiaryMenu::tab_changed, Qt::QueuedConnection); + connect(ui->diary_menu_tab, &QTabWidget::currentChanged, this, &DiaryMenu::tab_changed, Qt::QueuedConnection); // connect(InternalManager::instance(), &InternalManager::update_theme, this, &DiaryMenu::update_theme, // Qt::QueuedConnection); - update_theme(); + // update_theme(); } DiaryMenu::~DiaryMenu() @@ -49,30 +49,9 @@ DiaryMenu::~DiaryMenu() delete ui; } -void DiaryMenu::update_theme() -{ - QFile file(":/global/diarymenu.qss"); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); -} +void DiaryMenu::update_theme() {} -void DiaryMenu::tab_changed(int const tab) +void DiaryMenu::tab_changed(int const) { - switch (tab) { - case 0: - qDebug() << "Switched to editor tab."; - break; - case 1: - qDebug() << "Switched to entry list tab."; - break; - case 2: - qDebug() << "Switched to stats tab."; - break; - case 3: - qDebug() << "Switched to pixels tab."; - break; - case 4: - qDebug() << "Switched to options tab."; - break; - } + qDebug() << "Switched to tab:" << ui->diary_menu_tab->tabText(ui->diary_menu_tab->currentIndex()); } diff --git a/src/gui/diarymenu.h b/src/gui/diarymenu.h index 1b957f9..b2997f2 100644 --- a/src/gui/diarymenu.h +++ b/src/gui/diarymenu.h @@ -34,7 +34,7 @@ class DiaryMenu : public QWidget { public slots: void update_theme(); - void tab_changed(int const tab); + void tab_changed(int const); private: Ui::DiaryMenu *ui; diff --git a/src/gui/diarymenu.ui b/src/gui/diarymenu.ui index 74d9746..373ec35 100644 --- a/src/gui/diarymenu.ui +++ b/src/gui/diarymenu.ui @@ -42,21 +42,19 @@ 0 - + 0 0 - - - 11 - - 0 + + true + @@ -202,7 +200,7 @@ - tabWidget + diary_menu_tab diff --git a/src/gui/diarypixels.cpp b/src/gui/diarypixels.cpp index 7dc2dc1..c0e9f89 100644 --- a/src/gui/diarypixels.cpp +++ b/src/gui/diarypixels.cpp @@ -19,7 +19,9 @@ #include "diarypixels.h" #include "../core/diaryholder.h" #include "../util/custommessageboxes.h" +#include "../util/diarypixellabel.h" #include "../util/misc.h" +#include "styles/statecolorpalette.h" #include "ui_diarypixels.h" char const *MONTH_LETTERS = "JFMAMJJASOND"; @@ -52,35 +54,7 @@ DiaryPixels::~DiaryPixels() delete ui; } -void DiaryPixels::update_theme() -{ - QFile file(":/global/diarypixels.qss"); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); - file.close(); - - file.setFileName(":/global/small_white_star.qss"); - file.open(QIODevice::ReadOnly); - white_star = file.readAll(); - file.close(); - - file.setFileName(":/global/small_black_star.qss"); - file.open(QIODevice::ReadOnly); - black_star = file.readAll(); - file.close(); - - // for (auto &ss_ptr : rating_stylesheets) - // ss_ptr.reset(); - - // rating_stylesheets.clear(); - - for (int i = 0; i < 6; ++i) { - file.setFileName(QString(":/global/pixels/%1.qss").arg(QString::number(i))); - file.open(QIODevice::ReadOnly); - rating_stylesheets.push_back(std::make_unique(file.readAll())); - file.close(); - } -} +void DiaryPixels::update_theme() {} int DiaryPixels::calculate_size() { @@ -162,8 +136,12 @@ void DiaryPixels::render_grid(QDate const &new_date) if (iter == monthmap.end()) { for (int day = 0; day < days; ++day) { tmp_date.setDate(year, month + 1, day + 1); - ui->grid->addWidget(new PixelLabel(td::Rating::Unknown, false, tmp_date, size, this), month, - day + 1 /* +1 here because of the month label added at the start of each row */); + + auto ptr = new DiaryPixelLabel(td::Rating::Unknown, false, tmp_date, size, this); + connect(this, &DiaryPixels::sig_changed_size, ptr, &DiaryPixelLabel::resize, Qt::QueuedConnection); + + ui->grid->addWidget( + ptr, month, day + 1 /* +1 here because of the month label added at the start of each row */); } continue; @@ -176,11 +154,18 @@ void DiaryPixels::render_grid(QDate const &new_date) tmp_date.setDate(year, month + 1, day + 1); if (iter2 == entrymap.end()) { - ui->grid->addWidget(new PixelLabel(td::Rating::Unknown, false, tmp_date, size, this), month, day + 1); + auto ptr = new DiaryPixelLabel(td::Rating::Unknown, false, tmp_date, size, this); + connect(this, &DiaryPixels::sig_changed_size, ptr, &DiaryPixelLabel::resize, Qt::QueuedConnection); + + ui->grid->addWidget(ptr, month, day + 1); } else { auto const &[important, rating, dummy, d2] = iter2->second; - ui->grid->addWidget(new PixelLabel(rating, important, tmp_date, size, this), month, day + 1); + + auto ptr = new DiaryPixelLabel(rating, important, tmp_date, size, this); + connect(this, &DiaryPixels::sig_changed_size, ptr, &DiaryPixelLabel::resize, Qt::QueuedConnection); + + ui->grid->addWidget(ptr, month, day + 1); } } } @@ -212,52 +197,3 @@ void DiaryPixels::resizeEvent(QResizeEvent *) { emit sig_changed_size(calculate_size()); } - -/* - * PixelLabel class - */ -PixelLabel::PixelLabel(td::Rating const r, bool const special, QDate const &date, int const size, QWidget *parent) - : QLabel(parent) -{ - auto p = qobject_cast(parent); - - setFixedHeight(size); - setFixedWidth(size); - - auto stylesheet = *p->rating_stylesheets[static_cast(r)]; - - connect(p, &DiaryPixels::sig_changed_size, this, &PixelLabel::resize, Qt::QueuedConnection); - - // Set background star if necessary. - if (special) { - switch (r) { - case td::Rating::Unknown: - // Fall through - case td::Rating::VeryBad: - // Fall through - case td::Rating::Bad: - // Fall through - case td::Rating::Ok: - stylesheet.append(qobject_cast(parent)->white_star); - break; - case td::Rating::Good: - // Fall through - case td::Rating::VeryGood: - stylesheet.append(qobject_cast(parent)->black_star); - break; - } - } - - setStyleSheet(stylesheet); - - setToolTip( - QString("%1 %2%3").arg(date.toString("MMMM"), QString::number(date.day()), misc::get_day_suffix(date.day()))); -} - -PixelLabel::~PixelLabel() {} - -void PixelLabel::resize(int const new_width) -{ - setFixedHeight(new_width); - setFixedWidth(new_width); -} diff --git a/src/gui/diarypixels.h b/src/gui/diarypixels.h index 5989a29..63e2a7f 100644 --- a/src/gui/diarypixels.h +++ b/src/gui/diarypixels.h @@ -56,16 +56,4 @@ public slots: Ui::DiaryPixels *ui; }; -class PixelLabel : public QLabel { - Q_OBJECT - -public: - explicit PixelLabel( - td::Rating const r, bool const special, QDate const &date, int const size, QWidget *parent = nullptr); - ~PixelLabel(); - -public slots: - void resize(int const new_width); -}; - #endif // DIARYPIXELS_H diff --git a/src/gui/diarypixels.ui b/src/gui/diarypixels.ui index 5a16032..62e4bcb 100644 --- a/src/gui/diarypixels.ui +++ b/src/gui/diarypixels.ui @@ -43,12 +43,6 @@ - - QFrame::StyledPanel - - - QFrame::Raised - 15 @@ -194,17 +188,15 @@ - - - 11 - - Display the pixels. Render + + true + @@ -224,7 +216,7 @@ - 20 + 11 @@ -237,11 +229,6 @@ - - - 11 - - Export image @@ -267,6 +254,11 @@ + + year_edit + render_button + export_img_button + diff --git a/src/gui/diarystats.cpp b/src/gui/diarystats.cpp index c24d2ba..8954b11 100644 --- a/src/gui/diarystats.cpp +++ b/src/gui/diarystats.cpp @@ -36,13 +36,66 @@ auto const light_background = QColor(230, 230, 230, 170); auto const dark_white = light_background.darker(); auto const light_black = dark_background.lighter(); -auto const almost_white = QColor(245, 245, 245, 255); -auto const almost_black = QColor(60, 60, 60, 255); +auto const almost_white = QColor(202, 203, 206); +auto const almost_black = QColor(29, 29, 32); DiaryStats::DiaryStats(QWidget *parent) : QWidget(parent), ui(new Ui::DiaryStats) { ui->setupUi(this); + // Give DiaryComparisonLabels proper attributes. + ui->very_bad->rating = td::Rating::VeryBad; + ui->bad->rating = td::Rating::Bad; + ui->ok->rating = td::Rating::Ok; + ui->good->rating = td::Rating::Good; + ui->very_good->rating = td::Rating::VeryGood; + ui->unknown->rating = td::Rating::Unknown; + ui->starred->special = true; + + ui->very_bad_2->rating = td::Rating::VeryBad; + ui->bad_2->rating = td::Rating::Bad; + ui->ok_2->rating = td::Rating::Ok; + ui->good_2->rating = td::Rating::Good; + ui->very_good_2->rating = td::Rating::VeryGood; + ui->unknown_2->rating = td::Rating::Unknown; + ui->starred_2->special = true; + + ui->very_bad_3->rating = td::Rating::VeryBad; + ui->bad_3->rating = td::Rating::Bad; + ui->ok_3->rating = td::Rating::Ok; + ui->good_3->rating = td::Rating::Good; + ui->very_good_3->rating = td::Rating::VeryGood; + ui->unknown_3->rating = td::Rating::Unknown; + ui->starred_3->special = true; + + // Make the numbers display in a monospaced font. + auto monospaced = QFontDatabase::systemFont(QFontDatabase::FixedFont); + monospaced.setLetterSpacing(QFont::PercentageSpacing, 110); + + ui->l0->setFont(monospaced); + ui->l1->setFont(monospaced); + ui->l2->setFont(monospaced); + ui->l3->setFont(monospaced); + ui->l4->setFont(monospaced); + ui->l5->setFont(monospaced); + ui->ls->setFont(monospaced); + + ui->t0->setFont(monospaced); + ui->t1->setFont(monospaced); + ui->t2->setFont(monospaced); + ui->t3->setFont(monospaced); + ui->t4->setFont(monospaced); + ui->t5->setFont(monospaced); + ui->ts->setFont(monospaced); + + ui->d0->setFont(monospaced); + ui->d1->setFont(monospaced); + ui->d2->setFont(monospaced); + ui->d3->setFont(monospaced); + ui->d4->setFont(monospaced); + ui->d5->setFont(monospaced); + ui->ds->setFont(monospaced); + // Initilise pie chart. auto pie_chart = new QChart(); pie_chart->setMargins(QMargins(0, 0, 0, 0)); @@ -94,19 +147,6 @@ DiaryStats::~DiaryStats() void DiaryStats::update_theme() { - auto const &theme = InternalManager::instance()->get_theme_str(); - - QFile file(QString(":/global/diarystats.qss")); - file.open(QIODevice::ReadOnly); - QString stylesheet(file.readAll()); - file.close(); - - file.setFileName(QString(":/%1/diarystats.qss").arg(theme)); - file.open(QIODevice::ReadOnly); - stylesheet.append(file.readAll()); - - setStyleSheet(stylesheet); - render_stats(QDate::currentDate()); } @@ -249,9 +289,45 @@ void DiaryStats::render_spline_chart(std::optional const auto x_axis = new QValueAxis(); chart->addAxis(x_axis, Qt::AlignBottom); - x_axis->setRange(1, current_date.daysInMonth()); - x_axis->setTickCount(15); + + switch (current_date.daysInMonth()) { + case 28: + x_axis->setRange(0, current_date.daysInMonth()); + x_axis->setTickAnchor(0); + x_axis->setTickInterval(2); + x_axis->setTickCount(15); + break; + case 29: + x_axis->setRange(1, current_date.daysInMonth()); + x_axis->setTickAnchor(1); + x_axis->setTickInterval(2); + x_axis->setTickCount(15); + break; + case 30: + x_axis->setRange(0, current_date.daysInMonth()); + x_axis->setTickAnchor(0); + x_axis->setTickInterval(2); + x_axis->setTickCount(16); + break; + case 31: + x_axis->setRange(1, current_date.daysInMonth()); + x_axis->setTickAnchor(1); + x_axis->setTickInterval(2); + x_axis->setTickCount(16); + break; + default: + // This will probably happen if somebody puts the year all the way back to 1700s when the calendar was reset or + // something really obscure like that. + x_axis->setRange(1, current_date.daysInMonth()); + x_axis->setTickAnchor(1); + x_axis->setTickInterval(2); + x_axis->setTickCount(15); + qDebug() << "This month has an invalid number of days in it:" << current_date; + break; + } + x_axis->setGridLineColor(td::Theme::Dark == theme ? light_black : dark_white); + x_axis->setLabelFormat("%d"); x_axis->setLabelsColor(td::Theme::Dark == theme ? almost_white : almost_black); x_axis->setLabelsVisible(); x_axis->setTitleText("Day"); diff --git a/src/gui/diarystats.ui b/src/gui/diarystats.ui index f76bd49..cecdc2e 100644 --- a/src/gui/diarystats.ui +++ b/src/gui/diarystats.ui @@ -49,12 +49,6 @@ 0 - - QFrame::StyledPanel - - - QFrame::Raised - 15 @@ -83,7 +77,7 @@ - 40 + 50 16777215 @@ -96,10 +90,7 @@ Previous month. - - - - true + < @@ -242,7 +233,7 @@ - 40 + 50 16777215 @@ -255,10 +246,7 @@ Next month. - - - - true + > @@ -331,50 +319,50 @@ - - + + - - + + - - + + - - + + - - + + - - + + - - + + @@ -516,98 +504,98 @@ 15 - - + + - - + + - - + + - - + + - - + + - - + + - - + + - + - + - + - + - + - + - + @@ -721,8 +709,8 @@ - - + + @@ -735,8 +723,8 @@ - - + + @@ -749,36 +737,36 @@ - - + + - - + + - - + + - - + + - - + + @@ -915,6 +903,9 @@ 0 + + true + @@ -1081,7 +1072,22 @@ QGraphicsView
QtCharts
+ + DiaryComparisonLabel + QLabel +
src/util/diarycomparisonlabel.h
+
+ + prev_month + month_dropdown + year_edit + next_month + charts + spline_chart_view + pie_chart_view + polar_chart_view + diff --git a/src/gui/licensesdialog.cpp b/src/gui/licensesdialog.cpp deleted file mode 100644 index 16b70d6..0000000 --- a/src/gui/licensesdialog.cpp +++ /dev/null @@ -1,47 +0,0 @@ -/* - * This file is part of Theoretical Diary. - * Copyright (C) 2022 someretical - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "licensesdialog.h" -#include "ui_licensesdialog.h" - -LicensesDialog::LicensesDialog(QWidget *parent) : QDialog(parent), ui(new Ui::LicensesDialog) -{ - ui->setupUi(this); - - QFile file(":/LICENSES.txt"); - file.open(QIODevice::ReadOnly); - ui->licenses->setPlainText(file.readAll()); - - connect(ui->ok_button, &QPushButton::clicked, this, &LicensesDialog::accept, Qt::QueuedConnection); - - // connect(InternalManager::instance(), &InternalManager::update_theme, this, &LicensesDialog::update_theme, - // Qt::QueuedConnection); - update_theme(); -} - -LicensesDialog::~LicensesDialog() -{ - delete ui; -} - -void LicensesDialog::update_theme() -{ - QFile file(":/global/licensesdialog.qss"); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); -} diff --git a/src/gui/licensesdialog.h b/src/gui/licensesdialog.h deleted file mode 100644 index 6d88249..0000000 --- a/src/gui/licensesdialog.h +++ /dev/null @@ -1,42 +0,0 @@ -/* - * This file is part of Theoretical Diary. - * Copyright (C) 2022 someretical - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef LICENSESDIALOG_H -#define LICENSESDIALOG_H - -#include - -namespace Ui { -class LicensesDialog; -} - -class LicensesDialog : public QDialog { - Q_OBJECT - -public: - explicit LicensesDialog(QWidget *parent = nullptr); - ~LicensesDialog(); - -public slots: - void update_theme(); - -private: - Ui::LicensesDialog *ui; -}; - -#endif // LICENSESDIALOG_H diff --git a/src/gui/licensesdialog.ui b/src/gui/licensesdialog.ui deleted file mode 100644 index 6e80c16..0000000 --- a/src/gui/licensesdialog.ui +++ /dev/null @@ -1,75 +0,0 @@ - - - LicensesDialog - - - - 0 - 0 - 800 - 600 - - - - UpArrowCursor - - - Licenses - - - - 15 - - - 15 - - - 15 - - - 15 - - - 15 - - - - - - 16 - - - - Licenses - - - - - - - - 11 - - - - Qt::LinksAccessibleByKeyboard|Qt::LinksAccessibleByMouse|Qt::TextBrowserInteraction|Qt::TextSelectableByKeyboard|Qt::TextSelectableByMouse - - - - - - - - 11 - - - - OK - - - - - - - - diff --git a/src/gui/mainmenu.cpp b/src/gui/mainmenu.cpp index 84ed60a..0bd9208 100644 --- a/src/gui/mainmenu.cpp +++ b/src/gui/mainmenu.cpp @@ -56,7 +56,7 @@ MainMenu::MainMenu(bool const show_locked_message, QWidget *parent) : QWidget(pa // connect(InternalManager::instance(), &InternalManager::update_theme, this, &MainMenu::update_theme, // Qt::QueuedConnection); - update_theme(); + // update_theme(); } MainMenu::~MainMenu() @@ -65,12 +65,7 @@ MainMenu::~MainMenu() delete enter_shortcut; } -void MainMenu::update_theme() -{ - QFile file(":/global/mainmenu.qss"); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); -} +void MainMenu::update_theme() {} void MainMenu::open_options() { diff --git a/src/gui/mainmenu.ui b/src/gui/mainmenu.ui index 3b746ae..2de1ca7 100644 --- a/src/gui/mainmenu.ui +++ b/src/gui/mainmenu.ui @@ -20,22 +20,283 @@ Form
- - 30 - - - 30 - - - 30 - - - 30 - 0 - + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + Qt::Vertical + + + QSizePolicy::Fixed + + + + 20 + 30 + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + 550 + 0 + + + + + 550 + 16777215 + + + + + + + + 30 + + + 30 + + + 30 + + + 30 + + + 15 + + + + + 256 + + + QLineEdit::Password + + + Leave empty if the diary has no password. + + + + + + + + 9 + + + + Placeholder + + + + + + + Enter password: + + + + + + + 0 + + + 6 + + + + + + 100 + 0 + + + + Decrypt the diary. + + + Open + + + true + + + + + + + + 100 + 0 + + + + Import an unencrypted diary. + + + Import + + + + + + + + 100 + 0 + + + + Create a new diary. + + + New + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 16 + + + + <b>Open diary</b> + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + 0 + + + + + + + + 100 + 0 + + + + Open the settings menu. + + + Settings + + + + + + + + 100 + 0 + + + + Exit the application. + + + Quit + + + + + + + @@ -44,24 +305,6 @@ - - 15 - - - 15 - - - 15 - - - 15 - - - 10 - - - 0 - @@ -131,17 +374,12 @@ - Theoretical Diary + <b>Theoretical Diary</b> - - - 11 - - Version placeholder @@ -163,13 +401,8 @@ - + - - - 11 - - Welcome back to @@ -180,277 +413,19 @@ - - - - Qt::Vertical - - - QSizePolicy::Fixed - - - - 20 - 30 - - - - - - + + Qt::Vertical - - QSizePolicy::Fixed - 20 - 30 + 40 - - - - - 0 - 0 - - - - - 15 - - - 15 - - - 15 - - - 15 - - - 15 - - - - - - 500 - 0 - - - - - 11 - - - - 256 - - - QLineEdit::Password - - - Password - - - - - - - - 20 - - - - Open diary - - - - - - - 0 - - - 15 - - - - - - 90 - 0 - - - - - 11 - - - - Decrypt the diary. - - - Decrypt - - - - - - - - 90 - 0 - - - - - 11 - - - - Import an unencrypted diary. - - - Import - - - true - - - - - - - - 90 - 0 - - - - - 11 - - - - Create a new diary. - - - New - - - true - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 9 - - - - Placeholder - - - - - - - - 11 - - - - Enter password: - - - - - - - - - - - 0 - 0 - - - - - 10 - - - - - - 100 - 0 - - - - - 11 - - - - Open the settings menu. - - - Settings - - - true - - - - - - - - 100 - 0 - - - - - 11 - - - - Exit the application. - - - Quit - - - - - -
@@ -465,6 +440,13 @@
src/util/alertlabel.h
+ + decrypt_button + new_button + import_button + options_button + quit_button + diff --git a/src/gui/mainwindow.cpp b/src/gui/mainwindow.cpp index 5cf3c0b..ead6299 100644 --- a/src/gui/mainwindow.cpp +++ b/src/gui/mainwindow.cpp @@ -46,9 +46,9 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi connect(InternalManager::instance()->inactive_filter, &InactiveFilter::sig_inactive_timeout, this, &MainWindow::lock_diary); - connect(InternalManager::instance(), &InternalManager::update_theme, this, &MainWindow::update_theme, - Qt::QueuedConnection); - update_theme(); + // connect(InternalManager::instance(), &InternalManager::update_theme, this, &MainWindow::update_theme, + // Qt::QueuedConnection); + // update_theme(); } MainWindow::~MainWindow() @@ -160,12 +160,12 @@ void MainWindow::exit_diary_to_main_menu(bool const locked) return; auto const &[id1, id2] = gwrapper->get_file_ids(reply.response); + primary_id = id1; + secondary_id = id2; if (id1.isEmpty()) return upload_subroutine(); - primary_id = id1; - secondary_id = id2; gwrapper->copy_file(id1, "diary.dat.bak").subscribe(cb3); }; @@ -220,14 +220,7 @@ void MainWindow::lock_diary() exit_diary_to_main_menu(true); } -void MainWindow::update_theme() -{ - auto theme = InternalManager::instance()->get_theme_str(); - - QFile file(QString(":/%1/material_cyan.qss").arg(theme)); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); -} +void MainWindow::update_theme() {} void MainWindow::clear_grid() { @@ -298,7 +291,7 @@ void MainWindow::closeEvent(QCloseEvent *event) if (QMessageBox::RejectRole == res) return; - if (QMessageBox::YesRole == res) { + if (QMessageBox::AcceptRole == res) { // If the diary failed to save, don't exit to the main menu. InternalManager::instance()->start_busy_mode(__LINE__, __func__, __FILE__); auto saved = DiaryHolder::instance()->save(); diff --git a/src/gui/optionsmenu.cpp b/src/gui/optionsmenu.cpp index f54c13c..b56903d 100644 --- a/src/gui/optionsmenu.cpp +++ b/src/gui/optionsmenu.cpp @@ -27,7 +27,6 @@ #include "../util/misc.h" #include "aboutdialog.h" #include "apiresponse.h" -#include "licensesdialog.h" #include "mainwindow.h" #include "optionsmenu.h" #include "ui_optionsmenu.h" @@ -57,13 +56,12 @@ OptionsMenu::OptionsMenu(bool const from_diary_editor, QWidget *parent) : QWidge connect(ui->dev_copy_file_button, &QPushButton::clicked, this, &OptionsMenu::dev_copy, Qt::QueuedConnection); connect(ui->dev_delete_button, &QPushButton::clicked, this, &OptionsMenu::dev_delete, Qt::QueuedConnection); connect(ui->about_button, &QPushButton::clicked, this, &OptionsMenu::show_about, Qt::QueuedConnection); - connect(ui->licenses_button, &QPushButton::clicked, this, &OptionsMenu::show_licenses, Qt::QueuedConnection); connect(ui->reset_button, &QPushButton::clicked, this, &OptionsMenu::reset_settings, Qt::QueuedConnection); connect(ui->test_button, &QPushButton::clicked, this, &OptionsMenu::test, Qt::QueuedConnection); - connect(InternalManager::instance(), &InternalManager::update_theme, this, &OptionsMenu::update_theme, - Qt::QueuedConnection); - update_theme(); + // connect(InternalManager::instance(), &InternalManager::update_theme, this, &OptionsMenu::update_theme, + // Qt::QueuedConnection); + // update_theme(); setup_layout(); } @@ -73,14 +71,7 @@ OptionsMenu::~OptionsMenu() delete ui; } -void OptionsMenu::update_theme() -{ - auto const &theme = InternalManager::instance()->get_theme_str(); - - QFile file(QString(":/%1/optionsmenu.qss").arg(theme)); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); -} +void OptionsMenu::update_theme() {} void OptionsMenu::back() { @@ -97,7 +88,7 @@ void OptionsMenu::save_settings() auto new_theme = ui->theme_dropdown->currentIndex() == 0 ? td::Theme::Dark : td::Theme::Light; if (original_theme != new_theme) { settings->setValue("theme", static_cast(new_theme)); - InternalManager::instance()->update_theme(); + InternalManager::instance()->start_update_theme(); } qDebug() << "Saved settings."; @@ -348,12 +339,12 @@ void OptionsMenu::upload_diary() return; auto const &[id1, id2] = gwrapper->get_file_ids(reply.response); + primary_id = id1; + secondary_id = id2; if (id1.isEmpty()) return upload_subroutine(); - primary_id = id1; - secondary_id = id2; gwrapper->copy_file(id1, "diary.dat.bak").subscribe(cb3); }; @@ -627,12 +618,6 @@ void OptionsMenu::show_about() w.exec(); } -void OptionsMenu::show_licenses() -{ - LicensesDialog w(this); - w.exec(); -} - void OptionsMenu::reset_settings() { auto cb = [this](int const res) { diff --git a/src/gui/optionsmenu.h b/src/gui/optionsmenu.h index 3729d42..6754028 100644 --- a/src/gui/optionsmenu.h +++ b/src/gui/optionsmenu.h @@ -51,7 +51,6 @@ public slots: void dev_copy(); void dev_delete(); void show_about(); - void show_licenses(); void reset_settings(); void test(); diff --git a/src/gui/optionsmenu.ui b/src/gui/optionsmenu.ui index cdb7604..832e73a 100644 --- a/src/gui/optionsmenu.ui +++ b/src/gui/optionsmenu.ui @@ -38,19 +38,13 @@ 30 - - 0 - - - 15 - 0 - 15 + 10 @@ -73,14 +67,12 @@ 0 - - - 11 - - Apply + + true +
@@ -91,13 +83,8 @@ 0 - - - 11 - - - Back + OK
@@ -116,915 +103,6 @@
- - - - - 0 - 0 - - - - - 700 - 430 - - - - true - - - - - 0 - 0 - 684 - 1231 - - - - - 0 - 0 - - - - - - - - 11 - - - - Diary editor - - - - 15 - - - - - - - - 0 - 0 - - - - - 150 - 0 - - - - - 11 - - - - 18 - - - Set to zero to disable. - - - - - - - - 180 - 0 - - - - - 11 - - - - The diary will lock itself after this number of milliseconds of inactivity. - - - Lock timeout (ms) - - - - - - - - - - 11 - - - - Change - - - - - - - - - - 180 - 0 - - - - - 11 - - - - This will export the diary in unencrypted form! - - - Export diary - - - - - - - - 150 - 0 - - - - - 11 - - - - Export - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - 9 - - - - Placeholder - - - - - - - - - - - 11 - - - - About - - - - 15 - - - - - - 11 - - - - About - - - - - - - - 11 - - - - Licenses - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - 11 - - - - Change password - - - - 15 - - - - - - 11 - - - - Confirm new password: - - - - - - - - 11 - - - - Enter new password: - - - - - - - - 9 - - - - Placeholder - - - - - - - - 11 - - - - 256 - - - QLineEdit::Password - - - New password (leave blank to remove password) - - - - - - - - 11 - - - - 256 - - - QLineEdit::Password - - - New password (leave blank to remove password) - - - - - - - - 11 - - - - Update the password. - - - Change - - - - - - - - - - - 11 - - - - Developer tools - - - - 15 - - - - - - 11 - - - - Upload - - - - - - - - 11 - - - - Copy - - - - - - - - 11 - - - - List - - - - - - - - 11 - - - - New file name - - - - - - - - 11 - - - - Update - - - - - - - - 11 - - - - List files - - - - - - - - 11 - - - - Download file - - - - - - - - 11 - - - - Delete file - - - - - - - - 11 - - - - File ID - - - - - - - - 11 - - - - Upload file - - - - - - - - 11 - - - - File ID - - - - - - - - 11 - - - - File ID - - - - - - - - 11 - - - - Copy file - - - - - - - - 11 - - - - File ID - - - - - - - - 11 - - - - Download - - - - - - - - 11 - - - - Delete - - - - - - - - 11 - - - - Update file - - - - - - - - 11 - - - - Test - - - - - - - - 11 - - - - Test - - - - - - - Testing - - - - - - - - - - - 11 - - - - Appearance - - - - - - 0 - - - - - - 0 - 0 - - - - - 180 - 0 - - - - - 11 - - - - The theme of the app. - - - Theme - - - - - - - - 0 - 0 - - - - - 150 - 0 - - - - - Dark - - - - - Light - - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - 11 - - - - Google Drive Integration - - - - 15 - - - - - - 11 - - - - CrossCursor - - - Backups enabled - - - - - - - - - - 150 - 0 - - - - - 11 - - - - Download - - - - - - - - 200 - 0 - - - - - 11 - - - - This will overwrite the local diary! - - - Download backup - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 200 - 0 - - - - - 11 - - - - Removes the Google OAuth credentials. - - - Deauthorize Google Drive - - - - - - - - 150 - 0 - - - - - 11 - - - - Deauthorize - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - 150 - 0 - - - - - 11 - - - - Upload - - - - - - - - 200 - 0 - - - - - 11 - - - - This is done automatically when the diary menu is closed and backups are enabled. - - - Upload local diary - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - - - - - - 11 - - - - Reset settings - - - - - - - 11 - - - - Reset - - - - - - - - - - @@ -1051,6 +129,834 @@ + + + + + 640 + 0 + + + + 0 + + + true + + + + Normal + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + true + + + + + 0 + 0 + 622 + 882 + + + + + + + + 11 + + + + Google Drive Integration + + + + 15 + + + + + CrossCursor + + + Backups enabled + + + + + + + + + + 100 + 0 + + + + Download + + + + + + + + 200 + 0 + + + + This will overwrite the local diary! + + + Download backup + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 200 + 0 + + + + Removes the Google OAuth credentials. + + + Deauthorize Google Drive + + + + + + + + 100 + 0 + + + + Deauthorize + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + 100 + 0 + + + + Upload + + + + + + + + 200 + 0 + + + + This is done automatically when the diary menu is closed and backups are enabled. + + + Upload local diary + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Diary editor + + + + 15 + + + + + + + + 0 + 0 + + + + + 150 + 0 + + + + 18 + + + Set to zero to disable. + + + + + + + + 180 + 0 + + + + The diary will lock itself after this number of milliseconds of inactivity. + + + Lock timeout (ms) + + + + + + + + + + 100 + 0 + + + + Change + + + + + + + + + + 180 + 0 + + + + This will export the diary in unencrypted form! + + + Export diary + + + + + + + + 100 + 0 + + + + Export + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 9 + + + + Placeholder + + + + + + + + + + Appearance + + + + + + 0 + + + + + + 0 + 0 + + + + + 180 + 0 + + + + The theme of the app. + + + Theme + + + + + + + + 100 + 0 + + + + + Dark + + + + + Light + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + Reset settings + + + + + + + 100 + 0 + + + + Reset + + + + + + + + + + Change password + + + + 15 + + + + + Confirm new password: + + + + + + + Enter new password: + + + + + + + + 9 + + + + Placeholder + + + + + + + 256 + + + QLineEdit::Password + + + New password (leave blank to remove password) + + + + + + + 256 + + + QLineEdit::Password + + + New password (leave blank to remove password) + + + + + + + + 100 + 0 + + + + Update the password. + + + Change + + + + + + + + + + About + + + + 15 + + + + + + 100 + 0 + + + + About + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + Developer + + + + 0 + + + 0 + + + 0 + + + 0 + + + 0 + + + + + QFrame::NoFrame + + + true + + + + + 0 + 0 + 636 + 526 + + + + + + + Developer tools + + + + 15 + + + + + + 100 + 0 + + + + Upload + + + + + + + + 100 + 0 + + + + Copy + + + + + + + + 100 + 0 + + + + List + + + + + + + New file name + + + + + + + + 100 + 0 + + + + Update + + + + + + + List files + + + + + + + Download file + + + + + + + Delete file + + + + + + + File ID + + + + + + + Upload file + + + + + + + File ID + + + + + + + File ID + + + + + + + Copy file + + + + + + + File ID + + + + + + + + 100 + 0 + + + + Download + + + + + + + + 100 + 0 + + + + Delete + + + + + + + Update file + + + + + + + + 100 + 0 + + + + Test + + + + + + + Test + + + + + + + Testing + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Warning + + + + + + Only mess with these settings if you know what you are doing! + + + + + + + + + + + + + +
@@ -1066,8 +972,10 @@ - scrollArea + theme_dropdown export_button + lock_timeout_textedit + update_lock_timeout new_password new_password_confirm change_password_button @@ -1075,6 +983,8 @@ download_backup_button upload_backup_button flush_oauth_button + about_button + reset_button dev_list_files_button dev_upload_file_button dev_download_file_id @@ -1086,6 +996,8 @@ dev_copy_file_new_name dev_delete_file_id dev_delete_button + test_text_edit + test_button apply_button ok_button diff --git a/src/gui/standaloneoptions.cpp b/src/gui/standaloneoptions.cpp index 993ea37..1d913c1 100644 --- a/src/gui/standaloneoptions.cpp +++ b/src/gui/standaloneoptions.cpp @@ -27,7 +27,7 @@ StandaloneOptions::StandaloneOptions(QWidget *parent) : QWidget(parent), ui(new // connect(InternalManager::instance(), &InternalManager::update_theme, this, &StandaloneOptions::update_theme, // Qt::QueuedConnection); - update_theme(); + // update_theme(); } StandaloneOptions::~StandaloneOptions() @@ -35,9 +35,4 @@ StandaloneOptions::~StandaloneOptions() delete ui; } -void StandaloneOptions::update_theme() -{ - QFile file(":/global/standaloneoptions.qss"); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); -} +void StandaloneOptions::update_theme() {} diff --git a/src/gui/standaloneoptions.ui b/src/gui/standaloneoptions.ui index 260468e..990e228 100644 --- a/src/gui/standaloneoptions.ui +++ b/src/gui/standaloneoptions.ui @@ -82,10 +82,7 @@ - QFrame::StyledPanel - - - QFrame::Raised + QFrame::NoFrame diff --git a/src/gui/styles/base/basestyle.cpp b/src/gui/styles/base/basestyle.cpp new file mode 100644 index 0000000..873e773 --- /dev/null +++ b/src/gui/styles/base/basestyle.cpp @@ -0,0 +1,4775 @@ +/* + * Copyright (C) 2020 KeePassXC Team + * Copyright (C) 2019 Andrew Richards + * + * Derived from Phantomstyle and relicensed under the GPLv2 or v3. + * https://github.com/randrew/phantomstyle + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "basestyle.h" +#include "phantomcolor.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef Q_OS_MACOS +#include +#if QT_VERSION >= QT_VERSION_CHECK(5, 9, 0) +#include +#endif +#endif + +//#include "gui/Icons.h" + +QT_BEGIN_NAMESPACE +Q_GUI_EXPORT int qt_defaultDpiX(); +QT_END_NAMESPACE + +// Redefine Q_FALLTHROUGH for older Qt versions +#ifndef Q_FALLTHROUGH +#if (defined(Q_CC_GNU) && Q_CC_GNU >= 700) && !defined(Q_CC_INTEL) +#define Q_FALLTHROUGH() __attribute__((fallthrough)) +#else +#define Q_FALLTHROUGH() (void)0 +#endif +#endif + +namespace Phantom { +namespace { +constexpr qint16 DefaultFrameWidth = 6; +constexpr qint16 SplitterMaxLength = 25; // Length of splitter handle (not thickness) +constexpr qint16 MenuMinimumWidth = 20; // Smallest width that menu items can have +constexpr qint16 MenuBar_FrameWidth = 6; +constexpr qint16 SpinBox_ButtonWidth = 15; + +// These two are currently not based on font, but could be +constexpr qint16 LineEdit_ContentsHPad = 5; +constexpr qint16 ComboBox_NonEditable_ContentsHPad = 7; +constexpr qint16 HeaderSortIndicator_HOffset = 6; +constexpr qint16 HeaderSortIndicator_VOffset = 4; +constexpr qint16 HeaderSortIndicator_Width = 12; +constexpr qint16 TabBar_InactiveVShift = 0; + +constexpr qreal TabBarTab_Rounding = 1.0; +constexpr qreal SpinBox_Rounding = 1.0; +constexpr qreal LineEdit_Rounding = 1.0; +constexpr qreal FrameFocusRect_Rounding = 1.0; +constexpr qreal PushButton_Rounding = 1.0; +constexpr qreal ToolButton_Rounding = 1.0; +constexpr qreal ProgressBar_Rounding = 1.0; +constexpr qreal GroupBox_Rounding = 1.0; +constexpr qreal SliderGroove_Rounding = 1.0; +constexpr qreal SliderHandle_Rounding = 1.0; + +constexpr qreal CheckMark_WidthOfHeightScale = 0.8; +constexpr qreal PushButton_HorizontalPaddingFontHeightRatio = 1.0; +constexpr qreal TabBar_HPaddingFontRatio = 1.25; +constexpr qreal TabBar_VPaddingFontRatio = 1.0 / 1.25; +constexpr qreal GroupBox_LabelBottomMarginFontRatio = 1.0 / 4.0; +constexpr qreal ComboBox_ArrowMarginRatio = 1.0 / 3.25; + +constexpr qreal MenuBar_HorizontalPaddingFontRatio = 1.0 / 2.0; +constexpr qreal MenuBar_VerticalPaddingFontRatio = 1.0 / 3.0; + +constexpr qreal MenuItem_LeftMarginFontRatio = 1.0 / 2.0; +constexpr qreal MenuItem_RightMarginForTextFontRatio = 1.0 / 1.5; +constexpr qreal MenuItem_RightMarginForArrowFontRatio = 1.0 / 4.0; +constexpr qreal MenuItem_VerticalMarginsFontRatio = 1.0 / 5.0; +// Number that's multiplied with a font's height to get the space between a +// menu item's checkbox (or other sign) and its text (or icon). +constexpr qreal MenuItem_CheckRightSpaceFontRatio = 1.0 / 4.0; +constexpr qreal MenuItem_TextMnemonicSpaceFontRatio = 1.5; +constexpr qreal MenuItem_SubMenuArrowSpaceFontRatio = 1.0 / 1.5; +constexpr qreal MenuItem_SubMenuArrowWidthFontRatio = 1.0 / 2.75; +constexpr qreal MenuItem_SeparatorHeightFontRatio = 1.0 / 1.5; +constexpr qreal MenuItem_CheckMarkVerticalInsetFontRatio = 1.0 / 5.0; +constexpr qreal MenuItem_IconRightSpaceFontRatio = 1.0 / 3.0; + +constexpr bool BranchesOnEdge = false; +constexpr bool OverhangShadows = false; +constexpr bool IndicatorShadows = false; +constexpr bool MenuExtraBottomMargin = true; +constexpr bool MenuBarLeftMargin = false; +constexpr bool MenuBarDrawBorder = false; +constexpr bool AllowToolBarAutoRaise = true; +// Note that this only applies to the disclosure etc. decorators in tree views. +constexpr bool ShowItemViewDecorationSelected = false; +constexpr bool UseQMenuForComboBoxPopup = true; +constexpr bool ItemView_UseFontHeightForDecorationSize = true; + +// Whether or not the non-raised tabs in a tab bar have shininess/highlights to +// them. Setting this to false adds an extra visual hint for distinguishing +// between the current and non-current tabs, but makes the non-current tabs +// appear less clickable. Other ways to increase the visual differences could +// be to increase the color contrast for the background fill color, or increase +// the vertical offset. However, increasing the vertical offset comes with some +// layout challenges, and increasing the color contrast further may visually +// imply an incorrect layout structure. Not sure what's best. +// +// This doesn't disable creating the color/brush resource, even though it's +// currently a compile-time-only option, because it may be changed to be part +// of some dynamic config system for Phantom in the future, or have a +// per-widget style hint associated with it. +const bool TabBar_InactiveTabsHaveSpecular = false; + +struct Grad { + Grad(const QColor &from, const QColor &to) + { + rgbA = Rgb::ofQColor(from); + rgbB = Rgb::ofQColor(to); + lA = rgbA.toHsl().l; + lB = rgbB.toHsl().l; + } + QColor sample(qreal alpha) const + { + Hsl hsl = Rgb::lerp(rgbA, rgbB, alpha).toHsl(); + hsl.l = Phantom::lerp(lA, lB, alpha); + return hsl.toQColor(); + } + Rgb rgbA, rgbB; + qreal lA, lB; +}; + +namespace DeriveColors { +Q_NEVER_INLINE QColor adjustLightness(const QColor &qcolor, qreal ld) +{ + Hsl hsl = Hsl::ofQColor(qcolor); + const qreal gamma = 3.0; + hsl.l = std::pow(Phantom::saturate(std::pow(hsl.l, 1.0 / gamma) + ld * 0.8), gamma); + return hsl.toQColor(); +} +bool hack_isLightPalette(const QPalette &pal) +{ + Hsl hsl0 = Hsl::ofQColor(pal.color(QPalette::WindowText)); + Hsl hsl1 = Hsl::ofQColor(pal.color(QPalette::Window)); + return hsl0.l < hsl1.l; +} +QColor buttonColor(const QPalette &pal) +{ + // temp hack + if (pal.color(QPalette::Button) == pal.color(QPalette::Window)) + return adjustLightness(pal.color(QPalette::Button), 0.01); + return pal.color(QPalette::Button); +} +QColor highlightedOutlineOf(const QPalette &pal) +{ + return adjustLightness(pal.color(QPalette::Highlight), -0.08); +} +QColor dividerColor(const QColor &underlying) +{ + return adjustLightness(underlying, -0.05); +} +QColor lightDividerColor(const QColor &underlying) +{ + return adjustLightness(underlying, 0.02); +} +QColor outlineOf(const QPalette &pal) +{ + return adjustLightness(pal.color(QPalette::Window), -0.1); +} +QColor gutterColorOf(const QPalette &pal) +{ + return adjustLightness(pal.color(QPalette::Window), -0.05); +} +QColor darkGutterColorOf(const QPalette &pal) +{ + return adjustLightness(pal.color(QPalette::Window), -0.08); +} +QColor lightShadeOf(const QColor &underlying) +{ + return adjustLightness(underlying, 0.08); +} +QColor darkShadeOf(const QColor &underlying) +{ + return adjustLightness(underlying, -0.08); +} +QColor overhangShadowOf(const QColor &underlying) +{ + return adjustLightness(underlying, -0.05); +} +QColor sliderGutterShadowOf(const QColor &underlying) +{ + return adjustLightness(underlying, -0.01); +} +QColor specularOf(const QColor &underlying) +{ + return adjustLightness(underlying, 0.01); +} +QColor lightSpecularOf(const QColor &underlying) +{ + return adjustLightness(underlying, 0.05); +} +QColor pressedOf(const QColor &color) +{ + return adjustLightness(color, -0.05); +} +QColor darkPressedOf(const QColor &color) +{ + return adjustLightness(color, -0.08); +} +QColor lightOnOf(const QColor &color) +{ + return adjustLightness(color, -0.04); +} +QColor onOf(const QColor &color) +{ + return adjustLightness(color, -0.08); +} +QColor indicatorColorOf(const QPalette &palette, QPalette::ColorGroup group = QPalette::Current) +{ + if (hack_isLightPalette(palette)) { + qreal adjust = (palette.currentColorGroup() == QPalette::Disabled) ? 0.09 : 0.32; + return adjustLightness(palette.color(group, QPalette::WindowText), adjust); + } + return adjustLightness(palette.color(group, QPalette::WindowText), -0.05); +} +QColor inactiveTabFillColorOf(const QColor &underlying) +{ + // used to be -0.01 + return adjustLightness(underlying, -0.025); +} +QColor progressBarOutlineColorOf(const QPalette &pal) +{ + // Pretty wasteful + Hsl hsl0 = Hsl::ofQColor(pal.color(QPalette::Window)); + Hsl hsl1 = Hsl::ofQColor(pal.color(QPalette::Highlight)); + hsl1.l = Phantom::saturate(qMin(hsl0.l - 0.1, hsl1.l - 0.2)); + return hsl1.toQColor(); +} +QColor itemViewMultiSelectionCurrentBorderOf(const QPalette &pal) +{ + return adjustLightness(pal.color(QPalette::Highlight), -0.15); +} +QColor itemViewHeaderOnLineColorOf(const QPalette &pal) +{ + return hack_isLightPalette(pal) ? highlightedOutlineOf(pal) + : Grad(pal.color(QPalette::WindowText), pal.color(QPalette::Window)).sample(0.5); +} + +#ifdef Q_OS_MACOS +QColor tabBarBase(const QPalette &pal) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 10) && QT_VERSION < QT_VERSION_CHECK(5, 13, 0) || \ + QT_VERSION >= QT_VERSION_CHECK(5, 15, 1) + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSBigSur) { + return hack_isLightPalette(pal) ? QRgb(0xD4D4D4) : QRgb(0x2A2A2A); + } +#endif + return hack_isLightPalette(pal) ? QRgb(0xDD1D1D1) : QRgb(0x252525); +} +QColor tabBarBaseInactive(const QPalette &pal) +{ +#if QT_VERSION >= QT_VERSION_CHECK(5, 12, 10) && QT_VERSION < QT_VERSION_CHECK(5, 13, 0) || \ + QT_VERSION >= QT_VERSION_CHECK(5, 15, 1) + if (QOperatingSystemVersion::current() >= QOperatingSystemVersion::MacOSBigSur) { + return hack_isLightPalette(pal) ? QRgb(0xF5F5F5) : QRgb(0x2D2D2D); + } +#endif + return hack_isLightPalette(pal) ? QRgb(0xF4F4F4) : QRgb(0x282828); +} +#endif +} // namespace DeriveColors + +namespace SwatchColors { +enum SwatchColor { + S_none = 0, + S_window, + S_button, + S_base, + S_text, + S_windowText, + S_highlight, + S_highlightedText, + S_scrollbarGutter, + S_scrollbarSlider, + S_window_outline, + S_window_specular, + S_window_divider, + S_window_lighter, + S_window_darker, + S_frame_outline, + S_button_specular, + S_button_pressed, + S_button_on, + S_button_pressed_specular, + S_sliderHandle, + S_sliderHandle_pressed, + S_sliderHandle_specular, + S_sliderHandle_pressed_specular, + S_base_shadow, + S_base_divider, + S_windowText_disabled, + S_highlight_outline, + S_highlight_specular, + S_progressBar_outline, + S_inactiveTabYesFrame, + S_inactiveTabNoFrame, + S_inactiveTabYesFrame_specular, + S_inactiveTabNoFrame_specular, + S_indicator_current, + S_indicator_disabled, + S_itemView_multiSelection_currentBorder, + S_itemView_headerOnLine, + S_scrollbarGutter_disabled, + + S_tabBarBase, + S_tabBarBase_inactive, + + // Aliases + S_progressBar = S_highlight, + S_progressBar_specular = S_highlight_specular, + S_tabFrame = S_window, + S_tabFrame_specular = S_window_specular, +}; +} + +using Swatchy = SwatchColors::SwatchColor; + +enum { + Num_SwatchColors = SwatchColors::S_tabBarBase_inactive + 1, + Num_ShadowSteps = 3, +}; + +struct PhSwatch : public QSharedData { + // The pens store the brushes within them, so storing the brushes here as + // well is redundant. However, QPen::brush() does not return its brush by + // reference, so we'd end up doing a bunch of inc/dec work every time we use + // one. Also, it saves us the indirection of chasing two pointers (Swatch -> + // QPen -> QBrush) every time we want to get a QColor. + QBrush brushes[Num_SwatchColors]; + QPen pens[Num_SwatchColors]; + QColor scrollbarShadowColors[Num_ShadowSteps]; + + // Note: the casts to int in the assert macros are to suppress a false + // positive warning for tautological comparison in the clang linter. + inline const QColor &color(Swatchy swatchValue) const + { + Q_ASSERT(swatchValue >= 0 && static_cast(swatchValue) < Num_SwatchColors); + return brushes[swatchValue].color(); + } + inline const QBrush &brush(Swatchy swatchValue) const + { + Q_ASSERT(swatchValue >= 0 && static_cast(swatchValue) < Num_SwatchColors); + return brushes[swatchValue]; + } + inline const QPen &pen(Swatchy swatchValue) const + { + Q_ASSERT(swatchValue >= 0 && static_cast(swatchValue) < Num_SwatchColors); + return pens[swatchValue]; + } + + void loadFromQPalette(const QPalette &pal); +}; + +using PhSwatchPtr = QExplicitlySharedDataPointer; +using PhCacheEntry = QPair; +enum : int { + Num_ColorCacheEntries = 10, +}; +using PhSwatchCache = QVarLengthArray; +Q_NEVER_INLINE void PhSwatch::loadFromQPalette(const QPalette &pal) +{ + using namespace SwatchColors; + namespace Dc = DeriveColors; + bool isLight = Dc::hack_isLightPalette(pal); + QColor colors[Num_SwatchColors]; + colors[S_none] = QColor(); + + colors[S_window] = pal.color(QPalette::Window); + colors[S_button] = pal.color(QPalette::Button); + if (colors[S_button] == colors[S_window]) + colors[S_button] = Dc::adjustLightness(colors[S_button], 0.01); + colors[S_base] = pal.color(QPalette::Base); + colors[S_text] = pal.color(QPalette::Text); + colors[S_windowText] = pal.color(QPalette::WindowText); + colors[S_highlight] = pal.color(QPalette::Highlight); + colors[S_highlightedText] = pal.color(QPalette::HighlightedText); + colors[S_scrollbarGutter] = isLight ? Dc::gutterColorOf(pal) : Dc::darkGutterColorOf(pal); + colors[S_scrollbarSlider] = isLight ? colors[S_button] : Dc::adjustLightness(colors[S_window], 0.2); + + colors[S_window_outline] = + isLight ? Dc::adjustLightness(colors[S_window], -0.1) : Dc::adjustLightness(colors[S_window], 0.03); + colors[S_window_specular] = Dc::specularOf(colors[S_window]); + colors[S_window_divider] = isLight ? Dc::dividerColor(colors[S_window]) : Dc::lightDividerColor(colors[S_window]); + colors[S_window_lighter] = Dc::lightShadeOf(colors[S_window]); + colors[S_window_darker] = Dc::darkShadeOf(colors[S_window]); + colors[S_frame_outline] = isLight ? colors[S_window_outline] : Dc::adjustLightness(colors[S_window], 0.08); + colors[S_button_specular] = isLight ? Dc::specularOf(colors[S_button]) : Dc::lightSpecularOf(colors[S_button]); + colors[S_button_pressed] = isLight ? Dc::pressedOf(colors[S_button]) : Dc::darkPressedOf(colors[S_button]); + colors[S_button_on] = isLight ? Dc::lightOnOf(colors[S_button]) : Dc::onOf(colors[S_button]); + colors[S_button_pressed_specular] = + isLight ? Dc::specularOf(colors[S_button_pressed]) : Dc::lightSpecularOf(colors[S_button_pressed]); + + colors[S_sliderHandle] = isLight ? colors[S_button] : Dc::adjustLightness(colors[S_button], -0.03); + colors[S_sliderHandle_specular] = + isLight ? Dc::specularOf(colors[S_sliderHandle]) : Dc::lightSpecularOf(colors[S_sliderHandle]); + colors[S_sliderHandle_pressed] = + isLight ? colors[S_button_pressed] : Dc::adjustLightness(colors[S_button_pressed], 0.03); + colors[S_sliderHandle_pressed_specular] = + isLight ? Dc::specularOf(colors[S_sliderHandle_pressed]) : Dc::lightSpecularOf(colors[S_sliderHandle_pressed]); + + colors[S_base_shadow] = Dc::overhangShadowOf(colors[S_base]); + colors[S_base_divider] = colors[S_window_divider]; + colors[S_windowText_disabled] = pal.color(QPalette::Disabled, QPalette::WindowText); + colors[S_highlight_outline] = + isLight ? Dc::adjustLightness(colors[S_highlight], -0.02) : Dc::adjustLightness(colors[S_highlight], 0.05); + colors[S_highlight_specular] = Dc::specularOf(colors[S_highlight]); + colors[S_progressBar_outline] = Dc::progressBarOutlineColorOf(pal); + colors[S_inactiveTabYesFrame] = Dc::inactiveTabFillColorOf(colors[S_tabFrame]); + colors[S_inactiveTabNoFrame] = Dc::inactiveTabFillColorOf(colors[S_window]); + colors[S_inactiveTabYesFrame_specular] = Dc::specularOf(colors[S_inactiveTabYesFrame]); + colors[S_inactiveTabNoFrame_specular] = Dc::specularOf(colors[S_inactiveTabNoFrame]); + colors[S_indicator_current] = Dc::indicatorColorOf(pal, QPalette::Current); + colors[S_indicator_disabled] = Dc::indicatorColorOf(pal, QPalette::Disabled); + colors[S_itemView_multiSelection_currentBorder] = Dc::itemViewMultiSelectionCurrentBorderOf(pal); + colors[S_itemView_headerOnLine] = Dc::itemViewHeaderOnLineColorOf(pal); + colors[S_scrollbarGutter_disabled] = colors[S_window]; + +#ifdef Q_OS_MACOS + colors[S_tabBarBase] = Dc::tabBarBase(pal); + colors[S_tabBarBase_inactive] = Dc::tabBarBaseInactive(pal); +#else + colors[S_tabBarBase] = pal.color(QPalette::Active, QPalette::Window); + colors[S_tabBarBase_inactive] = pal.color(QPalette::Inactive, QPalette::Window); +#endif + + brushes[S_none] = Qt::NoBrush; + for (int i = S_none + 1; i < Num_SwatchColors; ++i) { + // todo try to reuse + brushes[i] = colors[i]; + } + pens[S_none] = Qt::NoPen; + // QPen::setColor constructs a QBrush behind the scenes, so better to just + // re-use the ones we already made. + for (int i = S_none + 1; i < Num_SwatchColors; ++i) { + pens[i].setBrush(brushes[i]); + // Width is already 1, don't need to set it. Caps and joins already fine at + // their defaults, too. + } + + Grad gutterGrad(Dc::sliderGutterShadowOf(colors[S_scrollbarGutter]), colors[S_scrollbarGutter]); + for (int i = 0; i < Num_ShadowSteps; ++i) { + scrollbarShadowColors[i] = gutterGrad.sample(i / static_cast(Num_ShadowSteps)); + } +} + +// This is the "hash" (not really a hash) function we'll use on the happy fast +// path when looking up a PhSwatch for a given QPalette. It's fragile, because +// it uses QPalette::cacheKey(), so it may not match even when the contents +// (currentColorGroup + the RGB colors) of the QPalette are actually a match. +// But it's cheaper to calculate, so we'll store a single one of these "hashes" +// for the head (most recently used) cached PhSwatch, and check to see if it +// matches. This is the most common case, so we can usually save some work by +// doing this. (The second most common case is probably having a different +// ColorGroup but the rest of the contents are the same, but we don't have a +// special path for that.) +inline quint64 fastfragile_hash_qpalette(const QPalette &p) +{ + union { + qint64 i; + quint64 u; + } x; + x.i = p.cacheKey(); + // QPalette::ColorGroup has range 0..5 (inclusive), so it only uses 3 bits. + // The high 32 bits in QPalette::cacheKey() are a global incrementing serial + // number for the QPalette creation. We don't store (2^29-1) things in our + // cache, and I doubt that many will ever be created in a real application + // while also retaining some of them across such a broad time range, so it's + // really unlikely that repurposing these top 3 bits to also include the + // QPalette::currentColorGroup() (which the cacheKey doesn't include for some + // reason...) will generate a collision. + // + // This may not be true in the future if the way the QPalette::cacheKey() is + // generated changes. If that happens, change to use the definition of + // `fastfragile_hash_qpalette` below, which is less likely to collide with an + // arbitrarily numbered key but also does more work. +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + x.u = x.u ^ (static_cast(p.currentColorGroup()) << (64 - 3)); + return x.u; +#else + // Use this definition here if the contents/layout of QPalette::cacheKey() + // (as in, the C++ code in qpalette.cpp) are changed. We'll also put a Qt6 + // guard for it, so that it will default to a more safe definition on the + // next guaranteed big breaking change for Qt. A warning will hopefully get + // someone to double-check it at some point in the future. +#warning "Verify contents and layout of QPalette::cacheKey() have not changed" + QtPrivate::QHashCombine c; + uint h = qHash(p.currentColorGroup()); + h = c(h, (uint)(x.u & 0xFFFFFFFFu)); + h = c(h, (uint)((x.u >> 32) & 0xFFFFFFFFu)); + return h; +#endif +} + +// This hash function is for when we want an actual accurate hash of a +// QPalette. QPalette's cacheKey() isn't very reliable -- it seems to change to +// a new random number whenever it's modified, with the exception of the +// currentColorGroup being changed. This kind of sucks for us, because it means +// two QPalette's can have the same contents but hash to different values. And +// this actually happens a lot! We'll do the hashing ourselves. Also, we're not +// interested in all of the colors, only some of them, and we ignore +// pens/brushes. +uint accurate_hash_qpalette(const QPalette &p) +{ + // Probably shouldn't use this, could replace with our own guy. It's not a + // great hasher anyway. + QtPrivate::QHashCombine c; + uint h = qHash(p.currentColorGroup()); + QPalette::ColorRole const roles[] = {QPalette::Window, QPalette::Button, QPalette::Base, QPalette::Text, + QPalette::WindowText, QPalette::Highlight, QPalette::HighlightedText}; + for (auto role : roles) { + h = c(h, p.color(role).rgb()); + } + return h; +} + +Q_NEVER_INLINE PhSwatchPtr deep_getCachedSwatchOfQPalette(PhSwatchCache *cache, + int cacheCount, // Just saving a call to cache->count() + const QPalette &qpalette) +{ + // Calculate our hash key from the QPalette's current ColorGroup and the + // actual RGBA values that we use. We have to mix the ColorGroup in + // ourselves, because QPalette does not account for it in the cache key. + uint key = accurate_hash_qpalette(qpalette); + int n = cacheCount; + int idx = -1; + for (int i = 0; i < n; ++i) { + const auto &x = cache->at(i); + if (x.first == key) { + idx = i; + break; + } + } + if (idx == -1) { + PhSwatchPtr ptr; + if (n < Num_ColorCacheEntries) { + ptr = new PhSwatch; + } + else { + // Remove the oldest guy from the cache. Remember that because we may + // re-enter QStyle functions multiple times when drawing or calculating + // something, we may have to load several swaitches derived from + // different QPalettes on different stack frames at the same time. But as + // an extra cost-savings measure, we'll check and see if something else + // has a reference to the removed guy. If there aren't any references to + // it, then we'll re-use it directly instead of allocating a new one. (We + // will only ever run into the case where we can't re-use it directly if + // some other stack frame has a reference to it.) This is nice because + // then the QPens and QBrushes don't all also have to reallocate their d + // ptr stuff. + ptr = cache->last().second; + cache->removeLast(); + ptr.detach(); + } + ptr->loadFromQPalette(qpalette); + cache->prepend(PhCacheEntry(key, ptr)); + return ptr; + } + else { + if (idx == 0) { + return cache->at(idx).second; + } + PhCacheEntry e = cache->at(idx); + // Using std::move from algorithm could be more efficient here, but I don't + // want to depend on algorithm or write this myself. Small N with a movable + // type means it doesn't really matter in this case. + cache->remove(idx); + cache->prepend(e); + return e.second; + } +} + +Q_NEVER_INLINE PhSwatchPtr getCachedSwatchOfQPalette(PhSwatchCache *cache, + quint64 *headSwatchFastKey, // Optimistic fast-path quick hash key + const QPalette &qpalette) +{ + quint64 ck = fastfragile_hash_qpalette(qpalette); + int cacheCount = cache->count(); + // This hint is counter-productive if we're being called in a way that + // interleaves different QPalettes. But misses to this optimistic path were + // rare in my tests. (Probably not going to amount to any significant + // difference, anyway.) + if (Q_LIKELY(cacheCount > 0 && *headSwatchFastKey == ck)) { + return cache->at(0).second; + } + *headSwatchFastKey = ck; + return deep_getCachedSwatchOfQPalette(cache, cacheCount, qpalette); +} + +} // namespace +} // namespace Phantom + +class BaseStylePrivate { +public: + BaseStylePrivate(); + + // A fast'n'easy hash of QPalette::cacheKey()+QPalette::currentColorGroup() + // of only the head element of swatchCache list. The most common thing that + // happens when deriving a PhSwatch from a QPalette is that we just end up + // re-using the last one that we used. For that case, we can potentially save + // calling `accurate_hash_qpalette()` and instead use the value returned by + // QPalette::cacheKey() (and QPalette::currentColorGroup()) and compare it to + // the last one that we used. If it matches, then we know we can just use the + // head of the cache list without having to do any further checks, which + // saves a few hundred (!) nanoseconds. + // + // However, the `QPalette::cacheKey()` value is fragile and may change even + // if none of the colors in the QPalette have changed. In other words, all of + // the colors in a QPalette may match another QPalette (or a derived + // PhSwatch) even if the `QPalette::cacheKey()` value is different. + // + // So if `QPalette::cacheKey()+currentColorGroup()` doesn't match, then we'll + // use our more accurate `accurate_hash_qpalette()` to get a more accurate + // comparison key, and then search through the cache list to find a matching + // cached PhSwatch. (The more accurate cache key is what we store alongside + // each PhSwatch element, as the `.first` in each QPair. The + // QPalette::cacheKey() that we associate with the PhSwatch in the head + // position, `headSwatchFastKey`, is only stored for our single head element, + // as a special fast case.) If we find it, we'll move it to the head of the + // cache list. If not, we'll make a new one, and put it at the head. Either + // way, the `headSwatchFastKey` will be updated to the + // `fastfragile_qpalette_hash()` of the QPalette that we needed to derive a + // PhSwatch from, so that if we get called with the same QPalette again next + // time (which is probably going to be the case), it'll match and we can take + // the fast path. + quint64 headSwatchFastKey; + + Phantom::PhSwatchCache swatchCache; + QPen checkBox_pen_scratch; +}; + +namespace Phantom { +namespace { + +// Minimal QPainter save/restore just for pen, brush, and AA render hint. If +// you touch more than that, this won't help you. But if you're only touching +// those things, this will save you some typing from manually storing/saving +// those properties each time. +struct PSave final { + Q_DISABLE_COPY(PSave) + + explicit PSave(QPainter *painter_) + { + Q_ASSERT(painter_); + painter = painter_; + pen = painter_->pen(); + brush = painter_->brush(); + hintAA = painter_->testRenderHint(QPainter::Antialiasing); + } + Q_NEVER_INLINE void restore() + { + QPainter *p = painter; + if (!p) + return; + bool hintAA_ = hintAA; + // QPainter will check both pen and brush for equality when setting, so we + // should set it unconditionally here. + p->setPen(pen); + p->setBrush(brush); + // But it won't check the render hint to guard against doing extra work. + // We'll do that ourselves. (Though at least for the raster engine, this + // doesn't cause very much work to occur. But it still chases a few + // pointers.) + if (p->testRenderHint(QPainter::Antialiasing) != hintAA_) { + p->setRenderHint(QPainter::Antialiasing, hintAA_); + } + painter = nullptr; + pen = QPen(); + brush = QBrush(); + hintAA = false; + } + ~PSave() + { + restore(); + } + +private: + QPainter *painter; + QPen pen; + QBrush brush; + bool hintAA; +}; + +const qreal Pi = M_PI; + +qreal dpiScaled(qreal value) +{ +#ifdef Q_OS_MAC + // On mac the DPI is always 72 so we should not scale it + return value; +#else + const qreal scale = qt_defaultDpiX() / 96.0; + return value * scale; +#endif +} + +struct MenuItemMetrics { + int fontHeight; + int frameThickness; + int leftMargin; + int rightMarginForText; + int rightMarginForArrow; + int topMargin; + int bottomMargin; + int checkWidth; + int checkRightSpace; + int iconRightSpace; + int mnemonicSpace; + int arrowSpace; + int arrowWidth; + int separatorHeight; + int totalHeight; + + static MenuItemMetrics ofFontHeight(int fontHeight); + +private: + MenuItemMetrics() {} +}; + +MenuItemMetrics MenuItemMetrics::ofFontHeight(int fontHeight) +{ + MenuItemMetrics m; + m.fontHeight = fontHeight; + m.frameThickness = dpiScaled(1.0); + m.leftMargin = static_cast(fontHeight * MenuItem_LeftMarginFontRatio); + m.rightMarginForText = static_cast(fontHeight * MenuItem_RightMarginForTextFontRatio); + m.rightMarginForArrow = static_cast(fontHeight * MenuItem_RightMarginForArrowFontRatio); + m.topMargin = static_cast(fontHeight * MenuItem_VerticalMarginsFontRatio); + m.bottomMargin = static_cast(fontHeight * MenuItem_VerticalMarginsFontRatio); + int checkVMargin = static_cast(fontHeight * MenuItem_CheckMarkVerticalInsetFontRatio); + int checkHeight = fontHeight - checkVMargin * 2; + if (checkHeight < 0) + checkHeight = 0; + m.checkWidth = static_cast(checkHeight * CheckMark_WidthOfHeightScale); + m.checkRightSpace = static_cast(fontHeight * MenuItem_CheckRightSpaceFontRatio); + m.iconRightSpace = static_cast(fontHeight * MenuItem_IconRightSpaceFontRatio); + m.mnemonicSpace = static_cast(fontHeight * MenuItem_TextMnemonicSpaceFontRatio); + m.arrowSpace = static_cast(fontHeight * MenuItem_SubMenuArrowSpaceFontRatio); + m.arrowWidth = static_cast(fontHeight * MenuItem_SubMenuArrowWidthFontRatio); + m.separatorHeight = static_cast(fontHeight * MenuItem_SeparatorHeightFontRatio); + // Odd numbers only + m.separatorHeight = (m.separatorHeight / 2) * 2 + 1; + m.totalHeight = fontHeight + m.frameThickness * 2 + m.topMargin + m.bottomMargin; + return m; +} + +QRect menuItemContentRect(const MenuItemMetrics &metrics, QRect itemRect, bool hasArrow) +{ + QRect r = itemRect; + int ft = metrics.frameThickness; + int rm = hasArrow ? metrics.rightMarginForArrow : metrics.rightMarginForText; + r.adjust(ft + metrics.leftMargin, ft + metrics.topMargin, -(ft + rm), -(ft + metrics.bottomMargin)); + return r.isValid() ? r : QRect(); +} +QRect menuItemCheckRect(const MenuItemMetrics &metrics, Qt::LayoutDirection direction, QRect itemRect, bool hasArrow) +{ + QRect r = menuItemContentRect(metrics, itemRect, hasArrow); + int checkVMargin = static_cast(metrics.fontHeight * MenuItem_CheckMarkVerticalInsetFontRatio); + if (checkVMargin < 0) + checkVMargin = 0; + r.setSize(QSize(metrics.checkWidth, metrics.fontHeight)); + r.adjust(0, checkVMargin, 0, -checkVMargin); + return QStyle::visualRect(direction, itemRect, r) & itemRect; +} +QRect menuItemIconRect(const MenuItemMetrics &metrics, Qt::LayoutDirection direction, QRect itemRect, bool hasArrow) +{ + QRect r = menuItemContentRect(metrics, itemRect, hasArrow); + r.setX(r.x() + metrics.checkWidth + metrics.checkRightSpace); + r.setSize(QSize(metrics.fontHeight, metrics.fontHeight)); + return QStyle::visualRect(direction, itemRect, r) & itemRect; +} +QRect menuItemTextRect(const MenuItemMetrics &metrics, Qt::LayoutDirection direction, QRect itemRect, bool hasArrow, + bool hasIcon, int tabWidth) +{ + QRect r = menuItemContentRect(metrics, itemRect, hasArrow); + r.setX(r.x() + metrics.checkWidth + metrics.checkRightSpace); + if (hasIcon) { + r.setX(r.x() + metrics.fontHeight + metrics.iconRightSpace); + } + r.setWidth(r.width() - tabWidth); + r.setHeight(metrics.fontHeight); + r &= itemRect; + return QStyle::visualRect(direction, itemRect, r); +} +QRect menuItemMnemonicRect( + const MenuItemMetrics &metrics, Qt::LayoutDirection direction, QRect itemRect, bool hasArrow, int tabWidth) +{ + QRect r = menuItemContentRect(metrics, itemRect, hasArrow); + int x = r.x() + r.width() - tabWidth; + if (hasArrow) + x -= metrics.arrowSpace + metrics.arrowWidth; + r.setX(x); + r.setHeight(metrics.fontHeight); + r &= itemRect; + return QStyle::visualRect(direction, itemRect, r); +} +QRect menuItemArrowRect(const MenuItemMetrics &metrics, Qt::LayoutDirection direction, QRect itemRect) +{ + QRect r = menuItemContentRect(metrics, itemRect, true); + int x = r.x() + r.width() - metrics.arrowWidth; + r.setX(x); + r &= itemRect; + return QStyle::visualRect(direction, itemRect, r); +} + +Q_NEVER_INLINE +void progressBarFillRects(const QStyleOptionProgressBar *bar, + // The rect that represents the filled/completed region + QRect &outFilled, + // The rect that represents the incomplete region + QRect &outNonFilled, + // Whether or not the progress bar is indeterminate + bool &outIsIndeterminate) +{ + QRect ra = bar->rect; + QRect rb = ra; + bool isHorizontal = bar->orientation != Qt::Vertical; + bool isInverted = bar->invertedAppearance; + bool isIndeterminate = bar->minimum == 0 && bar->maximum == 0; + bool isForward = !isHorizontal || bar->direction != Qt::RightToLeft; + if (isInverted) + isForward = !isForward; + int maxLen = isHorizontal ? ra.width() : ra.height(); + const auto availSteps = qMax(Q_INT64_C(1), qint64(bar->maximum) - bar->minimum); + const auto progress = qMax(bar->progress, bar->minimum); // workaround for bug in QProgressBar + const auto progressSteps = qint64(progress) - bar->minimum; + const auto progressBarWidth = progressSteps * maxLen / availSteps; + int barLen = isIndeterminate ? maxLen : progressBarWidth; + if (isHorizontal) { + if (isForward) { + ra.setWidth(barLen); + rb.setX(barLen); + } + else { + ra.setX(ra.x() + ra.width() - barLen); + rb.setWidth(rb.width() - barLen); + } + } + else { + if (isForward) { + ra.setY(ra.y() + ra.height() - barLen); + rb.setHeight(rb.height() - barLen); + } + else { + ra.setHeight(barLen); + rb.setY(barLen); + } + } + outFilled = ra; + outNonFilled = rb; + outIsIndeterminate = isIndeterminate; +} + +int calcBigLineSize(int radius) +{ + int bigLineSize = radius / 6; + if (bigLineSize < 4) + bigLineSize = 4; + if (bigLineSize > radius / 2) + bigLineSize = radius / 2; + return bigLineSize; +} +Q_NEVER_INLINE QPointF calcRadialPos(const QStyleOptionSlider *dial, qreal offset) +{ + const int width = dial->rect.width(); + const int height = dial->rect.height(); + const int r = qMin(width, height) / 2; + const int currentSliderPosition = dial->upsideDown ? dial->sliderPosition : (dial->maximum - dial->sliderPosition); + qreal a = 0; + if (dial->maximum == dial->minimum) + a = Pi / 2; + else if (dial->dialWrapping) + a = Pi * 3 / 2 - (currentSliderPosition - dial->minimum) * 2 * Pi / (dial->maximum - dial->minimum); + else + a = (Pi * 8 - (currentSliderPosition - dial->minimum) * 10 * Pi / (dial->maximum - dial->minimum)) / 6; + qreal xc = width / 2.0; + qreal yc = height / 2.0; + qreal len = r - calcBigLineSize(r) - 3; + qreal back = offset * len; + QPointF pos(QPointF(xc + back * qCos(a), yc - back * qSin(a))); + return pos; +} +Q_NEVER_INLINE QPolygonF calcLines(const QStyleOptionSlider *dial) +{ + QPolygonF poly; + qreal width = dial->rect.width(); + qreal height = dial->rect.height(); + qreal r = qMin(width, height) / 2.0; + int bigLineSize = calcBigLineSize(r); + + qreal xc = width / 2.0 + 0.5; + qreal yc = height / 2.0 + 0.5; + const int ns = dial->tickInterval; + if (!ns) // Invalid values may be set by Qt Designer. + return poly; + int notches = (dial->maximum + ns - 1 - dial->minimum) / ns; + if (notches <= 0) + return poly; + if (dial->maximum < dial->minimum || dial->maximum - dial->minimum > 1000) { + int maximum = dial->minimum + 1000; + notches = (maximum + ns - 1 - dial->minimum) / ns; + } + poly.resize(2 + 2 * notches); + int smallLineSize = bigLineSize / 2; + for (int i = 0; i <= notches; ++i) { + qreal angle = dial->dialWrapping ? Pi * 3 / 2 - i * 2 * Pi / notches : (Pi * 8 - i * 10 * Pi / notches) / 6; + qreal s = qSin(angle); + qreal c = qCos(angle); + if (i == 0 || (((ns * i) % (dial->pageStep ? dial->pageStep : 1)) == 0)) { + poly[2 * i] = QPointF(xc + (r - bigLineSize) * c, yc - (r - bigLineSize) * s); + poly[2 * i + 1] = QPointF(xc + r * c, yc - r * s); + } + else { + poly[2 * i] = QPointF(xc + (r - 1 - smallLineSize) * c, yc - (r - 1 - smallLineSize) * s); + poly[2 * i + 1] = QPointF(xc + (r - 1) * c, yc - (r - 1) * s); + } + } + return poly; +} +// This will draw a nice and shiny QDial for us. We don't want +// all the shinyness in QWindowsStyle, hence we place it here +Q_NEVER_INLINE void drawDial(const QStyleOptionSlider *option, QPainter *painter) +{ + namespace Dc = Phantom::DeriveColors; + const QPalette &pal = option->palette; + QColor buttonColor = Dc::buttonColor(option->palette); + const int width = option->rect.width(); + const int height = option->rect.height(); + const bool enabled = option->state & QStyle::State_Enabled; + qreal r = qMin(width, height) / 2.0; + r -= r / 50.0; + painter->save(); + painter->setRenderHint(QPainter::Antialiasing); + // Draw notches + if (option->subControls & QStyle::SC_DialTickmarks) { + painter->setPen(pal.color(QPalette::Disabled, QPalette::Text)); + painter->drawLines(calcLines(option)); + } + const qreal d_ = r / 6; + const qreal dx = option->rect.x() + d_ + (width - 2 * r) / 2 + 1; + const qreal dy = option->rect.y() + d_ + (height - 2 * r) / 2 + 1; + QRectF br = QRectF(dx + 0.5, dy + 0.5, int(r * 2 - 2 * d_ - 2), int(r * 2 - 2 * d_ - 2)); + if (enabled) { + painter->setBrush(buttonColor); + } + else { + painter->setBrush(Qt::NoBrush); + } + painter->setPen(Dc::outlineOf(option->palette)); + painter->drawEllipse(br); + painter->setBrush(Qt::NoBrush); + painter->setPen(Dc::specularOf(buttonColor)); + painter->drawEllipse(br.adjusted(1, 1, -1, -1)); + if (option->state & QStyle::State_HasFocus) { + QColor highlight = pal.highlight().color(); + highlight.setHsv(highlight.hue(), qMin(160, highlight.saturation()), qMax(230, highlight.value())); + highlight.setAlpha(127); + painter->setPen(QPen(highlight, 2.0)); + painter->setBrush(Qt::NoBrush); + painter->drawEllipse(br.adjusted(-1, -1, 1, 1)); + } + QPointF dp = calcRadialPos(option, 0.70); + const qreal ds = r / 7.0; + QRectF dialRect(dp.x() - ds, dp.y() - ds, 2 * ds, 2 * ds); + painter->setBrush(option->palette.color(QPalette::Window)); + painter->setPen(Dc::outlineOf(option->palette)); + painter->drawEllipse(dialRect.adjusted(-1, -1, 1, 1)); + painter->restore(); +} + +int fontMetricsWidth(const QFontMetrics &fontMetrics, const QString &text) +{ +#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0) + return fontMetrics.width(text, text.size(), Qt::TextBypassShaping); +#else + return fontMetrics.horizontalAdvance(text); +#endif +} + +// This always draws the arrow with the correct aspect ratio, even if the +// provided bounding rect is non-square. The base edge of the triangle is +// snapped to a whole pixel to avoid anti-aliasing making it look soft. +// +// Expected time (release): 5usecs for regular-sized arrows +Q_NEVER_INLINE void drawArrow(QPainter *p, QRect rect, Qt::ArrowType arrowDirection, const QBrush &brush) +{ + const qreal ArrowBaseRatio = 0.70; + qreal irx, iry, irw, irh; + QRectF(rect).getRect(&irx, &iry, &irw, &irh); + if (irw < 1.0 || irh < 1.0) + return; + qreal dw, dh; + if (arrowDirection == Qt::LeftArrow || arrowDirection == Qt::RightArrow) { + dw = ArrowBaseRatio; + dh = 1.0; + } + else { + dw = 1.0; + dh = ArrowBaseRatio; + } + QSizeF sz = QSizeF(dw, dh).scaled(irw, irh, Qt::KeepAspectRatio); + qreal aw = sz.width(); + qreal ah = sz.height(); + qreal ax, ay; + ax = irx + (irw - aw) / 2; + ay = iry + (irh - ah) / 2; + QRectF arrowRect(ax, ay, aw, ah); + QPointF points[3]; + switch (arrowDirection) { + case Qt::DownArrow: + arrowRect.setTop(std::round(arrowRect.top())); + points[0] = arrowRect.topLeft(); + points[1] = arrowRect.topRight(); + points[2] = QPointF(arrowRect.center().x(), arrowRect.bottom()); + break; + case Qt::RightArrow: { + arrowRect.setLeft(std::round(arrowRect.left())); + points[0] = arrowRect.topLeft(); + points[1] = arrowRect.bottomLeft(); + points[2] = QPointF(arrowRect.right(), arrowRect.center().y()); + break; + } + case Qt::LeftArrow: + arrowRect.setRight(std::round(arrowRect.right())); + points[0] = arrowRect.topRight(); + points[1] = arrowRect.bottomRight(); + points[2] = QPointF(arrowRect.left(), arrowRect.center().y()); + break; + case Qt::UpArrow: + default: + arrowRect.setBottom(std::round(arrowRect.bottom())); + points[0] = arrowRect.bottomLeft(); + points[1] = arrowRect.bottomRight(); + points[2] = QPointF(arrowRect.center().x(), arrowRect.top()); + break; + } + auto oldPen = p->pen(); + auto oldBrush = p->brush(); + bool oldAA = p->testRenderHint(QPainter::Antialiasing); + p->setPen(Qt::NoPen); + p->setBrush(brush); + if (!oldAA) { + p->setRenderHint(QPainter::Antialiasing); + } + p->drawConvexPolygon(points, 3); + p->setPen(oldPen); + p->setBrush(oldBrush); + if (!oldAA) { + p->setRenderHint(QPainter::Antialiasing, false); + } +} + +// Pass allowEnabled as false to always draw the arrow with the disabled color, +// even if the underlying palette's current color group is not disabled. Useful +// for parts of widgets which may want to be drawn as disabled even if the +// actual widget is not set as disabled, such as scrollbar step buttons when +// the scrollbar has no movable range. +Q_NEVER_INLINE void drawArrow(QPainter *painter, QRect rect, Qt::ArrowType type, const PhSwatch &swatch, + bool allowEnabled = true, qreal lightnessAdjustment = 0.0) +{ + if (rect.isEmpty()) + return; + using namespace SwatchColors; + auto brush = swatch.brush(allowEnabled ? S_indicator_current : S_indicator_disabled); + brush.setColor(DeriveColors::adjustLightness(brush.color(), lightnessAdjustment)); + Phantom::drawArrow(painter, rect, type, brush); +} + +// This draws exactly within the rect provided. If you provide a square rect, +// it will appear too wide -- you probably want to shrink the width of your +// square first by multiplying it with CheckMark_WidthOfHeightScale. +Q_NEVER_INLINE void drawCheck( + QPainter *painter, QPen &scratchPen, const QRectF &r, const PhSwatch &swatch, Swatchy color) +{ + using namespace Phantom::SwatchColors; + qreal rx, ry, rw, rh; + QRectF(r).getRect(&rx, &ry, &rw, &rh); + qreal penWidth = 0.25 * qMin(rw, rh); + qreal dimx = rw - penWidth; + qreal dimy = rh - penWidth; + if (dimx < 0.5 || dimy < 0.5) + return; + qreal x = (rw - dimx) / 2 + rx; + qreal y = (rh - dimy) / 2 + ry; + QPointF points[3]; + points[0] = QPointF(0.0, 0.55); + points[1] = QPointF(0.4, 1.0); + points[2] = QPointF(1.0, 0); + for (int i = 0; i < 3; ++i) { + QPointF pnt = points[i]; + pnt.setX(pnt.x() * dimx + x); + pnt.setY(pnt.y() * dimy + y); + points[i] = pnt; + } + scratchPen.setBrush(swatch.brush(color)); + scratchPen.setCapStyle(Qt::RoundCap); + scratchPen.setJoinStyle(Qt::RoundJoin); + scratchPen.setWidthF(penWidth); + Phantom::PSave save(painter); + if (!painter->testRenderHint(QPainter::Antialiasing)) + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(scratchPen); + painter->setBrush(Qt::NoBrush); + painter->drawPolyline(points, 3); +} + +Q_NEVER_INLINE void drawHyphen( + QPainter *painter, QPen &scratchPen, const QRectF &r, const PhSwatch &swatch, Swatchy color) +{ + using namespace Phantom::SwatchColors; + qreal rx, ry, rw, rh; + QRectF(r).getRect(&rx, &ry, &rw, &rh); + qreal penWidth = 0.25 * qMin(rw, rh); + qreal dimx = rw - penWidth; + qreal dimy = rh - penWidth; + if (dimx < 0.5 || dimy < 0.5) + return; + qreal x = (rw - dimx) / 2 + rx; + qreal y = (rh - dimy) / 2 + ry; + QPointF p0(0.0 * dimx + x, 0.5 * dimy + y); + QPointF p1(1.0 * dimx + x, 0.5 * dimy + y); + scratchPen.setBrush(swatch.brush(color)); + scratchPen.setCapStyle(Qt::RoundCap); + scratchPen.setWidthF(penWidth); + Phantom::PSave save(painter); + if (!painter->testRenderHint(QPainter::Antialiasing)) + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(scratchPen); + painter->setBrush(Qt::NoBrush); + painter->drawLine(p0, p1); +} + +Q_NEVER_INLINE void drawMdiButton( + QPainter *painter, const QStyleOptionTitleBar *option, QRect tmp, bool hover, bool sunken) +{ + QColor dark; + dark.setHsv(option->palette.button().color().hue(), qMin(255, (option->palette.button().color().saturation())), + qMin(255, option->palette.button().color().value() * 0.7)); + QColor highlight = option->palette.highlight().color(); + bool active = (option->titleBarState & QStyle::State_Active); + QColor titleBarHighlight(255, 255, 255, 60); + if (sunken) + painter->fillRect(tmp.adjusted(1, 1, -1, -1), option->palette.highlight().color().darker(120)); + else if (hover) + painter->fillRect(tmp.adjusted(1, 1, -1, -1), QColor(255, 255, 255, 20)); + if (sunken) + titleBarHighlight = highlight.darker(130); + QColor mdiButtonBorderColor(active ? option->palette.highlight().color().darker(180) : dark.darker(110)); + painter->setPen(QPen(mdiButtonBorderColor)); + const QLine lines[4] = {QLine(tmp.left() + 2, tmp.top(), tmp.right() - 2, tmp.top()), + QLine(tmp.left() + 2, tmp.bottom(), tmp.right() - 2, tmp.bottom()), + QLine(tmp.left(), tmp.top() + 2, tmp.left(), tmp.bottom() - 2), + QLine(tmp.right(), tmp.top() + 2, tmp.right(), tmp.bottom() - 2)}; + painter->drawLines(lines, 4); + const QPoint points[4] = {QPoint(tmp.left() + 1, tmp.top() + 1), QPoint(tmp.right() - 1, tmp.top() + 1), + QPoint(tmp.left() + 1, tmp.bottom() - 1), QPoint(tmp.right() - 1, tmp.bottom() - 1)}; + painter->drawPoints(points, 4); + painter->setPen(titleBarHighlight); + painter->drawLine(tmp.left() + 2, tmp.top() + 1, tmp.right() - 2, tmp.top() + 1); + painter->drawLine(tmp.left() + 1, tmp.top() + 2, tmp.left() + 1, tmp.bottom() - 2); +} + +Q_NEVER_INLINE void fillRectOutline(QPainter *p, QRect rect, QMargins margins, const QColor &brush) +{ + int x, y, w, h; + rect.getRect(&x, &y, &w, &h); + int ml = margins.left(); + int mt = margins.top(); + int mr = margins.right(); + int mb = margins.bottom(); + QRect r0(x, y, w, mt); + QRect r1(x, y + mt, ml, h - (mt + mb)); + QRect r2((x + w) - mr, y + mt, mr, h - (mt + mb)); + QRect r3(x, (y + h) - mb, w, mb); + p->fillRect(r0 & rect, brush); + p->fillRect(r1 & rect, brush); + p->fillRect(r2 & rect, brush); + p->fillRect(r3 & rect, brush); +} +void fillRectOutline(QPainter *p, QRect rect, int thickness, const QColor &color) +{ + fillRectOutline(p, rect, QMargins(thickness, thickness, thickness, thickness), color); +} +Q_NEVER_INLINE void fillRectEdges(QPainter *p, QRect rect, Qt::Edges edges, QMargins margins, const QColor &color) +{ + int x, y, w, h; + rect.getRect(&x, &y, &w, &h); + if (edges & Qt::LeftEdge) { + int ml = margins.left(); + QRect r0(x, y, ml, h); + p->fillRect(r0 & rect, color); + } + if (edges & Qt::TopEdge) { + int mt = margins.top(); + QRect r1(x, y, w, mt); + p->fillRect(r1 & rect, color); + } + if (edges & Qt::RightEdge) { + int mr = margins.right(); + QRect r2((x + w) - mr, y, mr, h); + p->fillRect(r2 & rect, color); + } + if (edges & Qt::BottomEdge) { + int mb = margins.bottom(); + QRect r3(x, (y + h) - mb, w, mb); + p->fillRect(r3 & rect, color); + } +} +void fillRectEdges(QPainter *p, QRect rect, Qt::Edges edges, int thickness, const QColor &color) +{ + fillRectEdges(p, rect, edges, QMargins(thickness, thickness, thickness, thickness), color); +} +inline QRect expandRect(QRect rect, Qt::Edges edges, int delta) +{ + int l = edges & Qt::LeftEdge ? -delta : 0; + int t = edges & Qt::TopEdge ? -delta : 0; + int r = edges & Qt::RightEdge ? delta : 0; + int b = edges & Qt::BottomEdge ? delta : 0; + return rect.adjusted(l, t, r, b); +} +inline Qt::Edge oppositeEdge(Qt::Edge edge) +{ + switch (edge) { + case Qt::LeftEdge: + return Qt::RightEdge; + case Qt::TopEdge: + return Qt::BottomEdge; + case Qt::RightEdge: + return Qt::LeftEdge; + case Qt::BottomEdge: + return Qt::TopEdge; + } + return Qt::TopEdge; +} +inline QRect rectTranslatedTowardEdge(QRect rect, Qt::Edge edge, int delta) +{ + switch (edge) { + case Qt::LeftEdge: + return rect.translated(-delta, 0); + case Qt::TopEdge: + return rect.translated(0, -delta); + case Qt::RightEdge: + return rect.translated(delta, 0); + case Qt::BottomEdge: + return rect.translated(0, delta); + } + return rect; +} +Q_NEVER_INLINE QRect rectFromInnerEdgeWithThickness(QRect rect, Qt::Edge edge, int thickness) +{ + int x, y, w, h; + rect.getRect(&x, &y, &w, &h); + QRect r; + switch (edge) { + case Qt::LeftEdge: + r = QRect(x, y, thickness, h); + break; + case Qt::TopEdge: + r = QRect(x, y, w, thickness); + break; + case Qt::RightEdge: + r = QRect((x + w) - thickness, y, thickness, h); + break; + case Qt::BottomEdge: + r = QRect(x, (y + h) - thickness, w, thickness); + break; + } + return r & rect; +} +Q_NEVER_INLINE void paintSolidRoundRect(QPainter *p, QRect rect, qreal radius, const PhSwatch &swatch, Swatchy fill) +{ + if (!fill) + return; + bool aa = p->testRenderHint(QPainter::Antialiasing); + if (radius > 0.5) { + if (!aa) + p->setRenderHint(QPainter::Antialiasing); + p->setPen(swatch.pen(SwatchColors::S_none)); + p->setBrush(swatch.brush(fill)); + p->drawRoundedRect(rect, radius, radius); + } + else { + if (aa) + p->setRenderHint(QPainter::Antialiasing, false); + p->fillRect(rect, swatch.color(fill)); + } +} +Q_NEVER_INLINE void paintBorderedRoundRect( + QPainter *p, QRect rect, qreal radius, const PhSwatch &swatch, Swatchy stroke, Swatchy fill) +{ + if (rect.width() < 1 || rect.height() < 1) + return; + if (!stroke && !fill) + return; + bool aa = p->testRenderHint(QPainter::Antialiasing); + if (radius > 0.5) { + if (!aa) + p->setRenderHint(QPainter::Antialiasing); + p->setPen(swatch.pen(stroke)); + p->setBrush(swatch.brush(fill)); + QRectF rf(rect.x() + 0.5, rect.y() + 0.5, rect.width() - 1.0, rect.height() - 1.0); + p->drawRoundedRect(rf, radius, radius); + } + else { + if (aa) + p->setRenderHint(QPainter::Antialiasing, false); + if (stroke) { + fillRectOutline(p, rect, 1, swatch.color(stroke)); + } + if (fill) { + p->fillRect(rect.adjusted(1, 1, -1, -1), swatch.color(fill)); + } + } +} +} // namespace +} // namespace Phantom + +BaseStylePrivate::BaseStylePrivate() : headSwatchFastKey(0) {} + +BaseStyle::BaseStyle() : d(new BaseStylePrivate) +{ + setObjectName(QLatin1String("Phantom")); +} + +BaseStyle::~BaseStyle() +{ + delete d; +} + +// Draw text in a rectangle. The current pen set on the painter is used, unless +// an explicit textRole is set, in which case the palette will be used. The +// enabled bool indicates whether the text is enabled or not, and can influence +// how the text is drawn outside of just color. Wrapping and alignment flags +// can be passed in `alignment`. +void BaseStyle::drawItemText(QPainter *painter, const QRect &rect, int alignment, const QPalette &pal, bool enabled, + const QString &text, QPalette::ColorRole textRole) const +{ + Q_UNUSED(enabled); + if (text.isEmpty()) + return; + if (textRole == QPalette::NoRole) { + painter->drawText(rect, alignment, text); + return; + } + QPen savedPen = painter->pen(); + const QBrush &newBrush = pal.brush(textRole); + bool changed = false; + if (savedPen.brush() != newBrush) { + changed = true; + painter->setPen(QPen(newBrush, savedPen.widthF())); + } + painter->drawText(rect, alignment, text); + if (changed) { + painter->setPen(savedPen); + } +} + +void BaseStyle::drawPrimitive( + PrimitiveElement elem, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ + Q_ASSERT(option); + if (!option) + return; +#ifdef BUILD_WITH_EASY_PROFILER + EASY_BLOCK("drawPrimitive"); + const char *elemCString = QMetaEnum::fromType().valueToKey(elem); + EASY_TEXT("Element", elemCString); +#endif + using Swatchy = Phantom::Swatchy; + using namespace Phantom::SwatchColors; + namespace Ph = Phantom; + auto ph_swatchPtr = getCachedSwatchOfQPalette(&d->swatchCache, &d->headSwatchFastKey, option->palette); + const Ph::PhSwatch &swatch = *ph_swatchPtr.data(); + const int state = option->state; + // Cast to int here to suppress warnings about cases listed which are not in + // the original enum. This is for custom primitive elements. + switch (static_cast(elem)) { + case PE_Frame: { + if (widget && widget->inherits("QComboBoxPrivateContainer")) { + QStyleOption copy = *option; + copy.state |= State_Raised; + proxy()->drawPrimitive(PE_PanelMenu, ©, painter, widget); + break; + } + Ph::fillRectOutline(painter, option->rect, 1, swatch.color(S_frame_outline)); + break; + } + case PE_FrameMenu: { + break; + } + case PE_FrameDockWidget: { + painter->save(); + QColor softshadow = option->palette.background().color().darker(120); + QRect r = option->rect; + painter->setPen(softshadow); + painter->drawRect(r.adjusted(0, 0, -1, -1)); + painter->setPen(QPen(option->palette.light(), 1)); + painter->drawLine(QPoint(r.left() + 1, r.top() + 1), QPoint(r.left() + 1, r.bottom() - 1)); + painter->setPen(QPen(option->palette.background().color().darker(120))); + painter->drawLine(QPoint(r.left() + 1, r.bottom() - 1), QPoint(r.right() - 2, r.bottom() - 1)); + painter->drawLine(QPoint(r.right() - 1, r.top() + 1), QPoint(r.right() - 1, r.bottom() - 1)); + painter->restore(); + break; + } + case PE_FrameGroupBox: { + QRect frame = option->rect; + Ph::PSave save(painter); + bool isFlat = false; + if (auto groupBox = qstyleoption_cast(option)) { + isFlat = groupBox->features & QStyleOptionFrame::Flat; + } + else if (auto frameOpt = qstyleoption_cast(option)) { + isFlat = frameOpt->features & QStyleOptionFrame::Flat; + } + if (isFlat) { + Ph::fillRectEdges(painter, frame, Qt::TopEdge, 1, swatch.color(S_window_divider)); + } + else { + Ph::paintBorderedRoundRect(painter, frame, Ph::GroupBox_Rounding, swatch, S_frame_outline, S_none); + } + break; + } + case PE_IndicatorBranch: { + if (!(option->state & State_Children)) + break; + Qt::ArrowType arrow; + if (option->state & State_Open) { + arrow = Qt::DownArrow; + } + else if (option->direction != Qt::RightToLeft) { + arrow = Qt::RightArrow; + } + else { + arrow = Qt::LeftArrow; + } + bool useSelectionColor = false; + if (option->state & State_Selected) { + if (auto ivopt = qstyleoption_cast(option)) { + useSelectionColor = ivopt->showDecorationSelected; + } + } + Swatchy color = useSelectionColor ? S_highlightedText : S_indicator_current; + QRect r = option->rect; + if (Ph::BranchesOnEdge) { + // TODO RTL + r.moveLeft(0); + if (r.width() < r.height()) + r.setWidth(r.height()); + } + int adj = qMin(r.width(), r.height()) / 4; + r.adjust(adj, adj, -adj, -adj); + Ph::drawArrow(painter, r, arrow, swatch.brush(color)); + break; + } + case PE_IndicatorMenuCheckMark: { + // For this PE, QCommonStyle treats State_On as drawing the check with the + // highlighted text color, and otherwise with the regular text color. I + // guess we should match that behavior, even though it's not consistent + // with other check box/mark drawing in QStyle (buttons and item view + // items.) QCommonStyle also doesn't care about tri-state or unchecked + // states -- it seems that if you call this, you want a check, and nothing + // else. + // + // We'll also catch State_Selected and treat it equivalently (the way you'd + // expect.) We'll use windowText instead of text, though -- probably + // doesn't matter. + Swatchy fgColor = S_windowText; + bool isSelected = option->state & (State_Selected | State_On); + bool isEnabled = option->state & State_Enabled; + if (isSelected) { + fgColor = S_highlightedText; + } + else if (!isEnabled) { + fgColor = S_windowText_disabled; + } + qreal rx, ry, rw, rh; + QRectF(option->rect).getRect(&rx, &ry, &rw, &rh); + qreal dim = qMin(rw, rh); + const qreal insetScale = 0.8; + qreal dimx = dim * insetScale * Ph::CheckMark_WidthOfHeightScale; + qreal dimy = dim * insetScale; + QRectF r_(rx + (rw - dimx) / 2, ry + (rh - dimy) / 2, dimx, dimy); + Ph::drawCheck(painter, d->checkBox_pen_scratch, r_, swatch, fgColor); + break; + } + // Called for the content area on tree view rows that are selected + case PE_PanelItemViewItem: { + QCommonStyle::drawPrimitive(elem, option, painter, widget); + break; + } + // Called for left-of-item-content-area on tree view rows that are selected + case PE_PanelItemViewRow: { + QCommonStyle::drawPrimitive(elem, option, painter, widget); + break; + } + case PE_FrameTabBarBase: { + auto tbb = qstyleoption_cast(option); + if (!tbb) + break; + +#ifdef Q_OS_MACOS + painter->fillRect( + widget->rect(), swatch.color(option->state & QStyle::State_Active ? S_tabBarBase : S_tabBarBase_inactive)); +#endif + + Qt::Edge edge = Qt::TopEdge; + switch (tbb->shape) { + case QTabBar::RoundedNorth: + case QTabBar::TriangularNorth: + edge = Qt::TopEdge; + break; + case QTabBar::RoundedSouth: + case QTabBar::TriangularSouth: + edge = Qt::BottomEdge; + break; + case QTabBar::RoundedWest: + case QTabBar::TriangularWest: + edge = Qt::LeftEdge; + break; + case QTabBar::RoundedEast: + case QTabBar::TriangularEast: + edge = Qt::RightEdge; + break; + } + Ph::fillRectEdges(painter, option->rect, edge, 1, swatch.color(S_frame_outline)); + // TODO need to check here if we're drawing with window or button color as + // the frame fill. Assuming window right now, but could be wrong. + Ph::fillRectEdges(painter, Ph::expandRect(option->rect, edge, -1), edge, 1, swatch.color(S_tabFrame_specular)); + break; + } + case PE_PanelScrollAreaCorner: { + bool isLeftToRight = option->direction != Qt::RightToLeft; + Qt::Edges edges = Qt::TopEdge; + QRect bgRect = option->rect; + if (isLeftToRight) { + edges |= Qt::LeftEdge; + bgRect.setX(bgRect.x() + 1); + } + else { + edges |= Qt::RightEdge; + bgRect.setWidth(bgRect.width() - 1); + } + painter->fillRect(bgRect, swatch.color(S_window)); + Ph::fillRectEdges(painter, option->rect, edges, 1, swatch.color(S_window_outline)); + break; + } + case PE_IndicatorArrowUp: + case PE_IndicatorArrowDown: + case PE_IndicatorArrowRight: + case PE_IndicatorArrowLeft: { + int rx, ry, rw, rh; + option->rect.getRect(&rx, &ry, &rw, &rh); + if (rw <= 1 || rh <= 1) + break; + Qt::ArrowType arrow = Qt::UpArrow; + switch (elem) { + case PE_IndicatorArrowUp: + arrow = Qt::UpArrow; + break; + case PE_IndicatorArrowDown: + arrow = Qt::DownArrow; + break; + case PE_IndicatorArrowRight: + arrow = Qt::RightArrow; + break; + case PE_IndicatorArrowLeft: + arrow = Qt::LeftArrow; + break; + default: + break; + } + // The caller may give us a huge rect and expect a normal-sized icon inside + // of it, so we don't want to fill the entire thing with an arrow, + // otherwise certain buttons will look weird, like the tab bar scroll + // buttons. Might want to break these out into editable parameters? + const int MaxArrowExt = Ph::dpiScaled(12); + const int MinMargin = qMin(rw, rh) / 4; + int aw, ah; + aw = qMin(MaxArrowExt, rw) - MinMargin; + ah = qMin(MaxArrowExt, rh) - MinMargin; + if (aw <= 2 || ah <= 2) + break; + // QCommonStyle's implementation of CC_ToolButton for non-instant popups + // gives us a pretty big rectangle to draw the arrow in -- shrink it. This + // is kind of a dirty temp hack thing until we do something smarter, like + // fully reimplement CC_ToolButton. Note that it passes us a regular + // QStyleOption and not a QStyleOptionToolButton in this case, so try to + // save some work before doing the inherits test. + if (arrow == Qt::DownArrow && !qstyleoption_cast(option) && widget) { + auto tbutton = qobject_cast(widget); + if (tbutton && tbutton->popupMode() != QToolButton::InstantPopup && tbutton->defaultAction()) { + int dim = static_cast(qMin(rw, rh) * 0.25); + aw -= dim; + ah -= dim; + // We have another hack in PE_IndicatorButtonDropDown where we shift + // the edge left or right by 1px to avoid having two borders touching + // (we make it overlap instead.) So we'll need to compensate for that + // in the arrow's position to avoid it looking off-center. + rw += 1; + if (option->direction != Qt::RightToLeft) { + rx -= 1; + } + } + } + aw += (rw - aw) % 2; + ah += (rh - ah) % 2; + int ax = (rw - aw) / 2 + rx; + int ay = (rh - ah) / 2 + ry; + Ph::drawArrow(painter, QRect(ax, ay, aw, ah), arrow, swatch); + break; + } + case PE_IndicatorItemViewItemCheck: { + QStyleOptionButton button; + button.QStyleOption::operator=(*option); + button.state &= ~State_MouseOver; + proxy()->drawPrimitive(PE_IndicatorCheckBox, &button, painter, widget); + return; + } + case PE_IndicatorHeaderArrow: { + auto header = qstyleoption_cast(option); + if (!header) + return; + QRect r = header->rect; + QPoint offset = QPoint(Phantom::HeaderSortIndicator_HOffset, Phantom::HeaderSortIndicator_VOffset); + qreal lightness = Phantom::DeriveColors::hack_isLightPalette(widget->palette()) ? 0.03 : 0.0; + if (header->sortIndicator & QStyleOptionHeader::SortUp) { + Ph::drawArrow(painter, r.translated(offset), Qt::DownArrow, swatch, true, lightness); + } + else if (header->sortIndicator & QStyleOptionHeader::SortDown) { + Ph::drawArrow(painter, r.translated(offset), Qt::UpArrow, swatch, true, lightness); + } + break; + } + case PE_IndicatorButtonDropDown: { + // Temp hack until we implement CC_ToolButton: avoid double-stacked border + // by clipping off one edge slightly. + QStyleOption opt0 = *option; + if (opt0.direction != Qt::RightToLeft) { + opt0.rect.adjust(-1, 0, 0, 0); + } + else { + opt0.rect.adjust(0, 0, 1, 0); + } + proxy()->drawPrimitive(PE_PanelButtonTool, &opt0, painter, widget); + break; + } + + case PE_IndicatorToolBarSeparator: { + QRect r = option->rect; + if (option->state & State_Horizontal) { + if (r.height() >= 10) + r.adjust(0, 3, 0, -3); + r.setWidth(r.width() / 2 + 1); + Ph::fillRectEdges(painter, r, Qt::RightEdge, 1, swatch.color(S_window_divider)); + } + else { + // TODO replace with new code + const int margin = 6; + const int offset = r.height() / 2; + painter->setPen(QPen(option->palette.background().color().darker(110))); + painter->drawLine(r.topLeft().x() + margin, r.topLeft().y() + offset, r.topRight().x() - margin, + r.topRight().y() + offset); + painter->setPen(QPen(option->palette.background().color().lighter(110))); + painter->drawLine(r.topLeft().x() + margin, r.topLeft().y() + offset + 1, r.topRight().x() - margin, + r.topRight().y() + offset + 1); + } + break; + } + case PE_PanelButtonTool: { + bool isDown = option->state & State_Sunken; + bool isOn = option->state & State_On; + bool hasFocus = (option->state & State_HasFocus && option->state & State_KeyboardFocusChange); + const qreal rounding = Ph::ToolButton_Rounding; + Swatchy outline = S_window_outline; + Swatchy fill = S_button; + Swatchy specular = S_button_specular; + if (isDown) { + fill = S_button_pressed; + specular = S_button_pressed_specular; + } + else if (isOn) { + fill = S_button_on; + specular = S_none; + } + if (hasFocus) { + outline = S_highlight_outline; + } + QRect r = option->rect; + Ph::PSave save(painter); + Ph::paintBorderedRoundRect(painter, r, rounding, swatch, outline, fill); + Ph::paintBorderedRoundRect(painter, r.adjusted(1, 1, -1, -1), rounding, swatch, specular, S_none); + break; + } + case PE_IndicatorDockWidgetResizeHandle: { + QStyleOption dockWidgetHandle = *option; + bool horizontal = option->state & State_Horizontal; + dockWidgetHandle.state = + !horizontal ? (dockWidgetHandle.state | State_Horizontal) : (dockWidgetHandle.state & ~State_Horizontal); + proxy()->drawControl(CE_Splitter, &dockWidgetHandle, painter, widget); + break; + } + case PE_FrameWindow: { + break; + } + case PE_FrameLineEdit: { + QRect r = option->rect; + bool hasFocus = option->state & State_HasFocus; + bool isEnabled = option->state & State_Enabled; + const qreal rounding = Ph::LineEdit_Rounding; + auto pen = hasFocus ? S_highlight_outline : S_window_outline; + Ph::PSave save(painter); + Ph::paintBorderedRoundRect(painter, r, rounding, swatch, pen, S_none); + save.restore(); + if (Ph::OverhangShadows && !hasFocus && isEnabled) { + // Imperfect when rounded, may leave a gap on left and right. Going + // closer would eat into the outline, though. + Ph::fillRectEdges(painter, r.adjusted(qRound(rounding / 2) + 1, 1, -(qRound(rounding / 2) + 1), -1), + Qt::TopEdge, 1, swatch.color(S_base_shadow)); + } + break; + } + case PE_PanelLineEdit: { + auto panel = qstyleoption_cast(option); + if (!panel) + break; + Ph::PSave save(painter); + // We intentionally don't inset the fill rect, even if the frame will paint + // over the perimeter, because an inset with rounding enabled may cause + // some miscolored separated pixels between the fill and the border, since + // we're forced to paint them in two separate draw calls. + Ph::paintSolidRoundRect(painter, option->rect, Ph::LineEdit_Rounding, swatch, S_base); + save.restore(); + if (panel->lineWidth > 0) + proxy()->drawPrimitive(PE_FrameLineEdit, option, painter, widget); + break; + } + case PE_IndicatorCheckBox: { + auto checkbox = qstyleoption_cast(option); + if (!checkbox) + break; + QRect r = option->rect; + bool isHighlighted = option->state & State_HasFocus && option->state & State_KeyboardFocusChange; + bool isSelected = option->state & State_Selected; + bool isFlat = checkbox->features & QStyleOptionButton::Flat; + bool isEnabled = option->state & State_Enabled; + bool isPressed = state & State_Sunken; + Swatchy outlineColor = isHighlighted ? S_highlight_outline : S_window_outline; + Swatchy bgFillColor = isPressed ? S_highlight : S_base; + Swatchy fgColor = isFlat ? S_windowText : S_text; + if (isPressed && !isFlat) { + fgColor = S_highlightedText; + } + // Bare checkmarks that are selected should draw with the highlighted text + // color. + if (isSelected && isFlat) { + fgColor = S_highlightedText; + } + if (!isFlat) { + QRect fillR = r; + Ph::fillRectOutline(painter, fillR, 1, swatch.color(outlineColor)); + fillR.adjust(1, 1, -1, -1); + if (Ph::IndicatorShadows && !isPressed && isEnabled) { + Ph::fillRectEdges(painter, fillR, Qt::TopEdge, 1, swatch.color(S_base_shadow)); + fillR.adjust(0, 1, 0, 0); + } + painter->fillRect(fillR, swatch.color(bgFillColor)); + } + if (checkbox->state & State_NoChange) { + const qreal insetScale = 0.7; + qreal rx, ry, rw, rh; + QRectF(r.adjusted(1, 1, -1, -1)).getRect(&rx, &ry, &rw, &rh); + qreal dimx = rw * insetScale; + qreal dimy = rh * insetScale; + QRectF r_(rx + (rw - dimx) / 2, ry + (rh - dimy) / 2, dimx, dimy); + Ph::drawHyphen(painter, d->checkBox_pen_scratch, r_, swatch, fgColor); + } + else if (checkbox->state & State_On) { + const qreal insetScale = 0.8; + qreal rx, ry, rw, rh; + QRectF(r.adjusted(1, 1, -1, -1)).getRect(&rx, &ry, &rw, &rh); + // kinda wrong, assumes we're already square, but we probably are + qreal dimx = rw * insetScale * Ph::CheckMark_WidthOfHeightScale; + qreal dimy = rh * insetScale; + QRectF r_(rx + (rw - dimx) / 2, ry + (rh - dimy) / 2, dimx, dimy); + Ph::drawCheck(painter, d->checkBox_pen_scratch, r_, swatch, fgColor); + } + break; + } + case PE_IndicatorRadioButton: { + qreal rx, ry, rw, rh; + QRectF(option->rect).getRect(&rx, &ry, &rw, &rh); + bool isHighlighted = option->state & State_HasFocus && option->state & State_KeyboardFocusChange; + bool isSunken = state & State_Sunken; + bool isEnabled = state & State_Enabled; + Swatchy outlineColor = isHighlighted ? S_highlight_outline : S_window_outline; + Swatchy bgFillColor = isSunken ? S_highlight : S_base; + QPointF circleCenter(rx + rw / 2.0, ry + rh / 2.0); + const qreal lineThickness = 1.0; + qreal outlineRadius = (qMin(rw, rh) - lineThickness) / 2.0; + qreal fillRadius = outlineRadius - lineThickness / 2.0; + Ph::PSave save(painter); + painter->setRenderHint(QPainter::Antialiasing); + painter->setBrush(swatch.brush(bgFillColor)); + painter->setPen(swatch.pen(outlineColor)); + painter->drawEllipse(circleCenter, outlineRadius, outlineRadius); + if (Ph::IndicatorShadows && !isSunken && isEnabled) { + // Really slow, just a temp demo test + painter->setPen(Qt::NoPen); + painter->setBrush(swatch.brush(S_base_shadow)); + QPainterPath path0, path1; + path0.addEllipse(circleCenter, fillRadius, fillRadius); + path1.addEllipse(circleCenter + QPointF(0, 1.25), fillRadius, fillRadius); + QPainterPath path2 = path0 - path1; + painter->drawPath(path2); + } + if (state & State_On) { + Swatchy fgColor = isSunken ? S_highlightedText : S_windowText; + qreal checkmarkRadius = outlineRadius / 2.32; + painter->setPen(Qt::NoPen); + painter->setBrush(swatch.brush(fgColor)); + painter->drawEllipse(circleCenter, checkmarkRadius, checkmarkRadius); + } + break; + } + case PE_IndicatorToolBarHandle: { + if (!option) + break; + QRect r = option->rect; + if (r.width() < 3 || r.height() < 3) + break; + int rows = 3; + int columns = 2; + if (option->state & State_Horizontal) { + } + else { + qSwap(columns, rows); + } + int dotLen = Ph::dpiScaled(2); + QSize occupied(dotLen * (columns * 2 - 1), dotLen * (rows * 2 - 1)); + QRect rr = QStyle::alignedRect(option->direction, Qt::AlignCenter, QSize(occupied), r); + int x = rr.x(); + int y = rr.y(); + for (int row = 0; row < rows; ++row) { + for (int col = 0; col < columns; ++col) { + int x_ = x + col * 2 * dotLen; + int y_ = y + row * 2 * dotLen; + painter->fillRect(x_, y_, dotLen, dotLen, swatch.color(S_window_divider)); + } + } + break; + } + case PE_FrameDefaultButton: + break; + case PE_FrameFocusRect: { + auto fropt = qstyleoption_cast(option); + if (!fropt) + break; + //### check for d->alt_down + if (!(fropt->state & State_KeyboardFocusChange)) + return; + if (fropt->state & State_Item) { + if (auto itemView = qobject_cast(widget)) { + // TODO either our grid line hack is interfering, or Qt has a bug, but + // in RTL layout the grid borders can leave junk behind in the grid + // areas and the right edge of the focus rect may not get painted. + // (Sometimes it will, though.) To replicate, set to RTL mode, and move + // the current around in a table view without the selection being on + // the current. + if (option->state & QStyle::State_Selected) { + bool showCurrent = true; + bool hasTableGrid = false; + const auto selectionMode = itemView->selectionMode(); + if (selectionMode == QAbstractItemView::SingleSelection) { + showCurrent = false; + } + else { + // Table views will can have a "current" frame drawn even if the + // "current" is within the selected range. Other item views won't, + // which means the "current" frame will be invisible if it's on a + // selected item. This is a compromise between the broken drawing + // behavior of Qt item views of drawing "current" frames when they + // don't make sense (like a tree view where you can only select + // entire rows, but Qt will the frame rect around whatever column + // was last clicked on by the mouse, but using keyboard navigation + // has no effect) and not drawing them at all. + bool isTableView = false; + if (auto tableView = qobject_cast(itemView)) { + hasTableGrid = tableView->showGrid(); + isTableView = true; + } + const auto selectionModel = itemView->selectionModel(); + if (selectionModel) { + const auto selection = selectionModel->selection(); + if (selection.count() == 1) { + const auto &range = selection.at(0); + if (isTableView) { + // For table views, we don't draw the "current" frame if + // there is exactly one cell selected and the "current" is + // that cell, or if there is exactly one row or one column + // selected with the behavior set to the corresponding + // selection, and the "current" is that one row or column. + const auto selectionBehavior = itemView->selectionBehavior(); + if ((range.width() == 1 && range.height() == 1) || + (selectionBehavior == QAbstractItemView::SelectRows && range.height() == 1) || + (selectionBehavior == QAbstractItemView::SelectColumns && range.width() == 1)) { + showCurrent = false; + } + } + else { + // For any other type of item view, don't draw the "current" + // frame if there is a single contiguous selection, and the + // "current" is within that selection. If there's a + // discontiguous selection, that means the user is probably + // doing something more advanced, and we should just draw the + // focus frame, even if Qt might be doing it badly in some + // cases. + showCurrent = false; + } + } + } + } + if (showCurrent) { + // TODO handle dark-highlight-light-text + const QColor &borderColor = swatch.color(S_itemView_multiSelection_currentBorder); + const int thickness = hasTableGrid ? 2 : 1; + Ph::fillRectOutline(painter, option->rect, thickness, borderColor); + } + } + else { + Ph::fillRectOutline(painter, option->rect, 1, swatch.color(S_highlight_outline)); + } + break; + } + } + // It would be nice to also handle QTreeView's allColumnsShowFocus thing in + // the above code, in addition to the normal cases for focus rects in item + // views. Unfortunately, with allColumnsShowFocus set to true, + // QTreeView::drawRow() calls the style to paint with PE_FrameFocusRect for + // the row frame with the widget set to nullptr. This makes it basically + // impossible to figure out that we need to draw a special frame for it. + // So, if any application code is using that mode in a QTreeView, it won't + // get special item view frames. Too bad. + Ph::PSave save(painter); + Ph::paintBorderedRoundRect( + painter, option->rect, Ph::FrameFocusRect_Rounding, swatch, S_highlight_outline, S_none); + break; + } + case PE_PanelButtonCommand: + case PE_PanelButtonBevel: { + bool isDefault = false; + bool isFlat = false; + bool isDown = option->state & State_Sunken; + bool isOn = option->state & State_On; + if (auto button = qstyleoption_cast(option)) { + isDefault = (button->features & QStyleOptionButton::DefaultButton) && (button->state & State_Enabled); + isFlat = (button->features & QStyleOptionButton::Flat); + } + if (isFlat && !isDown && !isOn) + break; + bool isEnabled = option->state & State_Enabled; + Q_UNUSED(isEnabled); + bool hasFocus = (option->state & State_HasFocus && option->state & State_KeyboardFocusChange); + const qreal rounding = Ph::PushButton_Rounding; + Swatchy outline = S_window_outline; + Swatchy fill = S_button; + Swatchy specular = S_button_specular; + if (isDown) { + fill = S_button_pressed; + specular = S_button_pressed_specular; + } + else if (isOn) { + // kinda repurposing this, hmm + fill = S_scrollbarGutter; + specular = S_button_pressed_specular; + } + if (hasFocus || isDefault) { + outline = S_highlight_outline; + } + QRect r = option->rect; + Ph::PSave save(painter); + Ph::paintBorderedRoundRect(painter, r, rounding, swatch, outline, fill); + Ph::paintBorderedRoundRect(painter, r.adjusted(1, 1, -1, -1), rounding, swatch, specular, S_none); + break; + } + case PE_FrameTabWidget: { + QRect bgRect = option->rect.adjusted(1, 1, -1, -1); + painter->fillRect(bgRect, swatch.color(S_tabFrame)); + auto twf = qstyleoption_cast(option); + if (!twf) + break; + Ph::fillRectOutline(painter, option->rect, 1, swatch.color(S_frame_outline)); + Ph::fillRectOutline(painter, bgRect, 1, swatch.color(S_tabFrame_specular)); + break; + } + case PE_FrameStatusBarItem: + break; + case PE_IndicatorTabClose: + case Phantom_PE_IndicatorTabNew: { + Swatchy fg = S_windowText; + Swatchy bg = S_none; + if ((option->state & State_Enabled) && (option->state & State_MouseOver)) { + fg = S_highlightedText; + bg = option->state & State_Sunken ? S_highlight_outline : S_highlight; + } + // temp code + Ph::PSave save(painter); + if (bg) { + Ph::paintSolidRoundRect(painter, option->rect, Ph::PushButton_Rounding, swatch, bg); + } + QPen pen = swatch.pen(fg); + pen.setCapStyle(Qt::RoundCap); + pen.setWidthF(1.5); + painter->setBrush(Qt::NoBrush); + painter->setPen(pen); + painter->setRenderHint(QPainter::Antialiasing); + QRect r = option->rect; + // int adj = (int)((qreal)qMin(r.width(), r.height()) * (1.0 / 2.5)); + int adj = Ph::dpiScaled(5.0); + r.adjust(adj, adj, -adj, -adj); + qreal x, y, w, h; + QRectF(r).getRect(&x, &y, &w, &h); + // painter->translate(-0.5, -0.5); + switch (static_cast(elem)) { + case PE_IndicatorTabClose: + painter->drawLine(QPointF(x - 0.5, y - 0.5), QPointF(x + 0.5 + w, y + 0.5 + h)); + painter->drawLine(QPointF(x - 0.5, y + h + 0.5), QPointF(x + 0.5 + w, y - 0.5)); + break; + case Phantom_PE_IndicatorTabNew: + // kinda hacky here on extra len + painter->drawLine(QPointF(x + w / 2, y - 1.0), QPointF(x + w / 2, y + h + 1.0)); + painter->drawLine(QPointF(x - 1.0, y + h / 2), QPointF(x + w + 1.0, y + h / 2)); + break; + } + save.restore(); + // painter->fillRect(option->rect, QColor(255, 0, 0, 30)); + break; + } + case PE_PanelMenu: { + bool isBelowMenuBar = false; + // works but currently unused + // QPoint gp = widget->mapToGlobal(widget->rect().topLeft()); + // gp.setY(gp.y() - 1); + // QWidget* bar = qApp->widgetAt(gp); + // if (bar && bar->inherits("QMenuBar")) { + // isBelowMenuBar = true; + // } + Ph::fillRectOutline(painter, option->rect, 1, swatch.color(S_window_divider)); + QRect bgRect = option->rect.adjusted(1, isBelowMenuBar ? 0 : 1, -1, -1); + painter->fillRect(bgRect, swatch.color(S_window)); + break; + } + case Phantom_PE_ScrollBarSliderVertical: { + bool isLeftToRight = option->direction != Qt::RightToLeft; + bool isSunken = option->state & State_Sunken; + Swatchy thumbFill, thumbSpecular; + if (isSunken) { + thumbFill = S_button_pressed; + thumbSpecular = S_button_pressed_specular; + } + else { + thumbFill = S_scrollbarSlider; + thumbSpecular = S_button_specular; + } + Qt::Edges edges; + QRect edgeRect = option->rect; + QRect mainRect = option->rect; + edgeRect.adjust(0, -1, 0, 1); + if (isLeftToRight) { + edges = Qt::LeftEdge | Qt::TopEdge | Qt::BottomEdge; + mainRect.setX(mainRect.x() + 1); + } + else { + edges = Qt::TopEdge | Qt::BottomEdge | Qt::RightEdge; + mainRect.setWidth(mainRect.width() - 1); + } + Ph::fillRectEdges(painter, edgeRect, edges, 1, swatch.color(S_window_outline)); + painter->fillRect(mainRect, swatch.color(thumbFill)); + Ph::fillRectOutline(painter, mainRect, 1, swatch.color(thumbSpecular)); + break; + } + case Phantom_PE_WindowFrameColor: { + painter->fillRect(option->rect, swatch.color(S_window_outline)); + break; + } + default: + QCommonStyle::drawPrimitive(elem, option, painter, widget); + break; + } +} + +void BaseStyle::drawControl( + ControlElement element, const QStyleOption *option, QPainter *painter, const QWidget *widget) const +{ +#ifdef BUILD_WITH_EASY_PROFILER + EASY_BLOCK("drawControl"); + const char *elemCString = QMetaEnum::fromType().valueToKey(element); + EASY_TEXT("Element", elemCString); +#endif + using Swatchy = Phantom::Swatchy; + using namespace Phantom::SwatchColors; + namespace Ph = Phantom; + auto ph_swatchPtr = Ph::getCachedSwatchOfQPalette(&d->swatchCache, &d->headSwatchFastKey, option->palette); + const Ph::PhSwatch &swatch = *ph_swatchPtr.data(); + + switch (element) { + case CE_CheckBox: { + QCommonStyle::drawControl(element, option, painter, widget); + // painter->fillRect(option->rect, QColor(255, 0, 0, 90)); + break; + } + case CE_ComboBoxLabel: { + auto cb = qstyleoption_cast(option); + if (!cb) + break; + QRect editRect = proxy()->subControlRect(CC_ComboBox, cb, SC_ComboBoxEditField, widget); + painter->save(); + painter->setClipRect(editRect); + if (!cb->currentIcon.isNull()) { + QIcon::Mode mode = cb->state & State_Enabled ? QIcon::Normal : QIcon::Disabled; + QPixmap pixmap = cb->currentIcon.pixmap(cb->iconSize, mode); + QRect iconRect(editRect); + iconRect.setWidth(cb->iconSize.width() + 4); + iconRect = alignedRect(cb->direction, Qt::AlignLeft | Qt::AlignVCenter, iconRect.size(), editRect); + if (cb->editable) + painter->fillRect(iconRect, cb->palette.brush(QPalette::Base)); + proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pixmap); + + if (cb->direction == Qt::RightToLeft) + editRect.translate(-4 - cb->iconSize.width(), 0); + else + editRect.translate(cb->iconSize.width() + 4, 0); + } + if (!cb->currentText.isEmpty() && !cb->editable) { + proxy()->drawItemText(painter, editRect.adjusted(1, 0, -1, 0), + visualAlignment(cb->direction, Qt::AlignLeft | Qt::AlignVCenter), cb->palette, + cb->state & State_Enabled, cb->currentText, cb->editable ? QPalette::Text : QPalette::ButtonText); + } + painter->restore(); + break; + } + case CE_Splitter: { + QRect r = option->rect; + // We don't have anything useful to draw if it's too thin + if (r.width() < 5 || r.height() < 5) + break; + int length = Ph::dpiScaled(Ph::SplitterMaxLength); + int thickness = Ph::dpiScaled(1); + QSize size; + if (option->state & State_Horizontal) { + if (r.height() < length) + length = r.height(); + size = QSize(thickness, length); + } + else { + if (r.width() < length) + length = r.width(); + size = QSize(length, thickness); + } + QRect filledRect = QStyle::alignedRect(option->direction, Qt::AlignCenter, size, r); + painter->fillRect(filledRect, swatch.color(S_button_specular)); + Ph::fillRectOutline(painter, filledRect.adjusted(-1, 0, 1, 0), 1, swatch.color(S_window_divider)); + break; + } + // TODO update this for phantom + case CE_RubberBand: { + if (!qstyleoption_cast(option)) + break; + QColor highlight = option->palette.color(QPalette::Active, QPalette::Highlight); + painter->save(); + QColor penColor = highlight.darker(120); + penColor.setAlpha(180); + painter->setPen(penColor); + QColor dimHighlight(qMin(highlight.red() / 2 + 110, 255), qMin(highlight.green() / 2 + 110, 255), + qMin(highlight.blue() / 2 + 110, 255)); + dimHighlight.setAlpha(widget && widget->isTopLevel() ? 255 : 80); + painter->setRenderHint(QPainter::Antialiasing, true); + painter->translate(0.5, 0.5); + painter->setBrush(dimHighlight); + painter->drawRoundedRect(option->rect.adjusted(0, 0, -1, -1), 1, 1); + QColor innerLine = Qt::white; + innerLine.setAlpha(40); + painter->setPen(innerLine); + painter->drawRoundedRect(option->rect.adjusted(1, 1, -2, -2), 1, 1); + painter->restore(); + break; + } + case CE_SizeGrip: { + Qt::LayoutDirection dir = option->direction; + QRect rect = option->rect; + int rcx = rect.center().x(); + int rcy = rect.center().y(); + // draw grips + for (int i = -6; i < 12; i += 3) { + for (int j = -6; j < 12; j += 3) { + if ((dir == Qt::LeftToRight && i > -j) || (dir == Qt::RightToLeft && j > i)) { + painter->fillRect(rcx + i, rcy + j, 2, 2, swatch.color(S_window_lighter)); + painter->fillRect(rcx + i, rcy + j, 1, 1, swatch.color(S_window_darker)); + } + } + } + break; + } + case CE_ToolBar: { + auto toolBar = qstyleoption_cast(option); + if (!toolBar) + break; + +#ifdef Q_OS_MACOS + if (auto *mainWindow = qobject_cast(widget->window())) { + // Fill toolbar background with transparent pixels to reveal the + // gradient background drawn by the Cocoa platform plugin. + // Inspired by qmacstyle_mac.mm. + if (m_drawNativeMacOsToolBar && toolBar && toolBar->toolBarArea == Qt::TopToolBarArea && + mainWindow->unifiedTitleAndToolBarOnMac()) { + painter->setCompositionMode(QPainter::CompositionMode_Source); + painter->fillRect(option->rect, Qt::transparent); + break; + } + } +#endif + + painter->fillRect(option->rect, option->palette.window().color()); + bool isFloating = false; + if (auto tb = qobject_cast(widget)) { + isFloating = tb->isFloating(); + } + if (isFloating) { + Ph::fillRectOutline(painter, option->rect, 1, swatch.color(S_window_outline)); + } + break; + } + case CE_DockWidgetTitle: { + auto dwOpt = qstyleoption_cast(option); + if (!dwOpt) + break; + painter->save(); + bool verticalTitleBar = dwOpt->verticalTitleBar; + + QRect titleRect = subElementRect(SE_DockWidgetTitleBarText, option, widget); + if (verticalTitleBar) { + QRect r = dwOpt->rect; + QRect rtrans = {r.x(), r.y(), r.height(), r.width()}; + titleRect = QRect(rtrans.left() + r.bottom() - titleRect.bottom(), + rtrans.top() + titleRect.left() - r.left(), titleRect.height(), titleRect.width()); + painter->translate(rtrans.left(), rtrans.top() + rtrans.width()); + painter->rotate(-90); + painter->translate(-rtrans.left(), -rtrans.top()); + } + if (!dwOpt->title.isEmpty()) { + QString titleText = painter->fontMetrics().elidedText(dwOpt->title, Qt::ElideRight, titleRect.width()); + proxy()->drawItemText(painter, titleRect, Qt::AlignLeft | Qt::AlignVCenter | Qt::TextShowMnemonic, + dwOpt->palette, dwOpt->state & State_Enabled, titleText, QPalette::WindowText); + } + painter->restore(); + break; + } + case CE_HeaderSection: { + auto header = qstyleoption_cast(option); + if (!header) + break; + QRect rect = header->rect; + Qt::Orientation orientation = header->orientation; + QStyleOptionHeader::SectionPosition position = header->position; + // See the "Table header layout reference" comment block at the bottom of + // this file for more information to help understand what's going on. + bool isLeftToRight = header->direction != Qt::RightToLeft; + bool isHorizontal = orientation == Qt::Horizontal; + bool isVertical = orientation == Qt::Vertical; + bool isEnd = position == QStyleOptionHeader::End; + bool isBegin = position == QStyleOptionHeader::Beginning; + bool isOnlyOne = position == QStyleOptionHeader::OnlyOneSection; + Qt::Edges edges; + bool spansToEnd = false; + bool isSpecialCorner = false; + if ((isHorizontal && isLeftToRight && isEnd) || (isHorizontal && !isLeftToRight && isBegin) || + (isVertical && isEnd) || isOnlyOne) { + auto hv = qobject_cast(widget); + if (hv) { + spansToEnd = hv->stretchLastSection(); + // In the case where the header item is not stretched to the end, but + // could plausibly be in a position where it could happen to be exactly + // the right width or height to be appear to be stretched to the end, + // we'll check to see if it actually does exactly meet the right (or + // bottom in vertical, or left in RTL) edge, and omit drawing the edge + // if that's the case. This can commonly happen if you have a tree or + // list view and don't set it to stretch, but the widget is still sized + // exactly to hold the one column. (It could also happen if there's + // user code running to manually stretch the last section as + // necessary.) + if (!spansToEnd) { + QRect viewBound = hv->contentsRect(); + if (isHorizontal) { + if (isLeftToRight) { + spansToEnd = rect.right() == viewBound.right(); + } + else { + spansToEnd = rect.left() == viewBound.left(); + } + } + else if (isVertical) { + spansToEnd = rect.bottom() == viewBound.bottom(); + } + } + } + else { + // We only need to do this check in RTL, because the corner button in + // RTL *doesn't* need hacks applied. In LTR, we can just treat the + // corner button like anything else on the horizontal header bar, and + // can skip doing this inherits check. + if (isOnlyOne && !isLeftToRight && widget && widget->inherits("QTableCornerButton")) { + isSpecialCorner = true; + } + } + } + + if (isSpecialCorner) { + // In RTL layout, the corner button in a table view doesn't have any + // offset problems. This branch we're on is only taken if we're in RTL + // layout and this is the corner button being drawn. + edges |= Qt::BottomEdge; + if (isLeftToRight) + edges |= Qt::RightEdge; + else + edges |= Qt::LeftEdge; + } + else if (isHorizontal) { + // This branch is taken for horizontal headers in either layout direction + // or for the corner button in LTR. + edges |= Qt::BottomEdge; + if (isLeftToRight) { + // In LTR, this code path may be for both the corner button *and* the + // actual header item. It doesn't matter in this case, and we were able + // to avoid doing an extra inherits call earlier. + if (!spansToEnd) { + edges |= Qt::RightEdge; + } + } + else { + // Note: in right-to-left layouts for horizontal headers, the header + // view will unfortunately be shifted to the right by 1 pixel, due to + // what appears to be a Qt bug. This causes the vertical lines we draw + // in the header view to misalign with the grid, and causes the + // rightmost section to have its right edge clipped off. Therefore, + // we'll draw the separator on the on the right edge instead of the + // left edge. (We would have expected to draw it on the left edge in + // RTL layout.) This makes it line up with the grid again, except for + // the last section. right by 1 pixel. + // + // In RTL, the "Begin" position is on the left side for some reason + // (the same as LTR.) So "End" is always on the right. Ok, whatever. + // See the table at the bottom of this file if you're confused. + if (!isOnlyOne && !isEnd) { + edges |= Qt::RightEdge; + } + // The leftmost section in RTL has to draw on both its right and left + // edges, instead of just 1 edge like every other configuration. The + // left edge will be offset by 1 pixel from the grid, but it's the best + // we can do. + if (isBegin && !spansToEnd) { + edges |= Qt::LeftEdge; + } + } + } + else if (isVertical) { + if (isLeftToRight) { + edges |= Qt::RightEdge; + } + else { + edges |= Qt::LeftEdge; + } + if (!spansToEnd) { + edges |= Qt::BottomEdge; + } + } + QRect bgRect = Ph::expandRect(rect, edges, -1); + painter->fillRect(bgRect, swatch.color(S_window)); + Ph::fillRectEdges(painter, rect, edges, 1, swatch.color(S_frame_outline)); + break; + } + case CE_HeaderLabel: { + auto header = qstyleoption_cast(option); + if (!header) + break; + QRect rect = header->rect; + if (!header->icon.isNull()) { + int iconExtent = qMin(qMin(rect.height(), rect.width()), option->fontMetrics.height()); + auto window = widget ? widget->window()->windowHandle() : nullptr; + QPixmap pixmap = header->icon.pixmap(window, QSize(iconExtent, iconExtent), + (header->state & State_Enabled) ? QIcon::Normal : QIcon::Disabled); + int pixw = static_cast(pixmap.width() / pixmap.devicePixelRatio()); + QRect aligned = alignedRect( + header->direction, QFlag(header->iconAlignment), pixmap.size() / pixmap.devicePixelRatio(), rect); + QRect inter = aligned.intersected(rect); + painter->drawPixmap(inter.x(), inter.y(), pixmap, inter.x() - aligned.x(), inter.y() - aligned.y(), + static_cast(aligned.width() * pixmap.devicePixelRatio()), + static_cast(pixmap.height() * pixmap.devicePixelRatio())); + int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, option, widget); + if (header->direction == Qt::LeftToRight) + rect.setLeft(rect.left() + pixw + margin); + else + rect.setRight(rect.right() - pixw - margin); + } + proxy()->drawItemText(painter, rect, header->textAlignment, header->palette, (header->state & State_Enabled), + header->text, QPalette::ButtonText); + + // But we still need some kind of indicator, so draw a line + bool drawHighlightLine = option->state & State_On; + // Special logic: if the selection mode of the item view is to select every + // row or every column, there's no real need to draw special "this + // row/column is selected" highlight indicators in the header view. The + // application programmer can also disable this explicitly on the header + // view, but it's nice to have it done automatically, I think. + if (drawHighlightLine) { + const QAbstractItemView *itemview = nullptr; + // Header view itself is an item view, and we don't care about its + // selection behavior -- we care about the actual item view. So try to + // get the widget as the header first, then find the item view from + // there. + auto headerview = qobject_cast(widget); + if (headerview) { + // Also don't care about highlights if there's only one row or column. + drawHighlightLine = headerview->count() > 1; + itemview = qobject_cast(headerview->parentWidget()); + } + if (drawHighlightLine && itemview) { + auto selBehavior = itemview->selectionBehavior(); + if (selBehavior == QAbstractItemView::SelectRows && header->orientation == Qt::Horizontal) + drawHighlightLine = false; + else if (selBehavior == QAbstractItemView::SelectColumns && header->orientation == Qt::Vertical) + drawHighlightLine = false; + } + } + + if (drawHighlightLine) { + QRect r = option->rect; + Qt::Edge edge; + if (header->orientation == Qt::Horizontal) { + edge = Qt::BottomEdge; + r.adjust(-2, 1, 1, 1); + } + else { + bool isLeftToRight = option->direction != Qt::RightToLeft; + if (isLeftToRight) { + edge = Qt::RightEdge; + r.adjust(1, -2, 1, 1); + } + else { + edge = Qt::LeftEdge; + r.adjust(-1, -2, -1, 1); + } + } + Ph::fillRectEdges(painter, r, edge, 1, swatch.color(S_itemView_headerOnLine)); + } + break; + } + case CE_ProgressBarGroove: { + const qreal rounding = Ph::ProgressBar_Rounding; + QRect rect = option->rect; + Ph::PSave save(painter); + Ph::paintBorderedRoundRect(painter, rect, rounding, swatch, S_window_outline, S_base); + save.restore(); + if (Ph::OverhangShadows && option->state & State_Enabled) { + // Inner shadow + const QColor &shadowColor = swatch.color(S_base_shadow); + // We can either have the shadow cut into the rounded corners, or leave a + // 1px gap, due to AA. + Ph::fillRectEdges(painter, rect.adjusted(qRound(rounding / 2) + 1, 1, -(qRound(rounding / 2) + 1), -1), + Qt::TopEdge, 1, shadowColor); + } + break; + } + case CE_ProgressBarContents: { + auto bar = qstyleoption_cast(option); + if (!bar) + break; + const qreal rounding = Ph::ProgressBar_Rounding; + QRect filled, nonFilled; + bool isIndeterminate = false; + Ph::progressBarFillRects(bar, filled, nonFilled, isIndeterminate); + if (isIndeterminate || bar->progress > bar->minimum) { + Ph::PSave save(painter); + Ph::paintBorderedRoundRect(painter, filled, rounding, swatch, S_progressBar_outline, S_progressBar); + Ph::paintBorderedRoundRect( + painter, filled.adjusted(1, 1, -1, -1), rounding, swatch, S_progressBar_specular, S_none); + if (isIndeterminate) { + // TODO paint indeterminate indicator + } + } + break; + } + case CE_ProgressBarLabel: { + auto bar = qstyleoption_cast(option); + if (!bar) + break; + if (bar->text.isEmpty()) + break; + QRect r = bar->rect.adjusted(2, 2, -2, -2); + if (r.isEmpty() || !r.isValid()) + break; + QSize textSize = option->fontMetrics.size(Qt::TextBypassShaping, bar->text); + QRect textRect = QStyle::alignedRect(option->direction, Qt::AlignCenter, textSize, option->rect); + textRect &= r; + if (textRect.isEmpty()) + break; + QRect filled, nonFilled; + bool isIndeterminate = false; + Ph::progressBarFillRects(bar, filled, nonFilled, isIndeterminate); + QRect textNonFilledR = textRect & nonFilled; + QRect textFilledR = textRect & filled; + bool needsNonFilled = !textNonFilledR.isEmpty(); + bool needsFilled = !textFilledR.isEmpty(); + bool needsMasking = needsNonFilled && needsFilled; + Ph::PSave save(painter); + if (needsNonFilled) { + if (needsMasking) { + painter->save(); + painter->setClipRect(textNonFilledR); + } + painter->setPen(swatch.pen(S_text)); + painter->setBrush(Qt::NoBrush); + painter->drawText(textRect, bar->text, Qt::AlignHCenter | Qt::AlignVCenter); + if (needsMasking) { + painter->restore(); + } + } + if (needsFilled) { + if (needsMasking) { + painter->save(); + painter->setClipRect(textFilledR); + } + painter->setPen(swatch.pen(S_highlightedText)); + painter->setBrush(Qt::NoBrush); + painter->drawText(textRect, bar->text, Qt::AlignHCenter | Qt::AlignVCenter); + if (needsMasking) { + painter->restore(); + } + } + break; + } + case CE_MenuBarItem: { + auto mbi = qstyleoption_cast(option); + if (!mbi) + break; + const QRect r = option->rect; + QRect textRect = r; + textRect.setY(textRect.y() + (r.height() - option->fontMetrics.height()) / 2); + int alignment = Qt::AlignHCenter | Qt::AlignTop | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; + if (!proxy()->styleHint(SH_UnderlineShortcut, mbi, widget)) + alignment |= Qt::TextHideMnemonic; + const auto itemState = mbi->state; + bool maybeHasAltKeyNavFocus = itemState & State_Selected && itemState & State_HasFocus; + bool isSelected = itemState & State_Selected || itemState & State_Sunken; + if (!isSelected && maybeHasAltKeyNavFocus && widget) { + isSelected = widget->hasFocus(); + } + Swatchy fill = isSelected ? S_highlight : S_window; + painter->fillRect(r, swatch.color(fill)); + QPalette::ColorRole textRole = isSelected ? QPalette::HighlightedText : QPalette::Text; + proxy()->drawItemText( + painter, textRect, alignment, mbi->palette, mbi->state & State_Enabled, mbi->text, textRole); + if (Phantom::MenuBarDrawBorder && !isSelected) { + Ph::fillRectEdges(painter, r, Qt::BottomEdge, 1, swatch.color(S_window_divider)); + } + break; + } + + case CE_MenuItem: { + auto menuItem = qstyleoption_cast(option); + if (!menuItem) + break; + const auto metrics = Ph::MenuItemMetrics::ofFontHeight(option->fontMetrics.height()); + // Draws one item in a popup menu. + if (menuItem->menuItemType == QStyleOptionMenuItem::Separator) { + // Phantom ignores text and icons in menu separators, because + // 1) The text and icons for separators don't render on Mac native menus + // 2) There doesn't seem to be a way to account for the width of the text + // properly (Fusion will often draw separator text clipped off) + // 3) Setting text on separators also seems to mess up the metrics for + // menu items on Mac native menus + QRect r = option->rect; + r.setHeight(r.height() / 2 + 1); + Ph::fillRectEdges(painter, r, Qt::BottomEdge, 1, swatch.color(S_window_divider)); + break; + } + const QRect itemRect = option->rect; + painter->save(); + bool isSelected = menuItem->state & State_Selected && menuItem->state & State_Enabled; + bool isCheckable = menuItem->checkType != QStyleOptionMenuItem::NotCheckable; + bool isChecked = menuItem->checked; + bool isSunken = menuItem->state & State_Sunken; + bool isEnabled = menuItem->state & State_Enabled; + bool hasSubMenu = menuItem->menuItemType == QStyleOptionMenuItem::SubMenu; + if (isSelected) { + Swatchy fillColor = isSunken ? S_highlight_outline : S_highlight; + painter->fillRect(option->rect, swatch.color(fillColor)); + } + + if (isCheckable) { + // Note: check rect might be misaligned vertically if it's a menu from a + // combo box. Probably a bug in Qt code? + QRect checkRect = Ph::menuItemCheckRect(metrics, option->direction, itemRect, hasSubMenu); + Swatchy signColor = !isEnabled ? S_windowText : isSelected ? S_highlightedText : S_windowText; + if (menuItem->checkType & QStyleOptionMenuItem::Exclusive) { + // Radio button + if (isChecked) { + painter->setRenderHint(QPainter::Antialiasing); + painter->setPen(Qt::NoPen); + // clang-format off + QPalette::ColorRole textRole = + !isEnabled ? QPalette::Text : isSelected ? QPalette::HighlightedText : QPalette::ButtonText; + // clang-format on + painter->setBrush(option->palette.brush(option->palette.currentColorGroup(), textRole)); + qreal rx, ry, rw, rh; + QRectF(checkRect).getRect(&rx, &ry, &rw, &rh); + qreal dim = qMin(checkRect.width(), checkRect.height()) * 0.75; + QRectF rf(rx + rw / dim, ry + rh / dim, dim, dim); + painter->drawEllipse(rf); + } + } + else { + // If we want mouse-down to immediately show the item as + // checked/unchecked (kinda bad if the user is click-holding on the + // menu instead of click-clicking.) + // + // if ((isChecked && !isSunken) || (!isChecked && isSunken)) { + if (isChecked) { + Ph::drawCheck(painter, d->checkBox_pen_scratch, checkRect, swatch, signColor); + } + } + } + + const bool hasIcon = !menuItem->icon.isNull(); + + if (hasIcon) { + QRect iconRect = Ph::menuItemIconRect(metrics, option->direction, itemRect, hasSubMenu); + QIcon::Mode mode = isEnabled ? QIcon::Normal : QIcon::Disabled; + if (isSelected && isEnabled) + mode = QIcon::Selected; + QIcon::State state = isChecked ? QIcon::On : QIcon::Off; + + // TODO hmm, we might be ending up with blurry icons at size 15 instead + // of 16 for example on Windows. + // + // int smallIconSize = + // proxy()->pixelMetric(PM_SmallIconSize, option, widget); + // QSize iconSize(smallIconSize, smallIconSize); + int iconExtent = qMin(iconRect.width(), iconRect.height()); + QSize iconSize(iconExtent, iconExtent); + if (auto combo = qobject_cast(widget)) { + iconSize = combo->iconSize(); + } + QWindow *window = widget ? widget->windowHandle() : nullptr; + QPixmap pixmap = menuItem->icon.pixmap(window, iconSize, mode, state); + const int pixw = static_cast(pixmap.width() / pixmap.devicePixelRatio()); + const int pixh = static_cast(pixmap.height() / pixmap.devicePixelRatio()); + QRect pixmapRect = QStyle::alignedRect(option->direction, Qt::AlignCenter, QSize(pixw, pixh), iconRect); + painter->drawPixmap(pixmapRect.topLeft(), pixmap); + } + + // Draw main text and mnemonic text + QStringRef s(&menuItem->text); + if (!s.isEmpty()) { + QRect textRect = + Ph::menuItemTextRect(metrics, option->direction, itemRect, hasSubMenu, hasIcon, menuItem->tabWidth); + int t = s.indexOf(QLatin1Char('\t')); + int text_flags = + Qt::AlignLeft | Qt::AlignTop | Qt::TextShowMnemonic | Qt::TextDontClip | Qt::TextSingleLine; + if (!styleHint(SH_UnderlineShortcut, menuItem, widget)) + text_flags |= Qt::TextHideMnemonic; +#if 0 + painter->save(); +#endif + painter->setPen(swatch.pen(isSelected ? S_highlightedText : S_text)); + + // Comment from original Qt code which did some dance with the font: + // + // font may not have any "hard" flags set. We override the point size so + // that when it is resolved against the device, this font will win. This + // is mainly to handle cases where someone sets the font on the window + // and then the combo inherits it and passes it onward. At that point the + // resolve mask is very, very weak. This makes it stonger. +#if 0 + QFont font = menuItem->font; + font.setPointSizeF(QFontInfo(menuItem->font).pointSizeF()); + painter->setFont(font); +#endif + + // My comment: + // + // What actually looks like is happening is that the qplatformtheme may + // have set a per-class font for menus. The QComboMenuDelegate sets the + // combo box's own font on the QStyleOptionMenuItem when passing it in + // here and when calling sizeFromContents with CT_MenuItem, but the + // QPainter we're called with hasn't had its font set to it -- it's still + // set to the QMenu/QMenuItem app fonts hash font. So if it's a menu + // coming from a combo box, let's just go ahead and set the font for it + // if it doesn't match, since that's probably what it wanted to do. I + // think. And as described above, we have to do the weird dance with the + // resolve mask... which is some internal Qt detail that we aren't + // supposed to have to deal with, but here we are. + // + // Ok, there's another problem, and QFusionStyle also suffers from it: in + // high DPI, setting the pointSizeF and setting the font again won't + // necessarily give us the right font (at least in Windows.) The font + // might have too thin of a weight, and probably other problems. So just + // forget about it: we'll have Phantom return 0 for the style hint that + // the combo box uses to determine if it should use a QMenu popup instead + // of a regular dropdown menu thing. The popup menu might actually be + // better for usability in some cases, and it's how combos work on Mac + // and BeOS, but it won't work anyway for editable combo boxes in Qt, and + // the font issues just make it not worth it. So we'll have a dropdown + // guy like a traditional Windows thing. + // + // If you want to try it out again, go to SH_ComboBox_Popup and have it + // return 1. + // + // Alternatively, we could instead have the CT_MenuItem handling code try + // to be aggressively clever and use the qt app font hash to look up the + // expected font for a QMenu and use that for calculating its metrics. + // Unfortunately, that probably won't work so great if the combo/menu + // actually wants to use custom fonts in its listing, since we'd be + // ignoring it. That's how UseQMenuForComboBoxPopup currently works, + // though it tests for Qt::WA_SetFont as an attempt at recognizing when + // it shouldn't use the qt font hash for QMenu. +#if 0 + if (qobject_cast(widget)) { + QFont font = menuItem->font; + font.setPointSizeF(QFontInfo(menuItem->font).pointSizeF()); + painter->setFont(font); + } +#endif + + // Draw mnemonic text + if (t >= 0) { + QRect mnemonicR = + Ph::menuItemMnemonicRect(metrics, option->direction, itemRect, hasSubMenu, menuItem->tabWidth); + const QStringRef textToDrawRef = s.mid(t + 1); + const QString unsafeTextToDraw = QString::fromRawData(textToDrawRef.constData(), textToDrawRef.size()); + painter->drawText(mnemonicR, text_flags, unsafeTextToDraw); + s = s.left(t); + } + const QStringRef textToDrawRef = s.left(t); + const QString unsafeTextToDraw = QString::fromRawData(textToDrawRef.constData(), textToDrawRef.size()); + painter->drawText(textRect, text_flags, unsafeTextToDraw); + +#if 0 + painter->restore(); +#endif + } + + // SubMenu Arrow + if (hasSubMenu) { + Qt::ArrowType arrow = option->direction == Qt::RightToLeft ? Qt::LeftArrow : Qt::RightArrow; + QRect arrowRect = Ph::menuItemArrowRect(metrics, option->direction, itemRect); + Swatchy arrowColor = isSelected ? S_highlightedText : S_indicator_current; + Ph::drawArrow(painter, arrowRect, arrow, swatch.brush(arrowColor)); + } + painter->restore(); + break; + } + case CE_MenuHMargin: + case CE_MenuVMargin: + case CE_MenuEmptyArea: + break; + case CE_PushButton: { + auto btn = qstyleoption_cast(option); + if (!btn) + break; + proxy()->drawControl(CE_PushButtonBevel, btn, painter, widget); + QStyleOptionButton subopt = *btn; + subopt.rect = subElementRect(SE_PushButtonContents, btn, widget); + proxy()->drawControl(CE_PushButtonLabel, &subopt, painter, widget); + break; + } + case CE_PushButtonLabel: { + auto button = qstyleoption_cast(option); + if (!button) + break; + // This code is very similar to QCommonStyle's implementation, but doesn't + // set the icon mode to active when focused. + QRect textRect = button->rect; + int tf = Qt::AlignVCenter | Qt::TextShowMnemonic; + if (!proxy()->styleHint(SH_UnderlineShortcut, button, widget)) + tf |= Qt::TextHideMnemonic; + if (!button->icon.isNull()) { + // Center both icon and text + QRect iconRect; + QIcon::Mode mode = button->state & State_Enabled ? QIcon::Normal : QIcon::Disabled; + QIcon::State state = button->state & State_On ? QIcon::On : QIcon::Off; + auto window = widget ? widget->window()->windowHandle() : nullptr; + QPixmap pixmap = button->icon.pixmap(window, button->iconSize, mode, state); + int pixmapWidth = static_cast(pixmap.width() / pixmap.devicePixelRatio()); + int pixmapHeight = static_cast(pixmap.height() / pixmap.devicePixelRatio()); + int labelWidth = pixmapWidth; + int labelHeight = pixmapHeight; + // 4 is hardcoded in QPushButton::sizeHint() + int iconSpacing = 4; + int textWidth = button->fontMetrics.boundingRect(option->rect, tf, button->text).width(); + if (!button->text.isEmpty()) + labelWidth += (textWidth + iconSpacing); + iconRect = QRect(textRect.x() + (textRect.width() - labelWidth) / 2, + textRect.y() + (textRect.height() - labelHeight) / 2, pixmapWidth, pixmapHeight); + iconRect = visualRect(button->direction, textRect, iconRect); + tf |= Qt::AlignLeft; // left align, we adjust the text-rect instead + if (button->direction == Qt::RightToLeft) + textRect.setRight(iconRect.left() - iconSpacing); + else + textRect.setLeft(iconRect.left() + iconRect.width() + iconSpacing); + if (button->state & (State_On | State_Sunken)) + iconRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, option, widget), + proxy()->pixelMetric(PM_ButtonShiftVertical, option, widget)); + painter->drawPixmap(iconRect, pixmap); + } + else { + tf |= Qt::AlignHCenter; + } + if (button->state & (State_On | State_Sunken)) + textRect.translate(proxy()->pixelMetric(PM_ButtonShiftHorizontal, option, widget), + proxy()->pixelMetric(PM_ButtonShiftVertical, option, widget)); + if (button->features & QStyleOptionButton::HasMenu) { + int indicatorSize = proxy()->pixelMetric(PM_MenuButtonIndicator, button, widget); + if (button->direction == Qt::LeftToRight) + textRect = textRect.adjusted(0, 0, -indicatorSize, 0); + else + textRect = textRect.adjusted(indicatorSize, 0, 0, 0); + } + proxy()->drawItemText(painter, textRect, tf, button->palette, (button->state & State_Enabled), button->text, + QPalette::ButtonText); + break; + } + case CE_MenuBarEmptyArea: { + QRect rect = option->rect; + if (Phantom::MenuBarDrawBorder) { + Ph::fillRectEdges(painter, rect, Qt::BottomEdge, 1, swatch.color(S_window_divider)); + } + painter->fillRect(rect.adjusted(0, 0, 0, -1), swatch.color(S_window)); + break; + } + case CE_TabBarTabShape: { + auto tab = qstyleoption_cast(option); + if (!tab) + break; + bool rtlHorTabs = (tab->direction == Qt::RightToLeft && + (tab->shape == QTabBar::RoundedNorth || tab->shape == QTabBar::RoundedSouth)); + bool isSelected = tab->state & State_Selected; + bool lastTab = ((!rtlHorTabs && tab->position == QStyleOptionTab::End) || + (rtlHorTabs && tab->position == QStyleOptionTab::Beginning)); + bool onlyOne = tab->position == QStyleOptionTab::OnlyOneTab; + int tabOverlap = pixelMetric(PM_TabBarTabOverlap, option, widget); + const qreal rounding = Ph::TabBarTab_Rounding; + Qt::Edge outerEdge = Qt::TopEdge; + Qt::Edge edgeTowardNextTab = Qt::RightEdge; + switch (tab->shape) { + case QTabBar::RoundedNorth: + outerEdge = Qt::TopEdge; + edgeTowardNextTab = Qt::RightEdge; + break; + case QTabBar::RoundedSouth: + outerEdge = Qt::BottomEdge; + edgeTowardNextTab = Qt::RightEdge; + break; + case QTabBar::RoundedWest: + outerEdge = Qt::LeftEdge; + edgeTowardNextTab = Qt::BottomEdge; + break; + case QTabBar::RoundedEast: + outerEdge = Qt::RightEdge; + edgeTowardNextTab = Qt::BottomEdge; + break; + default: + QCommonStyle::drawControl(element, tab, painter, widget); + return; + } + Qt::Edge innerEdge = Ph::oppositeEdge(outerEdge); + Qt::Edge edgeAwayNextTab = Ph::oppositeEdge(edgeTowardNextTab); + QRect shapeClipRect = Ph::expandRect(option->rect, innerEdge, -2); + QRect drawRect = Ph::expandRect(shapeClipRect, innerEdge, 3 + 2 * rounding + 1); + if (!onlyOne && !lastTab) { + drawRect = Ph::expandRect(drawRect, edgeTowardNextTab, tabOverlap); + shapeClipRect = Ph::expandRect(shapeClipRect, edgeTowardNextTab, tabOverlap); + } + if (!isSelected) { + int offset = proxy()->pixelMetric(PM_TabBarTabShiftVertical, option, widget); + drawRect = Ph::expandRect(drawRect, outerEdge, -offset); + } + painter->save(); + painter->setClipRect(shapeClipRect); + bool hasFrame = tab->features & QStyleOptionTab::HasFrame && !tab->documentMode; + Swatchy tabFrameColor, thisFillColor, specular; + if (hasFrame) { + tabFrameColor = S_tabFrame; + if (isSelected) { + thisFillColor = S_tabFrame; + specular = S_tabFrame_specular; + } + else { + thisFillColor = S_inactiveTabYesFrame; + specular = Ph::TabBar_InactiveTabsHaveSpecular ? S_inactiveTabYesFrame_specular : S_none; + } + } + else { + tabFrameColor = S_window; + if (isSelected) { + thisFillColor = S_window; + specular = S_window_specular; + } + else { + thisFillColor = S_inactiveTabNoFrame; + specular = Ph::TabBar_InactiveTabsHaveSpecular ? S_inactiveTabNoFrame_specular : S_none; + } + } + auto frameColor = isSelected ? S_frame_outline : S_window_outline; + Ph::paintBorderedRoundRect(painter, drawRect, rounding, swatch, frameColor, thisFillColor); + Ph::paintBorderedRoundRect(painter, drawRect.adjusted(1, 1, -1, -1), rounding, swatch, specular, S_none); + painter->restore(); + if (isSelected) { + QRect highlightRect = drawRect.adjusted(2, 1, -2, 0); + highlightRect.setHeight(Ph::dpiScaled(2.0)); + QRect highlightRectSpec = highlightRect.adjusted(-1, -1, 1, 0); + painter->fillRect(highlightRectSpec, Ph::DeriveColors::lightSpecularOf(swatch.color(S_highlight))); + painter->fillRect(highlightRect, swatch.color(S_highlight)); + + QRect refillRect = Ph::rectFromInnerEdgeWithThickness(shapeClipRect, innerEdge, 2); + refillRect = Ph::rectTranslatedTowardEdge(refillRect, innerEdge, 2); + refillRect = Ph::expandRect(refillRect, edgeAwayNextTab | edgeTowardNextTab, -1); + painter->fillRect(refillRect, swatch.color(tabFrameColor)); + Ph::fillRectEdges(painter, refillRect, edgeAwayNextTab | edgeTowardNextTab, 1, swatch.color(specular)); + } + break; + } + case CE_ItemViewItem: { + auto ivopt = qstyleoption_cast(option); + if (!ivopt) + break; + // Hack to work around broken grid line drawing in Qt's table view code: + // + // We tell it that the grid line color is a color via + // SH_Table_GridLineColor. It draws the grid lines, but it in high DPI it's + // broken because it uses a pen/path to draw the line, which makes it too + // narrow, subpixel-incorrectly-antialiased, and/or offset from its correct + // position. So when we draw the item view items in a table view, we'll + // also try to paint 1 pixel outside of our current rect to try to fill in + // the incorrectly painted areas where the grid lines are. + // + // Also note that the table views with the bad drawing code, when + // scrolling, will leave garbage behind in the incorrectly-drawn grid line + // areas. This will also paint over that. + bool overdrawGridHack = false; + if (auto tableWidget = qobject_cast(widget)) { + overdrawGridHack = tableWidget->showGrid() && tableWidget->gridStyle() == Qt::SolidLine; + } + if (overdrawGridHack) { + QRect r = option->rect.adjusted(-1, -1, 1, 1); + Ph::fillRectOutline(painter, r, 1, swatch.color(S_base_divider)); + } + QCommonStyle::drawControl(element, option, painter, widget); + break; + } + case CE_ShapedFrame: { + auto frameopt = qstyleoption_cast(option); + if (frameopt) { + if (frameopt->frameShape == QFrame::HLine) { + QRect r = option->rect; + r.setY(r.y() + r.height() / 2); + r.setHeight(2); + painter->fillRect(r, swatch.color(S_tabFrame_specular)); + r.setHeight(1); + painter->fillRect(r, swatch.color(S_frame_outline)); + break; + } + else if (frameopt->frameShape == QFrame::VLine) { + QRect r = option->rect; + r.setX(r.x() + r.width() / 2); + r.setWidth(2); + painter->fillRect(r, swatch.color(S_tabFrame_specular)); + r.setWidth(1); + painter->fillRect(r, swatch.color(S_frame_outline)); + break; + } + } + QCommonStyle::drawControl(element, option, painter, widget); + break; + } + default: + QCommonStyle::drawControl(element, option, painter, widget); + break; + } +} + +QPalette BaseStyle::standardPalette() const +{ + return QCommonStyle::standardPalette(); +} + +QIcon BaseStyle::standardIcon(StandardPixmap sp, const QStyleOption *opt, const QWidget *widget) const +{ + // TODO figure out how to link this code up properly. + // switch (sp) { + // case SP_ToolBarHorizontalExtensionButton: + // return icons()->icon("chevron-double-down"); + // case SP_ToolBarVerticalExtensionButton: + // return icons()->icon("chevron-double-right"); + // case SP_LineEditClearButton: + // return icons()->icon( + // QString("edit-clear-locationbar-").append((opt->direction == Qt::LeftToRight) ? "rtl" : "ltr")); + // default: + // } + return QCommonStyle::standardIcon(sp, opt, widget); +} + +void BaseStyle::drawComplexControl( + ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, const QWidget *widget) const +{ +#ifdef BUILD_WITH_EASY_PROFILER + EASY_BLOCK("drawControl"); + const char *controlCString = QMetaEnum::fromType().valueToKey(control); + EASY_TEXT("ComplexControl", controlCString); +#endif + using Swatchy = Phantom::Swatchy; + using namespace Phantom::SwatchColors; + namespace Ph = Phantom; + auto ph_swatchPtr = Ph::getCachedSwatchOfQPalette(&d->swatchCache, &d->headSwatchFastKey, option->palette); + const Ph::PhSwatch &swatch = *ph_swatchPtr.data(); + + switch (control) { + case CC_GroupBox: { + auto groupBox = qstyleoption_cast(option); + if (!groupBox) + break; + painter->save(); + // Draw frame + QRect textRect = proxy()->subControlRect(CC_GroupBox, option, SC_GroupBoxLabel, widget); + QRect checkBoxRect = proxy()->subControlRect(CC_GroupBox, option, SC_GroupBoxCheckBox, widget); + + if (groupBox->subControls & QStyle::SC_GroupBoxFrame) { + QStyleOptionFrame frame; + frame.QStyleOption::operator=(*groupBox); + frame.features = groupBox->features; + frame.lineWidth = groupBox->lineWidth; + frame.midLineWidth = groupBox->midLineWidth; + frame.rect = proxy()->subControlRect(CC_GroupBox, option, SC_GroupBoxFrame, widget); + proxy()->drawPrimitive(PE_FrameGroupBox, &frame, painter, widget); + } + + // Draw title + if ((groupBox->subControls & QStyle::SC_GroupBoxLabel) && !groupBox->text.isEmpty()) { + // groupBox->textColor gets the incorrect palette here + painter->setPen(QPen(option->palette.windowText(), 1)); + unsigned alignment = groupBox->textAlignment; + if (!proxy()->styleHint(QStyle::SH_UnderlineShortcut, option, widget)) + alignment |= Qt::TextHideMnemonic; + + proxy()->drawItemText(painter, textRect, alignment | Qt::TextShowMnemonic | Qt::AlignLeft, + groupBox->palette, groupBox->state & State_Enabled, groupBox->text, QPalette::NoRole); + + if (groupBox->state & State_HasFocus) { + QStyleOptionFocusRect fropt; + fropt.QStyleOption::operator=(*groupBox); + fropt.rect = textRect.adjusted(-1, 0, 1, 0); + proxy()->drawPrimitive(PE_FrameFocusRect, &fropt, painter, widget); + } + } + + // Draw checkbox + if (groupBox->subControls & SC_GroupBoxCheckBox) { + QStyleOptionButton box; + box.QStyleOption::operator=(*groupBox); + box.rect = checkBoxRect; + proxy()->drawPrimitive(PE_IndicatorCheckBox, &box, painter, widget); + } + painter->restore(); + break; + } + case CC_SpinBox: { + auto spinBox = qstyleoption_cast(option); + if (!spinBox) + break; + const qreal rounding = Ph::SpinBox_Rounding; + bool isLeftToRight = option->direction != Qt::RightToLeft; + const QRect rect = spinBox->rect; + bool sunken = spinBox->state & State_Sunken; + bool upIsActive = spinBox->activeSubControls == SC_SpinBoxUp; + bool downIsActive = spinBox->activeSubControls == SC_SpinBoxDown; + bool hasFocus = option->state & State_HasFocus; + bool isEnabled = option->state & State_Enabled; + QRect upRect = proxy()->subControlRect(CC_SpinBox, spinBox, SC_SpinBoxUp, widget); + QRect downRect = proxy()->subControlRect(CC_SpinBox, spinBox, SC_SpinBoxDown, widget); + if (spinBox->frame) { + QRect upDownRect = upRect | downRect; + upDownRect.adjust(0, -1, 0, 1); + painter->save(); // 0 + // Fill background + Ph::paintBorderedRoundRect(painter, rect, rounding, swatch, S_none, S_base); + // Draw button fill + painter->setClipRect(upDownRect); + // Side with the border + Qt::Edge edge = isLeftToRight ? Qt::LeftEdge : Qt::RightEdge; + Ph::paintBorderedRoundRect( + painter, Ph::expandRect(upDownRect, Ph::oppositeEdge(edge), -1), rounding, swatch, S_none, S_button); + painter->restore(); // 0 + if (Ph::OverhangShadows && !hasFocus && isEnabled) { + // Imperfect, leaves tiny gap on left and right. Going closer would eat + // into the outline, though. + QRect shadowRect = rect.adjusted(qRound(rounding / 2), 1, -qRound(rounding / 2), -1); + if (isLeftToRight) { + shadowRect.setRight(upDownRect.left()); + } + else { + shadowRect.setLeft(upDownRect.right()); + } + Ph::fillRectEdges(painter, shadowRect, Qt::TopEdge, 1, swatch.color(S_base_shadow)); + } + if ((spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled) && upIsActive && sunken) { + painter->fillRect(upRect, swatch.color(S_button_pressed)); + } + if ((spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled) && downIsActive && sunken) { + painter->fillRect(downRect, swatch.color(S_button_pressed)); + } + // Left or right border line + Ph::fillRectEdges(painter, upDownRect, edge, 1, swatch.color(S_window_outline)); + Ph::PSave save(painter); + // Outline over entire frame + Swatchy outlineColor = hasFocus ? S_highlight_outline : S_window_outline; + Ph::paintBorderedRoundRect(painter, rect, rounding, swatch, outlineColor, S_none); + save.restore(); + } + + if (spinBox->buttonSymbols == QAbstractSpinBox::PlusMinus) { + Ph::PSave save(painter); + // TODO fix up old fusion code here + int centerX = upRect.center().x(); + int centerY = upRect.center().y(); + Swatchy arrowColorUp = + spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled ? S_indicator_current : S_indicator_disabled; + Swatchy arrowColorDown = + spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled ? S_indicator_current : S_indicator_disabled; + painter->setPen(swatch.pen(arrowColorUp)); + painter->drawLine(centerX - 1, centerY, centerX + 3, centerY); + painter->drawLine(centerX + 1, centerY - 2, centerX + 1, centerY + 2); + centerX = downRect.center().x(); + centerY = downRect.center().y(); + painter->setPen(arrowColorDown); + painter->drawLine(centerX - 1, centerY, centerX + 3, centerY); + } + else if (spinBox->buttonSymbols == QAbstractSpinBox::UpDownArrows) { + int xoffs = isLeftToRight ? 0 : 1; + Ph::drawArrow(painter, upRect.adjusted(4 + xoffs, 1, -5 + xoffs, 1), Qt::UpArrow, swatch, + spinBox->stepEnabled & QAbstractSpinBox::StepUpEnabled); + Ph::drawArrow(painter, downRect.adjusted(4 + xoffs, 0, -5 + xoffs, -1), Qt::DownArrow, swatch, + spinBox->stepEnabled & QAbstractSpinBox::StepDownEnabled); + } + break; + } + case CC_TitleBar: { + auto titleBar = qstyleoption_cast(option); + if (!titleBar) + break; + painter->save(); + const int buttonMargin = 5; + bool active = (titleBar->titleBarState & State_Active); + QRect fullRect = titleBar->rect; + QPalette palette = option->palette; + QColor highlight = option->palette.highlight().color(); + QColor outline = option->palette.dark().color(); + + QColor titleBarFrameBorder(active ? highlight.darker(180) : outline.darker(110)); + QColor titleBarHighlight(active ? highlight.lighter(120) : palette.background().color().lighter(120)); + QColor textColor(active ? 0xffffff : 0xff000000); + QColor textAlphaColor(active ? 0xffffff : 0xff000000); + + { + // Fill title + QColor titlebarColor = QColor(active ? highlight : palette.background().color()); + painter->fillRect(option->rect.adjusted(1, 1, -1, 0), titlebarColor); + // Frame and rounded corners + painter->setPen(titleBarFrameBorder); + + // top outline + painter->drawLine(fullRect.left() + 5, fullRect.top(), fullRect.right() - 5, fullRect.top()); + painter->drawLine(fullRect.left(), fullRect.top() + 4, fullRect.left(), fullRect.bottom()); + const QPoint points[5] = {QPoint(fullRect.left() + 4, fullRect.top() + 1), + QPoint(fullRect.left() + 3, fullRect.top() + 1), QPoint(fullRect.left() + 2, fullRect.top() + 2), + QPoint(fullRect.left() + 1, fullRect.top() + 3), QPoint(fullRect.left() + 1, fullRect.top() + 4)}; + painter->drawPoints(points, 5); + + painter->drawLine(fullRect.right(), fullRect.top() + 4, fullRect.right(), fullRect.bottom()); + const QPoint points2[5] = {QPoint(fullRect.right() - 3, fullRect.top() + 1), + QPoint(fullRect.right() - 4, fullRect.top() + 1), QPoint(fullRect.right() - 2, fullRect.top() + 2), + QPoint(fullRect.right() - 1, fullRect.top() + 3), QPoint(fullRect.right() - 1, fullRect.top() + 4)}; + painter->drawPoints(points2, 5); + + // draw bottomline + painter->drawLine(fullRect.right(), fullRect.bottom(), fullRect.left(), fullRect.bottom()); + + // top highlight + painter->setPen(titleBarHighlight); + painter->drawLine(fullRect.left() + 6, fullRect.top() + 1, fullRect.right() - 6, fullRect.top() + 1); + } + // draw title + QRect textRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarLabel, widget); + painter->setPen(active ? (titleBar->palette.text().color().lighter(120)) : titleBar->palette.text().color()); + // Note workspace also does elliding but it does not use the correct font + QString title = painter->fontMetrics().elidedText(titleBar->text, Qt::ElideRight, textRect.width() - 14); + painter->drawText(textRect.adjusted(1, 1, 1, 1), title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter)); + painter->setPen(Qt::white); + if (active) + painter->drawText(textRect, title, QTextOption(Qt::AlignHCenter | Qt::AlignVCenter)); + // min button + if ((titleBar->subControls & SC_TitleBarMinButton) && + (titleBar->titleBarFlags & Qt::WindowMinimizeButtonHint) && + !(titleBar->titleBarState & Qt::WindowMinimized)) { + QRect minButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarMinButton, widget); + if (minButtonRect.isValid()) { + bool hover = + (titleBar->activeSubControls & SC_TitleBarMinButton) && (titleBar->state & State_MouseOver); + bool sunken = (titleBar->activeSubControls & SC_TitleBarMinButton) && (titleBar->state & State_Sunken); + Ph::drawMdiButton(painter, titleBar, minButtonRect, hover, sunken); + QRect minButtonIconRect = + minButtonRect.adjusted(buttonMargin, buttonMargin, -buttonMargin, -buttonMargin); + painter->setPen(textColor); + painter->drawLine(minButtonIconRect.center().x() - 2, minButtonIconRect.center().y() + 3, + minButtonIconRect.center().x() + 3, minButtonIconRect.center().y() + 3); + painter->drawLine(minButtonIconRect.center().x() - 2, minButtonIconRect.center().y() + 4, + minButtonIconRect.center().x() + 3, minButtonIconRect.center().y() + 4); + painter->setPen(textAlphaColor); + painter->drawLine(minButtonIconRect.center().x() - 3, minButtonIconRect.center().y() + 3, + minButtonIconRect.center().x() - 3, minButtonIconRect.center().y() + 4); + painter->drawLine(minButtonIconRect.center().x() + 4, minButtonIconRect.center().y() + 3, + minButtonIconRect.center().x() + 4, minButtonIconRect.center().y() + 4); + } + } + // max button + if ((titleBar->subControls & SC_TitleBarMaxButton) && + (titleBar->titleBarFlags & Qt::WindowMaximizeButtonHint) && + !(titleBar->titleBarState & Qt::WindowMaximized)) { + QRect maxButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarMaxButton, widget); + if (maxButtonRect.isValid()) { + bool hover = + (titleBar->activeSubControls & SC_TitleBarMaxButton) && (titleBar->state & State_MouseOver); + bool sunken = (titleBar->activeSubControls & SC_TitleBarMaxButton) && (titleBar->state & State_Sunken); + Ph::drawMdiButton(painter, titleBar, maxButtonRect, hover, sunken); + + QRect maxButtonIconRect = + maxButtonRect.adjusted(buttonMargin, buttonMargin, -buttonMargin, -buttonMargin); + + painter->setPen(textColor); + painter->drawRect(maxButtonIconRect.adjusted(0, 0, -1, -1)); + painter->drawLine(maxButtonIconRect.left() + 1, maxButtonIconRect.top() + 1, + maxButtonIconRect.right() - 1, maxButtonIconRect.top() + 1); + painter->setPen(textAlphaColor); + const QPoint points[4] = {maxButtonIconRect.topLeft(), maxButtonIconRect.topRight(), + maxButtonIconRect.bottomLeft(), maxButtonIconRect.bottomRight()}; + painter->drawPoints(points, 4); + } + } + + // close button + if ((titleBar->subControls & SC_TitleBarCloseButton) && (titleBar->titleBarFlags & Qt::WindowSystemMenuHint)) { + QRect closeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarCloseButton, widget); + if (closeButtonRect.isValid()) { + bool hover = + (titleBar->activeSubControls & SC_TitleBarCloseButton) && (titleBar->state & State_MouseOver); + bool sunken = + (titleBar->activeSubControls & SC_TitleBarCloseButton) && (titleBar->state & State_Sunken); + Ph::drawMdiButton(painter, titleBar, closeButtonRect, hover, sunken); + QRect closeIconRect = + closeButtonRect.adjusted(buttonMargin, buttonMargin, -buttonMargin, -buttonMargin); + painter->setPen(textAlphaColor); + const QLine lines[4] = {QLine(closeIconRect.left() + 1, closeIconRect.top(), closeIconRect.right(), + closeIconRect.bottom() - 1), + QLine(closeIconRect.left(), closeIconRect.top() + 1, closeIconRect.right() - 1, + closeIconRect.bottom()), + QLine(closeIconRect.right() - 1, closeIconRect.top(), closeIconRect.left(), + closeIconRect.bottom() - 1), + QLine(closeIconRect.right(), closeIconRect.top() + 1, closeIconRect.left() + 1, + closeIconRect.bottom())}; + painter->drawLines(lines, 4); + const QPoint points[4] = {closeIconRect.topLeft(), closeIconRect.topRight(), closeIconRect.bottomLeft(), + closeIconRect.bottomRight()}; + painter->drawPoints(points, 4); + + painter->setPen(textColor); + painter->drawLine(closeIconRect.left() + 1, closeIconRect.top() + 1, closeIconRect.right() - 1, + closeIconRect.bottom() - 1); + painter->drawLine(closeIconRect.left() + 1, closeIconRect.bottom() - 1, closeIconRect.right() - 1, + closeIconRect.top() + 1); + } + } + + // normalize button + if ((titleBar->subControls & SC_TitleBarNormalButton) && + (((titleBar->titleBarFlags & Qt::WindowMinimizeButtonHint) && + (titleBar->titleBarState & Qt::WindowMinimized)) || + ((titleBar->titleBarFlags & Qt::WindowMaximizeButtonHint) && + (titleBar->titleBarState & Qt::WindowMaximized)))) { + QRect normalButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarNormalButton, widget); + if (normalButtonRect.isValid()) { + + bool hover = + (titleBar->activeSubControls & SC_TitleBarNormalButton) && (titleBar->state & State_MouseOver); + bool sunken = + (titleBar->activeSubControls & SC_TitleBarNormalButton) && (titleBar->state & State_Sunken); + QRect normalButtonIconRect = + normalButtonRect.adjusted(buttonMargin, buttonMargin, -buttonMargin, -buttonMargin); + Ph::drawMdiButton(painter, titleBar, normalButtonRect, hover, sunken); + + QRect frontWindowRect = normalButtonIconRect.adjusted(0, 3, -3, 0); + painter->setPen(textColor); + painter->drawRect(frontWindowRect.adjusted(0, 0, -1, -1)); + painter->drawLine(frontWindowRect.left() + 1, frontWindowRect.top() + 1, frontWindowRect.right() - 1, + frontWindowRect.top() + 1); + painter->setPen(textAlphaColor); + const QPoint points[4] = {frontWindowRect.topLeft(), frontWindowRect.topRight(), + frontWindowRect.bottomLeft(), frontWindowRect.bottomRight()}; + painter->drawPoints(points, 4); + + QRect backWindowRect = normalButtonIconRect.adjusted(3, 0, 0, -3); + QRegion clipRegion = backWindowRect; + clipRegion -= frontWindowRect; + painter->save(); + painter->setClipRegion(clipRegion); + painter->setPen(textColor); + painter->drawRect(backWindowRect.adjusted(0, 0, -1, -1)); + painter->drawLine(backWindowRect.left() + 1, backWindowRect.top() + 1, backWindowRect.right() - 1, + backWindowRect.top() + 1); + painter->setPen(textAlphaColor); + const QPoint points2[4] = {backWindowRect.topLeft(), backWindowRect.topRight(), + backWindowRect.bottomLeft(), backWindowRect.bottomRight()}; + painter->drawPoints(points2, 4); + painter->restore(); + } + } + + // context help button + if (titleBar->subControls & SC_TitleBarContextHelpButton && + (titleBar->titleBarFlags & Qt::WindowContextHelpButtonHint)) { + QRect contextHelpButtonRect = + proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarContextHelpButton, widget); + if (contextHelpButtonRect.isValid()) { + bool hover = + (titleBar->activeSubControls & SC_TitleBarContextHelpButton) && (titleBar->state & State_MouseOver); + bool sunken = + (titleBar->activeSubControls & SC_TitleBarContextHelpButton) && (titleBar->state & State_Sunken); + Ph::drawMdiButton(painter, titleBar, contextHelpButtonRect, hover, sunken); + // This is lame, but I doubt it will get used often. Previously, XPM + // icon was used here (very poorly, by re-allocating a QImage over and + // over and modifying/painting it) + QIcon helpIcon = QCommonStyle::standardIcon(QStyle::SP_DialogHelpButton); + helpIcon.paint(painter, contextHelpButtonRect.adjusted(4, 4, -4, -4)); + } + } + + // shade button + if (titleBar->subControls & SC_TitleBarShadeButton && (titleBar->titleBarFlags & Qt::WindowShadeButtonHint)) { + QRect shadeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarShadeButton, widget); + if (shadeButtonRect.isValid()) { + bool hover = + (titleBar->activeSubControls & SC_TitleBarShadeButton) && (titleBar->state & State_MouseOver); + bool sunken = + (titleBar->activeSubControls & SC_TitleBarShadeButton) && (titleBar->state & State_Sunken); + Ph::drawMdiButton(painter, titleBar, shadeButtonRect, hover, sunken); + Ph::drawArrow(painter, shadeButtonRect.adjusted(5, 7, -5, -7), Qt::UpArrow, swatch); + } + } + + // unshade button + if (titleBar->subControls & SC_TitleBarUnshadeButton && (titleBar->titleBarFlags & Qt::WindowShadeButtonHint)) { + QRect unshadeButtonRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarUnshadeButton, widget); + if (unshadeButtonRect.isValid()) { + bool hover = + (titleBar->activeSubControls & SC_TitleBarUnshadeButton) && (titleBar->state & State_MouseOver); + bool sunken = + (titleBar->activeSubControls & SC_TitleBarUnshadeButton) && (titleBar->state & State_Sunken); + Ph::drawMdiButton(painter, titleBar, unshadeButtonRect, hover, sunken); + Ph::drawArrow(painter, unshadeButtonRect.adjusted(5, 7, -5, -7), Qt::DownArrow, swatch); + } + } + + if ((titleBar->subControls & SC_TitleBarSysMenu) && (titleBar->titleBarFlags & Qt::WindowSystemMenuHint)) { + QRect iconRect = proxy()->subControlRect(CC_TitleBar, titleBar, SC_TitleBarSysMenu, widget); + if (iconRect.isValid()) { + if (!titleBar->icon.isNull()) { + titleBar->icon.paint(painter, iconRect); + } + else { + QStyleOption tool = *titleBar; + QPixmap pm = proxy()->standardIcon(SP_TitleBarMenuButton, &tool, widget).pixmap(16, 16); + tool.rect = iconRect; + painter->save(); + proxy()->drawItemPixmap(painter, iconRect, Qt::AlignCenter, pm); + painter->restore(); + } + } + } + painter->restore(); + break; + } + case CC_ScrollBar: { + auto scrollBar = qstyleoption_cast(option); + if (!scrollBar) + break; + auto pr = proxy(); + QRect scrollBarSubLine = pr->subControlRect(control, scrollBar, SC_ScrollBarSubLine, widget); + QRect scrollBarAddLine = pr->subControlRect(control, scrollBar, SC_ScrollBarAddLine, widget); + QRect scrollBarSlider = pr->subControlRect(control, scrollBar, SC_ScrollBarSlider, widget); + QRect scrollBarGroove = pr->subControlRect(control, scrollBar, SC_ScrollBarGroove, widget); + + int padding = Ph::dpiScaled(4); + scrollBarSlider.setX(scrollBarSlider.x() + padding); + scrollBarSlider.setY(scrollBarSlider.y() + padding); + // Width and height should be reduced by 2 * padding, but somehow padding is enough. + scrollBarSlider.setWidth(scrollBarSlider.width() - padding); + scrollBarSlider.setHeight(scrollBarSlider.height() - padding); + + // Groove/gutter/trench area + if (scrollBar->subControls & SC_ScrollBarGroove) { + painter->fillRect(scrollBarGroove, swatch.color(S_window)); + } + + // Slider thumb + if (scrollBar->subControls & SC_ScrollBarSlider) { + qreal radius = + (scrollBar->orientation == Qt::Horizontal ? scrollBarSlider.height() : scrollBarSlider.width()) / 2.0; + painter->fillRect(scrollBarSlider, swatch.color(S_window)); + Ph::paintSolidRoundRect(painter, scrollBarSlider, radius, swatch, S_scrollbarSlider); + } + + // The SubLine (up/left) buttons + if (scrollBar->subControls & SC_ScrollBarSubLine) { + painter->fillRect(scrollBarSubLine, swatch.color(S_window)); + } + + // The AddLine (down/right) button + if (scrollBar->subControls & SC_ScrollBarAddLine) { + painter->fillRect(scrollBarAddLine, swatch.color(S_window)); + } + break; + } + case CC_ComboBox: { + auto comboBox = qstyleoption_cast(option); + if (!comboBox) + break; + painter->save(); + bool isLeftToRight = option->direction != Qt::RightToLeft; + bool hasFocus = option->state & State_HasFocus && option->state & State_KeyboardFocusChange; + bool isSunken = comboBox->state & State_Sunken; + QRect rect = comboBox->rect; + QRect downArrowRect = proxy()->subControlRect(CC_ComboBox, comboBox, SC_ComboBoxArrow, widget); + // Draw a line edit + if (comboBox->editable) { + Swatchy buttonFill = isSunken ? S_button_pressed : S_button; + // if (!hasOptions) + // buttonFill = S_window; + painter->fillRect(rect, swatch.color(buttonFill)); + if (comboBox->frame) { + QStyleOptionFrame buttonOption; + buttonOption.QStyleOption::operator=(*comboBox); + buttonOption.rect = rect; + buttonOption.state = + (comboBox->state & (State_Enabled | State_MouseOver | State_HasFocus)) | State_KeyboardFocusChange; + if (isSunken) { + buttonOption.state |= State_Sunken; + buttonOption.state &= ~State_MouseOver; + } + proxy()->drawPrimitive(PE_FrameLineEdit, &buttonOption, painter, widget); + QRect fr = proxy()->subControlRect(CC_ComboBox, option, SC_ComboBoxEditField, widget); + QRect br = rect; + if (isLeftToRight) { + br.setLeft(fr.x() + fr.width()); + } + else { + br.setRight(fr.left() - 1); + } + Qt::Edge edge = isLeftToRight ? Qt::LeftEdge : Qt::RightEdge; + Swatchy color = hasFocus ? S_highlight_outline : S_window_outline; + br.adjust(0, 1, 0, -1); + Ph::fillRectEdges(painter, br, edge, 1, swatch.color(color)); + br.adjust(1, 0, -1, 0); + Swatchy specular = isSunken ? S_button_pressed_specular : S_button_specular; + Ph::fillRectOutline(painter, br, 1, swatch.color(specular)); + } + } + else { + QStyleOptionButton buttonOption; + buttonOption.QStyleOption::operator=(*comboBox); + buttonOption.rect = rect; + buttonOption.state = comboBox->state & (State_Enabled | State_MouseOver | State_HasFocus | State_Active | + State_KeyboardFocusChange); + // Combo boxes should be shown to be keyboard interactive if they're + // focused at all, not just if the user has pressed tab to enter keyboard + // focus change mode. This is because the up/down arrows can, regardless + // of having pressed tab, control the combo box selection. + if (comboBox->state & State_HasFocus) + buttonOption.state |= State_KeyboardFocusChange; + if (isSunken) { + buttonOption.state |= State_Sunken; + buttonOption.state &= ~State_MouseOver; + } + proxy()->drawPrimitive(PE_PanelButtonCommand, &buttonOption, painter, widget); + } + if (comboBox->subControls & SC_ComboBoxArrow) { + int margin = + static_cast(qMin(downArrowRect.width(), downArrowRect.height()) * Ph::ComboBox_ArrowMarginRatio); + QRect r = downArrowRect; + r.adjust(margin, margin, -margin, -margin); + // Draw the up/down arrow + Ph::drawArrow(painter, r, Qt::DownArrow, swatch); + } + painter->restore(); + break; + } + case CC_Slider: { + auto slider = qstyleoption_cast(option); + if (!slider) + break; + const QRect groove = proxy()->subControlRect(CC_Slider, option, SC_SliderGroove, widget); + const QRect handle = proxy()->subControlRect(CC_Slider, option, SC_SliderHandle, widget); + bool horizontal = slider->orientation == Qt::Horizontal; + bool ticksAbove = slider->tickPosition & QSlider::TicksAbove; + bool ticksBelow = slider->tickPosition & QSlider::TicksBelow; + Swatchy outlineColor = S_window_outline; + if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange) + outlineColor = S_highlight_outline; + if ((option->subControls & SC_SliderGroove) && groove.isValid()) { + QRect g0 = groove; + if (g0.height() > 5) + g0.adjust(0, 1, 0, -1); + Ph::PSave saver(painter); + Swatchy gutterColor = option->state & State_Enabled ? S_scrollbarGutter : S_window; + Ph::paintBorderedRoundRect(painter, groove, Ph::SliderGroove_Rounding, swatch, outlineColor, gutterColor); + } + if (option->subControls & SC_SliderTickmarks) { + Ph::PSave save(painter); + painter->setPen(swatch.pen(S_window_outline)); + int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget); + int available = proxy()->pixelMetric(PM_SliderSpaceAvailable, slider, widget); + int interval = slider->tickInterval; + if (interval <= 0) { + interval = slider->singleStep; + if (QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, interval, available) - + QStyle::sliderPositionFromValue(slider->minimum, slider->maximum, 0, available) < + 3) + interval = slider->pageStep; + } + if (interval <= 0) + interval = 1; + + int v = slider->minimum; + int len = proxy()->pixelMetric(PM_SliderLength, slider, widget); + while (v <= slider->maximum + 1) { + if (v == slider->maximum + 1 && interval == 1) + break; + const int v_ = qMin(v, slider->maximum); + int pos = sliderPositionFromValue(slider->minimum, slider->maximum, v_, + (horizontal ? slider->rect.width() : slider->rect.height()) - len, slider->upsideDown) + + len / 2; + int extra = 2 - ((v_ == slider->minimum || v_ == slider->maximum) ? 1 : 0); + + if (horizontal) { + if (ticksAbove) { + painter->drawLine(pos, slider->rect.top() + extra, pos, slider->rect.top() + tickSize); + } + if (ticksBelow) { + painter->drawLine(pos, slider->rect.bottom() - extra, pos, slider->rect.bottom() - tickSize); + } + } + else { + if (ticksAbove) { + painter->drawLine(slider->rect.left() + extra, pos, slider->rect.left() + tickSize, pos); + } + if (ticksBelow) { + painter->drawLine(slider->rect.right() - extra, pos, slider->rect.right() - tickSize, pos); + } + } + // in the case where maximum is max int + int nextInterval = v + interval; + if (nextInterval < v) + break; + v = nextInterval; + } + } + // draw handle + if ((option->subControls & SC_SliderHandle)) { + bool isPressed = option->state & QStyle::State_Sunken && option->activeSubControls & SC_SliderHandle; + QRect r = handle; + Swatchy handleOutline, handleFill, handleSpecular; + if (option->state & State_HasFocus && option->state & State_KeyboardFocusChange) { + handleOutline = S_highlight_outline; + } + else { + handleOutline = S_window_outline; + } + if (isPressed) { + handleFill = S_sliderHandle_pressed; + handleSpecular = S_sliderHandle_pressed_specular; + } + else { + handleFill = S_sliderHandle; + handleSpecular = S_sliderHandle_specular; + } + Ph::PSave save(painter); + Ph::paintBorderedRoundRect(painter, r, Ph::SliderHandle_Rounding, swatch, handleOutline, handleFill); + r.adjust(1, 1, -1, -1); + Ph::paintBorderedRoundRect(painter, r, Ph::SliderHandle_Rounding, swatch, handleSpecular, S_none); + } + break; + } + case CC_ToolButton: { + auto tbopt = qstyleoption_cast(option); + if (Ph::AllowToolBarAutoRaise || !tbopt || !widget || !widget->parent() || + !widget->parent()->inherits("QToolBar")) { + QCommonStyle::drawComplexControl(control, option, painter, widget); + break; + } + QStyleOptionToolButton opt_; + opt_.QStyleOptionToolButton::operator=(*tbopt); + opt_.state &= ~State_AutoRaise; + QCommonStyle::drawComplexControl(control, &opt_, painter, widget); + break; + } + case CC_Dial: + if (auto dial = qstyleoption_cast(option)) + Ph::drawDial(dial, painter); + break; + default: + QCommonStyle::drawComplexControl(control, option, painter, widget); + break; + } +} + +int BaseStyle::pixelMetric(PixelMetric metric, const QStyleOption *option, const QWidget *widget) const +{ + // Calculate pixel metrics. + // Use immediate return if value is not supposed to be dpi-scaled. + int val = -1; + switch (metric) { + case PM_SliderTickmarkOffset: + val = 6; + break; + case PM_ToolTipLabelFrameWidth: + case PM_HeaderMargin: + case PM_ButtonMargin: + case PM_SpinBoxFrameWidth: + val = Phantom::DefaultFrameWidth; + break; + case PM_ButtonDefaultIndicator: + case PM_ButtonShiftHorizontal: + val = 0; + break; + case PM_ButtonShiftVertical: + if (qobject_cast(widget)) { + return 0; + } + val = 1; + break; + case PM_ComboBoxFrameWidth: + return 1; + case PM_DefaultFrameWidth: + // Original comment from fusion: + // Do not dpi-scale because the drawn frame is always exactly 1 pixel thick + // My note: + // I seriously doubt, with all of the hacky add-or-remove-1 things + // everywhere in fusion (and still in phantom), and the fact that fusion is + // totally broken in high dpi, that this actually holds true. + if (qobject_cast(widget)) { + return 1; + } + val = qMax(1, Phantom::DefaultFrameWidth - 2); + break; + case PM_MessageBoxIconSize: + val = 48; + break; + case PM_DialogButtonsSeparator: + case PM_ScrollBarSliderMin: + val = 26; + break; + case PM_TitleBarHeight: + val = 24; + break; + case PM_ScrollBarExtent: + val = 12; + break; + case PM_SliderThickness: + case PM_SliderLength: + val = 15; + break; + case PM_DockWidgetTitleMargin: + val = 1; + break; + case PM_MenuVMargin: + case PM_MenuHMargin: + case PM_MenuPanelWidth: + val = 0; + break; + case PM_MenuBarItemSpacing: + val = 0; + break; + case PM_MenuBarHMargin: + // option is usually nullptr, use widget instead to get font metrics + if (!Phantom::MenuBarLeftMargin || !widget) { + val = 0; + break; + } + return widget->fontMetrics().height() * Phantom::MenuBar_HorizontalPaddingFontRatio; + case PM_MenuBarVMargin: + case PM_MenuBarPanelWidth: + val = 0; + break; + case PM_ToolBarSeparatorExtent: + val = 9; + break; + case PM_ToolBarHandleExtent: { + int dotLen = Phantom::dpiScaled(2); + return dotLen * (3 * 2 - 1); + } + case PM_ToolBarItemSpacing: + val = 1; + break; + case PM_ToolBarFrameWidth: + val = Phantom::MenuBar_FrameWidth; + break; + case PM_ToolBarItemMargin: + val = 1; + break; + case PM_ToolBarExtensionExtent: + val = 32; + break; + case PM_ListViewIconSize: + case PM_SmallIconSize: + if (Phantom::ItemView_UseFontHeightForDecorationSize && widget && + qobject_cast(widget)) { + // QAbstractItemView::viewOptions() always uses nullptr for the + // styleoption when querying for PM_SmallIconSize. The best we can do is + // use the font set on the widget itself, which is obviously going to be + // wrong if the row has a custom font set on it. Hmm. + return widget->fontMetrics().height(); + } + val = 16; + break; + case PM_ButtonIconSize: { + if (option) + return option->fontMetrics.height(); + if (widget) + return widget->fontMetrics().height(); + val = 16; + break; + } + case PM_DockWidgetTitleBarButtonMargin: + val = 2; + break; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 8, 0)) + case PM_TitleBarButtonSize: + val = 19; + break; +#endif + case PM_MaximumDragDistance: + return -1; // Do not dpi-scale because the value is magic + case PM_TabCloseIndicatorWidth: + case PM_TabCloseIndicatorHeight: + val = 16; + break; + case PM_TabBarTabHSpace: + // Contents may clip out horizontally if we don't some extra pixels here or + // in sizeFromContents for CT_TabBarTab. + if (!option) + break; + return static_cast(option->fontMetrics.height() * Phantom::TabBar_HPaddingFontRatio) + + static_cast(Phantom::dpiScaled(4)); + case PM_TabBarTabVSpace: + if (!option) + break; + return static_cast(option->fontMetrics.height() * Phantom::TabBar_VPaddingFontRatio) + + static_cast(Phantom::dpiScaled(2)); + case PM_TabBarTabOverlap: + val = 1; + break; + case PM_TabBarBaseOverlap: + val = 2; + break; + case PM_TabBarIconSize: { + if (!widget) + break; + return widget->fontMetrics().height(); + } + case PM_TabBarTabShiftVertical: { + val = Phantom::TabBar_InactiveVShift; + break; + } + case PM_SubMenuOverlap: + val = 0; + break; + case PM_DockWidgetHandleExtent: + case PM_SplitterWidth: + val = 5; + break; + case PM_IndicatorHeight: + case PM_IndicatorWidth: + case PM_ExclusiveIndicatorHeight: + case PM_ExclusiveIndicatorWidth: + if (option) + return option->fontMetrics.height(); + if (widget) + return widget->fontMetrics().height(); + val = 14; + break; + case PM_ScrollView_ScrollBarOverlap: + case PM_ScrollView_ScrollBarSpacing: + val = 0; + break; + case PM_TreeViewIndentation: { + if (widget) + return widget->fontMetrics().height(); + val = 12; + break; + } + default: + val = QCommonStyle::pixelMetric(metric, option, widget); + } + return Phantom::dpiScaled(val); +} + +QSize BaseStyle::sizeFromContents( + ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const +{ + namespace Ph = Phantom; + // Cases which do not rely on the parent class to do any work + switch (type) { + case CT_RadioButton: + case CT_CheckBox: { + auto btn = qstyleoption_cast(option); + if (!btn) + break; + bool isRadio = type == CT_RadioButton; + int w = proxy()->pixelMetric(isRadio ? PM_ExclusiveIndicatorWidth : PM_IndicatorWidth, btn, widget); + int h = proxy()->pixelMetric(isRadio ? PM_ExclusiveIndicatorHeight : PM_IndicatorHeight, btn, widget); + int margins = 0; + if (!btn->icon.isNull() || !btn->text.isEmpty()) + margins = + proxy()->pixelMetric(isRadio ? PM_RadioButtonLabelSpacing : PM_CheckBoxLabelSpacing, option, widget); + return QSize(size.width() + w + margins, qMax(size.height(), h)); + } + case CT_MenuBarItem: { + int fontHeight = option ? option->fontMetrics.height() : size.height(); + int w = static_cast(fontHeight * Ph::MenuBar_HorizontalPaddingFontRatio); + int h = static_cast(fontHeight * Ph::MenuBar_VerticalPaddingFontRatio); + int line = Ph::dpiScaled(1); + return QSize(size.width() + w * 2, size.height() + h * 2 + line); + } + case CT_MenuItem: { + auto menuItem = qstyleoption_cast(option); + if (!menuItem) + return size; + bool hasTabChar = menuItem->text.contains(QLatin1Char('\t')); + bool hasSubMenu = menuItem->menuItemType == QStyleOptionMenuItem::SubMenu; + bool isSeparator = menuItem->menuItemType == QStyleOptionMenuItem::Separator; + int fontMetricsHeight = -1; + // See notes at CE_MenuItem and SH_ComboBox_Popup for more information + if (Ph::UseQMenuForComboBoxPopup && qobject_cast(widget)) { + if (!widget->testAttribute(Qt::WA_SetFont)) + fontMetricsHeight = QFontMetrics(qApp->font("QMenu")).height(); + } + if (fontMetricsHeight == -1) { + fontMetricsHeight = option->fontMetrics.height(); + } + auto metrics = Ph::MenuItemMetrics::ofFontHeight(fontMetricsHeight); + // Incoming width is the sum of the visual widths of the main item text and + // the mnemonic text (if any). To this width we will add the widths of the + // other features for this menu item -- the icon/checkbox, spacing between + // icon/text/mnemonic, etc. For cases like separators without any text, we + // may disregard the width. + // + // Height is the text height, probably. + int w = size.width(); + // Frame + w += metrics.frameThickness * 2; + // Left margins don't depend on whether or not we have a submenu arrow. + // Calculating the right margins requires knowing whether or not the menu + // item has a submenu arrow. + w += metrics.leftMargin; + // Phantom treats every menu item with the same space on the left for a + // check mark, even if it doesn't have the checkable property. + w += metrics.checkWidth + metrics.checkRightSpace; + + if (!menuItem->icon.isNull()) { + // Phantom disregards any user-specified icon sizing at the moment. + w += metrics.fontHeight; + w += metrics.iconRightSpace; + } + + // Tab character is used for separating the shortcut text + if (hasTabChar) + w += metrics.mnemonicSpace; + if (hasSubMenu) + w += metrics.arrowSpace + metrics.arrowWidth + metrics.rightMarginForArrow; + else + w += metrics.rightMarginForText; + int h; + if (isSeparator) { + h = metrics.separatorHeight; + } + else { + h = metrics.totalHeight; + } + if (!menuItem->icon.isNull()) { + if (auto combo = qobject_cast(widget)) { + h = qMax(combo->iconSize().height() + 2, h); + } + } + QSize sz; + sz.setWidth(qMax(w, Ph::dpiScaled(Ph::MenuMinimumWidth))); + sz.setHeight(h); + return sz; + } + case CT_Menu: { + if (!Ph::MenuExtraBottomMargin || !option || !widget) + break; + // Trick the QMenu into putting a margin only at the bottom by adding extra + // height to the contents size. We only want to add this tricky space if + // there is at least more than 1 item in the menu. + const auto acts = widget->actions(); + if (acts.count() < 2) + break; + // We only want to add the tricky space if there's at least 1 separator, + // otherwise it looks weird. + bool anySeps = false; + for (auto act : acts) { + if (act->isSeparator()) { + anySeps = true; + break; + } + } + if (!anySeps) + break; + int fheight = option->fontMetrics.height(); + int vmargin = static_cast(fheight * Ph::MenuItem_SeparatorHeightFontRatio) / 2; + QSize sz = size; + sz.setHeight(sz.height() + vmargin); + return sz; + } + case CT_TabBarTab: { + // Placeholder in case we change this in the future + return size; + } + case CT_Slider: { + QSize sz = size; + if (qobject_cast(widget)->orientation() == Qt::Horizontal) { + sz.setHeight(sz.height() + PM_SliderTickmarkOffset); + } + else { + sz.setWidth(sz.width() + PM_SliderTickmarkOffset); + } + return sz; + } + case CT_GroupBox: { + // This doesn't seem to get used except once by QGroupBox for + // minimumSizeHint(). After that, the sizing/layout calculations seem to + // use the rects given by subControlRect(). + auto opt = qstyleoption_cast(option); + if (!opt) + break; + // Checkbox and text height already accounted for, but margin between text + // and frame isn't. + int xadd = 0; + int yadd = 0; + if (opt->subControls & (SC_GroupBoxCheckBox | SC_GroupBoxLabel)) { + int fontHeight = option->fontMetrics.height(); + yadd += static_cast(fontHeight * Phantom::GroupBox_LabelBottomMarginFontRatio); + } + // We can test for the frame in general, but unfortunately testing to see + // if it's the 1-line "flat" style or 4-line box/rect "anything else" style + // doesn't seem to be possible here, only when painting. + if (opt->subControls & SC_GroupBoxFrame) { + xadd += 2; + yadd += 2; + } + return QSize(size.width() + xadd, size.height() + yadd); + } + case CT_ItemViewItem: { + auto vopt = qstyleoption_cast(option); + if (!vopt) + break; + QSize sz = QCommonStyle::sizeFromContents(type, option, size, widget); + sz += QSize(0, Phantom::DefaultFrameWidth); + // QCommonStyle has a bunch of complicated logic for laying out/calculating + // rects of view items, which is locked behind a private data guy. In + // sizeFromContents for CT_ItemViewItem, it unions all of the item row's + // rects together and then, if the decoration height is exactly the same as + // the row height, it adds 2 pixels (not dpi scaled) to the height. The + // comment says it's to prevent "icons from overlapping" but I have no idea + // how that's supposed to help. And we don't necessarily want those extra 2 + // pixels. Anyway, I don't want to copy and paste all of that code into + // Phantom and then maintain it. So when Phantom is in the mode where we're + // basing the item view decoration sizes off of the font size, we'll just + // take a guess when QCommonStyle has added 2 to the height (because the + // row height and decoration height are both the font height), and + // re-remove those two pixels. +#if 1 + if (Phantom::ItemView_UseFontHeightForDecorationSize) { + int fh = vopt->fontMetrics.height(); + if (sz.height() == fh + 2 && vopt->decorationSize.height() == fh) { + sz.setHeight(fh); + } + } +#endif + return sz; + } + case CT_HeaderSection: { + auto hdr = qstyleoption_cast(option); + if (!hdr) + break; + // This is pretty crummy. Should also check if we need multi-line support + // or not. + bool nullIcon = hdr->icon.isNull(); + int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, hdr, widget); + int iconSize = nullIcon ? 0 : option->fontMetrics.height(); + QSize txt = hdr->fontMetrics.size(Qt::TextSingleLine | Qt::TextBypassShaping, hdr->text); + QSize sz; + sz.setHeight(margin + qMax(iconSize, txt.height()) + margin); + sz.setWidth((nullIcon ? 0 : margin) + iconSize + (hdr->text.isNull() ? 0 : margin) + txt.width() + margin); + if (hdr->sortIndicator != QStyleOptionHeader::None) { + if (hdr->orientation == Qt::Horizontal) + sz.rwidth() += Phantom::dpiScaled(Phantom::HeaderSortIndicator_Width); + else + sz.rheight() += Phantom::dpiScaled(Phantom::HeaderSortIndicator_Width); + } + return sz; + } + default: + break; + } + + // Cases which modify the size given by the parent class + QSize newSize = QCommonStyle::sizeFromContents(type, option, size, widget); + switch (type) { + case CT_PushButton: { + auto pbopt = qstyleoption_cast(option); + if (!pbopt || pbopt->text.isEmpty()) + break; + int hpad = static_cast(pbopt->fontMetrics.height() * Phantom::PushButton_HorizontalPaddingFontHeightRatio); + newSize.rwidth() += hpad * 2; + if (widget && qobject_cast(widget->parent())) { + int dialogButtonMinWidth = Phantom::dpiScaled(80); + newSize.rwidth() = qMax(newSize.width(), dialogButtonMinWidth); + } + break; + } + case CT_ToolButton: +#if defined(Q_OS_MACOS) + newSize += QSize(Ph::dpiScaled(6 + Phantom::DefaultFrameWidth), Ph::dpiScaled(6 + Phantom::DefaultFrameWidth)); +#elif defined(Q_OS_WIN) + newSize += QSize(Ph::dpiScaled(4 + Phantom::DefaultFrameWidth), Ph::dpiScaled(4 + Phantom::DefaultFrameWidth)); +#else + newSize += QSize(Ph::dpiScaled(3 + Phantom::DefaultFrameWidth), Ph::dpiScaled(3 + Phantom::DefaultFrameWidth)); +#endif + break; + case CT_ComboBox: { + newSize += QSize(0, Ph::dpiScaled(4 + Phantom::DefaultFrameWidth)); + auto cb = qstyleoption_cast(option); + // Non-editable combo boxes have some extra padding on the left side, + // similar to push buttons. We should account for that here to avoid text + // being clipped off. + if (cb) { + int pad = 0; + if (cb->editable) { + pad = Ph::dpiScaled(Ph::LineEdit_ContentsHPad); + } + else { + pad = Ph::dpiScaled(Ph::ComboBox_NonEditable_ContentsHPad); + } + newSize.rwidth() += pad * 2; + } + break; + } + case CT_LineEdit: { + newSize += QSize(0, 4); + int pad = Ph::dpiScaled(Ph::LineEdit_ContentsHPad); + newSize.rwidth() += pad * 2; + break; + } + case CT_SpinBox: + // No changes needed + break; + case CT_SizeGrip: + newSize += QSize(4, 4); + break; + case CT_MdiControls: + newSize -= QSize(1, 0); + break; + default: + break; + } + return newSize; +} + +void BaseStyle::polish(QApplication *app) +{ + if (!app) { + return; + } + + Q_INIT_RESOURCE(styles); + + QString stylesheet; + QFile baseStylesheetFile(":/base/basestyle.qss"); + if (baseStylesheetFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + stylesheet = baseStylesheetFile.readAll(); + baseStylesheetFile.close(); + } + else { + qWarning("Failed to load base theme stylesheet."); + } + + stylesheet.append(getAppStyleSheet()); + app->setStyleSheet(stylesheet); + QCommonStyle::polish(app); +} + +QRect BaseStyle::subControlRect( + ComplexControl control, const QStyleOptionComplex *option, SubControl subControl, const QWidget *widget) const +{ + namespace Ph = Phantom; + QRect rect = QCommonStyle::subControlRect(control, option, subControl, widget); + switch (control) { + case CC_Slider: { + auto slider = qstyleoption_cast(option); + if (!slider) + break; + int tickSize = proxy()->pixelMetric(PM_SliderTickmarkOffset, option, widget); + switch (subControl) { + case SC_SliderHandle: { + if (slider->orientation == Qt::Horizontal) { + rect.setHeight(proxy()->pixelMetric(PM_SliderThickness)); + rect.setWidth(proxy()->pixelMetric(PM_SliderLength)); + int centerY = slider->rect.center().y() - rect.height() / 2; + if (slider->tickPosition & QSlider::TicksAbove) + centerY += tickSize; + if (slider->tickPosition & QSlider::TicksBelow) + centerY -= tickSize; + rect.moveTop(centerY); + } + else { + rect.setWidth(proxy()->pixelMetric(PM_SliderThickness)); + rect.setHeight(proxy()->pixelMetric(PM_SliderLength)); + int centerX = slider->rect.center().x() - rect.width() / 2; + if (slider->tickPosition & QSlider::TicksAbove) + centerX += tickSize; + if (slider->tickPosition & QSlider::TicksBelow) + centerX -= tickSize; + rect.moveLeft(centerX); + } + break; + } + case SC_SliderGroove: { + QPoint grooveCenter = slider->rect.center(); + const int grooveThickness = Ph::dpiScaled(7); + if (slider->orientation == Qt::Horizontal) { + rect.setHeight(grooveThickness); + if (slider->tickPosition & QSlider::TicksAbove) + grooveCenter.ry() += tickSize; + if (slider->tickPosition & QSlider::TicksBelow) + grooveCenter.ry() -= tickSize; + } + else { + rect.setWidth(grooveThickness); + if (slider->tickPosition & QSlider::TicksAbove) + grooveCenter.rx() += tickSize; + if (slider->tickPosition & QSlider::TicksBelow) + grooveCenter.rx() -= tickSize; + } + rect.moveCenter(grooveCenter); + break; + } + default: + break; + } + break; + } + case CC_SpinBox: { + auto spinbox = qstyleoption_cast(option); + if (!spinbox) + break; + // Some leftover Fusion code here. Should clean up this mess. + int center = spinbox->rect.height() / 2; + int fw = spinbox->frame ? 1 : 0; + int y = fw; + const int buttonWidth = static_cast(Ph::dpiScaled(Ph::SpinBox_ButtonWidth)) + 2; + int x, lx, rx; + x = spinbox->rect.width() - y - buttonWidth + 2; + lx = fw; + rx = x - fw; + switch (subControl) { + case SC_SpinBoxUp: + if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) + return {}; + rect = QRect(x, fw, buttonWidth, center - fw); + break; + case SC_SpinBoxDown: + if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) + return QRect(); + + rect = QRect(x, center, buttonWidth, spinbox->rect.bottom() - center - fw + 1); + break; + case SC_SpinBoxEditField: + if (spinbox->buttonSymbols == QAbstractSpinBox::NoButtons) { + rect = QRect(lx, fw, spinbox->rect.width() - 2 * fw, spinbox->rect.height() - 2 * fw); + } + else { + rect = QRect(lx, fw, rx - qMax(fw - 1, 0), spinbox->rect.height() - 2 * fw); + } + break; + case SC_SpinBoxFrame: + rect = spinbox->rect; + break; + default: + break; + } + rect = visualRect(spinbox->direction, spinbox->rect, rect); + break; + } + case CC_GroupBox: { + auto groupBox = qstyleoption_cast(option); + if (!groupBox) + break; + switch (subControl) { + case SC_GroupBoxFrame: + case SC_GroupBoxContents: { + QRect r = option->rect; + if (groupBox->subControls & (SC_GroupBoxLabel | SC_GroupBoxCheckBox)) { + int fontHeight = option->fontMetrics.height(); + int topMargin = qMax(pixelMetric(PM_ExclusiveIndicatorHeight), fontHeight); + topMargin += static_cast(fontHeight * Ph::GroupBox_LabelBottomMarginFontRatio); + r.setTop(r.top() + topMargin); + } + if (subControl == SC_GroupBoxContents && groupBox->subControls & SC_GroupBoxFrame) { + // Testing against groupBox->features for the frame type doesn't seem + // to work here. + r.adjust(1, 1, -1, -1); + } + return r; + } + case SC_GroupBoxCheckBox: + case SC_GroupBoxLabel: { + // Accurate height doesn't matter -- the other group box style + // implementations also fail with multi-line or too-tall text. + int textHeight = option->fontMetrics.height(); + // width()/horizontalAdvance() is faster than size() and good enough for + // us, since we only support a single line of text here anyway. + int textWidth = Phantom::fontMetricsWidth(option->fontMetrics, groupBox->text); + int indicatorWidth = proxy()->pixelMetric(PM_IndicatorWidth, option, widget); + int indicatorHeight = proxy()->pixelMetric(PM_IndicatorHeight, option, widget); + int margin = 0; + int indicatorRightSpace = textHeight / 3; + int contentWidth = textWidth; + if (option->subControls & QStyle::SC_GroupBoxCheckBox) { + contentWidth += indicatorWidth + indicatorRightSpace; + } + int x = margin; + int y = 0; + switch (groupBox->textAlignment & Qt::AlignHorizontal_Mask) { + case Qt::AlignHCenter: + x += (option->rect.width() - contentWidth) / 2; + break; + case Qt::AlignRight: + x += option->rect.width() - contentWidth; + break; + default: + break; + } + int w, h; + if (subControl == SC_GroupBoxCheckBox) { + w = indicatorWidth; + h = indicatorHeight; + if (textHeight > indicatorHeight) { + y = (textHeight - indicatorHeight) / 2; + } + } + else { + w = contentWidth; + h = textHeight; + if (option->subControls & QStyle::SC_GroupBoxCheckBox) { + x += indicatorWidth + indicatorRightSpace; + w -= indicatorWidth + indicatorRightSpace; + } + } + return visualRect(option->direction, option->rect, QRect(x, y, w, h)); + } + default: + break; + } + break; + } + case CC_ComboBox: { + auto cb = qstyleoption_cast(option); + if (!cb) + return QRect(); + int frame = cb->frame ? proxy()->pixelMetric(PM_ComboBoxFrameWidth, cb, widget) : 0; + QRect r = option->rect; + r.adjust(frame, frame, -frame, -frame); + int dim = qMin(r.width(), r.height()); + if (dim < 1) + return QRect(); + switch (subControl) { + case SC_ComboBoxFrame: + return cb->rect; + case SC_ComboBoxArrow: { + QRect r0 = r; + r0.setX((r0.x() + r0.width()) - dim + 1); + return visualRect(option->direction, option->rect, r0); + } + case SC_ComboBoxEditField: { + // Add extra padding if not editable + int pad = 0; + if (cb->editable) { + // Line edit padding already added + } + else { + pad = Ph::dpiScaled(Ph::ComboBox_NonEditable_ContentsHPad); + } + r.adjust(pad, 0, -dim, 0); + return visualRect(option->direction, option->rect, r); + } + case SC_ComboBoxListBoxPopup: { + return cb->rect; + } + default: + break; + } + break; + } + case CC_TitleBar: { + auto tb = qstyleoption_cast(option); + if (!tb) + break; + SubControl sc = subControl; + QRect &ret = rect; + const int indent = 3; + const int controlTopMargin = 3; + const int controlBottomMargin = 3; + const int controlWidthMargin = 2; + const int controlHeight = tb->rect.height() - controlTopMargin - controlBottomMargin; + const int delta = controlHeight + controlWidthMargin; + int offset = 0; + bool isMinimized = tb->titleBarState & Qt::WindowMinimized; + bool isMaximized = tb->titleBarState & Qt::WindowMaximized; + switch (sc) { + case SC_TitleBarLabel: + if (tb->titleBarFlags & (Qt::WindowTitleHint | Qt::WindowSystemMenuHint)) { + ret = tb->rect; + if (tb->titleBarFlags & Qt::WindowSystemMenuHint) + ret.adjust(delta, 0, -delta, 0); + if (tb->titleBarFlags & Qt::WindowMinimizeButtonHint) + ret.adjust(0, 0, -delta, 0); + if (tb->titleBarFlags & Qt::WindowMaximizeButtonHint) + ret.adjust(0, 0, -delta, 0); + if (tb->titleBarFlags & Qt::WindowShadeButtonHint) + ret.adjust(0, 0, -delta, 0); + if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) + ret.adjust(0, 0, -delta, 0); + } + break; + case SC_TitleBarContextHelpButton: + if (tb->titleBarFlags & Qt::WindowContextHelpButtonHint) + offset += delta; + Q_FALLTHROUGH(); + case SC_TitleBarMinButton: + if (!isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)) + offset += delta; + else if (sc == SC_TitleBarMinButton) + break; + Q_FALLTHROUGH(); + case SC_TitleBarNormalButton: + if (isMinimized && (tb->titleBarFlags & Qt::WindowMinimizeButtonHint)) + offset += delta; + else if (isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)) + offset += delta; + else if (sc == SC_TitleBarNormalButton) + break; + Q_FALLTHROUGH(); + case SC_TitleBarMaxButton: + if (!isMaximized && (tb->titleBarFlags & Qt::WindowMaximizeButtonHint)) + offset += delta; + else if (sc == SC_TitleBarMaxButton) + break; + Q_FALLTHROUGH(); + case SC_TitleBarShadeButton: + if (!isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint)) + offset += delta; + else if (sc == SC_TitleBarShadeButton) + break; + Q_FALLTHROUGH(); + case SC_TitleBarUnshadeButton: + if (isMinimized && (tb->titleBarFlags & Qt::WindowShadeButtonHint)) + offset += delta; + else if (sc == SC_TitleBarUnshadeButton) + break; + Q_FALLTHROUGH(); + case SC_TitleBarCloseButton: + if (tb->titleBarFlags & Qt::WindowSystemMenuHint) + offset += delta; + else if (sc == SC_TitleBarCloseButton) + break; + ret.setRect( + tb->rect.right() - indent - offset, tb->rect.top() + controlTopMargin, controlHeight, controlHeight); + break; + case SC_TitleBarSysMenu: + if (tb->titleBarFlags & Qt::WindowSystemMenuHint) { + ret.setRect(tb->rect.left() + controlWidthMargin + indent, tb->rect.top() + controlTopMargin, + controlHeight, controlHeight); + } + break; + default: + break; + } + ret = visualRect(tb->direction, tb->rect, ret); + break; + } + default: + break; + } + + return rect; +} + +QRect BaseStyle::itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const +{ + return QCommonStyle::itemPixmapRect(r, flags, pixmap); +} + +void BaseStyle::drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, const QPixmap &pixmap) const +{ + QCommonStyle::drawItemPixmap(painter, rect, alignment, pixmap); +} + +QStyle::SubControl BaseStyle::hitTestComplexControl( + ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt, const QWidget *w) const +{ + return QCommonStyle::hitTestComplexControl(cc, opt, pt, w); +} + +int BaseStyle::styleHint( + StyleHint hint, const QStyleOption *option, const QWidget *widget, QStyleHintReturn *returnData) const +{ + switch (hint) { + case SH_Slider_SnapToValue: + case SH_PrintDialog_RightAlignButtons: + case SH_FontDialog_SelectAssociatedText: + case SH_ComboBox_ListMouseTracking: + case SH_Slider_StopMouseOverSlider: + case SH_ScrollBar_MiddleClickAbsolutePosition: + case SH_TitleBar_AutoRaise: + case SH_TitleBar_NoBorder: + case SH_ItemView_ArrowKeysNavigateIntoChildren: + case SH_ItemView_ChangeHighlightOnFocus: + case SH_MenuBar_MouseTracking: + case SH_Menu_MouseTracking: + return 1; + case SH_Menu_SupportsSections: + return 0; +#ifndef Q_OS_MAC + case SH_MenuBar_AltKeyNavigation: + return 1; +#endif +#if defined(QT_PLATFORM_UIKIT) + case SH_ComboBox_UseNativePopup: + return 1; +#endif + case SH_ItemView_ShowDecorationSelected: + // QWindowsStyle does this as well -- QCommonStyle seems to have some + // internal confusion buried within its private implementation of laying + // out and drawing item views where it can't keep track of what's + // considered a decoration and what's not. For tree views, if you give 0 + // for ShowDecorationSelected, it applies only to the disclosure indicator + // and not to the QIcon/pixmap that might be present for the item. So + // selecting an item in a tree view will have the selection color drawn + // underneath the icon/pixmap, but not the disclosure indicator. However, + // in list views, if you give 0 for ShowDecorationSelected, it will *not* + // draw the selection color underneath the icon/pixmap. There's no way to + // access this internal logic in QCommonStyle without fully reimplementing + // the huge mass of stuff for item view layout and drawing. Therefore, the + // best we can do is at least try to get consistent behavior: if it's a + // list view, just always return 1 for ShowDecorationSelected. + if (!Phantom::ShowItemViewDecorationSelected && qobject_cast(widget)) + return 1; + return Phantom::ShowItemViewDecorationSelected; + case SH_ItemView_MovementWithoutUpdatingSelection: + return 1; +#if (QT_VERSION >= QT_VERSION_CHECK(5, 7, 0)) + case SH_ItemView_ScrollMode: + return QAbstractItemView::ScrollPerPixel; +#endif + case SH_ScrollBar_ContextMenu: +#ifdef Q_OS_MAC + return 0; +#else + return 1; +#endif + // Some Linux distros might want to enable this, but it doesn't behave very + // consistently with varied QPalettes, depending on how the QPA and icons + // deal with both light and dark themes. It might seem weird to just disable + // this, but none of (Mac, Windows, BeOS/Haiku) show icons in dialog buttons, + // and the results on Linux are generally pretty messy -- not sure why it's + // historically been the default, especially when other button types + // generally don't have any icons. + case SH_DialogButtonBox_ButtonsHaveIcons: + return 0; + case SH_ScrollBar_Transient: + return 1; + case SH_EtchDisabledText: + case SH_DitherDisabledText: + case SH_ToolBox_SelectedPageTitleBold: + case SH_Menu_AllowActiveAndDisabled: + case SH_MainWindow_SpaceBelowMenuBar: + case SH_MessageBox_CenterButtons: + case SH_RubberBand_Mask: + case SH_ScrollView_FrameOnlyAroundContents: + return 0; + case SH_ComboBox_Popup: { + return Phantom::UseQMenuForComboBoxPopup; + // Fusion did this, but we don't because of font bugs (especially in high + // DPI) with the QMenu that the combo box will create instead of a dropdown + // view. See notes in CE_MenuItem for more details. + if (auto cmb = qstyleoption_cast(option)) + return !cmb->editable; + return 0; + } + case SH_Table_GridLineColor: { + using namespace Phantom::SwatchColors; + namespace Ph = Phantom; + if (!option) + return 0; + auto ph_swatchPtr = Ph::getCachedSwatchOfQPalette(&d->swatchCache, &d->headSwatchFastKey, option->palette); + const Ph::PhSwatch &swatch = *ph_swatchPtr.data(); + // Qt code in table views for drawing grid lines is broken. See case for + // CE_ItemViewItem painting for more information. + return static_cast(swatch.color(S_base_divider).rgb()); + } + case SH_MessageBox_TextInteractionFlags: + return Qt::TextSelectableByMouse | Qt::LinksAccessibleByMouse; + case SH_WizardStyle: + return QWizard::ClassicStyle; + case SH_Menu_SubMenuPopupDelay: + // Returning 0 will break sloppy submenus even if they're enabled + return 10; + case SH_Menu_SloppySubMenus: + return true; + case SH_Menu_SubMenuSloppyCloseTimeout: + return 500; + case SH_Menu_SubMenuDontStartSloppyOnLeave: + return 1; + case SH_Menu_SubMenuSloppySelectOtherActions: + return 1; + case SH_Menu_SubMenuUniDirection: + return 1; + case SH_Menu_SubMenuUniDirectionFailCount: + return 1; + case SH_Menu_SubMenuResetWhenReenteringParent: + return 0; +#ifdef Q_OS_MAC + case SH_Menu_FlashTriggeredItem: + return 1; + case SH_Menu_FadeOutOnHide: + return 0; +#endif + case SH_WindowFrame_Mask: + return 0; + case SH_UnderlineShortcut: { + return false; + } + case SH_Widget_Animate: + return 1; + default: + break; + } + return QCommonStyle::styleHint(hint, option, widget, returnData); +} + +QRect BaseStyle::subElementRect(SubElement sr, const QStyleOption *opt, const QWidget *w) const +{ + switch (sr) { + case SE_ProgressBarLabel: + case SE_ProgressBarContents: + case SE_ProgressBarGroove: + return opt->rect; + case SE_PushButtonFocusRect: { + QRect r = QCommonStyle::subElementRect(sr, opt, w); + r.adjust(0, 1, 0, -1); + return r; + } + case SE_DockWidgetTitleBarText: { + auto titlebar = qstyleoption_cast(opt); + if (!titlebar) + break; + QRect r = QCommonStyle::subElementRect(sr, opt, w); + bool verticalTitleBar = titlebar->verticalTitleBar; + if (verticalTitleBar) { + r.adjust(0, 0, 0, -4); + } + else { + if (opt->direction == Qt::LeftToRight) + r.adjust(4, 0, 0, 0); + else + r.adjust(0, 0, -4, 0); + } + return r; + } + case SE_TreeViewDisclosureItem: { + if (Phantom::BranchesOnEdge) { + // Shove it all the way to the left (or right) side, probably outside of + // the rect it gave us. Old-school. + QRect rect = opt->rect; + if (opt->direction != Qt::RightToLeft) { + rect.moveLeft(0); + if (rect.width() < rect.height()) + rect.setWidth(rect.height()); + } + else { + // todo + } + return rect; + } + break; + } + case SE_LineEditContents: { + QRect r = QCommonStyle::subElementRect(sr, opt, w); + int pad = Phantom::LineEdit_ContentsHPad; + if (w && qobject_cast(w->parentWidget())) { + pad += 3; + } + pad = Phantom::dpiScaled(pad); + return r.adjusted(pad, 0, -pad, 0); + } + case SE_HeaderLabel: { + int margin = proxy()->pixelMetric(QStyle::PM_HeaderMargin, opt, w); + QRect r(opt->rect.x() + margin, opt->rect.y() + margin, opt->rect.width() - margin * 2, + opt->rect.height() - margin * 2); + if (auto header = qstyleoption_cast(opt)) { + // Subtract width needed for arrow, if there is one + if (header->sortIndicator != QStyleOptionHeader::None) { + if (opt->state & State_Horizontal) + r.setWidth(r.width() - Phantom::dpiScaled(Phantom::HeaderSortIndicator_Width)); + else + r.setHeight(r.height() - Phantom::dpiScaled(Phantom::HeaderSortIndicator_Width)); + } + } + return visualRect(opt->direction, opt->rect, r); + } + case SE_HeaderArrow: { + QRect r = QCommonStyle::subElementRect(sr, opt, w); + r.setWidth(Phantom::dpiScaled(Phantom::HeaderSortIndicator_Width)); + return r; + } + default: + break; + } + return QCommonStyle::subElementRect(sr, opt, w); +} + +// Table header layout reference +// ----------------------------- +// +// begin: QStyleOptionHeader::Beginning; +// mid: QStyleOptionHeader::Middle; +// end: QStyleOptionHeader::End; +// one: QStyleOptionHeader::OnlyOneSection; +// one*: +// This is specified as QStyleOptionHeader::OnlyOneSection, but the call to +// drawControl(CE_HeaderSection...) is being performed by an instance of +// QTableCornerButton, defined in qtableview.cpp as a subclass of +// QAbstractButton. Only table views can have these corner buttons, and they +// only appear if there are both at least 1 column and 1 row visible. +// +// Configuration A: A table view with both columns and rows +// +// Configuration B: A list view, or a tree view, or a table view with no rows +// in the data or all rows hidden, such that the corner button is also made +// hidden. +// +// Configuration C: A table view with no columns in the data or all columns +// hidden, such that the corner button is also made hidden. +// +// Configuration A, Left-to-right, 4x4 +// [ one* ][ begin ][ mid ][ mid ][ end ] +// [ begin ] +// [ mid ] +// [ mid ] +// [ end ] +// +// Configuration A, Left-to-right, 2x2 +// [ one* ][ begin ][ end ] +// [ begin ] +// [ end ] +// +// Configuration A, Left-to-right, 1x1 +// [ one* ][ one ] +// [ one ] +// +// Configuration A, Right-to-left, 4x4 +// [ begin ][ mid ][ mid ][ end ][ one* ] +// [ begin ] +// [ mid ] +// [ mid ] +// [ end ] +// +// Configuration A, Right-to-left, 2x2 +// [ begin ][ end ][ one* ] +// [ begin ] +// [ end ] +// +// Configuration A, Right-to-left, 1x1 +// [ one ][ one* ] +// [ one ] +// +// Configuration B, Left-to-right and right-to-left, 4 columns (table view: +// 4 columns with 0 rows, list/tree view: 4 columns, rows count doesn't matter): +// [ begin ][ mid ][ mid ][ end ] +// +// Configuration B, Left-to-right and right-to-left, 2 columns (table view: +// 2 columns with 0 rows, list/tree view: 2 columns, rows count doesn't matter): +// [ begin ][ end ] +// +// Configuration B, Left-to-right and right-to-left, 1 column (table view: +// 1 column with 0 rows, list view: 1 column, rows count doesn't matter): +// [ one ] +// +// Configuration C, left-to-right and right-to-left, table view with no columns +// and 4 rows: +// [ begin ] +// [ mid ] +// [ mid ] +// [ end ] +// +// Configuration C, left-to-right and right-to-left, table view with no columns +// and 2 rows: +// [ begin ] +// [ end ] +// +// Configuration C, left-to-right and right-to-left, table view with no columns +// and 1 row: +// [ one ] diff --git a/src/gui/styles/base/basestyle.h b/src/gui/styles/base/basestyle.h new file mode 100644 index 0000000..e376e43 --- /dev/null +++ b/src/gui/styles/base/basestyle.h @@ -0,0 +1,104 @@ +/* + * Copyright (C) 2020 KeePassXC Team + * Copyright (C) 2019 Andrew Richards + * + * Derived from Phantomstyle and relicensed under the GPLv2 or v3. + * https://github.com/randrew/phantomstyle + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_BASESTYLE_H +#define KEEPASSXC_BASESTYLE_H + +#include + +class BaseStylePrivate; + +class BaseStyle : public QCommonStyle { + Q_OBJECT + +public: + BaseStyle(); + ~BaseStyle() override; + + enum PhantomPrimitiveElement { + Phantom_PE_IndicatorTabNew = PE_CustomBase + 1, + Phantom_PE_ScrollBarSliderVertical, + Phantom_PE_WindowFrameColor, + }; + + QPalette standardPalette() const override; + + QIcon standardIcon( + StandardPixmap sp, const QStyleOption *opt = nullptr, const QWidget *widget = nullptr) const override; + + void drawPrimitive(PrimitiveElement elem, const QStyleOption *option, QPainter *painter, + const QWidget *widget = nullptr) const override; + + void drawControl( + ControlElement ce, const QStyleOption *option, QPainter *painter, const QWidget *widget) const override; + + int pixelMetric( + PixelMetric metric, const QStyleOption *option = nullptr, const QWidget *widget = nullptr) const override; + + void drawComplexControl(ComplexControl control, const QStyleOptionComplex *option, QPainter *painter, + const QWidget *widget) const override; + + QRect subElementRect(SubElement r, const QStyleOption *opt, const QWidget *widget = nullptr) const override; + + QSize sizeFromContents( + ContentsType type, const QStyleOption *option, const QSize &size, const QWidget *widget) const override; + + SubControl hitTestComplexControl( + ComplexControl cc, const QStyleOptionComplex *opt, const QPoint &pt, const QWidget *w = nullptr) const override; + + QRect subControlRect( + ComplexControl cc, const QStyleOptionComplex *opt, SubControl sc, const QWidget *widget) const override; + + int styleHint(StyleHint hint, const QStyleOption *option = nullptr, const QWidget *widget = nullptr, + QStyleHintReturn *returnData = nullptr) const override; + + QRect itemPixmapRect(const QRect &r, int flags, const QPixmap &pixmap) const override; + + void drawItemPixmap(QPainter *painter, const QRect &rect, int alignment, const QPixmap &pixmap) const override; + + void drawItemText(QPainter *painter, const QRect &rect, int flags, const QPalette &pal, bool enabled, + const QString &text, QPalette::ColorRole textRole = QPalette::NoRole) const override; + + using QCommonStyle::polish; + void polish(QApplication *app) override; + +protected: + /** + * @return Paths to application stylesheets + */ + virtual QString getAppStyleSheet() const + { + return {}; + } + +#ifdef Q_OS_MACOS + /** + * Whether to draw a native macOS toolbar or fill it with a solid color instead. + * Can be set to false to avoid mixed themes if the OS theme isn't the same as + * the KeePassXC application theme. + */ + bool m_drawNativeMacOsToolBar = true; +#endif + + BaseStylePrivate *d; +}; + +#endif diff --git a/src/gui/styles/base/phantomcolor.cpp b/src/gui/styles/base/phantomcolor.cpp new file mode 100644 index 0000000..a11ab3c --- /dev/null +++ b/src/gui/styles/base/phantomcolor.cpp @@ -0,0 +1,423 @@ +/* + * HSLuv-C: Human-friendly HSL + * + * + * + * Copyright (c) 2015 Alexei Boronine (original idea, JavaScript implementation) + * Copyright (c) 2015 Roger Tallada (Obj-C implementation) + * Copyright (c) 2017 Martin Mitas (C implementation, based on Obj-C implementation) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include "phantomcolor.h" +#include +#include + +namespace Phantom +{ + namespace + { + + // Th`ese declarations originate from hsluv.h, from the hsluv-c library. The + // hpluv functions have been removed, as they are unnecessary for Phantom. + /** + * Convert HSLuv to RGB. + * + * @param h Hue. Between 0.0 and 360.0. + * @param s Saturation. Between 0.0 and 100.0. + * @param l Lightness. Between 0.0 and 100.0. + * @param[out] pr Red component. Between 0.0 and 1.0. + * @param[out] pr Green component. Between 0.0 and 1.0. + * @param[out] pr Blue component. Between 0.0 and 1.0. + */ + void hsluv2rgb(double h, double s, double l, double* pr, double* pg, double* pb); + + /** + * Convert RGB to HSLuv. + * + * @param r Red component. Between 0.0 and 1.0. + * @param g Green component. Between 0.0 and 1.0. + * @param b Blue component. Between 0.0 and 1.0. + * @param[out] ph Hue. Between 0.0 and 360.0. + * @param[out] ps Saturation. Between 0.0 and 100.0. + * @param[out] pl Lightness. Between 0.0 and 100.0. + */ + void rgb2hsluv(double r, double g, double b, double* ph, double* ps, double* pl); + + // Contents below originate from hsluv.c from the hsluv-c library. They have + // been wrapped in a C++ namespace to avoid collisions and to reduce the + // translation unit count, and hsluv's own sRGB conversion code has been + // stripped out (sRGB conversion is now performed in the Phantom color code + // when going to/from the Rgb type.) + // + // If you need to update the hsluv-c code, be mindful of the removed sRGB + // conversions -- you will need to make similar modifications to the upstream + // hsluv-c code. Also note that that the hpluv (pastel) functions have been + // removed, as they are not used in Phantom. + typedef struct Triplet_tag Triplet; + struct Triplet_tag + { + double a; + double b; + double c; + }; + + /* for RGB */ + const Triplet m[3] = {{3.24096994190452134377, -1.53738317757009345794, -0.49861076029300328366}, + {-0.96924363628087982613, 1.87596750150772066772, 0.04155505740717561247}, + {0.05563007969699360846, -0.20397695888897656435, 1.05697151424287856072}}; + + /* for XYZ */ + const Triplet m_inv[3] = {{0.41239079926595948129, 0.35758433938387796373, 0.18048078840183428751}, + {0.21263900587151035754, 0.71516867876775592746, 0.07219231536073371500}, + {0.01933081871559185069, 0.11919477979462598791, 0.95053215224966058086}}; + + const double ref_u = 0.19783000664283680764; + const double ref_v = 0.46831999493879100370; + + const double kappa = 903.29629629629629629630; + const double epsilon = 0.00885645167903563082; + + typedef struct Bounds_tag Bounds; + struct Bounds_tag + { + double a; + double b; + }; + + void get_bounds(double l, Bounds bounds[6]) + { + double tl = l + 16.0; + double sub1 = (tl * tl * tl) / 1560896.0; + double sub2 = (sub1 > epsilon ? sub1 : (l / kappa)); + int channel; + int t; + + for (channel = 0; channel < 3; channel++) { + double m1 = m[channel].a; + double m2 = m[channel].b; + double m3 = m[channel].c; + + for (t = 0; t < 2; t++) { + double top1 = (284517.0 * m1 - 94839.0 * m3) * sub2; + double top2 = (838422.0 * m3 + 769860.0 * m2 + 731718.0 * m1) * l * sub2 - 769860.0 * t * l; + double bottom = (632260.0 * m3 - 126452.0 * m2) * sub2 + 126452.0 * t; + + bounds[channel * 2 + t].a = top1 / bottom; + bounds[channel * 2 + t].b = top2 / bottom; + } + } + } + + double ray_length_until_intersect(double theta, const Bounds* line) + { + return line->b / (sin(theta) - line->a * cos(theta)); + } + + double max_chroma_for_lh(double l, double h) + { + double min_len = DBL_MAX; + double hrad = h * 0.01745329251994329577; /* (2 * pi / 360) */ + Bounds bounds[6]; + int i; + + get_bounds(l, bounds); + for (i = 0; i < 6; i++) { + double len = ray_length_until_intersect(hrad, &bounds[i]); + + if (len >= 0 && len < min_len) + min_len = len; + } + return min_len; + } + + double dot_product(const Triplet* t1, const Triplet* t2) + { + return (t1->a * t2->a + t1->b * t2->b + t1->c * t2->c); + } + + void xyz2rgb(Triplet* in_out) + { + double r = dot_product(&m[0], in_out); + double g = dot_product(&m[1], in_out); + double b = dot_product(&m[2], in_out); + in_out->a = r; + in_out->b = g; + in_out->c = b; + } + + void rgb2xyz(Triplet* in_out) + { + Triplet rgbl = {in_out->a, in_out->b, in_out->c}; + double x = dot_product(&m_inv[0], &rgbl); + double y = dot_product(&m_inv[1], &rgbl); + double z = dot_product(&m_inv[2], &rgbl); + in_out->a = x; + in_out->b = y; + in_out->c = z; + } + + /* http://en.wikipedia.org/wiki/CIELUV + * In these formulas, Yn refers to the reference white point. We are using + * illuminant D65, so Yn (see refY in Maxima file) equals 1. The formula is + * simplified accordingly. + */ + double y2l(double y) + { + if (y <= epsilon) { + return y * kappa; + } else { + return 116.0 * cbrt(y) - 16.0; + } + } + + double l2y(double l) + { + if (l <= 8.0) { + return l / kappa; + } else { + double x = (l + 16.0) / 116.0; + return (x * x * x); + } + } + + void xyz2luv(Triplet* in_out) + { + double divisor = in_out->a + (15.0 * in_out->b) + (3.0 * in_out->c); + if (divisor <= 0.00000001) { + in_out->a = 0.0; + in_out->b = 0.0; + in_out->c = 0.0; + return; + } + + double var_u = (4.0 * in_out->a) / divisor; + double var_v = (9.0 * in_out->b) / divisor; + double l = y2l(in_out->b); + double u = 13.0 * l * (var_u - ref_u); + double v = 13.0 * l * (var_v - ref_v); + + in_out->a = l; + if (l < 0.00000001) { + in_out->b = 0.0; + in_out->c = 0.0; + } else { + in_out->b = u; + in_out->c = v; + } + } + + void luv2xyz(Triplet* in_out) + { + if (in_out->a <= 0.00000001) { + /* Black will create a divide-by-zero error. */ + in_out->a = 0.0; + in_out->b = 0.0; + in_out->c = 0.0; + return; + } + + double var_u = in_out->b / (13.0 * in_out->a) + ref_u; + double var_v = in_out->c / (13.0 * in_out->a) + ref_v; + double y = l2y(in_out->a); + double x = -(9.0 * y * var_u) / ((var_u - 4.0) * var_v - var_u * var_v); + double z = (9.0 * y - (15.0 * var_v * y) - (var_v * x)) / (3.0 * var_v); + in_out->a = x; + in_out->b = y; + in_out->c = z; + } + + void luv2lch(Triplet* in_out) + { + double l = in_out->a; + double u = in_out->b; + double v = in_out->c; + double h; + double c = sqrt(u * u + v * v); + + /* Grays: disambiguate hue */ + if (c < 0.00000001) { + h = 0; + } else { + h = atan2(v, u) * 57.29577951308232087680; /* (180 / pi) */ + if (h < 0.0) + h += 360.0; + } + + in_out->a = l; + in_out->b = c; + in_out->c = h; + } + + void lch2luv(Triplet* in_out) + { + double hrad = in_out->c * 0.01745329251994329577; /* (pi / 180.0) */ + double u = cos(hrad) * in_out->b; + double v = sin(hrad) * in_out->b; + + in_out->b = u; + in_out->c = v; + } + + void hsluv2lch(Triplet* in_out) + { + double h = in_out->a; + double s = in_out->b; + double l = in_out->c; + double c; + + /* White and black: disambiguate chroma */ + if (l > 99.9999999 || l < 0.00000001) { + c = 0.0; + } else { + c = max_chroma_for_lh(l, h) / 100.0 * s; + } + + /* Grays: disambiguate hue */ + if (s < 0.00000001) + h = 0.0; + + in_out->a = l; + in_out->b = c; + in_out->c = h; + } + + void lch2hsluv(Triplet* in_out) + { + double l = in_out->a; + double c = in_out->b; + double h = in_out->c; + double s; + + /* White and black: disambiguate saturation */ + if (l > 99.9999999 || l < 0.00000001) { + s = 0.0; + } else { + s = c / max_chroma_for_lh(l, h) * 100.0; + } + + /* Grays: disambiguate hue */ + if (c < 0.00000001) + h = 0.0; + + in_out->a = h; + in_out->b = s; + in_out->c = l; + } + + void hsluv2rgb(double h, double s, double l, double* pr, double* pg, double* pb) + { + Triplet tmp = {h, s, l}; + + hsluv2lch(&tmp); + lch2luv(&tmp); + luv2xyz(&tmp); + xyz2rgb(&tmp); + + *pr = tmp.a; + *pg = tmp.b; + *pb = tmp.c; + } + + void rgb2hsluv(double r, double g, double b, double* ph, double* ps, double* pl) + { + Triplet tmp = {r, g, b}; + + rgb2xyz(&tmp); + xyz2luv(&tmp); + luv2lch(&tmp); + lch2hsluv(&tmp); + + *ph = tmp.a; + *ps = tmp.b; + *pl = tmp.c; + } + + } // namespace +} // namespace Phantom + +// The code below is for Phantom, and is used for the Rgb/Hsl-based interface +// for color operations. +namespace Phantom +{ + namespace + { + // Note: these constants might be out of range when qreal is defined as float + // instead of double. + inline qreal linear_of_srgb(qreal x) + { + return x < 0.0404482362771082 ? x / 12.92 : std::pow((x + 0.055) / 1.055, 2.4f); + } + inline qreal srgb_of_linear(qreal x) + { + return x < 0.00313066844250063 ? x * 12.92 : std::pow(x, 1.0 / 2.4) * 1.055 - 0.055; + } + } // namespace + + Rgb rgb_of_qcolor(const QColor& color) + { + Rgb a; + a.r = linear_of_srgb(color.red() / 255.0); + a.g = linear_of_srgb(color.green() / 255.0); + a.b = linear_of_srgb(color.blue() / 255.0); + return a; + } + + Hsl hsl_of_rgb(qreal r, qreal g, qreal b) + { + double h, s, l; + rgb2hsluv(r, g, b, &h, &s, &l); + s /= 100.0; + l /= 100.0; + return {h, s, l}; + } + + Rgb rgb_of_hsl(qreal h, qreal s, qreal l) + { + double r, g, b; + hsluv2rgb(h, s * 100.0, l * 100.0, &r, &g, &b); + return {r, g, b}; + } + + QColor qcolor_of_rgb(qreal r, qreal g, qreal b) + { + int r_ = static_cast(std::lround(srgb_of_linear(r) * 255.0)); + int g_ = static_cast(std::lround(srgb_of_linear(g) * 255.0)); + int b_ = static_cast(std::lround(srgb_of_linear(b) * 255.0)); + return {r_, g_, b_}; + } + + QColor lerpQColor(const QColor& x, const QColor& y, qreal a) + { + Rgb x_ = rgb_of_qcolor(x); + Rgb y_ = rgb_of_qcolor(y); + Rgb z = Rgb::lerp(x_, y_, a); + return qcolor_of_rgb(z.r, z.g, z.b); + } + + Rgb Rgb::lerp(const Rgb& x, const Rgb& y, qreal a) + { + Rgb z; + z.r = (1.0 - a) * x.r + a * y.r; + z.g = (1.0 - a) * x.g + a * y.g; + z.b = (1.0 - a) * x.b + a * y.b; + return z; + } +} // namespace Phantom diff --git a/src/gui/styles/base/phantomcolor.h b/src/gui/styles/base/phantomcolor.h new file mode 100644 index 0000000..595f8cd --- /dev/null +++ b/src/gui/styles/base/phantomcolor.h @@ -0,0 +1,148 @@ +/* + * HSLuv-C: Human-friendly HSL + * + * + * + * Copyright (c) 2015 Alexei Boronine (original idea, JavaScript implementation) + * Copyright (c) 2015 Roger Tallada (Obj-C implementation) + * Copyright (c) 2017 Martin Mitas (C implementation, based on Obj-C implementation) + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef PHANTOMCOLOR_H +#define PHANTOMCOLOR_H + +#include + +namespace Phantom { +struct Rgb; +struct Hsl; + +// A color presumed to be in linear space, represented as RGB. Values are in +// the range 0.0 - 1.0. Conversions to and from QColor will assume the QColor +// is in sRGB space, and sRGB conversion will be performed. +struct Rgb { + qreal r, g, b; + Rgb() {} + Rgb(qreal r, qreal g, qreal b) : r(r), g(g), b(b) {} + + inline Hsl toHsl() const; + inline QColor toQColor() const; + static inline Rgb ofHsl(const Hsl &); + static inline Rgb ofQColor(const QColor &); + + static Rgb lerp(const Rgb &x, const Rgb &y, qreal a); +}; + +// A color represented as pseudo-CIE hue, saturation, and lightness. Hue is in +// the range 0.0 - 360.0 (degrees). Lightness and saturation are in the range +// 0.0 - 1.0. Using this and making adjustments to the L value will produce +// more consistent and predictable results than QColor's .darker()/.lighter(). +// Note that this is not strictly CIE -- some of the colorspace is distorted so +// that it can represented as a continuous coordinate space. Therefore not all +// adjustments to the parameters will produce perfectly linear results with +// regards to saturation and lightness. But it's still useful, and better than +// QColor's .darker()/.lighter(). Additionally, the L value is more useful for +// performing comparisons between two colors to measure relative and absolute +// brightness. +// +// See the documentation for the hsluv library for more information. (Note that +// for consistency we treat the S and L values in the range 0.0 - 1.0 instead +// of 0.0 - 100.0 like hsluv-c on its own does.) +struct Hsl { + qreal h, s, l; + Hsl() {} + Hsl(qreal h, qreal s, qreal l) : h(h), s(s), l(l) {} + + inline Rgb toRgb() const; + inline QColor toQColor() const; + static inline Hsl ofRgb(const Rgb &); + static inline Hsl ofQColor(const QColor &); +}; +Rgb rgb_of_qcolor(const QColor &color); +QColor qcolor_of_rgb(qreal r, qreal g, qreal b); +Hsl hsl_of_rgb(qreal r, qreal g, qreal b); +Rgb rgb_of_hsl(qreal h, qreal s, qreal l); + +// Clip a floating point value to the range 0.0 - 1.0. +inline qreal saturate(qreal x) +{ + if (x < 0.0) + return 0.0; + if (x > 1.0) + return 1.0; + return x; +} + +inline qreal lerp(qreal x, qreal y, qreal a) +{ + return (1.0 - a) * x + a * y; +} + +// Linearly interpolate two QColors after trasnforming them to linear color +// space, treating the QColor values as if they were in sRGB space. The +// returned QColor is converted back to sRGB space. +QColor lerpQColor(const QColor &x, const QColor &y, qreal a); + +Hsl Rgb::toHsl() const +{ + return hsl_of_rgb(r, g, b); +} + +QColor Rgb::toQColor() const +{ + return qcolor_of_rgb(r, g, b); +} + +Rgb Rgb::ofHsl(const Hsl &hsl) +{ + return rgb_of_hsl(hsl.h, hsl.s, hsl.l); +} + +Rgb Rgb::ofQColor(const QColor &color) +{ + return rgb_of_qcolor(color); +} + +Rgb Hsl::toRgb() const +{ + return rgb_of_hsl(h, s, l); +} + +QColor Hsl::toQColor() const +{ + Rgb rgb = rgb_of_hsl(h, s, l); + return qcolor_of_rgb(rgb.r, rgb.g, rgb.b); +} + +Hsl Hsl::ofRgb(const Rgb &rgb) +{ + return hsl_of_rgb(rgb.r, rgb.g, rgb.b); +} + +Hsl Hsl::ofQColor(const QColor &color) +{ + Rgb rgb = rgb_of_qcolor(color); + return hsl_of_rgb(rgb.r, rgb.g, rgb.b); +} + +} // namespace Phantom + +#endif diff --git a/src/gui/styles/dark/darkstyle.cpp b/src/gui/styles/dark/darkstyle.cpp new file mode 100644 index 0000000..2dc061a --- /dev/null +++ b/src/gui/styles/dark/darkstyle.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2020 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "darkstyle.h" + +#include +#include +#include +#include +#include +#include + +// TODO somehow make this cyclical includes disappear. +//#ifdef Q_OS_MACOS +//#include "../../../core/internalmanager.h" +//#endif + +DarkStyle::DarkStyle() : BaseStyle() +{ +#ifdef Q_OS_MACOS + m_drawNativeMacOsToolBar = true; // InternalManager::instance()->get_theme() == td::Theme::Dark; +#endif +} + +QPalette DarkStyle::standardPalette() const +{ + auto palette = BaseStyle::standardPalette(); + palette.setColor(QPalette::Active, QPalette::Window, QRgb(0x3B3B3D)); + palette.setColor(QPalette::Inactive, QPalette::Window, QRgb(0x404042)); + palette.setColor(QPalette::Disabled, QPalette::Window, QRgb(0x424242)); + + palette.setColor(QPalette::Active, QPalette::WindowText, QRgb(0xCACBCE)); + palette.setColor(QPalette::Inactive, QPalette::WindowText, QRgb(0xC8C8C6)); + palette.setColor(QPalette::Disabled, QPalette::WindowText, QRgb(0x707070)); + + palette.setColor(QPalette::Active, QPalette::Text, QRgb(0xCACBCE)); + palette.setColor(QPalette::Inactive, QPalette::Text, QRgb(0xC8C8C6)); + palette.setColor(QPalette::Disabled, QPalette::Text, QRgb(0x707070)); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + palette.setColor(QPalette::Active, QPalette::PlaceholderText, QRgb(0x7D7D82)); + palette.setColor(QPalette::Inactive, QPalette::PlaceholderText, QRgb(0x87888C)); + palette.setColor(QPalette::Disabled, QPalette::PlaceholderText, QRgb(0x737373)); +#endif + + palette.setColor(QPalette::Active, QPalette::BrightText, QRgb(0x252627)); + palette.setColor(QPalette::Inactive, QPalette::BrightText, QRgb(0x2D2D2F)); + palette.setColor(QPalette::Disabled, QPalette::BrightText, QRgb(0x333333)); + + palette.setColor(QPalette::Active, QPalette::Base, QRgb(0x27272A)); + palette.setColor(QPalette::Inactive, QPalette::Base, QRgb(0x2A2A2D)); + palette.setColor(QPalette::Disabled, QPalette::Base, QRgb(0x343437)); + + palette.setColor(QPalette::Active, QPalette::AlternateBase, QRgb(0x2C2C30)); + palette.setColor(QPalette::Inactive, QPalette::AlternateBase, QRgb(0x2B2B2F)); + palette.setColor(QPalette::Disabled, QPalette::AlternateBase, QRgb(0x36363A)); + + palette.setColor(QPalette::All, QPalette::ToolTipBase, QRgb(0x2D532D)); + palette.setColor(QPalette::All, QPalette::ToolTipText, QRgb(0xBFBFBF)); + + palette.setColor(QPalette::Active, QPalette::Button, QRgb(0x28282B)); + palette.setColor(QPalette::Inactive, QPalette::Button, QRgb(0x28282B)); + palette.setColor(QPalette::Disabled, QPalette::Button, QRgb(0x2B2A2A)); + + palette.setColor(QPalette::Active, QPalette::ButtonText, QRgb(0xB9B9BE)); + palette.setColor(QPalette::Inactive, QPalette::ButtonText, QRgb(0x9E9FA5)); + palette.setColor(QPalette::Disabled, QPalette::ButtonText, QRgb(0x73747E)); + + palette.setColor(QPalette::Active, QPalette::Highlight, QRgb(0x2D532D)); + palette.setColor(QPalette::Inactive, QPalette::Highlight, QRgb(0x354637)); + palette.setColor(QPalette::Disabled, QPalette::Highlight, QRgb(0x293D29)); + + palette.setColor(QPalette::Active, QPalette::HighlightedText, QRgb(0xCCCCCC)); + palette.setColor(QPalette::Inactive, QPalette::HighlightedText, QRgb(0xCECECE)); + palette.setColor(QPalette::Disabled, QPalette::HighlightedText, QRgb(0x707070)); + + palette.setColor(QPalette::All, QPalette::Light, QRgb(0x414145)); + palette.setColor(QPalette::All, QPalette::Midlight, QRgb(0x39393C)); + palette.setColor(QPalette::All, QPalette::Mid, QRgb(0x2F2F32)); + palette.setColor(QPalette::All, QPalette::Dark, QRgb(0x202022)); + palette.setColor(QPalette::All, QPalette::Shadow, QRgb(0x19191A)); + + palette.setColor(QPalette::All, QPalette::Link, QRgb(0x68B668)); + palette.setColor(QPalette::Disabled, QPalette::Link, QRgb(0x74A474)); + palette.setColor(QPalette::All, QPalette::LinkVisited, QRgb(0x75B875)); + palette.setColor(QPalette::Disabled, QPalette::LinkVisited, QRgb(0x77A677)); + + return palette; +} + +QString DarkStyle::getAppStyleSheet() const +{ + QFile extStylesheetFile(QStringLiteral(":/dark/darkstyle.qss")); + if (extStylesheetFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + return extStylesheetFile.readAll(); + } + qWarning("Failed to load dark theme stylesheet."); + return {}; +} + +void DarkStyle::polish(QWidget *widget) +{ + if (qobject_cast(widget) || qobject_cast(widget) || qobject_cast(widget) || + qobject_cast(widget) || qobject_cast(widget)) { + auto palette = widget->palette(); +#if defined(Q_OS_MACOS) + // if (InternalManager::instance()->get_theme() != td::Theme::Dark) { + palette.setColor(QPalette::Active, QPalette::Window, QRgb(0x2A2A2A)); + palette.setColor(QPalette::Inactive, QPalette::Window, QRgb(0x2D2D2D)); + palette.setColor(QPalette::Disabled, QPalette::Window, QRgb(0x2D2D2D)); +// } +#elif defined(Q_OS_WIN) + palette.setColor(QPalette::All, QPalette::Window, QRgb(0x2F2F30)); +#else + palette.setColor(QPalette::Active, QPalette::Window, QRgb(0x2F2F30)); + palette.setColor(QPalette::Inactive, QPalette::Window, QRgb(0x313133)); + palette.setColor(QPalette::Disabled, QPalette::Window, QRgb(0x3A3A3B)); +#endif + + widget->setPalette(palette); + } +} diff --git a/src/gui/styles/dark/darkstyle.h b/src/gui/styles/dark/darkstyle.h new file mode 100644 index 0000000..3591424 --- /dev/null +++ b/src/gui/styles/dark/darkstyle.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_DARKSTYLE_H +#define KEEPASSXC_DARKSTYLE_H + +#include "../base/basestyle.h" + +class DarkStyle : public BaseStyle { + Q_OBJECT + +public: + DarkStyle(); + QPalette standardPalette() const override; + + using BaseStyle::polish; + void polish(QWidget *widget) override; + +protected: + QString getAppStyleSheet() const override; +}; + +#endif // KEEPASSXC_DARKSTYLE_H diff --git a/src/gui/styles/light/lightstyle.cpp b/src/gui/styles/light/lightstyle.cpp new file mode 100644 index 0000000..1cd3463 --- /dev/null +++ b/src/gui/styles/light/lightstyle.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (C) 2020 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "lightstyle.h" + +#include +#include +#include +#include +#include +#include + +// TODO somehow make this cyclical includes disappear. +//#ifdef Q_OS_MACOS +//#include "../../../core/internalmanager.h" +//#endif + +LightStyle::LightStyle() : BaseStyle() +{ +#ifdef Q_OS_MACOS + m_drawNativeMacOsToolBar = true; // InternalManager::instance()->get_theme() != td::Theme::Dark; +#endif +} + +QPalette LightStyle::standardPalette() const +{ + auto palette = BaseStyle::standardPalette(); + palette.setColor(QPalette::Active, QPalette::Window, QRgb(0xF7F7F7)); + palette.setColor(QPalette::Inactive, QPalette::Window, QRgb(0xFCFCFC)); + palette.setColor(QPalette::Disabled, QPalette::Window, QRgb(0xEDEDED)); + + palette.setColor(QPalette::Active, QPalette::WindowText, QRgb(0x1D1D20)); + palette.setColor(QPalette::Inactive, QPalette::WindowText, QRgb(0x252528)); + palette.setColor(QPalette::Disabled, QPalette::WindowText, QRgb(0x8C8C92)); + + palette.setColor(QPalette::Active, QPalette::Text, QRgb(0x1D1D20)); + palette.setColor(QPalette::Inactive, QPalette::Text, QRgb(0x252528)); + palette.setColor(QPalette::Disabled, QPalette::Text, QRgb(0x8C8C92)); + +#if (QT_VERSION >= QT_VERSION_CHECK(5, 12, 0)) + palette.setColor(QPalette::Active, QPalette::PlaceholderText, QRgb(0x71727D)); + palette.setColor(QPalette::Inactive, QPalette::PlaceholderText, QRgb(0x878893)); + palette.setColor(QPalette::Disabled, QPalette::PlaceholderText, QRgb(0xA3A4AC)); +#endif + + palette.setColor(QPalette::Active, QPalette::BrightText, QRgb(0xF3F3F4)); + palette.setColor(QPalette::Inactive, QPalette::BrightText, QRgb(0xEAEAEB)); + palette.setColor(QPalette::Disabled, QPalette::BrightText, QRgb(0xE4E5E7)); + + palette.setColor(QPalette::Active, QPalette::Base, QRgb(0xF9F9F9)); + palette.setColor(QPalette::Inactive, QPalette::Base, QRgb(0xFCFCFC)); + palette.setColor(QPalette::Disabled, QPalette::Base, QRgb(0xEFEFF2)); + + palette.setColor(QPalette::Active, QPalette::AlternateBase, QRgb(0xECF3E8)); + palette.setColor(QPalette::Inactive, QPalette::AlternateBase, QRgb(0xF1F6EE)); + palette.setColor(QPalette::Disabled, QPalette::AlternateBase, QRgb(0xE1E9DD)); + + palette.setColor(QPalette::All, QPalette::ToolTipBase, QRgb(0x4D7F1A)); + palette.setColor(QPalette::All, QPalette::ToolTipText, QRgb(0xF9F9F9)); + + palette.setColor(QPalette::Active, QPalette::Button, QRgb(0xD4D5DD)); + palette.setColor(QPalette::Inactive, QPalette::Button, QRgb(0xDCDCE0)); + palette.setColor(QPalette::Disabled, QPalette::Button, QRgb(0xE5E5E6)); + + palette.setColor(QPalette::Active, QPalette::ButtonText, QRgb(0x181A18)); + palette.setColor(QPalette::Inactive, QPalette::ButtonText, QRgb(0x454A54)); + palette.setColor(QPalette::Disabled, QPalette::ButtonText, QRgb(0x97979B)); + + palette.setColor(QPalette::Active, QPalette::Highlight, QRgb(0x507F1F)); + palette.setColor(QPalette::Inactive, QPalette::Highlight, QRgb(0xA6BE8E)); + palette.setColor(QPalette::Disabled, QPalette::Highlight, QRgb(0xC3D5B4)); + + palette.setColor(QPalette::Active, QPalette::HighlightedText, QRgb(0xFFFFFF)); + palette.setColor(QPalette::Inactive, QPalette::HighlightedText, QRgb(0x252528)); + palette.setColor(QPalette::Disabled, QPalette::HighlightedText, QRgb(0x8C8C92)); + + palette.setColor(QPalette::All, QPalette::Light, QRgb(0xF9F9F9)); + palette.setColor(QPalette::All, QPalette::Midlight, QRgb(0xE9E9EB)); + palette.setColor(QPalette::All, QPalette::Mid, QRgb(0xC9C9CF)); + palette.setColor(QPalette::All, QPalette::Dark, QRgb(0xBBBBC2)); + palette.setColor(QPalette::All, QPalette::Shadow, QRgb(0x6C6D79)); + + palette.setColor(QPalette::All, QPalette::Link, QRgb(0x4B7B19)); + palette.setColor(QPalette::Disabled, QPalette::Link, QRgb(0x4F6935)); + palette.setColor(QPalette::All, QPalette::LinkVisited, QRgb(0x507826)); + palette.setColor(QPalette::Disabled, QPalette::LinkVisited, QRgb(0x506935)); + + return palette; +} + +QString LightStyle::getAppStyleSheet() const +{ + QFile extStylesheetFile(QStringLiteral(":/light/lightstyle.qss")); + if (extStylesheetFile.open(QIODevice::ReadOnly | QIODevice::Text)) { + return extStylesheetFile.readAll(); + } + qWarning("Failed to load light theme stylesheet."); + return {}; +} + +void LightStyle::polish(QWidget *widget) +{ + if (qobject_cast(widget) || qobject_cast(widget) || qobject_cast(widget) || + qobject_cast(widget) || qobject_cast(widget)) { + auto palette = widget->palette(); +#if defined(Q_OS_MACOS) + // if (InternalManager::instance()->get_theme() == td::Theme::Dark) { + palette.setColor(QPalette::Active, QPalette::Window, QRgb(0xD4D4D4)); + palette.setColor(QPalette::Inactive, QPalette::Window, QRgb(0xF5F5F5)); + palette.setColor(QPalette::Disabled, QPalette::Window, QRgb(0xF5F5F5)); +// } +#elif defined(Q_OS_WIN) + palette.setColor(QPalette::All, QPalette::Window, QRgb(0xFFFFFF)); +#else + palette.setColor(QPalette::Active, QPalette::Window, QRgb(0xEFF0F1)); + palette.setColor(QPalette::Inactive, QPalette::Window, QRgb(0xEFF0F1)); + palette.setColor(QPalette::Disabled, QPalette::Window, QRgb(0xE1E2E4)); +#endif + + widget->setPalette(palette); + } +} diff --git a/src/gui/styles/light/lightstyle.h b/src/gui/styles/light/lightstyle.h new file mode 100644 index 0000000..a2caa38 --- /dev/null +++ b/src/gui/styles/light/lightstyle.h @@ -0,0 +1,37 @@ +/* + * Copyright (C) 2020 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_LIGHTSTYLE_H +#define KEEPASSXC_LIGHTSTYLE_H + +#include "../base/basestyle.h" + +class LightStyle : public BaseStyle { + Q_OBJECT + +public: + LightStyle(); + QPalette standardPalette() const override; + + using BaseStyle::polish; + void polish(QWidget *widget) override; + +protected: + QString getAppStyleSheet() const override; +}; + +#endif // KEEPASSXC_LIGHTSTYLE_H diff --git a/src/gui/styles/statecolorpalette.cpp b/src/gui/styles/statecolorpalette.cpp new file mode 100644 index 0000000..0cefc3c --- /dev/null +++ b/src/gui/styles/statecolorpalette.cpp @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "statecolorpalette.h" + +StateColorPalette::StateColorPalette() {} + +void StateColorPalette::initDefaultPaletteLight() +{ + setColor(ColorRole::Error, QStringLiteral("#FF7D7D")); + setColor(ColorRole::Warning, QStringLiteral("#FFD30F")); + setColor(ColorRole::Info, QStringLiteral("#84D0E1")); + setColor(ColorRole::Incomplete, QStringLiteral("#FFD30F")); + + setColor(ColorRole::Unknown, QStringLiteral("#C9C9CF")); + setColor(ColorRole::VeryBad, QStringLiteral("#7b1fa2")); + setColor(ColorRole::Bad, QStringLiteral("#5e35b1")); + setColor(ColorRole::Ok, QStringLiteral("#1976d2")); + setColor(ColorRole::Good, QStringLiteral("#0097a7")); + setColor(ColorRole::VeryGood, QStringLiteral("#4caf50")); + + setColor(ColorRole::True, QStringLiteral("#5EA10E")); + setColor(ColorRole::False, QStringLiteral("#C43F31")); +} + +void StateColorPalette::initDefaultPaletteDark() +{ + setColor(ColorRole::Error, QStringLiteral("#802D2D")); + setColor(ColorRole::Warning, QStringLiteral("#73682E")); + setColor(ColorRole::Info, QStringLiteral("#207183")); + setColor(ColorRole::Incomplete, QStringLiteral("#665124")); + + setColor(ColorRole::Unknown, QStringLiteral("#2F2F32")); + setColor(ColorRole::VeryBad, QStringLiteral("#7b1fa2")); + setColor(ColorRole::Bad, QStringLiteral("#5e35b1")); + setColor(ColorRole::Ok, QStringLiteral("#1976d2")); + setColor(ColorRole::Good, QStringLiteral("#0097a7")); + setColor(ColorRole::VeryGood, QStringLiteral("#4caf50")); + + setColor(ColorRole::True, QStringLiteral("#608A22")); + setColor(ColorRole::False, QStringLiteral("#C43F31")); +} diff --git a/src/gui/styles/statecolorpalette.h b/src/gui/styles/statecolorpalette.h new file mode 100644 index 0000000..681c952 --- /dev/null +++ b/src/gui/styles/statecolorpalette.h @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2021 KeePassXC Team + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 2 or (at your option) + * version 3 of the License. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef KEEPASSXC_STATECOLORPALETTE_H +#define KEEPASSXC_STATECOLORPALETTE_H + +#include +#include +#include + +// TODO fix the really janky workaround keeping this class separate. +// Probably merge it into the internal manager class some time. + +/** + * Extended color palette for indicating custom widget states. + */ +class StateColorPalette { + Q_GADGET + +public: + StateColorPalette(); + + enum ColorRole { Error, Warning, Info, Incomplete, True, False, Unknown, VeryBad, Bad, Ok, Good, VeryGood }; + + inline void setColor(ColorRole role, const QColor &color) + { + m_colorMap[role] = color; + } + + inline QColor color(ColorRole role) const + { + return m_colorMap.value(role); + } + + void initDefaultPaletteLight(); + void initDefaultPaletteDark(); + +private: + QHash m_colorMap; +}; + +#endif // KEEPASSXC_STATECOLORPALETTE_H diff --git a/src/util/alertlabel.cpp b/src/util/alertlabel.cpp index 9ba2bb0..d6fcfb7 100644 --- a/src/util/alertlabel.cpp +++ b/src/util/alertlabel.cpp @@ -35,9 +35,9 @@ AlertLabel::AlertLabel(QWidget *parent) : QLabel(parent) void AlertLabel::update_theme() { - QFile file(":/global/alertlabel.qss"); - file.open(QIODevice::ReadOnly); - setStyleSheet(file.readAll()); + // QFile file(":/global/alertlabel.qss"); + // file.open(QIODevice::ReadOnly); + // setStylesheet\(file.readAll()); first_time_stylesheet_set = false; } diff --git a/src/util/custommessageboxes.h b/src/util/custommessageboxes.h index 105b664..656ea6f 100644 --- a/src/util/custommessageboxes.h +++ b/src/util/custommessageboxes.h @@ -85,8 +85,8 @@ void yn_messagebox(QWidget *p, Lambda const &cb, QString const &&top, QString co template void ync_messagebox(QWidget *p, Lambda const &cb, QString const &&top, QString const &&bottom, - QString const &&yes_text = "Yes", QString const &&no_text = "No", QString const &&cancel_text = "Cancel", - QMessageBox::ButtonRole const default_role = QMessageBox::RejectRole) + QString const &&yes_text = "Save", QString const &&no_text = "Do not save", QString const &&cancel_text = "Cancel", + QMessageBox::ButtonRole const default_role = QMessageBox::AcceptRole) { auto msgbox = new CustomMessageBox(p); auto yes_button = new QPushButton(yes_text, msgbox); @@ -94,13 +94,13 @@ void ync_messagebox(QWidget *p, Lambda const &cb, QString const &&top, QString c auto cancel_button = new QPushButton(cancel_text, msgbox); auto default_button = QMessageBox::RejectRole == default_role ? cancel_button - : QMessageBox::YesRole == default_role ? yes_button : no_button; + : QMessageBox::AcceptRole == default_role ? yes_button : no_button; msgbox->setText(top); msgbox->setInformativeText(bottom); - msgbox->addButton(yes_button, QMessageBox::YesRole); - msgbox->addButton(no_button, QMessageBox::NoRole); + msgbox->addButton(yes_button, QMessageBox::AcceptRole); msgbox->addButton(cancel_button, QMessageBox::RejectRole); + msgbox->addButton(no_button, QMessageBox::DestructiveRole); msgbox->setDefaultButton(default_button); msgbox->setEscapeButton(default_button); msgbox->setAttribute(Qt::WA_DeleteOnClose, true); @@ -162,8 +162,7 @@ template void dev_unknown_file(QWidget *p, Lambda const &cb) template void confirm_exit_to_main_menu(QWidget *p, Lambda const &cb) { - cmb::ync_messagebox(p, cb, "Are you sure you want to quit without saving?", "There are unsaved changes.", "Save", - "Do not save", "Cancel"); + cmb::ync_messagebox(p, cb, "Are you sure you want to quit without saving?", ""); } template void diary_downloaded(QWidget *p, Lambda const &cb) @@ -178,8 +177,7 @@ template void diary_uploaded(QWidget *p, Lambda const &cb) template void confirm_switch_date(QWidget *p, Lambda const &cb) { - cmb::ync_messagebox(p, cb, "Are you sure you want to switch dates without saving?", "There are unsaved changes.", - "Save", "Do not save", "Cancel"); + cmb::ync_messagebox(p, cb, "Are you sure you want to switch dates without saving?", ""); } } // namespace cmb diff --git a/src/util/diarycomparisonlabel.h b/src/util/diarycomparisonlabel.h new file mode 100644 index 0000000..32062a7 --- /dev/null +++ b/src/util/diarycomparisonlabel.h @@ -0,0 +1,97 @@ +/* + * This file is part of Theoretical Diary. + * Copyright (C) 2022 someretical + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DIARYCOMPARISONLABEL_H +#define DIARYCOMPARISONLABEL_H + +#include + +#include "../core/internalmanager.h" +#include "misc.h" + +// Not available to other files. +static int const SIZE = 50; + +class DiaryComparisonLabel : public QLabel { + Q_OBJECT + +public: + DiaryComparisonLabel(QWidget *parent = nullptr) : QLabel(parent) + { + setFixedSize(QSize(50, 50)); + rating = td::Rating::Unknown; + special = false; + } + + ~DiaryComparisonLabel() {} + + td::Rating rating; + bool special; + +private: + QPixmap generate_pixmap() + { + if (special) { + auto theme_str = InternalManager::instance()->get_theme() == td::Theme::Light ? "light" : "dark"; + auto svg = QIcon(QString(":/themes/%1/star.svg").arg(theme_str)).pixmap(size()); + + QPixmap bkg(SIZE, SIZE); + bkg.fill(Qt::transparent); + QPainter p(&bkg); + p.setOpacity(0.5); + p.drawPixmap(0, 0, svg); + return bkg; + } + else { + QPixmap bkg(SIZE, SIZE); + bkg.fill(Qt::transparent); + + QColor bkg_color = misc::rating_to_color(rating); + QPainter p(&bkg); + + if (InternalManager::instance()->get_theme() == td::Theme::Light) + p.setOpacity(0.8); + + p.setPen(bkg_color); + p.setBrush(QBrush(bkg_color)); + p.drawRoundedRect(0, 0, SIZE, SIZE, 5, 5); + + return bkg; + } + } + +protected: + void paintEvent(QPaintEvent *) + { + QString key = + QString("comparisonlabel:%1:%2") + .arg(QString::number(static_cast(rating)), + special ? "s" : QString::number(static_cast(InternalManager::instance()->get_theme()))); + QPixmap pixmap; + + if (!QPixmapCache::find(key, pixmap)) { + pixmap = generate_pixmap(); + QPixmapCache::insert(key, pixmap); + } + + QPainter p(this); + p.drawPixmap(0, 0, pixmap); + } +}; + +#endif // DIARYCOMPARISONLABEL_H diff --git a/src/util/diarypixellabel.h b/src/util/diarypixellabel.h new file mode 100644 index 0000000..22f9423 --- /dev/null +++ b/src/util/diarypixellabel.h @@ -0,0 +1,104 @@ +/* + * This file is part of Theoretical Diary. + * Copyright (C) 2022 someretical + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef DIARYPIXELLABEL_H +#define DIARYPIXELLABEL_H + +#include + +#include "../core/internalmanager.h" +#include "misc.h" + +class DiaryPixelLabel : public QLabel { + Q_OBJECT + +public: + explicit DiaryPixelLabel( + td::Rating const r, bool const s, QDate const &date, int const size, QWidget *parent = nullptr) + : QLabel(parent) + { + special = s; + rating = r; + + setFixedHeight(size); + setFixedWidth(size); + + setToolTip(QString("%1 %2%3").arg( + date.toString("MMMM"), QString::number(date.day()), misc::get_day_suffix(date.day()))); + } + + ~DiaryPixelLabel() {} + + td::Rating rating; + bool special; + +public slots: + void resize(int const new_width) + { + setFixedHeight(new_width); + setFixedWidth(new_width); + } + +protected: + void paintEvent(QPaintEvent *) + { + auto const &size_ = size(); + + QString key = QString("pixellabel:%1:%2:%3") + .arg(QString::number(static_cast(rating)), QString::number(size_.width()), + QString::number(static_cast(InternalManager::instance()->get_theme()))); + QPixmap pixmap; + + if (!QPixmapCache::find(key, pixmap)) { + pixmap = generate_pixmap(size_); + QPixmapCache::insert(key, pixmap); + } + + QPainter p(this); + p.drawPixmap(0, 0, pixmap); + + // Since starred days are supposed to be a lot less common, caching isn't done for them. + if (special) { + auto theme_str = misc::rating_to_theme(rating) == td::Theme::Light ? "light" : "dark"; + QPixmap svg_overlay = QIcon(QString(":/themes/%1/star.svg").arg(theme_str)).pixmap(size_); + + p.setOpacity(0.5); + p.drawPixmap(0, 0, svg_overlay); + } + } + +private: + QPixmap generate_pixmap(QSize const &size_) + { + QPixmap bkg(size_.width(), size_.width()); + bkg.fill(Qt::transparent); + QColor bkg_color = misc::rating_to_color(rating); + QPainter p(&bkg); + + if (InternalManager::instance()->get_theme() == td::Theme::Light) + p.setOpacity(0.8); + + p.setPen(bkg_color); + p.setBrush(QBrush(bkg_color)); + p.drawRoundedRect(0, 0, size_.width(), size_.width(), 5, 5); + + return bkg; + } +}; + +#endif // DIARYPIXELLABEL_H diff --git a/src/util/misc.cpp b/src/util/misc.cpp index 044923a..dfff3b1 100644 --- a/src/util/misc.cpp +++ b/src/util/misc.cpp @@ -18,7 +18,7 @@ #include -#include "../core/internalmanager.h" +#include "../gui/styles/statecolorpalette.h" #include "misc.h" namespace misc { @@ -102,4 +102,44 @@ void clear_message_boxes() } } } + +QColor rating_to_color(const td::Rating rating) +{ + auto const &c = InternalManager::instance()->state_color_palette; + + switch (rating) { + case td::Rating::Unknown: + return c.color(StateColorPalette::ColorRole::Unknown); + case td::Rating::VeryBad: + return c.color(StateColorPalette::ColorRole::VeryBad); + case td::Rating::Bad: + return c.color(StateColorPalette::ColorRole::Bad); + case td::Rating::Ok: + return c.color(StateColorPalette::ColorRole::Ok); + case td::Rating::Good: + return c.color(StateColorPalette::ColorRole::Good); + case td::Rating::VeryGood: + return c.color(StateColorPalette::ColorRole::VeryGood); + } + + // This can never happen, it's only here to shut down the compiler warning. + return c.color(StateColorPalette::ColorRole::Unknown); +} + +td::Theme rating_to_theme(const td::Rating rating) +{ + switch (rating) { + case td::Rating::Unknown: + case td::Rating::VeryBad: + case td::Rating::Bad: + case td::Rating::Ok: + return td::Theme::Light; + case td::Rating::Good: + case td::Rating::VeryGood: + return td::Theme::Dark; + } + + // This can never happen, it's only here to shut down the compiler warning. + return td::Theme::Dark; +} } // namespace misc diff --git a/src/util/misc.h b/src/util/misc.h index cdc6788..a77af72 100644 --- a/src/util/misc.h +++ b/src/util/misc.h @@ -23,6 +23,8 @@ #include #include +#include "../core/internalmanager.h" + namespace misc { QString get_day_suffix(int const day); std::string get_trunc_first_line(std::string input, int const max_line_len); @@ -49,6 +51,8 @@ inline std::string &trim(std::string &s) void extend_top_line(std::string &top, long unsigned int const max_line_len); QString get_danger_stylesheet(); void clear_message_boxes(); +QColor rating_to_color(td::Rating const rating); +td::Theme rating_to_theme(const td::Rating rating); } // namespace misc #endif // MISC_H diff --git a/src/util/passwordlineedit.cpp b/src/util/passwordlineedit.cpp index c14242a..36ccbc3 100644 --- a/src/util/passwordlineedit.cpp +++ b/src/util/passwordlineedit.cpp @@ -24,6 +24,11 @@ PasswordLineEdit::PasswordLineEdit(QWidget *parent) : QLineEdit(parent) { setEchoMode(QLineEdit::Password); + + auto monospaced = QFontDatabase::systemFont(QFontDatabase::FixedFont); + monospaced.setLetterSpacing(QFont::PercentageSpacing, 110); + setFont(monospaced); + QAction *action = addAction(QIcon(get_eye_icon(false)), QLineEdit::TrailingPosition); button = qobject_cast(action->associatedWidgets().last()); button->setCursor(QCursor(Qt::PointingHandCursor)); @@ -47,6 +52,5 @@ void PasswordLineEdit::on_released() QString PasswordLineEdit::get_eye_icon(bool const on) { - return QString(":/themes/%1/passwordlineedit/%2.svg") - .arg(InternalManager::instance()->get_theme_str(), on ? "eye_on" : "eye_off"); + return QString(":/themes/%1/%2.svg").arg(InternalManager::instance()->get_theme_str(), on ? "eye_on" : "eye_off"); } diff --git a/styles/base/basestyle.qss b/styles/base/basestyle.qss new file mode 100644 index 0000000..8b239b5 --- /dev/null +++ b/styles/base/basestyle.qss @@ -0,0 +1,56 @@ +QPushButton:default { + background: palette(highlight); + color: palette(highlighted-text); +} + +/* Note: default button hover is defined in the respective theme style */ +QPushButton:!default:hover { + background: palette(mid); +} + +QPushButton:checked { + background: palette(highlight); + color: palette(highlighted-text); +} + +QSpinBox { + min-width: 90px; +} + +QDialogButtonBox QPushButton { + min-width: 55px; +} + +QCheckBox, QRadioButton { + spacing: 10px; +} + +QGroupBox { + margin-top: 1.4em; + margin-bottom: 1.4em; + font-weight: bold; +} + +QGroupBox::title { + margin-top: -3.35em; + margin-left: -.4em; + subcontrol-origin: padding; +} + +QToolTip { + border: none; + padding: 3px; +} + +QPlainTextEdit, QTextEdit { + background-color: palette(base); + padding-left: 4px; +} + +QStatusBar { + background-color: palette(window); +} + +QTabWidget::tab-bar#diary_menu_tab, QTabWidget::tab-bar#settings_tabs, QTabWidget::tab-bar#charts { + alignment: center; +} diff --git a/styles/dark/dangerbutton.qss b/styles/dark/dangerbutton.qss deleted file mode 100644 index c9a6895..0000000 --- a/styles/dark/dangerbutton.qss +++ /dev/null @@ -1,20 +0,0 @@ -QPushButton { - border-color: #dc3545; - color: #dc3545; -} - -QPushButton:checked, -QPushButton:pressed { - color: #31363b; - background-color: #dc3545; -} - -QPushButton:flat:hover { - background-color: rgba(220, 53, 69, 0.2); -} - -QPushButton:flat:pressed, -QPushButton:flat:checked { - background-color: rgba(220, 53, 69, 0.1); - color: #dc3545; -} \ No newline at end of file diff --git a/styles/dark/darkstyle.qss b/styles/dark/darkstyle.qss new file mode 100644 index 0000000..a9aef28 --- /dev/null +++ b/styles/dark/darkstyle.qss @@ -0,0 +1,28 @@ +DatabaseWidget:!active, GroupView:!active, +EntryPreviewWidget QLineEdit:!active, EntryPreviewWidget QTextEdit:!active { + background-color: #404042; +} + +DatabaseWidget:disabled, GroupView:disabled, +EntryPreviewWidget QLineEdit:disabled, EntryPreviewWidget QTextEdit:disabled { + background-color: #424242; +} + +QPushButton:!default:hover { + /* Using slightly darker shade from palette(button) */ + background: #252528; +} + +QPushButton:default:hover, QPushButton:checked:hover { + /* Using slightly lighter shade from palette(highlight) */ + background: #2E582E; +} + +QToolTip { + color: #BFBFBF; + background-color: #2D532D; +} + +QGroupBox { + background-color: palette(light); +} diff --git a/styles/dark/diary_entry_list/0.qss b/styles/dark/diary_entry_list/0.qss deleted file mode 100644 index 3820389..0000000 --- a/styles/dark/diary_entry_list/0.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #f5f5f5; - background-color: rgba(84, 110, 122, 0.2); -} diff --git a/styles/dark/diary_entry_list/1.qss b/styles/dark/diary_entry_list/1.qss deleted file mode 100644 index 910ff1b..0000000 --- a/styles/dark/diary_entry_list/1.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #f5f5f5; - background-color: rgba(123, 31, 162, 1); -} diff --git a/styles/dark/diary_entry_list/2.qss b/styles/dark/diary_entry_list/2.qss deleted file mode 100644 index 36cbe51..0000000 --- a/styles/dark/diary_entry_list/2.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #f5f5f5; - background-color: rgba(94, 53, 177, 1); -} diff --git a/styles/dark/diary_entry_list/3.qss b/styles/dark/diary_entry_list/3.qss deleted file mode 100644 index 7a89acc..0000000 --- a/styles/dark/diary_entry_list/3.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #f5f5f5; - background-color: rgba(25, 118, 210, 1); -} diff --git a/styles/dark/diary_entry_list/4.qss b/styles/dark/diary_entry_list/4.qss deleted file mode 100644 index 245f5ee..0000000 --- a/styles/dark/diary_entry_list/4.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #3c3c3c; - background-color: rgba(0, 151, 167, 1); -} diff --git a/styles/dark/diary_entry_list/5.qss b/styles/dark/diary_entry_list/5.qss deleted file mode 100644 index 255799a..0000000 --- a/styles/dark/diary_entry_list/5.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #3c3c3c; - background-color: rgba(76, 175, 80, 1); -} diff --git a/styles/dark/diary_entry_list/base.qss b/styles/dark/diary_entry_list/base.qss deleted file mode 100644 index 8f559d0..0000000 --- a/styles/dark/diary_entry_list/base.qss +++ /dev/null @@ -1,11 +0,0 @@ -DiaryEntryDayLabel { - border: transparent; - border-radius: 25px; -} - -DiaryEntryDayMessage { - border: transparent; - border-radius: 4px; - background-color: #232629; - padding: 15px; -} diff --git a/styles/dark/diaryeditor.qss b/styles/dark/diaryeditor.qss deleted file mode 100644 index 4c086ee..0000000 --- a/styles/dark/diaryeditor.qss +++ /dev/null @@ -1,23 +0,0 @@ -QPlainTextEdit#entry_edit { - background-color: #232629; - border: 2px solid #4dd0e1; - border-radius: 4px; - padding: 8px; - height: 18px; -} - -QPushButton#next_month, QPushButton#prev_month { - text-align: center; -} - -QPushButton#prev_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/dark/primary/leftarrow.svg); -} - -QPushButton#next_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/dark/primary/rightarrow.svg); -} diff --git a/styles/dark/diaryentryviewer.qss b/styles/dark/diaryentryviewer.qss deleted file mode 100644 index d0bcf9c..0000000 --- a/styles/dark/diaryentryviewer.qss +++ /dev/null @@ -1,11 +0,0 @@ -QPushButton#prev_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/dark/primary/leftarrow.svg); -} - -QPushButton#next_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/dark/primary/rightarrow.svg); -} diff --git a/styles/dark/diarystats.qss b/styles/dark/diarystats.qss deleted file mode 100644 index 1907acc..0000000 --- a/styles/dark/diarystats.qss +++ /dev/null @@ -1,67 +0,0 @@ -QPushButton#prev_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/dark/primary/leftarrow.svg); -} - -QPushButton#next_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/dark/primary/rightarrow.svg); -} - -QLabel#very_bad, QLabel#very_bad_2, QLabel#very_bad_3 { - background-color: rgba(123, 31, 162, 1); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#bad, QLabel#bad_2, QLabel#bad_3 { - background-color: rgba(94, 53, 177, 1); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#ok, QLabel#ok_2, QLabel#ok_3 { - background-color: rgba(25, 118, 210, 1); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#good, QLabel#good_2, QLabel#good_3 { - background-color: rgba(0, 151, 167, 1); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#very_good, QLabel#very_good_2, QLabel#very_good_3 { - background-color: rgba(76, 175, 80, 1); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#unknown, QLabel#unknown_2, QLabel#unknown_3 { - background-color: rgba(84, 110, 122, 0.2); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#starred, QLabel#starred_2, QLabel#starred_3 { - min-width: 48px; - min-height: 48px; - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/global/star_white.svg); -} diff --git a/styles/dark/material_cyan.qss b/styles/dark/material_cyan.qss deleted file mode 100644 index e99b4c9..0000000 --- a/styles/dark/material_cyan.qss +++ /dev/null @@ -1,1305 +0,0 @@ -/* ------------------------------------------------------------------------ */ -/* QtMaterial - https://github.com/UN-GCPDS/qt-material -/* By Yeison Cardona - GCPDS -/* ------------------------------------------------------------------------ */ - -*{ - color: #ffffff; - font-family: "Roboto"; - selection-background-color: #88ffff; - selection-color: #000000; -} - -*:focus { - outline: none; -} - -/* ------------------------------------------------------------------------ */ -/* Custom colors */ - -.danger{ - color: #dc3545; - background-color: transparent; -} - -.warning{ - color: #ffc107; - background-color: transparent; -} - -.success{ - color: #17a2b8; - background-color: transparent; -} - -.danger:disabled{ - color: rgba(220, 53, 69, 0.4); - border-color: rgba(220, 53, 69, 0.4); -} - -.warning:disabled{ - color: rgba(255, 193, 7, 0.4); - border-color: rgba(255, 193, 7, 0.4); -} - -.success:disabled{ - color: rgba(23, 162, 184, 0.4); - border-color: rgba(23, 162, 184, 0.4); -} - -.danger:flat:disabled{ - background-color: rgba(220, 53, 69, 0.1); -} - -.warning:flat:disabled{ - background-color: rgba(255, 193, 7, 0.1); -} - -.success:flat:disabled{ - background-color: rgba(23, 162, 184, 0.1); -} - -/* ------------------------------------------------------------------------ */ -/* Basic widgets */ - -QWidget { - background-color: #31363b; -} - -QGroupBox, -QFrame { - background-color: #31363b; - border: 2px solid #4f5b62; - border-radius: 4px; -} - -QGroupBox.fill_background, -QFrame.fill_background { - background-color: #232629; - border: 2px solid #232629; - border-radius: 4px; -} - -QSplitter { - background-color: transparent; - border: none -} - -QStatusBar { - color: #ffffff; - background-color: rgba(79, 91, 98, 0.2); - border-radius: 0px; -} - -QScrollArea, -QStackedWidget, -QWidget > QToolBox, -QToolBox > QWidget, -QTabWidget > QWidget { - border: none; -} - -QTabWidget::pane { - border: none; -} - -/* ------------------------------------------------------------------------ */ -/* Inputs */ - -QDateTimeEdit, -QSpinBox, -QDoubleSpinBox, -QTextEdit, -QLineEdit, -QPushButton { - color: #4dd0e1; - background-color: #31363b; - border: 2px solid #4dd0e1; - border-radius: 4px; - height: 32px; -} - -QDateTimeEdit, -QSpinBox, -QDoubleSpinBox, -QTreeView, -QListView, -QLineEdit, -QComboBox { - padding-left: 16px; - border-radius: 0px; - background-color: #232629; - border-width: 0 0 2px 0; - border-radius: 0px; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - height: 32px; -} - -QPlainTextEdit { - border-radius: 4px; - padding: 8px 16px; - background-color: #31363b; - border: 2px solid #4f5b62; -} - -QTextEdit { - padding: 8px 16px; - border-radius: 4px; - background-color: #232629; -} - -QDateTimeEdit:disabled, -QSpinBox:disabled, -QDoubleSpinBox:disabled, -QTextEdit:disabled, -QLineEdit:disabled { - color: rgba(77, 208, 225, 0.2); - background-color: rgba(35, 38, 41, 0.75); - border: 2px solid rgba(77, 208, 225, 0.2); - border-width: 0 0 2px 0; - padding: 0px 16px; - border-radius: 0px; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - height: 32px; -} - -/* ------------------------------------------------------------------------ */ -/* QComboBox */ - -QComboBox { - color: #4dd0e1; - border: 1px solid #4dd0e1; - border-width: 0 0 2px 0; - background-color: #232629; - border-radius: 0px; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - height: 36px; -} - -QComboBox:disabled { - color: rgba(77, 208, 225, 0.2); - background-color: rgba(35, 38, 41, 0.75); - border-bottom: 2px solid rgba(77, 208, 225, 0.2); -} - -QComboBox::drop-down { - border: none; - color: #4dd0e1; - width: 20px; -} - -QComboBox::down-arrow { - image: url(:/themes/dark/primary/downarrow.svg); - margin-right: 12px; -} - -QComboBox::down-arrow:disabled { - image: url(:/themes/dark/disabled/downarrow.svg); - margin-right: 12px; -} - -QComboBox QAbstractItemView { - background-color: #232629; - border: 2px solid #4f5b62; - border-radius: 0px; -} - -QComboBox[frame='false'] { - color: #4dd0e1; - background-color: transparent; - border: 1px solid transparent; -} -QComboBox[frame='false']:disabled { - color: rgba(77, 208, 225, 0.2); -} - -/* ------------------------------------------------------------------------ */ -/* Spin buttons */ - -QDateTimeEdit::up-button, -QDoubleSpinBox::up-button, -QSpinBox::up-button { - subcontrol-origin: border; - subcontrol-position: top right; - width: 20px; - image: url(:/themes/dark/primary/uparrow.svg); - border-width: 0px; - margin-right: 5px; -} - -QDateTimeEdit::up-button:disabled, -QDoubleSpinBox::up-button:disabled, -QSpinBox::up-button:disabled { - image: url(:/themes/dark/disabled/uparrow.svg); -} - -QDateTimeEdit::down-button, -QDoubleSpinBox::down-button, -QSpinBox::down-button { - subcontrol-origin: border; - subcontrol-position: bottom right; - width: 20px; - image: url(:/themes/dark/primary/downarrow.svg); - border-width: 0px; - border-top-width: 0; - margin-right: 5px; -} - -QDateTimeEdit::down-button:disabled, -QDoubleSpinBox::down-button:disabled, -QSpinBox::down-button:disabled { - image: url(:/themes/dark/disabled/downarrow.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QPushButton */ - -QPushButton { - text-transform: uppercase; - margin: 0px; - padding: 0px 16px; - height: 32px; - font-weight: bold; - - - border-radius: 4px; - - - -} - -QPushButton:checked, -QPushButton:pressed { - color: #31363b; - background-color: #4dd0e1; -} - -QPushButton:flat { - margin: 0px; - color: #4dd0e1; - border: none; - background-color: transparent; -} - -QPushButton:flat:hover { - background-color: rgba(77, 208, 225, 0.2); -} - -QPushButton:flat:pressed, -QPushButton:flat:checked { - background-color: rgba(77, 208, 225, 0.1); -} - -QPushButton:disabled { - color: rgba(79, 91, 98, 0.75); - background-color: transparent; - border-color: #4f5b62; -} - -QPushButton:flat:disabled { - color: rgba(79, 91, 98, 0.75); - background-color: rgba(79, 91, 98, 0.25); - border: none; -} - -QPushButton:disabled { - border: 2px solid rgba(79, 91, 98, 0.75); -} - -QPushButton:checked:disabled { - color: #232629; - background-color: #4f5b62; - border-color: #4f5b62; -} - -/* ------------------------------------------------------------------------ */ -/* QTabBar */ - -QTabBar{ - text-transform: uppercase; - font-weight: bold; -} - -QTabBar::tab { - color: #ffffff; - border: 0px; -} - -QTabBar::tab:bottom, -QTabBar::tab:top{ - padding: 0 16px; - height: 28px; -} - -QTabBar::tab:left, -QTabBar::tab:right{ - padding: 16px 0; - width: 28px; -} - -QTabBar::tab:top:selected, -QTabBar::tab:top:hover { - color: #4dd0e1; - border-bottom: 2px solid #4dd0e1; -} - -QTabBar::tab:bottom:selected, -QTabBar::tab:bottom:hover { - color: #4dd0e1; - border-top: 2px solid #4dd0e1; -} - -QTabBar::tab:right:selected, -QTabBar::tab:right:hover { - color: #4dd0e1; - border-left: 2px solid #4dd0e1; -} - -QTabBar::tab:left:selected, -QTabBar::tab:left:hover { - color: #4dd0e1; - border-right: 2px solid #4dd0e1; -} - -QTabBar QToolButton:hover, -QTabBar QToolButton { - border: 20px; - background-color: #31363b; -} - -QTabBar QToolButton::up-arrow { - image: url(:/themes/dark/disabled/uparrow2.svg); -} - -QTabBar QToolButton::up-arrow:hover { - image: url(:/themes/dark/primary/uparrow2.svg); -} - -QTabBar QToolButton::down-arrow { - image: url(:/themes/dark/disabled/downarrow2.svg); -} - -QTabBar QToolButton::down-arrow:hover { - image: url(:/themes/dark/primary/downarrow2.svg); -} - -QTabBar QToolButton::right-arrow { - image: url(:/themes/dark/primary/rightarrow2.svg); -} - -QTabBar QToolButton::right-arrow:hover { - image: url(:/themes/dark/disabled/rightarrow2.svg); -} - -QTabBar QToolButton::left-arrow { - image: url(:/themes/dark/primary/leftarrow2.svg); -} - -QTabBar QToolButton::left-arrow:hover { - image: url(:/themes/dark/disabled/leftarrow2.svg); -} - -QTabBar::close-button { - image: url(:/themes/dark/disabled/tab_close.svg); -} - -QTabBar::close-button:hover { - image: url(:/themes/dark/primary/tab_close.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QGroupBox */ - -QGroupBox { - padding: 16px; - padding-top: 36px; - line-height: ; - text-transform: uppercase; - font-size: ; -} - -QGroupBox::title { - color: rgba(255, 255, 255, 0.4); - subcontrol-origin: margin; - subcontrol-position: top left; - padding: 16px; - background-color: #31363b; - background-color: transparent; - height: 36px; -} - -/* ------------------------------------------------------------------------ */ -/* QRadioButton and QCheckBox labels */ - -QRadioButton, -QCheckBox { - spacing: 12px; - color: #ffffff; - line-height: 14px; - height: 36px; - background-color: transparent; - spacing: 5px; -} - -QRadioButton:disabled, -QCheckBox:disabled { - color: rgba(255, 255, 255, 0.3); -} - -/* ------------------------------------------------------------------------ */ -/* General Indicators */ - -QGroupBox::indicator { - width: 24px; - height: 24px; - border-radius: 3px; -} - -QMenu::indicator, -QListView::indicator, -QTableWidget::indicator, -QRadioButton::indicator, -QCheckBox::indicator { - width: 28px; - height: 28px; - border-radius: 4px; - } - -/* ------------------------------------------------------------------------ */ -/* QListView Indicator */ - -QListView::indicator:checked, -QListView::indicator:checked:selected, -QListView::indicator:checked:focus { - image: url(:/themes/dark/primary/checklist.svg); -} - -QListView::indicator:checked:selected:active { - image: url(:/themes/dark/primary/checklist_invert.svg); -} - -QListView::indicator:checked:disabled { - image: url(:/themes/dark/disabled/checklist.svg); -} - -QListView::indicator:indeterminate, -QListView::indicator:indeterminate:selected, -QListView::indicator:indeterminate:focus { - image: url(:/themes/dark/primary/checklist_indeterminate.svg); -} - -QListView::indicator:indeterminate:selected:active { - image: url(:/themes/dark/primary/checklist_indeterminate_invert.svg); -} - -QListView::indicator:indeterminate:disabled { - image: url(:/themes/dark/disabled/checklist_indeterminate.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QTableView Indicator */ - -QTableView::indicator:enabled:checked, -QTableView::indicator:enabled:checked:selected, -QTableView::indicator:enabled:checked:focus { - image: url(:/themes/dark/primary/checkbox_checked.svg); -} - -QTableView::indicator:checked:selected:active { - image: url(:/themes/dark/primary/checkbox_checked_invert.svg); -} - -QTableView::indicator:disabled:checked, -QTableView::indicator:disabled:checked:selected, -QTableView::indicator:disabled:checked:focus { - image: url(:/themes/dark/disabled/checkbox_checked.svg); -} - -QTableView::indicator:enabled:unchecked, -QTableView::indicator:enabled:unchecked:selected, -QTableView::indicator:enabled:unchecked:focus { - image: url(:/themes/dark/primary/checkbox_unchecked.svg); -} - -QTableView::indicator:unchecked:selected:active { - image: url(:/themes/dark/primary/checkbox_unchecked_invert.svg); -} - -QTableView::indicator:disabled:unchecked, -QTableView::indicator:disabled:unchecked:selected, -QTableView::indicator:disabled:unchecked:focus { - image: url(:/themes/dark/disabled/checkbox_unchecked.svg); -} - -QTableView::indicator:enabled:indeterminate, -QTableView::indicator:enabled:indeterminate:selected, -QTableView::indicator:enabled:indeterminate:focus { - image: url(:/themes/dark/primary/checkbox_indeterminate.svg); -} - -QTableView::indicator:indeterminate:selected:active { - image: url(:/themes/dark/primary/checkbox_indeterminate_invert.svg); -} - -QTableView::indicator:disabled:indeterminate, -QTableView::indicator:disabled:indeterminate:selected, -QTableView::indicator:disabled:indeterminate:focus { - image: url(:/themes/dark/disabled/checkbox_indeterminate.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QCheckBox and QGroupBox Indicator */ - -QCheckBox::indicator:checked, -QGroupBox::indicator:checked { - image: url(:/themes/dark/primary/checkbox_checked.svg); -} - -QCheckBox::indicator:unchecked, -QGroupBox::indicator:unchecked { - image: url(:/themes/dark/primary/checkbox_unchecked.svg); -} - -QCheckBox::indicator:indeterminate, -QGroupBox::indicator:indeterminate { - image: url(:/themes/dark/primary/checkbox_indeterminate.svg); -} - -QCheckBox::indicator:checked:disabled, -QGroupBox::indicator:checked:disabled { - image: url(:/themes/dark/disabled/checkbox_checked.svg); -} - -QCheckBox::indicator:unchecked:disabled, -QGroupBox::indicator:unchecked:disabled { - image: url(:/themes/dark/disabled/checkbox_unchecked.svg); -} - -QCheckBox::indicator:indeterminate:disabled, -QGroupBox::indicator:indeterminate:disabled { - image: url(:/themes/dark/disabled/checkbox_indeterminate.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QRadioButton Indicator */ - -QRadioButton::indicator:checked { - image: url(:/themes/dark/primary/radiobutton_checked.svg); -} - -QRadioButton::indicator:unchecked { - image: url(:/themes/dark/primary/radiobutton_unchecked.svg); -} - -QRadioButton::indicator:checked:disabled { - image: url(:/themes/dark/disabled/radiobutton_checked.svg); -} - -QRadioButton::indicator:unchecked:disabled { - image: url(:/themes/dark/disabled/radiobutton_unchecked.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QDockWidget */ - -QDockWidget { - color: #ffffff; - text-transform: uppercase; - border: 2px solid #232629; - titlebar-close-icon: url(:/themes/dark/primary/close.svg); - titlebar-normal-icon: url(:/themes/dark/primary/float.svg); - border-radius: 4px; -} - -QDockWidget::title { - text-align: left; - padding-left: 36px; - padding: 3px; - margin-top: 4px; -} - -/* ------------------------------------------------------------------------ */ -/* QComboBox indicator */ - -QComboBox::indicator:checked { - image: url(:/themes/dark/primary/checklist.svg); -} - -QComboBox::indicator:checked:selected { - image: url(:/themes/dark/primary/checklist_invert.svg); -} - -/* ------------------------------------------------------------------------ */ -/* Menu Items */ - -QComboBox::item, -QCalendarWidget QMenu::item, -QMenu::item { - height: 28px; - width: 100px; - border: 8px solid transparent; - color: #ffffff; -} - -QComboBox::item:selected, -QCalendarWidget QMenu::item:selected, -QMenu::item:selected { - color: #000000; - background-color: #88ffff; - border-radius: 0px; -} - -QComboBox::item:disabled, -QCalendarWidget QMenu::item:disabled, -QMenu::item:disabled { - color: rgba(255, 255, 255, 0.3); -} - -/* ------------------------------------------------------------------------ */ -/* QMenu */ - -QCalendarWidget QMenu, -QMenu { - background-color: #232629; - border: 2px solid #4f5b62; - border-radius: 4px; -} - -QMenu::separator { - height: 2px; - background-color: #4f5b62; - margin-left: 2px; - margin-right: 2px; -} - -QMenu::right-arrow{ - image: url(:/themes/dark/primary/rightarrow.svg); - width: 16px; - height: 16px; -} - -QMenu::right-arrow:selected{ - image: url(:/themes/dark/disabled/rightarrow.svg); -} - -QMenu::indicator:non-exclusive:unchecked { - image: url(:/themes/dark/primary/checkbox_unchecked.svg); -} - -QMenu::indicator:non-exclusive:unchecked:selected { - image: url(:/themes/dark/primary/checkbox_unchecked_invert.svg); -} - -QMenu::indicator:non-exclusive:checked { - image: url(:/themes/dark/primary/checkbox_checked.svg); -} - -QMenu::indicator:non-exclusive:checked:selected { - image: url(:/themes/dark/primary/checkbox_checked_invert.svg); -} - -QMenu::indicator:exclusive:unchecked { - image: url(:/themes/dark/primary/radiobutton_unchecked.svg); -} - -QMenu::indicator:exclusive:unchecked:selected { - image: url(:/themes/dark/primary/radiobutton_unchecked_invert.svg); -} - -QMenu::indicator:exclusive:checked { - image: url(:/themes/dark/primary/radiobutton_checked.svg); -} - -QMenu::indicator:exclusive:checked:selected { - image: url(:/themes/dark/primary/radiobutton_checked_invert.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QMenuBar */ - -QMenuBar { - background-color: #232629; - color: #ffffff; -} - -QMenuBar::item { - height: 32px; - padding: 8px; - background-color: transparent; - color: #ffffff; -} - -QMenuBar::item:selected, -QMenuBar::item:pressed { - color: #000000; - background-color: #88ffff; -} - -/* ------------------------------------------------------------------------ */ -/* QToolBox */ - -QToolBox::tab { - background-color: #232629; - color: #ffffff; - text-transform: uppercase; - border-radius: 4px; - padding-left: 15px; -} - -QToolBox::tab:selected, -QToolBox::tab:hover { - background-color: rgba(77, 208, 225, 0.2); -} - -/* ------------------------------------------------------------------------ */ -/* QProgressBar */ - -QProgressBar { - border-radius: 0; - background-color: #4f5b62; - text-align: center; - color: transparent; -} - -QProgressBar::chunk { - background-color: #4dd0e1; -} - -/* ------------------------------------------------------------------------ */ -/* QScrollBar */ - -QScrollBar:horizontal { - border: 0; - background: #232629; - height: 8px; -} - -QScrollBar:vertical { - border: 0; - background: #232629; - width: 8px; -} - -QScrollBar::handle { - background: rgba(77, 208, 225, 0.1); -} - -QScrollBar::handle:horizontal { - min-width: 24px; -} - -QScrollBar::handle:vertical { - min-height: 24px; -} - -QScrollBar::handle:vertical:hover, -QScrollBar::handle:horizontal:hover { - background: #4dd0e1; -} - -QScrollBar::add-line:vertical, -QScrollBar::sub-line:vertical, -QScrollBar::add-line:horizontal, -QScrollBar::sub-line:horizontal { - border: 0; - background: transparent; - width: 0px; - height: 0px; -} - -/* ------------------------------------------------------------------------ */ -/* QScrollBar-Big */ - -QScrollBar.big:horizontal { - border: 0; - background: #232629; - height: 36px; -} - -QScrollBar.big:vertical { - border: 0; - background: #232629; - width: 36px; -} - -QScrollBar.big::handle, -QScrollBar.big::handle:vertical:hover, -QScrollBar.big::handle:horizontal:hover { - background: #4dd0e1; -} - -QScrollBar.big::handle:horizontal { - min-width: 24px; -} - -QScrollBar.big::handle:vertical { - min-height: 24px; -} - -QScrollBar.big::add-line:vertical, -QScrollBar.big::sub-line:vertical, -QScrollBar.big::add-line:horizontal, -QScrollBar.big::sub-line:horizontal { - border: 0; - background: transparent; - width: 0px; - height: 0px; -} - -/* ------------------------------------------------------------------------ */ -/* QSlider */ - -QSlider:horizontal { - min-height: 24px; - max-height: 24px; -} - -QSlider:vertical { - min-width: 24px; - max-width: 24px; -} - -QSlider::groove:horizontal { - height: 4px; - background: #393939; - margin: 0 12px; -} - -QSlider::groove:vertical { - width: 4px; - background: #393939; - margin: 12px 0; - border-radius: 24px; -} - -QSlider::handle:horizontal { - image: url(:/themes/dark/primary/slider.svg); - width: 24px; - height: 24px; - margin: -24px -12px; -} - -QSlider::handle:vertical { - image: url(:/themes/dark/primary/slider.svg); - border-radius: 24px; - width: 24px; - height: 24px; - margin: -12px -24px; -} - -QSlider::add-page { -background: #232629; -} - -QSlider::sub-page { -background: #4dd0e1; -} - -/* ------------------------------------------------------------------------ */ -/* QLabel */ - -QLabel { - border: none; - background: transparent; - color: #ffffff -} - -QLabel:disabled { - color: rgba(255, 255, 255, 0.2) -} - -/* ------------------------------------------------------------------------ */ -/* VLines and HLinex */ - -QFrame[frameShape="4"] { - border-width: 1px 0 0 0; - background: none; -} - -QFrame[frameShape="5"] { - border-width: 0 1px 0 0; - background: none; -} - -QFrame[frameShape="4"], -QFrame[frameShape="5"] { - border-color: #4f5b62; -} - -/* ------------------------------------------------------------------------ */ -/* QToolBar */ - -QToolBar { - background: #31363b; - border: 0px solid; -} - -QToolBar:horizontal { - border-bottom: 1px solid #4f5b62; -} - -QToolBar:vertical { - border-right: 1px solid #4f5b62; -} - -QToolBar::handle:horizontal { - image: url(:/themes/dark/primary/toolbar-handle-horizontal.svg); -} - -QToolBar::handle:vertical { - image: url(:/themes/dark/primary/toolbar-handle-vertical.svg); -} - -QToolBar::separator:horizontal { - border-right: 1px solid #4f5b62; - border-left: 1px solid #4f5b62; - width: 1px; -} - -QToolBar::separator:vertical { - border-top: 1px solid #4f5b62; - border-bottom: 1px solid #4f5b62; - height: 1px; -} - - -/* ------------------------------------------------------------------------ */ -/* QToolButton */ - -QToolButton { - background: #31363b; - border: 0px; - height: 36px; - margin: 3px; - padding: 3px; - border-right: 12px solid #31363b; - border-left: 12px solid #31363b; -} - -QToolButton:hover { - background: #4f5b62; - border-right: 12px solid #4f5b62; - border-left: 12px solid #4f5b62; -} - -QToolButton:pressed { - background: #232629; - border-right: 12px solid #232629; - border-left: 12px solid #232629; -} - -QToolButton:checked { - background: #4f5b62; - border-left: 12px solid #4f5b62; - border-right: 12px solid #4dd0e1; -} - -/* ------------------------------------------------------------------------ */ -/* General viewers */ - -QTableView { - background-color: #31363b; - border: 1px solid #232629; - border-radius: 4px; -} - -QTreeView, -QListView { - border-radius: 4px; - padding: 4px; - margin: 0px; - border: 0px; -} - -QTableView::item, -QTreeView::item, -QListView::item { - padding: 4px; - min-height: 32px; - color: #ffffff; - selection-color: #ffffff; /* For Windows */ - border-color: transparent; /* Fix #34 */ -} - -/* ------------------------------------------------------------------------ */ -/* Items Selection */ - -QTableView::item:selected, -QTreeView::item:selected, -QListView::item:selected { - background-color: rgba(77, 208, 225, 0.2); - selection-background-color: rgba(77, 208, 225, 0.2); - color: #ffffff; - selection-color: #ffffff; /* For Windows */ -} - -QTableView::item:selected:focus, -QTreeView::item:selected:focus, -QListView::item:selected:focus { - background-color: #4dd0e1; - selection-background-color: #4dd0e1; - color: #000000; - selection-color: #000000; /* For Windows */ -} - -QTableView { - selection-background-color: rgba(77, 208, 225, 0.2); -} - -QTableView:focus { - selection-background-color: #4dd0e1; -} - -QTableView::item:disabled { - color: rgba(255, 255, 255, 0.3); - selection-color: rgba(255, 255, 255, 0.3); - background-color: #232629; - selection-background-color: #232629; -} - -/* ------------------------------------------------------------------------ */ -/* QTreeView */ - -QTreeView::branch{ - background-color: #232629; -} - -QTreeView::branch:closed:has-children:has-siblings, -QTreeView::branch:closed:has-children:!has-siblings { - image: url(:/themes/dark/primary/branch-closed.svg); -} - -QTreeView::branch:open:has-children:!has-siblings, -QTreeView::branch:open:has-children:has-siblings { - image: url(:/themes/dark/primary/branch-open.svg); -} - -QTreeView::branch:has-siblings:!adjoins-item { - border-image: url(:/themes/dark/disabled/vline.svg) 0; -} - -QTreeView::branch:has-siblings:adjoins-item { - border-image: url(:/themes/dark/disabled/branch-more.svg) 0; -} - -QTreeView::branch:!has-children:!has-siblings:adjoins-item, -QTreeView::branch:has-children:!has-siblings:adjoins-item { - border-image: url(:/themes/dark/disabled/branch-end.svg) 0; -} - -QTreeView QHeaderView::section { - border: none; -} - - -/* ------------------------------------------------------------------------ */ -/* Custom buttons */ - -QPushButton.danger { - border-color: #dc3545; - color: #dc3545; -} - -QPushButton.danger:checked, -QPushButton.danger:pressed { - color: #31363b; - background-color: #dc3545; -} - -QPushButton.warning{ - border-color: #ffc107; - color: #ffc107; -} - -QPushButton.warning:checked, -QPushButton.warning:pressed { - color: #31363b; - background-color: #ffc107; -} - -QPushButton.success { - border-color: #17a2b8; - color: #17a2b8; -} - -QPushButton.success:checked, -QPushButton.success:pressed { - color: #31363b; - background-color: #17a2b8; -} - -QPushButton.danger:flat:hover { - background-color: rgba(220, 53, 69, 0.2); -} - -QPushButton.danger:flat:pressed, -QPushButton.danger:flat:checked { - background-color: rgba(220, 53, 69, 0.1); - color: #dc3545; -} - -QPushButton.warning:flat:hover { - background-color: rgba(255, 193, 7, 0.2); -} - -QPushButton.warning:flat:pressed, -QPushButton.warning:flat:checked { - background-color: rgba(255, 193, 7, 0.1); - color: #ffc107; -} - -QPushButton.success:flat:hover { - background-color: rgba(23, 162, 184, 0.2); -} - -QPushButton.success:flat:pressed, -QPushButton.success:flat:checked { - background-color: rgba(23, 162, 184, 0.1); - color: #17a2b8; -} - -/* ------------------------------------------------------------------------ */ -/* QTableView */ - -QTableCornerButton::section { - background-color: #232629; - border-radius: 0px; - border-right: 1px solid; - border-bottom: 1px solid; - border-color: #31363b; -} - -QTableView { - alternate-background-color: rgba(35, 38, 41, 0.7); -} - -QHeaderView { - border: none; -} - -QHeaderView::section { - color: rgba(255, 255, 255, 0.7); - text-transform: uppercase; - background-color: #232629; - padding: 0 24px; - height: 36px; - border-radius: 0px; - border-right: 1px solid; - border-bottom: 1px solid; - border-color: #31363b; -} - -QHeaderView::section:vertical { - -} - -QHeaderView::section:horizontal { - -} - -/* ------------------------------------------------------------------------ */ -/* QLCDNumber */ - -QLCDNumber { - color: #4dd0e1; - background-color:rgba(77, 208, 225, 0.1); - border: 1px solid rgba(77, 208, 225, 0.3); - border-radius: 4px; -} - -/* ------------------------------------------------------------------------ */ -/* QCalendarWidget */ - -#qt_calendar_prevmonth { - qproperty-icon: url(:/themes/dark/primary/leftarrow.svg); -} - -#qt_calendar_nextmonth { - qproperty-icon: url(:/themes/dark/primary/rightarrow.svg); -} - -/* ------------------------------------------------------------------------ */ -/* Inline QLineEdit */ - -QTreeView QLineEdit, -QTableView QLineEdit, -QListView QLineEdit { - color: #ffffff; - background-color: #232629; - border: 1px solid unset; - border-radius: unset; - padding: unset; - padding-left: unset; - height: unset; - border-width: unset; - border-top-left-radius: unset; - border-top-right-radius: unset; -} - -/* ------------------------------------------------------------------------ */ -/* QToolTip */ - -QToolTip { - padding: 4px; - border: 1px solid #31363b; - border-radius: 0px; - color: #ffffff; - background-color: #4f5b62; -} - -/* ------------------------------------------------------------------------ */ -/* QDialog */ - - - /* linux */ - QDialog QToolButton, - QDialog QToolButton:hover, - QDialog QToolButton:pressed, - QDialog QToolButton:checked { - border: 0px; - height: unset; - margin: unset; - padding: unset; - border-right: unset; - border-left: unset; - background-color: #4dd0e1; - color: #ffffff; - border-radius: 4px; - } - - -QDialog QToolButton:disabled { - background-color: #232629; - color: #ffffff -} - -/* ------------------------------------------------------------------------ */ -/* Grips */ - - -QMainWindow::separator:vertical, -QSplitter::handle:horizontal { - image: url(:/themes/dark/primary/splitter-horizontal.svg); -} - -QMainWindow::separator:horizontal, -QSplitter::handle:vertical { - image: url(:/themes/dark/primary/splitter-vertical.svg); -} - -QSizeGrip { - image: url(:/themes/dark/primary/sizegrip.svg); - background-color: transparent; -} - -QMenuBar QToolButton:hover, -QMenuBar QToolButton:pressed, -QMenuBar QToolButton { - border-width: 0; - border-left: 10px; - border-image: url(:/themes/dark/primary/rightarrow2.svg); - background-color: transparent; -} \ No newline at end of file diff --git a/styles/dark/optionsmenu.qss b/styles/dark/optionsmenu.qss deleted file mode 100644 index 9c53fb0..0000000 --- a/styles/dark/optionsmenu.qss +++ /dev/null @@ -1,30 +0,0 @@ -QLineEdit { - font-family: "Roboto Mono" -} - -QPushButton#reset_button, -QPushButton#change_password_button { - border-color: #dc3545; - color: #dc3545; -} - -QPushButton:checked#reset_button, -QPushButton:pressed#reset_button, -QPushButton:checked#change_password_button, -QPushButton:pressed#change_password_button { - color: #31363b; - background-color: #dc3545; -} - -QPushButton:flat:hover#reset_button, -QPushButton:flat:hover#change_password_button { - background-color: rgba(220, 53, 69, 0.2); -} - -QPushButton:flat:pressed#reset_button, -QPushButton:flat:checked#reset_button, -QPushButton:flat:pressed#change_password_button, -QPushButton:flat:checked#change_password_button { - background-color: rgba(220, 53, 69, 0.1); - color: #dc3545; -} diff --git a/styles/dark/theoretical_calendar/0.qss b/styles/dark/theoretical_calendar/0.qss deleted file mode 100644 index b7d62cc..0000000 --- a/styles/dark/theoretical_calendar/0.qss +++ /dev/null @@ -1,7 +0,0 @@ -CalendarButton { - background-color: rgba(84, 110, 122, 0.2); -} - -CalendarButton:pressed { - background-color: rgba(84, 110, 122, 0.1); -} \ No newline at end of file diff --git a/styles/dark/theoretical_calendar/1.qss b/styles/dark/theoretical_calendar/1.qss deleted file mode 100644 index df82630..0000000 --- a/styles/dark/theoretical_calendar/1.qss +++ /dev/null @@ -1,11 +0,0 @@ -CalendarButton { - color: #f5f5f5; - background-color: rgba(123, 31, 162, 1); - border: 2px solid transparent; -} - -CalendarButton:pressed { - color: #f5f5f5; - background-color: rgba(123, 31, 162, 0.7); - border: 2px solid transparent; -} diff --git a/styles/dark/theoretical_calendar/2.qss b/styles/dark/theoretical_calendar/2.qss deleted file mode 100644 index f28b3ea..0000000 --- a/styles/dark/theoretical_calendar/2.qss +++ /dev/null @@ -1,11 +0,0 @@ -CalendarButton { - color: #f5f5f5; - background-color: rgba(94, 53, 177, 1); - border: 2px solid transparent; -} - -CalendarButton:pressed { - color: #f5f5f5; - background-color: rgba(94, 53, 177, 0.7); - border: 2px solid transparent; -} diff --git a/styles/dark/theoretical_calendar/3.qss b/styles/dark/theoretical_calendar/3.qss deleted file mode 100644 index 279226f..0000000 --- a/styles/dark/theoretical_calendar/3.qss +++ /dev/null @@ -1,11 +0,0 @@ -CalendarButton { - color: #f5f5f5; - background-color: rgba(25, 118, 210, 1); - border: 2px solid transparent; -} - -CalendarButton:pressed { - color: #f5f5f5; - background-color: rgba(25, 118, 210, 0.7); - border: 2px solid transparent; -} diff --git a/styles/dark/theoretical_calendar/4.qss b/styles/dark/theoretical_calendar/4.qss deleted file mode 100644 index bb17e4b..0000000 --- a/styles/dark/theoretical_calendar/4.qss +++ /dev/null @@ -1,11 +0,0 @@ -CalendarButton { - color: #3c3c3c; - background-color: rgba(0, 151, 167, 1); - border: 2px solid transparent; -} - -CalendarButton:pressed { - color: #3c3c3c; - background-color: rgba(0, 151, 167, 0.7); - border: 2px solid transparent; -} diff --git a/styles/dark/theoretical_calendar/5.qss b/styles/dark/theoretical_calendar/5.qss deleted file mode 100644 index 65fa219..0000000 --- a/styles/dark/theoretical_calendar/5.qss +++ /dev/null @@ -1,11 +0,0 @@ -CalendarButton { - color: #3c3c3c; - background-color: rgba(76, 175, 80, 1); - border: 2px solid transparent; -} - -CalendarButton:pressed { - color: #3c3c3c; - background-color: rgba(76, 175, 80, 0.7); - border: 2px solid transparent; -} diff --git a/styles/dark/theoretical_calendar/base.qss b/styles/dark/theoretical_calendar/base.qss deleted file mode 100644 index b1cf239..0000000 --- a/styles/dark/theoretical_calendar/base.qss +++ /dev/null @@ -1,23 +0,0 @@ -CalendarButton { - color: #FFFFFF; - border: 2px solid #232629; - text-transform: uppercase; - margin: 0px; - width: 60px; - height: 60px; - font-weight: bold; - text-align: top right; - padding: 5px 5px; -} - -CalendarButton:pressed { - color: #FFFFFF; - border: 2px solid #232629; - text-transform: uppercase; - margin: 0px; - width: 60px; - height: 60px; - font-weight: bold; - text-align: top right; - padding: 5px 5px; -} diff --git a/styles/dark/theoretical_calendar/selected.qss b/styles/dark/theoretical_calendar/selected.qss deleted file mode 100644 index cfabc52..0000000 --- a/styles/dark/theoretical_calendar/selected.qss +++ /dev/null @@ -1,7 +0,0 @@ -CalendarButton { - border: 2px solid #FFFFFF; -} - -CalendarButton:pressed { - border: 2px solid #FFFFFF; -} \ No newline at end of file diff --git a/styles/global/aboutdialog.qss b/styles/global/aboutdialog.qss deleted file mode 100644 index 54fc02f..0000000 --- a/styles/global/aboutdialog.qss +++ /dev/null @@ -1,3 +0,0 @@ -QFrame#frame1, QFrame#frame2 { - border: none; -} diff --git a/styles/global/alertlabel.qss b/styles/global/alertlabel.qss deleted file mode 100644 index 30aebc7..0000000 --- a/styles/global/alertlabel.qss +++ /dev/null @@ -1,3 +0,0 @@ -AlertLabel { - color: #ff0000; -} diff --git a/styles/global/apiresponse.qss b/styles/global/apiresponse.qss deleted file mode 100644 index 432aa18..0000000 --- a/styles/global/apiresponse.qss +++ /dev/null @@ -1,3 +0,0 @@ -QPlainTextEdit { - font-family: "Roboto Mono"; -} diff --git a/styles/global/black_star.qss b/styles/global/black_star.qss deleted file mode 100644 index 8f45103..0000000 --- a/styles/global/black_star.qss +++ /dev/null @@ -1,5 +0,0 @@ -CalendarButton, CalendarButton:pressed, DiaryEntryDayLabel { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/global/star_black.svg); -} diff --git a/styles/global/diarymenu.qss b/styles/global/diarymenu.qss deleted file mode 100644 index 875e50b..0000000 --- a/styles/global/diarymenu.qss +++ /dev/null @@ -1,3 +0,0 @@ -QTabWidget::tab-bar { - alignment: center; -} diff --git a/styles/global/diarypixels.qss b/styles/global/diarypixels.qss deleted file mode 100644 index 9386972..0000000 --- a/styles/global/diarypixels.qss +++ /dev/null @@ -1,4 +0,0 @@ -QFrame#hidden_frame { - border: none; - border-radius: 0px; -} diff --git a/styles/global/diarystats.qss b/styles/global/diarystats.qss deleted file mode 100644 index 1ba8997..0000000 --- a/styles/global/diarystats.qss +++ /dev/null @@ -1,6 +0,0 @@ -QLabel#t0, QLabel#t1, QLabel#t2, QLabel#t3, QLabel#t4, QLabel#t5, QLabel#ts, -QLabel#l0, QLabel#l1, QLabel#l2, QLabel#l3, QLabel#l4, QLabel#l5, QLabel#ls, -QLabel#d0, QLabel#d1, QLabel#d2, QLabel#d3, QLabel#d4, QLabel#d5, QLabel#ds { - font-family: "Roboto Mono"; - font-size: 11pt; -} diff --git a/styles/global/licensesdialog.qss b/styles/global/licensesdialog.qss deleted file mode 100644 index 858f863..0000000 --- a/styles/global/licensesdialog.qss +++ /dev/null @@ -1,3 +0,0 @@ -QPlainTextEdit#licenses { - font-family: "Roboto Mono"; -} diff --git a/styles/global/mainmenu.qss b/styles/global/mainmenu.qss deleted file mode 100644 index ca426c7..0000000 --- a/styles/global/mainmenu.qss +++ /dev/null @@ -1,7 +0,0 @@ -QLineEdit#password_box { - font-family: "Roboto Mono" -} - -QFrame#frame3, QFrame#frame1 { - border: none; -} diff --git a/styles/global/pixels/0.qss b/styles/global/pixels/0.qss deleted file mode 100644 index fe6e063..0000000 --- a/styles/global/pixels/0.qss +++ /dev/null @@ -1,5 +0,0 @@ -PixelLabel { - background-color: rgba(84, 110, 122, 0.2); - border: none; - border-radius: 2px; -} diff --git a/styles/global/pixels/1.qss b/styles/global/pixels/1.qss deleted file mode 100644 index de46b40..0000000 --- a/styles/global/pixels/1.qss +++ /dev/null @@ -1,5 +0,0 @@ -PixelLabel { - background-color: rgba(123, 31, 162, 1); - border: none; - border-radius: 2px; -} \ No newline at end of file diff --git a/styles/global/pixels/2.qss b/styles/global/pixels/2.qss deleted file mode 100644 index a405768..0000000 --- a/styles/global/pixels/2.qss +++ /dev/null @@ -1,5 +0,0 @@ -PixelLabel { - background-color: rgba(94, 53, 177, 1); - border: none; - border-radius: 2px; -} \ No newline at end of file diff --git a/styles/global/pixels/3.qss b/styles/global/pixels/3.qss deleted file mode 100644 index e1467a2..0000000 --- a/styles/global/pixels/3.qss +++ /dev/null @@ -1,5 +0,0 @@ -PixelLabel { - background-color: rgba(25, 118, 210, 1); - border: none; - border-radius: 2px; -} \ No newline at end of file diff --git a/styles/global/pixels/4.qss b/styles/global/pixels/4.qss deleted file mode 100644 index f36710d..0000000 --- a/styles/global/pixels/4.qss +++ /dev/null @@ -1,5 +0,0 @@ -PixelLabel { - background-color: rgba(0, 151, 167, 1); - border: none; - border-radius: 2px; -} \ No newline at end of file diff --git a/styles/global/pixels/5.qss b/styles/global/pixels/5.qss deleted file mode 100644 index 48ad0bb..0000000 --- a/styles/global/pixels/5.qss +++ /dev/null @@ -1,5 +0,0 @@ -PixelLabel { - background-color: rgba(76, 175, 80, 1); - border: none; - border-radius: 2px; -} \ No newline at end of file diff --git a/styles/global/small_black_star.qss b/styles/global/small_black_star.qss deleted file mode 100644 index 37da1a8..0000000 --- a/styles/global/small_black_star.qss +++ /dev/null @@ -1,5 +0,0 @@ -PixelLabel { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/global/small_star_black.svg); -} diff --git a/styles/global/small_white_star.qss b/styles/global/small_white_star.qss deleted file mode 100644 index 2550904..0000000 --- a/styles/global/small_white_star.qss +++ /dev/null @@ -1,5 +0,0 @@ -PixelLabel { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/global/small_star_white.svg); -} diff --git a/styles/global/standaloneoptions.qss b/styles/global/standaloneoptions.qss deleted file mode 100644 index 6d76053..0000000 --- a/styles/global/standaloneoptions.qss +++ /dev/null @@ -1,4 +0,0 @@ -QFrame#settings_frame { - padding: 0px; - border: none; -} diff --git a/styles/global/white_star.qss b/styles/global/white_star.qss deleted file mode 100644 index 7fa57f9..0000000 --- a/styles/global/white_star.qss +++ /dev/null @@ -1,5 +0,0 @@ -CalendarButton, CalendarButton:pressed, DiaryEntryDayLabel { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/global/star_white.svg); -} diff --git a/styles/light/dangerbutton.qss b/styles/light/dangerbutton.qss deleted file mode 100644 index f8c2c60..0000000 --- a/styles/light/dangerbutton.qss +++ /dev/null @@ -1,20 +0,0 @@ -QPushButton { - border-color: #dc3545; - color: #dc3545; -} - -QPushButton:checked, -QPushButton:pressed { - color: #e6e6e6; - background-color: #dc3545; -} - -QPushButton:flat:hover { - background-color: rgba(220, 53, 69, 0.2); -} - -QPushButton:flat:pressed, -QPushButton:flat:checked { - background-color: rgba(220, 53, 69, 0.1); - color: #dc3545; -} \ No newline at end of file diff --git a/styles/light/diary_entry_list/0.qss b/styles/light/diary_entry_list/0.qss deleted file mode 100644 index 3820389..0000000 --- a/styles/light/diary_entry_list/0.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #f5f5f5; - background-color: rgba(84, 110, 122, 0.2); -} diff --git a/styles/light/diary_entry_list/1.qss b/styles/light/diary_entry_list/1.qss deleted file mode 100644 index 910ff1b..0000000 --- a/styles/light/diary_entry_list/1.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #f5f5f5; - background-color: rgba(123, 31, 162, 1); -} diff --git a/styles/light/diary_entry_list/2.qss b/styles/light/diary_entry_list/2.qss deleted file mode 100644 index 36cbe51..0000000 --- a/styles/light/diary_entry_list/2.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #f5f5f5; - background-color: rgba(94, 53, 177, 1); -} diff --git a/styles/light/diary_entry_list/3.qss b/styles/light/diary_entry_list/3.qss deleted file mode 100644 index 7a89acc..0000000 --- a/styles/light/diary_entry_list/3.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #f5f5f5; - background-color: rgba(25, 118, 210, 1); -} diff --git a/styles/light/diary_entry_list/4.qss b/styles/light/diary_entry_list/4.qss deleted file mode 100644 index 245f5ee..0000000 --- a/styles/light/diary_entry_list/4.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #3c3c3c; - background-color: rgba(0, 151, 167, 1); -} diff --git a/styles/light/diary_entry_list/5.qss b/styles/light/diary_entry_list/5.qss deleted file mode 100644 index 255799a..0000000 --- a/styles/light/diary_entry_list/5.qss +++ /dev/null @@ -1,4 +0,0 @@ -QLabel { - color: #3c3c3c; - background-color: rgba(76, 175, 80, 1); -} diff --git a/styles/light/diary_entry_list/base.qss b/styles/light/diary_entry_list/base.qss deleted file mode 100644 index f3c92c1..0000000 --- a/styles/light/diary_entry_list/base.qss +++ /dev/null @@ -1,11 +0,0 @@ -DiaryEntryDayLabel { - border: transparent; - border-radius: 25px; -} - -DiaryEntryDayMessage { - border: transparent; - border-radius: 4px; - background-color: #f5f5f5; - padding: 15px; -} diff --git a/styles/light/diaryeditor.qss b/styles/light/diaryeditor.qss deleted file mode 100644 index ffd6a84..0000000 --- a/styles/light/diaryeditor.qss +++ /dev/null @@ -1,23 +0,0 @@ -QPlainTextEdit#entry_edit { - background-color: #f5f5f5; - border: 2px solid #00bcd4; - border-radius: 4px; - padding: 8px; - height: 18px; -} - -QPushButton#next_month, QPushButton#prev_month { - text-align: center; -} - -QPushButton#prev_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/light/primary/leftarrow.svg); -} - -QPushButton#next_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/light/primary/rightarrow.svg); -} diff --git a/styles/light/diaryentryviewer.qss b/styles/light/diaryentryviewer.qss deleted file mode 100644 index d35d7fb..0000000 --- a/styles/light/diaryentryviewer.qss +++ /dev/null @@ -1,11 +0,0 @@ -QPushButton#prev_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/light/primary/leftarrow.svg); -} - -QPushButton#next_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/light/primary/rightarrow.svg); -} diff --git a/styles/light/diarystats.qss b/styles/light/diarystats.qss deleted file mode 100644 index 2a62416..0000000 --- a/styles/light/diarystats.qss +++ /dev/null @@ -1,67 +0,0 @@ -QPushButton#prev_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/light/primary/leftarrow.svg); -} - -QPushButton#next_month { - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/light/primary/rightarrow.svg); -} - -QLabel#very_bad, QLabel#very_bad_2, QLabel#very_bad_3 { - background-color: rgba(123, 31, 162, 1); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#bad, QLabel#bad_2, QLabel#bad_3 { - background-color: rgba(94, 53, 177, 1); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#ok, QLabel#ok_2, QLabel#ok_3 { - background-color: rgba(25, 118, 210, 1); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#good, QLabel#good_2, QLabel#good_3 { - background-color: rgba(0, 151, 167, 1); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#very_good, QLabel#very_good_2, QLabel#very_good_3 { - background-color: rgba(76, 175, 80, 1); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#unknown, QLabel#unknown_2, QLabel#unknown_3 { - background-color: rgba(84, 110, 122, 0.2); - min-width: 48px; - min-height: 48px; - border: none; - border-radius: 2px; -} - -QLabel#starred, QLabel#starred_2, QLabel#starred_3 { - min-width: 48px; - min-height: 48px; - background-position: center; - background-repeat: no-repeat; - background-image: url(:/themes/global/star_black.svg); -} diff --git a/styles/light/lightstyle.qss b/styles/light/lightstyle.qss new file mode 100644 index 0000000..5a8fe64 --- /dev/null +++ b/styles/light/lightstyle.qss @@ -0,0 +1,23 @@ +DatabaseWidget:!active, GroupView:!active, +EntryPreviewWidget QLineEdit:!active, EntryPreviewWidget QTextEdit:!active { + background-color: #FCFCFC; +} + +DatabaseWidget:disabled, GroupView:disabled, +EntryPreviewWidget QLineEdit:disabled, EntryPreviewWidget QTextEdit:disabled { + background-color: #EDEDED; +} + +QPushButton:default:hover, QPushButton:checked:hover { + /* Using slightly lighter shade from palette(highlight) */ + background: #568821; +} + +QToolTip { + color: #F9F9F9; + background-color: #4D7F1A; +} + +QGroupBox::title { + color: #4B7B19; +} diff --git a/styles/light/material_cyan.qss b/styles/light/material_cyan.qss deleted file mode 100644 index e10ab5b..0000000 --- a/styles/light/material_cyan.qss +++ /dev/null @@ -1,1305 +0,0 @@ -/* ------------------------------------------------------------------------ */ -/* QtMaterial - https://github.com/UN-GCPDS/qt-material -/* By Yeison Cardona - GCPDS -/* ------------------------------------------------------------------------ */ - -*{ - color: #555555; - font-family: "Roboto"; - selection-background-color: #62efff; - selection-color: #3c3c3c; -} - -*:focus { - outline: none; -} - -/* ------------------------------------------------------------------------ */ -/* Custom colors */ - -.danger{ - color: #dc3545; - background-color: transparent; -} - -.warning{ - color: #ffc107; - background-color: transparent; -} - -.success{ - color: #17a2b8; - background-color: transparent; -} - -.danger:disabled{ - color: rgba(220, 53, 69, 0.4); - border-color: rgba(220, 53, 69, 0.4); -} - -.warning:disabled{ - color: rgba(255, 193, 7, 0.4); - border-color: rgba(255, 193, 7, 0.4); -} - -.success:disabled{ - color: rgba(23, 162, 184, 0.4); - border-color: rgba(23, 162, 184, 0.4); -} - -.danger:flat:disabled{ - background-color: rgba(220, 53, 69, 0.1); -} - -.warning:flat:disabled{ - background-color: rgba(255, 193, 7, 0.1); -} - -.success:flat:disabled{ - background-color: rgba(23, 162, 184, 0.1); -} - -/* ------------------------------------------------------------------------ */ -/* Basic widgets */ - -QWidget { - background-color: #e6e6e6; -} - -QGroupBox, -QFrame { - background-color: #e6e6e6; - border: 2px solid #ffffff; - border-radius: 4px; -} - -QGroupBox.fill_background, -QFrame.fill_background { - background-color: #f5f5f5; - border: 2px solid #f5f5f5; - border-radius: 4px; -} - -QSplitter { - background-color: transparent; - border: none -} - -QStatusBar { - color: #555555; - background-color: rgba(255, 255, 255, 0.2); - border-radius: 0px; -} - -QScrollArea, -QStackedWidget, -QWidget > QToolBox, -QToolBox > QWidget, -QTabWidget > QWidget { - border: none; -} - -QTabWidget::pane { - border: none; -} - -/* ------------------------------------------------------------------------ */ -/* Inputs */ - -QDateTimeEdit, -QSpinBox, -QDoubleSpinBox, -QTextEdit, -QLineEdit, -QPushButton { - color: #00bcd4; - background-color: #e6e6e6; - border: 2px solid #00bcd4; - border-radius: 4px; - height: 32px; -} - -QDateTimeEdit, -QSpinBox, -QDoubleSpinBox, -QTreeView, -QListView, -QLineEdit, -QComboBox { - padding-left: 16px; - border-radius: 0px; - background-color: #f5f5f5; - border-width: 0 0 2px 0; - border-radius: 0px; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - height: 32px; -} - -QPlainTextEdit { - border-radius: 4px; - padding: 8px 16px; - background-color: #e6e6e6; - border: 2px solid #ffffff; -} - -QTextEdit { - padding: 8px 16px; - border-radius: 4px; - background-color: #f5f5f5; -} - -QDateTimeEdit:disabled, -QSpinBox:disabled, -QDoubleSpinBox:disabled, -QTextEdit:disabled, -QLineEdit:disabled { - color: rgba(0, 188, 212, 0.2); - background-color: rgba(245, 245, 245, 0.75); - border: 2px solid rgba(0, 188, 212, 0.2); - border-width: 0 0 2px 0; - padding: 0px 16px; - border-radius: 0px; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - height: 32px; -} - -/* ------------------------------------------------------------------------ */ -/* QComboBox */ - -QComboBox { - color: #00bcd4; - border: 1px solid #00bcd4; - border-width: 0 0 2px 0; - background-color: #f5f5f5; - border-radius: 0px; - border-top-left-radius: 4px; - border-top-right-radius: 4px; - height: 36px; -} - -QComboBox:disabled { - color: rgba(0, 188, 212, 0.2); - background-color: rgba(245, 245, 245, 0.75); - border-bottom: 2px solid rgba(0, 188, 212, 0.2); -} - -QComboBox::drop-down { - border: none; - color: #00bcd4; - width: 20px; -} - -QComboBox::down-arrow { - image: url(:/themes/light/primary/downarrow.svg); - margin-right: 12px; -} - -QComboBox::down-arrow:disabled { - image: url(:/themes/light/disabled/downarrow.svg); - margin-right: 12px; -} - -QComboBox QAbstractItemView { - background-color: #f5f5f5; - border: 2px solid #ffffff; - border-radius: 0px; -} - -QComboBox[frame='false'] { - color: #00bcd4; - background-color: transparent; - border: 1px solid transparent; -} -QComboBox[frame='false']:disabled { - color: rgba(0, 188, 212, 0.2); -} - -/* ------------------------------------------------------------------------ */ -/* Spin buttons */ - -QDateTimeEdit::up-button, -QDoubleSpinBox::up-button, -QSpinBox::up-button { - subcontrol-origin: border; - subcontrol-position: top right; - width: 20px; - image: url(:/themes/light/primary/uparrow.svg); - border-width: 0px; - margin-right: 5px; -} - -QDateTimeEdit::up-button:disabled, -QDoubleSpinBox::up-button:disabled, -QSpinBox::up-button:disabled { - image: url(:/themes/light/disabled/uparrow.svg); -} - -QDateTimeEdit::down-button, -QDoubleSpinBox::down-button, -QSpinBox::down-button { - subcontrol-origin: border; - subcontrol-position: bottom right; - width: 20px; - image: url(:/themes/light/primary/downarrow.svg); - border-width: 0px; - border-top-width: 0; - margin-right: 5px; -} - -QDateTimeEdit::down-button:disabled, -QDoubleSpinBox::down-button:disabled, -QSpinBox::down-button:disabled { - image: url(:/themes/light/disabled/downarrow.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QPushButton */ - -QPushButton { - text-transform: uppercase; - margin: 0px; - padding: 0px 16px; - height: 32px; - font-weight: bold; - - - border-radius: 4px; - - - -} - -QPushButton:checked, -QPushButton:pressed { - color: #e6e6e6; - background-color: #00bcd4; -} - -QPushButton:flat { - margin: 0px; - color: #00bcd4; - border: none; - background-color: transparent; -} - -QPushButton:flat:hover { - background-color: rgba(0, 188, 212, 0.2); -} - -QPushButton:flat:pressed, -QPushButton:flat:checked { - background-color: rgba(0, 188, 212, 0.1); -} - -QPushButton:disabled { - color: rgba(255, 255, 255, 0.75); - background-color: transparent; - border-color: #ffffff; -} - -QPushButton:flat:disabled { - color: rgba(255, 255, 255, 0.75); - background-color: rgba(255, 255, 255, 0.25); - border: none; -} - -QPushButton:disabled { - border: 2px solid rgba(255, 255, 255, 0.75); -} - -QPushButton:checked:disabled { - color: #f5f5f5; - background-color: #ffffff; - border-color: #ffffff; -} - -/* ------------------------------------------------------------------------ */ -/* QTabBar */ - -QTabBar{ - text-transform: uppercase; - font-weight: bold; -} - -QTabBar::tab { - color: #555555; - border: 0px; -} - -QTabBar::tab:bottom, -QTabBar::tab:top{ - padding: 0 16px; - height: 28px; -} - -QTabBar::tab:left, -QTabBar::tab:right{ - padding: 16px 0; - width: 28px; -} - -QTabBar::tab:top:selected, -QTabBar::tab:top:hover { - color: #00bcd4; - border-bottom: 2px solid #00bcd4; -} - -QTabBar::tab:bottom:selected, -QTabBar::tab:bottom:hover { - color: #00bcd4; - border-top: 2px solid #00bcd4; -} - -QTabBar::tab:right:selected, -QTabBar::tab:right:hover { - color: #00bcd4; - border-left: 2px solid #00bcd4; -} - -QTabBar::tab:left:selected, -QTabBar::tab:left:hover { - color: #00bcd4; - border-right: 2px solid #00bcd4; -} - -QTabBar QToolButton:hover, -QTabBar QToolButton { - border: 20px; - background-color: #e6e6e6; -} - -QTabBar QToolButton::up-arrow { - image: url(:/themes/light/disabled/uparrow2.svg); -} - -QTabBar QToolButton::up-arrow:hover { - image: url(:/themes/light/primary/uparrow2.svg); -} - -QTabBar QToolButton::down-arrow { - image: url(:/themes/light/disabled/downarrow2.svg); -} - -QTabBar QToolButton::down-arrow:hover { - image: url(:/themes/light/primary/downarrow2.svg); -} - -QTabBar QToolButton::right-arrow { - image: url(:/themes/light/primary/rightarrow2.svg); -} - -QTabBar QToolButton::right-arrow:hover { - image: url(:/themes/light/disabled/rightarrow2.svg); -} - -QTabBar QToolButton::left-arrow { - image: url(:/themes/light/primary/leftarrow2.svg); -} - -QTabBar QToolButton::left-arrow:hover { - image: url(:/themes/light/disabled/leftarrow2.svg); -} - -QTabBar::close-button { - image: url(:/themes/light/disabled/tab_close.svg); -} - -QTabBar::close-button:hover { - image: url(:/themes/light/primary/tab_close.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QGroupBox */ - -QGroupBox { - padding: 16px; - padding-top: 36px; - line-height: ; - text-transform: uppercase; - font-size: ; -} - -QGroupBox::title { - color: rgba(85, 85, 85, 0.4); - subcontrol-origin: margin; - subcontrol-position: top left; - padding: 16px; - background-color: #e6e6e6; - background-color: transparent; - height: 36px; -} - -/* ------------------------------------------------------------------------ */ -/* QRadioButton and QCheckBox labels */ - -QRadioButton, -QCheckBox { - spacing: 12px; - color: #555555; - line-height: 14px; - height: 36px; - background-color: transparent; - spacing: 5px; -} - -QRadioButton:disabled, -QCheckBox:disabled { - color: rgba(85, 85, 85, 0.3); -} - -/* ------------------------------------------------------------------------ */ -/* General Indicators */ - -QGroupBox::indicator { - width: 24px; - height: 24px; - border-radius: 3px; -} - -QMenu::indicator, -QListView::indicator, -QTableWidget::indicator, -QRadioButton::indicator, -QCheckBox::indicator { - width: 28px; - height: 28px; - border-radius: 4px; - } - -/* ------------------------------------------------------------------------ */ -/* QListView Indicator */ - -QListView::indicator:checked, -QListView::indicator:checked:selected, -QListView::indicator:checked:focus { - image: url(:/themes/light/primary/checklist.svg); -} - -QListView::indicator:checked:selected:active { - image: url(:/themes/light/primary/checklist_invert.svg); -} - -QListView::indicator:checked:disabled { - image: url(:/themes/light/disabled/checklist.svg); -} - -QListView::indicator:indeterminate, -QListView::indicator:indeterminate:selected, -QListView::indicator:indeterminate:focus { - image: url(:/themes/light/primary/checklist_indeterminate.svg); -} - -QListView::indicator:indeterminate:selected:active { - image: url(:/themes/light/primary/checklist_indeterminate_invert.svg); -} - -QListView::indicator:indeterminate:disabled { - image: url(:/themes/light/disabled/checklist_indeterminate.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QTableView Indicator */ - -QTableView::indicator:enabled:checked, -QTableView::indicator:enabled:checked:selected, -QTableView::indicator:enabled:checked:focus { - image: url(:/themes/light/primary/checkbox_checked.svg); -} - -QTableView::indicator:checked:selected:active { - image: url(:/themes/light/primary/checkbox_checked_invert.svg); -} - -QTableView::indicator:disabled:checked, -QTableView::indicator:disabled:checked:selected, -QTableView::indicator:disabled:checked:focus { - image: url(:/themes/light/disabled/checkbox_checked.svg); -} - -QTableView::indicator:enabled:unchecked, -QTableView::indicator:enabled:unchecked:selected, -QTableView::indicator:enabled:unchecked:focus { - image: url(:/themes/light/primary/checkbox_unchecked.svg); -} - -QTableView::indicator:unchecked:selected:active { - image: url(:/themes/light/primary/checkbox_unchecked_invert.svg); -} - -QTableView::indicator:disabled:unchecked, -QTableView::indicator:disabled:unchecked:selected, -QTableView::indicator:disabled:unchecked:focus { - image: url(:/themes/light/disabled/checkbox_unchecked.svg); -} - -QTableView::indicator:enabled:indeterminate, -QTableView::indicator:enabled:indeterminate:selected, -QTableView::indicator:enabled:indeterminate:focus { - image: url(:/themes/light/primary/checkbox_indeterminate.svg); -} - -QTableView::indicator:indeterminate:selected:active { - image: url(:/themes/light/primary/checkbox_indeterminate_invert.svg); -} - -QTableView::indicator:disabled:indeterminate, -QTableView::indicator:disabled:indeterminate:selected, -QTableView::indicator:disabled:indeterminate:focus { - image: url(:/themes/light/disabled/checkbox_indeterminate.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QCheckBox and QGroupBox Indicator */ - -QCheckBox::indicator:checked, -QGroupBox::indicator:checked { - image: url(:/themes/light/primary/checkbox_checked.svg); -} - -QCheckBox::indicator:unchecked, -QGroupBox::indicator:unchecked { - image: url(:/themes/light/primary/checkbox_unchecked.svg); -} - -QCheckBox::indicator:indeterminate, -QGroupBox::indicator:indeterminate { - image: url(:/themes/light/primary/checkbox_indeterminate.svg); -} - -QCheckBox::indicator:checked:disabled, -QGroupBox::indicator:checked:disabled { - image: url(:/themes/light/disabled/checkbox_checked.svg); -} - -QCheckBox::indicator:unchecked:disabled, -QGroupBox::indicator:unchecked:disabled { - image: url(:/themes/light/disabled/checkbox_unchecked.svg); -} - -QCheckBox::indicator:indeterminate:disabled, -QGroupBox::indicator:indeterminate:disabled { - image: url(:/themes/light/disabled/checkbox_indeterminate.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QRadioButton Indicator */ - -QRadioButton::indicator:checked { - image: url(:/themes/light/primary/radiobutton_checked.svg); -} - -QRadioButton::indicator:unchecked { - image: url(:/themes/light/primary/radiobutton_unchecked.svg); -} - -QRadioButton::indicator:checked:disabled { - image: url(:/themes/light/disabled/radiobutton_checked.svg); -} - -QRadioButton::indicator:unchecked:disabled { - image: url(:/themes/light/disabled/radiobutton_unchecked.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QDockWidget */ - -QDockWidget { - color: #555555; - text-transform: uppercase; - border: 2px solid #f5f5f5; - titlebar-close-icon: url(:/themes/light/primary/close.svg); - titlebar-normal-icon: url(:/themes/light/primary/float.svg); - border-radius: 4px; -} - -QDockWidget::title { - text-align: left; - padding-left: 36px; - padding: 3px; - margin-top: 4px; -} - -/* ------------------------------------------------------------------------ */ -/* QComboBox indicator */ - -QComboBox::indicator:checked { - image: url(:/themes/light/primary/checklist.svg); -} - -QComboBox::indicator:checked:selected { - image: url(:/themes/light/primary/checklist_invert.svg); -} - -/* ------------------------------------------------------------------------ */ -/* Menu Items */ - -QComboBox::item, -QCalendarWidget QMenu::item, -QMenu::item { - height: 28px; - width: 100px; - border: 8px solid transparent; - color: #555555; -} - -QComboBox::item:selected, -QCalendarWidget QMenu::item:selected, -QMenu::item:selected { - color: #3c3c3c; - background-color: #62efff; - border-radius: 0px; -} - -QComboBox::item:disabled, -QCalendarWidget QMenu::item:disabled, -QMenu::item:disabled { - color: rgba(85, 85, 85, 0.3); -} - -/* ------------------------------------------------------------------------ */ -/* QMenu */ - -QCalendarWidget QMenu, -QMenu { - background-color: #f5f5f5; - border: 2px solid #ffffff; - border-radius: 4px; -} - -QMenu::separator { - height: 2px; - background-color: #ffffff; - margin-left: 2px; - margin-right: 2px; -} - -QMenu::right-arrow{ - image: url(:/themes/light/primary/rightarrow.svg); - width: 16px; - height: 16px; -} - -QMenu::right-arrow:selected{ - image: url(:/themes/light/disabled/rightarrow.svg); -} - -QMenu::indicator:non-exclusive:unchecked { - image: url(:/themes/light/primary/checkbox_unchecked.svg); -} - -QMenu::indicator:non-exclusive:unchecked:selected { - image: url(:/themes/light/primary/checkbox_unchecked_invert.svg); -} - -QMenu::indicator:non-exclusive:checked { - image: url(:/themes/light/primary/checkbox_checked.svg); -} - -QMenu::indicator:non-exclusive:checked:selected { - image: url(:/themes/light/primary/checkbox_checked_invert.svg); -} - -QMenu::indicator:exclusive:unchecked { - image: url(:/themes/light/primary/radiobutton_unchecked.svg); -} - -QMenu::indicator:exclusive:unchecked:selected { - image: url(:/themes/light/primary/radiobutton_unchecked_invert.svg); -} - -QMenu::indicator:exclusive:checked { - image: url(:/themes/light/primary/radiobutton_checked.svg); -} - -QMenu::indicator:exclusive:checked:selected { - image: url(:/themes/light/primary/radiobutton_checked_invert.svg); -} - -/* ------------------------------------------------------------------------ */ -/* QMenuBar */ - -QMenuBar { - background-color: #f5f5f5; - color: #555555; -} - -QMenuBar::item { - height: 32px; - padding: 8px; - background-color: transparent; - color: #555555; -} - -QMenuBar::item:selected, -QMenuBar::item:pressed { - color: #3c3c3c; - background-color: #62efff; -} - -/* ------------------------------------------------------------------------ */ -/* QToolBox */ - -QToolBox::tab { - background-color: #f5f5f5; - color: #555555; - text-transform: uppercase; - border-radius: 4px; - padding-left: 15px; -} - -QToolBox::tab:selected, -QToolBox::tab:hover { - background-color: rgba(0, 188, 212, 0.2); -} - -/* ------------------------------------------------------------------------ */ -/* QProgressBar */ - -QProgressBar { - border-radius: 0; - background-color: #ffffff; - text-align: center; - color: transparent; -} - -QProgressBar::chunk { - background-color: #00bcd4; -} - -/* ------------------------------------------------------------------------ */ -/* QScrollBar */ - -QScrollBar:horizontal { - border: 0; - background: #f5f5f5; - height: 8px; -} - -QScrollBar:vertical { - border: 0; - background: #f5f5f5; - width: 8px; -} - -QScrollBar::handle { - background: rgba(0, 188, 212, 0.1); -} - -QScrollBar::handle:horizontal { - min-width: 24px; -} - -QScrollBar::handle:vertical { - min-height: 24px; -} - -QScrollBar::handle:vertical:hover, -QScrollBar::handle:horizontal:hover { - background: #00bcd4; -} - -QScrollBar::add-line:vertical, -QScrollBar::sub-line:vertical, -QScrollBar::add-line:horizontal, -QScrollBar::sub-line:horizontal { - border: 0; - background: transparent; - width: 0px; - height: 0px; -} - -/* ------------------------------------------------------------------------ */ -/* QScrollBar-Big */ - -QScrollBar.big:horizontal { - border: 0; - background: #f5f5f5; - height: 36px; -} - -QScrollBar.big:vertical { - border: 0; - background: #f5f5f5; - width: 36px; -} - -QScrollBar.big::handle, -QScrollBar.big::handle:vertical:hover, -QScrollBar.big::handle:horizontal:hover { - background: #00bcd4; -} - -QScrollBar.big::handle:horizontal { - min-width: 24px; -} - -QScrollBar.big::handle:vertical { - min-height: 24px; -} - -QScrollBar.big::add-line:vertical, -QScrollBar.big::sub-line:vertical, -QScrollBar.big::add-line:horizontal, -QScrollBar.big::sub-line:horizontal { - border: 0; - background: transparent; - width: 0px; - height: 0px; -} - -/* ------------------------------------------------------------------------ */ -/* QSlider */ - -QSlider:horizontal { - min-height: 24px; - max-height: 24px; -} - -QSlider:vertical { - min-width: 24px; - max-width: 24px; -} - -QSlider::groove:horizontal { - height: 4px; - background: #393939; - margin: 0 12px; -} - -QSlider::groove:vertical { - width: 4px; - background: #393939; - margin: 12px 0; - border-radius: 24px; -} - -QSlider::handle:horizontal { - image: url(:/themes/light/primary/slider.svg); - width: 24px; - height: 24px; - margin: -24px -12px; -} - -QSlider::handle:vertical { - image: url(:/themes/light/primary/slider.svg); - border-radius: 24px; - width: 24px; - height: 24px; - margin: -12px -24px; -} - -QSlider::add-page { -background: #f5f5f5; -} - -QSlider::sub-page { -background: #00bcd4; -} - -/* ------------------------------------------------------------------------ */ -/* QLabel */ - -QLabel { - border: none; - background: transparent; - color: #555555 -} - -QLabel:disabled { - color: rgba(85, 85, 85, 0.2) -} - -/* ------------------------------------------------------------------------ */ -/* VLines and HLinex */ - -QFrame[frameShape="4"] { - border-width: 1px 0 0 0; - background: none; -} - -QFrame[frameShape="5"] { - border-width: 0 1px 0 0; - background: none; -} - -QFrame[frameShape="4"], -QFrame[frameShape="5"] { - border-color: #ffffff; -} - -/* ------------------------------------------------------------------------ */ -/* QToolBar */ - -QToolBar { - background: #e6e6e6; - border: 0px solid; -} - -QToolBar:horizontal { - border-bottom: 1px solid #ffffff; -} - -QToolBar:vertical { - border-right: 1px solid #ffffff; -} - -QToolBar::handle:horizontal { - image: url(:/themes/light/primary/toolbar-handle-horizontal.svg); -} - -QToolBar::handle:vertical { - image: url(:/themes/light/primary/toolbar-handle-vertical.svg); -} - -QToolBar::separator:horizontal { - border-right: 1px solid #ffffff; - border-left: 1px solid #ffffff; - width: 1px; -} - -QToolBar::separator:vertical { - border-top: 1px solid #ffffff; - border-bottom: 1px solid #ffffff; - height: 1px; -} - - -/* ------------------------------------------------------------------------ */ -/* QToolButton */ - -QToolButton { - background: #e6e6e6; - border: 0px; - height: 36px; - margin: 3px; - padding: 3px; - border-right: 12px solid #e6e6e6; - border-left: 12px solid #e6e6e6; -} - -QToolButton:hover { - background: #ffffff; - border-right: 12px solid #ffffff; - border-left: 12px solid #ffffff; -} - -QToolButton:pressed { - background: #f5f5f5; - border-right: 12px solid #f5f5f5; - border-left: 12px solid #f5f5f5; -} - -QToolButton:checked { - background: #ffffff; - border-left: 12px solid #ffffff; - border-right: 12px solid #00bcd4; -} - -/* ------------------------------------------------------------------------ */ -/* General viewers */ - -QTableView { - background-color: #e6e6e6; - border: 1px solid #f5f5f5; - border-radius: 4px; -} - -QTreeView, -QListView { - border-radius: 4px; - padding: 4px; - margin: 0px; - border: 0px; -} - -QTableView::item, -QTreeView::item, -QListView::item { - padding: 4px; - min-height: 32px; - color: #555555; - selection-color: #555555; /* For Windows */ - border-color: transparent; /* Fix #34 */ -} - -/* ------------------------------------------------------------------------ */ -/* Items Selection */ - -QTableView::item:selected, -QTreeView::item:selected, -QListView::item:selected { - background-color: rgba(0, 188, 212, 0.2); - selection-background-color: rgba(0, 188, 212, 0.2); - color: #555555; - selection-color: #555555; /* For Windows */ -} - -QTableView::item:selected:focus, -QTreeView::item:selected:focus, -QListView::item:selected:focus { - background-color: #00bcd4; - selection-background-color: #00bcd4; - color: #3c3c3c; - selection-color: #3c3c3c; /* For Windows */ -} - -QTableView { - selection-background-color: rgba(0, 188, 212, 0.2); -} - -QTableView:focus { - selection-background-color: #00bcd4; -} - -QTableView::item:disabled { - color: rgba(85, 85, 85, 0.3); - selection-color: rgba(85, 85, 85, 0.3); - background-color: #f5f5f5; - selection-background-color: #f5f5f5; -} - -/* ------------------------------------------------------------------------ */ -/* QTreeView */ - -QTreeView::branch{ - background-color: #f5f5f5; -} - -QTreeView::branch:closed:has-children:has-siblings, -QTreeView::branch:closed:has-children:!has-siblings { - image: url(:/themes/light/primary/branch-closed.svg); -} - -QTreeView::branch:open:has-children:!has-siblings, -QTreeView::branch:open:has-children:has-siblings { - image: url(:/themes/light/primary/branch-open.svg); -} - -QTreeView::branch:has-siblings:!adjoins-item { - border-image: url(:/themes/light/disabled/vline.svg) 0; -} - -QTreeView::branch:has-siblings:adjoins-item { - border-image: url(:/themes/light/disabled/branch-more.svg) 0; -} - -QTreeView::branch:!has-children:!has-siblings:adjoins-item, -QTreeView::branch:has-children:!has-siblings:adjoins-item { - border-image: url(:/themes/light/disabled/branch-end.svg) 0; -} - -QTreeView QHeaderView::section { - border: none; -} - - -/* ------------------------------------------------------------------------ */ -/* Custom buttons */ - -QPushButton.danger { - border-color: #dc3545; - color: #dc3545; -} - -QPushButton.danger:checked, -QPushButton.danger:pressed { - color: #e6e6e6; - background-color: #dc3545; -} - -QPushButton.warning{ - border-color: #ffc107; - color: #ffc107; -} - -QPushButton.warning:checked, -QPushButton.warning:pressed { - color: #e6e6e6; - background-color: #ffc107; -} - -QPushButton.success { - border-color: #17a2b8; - color: #17a2b8; -} - -QPushButton.success:checked, -QPushButton.success:pressed { - color: #e6e6e6; - background-color: #17a2b8; -} - -QPushButton.danger:flat:hover { - background-color: rgba(220, 53, 69, 0.2); -} - -QPushButton.danger:flat:pressed, -QPushButton.danger:flat:checked { - background-color: rgba(220, 53, 69, 0.1); - color: #dc3545; -} - -QPushButton.warning:flat:hover { - background-color: rgba(255, 193, 7, 0.2); -} - -QPushButton.warning:flat:pressed, -QPushButton.warning:flat:checked { - background-color: rgba(255, 193, 7, 0.1); - color: #ffc107; -} - -QPushButton.success:flat:hover { - background-color: rgba(23, 162, 184, 0.2); -} - -QPushButton.success:flat:pressed, -QPushButton.success:flat:checked { - background-color: rgba(23, 162, 184, 0.1); - color: #17a2b8; -} - -/* ------------------------------------------------------------------------ */ -/* QTableView */ - -QTableCornerButton::section { - background-color: #f5f5f5; - border-radius: 0px; - border-right: 1px solid; - border-bottom: 1px solid; - border-color: #e6e6e6; -} - -QTableView { - alternate-background-color: rgba(245, 245, 245, 0.7); -} - -QHeaderView { - border: none; -} - -QHeaderView::section { - color: rgba(85, 85, 85, 0.7); - text-transform: uppercase; - background-color: #f5f5f5; - padding: 0 24px; - height: 36px; - border-radius: 0px; - border-right: 1px solid; - border-bottom: 1px solid; - border-color: #e6e6e6; -} - -QHeaderView::section:vertical { - -} - -QHeaderView::section:horizontal { - -} - -/* ------------------------------------------------------------------------ */ -/* QLCDNumber */ - -QLCDNumber { - color: #00bcd4; - background-color:rgba(0, 188, 212, 0.1); - border: 1px solid rgba(0, 188, 212, 0.3); - border-radius: 4px; -} - -/* ------------------------------------------------------------------------ */ -/* QCalendarWidget */ - -#qt_calendar_prevmonth { - qproperty-icon: url(:/themes/light/primary/leftarrow.svg); -} - -#qt_calendar_nextmonth { - qproperty-icon: url(:/themes/light/primary/rightarrow.svg); -} - -/* ------------------------------------------------------------------------ */ -/* Inline QLineEdit */ - -QTreeView QLineEdit, -QTableView QLineEdit, -QListView QLineEdit { - color: #555555; - background-color: #f5f5f5; - border: 1px solid unset; - border-radius: unset; - padding: unset; - padding-left: unset; - height: unset; - border-width: unset; - border-top-left-radius: unset; - border-top-right-radius: unset; -} - -/* ------------------------------------------------------------------------ */ -/* QToolTip */ - -QToolTip { - padding: 4px; - border: 1px solid #e6e6e6; - border-radius: 0px; - color: #555555; - background-color: #ffffff; -} - -/* ------------------------------------------------------------------------ */ -/* QDialog */ - - - /* linux */ - QDialog QToolButton, - QDialog QToolButton:hover, - QDialog QToolButton:pressed, - QDialog QToolButton:checked { - border: 0px; - height: unset; - margin: unset; - padding: unset; - border-right: unset; - border-left: unset; - background-color: #00bcd4; - color: #555555; - border-radius: 4px; - } - - -QDialog QToolButton:disabled { - background-color: #f5f5f5; - color: #555555 -} - -/* ------------------------------------------------------------------------ */ -/* Grips */ - - -QMainWindow::separator:vertical, -QSplitter::handle:horizontal { - image: url(:/themes/light/primary/splitter-horizontal.svg); -} - -QMainWindow::separator:horizontal, -QSplitter::handle:vertical { - image: url(:/themes/light/primary/splitter-vertical.svg); -} - -QSizeGrip { - image: url(:/themes/light/primary/sizegrip.svg); - background-color: transparent; -} - -QMenuBar QToolButton:hover, -QMenuBar QToolButton:pressed, -QMenuBar QToolButton { - border-width: 0; - border-left: 10px; - border-image: url(:/themes/light/primary/rightarrow2.svg); - background-color: transparent; -} \ No newline at end of file diff --git a/styles/light/optionsmenu.qss b/styles/light/optionsmenu.qss deleted file mode 100644 index 1e8fe4c..0000000 --- a/styles/light/optionsmenu.qss +++ /dev/null @@ -1,30 +0,0 @@ -QLineEdit { - font-family: "Roboto Mono" -} - -QPushButton#reset_button, -QPushButton#change_password_button { - border-color: #dc3545; - color: #dc3545; -} - -QPushButton:checked#reset_button, -QPushButton:pressed#reset_button, -QPushButton:checked#change_password_button, -QPushButton:pressed#change_password_button { - color: #e6e6e6; - background-color: #dc3545; -} - -QPushButton:flat:hover#reset_button, -QPushButton:flat:hover#change_password_button { - background-color: rgba(220, 53, 69, 0.2); -} - -QPushButton:flat:pressed#reset_button, -QPushButton:flat:checked#reset_button, -QPushButton:flat:pressed#change_password_button, -QPushButton:flat:checked#change_password_button { - background-color: rgba(220, 53, 69, 0.1); - color: #dc3545; -} diff --git a/styles/light/theoretical_calendar/0.qss b/styles/light/theoretical_calendar/0.qss deleted file mode 100644 index b7d62cc..0000000 --- a/styles/light/theoretical_calendar/0.qss +++ /dev/null @@ -1,7 +0,0 @@ -CalendarButton { - background-color: rgba(84, 110, 122, 0.2); -} - -CalendarButton:pressed { - background-color: rgba(84, 110, 122, 0.1); -} \ No newline at end of file diff --git a/styles/light/theoretical_calendar/1.qss b/styles/light/theoretical_calendar/1.qss deleted file mode 100644 index df82630..0000000 --- a/styles/light/theoretical_calendar/1.qss +++ /dev/null @@ -1,11 +0,0 @@ -CalendarButton { - color: #f5f5f5; - background-color: rgba(123, 31, 162, 1); - border: 2px solid transparent; -} - -CalendarButton:pressed { - color: #f5f5f5; - background-color: rgba(123, 31, 162, 0.7); - border: 2px solid transparent; -} diff --git a/styles/light/theoretical_calendar/2.qss b/styles/light/theoretical_calendar/2.qss deleted file mode 100644 index f28b3ea..0000000 --- a/styles/light/theoretical_calendar/2.qss +++ /dev/null @@ -1,11 +0,0 @@ -CalendarButton { - color: #f5f5f5; - background-color: rgba(94, 53, 177, 1); - border: 2px solid transparent; -} - -CalendarButton:pressed { - color: #f5f5f5; - background-color: rgba(94, 53, 177, 0.7); - border: 2px solid transparent; -} diff --git a/styles/light/theoretical_calendar/3.qss b/styles/light/theoretical_calendar/3.qss deleted file mode 100644 index 279226f..0000000 --- a/styles/light/theoretical_calendar/3.qss +++ /dev/null @@ -1,11 +0,0 @@ -CalendarButton { - color: #f5f5f5; - background-color: rgba(25, 118, 210, 1); - border: 2px solid transparent; -} - -CalendarButton:pressed { - color: #f5f5f5; - background-color: rgba(25, 118, 210, 0.7); - border: 2px solid transparent; -} diff --git a/styles/light/theoretical_calendar/4.qss b/styles/light/theoretical_calendar/4.qss deleted file mode 100644 index bb17e4b..0000000 --- a/styles/light/theoretical_calendar/4.qss +++ /dev/null @@ -1,11 +0,0 @@ -CalendarButton { - color: #3c3c3c; - background-color: rgba(0, 151, 167, 1); - border: 2px solid transparent; -} - -CalendarButton:pressed { - color: #3c3c3c; - background-color: rgba(0, 151, 167, 0.7); - border: 2px solid transparent; -} diff --git a/styles/light/theoretical_calendar/5.qss b/styles/light/theoretical_calendar/5.qss deleted file mode 100644 index 65fa219..0000000 --- a/styles/light/theoretical_calendar/5.qss +++ /dev/null @@ -1,11 +0,0 @@ -CalendarButton { - color: #3c3c3c; - background-color: rgba(76, 175, 80, 1); - border: 2px solid transparent; -} - -CalendarButton:pressed { - color: #3c3c3c; - background-color: rgba(76, 175, 80, 0.7); - border: 2px solid transparent; -} diff --git a/styles/light/theoretical_calendar/base.qss b/styles/light/theoretical_calendar/base.qss deleted file mode 100644 index a256f7e..0000000 --- a/styles/light/theoretical_calendar/base.qss +++ /dev/null @@ -1,23 +0,0 @@ -CalendarButton { - color: #3c3c3c; - border: 2px solid #f5f5f5; - text-transform: uppercase; - margin: 0px; - width: 60px; - height: 60px; - font-weight: bold; - text-align: top right; - padding: 5px 5px; -} - -CalendarButton:pressed { - color: #3c3c3c; - border: 2px solid #f5f5f5; - text-transform: uppercase; - margin: 0px; - width: 60px; - height: 60px; - font-weight: bold; - text-align: top right; - padding: 5px 5px; -} diff --git a/styles/light/theoretical_calendar/selected.qss b/styles/light/theoretical_calendar/selected.qss deleted file mode 100644 index ad039c1..0000000 --- a/styles/light/theoretical_calendar/selected.qss +++ /dev/null @@ -1,7 +0,0 @@ -CalendarButton { - border: 2px solid #3c3c3c; -} - -CalendarButton:pressed { - border: 2px solid #3c3c3c; -} \ No newline at end of file diff --git a/styles/styles.qrc b/styles/styles.qrc index 2747348..53a3069 100644 --- a/styles/styles.qrc +++ b/styles/styles.qrc @@ -1,65 +1,7 @@ - dark/diary_entry_list/2.qss - dark/diary_entry_list/base.qss - dark/diary_entry_list/4.qss - dark/diary_entry_list/3.qss - dark/diary_entry_list/1.qss - dark/diary_entry_list/5.qss - dark/theoretical_calendar/2.qss - dark/theoretical_calendar/base.qss - dark/theoretical_calendar/4.qss - dark/theoretical_calendar/3.qss - dark/theoretical_calendar/selected.qss - dark/theoretical_calendar/0.qss - dark/theoretical_calendar/1.qss - dark/theoretical_calendar/5.qss - dark/diaryeditor.qss - dark/material_cyan.qss - global/black_star.qss - global/white_star.qss - dark/dangerbutton.qss - dark/diaryentryviewer.qss - dark/diary_entry_list/0.qss - dark/diarystats.qss - global/diarystats.qss - global/small_white_star.qss - global/small_black_star.qss - global/mainmenu.qss - dark/optionsmenu.qss - global/aboutdialog.qss - global/licensesdialog.qss - light/material_cyan.qss - global/diarymenu.qss - global/diarypixels.qss - light/dangerbutton.qss - light/diaryeditor.qss - light/diaryentryviewer.qss - light/optionsmenu.qss - light/diary_entry_list/0.qss - light/diary_entry_list/1.qss - light/diary_entry_list/2.qss - light/diary_entry_list/3.qss - light/diary_entry_list/4.qss - light/diary_entry_list/5.qss - light/diary_entry_list/base.qss - light/theoretical_calendar/0.qss - light/theoretical_calendar/1.qss - light/theoretical_calendar/2.qss - light/theoretical_calendar/3.qss - light/theoretical_calendar/4.qss - light/theoretical_calendar/5.qss - light/theoretical_calendar/base.qss - light/theoretical_calendar/selected.qss - light/diarystats.qss - global/pixels/0.qss - global/pixels/1.qss - global/pixels/2.qss - global/pixels/3.qss - global/pixels/4.qss - global/pixels/5.qss - global/apiresponse.qss - global/alertlabel.qss - global/standaloneoptions.qss + base/basestyle.qss + dark/darkstyle.qss + light/lightstyle.qss diff --git a/text/CONTRIBUTORS.txt b/text/CONTRIBUTORS.txt deleted file mode 100644 index 22b3578..0000000 --- a/text/CONTRIBUTORS.txt +++ /dev/null @@ -1 +0,0 @@ -someretical - https://github.com/someretical \ No newline at end of file diff --git a/text/LICENSES.txt b/text/LICENSES.txt deleted file mode 100644 index 68dbc64..0000000 --- a/text/LICENSES.txt +++ /dev/null @@ -1,2643 +0,0 @@ -Theoretical Diary - https://github.com/someretical/theoretical-diary - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - - -Qt - https://www.qt.io/ - - GNU GENERAL PUBLIC LICENSE - Version 3, 29 June 2007 - - Copyright (C) 2007 Free Software Foundation, Inc. - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - - Preamble - - The GNU General Public License is a free, copyleft license for -software and other kinds of works. - - The licenses for most software and other practical works are designed -to take away your freedom to share and change the works. By contrast, -the GNU General Public License is intended to guarantee your freedom to -share and change all versions of a program--to make sure it remains free -software for all its users. We, the Free Software Foundation, use the -GNU General Public License for most of our software; it applies also to -any other work released this way by its authors. You can apply it to -your programs, too. - - When we speak of free software, we are referring to freedom, not -price. Our General Public Licenses are designed to make sure that you -have the freedom to distribute copies of free software (and charge for -them if you wish), that you receive source code or can get it if you -want it, that you can change the software or use pieces of it in new -free programs, and that you know you can do these things. - - To protect your rights, we need to prevent others from denying you -these rights or asking you to surrender the rights. Therefore, you have -certain responsibilities if you distribute copies of the software, or if -you modify it: responsibilities to respect the freedom of others. - - For example, if you distribute copies of such a program, whether -gratis or for a fee, you must pass on to the recipients the same -freedoms that you received. You must make sure that they, too, receive -or can get the source code. And you must show them these terms so they -know their rights. - - Developers that use the GNU GPL protect your rights with two steps: -(1) assert copyright on the software, and (2) offer you this License -giving you legal permission to copy, distribute and/or modify it. - - For the developers' and authors' protection, the GPL clearly explains -that there is no warranty for this free software. For both users' and -authors' sake, the GPL requires that modified versions be marked as -changed, so that their problems will not be attributed erroneously to -authors of previous versions. - - Some devices are designed to deny users access to install or run -modified versions of the software inside them, although the manufacturer -can do so. This is fundamentally incompatible with the aim of -protecting users' freedom to change the software. The systematic -pattern of such abuse occurs in the area of products for individuals to -use, which is precisely where it is most unacceptable. Therefore, we -have designed this version of the GPL to prohibit the practice for those -products. If such problems arise substantially in other domains, we -stand ready to extend this provision to those domains in future versions -of the GPL, as needed to protect the freedom of users. - - Finally, every program is threatened constantly by software patents. -States should not allow patents to restrict development and use of -software on general-purpose computers, but in those that do, we wish to -avoid the special danger that patents applied to a free program could -make it effectively proprietary. To prevent this, the GPL assures that -patents cannot be used to render the program non-free. - - The precise terms and conditions for copying, distribution and -modification follow. - - TERMS AND CONDITIONS - - 0. Definitions. - - "This License" refers to version 3 of the GNU General Public License. - - "Copyright" also means copyright-like laws that apply to other kinds of -works, such as semiconductor masks. - - "The Program" refers to any copyrightable work licensed under this -License. Each licensee is addressed as "you". "Licensees" and -"recipients" may be individuals or organizations. - - To "modify" a work means to copy from or adapt all or part of the work -in a fashion requiring copyright permission, other than the making of an -exact copy. The resulting work is called a "modified version" of the -earlier work or a work "based on" the earlier work. - - A "covered work" means either the unmodified Program or a work based -on the Program. - - To "propagate" a work means to do anything with it that, without -permission, would make you directly or secondarily liable for -infringement under applicable copyright law, except executing it on a -computer or modifying a private copy. Propagation includes copying, -distribution (with or without modification), making available to the -public, and in some countries other activities as well. - - To "convey" a work means any kind of propagation that enables other -parties to make or receive copies. Mere interaction with a user through -a computer network, with no transfer of a copy, is not conveying. - - An interactive user interface displays "Appropriate Legal Notices" -to the extent that it includes a convenient and prominently visible -feature that (1) displays an appropriate copyright notice, and (2) -tells the user that there is no warranty for the work (except to the -extent that warranties are provided), that licensees may convey the -work under this License, and how to view a copy of this License. If -the interface presents a list of user commands or options, such as a -menu, a prominent item in the list meets this criterion. - - 1. Source Code. - - The "source code" for a work means the preferred form of the work -for making modifications to it. "Object code" means any non-source -form of a work. - - A "Standard Interface" means an interface that either is an official -standard defined by a recognized standards body, or, in the case of -interfaces specified for a particular programming language, one that -is widely used among developers working in that language. - - The "System Libraries" of an executable work include anything, other -than the work as a whole, that (a) is included in the normal form of -packaging a Major Component, but which is not part of that Major -Component, and (b) serves only to enable use of the work with that -Major Component, or to implement a Standard Interface for which an -implementation is available to the public in source code form. A -"Major Component", in this context, means a major essential component -(kernel, window system, and so on) of the specific operating system -(if any) on which the executable work runs, or a compiler used to -produce the work, or an object code interpreter used to run it. - - The "Corresponding Source" for a work in object code form means all -the source code needed to generate, install, and (for an executable -work) run the object code and to modify the work, including scripts to -control those activities. However, it does not include the work's -System Libraries, or general-purpose tools or generally available free -programs which are used unmodified in performing those activities but -which are not part of the work. For example, Corresponding Source -includes interface definition files associated with source files for -the work, and the source code for shared libraries and dynamically -linked subprograms that the work is specifically designed to require, -such as by intimate data communication or control flow between those -subprograms and other parts of the work. - - The Corresponding Source need not include anything that users -can regenerate automatically from other parts of the Corresponding -Source. - - The Corresponding Source for a work in source code form is that -same work. - - 2. Basic Permissions. - - All rights granted under this License are granted for the term of -copyright on the Program, and are irrevocable provided the stated -conditions are met. This License explicitly affirms your unlimited -permission to run the unmodified Program. The output from running a -covered work is covered by this License only if the output, given its -content, constitutes a covered work. This License acknowledges your -rights of fair use or other equivalent, as provided by copyright law. - - You may make, run and propagate covered works that you do not -convey, without conditions so long as your license otherwise remains -in force. You may convey covered works to others for the sole purpose -of having them make modifications exclusively for you, or provide you -with facilities for running those works, provided that you comply with -the terms of this License in conveying all material for which you do -not control copyright. Those thus making or running the covered works -for you must do so exclusively on your behalf, under your direction -and control, on terms that prohibit them from making any copies of -your copyrighted material outside their relationship with you. - - Conveying under any other circumstances is permitted solely under -the conditions stated below. Sublicensing is not allowed; section 10 -makes it unnecessary. - - 3. Protecting Users' Legal Rights From Anti-Circumvention Law. - - No covered work shall be deemed part of an effective technological -measure under any applicable law fulfilling obligations under article -11 of the WIPO copyright treaty adopted on 20 December 1996, or -similar laws prohibiting or restricting circumvention of such -measures. - - When you convey a covered work, you waive any legal power to forbid -circumvention of technological measures to the extent such circumvention -is effected by exercising rights under this License with respect to -the covered work, and you disclaim any intention to limit operation or -modification of the work as a means of enforcing, against the work's -users, your or third parties' legal rights to forbid circumvention of -technological measures. - - 4. Conveying Verbatim Copies. - - You may convey verbatim copies of the Program's source code as you -receive it, in any medium, provided that you conspicuously and -appropriately publish on each copy an appropriate copyright notice; -keep intact all notices stating that this License and any -non-permissive terms added in accord with section 7 apply to the code; -keep intact all notices of the absence of any warranty; and give all -recipients a copy of this License along with the Program. - - You may charge any price or no price for each copy that you convey, -and you may offer support or warranty protection for a fee. - - 5. Conveying Modified Source Versions. - - You may convey a work based on the Program, or the modifications to -produce it from the Program, in the form of source code under the -terms of section 4, provided that you also meet all of these conditions: - - a) The work must carry prominent notices stating that you modified - it, and giving a relevant date. - - b) The work must carry prominent notices stating that it is - released under this License and any conditions added under section - 7. This requirement modifies the requirement in section 4 to - "keep intact all notices". - - c) You must license the entire work, as a whole, under this - License to anyone who comes into possession of a copy. This - License will therefore apply, along with any applicable section 7 - additional terms, to the whole of the work, and all its parts, - regardless of how they are packaged. This License gives no - permission to license the work in any other way, but it does not - invalidate such permission if you have separately received it. - - d) If the work has interactive user interfaces, each must display - Appropriate Legal Notices; however, if the Program has interactive - interfaces that do not display Appropriate Legal Notices, your - work need not make them do so. - - A compilation of a covered work with other separate and independent -works, which are not by their nature extensions of the covered work, -and which are not combined with it such as to form a larger program, -in or on a volume of a storage or distribution medium, is called an -"aggregate" if the compilation and its resulting copyright are not -used to limit the access or legal rights of the compilation's users -beyond what the individual works permit. Inclusion of a covered work -in an aggregate does not cause this License to apply to the other -parts of the aggregate. - - 6. Conveying Non-Source Forms. - - You may convey a covered work in object code form under the terms -of sections 4 and 5, provided that you also convey the -machine-readable Corresponding Source under the terms of this License, -in one of these ways: - - a) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by the - Corresponding Source fixed on a durable physical medium - customarily used for software interchange. - - b) Convey the object code in, or embodied in, a physical product - (including a physical distribution medium), accompanied by a - written offer, valid for at least three years and valid for as - long as you offer spare parts or customer support for that product - model, to give anyone who possesses the object code either (1) a - copy of the Corresponding Source for all the software in the - product that is covered by this License, on a durable physical - medium customarily used for software interchange, for a price no - more than your reasonable cost of physically performing this - conveying of source, or (2) access to copy the - Corresponding Source from a network server at no charge. - - c) Convey individual copies of the object code with a copy of the - written offer to provide the Corresponding Source. This - alternative is allowed only occasionally and noncommercially, and - only if you received the object code with such an offer, in accord - with subsection 6b. - - d) Convey the object code by offering access from a designated - place (gratis or for a charge), and offer equivalent access to the - Corresponding Source in the same way through the same place at no - further charge. You need not require recipients to copy the - Corresponding Source along with the object code. If the place to - copy the object code is a network server, the Corresponding Source - may be on a different server (operated by you or a third party) - that supports equivalent copying facilities, provided you maintain - clear directions next to the object code saying where to find the - Corresponding Source. Regardless of what server hosts the - Corresponding Source, you remain obligated to ensure that it is - available for as long as needed to satisfy these requirements. - - e) Convey the object code using peer-to-peer transmission, provided - you inform other peers where the object code and Corresponding - Source of the work are being offered to the general public at no - charge under subsection 6d. - - A separable portion of the object code, whose source code is excluded -from the Corresponding Source as a System Library, need not be -included in conveying the object code work. - - A "User Product" is either (1) a "consumer product", which means any -tangible personal property which is normally used for personal, family, -or household purposes, or (2) anything designed or sold for incorporation -into a dwelling. In determining whether a product is a consumer product, -doubtful cases shall be resolved in favor of coverage. For a particular -product received by a particular user, "normally used" refers to a -typical or common use of that class of product, regardless of the status -of the particular user or of the way in which the particular user -actually uses, or expects or is expected to use, the product. A product -is a consumer product regardless of whether the product has substantial -commercial, industrial or non-consumer uses, unless such uses represent -the only significant mode of use of the product. - - "Installation Information" for a User Product means any methods, -procedures, authorization keys, or other information required to install -and execute modified versions of a covered work in that User Product from -a modified version of its Corresponding Source. The information must -suffice to ensure that the continued functioning of the modified object -code is in no case prevented or interfered with solely because -modification has been made. - - If you convey an object code work under this section in, or with, or -specifically for use in, a User Product, and the conveying occurs as -part of a transaction in which the right of possession and use of the -User Product is transferred to the recipient in perpetuity or for a -fixed term (regardless of how the transaction is characterized), the -Corresponding Source conveyed under this section must be accompanied -by the Installation Information. But this requirement does not apply -if neither you nor any third party retains the ability to install -modified object code on the User Product (for example, the work has -been installed in ROM). - - The requirement to provide Installation Information does not include a -requirement to continue to provide support service, warranty, or updates -for a work that has been modified or installed by the recipient, or for -the User Product in which it has been modified or installed. Access to a -network may be denied when the modification itself materially and -adversely affects the operation of the network or violates the rules and -protocols for communication across the network. - - Corresponding Source conveyed, and Installation Information provided, -in accord with this section must be in a format that is publicly -documented (and with an implementation available to the public in -source code form), and must require no special password or key for -unpacking, reading or copying. - - 7. Additional Terms. - - "Additional permissions" are terms that supplement the terms of this -License by making exceptions from one or more of its conditions. -Additional permissions that are applicable to the entire Program shall -be treated as though they were included in this License, to the extent -that they are valid under applicable law. If additional permissions -apply only to part of the Program, that part may be used separately -under those permissions, but the entire Program remains governed by -this License without regard to the additional permissions. - - When you convey a copy of a covered work, you may at your option -remove any additional permissions from that copy, or from any part of -it. (Additional permissions may be written to require their own -removal in certain cases when you modify the work.) You may place -additional permissions on material, added by you to a covered work, -for which you have or can give appropriate copyright permission. - - Notwithstanding any other provision of this License, for material you -add to a covered work, you may (if authorized by the copyright holders of -that material) supplement the terms of this License with terms: - - a) Disclaiming warranty or limiting liability differently from the - terms of sections 15 and 16 of this License; or - - b) Requiring preservation of specified reasonable legal notices or - author attributions in that material or in the Appropriate Legal - Notices displayed by works containing it; or - - c) Prohibiting misrepresentation of the origin of that material, or - requiring that modified versions of such material be marked in - reasonable ways as different from the original version; or - - d) Limiting the use for publicity purposes of names of licensors or - authors of the material; or - - e) Declining to grant rights under trademark law for use of some - trade names, trademarks, or service marks; or - - f) Requiring indemnification of licensors and authors of that - material by anyone who conveys the material (or modified versions of - it) with contractual assumptions of liability to the recipient, for - any liability that these contractual assumptions directly impose on - those licensors and authors. - - All other non-permissive additional terms are considered "further -restrictions" within the meaning of section 10. If the Program as you -received it, or any part of it, contains a notice stating that it is -governed by this License along with a term that is a further -restriction, you may remove that term. If a license document contains -a further restriction but permits relicensing or conveying under this -License, you may add to a covered work material governed by the terms -of that license document, provided that the further restriction does -not survive such relicensing or conveying. - - If you add terms to a covered work in accord with this section, you -must place, in the relevant source files, a statement of the -additional terms that apply to those files, or a notice indicating -where to find the applicable terms. - - Additional terms, permissive or non-permissive, may be stated in the -form of a separately written license, or stated as exceptions; -the above requirements apply either way. - - 8. Termination. - - You may not propagate or modify a covered work except as expressly -provided under this License. Any attempt otherwise to propagate or -modify it is void, and will automatically terminate your rights under -this License (including any patent licenses granted under the third -paragraph of section 11). - - However, if you cease all violation of this License, then your -license from a particular copyright holder is reinstated (a) -provisionally, unless and until the copyright holder explicitly and -finally terminates your license, and (b) permanently, if the copyright -holder fails to notify you of the violation by some reasonable means -prior to 60 days after the cessation. - - Moreover, your license from a particular copyright holder is -reinstated permanently if the copyright holder notifies you of the -violation by some reasonable means, this is the first time you have -received notice of violation of this License (for any work) from that -copyright holder, and you cure the violation prior to 30 days after -your receipt of the notice. - - Termination of your rights under this section does not terminate the -licenses of parties who have received copies or rights from you under -this License. If your rights have been terminated and not permanently -reinstated, you do not qualify to receive new licenses for the same -material under section 10. - - 9. Acceptance Not Required for Having Copies. - - You are not required to accept this License in order to receive or -run a copy of the Program. Ancillary propagation of a covered work -occurring solely as a consequence of using peer-to-peer transmission -to receive a copy likewise does not require acceptance. However, -nothing other than this License grants you permission to propagate or -modify any covered work. These actions infringe copyright if you do -not accept this License. Therefore, by modifying or propagating a -covered work, you indicate your acceptance of this License to do so. - - 10. Automatic Licensing of Downstream Recipients. - - Each time you convey a covered work, the recipient automatically -receives a license from the original licensors, to run, modify and -propagate that work, subject to this License. You are not responsible -for enforcing compliance by third parties with this License. - - An "entity transaction" is a transaction transferring control of an -organization, or substantially all assets of one, or subdividing an -organization, or merging organizations. If propagation of a covered -work results from an entity transaction, each party to that -transaction who receives a copy of the work also receives whatever -licenses to the work the party's predecessor in interest had or could -give under the previous paragraph, plus a right to possession of the -Corresponding Source of the work from the predecessor in interest, if -the predecessor has it or can get it with reasonable efforts. - - You may not impose any further restrictions on the exercise of the -rights granted or affirmed under this License. For example, you may -not impose a license fee, royalty, or other charge for exercise of -rights granted under this License, and you may not initiate litigation -(including a cross-claim or counterclaim in a lawsuit) alleging that -any patent claim is infringed by making, using, selling, offering for -sale, or importing the Program or any portion of it. - - 11. Patents. - - A "contributor" is a copyright holder who authorizes use under this -License of the Program or a work on which the Program is based. The -work thus licensed is called the contributor's "contributor version". - - A contributor's "essential patent claims" are all patent claims -owned or controlled by the contributor, whether already acquired or -hereafter acquired, that would be infringed by some manner, permitted -by this License, of making, using, or selling its contributor version, -but do not include claims that would be infringed only as a -consequence of further modification of the contributor version. For -purposes of this definition, "control" includes the right to grant -patent sublicenses in a manner consistent with the requirements of -this License. - - Each contributor grants you a non-exclusive, worldwide, royalty-free -patent license under the contributor's essential patent claims, to -make, use, sell, offer for sale, import and otherwise run, modify and -propagate the contents of its contributor version. - - In the following three paragraphs, a "patent license" is any express -agreement or commitment, however denominated, not to enforce a patent -(such as an express permission to practice a patent or covenant not to -sue for patent infringement). To "grant" such a patent license to a -party means to make such an agreement or commitment not to enforce a -patent against the party. - - If you convey a covered work, knowingly relying on a patent license, -and the Corresponding Source of the work is not available for anyone -to copy, free of charge and under the terms of this License, through a -publicly available network server or other readily accessible means, -then you must either (1) cause the Corresponding Source to be so -available, or (2) arrange to deprive yourself of the benefit of the -patent license for this particular work, or (3) arrange, in a manner -consistent with the requirements of this License, to extend the patent -license to downstream recipients. "Knowingly relying" means you have -actual knowledge that, but for the patent license, your conveying the -covered work in a country, or your recipient's use of the covered work -in a country, would infringe one or more identifiable patents in that -country that you have reason to believe are valid. - - If, pursuant to or in connection with a single transaction or -arrangement, you convey, or propagate by procuring conveyance of, a -covered work, and grant a patent license to some of the parties -receiving the covered work authorizing them to use, propagate, modify -or convey a specific copy of the covered work, then the patent license -you grant is automatically extended to all recipients of the covered -work and works based on it. - - A patent license is "discriminatory" if it does not include within -the scope of its coverage, prohibits the exercise of, or is -conditioned on the non-exercise of one or more of the rights that are -specifically granted under this License. You may not convey a covered -work if you are a party to an arrangement with a third party that is -in the business of distributing software, under which you make payment -to the third party based on the extent of your activity of conveying -the work, and under which the third party grants, to any of the -parties who would receive the covered work from you, a discriminatory -patent license (a) in connection with copies of the covered work -conveyed by you (or copies made from those copies), or (b) primarily -for and in connection with specific products or compilations that -contain the covered work, unless you entered into that arrangement, -or that patent license was granted, prior to 28 March 2007. - - Nothing in this License shall be construed as excluding or limiting -any implied license or other defenses to infringement that may -otherwise be available to you under applicable patent law. - - 12. No Surrender of Others' Freedom. - - If conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot convey a -covered work so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you may -not convey it at all. For example, if you agree to terms that obligate you -to collect a royalty for further conveying from those to whom you convey -the Program, the only way you could satisfy both those terms and this -License would be to refrain entirely from conveying the Program. - - 13. Use with the GNU Affero General Public License. - - Notwithstanding any other provision of this License, you have -permission to link or combine any covered work with a work licensed -under version 3 of the GNU Affero General Public License into a single -combined work, and to convey the resulting work. The terms of this -License will continue to apply to the part which is the covered work, -but the special requirements of the GNU Affero General Public License, -section 13, concerning interaction through a network will apply to the -combination as such. - - 14. Revised Versions of this License. - - The Free Software Foundation may publish revised and/or new versions of -the GNU General Public License from time to time. Such new versions will -be similar in spirit to the present version, but may differ in detail to -address new problems or concerns. - - Each version is given a distinguishing version number. If the -Program specifies that a certain numbered version of the GNU General -Public License "or any later version" applies to it, you have the -option of following the terms and conditions either of that numbered -version or of any later version published by the Free Software -Foundation. If the Program does not specify a version number of the -GNU General Public License, you may choose any version ever published -by the Free Software Foundation. - - If the Program specifies that a proxy can decide which future -versions of the GNU General Public License can be used, that proxy's -public statement of acceptance of a version permanently authorizes you -to choose that version for the Program. - - Later license versions may give you additional or different -permissions. However, no additional obligations are imposed on any -author or copyright holder as a result of your choosing to follow a -later version. - - 15. Disclaimer of Warranty. - - THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY -APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT -HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY -OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, -THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM -IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF -ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. Limitation of Liability. - - IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING -WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS -THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY -GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE -USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF -DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD -PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), -EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF -SUCH DAMAGES. - - 17. Interpretation of Sections 15 and 16. - - If the disclaimer of warranty and limitation of liability provided -above cannot be given local legal effect according to their terms, -reviewing courts shall apply local law that most closely approximates -an absolute waiver of all civil liability in connection with the -Program, unless a warranty or assumption of liability accompanies a -copy of the Program in return for a fee. - - END OF TERMS AND CONDITIONS - - - -Penrose Tiling Online Generator - https://misc.0o0o.org/penrose/ - -Creative Commons Legal Code - -CC0 1.0 Universal - - CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE - LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN - ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS - INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES - REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS - PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM - THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED - HEREUNDER. - -Statement of Purpose - -The laws of most jurisdictions throughout the world automatically confer -exclusive Copyright and Related Rights (defined below) upon the creator -and subsequent owner(s) (each and all, an "owner") of an original work of -authorship and/or a database (each, a "Work"). - -Certain owners wish to permanently relinquish those rights to a Work for -the purpose of contributing to a commons of creative, cultural and -scientific works ("Commons") that the public can reliably and without fear -of later claims of infringement build upon, modify, incorporate in other -works, reuse and redistribute as freely as possible in any form whatsoever -and for any purposes, including without limitation commercial purposes. -These owners may contribute to the Commons to promote the ideal of a free -culture and the further production of creative, cultural and scientific -works, or to gain reputation or greater distribution for their Work in -part through the use and efforts of others. - -For these and/or other purposes and motivations, and without any -expectation of additional consideration or compensation, the person -associating CC0 with a Work (the "Affirmer"), to the extent that he or she -is an owner of Copyright and Related Rights in the Work, voluntarily -elects to apply CC0 to the Work and publicly distribute the Work under its -terms, with knowledge of his or her Copyright and Related Rights in the -Work and the meaning and intended legal effect of CC0 on those rights. - -1. Copyright and Related Rights. A Work made available under CC0 may be -protected by copyright and related or neighboring rights ("Copyright and -Related Rights"). Copyright and Related Rights include, but are not -limited to, the following: - - i. the right to reproduce, adapt, distribute, perform, display, - communicate, and translate a Work; - ii. moral rights retained by the original author(s) and/or performer(s); -iii. publicity and privacy rights pertaining to a person's image or - likeness depicted in a Work; - iv. rights protecting against unfair competition in regards to a Work, - subject to the limitations in paragraph 4(a), below; - v. rights protecting the extraction, dissemination, use and reuse of data - in a Work; - vi. database rights (such as those arising under Directive 96/9/EC of the - European Parliament and of the Council of 11 March 1996 on the legal - protection of databases, and under any national implementation - thereof, including any amended or successor version of such - directive); and -vii. other similar, equivalent or corresponding rights throughout the - world based on applicable law or treaty, and any national - implementations thereof. - -2. Waiver. To the greatest extent permitted by, but not in contravention -of, applicable law, Affirmer hereby overtly, fully, permanently, -irrevocably and unconditionally waives, abandons, and surrenders all of -Affirmer's Copyright and Related Rights and associated claims and causes -of action, whether now known or unknown (including existing as well as -future claims and causes of action), in the Work (i) in all territories -worldwide, (ii) for the maximum duration provided by applicable law or -treaty (including future time extensions), (iii) in any current or future -medium and for any number of copies, and (iv) for any purpose whatsoever, -including without limitation commercial, advertising or promotional -purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each -member of the public at large and to the detriment of Affirmer's heirs and -successors, fully intending that such Waiver shall not be subject to -revocation, rescission, cancellation, termination, or any other legal or -equitable action to disrupt the quiet enjoyment of the Work by the public -as contemplated by Affirmer's express Statement of Purpose. - -3. Public License Fallback. Should any part of the Waiver for any reason -be judged legally invalid or ineffective under applicable law, then the -Waiver shall be preserved to the maximum extent permitted taking into -account Affirmer's express Statement of Purpose. In addition, to the -extent the Waiver is so judged Affirmer hereby grants to each affected -person a royalty-free, non transferable, non sublicensable, non exclusive, -irrevocable and unconditional license to exercise Affirmer's Copyright and -Related Rights in the Work (i) in all territories worldwide, (ii) for the -maximum duration provided by applicable law or treaty (including future -time extensions), (iii) in any current or future medium and for any number -of copies, and (iv) for any purpose whatsoever, including without -limitation commercial, advertising or promotional purposes (the -"License"). The License shall be deemed effective as of the date CC0 was -applied by Affirmer to the Work. Should any part of the License for any -reason be judged legally invalid or ineffective under applicable law, such -partial invalidity or ineffectiveness shall not invalidate the remainder -of the License, and in such case Affirmer hereby affirms that he or she -will not (i) exercise any of his or her remaining Copyright and Related -Rights in the Work or (ii) assert any associated claims and causes of -action with respect to the Work, in either case contrary to Affirmer's -express Statement of Purpose. - -4. Limitations and Disclaimers. - - a. No trademark or patent rights held by Affirmer are waived, abandoned, - surrendered, licensed or otherwise affected by this document. - b. Affirmer offers the Work as-is and makes no representations or - warranties of any kind concerning the Work, express, implied, - statutory or otherwise, including without limitation warranties of - title, merchantability, fitness for a particular purpose, non - infringement, or the absence of latent or other defects, accuracy, or - the present or absence of errors, whether or not discoverable, all to - the greatest extent permissible under applicable law. - c. Affirmer disclaims responsibility for clearing rights of other persons - that may apply to the Work or any use thereof, including without - limitation any person's Copyright and Related Rights in the Work. - Further, Affirmer disclaims responsibility for obtaining any necessary - consents, permissions or other rights required for any use of the - Work. - d. Affirmer understands and acknowledges that Creative Commons is not a - party to this document and has no duty or obligation with respect to - this CC0 or use of the Work. - - - -Cryptopp - https://github.com/weidai11/cryptopp - -Compilation Copyright (c) 1995-2013 by Wei Dai. All rights reserved. -This copyright applies only to this software distribution package -as a compilation, and does not imply a copyright on any particular -file in the package. - -All individual files in this compilation are placed in the public domain by -Wei Dai and other contributors. - -I would like to thank the following authors for placing their works into -the public domain: - -Joan Daemen - 3way.cpp -Leonard Janke - cast.cpp, seal.cpp -Steve Reid - cast.cpp -Phil Karn - des.cpp -Andrew M. Kuchling - md2.cpp, md4.cpp -Colin Plumb - md5.cpp -Seal Woods - rc6.cpp -Chris Morgan - rijndael.cpp -Paulo Baretto - rijndael.cpp, skipjack.cpp, square.cpp -Richard De Moliner - safer.cpp -Matthew Skala - twofish.cpp -Kevin Springle - camellia.cpp, shacal2.cpp, ttmac.cpp, whrlpool.cpp, ripemd.cpp -Ronny Van Keer - sha3.cpp - -The Crypto++ Library (as a compilation) is currently licensed under the Boost -Software License 1.0 (http://www.boost.org/users/license.html). - -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, -ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -DEALINGS IN THE SOFTWARE. - - - -JSON - https://github.com/nlohmann/json - -MIT License - -Copyright (c) 2013-2021 Niels Lohmann - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - - -Material design icons - https://github.com/google/material-design-icons - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - -Qt-Material - https://github.com/UN-GCPDS/qt-material - -BSD 2-Clause License - -Copyright (c) 2020, GCPDS -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -Roboto - https://fonts.google.com/specimen/Roboto -Roboto Mono - https://fonts.google.com/specimen/Roboto+Mono - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - -o2 - https://github.com/pipacs/o2 - -Copyright (c) 2012, Akos Polster -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, this -list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright notice, -this list of conditions and the following disclaimer in the documentation -and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - - - -AsyncFuture - https://github.com/benlau/asyncfuture - - Apache License - Version 2.0, January 2004 - http://www.apache.org/licenses/ - - TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - - 1. Definitions. - - "License" shall mean the terms and conditions for use, reproduction, - and distribution as defined by Sections 1 through 9 of this document. - - "Licensor" shall mean the copyright owner or entity authorized by - the copyright owner that is granting the License. - - "Legal Entity" shall mean the union of the acting entity and all - other entities that control, are controlled by, or are under common - control with that entity. For the purposes of this definition, - "control" means (i) the power, direct or indirect, to cause the - direction or management of such entity, whether by contract or - otherwise, or (ii) ownership of fifty percent (50%) or more of the - outstanding shares, or (iii) beneficial ownership of such entity. - - "You" (or "Your") shall mean an individual or Legal Entity - exercising permissions granted by this License. - - "Source" form shall mean the preferred form for making modifications, - including but not limited to software source code, documentation - source, and configuration files. - - "Object" form shall mean any form resulting from mechanical - transformation or translation of a Source form, including but - not limited to compiled object code, generated documentation, - and conversions to other media types. - - "Work" shall mean the work of authorship, whether in Source or - Object form, made available under the License, as indicated by a - copyright notice that is included in or attached to the work - (an example is provided in the Appendix below). - - "Derivative Works" shall mean any work, whether in Source or Object - form, that is based on (or derived from) the Work and for which the - editorial revisions, annotations, elaborations, or other modifications - represent, as a whole, an original work of authorship. For the purposes - of this License, Derivative Works shall not include works that remain - separable from, or merely link (or bind by name) to the interfaces of, - the Work and Derivative Works thereof. - - "Contribution" shall mean any work of authorship, including - the original version of the Work and any modifications or additions - to that Work or Derivative Works thereof, that is intentionally - submitted to Licensor for inclusion in the Work by the copyright owner - or by an individual or Legal Entity authorized to submit on behalf of - the copyright owner. For the purposes of this definition, "submitted" - means any form of electronic, verbal, or written communication sent - to the Licensor or its representatives, including but not limited to - communication on electronic mailing lists, source code control systems, - and issue tracking systems that are managed by, or on behalf of, the - Licensor for the purpose of discussing and improving the Work, but - excluding communication that is conspicuously marked or otherwise - designated in writing by the copyright owner as "Not a Contribution." - - "Contributor" shall mean Licensor and any individual or Legal Entity - on behalf of whom a Contribution has been received by Licensor and - subsequently incorporated within the Work. - - 2. Grant of Copyright License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - copyright license to reproduce, prepare Derivative Works of, - publicly display, publicly perform, sublicense, and distribute the - Work and such Derivative Works in Source or Object form. - - 3. Grant of Patent License. Subject to the terms and conditions of - this License, each Contributor hereby grants to You a perpetual, - worldwide, non-exclusive, no-charge, royalty-free, irrevocable - (except as stated in this section) patent license to make, have made, - use, offer to sell, sell, import, and otherwise transfer the Work, - where such license applies only to those patent claims licensable - by such Contributor that are necessarily infringed by their - Contribution(s) alone or by combination of their Contribution(s) - with the Work to which such Contribution(s) was submitted. If You - institute patent litigation against any entity (including a - cross-claim or counterclaim in a lawsuit) alleging that the Work - or a Contribution incorporated within the Work constitutes direct - or contributory patent infringement, then any patent licenses - granted to You under this License for that Work shall terminate - as of the date such litigation is filed. - - 4. Redistribution. You may reproduce and distribute copies of the - Work or Derivative Works thereof in any medium, with or without - modifications, and in Source or Object form, provided that You - meet the following conditions: - - (a) You must give any other recipients of the Work or - Derivative Works a copy of this License; and - - (b) You must cause any modified files to carry prominent notices - stating that You changed the files; and - - (c) You must retain, in the Source form of any Derivative Works - that You distribute, all copyright, patent, trademark, and - attribution notices from the Source form of the Work, - excluding those notices that do not pertain to any part of - the Derivative Works; and - - (d) If the Work includes a "NOTICE" text file as part of its - distribution, then any Derivative Works that You distribute must - include a readable copy of the attribution notices contained - within such NOTICE file, excluding those notices that do not - pertain to any part of the Derivative Works, in at least one - of the following places: within a NOTICE text file distributed - as part of the Derivative Works; within the Source form or - documentation, if provided along with the Derivative Works; or, - within a display generated by the Derivative Works, if and - wherever such third-party notices normally appear. The contents - of the NOTICE file are for informational purposes only and - do not modify the License. You may add Your own attribution - notices within Derivative Works that You distribute, alongside - or as an addendum to the NOTICE text from the Work, provided - that such additional attribution notices cannot be construed - as modifying the License. - - You may add Your own copyright statement to Your modifications and - may provide additional or different license terms and conditions - for use, reproduction, or distribution of Your modifications, or - for any such Derivative Works as a whole, provided Your use, - reproduction, and distribution of the Work otherwise complies with - the conditions stated in this License. - - 5. Submission of Contributions. Unless You explicitly state otherwise, - any Contribution intentionally submitted for inclusion in the Work - by You to the Licensor shall be under the terms and conditions of - this License, without any additional terms or conditions. - Notwithstanding the above, nothing herein shall supersede or modify - the terms of any separate license agreement you may have executed - with Licensor regarding such Contributions. - - 6. Trademarks. This License does not grant permission to use the trade - names, trademarks, service marks, or product names of the Licensor, - except as required for reasonable and customary use in describing the - origin of the Work and reproducing the content of the NOTICE file. - - 7. Disclaimer of Warranty. Unless required by applicable law or - agreed to in writing, Licensor provides the Work (and each - Contributor provides its Contributions) on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or - implied, including, without limitation, any warranties or conditions - of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A - PARTICULAR PURPOSE. You are solely responsible for determining the - appropriateness of using or redistributing the Work and assume any - risks associated with Your exercise of permissions under this License. - - 8. Limitation of Liability. In no event and under no legal theory, - whether in tort (including negligence), contract, or otherwise, - unless required by applicable law (such as deliberate and grossly - negligent acts) or agreed to in writing, shall any Contributor be - liable to You for damages, including any direct, indirect, special, - incidental, or consequential damages of any character arising as a - result of this License or out of the use or inability to use the - Work (including but not limited to damages for loss of goodwill, - work stoppage, computer failure or malfunction, or any and all - other commercial damages or losses), even if such Contributor - has been advised of the possibility of such damages. - - 9. Accepting Warranty or Additional Liability. While redistributing - the Work or Derivative Works thereof, You may choose to offer, - and charge a fee for, acceptance of support, warranty, indemnity, - or other liability obligations and/or rights consistent with this - License. However, in accepting such obligations, You may act only - on Your own behalf and on Your sole responsibility, not on behalf - of any other Contributor, and only if You agree to indemnify, - defend, and hold each Contributor harmless for any liability - incurred by, or claims asserted against, such Contributor by reason - of your accepting any such warranty or additional liability. - - END OF TERMS AND CONDITIONS - - APPENDIX: How to apply the Apache License to your work. - - To apply the Apache License to your work, attach the following - boilerplate notice, with the fields enclosed by brackets "{}" - replaced with your own identifying information. (Don't include - the brackets!) The text should be enclosed in the appropriate - comment syntax for the file format. We also recommend that a - file or class name and description of purpose be included on the - same "printed page" as the copyright notice for easier - identification within third-party archives. - - Copyright {yyyy} {name of copyright owner} - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - - - -Phantom Style - https://github.com/randrew/phantomstyle - - GNU LESSER GENERAL PUBLIC LICENSE - Version 2.1, February 1999 - - Copyright (C) 1991, 1999 Free Software Foundation, Inc. - 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - Everyone is permitted to copy and distribute verbatim copies - of this license document, but changing it is not allowed. - -[This is the first released version of the Lesser GPL. It also counts - as the successor of the GNU Library Public License, version 2, hence - the version number 2.1.] - - Preamble - - The licenses for most software are designed to take away your -freedom to share and change it. By contrast, the GNU General Public -Licenses are intended to guarantee your freedom to share and change -free software--to make sure the software is free for all its users. - - This license, the Lesser General Public License, applies to some -specially designated software packages--typically libraries--of the -Free Software Foundation and other authors who decide to use it. You -can use it too, but we suggest you first think carefully about whether -this license or the ordinary General Public License is the better -strategy to use in any particular case, based on the explanations below. - - When we speak of free software, we are referring to freedom of use, -not price. Our General Public Licenses are designed to make sure that -you have the freedom to distribute copies of free software (and charge -for this service if you wish); that you receive source code or can get -it if you want it; that you can change the software and use pieces of -it in new free programs; and that you are informed that you can do -these things. - - To protect your rights, we need to make restrictions that forbid -distributors to deny you these rights or to ask you to surrender these -rights. These restrictions translate to certain responsibilities for -you if you distribute copies of the library or if you modify it. - - For example, if you distribute copies of the library, whether gratis -or for a fee, you must give the recipients all the rights that we gave -you. You must make sure that they, too, receive or can get the source -code. If you link other code with the library, you must provide -complete object files to the recipients, so that they can relink them -with the library after making changes to the library and recompiling -it. And you must show them these terms so they know their rights. - - We protect your rights with a two-step method: (1) we copyright the -library, and (2) we offer you this license, which gives you legal -permission to copy, distribute and/or modify the library. - - To protect each distributor, we want to make it very clear that -there is no warranty for the free library. Also, if the library is -modified by someone else and passed on, the recipients should know -that what they have is not the original version, so that the original -author's reputation will not be affected by problems that might be -introduced by others. - - Finally, software patents pose a constant threat to the existence of -any free program. We wish to make sure that a company cannot -effectively restrict the users of a free program by obtaining a -restrictive license from a patent holder. Therefore, we insist that -any patent license obtained for a version of the library must be -consistent with the full freedom of use specified in this license. - - Most GNU software, including some libraries, is covered by the -ordinary GNU General Public License. This license, the GNU Lesser -General Public License, applies to certain designated libraries, and -is quite different from the ordinary General Public License. We use -this license for certain libraries in order to permit linking those -libraries into non-free programs. - - When a program is linked with a library, whether statically or using -a shared library, the combination of the two is legally speaking a -combined work, a derivative of the original library. The ordinary -General Public License therefore permits such linking only if the -entire combination fits its criteria of freedom. The Lesser General -Public License permits more lax criteria for linking other code with -the library. - - We call this license the "Lesser" General Public License because it -does Less to protect the user's freedom than the ordinary General -Public License. It also provides other free software developers Less -of an advantage over competing non-free programs. These disadvantages -are the reason we use the ordinary General Public License for many -libraries. However, the Lesser license provides advantages in certain -special circumstances. - - For example, on rare occasions, there may be a special need to -encourage the widest possible use of a certain library, so that it becomes -a de-facto standard. To achieve this, non-free programs must be -allowed to use the library. A more frequent case is that a free -library does the same job as widely used non-free libraries. In this -case, there is little to gain by limiting the free library to free -software only, so we use the Lesser General Public License. - - In other cases, permission to use a particular library in non-free -programs enables a greater number of people to use a large body of -free software. For example, permission to use the GNU C Library in -non-free programs enables many more people to use the whole GNU -operating system, as well as its variant, the GNU/Linux operating -system. - - Although the Lesser General Public License is Less protective of the -users' freedom, it does ensure that the user of a program that is -linked with the Library has the freedom and the wherewithal to run -that program using a modified version of the Library. - - The precise terms and conditions for copying, distribution and -modification follow. Pay close attention to the difference between a -"work based on the library" and a "work that uses the library". The -former contains code derived from the library, whereas the latter must -be combined with the library in order to run. - - GNU LESSER GENERAL PUBLIC LICENSE - TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION - - 0. This License Agreement applies to any software library or other -program which contains a notice placed by the copyright holder or -other authorized party saying it may be distributed under the terms of -this Lesser General Public License (also called "this License"). -Each licensee is addressed as "you". - - A "library" means a collection of software functions and/or data -prepared so as to be conveniently linked with application programs -(which use some of those functions and data) to form executables. - - The "Library", below, refers to any such software library or work -which has been distributed under these terms. A "work based on the -Library" means either the Library or any derivative work under -copyright law: that is to say, a work containing the Library or a -portion of it, either verbatim or with modifications and/or translated -straightforwardly into another language. (Hereinafter, translation is -included without limitation in the term "modification".) - - "Source code" for a work means the preferred form of the work for -making modifications to it. For a library, complete source code means -all the source code for all modules it contains, plus any associated -interface definition files, plus the scripts used to control compilation -and installation of the library. - - Activities other than copying, distribution and modification are not -covered by this License; they are outside its scope. The act of -running a program using the Library is not restricted, and output from -such a program is covered only if its contents constitute a work based -on the Library (independent of the use of the Library in a tool for -writing it). Whether that is true depends on what the Library does -and what the program that uses the Library does. - - 1. You may copy and distribute verbatim copies of the Library's -complete source code as you receive it, in any medium, provided that -you conspicuously and appropriately publish on each copy an -appropriate copyright notice and disclaimer of warranty; keep intact -all the notices that refer to this License and to the absence of any -warranty; and distribute a copy of this License along with the -Library. - - You may charge a fee for the physical act of transferring a copy, -and you may at your option offer warranty protection in exchange for a -fee. - - 2. You may modify your copy or copies of the Library or any portion -of it, thus forming a work based on the Library, and copy and -distribute such modifications or work under the terms of Section 1 -above, provided that you also meet all of these conditions: - - a) The modified work must itself be a software library. - - b) You must cause the files modified to carry prominent notices - stating that you changed the files and the date of any change. - - c) You must cause the whole of the work to be licensed at no - charge to all third parties under the terms of this License. - - d) If a facility in the modified Library refers to a function or a - table of data to be supplied by an application program that uses - the facility, other than as an argument passed when the facility - is invoked, then you must make a good faith effort to ensure that, - in the event an application does not supply such function or - table, the facility still operates, and performs whatever part of - its purpose remains meaningful. - - (For example, a function in a library to compute square roots has - a purpose that is entirely well-defined independent of the - application. Therefore, Subsection 2d requires that any - application-supplied function or table used by this function must - be optional: if the application does not supply it, the square - root function must still compute square roots.) - -These requirements apply to the modified work as a whole. If -identifiable sections of that work are not derived from the Library, -and can be reasonably considered independent and separate works in -themselves, then this License, and its terms, do not apply to those -sections when you distribute them as separate works. But when you -distribute the same sections as part of a whole which is a work based -on the Library, the distribution of the whole must be on the terms of -this License, whose permissions for other licensees extend to the -entire whole, and thus to each and every part regardless of who wrote -it. - -Thus, it is not the intent of this section to claim rights or contest -your rights to work written entirely by you; rather, the intent is to -exercise the right to control the distribution of derivative or -collective works based on the Library. - -In addition, mere aggregation of another work not based on the Library -with the Library (or with a work based on the Library) on a volume of -a storage or distribution medium does not bring the other work under -the scope of this License. - - 3. You may opt to apply the terms of the ordinary GNU General Public -License instead of this License to a given copy of the Library. To do -this, you must alter all the notices that refer to this License, so -that they refer to the ordinary GNU General Public License, version 2, -instead of to this License. (If a newer version than version 2 of the -ordinary GNU General Public License has appeared, then you can specify -that version instead if you wish.) Do not make any other change in -these notices. - - Once this change is made in a given copy, it is irreversible for -that copy, so the ordinary GNU General Public License applies to all -subsequent copies and derivative works made from that copy. - - This option is useful when you wish to copy part of the code of -the Library into a program that is not a library. - - 4. You may copy and distribute the Library (or a portion or -derivative of it, under Section 2) in object code or executable form -under the terms of Sections 1 and 2 above provided that you accompany -it with the complete corresponding machine-readable source code, which -must be distributed under the terms of Sections 1 and 2 above on a -medium customarily used for software interchange. - - If distribution of object code is made by offering access to copy -from a designated place, then offering equivalent access to copy the -source code from the same place satisfies the requirement to -distribute the source code, even though third parties are not -compelled to copy the source along with the object code. - - 5. A program that contains no derivative of any portion of the -Library, but is designed to work with the Library by being compiled or -linked with it, is called a "work that uses the Library". Such a -work, in isolation, is not a derivative work of the Library, and -therefore falls outside the scope of this License. - - However, linking a "work that uses the Library" with the Library -creates an executable that is a derivative of the Library (because it -contains portions of the Library), rather than a "work that uses the -library". The executable is therefore covered by this License. -Section 6 states terms for distribution of such executables. - - When a "work that uses the Library" uses material from a header file -that is part of the Library, the object code for the work may be a -derivative work of the Library even though the source code is not. -Whether this is true is especially significant if the work can be -linked without the Library, or if the work is itself a library. The -threshold for this to be true is not precisely defined by law. - - If such an object file uses only numerical parameters, data -structure layouts and accessors, and small macros and small inline -functions (ten lines or less in length), then the use of the object -file is unrestricted, regardless of whether it is legally a derivative -work. (Executables containing this object code plus portions of the -Library will still fall under Section 6.) - - Otherwise, if the work is a derivative of the Library, you may -distribute the object code for the work under the terms of Section 6. -Any executables containing that work also fall under Section 6, -whether or not they are linked directly with the Library itself. - - 6. As an exception to the Sections above, you may also combine or -link a "work that uses the Library" with the Library to produce a -work containing portions of the Library, and distribute that work -under terms of your choice, provided that the terms permit -modification of the work for the customer's own use and reverse -engineering for debugging such modifications. - - You must give prominent notice with each copy of the work that the -Library is used in it and that the Library and its use are covered by -this License. You must supply a copy of this License. If the work -during execution displays copyright notices, you must include the -copyright notice for the Library among them, as well as a reference -directing the user to the copy of this License. Also, you must do one -of these things: - - a) Accompany the work with the complete corresponding - machine-readable source code for the Library including whatever - changes were used in the work (which must be distributed under - Sections 1 and 2 above); and, if the work is an executable linked - with the Library, with the complete machine-readable "work that - uses the Library", as object code and/or source code, so that the - user can modify the Library and then relink to produce a modified - executable containing the modified Library. (It is understood - that the user who changes the contents of definitions files in the - Library will not necessarily be able to recompile the application - to use the modified definitions.) - - b) Use a suitable shared library mechanism for linking with the - Library. A suitable mechanism is one that (1) uses at run time a - copy of the library already present on the user's computer system, - rather than copying library functions into the executable, and (2) - will operate properly with a modified version of the library, if - the user installs one, as long as the modified version is - interface-compatible with the version that the work was made with. - - c) Accompany the work with a written offer, valid for at - least three years, to give the same user the materials - specified in Subsection 6a, above, for a charge no more - than the cost of performing this distribution. - - d) If distribution of the work is made by offering access to copy - from a designated place, offer equivalent access to copy the above - specified materials from the same place. - - e) Verify that the user has already received a copy of these - materials or that you have already sent this user a copy. - - For an executable, the required form of the "work that uses the -Library" must include any data and utility programs needed for -reproducing the executable from it. However, as a special exception, -the materials to be distributed need not include anything that is -normally distributed (in either source or binary form) with the major -components (compiler, kernel, and so on) of the operating system on -which the executable runs, unless that component itself accompanies -the executable. - - It may happen that this requirement contradicts the license -restrictions of other proprietary libraries that do not normally -accompany the operating system. Such a contradiction means you cannot -use both them and the Library together in an executable that you -distribute. - - 7. You may place library facilities that are a work based on the -Library side-by-side in a single library together with other library -facilities not covered by this License, and distribute such a combined -library, provided that the separate distribution of the work based on -the Library and of the other library facilities is otherwise -permitted, and provided that you do these two things: - - a) Accompany the combined library with a copy of the same work - based on the Library, uncombined with any other library - facilities. This must be distributed under the terms of the - Sections above. - - b) Give prominent notice with the combined library of the fact - that part of it is a work based on the Library, and explaining - where to find the accompanying uncombined form of the same work. - - 8. You may not copy, modify, sublicense, link with, or distribute -the Library except as expressly provided under this License. Any -attempt otherwise to copy, modify, sublicense, link with, or -distribute the Library is void, and will automatically terminate your -rights under this License. However, parties who have received copies, -or rights, from you under this License will not have their licenses -terminated so long as such parties remain in full compliance. - - 9. You are not required to accept this License, since you have not -signed it. However, nothing else grants you permission to modify or -distribute the Library or its derivative works. These actions are -prohibited by law if you do not accept this License. Therefore, by -modifying or distributing the Library (or any work based on the -Library), you indicate your acceptance of this License to do so, and -all its terms and conditions for copying, distributing or modifying -the Library or works based on it. - - 10. Each time you redistribute the Library (or any work based on the -Library), the recipient automatically receives a license from the -original licensor to copy, distribute, link with or modify the Library -subject to these terms and conditions. You may not impose any further -restrictions on the recipients' exercise of the rights granted herein. -You are not responsible for enforcing compliance by third parties with -this License. - - 11. If, as a consequence of a court judgment or allegation of patent -infringement or for any other reason (not limited to patent issues), -conditions are imposed on you (whether by court order, agreement or -otherwise) that contradict the conditions of this License, they do not -excuse you from the conditions of this License. If you cannot -distribute so as to satisfy simultaneously your obligations under this -License and any other pertinent obligations, then as a consequence you -may not distribute the Library at all. For example, if a patent -license would not permit royalty-free redistribution of the Library by -all those who receive copies directly or indirectly through you, then -the only way you could satisfy both it and this License would be to -refrain entirely from distribution of the Library. - -If any portion of this section is held invalid or unenforceable under any -particular circumstance, the balance of the section is intended to apply, -and the section as a whole is intended to apply in other circumstances. - -It is not the purpose of this section to induce you to infringe any -patents or other property right claims or to contest validity of any -such claims; this section has the sole purpose of protecting the -integrity of the free software distribution system which is -implemented by public license practices. Many people have made -generous contributions to the wide range of software distributed -through that system in reliance on consistent application of that -system; it is up to the author/donor to decide if he or she is willing -to distribute software through any other system and a licensee cannot -impose that choice. - -This section is intended to make thoroughly clear what is believed to -be a consequence of the rest of this License. - - 12. If the distribution and/or use of the Library is restricted in -certain countries either by patents or by copyrighted interfaces, the -original copyright holder who places the Library under this License may add -an explicit geographical distribution limitation excluding those countries, -so that distribution is permitted only in or among countries not thus -excluded. In such case, this License incorporates the limitation as if -written in the body of this License. - - 13. The Free Software Foundation may publish revised and/or new -versions of the Lesser General Public License from time to time. -Such new versions will be similar in spirit to the present version, -but may differ in detail to address new problems or concerns. - -Each version is given a distinguishing version number. If the Library -specifies a version number of this License which applies to it and -"any later version", you have the option of following the terms and -conditions either of that version or of any later version published by -the Free Software Foundation. If the Library does not specify a -license version number, you may choose any version ever published by -the Free Software Foundation. - - 14. If you wish to incorporate parts of the Library into other free -programs whose distribution conditions are incompatible with these, -write to the author to ask for permission. For software which is -copyrighted by the Free Software Foundation, write to the Free -Software Foundation; we sometimes make exceptions for this. Our -decision will be guided by the two goals of preserving the free status -of all derivatives of our free software and of promoting the sharing -and reuse of software generally. - - NO WARRANTY - - 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO -WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. -EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR -OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY -KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE -LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME -THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. - - 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN -WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY -AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU -FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR -CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE -LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING -RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A -FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF -SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH -DAMAGES. - - END OF TERMS AND CONDITIONS - - How to Apply These Terms to Your New Libraries - - If you develop a new library, and you want it to be of the greatest -possible use to the public, we recommend making it free software that -everyone can redistribute and change. You can do so by permitting -redistribution under these terms (or, alternatively, under the terms of the -ordinary General Public License). - - To apply these terms, attach the following notices to the library. It is -safest to attach them to the start of each source file to most effectively -convey the exclusion of warranty; and each file should have at least the -"copyright" line and a pointer to where the full notice is found. - - - Copyright (C) - - This library is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - This library is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - Lesser General Public License for more details. - - You should have received a copy of the GNU Lesser General Public - License along with this library; if not, write to the Free Software - Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - USA - -Also add information on how to contact you by electronic and paper mail. - -You should also get your employer (if you work as a programmer) or your -school, if any, to sign a "copyright disclaimer" for the library, if -necessary. Here is a sample; alter the names: - - Yoyodyne, Inc., hereby disclaims all copyright interest in the - library `Frob' (a library for tweaking knobs) written by James Random - Hacker. - - , 1 April 1990 - Ty Coon, President of Vice - -That's all there is to it! \ No newline at end of file diff --git a/text/REVISION.txt b/text/REVISION.txt new file mode 100644 index 0000000..3edd32a --- /dev/null +++ b/text/REVISION.txt @@ -0,0 +1 @@ +DEBUG diff --git a/text/VERSION.txt b/text/VERSION.txt index 5859406..276cbf9 100644 --- a/text/VERSION.txt +++ b/text/VERSION.txt @@ -1 +1 @@ -2.2.3 +2.3.0 diff --git a/text/text.qrc b/text/text.qrc index 1af00e9..1ae26b8 100644 --- a/text/text.qrc +++ b/text/text.qrc @@ -1,8 +1,7 @@ - CONTRIBUTORS.txt - LICENSES.txt VERSION.txt dummysettings + REVISION.txt diff --git a/theoreticaldiary.pro b/theoreticaldiary.pro index 523e345..60e5c39 100644 --- a/theoreticaldiary.pro +++ b/theoreticaldiary.pro @@ -1,6 +1,5 @@ include(external-libs/someretical-o2/src/src.pri) include(external-libs/asyncfuture/asyncfuture.pri) -include(external-libs/phantomstyle/src/phantom/phantom.pri) INCLUDEPATH += external-libs/json/single_include/nlohmann \ external-libs/cryptopp \ @@ -41,11 +40,15 @@ SOURCES += \ src/gui/diarymenu.cpp \ src/gui/diarypixels.cpp \ src/gui/diarystats.cpp \ - src/gui/licensesdialog.cpp \ src/gui/mainmenu.cpp \ src/gui/mainwindow.cpp \ src/gui/optionsmenu.cpp \ src/gui/standaloneoptions.cpp \ + src/gui/styles/base/basestyle.cpp \ + src/gui/styles/base/phantomcolor.cpp \ + src/gui/styles/dark/darkstyle.cpp \ + src/gui/styles/light/lightstyle.cpp \ + src/gui/styles/statecolorpalette.cpp \ src/main.cpp \ src/util/alertlabel.cpp \ src/util/encryptor.cpp \ @@ -68,13 +71,19 @@ HEADERS += \ src/gui/diarymenu.h \ src/gui/diarypixels.h \ src/gui/diarystats.h \ - src/gui/licensesdialog.h \ src/gui/mainmenu.h \ src/gui/mainwindow.h \ src/gui/optionsmenu.h \ src/gui/standaloneoptions.h \ + src/gui/styles/base/basestyle.h \ + src/gui/styles/base/phantomcolor.h \ + src/gui/styles/dark/darkstyle.h \ + src/gui/styles/light/lightstyle.h \ + src/gui/styles/statecolorpalette.h \ src/util/alertlabel.h \ src/util/custommessageboxes.h \ + src/util/diarycomparisonlabel.h \ + src/util/diarypixellabel.h \ src/util/encryptor.h \ src/util/eventfilters.h \ src/util/hashcontroller.h \ @@ -91,7 +100,6 @@ FORMS += \ src/gui/diarymenu.ui \ src/gui/diarypixels.ui \ src/gui/diarystats.ui \ - src/gui/licensesdialog.ui \ src/gui/mainmenu.ui \ src/gui/mainwindow.ui \ src/gui/optionsmenu.ui \ @@ -110,7 +118,6 @@ win32:QMAKE_TARGET_DESCRIPTION = "Digital diary." win32:QMAKE_TARGET_COPYRIGHT = 2022 RESOURCES += \ - fonts/fonts.qrc \ images/images.qrc \ styles/styles.qrc \ text/text.qrc