diff --git a/GlosSIConfig/GlosSIConfig.vcxproj b/GlosSIConfig/GlosSIConfig.vcxproj
index 2a5107d..8ca3a14 100644
--- a/GlosSIConfig/GlosSIConfig.vcxproj
+++ b/GlosSIConfig/GlosSIConfig.vcxproj
@@ -68,7 +68,7 @@
..\deps\WinReg;%(AdditionalIncludeDirectories)
- PerMonitorHighDPIAware
+ true
$(ProjectDir)manifest.xml %(AdditionalManifestFiles)
@@ -86,7 +86,7 @@
..\deps\WinReg;%(AdditionalIncludeDirectories)
- PerMonitorHighDPIAware
+ true
$(ProjectDir)manifest.xml %(AdditionalManifestFiles)
diff --git a/GlosSIConfig/UIModel.cpp b/GlosSIConfig/UIModel.cpp
index ceded6e..7188cfb 100644
--- a/GlosSIConfig/UIModel.cpp
+++ b/GlosSIConfig/UIModel.cpp
@@ -16,7 +16,6 @@ limitations under the License.
#include "UIModel.h"
#include
-#include
#include
#ifdef _WIN32
@@ -34,7 +33,6 @@ using namespace Windows::Foundation::Collections;
#include
-#include "VDFParser.h"
#ifdef _WIN32
#include
#endif
@@ -86,7 +84,22 @@ void UIModel::readConfigs()
const auto data = file.readAll();
file.close();
const auto jsondoc = QJsonDocument::fromJson(data);
- const auto json = jsondoc.object();
+ const auto filejson = jsondoc.object();
+
+ QJsonObject json;
+ json["version"] = filejson["version"];
+ json["icon"] = filejson["icon"];
+ json["launch"] = filejson["launch"]["launch"];
+ json["launchPath"] = filejson["launch"]["launchPath"];
+ json["launchAppArgs"] = filejson["launch"]["launchAppArgs"];
+ json["closeOnExit"] = filejson["launch"]["closeOnExit"];
+ json["hideDevices"] = filejson["devices"]["hideDevices"];
+ json["windowMode"] = filejson["window"]["windowMode"];
+ json["maxFps"] = filejson["window"]["maxFps"];
+ json["scale"] = filejson["window"]["scale"];
+
+ json["name"] = QString(name).replace(QRegularExpression("\.json"), "");
+
targets_.append(json.toVariantMap());
});
@@ -101,22 +114,17 @@ QVariantList UIModel::getTargetList() const
void UIModel::addTarget(QVariant shortcut)
{
- // TODO: write config
const auto map = shortcut.toMap();
- const auto json = QJsonDocument(QJsonObject::fromVariantMap(map));
- auto wtf = json.toJson(QJsonDocument::Indented).toStdString();
-
- writeTarget(wtf, map["name"].toString());
-
- targets_.append(json.toVariant());
+ const auto json = QJsonObject::fromVariantMap(map);
+ writeTarget(json, map["name"].toString());
+ targets_.append(QJsonDocument(json).toVariant());
emit targetListChanged();
}
void UIModel::updateTarget(int index, QVariant shortcut)
{
const auto map = shortcut.toMap();
- const auto json = QJsonDocument(QJsonObject::fromVariantMap(map));
- auto wtf = json.toJson(QJsonDocument::Indented).toStdString();
+ const auto json = QJsonObject::fromVariantMap(map);
auto oldName = targets_[index].toMap()["name"].toString() + ".json";
auto path = config_path_;
@@ -124,10 +132,9 @@ void UIModel::updateTarget(int index, QVariant shortcut)
path /= (oldName).toStdString();
std::filesystem::remove(path);
- writeTarget(wtf, map["name"].toString());
-
+ writeTarget(json, map["name"].toString());
- targets_.replace(index, json.toVariant());
+ targets_.replace(index, QJsonDocument(json).toVariant());
emit targetListChanged();
}
@@ -142,6 +149,94 @@ void UIModel::deleteTarget(int index)
emit targetListChanged();
}
+bool UIModel::isInSteam(QVariant shortcut)
+{
+ const auto map = shortcut.toMap();
+ for (auto& steam_shortcut : shortcuts_vdf_.shortcuts)
+ {
+ if (map["name"].toString() == QString::fromStdString(steam_shortcut.appName.value))
+ {
+ if (QString::fromStdString(steam_shortcut.exe.value).toLower().contains("glossitarget.exe"))
+ {
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool UIModel::addToSteam(QVariant shortcut)
+{
+ QDir appDir = QDir::current();
+ const auto map = shortcut.toMap();
+ const auto name = map["name"].toString();
+ const auto maybeLaunchPath = map["launchPath"].toString();
+ const auto launch = map["launch"].toBool();
+
+ VDFParser::Shortcut vdfshortcut;
+ vdfshortcut.idx = shortcuts_vdf_.shortcuts.size();
+ vdfshortcut.appName.value = name.toStdString();
+ vdfshortcut.exe.value = ("\"" + appDir.absolutePath() + "/GlosSITarget.exe" + "\"").toStdString();
+ vdfshortcut.StartDir.value = (
+ launch && !maybeLaunchPath.isEmpty()
+ ? (std::string("\"") + std::filesystem::path(maybeLaunchPath.toStdString()).parent_path().string() + "\"")
+ : ("\"" + appDir.absolutePath() + "\"").toStdString()
+ );
+ vdfshortcut.appId.value = VDFParser::Parser::calculateAppId(vdfshortcut);
+ // ShortcutPath; default
+ vdfshortcut.LaunchOptions.value = (name + ".json").toStdString();
+ // IsHidden; default
+ // AllowDesktopConfig; default
+ // AllowOverlay; default
+ // openvr; default
+ // Devkit; default
+ // DevkitGameID; default
+ // DevkitOverrideAppID; default
+ // LastPlayTime; default
+ auto maybeIcon = map["icon"].toString();
+ if (maybeIcon.isEmpty())
+ {
+ if (launch && !maybeLaunchPath.isEmpty())
+ vdfshortcut.icon.value = maybeLaunchPath.toStdString();
+ } else {
+ vdfshortcut.icon.value = maybeIcon.toStdString();
+ }
+ // Add installed locally and GlosSI tag
+ VDFParser::ShortcutTag locallyTag;
+ locallyTag.idx = 0;
+ locallyTag.value = "Installed locally";
+ vdfshortcut.tags.value.push_back(locallyTag);
+
+ VDFParser::ShortcutTag glossitag;
+ glossitag.idx = 1;
+ glossitag.value = "GlosSI";
+ vdfshortcut.tags.value.push_back(glossitag);
+
+ shortcuts_vdf_.shortcuts.push_back(vdfshortcut);
+
+ const std::filesystem::path config_path = std::wstring(getSteamPath()) + user_data_path_.toStdWString() + getSteamUserId() + shortcutsfile_.toStdWString();
+ return VDFParser::Parser::writeShortcuts(config_path, shortcuts_vdf_);
+
+}
+bool UIModel::removeFromSteam(const QString& name)
+{
+ auto& scuts = shortcuts_vdf_.shortcuts;
+ scuts.erase(std::remove_if(scuts.begin(), scuts.end(), [&name](const auto& shortcut)
+ {
+ return shortcut.appName.value == name.toStdString();
+ }), scuts.end());
+ for (int i = 0; i < scuts.size(); i++)
+ {
+ if (scuts[i].idx != i)
+ {
+ scuts[i].idx = i;
+ }
+ }
+ const std::filesystem::path config_path = std::wstring(getSteamPath()) + user_data_path_.toStdWString() + getSteamUserId() + shortcutsfile_.toStdWString();
+ return VDFParser::Parser::writeShortcuts(config_path, shortcuts_vdf_);
+}
+
#ifdef _WIN32
QVariantList UIModel::uwpApps()
{
@@ -264,7 +359,7 @@ QVariantList UIModel::uwpApps()
if (SUCCEEDED(hr)) {
application->GetStringValue(L"Id", &appId);
application->GetStringValue(L"DisplayName", &manifestAppName);
- for (auto & logoNameStr : logoNames)
+ for (auto& logoNameStr : logoNames)
{
application->GetStringValue(logoNameStr.c_str(), &iconName);
if (!std::wstring(iconName).empty())
@@ -349,7 +444,7 @@ QVariantList UIModel::uwpApps()
std::vector possibleextensions = { ".scale-100", ".scale-125", ".scale-150", ".scale-200" };
if (!std::filesystem::exists(icoPath))
{
- for (const auto& ext: possibleextensions)
+ for (const auto& ext : possibleextensions)
{
QString maybeFname = QString(icoFName).replace(".png", ext + ".png");
std::filesystem::path maybePath(maybeFname.toStdString());
@@ -390,7 +485,7 @@ void UIModel::setAcrylicEffect(bool has_acrylic_affect)
emit acrylicChanged();
}
-void UIModel::writeTarget(const std::string& json, const QString& name)
+void UIModel::writeTarget(const QJsonObject& json, const QString& name)
{
auto path = config_path_;
path /= config_dir_name_.toStdString();
@@ -401,7 +496,29 @@ void UIModel::writeTarget(const std::string& json, const QString& name)
// meh
return;
}
- file.write(json.data());
+ QJsonObject fileJson;
+ fileJson["version"] = json["version"];
+ fileJson["icon"] = json["icon"];
+
+ QJsonObject launchObject;
+ launchObject["launch"] = json["launch"];
+ launchObject["launchPath"] = json["launchPath"];
+ launchObject["launchAppArgs"] = json["launchAppArgs"];
+ launchObject["closeOnExit"] = json["closeOnExit"];
+ fileJson["launch"] = launchObject;
+
+ QJsonObject devicesObject;
+ devicesObject["hideDevices"] = json["hideDevices"];
+ fileJson["devices"] = devicesObject;
+
+ QJsonObject windowObject;
+ windowObject["windowMode"] = json["windowMode"];
+ windowObject["maxFps"] = json["maxFps"];
+ windowObject["scale"] = json["scale"];
+ fileJson["window"] = windowObject;
+
+ auto wtf = QString(QJsonDocument(fileJson).toJson(QJsonDocument::Indented)).toStdString();
+ file.write(wtf.data());
file.close();
}
@@ -414,7 +531,7 @@ std::filesystem::path UIModel::getSteamPath() const
const auto res = key.GetStringValue(L"SteamPath");
return res;
#else
- return L""; // TODO
+ return L""; // TODO LINUX
#endif
}
@@ -427,15 +544,12 @@ std::wstring UIModel::getSteamUserId() const
const auto res = std::to_wstring(key.GetDwordValue(L"ActiveUser"));
return res;
#else
- return L""; // TODO
+ return L""; // TODO LINUX
#endif
}
void UIModel::parseShortcutVDF()
{
- const auto config_path = getSteamPath() /= user_data_path_.toStdWString() + getSteamUserId() + shortcutsfile_.toStdWString();
- auto wtf = VDFParser::Parser::parseShortcuts(config_path);
-
- int a = 0;
+ const std::filesystem::path config_path = std::wstring(getSteamPath()) + user_data_path_.toStdWString() + getSteamUserId() + shortcutsfile_.toStdWString();
+ shortcuts_vdf_ = VDFParser::Parser::parseShortcuts(config_path);
}
-
diff --git a/GlosSIConfig/UIModel.h b/GlosSIConfig/UIModel.h
index 81922d5..19d09db 100644
--- a/GlosSIConfig/UIModel.h
+++ b/GlosSIConfig/UIModel.h
@@ -17,6 +17,9 @@ limitations under the License.
#include
#include
#include
+#include
+#include "VDFParser.h"
+
class UIModel : public QObject
{
@@ -35,6 +38,9 @@ public:
Q_INVOKABLE void addTarget(QVariant shortcut);
Q_INVOKABLE void updateTarget(int index, QVariant shortcut);
Q_INVOKABLE void deleteTarget(int index);
+ Q_INVOKABLE bool isInSteam(QVariant shortcut);
+ Q_INVOKABLE bool addToSteam(QVariant shortcut);
+ Q_INVOKABLE bool removeFromSteam(const QString& name);
#ifdef _WIN32
Q_INVOKABLE QVariantList uwpApps();
#endif
@@ -51,7 +57,7 @@ private:
std::filesystem::path config_path_;
QString config_dir_name_;
- void writeTarget(const std::string& json, const QString& name);
+ void writeTarget(const QJsonObject& json, const QString& name);
std::filesystem::path getSteamPath() const;
@@ -62,6 +68,8 @@ private:
QVariantList targets_;
+ VDFParser::VDFFile shortcuts_vdf_;
+
#ifdef _WIN32
bool is_windows_ = true;
#else
diff --git a/GlosSIConfig/qml/ShortcutCards.qml b/GlosSIConfig/qml/ShortcutCards.qml
index 8065647..7bf4662 100644
--- a/GlosSIConfig/qml/ShortcutCards.qml
+++ b/GlosSIConfig/qml/ShortcutCards.qml
@@ -65,6 +65,7 @@ GridView {
}
delegate: RPane {
+ id: delegateRoot
color: Qt.lighter(Material.background, 1.6)
bgOpacity: 0.3
radius: 8
@@ -72,6 +73,7 @@ GridView {
height: 190
Material.elevation: 4
clip: true
+ property bool isInSteam: uiModel.isInSteam(modelData);
Label {
id: label
anchors.top: parent.top
@@ -86,7 +88,7 @@ GridView {
Column {
anchors.top: label.bottom
anchors.left: parent.left
- anchors.bottom: row.top
+ anchors.bottom: buttonrow.top
anchors.margins: 12
spacing: 4
Row {
@@ -112,17 +114,45 @@ GridView {
}
}
+ Image {
+ anchors.right: parent.right
+ anchors.bottom: buttonrow.top
+ id: maybeIcon
+ anchors.bottomMargin: 8
+ source: modelData.icon ? "file:///" + modelData.icon : null
+ // TODO: extract exe icons.
+ width: 48
+ height: 48
+ visible: modelData.icon
+ }
+
Button {
+ id: steambutton
anchors.left: parent.left
anchors.bottom: parent.bottom
width: 72
- onClicked: console.log("TODO") // TODO
+ onClicked: function(){
+ if (delegateRoot.isInSteam) {
+ if (!uiModel.removeFromSteam(modelData.name)) {
+ // TODO: show error
+ return;
+ }
+ } else {
+ if (!uiModel.addToSteam(modelData)) {
+ // TODO: show error
+ return;
+ }
+ }
+ delegateRoot.isInSteam = uiModel.isInSteam(modelData)
+ }
+ highlighted: delegateRoot.isInSteam
+ Material.accent: Material.color(Material.Red, Material.Shade400)
Row {
anchors.centerIn: parent
spacing: 8
Label {
anchors.verticalCenter: parent.verticalCenter
- text: "+"
+ text: delegateRoot.isInSteam ? "-" : "+"
font.bold: true
font.pixelSize: 24
}
@@ -143,7 +173,7 @@ GridView {
}
Row {
- id: row
+ id: buttonrow
anchors.right: parent.right
anchors.bottom: parent.bottom
spacing: 4
diff --git a/GlosSIConfig/qml/ShortcutProps.qml b/GlosSIConfig/qml/ShortcutProps.qml
index 9f70916..7db0a60 100644
--- a/GlosSIConfig/qml/ShortcutProps.qml
+++ b/GlosSIConfig/qml/ShortcutProps.qml
@@ -39,7 +39,8 @@ Item {
hideDevices: true,
windowMode: false,
maxFps: null,
- scale: null
+ scale: null,
+ icon: null,
})
function resetInfo() {
@@ -53,7 +54,8 @@ Item {
hideDevices: true,
windowMode: false,
maxFps: null,
- scale: null
+ scale: null,
+ icon: null,
})
}
@@ -286,6 +288,9 @@ Item {
if (nameInput.text == "") {
nameInput.text = modelData.AppName
}
+ if (modelData.IconPath) {
+ shortcutInfo.icon = modelData.IconPath
+ }
pathInput.text = modelData.AppUMId
launchApp.checked = true
}
diff --git a/GlosSITarget/example_conf.json b/GlosSITarget/example_conf.json
index df5033d..8322118 100644
--- a/GlosSITarget/example_conf.json
+++ b/GlosSITarget/example_conf.json
@@ -13,5 +13,6 @@
"windowMode": false,
"maxFps": null,
"scale": null
- }
+ },
+ "icon": null
}
\ No newline at end of file