+#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
+
+ 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 @@
+
+ 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