bsnes/kaijuu/interface.cpp

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;
}