diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c3be30e
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+bin/
+.vs/
+*.aps
+GeneratedFiles/
+Release/
+Debug/
+data*/
diff --git a/CMakeLists.txt b/CMakeLists.txt
new file mode 100644
index 0000000..0f02a98
--- /dev/null
+++ b/CMakeLists.txt
@@ -0,0 +1,29 @@
+
+cmake_minimum_required(VERSION 3.12)
+
+##################################################################################################################
+# Setup
+##################################################################################################################
+
+project(QuickCut
+ LANGUAGES C CXX
+ DESCRIPTION "QuickCut is the way to master your keyboard."
+)
+
+##################################################################################################################
+# IDE Representation
+##################################################################################################################
+
+# Groups CMake pre-defined projects
+set_property(GLOBAL PROPERTY USE_FOLDERS ON)
+
+set_property (DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY
+ VS_STARTUP_PROJECT QuickCut
+)
+
+##################################################################################################################
+# Submodules
+##################################################################################################################
+
+add_subdirectory(src)
+
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..74ba49f
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Gilad Reich
+
+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.
diff --git a/README.md b/README.md
new file mode 100644
index 0000000..0a9cf5b
--- /dev/null
+++ b/README.md
@@ -0,0 +1,148 @@
+
+
+
+# QuickCut
+
+QuickCut is a shortcut keyboard manager that allows you to map keys and activate specified processes.
+
+QuickCut allows you shorthand access to your most used apps at the convenience of your chosen keyboard keys. It allows you to tailor your keyboard layoutdesign making your time as effecient as possible.
+
+
+## Getting Started
+
+Download links can be found [here](https://github.com/giladreich/QuickCut/releases).
+
+
+QuickCut is designed to be as portable as possible by using `Profiles` and `Actions` in a one to many relationship(profile can create multiple actions) that are saved in `Json` format, so you can easily change between each profile to create different working environment depending on the selected profile(which also makes it easier sharing your profiles with others).
+
+### Creating your first `Profile`
+
+When you first starting QuickCut, you'll see the following window:
+
+![Create Profile](/pictures/create_profile.png)
+
+![Create Profile](/pictures/first_main_window.png)
+
+Don't forget that you can create multiple profiles. As soon as you click the `Default` button, all the shortcuts for the selected profile will be activated.
+
+### Creating your first `Action`
+
+There are two type of actions:
+
+* Key Mapping - Fully maps a desired key to the specified key(no restart required).
+* Start Application - Maps a desired key to do the specified action, i.e open specific directory or your favorite application.
+
+`Key Mapping` should look as the following:
+
+![Create Profile](/pictures/action_window_map_screenshot.png)
+
+As soon as you click the green record button, the keycode that related to that key you're targeting will be added to the text-box:
+
+![Create Profile](/pictures/action_window_map_screenshot_record.png)
+
+`Start Application` should look as the following:
+
+![Create Profile](/pictures/action_window_map_snippingtool.png)
+
+In this example, snipping tool will start as soon as we hit the F14 key.
+
+We can also also use multiple keys for a shortcut:
+
+![Create Profile](/pictures/action_window_map_keycombo.png)
+
+
+So we end up with a configuration file under `Config/profiles.json` that can be easily shared with others:
+
+```json
+{
+ "activeProfile": "{9d146d79-fba5-48bc-9841-aee8bea2826a}",
+ "profileCount": 1,
+ "profiles": [
+ {
+ "id": "{9d146d79-fba5-48bc-9841-aee8bea2826a}",
+ "name": "Home Environment",
+ "lastModified": "2019-06-06T08:16:26",
+ "actionsCount": 2,
+ "actions": [
+ {
+ "id": "{9c6f3bba-fc58-4ebd-98ba-cc70fa503ba7}",
+ "actionName": "F13 Map to Screenshot",
+ "type": "KeyMap",
+ "srcKey": "7c",
+ "dstKey": "2c",
+ "appPath": "",
+ "appArgs": "",
+ "createdDate": "2019-06-06T07:52:24"
+ },
+ {
+ "id": "{e75e41f5-de4f-422d-952f-a0a91bcaf62b}",
+ "actionName": "CTRL+SHIFT+F14 Start SnippingTool",
+ "type": "AppStart",
+ "srcKey": "a2a07d",
+ "dstKey": "",
+ "appPath": "C:\/WINDOWS\/system32\/SnippingTool.exe",
+ "appArgs": "",
+ "createdDate": "2019-06-06T08:04:59"
+ }
+ ]
+ }
+ ]
+}
+```
+
+### Summary
+
+We covered the important basics of QuickCut, so we know how to interact with profiles and actions, but there are more features added to QuickCut that you can explore around.
+
+Note that as soon as you're done creating your profiles and actions, you don't need to worry about the QuickCut GUI to be opened anymore. You can just use your computer regulary and everything should just work.
+
+### Prerequisites
+
+Project Structure:
+
+* QuickCut - The actual GUI.
+* QuickCutConsole - Mapps the actual key strokes and parses the `profiles.json` file.
+* QuickCutService - Responsible for making sure that `QuickCutConsole` is running and also future updater is planned.
+
+All QuickCut projects are using the Qt Framework and designed to be portable across different platforms. Currently the code should compile on all platforms, but the the `QuickCutConsole` and `QuickCutService` requires a Unix hook implementation to make this work on different platforms, which I didn't have the time yet to do so(pull requests for this feature are very welcomed!).
+
+Requirements for building the project:
+
+* Qt MSVC41 x64/x86 kits.
+* VS MSVC41 compiler.
+* Boost 1.69.0 MSVC141_x64/x86.
+* VS17 and Qt VS Plugin(if you want to use the VS solution).
+* CMake 3.12(will be supported later).
+
+
+## Motivation
+
+I always connect my laptop to a monitor using external keyboard and mouse.
+
+This is my favorite keyboard that I currently use at home:
+
+![Apple Keyboard](/pictures/apple_keyboard.png)
+
+It has F13 til F19 keys which never worked for me, so I looked up for alternative solutions and I found out about `KeyTweak` and some other programs that all they do, is editing the registry using the default functionality Windows has for mapping keys. So I was excited for a second and I though that this actually did it for me, but unfortunately every time you map a key on the windows registry, that requires a full reboot to the system in order to load the new key mapping layout.
+It also doesn't let you map a combination of keys to a key.
+
+Long story short, I though about alternative solutions that brought me to the idea of making a fully interactive application that runs as a background service which does all the key mapping for me with the ability of creating different actions to be as efficient as possible when using the keyboard.
+
+For that reason `QuickCut` is here and free to use :)
+
+## Contributing
+
+Pull-Requests are more than welcome and will be very appreciated. So feel free to contribute if you want to improve the project.
+
+Same goes for opening issues, if you have any suggestions, feedback or you found any bugs, please do not hesitate to open an [issue](https://github.com/giladreich/QtDirect3D/issues).
+
+## Authors
+
+* **Gilad Reich** - *Initial work* - [giladreich](https://github.com/giladreich)
+
+See also the list of [contributors](https://github.com/giladreich/QtDirect3D/graphs/contributors) who participated in this project.
+
+## License
+
+This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details
+
diff --git a/pictures/action_window_map_keycombo.png b/pictures/action_window_map_keycombo.png
new file mode 100644
index 0000000..57ab911
Binary files /dev/null and b/pictures/action_window_map_keycombo.png differ
diff --git a/pictures/action_window_map_screenshot.png b/pictures/action_window_map_screenshot.png
new file mode 100644
index 0000000..7f60894
Binary files /dev/null and b/pictures/action_window_map_screenshot.png differ
diff --git a/pictures/action_window_map_screenshot_record.png b/pictures/action_window_map_screenshot_record.png
new file mode 100644
index 0000000..034185e
Binary files /dev/null and b/pictures/action_window_map_screenshot_record.png differ
diff --git a/pictures/action_window_map_snippingtool.png b/pictures/action_window_map_snippingtool.png
new file mode 100644
index 0000000..938183a
Binary files /dev/null and b/pictures/action_window_map_snippingtool.png differ
diff --git a/pictures/apple_keyboard.png b/pictures/apple_keyboard.png
new file mode 100644
index 0000000..5e65575
Binary files /dev/null and b/pictures/apple_keyboard.png differ
diff --git a/pictures/clean_action_window.png b/pictures/clean_action_window.png
new file mode 100644
index 0000000..c223525
Binary files /dev/null and b/pictures/clean_action_window.png differ
diff --git a/pictures/create_profile.png b/pictures/create_profile.png
new file mode 100644
index 0000000..a4de1a9
Binary files /dev/null and b/pictures/create_profile.png differ
diff --git a/pictures/first_main_window.png b/pictures/first_main_window.png
new file mode 100644
index 0000000..3edfea6
Binary files /dev/null and b/pictures/first_main_window.png differ
diff --git a/pictures/logo.png b/pictures/logo.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/pictures/logo.png differ
diff --git a/pictures/logo.psd b/pictures/logo.psd
new file mode 100644
index 0000000..3cc3a83
Binary files /dev/null and b/pictures/logo.psd differ
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
new file mode 100644
index 0000000..009d3b7
--- /dev/null
+++ b/src/CMakeLists.txt
@@ -0,0 +1,3 @@
+
+# TODO: Finish writting scripts.
+
diff --git a/src/QuickCut.sln b/src/QuickCut.sln
new file mode 100644
index 0000000..6d00b81
--- /dev/null
+++ b/src/QuickCut.sln
@@ -0,0 +1,51 @@
+
+Microsoft Visual Studio Solution File, Format Version 12.00
+# Visual Studio 15
+VisualStudioVersion = 15.0.28307.572
+MinimumVisualStudioVersion = 10.0.40219.1
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickCut", "QuickCut\QuickCut.vcxproj", "{B12702AD-ABFB-343A-A199-8E24837244A3}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickCutService", "QuickCutService\QuickCutService.vcxproj", "{64C0215D-FA4A-4CFB-A36D-A65C0A041538}"
+EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "QuickCutConsole", "QuickCutConsole\QuickCutConsole.vcxproj", "{B741AF33-8F2D-4FC3-A9BA-FB36FA4A98A1}"
+EndProject
+Global
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug|x64 = Debug|x64
+ Debug|x86 = Debug|x86
+ Release|x64 = Release|x64
+ Release|x86 = Release|x86
+ EndGlobalSection
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.ActiveCfg = Debug|x64
+ {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x64.Build.0 = Debug|x64
+ {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.ActiveCfg = Debug|Win32
+ {B12702AD-ABFB-343A-A199-8E24837244A3}.Debug|x86.Build.0 = Debug|Win32
+ {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.ActiveCfg = Release|x64
+ {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x64.Build.0 = Release|x64
+ {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.ActiveCfg = Release|Win32
+ {B12702AD-ABFB-343A-A199-8E24837244A3}.Release|x86.Build.0 = Release|Win32
+ {64C0215D-FA4A-4CFB-A36D-A65C0A041538}.Debug|x64.ActiveCfg = Debug|x64
+ {64C0215D-FA4A-4CFB-A36D-A65C0A041538}.Debug|x64.Build.0 = Debug|x64
+ {64C0215D-FA4A-4CFB-A36D-A65C0A041538}.Debug|x86.ActiveCfg = Debug|Win32
+ {64C0215D-FA4A-4CFB-A36D-A65C0A041538}.Debug|x86.Build.0 = Debug|Win32
+ {64C0215D-FA4A-4CFB-A36D-A65C0A041538}.Release|x64.ActiveCfg = Release|x64
+ {64C0215D-FA4A-4CFB-A36D-A65C0A041538}.Release|x64.Build.0 = Release|x64
+ {64C0215D-FA4A-4CFB-A36D-A65C0A041538}.Release|x86.ActiveCfg = Release|Win32
+ {64C0215D-FA4A-4CFB-A36D-A65C0A041538}.Release|x86.Build.0 = Release|Win32
+ {B741AF33-8F2D-4FC3-A9BA-FB36FA4A98A1}.Debug|x64.ActiveCfg = Debug|x64
+ {B741AF33-8F2D-4FC3-A9BA-FB36FA4A98A1}.Debug|x64.Build.0 = Debug|x64
+ {B741AF33-8F2D-4FC3-A9BA-FB36FA4A98A1}.Debug|x86.ActiveCfg = Debug|Win32
+ {B741AF33-8F2D-4FC3-A9BA-FB36FA4A98A1}.Debug|x86.Build.0 = Debug|Win32
+ {B741AF33-8F2D-4FC3-A9BA-FB36FA4A98A1}.Release|x64.ActiveCfg = Release|x64
+ {B741AF33-8F2D-4FC3-A9BA-FB36FA4A98A1}.Release|x64.Build.0 = Release|x64
+ {B741AF33-8F2D-4FC3-A9BA-FB36FA4A98A1}.Release|x86.ActiveCfg = Release|Win32
+ {B741AF33-8F2D-4FC3-A9BA-FB36FA4A98A1}.Release|x86.Build.0 = Release|Win32
+ EndGlobalSection
+ GlobalSection(SolutionProperties) = preSolution
+ HideSolutionNode = FALSE
+ EndGlobalSection
+ GlobalSection(ExtensibilityGlobals) = postSolution
+ SolutionGuid = {DBB09E3C-F8A2-44EE-AB36-385C62851D8B}
+ EndGlobalSection
+EndGlobal
diff --git a/src/QuickCut/AboutWindow.cpp b/src/QuickCut/AboutWindow.cpp
new file mode 100644
index 0000000..d737ce9
--- /dev/null
+++ b/src/QuickCut/AboutWindow.cpp
@@ -0,0 +1,17 @@
+
+#include "AboutWindow.h"
+
+
+AboutWindow::AboutWindow(QWidget * parent)
+ : QDialog(parent)
+ , ui(new Ui::AboutWindow())
+{
+ ui->setupUi(this);
+ setWindowFlags((windowFlags() & ~Qt::WindowContextHelpButtonHint) | Qt::MSWindowsFixedSizeDialogHint);
+
+ connect(ui->btnClose, &QPushButton::clicked, this, [this] { close(); });
+}
+
+AboutWindow::~AboutWindow()
+{
+}
diff --git a/src/QuickCut/AboutWindow.h b/src/QuickCut/AboutWindow.h
new file mode 100644
index 0000000..85d8389
--- /dev/null
+++ b/src/QuickCut/AboutWindow.h
@@ -0,0 +1,18 @@
+
+#pragma once
+
+#include
+#include "ui_AboutWindow.h"
+
+
+class AboutWindow : public QDialog
+{
+ Q_OBJECT
+
+public:
+ AboutWindow(QWidget * parent = Q_NULLPTR);
+ ~AboutWindow();
+
+private:
+ Ui::AboutWindow * ui;
+};
diff --git a/src/QuickCut/AboutWindow.ui b/src/QuickCut/AboutWindow.ui
new file mode 100644
index 0000000..c0b380d
--- /dev/null
+++ b/src/QuickCut/AboutWindow.ui
@@ -0,0 +1,135 @@
+
+
+ AboutWindow
+
+
+
+ 0
+ 0
+ 468
+ 242
+
+
+
+ About QuickCut
+
+
+
+ :/Resources/logo.png
+
+
+
+
+
+ 360
+ 200
+ 91
+ 31
+
+
+
+ Qt::NoContextMenu
+
+
+ Close
+
+
+
+
+
+ 10
+ 20
+ 141
+ 151
+
+
+
+
+
+
+ :/Resources/logo.png
+
+
+ true
+
+
+
+
+
+ 160
+ 20
+ 291
+ 171
+
+
+
+
+
+
+
+ 14
+ 75
+ true
+
+
+
+ QuickCut
+
+
+
+
+
+
+ Version 1.0
+
+
+
+
+
+
+ QuickCut is a shortcut keyboard manager that allows you to map keys and activate specified processes.
+
+
+ Qt::AutoText
+
+
+ true
+
+
+
+
+
+
+ Copyright (C) 2019 Gilad Reich
+
+
+
+
+
+
+
+ 12
+ 75
+ true
+
+
+
+ <a href="https://github.com/giladreich">GitHub Page</a>
+
+
+ true
+
+
+ Qt::TextBrowserInteraction
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/QuickCut/ActionEditWindow.cpp b/src/QuickCut/ActionEditWindow.cpp
new file mode 100644
index 0000000..ad17245
--- /dev/null
+++ b/src/QuickCut/ActionEditWindow.cpp
@@ -0,0 +1,182 @@
+
+#include "ActionEditWindow.h"
+#include "Action.h"
+
+#include
+#include
+
+
+ActionEditWindow::ActionEditWindow(QWidget * parent, eEditMode eEditMode)
+ : QDialog(parent)
+ , ui(new Ui::ActionEditWindow())
+ , m_eEditMode(eEditMode)
+{
+ ui->setupUi(this);
+
+ fillActionTypes();
+ connectSlots();
+}
+
+ActionEditWindow::ActionEditWindow(QWidget * parent)
+ : ActionEditWindow(parent, ActionCreate)
+{
+ m_pAction = new Action();
+ ui->btnSave->setText("Create");
+ onTypeSelChange(0);
+}
+
+ActionEditWindow::ActionEditWindow(QWidget * parent, Action * pAction)
+ : ActionEditWindow(parent, ActionEdit)
+{
+ m_pAction = pAction;
+ ui->btnSave->setText("Save");
+
+ fillEntries();
+}
+
+ActionEditWindow::~ActionEditWindow()
+{
+}
+
+void ActionEditWindow::fillActionTypes()
+{
+ ui->cbxType->addItem("Key Mapping");
+ ui->cbxType->addItem("Start Application");
+}
+
+void ActionEditWindow::fillEntries()
+{
+ ui->tbxName->setText(QString::fromStdString(m_pAction->getName()));
+
+ int iTypeIndex = static_cast(m_pAction->getType());
+ ui->cbxType->setCurrentIndex(iTypeIndex);
+ onTypeSelChange(iTypeIndex);
+
+ ui->tbxSrcKey->setText(QString::fromStdString(m_pAction->getSrcKey()));
+ ui->tbxDstKey->setText(QString::fromStdString(m_pAction->getDstKey()));
+ ui->tbxAppPath->setText(QString::fromStdString(m_pAction->getAppPath()));
+ ui->tbxAppArgs->setText(QString::fromStdString(m_pAction->getAppArgs()));
+}
+
+void ActionEditWindow::connectSlots()
+{
+ connect(ui->cbxType, QOverload::of(&QComboBox::currentIndexChanged), this, &ActionEditWindow::onTypeSelChange);
+ connect(ui->btnSrcKeyPlay, &QPushButton::clicked, this, [this] { onBtnKeyPlay(ui->tbxSrcKey, ui->btnSrcKeyPlay); });
+ connect(ui->btnDstKeyPlay, &QPushButton::clicked, this, [this] { onBtnKeyPlay(ui->tbxDstKey, ui->btnDstKeyPlay); });
+ connect(ui->btnFilePicker, &QPushButton::clicked, this, &ActionEditWindow::onBtnFilePicker);
+ connect(ui->btnCancel, &QPushButton::clicked, this, &ActionEditWindow::onBtnCancel);
+ connect(ui->btnSave, &QPushButton::clicked, this, &ActionEditWindow::onBtnSave);
+
+}
+
+eEditMode ActionEditWindow::getEditMode()
+{
+ return m_eEditMode;
+}
+
+void ActionEditWindow::onTypeSelChange(int iIndex)
+{
+ if (iIndex < 0 || iIndex > ActionAppStart) return;
+
+ eActionType eType = static_cast(iIndex);
+ if (eType == ActionKeyMap)
+ {
+ ui->lblDstKey->setVisible(true);
+ ui->tbxDstKey->setVisible(true);
+ ui->btnDstKeyPlay->setVisible(true);
+
+ ui->lblAppStart->setVisible(false);
+ ui->tbxAppPath->setVisible(false);
+ ui->btnFilePicker->setVisible(false);
+ ui->lblAppArgs->setVisible(false);
+ ui->tbxAppArgs->setVisible(false);
+ }
+ else if (eType == ActionAppStart)
+ {
+ ui->lblDstKey->setVisible(false);
+ ui->tbxDstKey->setVisible(false);
+ ui->btnDstKeyPlay->setVisible(false);
+
+ ui->lblAppStart->setVisible(true);
+ ui->tbxAppPath->setVisible(true);
+ ui->btnFilePicker->setVisible(true);
+ ui->lblAppArgs->setVisible(true);
+ ui->tbxAppArgs->setVisible(true);
+ }
+}
+
+void ActionEditWindow::onBtnKeyPlay(QShortcutInput * pInput, QPushButton * pBtn)
+{
+ if (pInput->isEnabled())
+ {
+ for (auto && widget : findChildren())
+ widget->setEnabled(true);
+
+ pBtn->setIcon(QIcon(":/Resources/btn_start_recording.png"));
+ pBtn->setFocus();
+ pBtn->setEnabled(true);
+
+ ui->tbxSrcKey->setEnabled(false);
+ ui->tbxDstKey->setEnabled(false);
+ }
+ else
+ {
+ for (auto && widget : findChildren())
+ widget->setEnabled(false);
+
+ pBtn->setIcon(QIcon(":/Resources/btn_stop_recording.png"));
+ pBtn->setEnabled(true);
+ pInput->setEnabled(true);
+ pInput->setFocus();
+ }
+}
+
+void ActionEditWindow::onBtnFilePicker()
+{
+ QString szHome = QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first();
+ QString szFilePath = QFileDialog::getOpenFileName(this, tr("Load Executable"), szHome, tr("Executable files (*.exe)"));
+ if (szFilePath.isEmpty()) return;
+
+ ui->tbxAppPath->setText(szFilePath);
+}
+
+void ActionEditWindow::onBtnCancel()
+{
+ if (m_eEditMode == ActionCreate)
+ delete m_pAction;
+
+ close();
+}
+
+void ActionEditWindow::onBtnSave()
+{
+ if (ui->tbxName->text().isEmpty())
+ {
+ ui->tbxName->setFocus();
+ return;
+ }
+
+ m_pAction->reset();
+
+ eActionType eType = static_cast(ui->cbxType->currentIndex());
+
+ m_pAction->setName(ui->tbxName->text().toStdString());
+ m_pAction->setType(eType);
+ m_pAction->setSrcKey(ui->tbxSrcKey->text().toStdString());
+ if (eType == ActionKeyMap)
+ {
+ m_pAction->setDstKey(ui->tbxDstKey->text().toStdString());
+ }
+ else if (eType == ActionAppStart)
+ {
+ m_pAction->setAppPath(ui->tbxAppPath->text().toStdString());
+ m_pAction->setAppArgs(ui->tbxAppArgs->text().toStdString());
+ }
+
+ if (m_eEditMode == ActionCreate)
+ emit onCreated(m_pAction);
+ else
+ emit onSaved();
+
+ close();
+}
diff --git a/src/QuickCut/ActionEditWindow.h b/src/QuickCut/ActionEditWindow.h
new file mode 100644
index 0000000..600e6be
--- /dev/null
+++ b/src/QuickCut/ActionEditWindow.h
@@ -0,0 +1,52 @@
+
+#pragma once
+
+#include
+#include "ui_ActionEditWindow.h"
+
+
+class Action;
+
+enum eEditMode { ActionEdit = 1, ActionCreate = 2 };
+
+class ActionEditWindow : public QDialog
+{
+ Q_OBJECT
+
+
+private:
+ ActionEditWindow(QWidget * parent, eEditMode eEditMode);
+
+public:
+ ActionEditWindow(QWidget * parent);
+ ActionEditWindow(QWidget * parent, Action * pAction);
+ ~ActionEditWindow();
+
+ void fillActionTypes();
+ void fillEntries();
+ void connectSlots();
+
+
+ eEditMode getEditMode();
+
+signals:
+ void onSaved();
+ void onCreated(Action * pAction);
+ void onClosed();
+
+public slots:
+
+ void onTypeSelChange(int iIndex);
+
+ void onBtnKeyPlay(QShortcutInput * pInput, QPushButton * pBtn);
+ void onBtnFilePicker();
+ void onBtnCancel();
+ void onBtnSave();
+
+private:
+ Ui::ActionEditWindow * ui;
+
+ Action * m_pAction;
+
+ eEditMode m_eEditMode;
+};
diff --git a/src/QuickCut/ActionEditWindow.ui b/src/QuickCut/ActionEditWindow.ui
new file mode 100644
index 0000000..1e5dc8e
--- /dev/null
+++ b/src/QuickCut/ActionEditWindow.ui
@@ -0,0 +1,349 @@
+
+
+ ActionEditWindow
+
+
+
+ 0
+ 0
+ 326
+ 214
+
+
+
+ Qt::NoFocus
+
+
+ Edit Action
+
+
+
+ :/Resources/logo.png
+
+
+
+
+
+
+
+ 85
+ 16
+
+
+
+
+ 85
+ 16
+
+
+
+ Action Name:
+
+
+
+
+
+
+ * Required
+
+
+
+
+
+
+
+ 85
+ 16
+
+
+
+
+ 85
+ 16
+
+
+
+ Action Type:
+
+
+
+
+
+
+
+
+
+ -1
+
+
+
+
+
+
+
+ 85
+ 16
+
+
+
+
+ 85
+ 16
+
+
+
+ Source Key:
+
+
+
+
+
+
+ false
+
+
+ Qt::NoFocus
+
+
+ true
+
+
+
+
+
+
+
+ 25
+ 20
+
+
+
+
+ 25
+ 20
+
+
+
+
+
+
+
+ :/Resources/btn_start_recording.png
+
+
+
+
+ 29
+ 29
+
+
+
+
+
+
+
+
+ 85
+ 16
+
+
+
+
+ 85
+ 16
+
+
+
+ Destination Key:
+
+
+
+
+
+
+ false
+
+
+ Qt::NoFocus
+
+
+ false
+
+
+
+
+
+
+
+ 25
+ 20
+
+
+
+
+ 25
+ 20
+
+
+
+
+
+
+
+ :/Resources/btn_start_recording.png
+
+
+
+
+ 29
+ 29
+
+
+
+
+
+
+
+
+ 85
+ 16
+
+
+
+
+ 85
+ 16
+
+
+
+ Application Path:
+
+
+
+
+
+
+ The exe location.
+
+
+
+
+
+
+
+ 25
+ 20
+
+
+
+
+ 25
+ 20
+
+
+
+ ...
+
+
+
+
+
+
+
+ 85
+ 16
+
+
+
+
+ 85
+ 16
+
+
+
+ Application Args:
+
+
+
+
+
+
+ Arguments delimited with , (comma).
+
+
+
+
+
+
+
+ 120
+ 40
+
+
+
+
+ 120
+ 40
+
+
+
+ Cancel
+
+
+ false
+
+
+ false
+
+
+
+
+
+
+
+ 120
+ 40
+
+
+
+
+ 120
+ 40
+
+
+
+ Save
+
+
+ false
+
+
+
+
+
+
+
+
+ QShortcutInput
+ QLineEdit
+ qshortcutinput.h
+
+
+
+ tbxName
+ cbxType
+ btnSrcKeyPlay
+ btnDstKeyPlay
+ tbxAppPath
+ btnFilePicker
+ tbxAppArgs
+ btnSave
+ btnCancel
+ tbxSrcKey
+ tbxDstKey
+
+
+
+
+
+
diff --git a/src/QuickCut/CheckUpdatesWindow.cpp b/src/QuickCut/CheckUpdatesWindow.cpp
new file mode 100644
index 0000000..63d7066
--- /dev/null
+++ b/src/QuickCut/CheckUpdatesWindow.cpp
@@ -0,0 +1,14 @@
+
+#include "CheckUpdatesWindow.h"
+
+
+CheckUpdatesWindow::CheckUpdatesWindow(QWidget * parent)
+ : QDialog(parent)
+ , ui(new Ui::CheckUpdatesWindow())
+{
+ ui->setupUi(this);
+}
+
+CheckUpdatesWindow::~CheckUpdatesWindow()
+{
+}
diff --git a/src/QuickCut/CheckUpdatesWindow.h b/src/QuickCut/CheckUpdatesWindow.h
new file mode 100644
index 0000000..3d5b881
--- /dev/null
+++ b/src/QuickCut/CheckUpdatesWindow.h
@@ -0,0 +1,18 @@
+
+#pragma once
+
+#include
+#include "ui_CheckUpdatesWindow.h"
+
+
+class CheckUpdatesWindow : public QDialog
+{
+ Q_OBJECT
+
+public:
+ CheckUpdatesWindow(QWidget * parent = Q_NULLPTR);
+ ~CheckUpdatesWindow();
+
+private:
+ Ui::CheckUpdatesWindow * ui;
+};
diff --git a/src/QuickCut/CheckUpdatesWindow.ui b/src/QuickCut/CheckUpdatesWindow.ui
new file mode 100644
index 0000000..ddce49e
--- /dev/null
+++ b/src/QuickCut/CheckUpdatesWindow.ui
@@ -0,0 +1,40 @@
+
+
+ CheckUpdatesWindow
+
+
+
+ 0
+ 0
+ 400
+ 112
+
+
+
+ Check For Updates
+
+
+
+
+ 100
+ 20
+ 201
+ 71
+
+
+
+
+ 12
+ 75
+ true
+
+
+
+ What you doing here? ;)
+
+
+
+
+
+
+
diff --git a/src/QuickCut/ExamplesWindow.cpp b/src/QuickCut/ExamplesWindow.cpp
new file mode 100644
index 0000000..1ba0af2
--- /dev/null
+++ b/src/QuickCut/ExamplesWindow.cpp
@@ -0,0 +1,14 @@
+
+#include "ExamplesWindow.h"
+
+
+ExamplesWindow::ExamplesWindow(QWidget * parent)
+ : QDialog(parent)
+ , ui(new Ui::ExamplesWindow())
+{
+ ui->setupUi(this);
+}
+
+ExamplesWindow::~ExamplesWindow()
+{
+}
diff --git a/src/QuickCut/ExamplesWindow.h b/src/QuickCut/ExamplesWindow.h
new file mode 100644
index 0000000..59d731d
--- /dev/null
+++ b/src/QuickCut/ExamplesWindow.h
@@ -0,0 +1,18 @@
+
+#pragma once
+
+#include
+#include "ui_ExamplesWindow.h"
+
+
+class ExamplesWindow : public QDialog
+{
+ Q_OBJECT
+
+public:
+ ExamplesWindow(QWidget * parent = Q_NULLPTR);
+ ~ExamplesWindow();
+
+private:
+ Ui::ExamplesWindow * ui;
+};
diff --git a/src/QuickCut/ExamplesWindow.ui b/src/QuickCut/ExamplesWindow.ui
new file mode 100644
index 0000000..d4efa0d
--- /dev/null
+++ b/src/QuickCut/ExamplesWindow.ui
@@ -0,0 +1,40 @@
+
+
+ ExamplesWindow
+
+
+
+ 0
+ 0
+ 313
+ 111
+
+
+
+ QuickCut Examples
+
+
+
+
+ 50
+ 20
+ 201
+ 71
+
+
+
+
+ 12
+ 75
+ true
+
+
+
+ What you doing here? ;)
+
+
+
+
+
+
+
diff --git a/src/QuickCut/MainWindow.cpp b/src/QuickCut/MainWindow.cpp
new file mode 100644
index 0000000..f51a9ce
--- /dev/null
+++ b/src/QuickCut/MainWindow.cpp
@@ -0,0 +1,635 @@
+
+#include "MainWindow.h"
+#include "pch.h"
+
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "ActionEditWindow.h"
+#include "AboutWindow.h"
+#include "CheckUpdatesWindow.h"
+#include "ExamplesWindow.h"
+#include
+
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+ , ui(new Ui::MainWindowClass)
+ , m_pActionEditWindow(nullptr)
+ , m_pAboutWindow(nullptr)
+ , m_pCheckUpdatesWindow(nullptr)
+ , m_pExamplesWindow(nullptr)
+{
+ ui->setupUi(this);
+
+ connectSlots();
+
+ initPreferences();
+ initProfiles();
+
+ QProcess::execute("QuickCutService -i"); // TODO: Figure out how the installer executes this command.
+
+ QtServiceController service("QuickCut Service");
+ service.stop();
+ service.start();
+ //if (!service.isRunning())
+ //{
+ // service.start();
+ // ui->statusBar->showMessage("Activated QuickCut Service.");
+ //}
+
+ statusBar()->showMessage("Ready.");
+}
+
+MainWindow::~MainWindow()
+{
+ qDeleteAll(m_qProfiles);
+ m_qProfiles.clear();
+}
+
+void MainWindow::connectSlots()
+{
+ // File Menu
+ connect(ui->actionFileOpen, &QAction::triggered, this, &MainWindow::onActionFileOpen);
+ connect(ui->actionFileSave, &QAction::triggered, this, &MainWindow::onActionFileSave);
+ connect(ui->actionFileSaveAs, &QAction::triggered, this, &MainWindow::onActionFileSaveAs);
+ connect(ui->actionFileRestartService, &QAction::triggered, this, &MainWindow::onActionFileRestartService);
+ connect(ui->actionFileExit, &QAction::triggered, this, &MainWindow::onActionFileExit);
+
+ // View Menu
+ connect(ui->actionViewToolBar, &QAction::triggered, this, &MainWindow::onActionViewToolBar);
+ connect(ui->actionViewStatusBar, &QAction::triggered, this, &MainWindow::onActionViewStatusBar);
+ connect(ui->actionViewRefresh, &QAction::triggered, this, &MainWindow::onActionViewRefresh);
+
+ // Preferences Menu
+ connect(ui->actionThemeDefault, &QAction::triggered, this, [this] { onActionLoadTheme(ThemeDefault, ui->actionThemeDefault); });
+ connect(ui->actionThemeDark, &QAction::triggered, this, [this] { onActionLoadTheme(ThemeDark, ui->actionThemeDark); });
+ connect(ui->actionThemeBreezeDark, &QAction::triggered, this, [this] { onActionLoadTheme(ThemeBreezeDark, ui->actionThemeBreezeDark); });
+ connect(ui->actionThemeBreezeLight, &QAction::triggered, this, [this] { onActionLoadTheme(ThemeBreezeLight, ui->actionThemeBreezeLight); });
+ connect(ui->actionThemeConsoleDark, &QAction::triggered, this, [this] { onActionLoadTheme(ThemeConsoleDark, ui->actionThemeConsoleDark); });
+ connect(ui->actionThemeUbuntu, &QAction::triggered, this, [this] { onActionLoadTheme(ThemeUbuntu, ui->actionThemeUbuntu); });
+ m_qThemeActions.insert(ThemeDefault , ui->actionThemeDefault);
+ m_qThemeActions.insert(ThemeDark , ui->actionThemeDark);
+ m_qThemeActions.insert(ThemeBreezeDark , ui->actionThemeBreezeDark);
+ m_qThemeActions.insert(ThemeBreezeLight, ui->actionThemeBreezeLight);
+ m_qThemeActions.insert(ThemeConsoleDark, ui->actionThemeConsoleDark);
+ m_qThemeActions.insert(ThemeUbuntu , ui->actionThemeUbuntu);
+
+ connect(ui->actionThemeLoadQss, &QAction::triggered, this, &MainWindow::onLoadCustomStylesheet);
+
+ // Help Menu
+ connect(ui->actionHelpAbout, &QAction::triggered, this, &MainWindow::onActionHelpAbout);
+ connect(ui->actionHelpExamples, &QAction::triggered, this, &MainWindow::onActionHelpExamples);
+ connect(ui->actionHelpCheckUpdates, &QAction::triggered, this, &MainWindow::onActionHelpCheckUpdates);
+
+
+ // Controls
+ connect(ui->lbxActions, &QListWidget::currentRowChanged, this, &MainWindow::onActionSelChange);
+ connect(ui->lbxActions, &QListWidget::doubleClicked, this, &MainWindow::onActionDoubleClicked);
+ connect(ui->cbxProfile, QOverload::of(&QComboBox::currentIndexChanged), this, &MainWindow::onProfileSelChange);
+
+ connect(ui->btnSetActive, &QPushButton::clicked, this, &MainWindow::onBtnSetActiveProfile);
+ connect(ui->btnCreateProfile, &QPushButton::clicked, this, &MainWindow::onBtnCreateProfile);
+ connect(ui->btnDeleteProfile, &QPushButton::clicked, this, &MainWindow::onBtnDeleteProfile);
+
+ connect(ui->btnActionCreate, &QPushButton::clicked, this, &MainWindow::onBtnActionCreate);
+ connect(ui->btnActionDelete, &QPushButton::clicked, this, &MainWindow::onBtnActionDelete);
+ connect(ui->btnActionDuplicate, &QPushButton::clicked, this, &MainWindow::onBtnActionDuplicate);
+}
+
+
+void MainWindow::showEvent(QShowEvent* event)
+{
+ QMainWindow::showEvent(event);
+}
+
+void MainWindow::initPreferences()
+{
+ QFileInfo fiPre("Config/preferences.json");
+ if (!fiPre.exists())
+ {
+ if (!fiPre.dir().exists())
+ fiPre.dir().mkdir(".");
+
+ savePreferences(fiPre.filePath().toStdString(), m_Preferences);
+ }
+ else
+ {
+ loadPreferences(fiPre.filePath().toStdString(), &m_Preferences);
+ }
+
+ QAction * pAction = nullptr;
+ switch (m_Preferences.getThemeType())
+ {
+ case ThemeDefault: pAction = ui->actionThemeDefault; break;
+ case ThemeDark: pAction = ui->actionThemeDark; break;
+ case ThemeBreezeDark: pAction = ui->actionThemeBreezeDark; break;
+ case ThemeBreezeLight: pAction = ui->actionThemeBreezeLight; break;
+ case ThemeConsoleDark: pAction = ui->actionThemeConsoleDark; break;;
+ case ThemeUbuntu: pAction = ui->actionThemeUbuntu; break;
+ default:
+ break;
+ }
+
+ onActionLoadTheme(m_Preferences.getThemeFilePath(), pAction);
+
+ ui->actionViewToolBar->setChecked(m_Preferences.m_bViewToolBar);
+ ui->actionViewStatusBar->setChecked(m_Preferences.m_bViewStatusBar);
+ ui->toolBar->setVisible(m_Preferences.m_bViewToolBar);
+ ui->statusBar->setVisible(m_Preferences.m_bViewStatusBar);
+}
+
+void MainWindow::initProfiles()
+{
+ ui->cbxProfile->clear();
+ QFileInfo fiProfiles("Config/profiles.json");
+ if (!fiProfiles.exists())
+ {
+ if (!fiProfiles.dir().exists())
+ fiProfiles.dir().mkdir(".");
+
+ m_qszProfilesPath = fiProfiles.filePath();
+ onBtnCreateProfile();
+ // First created profile, need to set as default.
+ Profile * pProfile = m_qProfiles[ui->cbxProfile->currentIndex()];
+ m_qszActiveProfile = QString::fromStdString(pProfile->getId());
+ saveProfiles();
+ ui->btnSetActive->setEnabled(false);
+ }
+ else
+ {
+ m_qszProfilesPath = fiProfiles.filePath();
+
+ String szActiveProfile;
+ loadProfiles(m_qszProfilesPath, &szActiveProfile);
+ m_qszActiveProfile = QString::fromStdString(szActiveProfile);
+
+ for (auto && pProfile : m_qProfiles)
+ {
+ QString szProfileName = QString::fromStdString(pProfile->getName());
+ ui->cbxProfile->addItem(szProfileName);
+
+ if (szActiveProfile != pProfile->getId()) continue; // Not active profile
+
+ ui->lbxActions->clear();
+ for (auto && pAction : pProfile->getActions())
+ ui->lbxActions->addItem(QString::fromStdString(pAction->getName()));
+
+ ui->cbxProfile->setCurrentText(szProfileName);
+ }
+
+ ui->lbxActions->setCurrentRow(0);
+ }
+}
+
+#pragma region --- Parser ---
+bool MainWindow::loadPreferences(const std::string & szPath, Preferences * pOutPreferences)
+{
+ if (szPath.empty() || !pOutPreferences)
+ return false;
+
+ JSON rootJson;
+ bpt::read_json(szPath, rootJson);
+
+ int iTheme = rootJson.get("uiThemeType", static_cast(ThemeUbuntu));
+ pOutPreferences->setThemeType(static_cast(iTheme));
+ pOutPreferences->m_bViewToolBar = rootJson.get("viewToolBar", true);
+ pOutPreferences->m_bViewStatusBar = rootJson.get("viewStatusBar", true);
+
+ return true;
+}
+
+bool MainWindow::savePreferences(const std::string & szPath, const Preferences & preferences)
+{
+ if (szPath.empty())
+ return false;
+
+ JSON rootJson;
+ rootJson.put("uiThemeType", preferences.getThemeType());
+ rootJson.put("viewToolBar", preferences.m_bViewToolBar);
+ rootJson.put("viewStatusBar", preferences.m_bViewStatusBar);
+ bpt::write_jsonEx(szPath, rootJson);
+
+ return true;
+}
+
+bool MainWindow::loadPreferences()
+{
+ return loadPreferences("Config/preferences.json", &m_Preferences);
+}
+
+bool MainWindow::savePreferences()
+{
+ return savePreferences("Config/preferences.json", m_Preferences);
+}
+
+bool MainWindow::loadProfiles(const std::string & szProfilesPath, std::string * pszActiveProfileOut)
+{
+ if (szProfilesPath.empty())
+ return false;
+
+ JSON rootJson;
+ bpt::read_json(szProfilesPath, rootJson);
+ *pszActiveProfileOut = rootJson.get("activeProfile", "");
+ int profileCount = rootJson.get("profileCount", 0);
+ qDeleteAll(m_qProfiles);
+ m_qProfiles.clear();
+ m_qProfiles.reserve(profileCount);
+
+ JSON profilesJson = rootJson.get_child("profiles");
+ for (auto && profileJson : profilesJson)
+ {
+ String profileId = profileJson.second.get("id", "");
+ String profileName = profileJson.second.get("name", "");
+ String lastModified = profileJson.second.get("lastModified", "");
+ int actionsCount = profileJson.second.get("actionsCount", 0);
+
+ Profile * pProfile = new Profile(profileId, profileName, lastModified);
+ pProfile->setActionsCapacity(actionsCount);
+
+ JSON actionsJson = profileJson.second.get_child("actions");
+ for (auto && actionJson : actionsJson)
+ {
+ String actionId = actionJson.second.get("id", "");
+ String actionName = actionJson.second.get("actionName", "");
+ String actionType = actionJson.second.get("type", "");
+ String srcKey = actionJson.second.get("srcKey", "");
+ String dstKey = actionJson.second.get("dstKey", "");
+ String appPath = actionJson.second.get("appPath", "");
+ String appArgs = actionJson.second.get("appArgs", "");
+ String createdDate = actionJson.second.get("createdDate", "");
+
+ pProfile->addAction(new Action(actionId, actionName, Action::getType(actionType),
+ srcKey, dstKey,
+ appPath, appArgs, createdDate));
+ }
+
+ m_qProfiles.push_back(pProfile);
+ }
+
+ return true;
+}
+
+bool MainWindow::loadProfiles(const QString & szProfilesPath, QString * pszActiveProfileOut)
+{
+ String szActiveProfile;
+ if (!loadProfiles(szProfilesPath.toStdString(), &szActiveProfile))
+ return false;
+
+ *pszActiveProfileOut = QString::fromStdString(szActiveProfile);
+
+ return true;
+}
+
+bool MainWindow::loadProfiles(const QString & szProfilesPath, std::string * pszActiveProfileOut)
+{
+ return loadProfiles(szProfilesPath.toStdString(), pszActiveProfileOut);
+}
+
+bool MainWindow::reloadProfiles()
+{
+ if (!loadProfiles(m_qszProfilesPath, &m_qszActiveProfile))
+ return false;
+
+ onProfileSelChange(ui->cbxProfile->currentIndex());
+
+ return true;
+}
+
+bool MainWindow::saveProfiles(const std::string & szProfilesPath, const std::string & szActiveProfileId)
+{
+ if (szProfilesPath.empty() || szActiveProfileId.empty())
+ return false;
+
+ JSON rootJson;
+ rootJson.put("activeProfile", szActiveProfileId);
+ rootJson.put("profileCount", m_qProfiles.size());
+
+ JSON profilesJson;
+ for (auto && pProfile : m_qProfiles)
+ {
+ JSON profileJson;
+ profileJson.put("id", pProfile->getId());
+ profileJson.put("name", pProfile->getName());
+ profileJson.put("lastModified", pProfile->getLastModified());
+ profileJson.put("actionsCount", pProfile->getActionsCount());
+
+ JSON actionsJson;
+ for (auto && pAction : pProfile->getActions())
+ {
+ JSON actionJson;
+ actionJson.put("id", pAction->getId());
+ actionJson.put("actionName", pAction->getName());
+ actionJson.put("type", Action::getType(pAction->getType()));
+ actionJson.put("srcKey", pAction->getSrcKey());
+ actionJson.put("dstKey", pAction->getDstKey());
+ actionJson.put("appPath", pAction->getAppPath());
+ actionJson.put("appArgs", pAction->getAppArgs());
+ actionJson.put("createdDate", pAction->getCreatedDate());
+
+ actionsJson.push_back(std::make_pair("", actionJson));
+ }
+
+ profileJson.push_back(std::make_pair("actions", actionsJson));
+ profilesJson.push_back(std::make_pair("", profileJson));
+ }
+ rootJson.add_child("profiles", profilesJson);
+
+ bpt::write_jsonEx(szProfilesPath, rootJson);
+ Hook::sendReloadSignal();
+
+ return true;
+}
+
+bool MainWindow::saveProfiles(const QString & szProfilesPath, const QString & szActiveProfileId)
+{
+ return saveProfiles(szProfilesPath.toStdString(), szActiveProfileId.toStdString());
+}
+
+bool MainWindow::saveProfiles()
+{
+ return saveProfiles(m_qszProfilesPath, m_qszActiveProfile);
+}
+
+// end --- Parser ---
+#pragma endregion
+
+
+bool MainWindow::isActiveProfile(Profile * pProfile)
+{
+ return pProfile->getId() == m_qszActiveProfile.toStdString();
+}
+
+void MainWindow::onProfileSelChange(int iIndex)
+{
+ if (iIndex < 0 || iIndex > m_qProfiles.size())
+ {
+ ui->lbxActions->clear();
+ ui->btnSetActive->setEnabled(false);
+ ui->btnDeleteProfile->setEnabled(false);
+ ui->btnActionCreate->setEnabled(false);
+ return;
+ }
+
+ Profile * pProfile = m_qProfiles[iIndex];
+ ui->btnSetActive->setEnabled(!isActiveProfile(pProfile));
+ ui->btnDeleteProfile->setEnabled(true);
+ ui->btnActionCreate->setEnabled(true);
+
+ disconnect(ui->lbxActions, &QListWidget::currentRowChanged, this, &MainWindow::onActionSelChange);
+ ui->lbxActions->clear();
+ for (auto && pAction : pProfile->getActions())
+ ui->lbxActions->addItem(QString::fromStdString(pAction->getName()));
+ connect(ui->lbxActions, &QListWidget::currentRowChanged, this, &MainWindow::onActionSelChange);
+
+ if (!pProfile->getActionsCount())
+ onActionSelChange(-1);
+ else
+ ui->lbxActions->setCurrentRow(0);
+}
+
+void MainWindow::onBtnSetActiveProfile()
+{
+ Profile * pProfile = m_qProfiles[ui->cbxProfile->currentIndex()];
+ JSON rootJson;
+ bpt::read_json(m_qszProfilesPath.toStdString(), rootJson);
+ rootJson.put("activeProfile", pProfile->getId());
+ bpt::write_jsonEx(m_qszProfilesPath.toStdString(), rootJson);
+ reloadProfiles();
+ ui->btnSetActive->setEnabled(false);
+}
+
+void MainWindow::onBtnDeleteProfile()
+{
+ const int iIndex = ui->cbxProfile->currentIndex();
+ Profile * pProfile = m_qProfiles[iIndex];
+ ui->cbxProfile->removeItem(iIndex);
+ if (isActiveProfile(pProfile) && m_qProfiles.count() > 0)
+ {
+ m_qszActiveProfile = QString::fromStdString(m_qProfiles.first()->getId());
+ delete pProfile;
+ ui->cbxProfile->setCurrentIndex(0);
+ }
+
+ m_qProfiles.removeAt(iIndex);
+
+ saveProfiles();
+ reloadProfiles();
+}
+
+void MainWindow::onBtnCreateProfile()
+{
+ bool bOk;
+ QString szProfileName = QInputDialog::getText(this, tr("Create Profile"),
+ tr("Profile Name:"), QLineEdit::Normal,
+ QDir::home().dirName(), &bOk);
+ if (!bOk && szProfileName.isEmpty()) return;
+
+ const int iIndex = ui->cbxProfile->count() > 0 ? ui->cbxProfile->currentIndex() + 1 : 0;
+
+ Profile * pProfile = new Profile(szProfileName.toStdString());
+ m_qProfiles.push_back(pProfile);
+ ui->cbxProfile->addItem(szProfileName);
+ ui->cbxProfile->setCurrentIndex(iIndex);
+ saveProfiles();
+}
+
+void MainWindow::onActionSelChange(int iIndex)
+{
+ const bool bEnabled = iIndex != -1;
+ ui->btnActionDelete->setEnabled(bEnabled);
+ ui->btnActionDuplicate->setEnabled(bEnabled);
+}
+
+void MainWindow::onActionDoubleClicked(const QModelIndex & index)
+{
+ Profile * pProfile = m_qProfiles[ui->cbxProfile->currentIndex()];
+ Action * pAction = pProfile->getActionByIndex(index.row());
+ m_pActionEditWindow = new ActionEditWindow(this, pAction);
+ connect(m_pActionEditWindow, &ActionEditWindow::onSaved, this, &MainWindow::onActionSaved);
+ m_pActionEditWindow->exec();
+}
+
+void MainWindow::onBtnActionCreate()
+{
+ m_pActionEditWindow = new ActionEditWindow(this);
+ connect(m_pActionEditWindow, &ActionEditWindow::onCreated, this, &MainWindow::onActionCreated);
+ m_pActionEditWindow->exec();
+}
+
+void MainWindow::onBtnActionDelete()
+{
+ const int iIndex = ui->lbxActions->currentRow();
+ Profile * pProfile = m_qProfiles[ui->cbxProfile->currentIndex()];
+ pProfile->deleteActionByIndex(iIndex);
+
+ saveProfiles();
+ reloadProfiles();
+ ui->lbxActions->setCurrentRow(iIndex - 1);
+ if ((iIndex - 1) < 0)
+ ui->btnActionCreate->setFocus();
+}
+
+void MainWindow::onBtnActionDuplicate()
+{
+ const int iIndex = ui->lbxActions->currentRow();
+ Profile * pProfile = m_qProfiles[ui->cbxProfile->currentIndex()];
+ Action * pAction = pProfile->getActionByIndex(iIndex);
+
+ Action * pNewAction = new Action(pAction->getName(), pAction->getType(), pAction->getSrcKey(),
+ pAction->getDstKey(), pAction->getAppPath(), pAction->getAppArgs());
+
+ pProfile->insertAction(iIndex, pNewAction);
+
+ saveProfiles();
+ reloadProfiles();
+ ui->lbxActions->setCurrentRow(iIndex + 1);
+}
+
+void MainWindow::onActionSaved()
+{
+ const int iIndex = ui->lbxActions->currentRow();
+ saveProfiles();
+ reloadProfiles();
+ ui->lbxActions->setCurrentRow(iIndex);
+}
+
+void MainWindow::onActionCreated(Action * pAction)
+{
+ const int iIndex = ui->lbxActions->currentRow();
+ Profile * pProfile = m_qProfiles[ui->cbxProfile->currentIndex()];
+ pProfile->addAction(pAction);
+ saveProfiles();
+ reloadProfiles();
+ ui->lbxActions->setCurrentRow(iIndex == -1 ? 0 : iIndex + 1);
+}
+
+
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
+
+void MainWindow::onActionFileOpen()
+{
+ QString szDesktop = QStandardPaths::standardLocations(QStandardPaths::DesktopLocation).first();
+ QString szFileName = QFileDialog::getOpenFileName(this, tr("Open Profiles File"), szDesktop, tr("Profiles File (*.json)"));
+ if (szFileName.isEmpty()) return;
+
+ auto answer = QMessageBox::warning(this, "WARNING", "Opening existing profiles file will override the existing profiles setup "
+ "and previous configuration will be lost.\n"
+ "Are you sure you want to continue?",
+ QMessageBox::Yes | QMessageBox::No, QMessageBox::No);
+
+ if (answer != QMessageBox::Yes) return;
+
+ if (!QFile::copy(szFileName, m_qszProfilesPath))
+ {
+ qDebug() << "[MainWindow::onActionFileOpen] - Failed to copy file from '" << szFileName << "' to '" << m_qszProfilesPath << "'";
+ return;
+ }
+}
+
+void MainWindow::onActionFileSave()
+{
+}
+
+void MainWindow::onActionFileSaveAs()
+{
+ QString szFileDstPath = QFileDialog::getSaveFileName(this, tr("Save As File"), "", tr("Profiles File (*.json)"));
+ if (szFileDstPath.isEmpty()) return;
+
+ if (!QFile::copy(m_qszProfilesPath, szFileDstPath))
+ {
+ qDebug() << "[MainWindow::onActionFileSaveAs] - Failed to copy file from '" << m_qszProfilesPath << "' to '" << szFileDstPath << "'";
+ return;
+ }
+}
+
+void MainWindow::onActionFileRestartService()
+{
+ QtServiceController service("QuickCut Service");
+ service.stop();
+ service.start();
+}
+
+void MainWindow::onActionFileExit()
+{
+ close();
+}
+
+void MainWindow::onActionViewToolBar()
+{
+ const bool bChecked = ui->actionViewToolBar->isChecked();
+ ui->toolBar->setVisible(bChecked);
+ m_Preferences.m_bViewToolBar = bChecked;
+ savePreferences();
+}
+
+void MainWindow::onActionViewStatusBar()
+{
+ const bool bChecked = ui->actionViewStatusBar->isChecked();
+ ui->statusBar->setVisible(bChecked);
+ m_Preferences.m_bViewStatusBar = bChecked;
+ savePreferences();
+}
+
+void MainWindow::onActionViewRefresh()
+{
+ Hook::sendReloadSignal();
+ initProfiles();
+}
+
+void MainWindow::onActionHelpAbout()
+{
+ m_pAboutWindow = new AboutWindow(this);
+ m_pAboutWindow->exec();
+}
+
+void MainWindow::onActionHelpExamples()
+{
+ m_pExamplesWindow = new ExamplesWindow(this);
+ m_pExamplesWindow->exec();
+}
+
+void MainWindow::onActionHelpCheckUpdates()
+{
+ m_pCheckUpdatesWindow = new CheckUpdatesWindow(this);
+ m_pCheckUpdatesWindow->exec();
+}
+
+void MainWindow::onActionLoadTheme(eThemeType eType, QAction * pAction/*= nullptr*/)
+{
+ onActionLoadTheme(Preferences::getThemeFilePath(eType), pAction);
+ m_Preferences.setThemeType(eType);
+ savePreferences();
+}
+void MainWindow::onActionLoadTheme(const QString & szQssPath, QAction * pAction/*= nullptr*/)
+{
+ for (auto && qAction : m_qThemeActions)
+ qAction->setChecked(false);
+
+ if (pAction)
+ pAction->setChecked(true);
+
+ QFile file(szQssPath);
+ if (!file.open(QFile::ReadOnly | QFile::Text))
+ {
+ qApp->setStyleSheet("");
+ return;
+ }
+
+ QTextStream ts(&file);
+ qApp->setStyleSheet(ts.readAll());
+}
+
+void MainWindow::onLoadCustomStylesheet()
+{
+ QString szFileName = QFileDialog::getOpenFileName(this, tr("Open Stylesheet File"), "", tr("Stylesheet File (*.qss)"));
+ if (szFileName.isEmpty()) return;
+
+ onActionLoadTheme(szFileName);
+}
diff --git a/src/QuickCut/MainWindow.h b/src/QuickCut/MainWindow.h
new file mode 100644
index 0000000..adda134
--- /dev/null
+++ b/src/QuickCut/MainWindow.h
@@ -0,0 +1,98 @@
+
+#pragma once
+
+#include
+#include "ui_MainWindow.h"
+
+#include "Profile.h"
+#include "Preferences.h"
+
+
+class ExamplesWindow;
+class CheckUpdatesWindow;
+class AboutWindow;
+class ActionEditWindow;
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget * parent = nullptr);
+ ~MainWindow();
+
+ void connectSlots();
+
+ void initPreferences();
+ void initProfiles();
+
+ // TODO: Implement parser and move all of these.
+ bool loadPreferences(const std::string & szPath, Preferences * pOutPreferences);
+ bool savePreferences(const std::string & szPath, const Preferences & preferences);
+ bool loadPreferences();
+ bool savePreferences();
+
+ bool loadProfiles(const std::string & szProfilesPath, std::string * pszActiveProfileOut);
+ bool loadProfiles(const QString & szProfilesPath, QString * pszActiveProfileOut);
+ bool loadProfiles(const QString & szProfilesPath, std::string * pszActiveProfileOut);
+ bool reloadProfiles();
+ bool saveProfiles(const std::string & szProfilesPath, const std::string & szActiveProfileId);
+ bool saveProfiles(const QString & szProfilesPath, const QString & szActiveProfileId);
+ bool saveProfiles();
+
+
+ bool isActiveProfile(Profile * pProfile);
+ void showEvent(QShowEvent * event) override;
+
+
+public slots:
+
+ void onProfileSelChange(int iIndex);
+ void onBtnSetActiveProfile();
+ void onBtnDeleteProfile();
+ void onBtnCreateProfile();
+
+ void onActionSelChange(int iIndex);
+ void onActionDoubleClicked(const QModelIndex & index);
+ void onBtnActionCreate();
+ void onBtnActionDelete();
+ void onBtnActionDuplicate();
+
+ void onActionSaved();
+ void onActionCreated(Action * pAction);
+
+ // File Menu
+ void onActionFileOpen();
+ void onActionFileSave();
+ void onActionFileSaveAs();
+ void onActionFileRestartService();
+ void onActionFileExit();
+
+ void onActionViewToolBar();
+ void onActionViewStatusBar();
+ void onActionViewRefresh();
+
+ void onActionHelpAbout();
+ void onActionHelpExamples();
+ void onActionHelpCheckUpdates();
+
+ void onActionLoadTheme(eThemeType eType, QAction * pAction = nullptr);
+ void onActionLoadTheme(const QString & szQssPath, QAction * pAction = nullptr);
+ void onLoadCustomStylesheet();
+
+
+private:
+ Ui::MainWindowClass * ui;
+
+ ActionEditWindow * m_pActionEditWindow;
+ AboutWindow * m_pAboutWindow;
+ CheckUpdatesWindow * m_pCheckUpdatesWindow;
+ ExamplesWindow * m_pExamplesWindow;
+
+ QMap m_qThemeActions;
+ QList m_qProfiles;
+ QString m_qszProfilesPath;
+ QString m_qszActiveProfile;
+ Preferences m_Preferences;
+
+};
diff --git a/src/QuickCut/MainWindow.qrc b/src/QuickCut/MainWindow.qrc
new file mode 100644
index 0000000..108d5c3
--- /dev/null
+++ b/src/QuickCut/MainWindow.qrc
@@ -0,0 +1,22 @@
+
+
+ Resources/logo.png
+ Resources/btn_start_recording.png
+ Resources/btn_stop_recording.png
+ Resources/file_exit.png
+ Resources/file_open.png
+ Resources/file_save.png
+ Resources/file_saveas.png
+ Resources/help_about.png
+ Resources/help_check_updates.png
+ Resources/help_help.png
+ Resources/help_search.png
+ Resources/preferences.png
+ Resources/preferences_open_theme.png
+ Resources/preferences_theme.png
+ Resources/view_refresh.png
+ Resources/view_statusbar.png
+ Resources/view_toolbar.png
+ Resources/file_restart_service.png
+
+
diff --git a/src/QuickCut/MainWindow.ui b/src/QuickCut/MainWindow.ui
new file mode 100644
index 0000000..def2a4a
--- /dev/null
+++ b/src/QuickCut/MainWindow.ui
@@ -0,0 +1,462 @@
+
+
+ MainWindowClass
+
+
+
+ 0
+ 0
+ 310
+ 346
+
+
+
+ QuickCut
+
+
+
+ :/Resources/logo.png
+
+
+
+
+
+
+
+
+ 12
+ 50
+ false
+
+
+
+ User Actions
+
+
+
+
+
+
+
+
+
+
+
+
+ 95
+ 40
+
+
+
+
+ 85
+ 40
+
+
+
+ Create Action
+
+
+
+
+
+
+
+ 95
+ 40
+
+
+
+
+ 85
+ 40
+
+
+
+ Delete Action
+
+
+
+
+
+
+
+ 95
+ 40
+
+
+
+
+ 85
+ 40
+
+
+
+ Duplicate Action
+
+
+
+
+
+
+
+
+ Profile
+
+
+
+
+
+
+
+
+ 32
+ 16
+
+
+
+
+ 32
+ 16
+
+
+
+ Name:
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 55
+ 25
+
+
+
+ Default
+
+
+
+
+
+
+
+ 55
+ 25
+
+
+
+ Delete
+
+
+
+
+
+
+
+ 55
+ 25
+
+
+
+ Create
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 0
+ 0
+ 310
+ 21
+
+
+
+
+ File
+
+
+
+
+
+
+
+
+
+
+ Edit
+
+
+
+
+ Preferences
+
+
+
+ Theme
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ View
+
+
+
+
+
+
+
+
+ Help
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ TopToolBarArea
+
+
+ false
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ :/Resources/file_open.png:/Resources/file_open.png
+
+
+ Open
+
+
+
+
+
+ :/Resources/file_save.png:/Resources/file_save.png
+
+
+ Save
+
+
+
+
+
+ :/Resources/file_saveas.png:/Resources/file_saveas.png
+
+
+ Save As...
+
+
+
+
+
+ :/Resources/file_exit.png:/Resources/file_exit.png
+
+
+ Exit
+
+
+
+
+
+ :/Resources/help_about.png:/Resources/help_about.png
+
+
+ About
+
+
+
+
+
+ :/Resources/help_search.png:/Resources/help_search.png
+
+
+ Examples
+
+
+
+
+
+ :/Resources/help_check_updates.png:/Resources/help_check_updates.png
+
+
+ Check for updates...
+
+
+
+
+ Fully Map Key
+
+
+
+
+ true
+
+
+ true
+
+
+
+ :/Resources/view_toolbar.png:/Resources/view_toolbar.png
+
+
+ Tool Bar
+
+
+
+
+ true
+
+
+ true
+
+
+
+ :/Resources/view_statusbar.png:/Resources/view_statusbar.png
+
+
+ Status Bar
+
+
+
+
+ true
+
+
+ false
+
+
+ Default
+
+
+
+
+ true
+
+
+ Dark
+
+
+
+
+
+ :/Resources/view_refresh.png:/Resources/view_refresh.png
+
+
+ Refresh
+
+
+
+
+
+ :/Resources/preferences_open_theme.png:/Resources/preferences_open_theme.png
+
+
+ Load Custom Stylesheet...
+
+
+
+
+ true
+
+
+ Breeze Dark
+
+
+
+
+ true
+
+
+ Breeze Light
+
+
+
+
+ true
+
+
+ true
+
+
+ Ubuntu
+
+
+
+
+ true
+
+
+ Console Dark
+
+
+
+
+
+ :/Resources/file_restart_service.png:/Resources/file_restart_service.png
+
+
+ Restart Service
+
+
+
+
+
+ lbxActions
+ btnActionCreate
+ btnActionDelete
+ btnActionDuplicate
+ cbxProfile
+ btnCreateProfile
+ btnSetActive
+
+
+
+
+
+
diff --git a/src/QuickCut/Preferences.cpp b/src/QuickCut/Preferences.cpp
new file mode 100644
index 0000000..4189d7a
--- /dev/null
+++ b/src/QuickCut/Preferences.cpp
@@ -0,0 +1,38 @@
+
+#include "Preferences.h"
+
+Preferences::Preferences()
+ : m_bViewToolBar(true)
+ , m_bViewStatusBar(true)
+ , m_eThemeType(ThemeUbuntu)
+{
+}
+
+QString Preferences::getThemeFilePath() const
+{
+ return getThemeFilePath(m_eThemeType);
+}
+
+QString Preferences::getThemeFilePath(eThemeType eType)
+{
+ switch (eType)
+ {
+ case ThemeDefault: return "";
+ case ThemeDark: return ":stylesheet/theme_dark.qss";
+ case ThemeBreezeDark: return ":stylesheet/theme_breezeDark.qss";
+ case ThemeBreezeLight: return ":stylesheet/theme_breezeLight.qss";
+ case ThemeConsoleDark: return ":stylesheet/theme_console.qss";
+ case ThemeUbuntu:
+ default: return ":stylesheet/theme_ubuntu.qss";
+ }
+}
+
+eThemeType Preferences::getThemeType() const
+{
+ return m_eThemeType;
+}
+
+void Preferences::setThemeType(eThemeType eType)
+{
+ m_eThemeType = eType;
+}
diff --git a/src/QuickCut/Preferences.h b/src/QuickCut/Preferences.h
new file mode 100644
index 0000000..83ac1a9
--- /dev/null
+++ b/src/QuickCut/Preferences.h
@@ -0,0 +1,35 @@
+
+#pragma once
+
+#include
+
+
+enum eThemeType
+{
+ ThemeDefault = 0,
+ ThemeDark,
+ ThemeBreezeDark,
+ ThemeBreezeLight,
+ ThemeConsoleDark,
+ ThemeUbuntu,
+
+ THEME_COUNT
+};
+
+class Preferences
+{
+public:
+ Preferences();
+
+ QString getThemeFilePath() const;
+ static QString getThemeFilePath(eThemeType eType);
+ eThemeType getThemeType() const;
+ void setThemeType(eThemeType eType);
+
+public:
+ bool m_bViewToolBar;
+ bool m_bViewStatusBar;
+
+ eThemeType m_eThemeType;
+
+};
\ No newline at end of file
diff --git a/src/QuickCut/QShortcutInput.cpp b/src/QuickCut/QShortcutInput.cpp
new file mode 100644
index 0000000..60ff4e6
--- /dev/null
+++ b/src/QuickCut/QShortcutInput.cpp
@@ -0,0 +1,113 @@
+
+#include "QShortcutInput.h"
+
+#include
+
+
+QShortcutInput * QShortcutInput::s_pInstance = nullptr;
+
+#ifdef Q_OS_WIN
+HHOOK QShortcutInput::s_hHook = nullptr;
+#endif
+
+
+QShortcutInput::QShortcutInput(QWidget * parent)
+ : QLineEdit(parent)
+{ }
+
+QShortcutInput::~QShortcutInput()
+{
+ if (s_hHook)
+ {
+ qDebug() << "[QShortcutInput::dtor] - Unhooking...";
+ UnhookWindowsHookEx(s_hHook);
+ s_pInstance = nullptr;
+ s_hHook = nullptr;
+ }
+}
+
+#ifdef Q_OS_WIN
+LRESULT CALLBACK QShortcutInput::WndProc(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ if (nCode < 0 || !s_pInstance)
+ return CallNextHookEx(s_hHook, nCode, wParam, lParam);
+
+ KBDLLHOOKSTRUCT * pKbd = reinterpret_cast(lParam);
+
+ // Workaround for auto-repeat, since low level hook doesn't provide KF_REPEAT flags in lParam:
+ // (lParam & KF_REPEAT)
+ static DWORD dwPrevVkCode = 0;
+
+ static QString szKeys;
+
+ if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
+ {
+ if (dwPrevVkCode == pKbd->vkCode)
+ return -1;
+
+ dwPrevVkCode = pKbd->vkCode;
+
+ if (s_pInstance->property("multiShortcuts").toBool())
+ szKeys += QString::number(pKbd->vkCode, 16);
+ else
+ szKeys = QString::number(pKbd->vkCode, 16);
+
+ s_pInstance->setText(szKeys);
+
+ return -1;
+ }
+
+ if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
+ {
+ szKeys.clear();
+
+ dwPrevVkCode = 0;
+
+ return -1;
+ }
+
+ return CallNextHookEx(s_hHook, nCode, wParam, lParam);
+}
+#endif // #ifdef Q_OS_WIN
+
+#ifdef Q_OS_WIN
+void QShortcutInput::focusInEvent(QFocusEvent * event)
+{
+ if (!s_hHook)
+ {
+ qDebug() << "[QShortcutInput::focusInEvent] - Hooking...";
+ s_pInstance = this;
+ s_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, WndProc, nullptr, 0);
+ if (!s_hHook)
+ {
+ qDebug() << "[QShortcutInput::focusInEvent] - Hook failed...";
+ }
+ }
+}
+#elif Q_OS_UNIX
+void QShortcutInput::focusInEvent(QFocusEvent * event)
+{
+ // TODO: Add unix hook.
+
+}
+#endif // #ifdef Q_OS_WIN
+
+
+#ifdef Q_OS_WIN
+void QShortcutInput::focusOutEvent(QFocusEvent * event)
+{
+ if (s_hHook)
+ {
+ qDebug() << "[QShortcutInput::focusInEvent] - Unhooking...";
+ UnhookWindowsHookEx(s_hHook);
+ s_pInstance = nullptr;
+ s_hHook = nullptr;
+ }
+}
+#elif Q_OS_UNIX
+void QShortcutInput::focusOutEvent(QFocusEvent * event)
+{
+ // TODO: Add unix hook.
+
+}
+#endif // #ifdef Q_OS_WIN
diff --git a/src/QuickCut/QShortcutInput.h b/src/QuickCut/QShortcutInput.h
new file mode 100644
index 0000000..2429f4b
--- /dev/null
+++ b/src/QuickCut/QShortcutInput.h
@@ -0,0 +1,35 @@
+
+#pragma once
+
+#include
+
+#ifdef Q_OS_WIN
+#include
+#endif
+
+
+class QShortcutInput : public QLineEdit
+{
+ Q_OBJECT
+
+public:
+ QShortcutInput(QWidget * parent);
+ ~QShortcutInput();
+
+#ifdef Q_OS_WIN
+ static LRESULT CALLBACK WndProc(int nCode, WPARAM wParam, LPARAM lParam);
+#endif
+
+protected:
+ void focusInEvent(QFocusEvent * event) override;
+ void focusOutEvent(QFocusEvent * event) override;
+
+public:
+ static QShortcutInput * s_pInstance;
+
+#ifdef Q_OS_WIN
+ static HHOOK s_hHook;
+#endif
+
+
+};
\ No newline at end of file
diff --git a/src/QuickCut/QuickCut.exe.manifest b/src/QuickCut/QuickCut.exe.manifest
new file mode 100644
index 0000000..16e40a9
--- /dev/null
+++ b/src/QuickCut/QuickCut.exe.manifest
@@ -0,0 +1,76 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/QuickCut/QuickCut.ico b/src/QuickCut/QuickCut.ico
new file mode 100644
index 0000000..36a2187
Binary files /dev/null and b/src/QuickCut/QuickCut.ico differ
diff --git a/src/QuickCut/QuickCut.rc b/src/QuickCut/QuickCut.rc
new file mode 100644
index 0000000..b73d711
--- /dev/null
+++ b/src/QuickCut/QuickCut.rc
@@ -0,0 +1,4 @@
+//#include
+
+IDI_ICON1 ICON DISCARDABLE "QuickCut.ico"
+//CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "QuickCut.exe.manifest"
\ No newline at end of file
diff --git a/src/QuickCut/QuickCut.vcxproj b/src/QuickCut/QuickCut.vcxproj
new file mode 100644
index 0000000..4931eaa
--- /dev/null
+++ b/src/QuickCut/QuickCut.vcxproj
@@ -0,0 +1,382 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {B12702AD-ABFB-343A-A199-8E24837244A3}
+ Qt4VSv1.0
+ 10.0.17763.0
+
+
+
+ Application
+ v141
+
+
+ Application
+ v141
+
+
+ Application
+ v141
+
+
+ Application
+ v141
+
+
+
+ $(MSBuildProjectDirectory)\QtMsBuild
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ true
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ true
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ true
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)
+ Disabled
+ ProgramDatabase
+ MultiThreadedDebugDLL
+ true
+ stdcpp17
+
+
+ Windows
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ true
+ qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)
+
+
+ Uic'ing %(Identity)...
+ .\GeneratedFiles\ui_%(Filename).h
+
+
+ Rcc'ing %(Identity)...
+ .\GeneratedFiles\qrc_%(Filename).cpp
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)
+ Disabled
+ ProgramDatabase
+ MultiThreadedDebugDLL
+ true
+ stdcpp17
+
+
+ Windows
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ true
+ qtmaind.lib;Qt5Cored.lib;Qt5Guid.lib;Qt5Widgetsd.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)
+
+
+ Uic'ing %(Identity)...
+ .\GeneratedFiles\ui_%(Filename).h
+
+
+ Rcc'ing %(Identity)...
+ .\GeneratedFiles\qrc_%(Filename).cpp
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)
+
+ MultiThreadedDLL
+ true
+ stdcpp17
+
+
+ Windows
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ false
+ qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)
+
+
+ Uic'ing %(Identity)...
+ .\GeneratedFiles\ui_%(Filename).h
+
+
+ Rcc'ing %(Identity)...
+ .\GeneratedFiles\qrc_%(Filename).cpp
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)
+
+
+ MultiThreadedDLL
+ true
+ stdcpp17
+
+
+ Windows
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ false
+ qtmain.lib;Qt5Core.lib;Qt5Gui.lib;Qt5Widgets.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets;%(AdditionalIncludeDirectories)
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;QT_GUI_LIB;QT_WIDGETS_LIB;%(PreprocessorDefinitions)
+
+
+ Uic'ing %(Identity)...
+ .\GeneratedFiles\ui_%(Filename).h
+
+
+ Rcc'ing %(Identity)...
+ .\GeneratedFiles\qrc_%(Filename).cpp
+
+
+
+
+
+
+
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+
+
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+
+
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+
+
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+
+
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+
+
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.\GeneratedFiles;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;$(QTDIR)\include\QtGui;$(QTDIR)\include\QtANGLE;$(QTDIR)\include\QtWidgets
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/QuickCut/QuickCut.vcxproj.filters b/src/QuickCut/QuickCut.vcxproj.filters
new file mode 100644
index 0000000..4c1565d
--- /dev/null
+++ b/src/QuickCut/QuickCut.vcxproj.filters
@@ -0,0 +1,191 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}
+ qrc;*
+ false
+
+
+ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}
+ qrc;*
+ false
+
+
+ {99349809-55BA-4b9d-BF79-8FDBB0286EB3}
+ ui
+
+
+ {2a4189da-2ece-42ba-8e03-b1d8a6f263c4}
+
+
+ {80c4178e-2351-45d0-8f90-989ac359865e}
+
+
+ {53dc6066-eb3c-4322-96ec-0aca7ea14107}
+
+
+ {ecfa802f-1d58-4a93-becc-e4ec270eb0f5}
+
+
+ {fe2dcfee-f9b3-4235-8061-e6ffb1101abb}
+
+
+ {07788dd5-09af-4d85-bdd6-6d8081874c7b}
+
+
+ {6a78aaec-05d5-4802-a480-b54fa29d4754}
+
+
+ {e0269331-a5e5-466a-81a2-0fe92d77afd2}
+
+
+ {fa024f4c-4d40-4adb-85b8-4ba6d64943a6}
+
+
+
+
+
+ Source Files\Widgets
+
+
+ Source Files\Windows
+
+
+ Source Files\Windows
+
+
+ Source Files\Windows
+
+
+ Source Files\Windows
+
+
+ Source Files\Windows
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files\Models
+
+
+
+
+ Resource Files\Form Files
+
+
+ Resource Files\Form Files
+
+
+ Resource Files\Form Files
+
+
+ Resource Files\Form Files
+
+
+ Resource Files\Form Files
+
+
+
+
+ Resource Files\Themes
+
+
+ Resource Files
+
+
+
+
+ Source Files\Widgets
+
+
+ Source Files\Windows
+
+
+ Source Files\Windows
+
+
+ Source Files\Windows
+
+
+ Source Files\Windows
+
+
+ Source Files\Windows
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Resource Files\Themes\Dark
+
+
+ Resource Files\Themes\Breeze
+
+
+ Resource Files\Themes\Breeze
+
+
+ Resource Files\Themes\Misc
+
+
+ Resource Files\Themes\Misc
+
+
+ Resource Files\Themes\Misc
+
+
+ Resource Files\Themes\Misc
+
+
+ Resource Files\Themes\Misc
+
+
+ Resource Files\Themes\Misc
+
+
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files\Models
+
+
+ Source Files\Shared\QtService
+
+
+ Source Files\Shared\QtService
+
+
+
+
+ Resource Files
+
+
+
\ No newline at end of file
diff --git a/src/QuickCut/QuickCut.vcxproj.user b/src/QuickCut/QuickCut.vcxproj.user
new file mode 100644
index 0000000..f109c46
--- /dev/null
+++ b/src/QuickCut/QuickCut.vcxproj.user
@@ -0,0 +1,28 @@
+
+
+
+
+ C:\Qt\5.12.0\msvc2017
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ WindowsLocalDebugger
+ PATH=$(QTDIR)\bin%3b$(PATH)
+
+
+ C:\Qt\5.12.0\msvc2017_64
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ WindowsLocalDebugger
+ PATH=$(QTDIR)\bin%3b$(PATH)
+
+
+ C:\Qt\5.12.0\msvc2017
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ WindowsLocalDebugger
+ PATH=$(QTDIR)\bin%3b$(PATH)
+
+
+ C:\Qt\5.12.0\msvc2017_64
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ WindowsLocalDebugger
+ PATH=$(QTDIR)\bin%3b$(PATH)
+
+
\ No newline at end of file
diff --git a/src/QuickCut/Resources/btn_start_recording.png b/src/QuickCut/Resources/btn_start_recording.png
new file mode 100644
index 0000000..33cbab9
Binary files /dev/null and b/src/QuickCut/Resources/btn_start_recording.png differ
diff --git a/src/QuickCut/Resources/btn_stop_recording.png b/src/QuickCut/Resources/btn_stop_recording.png
new file mode 100644
index 0000000..0ff1515
Binary files /dev/null and b/src/QuickCut/Resources/btn_stop_recording.png differ
diff --git a/src/QuickCut/Resources/file_exit.png b/src/QuickCut/Resources/file_exit.png
new file mode 100644
index 0000000..13095dd
Binary files /dev/null and b/src/QuickCut/Resources/file_exit.png differ
diff --git a/src/QuickCut/Resources/file_open.png b/src/QuickCut/Resources/file_open.png
new file mode 100644
index 0000000..5c50028
Binary files /dev/null and b/src/QuickCut/Resources/file_open.png differ
diff --git a/src/QuickCut/Resources/file_restart_service.png b/src/QuickCut/Resources/file_restart_service.png
new file mode 100644
index 0000000..dbd34db
Binary files /dev/null and b/src/QuickCut/Resources/file_restart_service.png differ
diff --git a/src/QuickCut/Resources/file_save.png b/src/QuickCut/Resources/file_save.png
new file mode 100644
index 0000000..e1c3ac7
Binary files /dev/null and b/src/QuickCut/Resources/file_save.png differ
diff --git a/src/QuickCut/Resources/file_saveas.png b/src/QuickCut/Resources/file_saveas.png
new file mode 100644
index 0000000..ecbd10d
Binary files /dev/null and b/src/QuickCut/Resources/file_saveas.png differ
diff --git a/src/QuickCut/Resources/help_about.png b/src/QuickCut/Resources/help_about.png
new file mode 100644
index 0000000..d929681
Binary files /dev/null and b/src/QuickCut/Resources/help_about.png differ
diff --git a/src/QuickCut/Resources/help_check_updates.png b/src/QuickCut/Resources/help_check_updates.png
new file mode 100644
index 0000000..79ff5ea
Binary files /dev/null and b/src/QuickCut/Resources/help_check_updates.png differ
diff --git a/src/QuickCut/Resources/help_help.png b/src/QuickCut/Resources/help_help.png
new file mode 100644
index 0000000..5752d17
Binary files /dev/null and b/src/QuickCut/Resources/help_help.png differ
diff --git a/src/QuickCut/Resources/help_search.png b/src/QuickCut/Resources/help_search.png
new file mode 100644
index 0000000..ba4aaf7
Binary files /dev/null and b/src/QuickCut/Resources/help_search.png differ
diff --git a/src/QuickCut/Resources/logo.png b/src/QuickCut/Resources/logo.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCut/Resources/logo.png differ
diff --git a/src/QuickCut/Resources/preferences.png b/src/QuickCut/Resources/preferences.png
new file mode 100644
index 0000000..6811538
Binary files /dev/null and b/src/QuickCut/Resources/preferences.png differ
diff --git a/src/QuickCut/Resources/preferences_open_theme.png b/src/QuickCut/Resources/preferences_open_theme.png
new file mode 100644
index 0000000..c729dc9
Binary files /dev/null and b/src/QuickCut/Resources/preferences_open_theme.png differ
diff --git a/src/QuickCut/Resources/preferences_theme.png b/src/QuickCut/Resources/preferences_theme.png
new file mode 100644
index 0000000..33e0efc
Binary files /dev/null and b/src/QuickCut/Resources/preferences_theme.png differ
diff --git a/src/QuickCut/Resources/view_refresh.png b/src/QuickCut/Resources/view_refresh.png
new file mode 100644
index 0000000..1908840
Binary files /dev/null and b/src/QuickCut/Resources/view_refresh.png differ
diff --git a/src/QuickCut/Resources/view_statusbar.png b/src/QuickCut/Resources/view_statusbar.png
new file mode 100644
index 0000000..8ce4b50
Binary files /dev/null and b/src/QuickCut/Resources/view_statusbar.png differ
diff --git a/src/QuickCut/Resources/view_toolbar.png b/src/QuickCut/Resources/view_toolbar.png
new file mode 100644
index 0000000..02ab1b4
Binary files /dev/null and b/src/QuickCut/Resources/view_toolbar.png differ
diff --git a/src/QuickCut/Styles/breeze.qrc b/src/QuickCut/Styles/breeze.qrc
new file mode 100644
index 0000000..88fb185
--- /dev/null
+++ b/src/QuickCut/Styles/breeze.qrc
@@ -0,0 +1,89 @@
+
+
+ light/hmovetoolbar.svg
+ light/vmovetoolbar.svg
+ light/hsepartoolbar.svg
+ light/vsepartoolbars.svg
+ light/stylesheet-branch-end.svg
+ light/stylesheet-branch-end-closed.svg
+ light/stylesheet-branch-end-open.svg
+ light/stylesheet-vline.svg
+ light/stylesheet-branch-more.svg
+ light/branch_closed.svg
+ light/branch_closed-on.svg
+ light/branch_open.svg
+ light/branch_open-on.svg
+ light/down_arrow.svg
+ light/down_arrow_disabled.svg
+ light/down_arrow-hover.svg
+ light/left_arrow.svg
+ light/left_arrow_disabled.svg
+ light/right_arrow.svg
+ light/right_arrow_disabled.svg
+ light/up_arrow.svg
+ light/up_arrow_disabled.svg
+ light/up_arrow-hover.svg
+ light/sizegrip.svg
+ light/transparent.svg
+ light/close.svg
+ light/close-hover.svg
+ light/close-pressed.svg
+ light/undock.svg
+ light/undock-hover.svg
+ light/checkbox_checked-hover.svg
+ light/checkbox_checked.svg
+ light/checkbox_checked_disabled.svg
+ light/checkbox_indeterminate.svg
+ light/checkbox_indeterminate-hover.svg
+ light/checkbox_indeterminate_disabled.svg
+ light/checkbox_unchecked-hover.svg
+ light/checkbox_unchecked_disabled.svg
+ light/radio_checked-hover.svg
+ light/radio_checked.svg
+ light/radio_checked_disabled.svg
+ light/radio_unchecked-hover.svg
+ light/radio_unchecked_disabled.svg
+ dark/hmovetoolbar.svg
+ dark/vmovetoolbar.svg
+ dark/hsepartoolbar.svg
+ dark/vsepartoolbars.svg
+ dark/stylesheet-branch-end.svg
+ dark/stylesheet-branch-end-closed.svg
+ dark/stylesheet-branch-end-open.svg
+ dark/stylesheet-vline.svg
+ dark/stylesheet-branch-more.svg
+ dark/branch_closed.svg
+ dark/branch_closed-on.svg
+ dark/branch_open.svg
+ dark/branch_open-on.svg
+ dark/down_arrow.svg
+ dark/down_arrow_disabled.svg
+ dark/down_arrow-hover.svg
+ dark/left_arrow.svg
+ dark/left_arrow_disabled.svg
+ dark/right_arrow.svg
+ dark/right_arrow_disabled.svg
+ dark/up_arrow.svg
+ dark/up_arrow_disabled.svg
+ dark/up_arrow-hover.svg
+ dark/sizegrip.svg
+ dark/transparent.svg
+ dark/close.svg
+ dark/close-hover.svg
+ dark/close-pressed.svg
+ dark/undock.svg
+ dark/undock-hover.svg
+ dark/checkbox_checked.svg
+ dark/checkbox_checked_disabled.svg
+ dark/checkbox_indeterminate.svg
+ dark/checkbox_indeterminate_disabled.svg
+ dark/checkbox_unchecked.svg
+ dark/checkbox_unchecked_disabled.svg
+ dark/radio_checked.svg
+ dark/radio_checked_disabled.svg
+ dark/radio_unchecked.svg
+ dark/radio_unchecked_disabled.svg
+ light.qss
+ dark.qss
+
+
diff --git a/src/QuickCut/Styles/dark/branch_closed-on.svg b/src/QuickCut/Styles/dark/branch_closed-on.svg
new file mode 100644
index 0000000..8bd398f
--- /dev/null
+++ b/src/QuickCut/Styles/dark/branch_closed-on.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/branch_closed.svg b/src/QuickCut/Styles/dark/branch_closed.svg
new file mode 100644
index 0000000..f5a072f
--- /dev/null
+++ b/src/QuickCut/Styles/dark/branch_closed.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/branch_open-on.svg b/src/QuickCut/Styles/dark/branch_open-on.svg
new file mode 100644
index 0000000..4dd0c06
--- /dev/null
+++ b/src/QuickCut/Styles/dark/branch_open-on.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/branch_open.svg b/src/QuickCut/Styles/dark/branch_open.svg
new file mode 100644
index 0000000..0745890
--- /dev/null
+++ b/src/QuickCut/Styles/dark/branch_open.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/checkbox_checked.svg b/src/QuickCut/Styles/dark/checkbox_checked.svg
new file mode 100644
index 0000000..6753d8b
--- /dev/null
+++ b/src/QuickCut/Styles/dark/checkbox_checked.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/dark/checkbox_checked_disabled.svg b/src/QuickCut/Styles/dark/checkbox_checked_disabled.svg
new file mode 100644
index 0000000..ff7e63a
--- /dev/null
+++ b/src/QuickCut/Styles/dark/checkbox_checked_disabled.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/dark/checkbox_indeterminate.svg b/src/QuickCut/Styles/dark/checkbox_indeterminate.svg
new file mode 100644
index 0000000..0f17124
--- /dev/null
+++ b/src/QuickCut/Styles/dark/checkbox_indeterminate.svg
@@ -0,0 +1,7 @@
+
diff --git a/src/QuickCut/Styles/dark/checkbox_indeterminate_disabled.svg b/src/QuickCut/Styles/dark/checkbox_indeterminate_disabled.svg
new file mode 100644
index 0000000..bc0f285
--- /dev/null
+++ b/src/QuickCut/Styles/dark/checkbox_indeterminate_disabled.svg
@@ -0,0 +1,7 @@
+
diff --git a/src/QuickCut/Styles/dark/checkbox_unchecked.svg b/src/QuickCut/Styles/dark/checkbox_unchecked.svg
new file mode 100644
index 0000000..6f3e569
--- /dev/null
+++ b/src/QuickCut/Styles/dark/checkbox_unchecked.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/dark/checkbox_unchecked_disabled.svg b/src/QuickCut/Styles/dark/checkbox_unchecked_disabled.svg
new file mode 100644
index 0000000..dd73f75
--- /dev/null
+++ b/src/QuickCut/Styles/dark/checkbox_unchecked_disabled.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/dark/close-hover.svg b/src/QuickCut/Styles/dark/close-hover.svg
new file mode 100644
index 0000000..e2b0dd8
--- /dev/null
+++ b/src/QuickCut/Styles/dark/close-hover.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/close-pressed.svg b/src/QuickCut/Styles/dark/close-pressed.svg
new file mode 100644
index 0000000..a0dc249
--- /dev/null
+++ b/src/QuickCut/Styles/dark/close-pressed.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/close.svg b/src/QuickCut/Styles/dark/close.svg
new file mode 100644
index 0000000..07b50c9
--- /dev/null
+++ b/src/QuickCut/Styles/dark/close.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/down_arrow-hover.svg b/src/QuickCut/Styles/dark/down_arrow-hover.svg
new file mode 100644
index 0000000..408397f
--- /dev/null
+++ b/src/QuickCut/Styles/dark/down_arrow-hover.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/down_arrow.svg b/src/QuickCut/Styles/dark/down_arrow.svg
new file mode 100644
index 0000000..a50df00
--- /dev/null
+++ b/src/QuickCut/Styles/dark/down_arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/down_arrow_disabled.svg b/src/QuickCut/Styles/dark/down_arrow_disabled.svg
new file mode 100644
index 0000000..af74a30
--- /dev/null
+++ b/src/QuickCut/Styles/dark/down_arrow_disabled.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/hmovetoolbar.svg b/src/QuickCut/Styles/dark/hmovetoolbar.svg
new file mode 100644
index 0000000..e4904db
--- /dev/null
+++ b/src/QuickCut/Styles/dark/hmovetoolbar.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/dark/hsepartoolbar.svg b/src/QuickCut/Styles/dark/hsepartoolbar.svg
new file mode 100644
index 0000000..89beb22
--- /dev/null
+++ b/src/QuickCut/Styles/dark/hsepartoolbar.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/left_arrow.svg b/src/QuickCut/Styles/dark/left_arrow.svg
new file mode 100644
index 0000000..9c787ce
--- /dev/null
+++ b/src/QuickCut/Styles/dark/left_arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/left_arrow_disabled.svg b/src/QuickCut/Styles/dark/left_arrow_disabled.svg
new file mode 100644
index 0000000..2d749e7
--- /dev/null
+++ b/src/QuickCut/Styles/dark/left_arrow_disabled.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/radio_checked.svg b/src/QuickCut/Styles/dark/radio_checked.svg
new file mode 100644
index 0000000..b8f7064
--- /dev/null
+++ b/src/QuickCut/Styles/dark/radio_checked.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/dark/radio_checked_disabled.svg b/src/QuickCut/Styles/dark/radio_checked_disabled.svg
new file mode 100644
index 0000000..523ee00
--- /dev/null
+++ b/src/QuickCut/Styles/dark/radio_checked_disabled.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/dark/radio_unchecked.svg b/src/QuickCut/Styles/dark/radio_unchecked.svg
new file mode 100644
index 0000000..1a556e3
--- /dev/null
+++ b/src/QuickCut/Styles/dark/radio_unchecked.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/dark/radio_unchecked_disabled.svg b/src/QuickCut/Styles/dark/radio_unchecked_disabled.svg
new file mode 100644
index 0000000..b3da8a2
--- /dev/null
+++ b/src/QuickCut/Styles/dark/radio_unchecked_disabled.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/dark/right_arrow.svg b/src/QuickCut/Styles/dark/right_arrow.svg
new file mode 100644
index 0000000..b793513
--- /dev/null
+++ b/src/QuickCut/Styles/dark/right_arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/right_arrow_disabled.svg b/src/QuickCut/Styles/dark/right_arrow_disabled.svg
new file mode 100644
index 0000000..4940025
--- /dev/null
+++ b/src/QuickCut/Styles/dark/right_arrow_disabled.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/sizegrip.svg b/src/QuickCut/Styles/dark/sizegrip.svg
new file mode 100644
index 0000000..3388f07
--- /dev/null
+++ b/src/QuickCut/Styles/dark/sizegrip.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/spinup_disabled.svg b/src/QuickCut/Styles/dark/spinup_disabled.svg
new file mode 100644
index 0000000..838436d
--- /dev/null
+++ b/src/QuickCut/Styles/dark/spinup_disabled.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/stylesheet-branch-end-closed.svg b/src/QuickCut/Styles/dark/stylesheet-branch-end-closed.svg
new file mode 100644
index 0000000..eb73b13
--- /dev/null
+++ b/src/QuickCut/Styles/dark/stylesheet-branch-end-closed.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/dark/stylesheet-branch-end-open.svg b/src/QuickCut/Styles/dark/stylesheet-branch-end-open.svg
new file mode 100644
index 0000000..eb73b13
--- /dev/null
+++ b/src/QuickCut/Styles/dark/stylesheet-branch-end-open.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/dark/stylesheet-branch-end.svg b/src/QuickCut/Styles/dark/stylesheet-branch-end.svg
new file mode 100644
index 0000000..334ca0c
--- /dev/null
+++ b/src/QuickCut/Styles/dark/stylesheet-branch-end.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/dark/stylesheet-branch-more.svg b/src/QuickCut/Styles/dark/stylesheet-branch-more.svg
new file mode 100644
index 0000000..f5250ba
--- /dev/null
+++ b/src/QuickCut/Styles/dark/stylesheet-branch-more.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/dark/stylesheet-vline.svg b/src/QuickCut/Styles/dark/stylesheet-vline.svg
new file mode 100644
index 0000000..4e7ff6a
--- /dev/null
+++ b/src/QuickCut/Styles/dark/stylesheet-vline.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/transparent.svg b/src/QuickCut/Styles/dark/transparent.svg
new file mode 100644
index 0000000..3a8ca5c
--- /dev/null
+++ b/src/QuickCut/Styles/dark/transparent.svg
@@ -0,0 +1 @@
+
diff --git a/src/QuickCut/Styles/dark/undock-hover.svg b/src/QuickCut/Styles/dark/undock-hover.svg
new file mode 100644
index 0000000..6bddbd7
--- /dev/null
+++ b/src/QuickCut/Styles/dark/undock-hover.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/dark/undock.svg b/src/QuickCut/Styles/dark/undock.svg
new file mode 100644
index 0000000..9ab2197
--- /dev/null
+++ b/src/QuickCut/Styles/dark/undock.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/up_arrow-hover.svg b/src/QuickCut/Styles/dark/up_arrow-hover.svg
new file mode 100644
index 0000000..dd1271a
--- /dev/null
+++ b/src/QuickCut/Styles/dark/up_arrow-hover.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/up_arrow.svg b/src/QuickCut/Styles/dark/up_arrow.svg
new file mode 100644
index 0000000..9f42239
--- /dev/null
+++ b/src/QuickCut/Styles/dark/up_arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/up_arrow_disabled.svg b/src/QuickCut/Styles/dark/up_arrow_disabled.svg
new file mode 100644
index 0000000..742e1c5
--- /dev/null
+++ b/src/QuickCut/Styles/dark/up_arrow_disabled.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/dark/vmovetoolbar.svg b/src/QuickCut/Styles/dark/vmovetoolbar.svg
new file mode 100644
index 0000000..0a30d45
--- /dev/null
+++ b/src/QuickCut/Styles/dark/vmovetoolbar.svg
@@ -0,0 +1,8 @@
+
diff --git a/src/QuickCut/Styles/dark/vsepartoolbars.svg b/src/QuickCut/Styles/dark/vsepartoolbars.svg
new file mode 100644
index 0000000..00e91ab
--- /dev/null
+++ b/src/QuickCut/Styles/dark/vsepartoolbars.svg
@@ -0,0 +1,7 @@
+
diff --git a/src/QuickCut/Styles/light/branch_closed-on.svg b/src/QuickCut/Styles/light/branch_closed-on.svg
new file mode 100644
index 0000000..23c5421
--- /dev/null
+++ b/src/QuickCut/Styles/light/branch_closed-on.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/branch_closed.svg b/src/QuickCut/Styles/light/branch_closed.svg
new file mode 100644
index 0000000..286c1a9
--- /dev/null
+++ b/src/QuickCut/Styles/light/branch_closed.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/branch_open-on.svg b/src/QuickCut/Styles/light/branch_open-on.svg
new file mode 100644
index 0000000..9e75927
--- /dev/null
+++ b/src/QuickCut/Styles/light/branch_open-on.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/branch_open.svg b/src/QuickCut/Styles/light/branch_open.svg
new file mode 100644
index 0000000..514a312
--- /dev/null
+++ b/src/QuickCut/Styles/light/branch_open.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/checkbox_checked-hover.svg b/src/QuickCut/Styles/light/checkbox_checked-hover.svg
new file mode 100644
index 0000000..64d6667
--- /dev/null
+++ b/src/QuickCut/Styles/light/checkbox_checked-hover.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/light/checkbox_checked.svg b/src/QuickCut/Styles/light/checkbox_checked.svg
new file mode 100644
index 0000000..f3acb63
--- /dev/null
+++ b/src/QuickCut/Styles/light/checkbox_checked.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/light/checkbox_checked_disabled.svg b/src/QuickCut/Styles/light/checkbox_checked_disabled.svg
new file mode 100644
index 0000000..b7be04b
--- /dev/null
+++ b/src/QuickCut/Styles/light/checkbox_checked_disabled.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/light/checkbox_indeterminate-hover.svg b/src/QuickCut/Styles/light/checkbox_indeterminate-hover.svg
new file mode 100644
index 0000000..def9596
--- /dev/null
+++ b/src/QuickCut/Styles/light/checkbox_indeterminate-hover.svg
@@ -0,0 +1,7 @@
+
diff --git a/src/QuickCut/Styles/light/checkbox_indeterminate.svg b/src/QuickCut/Styles/light/checkbox_indeterminate.svg
new file mode 100644
index 0000000..a619ab0
--- /dev/null
+++ b/src/QuickCut/Styles/light/checkbox_indeterminate.svg
@@ -0,0 +1,7 @@
+
diff --git a/src/QuickCut/Styles/light/checkbox_indeterminate_disabled.svg b/src/QuickCut/Styles/light/checkbox_indeterminate_disabled.svg
new file mode 100644
index 0000000..74d7168
--- /dev/null
+++ b/src/QuickCut/Styles/light/checkbox_indeterminate_disabled.svg
@@ -0,0 +1,7 @@
+
diff --git a/src/QuickCut/Styles/light/checkbox_unchecked-hover.svg b/src/QuickCut/Styles/light/checkbox_unchecked-hover.svg
new file mode 100644
index 0000000..8f0bb01
--- /dev/null
+++ b/src/QuickCut/Styles/light/checkbox_unchecked-hover.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/light/checkbox_unchecked_disabled.svg b/src/QuickCut/Styles/light/checkbox_unchecked_disabled.svg
new file mode 100644
index 0000000..0ef4300
--- /dev/null
+++ b/src/QuickCut/Styles/light/checkbox_unchecked_disabled.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/light/close-hover.svg b/src/QuickCut/Styles/light/close-hover.svg
new file mode 100644
index 0000000..cb44c78
--- /dev/null
+++ b/src/QuickCut/Styles/light/close-hover.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/close-pressed.svg b/src/QuickCut/Styles/light/close-pressed.svg
new file mode 100644
index 0000000..a0dc249
--- /dev/null
+++ b/src/QuickCut/Styles/light/close-pressed.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/close.svg b/src/QuickCut/Styles/light/close.svg
new file mode 100644
index 0000000..07b50c9
--- /dev/null
+++ b/src/QuickCut/Styles/light/close.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/down_arrow-hover.svg b/src/QuickCut/Styles/light/down_arrow-hover.svg
new file mode 100644
index 0000000..408397f
--- /dev/null
+++ b/src/QuickCut/Styles/light/down_arrow-hover.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/down_arrow.svg b/src/QuickCut/Styles/light/down_arrow.svg
new file mode 100644
index 0000000..34c5d6a
--- /dev/null
+++ b/src/QuickCut/Styles/light/down_arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/down_arrow_disabled.svg b/src/QuickCut/Styles/light/down_arrow_disabled.svg
new file mode 100644
index 0000000..af74a30
--- /dev/null
+++ b/src/QuickCut/Styles/light/down_arrow_disabled.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/hmovetoolbar.svg b/src/QuickCut/Styles/light/hmovetoolbar.svg
new file mode 100644
index 0000000..57e54c9
--- /dev/null
+++ b/src/QuickCut/Styles/light/hmovetoolbar.svg
@@ -0,0 +1,5 @@
+
+
diff --git a/src/QuickCut/Styles/light/hsepartoolbar.svg b/src/QuickCut/Styles/light/hsepartoolbar.svg
new file mode 100644
index 0000000..a446425
--- /dev/null
+++ b/src/QuickCut/Styles/light/hsepartoolbar.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/left_arrow.svg b/src/QuickCut/Styles/light/left_arrow.svg
new file mode 100644
index 0000000..f77acf4
--- /dev/null
+++ b/src/QuickCut/Styles/light/left_arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/left_arrow_disabled.svg b/src/QuickCut/Styles/light/left_arrow_disabled.svg
new file mode 100644
index 0000000..2d749e7
--- /dev/null
+++ b/src/QuickCut/Styles/light/left_arrow_disabled.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/radio_checked-hover.svg b/src/QuickCut/Styles/light/radio_checked-hover.svg
new file mode 100644
index 0000000..f3d5c98
--- /dev/null
+++ b/src/QuickCut/Styles/light/radio_checked-hover.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/light/radio_checked.svg b/src/QuickCut/Styles/light/radio_checked.svg
new file mode 100644
index 0000000..86ff6bf
--- /dev/null
+++ b/src/QuickCut/Styles/light/radio_checked.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/light/radio_checked_disabled.svg b/src/QuickCut/Styles/light/radio_checked_disabled.svg
new file mode 100644
index 0000000..269ae12
--- /dev/null
+++ b/src/QuickCut/Styles/light/radio_checked_disabled.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/light/radio_unchecked-hover.svg b/src/QuickCut/Styles/light/radio_unchecked-hover.svg
new file mode 100644
index 0000000..f5fc943
--- /dev/null
+++ b/src/QuickCut/Styles/light/radio_unchecked-hover.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/light/radio_unchecked_disabled.svg b/src/QuickCut/Styles/light/radio_unchecked_disabled.svg
new file mode 100644
index 0000000..41f503d
--- /dev/null
+++ b/src/QuickCut/Styles/light/radio_unchecked_disabled.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/light/right_arrow.svg b/src/QuickCut/Styles/light/right_arrow.svg
new file mode 100644
index 0000000..a43ea2b
--- /dev/null
+++ b/src/QuickCut/Styles/light/right_arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/right_arrow_disabled.svg b/src/QuickCut/Styles/light/right_arrow_disabled.svg
new file mode 100644
index 0000000..4940025
--- /dev/null
+++ b/src/QuickCut/Styles/light/right_arrow_disabled.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/sizegrip.svg b/src/QuickCut/Styles/light/sizegrip.svg
new file mode 100644
index 0000000..3388f07
--- /dev/null
+++ b/src/QuickCut/Styles/light/sizegrip.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/spinup_disabled.svg b/src/QuickCut/Styles/light/spinup_disabled.svg
new file mode 100644
index 0000000..838436d
--- /dev/null
+++ b/src/QuickCut/Styles/light/spinup_disabled.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/stylesheet-branch-end-closed.svg b/src/QuickCut/Styles/light/stylesheet-branch-end-closed.svg
new file mode 100644
index 0000000..a31f5c0
--- /dev/null
+++ b/src/QuickCut/Styles/light/stylesheet-branch-end-closed.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/light/stylesheet-branch-end-open.svg b/src/QuickCut/Styles/light/stylesheet-branch-end-open.svg
new file mode 100644
index 0000000..a31f5c0
--- /dev/null
+++ b/src/QuickCut/Styles/light/stylesheet-branch-end-open.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/light/stylesheet-branch-end.svg b/src/QuickCut/Styles/light/stylesheet-branch-end.svg
new file mode 100644
index 0000000..a1c0a42
--- /dev/null
+++ b/src/QuickCut/Styles/light/stylesheet-branch-end.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/light/stylesheet-branch-more.svg b/src/QuickCut/Styles/light/stylesheet-branch-more.svg
new file mode 100644
index 0000000..ebef839
--- /dev/null
+++ b/src/QuickCut/Styles/light/stylesheet-branch-more.svg
@@ -0,0 +1,4 @@
+
diff --git a/src/QuickCut/Styles/light/stylesheet-vline.svg b/src/QuickCut/Styles/light/stylesheet-vline.svg
new file mode 100644
index 0000000..688177e
--- /dev/null
+++ b/src/QuickCut/Styles/light/stylesheet-vline.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/transparent.svg b/src/QuickCut/Styles/light/transparent.svg
new file mode 100644
index 0000000..3a8ca5c
--- /dev/null
+++ b/src/QuickCut/Styles/light/transparent.svg
@@ -0,0 +1 @@
+
diff --git a/src/QuickCut/Styles/light/undock-hover.svg b/src/QuickCut/Styles/light/undock-hover.svg
new file mode 100644
index 0000000..6bddbd7
--- /dev/null
+++ b/src/QuickCut/Styles/light/undock-hover.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/QuickCut/Styles/light/undock.svg b/src/QuickCut/Styles/light/undock.svg
new file mode 100644
index 0000000..9ab2197
--- /dev/null
+++ b/src/QuickCut/Styles/light/undock.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/up_arrow-hover.svg b/src/QuickCut/Styles/light/up_arrow-hover.svg
new file mode 100644
index 0000000..dd1271a
--- /dev/null
+++ b/src/QuickCut/Styles/light/up_arrow-hover.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/up_arrow.svg b/src/QuickCut/Styles/light/up_arrow.svg
new file mode 100644
index 0000000..b02bb26
--- /dev/null
+++ b/src/QuickCut/Styles/light/up_arrow.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/up_arrow_disabled.svg b/src/QuickCut/Styles/light/up_arrow_disabled.svg
new file mode 100644
index 0000000..742e1c5
--- /dev/null
+++ b/src/QuickCut/Styles/light/up_arrow_disabled.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/QuickCut/Styles/light/vmovetoolbar.svg b/src/QuickCut/Styles/light/vmovetoolbar.svg
new file mode 100644
index 0000000..0a30d45
--- /dev/null
+++ b/src/QuickCut/Styles/light/vmovetoolbar.svg
@@ -0,0 +1,8 @@
+
diff --git a/src/QuickCut/Styles/light/vsepartoolbars.svg b/src/QuickCut/Styles/light/vsepartoolbars.svg
new file mode 100644
index 0000000..00e91ab
--- /dev/null
+++ b/src/QuickCut/Styles/light/vsepartoolbars.svg
@@ -0,0 +1,7 @@
+
diff --git a/src/QuickCut/Styles/rc/Hmovetoolbar.png b/src/QuickCut/Styles/rc/Hmovetoolbar.png
new file mode 100644
index 0000000..cead99e
Binary files /dev/null and b/src/QuickCut/Styles/rc/Hmovetoolbar.png differ
diff --git a/src/QuickCut/Styles/rc/Hsepartoolbar.png b/src/QuickCut/Styles/rc/Hsepartoolbar.png
new file mode 100644
index 0000000..7f183c8
Binary files /dev/null and b/src/QuickCut/Styles/rc/Hsepartoolbar.png differ
diff --git a/src/QuickCut/Styles/rc/Vmovetoolbar.png b/src/QuickCut/Styles/rc/Vmovetoolbar.png
new file mode 100644
index 0000000..ac6a655
Binary files /dev/null and b/src/QuickCut/Styles/rc/Vmovetoolbar.png differ
diff --git a/src/QuickCut/Styles/rc/Vsepartoolbar.png b/src/QuickCut/Styles/rc/Vsepartoolbar.png
new file mode 100644
index 0000000..7bf62f1
Binary files /dev/null and b/src/QuickCut/Styles/rc/Vsepartoolbar.png differ
diff --git a/src/QuickCut/Styles/rc/branch_closed-on.png b/src/QuickCut/Styles/rc/branch_closed-on.png
new file mode 100644
index 0000000..d081e9b
Binary files /dev/null and b/src/QuickCut/Styles/rc/branch_closed-on.png differ
diff --git a/src/QuickCut/Styles/rc/branch_closed.png b/src/QuickCut/Styles/rc/branch_closed.png
new file mode 100644
index 0000000..d652159
Binary files /dev/null and b/src/QuickCut/Styles/rc/branch_closed.png differ
diff --git a/src/QuickCut/Styles/rc/branch_open-on.png b/src/QuickCut/Styles/rc/branch_open-on.png
new file mode 100644
index 0000000..ec372b2
Binary files /dev/null and b/src/QuickCut/Styles/rc/branch_open-on.png differ
diff --git a/src/QuickCut/Styles/rc/branch_open.png b/src/QuickCut/Styles/rc/branch_open.png
new file mode 100644
index 0000000..66f8e1a
Binary files /dev/null and b/src/QuickCut/Styles/rc/branch_open.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_checked.png b/src/QuickCut/Styles/rc/checkbox_checked.png
new file mode 100644
index 0000000..4007c2e
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_checked.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_checked@2x.png b/src/QuickCut/Styles/rc/checkbox_checked@2x.png
new file mode 100644
index 0000000..b9c3204
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_checked@2x.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_checked_disabled.png b/src/QuickCut/Styles/rc/checkbox_checked_disabled.png
new file mode 100644
index 0000000..4762561
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_checked_disabled.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_checked_disabled@2x.png b/src/QuickCut/Styles/rc/checkbox_checked_disabled@2x.png
new file mode 100644
index 0000000..98bf547
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_checked_disabled@2x.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_checked_focus.png b/src/QuickCut/Styles/rc/checkbox_checked_focus.png
new file mode 100644
index 0000000..91cb16c
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_checked_focus.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_checked_focus@2x.png b/src/QuickCut/Styles/rc/checkbox_checked_focus@2x.png
new file mode 100644
index 0000000..04b3bb5
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_checked_focus@2x.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_indeterminate.png b/src/QuickCut/Styles/rc/checkbox_indeterminate.png
new file mode 100644
index 0000000..6b84636
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_indeterminate.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_indeterminate@2x.png b/src/QuickCut/Styles/rc/checkbox_indeterminate@2x.png
new file mode 100644
index 0000000..baa5020
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_indeterminate@2x.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_indeterminate_disabled.png b/src/QuickCut/Styles/rc/checkbox_indeterminate_disabled.png
new file mode 100644
index 0000000..435048a
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_indeterminate_disabled.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_indeterminate_disabled@2x.png b/src/QuickCut/Styles/rc/checkbox_indeterminate_disabled@2x.png
new file mode 100644
index 0000000..3e7f76c
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_indeterminate_disabled@2x.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_indeterminate_focus.png b/src/QuickCut/Styles/rc/checkbox_indeterminate_focus.png
new file mode 100644
index 0000000..4bf4d53
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_indeterminate_focus.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_indeterminate_focus@2x.png b/src/QuickCut/Styles/rc/checkbox_indeterminate_focus@2x.png
new file mode 100644
index 0000000..1f5cb3e
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_indeterminate_focus@2x.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_unchecked.png b/src/QuickCut/Styles/rc/checkbox_unchecked.png
new file mode 100644
index 0000000..54044ba
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_unchecked.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_unchecked@2x.png b/src/QuickCut/Styles/rc/checkbox_unchecked@2x.png
new file mode 100644
index 0000000..1259a98
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_unchecked@2x.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_unchecked_disabled.png b/src/QuickCut/Styles/rc/checkbox_unchecked_disabled.png
new file mode 100644
index 0000000..75f0490
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_unchecked_disabled.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_unchecked_disabled@2x.png b/src/QuickCut/Styles/rc/checkbox_unchecked_disabled@2x.png
new file mode 100644
index 0000000..e4ecef9
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_unchecked_disabled@2x.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_unchecked_focus.png b/src/QuickCut/Styles/rc/checkbox_unchecked_focus.png
new file mode 100644
index 0000000..5b0a18f
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_unchecked_focus.png differ
diff --git a/src/QuickCut/Styles/rc/checkbox_unchecked_focus@2x.png b/src/QuickCut/Styles/rc/checkbox_unchecked_focus@2x.png
new file mode 100644
index 0000000..14bec86
Binary files /dev/null and b/src/QuickCut/Styles/rc/checkbox_unchecked_focus@2x.png differ
diff --git a/src/QuickCut/Styles/rc/close-hover.png b/src/QuickCut/Styles/rc/close-hover.png
new file mode 100644
index 0000000..fdbaf9b
Binary files /dev/null and b/src/QuickCut/Styles/rc/close-hover.png differ
diff --git a/src/QuickCut/Styles/rc/close-pressed.png b/src/QuickCut/Styles/rc/close-pressed.png
new file mode 100644
index 0000000..9b243bf
Binary files /dev/null and b/src/QuickCut/Styles/rc/close-pressed.png differ
diff --git a/src/QuickCut/Styles/rc/close.png b/src/QuickCut/Styles/rc/close.png
new file mode 100644
index 0000000..89407de
Binary files /dev/null and b/src/QuickCut/Styles/rc/close.png differ
diff --git a/src/QuickCut/Styles/rc/down_arrow.png b/src/QuickCut/Styles/rc/down_arrow.png
new file mode 100644
index 0000000..e271f7f
Binary files /dev/null and b/src/QuickCut/Styles/rc/down_arrow.png differ
diff --git a/src/QuickCut/Styles/rc/down_arrow_disabled.png b/src/QuickCut/Styles/rc/down_arrow_disabled.png
new file mode 100644
index 0000000..5805d98
Binary files /dev/null and b/src/QuickCut/Styles/rc/down_arrow_disabled.png differ
diff --git a/src/QuickCut/Styles/rc/left_arrow.png b/src/QuickCut/Styles/rc/left_arrow.png
new file mode 100644
index 0000000..f808d2d
Binary files /dev/null and b/src/QuickCut/Styles/rc/left_arrow.png differ
diff --git a/src/QuickCut/Styles/rc/left_arrow_disabled.png b/src/QuickCut/Styles/rc/left_arrow_disabled.png
new file mode 100644
index 0000000..f5b9af8
Binary files /dev/null and b/src/QuickCut/Styles/rc/left_arrow_disabled.png differ
diff --git a/src/QuickCut/Styles/rc/radio_checked.png b/src/QuickCut/Styles/rc/radio_checked.png
new file mode 100644
index 0000000..368acce
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_checked.png differ
diff --git a/src/QuickCut/Styles/rc/radio_checked@2x.png b/src/QuickCut/Styles/rc/radio_checked@2x.png
new file mode 100644
index 0000000..b5f5eed
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_checked@2x.png differ
diff --git a/src/QuickCut/Styles/rc/radio_checked_disabled.png b/src/QuickCut/Styles/rc/radio_checked_disabled.png
new file mode 100644
index 0000000..73ff735
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_checked_disabled.png differ
diff --git a/src/QuickCut/Styles/rc/radio_checked_disabled@2x.png b/src/QuickCut/Styles/rc/radio_checked_disabled@2x.png
new file mode 100644
index 0000000..827e592
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_checked_disabled@2x.png differ
diff --git a/src/QuickCut/Styles/rc/radio_checked_focus.png b/src/QuickCut/Styles/rc/radio_checked_focus.png
new file mode 100644
index 0000000..ad6d2cf
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_checked_focus.png differ
diff --git a/src/QuickCut/Styles/rc/radio_checked_focus@2x.png b/src/QuickCut/Styles/rc/radio_checked_focus@2x.png
new file mode 100644
index 0000000..7e59305
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_checked_focus@2x.png differ
diff --git a/src/QuickCut/Styles/rc/radio_unchecked.png b/src/QuickCut/Styles/rc/radio_unchecked.png
new file mode 100644
index 0000000..82f2abb
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_unchecked.png differ
diff --git a/src/QuickCut/Styles/rc/radio_unchecked@2x.png b/src/QuickCut/Styles/rc/radio_unchecked@2x.png
new file mode 100644
index 0000000..793719b
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_unchecked@2x.png differ
diff --git a/src/QuickCut/Styles/rc/radio_unchecked_disabled.png b/src/QuickCut/Styles/rc/radio_unchecked_disabled.png
new file mode 100644
index 0000000..5c54ee9
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_unchecked_disabled.png differ
diff --git a/src/QuickCut/Styles/rc/radio_unchecked_disabled@2x.png b/src/QuickCut/Styles/rc/radio_unchecked_disabled@2x.png
new file mode 100644
index 0000000..d50153d
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_unchecked_disabled@2x.png differ
diff --git a/src/QuickCut/Styles/rc/radio_unchecked_focus.png b/src/QuickCut/Styles/rc/radio_unchecked_focus.png
new file mode 100644
index 0000000..f42d85c
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_unchecked_focus.png differ
diff --git a/src/QuickCut/Styles/rc/radio_unchecked_focus@2x.png b/src/QuickCut/Styles/rc/radio_unchecked_focus@2x.png
new file mode 100644
index 0000000..0927b49
Binary files /dev/null and b/src/QuickCut/Styles/rc/radio_unchecked_focus@2x.png differ
diff --git a/src/QuickCut/Styles/rc/right_arrow.png b/src/QuickCut/Styles/rc/right_arrow.png
new file mode 100644
index 0000000..9b0a4e6
Binary files /dev/null and b/src/QuickCut/Styles/rc/right_arrow.png differ
diff --git a/src/QuickCut/Styles/rc/right_arrow_disabled.png b/src/QuickCut/Styles/rc/right_arrow_disabled.png
new file mode 100644
index 0000000..5c0bee4
Binary files /dev/null and b/src/QuickCut/Styles/rc/right_arrow_disabled.png differ
diff --git a/src/QuickCut/Styles/rc/sizegrip.png b/src/QuickCut/Styles/rc/sizegrip.png
new file mode 100644
index 0000000..350583a
Binary files /dev/null and b/src/QuickCut/Styles/rc/sizegrip.png differ
diff --git a/src/QuickCut/Styles/rc/stylesheet-branch-end.png b/src/QuickCut/Styles/rc/stylesheet-branch-end.png
new file mode 100644
index 0000000..cb5d3b5
Binary files /dev/null and b/src/QuickCut/Styles/rc/stylesheet-branch-end.png differ
diff --git a/src/QuickCut/Styles/rc/stylesheet-branch-more.png b/src/QuickCut/Styles/rc/stylesheet-branch-more.png
new file mode 100644
index 0000000..6271140
Binary files /dev/null and b/src/QuickCut/Styles/rc/stylesheet-branch-more.png differ
diff --git a/src/QuickCut/Styles/rc/stylesheet-vline.png b/src/QuickCut/Styles/rc/stylesheet-vline.png
new file mode 100644
index 0000000..87536cc
Binary files /dev/null and b/src/QuickCut/Styles/rc/stylesheet-vline.png differ
diff --git a/src/QuickCut/Styles/rc/transparent.png b/src/QuickCut/Styles/rc/transparent.png
new file mode 100644
index 0000000..483df25
Binary files /dev/null and b/src/QuickCut/Styles/rc/transparent.png differ
diff --git a/src/QuickCut/Styles/rc/undock.png b/src/QuickCut/Styles/rc/undock.png
new file mode 100644
index 0000000..58cde37
Binary files /dev/null and b/src/QuickCut/Styles/rc/undock.png differ
diff --git a/src/QuickCut/Styles/rc/up_arrow.png b/src/QuickCut/Styles/rc/up_arrow.png
new file mode 100644
index 0000000..abcc724
Binary files /dev/null and b/src/QuickCut/Styles/rc/up_arrow.png differ
diff --git a/src/QuickCut/Styles/rc/up_arrow_disabled.png b/src/QuickCut/Styles/rc/up_arrow_disabled.png
new file mode 100644
index 0000000..b9c8e3b
Binary files /dev/null and b/src/QuickCut/Styles/rc/up_arrow_disabled.png differ
diff --git a/src/QuickCut/Styles/stylesheet.qrc b/src/QuickCut/Styles/stylesheet.qrc
new file mode 100644
index 0000000..cc57e98
--- /dev/null
+++ b/src/QuickCut/Styles/stylesheet.qrc
@@ -0,0 +1,135 @@
+
+
+ theme_dark.qss
+ theme_breezeDark.qss
+ theme_breezeLight.qss
+ theme_console.qss
+ theme_ubuntu.qss
+
+
+ rc/up_arrow_disabled.png
+ rc/Hmovetoolbar.png
+ rc/stylesheet-branch-end.png
+ rc/branch_closed-on.png
+ rc/stylesheet-vline.png
+ rc/branch_closed.png
+ rc/branch_open-on.png
+ rc/transparent.png
+ rc/right_arrow_disabled.png
+ rc/sizegrip.png
+ rc/close.png
+ rc/close-hover.png
+ rc/close-pressed.png
+ rc/down_arrow.png
+ rc/Vmovetoolbar.png
+ rc/left_arrow.png
+ rc/stylesheet-branch-more.png
+ rc/up_arrow.png
+ rc/right_arrow.png
+ rc/left_arrow_disabled.png
+ rc/Hsepartoolbar.png
+ rc/branch_open.png
+ rc/Vsepartoolbar.png
+ rc/down_arrow_disabled.png
+ rc/undock.png
+ rc/checkbox_checked_disabled.png
+ rc/checkbox_checked_focus.png
+ rc/checkbox_checked.png
+ rc/checkbox_indeterminate.png
+ rc/checkbox_indeterminate_focus.png
+ rc/checkbox_unchecked_disabled.png
+ rc/checkbox_unchecked_focus.png
+ rc/checkbox_unchecked.png
+ rc/radio_checked_disabled.png
+ rc/radio_checked_focus.png
+ rc/radio_checked.png
+ rc/radio_unchecked_disabled.png
+ rc/radio_unchecked_focus.png
+ rc/radio_unchecked.png
+
+
+ light/hmovetoolbar.svg
+ light/vmovetoolbar.svg
+ light/hsepartoolbar.svg
+ light/vsepartoolbars.svg
+ light/stylesheet-branch-end.svg
+ light/stylesheet-branch-end-closed.svg
+ light/stylesheet-branch-end-open.svg
+ light/stylesheet-vline.svg
+ light/stylesheet-branch-more.svg
+ light/branch_closed.svg
+ light/branch_closed-on.svg
+ light/branch_open.svg
+ light/branch_open-on.svg
+ light/down_arrow.svg
+ light/down_arrow_disabled.svg
+ light/down_arrow-hover.svg
+ light/left_arrow.svg
+ light/left_arrow_disabled.svg
+ light/right_arrow.svg
+ light/right_arrow_disabled.svg
+ light/up_arrow.svg
+ light/up_arrow_disabled.svg
+ light/up_arrow-hover.svg
+ light/sizegrip.svg
+ light/transparent.svg
+ light/close.svg
+ light/close-hover.svg
+ light/close-pressed.svg
+ light/undock.svg
+ light/undock-hover.svg
+ light/checkbox_checked-hover.svg
+ light/checkbox_checked.svg
+ light/checkbox_checked_disabled.svg
+ light/checkbox_indeterminate.svg
+ light/checkbox_indeterminate-hover.svg
+ light/checkbox_indeterminate_disabled.svg
+ light/checkbox_unchecked-hover.svg
+ light/checkbox_unchecked_disabled.svg
+ light/radio_checked-hover.svg
+ light/radio_checked.svg
+ light/radio_checked_disabled.svg
+ light/radio_unchecked-hover.svg
+ light/radio_unchecked_disabled.svg
+ dark/hmovetoolbar.svg
+ dark/vmovetoolbar.svg
+ dark/hsepartoolbar.svg
+ dark/vsepartoolbars.svg
+ dark/stylesheet-branch-end.svg
+ dark/stylesheet-branch-end-closed.svg
+ dark/stylesheet-branch-end-open.svg
+ dark/stylesheet-vline.svg
+ dark/stylesheet-branch-more.svg
+ dark/branch_closed.svg
+ dark/branch_closed-on.svg
+ dark/branch_open.svg
+ dark/branch_open-on.svg
+ dark/down_arrow.svg
+ dark/down_arrow_disabled.svg
+ dark/down_arrow-hover.svg
+ dark/left_arrow.svg
+ dark/left_arrow_disabled.svg
+ dark/right_arrow.svg
+ dark/right_arrow_disabled.svg
+ dark/up_arrow.svg
+ dark/up_arrow_disabled.svg
+ dark/up_arrow-hover.svg
+ dark/sizegrip.svg
+ dark/transparent.svg
+ dark/close.svg
+ dark/close-hover.svg
+ dark/close-pressed.svg
+ dark/undock.svg
+ dark/undock-hover.svg
+ dark/checkbox_checked.svg
+ dark/checkbox_checked_disabled.svg
+ dark/checkbox_indeterminate.svg
+ dark/checkbox_indeterminate_disabled.svg
+ dark/checkbox_unchecked.svg
+ dark/checkbox_unchecked_disabled.svg
+ dark/radio_checked.svg
+ dark/radio_checked_disabled.svg
+ dark/radio_unchecked.svg
+ dark/radio_unchecked_disabled.svg
+
+
diff --git a/src/QuickCut/Styles/theme_amoled.qss b/src/QuickCut/Styles/theme_amoled.qss
new file mode 100644
index 0000000..b5fd7c2
--- /dev/null
+++ b/src/QuickCut/Styles/theme_amoled.qss
@@ -0,0 +1,579 @@
+/*
+AMOLED Style Sheet for QT Applications
+Author: Jaime A. Quiroga P.
+Company: GTRONICK
+Last updated: 22/01/2019, 12:33.
+Available at: https://github.com/GTRONICK/QSS/blob/master/AMOLED.qss
+*/
+QMainWindow {
+ background-color:#000000;
+}
+QDialog {
+ background-color:#000000;
+}
+QColorDialog {
+ background-color:#000000;
+}
+QTextEdit {
+ background-color:#000000;
+ color: #a9b7c6;
+}
+QPlainTextEdit {
+ selection-background-color:#f39c12;
+ background-color:#000000;
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ border-width: 1px;
+ color: #a9b7c6;
+}
+QPushButton{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ border-width: 1px;
+ border-style: solid;
+ color: #a9b7c6;
+ padding: 2px;
+ background-color: #000000;
+}
+QPushButton::default{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #e67e22;
+ border-width: 1px;
+ color: #a9b7c6;
+ padding: 2px;
+ background-color: #000000;
+}
+QToolButton {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #e67e22;
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: #a9b7c6;
+ padding: 2px;
+ background-color: #000000;
+}
+QToolButton:hover{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #e67e22;
+ border-bottom-width: 2px;
+ border-bottom-radius: 6px;
+ border-style: solid;
+ color: #FFFFFF;
+ padding-bottom: 1px;
+ background-color: #000000;
+}
+QPushButton:hover{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #e67e22;
+ border-bottom-width: 1px;
+ border-bottom-radius: 6px;
+ border-style: solid;
+ color: #FFFFFF;
+ padding-bottom: 2px;
+ background-color: #000000;
+}
+QPushButton:pressed{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #e67e22;
+ border-bottom-width: 2px;
+ border-bottom-radius: 6px;
+ border-style: solid;
+ color: #e67e22;
+ padding-bottom: 1px;
+ background-color: #000000;
+}
+QPushButton:disabled{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ border-bottom-width: 2px;
+ border-bottom-radius: 6px;
+ border-style: solid;
+ color: #808086;
+ padding-bottom: 1px;
+ background-color: #000000;
+}
+QLineEdit {
+ border-width: 1px; border-radius: 4px;
+ border-color: rgb(58, 58, 58);
+ border-style: inset;
+ padding: 0 8px;
+ color: #a9b7c6;
+ background:#000000;
+ selection-background-color:#007b50;
+ selection-color: #FFFFFF;
+}
+QLabel {
+ color: #a9b7c6;
+}
+QLCDNumber {
+ color: #e67e22;
+}
+QProgressBar {
+ text-align: center;
+ color: rgb(240, 240, 240);
+ border-width: 1px;
+ border-radius: 10px;
+ border-color: rgb(58, 58, 58);
+ border-style: inset;
+ background-color:#000000;
+}
+QProgressBar::chunk {
+ background-color: #e67e22;
+ border-radius: 5px;
+}
+QMenuBar {
+ background-color:#000000;
+}
+QMenuBar::item {
+ color: #a9b7c6;
+ spacing: 3px;
+ padding: 1px 4px;
+ background: #000000;
+}
+
+QMenuBar::item:selected {
+ background:#000000;
+ color: #FFFFFF;
+}
+QMenu::item:selected {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: #e67e22;
+ border-bottom-color: transparent;
+ border-left-width: 2px;
+ color: #FFFFFF;
+ padding-left:15px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:7px;
+ background-color:#000000;
+}
+QMenu::item {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: #a9b7c6;
+ padding-left:17px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:7px;
+ background-color:#000000;
+}
+QMenu{
+ background-color:#000000;
+}
+QTabWidget {
+ color:rgb(0,0,0);
+ background-color:#000000;
+}
+QTabWidget::pane {
+ border-color: rgb(77,77,77);
+ background-color:#000000;
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 6px;
+}
+QTabBar::tab {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: #808086;
+ padding: 3px;
+ margin-left:3px;
+ background-color:#000000;
+}
+QTabBar::tab:selected, QTabBar::tab:last:selected, QTabBar::tab:hover {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #e67e22;
+ border-bottom-width: 2px;
+ border-style: solid;
+ color: #FFFFFF;
+ padding-left: 3px;
+ padding-bottom: 2px;
+ margin-left:3px;
+ background-color:#000000;
+}
+
+QCheckBox {
+ color: #a9b7c6;
+ padding: 2px;
+}
+QCheckBox:disabled {
+ color: #808086;
+ padding: 2px;
+}
+
+QCheckBox:hover {
+ border-radius:4px;
+ border-style:solid;
+ padding-left: 1px;
+ padding-right: 1px;
+ padding-bottom: 1px;
+ padding-top: 1px;
+ border-width:1px;
+ border-color: rgb(87, 97, 106);
+ background-color:#000000;
+}
+QCheckBox::indicator:checked {
+
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-width: 1px;
+ border-color: #e67e22;
+ color: #a9b7c6;
+ background-color: #e67e22;
+}
+QCheckBox::indicator:unchecked {
+
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-width: 1px;
+ border-color: #e67e22;
+ color: #a9b7c6;
+ background-color: transparent;
+}
+QRadioButton {
+ color: #a9b7c6;
+ background-color:#000000;
+ padding: 1px;
+}
+QRadioButton::indicator:checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: #e67e22;
+ color: #a9b7c6;
+ background-color: #e67e22;
+}
+QRadioButton::indicator:!checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: #e67e22;
+ color: #a9b7c6;
+ background-color: transparent;
+}
+QStatusBar {
+ color:#027f7f;
+}
+QSpinBox {
+ color: #a9b7c6;
+ background-color:#000000;
+}
+QDoubleSpinBox {
+ color: #a9b7c6;
+ background-color:#000000;
+}
+QTimeEdit {
+ color: #a9b7c6;
+ background-color:#000000;
+}
+QDateTimeEdit {
+ color: #a9b7c6;
+ background-color:#000000;
+}
+QDateEdit {
+ color: #a9b7c6;
+ background-color:#000000;
+}
+QComboBox {
+ color: #a9b7c6;
+ background: #1e1d23;
+}
+QComboBox:editable {
+ background: #1e1d23;
+ color: #a9b7c6;
+ selection-background-color:#000000;
+}
+QComboBox QAbstractItemView {
+ color: #a9b7c6;
+ background: #1e1d23;
+ selection-color: #FFFFFF;
+ selection-background-color:#000000;
+}
+QComboBox:!editable:on, QComboBox::drop-down:editable:on {
+ color: #a9b7c6;
+ background: #1e1d23;
+}
+QFontComboBox {
+ color: #a9b7c6;
+ background-color:#000000;
+}
+QToolBox {
+ color: #a9b7c6;
+ background-color:#000000;
+}
+QToolBox::tab {
+ color: #a9b7c6;
+ background-color:#000000;
+}
+QToolBox::tab:selected {
+ color: #FFFFFF;
+ background-color:#000000;
+}
+QScrollArea {
+ color: #FFFFFF;
+ background-color:#000000;
+}
+QSlider::groove:horizontal {
+ height: 5px;
+ background: #e67e22;
+}
+QSlider::groove:vertical {
+ width: 5px;
+ background: #e67e22;
+}
+QSlider::handle:horizontal {
+ background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);
+ border: 1px solid #5c5c5c;
+ width: 14px;
+ margin: -5px 0;
+ border-radius: 7px;
+}
+QSlider::handle:vertical {
+ background: qlineargradient(x1:1, y1:1, x2:0, y2:0, stop:0 #b4b4b4, stop:1 #8f8f8f);
+ border: 1px solid #5c5c5c;
+ height: 14px;
+ margin: 0 -5px;
+ border-radius: 7px;
+}
+QSlider::add-page:horizontal {
+ background: white;
+}
+QSlider::add-page:vertical {
+ background: white;
+}
+QSlider::sub-page:horizontal {
+ background: #e67e22;
+}
+QSlider::sub-page:vertical {
+ background: #e67e22;
+}
+QScrollBar:horizontal {
+ max-height: 20px;
+ background: rgb(0,0,0);
+ border: 1px transparent grey;
+ margin: 0px 20px 0px 20px;
+}
+QScrollBar::handle:horizontal {
+ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 0, 0, 0), stop:0.7 rgba(255, 0, 0, 0), stop:0.71 rgb(230, 126, 34), stop:1 rgb(230, 126, 34));
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(0,0,0);
+ min-width: 25px;
+}
+QScrollBar::handle:horizontal:hover {
+ background: rgb(230, 126, 34);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(0,0,0);
+ min-width: 25px;
+}
+QScrollBar::add-line:horizontal {
+ border: 1px solid;
+ border-color: rgb(0,0,0);
+ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 0, 0, 0), stop:0.7 rgba(255, 0, 0, 0), stop:0.71 rgb(230, 126, 34), stop:1 rgb(230, 126, 34));
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:horizontal:hover {
+ border: 1px solid;
+ border-color: rgb(0,0,0);
+ border-radius: 8px;
+ background: rgb(230, 126, 34);
+ height: 16px;
+ width: 16px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:horizontal:pressed {
+ border: 1px solid;
+ border-color: grey;
+ border-radius: 8px;
+ background: rgb(230, 126, 34);
+ height: 16px;
+ width: 16px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal {
+ border: 1px solid;
+ border-color: rgb(0,0,0);
+ background-color: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 rgba(255, 0, 0, 0), stop:0.7 rgba(255, 0, 0, 0), stop:0.71 rgb(230, 126, 34), stop:1 rgb(230, 126, 34));
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal:hover {
+ border: 1px solid;
+ border-color: rgb(0,0,0);
+ border-radius: 8px;
+ background: rgb(230, 126, 34);
+ height: 16px;
+ width: 16px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal:pressed {
+ border: 1px solid;
+ border-color: grey;
+ border-radius: 8px;
+ background: rgb(230, 126, 34);
+ height: 16px;
+ width: 16px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::left-arrow:horizontal {
+ border: 1px transparent grey;
+ border-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(0,0,0);
+}
+QScrollBar::right-arrow:horizontal {
+ border: 1px transparent grey;
+ border-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(0,0,0);
+}
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
+ background: none;
+}
+QScrollBar:vertical {
+ max-width: 20px;
+ background: rgb(0,0,0);
+ border: 1px transparent grey;
+ margin: 20px 0px 20px 0px;
+}
+QScrollBar::add-line:vertical {
+ border: 1px solid;
+ border-color: rgb(0,0,0);
+ background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 0), stop:0.7 rgba(255, 0, 0, 0), stop:0.71 rgb(230, 126, 34), stop:1 rgb(230, 126, 34));
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:vertical:hover {
+ border: 1px solid;
+ border-color: rgb(0,0,0);
+ border-radius: 8px;
+ background: rgb(230, 126, 34);
+ height: 16px;
+ width: 16px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:vertical:pressed {
+ border: 1px solid;
+ border-color: grey;
+ border-radius: 8px;
+ background: rgb(230, 126, 34);
+ height: 16px;
+ width: 16px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical {
+ border: 1px solid;
+ border-color: rgb(0,0,0);
+ background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 0), stop:0.7 rgba(255, 0, 0, 0), stop:0.71 rgb(230, 126, 34), stop:1 rgb(230, 126, 34));
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical:hover {
+ border: 1px solid;
+ border-color: rgb(0,0,0);
+ border-radius: 8px;
+ background: rgb(230, 126, 34);
+ height: 16px;
+ width: 16px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical:pressed {
+ border: 1px solid;
+ border-color: grey;
+ border-radius: 8px;
+ background: rgb(230, 126, 34);
+ height: 16px;
+ width: 16px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+ QScrollBar::handle:vertical {
+ background-color: qlineargradient(x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 0), stop:0.7 rgba(255, 0, 0, 0), stop:0.71 rgb(230, 126, 34), stop:1 rgb(230, 126, 34));
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(0,0,0);
+ min-height: 25px;
+}
+QScrollBar::handle:vertical:hover {
+ background: rgb(230, 126, 34);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(0,0,0);
+ min-heigth: 25px;
+}
+QScrollBar::up-arrow:vertical {
+ border: 1px transparent grey;
+ border-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(0,0,0);
+}
+QScrollBar::down-arrow:vertical {
+ border: 1px transparent grey;
+ border-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(0,0,0);
+}
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
+ background: none;
+}
diff --git a/src/QuickCut/Styles/theme_aqua.qss b/src/QuickCut/Styles/theme_aqua.qss
new file mode 100644
index 0000000..cce4c77
--- /dev/null
+++ b/src/QuickCut/Styles/theme_aqua.qss
@@ -0,0 +1,559 @@
+/*
+Aqua Style Sheet for QT Applications
+Author: Jaime A. Quiroga P.
+Company: GTRONICK
+Last updated: 22/01/2019, 07:55.
+Available at: https://github.com/GTRONICK/QSS/blob/master/Aqua.qss
+*/
+QMainWindow {
+ background-color:#ececec;
+}
+QTextEdit {
+ border-width: 1px;
+ border-style: solid;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+QPlainTextEdit {
+ border-width: 1px;
+ border-style: solid;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+QToolButton {
+ border-style: solid;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(217, 217, 217), stop:1 rgb(227, 227, 227));
+ border-left-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(227, 227, 227), stop:1 rgb(217, 217, 217));
+ border-bottom-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-width: 1px;
+ border-radius: 5px;
+ color: rgb(0,0,0);
+ padding: 2px;
+ background-color: rgb(255,255,255);
+}
+QToolButton:hover{
+ border-style: solid;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(195, 195, 195), stop:1 rgb(222, 222, 222));
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(197, 197, 197), stop:1 rgb(227, 227, 227));
+ border-left-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(227, 227, 227), stop:1 rgb(197, 197, 197));
+ border-bottom-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(195, 195, 195), stop:1 rgb(222, 222, 222));
+ border-width: 1px;
+ border-radius: 5px;
+ color: rgb(0,0,0);
+ padding: 2px;
+ background-color: rgb(255,255,255);
+}
+QToolButton:pressed{
+ border-style: solid;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(217, 217, 217), stop:1 rgb(227, 227, 227));
+ border-left-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(227, 227, 227), stop:1 rgb(217, 217, 217));
+ border-bottom-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-width: 1px;
+ border-radius: 5px;
+ color: rgb(0,0,0);
+ padding: 2px;
+ background-color: rgb(142,142,142);
+}
+QPushButton{
+ border-style: solid;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(217, 217, 217), stop:1 rgb(227, 227, 227));
+ border-left-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(227, 227, 227), stop:1 rgb(217, 217, 217));
+ border-bottom-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-width: 1px;
+ border-radius: 5px;
+ color: rgb(0,0,0);
+ padding: 2px;
+ background-color: rgb(255,255,255);
+}
+QPushButton::default{
+ border-style: solid;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(217, 217, 217), stop:1 rgb(227, 227, 227));
+ border-left-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(227, 227, 227), stop:1 rgb(217, 217, 217));
+ border-bottom-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-width: 1px;
+ border-radius: 5px;
+ color: rgb(0,0,0);
+ padding: 2px;
+ background-color: rgb(255,255,255);
+}
+QPushButton:hover{
+ border-style: solid;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(195, 195, 195), stop:1 rgb(222, 222, 222));
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(197, 197, 197), stop:1 rgb(227, 227, 227));
+ border-left-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(227, 227, 227), stop:1 rgb(197, 197, 197));
+ border-bottom-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(195, 195, 195), stop:1 rgb(222, 222, 222));
+ border-width: 1px;
+ border-radius: 5px;
+ color: rgb(0,0,0);
+ padding: 2px;
+ background-color: rgb(255,255,255);
+}
+QPushButton:pressed{
+ border-style: solid;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(217, 217, 217), stop:1 rgb(227, 227, 227));
+ border-left-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(227, 227, 227), stop:1 rgb(217, 217, 217));
+ border-bottom-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-width: 1px;
+ border-radius: 5px;
+ color: rgb(0,0,0);
+ padding: 2px;
+ background-color: rgb(142,142,142);
+}
+QPushButton:disabled{
+ border-style: solid;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(217, 217, 217), stop:1 rgb(227, 227, 227));
+ border-left-color: qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgb(227, 227, 227), stop:1 rgb(217, 217, 217));
+ border-bottom-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgb(215, 215, 215), stop:1 rgb(222, 222, 222));
+ border-width: 1px;
+ border-radius: 5px;
+ color: #808086;
+ padding: 2px;
+ background-color: rgb(142,142,142);
+}
+QLineEdit {
+ border-width: 1px; border-radius: 4px;
+ border-style: solid;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+QLabel {
+ color: #000000;
+}
+QLCDNumber {
+ color: rgb(0, 113, 255, 255);
+}
+QProgressBar {
+ text-align: center;
+ color: rgb(240, 240, 240);
+ border-width: 1px;
+ border-radius: 10px;
+ border-color: rgb(230, 230, 230);
+ border-style: solid;
+ background-color:rgb(207,207,207);
+}
+QProgressBar::chunk {
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(49, 147, 250, 255), stop:1 rgba(34, 142, 255, 255));
+ border-radius: 10px;
+}
+QMenuBar {
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(207, 209, 207, 255), stop:1 rgba(230, 229, 230, 255));
+}
+QMenuBar::item {
+ color: #000000;
+ spacing: 3px;
+ padding: 1px 4px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(207, 209, 207, 255), stop:1 rgba(230, 229, 230, 255));
+}
+
+QMenuBar::item:selected {
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+ color: #FFFFFF;
+}
+QMenu::item:selected {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+ border-bottom-color: transparent;
+ border-left-width: 2px;
+ color: #000000;
+ padding-left:15px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:7px;
+}
+QMenu::item {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ border-bottom-width: 1px;
+ color: #000000;
+ padding-left:17px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:7px;
+}
+QTabWidget {
+ color:rgb(0,0,0);
+ background-color:#000000;
+}
+QTabWidget::pane {
+ border-color: rgb(223,223,223);
+ background-color:rgb(226,226,226);
+ border-style: solid;
+ border-width: 2px;
+ border-radius: 6px;
+}
+QTabBar::tab:first {
+ border-style: solid;
+ border-left-width:1px;
+ border-right-width:0px;
+ border-top-width:1px;
+ border-bottom-width:1px;
+ border-top-color: rgb(209,209,209);
+ border-left-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(209, 209, 209, 209), stop:1 rgba(229, 229, 229, 229));
+ border-bottom-color: rgb(229,229,229);
+ border-top-left-radius: 4px;
+ border-bottom-left-radius: 4px;
+ color: #000000;
+ padding: 3px;
+ margin-left:0px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(247, 247, 247, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QTabBar::tab:last {
+ border-style: solid;
+ border-width:1px;
+ border-top-color: rgb(209,209,209);
+ border-left-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(209, 209, 209, 209), stop:1 rgba(229, 229, 229, 229));
+ border-right-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(209, 209, 209, 209), stop:1 rgba(229, 229, 229, 229));
+ border-bottom-color: rgb(229,229,229);
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ color: #000000;
+ padding: 3px;
+ margin-left:0px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(247, 247, 247, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QTabBar::tab {
+ border-style: solid;
+ border-top-width:1px;
+ border-bottom-width:1px;
+ border-left-width:1px;
+ border-top-color: rgb(209,209,209);
+ border-left-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(209, 209, 209, 209), stop:1 rgba(229, 229, 229, 229));
+ border-bottom-color: rgb(229,229,229);
+ color: #000000;
+ padding: 3px;
+ margin-left:0px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(247, 247, 247, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QTabBar::tab:selected, QTabBar::tab:last:selected, QTabBar::tab:hover {
+ border-style: solid;
+ border-left-width:1px;
+ border-right-color: transparent;
+ border-top-color: rgb(209,209,209);
+ border-left-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(209, 209, 209, 209), stop:1 rgba(229, 229, 229, 229));
+ border-bottom-color: rgb(229,229,229);
+ color: #FFFFFF;
+ padding: 3px;
+ margin-left:0px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+
+QTabBar::tab:selected, QTabBar::tab:first:selected, QTabBar::tab:hover {
+ border-style: solid;
+ border-left-width:1px;
+ border-bottom-width:1px;
+ border-top-width:1px;
+ border-right-color: transparent;
+ border-top-color: rgb(209,209,209);
+ border-left-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(209, 209, 209, 209), stop:1 rgba(229, 229, 229, 229));
+ border-bottom-color: rgb(229,229,229);
+ color: #FFFFFF;
+ padding: 3px;
+ margin-left:0px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+
+QCheckBox {
+ color: #000000;
+ padding: 2px;
+}
+QCheckBox:disabled {
+ color: #808086;
+ padding: 2px;
+}
+
+QCheckBox:hover {
+ border-radius:4px;
+ border-style:solid;
+ padding-left: 1px;
+ padding-right: 1px;
+ padding-bottom: 1px;
+ padding-top: 1px;
+ border-width:1px;
+ border-color: transparent;
+}
+QCheckBox::indicator:checked {
+
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-width: 1px;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+ color: #000000;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+QCheckBox::indicator:unchecked {
+
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-width: 1px;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+ color: #000000;
+}
+QRadioButton {
+ color: 000000;
+ padding: 1px;
+}
+QRadioButton::indicator:checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+ color: #a9b7c6;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+QRadioButton::indicator:!checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+ color: #a9b7c6;
+ background-color: transparent;
+}
+QStatusBar {
+ color:#027f7f;
+}
+QSpinBox {
+ border-style: solid;
+ border-width: 1px;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+QDoubleSpinBox {
+ border-style: solid;
+ border-width: 1px;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+QTimeEdit {
+ border-style: solid;
+ border-width: 1px;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+QDateTimeEdit {
+ border-style: solid;
+ border-width: 1px;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+QDateEdit {
+ border-style: solid;
+ border-width: 1px;
+ border-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(0, 113, 255, 255), stop:1 rgba(91, 171, 252, 255));
+}
+
+QToolBox {
+ color: #a9b7c6;
+ background-color:#000000;
+}
+QToolBox::tab {
+ color: #a9b7c6;
+ background-color:#000000;
+}
+QToolBox::tab:selected {
+ color: #FFFFFF;
+ background-color:#000000;
+}
+QScrollArea {
+ color: #FFFFFF;
+ background-color:#000000;
+}
+QSlider::groove:horizontal {
+ height: 5px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(49, 147, 250, 255), stop:1 rgba(34, 142, 255, 255));
+}
+QSlider::groove:vertical {
+ width: 5px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(49, 147, 250, 255), stop:1 rgba(34, 142, 255, 255));
+}
+QSlider::handle:horizontal {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ width: 12px;
+ margin: -5px 0;
+ border-radius: 7px;
+}
+QSlider::handle:vertical {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ height: 12px;
+ margin: 0 -5px;
+ border-radius: 7px;
+}
+QSlider::add-page:horizontal {
+ background: rgb(181,181,181);
+}
+QSlider::add-page:vertical {
+ background: rgb(181,181,181);
+}
+QSlider::sub-page:horizontal {
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(49, 147, 250, 255), stop:1 rgba(34, 142, 255, 255));
+}
+QSlider::sub-page:vertical {
+ background-color: qlineargradient(spread:pad, y1:0.5, x1:1, y2:0.5, x2:0, stop:0 rgba(49, 147, 250, 255), stop:1 rgba(34, 142, 255, 255));
+}
+QScrollBar:horizontal {
+ max-height: 20px;
+ border: 1px transparent grey;
+ margin: 0px 20px 0px 20px;
+}
+QScrollBar:vertical {
+ max-width: 20px;
+ border: 1px transparent grey;
+ margin: 20px 0px 20px 0px;
+}
+QScrollBar::handle:horizontal {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ border-radius: 7px;
+ min-width: 25px;
+}
+QScrollBar::handle:horizontal:hover {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(147, 200, 200);
+ border-radius: 7px;
+ min-width: 25px;
+}
+QScrollBar::handle:vertical {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ border-radius: 7px;
+ min-height: 25px;
+}
+QScrollBar::handle:vertical:hover {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(147, 200, 200);
+ border-radius: 7px;
+ min-height: 25px;
+}
+QScrollBar::add-line:horizontal {
+ border: 2px transparent grey;
+ border-top-right-radius: 7px;
+ border-bottom-right-radius: 7px;
+ background: rgba(34, 142, 255, 255);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:horizontal:pressed {
+ border: 2px transparent grey;
+ border-top-right-radius: 7px;
+ border-bottom-right-radius: 7px;
+ background: rgb(181,181,181);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:vertical {
+ border: 2px transparent grey;
+ border-bottom-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ background: rgba(34, 142, 255, 255);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:vertical:pressed {
+ border: 2px transparent grey;
+ border-bottom-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ background: rgb(181,181,181);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal {
+ border: 2px transparent grey;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgba(34, 142, 255, 255);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal:pressed {
+ border: 2px transparent grey;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(181,181,181);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical {
+ border: 2px transparent grey;
+ border-top-left-radius: 7px;
+ border-top-right-radius: 7px;
+ background: rgba(34, 142, 255, 255);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical:pressed {
+ border: 2px transparent grey;
+ border-top-left-radius: 7px;
+ border-top-right-radius: 7px;
+ background: rgb(181,181,181);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+QScrollBar::left-arrow:horizontal {
+ border: 1px transparent grey;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: white;
+}
+QScrollBar::right-arrow:horizontal {
+ border: 1px transparent grey;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: white;
+}
+QScrollBar::up-arrow:vertical {
+ border: 1px transparent grey;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: white;
+}
+QScrollBar::down-arrow:vertical {
+ border: 1px transparent grey;
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: white;
+}
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
+ background: none;
+}
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
+ background: none;
+}
diff --git a/src/QuickCut/Styles/theme_breezeDark.qss b/src/QuickCut/Styles/theme_breezeDark.qss
new file mode 100644
index 0000000..1a14b05
--- /dev/null
+++ b/src/QuickCut/Styles/theme_breezeDark.qss
@@ -0,0 +1,1648 @@
+/*
+ * BreezeDark stylesheet.
+ *
+ * :author: Colin Duquesnoy
+ * :editor: Alex Huszagh
+ * :license: MIT, see LICENSE.md
+ *
+ * This is originally a fork of QDarkStyleSheet, and is based on Breeze/
+ * BreezeDark color scheme, but is in no way affiliated with KDE.
+ *
+ * ---------------------------------------------------------------------
+ * The MIT License (MIT)
+ *
+ * Copyright (c) <2013-2014>
+ * Copyright (c) <2015-2016>
+ *
+ * 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.
+ * ---------------------------------------------------------------------
+ */
+
+QToolTip
+{
+ border: 0.1ex solid #eff0f1;
+ background-color: #31363b;
+ alternate-background-color: #3b4045;
+ color: #eff0f1;
+ padding: 0.5ex;
+ opacity: 200;
+}
+
+QWidget
+{
+ color: #eff0f1;
+ background-color: #31363b;
+ selection-background-color:#3daee9;
+ selection-color: #eff0f1;
+ background-clip: border;
+ border-image: none;
+ border: 0px transparent black;
+ outline: 0;
+}
+
+QWidget:item:hover
+{
+ background-color: #3daee9;
+ color: #eff0f1;
+}
+
+QWidget:item:selected
+{
+ background-color: #3daee9;
+}
+
+
+QCheckBox
+{
+ spacing: 0.5ex;
+ outline: none;
+ color: #eff0f1;
+ margin-bottom: 0.2ex;
+ opacity: 200;
+}
+
+QCheckBox:disabled
+{
+ color: #76797c;
+}
+
+QGroupBox::indicator
+{
+ margin-left: 0.2ex;
+}
+
+QCheckBox::indicator:unchecked,
+QCheckBox::indicator:unchecked:focus
+{
+ border-image: url(:/breeze_icons/dark/checkbox_unchecked_disabled.svg);
+}
+
+QCheckBox::indicator:unchecked:hover,
+QCheckBox::indicator:unchecked:pressed,
+QGroupBox::indicator:unchecked:hover,
+QGroupBox::indicator:unchecked:focus,
+QGroupBox::indicator:unchecked:pressed
+{
+ border: none;
+ border-image: url(:/breeze_icons/dark/checkbox_unchecked.svg);
+}
+
+QCheckBox::indicator:checked
+{
+ border-image: url(:/breeze_icons/dark/checkbox_checked.svg);
+}
+
+QCheckBox::indicator:checked:hover,
+QCheckBox::indicator:checked:focus,
+QCheckBox::indicator:checked:pressed,
+QGroupBox::indicator:checked:hover,
+QGroupBox::indicator:checked:focus,
+QGroupBox::indicator:checked:pressed
+{
+ border: none;
+ border-image: url(:/breeze_icons/dark/checkbox_checked.svg);
+}
+
+QCheckBox::indicator:indeterminate
+{
+ border-image: url(:/breeze_icons/dark/checkbox_indeterminate.svg);
+}
+
+QCheckBox::indicator:indeterminate:focus,
+QCheckBox::indicator:indeterminate:hover,
+QCheckBox::indicator:indeterminate:pressed
+{
+ border-image: url(:/breeze_icons/dark/checkbox_indeterminate.svg);
+}
+
+QCheckBox::indicator:indeterminate:disabled
+{
+ border-image: url(:/breeze_icons/dark/checkbox_indeterminate_disabled.svg);
+}
+
+QCheckBox::indicator:checked:disabled,
+QGroupBox::indicator:checked:disabled
+{
+ border-image: url(:/breeze_icons/dark/checkbox_checked_disabled.svg);
+}
+
+QCheckBox::indicator:unchecked:disabled,
+QGroupBox::indicator:unchecked:disabled
+{
+ border-image: url(:/breeze_icons/dark/checkbox_unchecked_disabled.svg);
+}
+
+QRadioButton
+{
+ spacing: 0.5ex;
+ outline: none;
+ color: #eff0f1;
+ margin-bottom: 0.2ex;
+}
+
+QRadioButton:disabled
+{
+ color: #76797c;
+}
+
+QRadioButton::indicator:unchecked,
+QRadioButton::indicator:unchecked:focus
+{
+ border-image: url(:/breeze_icons/dark/radio_unchecked_disabled.svg);
+}
+
+
+QRadioButton::indicator:unchecked:hover,
+QRadioButton::indicator:unchecked:pressed
+{
+ border: none;
+ outline: none;
+ border-image: url(:/breeze_icons/dark/radio_unchecked.svg);
+}
+
+
+QRadioButton::indicator:checked
+{
+ border: none;
+ outline: none;
+ border-image: url(:/breeze_icons/dark/radio_checked.svg);
+}
+
+QRadioButton::indicator:checked:hover,
+QRadioButton::indicator:checked:focus,
+QRadioButton::indicator:checked:pressed
+{
+ border: none;
+ outline: none;
+ border-image: url(:/breeze_icons/dark/radio_checked.svg);
+}
+
+QRadioButton::indicator:checked:disabled
+{
+ outline: none;
+ border-image: url(:/breeze_icons/dark/radio_checked_disabled.svg);
+}
+
+QRadioButton::indicator:unchecked:disabled
+{
+ border-image: url(:/breeze_icons/dark/radio_unchecked_disabled.svg);
+}
+
+QMenuBar
+{
+ background-color: #31363b;
+ color: #eff0f1;
+}
+
+QMenuBar::item
+{
+ background: transparent;
+}
+
+QMenuBar::item:selected
+{
+ background: transparent;
+ border: 0.1ex solid #76797c;
+}
+
+QMenuBar::item:pressed
+{
+ border: 0.1ex solid #76797c;
+ background-color: #3daee9;
+ color: #eff0f1;
+ margin-bottom: -0.1ex;
+ padding-bottom: 0.1ex;
+}
+
+QMenu
+{
+ border: 0.1ex solid #76797c;
+ color: #eff0f1;
+ margin: 0.2ex;
+}
+
+QMenu::icon
+{
+ margin: 0.5ex;
+}
+
+QMenu::item
+{
+ padding: 0.5ex 3ex 0.5ex 3ex;
+ margin-left: 0.5ex;
+ border: 0.1ex solid transparent; /* reserve space for selection border */
+}
+
+QMenu::item:selected
+{
+ color: #eff0f1;
+}
+
+QMenu::separator
+{
+ height: 0.2ex;
+ background: lightblue;
+ margin-left: 1ex;
+ margin-right: 0.5ex;
+}
+
+/* non-exclusive indicator = check box style indicator
+ (see QActionGroup::setExclusive) */
+QMenu::indicator:non-exclusive:unchecked
+{
+ border-image: url(:/breeze_icons/dark/checkbox_unchecked_disabled.svg);
+}
+
+QMenu::indicator:non-exclusive:unchecked:selected
+{
+ border-image: url(:/breeze_icons/dark/checkbox_unchecked_disabled.svg);
+}
+
+QMenu::indicator:non-exclusive:checked
+{
+ border-image: url(:/breeze_icons/dark/checkbox_checked.svg);
+}
+
+QMenu::indicator:non-exclusive:checked:selected
+{
+ border-image: url(:/breeze_icons/dark/checkbox_checked.svg);
+}
+
+/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */
+QMenu::indicator:exclusive:unchecked
+{
+ border-image: url(:/breeze_icons/dark/radio_unchecked_disabled.svg);
+}
+
+QMenu::indicator:exclusive:unchecked:selected
+{
+ border-image: url(:/breeze_icons/dark/radio_unchecked_disabled.svg);
+}
+
+QMenu::indicator:exclusive:checked
+{
+ border-image: url(:/breeze_icons/dark/radio_checked.svg);
+}
+
+QMenu::indicator:exclusive:checked:selected
+{
+ border-image: url(:/breeze_icons/dark/radio_checked.svg);
+}
+
+QMenu::right-arrow
+{
+ margin: 0.5ex;
+ border-image: url(:/breeze_icons/light/right_arrow.svg);
+ width: 0.6ex;
+ height: 0.9ex;
+}
+
+
+QWidget:disabled
+{
+ color: #454545;
+ background-color: #31363b;
+}
+
+QAbstractItemView
+{
+ alternate-background-color: #31363b;
+ color: #eff0f1;
+ border: 0.1ex solid 3A3939;
+ border-radius: 0.2ex;
+}
+
+QWidget:focus,
+QMenuBar:focus
+{
+ border: 0.1ex solid #3daee9;
+}
+
+QTabWidget:focus,
+QCheckBox:focus,
+QRadioButton:focus,
+QSlider:focus
+{
+ border: none;
+}
+
+QLineEdit
+{
+ background-color: #232629;
+ padding: 0.5ex;
+ border-style: solid;
+ border: 0.1ex solid #76797c;
+ border-radius: 0.2ex;
+ color: #eff0f1;
+}
+
+QGroupBox
+{
+ border: 0.1ex solid #76797c;
+ border-radius: 0.2ex;
+ padding-top: 1ex;
+ margin-top: 1ex;
+}
+
+QGroupBox::title
+{
+ subcontrol-origin: margin;
+ subcontrol-position: top center;
+ padding-left: 0.1ex;
+ padding-right: 0.1ex;
+ margin-top: -0.7ex;
+}
+
+QAbstractScrollArea
+{
+ border-radius: 0.2ex;
+ border: 0.1ex solid #76797c;
+ background-color: transparent;
+}
+
+QScrollBar:horizontal
+{
+ height: 1.5ex;
+ margin: 0.3ex 1.5ex 0.3ex 1.5ex;
+ border: 0.1ex transparent #2A2929;
+ border-radius: 0.4ex;
+ background-color: #2A2929;
+}
+
+QScrollBar::handle:horizontal
+{
+ background-color: #3daee9;
+ min-width: 0.5ex;
+ border-radius: 0.4ex;
+}
+
+QScrollBar::add-line:horizontal
+{
+ margin: 0px 0.3ex 0px 0.3ex;
+ border-image: url(:/breeze_icons/dark/right_arrow_disabled.svg);
+ width: 1ex;
+ height: 1ex;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:horizontal
+{
+ margin: 0ex 0.3ex 0ex 0.3ex;
+ border-image: url(:/breeze_icons/dark/left_arrow_disabled.svg);
+ width: 1ex;
+ height: 1ex;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::add-line:horizontal:hover,
+QScrollBar::add-line:horizontal:on
+{
+ border-image: url(:/breeze_icons/dark/right_arrow.svg);
+ width: 1ex;
+ height: 1ex;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+
+
+QScrollBar::sub-line:horizontal:hover,
+QScrollBar::sub-line:horizontal:on
+{
+ border-image: url(:/breeze_icons/dark/left_arrow.svg);
+ width: 1ex;
+ height: 1ex;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::up-arrow:horizontal,
+QScrollBar::down-arrow:horizontal
+{
+ background: none;
+}
+
+
+QScrollBar::add-page:horizontal,
+QScrollBar::sub-page:horizontal
+{
+ background: none;
+}
+
+QScrollBar:vertical
+{
+ background-color: #2A2929;
+ width: 1.5ex;
+ margin: 1.5ex 0.3ex 1.5ex 0.3ex;
+ border: 0.1ex transparent #2A2929;
+ border-radius: 0.4ex;
+}
+
+QScrollBar::handle:vertical
+{
+ background-color: #3daee9;
+ min-height: 0.5ex;
+ border-radius: 0.4ex;
+}
+
+QScrollBar::sub-line:vertical
+{
+ margin: 0.3ex 0ex 0.3ex 0ex;
+ border-image: url(:/breeze_icons/dark/up_arrow_disabled.svg);
+ height: 1ex;
+ width: 1ex;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::add-line:vertical
+{
+ margin: 0.3ex 0ex 0.3ex 0ex;
+ border-image: url(:/breeze_icons/dark/down_arrow_disabled.svg);
+ height: 1ex;
+ width: 1ex;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:vertical:hover,
+QScrollBar::sub-line:vertical:on
+{
+
+ border-image: url(:/breeze_icons/dark/up_arrow.svg);
+ height: 1ex;
+ width: 1ex;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+
+
+QScrollBar::add-line:vertical:hover,
+QScrollBar::add-line:vertical:on
+{
+ border-image: url(:/breeze_icons/dark/down_arrow.svg);
+ height: 1ex;
+ width: 1ex;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::up-arrow:vertical, QScrollBar::down-arrow:vertical
+{
+ background: none;
+}
+
+
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical
+{
+ background: none;
+}
+
+QTextEdit
+{
+ background-color: #232629;
+ color: #eff0f1;
+ border: 0.1ex solid #76797c;
+}
+
+QPlainTextEdit
+{
+ background-color: #232629;;
+ color: #eff0f1;
+ border-radius: 0.2ex;
+ border: 0.1ex solid #76797c;
+}
+
+QHeaderView::section
+{
+ background-color: #76797c;
+ color: #eff0f1;
+ padding: 0.5ex;
+ border: 0.1ex solid #76797c;
+}
+
+QSizeGrip
+{
+ border-image: url(:/breeze_icons/dark/sizegrip.svg);
+ width: 1.2ex;
+ height: 1.2ex;
+}
+
+QMainWindow::separator
+{
+ background-color: #31363b;
+ color: white;
+ padding-left: 0.4ex;
+ spacing: 0.2ex;
+ border: 0.1ex dashed #76797c;
+}
+
+QMainWindow::separator:hover
+{
+
+ background-color: #787876;
+ color: white;
+ padding-left: 0.4ex;
+ border: 0.1ex solid #76797c;
+ spacing: 0.2ex;
+}
+
+QMenu::separator
+{
+ height: 0.1ex;
+ background-color: #76797c;
+ color: white;
+ padding-left: 0.4ex;
+ margin-left: 1ex;
+ margin-right: 0.5ex;
+}
+
+QFrame[frameShape="2"], /* QFrame::Panel == 0x0003 */
+QFrame[frameShape="3"], /* QFrame::WinPanel == 0x0003 */
+QFrame[frameShape="4"], /* QFrame::HLine == 0x0004 */
+QFrame[frameShape="5"], /* QFrame::VLine == 0x0005 */
+QFrame[frameShape="6"] /* QFrame::StyledPanel == 0x0006 */
+{
+ border-width: 0.1ex;
+ padding: 0.1ex;
+ border-style: solid;
+ border-color: #31363b;
+ background-color: #76797c;
+ border-radius: 0.5ex;
+}
+
+QStackedWidget
+{
+ border: 0.1ex transparent black;
+}
+
+QToolBar
+{
+ border: 0.1ex transparent #393838;
+ background: 0.1ex solid #31363b;
+ font-weight: bold;
+}
+
+QToolBar::handle:horizontal
+{
+ border-image: url(:/breeze_icons/dark/hmovetoolbar.svg);
+ width = 1.6ex;
+ height = 6.4ex;
+}
+
+QToolBar::handle:vertical
+{
+ border-image: url(:/breeze_icons/dark/vmovetoolbar.svg);
+ width = 5.4ex;
+ height = 1ex;
+}
+
+QToolBar::separator:horizontal
+{
+ border-image: url(:/breeze_icons/dark/hsepartoolbar.svg);
+ width = 0.7ex;
+ height = 6.3ex;
+}
+
+QToolBar::separator:vertical
+{
+ border-image: url(:/breeze_icons/dark/vsepartoolbars.svg);
+ width = 6.3ex;
+ height = 0.7ex;
+}
+
+QPushButton
+{
+ color: #eff0f1;
+ background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #3b4045, stop: 0.5 #31363b);
+ border-width: 0.1ex;
+ border-color: #76797c;
+ border-style: solid;
+ padding: 0.5ex;
+ border-radius: 0.2ex;
+ outline: none;
+}
+
+QPushButton:disabled
+{
+ background-color: #31363b;
+ border-width: 0.1ex;
+ border-color: #454545;
+ border-style: solid;
+ padding-top: 0.5ex;
+ padding-bottom: 0.5ex;
+ padding-left: 1ex;
+ padding-right: 1ex;
+ border-radius: 0.2ex;
+ color: #454545;
+}
+
+QPushButton:focus
+{
+ color: white;
+}
+
+QPushButton:pressed
+{
+ background-color: #31363b;
+ padding-top: -1.5ex;
+ padding-bottom: -1.7ex;
+}
+
+QComboBox
+{
+ selection-background-color: #3daee9;
+ border-style: solid;
+ border: 0.1ex solid #76797c;
+ border-radius: 0.2ex;
+ padding: 0.5ex;
+ min-width: 7.5ex;
+}
+
+QPushButton:checked
+{
+ background-color: #76797c;
+ border-color: #6A6969;
+}
+
+QPushButton:hover
+{
+ background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #454a4f, stop: 0.5 #3b4045);
+ border: 0.1ex solid #3daee9;
+ color: #eff0f1;
+}
+
+QPushButton:checked:hover
+{
+ background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #808386, stop: 0.5 #76797c);
+ border: 0.1ex solid #3daee9;
+ color: #eff0f1;
+}
+
+QComboBox:hover,
+QAbstractSpinBox:hover,
+QLineEdit:hover,
+QTextEdit:hover,
+QPlainTextEdit:hover,
+QAbstractView:hover,
+QTreeView:hover
+{
+ border: 0.1ex solid #3daee9;
+ color: #eff0f1;
+}
+
+QComboBox:hover:pressed,
+QPushButton:hover:pressed,
+QAbstractSpinBox:hover:pressed,
+QLineEdit:hover:pressed,
+QTextEdit:hover:pressed,
+QPlainTextEdit:hover:pressed,
+QAbstractView:hover:pressed,
+QTreeView:hover:pressed
+{
+ background-color: #31363b;
+}
+
+QComboBox:on
+{
+ padding-top: 0.3ex;
+ padding-left: 0.4ex;
+ selection-background-color: #4a4a4a;
+}
+
+QComboBox QAbstractItemView
+{
+ background-color: #232629;
+ border-radius: 0.2ex;
+ border: 0.1ex solid #76797c;
+ selection-background-color: #3daee9;
+}
+
+QComboBox::drop-down
+{
+ subcontrol-origin: padding;
+ subcontrol-position: top right;
+ width: 1.5ex;
+
+ border-left-width: 0ex;
+ border-left-color: darkgray;
+ border-left-style: solid;
+ border-top-right-radius: 0.3ex;
+ border-bottom-right-radius: 0.3ex;
+}
+
+QComboBox::down-arrow
+{
+ border-image: url(:/breeze_icons/dark/down_arrow_disabled.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QComboBox::down-arrow:on,
+QComboBox::down-arrow:hover,
+QComboBox::down-arrow:focus
+{
+ border-image: url(:/breeze_icons/dark/down_arrow.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QAbstractSpinBox
+{
+ padding: 0.5ex;
+ border: 0.1ex solid #76797c;
+ background-color: #232629;
+ color: #eff0f1;
+ border-radius: 0.2ex;
+ min-width: 7.5ex;
+}
+
+QAbstractSpinBox:up-button
+{
+ background-color: transparent;
+ subcontrol-origin: border;
+ subcontrol-position: center right;
+}
+
+QAbstractSpinBox:down-button
+{
+ background-color: transparent;
+ subcontrol-origin: border;
+ subcontrol-position: center left;
+}
+
+QAbstractSpinBox::up-arrow,
+QAbstractSpinBox::up-arrow:disabled,
+QAbstractSpinBox::up-arrow:off
+{
+ border-image: url(:/breeze_icons/dark/up_arrow_disabled.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QAbstractSpinBox::up-arrow:hover
+{
+ border-image: url(:/breeze_icons/dark/up_arrow.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QAbstractSpinBox::down-arrow,
+QAbstractSpinBox::down-arrow:disabled,
+QAbstractSpinBox::down-arrow:off
+{
+ border-image: url(:/breeze_icons/dark/down_arrow_disabled.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QAbstractSpinBox::down-arrow:hover
+{
+ border-image: url(:/breeze_icons/dark/down_arrow.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QLabel
+{
+ border: 0ex solid black;
+}
+
+/* BORDERS */
+QTabWidget::pane
+{
+ padding: 0.5ex;
+ margin: 0.1ex;
+}
+
+QTabWidget::pane:top
+{
+ border: 0.1ex solid #76797c;
+ top: -0.1ex;
+}
+
+QTabWidget::pane:bottom
+{
+ border: 0.1ex solid #76797c;
+ bottom: -0.1ex;
+}
+
+QTabWidget::pane:left
+{
+ border: 0.1ex solid #76797c;
+ right: -0.1ex;
+}
+
+QTabWidget::pane:right
+{
+ border: 0.1ex solid #76797c;
+ left: -0.1ex;
+}
+
+
+QTabBar
+{
+ qproperty-drawBase: 0;
+ left: 0.5ex; /* move to the right by 0.5ex */
+ border-radius: 0.3ex;
+}
+
+QTabBar:focus
+{
+ border: 0ex transparent black;
+}
+
+QTabBar::close-button
+{
+ border-image: url(:/breeze_icons/dark/close.svg);
+ background: transparent;
+}
+
+QTabBar::close-button:hover
+{
+ border-image: url(:/breeze_icons/dark/close-hover.svg);
+ width: 1.2ex;
+ height: 1.2ex;
+ background: transparent;
+}
+
+QTabBar::close-button:pressed
+{
+ border-image: url(:/breeze_icons/dark/close-pressed.svg);
+ width: 1.2ex;
+ height: 1.2ex;
+ background: transparent;
+}
+
+/* TOP TABS */
+QTabBar::tab:top
+{
+ color: #eff0f1;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #76797c;
+ border-top: 0.1ex solid #76797c;
+ background-color: #31363b;
+ padding: 0.5ex;
+ min-width: 50px;
+ border-top-left-radius: 0.2ex;
+ border-top-right-radius: 0.2ex;
+}
+
+QTabBar::tab:top:last,
+QTabBar::tab:top:only-one
+{
+ color: #eff0f1;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #76797c;
+ border-right: 0.1ex solid #76797c;
+ border-top: 0.1ex solid #76797c;
+ background-color: #31363b;
+ padding: 0.5ex;
+ min-width: 50px;
+ border-top-left-radius: 0.2ex;
+ border-top-right-radius: 0.2ex;
+}
+
+QTabBar::tab:top:!selected
+{
+ color: #eff0f1;
+ background-color: #54575B;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #76797c;
+ border-top-left-radius: 0.2ex;
+ border-top-right-radius: 0.2ex;
+}
+
+QTabBar::tab:top:first:!selected
+{
+ color: #eff0f1;
+ background-color: #54575B;
+ border: 0.1ex transparent black;
+ border-top-left-radius: 0.2ex;
+ border-top-right-radius: 0.2ex;
+}
+
+QTabBar::tab:top:!selected:hover
+{
+ background-color: rgba(61, 173, 232, 0.2);
+ border: 0.1ex rgba(61, 173, 232, 0.2);
+ border-left: 0.1ex solid #76797c;
+}
+
+QTabBar::tab:top:!selected:first:hover
+{
+ background-color: rgba(61, 173, 232, 0.2);
+ border: 0.1ex rgba(61, 173, 232, 0.2);
+}
+
+/* BOTTOM TABS */
+
+QTabBar::tab:bottom
+{
+ color: #eff0f1;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #76797c;
+ border-bottom: 0.1ex solid #76797c;
+ background-color: #31363b;
+ padding: 0.5ex;
+ border-bottom-left-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+ min-width: 50px;
+}
+
+QTabBar::tab:bottom:last,
+QTabBar::tab:bottom:only-one
+{
+ color: #eff0f1;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #76797c;
+ border-right: 0.1ex solid #76797c;
+ border-bottom: 0.1ex solid #76797c;
+ background-color: #31363b;
+ padding: 0.5ex;
+ border-bottom-left-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+ min-width: 50px;
+}
+
+QTabBar::tab:bottom:!selected
+{
+ color: #eff0f1;
+ background-color: #54575B;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #76797c;
+ border-bottom-left-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+}
+
+QTabBar::tab:bottom:first:!selected
+{
+ color: #eff0f1;
+ background-color: #54575B;
+ border: 0.1ex transparent black;
+ border-top-left-radius: 0.2ex;
+ border-top-right-radius: 0.2ex;
+}
+
+QTabBar::tab:bottom:!selected:hover
+{
+ background-color: rgba(61, 173, 232, 0.2);
+ border: 0.1ex rgba(61, 173, 232, 0.2);
+ border-left: 0.1ex solid #76797c;
+}
+
+QTabBar::tab:bottom:!selected:first:hover
+{
+ background-color: rgba(61, 173, 232, 0.2);
+ border: 0.1ex rgba(61, 173, 232, 0.2);
+}
+
+/* LEFT TABS */
+QTabBar::tab:left
+{
+ color: #eff0f1;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #76797c;
+ border-right: 0.1ex solid #76797c;
+ background-color: #31363b;
+ padding: 0.5ex;
+ border-top-right-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+ min-height: 50px;
+}
+
+QTabBar::tab:left:last,
+QTabBar::tab:left:only-one
+{
+ color: #eff0f1;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #76797c;
+ border-bottom: 0.1ex solid #76797c;
+ border-right: 0.1ex solid #76797c;
+ background-color: #31363b;
+ padding: 0.5ex;
+ border-top-right-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+ min-height: 50px;
+}
+
+QTabBar::tab:left:!selected
+{
+ color: #eff0f1;
+ background-color: #54575B;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #76797c;
+ border-top-right-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+}
+
+QTabBar::tab:left:!selected:hover
+{
+ background-color: rgba(61, 173, 232, 0.2);
+ border: 0.1ex rgba(61, 173, 232, 0.2);
+ border-top: 0.1ex solid #76797c;
+}
+
+QTabBar::tab:left:!selected:first:hover
+{
+ background-color: rgba(61, 173, 232, 0.2);
+ border: 0.1ex rgba(61, 173, 232, 0.2);
+}
+
+/* RIGHT TABS */
+QTabBar::tab:right
+{
+ color: #eff0f1;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #76797c;
+ border-left: 0.1ex solid #76797c;
+ background-color: #31363b;
+ padding: 0.5ex;
+ border-top-left-radius: 0.2ex;
+ border-bottom-left-radius: 0.2ex;
+ min-height: 50px;
+}
+
+QTabBar::tab:right:last,
+QTabBar::tab:right:only-one
+{
+ color: #eff0f1;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #76797c;
+ border-bottom: 0.1ex solid #76797c;
+ border-left: 0.1ex solid #76797c;
+ background-color: #31363b;
+ padding: 0.5ex;
+ border-top-left-radius: 0.2ex;
+ border-bottom-left-radius: 0.2ex;
+ min-height: 50px;
+}
+
+QTabBar::tab:right:!selected
+{
+ color: #eff0f1;
+ background-color: #54575B;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #76797c;
+ border-top-left-radius: 0.2ex;
+ border-bottom-left-radius: 0.2ex;
+}
+
+QTabBar::tab:right:!selected:hover
+{
+ background-color: rgba(61, 173, 232, 0.2);
+ border: 0.1ex rgba(61, 173, 232, 0.2);
+ border-top: 0.1ex solid #76797c;
+}
+
+QTabBar::tab:right:!selected:first:hover
+{
+ background-color: rgba(61, 173, 232, 0.2);
+ border: 0.1ex rgba(61, 173, 232, 0.2);
+}
+
+QTabBar QToolButton::right-arrow:enabled
+{
+ border-image: url(:/breeze_icons/dark/right_arrow.svg);
+}
+
+QTabBar QToolButton::left-arrow:enabled
+{
+ border-image: url(:/breeze_icons/dark/left_arrow.svg);
+}
+
+QTabBar QToolButton::right-arrow:disabled
+{
+ border-image: url(:/breeze_icons/dark/right_arrow_disabled.svg);
+}
+
+QTabBar QToolButton::left-arrow:disabled
+{
+ border-image: url(:/breeze_icons/dark/left_arrow_disabled.svg);
+}
+
+QDockWidget
+{
+ background: #31363b;
+ border: 0.1ex solid #403F3F;
+ titlebar-close-icon: url(:/breeze_icons/dark/transparent.svg);
+ titlebar-normal-icon: url(:/breeze_icons/dark/transparent.svg);
+}
+
+QDockWidget::close-button,
+QDockWidget::float-button
+{
+ border: 0.1ex solid transparent;
+ border-radius: 0.2ex;
+ background: transparent;
+}
+
+QDockWidget::float-button
+{
+ border-image: url(:/breeze_icons/dark/undock.svg);
+}
+
+QDockWidget::float-button:hover
+{
+ border-image: url(:/breeze_icons/dark/undock-hover.svg) ;
+}
+
+QDockWidget::close-button
+{
+ border-image: url(:/breeze_icons/dark/close.svg) ;
+}
+
+QDockWidget::close-button:hover
+{
+ border-image: url(:/breeze_icons/dark/close-hover.svg) ;
+}
+
+QDockWidget::close-button:pressed
+{
+ border-image: url(:/breeze_icons/dark/close-pressed.svg) ;
+}
+
+QTreeView,
+QListView
+{
+ border: 0.1ex solid #76797c;
+ background-color: #232629;
+}
+
+QTreeView::branch:has-siblings:!adjoins-item
+{
+ border-image: url(:/breeze_icons/dark/stylesheet-vline.svg) 0;
+}
+
+QTreeView::branch:has-siblings:adjoins-item
+{
+ border-image: url(:/breeze_icons/dark/stylesheet-branch-more.svg) 0;
+}
+
+QTreeView::branch:!has-children:!has-siblings:adjoins-item
+{
+ border-image: url(:/breeze_icons/dark/stylesheet-branch-end.svg) 0;
+}
+
+QTreeView::branch:has-children:!has-siblings:closed,
+QTreeView::branch:closed:has-children:has-siblings
+{
+ border-image: url(:/breeze_icons/dark/stylesheet-branch-end-closed.svg) 0;
+ image: url(:/breeze_icons/dark/branch_closed.svg);
+}
+
+QTreeView::branch:open:has-children:!has-siblings,
+QTreeView::branch:open:has-children:has-siblings
+{
+ border-image: url(:/breeze_icons/dark/stylesheet-branch-end-open.svg) 0;
+ image: url(:/breeze_icons/dark/branch_open.svg);
+}
+
+/*
+QTreeView::branch:has-siblings:!adjoins-item {
+ background: cyan;
+}
+
+QTreeView::branch:has-siblings:adjoins-item {
+ background: red;
+}
+
+QTreeView::branch:!has-children:!has-siblings:adjoins-item {
+ background: blue;
+}
+
+QTreeView::branch:closed:has-children:has-siblings {
+ background: pink;
+}
+
+QTreeView::branch:has-children:!has-siblings:closed {
+ background: gray;
+}
+
+QTreeView::branch:open:has-children:has-siblings {
+ background: magenta;
+}
+
+QTreeView::branch:open:has-children:!has-siblings {
+ background: green;
+}
+*/
+
+QTableView::item,
+QListView::item,
+QTreeView::item
+{
+ padding: 0.3ex;
+}
+
+QTableView::item:!selected:hover,
+QListView::item:!selected:hover,
+QTreeView::item:!selected:hover
+{
+ background-color: rgba(61, 173, 232, 0.2);
+ outline: 0;
+ color: #eff0f1;
+ padding: 0.3ex;
+}
+
+
+QSlider::groove:horizontal
+{
+ border: 0.1ex solid #31363b;
+ height: 0.4ex;
+ background: #565a5e;
+ margin: 0ex;
+ border-radius: 0.2ex;
+}
+
+QSlider::handle:horizontal
+{
+ background: #232629;
+ border: 0.1ex solid #626568;
+ width: 1.6ex;
+ height: 1.6ex;
+ margin: -0.8ex 0;
+ border-radius: 0.9ex;
+}
+
+QSlider::groove:vertical
+{
+ border: 0.1ex solid #31363b;
+ width: 0.4ex;
+ background: #565a5e;
+ margin: 0ex;
+ border-radius: 0.3ex;
+}
+
+QSlider::handle:vertical
+{
+ background: #232629;
+ border: 0.1ex solid #626568;
+ width: 1.6ex;
+ height: 1.6ex;
+ margin: 0 -0.8ex;
+ border-radius: 0.9ex;
+}
+
+QSlider::handle:horizontal:hover,
+QSlider::handle:horizontal:focus,
+QSlider::handle:vertical:hover,
+QSlider::handle:vertical:focus
+{
+ border: 0.1ex solid #3daee9;
+}
+
+QSlider::sub-page:horizontal,
+QSlider::add-page:vertical
+{
+ background: #3daee9;
+ border-radius: 0.3ex;
+}
+
+QSlider::add-page:horizontal,
+QSlider::sub-page:vertical
+{
+ background: #626568;
+ border-radius: 0.3ex;
+}
+
+QToolButton
+{
+ background-color: transparent;
+ border: 0.1ex solid #76797c;
+ border-radius: 0.2ex;
+ margin: 0.3ex;
+ padding: 0.5ex;
+}
+
+QToolButton[popupMode="1"] /* only for MenuButtonPopup */
+{
+ padding-right: 2ex; /* make way for the popup button */
+}
+
+QToolButton[popupMode="2"] /* only for InstantPopup */
+{
+ padding-right: 1ex; /* make way for the popup button */
+}
+
+QToolButton::menu-indicator
+{
+ border-image: none;
+ image: url(:/breeze_icons/dark/down_arrow.svg);
+ top: -0.7ex;
+ left: -0.2ex;
+}
+
+QToolButton::menu-arrow
+{
+ border-image: none;
+ image: url(:/breeze_icons/dark/down_arrow.svg);
+}
+
+QToolButton:hover,
+QToolButton::menu-button:hover
+{
+ background-color: transparent;
+ border: 0.1ex solid #3daee9;
+}
+
+QToolButton:checked,
+QToolButton:pressed,
+QToolButton::menu-button:pressed
+{
+ background-color: #3daee9;
+ border: 0.1ex solid #3daee9;
+ padding: 0.5ex;
+}
+
+QToolButton::menu-button
+{
+ border: 0.1ex solid #76797c;
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+ /* 1ex width + 0.4ex for border + no text = 2ex allocated above */
+ width: 1ex;
+ padding: 0.5ex;
+ outline: none;
+}
+
+QToolButton::menu-arrow:open
+{
+ border: 0.1ex solid #76797c;
+}
+
+QPushButton::menu-indicator
+{
+ subcontrol-origin: padding;
+ subcontrol-position: bottom right;
+ left: 0.8ex;
+}
+
+QTableView
+{
+ border: 0.1ex solid #76797c;
+ gridline-color: #31363b;
+ background-color: #232629;
+}
+
+
+QTableView,
+QHeaderView
+{
+ border-radius: 0px;
+}
+
+QTableView::item:pressed,
+QListView::item:pressed,
+QTreeView::item:pressed
+{
+ background: #3daee9;
+ color: #eff0f1;
+}
+
+QTableView::item:selected:active,
+QTreeView::item:selected:active,
+QListView::item:selected:active
+{
+ background: #3daee9;
+ color: #eff0f1;
+}
+
+QListView::item:selected:hover,
+QTreeView::item:selected:hover
+{
+ background-color: #47b8f3;
+ color: #eff0f1;
+}
+
+QHeaderView
+{
+ background-color: #31363b;
+ border: 0.1ex transparent;
+ border-radius: 0px;
+ margin: 0px;
+ padding: 0px;
+
+}
+
+QHeaderView::section
+{
+ background-color: #31363b;
+ color: #eff0f1;
+ padding: 0.5ex;
+ border: 0.1ex solid #76797c;
+ border-radius: 0px;
+ text-align: center;
+}
+
+QHeaderView::section::vertical::first,
+QHeaderView::section::vertical::only-one
+{
+ border-top: 0.1ex solid #76797c;
+}
+
+QHeaderView::section::vertical
+{
+ border-top: transparent;
+}
+
+QHeaderView::section::horizontal::first,
+QHeaderView::section::horizontal::only-one
+{
+ border-left: 0.1ex solid #76797c;
+}
+
+QHeaderView::section::horizontal
+{
+ border-left: transparent;
+}
+
+
+QHeaderView::section:checked
+{
+ color: white;
+ background-color: #334e5e;
+}
+
+ /* style the sort indicator */
+QHeaderView::down-arrow
+{
+ image: url(:/breeze_icons/dark/down_arrow.svg);
+}
+
+QHeaderView::up-arrow
+{
+ image: url(:/breeze_icons/dark/up_arrow.svg);
+}
+
+QTableCornerButton::section
+{
+ background-color: #31363b;
+ border: 0.1ex transparent #76797c;
+ border-radius: 0px;
+}
+
+QToolBox
+{
+ padding: 0.5ex;
+ border: 0.1ex transparent black;
+}
+
+QToolBox:selected
+{
+ background-color: #31363b;
+ border-color: #3daee9;
+}
+
+QToolBox:hover
+{
+ border-color: #3daee9;
+}
+
+QStatusBar::item
+{
+ border: 0px transparent dark;
+}
+
+QFrame[height="3"],
+QFrame[width="3"]
+{
+ background-color: #76797c;
+}
+
+QSplitter::handle
+{
+ border: 0.1ex dashed #76797c;
+}
+
+QSplitter::handle:hover
+{
+ background-color: #787876;
+ border: 0.1ex solid #76797c;
+}
+
+QSplitter::handle:horizontal
+{
+ width: 0.1ex;
+}
+
+QSplitter::handle:vertical
+{
+ height: 0.1ex;
+}
+
+QProgressBar:horizontal
+{
+ background-color: #626568;
+ border: 0.1ex solid #31363b;
+ border-radius: 0.3ex;
+ height: 0.5ex;
+ text-align: right;
+ margin-top: 0.5ex;
+ margin-bottom: 0.5ex;
+ margin-right: 5ex;
+ padding: 0px;
+}
+
+QProgressBar::chunk:horizontal
+{
+ background-color: #3daee9;
+ border: 0.1ex transparent;
+ border-radius: 0.3ex;
+}
+
+QSpinBox,
+QDoubleSpinBox
+{
+ padding-right: 1.5ex;
+}
+
+QSpinBox::up-button,
+QDoubleSpinBox::up-button
+{
+ subcontrol-origin: content;
+ subcontrol-position: right top;
+
+ width: 1.6ex;
+ border-width: 0.1ex;
+}
+
+QSpinBox::up-arrow,
+QDoubleSpinBox::up-arrow
+{
+ border-image: url(:/breeze_icons/dark/up_arrow.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QSpinBox::up-arrow:hover,
+QSpinBox::up-arrow:pressed,
+QDoubleSpinBox::up-arrow:hover,
+QDoubleSpinBox::up-arrow:pressed
+{
+ border-image: url(:/breeze_icons/dark/up_arrow-hover.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QSpinBox::up-arrow:disabled,
+QSpinBox::up-arrow:off,
+QDoubleSpinBox::up-arrow:disabled,
+QDoubleSpinBox::up-arrow:off
+{
+ border-image: url(:/breeze_icons/dark/up_arrow_disabled.svg);
+}
+
+QSpinBox::down-button,
+QDoubleSpinBox::down-button
+{
+ subcontrol-origin: content;
+ subcontrol-position: right bottom;
+
+ width: 1.6ex;
+ border-width: 0.1ex;
+}
+
+QSpinBox::down-arrow,
+QDoubleSpinBox::down-arrow
+{
+ border-image: url(:/breeze_icons/dark/down_arrow.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QSpinBox::down-arrow:hover,
+QSpinBox::down-arrow:pressed,
+QDoubleSpinBox::down-arrow:hover,
+QDoubleSpinBox::down-arrow:pressed
+{
+ border-image: url(:/breeze_icons/dark/down_arrow-hover.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QSpinBox::down-arrow:disabled,
+QSpinBox::down-arrow:off,
+QDoubleSpinBox::down-arrow:disabled,
+QDoubleSpinBox::down-arrow:off
+{
+ border-image: url(:/breeze_icons/dark/down_arrow_disabled.svg);
+}
diff --git a/src/QuickCut/Styles/theme_breezeLight.qss b/src/QuickCut/Styles/theme_breezeLight.qss
new file mode 100644
index 0000000..3937deb
--- /dev/null
+++ b/src/QuickCut/Styles/theme_breezeLight.qss
@@ -0,0 +1,1654 @@
+/*
+ * Breeze stylesheet.
+ *
+ * :author: Colin Duquesnoy
+ * :editor: Alex Huszagh
+ * :license: MIT, see LICENSE.md
+ *
+ * This is originally a fork of QDarkStyleSheet, and is based on Breeze/
+ * BreezeDark color scheme, but is in no way affiliated with KDE.
+ *
+ * ---------------------------------------------------------------------
+ * The MIT License (MIT)
+ *
+ * Copyright (c) <2013-2014>
+ * Copyright (c) <2015-2016>
+ *
+ * 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.
+ * ---------------------------------------------------------------------
+ */
+
+QToolTip
+{
+ background-color: black;
+ color: white;
+ padding: 0.5ex;
+}
+
+QWidget
+{
+ color: #31363B;
+ background-color: #EFF0F1;
+ selection-background-color:#33A4DF;
+ selection-color: #31363B;
+ background-clip: border;
+ border-image: none;
+ border: 0px transparent black;
+ outline: 0;
+}
+
+QWidget:item:hover
+{
+ background-color: #33A4DF;
+ color: #31363B;
+}
+
+QWidget:item:selected
+{
+ background-color: #33A4DF;
+}
+
+
+QCheckBox
+{
+ spacing: 0.5ex;
+ outline: none;
+ color: #31363B;
+ margin-bottom: 0.2ex;
+ opacity: 200;
+}
+
+QCheckBox:disabled
+{
+ color: #BAB9B8;
+}
+
+QGroupBox::indicator
+{
+ margin-left: 0.2ex;
+ margin-left: 0.2ex;
+}
+
+QCheckBox::indicator:unchecked,
+QCheckBox::indicator:unchecked:focus
+{
+ border-image: url(:/breeze_icons/light/checkbox_unchecked_disabled.svg);
+}
+
+QCheckBox::indicator:unchecked:hover,
+QCheckBox::indicator:unchecked:pressed,
+QGroupBox::indicator:unchecked:hover,
+QGroupBox::indicator:unchecked:focus,
+QGroupBox::indicator:unchecked:pressed
+{
+ border: none;
+ border-image: url(:/breeze_icons/light/checkbox_unchecked-hover.svg);
+}
+
+QCheckBox::indicator:checked
+{
+ border-image: url(:/breeze_icons/light/checkbox_checked.svg);
+}
+
+QCheckBox::indicator:checked:focus,
+QCheckBox::indicator:checked:pressed,
+QGroupBox::indicator:checked:focus,
+QGroupBox::indicator:checked:pressed
+{
+ border: none;
+ border-image: url(:/breeze_icons/light/checkbox_checked.svg);
+}
+
+QCheckBox::indicator:checked:hover,
+QGroupBox::indicator:checked:hover
+{
+ border-image: url(:/breeze_icons/light/checkbox_checked-hover.svg);
+}
+
+QCheckBox::indicator:indeterminate
+{
+ border-image: url(:/breeze_icons/light/checkbox_indeterminate.svg);
+}
+
+QCheckBox::indicator:indeterminate:hover
+{
+ border-image: url(:/breeze_icons/light/checkbox_indeterminate-hover.svg);
+}
+
+QCheckBox::indicator:indeterminate:focus,
+QCheckBox::indicator:indeterminate:pressed
+{
+}
+
+QCheckBox::indicator:indeterminate:disabled
+{
+ border-image: url(:/breeze_icons/light/checkbox_indeterminate_disabled.svg);
+}
+
+QCheckBox::indicator:checked:disabled,
+QGroupBox::indicator:checked:disabled
+{
+ border-image: url(:/breeze_icons/light/checkbox_checked_disabled.svg);
+}
+
+QCheckBox::indicator:unchecked:disabled,
+QGroupBox::indicator:unchecked:disabled
+{
+ border-image: url(:/breeze_icons/light/checkbox_unchecked_disabled.svg);
+}
+
+QRadioButton
+{
+ spacing: 0.5ex;
+ outline: none;
+ color: #31363B;
+ margin-bottom: 0.2ex;
+}
+
+QRadioButton:disabled
+{
+ color: #BAB9B8;
+}
+
+QRadioButton::indicator:unchecked,
+QRadioButton::indicator:unchecked:focus
+{
+ border-image: url(:/breeze_icons/light/radio_unchecked_disabled.svg);
+}
+
+QRadioButton::indicator:unchecked:hover,
+QRadioButton::indicator:unchecked:pressed
+{
+ border: none;
+ outline: none;
+ border-image: url(:/breeze_icons/light/radio_unchecked-hover.svg);
+}
+
+QRadioButton::indicator:checked
+{
+ border: none;
+ outline: none;
+ border-image: url(:/breeze_icons/light/radio_checked.svg);
+}
+
+QRadioButton::indicator:checked:focus,
+QRadioButton::indicator:checked:pressed
+{
+ border: none;
+ outline: none;
+ border-image: url(:/breeze_icons/light/radio_checked.svg);
+}
+
+QRadioButton::indicator:checked:hover
+{
+ border-image: url(:/breeze_icons/light/radio_checked-hover.svg);
+}
+
+QRadioButton::indicator:checked:disabled
+{
+ outline: none;
+ border-image: url(:/breeze_icons/light/radio_checked_disabled.svg);
+}
+
+QRadioButton::indicator:unchecked:disabled
+{
+ border-image: url(:/breeze_icons/light/radio_unchecked_disabled.svg);
+}
+
+QMenuBar
+{
+ background-color: #EFF0F1;
+ color: #31363B;
+}
+
+QMenuBar::item
+{
+ background: transparent;
+}
+
+QMenuBar::item:selected
+{
+ background: transparent;
+ border: 0.1ex solid #BAB9B8;
+}
+
+QMenuBar::item:pressed
+{
+ border: 0.1ex solid #BAB9B8;
+ background-color: #33A4DF;
+ color: #31363B;
+ margin-bottom: -0.1ex;
+ padding-bottom: 0.1ex;
+}
+
+QMenu
+{
+ border: 0.1ex solid #BAB9B8;
+ color: #31363B;
+ margin: 0.2ex;
+}
+
+QMenu::icon
+{
+ margin: 0.5ex;
+}
+
+QMenu::item
+{
+ padding: 0.5ex 3ex 0.5ex 3ex;
+ margin-left: 0.5ex;
+ border: 0.1ex solid transparent; /* reserve space for selection border */
+}
+
+QMenu::item:selected
+{
+ color: #31363B;
+}
+
+QMenu::separator
+{
+ height: 0.2ex;
+ background: lightblue;
+ margin-left: 1ex;
+ margin-right: 0.5ex;
+}
+
+/* non-exclusive indicator = check box style indicator
+ (see QActionGroup::setExclusive) */
+QMenu::indicator:non-exclusive:unchecked
+{
+ border-image: url(:/breeze_icons/light/checkbox_unchecked_disabled.svg);
+}
+
+QMenu::indicator:non-exclusive:unchecked:selected
+{
+ border-image: url(:/breeze_icons/light/checkbox_unchecked_disabled.svg);
+}
+
+QMenu::indicator:non-exclusive:checked
+{
+ border-image: url(:/breeze_icons/light/checkbox_checked.svg);
+}
+
+QMenu::indicator:non-exclusive:checked:selected
+{
+ border-image: url(:/breeze_icons/light/checkbox_checked.svg);
+}
+
+/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */
+QMenu::indicator:exclusive:unchecked
+{
+ border-image: url(:/breeze_icons/light/radio_unchecked_disabled.svg);
+}
+
+QMenu::indicator:exclusive:unchecked:selected
+{
+ border-image: url(:/breeze_icons/light/radio_unchecked_disabled.svg);
+}
+
+QMenu::indicator:exclusive:checked
+{
+ border-image: url(:/breeze_icons/light/radio_checked.svg);
+}
+
+QMenu::indicator:exclusive:checked:selected
+{
+ border-image: url(:/breeze_icons/light/radio_checked.svg);
+}
+
+QMenu::right-arrow
+{
+ margin: 0.5ex;
+ border-image: url(:/breeze_icons/light/right_arrow.svg);
+ width: 0.6ex;
+ height: 0.9ex;
+}
+
+
+QWidget:disabled
+{
+ color: #454545;
+ background-color: #EFF0F1;
+}
+
+QAbstractItemView
+{
+ alternate-background-color: #EFF0F1;
+ color: #31363B;
+ border: 0.1ex solid 3A3939;
+ border-radius: 0.2ex;
+}
+
+QWidget:focus,
+QMenuBar:focus
+{
+ border: 0.1ex solid #33A4DF;
+}
+
+QTabWidget:focus,
+QCheckBox:focus,
+QRadioButton:focus,
+QSlider:focus
+{
+ border: none;
+}
+
+QLineEdit
+{
+ background-color: #FCFCFC;
+ padding: 0.5ex;
+ border-style: solid;
+ border: 0.1ex solid #BAB9B8;
+ border-radius: 0.2ex;
+ color: #31363B;
+}
+
+QGroupBox
+{
+ border: 0.1ex solid #BAB9B8;
+ border-radius: 0.2ex;
+ padding-top: 1ex;
+ margin-top: 1ex;
+}
+
+QGroupBox::title
+{
+ subcontrol-origin: margin;
+ subcontrol-position: top center;
+ padding-left: 0.1ex;
+ padding-right: 0.1ex;
+ margin-top: -0.7ex;
+}
+
+QAbstractScrollArea
+{
+ border-radius: 0.2ex;
+ border: 0.1ex solid #BAB9B8;
+ background-color: transparent;
+}
+
+QScrollBar:horizontal
+{
+ height: 1.5ex;
+ margin: 0.3ex 1.5ex 0.3ex 1.5ex;
+ border: 0.1ex transparent #2A2929;
+ border-radius: 0.4ex;
+ background-color: #2A2929;
+}
+
+QScrollBar::handle:horizontal
+{
+ background-color: #605F5F;
+ min-width: 0.5ex;
+ border-radius: 0.4ex;
+}
+
+QScrollBar::add-line:horizontal
+{
+ margin: 0ex 0.3ex 0ex 0.3ex;
+ border-image: url(:/breeze_icons/light/right_arrow_disabled.svg);
+ width: 1ex;
+ height: 1ex;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:horizontal
+{
+ margin: 0px 0.3ex 0px 0.3ex;
+ border-image: url(:/breeze_icons/light/left_arrow_disabled.svg);
+ height: 1ex;
+ width: 1ex;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::add-line:horizontal:hover,QScrollBar::add-line:horizontal:on
+{
+ border-image: url(:/breeze_icons/light/right_arrow.svg);
+ width: 1ex;
+ height: 1ex;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+
+
+QScrollBar::sub-line:horizontal:hover, QScrollBar::sub-line:horizontal:on
+{
+ border-image: url(:/breeze_icons/light/left_arrow.svg);
+ width: 1ex;
+ height: 1ex;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::up-arrow:horizontal, QScrollBar::down-arrow:horizontal
+{
+ background: none;
+}
+
+
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal
+{
+ background: none;
+}
+
+QScrollBar:vertical
+{
+ background-color: #2A2929;
+ width: 1.5ex;
+ margin: 1.5ex 0.3ex 1.5ex 0.3ex;
+ border: 0.1ex transparent #2A2929;
+ border-radius: 0.4ex;
+}
+
+QScrollBar::handle:vertical
+{
+ background-color: #605F5F;
+ min-height: 0.5ex;
+ border-radius: 0.4ex;
+}
+
+QScrollBar::sub-line:vertical
+{
+ margin: 0.3ex 0ex 0.3ex 0ex;
+ border-image: url(:/breeze_icons/light/up_arrow_disabled.svg);
+ height: 1ex;
+ width: 1ex;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::add-line:vertical
+{
+ margin: 0.3ex 0ex 0.3ex 0ex;
+ border-image: url(:/breeze_icons/light/down_arrow_disabled.svg);
+ height: 1ex;
+ width: 1ex;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:vertical:hover,
+QScrollBar::sub-line:vertical:on
+{
+
+ border-image: url(:/breeze_icons/light/up_arrow.svg);
+ height: 1ex;
+ width: 1ex;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+
+
+QScrollBar::add-line:vertical:hover,
+QScrollBar::add-line:vertical:on
+{
+ border-image: url(:/breeze_icons/light/down_arrow.svg);
+ height: 1ex;
+ width: 1ex;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::up-arrow:vertical,
+QScrollBar::down-arrow:vertical
+{
+ background: none;
+}
+
+
+QScrollBar::add-page:vertical,
+QScrollBar::sub-page:vertical
+{
+ background: none;
+}
+
+QTextEdit
+{
+ background-color: #EFF0F1;
+ color: #31363B;
+ border: 0.1ex solid #BAB9B8;
+}
+
+QPlainTextEdit
+{
+ background-color: #EFF0F1;
+ color: #31363B;
+ border-radius: 0.2ex;
+ border: 0.1ex solid #BAB9B8;
+}
+
+QHeaderView::section
+{
+ background-color: #BAB9B8;
+ color: #31363B;
+ padding: 0.5ex;
+ border: 0.1ex solid #BAB9B8;
+}
+
+QSizeGrip
+{
+ border-image: url(:/breeze_icons/light/sizegrip.svg);
+ width: 1.2ex;
+ height: 1.2ex;
+}
+
+QMainWindow::separator
+{
+ background-color: #EFF0F1;
+ color: white;
+ padding-left: 0.4ex;
+ spacing: 0.2ex;
+ border: 0.1ex dashed #BAB9B8;
+}
+
+QMainWindow::separator:hover
+{
+
+ background-color: #787876;
+ color: white;
+ padding-left: 0.4ex;
+ border: 0.1ex solid #BAB9B8;
+ spacing: 0.2x;
+}
+
+QMenu::separator
+{
+ height: 0.1ex;
+ background-color: #BAB9B8;
+ color: white;
+ padding-left: 0.4ex;
+ margin-left: 1ex;
+ margin-right: 0.5ex;
+}
+
+QFrame[frameShape="2"], /* QFrame::Panel == 0x0003 */
+QFrame[frameShape="3"], /* QFrame::WinPanel == 0x0003 */
+QFrame[frameShape="4"], /* QFrame::HLine == 0x0004 */
+QFrame[frameShape="5"], /* QFrame::VLine == 0x0005 */
+QFrame[frameShape="6"] /* QFrame::StyledPanel == 0x0006 */
+{
+ border-width: 0.1ex;
+ padding: 0.1ex;
+ border-style: solid;
+ border-color: #EFF0F1;
+ background-color: #bcbfc2;
+ border-radius: 0.5ex;
+}
+
+QStackedWidget
+{
+ border: 0.1ex transparent black;
+}
+
+QToolBar
+{
+ border: 0.1ex transparent #393838;
+ background: 0.1ex solid #EFF0F1;
+ font-weight: bold;
+}
+
+QToolBar::handle:horizontal
+{
+ border-image: url(:/breeze_icons/light/hmovetoolbar.svg);
+ width = 1.6ex;
+ height = 6.4ex;
+}
+
+QToolBar::handle:vertical
+{
+ border-image: url(:/breeze_icons/light/vmovetoolbar.svg);
+ width = 5.4ex;
+ height = 1ex;
+}
+
+QToolBar::separator:horizontal
+{
+ border-image: url(:/breeze_icons/light/hsepartoolbar.svg);
+ width = 0.7ex;
+ height = 6.3ex;
+}
+
+QToolBar::separator:vertical
+{
+ border-image: url(:/breeze_icons/light/vsepartoolbars.svg);
+ width = 6.3ex;
+ height = 0.7ex;
+}
+
+QPushButton
+{
+ color: #31363B;
+ background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #EFF0F1, stop: 0.5 #eaebec);
+ border-width: 0.1ex;
+ border-color: #BAB9B8;
+ border-style: solid;
+ padding: 0.5ex;
+ border-radius: 0.2ex;
+ outline: none;
+}
+
+QPushButton:disabled
+{
+ background-color: #e0e1e2;
+ border-width: 0.1ex;
+ border-color: #b4b4b4;
+ border-style: solid;
+ padding-top: 0.5ex;
+ padding-bottom: 0.5ex;
+ padding-left: 1ex;
+ padding-right: 1ex;
+ border-radius: 0.2ex;
+ color: #b4b4b4;
+}
+
+QPushButton:focus
+{
+ color: black;
+}
+
+QComboBox
+{
+ selection-background-color: #33A4DF;
+ border-style: solid;
+ border: 0.1ex solid #BAB9B8;
+ border-radius: 0.2ex;
+ padding: 0.5ex;
+ min-width: 7.5ex;
+}
+
+QPushButton:checked
+{
+ background-color: #BAB9B8;
+ border-color: #6A6969;
+}
+
+QComboBox:hover,
+QAbstractSpinBox:hover,
+QLineEdit:hover,
+QTextEdit:hover,
+QPlainTextEdit:hover,
+QAbstractView:hover,
+QTreeView:hover
+{
+ border: 0.1ex solid #33A4DF;
+ color: #31363B;
+}
+
+QComboBox:hover:pressed,
+QPushButton:hover:pressed,
+QAbstractSpinBox:hover:pressed,
+QLineEdit:hover:pressed,
+QTextEdit:hover:pressed,
+QPlainTextEdit:hover:pressed,
+QAbstractView:hover:pressed,
+QTreeView:hover:pressed
+{
+ background-color: #EFF0F1;
+}
+
+QComboBox:on
+{
+ padding-top: 0.3ex;
+ padding-left: 0.4ex;
+ selection-background-color: #4a4a4a;
+}
+
+QComboBox QAbstractItemView
+{
+ background-color: #FCFCFC;
+ border-radius: 0.2ex;
+ border: 0.1ex solid #BAB9B8;
+ selection-background-color: #33A4DF;
+}
+
+QComboBox::drop-down
+{
+ subcontrol-origin: padding;
+ subcontrol-position: top right;
+ width: 1.5ex;
+
+ border-left-width: 0ex;
+ border-left-color: darkgray;
+ border-left-style: solid;
+ border-top-right-radius: 0.3ex;
+ border-bottom-right-radius: 0.3ex;
+}
+
+QComboBox::down-arrow
+{
+ border-image: url(:/breeze_icons/light/down_arrow_disabled.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QComboBox::down-arrow:on,
+QComboBox::down-arrow:hover,
+QComboBox::down-arrow:focus
+{
+ border-image: url(:/breeze_icons/light/down_arrow.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QAbstractSpinBox
+{
+ padding: 0.5ex;
+ border: 0.1ex solid #BAB9B8;
+ background-color: #D9D8D7;
+ color: #31363B;
+ border-radius: 0.2ex;
+ min-width: 7.5ex;
+}
+
+QAbstractSpinBox:up-button
+{
+ background-color: transparent;
+ subcontrol-origin: border;
+ subcontrol-position: center right;
+}
+
+QAbstractSpinBox:down-button
+{
+ background-color: transparent;
+ subcontrol-origin: border;
+ subcontrol-position: center left;
+}
+
+QAbstractSpinBox::up-arrow,
+QAbstractSpinBox::up-arrow:disabled,
+QAbstractSpinBox::up-arrow:off
+{
+ border-image: url(:/breeze_icons/light/up_arrow_disabled.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QAbstractSpinBox::up-arrow:hover
+{
+ border-image: url(:/breeze_icons/light/up_arrow.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QAbstractSpinBox::down-arrow,
+QAbstractSpinBox::down-arrow:disabled,
+QAbstractSpinBox::down-arrow:off
+{
+ border-image: url(:/breeze_icons/light/down_arrow_disabled.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QAbstractSpinBox::down-arrow:hover
+{
+ border-image: url(:/breeze_icons/light/down_arrow.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QLabel
+{
+ border: 0ex solid black;
+}
+
+QTabWidget{
+ border: 0.1ex solid #BAB9B8;
+}
+
+/* BORDERS */
+QTabWidget::pane
+{
+ padding: 0.5ex;
+ margin: 0.1ex;
+}
+
+QTabWidget::pane:top
+{
+ border: 0.1ex solid #BAB9B8;
+ top: -0.1ex;
+}
+
+QTabWidget::pane:bottom
+{
+ border: 0.1ex solid #BAB9B8;
+ bottom: -0.1ex;
+}
+
+QTabWidget::pane:left
+{
+ border: 0.1ex solid #BAB9B8;
+ right: -0.1ex;
+}
+
+QTabWidget::pane:right
+{
+ border: 0.1ex solid #BAB9B8;
+ left: -0.1ex;
+}
+
+QTabBar
+{
+ qproperty-drawBase: 0;
+ left: 0.5ex; /* move to the right by 0.5ex */
+ border-radius: 0.3ex;
+}
+
+QTabBar:focus
+{
+ border: 0ex transparent black;
+}
+
+QTabBar::close-button
+{
+ border-image: url(:/breeze_icons/light/close.svg);
+ width: 1.2ex;
+ height: 1.2ex;
+ background: transparent;
+}
+
+QTabBar::close-button:hover
+{
+ border-image: url(:/breeze_icons/light/close-hover.svg);
+ width: 1.2ex;
+ height: 1.2ex;
+ background: transparent;
+}
+
+QTabBar::close-button:pressed
+{
+ border-image: url(:/breeze_icons/light/close-pressed.svg);
+ width: 1.2ex;
+ height: 1.2ex;
+ background: transparent;
+}
+
+/* TOP TABS */
+QTabBar::tab:top
+{
+ color: #31363B;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #BAB9B8;
+ border-top: 0.1ex solid #BAB9B8;
+ background-color: #EFF0F1;
+ padding: 0.5ex;
+ min-width: 5ex;
+ border-top-left-radius: 0.2ex;
+ border-top-right-radius: 0.2ex;
+}
+
+QTabBar::tab:top:last,
+QTabBar::tab:top:only-one
+{
+ color: #31363B;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #BAB9B8;
+ border-right: 0.1ex solid #BAB9B8;
+ border-top: 0.1ex solid #BAB9B8;
+ background-color: #EFF0F1;
+ padding: 0.5ex;
+ min-width: 5ex;
+ border-top-left-radius: 0.2ex;
+ border-top-right-radius: 0.2ex;
+}
+
+QTabBar::tab:top:!selected
+{
+ color: #31363B;
+ background-color: #D9D8D7;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #BAB9B8;
+ border-top-left-radius: 0.2ex;
+ border-top-right-radius: 0.2ex;
+}
+
+QTabBar::tab:top:first:!selected
+{
+ color: #31363B;
+ background-color: #D9D8D7;
+ border: 0.1ex transparent black;
+ border-top-left-radius: 0.2ex;
+ border-top-right-radius: 0.2ex;
+}
+
+QTabBar::tab:top:!selected:hover
+{
+ background-color: rgba(61, 173, 232, 0.1);
+ border: 0.1ex rgba(61, 173, 232, 0.1);
+ border-left: 0.1ex solid #BAB9B8;
+}
+
+QTabBar::tab:top:!selected:first:hover
+{
+ background-color: rgba(61, 173, 232, 0.1);
+ border: 0.1ex rgba(61, 173, 232, 0.1);
+}
+
+/* BOTTOM TABS */
+QTabBar::tab:bottom
+{
+ color: #31363B;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #BAB9B8;
+ border-bottom: 0.1ex solid #BAB9B8;
+ background-color: #EFF0F1;
+ padding: 0.5ex;
+ border-bottom-left-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+ min-width: 5ex;
+}
+
+QTabBar::tab:bottom:last,
+QTabBar::tab:bottom:only-one
+{
+ color: #31363B;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #BAB9B8;
+ border-right: 0.1ex solid #BAB9B8;
+ border-bottom: 0.1ex solid #BAB9B8;
+ background-color: #EFF0F1;
+ padding: 0.5ex;
+ border-bottom-left-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+ min-width: 5ex;
+}
+
+QTabBar::tab:bottom:!selected
+{
+ color: #31363B;
+ background-color: #D9D8D7;
+ border: 0.1ex transparent black;
+ border-left: 0.1ex solid #BAB9B8;
+ border-bottom-left-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+}
+
+QTabBar::tab:bottom:first:!selected
+{
+ color: #31363B;
+ background-color: #D9D8D7;
+ border: 0.1ex transparent black;
+ border-bottom-left-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+}
+
+QTabBar::tab:bottom:!selected:hover
+{
+ background-color: rgba(61, 173, 232, 0.1);
+ border: 0.1ex rgba(61, 173, 232, 0.1);
+ border-left: 0.1ex solid #BAB9B8;
+}
+
+QTabBar::tab:bottom:!selected:first:hover
+{
+ background-color: rgba(61, 173, 232, 0.1);
+ border: 0.1ex rgba(61, 173, 232, 0.1);
+}
+
+/* LEFT TABS */
+QTabBar::tab:left
+{
+ color: #31363B;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #BAB9B8;
+ border-right: 0.1ex solid #BAB9B8;
+ background-color: #EFF0F1;
+ padding: 0.5ex;
+ border-top-right-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+ min-height: 5ex;
+}
+
+QTabBar::tab:left:last,
+QTabBar::tab:left:only-one
+{
+ color: #31363B;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #BAB9B8;
+ border-bottom: 0.1ex solid #BAB9B8;
+ border-right: 0.1ex solid #BAB9B8;
+ background-color: #EFF0F1;
+ padding: 0.5ex;
+ border-top-right-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+ min-height: 5ex;
+}
+
+QTabBar::tab:left:!selected
+{
+ color: #31363B;
+ background-color: #D9D8D7;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #BAB9B8;
+ border-top-right-radius: 0.2ex;
+ border-bottom-right-radius: 0.2ex;
+}
+
+QTabBar::tab:left:!selected:hover
+{
+ background-color: rgba(61, 173, 232, 0.1);
+ border: 0.1ex rgba(61, 173, 232, 0.1);
+ border-top: 0.1ex solid #BAB9B8;
+}
+
+QTabBar::tab:left:!selected:first:hover
+{
+ background-color: rgba(61, 173, 232, 0.1);
+ border: 0.1ex rgba(61, 173, 232, 0.1);
+}
+
+/* RIGHT TABS */
+QTabBar::tab:right
+{
+ color: #31363B;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #BAB9B8;
+ border-left: 0.1ex solid #BAB9B8;
+ background-color: #D9D8D7;
+ padding: 0.5ex;
+ border-top-left-radius: 0.2ex;
+ border-bottom-left-radius: 0.2ex;
+ min-height: 5ex;
+}
+
+QTabBar::tab:right:last,
+QTabBar::tab:right:only-one
+{
+ color: #31363B;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #BAB9B8;
+ border-bottom: 0.1ex solid #BAB9B8;
+ border-left: 0.1ex solid #BAB9B8;
+ background-color: #D9D8D7;
+ padding: 0.5ex;
+ border-top-left-radius: 0.2ex;
+ border-bottom-left-radius: 0.2ex;
+ min-height: 5ex;
+}
+
+QTabBar::tab:right:!selected
+{
+ color: #31363B;
+ background-color: #54575B;
+ border: 0.1ex transparent black;
+ border-top: 0.1ex solid #BAB9B8;
+ border-top-left-radius: 0.2ex;
+ border-bottom-left-radius: 0.2ex;
+}
+
+QTabBar::tab:right:!selected:hover
+{
+ background-color: rgba(61, 173, 232, 0.1);
+ border: 0.1ex rgba(61, 173, 232, 0.1);
+ border-top: 0.1ex solid #BAB9B8;
+}
+
+QTabBar::tab:right:!selected:first:hover
+{
+ background-color: rgba(61, 173, 232, 0.1);
+ border: 0.1ex rgba(61, 173, 232, 0.1);
+}
+
+QTabBar QToolButton::right-arrow:enabled
+{
+ border-image: url(:/breeze_icons/light/right_arrow.svg);
+}
+
+QTabBar QToolButton::left-arrow:enabled
+{
+ border-image: url(:/breeze_icons/light/left_arrow.svg);
+}
+
+QTabBar QToolButton::right-arrow:disabled
+{
+ border-image: url(:/breeze_icons/light/right_arrow_disabled.svg);
+}
+
+QTabBar QToolButton::left-arrow:disabled
+{
+ border-image: url(:/breeze_icons/light/left_arrow_disabled.svg);
+}
+
+QDockWidget
+{
+ background: #EFF0F1;
+ border: 0.1ex solid #403F3F;
+ titlebar-close-icon: url(:/breeze_icons/light/transparent.svg);
+ titlebar-normal-icon: url(:/breeze_icons/light/transparent.svg);
+}
+
+QDockWidget::close-button,
+QDockWidget::float-button
+{
+ border: 0.1ex solid transparent;
+ border-radius: 0.2ex;
+ background: transparent;
+}
+
+
+QDockWidget::float-button
+{
+ border-image: url(:/breeze_icons/dark/undock.svg);
+}
+
+QDockWidget::float-button:hover
+{
+ border-image: url(:/breeze_icons/dark/undock-hover.svg) ;
+}
+
+QDockWidget::close-button
+{
+ border-image: url(:/breeze_icons/dark/close.svg) ;
+}
+
+QDockWidget::close-button:hover
+{
+ border-image: url(:/breeze_icons/dark/close-hover.svg) ;
+}
+
+QDockWidget::close-button:pressed
+{
+ border-image: url(:/breeze_icons/dark/close-pressed.svg) ;
+}
+
+QTreeView,
+QListView
+{
+ border: 0.1ex solid #BAB9B8;
+ background-color: #FCFCFC;
+}
+
+
+QTreeView::branch:has-siblings:!adjoins-item
+{
+ border-image: url(:/breeze_icons/light/stylesheet-vline.svg) 0;
+}
+
+QTreeView::branch:has-siblings:adjoins-item
+{
+ border-image: url(:/breeze_icons/light/stylesheet-branch-more.svg) 0;
+}
+
+QTreeView::branch:!has-children:!has-siblings:adjoins-item
+{
+ border-image: url(:/breeze_icons/light/stylesheet-branch-end.svg) 0;
+}
+
+QTreeView::branch:has-children:!has-siblings:closed,
+QTreeView::branch:closed:has-children:has-siblings
+{
+ border-image: url(:/breeze_icons/light/stylesheet-branch-end-closed.svg) 0;
+ image: url(:/breeze_icons/light/branch_closed.svg);
+}
+
+QTreeView::branch:open:has-children:!has-siblings,
+QTreeView::branch:open:has-children:has-siblings
+{
+ border-image: url(:/breeze_icons/light/stylesheet-branch-end-open.svg) 0;
+ image: url(:/breeze_icons/light/branch_open.svg);
+}
+
+QTableView::item,
+QListView::item,
+QTreeView::item
+{
+ padding: 0.3ex;
+}
+
+QTableView::item:!selected:hover,
+QListView::item:!selected:hover,
+QTreeView::item:!selected:hover
+{
+ background-color: rgba(61, 173, 232, 0.1);
+ outline: 0;
+ color: #31363B;
+ padding: 0.3ex;
+}
+
+QSlider::groove:horizontal
+{
+ border: 0.1ex solid #EFF0F1;
+ height: 0.4ex;
+ background: #9CA0A4;
+ margin: 0px;
+ border-radius: 0.2ex;
+}
+
+QSlider::handle:horizontal
+{
+ background: #D9D8D7;
+ border: 0.1ex solid #BABEC2;
+ width: 1.6ex;
+ height: 1.6ex;
+ margin: -0.8ex 0;
+ border-radius: 0.9ex;
+}
+
+QSlider::groove:vertical
+{
+ border: 0.1ex solid #EFF0F1;
+ width: 0.4ex;
+ background: #9CA0A4;
+ margin: 0ex;
+ border-radius: 0.3ex;
+}
+
+QSlider::handle:vertical
+{
+ background: #D9D8D7;
+ border: 0.1ex solid #BABEC2;
+ width: 1.6ex;
+ height: 1.6ex;
+ margin: 0 -0.8ex;
+ border-radius: 0.9ex;
+}
+
+QSlider::handle:horizontal:focus,
+QSlider::handle:vertical:focus
+{
+ border: 0.1ex solid #33A4DF;
+}
+
+QSlider::handle:horizontal:hover,
+QSlider::handle:vertical:hover
+{
+ border: 0.1ex solid #51c2fc;
+}
+
+QSlider::sub-page:horizontal,
+QSlider::add-page:vertical
+{
+ background: #33A4DF;
+ border-radius: 0.3ex;
+}
+
+QSlider::add-page:horizontal,
+QSlider::sub-page:vertical
+{
+ background: #BABEC2;
+ border-radius: 0.3ex;
+}
+
+QToolButton
+{
+ background-color: transparent;
+ border: 0.1ex solid #BAB9B8;
+ border-radius: 0.2ex;
+ margin: 0.3ex;
+ padding: 0.5ex;
+}
+
+QToolButton[popupMode="1"] /* only for MenuButtonPopup */
+{
+ padding-right: 2ex; /* make way for the popup button */
+}
+
+QToolButton[popupMode="2"] /* only for InstantPopup */
+{
+ padding-right: 1ex; /* make way for the popup button */
+}
+
+QToolButton::menu-indicator
+{
+ border-image: url(:/breeze_icons/light/down_arrow.svg);
+ top: -0.7ex; left: -0.2ex; /* shift it a bit */
+ width = 0.9ex;
+ height = 0.6ex;
+}
+
+QToolButton::menu-arrow
+{
+ border-image: url(:/breeze_icons/light/down_arrow.svg);
+ width = 0.9ex;
+ height = 0.6ex;
+}
+
+QToolButton:hover,
+QToolButton::menu-button:hover
+{
+ background-color: transparent;
+ border: 0.1ex solid #33A4DF;
+}
+
+QToolButton:checked,
+QToolButton:pressed,
+QToolButton::menu-button:pressed
+{
+ background-color: #47b8fc;
+ border: 0.1ex solid #47b8fc;
+ padding: 0.5ex;
+}
+
+QToolButton::menu-button
+{
+ border: 0.1ex solid #BAB9B8;
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+ /* 1ex width + 0.4ex for border + no text = 2ex allocated above */
+ width: 1ex;
+ padding: 0.5ex;
+ outline: none;
+}
+
+QToolButton::menu-arrow:open
+{
+ border: 0.1ex solid #BAB9B8;
+}
+
+QPushButton::menu-indicator
+{
+ subcontrol-origin: padding;
+ subcontrol-position: bottom right;
+ left: 0.8ex;
+}
+
+QTableView
+{
+ border: 0.1ex solid #BAB9B8;
+ gridline-color: #BAB9B8;
+ background-color: #FCFCFC;
+}
+
+
+QTableView,
+QHeaderView
+{
+ border-radius: 0px;
+}
+
+QTableView::item:pressed
+{
+ background: #33A4DF;
+ color: #31363B;
+}
+
+QTableView::item:selected:active
+{
+ background: #33A4DF;
+ color: #31363B;
+}
+
+QTableView::item:selected:hover
+{
+ background-color: #47b8f3;
+ color: #31363B;
+}
+
+QListView::item:pressed,
+QTreeView::item:pressed
+{
+ background: #3daee9;
+ color: #31363B;
+}
+
+QTreeView::item:selected:active,
+QListView::item:selected:active
+{
+ background: #3daee9;
+ color: #31363B;
+}
+
+QListView::item:selected:hover,
+QTreeView::item:selected:hover
+{
+ background-color: #51c2fc;
+ color: #31363B;
+}
+
+
+QHeaderView
+{
+ background-color: #EFF0F1;
+ border: 0.1ex transparent;
+ border-radius: 0px;
+ margin: 0px;
+ padding: 0px;
+
+}
+
+QHeaderView::section
+{
+ background-color: #EFF0F1;
+ color: #31363B;
+ padding: 0.5ex;
+ border: 0.1ex solid #BAB9B8;
+ border-radius: 0px;
+ text-align: center;
+}
+
+QHeaderView::section::vertical::first,
+QHeaderView::section::vertical::only-one
+{
+ border-top: 0.1ex solid #BAB9B8;
+}
+
+QHeaderView::section::vertical
+{
+ border-top: transparent;
+}
+
+QHeaderView::section::horizontal::first, QHeaderView::section::horizontal::only-one
+{
+ border-left: 0.1ex solid #BAB9B8;
+}
+
+QHeaderView::section::horizontal
+{
+ border-left: transparent;
+}
+
+
+QHeaderView::section:checked
+
+ {
+ color: black;
+ background-color: #b9dae7;
+ }
+
+ /* style the sort indicator */
+QHeaderView::down-arrow
+{
+ image: url(:/breeze_icons/light/down_arrow.svg);
+}
+
+QHeaderView::up-arrow
+{
+ image: url(:/breeze_icons/light/up_arrow.svg);
+}
+
+QTableCornerButton::section
+{
+ background-color: #EFF0F1;
+ border: 0.1ex transparent #BAB9B8;
+ border-radius: 0px;
+}
+
+QToolBox
+{
+ padding: 0.5ex;
+ border: 0.1ex transparent black;
+}
+
+QToolBox:selected
+{
+ background-color: #EFF0F1;
+ border-color: #33A4DF;
+}
+
+QToolBox:hover
+{
+ border-color: #33A4DF;
+}
+
+QStatusBar::item
+{
+ border: 0px transparent dark;
+}
+
+QSplitter::handle
+{
+ border: 0.1ex dashed #BAB9B8;
+}
+
+QSplitter::handle:hover
+{
+ background-color: #787876;
+ border: 0.1ex solid #BAB9B8;
+}
+
+QSplitter::handle:horizontal
+{
+ width: 0.1ex;
+}
+
+QSplitter::handle:vertical
+{
+ height: 0.1ex;
+}
+
+QProgressBar:horizontal
+{
+ background-color: #BABEC2;
+ border: 0.1ex solid #EFF0F1;
+ border-radius: 0.3ex;
+ height: 0.5ex;
+ text-align: right;
+ margin-top: 0.5ex;
+ margin-bottom: 0.5ex;
+ margin-right: 5ex;
+ padding: 0px;
+}
+
+QProgressBar::chunk:horizontal
+{
+ background-color: #33A4DF;
+ border: 0.1ex transparent;
+ border-radius: 0.3ex;
+}
+
+QAbstractSpinBox
+{
+ background-color: #EFF0F1;
+}
+
+QSpinBox,
+QDoubleSpinBox
+{
+ padding-right: 1.5ex;
+}
+
+QSpinBox::up-button,
+QDoubleSpinBox::up-button
+{
+ subcontrol-origin: content;
+ subcontrol-position: right top;
+
+ width: 1.6ex;
+ border-width: 0.1ex;
+}
+
+QSpinBox::up-arrow,
+QDoubleSpinBox::up-arrow
+{
+ border-image: url(:/breeze_icons/light/up_arrow.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QSpinBox::up-arrow:hover,
+QSpinBox::up-arrow:pressed,
+QDoubleSpinBox::up-arrow:hover,
+QDoubleSpinBox::up-arrow:pressed
+{
+ border-image: url(:/breeze_icons/light/up_arrow-hover.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QSpinBox::up-arrow:disabled,
+QSpinBox::up-arrow:off,
+QDoubleSpinBox::up-arrow:disabled,
+QDoubleSpinBox::up-arrow:off
+{
+ border-image: url(:/breeze_icons/light/up_arrow_disabled.svg);
+}
+
+QSpinBox::down-button,
+QDoubleSpinBox::down-button
+{
+ subcontrol-origin: content;
+ subcontrol-position: right bottom;
+
+ width: 1.6ex;
+ border-width: 0.1ex;
+}
+
+QSpinBox::down-arrow,
+QDoubleSpinBox::down-arrow
+{
+ border-image: url(:/breeze_icons/light/down_arrow.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QSpinBox::down-arrow:hover,
+QSpinBox::down-arrow:pressed,
+QDoubleSpinBox::down-arrow:hover,
+QDoubleSpinBox::down-arrow:pressed
+{
+ border-image: url(:/breeze_icons/light/down_arrow-hover.svg);
+ width: 0.9ex;
+ height: 0.6ex;
+}
+
+QSpinBox::down-arrow:disabled,
+QSpinBox::down-arrow:off,
+QDoubleSpinBox::down-arrow:disabled,
+QDoubleSpinBox::down-arrow:off
+{
+ border-image: url(:/breeze_icons/light/down_arrow_disabled.svg);
+}
+
+QPushButton:hover
+{
+ border: 0.1ex solid #3daef3;
+ color: #31363B;
+}
+
+QPushButton:focus
+{
+ background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #4cbdff, stop: 0.5 #33a4e8);
+ color: white;
+}
+
+QPushButton:focus:hover
+{
+ background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #bedfec, stop: 0.5 #b9dae7);
+ color: #31363B;
+}
+
+QPushButton:focus:pressed,
+QPushButton:pressed
+{
+ background-color: qlineargradient(x1: 0.5, y1: 0.5 x2: 0.5, y2: 1, stop: 0 #bedfec, stop: 0.5 #b9dae7);
+ color: #31363B;
+}
+
diff --git a/src/QuickCut/Styles/theme_console.qss b/src/QuickCut/Styles/theme_console.qss
new file mode 100644
index 0000000..af6c204
--- /dev/null
+++ b/src/QuickCut/Styles/theme_console.qss
@@ -0,0 +1,181 @@
+/*
+Dark Console Style Sheet for QT Applications
+Author: Jaime A. Quiroga P.
+Company: GTRONICK
+Last updated: 24/05/2018, 17:12.
+Available at: https://github.com/GTRONICK/QSS/blob/master/ConsoleStyle.qss
+*/
+QWidget {
+ background-color:rgb(0, 0, 0);
+ color: rgb(240, 240, 240);
+ border-color: rgb(58, 58, 58);
+}
+
+QPlainTextEdit {
+ background-color:rgb(0, 0, 0);
+ color: rgb(200, 200, 200);
+ selection-background-color: rgb(255, 153, 0);
+ selection-color: rgb(0, 0, 0);
+}
+
+QTabWidget::pane {
+ border-top: 1px solid #000000;
+}
+
+QTabBar::tab {
+ background-color:rgb(0, 0, 0);
+ border-style: outset;
+ border-width: 1px;
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-bottom-color: rgb(58, 58, 58);
+ border-bottom-width: 1px;
+ border-top-width: 0px;
+ border-style: solid;
+ color: rgb(255, 153, 0);
+ padding: 4px;
+}
+
+QTabBar::tab:selected, QTabBar::tab:hover {
+ color: rgb(255, 255, 255);
+ background-color:rgb(0, 0, 0);
+ border-color:rgb(42, 42, 42);
+ margin-left: 0px;
+ margin-right: 0px;
+ border-bottom-right-radius:4px;
+ border-bottom-left-radius:4px;
+}
+
+QTabBar::tab:last:selected {
+ background-color:rgb(0, 0, 0);
+ border-color:rgb(42, 42, 42);
+ margin-left: 0px;
+ margin-right: 0px;
+ border-bottom-right-radius:4px;
+ border-bottom-left-radius:4px;
+}
+
+QTabBar::tab:!selected {
+ margin-bottom: 4px;
+ border-bottom-right-radius:4px;
+ border-bottom-left-radius:4px;
+}
+
+QPushButton{
+ border-style: outset;
+ border-width: 2px;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-bottom-color: rgb(58, 58, 58);
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: rgb(255, 255, 255);
+ padding: 6px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(77, 77, 77, 255), stop:1 rgba(97, 97, 97, 255));
+}
+
+QPushButton:hover{
+ border-style: outset;
+ border-width: 2px;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(180, 180, 180, 255), stop:1 rgba(110, 110, 110, 255));
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(180, 180, 180, 255), stop:1 rgba(110, 110, 110, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(180, 180, 180, 255), stop:1 rgba(110, 110, 110, 255));
+ border-bottom-color: rgb(115, 115, 115);
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: rgb(255, 255, 255);
+ padding: 6px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(107, 107, 107, 255), stop:1 rgba(157, 157, 157, 255));
+}
+
+QPushButton:pressed{
+ border-style: outset;
+ border-width: 2px;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(62, 62, 62, 255), stop:1 rgba(22, 22, 22, 255));
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-bottom-color: rgb(58, 58, 58);
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: rgb(255, 255, 255);
+ padding: 6px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(77, 77, 77, 255), stop:1 rgba(97, 97, 97, 255));
+}
+
+QPushButton:disabled{
+ border-style: outset;
+ border-width: 2px;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-bottom-color: rgb(58, 58, 58);
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: rgb(0, 0, 0);
+ padding: 6px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(57, 57, 57, 255), stop:1 rgba(77, 77, 77, 255));
+}
+
+QLineEdit {
+ border-width: 1px; border-radius: 4px;
+ border-color: rgb(58, 58, 58);
+ border-style: inset;
+ padding: 0 8px;
+ color: rgb(255, 255, 255);
+ background:rgb(101, 101, 101);
+ selection-background-color: rgb(187, 187, 187);
+ selection-color: rgb(60, 63, 65);
+}
+
+QProgressBar {
+ text-align: center;
+ color: rgb(255, 255, 255);
+ border-width: 1px;
+ border-radius: 10px;
+ border-color: rgb(58, 58, 58);
+ border-style: inset;
+}
+
+QProgressBar::chunk {
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:0.7, x2:0.5, y2:0.3, stop:0 rgba(0, 200, 0, 255), stop:1 rgba(30, 230, 30, 255));
+ border-radius: 10px;
+}
+
+QMenuBar {
+ background:rgb(0, 0, 0);
+ color: rgb(255, 153, 0);
+}
+
+QMenuBar::item {
+ spacing: 3px;
+ padding: 1px 4px;
+ background: transparent;
+}
+
+QMenuBar::item:selected {
+ background:rgb(115, 115, 115);
+}
+
+QMenu {
+ border-width: 2px;
+ border-radius: 10px;
+ border-color: rgb(255, 153, 0);
+ border-style: outset;
+}
+
+QMenu::item {
+ spacing: 3px;
+ padding: 3px 15px;
+}
+
+QMenu::item:selected {
+ spacing: 3px;
+ padding: 3px 15px;
+ background:rgb(115, 115, 115);
+ color:rgb(255, 255, 255);
+ border-width: 1px;
+ border-radius: 10px;
+ border-color: rgb(58, 58, 58);
+ border-style: inset;
+}
diff --git a/src/QuickCut/Styles/theme_dark.qss b/src/QuickCut/Styles/theme_dark.qss
new file mode 100644
index 0000000..8007fd6
--- /dev/null
+++ b/src/QuickCut/Styles/theme_dark.qss
@@ -0,0 +1,1939 @@
+/* QDarkStyleSheet --------------------------------------------------------
+
+This is the main style sheet, the palette has nine main colors.
+It is based on three selecting colors, three greyish (background) colors
+plus three whitish (foreground) colors. Each set of widgets of the same
+type have a header like this:
+
+ ------------------
+ GroupName --------
+ ------------------
+
+And each widget is separated with a header like this:
+
+ QWidgetName ------
+
+This makes more easy to find and change some css field. The basic
+configuration is described bellow.
+
+ SELECTION ------------
+
+ sel_light #179AE0 #148CD2 (selection/hover/active)
+ sel_normal #3375A3 #1464A0 (selected)
+ sel_dark #18465D #14506E (selected disabled)
+
+ FOREGROUND -----------
+
+ for_light #EFF0F1 #F0F0F0 (texts/labels)
+ for_normal #AAAAAA (not used yet)
+ for_dark #505F69 #787878 (disabled texts)
+
+ BACKGROUND -----------
+
+ bac_light #4D545B #505F69 (unpressed)
+ bac_normal #31363B #32414B (border, disabled, pressed, checked, toolbars, menus)
+ bac_dark #232629 #19232D (background)
+
+If a stranger configuration is required because of a bugfix or anything
+else, keep the comment on that line to nobodys changed it, including the
+issue number.
+--------------------------------------------------------------------------- */
+
+
+
+/* QWidget ---------------------------------------------------------------- */
+
+QWidget {
+ background-color: #19232D;
+ border: 0px solid #32414B;
+ padding: 0px;
+ color: #F0F0F0;
+ selection-background-color: #1464A0;
+ selection-color: #F0F0F0;
+}
+
+QWidget:disabled {
+ background-color: #19232D;
+ color: #787878;
+ selection-background-color: #14506E;
+ selection-color: #787878;
+}
+
+QWidget:item:selected {
+ background-color: #1464A0;
+}
+
+QWidget:item:hover {
+ background-color: #148CD2;
+ color: #32414B;
+}
+
+/* QMainWindow ------------------------------------------------------------ */
+/* This adjusts the splitter in the dock widget, not qsplitter */
+
+
+QMainWindow::separator {
+ background-color: #32414B;
+ border: 0 solid #19232D;
+ spacing: 0;
+ padding: 2px;
+}
+
+QMainWindow::separator:hover {
+ background-color: #505F69;
+ border: 0px solid #148CD2;
+}
+
+QMainWindow::separator:horizontal {
+ width: 5px;
+ margin-top: 2px;
+ margin-bottom: 2px;
+ image: url(:/qss_icons/rc/Vsepartoolbar.png);
+}
+
+QMainWindow::separator:vertical {
+ height: 5px;
+ margin-left: 2px;
+ margin-right: 2px;
+ image: url(:/qss_icons/rc/Hsepartoolbar.png);
+}
+
+/* QToolTip --------------------------------------------------------------- */
+
+QToolTip {
+ background-color: #148CD2;
+ border: 1px solid #19232D;
+ color: #19232D;
+ padding: 0; /*remove padding, for fix combo box tooltip*/
+ opacity: 230; /*reducing transparency to read better*/
+}
+
+/* QStatusBar ------------------------------------------------------------- */
+
+QStatusBar {
+ border: 1px solid #32414B;
+ background: #32414B; /*fixes spyder #9120,#9121*/
+}
+
+QStatusBar QToolTip {
+ background-color: #148CD2;
+ border: 1px solid #19232D;
+ color: #19232D;
+ padding: 0; /*remove padding, for fix combo box tooltip*/
+ opacity: 230; /*reducing transparency to read better*/
+}
+
+QStatusBar QLabel {
+ background-color: transparent; /*fixes spyder #9120,#9121*/
+}
+
+/* QCheckBox -------------------------------------------------------------- */
+
+QCheckBox {
+ background-color: #19232D;
+ color: #F0F0F0;
+ spacing: 4px;
+ outline: none;
+ padding-top: 4px;
+ padding-bottom: 4px;
+}
+
+QCheckBox:focus {
+ border: none;
+}
+
+QCheckBox QWidget:disabled {
+ background-color: #19232D;
+ color: #787878;
+}
+
+QCheckBox::indicator {
+ margin-left: 4px;
+ width: 16px;
+ height: 16px;
+}
+
+QCheckBox::indicator:unchecked {
+ image: url(:/qss_icons/rc/checkbox_unchecked.png);
+}
+
+QCheckBox::indicator:unchecked:hover,
+QCheckBox::indicator:unchecked:focus,
+QCheckBox::indicator:unchecked:pressed {
+ border: none;
+ image: url(:/qss_icons/rc/checkbox_unchecked_focus.png);
+}
+
+QCheckBox::indicator:unchecked:disabled {
+ image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png);
+}
+
+QCheckBox::indicator:checked {
+ image: url(:/qss_icons/rc/checkbox_checked.png);
+}
+
+QCheckBox::indicator:checked:hover,
+QCheckBox::indicator:checked:focus,
+QCheckBox::indicator:checked:pressed {
+ border: none;
+ image: url(:/qss_icons/rc/checkbox_checked_focus.png);
+}
+
+QCheckBox::indicator:checked:disabled{
+ image: url(:/qss_icons/rc/checkbox_checked_disabled.png);
+}
+
+QCheckBox::indicator:indeterminate {
+ image: url(:/qss_icons/rc/checkbox_indeterminate.png);
+}
+
+QCheckBox::indicator:indeterminate:disabled {
+ image: url(:/qss_icons/rc/checkbox_indeterminate_disabled.png);
+}
+
+QCheckBox::indicator:indeterminate:focus,
+QCheckBox::indicator:indeterminate:hover,
+QCheckBox::indicator:indeterminate:pressed {
+ image: url(:/qss_icons/rc/checkbox_indeterminate_focus.png);
+}
+
+/* QGroupBox -------------------------------------------------------------- */
+
+QGroupBox {
+ font-weight: bold;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ padding: 4px;
+ margin-top: 16px;
+}
+
+
+
+QGroupBox::title {
+ subcontrol-origin: margin;
+ subcontrol-position: top left;
+ left: 3px;
+ padding-left: 3px;
+ padding-right: 5px;
+ padding-top: 8px;
+ padding-bottom: 16px;
+}
+
+QGroupBox::indicator {
+ margin-left: 4px;
+ width: 16px;
+ height: 16px;
+}
+
+QGroupBox::indicator {
+ margin-left: 2px;
+}
+
+QGroupBox::indicator:unchecked:hover,
+QGroupBox::indicator:unchecked:focus,
+QGroupBox::indicator:unchecked:pressed {
+ border: none;
+ image: url(:/qss_icons/rc/checkbox_unchecked_focus.png);
+}
+
+QGroupBox::indicator:checked:hover,
+QGroupBox::indicator:checked:focus,
+QGroupBox::indicator:checked:pressed {
+ border: none;
+ image: url(:/qss_icons/rc/checkbox_checked_focus.png);
+}
+
+QGroupBox::indicator:checked:disabled {
+ image: url(:/qss_icons/rc/checkbox_checked_disabled.png);
+}
+
+QGroupBox::indicator:unchecked:disabled {
+ image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png);
+}
+
+/* QRadioButton ----------------------------------------------------------- */
+
+QRadioButton {
+ background-color: #19232D;
+ color: #F0F0F0;
+ spacing: 0;
+ padding: 0;
+ border: none;
+ outline: none;
+}
+
+QRadioButton:focus {
+ border: none;
+}
+
+QRadioButton:disabled {
+ background-color: #19232D;
+ color: #787878;
+ border: none;
+ outline: none;
+}
+
+QRadioButton QWidget {
+ background-color: #19232D;
+ color: #F0F0F0;
+ spacing: 0px;
+ padding: 0px;
+ outline: none;
+ border: none;
+}
+
+QRadioButton::indicator {
+ border: none;
+ outline: none;
+ margin-bottom: 2px;
+ width: 25px;
+ height: 25px;
+}
+
+QRadioButton::indicator:unchecked {
+ image: url(:/qss_icons/rc/radio_unchecked.png);
+}
+
+QRadioButton::indicator:unchecked:hover,
+QRadioButton::indicator:unchecked:focus,
+QRadioButton::indicator:unchecked:pressed {
+ border: none;
+ outline: none;
+ image: url(:/qss_icons/rc/radio_unchecked_focus.png);
+}
+
+QRadioButton::indicator:checked {
+ border: none;
+ outline: none;
+ image: url(:/qss_icons/rc/radio_checked.png);
+}
+
+QRadioButton::indicator:checked:hover,
+QRadioButton::indicator:checked:focus,
+QRadioButton::indicator:checked:pressed {
+ border: none;
+ outline: none;
+ image: url(:/qss_icons/rc/radio_checked_focus.png);
+}
+
+QRadioButton::indicator:checked:disabled {
+ outline: none;
+ image: url(:/qss_icons/rc/radio_checked_disabled.png);
+}
+
+QRadioButton::indicator:unchecked:disabled {
+ image: url(:/qss_icons/rc/radio_unchecked_disabled.png);
+}
+
+/* QMenuBar --------------------------------------------------------------- */
+
+QMenuBar {
+ background-color: #32414B;
+ padding: 2px;
+ border: 1px solid #19232D;
+ color: #F0F0F0;
+}
+
+QMenuBar:focus {
+ border: 1px solid #148CD2;
+}
+
+QMenuBar::item {
+ background: transparent;
+ padding: 4px;
+}
+
+QMenuBar::item:selected {
+ padding: 4px;
+ background: transparent;
+ border: 0px solid #32414B;
+}
+
+QMenuBar::item:pressed {
+ padding: 4px;
+ border: 0px solid #32414B;
+ background-color: #148CD2;
+ color: #F0F0F0;
+ margin-bottom: 0px;
+ padding-bottom: 0px;
+}
+
+/* QMenu ------------------------------------------------------------------ */
+
+QMenu {
+ border: 0px solid #32414B;
+ color: #F0F0F0;
+ margin: 0px;
+}
+
+QMenu::separator {
+ height: 2px;
+ background-color: #505F69;
+ color: #F0F0F0;
+ padding-left: 4px;
+ margin-left: 2px;
+ margin-right: 2px;
+}
+
+QMenu::icon {
+ margin: 0px;
+ padding-left:4px;
+}
+
+QMenu::item {
+ padding: 4px 24px 4px 24px;
+ border: 1px transparent #32414B; /* reserve space for selection border */
+}
+
+QMenu::item:selected {
+ color: #F0F0F0;
+}
+
+
+
+QMenu::indicator {
+ width: 12px;
+ height: 12px;
+ padding-left:6px;
+}
+
+/* non-exclusive indicator = check box style indicator (see QActionGroup::setExclusive) */
+
+QMenu::indicator:non-exclusive:unchecked {
+ image: url(:/qss_icons/rc/checkbox_unchecked.png);
+}
+
+QMenu::indicator:non-exclusive:unchecked:selected {
+ image: url(:/qss_icons/rc/checkbox_unchecked_disabled.png);
+}
+
+QMenu::indicator:non-exclusive:checked {
+ image: url(:/qss_icons/rc/checkbox_checked.png);
+}
+
+QMenu::indicator:non-exclusive:checked:selected {
+ image: url(:/qss_icons/rc/checkbox_checked_disabled.png);
+}
+
+/* exclusive indicator = radio button style indicator (see QActionGroup::setExclusive) */
+
+QMenu::indicator:exclusive:unchecked {
+ image: url(:/qss_icons/rc/radio_unchecked.png);
+}
+
+QMenu::indicator:exclusive:unchecked:selected {
+ image: url(:/qss_icons/rc/radio_unchecked_disabled.png);
+}
+
+QMenu::indicator:exclusive:checked {
+ image: url(:/qss_icons/rc/radio_checked.png);
+}
+
+QMenu::indicator:exclusive:checked:selected {
+ image: url(:/qss_icons/rc/radio_checked_disabled.png);
+}
+
+QMenu::right-arrow {
+ margin: 5px;
+ image: url(:/qss_icons/rc/right_arrow.png)
+}
+
+/* QAbstractItemView ------------------------------------------------------ */
+
+QAbstractItemView {
+ alternate-background-color: #19232D;
+ color: #F0F0F0;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+}
+
+QAbstractItemView QLineEdit {
+ padding: 2px;
+}
+
+/* QAbstractScrollArea ---------------------------------------------------- */
+
+QAbstractScrollArea {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ padding: 4px;
+ color: #F0F0F0;
+}
+
+QAbstractScrollArea:disabled {
+ color: #787878;
+}
+
+/* QScrollArea ------------------------------------------------------------ */
+
+QScrollArea QWidget QWidget:disabled {
+ background-color: #19232D;
+}
+
+/* QScrollBar ------------------------------------------------------------- */
+
+QScrollBar:horizontal {
+ height: 16px;
+ margin: 2px 16px 2px 16px;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ background-color: #19232D;
+}
+
+QScrollBar::handle:horizontal {
+ background-color: #787878;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ min-width: 8px;
+
+}
+
+QScrollBar::handle:horizontal:hover {
+ background-color: #148CD2;
+ border: 1px solid #148CD2;
+ border-radius: 4px;
+ min-width: 8px;
+}
+
+QScrollBar::add-line:horizontal {
+ margin: 0px 0px 0px 0px;
+ border-image: url(:/qss_icons/rc/right_arrow_disabled.png);
+ width: 10px;
+ height: 10px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:horizontal {
+ margin: 0px 3px 0px 3px;
+ border-image: url(:/qss_icons/rc/left_arrow_disabled.png);
+ height: 10px;
+ width: 10px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::add-line:horizontal:hover,
+QScrollBar::add-line:horizontal:on {
+ border-image: url(:/qss_icons/rc/right_arrow.png);
+ height: 10px;
+ width: 10px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:horizontal:hover,
+QScrollBar::sub-line:horizontal:on {
+ border-image: url(:/qss_icons/rc/left_arrow.png);
+ height: 10px;
+ width: 10px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::up-arrow:horizontal,
+QScrollBar::down-arrow:horizontal {
+ background: none;
+}
+
+QScrollBar::add-page:horizontal,
+QScrollBar::sub-page:horizontal {
+ background: none;
+}
+
+QScrollBar:vertical {
+ background-color: #19232D;
+ width: 16px;
+ margin: 16px 2px 16px 2px;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+}
+
+QScrollBar::handle:vertical {
+ background-color: #787878;
+ border: 1px solid #32414B;
+ min-height: 8px;
+ border-radius: 4px;
+}
+
+QScrollBar::handle:vertical:hover {
+ background-color: #148CD2;
+ border: 1px solid #148CD2;
+ border-radius: 4px;
+ min-height: 8px;
+
+}
+
+QScrollBar::sub-line:vertical {
+ margin: 3px 0px 3px 0px;
+ border-image: url(:/qss_icons/rc/up_arrow_disabled.png);
+ height: 10px;
+ width: 10px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::add-line:vertical {
+ margin: 3px 0px 3px 0px;
+ border-image: url(:/qss_icons/rc/down_arrow_disabled.png);
+ height: 10px;
+ width: 10px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::sub-line:vertical:hover,
+QScrollBar::sub-line:vertical:on {
+ border-image: url(:/qss_icons/rc/up_arrow.png);
+ height: 10px;
+ width: 10px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::add-line:vertical:hover,
+QScrollBar::add-line:vertical:on {
+ border-image: url(:/qss_icons/rc/down_arrow.png);
+ height: 10px;
+ width: 10px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+
+QScrollBar::up-arrow:vertical,
+QScrollBar::down-arrow:vertical {
+ background: none;
+}
+
+QScrollBar::add-page:vertical,
+QScrollBar::sub-page:vertical {
+ background: none;
+}
+
+/* QTextEdit--------------------------------------------------------------- */
+
+QTextEdit {
+ background-color: #19232D;
+ color: #F0F0F0;
+ border: 1px solid #32414B;
+}
+
+QTextEdit:hover {
+ border: 1px solid #148CD2;
+ color: #F0F0F0;
+}
+
+QTextEdit:selected {
+ background: #1464A0;
+ color: #32414B;
+}
+
+/* QPlainTextEdit --------------------------------------------------------- */
+
+QPlainTextEdit {
+ background-color: #19232D;
+ color: #F0F0F0;
+ border-radius: 4px;
+ border: 1px solid #32414B;
+}
+
+QPlainTextEdit:hover {
+ border: 1px solid #148CD2;
+ color: #F0F0F0;
+}
+
+QPlainTextEdit:selected {
+ background: #1464A0;
+ color: #32414B;
+}
+
+/* QSizeGrip --------------------------------------------------------------- */
+
+QSizeGrip {
+ image: url(:/qss_icons/rc/sizegrip.png);
+ width: 12px;
+ height: 12px;
+}
+
+/* QStackedWidget --------------------------------------------------------- */
+
+QStackedWidget {
+ padding: 4px;
+ border: 1px solid #32414B;
+ border: 1px solid #19232D;
+}
+
+/* QToolBar --------------------------------------------------------------- */
+
+QToolBar {
+ background-color: #32414B;
+ border-bottom: 1px solid #19232D;
+ padding: 2px;
+ font-weight: bold;
+}
+
+QToolBar QToolButton{
+ background-color: #32414B;
+}
+
+QToolBar::handle:horizontal {
+ width: 6px;
+ image: url(:/qss_icons/rc/Hmovetoolbar.png);
+}
+
+QToolBar::handle:vertical {
+ height: 6px;
+ image: url(:/qss_icons/rc/Vmovetoolbar.png);
+}
+
+QToolBar::separator:horizontal {
+ width: 3px;
+ image: url(:/qss_icons/rc/Hsepartoolbar.png);
+}
+
+QToolBar::separator:vertical {
+ height: 3px;
+ image: url(:/qss_icons/rc/Vsepartoolbar.png);
+}
+
+QToolButton#qt_toolbar_ext_button {
+ background: #32414B;
+ border: 0px;
+ color: #F0F0F0;
+ image: url(:/qss_icons/rc/right_arrow.png);
+}
+
+/* QAbstractSpinBox ------------------------------------------------------- */
+
+QAbstractSpinBox {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ color: #F0F0F0;
+ padding-top: 2px; /* This fix 103, 111*/
+ padding-bottom: 2px; /* This fix 103, 111*/
+ padding-left: 4px;
+ padding-right: 4px;
+ border-radius: 4px;
+ /* min-width: 5px; removed to fix 109 */
+}
+
+QAbstractSpinBox:up-button {
+ background-color: transparent #19232D;
+ subcontrol-origin: border;
+ subcontrol-position: top right;
+ border-left: 1px solid #32414B;
+ margin: 1px;
+}
+
+QAbstractSpinBox::up-arrow,
+QAbstractSpinBox::up-arrow:disabled,
+QAbstractSpinBox::up-arrow:off {
+ image: url(:/qss_icons/rc/up_arrow_disabled.png);
+ width: 9px;
+ height: 9px;
+}
+
+QAbstractSpinBox::up-arrow:hover {
+ image: url(:/qss_icons/rc/up_arrow.png);
+}
+
+QAbstractSpinBox:down-button {
+ background-color: transparent #19232D;
+ subcontrol-origin: border;
+ subcontrol-position: bottom right;
+ border-left: 1px solid #32414B;
+ margin: 1px;
+}
+
+QAbstractSpinBox::down-arrow,
+QAbstractSpinBox::down-arrow:disabled,
+QAbstractSpinBox::down-arrow:off {
+ image: url(:/qss_icons/rc/down_arrow_disabled.png);
+ width: 9px;
+ height: 9px;
+}
+
+QAbstractSpinBox::down-arrow:hover {
+ image: url(:/qss_icons/rc/down_arrow.png);
+}
+
+QAbstractSpinBox:hover{
+ border: 1px solid #148CD2;
+ color: #F0F0F0;
+}
+
+QAbstractSpinBox:selected {
+ background: #1464A0;
+ color: #32414B;
+}
+
+/* ------------------------------------------------------------------------ */
+/* DISPLAYS --------------------------------------------------------------- */
+/* ------------------------------------------------------------------------ */
+
+/* QLabel ----------------------------------------------------------------- */
+
+QLabel {
+ background-color: #19232D;
+ border: 0px solid #32414B;
+ padding: 2px;
+ margin: 0px;
+ color: #F0F0F0
+}
+
+QLabel::disabled {
+ background-color: #19232D;
+ border: 0px solid #32414B;
+ color: #787878;
+}
+
+/* QTextBrowser ----------------------------------------------------------- */
+
+QTextBrowser {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ color: #F0F0F0;
+ border-radius: 4px;
+}
+
+QTextBrowser:disabled {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ color: #787878;
+ border-radius: 4px;
+}
+
+QTextBrowser:hover,
+QTextBrowser:!hover,
+QTextBrowser::selected,
+QTextBrowser::pressed {
+ border: 1px solid #32414B;
+}
+
+/* QGraphicsView --------------------------------------------------------- */
+
+QGraphicsView {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ color: #F0F0F0;
+ border-radius: 4px;
+}
+
+QGraphicsView:disabled {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ color: #787878;
+ border-radius: 4px;
+}
+
+QGraphicsView:hover,
+QGraphicsView:!hover,
+QGraphicsView::selected,
+QGraphicsView::pressed {
+ border: 1px solid #32414B;
+}
+
+/* QCalendarWidget -------------------------------------------------------- */
+
+QCalendarWidget {
+ border: 1px solid #32414B;
+ border-radius: 4px;
+}
+
+QCalendarWidget:disabled {
+ background-color: #19232D;
+ color: #787878;
+}
+
+/* QLCDNumber ------------------------------------------------------------- */
+
+QLCDNumber {
+ background-color: #19232D;
+ color: #F0F0F0;
+}
+
+QLCDNumber:disabled {
+ background-color: #19232D;
+ color: #787878;
+}
+
+/* QProgressBar ----------------------------------------------------------- */
+
+QProgressBar {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ color: #F0F0F0;
+ border-radius: 4px;
+ text-align: center;
+}
+
+QProgressBar:disabled {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ color: #787878;
+ border-radius: 4px;
+ text-align: center;
+}
+
+QProgressBar::chunk {
+ background-color: #1464A0;
+ color: #19232D;
+ border-radius: 4px;
+}
+
+QProgressBar::chunk:disabled {
+ background-color: #14506E;
+ color: #787878;
+ border-radius: 4px;
+}
+
+
+/* ------------------------------------------------------------------------ */
+/* BUTTONS ---------------------------------------------------------------- */
+/* ------------------------------------------------------------------------ */
+
+/* QPushButton ------------------------------------------------------------ */
+
+QPushButton {
+ background-color: #505F69 ;
+ border: 1px solid #32414B;
+ color: #F0F0F0;
+ border-radius: 4px;
+ padding: 3px;
+ outline: none;
+}
+
+QPushButton:disabled {
+ background-color: #32414B;
+ border: 1px solid #32414B;
+ color: #787878;
+ border-radius: 4px;
+ padding: 3px;
+}
+
+
+QPushButton:checked {
+ background-color: #32414B;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ padding: 3px;
+ outline: none;
+}
+
+QPushButton:checked:disabled {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ color: #787878;
+ border-radius: 4px;
+ padding: 3px;
+ outline: none;
+}
+
+QPushButton::menu-indicator {
+ subcontrol-origin: padding;
+ subcontrol-position: bottom right;
+ bottom: 4px;
+}
+
+QPushButton:pressed {
+ background-color: #19232D;
+ border: 1px solid #19232D;
+}
+
+QPushButton:hover,
+QPushButton:checked:hover{
+ border: 1px solid #148CD2;
+ color: #F0F0F0;
+}
+
+QPushButton:pressed:hover{
+ border: 1px solid #1464A0;
+}
+
+QPushButton:selected,
+QPushButton:checked:selected{
+ background: #1464A0;
+ color: #32414B;
+}
+
+/* QToolButton ------------------------------------------------------------ */
+
+QToolButton {
+ background-color: transparent;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ margin: 0px;
+ padding: 2px;
+}
+
+QToolButton:checked {
+ background-color: #19232D;
+ border: 1px solid #19232D;
+}
+
+QToolButton:pressed {
+ background-color: #19232D;
+ border: 1px solid #19232D;
+
+}
+
+QToolButton:disabled {
+ border: 1px solid #32414B;
+}
+
+QToolButton:hover,
+QToolButton:checked:hover{
+ border: 1px solid #148CD2;
+}
+QToolButton:pressed:hover{
+ border: 1px solid #1464A0;
+}
+
+/* the subcontrols below are used only in the MenuButtonPopup mode */
+
+QToolButton[popupMode="1"] {
+ padding: 2px;
+ padding-right: 12px; /* only for MenuButtonPopup */
+ border: 1px solid #32414B; /* make way for the popup button */
+ border-radius: 4px;
+}
+
+/* The subcontrol below is used only in the InstantPopup or DelayedPopup mode */
+
+QToolButton[popupMode="2"] {
+ padding: 2px;
+ padding-right: 12px; /* only for InstantPopup */
+ border: 1px solid #32414B; /* make way for the popup button */
+}
+
+QToolButton::menu-button {
+ padding: 2px;
+ border-radius: 4px;
+ border: 1px solid #32414B;
+ border-top-right-radius: 4px;
+ border-bottom-right-radius: 4px;
+ /* 16px width + 4px for border = 20px allocated above */
+ width: 16px;
+ outline: none;
+}
+
+QToolButton::menu-button:hover,
+QToolButton::menu-button:checked:hover {
+ border: 1px solid #148CD2;
+}
+
+QToolButton::menu-indicator {
+ image: url(:/qss_icons/rc/down_arrow.png);
+ top: -8px; /* shift it a bit */
+ left: -4px; /* shift it a bit */
+}
+
+QToolButton::menu-arrow {
+ image: url(:/qss_icons/rc/down_arrow.png);
+}
+
+QToolButton::menu-arrow:open {
+ border: 1px solid #32414B;
+}
+
+/* QCommandLinkButton ----------------------------------------------------- */
+
+QCommandLinkButton {
+ background-color: transparent;
+ border: 1px solid #32414B;
+ color: #F0F0F0;
+ border-radius: 4px;
+ padding: 0px;
+ margin: 0px;
+}
+
+QCommandLinkButton:disabled {
+ background-color: transparent;
+ color: #787878;
+}
+
+/* ------------------------------------------------------------------------ */
+/* INPUTS - NO FIELDS ----------------------------------------------------- */
+/* ------------------------------------------------------------------------ */
+
+/* QCombobox -------------------------------------------------------------- */
+QComboBox {
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ selection-background-color: #1464A0;
+ padding-left: 4px;
+ padding-right: 4px;
+ min-height: 1.5em; /* fix #103, #111 */
+ /* padding-top: 2px; removed to fix #132 */
+ /* padding-bottom: 2px; removed to fix #132 */
+ /* min-width: 75px; removed to fix #109 */
+}
+
+QComboBox QAbstractItemView {
+ background-color: #19232d;
+ border-radius: 4px;
+ border: 1px solid #32414B;
+ selection-color: #148CD2;
+ selection-background-color: #32414B;
+}
+
+QComboBox:disabled {
+ background-color: #19232D;
+ color: #787878;
+}
+
+QComboBox:hover{
+ border: 1px solid #148CD2;
+}
+
+QComboBox:on {
+ selection-background-color: #19232D;
+}
+
+/* Needed to remove indicator - fix #132 */
+QComboBox::indicator {
+ background-color:transparent;
+ selection-background-color:transparent;
+ color:transparent;
+ selection-color:transparent;
+}
+
+/* Needed to remove indicator - fix #132 */
+QComboBox::item:alternate {
+ background: #19232D;
+}
+
+QComboBox::item:checked {
+ font-weight: bold;
+}
+
+QComboBox::item:selected {
+ border: 0px solid transparent;
+}
+
+QComboBox::drop-down {
+ subcontrol-origin: padding;
+ subcontrol-position: top right;
+ width: 20px;
+ border-left-width: 0px;
+ border-left-color: #32414B;
+ border-left-style: solid;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+QComboBox::down-arrow {
+ image: url(:/qss_icons/rc/down_arrow_disabled.png);
+}
+
+QComboBox::down-arrow:on,
+QComboBox::down-arrow:hover,
+QComboBox::down-arrow:focus {
+ image: url(:/qss_icons/rc/down_arrow.png);
+}
+
+/* QSlider ---------------------------------------------------------------- */
+
+QSlider:disabled {
+ background: #19232D;
+}
+
+QSlider:focus {
+ border: none;
+}
+
+QSlider::groove:horizontal {
+ background: #32414B;
+ border: 1px solid #32414B;
+ height: 4px;
+ margin: 0px;
+ border-radius: 4px;
+}
+
+QSlider::sub-page:horizontal {
+ background: #1464A0;
+ border: 1px solid #32414B;
+ height: 4px;
+ margin: 0px;
+ border-radius: 4px;
+}
+
+QSlider::sub-page:horizontal:disabled {
+ background: #14506E;
+}
+
+QSlider::handle:horizontal {
+ background: #787878;
+ border: 1px solid #32414B;
+ width: 8px;
+ height: 8px;
+ margin: -8px 0;
+ border-radius: 4px;
+}
+
+QSlider::handle:horizontal:hover {
+ background: #148CD2;
+ border: 1px solid #148CD2;
+}
+
+QSlider::groove:vertical {
+ background: #32414B;
+ border: 1px solid #32414B;
+ width: 4px;
+ margin: 0px;
+ border-radius: 4px;
+}
+
+QSlider::sub-page:vertical {
+ background: #1464A0;
+ border: 1px solid #32414B;
+ width: 4px;
+ margin: 0px;
+ border-radius: 4px;
+}
+
+QSlider::sub-page:vertical:disabled {
+ background: #14506E;
+}
+
+QSlider::handle:vertical {
+ background: #787878;
+ border: 1px solid #32414B;
+ width: 8px;
+ height: 8px;
+ margin: 0 -8px;
+ border-radius: 4px;
+}
+
+QSlider::handle:vertical:hover {
+ background: #148CD2;
+ border: 1px solid #148CD2;
+}
+
+/* QLine ------------------------------------------------------------------ */
+
+QLineEdit {
+ background-color: #19232D;
+ padding-top: 2px; /* This QLineEdit fix 103, 111 */
+ padding-bottom: 2px; /* This QLineEdit fix 103, 111 */
+ padding-left: 4px;
+ padding-right: 4px;
+ border-style: solid;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ color: #F0F0F0;
+}
+
+QLineEdit:disabled {
+ background-color: #19232D;
+ color: #787878;
+}
+
+QLineEdit:hover{
+ border: 1px solid #148CD2;
+ color: #F0F0F0;
+}
+
+QLineEdit:selected{
+ background: #1464A0;
+ color: #32414B;
+}
+
+/* QTabWiget -------------------------------------------------------------- */
+
+QTabWidget {
+ padding: 2px;
+ selection-background-color: #32414B;
+}
+
+
+QTabWidget QWidget QWidget /* add wanted borders fix #141, #126, #123 */
+QTabWidget QFrame {
+ border: 1px solid #32414B;
+}
+
+QTabWidget QLabel {
+ border: 0px solid #32414B; /* label derived from frame, remove border #141 */
+}
+
+QTabWidget::pane {
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ padding: 0px; /* fixes double border inside pane wit pyqt5 */
+ margin: 0px;
+}
+
+QTabWidget::pane:selected {
+ background-color: #32414B;
+ border: 1px solid #1464A0;
+}
+
+/* QTabBar ---------------------------------------------------------------- */
+
+QTabBar {
+ qproperty-drawBase: 0;
+ border-radius: 4px;
+ margin: 0px;
+ padding: 2px;
+ border: 0;
+
+ /* left: 5px; move to the right by 5px - removed for fix */
+ }
+
+QTabBar::close-button {
+ border: 0;
+ margin: 2px;
+ padding: 0;
+ image: url(:/qss_icons/rc/close.png);
+}
+
+QTabBar::close-button:hover {
+ image: url(:/qss_icons/rc/close-hover.png);
+}
+
+QTabBar::close-button:pressed {
+ image: url(:/qss_icons/rc/close-pressed.png);
+}
+
+/* QTabBar::tab - selected ----------------------------------------------- */
+
+QTabBar::tab:top:selected:disabled {
+ border-bottom: 3px solid #14506E;
+ color: #787878;
+ background-color: #32414B;
+}
+
+QTabBar::tab:bottom:selected:disabled {
+ border-top: 3px solid #14506E;
+ color: #787878;
+ background-color: #32414B;
+}
+
+QTabBar::tab:left:selected:disabled {
+ border-left: 3px solid #14506E;
+ color: #787878;
+ background-color: #32414B;
+}
+
+QTabBar::tab:right:selected:disabled {
+ border-right: 3px solid #14506E;
+ color: #787878;
+ background-color: #32414B;
+}
+
+/* QTabBar::tab - !selected and disabled ---------------------------------- */
+
+QTabBar::tab:top:!selected:disabled {
+ border-bottom: 3px solid #19232D;
+ color: #787878;
+ background-color: #19232D;
+}
+
+QTabBar::tab:bottom:!selected:disabled {
+ border-top: 3px solid #19232D;
+ color: #787878;
+ background-color: #19232D;
+}
+
+QTabBar::tab:left:!selected:disabled {
+ border-right: 3px solid #19232D;
+ color: #787878;
+ background-color: #19232D;
+}
+
+QTabBar::tab:right:!selected:disabled {
+ border-left: 3px solid #19232D;
+ color: #787878;
+ background-color: #19232D;
+}
+
+/* QTabBar::tab - selected ----------------------------------------------- */
+
+QTabBar::tab:top:!selected {
+ border-bottom: 2px solid #19232D;
+ margin-top: 2px;
+}
+
+QTabBar::tab:bottom:!selected {
+ border-top: 2px solid #19232D;
+ margin-bottom: 3px;
+}
+
+QTabBar::tab:left:!selected {
+ border-left: 2px solid #19232D;
+ margin-right: 2px;
+}
+
+QTabBar::tab:right:!selected {
+ border-right: 2px solid #19232D;
+ margin-left: 2px;
+}
+
+
+QTabBar::tab:top {
+ background-color: #32414B;
+ color: #F0F0F0;
+ margin-left: 2px;
+ padding-left: 4px;
+ padding-right: 4px;
+ padding-top: 2px;
+ padding-bottom: 2px;
+ min-width: 5px;
+ border-bottom: 3px solid #32414B;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+
+QTabBar::tab:top:selected {
+ background-color: #505F69;
+ color: #F0F0F0;
+ border-bottom: 3px solid #1464A0;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+}
+
+QTabBar::tab:top:!selected:hover {
+ border: 1px solid #148CD2;
+ border-bottom: 3px solid #148CD2;
+ padding: 0px;
+}
+
+QTabBar::tab:bottom {
+ color: #F0F0F0;
+ border-top: 3px solid #32414B;
+ background-color: #32414B;
+ margin-left: 2px;
+ padding-left: 4px;
+ padding-right: 4px;
+ padding-top: 2px;
+ padding-bottom: 2px;
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+ min-width: 5px;
+}
+
+QTabBar::tab:bottom:selected {
+ color: #F0F0F0;
+ background-color: #505F69;
+ border-top: 3px solid #1464A0;
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+QTabBar::tab:bottom:!selected:hover {
+ border: 1px solid #148CD2;
+ border-top: 3px solid #148CD2;
+ padding: 0px;
+}
+
+QTabBar::tab:left {
+ color: #F0F0F0;
+ background-color: #32414B;
+ margin-top: 2px;
+ padding-left: 2px;
+ padding-right: 2px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ min-height: 5px;
+}
+
+QTabBar::tab:left:selected {
+ color: #F0F0F0;
+ background-color: #505F69;
+ border-left: 3px solid #1464A0;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+QTabBar::tab:left:!selected:hover {
+ border: 1px solid #148CD2;
+ border-left: 3px solid #148CD2;
+ padding: 0px;
+}
+
+QTabBar::tab:right {
+ color: #F0F0F0;
+ background-color: #32414B;
+ margin-top: 2px;
+ padding-left: 2px;
+ padding-right: 2px;
+ padding-top: 4px;
+ padding-bottom: 4px;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+ min-height: 5px;
+}
+
+QTabBar::tab:right:selected {
+ color: #F0F0F0;
+ background-color: #505F69;
+ border-right: 3px solid #1464A0;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+}
+
+QTabBar::tab:right:!selected:hover {
+ border: 1px solid #148CD2;
+ border-right: 3px solid #148CD2;
+ padding: 0px;
+}
+
+QTabBar QToolButton::right-arrow:enabled {
+ image: url(:/qss_icons/rc/right_arrow.png);
+}
+
+QTabBar QToolButton::left-arrow:enabled {
+ image: url(:/qss_icons/rc/left_arrow.png);
+}
+
+QTabBar QToolButton::right-arrow:disabled {
+ image: url(:/qss_icons/rc/right_arrow_disabled.png);
+}
+
+QTabBar QToolButton::left-arrow:disabled {
+ image: url(:/qss_icons/rc/left_arrow_disabled.png);
+}
+
+QTabBar QToolButton{
+ background-color: #32414B; /* fixes #136 */
+ width: 16px;
+ height: 16px;
+}
+
+/* QDockWiget ------------------------------------------------------------- */
+
+QDockWidget {
+ outline: 1px solid #32414B;
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ titlebar-close-icon: url(:/qss_icons/rc/close.png);
+ titlebar-normal-icon: url(:/qss_icons/rc/undock.png);
+}
+
+QDockWidget::title {
+ padding: 6px; /* better size for title bar */
+ border: none;
+ background-color: #32414B;
+}
+
+QDockWidget::close-button {
+ background-color: #32414B;
+ border-radius: 4px;
+ border: none;
+}
+
+QDockWidget::close-button:hover {
+ border: 1px solid #32414B;
+}
+
+QDockWidget::close-button:pressed {
+ border: 1px solid #32414B;
+}
+
+QDockWidget::float-button {
+ background-color: #32414B;
+ border-radius: 4px;
+ border: none;
+}
+
+QDockWidget::float-button:hover {
+ border: 1px solid #32414B;
+}
+
+QDockWidget::float-button:pressed {
+ border: 1px solid #32414B;
+}
+
+
+/* QTreeView QTableView QListView ----------------------------------------- */
+
+QTreeView:branch:selected,
+QTreeView:branch:hover {
+ background: url(:/qss_icons/rc/transparent.png);
+}
+
+QTreeView::branch:has-siblings:!adjoins-item {
+ border-image: url(:/qss_icons/rc/transparent.png);
+}
+
+QTreeView::branch:has-siblings:adjoins-item {
+ border-image: url(:/qss_icons/rc/transparent.png);
+}
+
+QTreeView::branch:!has-children:!has-siblings:adjoins-item {
+ border-image: url(:/qss_icons/rc/transparent.png);
+}
+
+QTreeView::branch:has-children:!has-siblings:closed,
+QTreeView::branch:closed:has-children:has-siblings {
+ image: url(:/qss_icons/rc/branch_closed.png);
+}
+
+QTreeView::branch:open:has-children:!has-siblings,
+QTreeView::branch:open:has-children:has-siblings {
+ image: url(:/qss_icons/rc/branch_open.png);
+}
+
+QTreeView::branch:has-children:!has-siblings:closed:hover,
+QTreeView::branch:closed:has-children:has-siblings:hover {
+ image: url(:/qss_icons/rc/branch_closed-on.png);
+}
+
+QTreeView::branch:open:has-children:!has-siblings:hover,
+QTreeView::branch:open:has-children:has-siblings:hover {
+ image: url(:/qss_icons/rc/branch_open-on.png);
+}
+
+QListView::item:!selected:hover,
+QTreeView::item:!selected:hover,
+QTableView::item:!selected:hover,
+QColumnView::item:!selected:hover {
+ outline: 0;
+ color: #148CD2;
+ background-color: #32414B;
+}
+
+QListView::item:selected:hover,
+QTreeView::item:selected:hover,
+QTableView::item:selected:hover,
+QColumnView::item:selected:hover {
+ background: #1464A0;
+ color: #19232D;
+}
+
+QTreeView::indicator:checked,
+QListView::indicator:checked {
+ image: url(:/qss_icons/rc/checkbox_checked.png);
+}
+
+QTreeView::indicator:unchecked,
+QListView::indicator:unchecked {
+ image: url(:/qss_icons/rc/checkbox_unchecked.png);
+}
+
+QTreeView::indicator:checked:hover,
+QTreeView::indicator:checked:focus,
+QTreeView::indicator:checked:pressed,
+QListView::indicator:checked:hover,
+QListView::indicator:checked:focus,
+QListView::indicator:checked:pressed {
+ image: url(:/qss_icons/rc/checkbox_checked_focus.png);
+}
+
+QTreeView::indicator:unchecked:hover,
+QTreeView::indicator:unchecked:focus,
+QTreeView::indicator:unchecked:pressed,
+QListView::indicator:unchecked:hover,
+QListView::indicator:unchecked:focus,
+QListView::indicator:unchecked:pressed {
+ image: url(:/qss_icons/rc/checkbox_unchecked_focus.png);
+}
+
+QTreeView::indicator:indeterminate:hover,
+QTreeView::indicator:indeterminate:focus,
+QTreeView::indicator:indeterminate:pressed,
+QListView::indicator:indeterminate:hover,
+QListView::indicator:indeterminate:focus,
+QListView::indicator:indeterminate:pressed {
+ image: url(:/qss_icons/rc/checkbox_indeterminate_focus.png);
+}
+
+QTreeView::indicator:indeterminate,
+QListView::indicator:indeterminate {
+ image: url(:/qss_icons/rc/checkbox_indeterminate.png);
+}
+
+QListView,
+QTreeView,
+QTableView,
+QColumnView {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ color: #F0F0F0;
+ gridline-color: #32414B;
+ border-radius: 4px;
+}
+
+QListView:disabled,
+QTreeView:disabled,
+QTableView:disabled,
+QColumnView:disabled {
+ background-color: #19232D;
+ color: #787878;
+}
+
+QListView:selected,
+QTreeView:selected,
+QTableView:selected,
+QColumnView:selected {
+ background: #1464A0;
+ color: #32414B;
+}
+
+QListView:hover,
+QTreeView::hover,
+QTableView::hover,
+QColumnView::hover {
+ background-color: #19232D;
+ border: 1px solid #148CD2;
+}
+
+QListView::item:pressed,
+QTreeView::item:pressed,
+QTableView::item:pressed,
+QColumnView::item:pressed {
+ background-color: #1464A0;
+}
+
+QListView::item:selected:active,
+QTreeView::item:selected:active,
+QTableView::item:selected:active,
+QColumnView::item:selected:active {
+ background-color: #1464A0;
+}
+
+QTableCornerButton::section {
+ background-color: #19232D;
+ border: 1px transparent #32414B;
+ border-radius: 0px;
+}
+
+/* QHeaderView ------------------------------------------------------------ */
+
+QHeaderView {
+ background-color: #32414B;
+ border: 0px transparent #32414B;
+ padding: 0px;
+ margin: 0px;
+ border-radius: 0px;
+}
+
+QHeaderView:disabled {
+ background-color: #32414B;
+ border: 1px transparent #32414B;
+ padding: 2px;
+}
+
+QHeaderView::section {
+ background-color: #32414B;
+ color: #F0F0F0;
+ padding: 2px;
+ border-radius: 0px;
+ text-align: left;
+}
+
+QHeaderView::section:checked {
+ color: #F0F0F0;
+ background-color: #1464A0;
+}
+
+QHeaderView::section:checked:disabled {
+ color: #787878;
+ background-color: #14506E;
+}
+
+QHeaderView::section::horizontal:disabled,
+QHeaderView::section::vertical:disabled {
+ color: #787878;
+}
+
+QHeaderView::section::vertical::first,
+QHeaderView::section::vertical::only-one {
+ border-top: 1px solid #32414B;
+}
+
+QHeaderView::section::vertical {
+ border-top: 1px solid #19232D;
+}
+
+QHeaderView::section::horizontal::first,
+QHeaderView::section::horizontal::only-one {
+ border-left: 1px solid #32414B;
+}
+
+QHeaderView::section::horizontal {
+ border-left: 1px solid #19232D;
+}
+
+/* Those settings (border/width/height/background-color) solve bug */
+/* transparent arrow background and size */
+
+QHeaderView::down-arrow {
+ background-color: #32414B;
+ width: 16px;
+ height: 16px;
+ border-right: 1px solid #19232D;
+ image: url(:/qss_icons/rc/down_arrow.png);
+}
+
+QHeaderView::up-arrow {
+ background-color: #32414B;
+ width: 16px;
+ height: 16px;
+ border-right: 1px solid #19232D;
+ image: url(:/qss_icons/rc/up_arrow.png);
+}
+
+/* QToolBox -------------------------------------------------------------- */
+
+QToolBox {
+ padding: 0px;
+ border: 1px solid #32414B;
+}
+
+QToolBox::selected {
+ padding: 0px;
+ border: 2px solid #1464A0;
+}
+
+QToolBox::tab {
+ background-color: #19232D;
+ border: 1px solid #32414B;
+ color: #F0F0F0;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+}
+
+QToolBox::tab:disabled {
+ color: #787878;
+}
+
+QToolBox::tab:selected {
+ background-color: #505F69;
+ border-bottom: 2px solid #1464A0;
+}
+
+QToolBox::tab:!selected {
+ background-color: #32414B;
+ border-bottom: 2px solid #32414B;
+}
+
+QToolBox::tab:selected:disabled {
+ background-color: #32414B;
+ border-bottom: 2px solid #14506E;
+}
+
+QToolBox::tab:!selected:disabled {
+ background-color: #19232D;
+}
+
+QToolBox::tab:hover {
+ border-color: #148CD2;
+ border-bottom: 2px solid #148CD2;
+}
+
+QToolBox QScrollArea QWidget QWidget {
+ padding: 0px;
+ background-color: #19232D;
+}
+
+/* QFrame ----------------------------------------------------------------- */
+
+QFrame {
+ border-radius: 4px;
+ border: 1px solid #32414B;
+}
+
+QFrame[frameShape="0"] {
+ border-radius: 4px;
+ border: 1px transparent #32414B;
+}
+
+QFrame[height="3"],
+QFrame[width="3"] {
+ background-color: #19232D;
+}
+
+/* QSplitter -------------------------------------------------------------- */
+
+QSplitter {
+ background-color: #32414B;
+ spacing: 0;
+ padding: 0;
+ margin: 0;
+}
+
+QSplitter::separator {
+ background-color: #32414B;
+ border: 0 solid #19232D;
+ spacing: 0;
+ padding: 1px;
+ margin: 0;
+}
+
+QSplitter::separator:hover {
+ background-color: #787878;
+}
+
+QSplitter::separator:horizontal {
+ width: 5px;
+ image: url(:/qss_icons/rc/Vsepartoolbar.png);
+}
+
+QSplitter::separator:vertical {
+ height: 5px;
+ image: url(:/qss_icons/rc/Hsepartoolbar.png);
+}
+
+
+/* QDateEdit-------------------------------------------------------------- */
+
+QDateEdit {
+ selection-background-color: #1464A0;
+ border-style: solid;
+ border: 1px solid #32414B;
+ border-radius: 4px;
+ padding-top: 2px; /* This fix #103, #111*/
+ padding-bottom: 2px; /* This fix #103, #111*/
+ padding-left: 4px;
+ padding-right: 4px;
+ min-width: 10px;
+}
+
+QDateEdit:on {
+ selection-background-color: #1464A0;
+}
+
+QDateEdit::drop-down {
+ subcontrol-origin: padding;
+ subcontrol-position: top right;
+ width: 20px;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+}
+
+QDateEdit::down-arrow {
+ image: url(:/qss_icons/rc/down_arrow_disabled.png);
+}
+
+QDateEdit::down-arrow:on,
+QDateEdit::down-arrow:hover,
+QDateEdit::down-arrow:focus {
+ image: url(:/qss_icons/rc/down_arrow.png);
+}
+
+QDateEdit QAbstractItemView {
+ background-color: #19232D;
+ border-radius: 4px;
+ border: 1px solid #32414B;
+ selection-background-color: #1464A0;
+}
+
+QAbstractView:hover{
+ border: 1px solid #148CD2;
+ color: #F0F0F0;
+}
+
+QAbstractView:selected {
+ background: #1464A0;
+ color: #32414B;
+}
+
+
+PlotWidget {
+ padding: 0px; /* to fix cut labels in plots #134 */
+}
diff --git a/src/QuickCut/Styles/theme_elegantDark.qss b/src/QuickCut/Styles/theme_elegantDark.qss
new file mode 100644
index 0000000..49d2b0b
--- /dev/null
+++ b/src/QuickCut/Styles/theme_elegantDark.qss
@@ -0,0 +1,196 @@
+/*
+ElegantDark Style Sheet for QT Applications
+Author: Jaime A. Quiroga P.
+Company: GTRONICK
+Last updated: 17/04/2018
+Available at: https://github.com/GTRONICK/QSS/blob/master/ElegantDark.qss
+*/
+QMainWindow {
+ background-color:rgb(82, 82, 82);
+}
+QTextEdit {
+ background-color:rgb(42, 42, 42);
+ color: rgb(0, 255, 0);
+}
+QPushButton{
+ border-style: outset;
+ border-width: 2px;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-bottom-color: rgb(58, 58, 58);
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: rgb(255, 255, 255);
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(77, 77, 77, 255), stop:1 rgba(97, 97, 97, 255));
+}
+QPushButton:hover{
+ border-style: outset;
+ border-width: 2px;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(180, 180, 180, 255), stop:1 rgba(110, 110, 110, 255));
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(180, 180, 180, 255), stop:1 rgba(110, 110, 110, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(180, 180, 180, 255), stop:1 rgba(110, 110, 110, 255));
+ border-bottom-color: rgb(115, 115, 115);
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: rgb(255, 255, 255);
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(107, 107, 107, 255), stop:1 rgba(157, 157, 157, 255));
+}
+QPushButton:pressed{
+ border-style: outset;
+ border-width: 2px;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(62, 62, 62, 255), stop:1 rgba(22, 22, 22, 255));
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-bottom-color: rgb(58, 58, 58);
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: rgb(255, 255, 255);
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(77, 77, 77, 255), stop:1 rgba(97, 97, 97, 255));
+}
+QPushButton:disabled{
+ border-style: outset;
+ border-width: 2px;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-bottom-color: rgb(58, 58, 58);
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: rgb(0, 0, 0);
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(57, 57, 57, 255), stop:1 rgba(77, 77, 77, 255));
+}
+QLineEdit {
+ border-width: 1px; border-radius: 4px;
+ border-color: rgb(58, 58, 58);
+ border-style: inset;
+ padding: 0 8px;
+ color: rgb(255, 255, 255);
+ background:rgb(100, 100, 100);
+ selection-background-color: rgb(187, 187, 187);
+ selection-color: rgb(60, 63, 65);
+}
+QLabel {
+ color:rgb(255,255,255);
+}
+QProgressBar {
+ text-align: center;
+ color: rgb(240, 240, 240);
+ border-width: 1px;
+ border-radius: 10px;
+ border-color: rgb(58, 58, 58);
+ border-style: inset;
+ background-color:rgb(77,77,77);
+}
+QProgressBar::chunk {
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:0.7, x2:0.5, y2:0.3, stop:0 rgba(87, 97, 106, 255), stop:1 rgba(93, 103, 113, 255));
+ border-radius: 5px;
+}
+QMenuBar {
+ background:rgb(82, 82, 82);
+}
+QMenuBar::item {
+ color:rgb(223,219,210);
+ spacing: 3px;
+ padding: 1px 4px;
+ background: transparent;
+}
+
+QMenuBar::item:selected {
+ background:rgb(115, 115, 115);
+}
+QMenu::item:selected {
+ color:rgb(255,255,255);
+ border-width:2px;
+ border-style:solid;
+ padding-left:18px;
+ padding-right:8px;
+ padding-top:2px;
+ padding-bottom:3px;
+ background:qlineargradient(spread:pad, x1:0.5, y1:0.7, x2:0.5, y2:0.3, stop:0 rgba(87, 97, 106, 255), stop:1 rgba(93, 103, 113, 255));
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(62, 62, 62, 255));
+ border-bottom-color: rgb(58, 58, 58);
+ border-bottom-width: 1px;
+}
+QMenu::item {
+ color:rgb(223,219,210);
+ background-color:rgb(78,78,78);
+ padding-left:20px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:10px;
+}
+QMenu{
+ background-color:rgb(78,78,78);
+}
+QTabWidget {
+ color:rgb(0,0,0);
+ background-color:rgb(247,246,246);
+}
+QTabWidget::pane {
+ border-color: rgb(77,77,77);
+ background-color:rgb(101,101,101);
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 6px;
+}
+QTabBar::tab {
+ padding:2px;
+ color:rgb(250,250,250);
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(77, 77, 77, 255), stop:1 rgba(97, 97, 97, 255));
+ border-style: solid;
+ border-width: 2px;
+ border-top-right-radius:4px;
+ border-top-left-radius:4px;
+ border-top-color: qlineargradient(spread:pad, x1:0.5, y1:0.6, x2:0.5, y2:0.4, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(95, 92, 93, 255));
+ border-right-color: qlineargradient(spread:pad, x1:0.4, y1:0.5, x2:0.6, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(95, 92, 93, 255));
+ border-left-color: qlineargradient(spread:pad, x1:0.6, y1:0.5, x2:0.4, y2:0.5, stop:0 rgba(115, 115, 115, 255), stop:1 rgba(95, 92, 93, 255));
+ border-bottom-color: rgb(101,101,101);
+}
+QTabBar::tab:selected, QTabBar::tab:last:selected, QTabBar::tab:hover {
+ background-color:rgb(101,101,101);
+ margin-left: 0px;
+ margin-right: 1px;
+}
+QTabBar::tab:!selected {
+ margin-top: 1px;
+ margin-right: 1px;
+}
+QCheckBox {
+ color:rgb(223,219,210);
+ padding: 2px;
+}
+QCheckBox:hover {
+ border-radius:4px;
+ border-style:solid;
+ padding-left: 1px;
+ padding-right: 1px;
+ padding-bottom: 1px;
+ padding-top: 1px;
+ border-width:1px;
+ border-color: rgb(87, 97, 106);
+ background-color:qlineargradient(spread:pad, x1:0.5, y1:0.7, x2:0.5, y2:0.3, stop:0 rgba(87, 97, 106, 150), stop:1 rgba(93, 103, 113, 150));
+}
+QCheckBox::indicator:checked {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ border-color: rgb(180,180,180);
+ background-color:qlineargradient(spread:pad, x1:0.5, y1:0.7, x2:0.5, y2:0.3, stop:0 rgba(87, 97, 106, 255), stop:1 rgba(93, 103, 113, 255));
+}
+QCheckBox::indicator:unchecked {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ border-color: rgb(87, 97, 106);
+ background-color:rgb(255,255,255);
+}
+QStatusBar {
+ color:rgb(240,240,240);
+}
diff --git a/src/QuickCut/Styles/theme_materialDark.qss b/src/QuickCut/Styles/theme_materialDark.qss
new file mode 100644
index 0000000..c5a94aa
--- /dev/null
+++ b/src/QuickCut/Styles/theme_materialDark.qss
@@ -0,0 +1,390 @@
+/*
+Material Dark Style Sheet for QT Applications
+Author: Jaime A. Quiroga P.
+Inspired on https://github.com/jxfwinter/qt-material-stylesheet
+Company: GTRONICK
+Last updated: 04/12/2018, 15:00.
+Available at: https://github.com/GTRONICK/QSS/blob/master/MaterialDark.qss
+*/
+QMainWindow {
+ background-color:#1e1d23;
+}
+QDialog {
+ background-color:#1e1d23;
+}
+QColorDialog {
+ background-color:#1e1d23;
+}
+QTextEdit {
+ background-color:#1e1d23;
+ color: #a9b7c6;
+}
+QPlainTextEdit {
+ selection-background-color:#007b50;
+ background-color:#1e1d23;
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ border-width: 1px;
+ color: #a9b7c6;
+}
+QPushButton{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ border-width: 1px;
+ border-style: solid;
+ color: #a9b7c6;
+ padding: 2px;
+ background-color: #1e1d23;
+}
+QPushButton::default{
+ border-style: inset;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #04b97f;
+ border-width: 1px;
+ color: #a9b7c6;
+ padding: 2px;
+ background-color: #1e1d23;
+}
+QToolButton {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #04b97f;
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: #a9b7c6;
+ padding: 2px;
+ background-color: #1e1d23;
+}
+QToolButton:hover{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #37efba;
+ border-bottom-width: 2px;
+ border-style: solid;
+ color: #FFFFFF;
+ padding-bottom: 1px;
+ background-color: #1e1d23;
+}
+QPushButton:hover{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #37efba;
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: #FFFFFF;
+ padding-bottom: 2px;
+ background-color: #1e1d23;
+}
+QPushButton:pressed{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #37efba;
+ border-bottom-width: 2px;
+ border-style: solid;
+ color: #37efba;
+ padding-bottom: 1px;
+ background-color: #1e1d23;
+}
+QPushButton:disabled{
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #808086;
+ border-bottom-width: 2px;
+ border-style: solid;
+ color: #808086;
+ padding-bottom: 1px;
+ background-color: #1e1d23;
+}
+QLineEdit {
+ border-width: 1px; border-radius: 4px;
+ border-color: rgb(58, 58, 58);
+ border-style: inset;
+ padding: 0 8px;
+ color: #a9b7c6;
+ background:#1e1d23;
+ selection-background-color:#007b50;
+ selection-color: #FFFFFF;
+}
+QLabel {
+ color: #a9b7c6;
+}
+QLCDNumber {
+ color: #37e6b4;
+}
+QProgressBar {
+ text-align: center;
+ color: rgb(240, 240, 240);
+ border-width: 1px;
+ border-radius: 10px;
+ border-color: rgb(58, 58, 58);
+ border-style: inset;
+ background-color:#1e1d23;
+}
+QProgressBar::chunk {
+ background-color: #04b97f;
+ border-radius: 5px;
+}
+QMenuBar {
+ background-color: #1e1d23;
+}
+QMenuBar::item {
+ color: #a9b7c6;
+ spacing: 3px;
+ padding: 1px 4px;
+ background: #1e1d23;
+}
+
+QMenuBar::item:selected {
+ background:#1e1d23;
+ color: #FFFFFF;
+}
+QMenu::item:selected {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: #04b97f;
+ border-bottom-color: transparent;
+ border-left-width: 2px;
+ color: #FFFFFF;
+ padding-left:15px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:7px;
+ background-color: #1e1d23;
+}
+QMenu::item {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: #a9b7c6;
+ padding-left:17px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:7px;
+ background-color: #1e1d23;
+}
+QMenu{
+ background-color:#1e1d23;
+}
+QTabWidget {
+ color:rgb(0,0,0);
+ background-color:#1e1d23;
+}
+QTabWidget::pane {
+ border-color: rgb(77,77,77);
+ background-color:#1e1d23;
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 6px;
+}
+QTabBar::tab {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: transparent;
+ border-bottom-width: 1px;
+ border-style: solid;
+ color: #808086;
+ padding: 3px;
+ margin-left:3px;
+ background-color: #1e1d23;
+}
+QTabBar::tab:selected, QTabBar::tab:last:selected, QTabBar::tab:hover {
+ border-style: solid;
+ border-top-color: transparent;
+ border-right-color: transparent;
+ border-left-color: transparent;
+ border-bottom-color: #04b97f;
+ border-bottom-width: 2px;
+ border-style: solid;
+ color: #FFFFFF;
+ padding-left: 3px;
+ padding-bottom: 2px;
+ margin-left:3px;
+ background-color: #1e1d23;
+}
+
+QCheckBox {
+ color: #a9b7c6;
+ padding: 2px;
+}
+QCheckBox:disabled {
+ color: #808086;
+ padding: 2px;
+}
+
+QCheckBox:hover {
+ border-radius:4px;
+ border-style:solid;
+ padding-left: 1px;
+ padding-right: 1px;
+ padding-bottom: 1px;
+ padding-top: 1px;
+ border-width:1px;
+ border-color: rgb(87, 97, 106);
+ background-color:#1e1d23;
+}
+QCheckBox::indicator:checked {
+
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-width: 1px;
+ border-color: #04b97f;
+ color: #a9b7c6;
+ background-color: #04b97f;
+}
+QCheckBox::indicator:unchecked {
+
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-width: 1px;
+ border-color: #04b97f;
+ color: #a9b7c6;
+ background-color: transparent;
+}
+QRadioButton {
+ color: #a9b7c6;
+ background-color: #1e1d23;
+ padding: 1px;
+}
+QRadioButton::indicator:checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: #04b97f;
+ color: #a9b7c6;
+ background-color: #04b97f;
+}
+QRadioButton::indicator:!checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: #04b97f;
+ color: #a9b7c6;
+ background-color: transparent;
+}
+QStatusBar {
+ color:#027f7f;
+}
+QSpinBox {
+ color: #a9b7c6;
+ background-color: #1e1d23;
+}
+QDoubleSpinBox {
+ color: #a9b7c6;
+ background-color: #1e1d23;
+}
+QTimeEdit {
+ color: #a9b7c6;
+ background-color: #1e1d23;
+}
+QDateTimeEdit {
+ color: #a9b7c6;
+ background-color: #1e1d23;
+}
+QDateEdit {
+ color: #a9b7c6;
+ background-color: #1e1d23;
+}
+QComboBox {
+ color: #a9b7c6;
+ background: #1e1d23;
+}
+QComboBox:editable {
+ background: #1e1d23;
+ color: #a9b7c6;
+ selection-background-color: #1e1d23;
+}
+QComboBox QAbstractItemView {
+ color: #a9b7c6;
+ background: #1e1d23;
+ selection-color: #FFFFFF;
+ selection-background-color: #1e1d23;
+}
+QComboBox:!editable:on, QComboBox::drop-down:editable:on {
+ color: #a9b7c6;
+ background: #1e1d23;
+}
+QFontComboBox {
+ color: #a9b7c6;
+ background-color: #1e1d23;
+}
+QToolBox {
+ color: #a9b7c6;
+ background-color: #1e1d23;
+}
+QToolBox::tab {
+ color: #a9b7c6;
+ background-color: #1e1d23;
+}
+QToolBox::tab:selected {
+ color: #FFFFFF;
+ background-color: #1e1d23;
+}
+QScrollArea {
+ color: #FFFFFF;
+ background-color: #1e1d23;
+}
+QSlider::groove:horizontal {
+ height: 5px;
+ background: #04b97f;
+}
+QSlider::groove:vertical {
+ width: 5px;
+ background: #04b97f;
+}
+QSlider::handle:horizontal {
+ background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #b4b4b4, stop:1 #8f8f8f);
+ border: 1px solid #5c5c5c;
+ width: 14px;
+ margin: -5px 0;
+ border-radius: 7px;
+}
+QSlider::handle:vertical {
+ background: qlineargradient(x1:1, y1:1, x2:0, y2:0, stop:0 #b4b4b4, stop:1 #8f8f8f);
+ border: 1px solid #5c5c5c;
+ height: 14px;
+ margin: 0 -5px;
+ border-radius: 7px;
+}
+QSlider::add-page:horizontal {
+ background: white;
+}
+QSlider::add-page:vertical {
+ background: white;
+}
+QSlider::sub-page:horizontal {
+ background: #04b97f;
+}
+QSlider::sub-page:vertical {
+ background: #04b97f;
+}
diff --git a/src/QuickCut/Styles/theme_ubuntu.qss b/src/QuickCut/Styles/theme_ubuntu.qss
new file mode 100644
index 0000000..2e4a99e
--- /dev/null
+++ b/src/QuickCut/Styles/theme_ubuntu.qss
@@ -0,0 +1,564 @@
+/*
+Ubuntu Style Sheet for QT Applications
+Author: Jaime A. Quiroga P.
+Company: GTRONICK
+Last updated: 21/01/2019, 12:31.
+Available at: https://github.com/GTRONICK/QSS/blob/master/Ubuntu.qss
+*/
+QMainWindow {
+ background-color:#f0f0f0;
+}
+QDialog {
+ background-color:#f0f0f0;
+}
+QColorDialog {
+ background-color:#f0f0f0;
+}
+QLabel {
+ color:rgb(17,17,17);
+}
+QLineEdit {
+ background-color:rgb(255,255,255);
+ selection-background-color:rgb(236,116,64);
+ color:rgb(17,17,17);
+}
+QTextEdit {
+ border-width: 1px;
+ border-style: solid;
+ border-color:transparent;
+ color:rgb(17,17,17);
+ selection-background-color:rgb(236,116,64);
+}
+QPlainTextEdit {
+ border-width: 1px;
+ border-style: solid;
+ border-color:transparent;
+ color:rgb(17,17,17);
+ selection-background-color:rgb(236,116,64);
+}
+QPushButton{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius: 6px;
+ border-bottom-color: rgb(150,150,150);
+ border-right-color: rgb(165,165,165);
+ border-left-color: rgb(165,165,165);
+ border-top-color: rgb(180,180,180);
+ border-style: solid;
+ padding: 4px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:hover{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius:6px;
+ border-top-color: rgb(255,150,60);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-bottom-color: rgb(200,70,20);
+ border-style: solid;
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:default{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius:6px;
+ border-top-color: rgb(255,150,60);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-bottom-color: rgb(200,70,20);
+ border-style: solid;
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:pressed{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius: 6px;
+ border-width: 1px;
+ border-top-color: rgba(255,150,60,200);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 200));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 200));
+ border-bottom-color: rgba(200,70,20,200);
+ border-style: solid;
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:disabled{
+ color:rgb(174,167,159);
+ border-width: 1px;
+ border-radius: 6px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(200, 200, 200, 255), stop:1 rgba(230, 230, 230, 255));
+}
+QProgressBar {
+ text-align: center;
+ color: rgb(0, 0, 0);
+ border-width: 1px;
+ border-radius: 10px;
+ border-style: inset;
+ border-color: rgb(150,150,150);
+ background-color:rgb(221,221,219);
+}
+QProgressBar::chunk:horizontal {
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(225, 108, 54, 255), stop:1 rgba(246, 134, 86, 255));
+ border-style: solid;
+ border-radius:8px;
+ border-width:1px;
+ border-bottom-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(175,85,48,255), stop:1 rgba(236,114,67, 255));
+ border-top-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-right-color:qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-left-color:qlineargradient(spread:pad, x1:1, y1:0.5, x2:0, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+}
+QTabWidget {
+ color:rgb(0,0,0);
+ background-color:rgb(247,246,246);
+}
+QTabWidget::pane {
+ border-color: rgb(180,180,180);
+ background-color:rgb(247,246,246);
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 6px;
+}
+QTabBar::tab {
+ padding-left:4px;
+ padding-right:4px;
+ padding-bottom:2px;
+ padding-top:2px;
+ color:rgb(81,72,65);
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(221,218,217,255), stop:1 rgba(240,239,238,255));
+ border-style: solid;
+ border-width: 1px;
+ border-top-right-radius:4px;
+ border-top-left-radius:4px;
+ border-top-color: rgb(180,180,180);
+ border-left-color: rgb(180,180,180);
+ border-right-color: rgb(180,180,180);
+ border-bottom-color: transparent;
+}
+QTabBar::tab:selected, QTabBar::tab:last:selected, QTabBar::tab:hover {
+ background-color:rgb(247,246,246);
+ margin-left: 0px;
+ margin-right: 1px;
+}
+QTabBar::tab:!selected {
+ margin-top: 1px;
+ margin-right: 1px;
+}
+QMenuBar {
+ color:rgb(223,219,210);
+ background-color:rgb(65,64,59);
+}
+QMenuBar::item {
+ padding-top:4px;
+ padding-left:4px;
+ padding-right:4px;
+ color:rgb(223,219,210);
+ background-color:rgb(65,64,59);
+}
+QMenuBar::item:selected {
+ color:rgb(255,255,255);
+ padding-top:2px;
+ padding-left:2px;
+ padding-right:2px;
+ border-top-width:2px;
+ border-left-width:2px;
+ border-right-width:2px;
+ border-top-right-radius:4px;
+ border-top-left-radius:4px;
+ border-style:solid;
+ background-color:rgb(65,64,59);
+ border-top-color: rgb(47,47,44);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(90, 87, 78, 255), stop:1 rgba(47,47,44, 255));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(90, 87, 78, 255), stop:1 rgba(47,47,44, 255));
+}
+QMenu::item:selected {
+ color:rgb(255,255,255);
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(225, 108, 54, 255), stop:1 rgba(246, 134, 86, 255));
+ border-style:solid;
+ border-width:3px;
+ padding-left:17px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:7px;
+ border-bottom-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(175,85,48,255), stop:1 rgba(236,114,67, 255));
+ border-top-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-right-color:qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-left-color:qlineargradient(spread:pad, x1:1, y1:0.5, x2:0, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+}
+QMenu::item {
+ color:rgb(223,219,210);
+ padding-left:20px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:10px;
+}
+QMenu {
+ color:rgb(223,219,210);
+ background-color:rgb(65,64,59);
+}
+QCheckBox {
+ padding:2px;
+}
+QCheckBox:hover {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ padding-left: 1px;
+ padding-right: 1px;
+ padding-bottom: 1px;
+ padding-top: 1px;
+ border-color: rgb(255,150,60);
+ background-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(190, 90, 50, 50), stop:1 rgba(250, 130, 40, 50));
+}
+QCheckBox::indicator:checked {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ border-color: rgb(246, 134, 86);
+ background-color:rgb(246, 134, 86)
+}
+QCheckBox::indicator:unchecked {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ border-color:rgb(246, 134, 86);
+ background-color:rgb(255,255,255);
+}
+QRadioButton {
+ padding: 1px;
+}
+QRadioButton::indicator:checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: rgba(246, 134, 86, 255);
+ color: #a9b7c6;
+ background-color:rgba(246, 134, 86, 255);
+}
+QRadioButton::indicator:!checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: rgb(246, 134, 86);
+ color: #a9b7c6;
+ background-color: transparent;
+}
+QStatusBar {
+ color:rgb(81,72,65);
+}
+QSpinBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QDoubleSpinBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QTimeEdit {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QDateTimeEdit {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QDateEdit {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QComboBox {
+ color:rgb(81,72,65);
+ background: #ffffff;
+}
+QComboBox:editable {
+ background: #ffffff;
+ color: rgb(81,72,65);
+ selection-color:rgb(81,72,65);
+ selection-background-color: #ffffff;
+}
+QComboBox QAbstractItemView {
+ color:rgb(81,72,65);
+ background: #ffffff;
+ selection-color: #ffffff;
+ selection-background-color: rgb(246, 134, 86);
+}
+QComboBox:!editable:on, QComboBox::drop-down:editable:on {
+ color: #1e1d23;
+ background: #ffffff;
+}
+QFontComboBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QToolBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QToolBox::tab {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QToolBox::tab:selected {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QScrollArea {
+ color: #FFFFFF;
+ background-color:#f0f0f0;
+}
+QSlider::groove {
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+}
+QSlider::groove:horizontal {
+ height: 5px;
+ background: rgb(246, 134, 86);
+}
+QSlider::groove:vertical {
+ width: 5px;
+ background: rgb(246, 134, 86);
+}
+QSlider::handle:horizontal {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ width: 12px;
+ margin: -5px 0;
+ border-radius: 7px;
+}
+QSlider::handle:vertical {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ height: 12px;
+ margin: 0 -5px;
+ border-radius: 7px;
+}
+QSlider::add-page:horizontal {
+ background: white;
+}
+QSlider::add-page:vertical {
+ background: white;
+}
+QSlider::sub-page:horizontal {
+ background: rgb(246, 134, 86);
+}
+QSlider::sub-page:vertical {
+ background: rgb(246, 134, 86);
+}
+QScrollBar:horizontal {
+ max-height: 20px;
+ border: 1px transparent grey;
+ margin: 0px 20px 0px 20px;
+}
+QScrollBar::handle:horizontal {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ border-radius: 7px;
+ min-width: 25px;
+}
+QScrollBar::handle:horizontal:hover {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(255,150,60);
+ border-radius: 7px;
+ min-width: 25px;
+}
+QScrollBar::add-line:horizontal {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:horizontal:hover {
+ border: 1px solid;
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ border-color: rgb(255,150,60);
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:horizontal:pressed {
+ border: 1px solid grey;
+ border-top-left-radius: 7px;
+ border-top-right-radius: 7px;
+ border-bottom-right-radius: 7px;
+ background: rgb(231,231,231);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal:hover {
+ border: 1px solid;
+ border-color: rgb(255,150,60);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal:pressed {
+ border: 1px solid grey;
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(231,231,231);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::left-arrow:horizontal {
+ border: 1px transparent grey;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::right-arrow:horizontal {
+ border: 1px transparent grey;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
+ background: none;
+}
+QScrollBar:vertical {
+ max-width: 20px;
+ border: 1px transparent grey;
+ margin: 20px 0px 20px 0px;
+}
+QScrollBar::add-line:vertical {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-bottom-right-radius: 7px;
+ border-bottom-left-radius: 7px;
+ border-top-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:vertical:hover {
+ border: 1px solid;
+ border-color: rgb(255,150,60);
+ border-bottom-right-radius: 7px;
+ border-bottom-left-radius: 7px;
+ border-top-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:vertical:pressed {
+ border: 1px solid grey;
+ border-bottom-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ border-top-left-radius: 7px;
+ background: rgb(231,231,231);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical:hover {
+ border: 1px solid;
+ border-color: rgb(255,150,60);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical:pressed {
+ border: 1px solid grey;
+ border-top-left-radius: 7px;
+ border-top-right-radius: 7px;
+ background: rgb(231,231,231);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+ QScrollBar::handle:vertical {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ border-radius: 7px;
+ min-height: 25px;
+}
+QScrollBar::handle:vertical:hover {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(255,150,60);
+ border-radius: 7px;
+ min-height: 25px;
+}
+QScrollBar::up-arrow:vertical {
+ border: 1px transparent grey;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::down-arrow:vertical {
+ border: 1px transparent grey;
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
+ background: none;
+}
diff --git a/src/QuickCut/main.cpp b/src/QuickCut/main.cpp
new file mode 100644
index 0000000..a0b8982
--- /dev/null
+++ b/src/QuickCut/main.cpp
@@ -0,0 +1,19 @@
+
+#include
+#include "MainWindow.h"
+#include "QSingleApplication/QSingleInstance.h"
+
+
+int main(int argc, char *argv[])
+{
+ QSingleInstance instance("8c06d447-da32-447c-adfd-2d227605ae4b");
+ if (!instance.tryToRun())
+ {
+ return 0;
+ }
+
+ QApplication a(argc, argv);
+ MainWindow w;
+ w.show();
+ return a.exec();
+}
diff --git a/src/QuickCutConsole/QuickCutConsole.cpp b/src/QuickCutConsole/QuickCutConsole.cpp
new file mode 100644
index 0000000..1a14003
--- /dev/null
+++ b/src/QuickCutConsole/QuickCutConsole.cpp
@@ -0,0 +1,134 @@
+
+#include "QuickCutConsole.h"
+#include "pch.h"
+#include "Profile.h"
+
+#include
+#include
+#include
+#include
+
+
+QuickCutConsole * QuickCutConsole::s_pInstance = nullptr;
+
+std::unique_ptr QuickCutConsole::s_pProfile = nullptr;
+String QuickCutConsole::s_qszProfilesPath;
+
+QuickCutConsole::QuickCutConsole(int argc, char * argv[])
+ : QCoreApplication(argc, argv)
+{
+ if (!s_pInstance)
+ s_pInstance = this;
+}
+
+QuickCutConsole::~QuickCutConsole()
+{ }
+
+bool QuickCutConsole::start()
+{
+ // The QuickCut GUI every changes are made to our profiles, we'll restart the service to reload profiles.
+ if (!loadProfiles())
+ return false;
+
+ return true;
+}
+
+
+bool QuickCutConsole::stop()
+{
+ return true;
+}
+
+bool QuickCutConsole::loadProfiles()
+{
+ QFileInfo fiProfiles(applicationDirPath() + "/Config/profiles.json");
+ if (!fiProfiles.exists())
+ {
+ qDebug() << "[QuickCutConsole::loadProfiles] - Profiles file not found: " << fiProfiles.filePath();
+ return false;
+ }
+
+ s_qszProfilesPath = fiProfiles.filePath().toStdString();
+
+ JSON rootJson;
+ bpt::read_json(s_qszProfilesPath, rootJson);
+ String szActiveProfile = rootJson.get("activeProfile", "");
+
+ JSON profilesJson = rootJson.get_child("profiles");
+ for (auto && profileJson : profilesJson)
+ {
+ String profileId = profileJson.second.get("id", "");
+ if (profileId != szActiveProfile) continue;
+
+ String profileName = profileJson.second.get("name", "");
+ String lastModified = profileJson.second.get("lastModified", "");
+ int actionsCount = profileJson.second.get("actionsCount", 0);
+
+ s_pProfile = std::make_unique(profileId, profileName, lastModified);
+ s_pProfile->setActionsCapacity(actionsCount);
+
+ JSON actionsJson = profileJson.second.get_child("actions");
+ for (auto && actionJson : actionsJson)
+ {
+ String actionId = actionJson.second.get("id", "");
+ String actionName = actionJson.second.get("actionName", "");
+ String actionType = actionJson.second.get("type", "");
+ String srcKey = actionJson.second.get("srcKey", "");
+ String dstKey = actionJson.second.get("dstKey", "");
+ String appPath = actionJson.second.get("appPath", "");
+ String appArgs = actionJson.second.get("appArgs", "");
+ String createdDate = actionJson.second.get("createdDate", "");
+
+ s_pProfile->addAction(new Action(actionId, actionName,
+ Action::getType(actionType), srcKey, dstKey,
+ appPath, appArgs, createdDate));
+ }
+
+ break;
+ }
+
+ return true;
+}
+
+void QuickCutConsole::executeProcess(const std::string & szProc, const std::string & szArgs)
+{
+ // QProc won't expand environment variable strings.
+ // Invoking using the user console will allow for expanded string to work as expected.
+#ifdef Q_OS_WIN
+ QString szCommand = "cmd /c start \"\" \"" + QString::fromStdString(szProc) + "\"";
+ QString szExt = ".cmd";
+#elif Q_OS_UNIX
+ QString szCommand = "sh -c '" + QString::fromStdString(szProc) + "'";
+ QString szExt = ".sh";
+#endif
+
+ QStringList qArgsTmp = QString::fromStdString(szArgs).trimmed().split(",");
+ for (auto && arg : qArgsTmp)
+ {
+ QString argTrimmed = arg.trimmed();
+ if (argTrimmed.isEmpty()) continue;
+
+ szCommand += " " + argTrimmed;
+ }
+ qDebug() << "[QuickCutConsole::executeProcess] - Execute Command: " << szCommand;
+
+ QString szFilePath = applicationDirPath() + "/tempCmd" + szExt;
+ QFile file(szFilePath);
+ file.open(QIODevice::ReadWrite);
+ QTextStream ts(&file);
+ ts << szCommand;
+ file.close();
+ QProcess::execute(szFilePath);
+ file.remove();
+}
+
+void QuickCutConsole::log(const QString & szFilePath, const QString & szMessage)
+{
+ QFile file(szFilePath);
+ file.open(QFile::WriteOnly);
+ QTextStream text(&file);
+ text << szMessage;
+ file.flush();
+ file.close();
+}
+
diff --git a/src/QuickCutConsole/QuickCutConsole.h b/src/QuickCutConsole/QuickCutConsole.h
new file mode 100644
index 0000000..d71367c
--- /dev/null
+++ b/src/QuickCutConsole/QuickCutConsole.h
@@ -0,0 +1,27 @@
+
+#pragma once
+
+#include
+
+
+class QuickCutConsole : public QCoreApplication
+{
+
+public:
+ QuickCutConsole(int argc, char * argv[]);
+ virtual ~QuickCutConsole();
+
+ virtual bool start();
+ virtual bool stop();
+
+ static bool loadProfiles();
+ static void executeProcess(const std::string & szProc, const std::string & szArgs);
+ static void log(const QString & szFilePath, const QString & szMessage);
+
+
+public:
+ static QuickCutConsole * s_pInstance;
+ static std::unique_ptr s_pProfile;
+ static std::string s_qszProfilesPath;
+
+};
diff --git a/src/QuickCutConsole/QuickCutConsole.vcxproj b/src/QuickCutConsole/QuickCutConsole.vcxproj
new file mode 100644
index 0000000..bdcef37
--- /dev/null
+++ b/src/QuickCutConsole/QuickCutConsole.vcxproj
@@ -0,0 +1,229 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {B741AF33-8F2D-4FC3-A9BA-FB36FA4A98A1}
+ Qt4VSv1.0
+ 10.0.18362.0
+
+
+
+ Application
+ v141
+
+
+ Application
+ v141
+
+
+ Application
+ v141
+
+
+ Application
+ v141
+
+
+
+ $(MSBuildProjectDirectory)\QtMsBuild
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;%(PreprocessorDefinitions)
+ Disabled
+ ProgramDatabase
+ MultiThreadedDebugDLL
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ true
+ stdcpp17
+
+
+ Console
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ true
+ qtmaind.lib;Qt5Cored.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;%(PreprocessorDefinitions)
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;%(PreprocessorDefinitions)
+ Disabled
+ ProgramDatabase
+ MultiThreadedDebugDLL
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ true
+ stdcpp17
+
+
+ Console
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ true
+ qtmaind.lib;Qt5Cored.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;%(PreprocessorDefinitions)
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions)
+
+ MultiThreadedDLL
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ true
+ stdcpp17
+
+
+ Windows
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ false
+ qtmain.lib;Qt5Core.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions)
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions)
+
+
+ MultiThreadedDLL
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ true
+ stdcpp17
+
+
+ Windows
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ false
+ qtmain.lib;Qt5Core.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions)
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/QuickCutConsole/QuickCutConsole.vcxproj.filters b/src/QuickCutConsole/QuickCutConsole.vcxproj.filters
new file mode 100644
index 0000000..e4fb8d4
--- /dev/null
+++ b/src/QuickCutConsole/QuickCutConsole.vcxproj.filters
@@ -0,0 +1,64 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}
+ qrc;*
+ false
+
+
+ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}
+ qrc;*
+ false
+
+
+ {2c3a65d4-0238-45b6-9986-dce6e3459f29}
+
+
+
+
+ Source Files
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+
+
\ No newline at end of file
diff --git a/src/QuickCutConsole/QuickCutConsole.vcxproj.user b/src/QuickCutConsole/QuickCutConsole.vcxproj.user
new file mode 100644
index 0000000..3406071
--- /dev/null
+++ b/src/QuickCutConsole/QuickCutConsole.vcxproj.user
@@ -0,0 +1,28 @@
+
+
+
+
+ C:\Qt\5.12.0\msvc2017
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ WindowsLocalDebugger
+ PATH=$(QTDIR)\bin%3b$(PATH)
+
+
+ C:\Qt\5.12.0\msvc2017_64
+ PATH=$(QTDIR)\bin%3b$(PATH)
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ WindowsLocalDebugger
+
+
+ C:\Qt\5.12.0\msvc2017
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ WindowsLocalDebugger
+ PATH=$(QTDIR)\bin%3b$(PATH)
+
+
+ C:\Qt\5.12.0\msvc2017_64
+ PATH=$(QTDIR)\bin%3b$(PATH)
+ $(SolutionDir)$(Platform)\$(Configuration)\
+ WindowsLocalDebugger
+
+
\ No newline at end of file
diff --git a/src/QuickCutConsole/QuickCutConsoleUnix.cpp b/src/QuickCutConsole/QuickCutConsoleUnix.cpp
new file mode 100644
index 0000000..f238529
--- /dev/null
+++ b/src/QuickCutConsole/QuickCutConsoleUnix.cpp
@@ -0,0 +1,39 @@
+
+
+#include "QuickCutConsoleUnix.h"
+#include "pch.h"
+#include "Profile.h"
+
+#include
+#include
+#include
+#include
+
+
+QuickCutConsoleUnix::QuickCutConsoleUnix(int argc, char * argv[])
+ : QuickCutConsole(argc, argv)
+{
+ s_pInstance = this;
+}
+
+QuickCutConsoleUnix::~QuickCutConsoleUnix()
+{ }
+
+
+bool QuickCutConsoleUnix::start()
+{
+ if (!QuickCutConsole::start())
+ return false;
+
+ // TODO: Implement hook.
+
+ return true;
+}
+
+bool QuickCutConsoleUnix::stop()
+{
+ if (!QuickCutConsole::stop())
+ return false;
+
+ return true;
+}
diff --git a/src/QuickCutConsole/QuickCutConsoleUnix.h b/src/QuickCutConsole/QuickCutConsoleUnix.h
new file mode 100644
index 0000000..bae925d
--- /dev/null
+++ b/src/QuickCutConsole/QuickCutConsoleUnix.h
@@ -0,0 +1,19 @@
+
+#pragma once
+
+#include "QuickCutConsole.h"
+
+
+class QuickCutConsoleUnix : public QuickCutConsole
+{
+
+public:
+ QuickCutConsoleUnix(int argc, char * argv[]);
+ ~QuickCutConsoleUnix();
+
+ bool start() override;
+ bool stop() override;
+
+public:
+
+};
diff --git a/src/QuickCutConsole/QuickCutConsoleWindows.cpp b/src/QuickCutConsole/QuickCutConsoleWindows.cpp
new file mode 100644
index 0000000..c0ab90e
--- /dev/null
+++ b/src/QuickCutConsole/QuickCutConsoleWindows.cpp
@@ -0,0 +1,181 @@
+
+
+#include "QuickCutConsoleWindows.h"
+#include "pch.h"
+#include "Profile.h"
+
+#include
+#include
+#include
+#include
+
+
+// The GUI will send this pattern of key codes to notify that profile changes has been made
+// so it knows when to reload the profile data.
+#define RESERVED_RELOAD_KEY "82818281"
+
+#define KEY_WAS_DOWN_MASK 0x80
+#define KEY_IS_DOWN_MASK 0x01
+
+HHOOK QuickCutConsoleWindows::s_hHook = nullptr;
+
+
+QuickCutConsoleWindows::QuickCutConsoleWindows(int argc, char * argv[])
+ : QuickCutConsole(argc, argv)
+{
+ s_pInstance = this;
+}
+
+QuickCutConsoleWindows::~QuickCutConsoleWindows()
+{
+ if (s_hHook)
+ {
+ qDebug() << "[QuickCutConsoleWindows::dtor] - Unhooking...";
+ UnhookWindowsHookEx(s_hHook);
+ s_hHook = nullptr;
+ }
+}
+
+LRESULT CALLBACK QuickCutConsoleWindows::WndProc(int nCode, WPARAM wParam, LPARAM lParam)
+{
+ if (nCode < 0)
+ return CallNextHookEx(s_hHook, nCode, wParam, lParam);
+
+ KBDLLHOOKSTRUCT * pKbd = reinterpret_cast(lParam);
+
+ static byte byKeys[256] = { 0 };
+ static QString szPressedKeys;
+ static bool bKeysProcessed = false;
+
+ // Workaround for auto-repeat, since low level hook doesn't provide KF_REPEAT flags in lParam:
+ // (lParam & KF_REPEAT)
+ static DWORD dwPrevVkCode = 0;
+
+ if (wParam == WM_KEYDOWN || wParam == WM_SYSKEYDOWN)
+ {
+ if (dwPrevVkCode == pKbd->vkCode)
+ return CallNextHookEx(s_hHook, nCode, wParam, lParam);
+
+ dwPrevVkCode = pKbd->vkCode;
+
+ if (bKeysProcessed)
+ {
+ szPressedKeys.clear();
+ bKeysProcessed = false;
+ }
+
+ szPressedKeys += QString::number(pKbd->vkCode, 16);
+ qDebug() << "Current Pressed Keys: " << szPressedKeys;
+
+ byKeys[pKbd->vkCode] = KEY_WAS_DOWN_MASK | KEY_IS_DOWN_MASK;
+ printKeyName(pKbd);
+
+
+ if (szPressedKeys == RESERVED_RELOAD_KEY)
+ {
+ loadProfiles();
+ qDebug() << "Refresh signal requested. Reloading profiles.";
+ return CallNextHookEx(s_hHook, nCode, wParam, lParam);
+ }
+
+ if (!s_pProfile)
+ {
+ return CallNextHookEx(s_hHook, nCode, wParam, lParam);
+ }
+
+ for (auto && action : s_pProfile->getActions())
+ {
+ if (szPressedKeys.toStdString() == action->getSrcKey())
+ {
+ qDebug() << "Pressed Keys Match!: " << szPressedKeys << " | Actual Keys: " << QString::fromStdString(action->getSrcKey());
+ eActionType eType = action->getType();
+ if (eType == ActionKeyMap)
+ {
+ qDebug() << "Mapping key -> " << szPressedKeys << " To -> " << QString::fromStdString(action->getDstKey());
+ szPressedKeys.clear(); // Make sure to clear keys before sending another key.
+ static int vkDstCode = 0;
+ vkDstCode = std::strtol(action->getDstKey().c_str(), nullptr, 16);
+
+ INPUT in = { 0 };
+ in.type = INPUT_KEYBOARD;
+ in.ki.wVk = vkDstCode;
+ SendInput(1, &in, sizeof(INPUT));
+
+ return -1; // Don't process the source input.
+ }
+ else if (eType == ActionAppStart)
+ {
+ qDebug() << "Running process -> " << QString::fromStdString(action->getAppPath()) << " With key -> " << szPressedKeys;
+ executeProcess(action->getAppPath(), action->getAppArgs());
+ }
+ }
+ } // end for
+ }
+
+ if (wParam == WM_KEYUP || wParam == WM_SYSKEYUP)
+ {
+ byKeys[pKbd->vkCode] = KEY_WAS_DOWN_MASK | KEY_IS_DOWN_MASK;
+
+ if (!bKeysProcessed)
+ {
+ dwPrevVkCode = 0;
+ bKeysProcessed = true;
+ }
+ }
+
+ return CallNextHookEx(s_hHook, nCode, wParam, lParam);
+}
+
+bool QuickCutConsoleWindows::isKeyDown(byte byKey)
+{
+ return ((byKey & KEY_IS_DOWN_MASK) == KEY_IS_DOWN_MASK);
+}
+
+void QuickCutConsoleWindows::printKeyName(KBDLLHOOKSTRUCT * pKbd)
+{
+ char lpszName[256] = { 0 };
+ DWORD dwMsg = 1;
+ dwMsg += pKbd->scanCode << 16;
+ dwMsg += pKbd->flags << 24;
+ GetKeyNameText(dwMsg, reinterpret_cast(lpszName), sizeof(lpszName));
+
+ QString str;
+ str.sprintf("ScanCode: %d | VirtualKey: 0x%02X | KeyName: ", pKbd->scanCode, pKbd->vkCode);
+ str += QString::fromUtf16(reinterpret_cast(lpszName));
+ qDebug() << str;
+}
+
+bool QuickCutConsoleWindows::start()
+{
+ if (!QuickCutConsole::start())
+ {
+ qDebug() << "[QuickCutConsoleWindows::start] - Profiles file hasn't been loaded yet.";
+ }
+
+ if (!s_hHook)
+ {
+ qDebug() << "[QuickCutConsoleWindows::start] - Hooking...";
+ s_hHook = SetWindowsHookEx(WH_KEYBOARD_LL, WndProc, nullptr, 0);
+ if (!s_hHook)
+ {
+ qDebug() << "[QuickCutConsoleWindows::start] - Hook failed...";
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool QuickCutConsoleWindows::stop()
+{
+ QuickCutConsole::stop();
+
+ if (s_hHook)
+ {
+ qDebug() << "[QuickCutConsoleWindows::stop] - Unhooking...";
+ UnhookWindowsHookEx(s_hHook);
+ s_hHook = nullptr;
+ }
+
+ return true;
+}
diff --git a/src/QuickCutConsole/QuickCutConsoleWindows.h b/src/QuickCutConsole/QuickCutConsoleWindows.h
new file mode 100644
index 0000000..04dbd14
--- /dev/null
+++ b/src/QuickCutConsole/QuickCutConsoleWindows.h
@@ -0,0 +1,26 @@
+
+#pragma once
+
+#include "QuickCutConsole.h"
+
+#include
+
+
+class QuickCutConsoleWindows : public QuickCutConsole
+{
+
+public:
+ QuickCutConsoleWindows(int argc, char * argv[]);
+ ~QuickCutConsoleWindows();
+
+ bool start() override;
+ bool stop() override;
+
+ static LRESULT CALLBACK WndProc(int nCode, WPARAM wParam, LPARAM lParam);
+ static bool isKeyDown(byte byKey);
+ static void printKeyName(KBDLLHOOKSTRUCT * pKbd);
+
+public:
+ static HHOOK s_hHook;
+
+};
diff --git a/src/QuickCutConsole/main.cpp b/src/QuickCutConsole/main.cpp
new file mode 100644
index 0000000..dcc56bb
--- /dev/null
+++ b/src/QuickCutConsole/main.cpp
@@ -0,0 +1,30 @@
+
+#include
+#include
+
+
+#ifdef Q_OS_WIN
+#include "QuickCutConsoleWindows.h"
+#elif Q_OS_UNIX
+#include "QuickCutConsoleUnix.h"
+#endif
+
+
+int main(int argc, char *argv[])
+{
+ QSingleInstance instance("abbebe64-b962-42e7-8367-1c800819883b");
+ if (!instance.tryToRun())
+ {
+ return 0;
+ }
+
+#ifdef Q_OS_WIN
+ QuickCutConsoleWindows qc(argc, argv);
+#elif Q_OS_UNIX
+ QuickCutConsoleUnix qc(argc, argv);
+#endif
+
+ qc.start();
+
+ return qc.exec();
+}
diff --git a/src/QuickCutInstaller/Linux/.gitkeep b/src/QuickCutInstaller/Linux/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/src/QuickCutInstaller/Mac/.gitkeep b/src/QuickCutInstaller/Mac/.gitkeep
new file mode 100644
index 0000000..e69de29
diff --git a/src/QuickCutInstaller/Windows/x64/QuickCut.pro b/src/QuickCutInstaller/Windows/x64/QuickCut.pro
new file mode 100644
index 0000000..0e3a074
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x64/QuickCut.pro
@@ -0,0 +1,26 @@
+TEMPLATE = aux
+
+INSTALLER = QuickCut-x64-1.0.0-installer
+
+INPUT = \
+ $$PWD/config/config.xml \
+ $$PWD/packages
+
+RESOURCES += \
+ resources/installer.qrc
+
+
+installer.input = INPUT
+installer.output = $$INSTALLER
+installer.commands = C:\Qt\QtIFW-3.1.1\bin\binarycreator.exe -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT}
+installer.CONFIG += target_predeps no_link combine
+
+QMAKE_EXTRA_COMPILERS += installer
+
+FORMS += $$PWD/com.greich.quickcut.msvc141.x64/meta/licensewidget.ui
+
+OTHER_FILES += \
+ $$PWD/resources/* \
+ $$PWD/README \
+ $$PWD/com.greich.quickcut.msvc141.x64/data/* \
+ $$PWD/com.greich.quickcut.msvc141.x64/meta/*
diff --git a/src/QuickCutInstaller/Windows/x64/README b/src/QuickCutInstaller/Windows/x64/README
new file mode 100644
index 0000000..0d2453c
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x64/README
@@ -0,0 +1,6 @@
+Shows how to add an entry to the Windows start menu.
+
+Generate installer with
+
+binarycreator --offline-only -c config/config.xml -p packages QuickCut_x64_1.0.0_installer
+
diff --git a/src/QuickCutInstaller/Windows/x64/config/Background.png b/src/QuickCutInstaller/Windows/x64/config/Background.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x64/config/Background.png differ
diff --git a/src/QuickCutInstaller/Windows/x64/config/InstallerApplicationIcon.ico b/src/QuickCutInstaller/Windows/x64/config/InstallerApplicationIcon.ico
new file mode 100644
index 0000000..36a2187
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x64/config/InstallerApplicationIcon.ico differ
diff --git a/src/QuickCutInstaller/Windows/x64/config/InstallerWindowIcon.png b/src/QuickCutInstaller/Windows/x64/config/InstallerWindowIcon.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x64/config/InstallerWindowIcon.png differ
diff --git a/src/QuickCutInstaller/Windows/x64/config/Logo.png b/src/QuickCutInstaller/Windows/x64/config/Logo.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x64/config/Logo.png differ
diff --git a/src/QuickCutInstaller/Windows/x64/config/Watermark.png b/src/QuickCutInstaller/Windows/x64/config/Watermark.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x64/config/Watermark.png differ
diff --git a/src/QuickCutInstaller/Windows/x64/config/config.xml b/src/QuickCutInstaller/Windows/x64/config/config.xml
new file mode 100644
index 0000000..6afbf05
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x64/config/config.xml
@@ -0,0 +1,22 @@
+
+
+ QuickCut
+ 1.0.0
+ QuickCut
+ Gilad Reich
+ www.greich.com
+ InstallerWindowIcon.png
+ InstallerApplicationIcon.ico
+ Logo.png
+ Watermark.png
+
+
+ QuickCut
+ Uninstaller
+ true
+ Background.png
+
+
+ @HomeDir@/QuickCut
+ true
+
diff --git a/src/QuickCutInstaller/Windows/x64/config/theme_ubuntu.qss b/src/QuickCutInstaller/Windows/x64/config/theme_ubuntu.qss
new file mode 100644
index 0000000..2e4a99e
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x64/config/theme_ubuntu.qss
@@ -0,0 +1,564 @@
+/*
+Ubuntu Style Sheet for QT Applications
+Author: Jaime A. Quiroga P.
+Company: GTRONICK
+Last updated: 21/01/2019, 12:31.
+Available at: https://github.com/GTRONICK/QSS/blob/master/Ubuntu.qss
+*/
+QMainWindow {
+ background-color:#f0f0f0;
+}
+QDialog {
+ background-color:#f0f0f0;
+}
+QColorDialog {
+ background-color:#f0f0f0;
+}
+QLabel {
+ color:rgb(17,17,17);
+}
+QLineEdit {
+ background-color:rgb(255,255,255);
+ selection-background-color:rgb(236,116,64);
+ color:rgb(17,17,17);
+}
+QTextEdit {
+ border-width: 1px;
+ border-style: solid;
+ border-color:transparent;
+ color:rgb(17,17,17);
+ selection-background-color:rgb(236,116,64);
+}
+QPlainTextEdit {
+ border-width: 1px;
+ border-style: solid;
+ border-color:transparent;
+ color:rgb(17,17,17);
+ selection-background-color:rgb(236,116,64);
+}
+QPushButton{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius: 6px;
+ border-bottom-color: rgb(150,150,150);
+ border-right-color: rgb(165,165,165);
+ border-left-color: rgb(165,165,165);
+ border-top-color: rgb(180,180,180);
+ border-style: solid;
+ padding: 4px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:hover{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius:6px;
+ border-top-color: rgb(255,150,60);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-bottom-color: rgb(200,70,20);
+ border-style: solid;
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:default{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius:6px;
+ border-top-color: rgb(255,150,60);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-bottom-color: rgb(200,70,20);
+ border-style: solid;
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:pressed{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius: 6px;
+ border-width: 1px;
+ border-top-color: rgba(255,150,60,200);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 200));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 200));
+ border-bottom-color: rgba(200,70,20,200);
+ border-style: solid;
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:disabled{
+ color:rgb(174,167,159);
+ border-width: 1px;
+ border-radius: 6px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(200, 200, 200, 255), stop:1 rgba(230, 230, 230, 255));
+}
+QProgressBar {
+ text-align: center;
+ color: rgb(0, 0, 0);
+ border-width: 1px;
+ border-radius: 10px;
+ border-style: inset;
+ border-color: rgb(150,150,150);
+ background-color:rgb(221,221,219);
+}
+QProgressBar::chunk:horizontal {
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(225, 108, 54, 255), stop:1 rgba(246, 134, 86, 255));
+ border-style: solid;
+ border-radius:8px;
+ border-width:1px;
+ border-bottom-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(175,85,48,255), stop:1 rgba(236,114,67, 255));
+ border-top-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-right-color:qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-left-color:qlineargradient(spread:pad, x1:1, y1:0.5, x2:0, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+}
+QTabWidget {
+ color:rgb(0,0,0);
+ background-color:rgb(247,246,246);
+}
+QTabWidget::pane {
+ border-color: rgb(180,180,180);
+ background-color:rgb(247,246,246);
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 6px;
+}
+QTabBar::tab {
+ padding-left:4px;
+ padding-right:4px;
+ padding-bottom:2px;
+ padding-top:2px;
+ color:rgb(81,72,65);
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(221,218,217,255), stop:1 rgba(240,239,238,255));
+ border-style: solid;
+ border-width: 1px;
+ border-top-right-radius:4px;
+ border-top-left-radius:4px;
+ border-top-color: rgb(180,180,180);
+ border-left-color: rgb(180,180,180);
+ border-right-color: rgb(180,180,180);
+ border-bottom-color: transparent;
+}
+QTabBar::tab:selected, QTabBar::tab:last:selected, QTabBar::tab:hover {
+ background-color:rgb(247,246,246);
+ margin-left: 0px;
+ margin-right: 1px;
+}
+QTabBar::tab:!selected {
+ margin-top: 1px;
+ margin-right: 1px;
+}
+QMenuBar {
+ color:rgb(223,219,210);
+ background-color:rgb(65,64,59);
+}
+QMenuBar::item {
+ padding-top:4px;
+ padding-left:4px;
+ padding-right:4px;
+ color:rgb(223,219,210);
+ background-color:rgb(65,64,59);
+}
+QMenuBar::item:selected {
+ color:rgb(255,255,255);
+ padding-top:2px;
+ padding-left:2px;
+ padding-right:2px;
+ border-top-width:2px;
+ border-left-width:2px;
+ border-right-width:2px;
+ border-top-right-radius:4px;
+ border-top-left-radius:4px;
+ border-style:solid;
+ background-color:rgb(65,64,59);
+ border-top-color: rgb(47,47,44);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(90, 87, 78, 255), stop:1 rgba(47,47,44, 255));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(90, 87, 78, 255), stop:1 rgba(47,47,44, 255));
+}
+QMenu::item:selected {
+ color:rgb(255,255,255);
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(225, 108, 54, 255), stop:1 rgba(246, 134, 86, 255));
+ border-style:solid;
+ border-width:3px;
+ padding-left:17px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:7px;
+ border-bottom-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(175,85,48,255), stop:1 rgba(236,114,67, 255));
+ border-top-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-right-color:qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-left-color:qlineargradient(spread:pad, x1:1, y1:0.5, x2:0, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+}
+QMenu::item {
+ color:rgb(223,219,210);
+ padding-left:20px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:10px;
+}
+QMenu {
+ color:rgb(223,219,210);
+ background-color:rgb(65,64,59);
+}
+QCheckBox {
+ padding:2px;
+}
+QCheckBox:hover {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ padding-left: 1px;
+ padding-right: 1px;
+ padding-bottom: 1px;
+ padding-top: 1px;
+ border-color: rgb(255,150,60);
+ background-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(190, 90, 50, 50), stop:1 rgba(250, 130, 40, 50));
+}
+QCheckBox::indicator:checked {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ border-color: rgb(246, 134, 86);
+ background-color:rgb(246, 134, 86)
+}
+QCheckBox::indicator:unchecked {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ border-color:rgb(246, 134, 86);
+ background-color:rgb(255,255,255);
+}
+QRadioButton {
+ padding: 1px;
+}
+QRadioButton::indicator:checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: rgba(246, 134, 86, 255);
+ color: #a9b7c6;
+ background-color:rgba(246, 134, 86, 255);
+}
+QRadioButton::indicator:!checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: rgb(246, 134, 86);
+ color: #a9b7c6;
+ background-color: transparent;
+}
+QStatusBar {
+ color:rgb(81,72,65);
+}
+QSpinBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QDoubleSpinBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QTimeEdit {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QDateTimeEdit {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QDateEdit {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QComboBox {
+ color:rgb(81,72,65);
+ background: #ffffff;
+}
+QComboBox:editable {
+ background: #ffffff;
+ color: rgb(81,72,65);
+ selection-color:rgb(81,72,65);
+ selection-background-color: #ffffff;
+}
+QComboBox QAbstractItemView {
+ color:rgb(81,72,65);
+ background: #ffffff;
+ selection-color: #ffffff;
+ selection-background-color: rgb(246, 134, 86);
+}
+QComboBox:!editable:on, QComboBox::drop-down:editable:on {
+ color: #1e1d23;
+ background: #ffffff;
+}
+QFontComboBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QToolBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QToolBox::tab {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QToolBox::tab:selected {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QScrollArea {
+ color: #FFFFFF;
+ background-color:#f0f0f0;
+}
+QSlider::groove {
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+}
+QSlider::groove:horizontal {
+ height: 5px;
+ background: rgb(246, 134, 86);
+}
+QSlider::groove:vertical {
+ width: 5px;
+ background: rgb(246, 134, 86);
+}
+QSlider::handle:horizontal {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ width: 12px;
+ margin: -5px 0;
+ border-radius: 7px;
+}
+QSlider::handle:vertical {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ height: 12px;
+ margin: 0 -5px;
+ border-radius: 7px;
+}
+QSlider::add-page:horizontal {
+ background: white;
+}
+QSlider::add-page:vertical {
+ background: white;
+}
+QSlider::sub-page:horizontal {
+ background: rgb(246, 134, 86);
+}
+QSlider::sub-page:vertical {
+ background: rgb(246, 134, 86);
+}
+QScrollBar:horizontal {
+ max-height: 20px;
+ border: 1px transparent grey;
+ margin: 0px 20px 0px 20px;
+}
+QScrollBar::handle:horizontal {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ border-radius: 7px;
+ min-width: 25px;
+}
+QScrollBar::handle:horizontal:hover {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(255,150,60);
+ border-radius: 7px;
+ min-width: 25px;
+}
+QScrollBar::add-line:horizontal {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:horizontal:hover {
+ border: 1px solid;
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ border-color: rgb(255,150,60);
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:horizontal:pressed {
+ border: 1px solid grey;
+ border-top-left-radius: 7px;
+ border-top-right-radius: 7px;
+ border-bottom-right-radius: 7px;
+ background: rgb(231,231,231);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal:hover {
+ border: 1px solid;
+ border-color: rgb(255,150,60);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal:pressed {
+ border: 1px solid grey;
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(231,231,231);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::left-arrow:horizontal {
+ border: 1px transparent grey;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::right-arrow:horizontal {
+ border: 1px transparent grey;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
+ background: none;
+}
+QScrollBar:vertical {
+ max-width: 20px;
+ border: 1px transparent grey;
+ margin: 20px 0px 20px 0px;
+}
+QScrollBar::add-line:vertical {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-bottom-right-radius: 7px;
+ border-bottom-left-radius: 7px;
+ border-top-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:vertical:hover {
+ border: 1px solid;
+ border-color: rgb(255,150,60);
+ border-bottom-right-radius: 7px;
+ border-bottom-left-radius: 7px;
+ border-top-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:vertical:pressed {
+ border: 1px solid grey;
+ border-bottom-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ border-top-left-radius: 7px;
+ background: rgb(231,231,231);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical:hover {
+ border: 1px solid;
+ border-color: rgb(255,150,60);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical:pressed {
+ border: 1px solid grey;
+ border-top-left-radius: 7px;
+ border-top-right-radius: 7px;
+ background: rgb(231,231,231);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+ QScrollBar::handle:vertical {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ border-radius: 7px;
+ min-height: 25px;
+}
+QScrollBar::handle:vertical:hover {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(255,150,60);
+ border-radius: 7px;
+ min-height: 25px;
+}
+QScrollBar::up-arrow:vertical {
+ border: 1px transparent grey;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::down-arrow:vertical {
+ border: 1px transparent grey;
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
+ background: none;
+}
diff --git a/src/QuickCutInstaller/Windows/x64/create.cmd b/src/QuickCutInstaller/Windows/x64/create.cmd
new file mode 100644
index 0000000..2b8ab93
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x64/create.cmd
@@ -0,0 +1 @@
+binarycreator --offline-only -c config/config.xml -p packages QuickCut_x64_1.0.0_installer
\ No newline at end of file
diff --git a/src/QuickCutInstaller/Windows/x64/packages/com.greich.quickcut.msvc141.x64/meta/installscript.qs b/src/QuickCutInstaller/Windows/x64/packages/com.greich.quickcut.msvc141.x64/meta/installscript.qs
new file mode 100644
index 0000000..462412e
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x64/packages/com.greich.quickcut.msvc141.x64/meta/installscript.qs
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the FOO module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+function Component()
+{
+ // default constructor
+ installer.setValue("TargetDir", "@HomeDir@/QuickCut");
+ installer.finishButtonClicked.connect(this, Component.prototype.installationFinished);
+
+ if (installer.isInstaller()) {
+ component.loaded.connect(this, Component.prototype.installerLoaded);
+
+ // ComponentSelectionPage = gui.pageById(QInstaller.ComponentSelection);
+
+ // installer.setDefaultPageVisible(QInstaller.TargetDirectory, false);
+ // installer.setDefaultPageVisible(QInstaller.ComponentSelection, false);
+ // installer.setDefaultPageVisible(QInstaller.LicenseCheck, false);
+ // if (systemInfo.productType === "windows")
+ // installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false);
+ // installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false);
+ }
+}
+
+Component.prototype.createOperations = function()
+{
+ // call default implementation to actually install README.txt!
+ component.createOperations();
+
+ component.addOperation("CreateShortcut", "@TargetDir@/QuickCut.exe", "@DesktopDir@/QuickCut.lnk");
+ component.addOperation("CreateShortcut", "@TargetDir@/QuickCut.exe", "@StartMenuDir@/QuickCut.lnk");
+
+ if (component.uninstallationRequested()) {
+ component.addElevatedOperation("Execute", "@TargetDir@/QuickCutService.exe", "-t"); // Terminnate/stop
+ component.addElevatedOperation("Execute", "@TargetDir@/QuickCutService.exe", "-u"); // Uninstall
+ component.addElevatedOperation("Execute", "sc", "stop", "QuickCut Service"); // test
+ component.addElevatedOperation("Execute", "sc", "delete", "QuickCut Service"); // test
+ component.addElevatedOperation("Execute", "@TargetDir@/UninstallService.cmd"); // test..
+ }
+}
+
+Component.prototype.installerLoaded = function () {
+
+ if (installer.addWizardPage(component, "LicenseWidget", QInstaller.LicenseCheck)) {
+ var widget = gui.pageWidgetByObjectName("DynamicLicenseWidget");
+ if (widget != null) {
+ widget.acceptLicense.toggled.connect(this, Component.prototype.checkAccepted);
+
+ widget.complete = false;
+ widget.declineLicense.checked = true;
+ widget.windowTitle = "License Agreement";
+ // widget.textBrowser.setText("qrc:/LICENSE.txt");
+ }
+ }
+
+}
+
+Component.prototype.checkAccepted = function (checked) {
+ var widget = gui.pageWidgetByObjectName("DynamicLicenseWidget");
+ if (widget != null)
+ widget.complete = checked;
+}
+
+Component.prototype.installationFinished = function()
+{
+ component.addOperation("Execute", "QuickCutService.exe", "-i");
+}
\ No newline at end of file
diff --git a/src/QuickCutInstaller/Windows/x64/packages/com.greich.quickcut.msvc141.x64/meta/licensewidget.ui b/src/QuickCutInstaller/Windows/x64/packages/com.greich.quickcut.msvc141.x64/meta/licensewidget.ui
new file mode 100644
index 0000000..7b82fb3
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x64/packages/com.greich.quickcut.msvc141.x64/meta/licensewidget.ui
@@ -0,0 +1,102 @@
+
+
+ LicenseWidget
+
+
+
+ 0
+ 0
+ 491
+ 190
+
+
+
+
+ 491
+ 190
+
+
+
+ Form
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.
+
+
+ true
+
+
+
+
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">MIT License</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2019 Gilad Reich</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Permission is hereby granted, free of charge, to any person obtaining a copy</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">of this software and associated documentation files (the "Software"), to deal</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">in the Software without restriction, including without limitation the rights</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to use, copy, modify, merge, publish, distribute, sublicense, and/or sell</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">copies of the Software, and to permit persons to whom the Software is</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">furnished to do so, subject to the following conditions:</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above copyright notice and this permission notice shall be included in all</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">copies or substantial portions of the Software.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">SOFTWARE.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>
+
+
+
+
+
+
+ qrc:/LICENSE.txt
+
+
+
+
+
+
+
+ I accept the license.
+
+
+
+
+
+
+ I do not accept the license.
+
+
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/src/QuickCutInstaller/Windows/x64/packages/com.greich.quickcut.msvc141.x64/meta/package.xml b/src/QuickCutInstaller/Windows/x64/packages/com.greich.quickcut.msvc141.x64/meta/package.xml
new file mode 100644
index 0000000..d4aae1a
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x64/packages/com.greich.quickcut.msvc141.x64/meta/package.xml
@@ -0,0 +1,13 @@
+
+
+ QuickCut x64
+ QuickCut is a shortcut keyboard manager that allows you to map keys and activate specified processes.
+ 1.0.0
+ 2019-06-05
+ true
+
+
+ licensewidget.ui
+
+ com.greich.quickcut.msvc141.x64
+
diff --git a/src/QuickCutInstaller/Windows/x64/resources/LICENSE.txt b/src/QuickCutInstaller/Windows/x64/resources/LICENSE.txt
new file mode 100644
index 0000000..74ba49f
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x64/resources/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Gilad Reich
+
+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.
diff --git a/src/QuickCutInstaller/Windows/x64/resources/icon.png b/src/QuickCutInstaller/Windows/x64/resources/icon.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x64/resources/icon.png differ
diff --git a/src/QuickCutInstaller/Windows/x64/resources/installer.qrc b/src/QuickCutInstaller/Windows/x64/resources/installer.qrc
new file mode 100644
index 0000000..bfb4c37
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x64/resources/installer.qrc
@@ -0,0 +1,6 @@
+
+
+ icon.png
+ LICENSE.txt
+
+
diff --git a/src/QuickCutInstaller/Windows/x86/QuickCut.pro b/src/QuickCutInstaller/Windows/x86/QuickCut.pro
new file mode 100644
index 0000000..a8c922c
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x86/QuickCut.pro
@@ -0,0 +1,26 @@
+TEMPLATE = aux
+
+INSTALLER = QuickCut-x86-1.0.0-installer
+
+INPUT = \
+ $$PWD/config/config.xml \
+ $$PWD/packages
+
+RESOURCES += \
+ resources/installer.qrc
+
+
+installer.input = INPUT
+installer.output = $$INSTALLER
+installer.commands = C:\Qt\QtIFW-3.1.1\bin\binarycreator.exe -c $$PWD/config/config.xml -p $$PWD/packages ${QMAKE_FILE_OUT}
+installer.CONFIG += target_predeps no_link combine
+
+QMAKE_EXTRA_COMPILERS += installer
+
+FORMS += $$PWD/com.greich.quickcut.msvc141.x86/meta/licensewidget.ui
+
+OTHER_FILES += \
+ $$PWD/resources/* \
+ $$PWD/README \
+ $$PWD/com.greich.quickcut.msvc141.x86/data/* \
+ $$PWD/com.greich.quickcut.msvc141.x86/meta/*
diff --git a/src/QuickCutInstaller/Windows/x86/README b/src/QuickCutInstaller/Windows/x86/README
new file mode 100644
index 0000000..04a26d0
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x86/README
@@ -0,0 +1,6 @@
+Shows how to add an entry to the Windows start menu.
+
+Generate installer with
+
+binarycreator --offline-only -c config/config.xml -p packages QuickCut_x86_1.0.0_installer
+
diff --git a/src/QuickCutInstaller/Windows/x86/config/Background.png b/src/QuickCutInstaller/Windows/x86/config/Background.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x86/config/Background.png differ
diff --git a/src/QuickCutInstaller/Windows/x86/config/InstallerApplicationIcon.ico b/src/QuickCutInstaller/Windows/x86/config/InstallerApplicationIcon.ico
new file mode 100644
index 0000000..36a2187
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x86/config/InstallerApplicationIcon.ico differ
diff --git a/src/QuickCutInstaller/Windows/x86/config/InstallerWindowIcon.png b/src/QuickCutInstaller/Windows/x86/config/InstallerWindowIcon.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x86/config/InstallerWindowIcon.png differ
diff --git a/src/QuickCutInstaller/Windows/x86/config/Logo.png b/src/QuickCutInstaller/Windows/x86/config/Logo.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x86/config/Logo.png differ
diff --git a/src/QuickCutInstaller/Windows/x86/config/Watermark.png b/src/QuickCutInstaller/Windows/x86/config/Watermark.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x86/config/Watermark.png differ
diff --git a/src/QuickCutInstaller/Windows/x86/config/config.xml b/src/QuickCutInstaller/Windows/x86/config/config.xml
new file mode 100644
index 0000000..6afbf05
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x86/config/config.xml
@@ -0,0 +1,22 @@
+
+
+ QuickCut
+ 1.0.0
+ QuickCut
+ Gilad Reich
+ www.greich.com
+ InstallerWindowIcon.png
+ InstallerApplicationIcon.ico
+ Logo.png
+ Watermark.png
+
+
+ QuickCut
+ Uninstaller
+ true
+ Background.png
+
+
+ @HomeDir@/QuickCut
+ true
+
diff --git a/src/QuickCutInstaller/Windows/x86/config/theme_ubuntu.qss b/src/QuickCutInstaller/Windows/x86/config/theme_ubuntu.qss
new file mode 100644
index 0000000..2e4a99e
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x86/config/theme_ubuntu.qss
@@ -0,0 +1,564 @@
+/*
+Ubuntu Style Sheet for QT Applications
+Author: Jaime A. Quiroga P.
+Company: GTRONICK
+Last updated: 21/01/2019, 12:31.
+Available at: https://github.com/GTRONICK/QSS/blob/master/Ubuntu.qss
+*/
+QMainWindow {
+ background-color:#f0f0f0;
+}
+QDialog {
+ background-color:#f0f0f0;
+}
+QColorDialog {
+ background-color:#f0f0f0;
+}
+QLabel {
+ color:rgb(17,17,17);
+}
+QLineEdit {
+ background-color:rgb(255,255,255);
+ selection-background-color:rgb(236,116,64);
+ color:rgb(17,17,17);
+}
+QTextEdit {
+ border-width: 1px;
+ border-style: solid;
+ border-color:transparent;
+ color:rgb(17,17,17);
+ selection-background-color:rgb(236,116,64);
+}
+QPlainTextEdit {
+ border-width: 1px;
+ border-style: solid;
+ border-color:transparent;
+ color:rgb(17,17,17);
+ selection-background-color:rgb(236,116,64);
+}
+QPushButton{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius: 6px;
+ border-bottom-color: rgb(150,150,150);
+ border-right-color: rgb(165,165,165);
+ border-left-color: rgb(165,165,165);
+ border-top-color: rgb(180,180,180);
+ border-style: solid;
+ padding: 4px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:hover{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius:6px;
+ border-top-color: rgb(255,150,60);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-bottom-color: rgb(200,70,20);
+ border-style: solid;
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:default{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius:6px;
+ border-top-color: rgb(255,150,60);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 255));
+ border-bottom-color: rgb(200,70,20);
+ border-style: solid;
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:pressed{
+ color:rgb(17,17,17);
+ border-width: 1px;
+ border-radius: 6px;
+ border-width: 1px;
+ border-top-color: rgba(255,150,60,200);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 200));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(200, 70, 20, 255), stop:1 rgba(255,150,60, 200));
+ border-bottom-color: rgba(200,70,20,200);
+ border-style: solid;
+ padding: 2px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:0, x2:0.5, y2:1, stop:0 rgba(220, 220, 220, 255), stop:1 rgba(255, 255, 255, 255));
+}
+QPushButton:disabled{
+ color:rgb(174,167,159);
+ border-width: 1px;
+ border-radius: 6px;
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(200, 200, 200, 255), stop:1 rgba(230, 230, 230, 255));
+}
+QProgressBar {
+ text-align: center;
+ color: rgb(0, 0, 0);
+ border-width: 1px;
+ border-radius: 10px;
+ border-style: inset;
+ border-color: rgb(150,150,150);
+ background-color:rgb(221,221,219);
+}
+QProgressBar::chunk:horizontal {
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(225, 108, 54, 255), stop:1 rgba(246, 134, 86, 255));
+ border-style: solid;
+ border-radius:8px;
+ border-width:1px;
+ border-bottom-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(175,85,48,255), stop:1 rgba(236,114,67, 255));
+ border-top-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-right-color:qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-left-color:qlineargradient(spread:pad, x1:1, y1:0.5, x2:0, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+}
+QTabWidget {
+ color:rgb(0,0,0);
+ background-color:rgb(247,246,246);
+}
+QTabWidget::pane {
+ border-color: rgb(180,180,180);
+ background-color:rgb(247,246,246);
+ border-style: solid;
+ border-width: 1px;
+ border-radius: 6px;
+}
+QTabBar::tab {
+ padding-left:4px;
+ padding-right:4px;
+ padding-bottom:2px;
+ padding-top:2px;
+ color:rgb(81,72,65);
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(221,218,217,255), stop:1 rgba(240,239,238,255));
+ border-style: solid;
+ border-width: 1px;
+ border-top-right-radius:4px;
+ border-top-left-radius:4px;
+ border-top-color: rgb(180,180,180);
+ border-left-color: rgb(180,180,180);
+ border-right-color: rgb(180,180,180);
+ border-bottom-color: transparent;
+}
+QTabBar::tab:selected, QTabBar::tab:last:selected, QTabBar::tab:hover {
+ background-color:rgb(247,246,246);
+ margin-left: 0px;
+ margin-right: 1px;
+}
+QTabBar::tab:!selected {
+ margin-top: 1px;
+ margin-right: 1px;
+}
+QMenuBar {
+ color:rgb(223,219,210);
+ background-color:rgb(65,64,59);
+}
+QMenuBar::item {
+ padding-top:4px;
+ padding-left:4px;
+ padding-right:4px;
+ color:rgb(223,219,210);
+ background-color:rgb(65,64,59);
+}
+QMenuBar::item:selected {
+ color:rgb(255,255,255);
+ padding-top:2px;
+ padding-left:2px;
+ padding-right:2px;
+ border-top-width:2px;
+ border-left-width:2px;
+ border-right-width:2px;
+ border-top-right-radius:4px;
+ border-top-left-radius:4px;
+ border-style:solid;
+ background-color:rgb(65,64,59);
+ border-top-color: rgb(47,47,44);
+ border-right-color: qlineargradient(spread:pad, x1:0, y1:1, x2:1, y2:0, stop:0 rgba(90, 87, 78, 255), stop:1 rgba(47,47,44, 255));
+ border-left-color: qlineargradient(spread:pad, x1:1, y1:0, x2:0, y2:0, stop:0 rgba(90, 87, 78, 255), stop:1 rgba(47,47,44, 255));
+}
+QMenu::item:selected {
+ color:rgb(255,255,255);
+ background-color: qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(225, 108, 54, 255), stop:1 rgba(246, 134, 86, 255));
+ border-style:solid;
+ border-width:3px;
+ padding-left:17px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:7px;
+ border-bottom-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(175,85,48,255), stop:1 rgba(236,114,67, 255));
+ border-top-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-right-color:qlineargradient(spread:pad, x1:0, y1:0.5, x2:1, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+ border-left-color:qlineargradient(spread:pad, x1:1, y1:0.5, x2:0, y2:0.5, stop:0 rgba(253,156,113,255), stop:1 rgba(205,90,46, 255));
+}
+QMenu::item {
+ color:rgb(223,219,210);
+ padding-left:20px;
+ padding-top:4px;
+ padding-bottom:4px;
+ padding-right:10px;
+}
+QMenu {
+ color:rgb(223,219,210);
+ background-color:rgb(65,64,59);
+}
+QCheckBox {
+ padding:2px;
+}
+QCheckBox:hover {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ padding-left: 1px;
+ padding-right: 1px;
+ padding-bottom: 1px;
+ padding-top: 1px;
+ border-color: rgb(255,150,60);
+ background-color:qlineargradient(spread:pad, x1:0.5, y1:1, x2:0.5, y2:0, stop:0 rgba(190, 90, 50, 50), stop:1 rgba(250, 130, 40, 50));
+}
+QCheckBox::indicator:checked {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ border-color: rgb(246, 134, 86);
+ background-color:rgb(246, 134, 86)
+}
+QCheckBox::indicator:unchecked {
+ border-radius:4px;
+ border-style:solid;
+ border-width:1px;
+ border-color:rgb(246, 134, 86);
+ background-color:rgb(255,255,255);
+}
+QRadioButton {
+ padding: 1px;
+}
+QRadioButton::indicator:checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: rgba(246, 134, 86, 255);
+ color: #a9b7c6;
+ background-color:rgba(246, 134, 86, 255);
+}
+QRadioButton::indicator:!checked {
+ height: 10px;
+ width: 10px;
+ border-style:solid;
+ border-radius:5px;
+ border-width: 1px;
+ border-color: rgb(246, 134, 86);
+ color: #a9b7c6;
+ background-color: transparent;
+}
+QStatusBar {
+ color:rgb(81,72,65);
+}
+QSpinBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QDoubleSpinBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QTimeEdit {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QDateTimeEdit {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QDateEdit {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QComboBox {
+ color:rgb(81,72,65);
+ background: #ffffff;
+}
+QComboBox:editable {
+ background: #ffffff;
+ color: rgb(81,72,65);
+ selection-color:rgb(81,72,65);
+ selection-background-color: #ffffff;
+}
+QComboBox QAbstractItemView {
+ color:rgb(81,72,65);
+ background: #ffffff;
+ selection-color: #ffffff;
+ selection-background-color: rgb(246, 134, 86);
+}
+QComboBox:!editable:on, QComboBox::drop-down:editable:on {
+ color: #1e1d23;
+ background: #ffffff;
+}
+QFontComboBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QToolBox {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QToolBox::tab {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QToolBox::tab:selected {
+ color:rgb(81,72,65);
+ background-color: #ffffff;
+}
+QScrollArea {
+ color: #FFFFFF;
+ background-color:#f0f0f0;
+}
+QSlider::groove {
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+}
+QSlider::groove:horizontal {
+ height: 5px;
+ background: rgb(246, 134, 86);
+}
+QSlider::groove:vertical {
+ width: 5px;
+ background: rgb(246, 134, 86);
+}
+QSlider::handle:horizontal {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ width: 12px;
+ margin: -5px 0;
+ border-radius: 7px;
+}
+QSlider::handle:vertical {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ height: 12px;
+ margin: 0 -5px;
+ border-radius: 7px;
+}
+QSlider::add-page:horizontal {
+ background: white;
+}
+QSlider::add-page:vertical {
+ background: white;
+}
+QSlider::sub-page:horizontal {
+ background: rgb(246, 134, 86);
+}
+QSlider::sub-page:vertical {
+ background: rgb(246, 134, 86);
+}
+QScrollBar:horizontal {
+ max-height: 20px;
+ border: 1px transparent grey;
+ margin: 0px 20px 0px 20px;
+}
+QScrollBar::handle:horizontal {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ border-radius: 7px;
+ min-width: 25px;
+}
+QScrollBar::handle:horizontal:hover {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(255,150,60);
+ border-radius: 7px;
+ min-width: 25px;
+}
+QScrollBar::add-line:horizontal {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:horizontal:hover {
+ border: 1px solid;
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ border-color: rgb(255,150,60);
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:horizontal:pressed {
+ border: 1px solid grey;
+ border-top-left-radius: 7px;
+ border-top-right-radius: 7px;
+ border-bottom-right-radius: 7px;
+ background: rgb(231,231,231);
+ width: 20px;
+ subcontrol-position: right;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal:hover {
+ border: 1px solid;
+ border-color: rgb(255,150,60);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:horizontal:pressed {
+ border: 1px solid grey;
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(231,231,231);
+ width: 20px;
+ subcontrol-position: left;
+ subcontrol-origin: margin;
+}
+QScrollBar::left-arrow:horizontal {
+ border: 1px transparent grey;
+ border-top-left-radius: 3px;
+ border-bottom-left-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::right-arrow:horizontal {
+ border: 1px transparent grey;
+ border-top-right-radius: 3px;
+ border-bottom-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::add-page:horizontal, QScrollBar::sub-page:horizontal {
+ background: none;
+}
+QScrollBar:vertical {
+ max-width: 20px;
+ border: 1px transparent grey;
+ margin: 20px 0px 20px 0px;
+}
+QScrollBar::add-line:vertical {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-bottom-right-radius: 7px;
+ border-bottom-left-radius: 7px;
+ border-top-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:vertical:hover {
+ border: 1px solid;
+ border-color: rgb(255,150,60);
+ border-bottom-right-radius: 7px;
+ border-bottom-left-radius: 7px;
+ border-top-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::add-line:vertical:pressed {
+ border: 1px solid grey;
+ border-bottom-left-radius: 7px;
+ border-bottom-right-radius: 7px;
+ border-top-left-radius: 7px;
+ background: rgb(231,231,231);
+ height: 20px;
+ subcontrol-position: bottom;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical {
+ border: 1px solid;
+ border-color: rgb(207,207,207);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical:hover {
+ border: 1px solid;
+ border-color: rgb(255,150,60);
+ border-top-right-radius: 7px;
+ border-top-left-radius: 7px;
+ border-bottom-left-radius: 7px;
+ background: rgb(255, 255, 255);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+QScrollBar::sub-line:vertical:pressed {
+ border: 1px solid grey;
+ border-top-left-radius: 7px;
+ border-top-right-radius: 7px;
+ background: rgb(231,231,231);
+ height: 20px;
+ subcontrol-position: top;
+ subcontrol-origin: margin;
+}
+ QScrollBar::handle:vertical {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(207,207,207);
+ border-radius: 7px;
+ min-height: 25px;
+}
+QScrollBar::handle:vertical:hover {
+ background: rgb(253,253,253);
+ border-style: solid;
+ border-width: 1px;
+ border-color: rgb(255,150,60);
+ border-radius: 7px;
+ min-height: 25px;
+}
+QScrollBar::up-arrow:vertical {
+ border: 1px transparent grey;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::down-arrow:vertical {
+ border: 1px transparent grey;
+ border-bottom-left-radius: 3px;
+ border-bottom-right-radius: 3px;
+ width: 6px;
+ height: 6px;
+ background: rgb(230,230,230);
+}
+QScrollBar::add-page:vertical, QScrollBar::sub-page:vertical {
+ background: none;
+}
diff --git a/src/QuickCutInstaller/Windows/x86/create.cmd b/src/QuickCutInstaller/Windows/x86/create.cmd
new file mode 100644
index 0000000..38583bc
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x86/create.cmd
@@ -0,0 +1 @@
+binarycreator --offline-only -c config/config.xml -p packages QuickCut_x86_1.0.0_installer
\ No newline at end of file
diff --git a/src/QuickCutInstaller/Windows/x86/packages/com.greich.quickcut.msvc141.x86/meta/installscript.qs b/src/QuickCutInstaller/Windows/x86/packages/com.greich.quickcut.msvc141.x86/meta/installscript.qs
new file mode 100644
index 0000000..462412e
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x86/packages/com.greich.quickcut.msvc141.x86/meta/installscript.qs
@@ -0,0 +1,91 @@
+/****************************************************************************
+**
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the FOO module of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:GPL-EXCEPT$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+function Component()
+{
+ // default constructor
+ installer.setValue("TargetDir", "@HomeDir@/QuickCut");
+ installer.finishButtonClicked.connect(this, Component.prototype.installationFinished);
+
+ if (installer.isInstaller()) {
+ component.loaded.connect(this, Component.prototype.installerLoaded);
+
+ // ComponentSelectionPage = gui.pageById(QInstaller.ComponentSelection);
+
+ // installer.setDefaultPageVisible(QInstaller.TargetDirectory, false);
+ // installer.setDefaultPageVisible(QInstaller.ComponentSelection, false);
+ // installer.setDefaultPageVisible(QInstaller.LicenseCheck, false);
+ // if (systemInfo.productType === "windows")
+ // installer.setDefaultPageVisible(QInstaller.StartMenuSelection, false);
+ // installer.setDefaultPageVisible(QInstaller.ReadyForInstallation, false);
+ }
+}
+
+Component.prototype.createOperations = function()
+{
+ // call default implementation to actually install README.txt!
+ component.createOperations();
+
+ component.addOperation("CreateShortcut", "@TargetDir@/QuickCut.exe", "@DesktopDir@/QuickCut.lnk");
+ component.addOperation("CreateShortcut", "@TargetDir@/QuickCut.exe", "@StartMenuDir@/QuickCut.lnk");
+
+ if (component.uninstallationRequested()) {
+ component.addElevatedOperation("Execute", "@TargetDir@/QuickCutService.exe", "-t"); // Terminnate/stop
+ component.addElevatedOperation("Execute", "@TargetDir@/QuickCutService.exe", "-u"); // Uninstall
+ component.addElevatedOperation("Execute", "sc", "stop", "QuickCut Service"); // test
+ component.addElevatedOperation("Execute", "sc", "delete", "QuickCut Service"); // test
+ component.addElevatedOperation("Execute", "@TargetDir@/UninstallService.cmd"); // test..
+ }
+}
+
+Component.prototype.installerLoaded = function () {
+
+ if (installer.addWizardPage(component, "LicenseWidget", QInstaller.LicenseCheck)) {
+ var widget = gui.pageWidgetByObjectName("DynamicLicenseWidget");
+ if (widget != null) {
+ widget.acceptLicense.toggled.connect(this, Component.prototype.checkAccepted);
+
+ widget.complete = false;
+ widget.declineLicense.checked = true;
+ widget.windowTitle = "License Agreement";
+ // widget.textBrowser.setText("qrc:/LICENSE.txt");
+ }
+ }
+
+}
+
+Component.prototype.checkAccepted = function (checked) {
+ var widget = gui.pageWidgetByObjectName("DynamicLicenseWidget");
+ if (widget != null)
+ widget.complete = checked;
+}
+
+Component.prototype.installationFinished = function()
+{
+ component.addOperation("Execute", "QuickCutService.exe", "-i");
+}
\ No newline at end of file
diff --git a/src/QuickCutInstaller/Windows/x86/packages/com.greich.quickcut.msvc141.x86/meta/licensewidget.ui b/src/QuickCutInstaller/Windows/x86/packages/com.greich.quickcut.msvc141.x86/meta/licensewidget.ui
new file mode 100644
index 0000000..7b82fb3
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x86/packages/com.greich.quickcut.msvc141.x86/meta/licensewidget.ui
@@ -0,0 +1,102 @@
+
+
+ LicenseWidget
+
+
+
+ 0
+ 0
+ 491
+ 190
+
+
+
+
+ 491
+ 190
+
+
+
+ Form
+
+
+
+
+
+
+ 0
+ 0
+
+
+
+ Please read the following license agreement. You must accept the terms contained in this agreement before continuing with the installation.
+
+
+ true
+
+
+
+
+
+
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
+<html><head><meta name="qrichtext" content="1" /><style type="text/css">
+p, li { white-space: pre-wrap; }
+</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">MIT License</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Copyright (c) 2019 Gilad Reich</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Permission is hereby granted, free of charge, to any person obtaining a copy</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">of this software and associated documentation files (the "Software"), to deal</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">in the Software without restriction, including without limitation the rights</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">to use, copy, modify, merge, publish, distribute, sublicense, and/or sell</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">copies of the Software, and to permit persons to whom the Software is</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">furnished to do so, subject to the following conditions:</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">The above copyright notice and this permission notice shall be included in all</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">copies or substantial portions of the Software.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE</p>
+<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">SOFTWARE.</p>
+<p style="-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><br /></p></body></html>
+
+
+
+
+
+
+ qrc:/LICENSE.txt
+
+
+
+
+
+
+
+ I accept the license.
+
+
+
+
+
+
+ I do not accept the license.
+
+
+ true
+
+
+
+
+
+
+
+
+
+
diff --git a/src/QuickCutInstaller/Windows/x86/packages/com.greich.quickcut.msvc141.x86/meta/package.xml b/src/QuickCutInstaller/Windows/x86/packages/com.greich.quickcut.msvc141.x86/meta/package.xml
new file mode 100644
index 0000000..1a0fa3b
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x86/packages/com.greich.quickcut.msvc141.x86/meta/package.xml
@@ -0,0 +1,13 @@
+
+
+ QuickCut x86
+ QuickCut is a shortcut keyboard manager that allows you to map keys and activate specified processes.
+ 1.0.0
+ 2019-06-05
+ true
+
+
+ licensewidget.ui
+
+ com.greich.quickcut.msvc141.x86
+
diff --git a/src/QuickCutInstaller/Windows/x86/resources/LICENSE.txt b/src/QuickCutInstaller/Windows/x86/resources/LICENSE.txt
new file mode 100644
index 0000000..74ba49f
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x86/resources/LICENSE.txt
@@ -0,0 +1,21 @@
+MIT License
+
+Copyright (c) 2019 Gilad Reich
+
+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.
diff --git a/src/QuickCutInstaller/Windows/x86/resources/icon.png b/src/QuickCutInstaller/Windows/x86/resources/icon.png
new file mode 100644
index 0000000..11dcf09
Binary files /dev/null and b/src/QuickCutInstaller/Windows/x86/resources/icon.png differ
diff --git a/src/QuickCutInstaller/Windows/x86/resources/installer.qrc b/src/QuickCutInstaller/Windows/x86/resources/installer.qrc
new file mode 100644
index 0000000..bfb4c37
--- /dev/null
+++ b/src/QuickCutInstaller/Windows/x86/resources/installer.qrc
@@ -0,0 +1,6 @@
+
+
+ icon.png
+ LICENSE.txt
+
+
diff --git a/src/QuickCutService/QuickCutService.cpp b/src/QuickCutService/QuickCutService.cpp
new file mode 100644
index 0000000..186fbed
--- /dev/null
+++ b/src/QuickCutService/QuickCutService.cpp
@@ -0,0 +1,54 @@
+
+#include "QuickCutService.h"
+
+#include "pch.h"
+
+#include
+#include
+
+
+QuickCutService::QuickCutService(int argc, char * argv[])
+ : QtService(argc, argv, "QuickCut Service")
+{
+ setServiceDescription("QuickCut Service is responsible for activating the shortcut-keys "
+ "defined by the user using the QuickCut GUI. It starts QuickCutConsole background process "
+ "as the currently signed-in user in order allow key messages communication between processes.");
+
+ setServiceFlags(QtServiceBase::CanBeSuspended);
+ setStartupType(QtServiceController::StartupType::AutoStartup);
+}
+
+QuickCutService::~QuickCutService()
+{}
+
+void QuickCutService::start()
+{}
+
+void QuickCutService::pause()
+{
+ stop();
+}
+
+void QuickCutService::resume()
+{
+ start();
+}
+
+void QuickCutService::stop()
+{}
+
+bool QuickCutService::isProcessRunning(const QString & szProc)
+{
+ return false;
+}
+
+void QuickCutService::log(const QString & szFilePath, const QString & szMessage)
+{
+ QFile file(szFilePath);
+ file.open(QFile::WriteOnly);
+ QTextStream text(&file);
+ text << szMessage;
+ file.flush();
+ file.close();
+}
+
diff --git a/src/QuickCutService/QuickCutService.h b/src/QuickCutService/QuickCutService.h
new file mode 100644
index 0000000..4ebb6b6
--- /dev/null
+++ b/src/QuickCutService/QuickCutService.h
@@ -0,0 +1,25 @@
+
+#pragma once
+
+#include "QtService/QtService"
+
+
+class QuickCutService : public QtService
+{
+public:
+ QuickCutService(int argc, char * argv[]);
+ virtual ~QuickCutService();
+
+ virtual void start() override;
+ virtual void pause() override;
+ virtual void resume() override;
+ virtual void stop() override;
+
+ virtual bool isProcessRunning(const QString & szProc);
+
+ static void log(const QString & szFilePath, const QString & szMessage);
+
+public:
+
+
+};
diff --git a/src/QuickCutService/QuickCutService.vcxproj b/src/QuickCutService/QuickCutService.vcxproj
new file mode 100644
index 0000000..8d7deee
--- /dev/null
+++ b/src/QuickCutService/QuickCutService.vcxproj
@@ -0,0 +1,245 @@
+
+
+
+
+ Debug
+ Win32
+
+
+ Debug
+ x64
+
+
+ Release
+ Win32
+
+
+ Release
+ x64
+
+
+
+ {64C0215D-FA4A-4CFB-A36D-A65C0A041538}
+ Qt4VSv1.0
+ 10.0.17763.0
+
+
+
+ Application
+ v141
+
+
+ Application
+ v141
+
+
+ Application
+ v141
+
+
+ Application
+ v141
+
+
+
+ $(MSBuildProjectDirectory)\QtMsBuild
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+
+
+ $(SolutionDir)$(Platform)\$(Configuration)\
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;%(PreprocessorDefinitions)
+ Disabled
+ ProgramDatabase
+ MultiThreadedDebugDLL
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;$(ProjectDir)GeneratedFiles\$(Configuration);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ true
+ stdcpp17
+
+
+ Console
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ true
+ qtmaind.lib;Qt5Cored.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;%(PreprocessorDefinitions)
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;%(PreprocessorDefinitions)
+ Disabled
+ ProgramDatabase
+ MultiThreadedDebugDLL
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;$(ProjectDir)GeneratedFiles\$(Configuration);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ true
+
+
+ Console
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ true
+ qtmaind.lib;Qt5Cored.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_CORE_LIB;%(PreprocessorDefinitions)
+ .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions)
+
+ MultiThreadedDLL
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;$(ProjectDir)GeneratedFiles\$(Configuration);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ true
+ stdcpp17
+
+
+ Console
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ false
+ qtmain.lib;Qt5Core.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions)
+ $(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+
+
+
+
+ true
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions)
+
+
+ MultiThreadedDLL
+ $(SolutionDir)QuickCutShared;$(BOOST_ROOT)\$(PlatformTarget)-vc$(PlatformToolsetVersion)\$(Configuration)\include;.;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ true
+
+
+ Console
+ $(OutDir)\$(ProjectName).exe
+ $(QTDIR)\lib;%(AdditionalLibraryDirectories)
+ false
+ qtmain.lib;Qt5Core.lib;%(AdditionalDependencies)
+ RequireAdministrator
+
+
+ UNICODE;_UNICODE;WIN32;_ENABLE_EXTENDED_ALIGNED_STORAGE;WIN64;QT_DLL;QT_NO_DEBUG;NDEBUG;QT_CORE_LIB;%(PreprocessorDefinitions)
+ .;$(QTDIR)\include;.\GeneratedFiles\$(ConfigurationName);$(QTDIR)\include\QtCore;%(AdditionalIncludeDirectories)
+ .\GeneratedFiles\$(ConfigurationName)\moc_%(Filename).cpp
+ Moc'ing %(Identity)...
+
+
+
+
+
+
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+
+
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+ .\GeneratedFiles\$(ConfigurationName)\%(Filename).moc
+ input
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+ true
+ true
+ true
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/QuickCutService/QuickCutService.vcxproj.filters b/src/QuickCutService/QuickCutService.vcxproj.filters
new file mode 100644
index 0000000..28779d8
--- /dev/null
+++ b/src/QuickCutService/QuickCutService.vcxproj.filters
@@ -0,0 +1,77 @@
+
+
+
+
+ {4FC737F1-C7A5-4376-A066-2A32D752A2FF}
+ cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx
+
+
+ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}
+ qrc;*
+ false
+
+
+ {D9D6E242-F8AF-46E4-B9FD-80ECBC20BA3E}
+ qrc;*
+ false
+
+
+ {f2c1f007-8642-488c-b0c6-22502be9a1c4}
+
+
+ {a4b46907-1b77-4132-b3ec-32115242b68d}
+
+
+
+
+ Source Files
+
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files
+
+
+ Source Files
+
+
+
+
+ Source Files
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files\Shared
+
+
+ Source Files
+
+
+ Source Files
+
+
+ Source Files\Shared\QtService
+
+
+ Source Files\Shared\QtService
+
+
+
+
+ Source Files
+
+
+ Source Files
+
+
+
\ No newline at end of file
diff --git a/src/QuickCutService/QuickCutService.vcxproj.user b/src/QuickCutService/QuickCutService.vcxproj.user
new file mode 100644
index 0000000..a3fde02
--- /dev/null
+++ b/src/QuickCutService/QuickCutService.vcxproj.user
@@ -0,0 +1,30 @@
+
+
+
+
+ C:\Qt\5.12.0\msvc2017
+ -e
+ WindowsLocalDebugger
+ PATH=$(QTDIR)\bin%3b$(PATH)
+
+
+ C:\Qt\5.12.0\msvc2017_64
+ PATH=$(QTDIR)\bin%3b$(PATH)
+ -e
+ WindowsLocalDebugger
+ $(SolutionDir)$(Platform)\$(Configuration)\
+
+
+ C:\Qt\5.12.0\msvc2017
+ -e
+ WindowsLocalDebugger
+ PATH=$(QTDIR)\bin%3b$(PATH)
+
+
+ C:\Qt\5.12.0\msvc2017_64
+ PATH=$(QTDIR)\bin%3b$(PATH)
+ -e
+ WindowsLocalDebugger
+ $(SolutionDir)$(Platform)\$(Configuration)\
+
+
\ No newline at end of file
diff --git a/src/QuickCutService/QuickCutServiceUnix.cpp b/src/QuickCutService/QuickCutServiceUnix.cpp
new file mode 100644
index 0000000..7622af0
--- /dev/null
+++ b/src/QuickCutService/QuickCutServiceUnix.cpp
@@ -0,0 +1,52 @@
+
+#include "QuickCutServiceUnix.h"
+#include "pch.h"
+
+#include
+#include
+#include
+
+
+QuickCutServiceUnix::QuickCutServiceUnix(int argc, char * argv[])
+ : QuickCutService(argc, argv)
+{}
+
+QuickCutServiceUnix::~QuickCutServiceUnix()
+{
+ if (isProcessRunning("QuickCutConsole"))
+ QProcess::execute("killall -9 QuickCutConsole");
+}
+
+void QuickCutServiceUnix::start()
+{
+ QuickCutService::start();
+
+ QString proc = QCoreApplication::applicationDirPath() + "/QuickCutConsole";
+ QProcess::execute(proc);
+}
+
+void QuickCutServiceUnix::pause()
+{
+ QuickCutService::pause();
+
+ stop();
+}
+
+void QuickCutServiceUnix::resume()
+{
+ QuickCutService::resume();
+
+ start();
+}
+
+void QuickCutServiceUnix::stop()
+{
+ QuickCutService::stop();
+ if (isProcessRunning("QuickCutConsole"))
+ QProcess::execute("killall -9 QuickCutConsole");
+}
+
+bool QuickCutServiceUnix::isProcessRunning(const QString & szProc)
+{
+ return false;
+}
diff --git a/src/QuickCutService/QuickCutServiceUnix.h b/src/QuickCutService/QuickCutServiceUnix.h
new file mode 100644
index 0000000..8f094c3
--- /dev/null
+++ b/src/QuickCutService/QuickCutServiceUnix.h
@@ -0,0 +1,22 @@
+
+#pragma once
+
+#include "QuickCutService.h"
+
+
+class QuickCutServiceUnix : public QuickCutService
+{
+public:
+ QuickCutServiceUnix(int argc, char * argv[]);
+ ~QuickCutServiceUnix();
+
+ void start() override;
+ void pause() override;
+ void resume() override;
+ void stop() override;
+
+ bool isProcessRunning(const QString & szProc) override;
+
+public:
+
+};
diff --git a/src/QuickCutService/QuickCutServiceWindows.cpp b/src/QuickCutService/QuickCutServiceWindows.cpp
new file mode 100644
index 0000000..c4e32e2
--- /dev/null
+++ b/src/QuickCutService/QuickCutServiceWindows.cpp
@@ -0,0 +1,215 @@
+
+#pragma comment(lib, "userenv.lib")
+
+#include "QuickCutServiceWindows.h"
+#include "pch.h"
+
+#include
+#include
+#include
+
+#include
+
+#undef UNICODE
+
+#define QUICKCUT_CONSOLE "QuickCutConsole.exe"
+
+QuickCutServiceWindows * QuickCutServiceWindows::s_pInstance = nullptr;
+
+
+QuickCutServiceWindows::QuickCutServiceWindows(int argc, char * argv[])
+ : QuickCutService(argc, argv)
+{
+ s_pInstance = this;
+}
+
+QuickCutServiceWindows::~QuickCutServiceWindows()
+{
+ killHookIfRunning();
+}
+
+void QuickCutServiceWindows::start()
+{
+ killHookIfRunning();
+
+ QuickCutService::start();
+
+ std::wstring szProc = (QCoreApplication::applicationDirPath() + "/" + QUICKCUT_CONSOLE).toStdWString();
+ RunProcessAsUserW(szProc);
+}
+
+void QuickCutServiceWindows::pause()
+{
+ QuickCutService::pause();
+
+ stop();
+}
+
+void QuickCutServiceWindows::resume()
+{
+ QuickCutService::resume();
+
+ start();
+}
+
+void QuickCutServiceWindows::stop()
+{
+ QuickCutService::stop();
+
+ killHookIfRunning();
+}
+
+
+void QuickCutServiceWindows::killHookIfRunning()
+{
+ if (isProcessRunning(QUICKCUT_CONSOLE))
+ QProcess::execute("taskkill /im " QUICKCUT_CONSOLE " /f");
+}
+
+bool QuickCutServiceWindows::isProcessRunning(const QString & szProc)
+{
+ PROCESSENTRY32 procEntry;
+ memset(&procEntry, 0, sizeof(PROCESSENTRY32));
+
+ if (szProc.isEmpty())
+ return false;
+
+ HANDLE hProcSnap = nullptr;
+ hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hProcSnap == INVALID_HANDLE_VALUE)
+ return false;
+
+ procEntry.dwSize = sizeof(PROCESSENTRY32);
+ if (!Process32First(hProcSnap, &procEntry))
+ {
+ CloseHandle(hProcSnap);
+ return false;
+ }
+
+
+ wchar_t * szProcW = new wchar_t[szProc.length()+1];
+ szProcW[szProc.length()] = '\0';
+ szProc.toWCharArray(szProcW);
+ do
+ {
+ if (_wcsicmp(procEntry.szExeFile, szProcW) == 0) // equals
+ {
+ delete [] szProcW;
+ CloseHandle(hProcSnap);
+ return true;
+ }
+ } while (Process32Next(hProcSnap, &procEntry));
+
+ delete [] szProcW;
+
+ CloseHandle(hProcSnap);
+ return false;
+}
+
+
+bool QuickCutServiceWindows::RunProcessAsUserA(const std::string & szProc)
+{
+ if (szProc.empty())
+ return false;
+
+ HANDLE hToken = nullptr;
+ if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY, true, &hToken))
+ {
+ qDebug() << "[QuickCutServiceWindows::RunProcessAsUserA] - Failed to retrieve token handle for user.";
+ return false;
+ }
+
+ STARTUPINFOA startInfo;
+ PROCESS_INFORMATION procInfo;
+ memset(&startInfo, 0, sizeof(startInfo));
+ memset(&procInfo, 0, sizeof(procInfo));
+
+ startInfo.cb = sizeof(STARTUPINFOA);
+ startInfo.lpDesktop = "winsta0\\default";
+
+ bool bSucceed = CreateProcessAsUserA(hToken, szProc.c_str(), nullptr, nullptr, nullptr,
+ false, 0, nullptr, nullptr,
+ &startInfo, &procInfo);
+
+ if (bSucceed)
+ {
+ qDebug() << "[QuickCutServiceWindows::RunProcessAsUserA] - Successfully created process as user.";
+ }
+ else
+ {
+ qDebug() << "[QuickCutServiceWindows::RunProcessAsUserA] - Failed to create process as user.";
+ }
+
+ CloseHandle(hToken);
+ return bSucceed;
+}
+
+bool QuickCutServiceWindows::RunProcessAsUserW(const std::wstring & szProc)
+{
+ if (szProc.empty())
+ return false;
+
+ HANDLE hToken = nullptr;
+ if (!GetTokenByName(hToken, L"explorer.exe"))
+ {
+ qDebug() << "[QuickCutServiceWindows::RunProcessAsUserW] - Failed to retrieve explorer token handle for user.";
+ return false;
+ }
+
+ STARTUPINFO startInfo;
+ PROCESS_INFORMATION procInfo;
+ memset(&startInfo, 0, sizeof(STARTUPINFO));
+ memset(&procInfo, 0, sizeof(PROCESS_INFORMATION));
+
+ startInfo.cb = sizeof(STARTUPINFO);
+ startInfo.lpDesktop = L"winsta0\\default";
+
+ bool bSucceed = CreateProcessAsUser(hToken, szProc.c_str(), nullptr, nullptr, nullptr,
+ false, NORMAL_PRIORITY_CLASS, nullptr, nullptr,
+ &startInfo, &procInfo);
+ if (bSucceed)
+ {
+ qDebug() << "[QuickCutServiceWindows::RunProcessAsUserW] - Successfully created process as user.";
+ }
+ else
+ {
+ qDebug() << "[QuickCutServiceWindows::RunProcessAsUserW] - Failed to create process as user.";
+ }
+
+ CloseHandle(hToken);
+ return bSucceed;
+}
+
+bool QuickCutServiceWindows::GetTokenByName(HANDLE & hToken, const WCHAR * szProcName)
+{
+ if (!szProcName)
+ return false;
+
+ HANDLE hProcSnap = nullptr;
+ hProcSnap = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
+ if (hProcSnap == INVALID_HANDLE_VALUE)
+ return false;
+
+ PROCESSENTRY32 procEntry;
+ memset(&procEntry, 0, sizeof(PROCESSENTRY32));
+ procEntry.dwSize = sizeof(PROCESSENTRY32);
+ if (!Process32First(hProcSnap, &procEntry))
+ {
+ CloseHandle(hProcSnap);
+ return false;
+ }
+
+ do
+ {
+ if (_wcsicmp(procEntry.szExeFile, szProcName) == 0) // equals
+ {
+ HANDLE hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, false, procEntry.th32ProcessID);
+ bool bSucceed = OpenProcessToken(hProcess, TOKEN_ALL_ACCESS, &hToken);
+ CloseHandle(hProcSnap);
+ return bSucceed;
+ }
+ } while (Process32Next(hProcSnap, &procEntry));
+
+ CloseHandle(hProcSnap);
+ return true;
+}
diff --git a/src/QuickCutService/QuickCutServiceWindows.h b/src/QuickCutService/QuickCutServiceWindows.h
new file mode 100644
index 0000000..6c442e7
--- /dev/null
+++ b/src/QuickCutService/QuickCutServiceWindows.h
@@ -0,0 +1,32 @@
+
+#pragma once
+
+#include "QuickCutService.h"
+
+#include
+
+
+class QuickCutServiceWindows : public QuickCutService
+{
+public:
+ QuickCutServiceWindows(int argc, char * argv[]);
+ ~QuickCutServiceWindows();
+
+ void start() override;
+ void pause() override;
+ void resume() override;
+ void stop() override;
+
+ bool isProcessRunning(const QString & szProc) override;
+
+ bool RunProcessAsUserW(const std::wstring & szProc);
+ bool RunProcessAsUserA(const std::string & szProc);
+ bool GetTokenByName(HANDLE & hToken, const WCHAR * szProcName);
+
+private:
+ void killHookIfRunning();
+
+public:
+ static QuickCutServiceWindows * s_pInstance;
+
+};
diff --git a/src/QuickCutService/main.cpp b/src/QuickCutService/main.cpp
new file mode 100644
index 0000000..d10b44a
--- /dev/null
+++ b/src/QuickCutService/main.cpp
@@ -0,0 +1,19 @@
+
+#include
+
+#ifdef Q_OS_WIN
+#include "QuickCutServiceWindows.h"
+#elif Q_OS_UNIX
+#include "QuickCutServiceUnix.h"
+#endif
+
+int main(int argc, char * argv[])
+{
+#ifdef Q_OS_WIN
+ QuickCutServiceWindows service(argc, argv);
+#elif Q_OS_UNIX
+ QuickCutServiceUnix service(argc, argv);
+#endif
+
+ return service.exec();
+}
diff --git a/src/QuickCutShared/Action.cpp b/src/QuickCutShared/Action.cpp
new file mode 100644
index 0000000..25cc38a
--- /dev/null
+++ b/src/QuickCutShared/Action.cpp
@@ -0,0 +1,153 @@
+
+#include "Action.h"
+#include "pch.h"
+#include
+
+
+Action::Action()
+ : m_szUuid(createUuid())
+ , m_szName("")
+ , m_eType(ActionUnknown)
+ , m_szSrcKey("")
+ , m_szDstKey("")
+ , m_szAppPath("")
+ , m_szAppArgs("")
+ , m_szCreatedDate(getDateTime())
+{
+
+}
+
+Action::Action(std::string name, const eActionType & type,
+ std::string srcKey, std::string dstKey,
+ std::string appPath, std::string appArgs)
+ : m_szUuid(createUuid())
+ , m_szName(std::move(name))
+ , m_eType(type)
+ , m_szSrcKey(std::move(srcKey))
+ , m_szDstKey(std::move(dstKey))
+ , m_szAppPath(std::move(appPath))
+ , m_szAppArgs(std::move(appArgs))
+ , m_szCreatedDate(getDateTime())
+{
+
+}
+
+Action::Action(std::string id, std::string name, const eActionType & type,
+ std::string srcKey, std::string dstKey,
+ std::string appPath, std::string appArgs,
+ std::string createdDate)
+ : m_szUuid(std::move(id))
+ , m_szName(std::move(name))
+ , m_eType(type)
+ , m_szSrcKey(std::move(srcKey))
+ , m_szDstKey(std::move(dstKey))
+ , m_szAppPath(std::move(appPath))
+ , m_szAppArgs(std::move(appArgs))
+ , m_szCreatedDate(std::move(createdDate))
+{
+}
+
+std::string Action::getType(eActionType type)
+{
+ switch (type)
+ {
+ case ActionKeyMap: return "KeyMap";
+ case ActionAppStart: return "AppStart";
+
+ case ActionUnknown:
+ default:
+ return "Unknown";
+ }
+}
+
+eActionType Action::getType(const std::string & type)
+{
+ if (type == "KeyMap") return ActionKeyMap;
+ if (type == "AppStart") return ActionAppStart;
+ return ActionUnknown;
+}
+
+std::string Action::getKey(int key)
+{
+ return std::to_string(key);
+}
+
+const std::string & Action::getId() const
+{
+ return m_szUuid;
+}
+
+const std::string & Action::getName() const
+{
+ return m_szName;
+}
+
+void Action::setName(const std::string & name)
+{
+ m_szName = name;
+}
+
+eActionType Action::getType() const
+{
+ return m_eType;
+}
+
+void Action::setType(eActionType type)
+{
+ m_eType = type;
+}
+
+std::string Action::getSrcKey() const
+{
+ return m_szSrcKey;
+}
+
+void Action::setSrcKey(const std::string & key)
+{
+ m_szSrcKey = key;
+}
+
+std::string Action::getDstKey() const
+{
+ return m_szDstKey;
+}
+
+void Action::setDstKey(const std::string & key)
+{
+ m_szDstKey = key;
+}
+
+const std::string & Action::getAppPath() const
+{
+ return m_szAppPath;
+}
+
+void Action::setAppPath(const std::string & path)
+{
+ m_szAppPath = path;
+}
+
+const std::string & Action::getAppArgs() const
+{
+ return m_szAppArgs;
+}
+
+void Action::setAppArgs(const std::string & args)
+{
+ m_szAppArgs = args;
+}
+
+const std::string & Action::getCreatedDate() const
+{
+ return m_szCreatedDate;
+}
+
+void Action::reset()
+{
+ m_szName.clear();
+ m_eType = ActionUnknown;
+ m_szSrcKey.clear();
+ m_szDstKey.clear();
+ m_szAppPath.clear();
+ m_szAppArgs.clear();
+}
diff --git a/src/QuickCutShared/Action.h b/src/QuickCutShared/Action.h
new file mode 100644
index 0000000..1ca346a
--- /dev/null
+++ b/src/QuickCutShared/Action.h
@@ -0,0 +1,60 @@
+
+#pragma once
+
+#include
+
+
+enum eActionType { ActionKeyMap = 0x00, ActionAppStart = 0x01, ActionUnknown = 0xFF };
+
+class Action
+{
+public:
+ Action();
+ Action(std::string name, const eActionType & type,
+ std::string srcKey, std::string dstKey,
+ std::string appPath, std::string appArgs);
+ Action(std::string id, std::string name, const eActionType & type,
+ std::string srcKey, std::string dstKey,
+ std::string appPath, std::string appArgs,
+ std::string createdDate);
+
+
+ static std::string getType(eActionType type);
+ static eActionType getType(const std::string & type);
+ static std::string getKey(int key);
+
+ const std::string & getId() const;
+
+ const std::string & getName() const;
+ void setName(const std::string & name);
+
+ eActionType getType() const;
+ void setType(eActionType type);
+
+ std::string getSrcKey() const;
+ void setSrcKey(const std::string & key);
+
+ std::string getDstKey() const;
+ void setDstKey(const std::string & key);
+
+ const std::string & getAppPath() const;
+ void setAppPath(const std::string & path);
+
+ const std::string & getAppArgs() const;
+ void setAppArgs(const std::string & path);
+
+ const std::string & getCreatedDate() const;
+
+ void reset();
+
+private:
+ std::string m_szUuid;
+ std::string m_szName;
+ eActionType m_eType;
+ std::string m_szSrcKey; // string with delimited ',' char. Could have multiple keys.
+ std::string m_szDstKey;
+ std::string m_szAppPath;
+ std::string m_szAppArgs;
+ std::string m_szCreatedDate;
+
+};
\ No newline at end of file
diff --git a/src/QuickCutShared/Profile.cpp b/src/QuickCutShared/Profile.cpp
new file mode 100644
index 0000000..0da2e9c
--- /dev/null
+++ b/src/QuickCutShared/Profile.cpp
@@ -0,0 +1,134 @@
+
+#include "Profile.h"
+#include "pch.h"
+
+
+Profile::Profile()
+ : m_szUuid(createUuid())
+ , m_szName("")
+ , m_szLastModified(getDateTime())
+{
+}
+
+Profile::Profile(std::string name)
+ : m_szUuid(createUuid())
+ , m_szName(std::move(name))
+ , m_szLastModified(getDateTime())
+{
+}
+
+Profile::Profile(std::string id, std::string name, std::string lastModified)
+ : m_szUuid(std::move(id))
+ , m_szName(std::move(name))
+ , m_szLastModified(std::move(lastModified))
+{
+}
+
+Profile::~Profile()
+{
+ for (auto itr : m_vActions)
+ {
+ Action * pAction = itr;
+ delete pAction;
+ }
+ m_vActions.clear();
+}
+
+const std::string & Profile::getId() const
+{
+ return m_szUuid;
+}
+
+const std::string & Profile::getName() const
+{
+ return m_szName;
+}
+
+void Profile::setName(const std::string & name)
+{
+ m_szName = name;
+ updated();
+}
+
+const std::string & Profile::getLastModified() const
+{
+ return m_szLastModified;
+}
+
+void Profile::setActionsCapacity(int capacity)
+{
+ m_vActions.reserve(capacity);
+}
+
+const std::vector & Profile::getActions() const
+{
+ return m_vActions;
+}
+
+int Profile::getActionsCount() const
+{
+ return m_vActions.size();
+}
+
+bool Profile::addAction(Action * action)
+{
+ m_vActions.emplace_back(action);
+ updated();
+
+ return true;
+}
+
+bool Profile::insertAction(uint32_t iIndex, Action * pAction)
+{
+ m_vActions.insert(m_vActions.begin() + iIndex + 1, pAction);
+ updated();
+
+ return true;
+}
+
+bool Profile::deleteAction(Action * pAction)
+{
+ auto itr = std::find(m_vActions.begin(), m_vActions.end(), pAction);
+ if (itr == m_vActions.end()) return false;
+
+ delete pAction;
+ pAction = nullptr;
+ m_vActions.erase(itr);
+
+ return true;
+}
+
+bool Profile::deleteActionByIndex(const uint32_t & iIndex)
+{
+ return deleteAction(getActionByIndex(iIndex));
+}
+
+void Profile::getActionById(const std::string & uuid) const
+{
+
+}
+
+void Profile::getActionByName(const std::string & name) const
+{
+
+}
+
+Action * Profile::getActionByIndex(const uint32_t & iIndex) const
+{
+ if (iIndex > m_vActions.size()) return nullptr;
+
+ return m_vActions[iIndex];
+}
+
+
+Action * Profile::operator [] (uint32_t iIndex)
+{
+ if (iIndex > m_vActions.size()) return nullptr;
+
+ return m_vActions[iIndex];
+}
+
+void Profile::updated()
+{
+ m_szLastModified = getDateTime();
+}
diff --git a/src/QuickCutShared/Profile.h b/src/QuickCutShared/Profile.h
new file mode 100644
index 0000000..c8839e9
--- /dev/null
+++ b/src/QuickCutShared/Profile.h
@@ -0,0 +1,55 @@
+
+#pragma once
+
+#include "Action.h"
+#include
+
+
+class Profile
+{
+public:
+ Profile();
+ Profile(std::string name);
+ Profile(std::string id, std::string name, std::string lastModified);
+ ~Profile();
+
+
+ const std::string & getId() const;
+
+ const std::string & getName() const;
+ void setName(const std::string & name);
+
+ const std::string & getLastModified() const;
+
+ void setActionsCapacity(int capacity);
+ const std::vector & getActions() const;
+ int getActionsCount() const;
+
+ bool addAction(Action * action);
+ bool insertAction(uint32_t iIndex, Action * pAction);
+ bool deleteAction(Action * action);
+ bool deleteActionByIndex(const uint32_t & iIndex);
+
+ void getActionById(const std::string & uuid) const;
+ void getActionByName(const std::string & name) const;
+ Action * getActionByIndex(const uint32_t & iIndex) const;
+
+ Action * operator [] (uint32_t iIndex);
+
+
+private:
+ void updated();
+
+
+private:
+ std::string m_szUuid;
+ std::string m_szName;
+ std::string m_szLastModified;
+
+ std::vector m_vActions;
+
+};
+
+
+
+
diff --git a/src/QuickCutShared/QSingleApplication/QSingleInstance.cpp b/src/QuickCutShared/QSingleApplication/QSingleInstance.cpp
new file mode 100644
index 0000000..e2fd277
--- /dev/null
+++ b/src/QuickCutShared/QSingleApplication/QSingleInstance.cpp
@@ -0,0 +1,81 @@
+
+#include "QSingleInstance.h"
+
+#include
+
+
+namespace
+{
+
+ QString generateKeyHash(const QString & szKey, const QString & szSalt)
+ {
+ QByteArray data;
+
+ data.append(szKey.toUtf8());
+ data.append(szSalt.toUtf8());
+ data = QCryptographicHash::hash(data, QCryptographicHash::Sha1).toHex();
+
+ return data;
+ }
+
+}
+
+
+QSingleInstance::QSingleInstance(const QString & szKey)
+ : m_szKey(szKey)
+ , m_szMemLockKey(generateKeyHash(szKey, "_memLockKey"))
+ , m_szSharedMemKey(generateKeyHash(szKey, "_sharedmemKey"))
+ , m_qSharedMem(m_szSharedMemKey)
+ , m_qMemLock(m_szMemLockKey, 1)
+{
+ m_qMemLock.acquire();
+ {
+ QSharedMemory fix(m_szSharedMemKey); // Fix for *nix: http://habrahabr.ru/post/173281/
+ fix.attach();
+ }
+ m_qMemLock.release();
+}
+
+QSingleInstance::~QSingleInstance()
+{
+ release();
+}
+
+bool QSingleInstance::isAnotherRunning()
+{
+ if (m_qSharedMem.isAttached())
+ return false;
+
+ m_qMemLock.acquire();
+ const bool isRunning = m_qSharedMem.attach();
+ if (isRunning)
+ m_qSharedMem.detach();
+ m_qMemLock.release();
+
+ return isRunning;
+}
+
+bool QSingleInstance::tryToRun()
+{
+ if (isAnotherRunning()) // Extra check
+ return false;
+
+ m_qMemLock.acquire();
+ const bool result = m_qSharedMem.create(sizeof(quint64));
+ m_qMemLock.release();
+ if (!result)
+ {
+ release();
+ return false;
+ }
+
+ return true;
+}
+
+void QSingleInstance::release()
+{
+ m_qMemLock.acquire();
+ if (m_qSharedMem.isAttached())
+ m_qSharedMem.detach();
+ m_qMemLock.release();
+}
\ No newline at end of file
diff --git a/src/QuickCutShared/QSingleApplication/QSingleInstance.h b/src/QuickCutShared/QSingleApplication/QSingleInstance.h
new file mode 100644
index 0000000..a10a816
--- /dev/null
+++ b/src/QuickCutShared/QSingleApplication/QSingleInstance.h
@@ -0,0 +1,31 @@
+/*
+ * https://stackoverflow.com/questions/5006547/qt-best-practice-for-a-single-instance-app-protection
+ */
+#pragma once
+
+#include
+#include
+#include
+
+
+class QSingleInstance
+{
+ Q_DISABLE_COPY(QSingleInstance)
+
+public:
+ QSingleInstance(const QString & szKey);
+ ~QSingleInstance();
+
+ bool isAnotherRunning();
+ bool tryToRun();
+ void release();
+
+private:
+ const QString m_szKey;
+ const QString m_szMemLockKey;
+ const QString m_szSharedMemKey;
+
+ QSharedMemory m_qSharedMem;
+ QSystemSemaphore m_qMemLock;
+
+};
diff --git a/src/QuickCutShared/QSingleApplication/singleapplication.cpp b/src/QuickCutShared/QSingleApplication/singleapplication.cpp
new file mode 100644
index 0000000..a797231
--- /dev/null
+++ b/src/QuickCutShared/QSingleApplication/singleapplication.cpp
@@ -0,0 +1,174 @@
+// The MIT License (MIT)
+//
+// Copyright (c) Itay Grudev 2015 - 2018
+//
+// 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
+#include
+#include
+#include
+#include
+
+#include "singleapplication.h"
+#include "singleapplication_p.h"
+
+/**
+ * @brief Constructor. Checks and fires up LocalServer or closes the program
+ * if another instance already exists
+ * @param argc
+ * @param argv
+ * @param {bool} allowSecondaryInstances
+ */
+SingleApplication::SingleApplication( int &argc, char *argv[], bool allowSecondary, Options options, int timeout )
+ : app_t( argc, argv ), d_ptr( new SingleApplicationPrivate( this ) )
+{
+ Q_D(SingleApplication);
+
+ // Store the current mode of the program
+ d->options = options;
+
+ // Generating an application ID used for identifying the shared memory
+ // block and QLocalServer
+ d->genBlockServerName();
+
+#ifdef Q_OS_UNIX
+ // By explicitly attaching it and then deleting it we make sure that the
+ // memory is deleted even after the process has crashed on Unix.
+ d->memory = new QSharedMemory( d->blockServerName );
+ d->memory->attach();
+ delete d->memory;
+#endif
+ // Guarantee thread safe behaviour with a shared memory block.
+ d->memory = new QSharedMemory( d->blockServerName );
+
+ // Create a shared memory block
+ if( d->memory->create( sizeof( InstancesInfo ) ) ) {
+ // Initialize the shared memory block
+ d->memory->lock();
+ d->initializeMemoryBlock();
+ d->memory->unlock();
+ } else {
+ // Attempt to attach to the memory segment
+ if( ! d->memory->attach() ) {
+ qCritical() << "SingleApplication: Unable to attach to shared memory block.";
+ qCritical() << d->memory->errorString();
+ delete d;
+ ::exit( EXIT_FAILURE );
+ }
+ }
+
+ InstancesInfo* inst = static_cast( d->memory->data() );
+ QTime time;
+ time.start();
+
+ // Make sure the shared memory block is initialised and in consistent state
+ while( true ) {
+ d->memory->lock();
+
+ if( d->blockChecksum() == inst->checksum ) break;
+
+ if( time.elapsed() > 5000 ) {
+ qWarning() << "SingleApplication: Shared memory block has been in an inconsistent state from more than 5s. Assuming primary instance failure.";
+ d->initializeMemoryBlock();
+ }
+
+ d->memory->unlock();
+
+ // Random sleep here limits the probability of a collision between two racing apps
+ qsrand( QDateTime::currentMSecsSinceEpoch() % std::numeric_limits::max() );
+ QThread::sleep( 8 + static_cast ( static_cast ( qrand() ) / RAND_MAX * 10 ) );
+ }
+
+ if( inst->primary == false) {
+ d->startPrimary();
+ d->memory->unlock();
+ return;
+ }
+
+ // Check if another instance can be started
+ if( allowSecondary ) {
+ inst->secondary += 1;
+ inst->checksum = d->blockChecksum();
+ d->instanceNumber = inst->secondary;
+ d->startSecondary();
+ if( d->options & Mode::SecondaryNotification ) {
+ d->connectToPrimary( timeout, SingleApplicationPrivate::SecondaryInstance );
+ }
+ d->memory->unlock();
+ return;
+ }
+
+ d->memory->unlock();
+
+ d->connectToPrimary( timeout, SingleApplicationPrivate::NewInstance );
+
+ delete d;
+
+ ::exit( EXIT_SUCCESS );
+}
+
+/**
+ * @brief Destructor
+ */
+SingleApplication::~SingleApplication()
+{
+ Q_D(SingleApplication);
+ delete d;
+}
+
+bool SingleApplication::isPrimary()
+{
+ Q_D(SingleApplication);
+ return d->server != nullptr;
+}
+
+bool SingleApplication::isSecondary()
+{
+ Q_D(SingleApplication);
+ return d->server == nullptr;
+}
+
+quint32 SingleApplication::instanceId()
+{
+ Q_D(SingleApplication);
+ return d->instanceNumber;
+}
+
+qint64 SingleApplication::primaryPid()
+{
+ Q_D(SingleApplication);
+ return d->primaryPid();
+}
+
+bool SingleApplication::sendMessage( QByteArray message, int timeout )
+{
+ Q_D(SingleApplication);
+
+ // Nobody to connect to
+ if( isPrimary() ) return false;
+
+ // Make sure the socket is connected
+ d->connectToPrimary( timeout, SingleApplicationPrivate::Reconnect );
+
+ d->socket->write( message );
+ bool dataWritten = d->socket->flush();
+ d->socket->waitForBytesWritten( timeout );
+ return dataWritten;
+}
diff --git a/src/QuickCutShared/QSingleApplication/singleapplication.h b/src/QuickCutShared/QSingleApplication/singleapplication.h
new file mode 100644
index 0000000..f123abd
--- /dev/null
+++ b/src/QuickCutShared/QSingleApplication/singleapplication.h
@@ -0,0 +1,135 @@
+// The MIT License (MIT)
+//
+// Copyright (c) Itay Grudev 2015 - 2018
+//
+// 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 SINGLE_APPLICATION_H
+#define SINGLE_APPLICATION_H
+
+#include
+#include
+
+#ifndef QAPPLICATION_CLASS
+ #define QAPPLICATION_CLASS QCoreApplication
+#endif
+
+#include QT_STRINGIFY(QAPPLICATION_CLASS)
+
+class SingleApplicationPrivate;
+
+/**
+ * @brief The SingleApplication class handles multipe instances of the same
+ * Application
+ * @see QCoreApplication
+ */
+class SingleApplication : public QAPPLICATION_CLASS
+{
+ Q_OBJECT
+
+ typedef QAPPLICATION_CLASS app_t;
+
+public:
+ /**
+ * @brief Mode of operation of SingleApplication.
+ * Whether the block should be user-wide or system-wide and whether the
+ * primary instance should be notified when a secondary instance had been
+ * started.
+ * @note Operating system can restrict the shared memory blocks to the same
+ * user, in which case the User/System modes will have no effect and the
+ * block will be user wide.
+ * @enum
+ */
+ enum Mode {
+ User = 1 << 0,
+ System = 1 << 1,
+ SecondaryNotification = 1 << 2,
+ ExcludeAppVersion = 1 << 3,
+ ExcludeAppPath = 1 << 4
+ };
+ Q_DECLARE_FLAGS(Options, Mode)
+
+ /**
+ * @brief Intitializes a SingleApplication instance with argc command line
+ * arguments in argv
+ * @arg {int &} argc - Number of arguments in argv
+ * @arg {const char *[]} argv - Supplied command line arguments
+ * @arg {bool} allowSecondary - Whether to start the instance as secondary
+ * if there is already a primary instance.
+ * @arg {Mode} mode - Whether for the SingleApplication block to be applied
+ * User wide or System wide.
+ * @arg {int} timeout - Timeout to wait in miliseconds.
+ * @note argc and argv may be changed as Qt removes arguments that it
+ * recognizes
+ * @note Mode::SecondaryNotification only works if set on both the primary
+ * instance and the secondary instance.
+ * @note The timeout is just a hint for the maximum time of blocking
+ * operations. It does not guarantee that the SingleApplication
+ * initialisation will be completed in given time, though is a good hint.
+ * Usually 4*timeout would be the worst case (fail) scenario.
+ * @see See the corresponding QAPPLICATION_CLASS constructor for reference
+ */
+ explicit SingleApplication( int &argc, char *argv[], bool allowSecondary = false, Options options = Mode::User, int timeout = 1000 );
+ ~SingleApplication();
+
+ /**
+ * @brief Returns if the instance is the primary instance
+ * @returns {bool}
+ */
+ bool isPrimary();
+
+ /**
+ * @brief Returns if the instance is a secondary instance
+ * @returns {bool}
+ */
+ bool isSecondary();
+
+ /**
+ * @brief Returns a unique identifier for the current instance
+ * @returns {qint32}
+ */
+ quint32 instanceId();
+
+ /**
+ * @brief Returns the process ID (PID) of the primary instance
+ * @returns {qint64}
+ */
+ qint64 primaryPid();
+
+ /**
+ * @brief Sends a message to the primary instance. Returns true on success.
+ * @param {int} timeout - Timeout for connecting
+ * @returns {bool}
+ * @note sendMessage() will return false if invoked from the primary
+ * instance.
+ */
+ bool sendMessage( QByteArray message, int timeout = 100 );
+
+Q_SIGNALS:
+ void instanceStarted();
+ void receivedMessage( quint32 instanceId, QByteArray message );
+
+private:
+ SingleApplicationPrivate *d_ptr;
+ Q_DECLARE_PRIVATE(SingleApplication)
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(SingleApplication::Options)
+
+#endif // SINGLE_APPLICATION_H
diff --git a/src/QuickCutShared/QSingleApplication/singleapplication_p.cpp b/src/QuickCutShared/QSingleApplication/singleapplication_p.cpp
new file mode 100644
index 0000000..de4945e
--- /dev/null
+++ b/src/QuickCutShared/QSingleApplication/singleapplication_p.cpp
@@ -0,0 +1,404 @@
+// The MIT License (MIT)
+//
+// Copyright (c) Itay Grudev 2015 - 2018
+//
+// 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.
+
+//
+// W A R N I N G !!!
+// -----------------
+//
+// This file is not part of the SingleApplication API. It is used purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or may even be removed.
+//
+
+#include
+#include
+
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+#include "singleapplication.h"
+#include "singleapplication_p.h"
+
+#ifdef Q_OS_WIN
+ #include
+ #include
+#endif
+
+SingleApplicationPrivate::SingleApplicationPrivate( SingleApplication *q_ptr )
+ : q_ptr( q_ptr )
+{
+ server = nullptr;
+ socket = nullptr;
+ memory = nullptr;
+ instanceNumber = -1;
+}
+
+SingleApplicationPrivate::~SingleApplicationPrivate()
+{
+ if( socket != nullptr ) {
+ socket->close();
+ delete socket;
+ }
+
+ memory->lock();
+ InstancesInfo* inst = static_cast(memory->data());
+ if( server != nullptr ) {
+ server->close();
+ delete server;
+ inst->primary = false;
+ inst->primaryPid = -1;
+ inst->checksum = blockChecksum();
+ }
+ memory->unlock();
+
+ delete memory;
+}
+
+void SingleApplicationPrivate::genBlockServerName()
+{
+ QCryptographicHash appData( QCryptographicHash::Sha256 );
+ appData.addData( "SingleApplication", 17 );
+ appData.addData( SingleApplication::app_t::applicationName().toUtf8() );
+ appData.addData( SingleApplication::app_t::organizationName().toUtf8() );
+ appData.addData( SingleApplication::app_t::organizationDomain().toUtf8() );
+
+ if( ! (options & SingleApplication::Mode::ExcludeAppVersion) ) {
+ appData.addData( SingleApplication::app_t::applicationVersion().toUtf8() );
+ }
+
+ if( ! (options & SingleApplication::Mode::ExcludeAppPath) ) {
+#ifdef Q_OS_WIN
+ appData.addData( SingleApplication::app_t::applicationFilePath().toLower().toUtf8() );
+#else
+ appData.addData( SingleApplication::app_t::applicationFilePath().toUtf8() );
+#endif
+ }
+
+ // User level block requires a user specific data in the hash
+ if( options & SingleApplication::Mode::User ) {
+#ifdef Q_OS_WIN
+ wchar_t username [ UNLEN + 1 ];
+ // Specifies size of the buffer on input
+ DWORD usernameLength = UNLEN + 1;
+ if( GetUserNameW( username, &usernameLength ) ) {
+ appData.addData( QString::fromWCharArray(username).toUtf8() );
+ } else {
+ appData.addData( QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).join("").toUtf8() );
+ }
+#endif
+#ifdef Q_OS_UNIX
+ QProcess process;
+ process.start( "whoami" );
+ if( process.waitForFinished( 100 ) &&
+ process.exitCode() == QProcess::NormalExit) {
+ appData.addData( process.readLine() );
+ } else {
+ appData.addData(
+ QDir(
+ QStandardPaths::standardLocations( QStandardPaths::HomeLocation ).first()
+ ).absolutePath().toUtf8()
+ );
+ }
+#endif
+ }
+
+ // Replace the backslash in RFC 2045 Base64 [a-zA-Z0-9+/=] to comply with
+ // server naming requirements.
+ blockServerName = appData.result().toBase64().replace("/", "_");
+}
+
+void SingleApplicationPrivate::initializeMemoryBlock()
+{
+ InstancesInfo* inst = static_cast( memory->data() );
+ inst->primary = false;
+ inst->secondary = 0;
+ inst->primaryPid = -1;
+ inst->checksum = blockChecksum();
+}
+
+void SingleApplicationPrivate::startPrimary()
+{
+ Q_Q(SingleApplication);
+
+ // Successful creation means that no main process exists
+ // So we start a QLocalServer to listen for connections
+ QLocalServer::removeServer( blockServerName );
+ server = new QLocalServer();
+
+ // Restrict access to the socket according to the
+ // SingleApplication::Mode::User flag on User level or no restrictions
+ if( options & SingleApplication::Mode::User ) {
+ server->setSocketOptions( QLocalServer::UserAccessOption );
+ } else {
+ server->setSocketOptions( QLocalServer::WorldAccessOption );
+ }
+
+ server->listen( blockServerName );
+ QObject::connect(
+ server,
+ &QLocalServer::newConnection,
+ this,
+ &SingleApplicationPrivate::slotConnectionEstablished
+ );
+
+ // Reset the number of connections
+ InstancesInfo* inst = static_cast ( memory->data() );
+
+ inst->primary = true;
+ inst->primaryPid = q->applicationPid();
+ inst->checksum = blockChecksum();
+
+ instanceNumber = 0;
+}
+
+void SingleApplicationPrivate::startSecondary()
+{
+}
+
+void SingleApplicationPrivate::connectToPrimary( int msecs, ConnectionType connectionType )
+{
+ // Connect to the Local Server of the Primary Instance if not already
+ // connected.
+ if( socket == nullptr ) {
+ socket = new QLocalSocket();
+ }
+
+ // If already connected - we are done;
+ if( socket->state() == QLocalSocket::ConnectedState )
+ return;
+
+ // If not connect
+ if( socket->state() == QLocalSocket::UnconnectedState ||
+ socket->state() == QLocalSocket::ClosingState ) {
+ socket->connectToServer( blockServerName );
+ }
+
+ // Wait for being connected
+ if( socket->state() == QLocalSocket::ConnectingState ) {
+ socket->waitForConnected( msecs );
+ }
+
+ // Initialisation message according to the SingleApplication protocol
+ if( socket->state() == QLocalSocket::ConnectedState ) {
+ // Notify the parent that a new instance had been started;
+ QByteArray initMsg;
+ QDataStream writeStream(&initMsg, QIODevice::WriteOnly);
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+ writeStream.setVersion(QDataStream::Qt_5_6);
+#endif
+
+ writeStream << blockServerName.toLatin1();
+ writeStream << static_cast(connectionType);
+ writeStream << instanceNumber;
+ quint16 checksum = qChecksum(initMsg.constData(), static_cast(initMsg.length()));
+ writeStream << checksum;
+
+ // The header indicates the message length that follows
+ QByteArray header;
+ QDataStream headerStream(&header, QIODevice::WriteOnly);
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+ headerStream.setVersion(QDataStream::Qt_5_6);
+#endif
+ headerStream << static_cast ( initMsg.length() );
+
+ socket->write( header );
+ socket->write( initMsg );
+ socket->flush();
+ socket->waitForBytesWritten( msecs );
+ }
+}
+
+quint16 SingleApplicationPrivate::blockChecksum()
+{
+ return qChecksum(
+ static_cast ( memory->data() ),
+ offsetof( InstancesInfo, checksum )
+ );
+}
+
+qint64 SingleApplicationPrivate::primaryPid()
+{
+ qint64 pid;
+
+ memory->lock();
+ InstancesInfo* inst = static_cast( memory->data() );
+ pid = inst->primaryPid;
+ memory->unlock();
+
+ return pid;
+}
+
+/**
+ * @brief Executed when a connection has been made to the LocalServer
+ */
+void SingleApplicationPrivate::slotConnectionEstablished()
+{
+ QLocalSocket *nextConnSocket = server->nextPendingConnection();
+ connectionMap.insert(nextConnSocket, ConnectionInfo());
+
+ QObject::connect(nextConnSocket, &QLocalSocket::aboutToClose,
+ [nextConnSocket, this]() {
+ auto &info = connectionMap[nextConnSocket];
+ Q_EMIT this->slotClientConnectionClosed( nextConnSocket, info.instanceId );
+ }
+ );
+
+ QObject::connect(nextConnSocket, &QLocalSocket::disconnected,
+ [nextConnSocket, this](){
+ connectionMap.remove(nextConnSocket);
+ nextConnSocket->deleteLater();
+ }
+ );
+
+ QObject::connect(nextConnSocket, &QLocalSocket::readyRead,
+ [nextConnSocket, this]() {
+ auto &info = connectionMap[nextConnSocket];
+ switch(info.stage) {
+ case StageHeader:
+ readInitMessageHeader(nextConnSocket);
+ break;
+ case StageBody:
+ readInitMessageBody(nextConnSocket);
+ break;
+ case StageConnected:
+ Q_EMIT this->slotDataAvailable( nextConnSocket, info.instanceId );
+ break;
+ default:
+ break;
+ };
+ }
+ );
+}
+
+void SingleApplicationPrivate::readInitMessageHeader( QLocalSocket *sock )
+{
+ if (!connectionMap.contains( sock )) {
+ return;
+ }
+
+ if( sock->bytesAvailable() < ( qint64 )sizeof( quint64 ) ) {
+ return;
+ }
+
+ QDataStream headerStream( sock );
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+ headerStream.setVersion( QDataStream::Qt_5_6 );
+#endif
+
+ // Read the header to know the message length
+ quint64 msgLen = 0;
+ headerStream >> msgLen;
+ ConnectionInfo &info = connectionMap[sock];
+ info.stage = StageBody;
+ info.msgLen = msgLen;
+
+ if ( sock->bytesAvailable() >= (qint64) msgLen ) {
+ readInitMessageBody( sock );
+ }
+}
+
+void SingleApplicationPrivate::readInitMessageBody( QLocalSocket *sock )
+{
+ Q_Q(SingleApplication);
+
+ if (!connectionMap.contains( sock )) {
+ return;
+ }
+
+ ConnectionInfo &info = connectionMap[sock];
+ if( sock->bytesAvailable() < ( qint64 )info.msgLen ) {
+ return;
+ }
+
+ // Read the message body
+ QByteArray msgBytes = sock->read(info.msgLen);
+ QDataStream readStream(msgBytes);
+
+#if (QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))
+ readStream.setVersion( QDataStream::Qt_5_6 );
+#endif
+
+ // server name
+ QByteArray latin1Name;
+ readStream >> latin1Name;
+
+ // connection type
+ ConnectionType connectionType = InvalidConnection;
+ quint8 connTypeVal = InvalidConnection;
+ readStream >> connTypeVal;
+ connectionType = static_cast ( connTypeVal );
+
+ // instance id
+ quint32 instanceId = 0;
+ readStream >> instanceId;
+
+ // checksum
+ quint16 msgChecksum = 0;
+ readStream >> msgChecksum;
+
+ const quint16 actualChecksum = qChecksum( msgBytes.constData(), static_cast( msgBytes.length() - sizeof( quint16 ) ) );
+
+ bool isValid = readStream.status() == QDataStream::Ok &&
+ QLatin1String(latin1Name) == blockServerName &&
+ msgChecksum == actualChecksum;
+
+ if( !isValid ) {
+ sock->close();
+ return;
+ }
+
+ info.instanceId = instanceId;
+ info.stage = StageConnected;
+
+ if( connectionType == NewInstance ||
+ ( connectionType == SecondaryInstance &&
+ options & SingleApplication::Mode::SecondaryNotification ) )
+ {
+ Q_EMIT q->instanceStarted();
+ }
+
+ if (sock->bytesAvailable() > 0) {
+ Q_EMIT this->slotDataAvailable( sock, instanceId );
+ }
+}
+
+void SingleApplicationPrivate::slotDataAvailable( QLocalSocket *dataSocket, quint32 instanceId )
+{
+ Q_Q(SingleApplication);
+ Q_EMIT q->receivedMessage( instanceId, dataSocket->readAll() );
+}
+
+void SingleApplicationPrivate::slotClientConnectionClosed( QLocalSocket *closedSocket, quint32 instanceId )
+{
+ if( closedSocket->bytesAvailable() > 0 )
+ Q_EMIT slotDataAvailable( closedSocket, instanceId );
+}
diff --git a/src/QuickCutShared/QSingleApplication/singleapplication_p.h b/src/QuickCutShared/QSingleApplication/singleapplication_p.h
new file mode 100644
index 0000000..e2c361f
--- /dev/null
+++ b/src/QuickCutShared/QSingleApplication/singleapplication_p.h
@@ -0,0 +1,99 @@
+// The MIT License (MIT)
+//
+// Copyright (c) Itay Grudev 2015 - 2016
+//
+// 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.
+
+//
+// W A R N I N G !!!
+// -----------------
+//
+// This file is not part of the SingleApplication API. It is used purely as an
+// implementation detail. This header file may change from version to
+// version without notice, or may even be removed.
+//
+
+#ifndef SINGLEAPPLICATION_P_H
+#define SINGLEAPPLICATION_P_H
+
+#include
+#include
+#include
+#include "singleapplication.h"
+
+struct InstancesInfo {
+ bool primary;
+ quint32 secondary;
+ qint64 primaryPid;
+ quint16 checksum;
+};
+
+struct ConnectionInfo {
+ explicit ConnectionInfo() :
+ msgLen(0), instanceId(0), stage(0) {}
+ qint64 msgLen;
+ quint32 instanceId;
+ quint8 stage;
+};
+
+class SingleApplicationPrivate : public QObject {
+Q_OBJECT
+public:
+ enum ConnectionType : quint8 {
+ InvalidConnection = 0,
+ NewInstance = 1,
+ SecondaryInstance = 2,
+ Reconnect = 3
+ };
+ enum ConnectionStage : quint8 {
+ StageHeader = 0,
+ StageBody = 1,
+ StageConnected = 2,
+ };
+ Q_DECLARE_PUBLIC(SingleApplication)
+
+ SingleApplicationPrivate( SingleApplication *q_ptr );
+ ~SingleApplicationPrivate();
+
+ void genBlockServerName();
+ void initializeMemoryBlock();
+ void startPrimary();
+ void startSecondary();
+ void connectToPrimary(int msecs, ConnectionType connectionType );
+ quint16 blockChecksum();
+ qint64 primaryPid();
+ void readInitMessageHeader(QLocalSocket *socket);
+ void readInitMessageBody(QLocalSocket *socket);
+
+ SingleApplication *q_ptr;
+ QSharedMemory *memory;
+ QLocalSocket *socket;
+ QLocalServer *server;
+ quint32 instanceNumber;
+ QString blockServerName;
+ SingleApplication::Options options;
+ QMap connectionMap;
+
+public Q_SLOTS:
+ void slotConnectionEstablished();
+ void slotDataAvailable( QLocalSocket*, quint32 );
+ void slotClientConnectionClosed( QLocalSocket*, quint32 );
+};
+
+#endif // SINGLEAPPLICATION_P_H
diff --git a/src/QuickCutShared/QtService/QtService b/src/QuickCutShared/QtService/QtService
new file mode 100644
index 0000000..57e17a5
--- /dev/null
+++ b/src/QuickCutShared/QtService/QtService
@@ -0,0 +1 @@
+#include "qtservice.h"
diff --git a/src/QuickCutShared/QtService/QtServiceBase b/src/QuickCutShared/QtService/QtServiceBase
new file mode 100644
index 0000000..57e17a5
--- /dev/null
+++ b/src/QuickCutShared/QtService/QtServiceBase
@@ -0,0 +1 @@
+#include "qtservice.h"
diff --git a/src/QuickCutShared/QtService/QtServiceController b/src/QuickCutShared/QtService/QtServiceController
new file mode 100644
index 0000000..57e17a5
--- /dev/null
+++ b/src/QuickCutShared/QtService/QtServiceController
@@ -0,0 +1 @@
+#include "qtservice.h"
diff --git a/src/QuickCutShared/QtService/qtservice.cpp b/src/QuickCutShared/QtService/qtservice.cpp
new file mode 100644
index 0000000..5eae058
--- /dev/null
+++ b/src/QuickCutShared/QtService/qtservice.cpp
@@ -0,0 +1,1129 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Solutions component.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtservice.h"
+#include "qtservice_p.h"
+#include
+#include
+#include
+#include
+#include
+
+#if defined(QTSERVICE_DEBUG)
+#include
+#include
+#include
+#include
+#include
+#if defined(Q_OS_WIN32)
+#include
+#else
+#include
+#include
+#endif
+
+static QFile* f = 0;
+
+static void qtServiceCloseDebugLog()
+{
+ if (!f)
+ return;
+ f->write(QTime::currentTime().toString("HH:mm:ss.zzz").toLatin1());
+ f->write(" --- DEBUG LOG CLOSED ---\n\n");
+ f->flush();
+ f->close();
+ delete f;
+ f = 0;
+}
+
+#if QT_VERSION >= 0x050000
+void qtServiceLogDebug(QtMsgType type, const QMessageLogContext &context, const QString &msg)
+#else
+void qtServiceLogDebug(QtMsgType type, const char* msg)
+#endif
+{
+ static QMutex mutex;
+ QMutexLocker locker(&mutex);
+#if defined(Q_OS_WIN32)
+ const qulonglong processId = GetCurrentProcessId();
+#else
+ const qulonglong processId = getpid();
+#endif
+ QByteArray s(QTime::currentTime().toString("HH:mm:ss.zzz").toLatin1());
+ s += " [";
+ s += QByteArray::number(processId);
+ s += "] ";
+
+ if (!f) {
+#if defined(Q_OS_WIN32)
+ f = new QFile("c:/service-debuglog.txt");
+#else
+ f = new QFile("/tmp/service-debuglog.txt");
+#endif
+ if (!f->open(QIODevice::WriteOnly | QIODevice::Append)) {
+ delete f;
+ f = 0;
+ return;
+ }
+ QByteArray ps('\n' + s + "--- DEBUG LOG OPENED ---\n");
+ f->write(ps);
+ }
+
+ switch (type) {
+ case QtWarningMsg:
+ s += "WARNING: ";
+ break;
+ case QtCriticalMsg:
+ s += "CRITICAL: ";
+ break;
+ case QtFatalMsg:
+ s+= "FATAL: ";
+ break;
+ case QtDebugMsg:
+ s += "DEBUG: ";
+ break;
+ default:
+ // Nothing
+ break;
+ }
+
+#if QT_VERSION >= 0x050400
+ s += qFormatLogMessage(type, context, msg).toLocal8Bit();
+#elif QT_VERSION >= 0x050000
+ s += msg.toLocal8Bit();
+ Q_UNUSED(context)
+#else
+ s += msg;
+#endif
+ s += '\n';
+
+ f->write(s);
+ f->flush();
+
+ if (type == QtFatalMsg) {
+ qtServiceCloseDebugLog();
+ exit(1);
+ }
+}
+
+#endif
+
+/*!
+ \class QtServiceController
+
+ \brief The QtServiceController class allows you to control
+ services from separate applications.
+
+ QtServiceController provides a collection of functions that lets
+ you install and run a service controlling its execution, as well
+ as query its status.
+
+ In order to run a service, the service must be installed in the
+ system's service database using the install() function. The system
+ will start the service depending on the specified StartupType; it
+ can either be started during system startup, or when a process
+ starts it manually.
+
+ Once a service is installed, the service can be run and controlled
+ manually using the start(), stop(), pause(), resume() or
+ sendCommand() functions. You can at any time query for the
+ service's status using the isInstalled() and isRunning()
+ functions, or you can query its properties using the
+ serviceDescription(), serviceFilePath(), serviceName() and
+ startupType() functions. For example:
+
+ \code
+ MyService service; \\ which inherits QtService
+ QString serviceFilePath;
+
+ QtServiceController controller(service.serviceName());
+
+ if (controller.install(serviceFilePath))
+ controller.start()
+
+ if (controller.isRunning())
+ QMessageBox::information(this, tr("Service Status"),
+ tr("The %1 service is started").arg(controller.serviceName()));
+
+ ...
+
+ controller.stop();
+ controller.uninstall();
+ }
+ \endcode
+
+ An instance of the service controller can only control one single
+ service. To control several services within one application, you
+ must create en equal number of service controllers.
+
+ The QtServiceController destructor neither stops nor uninstalls
+ the associated service. To stop a service the stop() function must
+ be called explicitly. To uninstall a service, you can use the
+ uninstall() function.
+
+ \sa QtServiceBase, QtService
+*/
+
+/*!
+ \enum QtServiceController::StartupType
+ This enum describes when a service should be started.
+
+ \value AutoStartup The service is started during system startup.
+ \value ManualStartup The service must be started manually by a process.
+
+ \warning The \a StartupType enum is ignored under UNIX-like
+ systems. A service, or daemon, can only be started manually on such
+ systems with current implementation.
+
+ \sa startupType()
+*/
+
+
+/*!
+ Creates a controller object for the service with the given
+ \a name.
+*/
+QtServiceController::QtServiceController(const QString &name)
+ : d_ptr(new QtServiceControllerPrivate())
+{
+ Q_D(QtServiceController);
+ d->q_ptr = this;
+ d->serviceName = name;
+}
+/*!
+ Destroys the service controller. This neither stops nor uninstalls
+ the controlled service.
+
+ To stop a service the stop() function must be called
+ explicitly. To uninstall a service, you can use the uninstall()
+ function.
+
+ \sa stop(), QtServiceController::uninstall()
+*/
+QtServiceController::~QtServiceController()
+{
+ delete d_ptr;
+}
+/*!
+ \fn bool QtServiceController::isInstalled() const
+
+ Returns true if the service is installed; otherwise returns false.
+
+ On Windows it uses the system's service control manager.
+
+ On Unix it checks configuration written to QSettings::SystemScope
+ using "QtSoftware" as organization name.
+
+ \sa install()
+*/
+
+/*!
+ \fn bool QtServiceController::isRunning() const
+
+ Returns true if the service is running; otherwise returns false. A
+ service must be installed before it can be run using a controller.
+
+ \sa start(), isInstalled()
+*/
+
+/*!
+ Returns the name of the controlled service.
+
+ \sa QtServiceController(), serviceDescription()
+*/
+QString QtServiceController::serviceName() const
+{
+ Q_D(const QtServiceController);
+ return d->serviceName;
+}
+/*!
+ \fn QString QtServiceController::serviceDescription() const
+
+ Returns the description of the controlled service.
+
+ \sa install(), serviceName()
+*/
+
+/*!
+ \fn QtServiceController::StartupType QtServiceController::startupType() const
+
+ Returns the startup type of the controlled service.
+
+ \sa install(), serviceName()
+*/
+
+/*!
+ \fn QString QtServiceController::serviceFilePath() const
+
+ Returns the file path to the controlled service.
+
+ \sa install(), serviceName()
+*/
+
+/*!
+ Installs the service with the given \a serviceFilePath
+ and returns true if the service is installed
+ successfully; otherwise returns false.
+
+ On Windows service is installed in the system's service control manager with the given
+ \a account and \a password.
+
+ On Unix service configuration is written to QSettings::SystemScope
+ using "QtSoftware" as organization name. \a account and \a password
+ arguments are ignored.
+
+ \warning Due to the different implementations of how services (daemons)
+ are installed on various UNIX-like systems, this method doesn't
+ integrate the service into the system's startup scripts.
+
+ \sa uninstall(), start()
+*/
+bool QtServiceController::install(const QString &serviceFilePath, const QString &account,
+ const QString &password)
+{
+ QStringList arguments;
+ arguments << QLatin1String("-i");
+ arguments << account;
+ arguments << password;
+ return (QProcess::execute(serviceFilePath, arguments) == 0);
+}
+
+
+/*!
+ \fn bool QtServiceController::uninstall()
+
+ Uninstalls the service and returns true if successful; otherwise returns false.
+
+ On Windows service is uninstalled using the system's service control manager.
+
+ On Unix service configuration is cleared using QSettings::SystemScope
+ with "QtSoftware" as organization name.
+
+
+ \sa install()
+*/
+
+/*!
+ \fn bool QtServiceController::start(const QStringList &arguments)
+
+ Starts the installed service passing the given \a arguments to the
+ service. A service must be installed before a controller can run it.
+
+ Returns true if the service could be started; otherwise returns
+ false.
+
+ \sa install(), stop()
+*/
+
+/*!
+ \overload
+
+ Starts the installed service without passing any arguments to the service.
+*/
+bool QtServiceController::start()
+{
+ return start(QStringList());
+}
+
+/*!
+ \fn bool QtServiceController::stop()
+
+ Requests the running service to stop. The service will call the
+ QtServiceBase::stop() implementation unless the service's state
+ is QtServiceBase::CannotBeStopped. This function does nothing if
+ the service is not running.
+
+ Returns true if a running service was successfully stopped;
+ otherwise false.
+
+ \sa start(), QtServiceBase::stop(), QtServiceBase::ServiceFlags
+*/
+
+/*!
+ \fn bool QtServiceController::pause()
+
+ Requests the running service to pause. If the service's state is
+ QtServiceBase::CanBeSuspended, the service will call the
+ QtServiceBase::pause() implementation. The function does nothing
+ if the service is not running.
+
+ Returns true if a running service was successfully paused;
+ otherwise returns false.
+
+ \sa resume(), QtServiceBase::pause(), QtServiceBase::ServiceFlags
+*/
+
+/*!
+ \fn bool QtServiceController::resume()
+
+ Requests the running service to continue. If the service's state
+ is QtServiceBase::CanBeSuspended, the service will call the
+ QtServiceBase::resume() implementation. This function does nothing
+ if the service is not running.
+
+ Returns true if a running service was successfully resumed;
+ otherwise returns false.
+
+ \sa pause(), QtServiceBase::resume(), QtServiceBase::ServiceFlags
+*/
+
+/*!
+ \fn bool QtServiceController::sendCommand(int code)
+
+ Sends the user command \a code to the service. The service will
+ call the QtServiceBase::processCommand() implementation. This
+ function does nothing if the service is not running.
+
+ Returns true if the request was sent to a running service;
+ otherwise returns false.
+
+ \sa QtServiceBase::processCommand()
+*/
+
+class QtServiceStarter : public QObject
+{
+ Q_OBJECT
+public:
+ QtServiceStarter(QtServiceBasePrivate *service)
+ : QObject(), d_ptr(service) {}
+public slots:
+ void slotStart()
+ {
+ d_ptr->startService();
+ }
+private:
+ QtServiceBasePrivate *d_ptr;
+};
+#include "qtservice.moc"
+
+QtServiceBase *QtServiceBasePrivate::instance = 0;
+
+QtServiceBasePrivate::QtServiceBasePrivate(const QString &name)
+ : startupType(QtServiceController::ManualStartup), serviceFlags(0), controller(name)
+{
+
+}
+
+QtServiceBasePrivate::~QtServiceBasePrivate()
+{
+
+}
+
+void QtServiceBasePrivate::startService()
+{
+ q_ptr->start();
+}
+
+int QtServiceBasePrivate::run(bool asService, const QStringList &argList)
+{
+ int argc = argList.size();
+ QVector argv(argc);
+ QList argvData;
+ for (int i = 0; i < argc; ++i)
+ argvData.append(argList.at(i).toLocal8Bit());
+ for (int i = 0; i < argc; ++i)
+ argv[i] = argvData[i].data();
+
+ if (asService && !sysInit())
+ return -1;
+
+ q_ptr->createApplication(argc, argv.data());
+ QCoreApplication *app = QCoreApplication::instance();
+ if (!app)
+ return -1;
+
+ if (asService)
+ sysSetPath();
+
+ QtServiceStarter starter(this);
+ QTimer::singleShot(0, &starter, SLOT(slotStart()));
+ int res = q_ptr->executeApplication();
+ delete app;
+
+ if (asService)
+ sysCleanup();
+ return res;
+}
+
+
+/*!
+ \class QtServiceBase
+
+ \brief The QtServiceBase class provides an API for implementing
+ Windows services and Unix daemons.
+
+ A Windows service or Unix daemon (a "service"), is a program that
+ runs "in the background" independently of whether a user is logged
+ in or not. A service is often set up to start when the machine
+ boots up, and will typically run continuously as long as the
+ machine is on.
+
+ Services are usually non-interactive console applications. User
+ interaction, if required, is usually implemented in a separate,
+ normal GUI application that communicates with the service through
+ an IPC channel. For simple communication,
+ QtServiceController::sendCommand() and QtService::processCommand()
+ may be used, possibly in combination with a shared settings
+ file. For more complex, interactive communication, a custom IPC
+ channel should be used, e.g. based on Qt's networking classes. (In
+ certain circumstances, a service may provide a GUI itself,
+ ref. the "interactive" example documentation).
+
+ Typically, you will create a service by subclassing the QtService
+ template class which inherits QtServiceBase and allows you to
+ create a service for a particular application type.
+
+ The Windows implementation uses the NT Service Control Manager,
+ and the application can be controlled through the system
+ administration tools. Services are usually launched using the
+ system account, which requires that all DLLs that the service
+ executable depends on (i.e. Qt), are located in the same directory
+ as the service, or in a system path.
+
+ On Unix a service is implemented as a daemon.
+
+ You can retrieve the service's description, state, and startup
+ type using the serviceDescription(), serviceFlags() and
+ startupType() functions respectively. The service's state is
+ decribed by the ServiceFlag enum. The mentioned properites can
+ also be set using the corresponding set functions. In addition you
+ can retrieve the service's name using the serviceName() function.
+
+ Several of QtServiceBase's protected functions are called on
+ requests from the QtServiceController class:
+
+ \list
+ \o start()
+ \o pause()
+ \o processCommand()
+ \o resume()
+ \o stop()
+ \endlist
+
+ You can control any given service using an instance of the
+ QtServiceController class which also allows you to control
+ services from separate applications. The mentioned functions are
+ all virtual and won't do anything unless they are
+ reimplemented. You can reimplement these functions to pause and
+ resume the service's execution, as well as process user commands
+ and perform additional clean-ups before shutting down.
+
+ QtServiceBase also provides the static instance() function which
+ returns a pointer to an application's QtServiceBase instance. In
+ addition, a service can report events to the system's event log
+ using the logMessage() function. The MessageType enum describes
+ the different types of messages a service reports.
+
+ The implementation of a service application's main function
+ typically creates an service object derived by subclassing the
+ QtService template class. Then the main function will call this
+ service's exec() function, and return the result of that call. For
+ example:
+
+ \code
+ int main(int argc, char **argv)
+ {
+ MyService service(argc, argv);
+ return service.exec();
+ }
+ \endcode
+
+ When the exec() function is called, it will parse the service
+ specific arguments passed in \c argv, perform the required
+ actions, and return.
+
+ \target serviceSpecificArguments
+
+ The following arguments are recognized as service specific:
+
+ \table
+ \header \i Short \i Long \i Explanation
+ \row \i -i \i -install \i Install the service.
+ \row \i -u \i -uninstall \i Uninstall the service.
+ \row \i -e \i -exec
+ \i Execute the service as a standalone application (useful for debug purposes).
+ This is a blocking call, the service will be executed like a normal application.
+ In this mode you will not be able to communicate with the service from the contoller.
+ \row \i -t \i -terminate \i Stop the service.
+ \row \i -p \i -pause \i Pause the service.
+ \row \i -r \i -resume \i Resume a paused service.
+ \row \i -c \e{cmd} \i -command \e{cmd}
+ \i Send the user defined command code \e{cmd} to the service application.
+ \row \i -v \i -version \i Display version and status information.
+ \endtable
+
+ If \e none of the arguments is recognized as service specific,
+ exec() will first call the createApplication() function, then
+ executeApplication() and finally the start() function. In the end,
+ exec() returns while the service continues in its own process
+ waiting for commands from the service controller.
+
+ \sa QtService, QtServiceController
+*/
+
+/*!
+ \enum QtServiceBase::MessageType
+
+ This enum describes the different types of messages a service
+ reports to the system log.
+
+ \value Success An operation has succeeded, e.g. the service
+ is started.
+ \value Error An operation failed, e.g. the service failed to start.
+ \value Warning An operation caused a warning that might require user
+ interaction.
+ \value Information Any type of usually non-critical information.
+*/
+
+/*!
+ \enum QtServiceBase::ServiceFlag
+
+ This enum describes the different capabilities of a service.
+
+ \value Default The service can be stopped, but not suspended.
+ \value CanBeSuspended The service can be suspended.
+ \value CannotBeStopped The service cannot be stopped.
+ \value NeedsStopOnShutdown (Windows only) The service will be stopped before the system shuts down. Note that Microsoft recommends this only for services that must absolutely clean up during shutdown, because there is a limited time available for shutdown of services.
+*/
+
+/*!
+ Creates a service instance called \a name. The \a argc and \a argv
+ parameters are parsed after the exec() function has been
+ called. Then they are passed to the application's constructor.
+ The application type is determined by the QtService subclass.
+
+ The service is neither installed nor started. The name must not
+ contain any backslashes or be longer than 255 characters. In
+ addition, the name must be unique in the system's service
+ database.
+
+ \sa exec(), start(), QtServiceController::install()
+*/
+QtServiceBase::QtServiceBase(int argc, char **argv, const QString &name)
+{
+#if defined(QTSERVICE_DEBUG)
+# if QT_VERSION >= 0x050000
+ qInstallMessageHandler(qtServiceLogDebug);
+# else
+ qInstallMsgHandler(qtServiceLogDebug);
+# endif
+ qAddPostRoutine(qtServiceCloseDebugLog);
+#endif
+
+ Q_ASSERT(!QtServiceBasePrivate::instance);
+ QtServiceBasePrivate::instance = this;
+
+ QString nm(name);
+ if (nm.length() > 255) {
+ qWarning("QtService: 'name' is longer than 255 characters.");
+ nm.truncate(255);
+ }
+ if (nm.contains('\\')) {
+ qWarning("QtService: 'name' contains backslashes '\\'.");
+ nm.replace((QChar)'\\', (QChar)'\0');
+ }
+
+ d_ptr = new QtServiceBasePrivate(nm);
+ d_ptr->q_ptr = this;
+
+ d_ptr->serviceFlags = 0;
+ d_ptr->sysd = 0;
+ for (int i = 0; i < argc; ++i)
+ d_ptr->args.append(QString::fromLocal8Bit(argv[i]));
+}
+
+/*!
+ Destroys the service object. This neither stops nor uninstalls the
+ service.
+
+ To stop a service the stop() function must be called
+ explicitly. To uninstall a service, you can use the
+ QtServiceController::uninstall() function.
+
+ \sa stop(), QtServiceController::uninstall()
+*/
+QtServiceBase::~QtServiceBase()
+{
+ delete d_ptr;
+ QtServiceBasePrivate::instance = 0;
+}
+
+/*!
+ Returns the name of the service.
+
+ \sa QtServiceBase(), serviceDescription()
+*/
+QString QtServiceBase::serviceName() const
+{
+ return d_ptr->controller.serviceName();
+}
+
+/*!
+ Returns the description of the service.
+
+ \sa setServiceDescription(), serviceName()
+*/
+QString QtServiceBase::serviceDescription() const
+{
+ return d_ptr->serviceDescription;
+}
+
+/*!
+ Sets the description of the service to the given \a description.
+
+ \sa serviceDescription()
+*/
+void QtServiceBase::setServiceDescription(const QString &description)
+{
+ d_ptr->serviceDescription = description;
+}
+
+/*!
+ Returns the service's startup type.
+
+ \sa QtServiceController::StartupType, setStartupType()
+*/
+QtServiceController::StartupType QtServiceBase::startupType() const
+{
+ return d_ptr->startupType;
+}
+
+/*!
+ Sets the service's startup type to the given \a type.
+
+ \sa QtServiceController::StartupType, startupType()
+*/
+void QtServiceBase::setStartupType(QtServiceController::StartupType type)
+{
+ d_ptr->startupType = type;
+}
+
+/*!
+ Returns the service's state which is decribed using the
+ ServiceFlag enum.
+
+ \sa ServiceFlags, setServiceFlags()
+*/
+QtServiceBase::ServiceFlags QtServiceBase::serviceFlags() const
+{
+ return d_ptr->serviceFlags;
+}
+
+/*!
+ \fn void QtServiceBase::setServiceFlags(ServiceFlags flags)
+
+ Sets the service's state to the state described by the given \a
+ flags.
+
+ \sa ServiceFlags, serviceFlags()
+*/
+
+/*!
+ Executes the service.
+
+ When the exec() function is called, it will parse the \l
+ {serviceSpecificArguments} {service specific arguments} passed in
+ \c argv, perform the required actions, and exit.
+
+ If none of the arguments is recognized as service specific, exec()
+ will first call the createApplication() function, then executeApplication() and
+ finally the start() function. In the end, exec()
+ returns while the service continues in its own process waiting for
+ commands from the service controller.
+
+ \sa QtServiceController
+*/
+int QtServiceBase::exec()
+{
+ if (d_ptr->args.size() > 1) {
+ QString a = d_ptr->args.at(1);
+ if (a == QLatin1String("-i") || a == QLatin1String("-install")) {
+ if (!d_ptr->controller.isInstalled()) {
+ QString account;
+ QString password;
+ if (d_ptr->args.size() > 2)
+ account = d_ptr->args.at(2);
+ if (d_ptr->args.size() > 3)
+ password = d_ptr->args.at(3);
+ if (!d_ptr->install(account, password)) {
+ fprintf(stderr, "The service %s could not be installed\n", serviceName().toLatin1().constData());
+ return -1;
+ } else {
+ printf("The service %s has been installed under: %s\n",
+ serviceName().toLatin1().constData(), d_ptr->filePath().toLatin1().constData());
+ }
+ } else {
+ fprintf(stderr, "The service %s is already installed\n", serviceName().toLatin1().constData());
+ }
+ return 0;
+ } else if (a == QLatin1String("-u") || a == QLatin1String("-uninstall")) {
+ if (d_ptr->controller.isInstalled()) {
+ if (!d_ptr->controller.uninstall()) {
+ fprintf(stderr, "The service %s could not be uninstalled\n", serviceName().toLatin1().constData());
+ return -1;
+ } else {
+ printf("The service %s has been uninstalled.\n",
+ serviceName().toLatin1().constData());
+ }
+ } else {
+ fprintf(stderr, "The service %s is not installed\n", serviceName().toLatin1().constData());
+ }
+ return 0;
+ } else if (a == QLatin1String("-v") || a == QLatin1String("-version")) {
+ printf("The service\n"
+ "\t%s\n\t%s\n\n", serviceName().toLatin1().constData(), d_ptr->args.at(0).toLatin1().constData());
+ printf("is %s", (d_ptr->controller.isInstalled() ? "installed" : "not installed"));
+ printf(" and %s\n\n", (d_ptr->controller.isRunning() ? "running" : "not running"));
+ return 0;
+ } else if (a == QLatin1String("-e") || a == QLatin1String("-exec")) {
+ d_ptr->args.removeAt(1);
+ int ec = d_ptr->run(false, d_ptr->args);
+ if (ec == -1)
+ qErrnoWarning("The service could not be executed.");
+ return ec;
+ } else if (a == QLatin1String("-t") || a == QLatin1String("-terminate")) {
+ if (!d_ptr->controller.stop())
+ qErrnoWarning("The service could not be stopped.");
+ return 0;
+ } else if (a == QLatin1String("-p") || a == QLatin1String("-pause")) {
+ d_ptr->controller.pause();
+ return 0;
+ } else if (a == QLatin1String("-r") || a == QLatin1String("-resume")) {
+ d_ptr->controller.resume();
+ return 0;
+ } else if (a == QLatin1String("-c") || a == QLatin1String("-command")) {
+ int code = 0;
+ if (d_ptr->args.size() > 2)
+ code = d_ptr->args.at(2).toInt();
+ d_ptr->controller.sendCommand(code);
+ return 0;
+ } else if (a == QLatin1String("-h") || a == QLatin1String("-help")) {
+ printf("\n%s -[i|u|e|t|p|r|c|v|h]\n"
+ "\t-i(nstall) [account] [password]\t: Install the service, optionally using given account and password\n"
+ "\t-u(ninstall)\t: Uninstall the service.\n"
+ "\t-e(xec)\t\t: Run as a regular application. Useful for debugging.\n"
+ "\t-t(erminate)\t: Stop the service.\n"
+ "\t-p(ause)\t: Pause the service.\n"
+ "\t-r(esume)\t: Resume a paused service.\n"
+ "\t-c(ommand) num\t: Send command code num to the service.\n"
+ "\t-v(ersion)\t: Print version and status information.\n"
+ "\t-h(elp) \t: Show this help\n"
+ "\tNo arguments\t: Start the service.\n",
+ d_ptr->args.at(0).toLatin1().constData());
+ return 0;
+ }
+ }
+#if defined(Q_OS_UNIX)
+ if (::getenv("QTSERVICE_RUN")) {
+ // Means we're the detached, real service process.
+ int ec = d_ptr->run(true, d_ptr->args);
+ if (ec == -1)
+ qErrnoWarning("The service failed to run.");
+ return ec;
+ }
+#endif
+ if (!d_ptr->start()) {
+ fprintf(stderr, "The service %s could not start\n", serviceName().toLatin1().constData());
+ return -4;
+ }
+ return 0;
+}
+
+/*!
+ \fn void QtServiceBase::logMessage(const QString &message, MessageType type,
+ int id, uint category, const QByteArray &data)
+
+ Reports a message of the given \a type with the given \a message
+ to the local system event log. The message identifier \a id and
+ the message \a category are user defined values. The \a data
+ parameter can contain arbitrary binary data.
+
+ Message strings for \a id and \a category must be provided by a
+ message file, which must be registered in the system registry.
+ Refer to the MSDN for more information about how to do this on
+ Windows.
+
+ \sa MessageType
+*/
+
+/*!
+ Returns a pointer to the current application's QtServiceBase
+ instance.
+*/
+QtServiceBase *QtServiceBase::instance()
+{
+ return QtServiceBasePrivate::instance;
+}
+
+/*!
+ \fn void QtServiceBase::start()
+
+ This function must be implemented in QtServiceBase subclasses in
+ order to perform the service's work. Usually you create some main
+ object on the heap which is the heart of your service.
+
+ The function is only called when no service specific arguments
+ were passed to the service constructor, and is called by exec()
+ after it has called the executeApplication() function.
+
+ Note that you \e don't need to create an application object or
+ call its exec() function explicitly.
+
+ \sa exec(), stop(), QtServiceController::start()
+*/
+
+/*!
+ Reimplement this function to perform additional cleanups before
+ shutting down (for example deleting a main object if it was
+ created in the start() function).
+
+ This function is called in reply to controller requests. The
+ default implementation does nothing.
+
+ \sa start(), QtServiceController::stop()
+*/
+void QtServiceBase::stop()
+{
+}
+
+/*!
+ Reimplement this function to pause the service's execution (for
+ example to stop a polling timer, or to ignore socket notifiers).
+
+ This function is called in reply to controller requests. The
+ default implementation does nothing.
+
+ \sa resume(), QtServiceController::pause()
+*/
+void QtServiceBase::pause()
+{
+}
+
+/*!
+ Reimplement this function to continue the service after a call to
+ pause().
+
+ This function is called in reply to controller requests. The
+ default implementation does nothing.
+
+ \sa pause(), QtServiceController::resume()
+*/
+void QtServiceBase::resume()
+{
+}
+
+/*!
+ Reimplement this function to process the user command \a code.
+
+
+ This function is called in reply to controller requests. The
+ default implementation does nothing.
+
+ \sa QtServiceController::sendCommand()
+*/
+void QtServiceBase::processCommand(int /*code*/)
+{
+}
+
+/*!
+ \fn void QtServiceBase::createApplication(int &argc, char **argv)
+
+ Creates the application object using the \a argc and \a argv
+ parameters.
+
+ This function is only called when no \l
+ {serviceSpecificArguments}{service specific arguments} were
+ passed to the service constructor, and is called by exec() before
+ it calls the executeApplication() and start() functions.
+
+ The createApplication() function is implemented in QtService, but
+ you might want to reimplement it, for example, if the chosen
+ application type's constructor needs additional arguments.
+
+ \sa exec(), QtService
+*/
+
+/*!
+ \fn int QtServiceBase::executeApplication()
+
+ Executes the application previously created with the
+ createApplication() function.
+
+ This function is only called when no \l
+ {serviceSpecificArguments}{service specific arguments} were
+ passed to the service constructor, and is called by exec() after
+ it has called the createApplication() function and before start() function.
+
+ This function is implemented in QtService.
+
+ \sa exec(), createApplication()
+*/
+
+/*!
+ \class QtService
+
+ \brief The QtService is a convenient template class that allows
+ you to create a service for a particular application type.
+
+ A Windows service or Unix daemon (a "service"), is a program that
+ runs "in the background" independently of whether a user is logged
+ in or not. A service is often set up to start when the machine
+ boots up, and will typically run continuously as long as the
+ machine is on.
+
+ Services are usually non-interactive console applications. User
+ interaction, if required, is usually implemented in a separate,
+ normal GUI application that communicates with the service through
+ an IPC channel. For simple communication,
+ QtServiceController::sendCommand() and QtService::processCommand()
+ may be used, possibly in combination with a shared settings file. For
+ more complex, interactive communication, a custom IPC channel
+ should be used, e.g. based on Qt's networking classes. (In certain
+ circumstances, a service may provide a GUI itself, ref. the
+ "interactive" example documentation).
+
+ \bold{Note:} On Unix systems, this class relies on facilities
+ provided by the QtNetwork module, provided as part of the
+ \l{Qt Open Source Edition} and certain \l{Qt Commercial Editions}.
+
+ The QtService class functionality is inherited from QtServiceBase,
+ but in addition the QtService class binds an instance of
+ QtServiceBase with an application type.
+
+ Typically, you will create a service by subclassing the QtService
+ template class. For example:
+
+ \code
+ class MyService : public QtService
+ {
+ public:
+ MyService(int argc, char **argv);
+ ~MyService();
+
+ protected:
+ void start();
+ void stop();
+ void pause();
+ void resume();
+ void processCommand(int code);
+ };
+ \endcode
+
+ The application type can be QCoreApplication for services without
+ GUI, QApplication for services with GUI or you can use your own
+ custom application type.
+
+ You must reimplement the QtServiceBase::start() function to
+ perform the service's work. Usually you create some main object on
+ the heap which is the heart of your service.
+
+ In addition, you might want to reimplement the
+ QtServiceBase::pause(), QtServiceBase::processCommand(),
+ QtServiceBase::resume() and QtServiceBase::stop() to intervene the
+ service's process on controller requests. You can control any
+ given service using an instance of the QtServiceController class
+ which also allows you to control services from separate
+ applications. The mentioned functions are all virtual and won't do
+ anything unless they are reimplemented.
+
+ Your custom service is typically instantiated in the application's
+ main function. Then the main function will call your service's
+ exec() function, and return the result of that call. For example:
+
+ \code
+ int main(int argc, char **argv)
+ {
+ MyService service(argc, argv);
+ return service.exec();
+ }
+ \endcode
+
+ When the exec() function is called, it will parse the \l
+ {serviceSpecificArguments} {service specific arguments} passed in
+ \c argv, perform the required actions, and exit.
+
+ If none of the arguments is recognized as service specific, exec()
+ will first call the createApplication() function, then executeApplication() and
+ finally the start() function. In the end, exec()
+ returns while the service continues in its own process waiting for
+ commands from the service controller.
+
+ \sa QtServiceBase, QtServiceController
+*/
+
+/*!
+ \fn QtService::QtService(int argc, char **argv, const QString &name)
+
+ Constructs a QtService object called \a name. The \a argc and \a
+ argv parameters are parsed after the exec() function has been
+ called. Then they are passed to the application's constructor.
+
+ There can only be one QtService object in a process.
+
+ \sa QtServiceBase()
+*/
+
+/*!
+ \fn QtService::~QtService()
+
+ Destroys the service object.
+*/
+
+/*!
+ \fn Application *QtService::application() const
+
+ Returns a pointer to the application object.
+*/
+
+/*!
+ \fn void QtService::createApplication(int &argc, char **argv)
+
+ Creates application object of type Application passing \a argc and
+ \a argv to its constructor.
+
+ \reimp
+
+*/
+
+/*!
+ \fn int QtService::executeApplication()
+
+ \reimp
+*/
diff --git a/src/QuickCutShared/QtService/qtservice.h b/src/QuickCutShared/QtService/qtservice.h
new file mode 100644
index 0000000..01d5b07
--- /dev/null
+++ b/src/QuickCutShared/QtService/qtservice.h
@@ -0,0 +1,192 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Solutions component.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTSERVICE_H
+#define QTSERVICE_H
+
+#include
+
+#if defined(Q_OS_WIN)
+# if !defined(QT_QTSERVICE_EXPORT) && !defined(QT_QTSERVICE_IMPORT)
+# define QT_QTSERVICE_EXPORT
+# elif defined(QT_QTSERVICE_IMPORT)
+# if defined(QT_QTSERVICE_EXPORT)
+# undef QT_QTSERVICE_EXPORT
+# endif
+# define QT_QTSERVICE_EXPORT __declspec(dllimport)
+# elif defined(QT_QTSERVICE_EXPORT)
+# undef QT_QTSERVICE_EXPORT
+# define QT_QTSERVICE_EXPORT __declspec(dllexport)
+# endif
+#else
+# define QT_QTSERVICE_EXPORT
+#endif
+
+class QStringList;
+class QtServiceControllerPrivate;
+
+class QT_QTSERVICE_EXPORT QtServiceController
+{
+ Q_DECLARE_PRIVATE(QtServiceController)
+public:
+ enum StartupType
+ {
+ AutoStartup = 0, ManualStartup
+ };
+
+ QtServiceController(const QString &name);
+ virtual ~QtServiceController();
+
+ bool isInstalled() const;
+ bool isRunning() const;
+
+ QString serviceName() const;
+ QString serviceDescription() const;
+ StartupType startupType() const;
+ QString serviceFilePath() const;
+
+ static bool install(const QString &serviceFilePath, const QString &account = QString(),
+ const QString &password = QString());
+ bool uninstall();
+
+ bool start(const QStringList &arguments);
+ bool start();
+ bool stop();
+ bool pause();
+ bool resume();
+ bool sendCommand(int code);
+
+private:
+ QtServiceControllerPrivate *d_ptr;
+};
+
+class QtServiceBasePrivate;
+
+class QT_QTSERVICE_EXPORT QtServiceBase
+{
+ Q_DECLARE_PRIVATE(QtServiceBase)
+public:
+
+ enum MessageType
+ {
+ Success = 0, Error, Warning, Information
+ };
+
+ enum ServiceFlag
+ {
+ Default = 0x00,
+ CanBeSuspended = 0x01,
+ CannotBeStopped = 0x02,
+ NeedsStopOnShutdown = 0x04
+ };
+
+ Q_DECLARE_FLAGS(ServiceFlags, ServiceFlag)
+
+ QtServiceBase(int argc, char **argv, const QString &name);
+ virtual ~QtServiceBase();
+
+ QString serviceName() const;
+
+ QString serviceDescription() const;
+ void setServiceDescription(const QString &description);
+
+ QtServiceController::StartupType startupType() const;
+ void setStartupType(QtServiceController::StartupType startupType);
+
+ ServiceFlags serviceFlags() const;
+ void setServiceFlags(ServiceFlags flags);
+
+ int exec();
+
+ void logMessage(const QString &message, MessageType type = Success,
+ int id = 0, uint category = 0, const QByteArray &data = QByteArray());
+
+ static QtServiceBase *instance();
+
+protected:
+
+ virtual void start() = 0;
+ virtual void stop();
+ virtual void pause();
+ virtual void resume();
+ virtual void processCommand(int code);
+
+ virtual void createApplication(int &argc, char **argv) = 0;
+
+ virtual int executeApplication() = 0;
+
+private:
+
+ friend class QtServiceSysPrivate;
+ QtServiceBasePrivate *d_ptr;
+};
+
+template
+class QtService : public QtServiceBase
+{
+public:
+ QtService(int argc, char **argv, const QString &name)
+ : QtServiceBase(argc, argv, name), app(0)
+ { }
+ ~QtService()
+ {
+ }
+
+protected:
+ Application *application() const
+ { return app; }
+
+ virtual void createApplication(int &argc, char **argv)
+ {
+ app = new Application(argc, argv);
+ QCoreApplication *a = app;
+ Q_UNUSED(a);
+ }
+
+ virtual int executeApplication()
+ { return Application::exec(); }
+
+private:
+ Application *app;
+};
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(QtServiceBase::ServiceFlags)
+
+#endif // QTSERVICE_H
diff --git a/src/QuickCutShared/QtService/qtservice.pri b/src/QuickCutShared/QtService/qtservice.pri
new file mode 100644
index 0000000..0945298
--- /dev/null
+++ b/src/QuickCutShared/QtService/qtservice.pri
@@ -0,0 +1,21 @@
+include(../common.pri)
+INCLUDEPATH += $$PWD
+DEPENDPATH += $$PWD
+!win32:QT += network
+win32:LIBS += -luser32
+
+qtservice-uselib:!qtservice-buildlib {
+ LIBS += -L$$QTSERVICE_LIBDIR -l$$QTSERVICE_LIBNAME
+} else {
+ HEADERS += $$PWD/qtservice.h \
+ $$PWD/qtservice_p.h
+ SOURCES += $$PWD/qtservice.cpp
+ win32:SOURCES += $$PWD/qtservice_win.cpp
+ unix:HEADERS += $$PWD/qtunixsocket.h $$PWD/qtunixserversocket.h
+ unix:SOURCES += $$PWD/qtservice_unix.cpp $$PWD/qtunixsocket.cpp $$PWD/qtunixserversocket.cpp
+}
+
+win32 {
+ qtservice-buildlib:shared:DEFINES += QT_QTSERVICE_EXPORT
+ else:qtservice-uselib:DEFINES += QT_QTSERVICE_IMPORT
+}
diff --git a/src/QuickCutShared/QtService/qtservice_p.h b/src/QuickCutShared/QtService/qtservice_p.h
new file mode 100644
index 0000000..a88992c
--- /dev/null
+++ b/src/QuickCutShared/QtService/qtservice_p.h
@@ -0,0 +1,87 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Solutions component.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTSERVICE_P_H
+#define QTSERVICE_P_H
+
+#include
+#include "qtservice.h"
+
+class QtServiceControllerPrivate
+{
+ Q_DECLARE_PUBLIC(QtServiceController)
+public:
+ QString serviceName;
+ QtServiceController *q_ptr;
+};
+
+class QtServiceBasePrivate
+{
+ Q_DECLARE_PUBLIC(QtServiceBase)
+public:
+
+ QtServiceBasePrivate(const QString &name);
+ ~QtServiceBasePrivate();
+
+ QtServiceBase *q_ptr;
+
+ QString serviceDescription;
+ QtServiceController::StartupType startupType;
+ QtServiceBase::ServiceFlags serviceFlags;
+ QStringList args;
+
+ static class QtServiceBase *instance;
+
+ QtServiceController controller;
+
+ void startService();
+ int run(bool asService, const QStringList &argList);
+ bool install(const QString &account, const QString &password);
+
+ bool start();
+
+ QString filePath() const;
+ bool sysInit();
+ void sysSetPath();
+ void sysCleanup();
+ class QtServiceSysPrivate *sysd;
+};
+
+#endif
diff --git a/src/QuickCutShared/QtService/qtservice_unix.cpp b/src/QuickCutShared/QtService/qtservice_unix.cpp
new file mode 100644
index 0000000..345acc6
--- /dev/null
+++ b/src/QuickCutShared/QtService/qtservice_unix.cpp
@@ -0,0 +1,482 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Solutions component.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtservice.h"
+#include "qtservice_p.h"
+#include "qtunixsocket.h"
+#include "qtunixserversocket.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+static QString encodeName(const QString &name, bool allowUpper = false)
+{
+ QString n = name.toLower();
+ QString legal = QLatin1String("abcdefghijklmnopqrstuvwxyz1234567890");
+ if (allowUpper)
+ legal += QLatin1String("ABCDEFGHIJKLMNOPQRSTUVWXYZ");
+ int pos = 0;
+ while (pos < n.size()) {
+ if (legal.indexOf(n[pos]) == -1)
+ n.remove(pos, 1);
+ else
+ ++pos;
+ }
+ return n;
+}
+
+static QString login()
+{
+ QString l;
+ uid_t uid = getuid();
+ passwd *pw = getpwuid(uid);
+ if (pw)
+ l = QString(pw->pw_name);
+ return l;
+}
+
+static QString socketPath(const QString &serviceName)
+{
+ QString sn = encodeName(serviceName);
+ return QString(QLatin1String("/var/tmp/") + sn + QLatin1String(".") + login());
+}
+
+static bool sendCmd(const QString &serviceName, const QString &cmd)
+{
+ bool retValue = false;
+ QtUnixSocket sock;
+ if (sock.connectTo(socketPath(serviceName))) {
+ sock.write(QString(cmd+"\r\n").toLatin1().constData());
+ sock.flush();
+ sock.waitForReadyRead(-1);
+ QString reply = sock.readAll();
+ if (reply == QLatin1String("true"))
+ retValue = true;
+ sock.close();
+ }
+ return retValue;
+}
+
+static QString absPath(const QString &path)
+{
+ QString ret;
+ if (path[0] != QChar('/')) { // Not an absolute path
+ int slashpos;
+ if ((slashpos = path.lastIndexOf('/')) != -1) { // Relative path
+ QDir dir = QDir::current();
+ dir.cd(path.left(slashpos));
+ ret = dir.absolutePath();
+ } else { // Need to search $PATH
+ char *envPath = ::getenv("PATH");
+ if (envPath) {
+ QStringList envPaths = QString::fromLocal8Bit(envPath).split(':');
+ for (int i = 0; i < envPaths.size(); ++i) {
+ if (QFile::exists(envPaths.at(i) + QLatin1String("/") + QString(path))) {
+ QDir dir(envPaths.at(i));
+ ret = dir.absolutePath();
+ break;
+ }
+ }
+ }
+ }
+ } else {
+ QFileInfo fi(path);
+ ret = fi.absolutePath();
+ }
+ return ret;
+}
+
+QString QtServiceBasePrivate::filePath() const
+{
+ QString ret;
+ if (args.isEmpty())
+ return ret;
+ QFileInfo fi(args[0]);
+ QDir dir(absPath(args[0]));
+ return dir.absoluteFilePath(fi.fileName());
+}
+
+
+QString QtServiceController::serviceDescription() const
+{
+ QSettings settings(QSettings::SystemScope, "QtSoftware");
+ settings.beginGroup("services");
+ settings.beginGroup(serviceName());
+
+ QString desc = settings.value("description").toString();
+
+ settings.endGroup();
+ settings.endGroup();
+
+ return desc;
+}
+
+QtServiceController::StartupType QtServiceController::startupType() const
+{
+ QSettings settings(QSettings::SystemScope, "QtSoftware");
+ settings.beginGroup("services");
+ settings.beginGroup(serviceName());
+
+ StartupType startupType = (StartupType)settings.value("startupType").toInt();
+
+ settings.endGroup();
+ settings.endGroup();
+
+ return startupType;
+}
+
+QString QtServiceController::serviceFilePath() const
+{
+ QSettings settings(QSettings::SystemScope, "QtSoftware");
+ settings.beginGroup("services");
+ settings.beginGroup(serviceName());
+
+ QString path = settings.value("path").toString();
+
+ settings.endGroup();
+ settings.endGroup();
+
+ return path;
+}
+
+bool QtServiceController::uninstall()
+{
+ QSettings settings(QSettings::SystemScope, "QtSoftware");
+ settings.beginGroup("services");
+
+ settings.remove(serviceName());
+
+ settings.endGroup();
+ settings.sync();
+
+ QSettings::Status ret = settings.status();
+ if (ret == QSettings::AccessError) {
+ fprintf(stderr, "Cannot uninstall \"%s\". Cannot write to: %s. Check permissions.\n",
+ serviceName().toLatin1().constData(),
+ settings.fileName().toLatin1().constData());
+ }
+ return (ret == QSettings::NoError);
+}
+
+
+bool QtServiceController::start(const QStringList &arguments)
+{
+ if (!isInstalled())
+ return false;
+ if (isRunning())
+ return false;
+ return QProcess::startDetached(serviceFilePath(), arguments);
+}
+
+bool QtServiceController::stop()
+{
+ return sendCmd(serviceName(), QLatin1String("terminate"));
+}
+
+bool QtServiceController::pause()
+{
+ return sendCmd(serviceName(), QLatin1String("pause"));
+}
+
+bool QtServiceController::resume()
+{
+ return sendCmd(serviceName(), QLatin1String("resume"));
+}
+
+bool QtServiceController::sendCommand(int code)
+{
+ return sendCmd(serviceName(), QString(QLatin1String("num:") + QString::number(code)));
+}
+
+bool QtServiceController::isInstalled() const
+{
+ QSettings settings(QSettings::SystemScope, "QtSoftware");
+ settings.beginGroup("services");
+
+ QStringList list = settings.childGroups();
+
+ settings.endGroup();
+
+ QStringListIterator it(list);
+ while (it.hasNext()) {
+ if (it.next() == serviceName())
+ return true;
+ }
+
+ return false;
+}
+
+bool QtServiceController::isRunning() const
+{
+ QtUnixSocket sock;
+ if (sock.connectTo(socketPath(serviceName())))
+ return true;
+ return false;
+}
+
+
+
+
+///////////////////////////////////
+
+class QtServiceSysPrivate : public QtUnixServerSocket
+{
+ Q_OBJECT
+public:
+ QtServiceSysPrivate();
+ ~QtServiceSysPrivate();
+
+ char *ident;
+
+ QtServiceBase::ServiceFlags serviceFlags;
+
+protected:
+#if QT_VERSION >= 0x050000
+ void incomingConnection(qintptr socketDescriptor);
+#else
+ void incomingConnection(int socketDescriptor);
+#endif
+
+private slots:
+ void slotReady();
+ void slotClosed();
+
+private:
+ QString getCommand(const QTcpSocket *socket);
+ QMap cache;
+};
+
+QtServiceSysPrivate::QtServiceSysPrivate()
+ : QtUnixServerSocket(), ident(0), serviceFlags(0)
+{
+}
+
+QtServiceSysPrivate::~QtServiceSysPrivate()
+{
+ if (ident)
+ delete[] ident;
+}
+
+#if QT_VERSION >= 0x050000
+void QtServiceSysPrivate::incomingConnection(qintptr socketDescriptor)
+#else
+void QtServiceSysPrivate::incomingConnection(int socketDescriptor)
+#endif
+{
+ QTcpSocket *s = new QTcpSocket(this);
+ s->setSocketDescriptor(socketDescriptor);
+ connect(s, SIGNAL(readyRead()), this, SLOT(slotReady()));
+ connect(s, SIGNAL(disconnected()), this, SLOT(slotClosed()));
+}
+
+void QtServiceSysPrivate::slotReady()
+{
+ QTcpSocket *s = (QTcpSocket *)sender();
+ cache[s] += QString(s->readAll());
+ QString cmd = getCommand(s);
+ while (!cmd.isEmpty()) {
+ bool retValue = false;
+ if (cmd == QLatin1String("terminate")) {
+ if (!(serviceFlags & QtServiceBase::CannotBeStopped)) {
+ QtServiceBase::instance()->stop();
+ QCoreApplication::instance()->quit();
+ retValue = true;
+ }
+ } else if (cmd == QLatin1String("pause")) {
+ if (serviceFlags & QtServiceBase::CanBeSuspended) {
+ QtServiceBase::instance()->pause();
+ retValue = true;
+ }
+ } else if (cmd == QLatin1String("resume")) {
+ if (serviceFlags & QtServiceBase::CanBeSuspended) {
+ QtServiceBase::instance()->resume();
+ retValue = true;
+ }
+ } else if (cmd == QLatin1String("alive")) {
+ retValue = true;
+ } else if (cmd.length() > 4 && cmd.left(4) == QLatin1String("num:")) {
+ cmd = cmd.mid(4);
+ QtServiceBase::instance()->processCommand(cmd.toInt());
+ retValue = true;
+ }
+ QString retString;
+ if (retValue)
+ retString = QLatin1String("true");
+ else
+ retString = QLatin1String("false");
+ s->write(retString.toLatin1().constData());
+ s->flush();
+ cmd = getCommand(s);
+ }
+}
+
+void QtServiceSysPrivate::slotClosed()
+{
+ QTcpSocket *s = (QTcpSocket *)sender();
+ s->deleteLater();
+}
+
+QString QtServiceSysPrivate::getCommand(const QTcpSocket *socket)
+{
+ int pos = cache[socket].indexOf("\r\n");
+ if (pos >= 0) {
+ QString ret = cache[socket].left(pos);
+ cache[socket].remove(0, pos+2);
+ return ret;
+ }
+ return "";
+}
+
+#include "qtservice_unix.moc"
+
+bool QtServiceBasePrivate::sysInit()
+{
+ sysd = new QtServiceSysPrivate;
+ sysd->serviceFlags = serviceFlags;
+ // Restrict permissions on files that are created by the service
+ ::umask(027);
+
+ return true;
+}
+
+void QtServiceBasePrivate::sysSetPath()
+{
+ if (sysd)
+ sysd->setPath(socketPath(controller.serviceName()));
+}
+
+void QtServiceBasePrivate::sysCleanup()
+{
+ if (sysd) {
+ sysd->close();
+ delete sysd;
+ sysd = 0;
+ }
+}
+
+bool QtServiceBasePrivate::start()
+{
+ if (sendCmd(controller.serviceName(), "alive")) {
+ // Already running
+ return false;
+ }
+ // Could just call controller.start() here, but that would fail if
+ // we're not installed. We do not want to strictly require installation.
+ ::setenv("QTSERVICE_RUN", "1", 1); // Tell the detached process it's it
+ return QProcess::startDetached(filePath(), args.mid(1), "/");
+}
+
+bool QtServiceBasePrivate::install(const QString &account, const QString &password)
+{
+ Q_UNUSED(account)
+ Q_UNUSED(password)
+ QSettings settings(QSettings::SystemScope, "QtSoftware");
+
+ settings.beginGroup("services");
+ settings.beginGroup(controller.serviceName());
+
+ settings.setValue("path", filePath());
+ settings.setValue("description", serviceDescription);
+ settings.setValue("automaticStartup", startupType);
+
+ settings.endGroup();
+ settings.endGroup();
+ settings.sync();
+
+ QSettings::Status ret = settings.status();
+ if (ret == QSettings::AccessError) {
+ fprintf(stderr, "Cannot install \"%s\". Cannot write to: %s. Check permissions.\n",
+ controller.serviceName().toLatin1().constData(),
+ settings.fileName().toLatin1().constData());
+ }
+ return (ret == QSettings::NoError);
+}
+
+void QtServiceBase::logMessage(const QString &message, QtServiceBase::MessageType type,
+ int, uint, const QByteArray &)
+{
+ if (!d_ptr->sysd)
+ return;
+ int st;
+ switch(type) {
+ case QtServiceBase::Error:
+ st = LOG_ERR;
+ break;
+ case QtServiceBase::Warning:
+ st = LOG_WARNING;
+ break;
+ default:
+ st = LOG_INFO;
+ }
+ if (!d_ptr->sysd->ident) {
+ QString tmp = encodeName(serviceName(), true);
+ int len = tmp.toLocal8Bit().size();
+ d_ptr->sysd->ident = new char[len+1];
+ d_ptr->sysd->ident[len] = '\0';
+ ::memcpy(d_ptr->sysd->ident, tmp.toLocal8Bit().constData(), len);
+ }
+ openlog(d_ptr->sysd->ident, LOG_PID, LOG_DAEMON);
+ foreach(QString line, message.split('\n'))
+ syslog(st, "%s", line.toLocal8Bit().constData());
+ closelog();
+}
+
+void QtServiceBase::setServiceFlags(QtServiceBase::ServiceFlags flags)
+{
+ if (d_ptr->serviceFlags == flags)
+ return;
+ d_ptr->serviceFlags = flags;
+ if (d_ptr->sysd)
+ d_ptr->sysd->serviceFlags = flags;
+}
+
diff --git a/src/QuickCutShared/QtService/qtservice_win.cpp b/src/QuickCutShared/QtService/qtservice_win.cpp
new file mode 100644
index 0000000..e5b7ecc
--- /dev/null
+++ b/src/QuickCutShared/QtService/qtservice_win.cpp
@@ -0,0 +1,952 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Solutions component.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtservice.h"
+#include "qtservice_p.h"
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#if QT_VERSION >= 0x050000
+# include
+#endif
+#include
+#if defined(QTSERVICE_DEBUG)
+#include
+#endif
+
+typedef SERVICE_STATUS_HANDLE(WINAPI*PRegisterServiceCtrlHandler)(const wchar_t*,LPHANDLER_FUNCTION);
+static PRegisterServiceCtrlHandler pRegisterServiceCtrlHandler = 0;
+typedef BOOL(WINAPI*PSetServiceStatus)(SERVICE_STATUS_HANDLE,LPSERVICE_STATUS);
+static PSetServiceStatus pSetServiceStatus = 0;
+typedef BOOL(WINAPI*PChangeServiceConfig2)(SC_HANDLE,DWORD,LPVOID);
+static PChangeServiceConfig2 pChangeServiceConfig2 = 0;
+typedef BOOL(WINAPI*PCloseServiceHandle)(SC_HANDLE);
+static PCloseServiceHandle pCloseServiceHandle = 0;
+typedef SC_HANDLE(WINAPI*PCreateService)(SC_HANDLE,LPCTSTR,LPCTSTR,DWORD,DWORD,DWORD,DWORD,LPCTSTR,LPCTSTR,LPDWORD,LPCTSTR,LPCTSTR,LPCTSTR);
+static PCreateService pCreateService = 0;
+typedef SC_HANDLE(WINAPI*POpenSCManager)(LPCTSTR,LPCTSTR,DWORD);
+static POpenSCManager pOpenSCManager = 0;
+typedef BOOL(WINAPI*PDeleteService)(SC_HANDLE);
+static PDeleteService pDeleteService = 0;
+typedef SC_HANDLE(WINAPI*POpenService)(SC_HANDLE,LPCTSTR,DWORD);
+static POpenService pOpenService = 0;
+typedef BOOL(WINAPI*PQueryServiceStatus)(SC_HANDLE,LPSERVICE_STATUS);
+static PQueryServiceStatus pQueryServiceStatus = 0;
+typedef BOOL(WINAPI*PStartServiceCtrlDispatcher)(CONST SERVICE_TABLE_ENTRY*);
+static PStartServiceCtrlDispatcher pStartServiceCtrlDispatcher = 0;
+typedef BOOL(WINAPI*PStartService)(SC_HANDLE,DWORD,const wchar_t**);
+static PStartService pStartService = 0;
+typedef BOOL(WINAPI*PControlService)(SC_HANDLE,DWORD,LPSERVICE_STATUS);
+static PControlService pControlService = 0;
+typedef HANDLE(WINAPI*PDeregisterEventSource)(HANDLE);
+static PDeregisterEventSource pDeregisterEventSource = 0;
+typedef BOOL(WINAPI*PReportEvent)(HANDLE,WORD,WORD,DWORD,PSID,WORD,DWORD,LPCTSTR*,LPVOID);
+static PReportEvent pReportEvent = 0;
+typedef HANDLE(WINAPI*PRegisterEventSource)(LPCTSTR,LPCTSTR);
+static PRegisterEventSource pRegisterEventSource = 0;
+typedef DWORD(WINAPI*PRegisterServiceProcess)(DWORD,DWORD);
+static PRegisterServiceProcess pRegisterServiceProcess = 0;
+typedef BOOL(WINAPI*PQueryServiceConfig)(SC_HANDLE,LPQUERY_SERVICE_CONFIG,DWORD,LPDWORD);
+static PQueryServiceConfig pQueryServiceConfig = 0;
+typedef BOOL(WINAPI*PQueryServiceConfig2)(SC_HANDLE,DWORD,LPBYTE,DWORD,LPDWORD);
+static PQueryServiceConfig2 pQueryServiceConfig2 = 0;
+
+
+#define RESOLVE(name) p##name = (P##name)lib.resolve(#name);
+#define RESOLVEA(name) p##name = (P##name)lib.resolve(#name"A");
+#define RESOLVEW(name) p##name = (P##name)lib.resolve(#name"W");
+
+static bool winServiceInit()
+{
+ if (!pOpenSCManager) {
+ QLibrary lib("advapi32");
+
+ // only resolve unicode versions
+ RESOLVEW(RegisterServiceCtrlHandler);
+ RESOLVE(SetServiceStatus);
+ RESOLVEW(ChangeServiceConfig2);
+ RESOLVE(CloseServiceHandle);
+ RESOLVEW(CreateService);
+ RESOLVEW(OpenSCManager);
+ RESOLVE(DeleteService);
+ RESOLVEW(OpenService);
+ RESOLVE(QueryServiceStatus);
+ RESOLVEW(StartServiceCtrlDispatcher);
+ RESOLVEW(StartService); // need only Ansi version
+ RESOLVE(ControlService);
+ RESOLVE(DeregisterEventSource);
+ RESOLVEW(ReportEvent);
+ RESOLVEW(RegisterEventSource);
+ RESOLVEW(QueryServiceConfig);
+ RESOLVEW(QueryServiceConfig2);
+ }
+ return pOpenSCManager != 0;
+}
+
+bool QtServiceController::isInstalled() const
+{
+ Q_D(const QtServiceController);
+ bool result = false;
+ if (!winServiceInit())
+ return result;
+
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, 0);
+ if (hSCM) {
+ // Try to open the service
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t*)d->serviceName.utf16(),
+ SERVICE_QUERY_CONFIG);
+
+ if (hService) {
+ result = true;
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+bool QtServiceController::isRunning() const
+{
+ Q_D(const QtServiceController);
+ bool result = false;
+ if (!winServiceInit())
+ return result;
+
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, 0);
+ if (hSCM) {
+ // Try to open the service
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(),
+ SERVICE_QUERY_STATUS);
+ if (hService) {
+ SERVICE_STATUS info;
+ int res = pQueryServiceStatus(hService, &info);
+ if (res)
+ result = info.dwCurrentState != SERVICE_STOPPED;
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+
+QString QtServiceController::serviceFilePath() const
+{
+ Q_D(const QtServiceController);
+ QString result;
+ if (!winServiceInit())
+ return result;
+
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, 0);
+ if (hSCM) {
+ // Try to open the service
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(),
+ SERVICE_QUERY_CONFIG);
+ if (hService) {
+ DWORD sizeNeeded = 0;
+ char data[8 * 1024];
+ if (pQueryServiceConfig(hService, (LPQUERY_SERVICE_CONFIG)data, 8 * 1024, &sizeNeeded)) {
+ LPQUERY_SERVICE_CONFIG config = (LPQUERY_SERVICE_CONFIG)data;
+ result = QString::fromUtf16((const ushort*)config->lpBinaryPathName);
+ }
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+QString QtServiceController::serviceDescription() const
+{
+ Q_D(const QtServiceController);
+ QString result;
+ if (!winServiceInit())
+ return result;
+
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, 0);
+ if (hSCM) {
+ // Try to open the service
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(),
+ SERVICE_QUERY_CONFIG);
+ if (hService) {
+ DWORD dwBytesNeeded;
+ char data[8 * 1024];
+ if (pQueryServiceConfig2(
+ hService,
+ SERVICE_CONFIG_DESCRIPTION,
+ (unsigned char *)data,
+ 8096,
+ &dwBytesNeeded)) {
+ LPSERVICE_DESCRIPTION desc = (LPSERVICE_DESCRIPTION)data;
+ if (desc->lpDescription)
+ result = QString::fromUtf16((const ushort*)desc->lpDescription);
+ }
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+QtServiceController::StartupType QtServiceController::startupType() const
+{
+ Q_D(const QtServiceController);
+ StartupType result = ManualStartup;
+ if (!winServiceInit())
+ return result;
+
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, 0);
+ if (hSCM) {
+ // Try to open the service
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(),
+ SERVICE_QUERY_CONFIG);
+ if (hService) {
+ DWORD sizeNeeded = 0;
+ char data[8 * 1024];
+ if (pQueryServiceConfig(hService, (QUERY_SERVICE_CONFIG *)data, 8 * 1024, &sizeNeeded)) {
+ QUERY_SERVICE_CONFIG *config = (QUERY_SERVICE_CONFIG *)data;
+ result = config->dwStartType == SERVICE_DEMAND_START ? ManualStartup : AutoStartup;
+ }
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+bool QtServiceController::uninstall()
+{
+ Q_D(QtServiceController);
+ bool result = false;
+ if (!winServiceInit())
+ return result;
+
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
+ if (hSCM) {
+ // Try to open the service
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), DELETE);
+ if (hService) {
+ if (pDeleteService(hService))
+ result = true;
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+bool QtServiceController::start(const QStringList &args)
+{
+ Q_D(QtServiceController);
+ bool result = false;
+ if (!winServiceInit())
+ return result;
+
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT);
+ if (hSCM) {
+ // Try to open the service
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), SERVICE_START);
+ if (hService) {
+ QVector argv(args.size());
+ for (int i = 0; i < args.size(); ++i)
+ argv[i] = (const wchar_t*)args.at(i).utf16();
+
+ if (pStartService(hService, args.size(), argv.data()))
+ result = true;
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+bool QtServiceController::stop()
+{
+ Q_D(QtServiceController);
+ bool result = false;
+ if (!winServiceInit())
+ return result;
+
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT);
+ if (hSCM) {
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(), SERVICE_STOP|SERVICE_QUERY_STATUS);
+ if (hService) {
+ SERVICE_STATUS status;
+ if (pControlService(hService, SERVICE_CONTROL_STOP, &status)) {
+ bool stopped = status.dwCurrentState == SERVICE_STOPPED;
+ int i = 0;
+ while(!stopped && i < 10) {
+ Sleep(200);
+ if (!pQueryServiceStatus(hService, &status))
+ break;
+ stopped = status.dwCurrentState == SERVICE_STOPPED;
+ ++i;
+ }
+ result = stopped;
+ } else {
+ qErrnoWarning(GetLastError(), "stopping");
+ }
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+bool QtServiceController::pause()
+{
+ Q_D(QtServiceController);
+ bool result = false;
+ if (!winServiceInit())
+ return result;
+
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT);
+ if (hSCM) {
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(),
+ SERVICE_PAUSE_CONTINUE);
+ if (hService) {
+ SERVICE_STATUS status;
+ if (pControlService(hService, SERVICE_CONTROL_PAUSE, &status))
+ result = true;
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+bool QtServiceController::resume()
+{
+ Q_D(QtServiceController);
+ bool result = false;
+ if (!winServiceInit())
+ return result;
+
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT);
+ if (hSCM) {
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(),
+ SERVICE_PAUSE_CONTINUE);
+ if (hService) {
+ SERVICE_STATUS status;
+ if (pControlService(hService, SERVICE_CONTROL_CONTINUE, &status))
+ result = true;
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+bool QtServiceController::sendCommand(int code)
+{
+ Q_D(QtServiceController);
+ bool result = false;
+ if (!winServiceInit())
+ return result;
+
+ if (code < 0 || code > 127 || !isRunning())
+ return result;
+
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_CONNECT);
+ if (hSCM) {
+ SC_HANDLE hService = pOpenService(hSCM, (wchar_t *)d->serviceName.utf16(),
+ SERVICE_USER_DEFINED_CONTROL);
+ if (hService) {
+ SERVICE_STATUS status;
+ if (pControlService(hService, 128 + code, &status))
+ result = true;
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+#if defined(QTSERVICE_DEBUG)
+# if QT_VERSION >= 0x050000
+extern void qtServiceLogDebug(QtMsgType type, const QMessageLogContext &context, const QString &msg);
+# else
+extern void qtServiceLogDebug(QtMsgType type, const char* msg);
+# endif
+#endif
+
+void QtServiceBase::logMessage(const QString &message, MessageType type,
+ int id, uint category, const QByteArray &data)
+{
+#if defined(QTSERVICE_DEBUG)
+ QByteArray dbgMsg("[LOGGED ");
+ switch (type) {
+ case Error: dbgMsg += "Error] " ; break;
+ case Warning: dbgMsg += "Warning] "; break;
+ case Success: dbgMsg += "Success] "; break;
+ case Information: //fall through
+ default: dbgMsg += "Information] "; break;
+ }
+# if QT_VERSION >= 0x050000
+ qtServiceLogDebug((QtMsgType)-1, QMessageLogContext(), QLatin1String(dbgMsg) + message);
+# else
+ qtServiceLogDebug((QtMsgType)-1, (dbgMsg + message.toAscii()).constData());
+# endif
+#endif
+
+ Q_D(QtServiceBase);
+ if (!winServiceInit())
+ return;
+ WORD wType;
+ switch (type) {
+ case Error: wType = EVENTLOG_ERROR_TYPE; break;
+ case Warning: wType = EVENTLOG_WARNING_TYPE; break;
+ case Information: wType = EVENTLOG_INFORMATION_TYPE; break;
+ default: wType = EVENTLOG_SUCCESS; break;
+ }
+ HANDLE h = pRegisterEventSource(0, (wchar_t *)d->controller.serviceName().utf16());
+ if (h) {
+ const wchar_t *msg = (wchar_t*)message.utf16();
+ const char *bindata = data.size() ? data.constData() : 0;
+ pReportEvent(h, wType, category, id, 0, 1, data.size(),(const wchar_t **)&msg,
+ const_cast(bindata));
+ pDeregisterEventSource(h);
+ }
+}
+
+class QtServiceControllerHandler : public QObject
+{
+ Q_OBJECT
+public:
+ QtServiceControllerHandler(QtServiceSysPrivate *sys);
+
+protected:
+ void customEvent(QEvent *e);
+
+private:
+ QtServiceSysPrivate *d_sys;
+};
+
+class QtServiceSysPrivate
+{
+public:
+ enum {
+ QTSERVICE_STARTUP = 256
+ };
+ QtServiceSysPrivate();
+
+ void setStatus( DWORD dwState );
+ void setServiceFlags(QtServiceBase::ServiceFlags flags);
+ DWORD serviceFlags(QtServiceBase::ServiceFlags flags) const;
+ inline bool available() const;
+ static void WINAPI serviceMain( DWORD dwArgc, wchar_t** lpszArgv );
+ static void WINAPI handler( DWORD dwOpcode );
+
+ SERVICE_STATUS status;
+ SERVICE_STATUS_HANDLE serviceStatus;
+ QStringList serviceArgs;
+
+ static QtServiceSysPrivate *instance;
+#if QT_VERSION < 0x050000
+ static QCoreApplication::EventFilter nextFilter;
+#endif
+
+ QWaitCondition condition;
+ QMutex mutex;
+ QSemaphore startSemaphore;
+ QSemaphore startSemaphore2;
+
+ QtServiceControllerHandler *controllerHandler;
+
+ void handleCustomEvent(QEvent *e);
+};
+
+QtServiceControllerHandler::QtServiceControllerHandler(QtServiceSysPrivate *sys)
+ : QObject(), d_sys(sys)
+{
+
+}
+
+void QtServiceControllerHandler::customEvent(QEvent *e)
+{
+ d_sys->handleCustomEvent(e);
+}
+
+
+QtServiceSysPrivate *QtServiceSysPrivate::instance = 0;
+#if QT_VERSION < 0x050000
+QCoreApplication::EventFilter QtServiceSysPrivate::nextFilter = 0;
+#endif
+
+QtServiceSysPrivate::QtServiceSysPrivate()
+{
+ instance = this;
+}
+
+inline bool QtServiceSysPrivate::available() const
+{
+ return 0 != pOpenSCManager;
+}
+
+void WINAPI QtServiceSysPrivate::serviceMain(DWORD dwArgc, wchar_t** lpszArgv)
+{
+ if (!instance || !QtServiceBase::instance())
+ return;
+
+ // Windows spins off a random thread to call this function on
+ // startup, so here we just signal to the QApplication event loop
+ // in the main thread to go ahead with start()'ing the service.
+
+ for (DWORD i = 0; i < dwArgc; i++)
+ instance->serviceArgs.append(QString::fromUtf16((unsigned short*)lpszArgv[i]));
+
+ instance->startSemaphore.release(); // let the qapp creation start
+ instance->startSemaphore2.acquire(); // wait until its done
+ // Register the control request handler
+ instance->serviceStatus = pRegisterServiceCtrlHandler((TCHAR*)QtServiceBase::instance()->serviceName().utf16(), handler);
+
+ if (!instance->serviceStatus) // cannot happen - something is utterly wrong
+ return;
+
+ handler(QTSERVICE_STARTUP); // Signal startup to the application -
+ // causes QtServiceBase::start() to be called in the main thread
+
+ // The MSDN doc says that this thread should just exit - the service is
+ // running in the main thread (here, via callbacks in the handler thread).
+}
+
+
+// The handler() is called from the thread that called
+// StartServiceCtrlDispatcher, i.e. our HandlerThread, and
+// not from the main thread that runs the event loop, so we
+// have to post an event to ourselves, and use a QWaitCondition
+// and a QMutex to synchronize.
+void QtServiceSysPrivate::handleCustomEvent(QEvent *e)
+{
+ int code = e->type() - QEvent::User;
+
+ switch(code) {
+ case QTSERVICE_STARTUP: // Startup
+ QtServiceBase::instance()->start();
+ break;
+ case SERVICE_CONTROL_STOP:
+ QtServiceBase::instance()->stop();
+ QCoreApplication::instance()->quit();
+ break;
+ case SERVICE_CONTROL_PAUSE:
+ QtServiceBase::instance()->pause();
+ break;
+ case SERVICE_CONTROL_CONTINUE:
+ QtServiceBase::instance()->resume();
+ break;
+ default:
+ if (code >= 128 && code <= 255)
+ QtServiceBase::instance()->processCommand(code - 128);
+ break;
+ }
+
+ mutex.lock();
+ condition.wakeAll();
+ mutex.unlock();
+}
+
+void WINAPI QtServiceSysPrivate::handler( DWORD code )
+{
+ if (!instance)
+ return;
+
+ instance->mutex.lock();
+ switch (code) {
+ case QTSERVICE_STARTUP: // QtService startup (called from WinMain when started)
+ instance->setStatus(SERVICE_START_PENDING);
+ QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code)));
+ instance->condition.wait(&instance->mutex);
+ instance->setStatus(SERVICE_RUNNING);
+ break;
+ case SERVICE_CONTROL_STOP: // 1
+ instance->setStatus(SERVICE_STOP_PENDING);
+ QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code)));
+ instance->condition.wait(&instance->mutex);
+ // status will be reported as stopped by start() when qapp::exec returns
+ break;
+
+ case SERVICE_CONTROL_PAUSE: // 2
+ instance->setStatus(SERVICE_PAUSE_PENDING);
+ QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code)));
+ instance->condition.wait(&instance->mutex);
+ instance->setStatus(SERVICE_PAUSED);
+ break;
+
+ case SERVICE_CONTROL_CONTINUE: // 3
+ instance->setStatus(SERVICE_CONTINUE_PENDING);
+ QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code)));
+ instance->condition.wait(&instance->mutex);
+ instance->setStatus(SERVICE_RUNNING);
+ break;
+
+ case SERVICE_CONTROL_INTERROGATE: // 4
+ break;
+
+ case SERVICE_CONTROL_SHUTDOWN: // 5
+ // Don't waste time with reporting stop pending, just do it
+ QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + SERVICE_CONTROL_STOP)));
+ instance->condition.wait(&instance->mutex);
+ // status will be reported as stopped by start() when qapp::exec returns
+ break;
+
+ default:
+ if ( code >= 128 && code <= 255 ) {
+ QCoreApplication::postEvent(instance->controllerHandler, new QEvent(QEvent::Type(QEvent::User + code)));
+ instance->condition.wait(&instance->mutex);
+ }
+ break;
+ }
+
+ instance->mutex.unlock();
+
+ // Report current status
+ if (instance->available() && instance->status.dwCurrentState != SERVICE_STOPPED)
+ pSetServiceStatus(instance->serviceStatus, &instance->status);
+}
+
+void QtServiceSysPrivate::setStatus(DWORD state)
+{
+ if (!available())
+ return;
+ status.dwCurrentState = state;
+ pSetServiceStatus(serviceStatus, &status);
+}
+
+void QtServiceSysPrivate::setServiceFlags(QtServiceBase::ServiceFlags flags)
+{
+ if (!available())
+ return;
+ status.dwControlsAccepted = serviceFlags(flags);
+ pSetServiceStatus(serviceStatus, &status);
+}
+
+DWORD QtServiceSysPrivate::serviceFlags(QtServiceBase::ServiceFlags flags) const
+{
+ DWORD control = 0;
+ if (flags & QtServiceBase::CanBeSuspended)
+ control |= SERVICE_ACCEPT_PAUSE_CONTINUE;
+ if (!(flags & QtServiceBase::CannotBeStopped))
+ control |= SERVICE_ACCEPT_STOP;
+ if (flags & QtServiceBase::NeedsStopOnShutdown)
+ control |= SERVICE_ACCEPT_SHUTDOWN;
+
+ return control;
+}
+
+#include "qtservice_win.moc"
+
+
+class HandlerThread : public QThread
+{
+public:
+ HandlerThread()
+ : success(true), console(false), QThread()
+ {}
+
+ bool calledOk() { return success; }
+ bool runningAsConsole() { return console; }
+
+protected:
+ bool success, console;
+ void run()
+ {
+ SERVICE_TABLE_ENTRYW st [2];
+ st[0].lpServiceName = (wchar_t*)QtServiceBase::instance()->serviceName().utf16();
+ st[0].lpServiceProc = QtServiceSysPrivate::serviceMain;
+ st[1].lpServiceName = 0;
+ st[1].lpServiceProc = 0;
+
+ success = (pStartServiceCtrlDispatcher(st) != 0); // should block
+
+ if (!success) {
+ if (GetLastError() == ERROR_FAILED_SERVICE_CONTROLLER_CONNECT) {
+ // Means we're started from console, not from service mgr
+ // start() will ask the mgr to start another instance of us as a service instead
+ console = true;
+ }
+ else {
+ QtServiceBase::instance()->logMessage(QString("The Service failed to start [%1]").arg(qt_error_string(GetLastError())), QtServiceBase::Error);
+ }
+ QtServiceSysPrivate::instance->startSemaphore.release(); // let start() continue, since serviceMain won't be doing it
+ }
+ }
+};
+
+/*
+ Ignore WM_ENDSESSION system events, since they make the Qt kernel quit
+*/
+
+#if QT_VERSION >= 0x050000
+
+class QtServiceAppEventFilter : public QAbstractNativeEventFilter
+{
+public:
+ QtServiceAppEventFilter() {}
+ bool nativeEventFilter(const QByteArray &eventType, void *message, long *result);
+};
+
+bool QtServiceAppEventFilter::nativeEventFilter(const QByteArray &, void *message, long *result)
+{
+ MSG *winMessage = (MSG*)message;
+ if (winMessage->message == WM_ENDSESSION && (winMessage->lParam & ENDSESSION_LOGOFF)) {
+ *result = TRUE;
+ return true;
+ }
+ return false;
+}
+
+Q_GLOBAL_STATIC(QtServiceAppEventFilter, qtServiceAppEventFilter)
+
+#else
+
+bool myEventFilter(void* message, long* result)
+{
+ MSG* msg = reinterpret_cast(message);
+ if (!msg || (msg->message != WM_ENDSESSION) || !(msg->lParam & ENDSESSION_LOGOFF))
+ return QtServiceSysPrivate::nextFilter ? QtServiceSysPrivate::nextFilter(message, result) : false;
+
+ if (QtServiceSysPrivate::nextFilter)
+ QtServiceSysPrivate::nextFilter(message, result);
+ if (result)
+ *result = TRUE;
+ return true;
+}
+
+#endif
+
+/* There are three ways we can be started:
+
+ - By a service controller (e.g. the Services control panel), with
+ no (service-specific) arguments. ServiceBase::exec() will then call
+ start() below, and the service will start.
+
+ - From the console, but with no (service-specific) arguments. This
+ means we should ask a controller to start the service (i.e. another
+ instance of this executable), and then just terminate. We discover
+ this case (as different from the above) by the fact that
+ StartServiceCtrlDispatcher will return an error, instead of blocking.
+
+ - From the console, with -e(xec) argument. ServiceBase::exec() will
+ then call ServiceBasePrivate::exec(), which calls
+ ServiceBasePrivate::run(), which runs the application as a normal
+ program.
+*/
+
+bool QtServiceBasePrivate::start()
+{
+ sysInit();
+ if (!winServiceInit())
+ return false;
+
+ // Since StartServiceCtrlDispatcher() blocks waiting for service
+ // control events, we need to call it in another thread, so that
+ // the main thread can run the QApplication event loop.
+ HandlerThread* ht = new HandlerThread();
+ ht->start();
+
+ QtServiceSysPrivate* sys = QtServiceSysPrivate::instance;
+
+ // Wait until service args have been received by serviceMain.
+ // If Windows doesn't call serviceMain (or
+ // StartServiceControlDispatcher doesn't return an error) within
+ // a timeout of 20 secs, something is very wrong; give up
+ if (!sys->startSemaphore.tryAcquire(1, 20000))
+ return false;
+
+ if (!ht->calledOk()) {
+ if (ht->runningAsConsole())
+ return controller.start(args.mid(1));
+ else
+ return false;
+ }
+
+ int argc = sys->serviceArgs.size();
+ QVector argv(argc);
+ QList argvData;
+ for (int i = 0; i < argc; ++i)
+ argvData.append(sys->serviceArgs.at(i).toLocal8Bit());
+ for (int i = 0; i < argc; ++i)
+ argv[i] = argvData[i].data();
+
+ q_ptr->createApplication(argc, argv.data());
+ QCoreApplication *app = QCoreApplication::instance();
+ if (!app)
+ return false;
+
+#if QT_VERSION >= 0x050000
+ QAbstractEventDispatcher::instance()->installNativeEventFilter(qtServiceAppEventFilter());
+#else
+ QtServiceSysPrivate::nextFilter = app->setEventFilter(myEventFilter);
+#endif
+
+ sys->controllerHandler = new QtServiceControllerHandler(sys);
+
+ sys->startSemaphore2.release(); // let serviceMain continue (and end)
+
+ sys->status.dwWin32ExitCode = q_ptr->executeApplication();
+ sys->setStatus(SERVICE_STOPPED);
+
+ if (ht->isRunning())
+ ht->wait(1000); // let the handler thread finish
+ delete sys->controllerHandler;
+ sys->controllerHandler = 0;
+ if (ht->isFinished())
+ delete ht;
+ delete app;
+ sysCleanup();
+ return true;
+}
+
+bool QtServiceBasePrivate::install(const QString &account, const QString &password)
+{
+ bool result = false;
+ if (!winServiceInit())
+ return result;
+
+ // Open the Service Control Manager
+ SC_HANDLE hSCM = pOpenSCManager(0, 0, SC_MANAGER_ALL_ACCESS);
+ if (hSCM) {
+ QString acc = account;
+ DWORD dwStartType = startupType == QtServiceController::AutoStartup ? SERVICE_AUTO_START : SERVICE_DEMAND_START;
+ DWORD dwServiceType = SERVICE_WIN32_OWN_PROCESS;
+ wchar_t *act = 0;
+ wchar_t *pwd = 0;
+ if (!acc.isEmpty()) {
+ // The act string must contain a string of the format "Domain\UserName",
+ // so if only a username was specified without a domain, default to the local machine domain.
+ if (!acc.contains(QChar('\\'))) {
+ acc.prepend(QLatin1String(".\\"));
+ }
+ if (!acc.endsWith(QLatin1String("\\LocalSystem")))
+ act = (wchar_t*)acc.utf16();
+ }
+ if (!password.isEmpty() && act) {
+ pwd = (wchar_t*)password.utf16();
+ }
+
+ // Only set INTERACTIVE if act is LocalSystem. (and act should be 0 if it is LocalSystem).
+ if (!act) dwServiceType |= SERVICE_INTERACTIVE_PROCESS;
+
+ // Create the service
+ SC_HANDLE hService = pCreateService(hSCM, (wchar_t *)controller.serviceName().utf16(),
+ (wchar_t *)controller.serviceName().utf16(),
+ SERVICE_ALL_ACCESS,
+ dwServiceType, // QObject::inherits ( const char * className ) for no inter active ????
+ dwStartType, SERVICE_ERROR_NORMAL, (wchar_t *)filePath().utf16(),
+ 0, 0, 0,
+ act, pwd);
+ if (hService) {
+ result = true;
+ if (!serviceDescription.isEmpty()) {
+ SERVICE_DESCRIPTION sdesc;
+ sdesc.lpDescription = (wchar_t *)serviceDescription.utf16();
+ pChangeServiceConfig2(hService, SERVICE_CONFIG_DESCRIPTION, &sdesc);
+ }
+ pCloseServiceHandle(hService);
+ }
+ pCloseServiceHandle(hSCM);
+ }
+ return result;
+}
+
+QString QtServiceBasePrivate::filePath() const
+{
+ wchar_t path[_MAX_PATH];
+ ::GetModuleFileNameW( 0, path, sizeof(path) );
+ return QString::fromUtf16((unsigned short*)path);
+}
+
+bool QtServiceBasePrivate::sysInit()
+{
+ sysd = new QtServiceSysPrivate();
+
+ sysd->serviceStatus = 0;
+ sysd->status.dwServiceType = SERVICE_WIN32_OWN_PROCESS|SERVICE_INTERACTIVE_PROCESS;
+ sysd->status.dwCurrentState = SERVICE_STOPPED;
+ sysd->status.dwControlsAccepted = sysd->serviceFlags(serviceFlags);
+ sysd->status.dwWin32ExitCode = NO_ERROR;
+ sysd->status.dwServiceSpecificExitCode = 0;
+ sysd->status.dwCheckPoint = 0;
+ sysd->status.dwWaitHint = 0;
+
+ return true;
+}
+
+void QtServiceBasePrivate::sysSetPath()
+{
+
+}
+
+void QtServiceBasePrivate::sysCleanup()
+{
+ if (sysd) {
+ delete sysd;
+ sysd = 0;
+ }
+}
+
+void QtServiceBase::setServiceFlags(QtServiceBase::ServiceFlags flags)
+{
+ if (d_ptr->serviceFlags == flags)
+ return;
+ d_ptr->serviceFlags = flags;
+ if (d_ptr->sysd)
+ d_ptr->sysd->setServiceFlags(flags);
+}
+
+
diff --git a/src/QuickCutShared/QtService/qtunixserversocket.cpp b/src/QuickCutShared/QtService/qtunixserversocket.cpp
new file mode 100644
index 0000000..0ad9134
--- /dev/null
+++ b/src/QuickCutShared/QtService/qtunixserversocket.cpp
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Solutions component.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtunixserversocket.h"
+#include
+#include
+#include
+#include
+#include
+
+#ifndef SUN_LEN
+#define SUN_LEN(ptr) ((size_t)(((struct sockaddr_un *) 0)->sun_path) \
+ +strlen ((ptr)->sun_path))
+#endif
+
+QtUnixServerSocket::QtUnixServerSocket(const QString &path, QObject *parent)
+ : QTcpServer(parent)
+{
+ setPath(path);
+}
+
+QtUnixServerSocket::QtUnixServerSocket(QObject *parent)
+ : QTcpServer(parent)
+{
+}
+
+void QtUnixServerSocket::setPath(const QString &path)
+{
+ path_.clear();
+
+ int sock = ::socket(PF_UNIX, SOCK_STREAM, 0);
+ if (sock != -1) {
+ struct sockaddr_un addr;
+ ::memset(&addr, 0, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ ::unlink(path.toLatin1().constData()); // ### This might need to be changed
+ unsigned int pathlen = strlen(path.toLatin1().constData());
+ if (pathlen > sizeof(addr.sun_path)) pathlen = sizeof(addr.sun_path);
+ ::memcpy(addr.sun_path, path.toLatin1().constData(), pathlen);
+ if ((::bind(sock, (struct sockaddr *)&addr, SUN_LEN(&addr)) != -1) &&
+ (::listen(sock, 5) != -1)) {
+ setSocketDescriptor(sock);
+ path_ = path;
+ }
+ }
+}
+
+void QtUnixServerSocket::close()
+{
+ QTcpServer::close();
+ if (!path_.isEmpty()) {
+ ::unlink(path_.toLatin1().constData());
+ path_.clear();
+ }
+}
diff --git a/src/QuickCutShared/QtService/qtunixserversocket.h b/src/QuickCutShared/QtService/qtunixserversocket.h
new file mode 100644
index 0000000..1fc8b70
--- /dev/null
+++ b/src/QuickCutShared/QtService/qtunixserversocket.h
@@ -0,0 +1,61 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Solutions component.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTUNIXSERVERSOCKET_H
+#define QTUNIXSERVERSOCKET_H
+
+#include
+
+class QtUnixServerSocket : public QTcpServer
+{
+ Q_OBJECT
+public:
+ QtUnixServerSocket(const QString &path, QObject *parent = 0);
+ QtUnixServerSocket(QObject *parent = 0);
+
+ void setPath(const QString &path);
+ void close();
+
+private:
+ QString path_;
+};
+
+
+#endif
diff --git a/src/QuickCutShared/QtService/qtunixsocket.cpp b/src/QuickCutShared/QtService/qtunixsocket.cpp
new file mode 100644
index 0000000..f6d4c97
--- /dev/null
+++ b/src/QuickCutShared/QtService/qtunixsocket.cpp
@@ -0,0 +1,78 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Solutions component.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "qtunixsocket.h"
+#include
+#include
+#include
+#include
+#include
+
+#ifndef SUN_LEN
+#define SUN_LEN(ptr) ((size_t)(((struct sockaddr_un *) 0)->sun_path) \
+ +strlen ((ptr)->sun_path))
+#endif
+
+QtUnixSocket::QtUnixSocket(QObject *parent)
+ : QTcpSocket(parent)
+{
+}
+
+bool QtUnixSocket::connectTo(const QString &path)
+{
+ bool ret = false;
+ int sock = ::socket(PF_UNIX, SOCK_STREAM, 0);
+ if (sock != -1) {
+ struct sockaddr_un addr;
+ ::memset(&addr, 0, sizeof(struct sockaddr_un));
+ addr.sun_family = AF_UNIX;
+ size_t pathlen = strlen(path.toLatin1().constData());
+ pathlen = qMin(pathlen, sizeof(addr.sun_path));
+ ::memcpy(addr.sun_path, path.toLatin1().constData(), pathlen);
+ int err = ::connect(sock, (struct sockaddr *)&addr, SUN_LEN(&addr));
+ if (err != -1) {
+ setSocketDescriptor(sock);
+ ret = true;
+ } else {
+ ::close(sock);
+ }
+ }
+ return ret;
+}
diff --git a/src/QuickCutShared/QtService/qtunixsocket.h b/src/QuickCutShared/QtService/qtunixsocket.h
new file mode 100644
index 0000000..1d34fba
--- /dev/null
+++ b/src/QuickCutShared/QtService/qtunixsocket.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
+** Contact: http://www.qt-project.org/legal
+**
+** This file is part of the Qt Solutions component.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** You may use this file under the terms of the BSD license as follows:
+**
+** "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.
+** * Neither the name of Digia Plc and its Subsidiary(-ies) nor the names
+** of its contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** 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
+** OWNER 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."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef QTUNIXSOCKET_H
+#define QTUNIXSOCKET_H
+
+#include
+
+class QtUnixSocket : public QTcpSocket
+{
+ Q_OBJECT
+public:
+ QtUnixSocket(QObject *parent = 0);
+
+ bool connectTo(const QString &path);
+};
+
+#endif
diff --git a/src/QuickCutShared/pch.h b/src/QuickCutShared/pch.h
new file mode 100644
index 0000000..f5a479f
--- /dev/null
+++ b/src/QuickCutShared/pch.h
@@ -0,0 +1,74 @@
+
+#pragma once
+
+
+#include
+#include
+#include
+
+#include
+#include
+#include
+
+namespace bpt = boost::property_tree;
+typedef bpt::ptree JSON;
+namespace boost { namespace property_tree {
+ inline void write_jsonEx(const std::string & path, const JSON & ptree)
+ {
+ std::ostringstream oss;
+ bpt::write_json(oss, ptree);
+ std::regex reg("\\\"([0-9]+\\.{0,1}[0-9]*)\\\"");
+ std::string result = std::regex_replace(oss.str(), reg, "$1");
+
+ std::ofstream file;
+ file.open(path);
+ file << result;
+ file.close();
+ }
+} }
+
+#ifdef Q_OS_WIN
+#define WIN32_LEAN_AND_MEAN
+#include
+namespace Hook {
+ /*
+ * The keyboard hook will check if this key pattern matched, if it matched,
+ * it will reload the profiles file so changes will take affect on the
+ * system without having to restart the application nor the service.
+ */
+ inline void sendReloadSignal()
+ {
+ const int INPUT_COUNT = 4;
+ int vkKey1 = std::strtol("82", nullptr, 16);
+ int vkKey2 = std::strtol("81", nullptr, 16);
+ INPUT in[INPUT_COUNT] = { 0 };
+ for (int i = 0; i < INPUT_COUNT; i++)
+ {
+ in[i].type = INPUT_KEYBOARD;
+ in[i].ki.dwFlags = KEYEVENTF_UNICODE;
+ in[i].ki.wVk = (i % 2 == 0) ? vkKey1 : vkKey2;
+ }
+ SendInput(INPUT_COUNT, in, sizeof(INPUT));
+
+ // Sending key up, which should reset the key codes pattern and profiles has been reloaded.
+ INPUT inUp = { 0 };
+ inUp.type = INPUT_KEYBOARD;
+ inUp.ki.dwFlags = KEYEVENTF_KEYUP;
+ inUp.ki.wVk = vkKey1;
+ SendInput(1, &inUp, sizeof(INPUT));
+ }
+}
+#endif
+
+inline std::string getDateTime()
+{
+ return QDateTime::currentDateTime().toString(Qt::DateFormat::ISODate).toStdString();
+}
+
+inline std::string createUuid()
+{
+ return QUuid::createUuid().toString().toStdString();
+}
+
+
+typedef std::string String;
\ No newline at end of file