mirror of https://github.com/bsnes-emu/bsnes.git
308 lines
10 KiB
C++
308 lines
10 KiB
C++
|
#include "interface.hpp"
|
||
|
Application *application = nullptr;
|
||
|
RuleEditor *ruleEditor = nullptr;
|
||
|
|
||
|
#include "resource/resource.hpp"
|
||
|
#include "resource/resource.cpp"
|
||
|
|
||
|
Application::Application(const string &pathname) : pathname(pathname) {
|
||
|
setTitle("kaijuu v05");
|
||
|
setFrameGeometry({64, 64, 725, 480});
|
||
|
|
||
|
layout.setMargin(5);
|
||
|
statusLabel.setFont("Tahoma, 8, Bold");
|
||
|
uninstallButton.setText("Uninstall");
|
||
|
installButton.setText("Install");
|
||
|
settingList.setHeaderText("Name", "Default", "Match", "Pattern", "Command");
|
||
|
settingList.setHeaderVisible();
|
||
|
appendButton.setText("Append");
|
||
|
modifyButton.setText("Modify");
|
||
|
moveUpButton.setText("Move Up");
|
||
|
moveDownButton.setText("Move Down");
|
||
|
removeButton.setText("Remove");
|
||
|
resetButton.setText("Reset");
|
||
|
helpButton.setText("Help ...");
|
||
|
|
||
|
append(layout);
|
||
|
layout.append(installLayout, {~0, 0}, 5);
|
||
|
installLayout.append(statusLabel, {~0, 0}, 5);
|
||
|
installLayout.append(uninstallButton, {80, 0}, 5);
|
||
|
installLayout.append(installButton, {80, 0});
|
||
|
layout.append(settingLayout, {~0, ~0});
|
||
|
settingLayout.append(settingList, {~0, ~0}, 5);
|
||
|
settingLayout.append(controlLayout, {0, ~0});
|
||
|
controlLayout.append(appendButton, {80, 0}, 5);
|
||
|
controlLayout.append(modifyButton, {80, 0}, 5);
|
||
|
controlLayout.append(moveUpButton, {80, 0}, 5);
|
||
|
controlLayout.append(moveDownButton, {80, 0}, 5);
|
||
|
controlLayout.append(removeButton, {80, 0}, 5);
|
||
|
controlLayout.append(spacer, {0, ~0});
|
||
|
controlLayout.append(resetButton, {80, 0}, 5);
|
||
|
controlLayout.append(helpButton, {80, 0}, 5);
|
||
|
controlLayout.append(canvas, {80, 88});
|
||
|
|
||
|
canvas.setImage({resource::icon, sizeof resource::icon});
|
||
|
canvas.update();
|
||
|
|
||
|
onClose = &OS::quit;
|
||
|
installButton.onActivate = {&Application::install, this};
|
||
|
uninstallButton.onActivate = {&Application::uninstall, this};
|
||
|
settingList.onActivate = {&Application::modifyAction, this};
|
||
|
settingList.onChange = {&Application::synchronize, this};
|
||
|
appendButton.onActivate = {&Application::appendAction, this};
|
||
|
modifyButton.onActivate = {&Application::modifyAction, this};
|
||
|
moveUpButton.onActivate = {&Application::moveUpAction, this};
|
||
|
moveDownButton.onActivate = {&Application::moveDownAction, this};
|
||
|
removeButton.onActivate = {&Application::removeAction, this};
|
||
|
resetButton.onActivate = {&Application::resetAction, this};
|
||
|
helpButton.onActivate = [&] { nall::invoke("kaijuu.html"); };
|
||
|
refresh();
|
||
|
synchronize();
|
||
|
setVisible();
|
||
|
}
|
||
|
|
||
|
void Application::synchronize() {
|
||
|
if(registry::read({"HKLM/Software/Microsoft/Windows/CurrentVersion/Shell Extensions/Approved/", classID}) == classDescription) {
|
||
|
statusLabel.setText("Extension status: installed");
|
||
|
installButton.setEnabled(false);
|
||
|
uninstallButton.setEnabled(true);
|
||
|
} else {
|
||
|
statusLabel.setText("Extension status: not installed");
|
||
|
installButton.setEnabled(true);
|
||
|
uninstallButton.setEnabled(false);
|
||
|
}
|
||
|
modifyButton.setEnabled(settingList.selected());
|
||
|
moveUpButton.setEnabled(settingList.selected() && settings.rules.size() > 1 && settingList.selection() != 0);
|
||
|
moveDownButton.setEnabled(settingList.selected() && settings.rules.size() > 1 && settingList.selection() < settings.rules.size() - 1);
|
||
|
removeButton.setEnabled(settingList.selected());
|
||
|
resetButton.setEnabled(settings.rules.size() > 0);
|
||
|
}
|
||
|
|
||
|
void Application::refresh() {
|
||
|
settings.load();
|
||
|
settingList.reset();
|
||
|
for(auto &rule : settings.rules) {
|
||
|
string match = "Nothing";
|
||
|
if(rule.matchFiles && rule.matchFolders) match = "Everything";
|
||
|
else if(rule.matchFiles) match = "Files";
|
||
|
else if(rule.matchFolders) match = "Folders";
|
||
|
settingList.append(rule.name, rule.defaultAction ? "Yes" : "No", match, rule.pattern, rule.command);
|
||
|
}
|
||
|
settingList.autoSizeColumns();
|
||
|
}
|
||
|
|
||
|
void Application::install() {
|
||
|
string command = {"regsvr32 \"", pathname, classDriver, "\""};
|
||
|
_wsystem(utf16_t(command));
|
||
|
synchronize();
|
||
|
}
|
||
|
|
||
|
void Application::uninstall() {
|
||
|
string command = {"regsvr32 /u \"", pathname, classDriver, "\""};
|
||
|
_wsystem(utf16_t(command));
|
||
|
synchronize();
|
||
|
}
|
||
|
|
||
|
void Application::appendAction() {
|
||
|
ruleEditor->show();
|
||
|
}
|
||
|
|
||
|
void Application::modifyAction() {
|
||
|
if(settingList.selected() == false) return;
|
||
|
unsigned selection = settingList.selection();
|
||
|
ruleEditor->show(selection);
|
||
|
}
|
||
|
|
||
|
void Application::moveUpAction() {
|
||
|
if(settingList.selected() == false) return;
|
||
|
if(settingList.selection() == 0) return;
|
||
|
unsigned selection = settingList.selection();
|
||
|
auto temp = settings.rules(selection - 1);
|
||
|
settings.rules(selection - 1) = settings.rules(selection);
|
||
|
settings.rules(selection) = temp;
|
||
|
settings.save();
|
||
|
refresh();
|
||
|
settingList.setSelection(selection - 1);
|
||
|
synchronize();
|
||
|
}
|
||
|
|
||
|
void Application::moveDownAction() {
|
||
|
if(settingList.selected() == false) return;
|
||
|
if(settingList.selection() >= settings.rules.size() - 1) return;
|
||
|
unsigned selection = settingList.selection();
|
||
|
auto temp = settings.rules(selection + 1);
|
||
|
settings.rules(selection + 1) = settings.rules(selection);
|
||
|
settings.rules(selection) = temp;
|
||
|
settings.save();
|
||
|
refresh();
|
||
|
settingList.setSelection(selection + 1);
|
||
|
synchronize();
|
||
|
}
|
||
|
|
||
|
void Application::removeAction() {
|
||
|
if(settingList.selected() == false) return;
|
||
|
unsigned selection = settingList.selection();
|
||
|
settings.rules.remove(selection);
|
||
|
settings.save();
|
||
|
refresh();
|
||
|
synchronize();
|
||
|
}
|
||
|
|
||
|
void Application::resetAction() {
|
||
|
if(MessageWindow::question(*this, "Warning: this will permanently remove all rules! Are you sure you want to do this?")
|
||
|
== MessageWindow::Response::No) return;
|
||
|
settings.rules.reset();
|
||
|
settings.save();
|
||
|
refresh();
|
||
|
synchronize();
|
||
|
}
|
||
|
|
||
|
RuleEditor::RuleEditor() : index(-1) {
|
||
|
setTitle("Rule Editor");
|
||
|
setFrameGeometry({128, 256, 500, 160});
|
||
|
|
||
|
layout.setMargin(5);
|
||
|
nameLabel.setText("Name:");
|
||
|
patternLabel.setText("Pattern:");
|
||
|
commandLabel.setText("Command:");
|
||
|
commandSelect.setText("Select ...");
|
||
|
defaultAction.setText("Default Action");
|
||
|
filesAction.setText("Match Files");
|
||
|
foldersAction.setText("Match Folders");
|
||
|
assignButton.setText("Assign");
|
||
|
|
||
|
Font font("Tahoma, 8");
|
||
|
unsigned length = 0;
|
||
|
length = max(length, font.geometry("Name:").width);
|
||
|
length = max(length, font.geometry("Pattern:").width);
|
||
|
length = max(length, font.geometry("Command:").width);
|
||
|
|
||
|
append(layout);
|
||
|
layout.append(nameLayout, {~0, 0}, 5);
|
||
|
nameLayout.append(nameLabel, {length, 0}, 5);
|
||
|
nameLayout.append(nameValue, {~0, 0});
|
||
|
layout.append(patternLayout, {~0, 0}, 5);
|
||
|
patternLayout.append(patternLabel, {length, 0}, 5);
|
||
|
patternLayout.append(patternValue, {~0, 0});
|
||
|
layout.append(commandLayout, {~0, 0}, 5);
|
||
|
commandLayout.append(commandLabel, {length, 0}, 5);
|
||
|
commandLayout.append(commandValue, {~0, 0}, 5);
|
||
|
commandLayout.append(commandSelect, {80, 0});
|
||
|
layout.append(controlLayout, {~0, 0});
|
||
|
controlLayout.append(defaultAction, {0, 0}, 5);
|
||
|
controlLayout.append(filesAction, {0, 0}, 5);
|
||
|
controlLayout.append(foldersAction, {0, 0}, 5);
|
||
|
controlLayout.append(spacer, {~0, 0});
|
||
|
controlLayout.append(assignButton, {80, 0});
|
||
|
|
||
|
Geometry geometry = Window::geometry();
|
||
|
geometry.height = layout.minimumGeometry().height;
|
||
|
setGeometry(geometry);
|
||
|
|
||
|
onClose = [&] {
|
||
|
modal = false;
|
||
|
};
|
||
|
|
||
|
nameValue.onChange =
|
||
|
patternValue.onChange =
|
||
|
commandValue.onChange =
|
||
|
{&RuleEditor::synchronize, this};
|
||
|
|
||
|
commandSelect.onActivate = [&] {
|
||
|
string pathname = DialogWindow::fileOpen(*this, application->pathname, "Programs (*.exe)", "All Files (*)");
|
||
|
if(pathname.empty() == false) {
|
||
|
pathname.transform("/", "\\");
|
||
|
commandValue.setText({"\"", pathname, "\" {file}"});
|
||
|
}
|
||
|
synchronize();
|
||
|
};
|
||
|
|
||
|
nameValue.onActivate =
|
||
|
patternValue.onActivate =
|
||
|
commandValue.onActivate =
|
||
|
assignButton.onActivate = [&] {
|
||
|
Settings::Rule rule = {
|
||
|
nameValue.text(),
|
||
|
patternValue.text(),
|
||
|
defaultAction.checked(),
|
||
|
filesAction.checked(),
|
||
|
foldersAction.checked(),
|
||
|
commandValue.text()
|
||
|
};
|
||
|
if(index == -1) {
|
||
|
settings.rules.append(rule);
|
||
|
} else {
|
||
|
settings.rules(index) = rule;
|
||
|
}
|
||
|
settings.save();
|
||
|
application->refresh();
|
||
|
application->synchronize();
|
||
|
setVisible(false);
|
||
|
modal = false;
|
||
|
};
|
||
|
}
|
||
|
|
||
|
void RuleEditor::synchronize() {
|
||
|
bool enable = true;
|
||
|
if(nameValue.text().empty()) enable = false;
|
||
|
if(patternValue.text().empty()) enable = false;
|
||
|
if(commandValue.text().empty()) enable = false;
|
||
|
assignButton.setEnabled(enable);
|
||
|
}
|
||
|
|
||
|
void RuleEditor::show(signed ruleID) {
|
||
|
Settings::Rule rule{"", "", false, true, false, "", false};
|
||
|
if(ruleID >= 0) rule = settings.rules(ruleID);
|
||
|
|
||
|
index = ruleID;
|
||
|
nameValue.setText(rule.name);
|
||
|
patternValue.setText(rule.pattern);
|
||
|
commandValue.setText(rule.command);
|
||
|
defaultAction.setChecked(rule.defaultAction);
|
||
|
filesAction.setChecked(rule.matchFiles);
|
||
|
foldersAction.setChecked(rule.matchFolders);
|
||
|
synchronize();
|
||
|
setVisible();
|
||
|
setFocused();
|
||
|
nameValue.setFocused();
|
||
|
|
||
|
setModal(modal = true);
|
||
|
while(modal == true) {
|
||
|
OS::processEvents();
|
||
|
}
|
||
|
setModal(false);
|
||
|
application->setFocused();
|
||
|
}
|
||
|
|
||
|
typedef BOOL (WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
|
||
|
|
||
|
bool isWow64() {
|
||
|
LPFN_ISWOW64PROCESS fnIsWow64Process;
|
||
|
fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleW(L"kernel32"), "IsWow64Process");
|
||
|
if(!fnIsWow64Process) return false;
|
||
|
BOOL result = FALSE;
|
||
|
fnIsWow64Process(GetCurrentProcess(), &result);
|
||
|
return result == TRUE;
|
||
|
}
|
||
|
|
||
|
int CALLBACK WinMain(HINSTANCE module, HINSTANCE, LPSTR, int) {
|
||
|
if(isWow64()) {
|
||
|
MessageWindow::critical(Window::none(), "Error: you must run kaijuu64.exe on 64-bit Windows.");
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
wchar_t filename[MAX_PATH];
|
||
|
GetModuleFileNameW(module, filename, MAX_PATH);
|
||
|
|
||
|
string pathname = (const char*)utf8_t(filename);
|
||
|
pathname.transform("\\", "/");
|
||
|
pathname = dir(pathname);
|
||
|
|
||
|
application = new Application(pathname);
|
||
|
ruleEditor = new RuleEditor;
|
||
|
application->setFocused();
|
||
|
OS::main();
|
||
|
|
||
|
return 0;
|
||
|
}
|