mirror of
https://github.com/Syping/dtranslatebot.git
synced 2026-04-21 14:40:41 +02:00
gui: add configuration system
This commit is contained in:
parent
84b01d9ae1
commit
9971378f3c
8 changed files with 564 additions and 31 deletions
|
|
@ -94,10 +94,14 @@ if (WITH_GUI)
|
|||
find_package(PkgConfig REQUIRED)
|
||||
pkg_check_modules(GTKMM REQUIRED gtkmm-4.0)
|
||||
list(APPEND DTRANSLATEBOT_HEADERS
|
||||
src/gui/translator_dialog.h
|
||||
src/gui/user_config.h
|
||||
src/gui/user_interface.h
|
||||
)
|
||||
list(APPEND DTRANSLATEBOT_SOURCES
|
||||
src/gui/main.cpp
|
||||
src/gui/translator_dialog.cpp
|
||||
src/gui/user_config.cpp
|
||||
src/gui/user_interface.cpp
|
||||
)
|
||||
else()
|
||||
|
|
|
|||
|
|
@ -37,6 +37,6 @@ namespace bot {
|
|||
CURLcode m_error;
|
||||
};
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#endif // CURL_EXCEPTION_H
|
||||
|
|
|
|||
175
src/gui/translator_dialog.cpp
Normal file
175
src/gui/translator_dialog.cpp
Normal file
|
|
@ -0,0 +1,175 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2026 Syping
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* This software is provided as-is, no warranties are given to you, we are not
|
||||
* responsible for anything with use of the software, you are self responsible.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <gtkmm/checkbutton.h>
|
||||
#include <gtkmm/entry.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include "translator_dialog.h"
|
||||
using namespace bot::gui;
|
||||
|
||||
translator_dialog::translator_dialog(Gtk::Window &parent, const std::string &translator, user_config &user_config) :
|
||||
Gtk::Dialog("dtranslatebot - Translator", parent, true), m_user_config(user_config) {
|
||||
m_json = m_user_config.get_translator_settings(translator);
|
||||
|
||||
set_default_size(300, 0);
|
||||
set_resizable(false);
|
||||
|
||||
auto vertical_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 6);
|
||||
vertical_box->set_margin(6);
|
||||
|
||||
auto hostname_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 6);
|
||||
vertical_box->append(*hostname_box);
|
||||
|
||||
auto hostname_label = Gtk::make_managed<Gtk::Label>("Hostname");
|
||||
hostname_box->append(*hostname_label);
|
||||
|
||||
auto hostname_entry = Gtk::make_managed<Gtk::Entry>();
|
||||
hostname_entry->set_hexpand(true);
|
||||
auto json_hostname = m_json.find("hostname");
|
||||
if (json_hostname != m_json.end())
|
||||
hostname_entry->set_text(static_cast<const std::string>(*json_hostname));
|
||||
hostname_entry->signal_changed().connect([=]() {
|
||||
m_json["hostname"] = hostname_entry->get_text();
|
||||
});
|
||||
hostname_box->append(*hostname_entry);
|
||||
|
||||
if (translator != "deepl") {
|
||||
auto url_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 6);
|
||||
vertical_box->append(*url_box);
|
||||
|
||||
auto url_label = Gtk::make_managed<Gtk::Label>("URL");
|
||||
url_box->append(*url_label);
|
||||
|
||||
auto url_entry = Gtk::make_managed<Gtk::Entry>();
|
||||
url_entry->set_hexpand(true);
|
||||
auto json_url = m_json.find("url");
|
||||
if (json_url != m_json.end())
|
||||
url_entry->set_text(static_cast<const std::string>(*json_url));
|
||||
url_entry->signal_changed().connect([=]() {
|
||||
m_json["url"] = url_entry->get_text();
|
||||
});
|
||||
url_box->append(*url_entry);
|
||||
|
||||
auto port_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 6);
|
||||
vertical_box->append(*port_box);
|
||||
|
||||
auto port_label = Gtk::make_managed<Gtk::Label>("Port");
|
||||
port_box->append(*port_label);
|
||||
|
||||
auto port_entry = Gtk::make_managed<Gtk::Entry>();
|
||||
port_entry->set_hexpand(true);
|
||||
auto json_port = m_json.find("port");
|
||||
if (json_port != m_json.end())
|
||||
port_entry->set_text(std::to_string(static_cast<int>(*json_port)));
|
||||
else
|
||||
port_entry->set_text("443");
|
||||
port_entry->signal_changed().connect([=]() {
|
||||
try {
|
||||
m_json["port"] = std::stoi(port_entry->get_text());
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
// TODO: Enforce Entry being Number only
|
||||
}
|
||||
});
|
||||
port_box->append(*port_entry);
|
||||
|
||||
auto tls_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 6);
|
||||
vertical_box->append(*tls_box);
|
||||
|
||||
auto tls_label = Gtk::make_managed<Gtk::Label>("TLS");
|
||||
tls_box->append(*tls_label);
|
||||
|
||||
auto tls_checkbutton = Gtk::make_managed<Gtk::CheckButton>("Enabled");
|
||||
auto json_tls = m_json.find("tls");
|
||||
if (json_tls != m_json.end())
|
||||
tls_checkbutton->set_active(*json_tls);
|
||||
else
|
||||
tls_checkbutton->set_active(true);
|
||||
tls_checkbutton->signal_toggled().connect([=]() {
|
||||
m_json["tls"] = tls_checkbutton->get_active();
|
||||
if (tls_checkbutton->get_active() && port_entry->get_text() == "80")
|
||||
port_entry->set_text("443");
|
||||
else if (!tls_checkbutton->get_active() && port_entry->get_text() == "443")
|
||||
port_entry->set_text("80");
|
||||
});
|
||||
tls_box->append(*tls_checkbutton);
|
||||
}
|
||||
|
||||
if (translator == "mozhi") {
|
||||
auto engine_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 6);
|
||||
vertical_box->append(*engine_box);
|
||||
|
||||
auto engine_label = Gtk::make_managed<Gtk::Label>("Engine");
|
||||
engine_box->append(*engine_label);
|
||||
|
||||
auto engine_entry = Gtk::make_managed<Gtk::Entry>();
|
||||
engine_entry->set_hexpand(true);
|
||||
auto json_engine = m_json.find("engine");
|
||||
if (json_engine != m_json.end())
|
||||
engine_entry->set_text(static_cast<const std::string>(*json_engine));
|
||||
engine_entry->signal_changed().connect([=]() {
|
||||
m_json["engine"] = engine_entry->get_text();
|
||||
});
|
||||
engine_box->append(*engine_entry);
|
||||
}
|
||||
|
||||
if (translator != "lingvatranslate" && translator != "mozhi") {
|
||||
auto apikey_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 6);
|
||||
vertical_box->append(*apikey_box);
|
||||
|
||||
auto apikey_label = Gtk::make_managed<Gtk::Label>("API Key");
|
||||
apikey_box->append(*apikey_label);
|
||||
|
||||
auto apikey_entry = Gtk::make_managed<Gtk::Entry>();
|
||||
apikey_entry->set_hexpand(true);
|
||||
auto json_apiKey = m_json.find("apiKey");
|
||||
if (json_apiKey != m_json.end())
|
||||
apikey_entry->set_text(static_cast<const std::string>(*json_apiKey));
|
||||
apikey_entry->signal_changed().connect([=]() {
|
||||
m_json["apiKey"] = apikey_entry->get_text();
|
||||
});
|
||||
apikey_box->append(*apikey_entry);
|
||||
}
|
||||
|
||||
auto button_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 6);
|
||||
button_box->set_halign(Gtk::Align::CENTER);
|
||||
vertical_box->append(*button_box);
|
||||
|
||||
auto save_button = Gtk::make_managed<Gtk::Button>("Save");
|
||||
save_button->set_size_request(80, -1);
|
||||
save_button->signal_clicked().connect(sigc::mem_fun(*this, &translator_dialog::on_save_button_clicked));
|
||||
button_box->append(*save_button);
|
||||
|
||||
auto close_button = Gtk::make_managed<Gtk::Button>("Close");
|
||||
close_button->set_size_request(80, -1);
|
||||
close_button->signal_clicked().connect(sigc::mem_fun(*this, &Gtk::Dialog::close));
|
||||
button_box->append(*close_button);
|
||||
|
||||
set_child(*vertical_box);
|
||||
}
|
||||
|
||||
void translator_dialog::configure(Gtk::Window &parent, const std::string &translator, user_config &user_config) {
|
||||
auto dialog = Gtk::make_managed<translator_dialog>(parent, translator, user_config);
|
||||
dialog->set_visible();
|
||||
}
|
||||
|
||||
void translator_dialog::on_save_button_clicked() {
|
||||
m_user_config.set_translator_settings(m_json);
|
||||
m_user_config.save();
|
||||
close();
|
||||
}
|
||||
41
src/gui/translator_dialog.h
Normal file
41
src/gui/translator_dialog.h
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2026 Syping
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* This software is provided as-is, no warranties are given to you, we are not
|
||||
* responsible for anything with use of the software, you are self responsible.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TRANSLATOR_DIALOG_H
|
||||
#define TRANSLATOR_DIALOG_H
|
||||
|
||||
#include <dpp/json.h>
|
||||
#include <gtkmm/dialog.h>
|
||||
#include "user_config.h"
|
||||
|
||||
namespace bot {
|
||||
namespace gui {
|
||||
class translator_dialog : public Gtk::Dialog {
|
||||
public:
|
||||
explicit translator_dialog(Gtk::Window &parent, const std::string &translator, user_config &user_config);
|
||||
static void configure(Gtk::Window &parent, const std::string &translator, user_config &user_config);
|
||||
void on_save_button_clicked();
|
||||
|
||||
private:
|
||||
dpp::json m_json;
|
||||
user_config& m_user_config;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // TRANSLATOR_DIALOG_H
|
||||
183
src/gui/user_config.cpp
Normal file
183
src/gui/user_config.cpp
Normal file
|
|
@ -0,0 +1,183 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2026 Syping
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* This software is provided as-is, no warranties are given to you, we are not
|
||||
* responsible for anything with use of the software, you are self responsible.
|
||||
*****************************************************************************/
|
||||
|
||||
#include <giomm/file.h>
|
||||
#include <glibmm/fileutils.h>
|
||||
#include <glibmm/miscutils.h>
|
||||
#include "user_config.h"
|
||||
using namespace bot::gui;
|
||||
|
||||
user_config::user_config() {
|
||||
m_key_file = Glib::KeyFile::create();
|
||||
try {
|
||||
m_key_file->load_from_file(get_app_config_file());
|
||||
m_is_loaded = true;
|
||||
}
|
||||
catch (const Glib::FileError &exception) {
|
||||
m_is_loaded = false;
|
||||
}
|
||||
catch (const Glib::KeyFileError &exception) {
|
||||
m_is_loaded = false;
|
||||
}
|
||||
m_is_saved = true;
|
||||
}
|
||||
|
||||
user_config::~user_config() {
|
||||
if (!m_is_saved)
|
||||
save();
|
||||
}
|
||||
|
||||
const std::string user_config::get_app_config_directory() {
|
||||
return Glib::build_filename(Glib::get_user_config_dir(), "dtranslatebot");
|
||||
}
|
||||
|
||||
const std::string user_config::get_app_config_file() {
|
||||
return Glib::build_filename(get_app_config_directory(), "dtranslatebot.conf");
|
||||
}
|
||||
|
||||
const std::string user_config::get_token() const {
|
||||
if (!m_key_file->has_group("Discord"))
|
||||
return {};
|
||||
if (!m_key_file->has_key("Discord", "Token"))
|
||||
return {};
|
||||
return m_key_file->get_string("Discord", "Token");
|
||||
}
|
||||
|
||||
const std::string user_config::get_translator() const {
|
||||
if (!m_key_file->has_group("Translator"))
|
||||
return "stub";
|
||||
if (!m_key_file->has_key("Translator", "Type"))
|
||||
return "stub";
|
||||
return m_key_file->get_string("Translator", "Type");
|
||||
}
|
||||
|
||||
void user_config::get_translator_settings(const std::string &group, dpp::json &json) const {
|
||||
if (m_key_file->has_key(group, "Hostname"))
|
||||
json["hostname"] = m_key_file->get_string(group, "Hostname");
|
||||
if (m_key_file->has_key(group, "TLS"))
|
||||
json["tls"] = m_key_file->get_boolean(group, "TLS");
|
||||
if (m_key_file->has_key(group, "Port"))
|
||||
json["port"] = m_key_file->get_integer(group, "Port");
|
||||
if (m_key_file->has_key(group, "URL"))
|
||||
json["url"] = m_key_file->get_string(group, "URL");
|
||||
if (m_key_file->has_key(group, "ApiKey"))
|
||||
json["apiKey"] = m_key_file->get_string(group, "ApiKey");
|
||||
}
|
||||
|
||||
const dpp::json user_config::get_translator_settings(const std::string &translator) const {
|
||||
dpp::json json = {
|
||||
{"type", translator}
|
||||
};
|
||||
if (translator == "deepl") {
|
||||
if (!m_key_file->has_group("DeepL"))
|
||||
return json;
|
||||
if (m_key_file->has_key("DeepL", "Hostname"))
|
||||
json["hostname"] = m_key_file->get_string("DeepL", "Hostname");
|
||||
if (m_key_file->has_key("DeepL", "ApiKey"))
|
||||
json["apiKey"] = m_key_file->get_string("DeepL", "ApiKey");
|
||||
}
|
||||
else if (translator == "mozhi") {
|
||||
if (!m_key_file->has_group("Mozhi"))
|
||||
return json;
|
||||
get_translator_settings("Mozhi", json);
|
||||
if (m_key_file->has_key("Mozhi", "Engine"))
|
||||
json["engine"] = m_key_file->get_string("Mozhi", "Engine");
|
||||
}
|
||||
else if (translator == "libretranslate") {
|
||||
if (!m_key_file->has_group("LibreTranslate"))
|
||||
return json;
|
||||
get_translator_settings("LibreTranslate", json);
|
||||
}
|
||||
else if (translator == "lingvatranslate") {
|
||||
if (!m_key_file->has_group("LingvaTranslate"))
|
||||
return json;
|
||||
get_translator_settings("LingvaTranslate", json);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
bool user_config::save() {
|
||||
auto app_config_directory = Gio::File::create_for_path(get_app_config_directory());
|
||||
if (!app_config_directory->query_exists() && !app_config_directory->make_directory_with_parents())
|
||||
return false;
|
||||
if (!m_key_file->save_to_file(get_app_config_file()))
|
||||
return false;
|
||||
m_is_saved = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void user_config::set_token(const std::string &token) {
|
||||
m_key_file->set_string("Discord", "Token", token);
|
||||
m_is_loaded = false;
|
||||
m_is_saved = false;
|
||||
}
|
||||
|
||||
void user_config::set_translator(const std::string &translator) {
|
||||
m_key_file->set_string("Translator", "Type", translator);
|
||||
m_is_loaded = false;
|
||||
m_is_saved = false;
|
||||
}
|
||||
|
||||
void user_config::set_translator_settings(const dpp::json &json) {
|
||||
if (!json.is_object())
|
||||
return;
|
||||
auto json_type = json.find("type");
|
||||
if (json_type == json.end())
|
||||
return;
|
||||
const std::string translator = *json_type;
|
||||
if (translator == "deepl") {
|
||||
auto json_deepl_hostname = json.find("hostname");
|
||||
if (json_deepl_hostname != json.end())
|
||||
m_key_file->set_string("DeepL", "Hostname", static_cast<const std::string>(*json_deepl_hostname));
|
||||
auto json_deepl_apiKey = json.find("apiKey");
|
||||
if (json_deepl_apiKey != json.end())
|
||||
m_key_file->set_string("DeepL", "ApiKey", static_cast<const std::string>(*json_deepl_apiKey));
|
||||
}
|
||||
else if (translator == "mozhi") {
|
||||
set_translator_settings("Mozhi", json);
|
||||
auto json_mozhi_engine = json.find("engine");
|
||||
if (json_mozhi_engine != json.end())
|
||||
m_key_file->set_string("Mozhi", "Engine", static_cast<const std::string>(*json_mozhi_engine));
|
||||
}
|
||||
else if (translator == "libretranslate") {
|
||||
set_translator_settings("LibreTranslate", json);
|
||||
}
|
||||
else if (translator == "lingvatranslate") {
|
||||
set_translator_settings("LingvaTranslate", json);
|
||||
}
|
||||
m_is_loaded = false;
|
||||
m_is_saved = false;
|
||||
}
|
||||
|
||||
void user_config::set_translator_settings(const std::string &group, const dpp::json &json) {
|
||||
auto json_hostname = json.find("hostname");
|
||||
if (json_hostname != json.end())
|
||||
m_key_file->set_string(group, "Hostname", static_cast<const std::string>(*json_hostname));
|
||||
auto json_tls = json.find("tls");
|
||||
if (json_tls != json.end())
|
||||
m_key_file->set_boolean(group, "TLS", *json_tls);
|
||||
auto json_port = json.find("port");
|
||||
if (json_port != json.end())
|
||||
m_key_file->set_integer(group, "Port", *json_port);
|
||||
auto json_url = json.find("url");
|
||||
if (json_url != json.end())
|
||||
m_key_file->set_string(group, "URL", static_cast<const std::string>(*json_hostname));
|
||||
auto json_apiKey = json.find("apiKey");
|
||||
if (json_url != json.end())
|
||||
m_key_file->set_string(group, "ApiKey", static_cast<const std::string>(*json_apiKey));
|
||||
}
|
||||
51
src/gui/user_config.h
Normal file
51
src/gui/user_config.h
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
/*****************************************************************************
|
||||
* dtranslatebot Discord Translate Bot
|
||||
* Copyright (C) 2026 Syping
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification,
|
||||
* are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
* this list of conditions and the following disclaimer in the documentation
|
||||
* and/or other materials provided with the distribution.
|
||||
*
|
||||
* This software is provided as-is, no warranties are given to you, we are not
|
||||
* responsible for anything with use of the software, you are self responsible.
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef USER_CONFIG_H
|
||||
#define USER_CONFIG_H
|
||||
|
||||
#include <dpp/json.h>
|
||||
#include <glibmm/keyfile.h>
|
||||
|
||||
namespace bot {
|
||||
namespace gui {
|
||||
class user_config {
|
||||
public:
|
||||
explicit user_config();
|
||||
~user_config();
|
||||
static const std::string get_app_config_directory();
|
||||
static const std::string get_app_config_file();
|
||||
const std::string get_token() const;
|
||||
const std::string get_translator() const;
|
||||
void get_translator_settings(const std::string &group, dpp::json &json) const;
|
||||
const dpp::json get_translator_settings(const std::string &translator) const;
|
||||
bool save();
|
||||
void set_token(const std::string &token);
|
||||
void set_translator(const std::string &translator);
|
||||
void set_translator_settings(const dpp::json &json);
|
||||
void set_translator_settings(const std::string &group, const dpp::json &json);
|
||||
|
||||
private:
|
||||
Glib::RefPtr<Glib::KeyFile> m_key_file;
|
||||
bool m_is_loaded;
|
||||
bool m_is_saved;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif // USER_CONFIG_H
|
||||
|
|
@ -19,47 +19,75 @@
|
|||
#include <gtkmm/alertdialog.h>
|
||||
#include <gtkmm/box.h>
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/editable.h>
|
||||
#include <gtkmm/dropdown.h>
|
||||
#include <gtkmm/label.h>
|
||||
#include <gtkmm/passwordentry.h>
|
||||
#include <gtkmm/scrolledwindow.h>
|
||||
#include <gtkmm/stringlist.h>
|
||||
#include <gtkmm/textview.h>
|
||||
#include <memory>
|
||||
#include "../core/regex.h"
|
||||
#include "translator_dialog.h"
|
||||
#include "user_interface.h"
|
||||
using namespace bot::gui;
|
||||
|
||||
const char* translators[] = {"stub", "libretranslate", "lingvatranslate", "mozhi", "deepl"};
|
||||
|
||||
user_interface::user_interface()
|
||||
{
|
||||
set_title("dtranslatebot");
|
||||
set_default_size(500, 0);
|
||||
set_resizable(false);
|
||||
|
||||
auto vertical_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
|
||||
auto vertical_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 6);
|
||||
vertical_box->set_margin(6);
|
||||
vertical_box->set_spacing(6);
|
||||
|
||||
auto token_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL);
|
||||
token_box->set_spacing(6);
|
||||
auto token_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 6);
|
||||
vertical_box->append(*token_box);
|
||||
|
||||
auto token_label = Gtk::make_managed<Gtk::Label>("Discord Bot Token:");
|
||||
token_box->append(*token_label);
|
||||
|
||||
m_token_entry = Gtk::make_managed<Gtk::PasswordEntry>();
|
||||
m_token_entry->set_show_peek_icon(true);
|
||||
m_token_entry->set_hexpand(true);
|
||||
m_token_entry->set_show_peek_icon(true);
|
||||
m_token_entry->signal_changed().connect(sigc::mem_fun(*this, &user_interface::on_token_entry_changed));
|
||||
token_box->append(*m_token_entry);
|
||||
|
||||
auto log_textview = Gtk::make_managed<Gtk::TextView>();
|
||||
log_textview->set_size_request(-1, 300);
|
||||
log_textview->set_editable(false);
|
||||
log_textview->set_monospace(true);
|
||||
log_textview->set_wrap_mode(Gtk::WrapMode::WORD_CHAR);
|
||||
m_log = log_textview->get_buffer();
|
||||
vertical_box->append(*log_textview);
|
||||
auto translator_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 6);
|
||||
vertical_box->append(*translator_box);
|
||||
|
||||
auto button_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL);
|
||||
button_box->set_spacing(6);
|
||||
auto translator_label = Gtk::make_managed<Gtk::Label>("Translator:");
|
||||
translator_box->append(*translator_label);
|
||||
|
||||
auto translator_list = Gtk::StringList::create({"Stub", "LibreTranslate", "Lingva Translate", "Mozhi", "DeepL"});
|
||||
m_translator_dropdown = Gtk::make_managed<Gtk::DropDown>(translator_list);
|
||||
m_translator_dropdown->property_selected().signal_changed().connect(sigc::mem_fun(*this, &user_interface::on_translator_dropdown_changed));
|
||||
translator_box->append(*m_translator_dropdown);
|
||||
|
||||
auto translator_spacer = Gtk::make_managed<Gtk::Box>();
|
||||
translator_spacer->set_hexpand(true);
|
||||
translator_box->append(*translator_spacer);
|
||||
|
||||
m_translator_configure_button = Gtk::make_managed<Gtk::Button>("Configure...");
|
||||
m_translator_configure_button->set_size_request(80, -1);
|
||||
m_translator_configure_button->set_sensitive(false);
|
||||
m_translator_configure_button->signal_clicked().connect(sigc::mem_fun(*this, &user_interface::on_translator_configure_pressed));
|
||||
translator_box->append(*m_translator_configure_button);
|
||||
|
||||
auto log_scrolledwindow = Gtk::make_managed<Gtk::ScrolledWindow>();
|
||||
log_scrolledwindow->set_size_request(-1, 300);
|
||||
log_scrolledwindow->set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC);
|
||||
vertical_box->append(*log_scrolledwindow);
|
||||
|
||||
m_log_textview = Gtk::make_managed<Gtk::TextView>();
|
||||
m_log_textview->set_editable(false);
|
||||
m_log_textview->set_monospace(true);
|
||||
m_log_textview->set_wrap_mode(Gtk::WrapMode::WORD_CHAR);
|
||||
m_log = m_log_textview->get_buffer();
|
||||
log_scrolledwindow->set_child(*m_log_textview);
|
||||
|
||||
auto button_box = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL, 6);
|
||||
button_box->set_halign(Gtk::Align::CENTER);
|
||||
vertical_box->append(*button_box);
|
||||
|
||||
|
|
@ -75,20 +103,22 @@ user_interface::user_interface()
|
|||
m_stop_button->signal_clicked().connect(sigc::mem_fun(*this, &user_interface::terminate));
|
||||
button_box->append(*m_stop_button);
|
||||
|
||||
m_token_entry->signal_changed().connect([=]{
|
||||
bool token_valid = bot::regex::verify_discord_bot_token(m_token_entry->get_text());
|
||||
m_start_button->set_sensitive(!m_bot.is_running() ? token_valid : false);
|
||||
});
|
||||
const std::string token = m_user_config.get_token();
|
||||
m_token_entry->set_text(token);
|
||||
|
||||
set_child(*vertical_box);
|
||||
const std::string translator = m_user_config.get_translator();
|
||||
for (guint i = 0; i < sizeof(translators); i++) {
|
||||
if (translators[i] != translator)
|
||||
continue;
|
||||
m_translator_dropdown->set_selected(i);
|
||||
break;
|
||||
}
|
||||
|
||||
m_log_callback = std::bind(&user_interface::log_append, this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3);
|
||||
m_bot.log_callback_add(m_log_callback);
|
||||
m_log_dispatcher.connect([=](){
|
||||
const std::lock_guard<std::mutex> guard(m_log_buffer_mutex);
|
||||
m_log->insert(m_log->end(), m_log->begin() != m_log->end() ? m_log_buffer : m_log_buffer.substr(1));
|
||||
m_log_buffer.clear();
|
||||
});
|
||||
m_log_dispatcher.connect(sigc::mem_fun(*this, &user_interface::on_log_dispatched));
|
||||
|
||||
set_child(*vertical_box);
|
||||
}
|
||||
|
||||
void user_interface::log_append(const std::string &message, const std::string &type, bool is_error) {
|
||||
|
|
@ -97,13 +127,26 @@ void user_interface::log_append(const std::string &message, const std::string &t
|
|||
m_log_dispatcher.emit();
|
||||
}
|
||||
|
||||
void user_interface::log_scroll_down() {
|
||||
m_log->place_cursor(m_log->end());
|
||||
m_log_textview->scroll_to(m_log->get_insert(), 0, 1, 1);
|
||||
}
|
||||
|
||||
void user_interface::run() {
|
||||
const std::string token = m_token_entry->get_text();
|
||||
const std::string translator = translators[m_translator_dropdown->get_selected()];
|
||||
m_user_config.set_token(token);
|
||||
m_user_config.set_translator(translator);
|
||||
m_user_config.save();
|
||||
auto settings = std::make_shared<bot::settings::settings>();
|
||||
if (settings->process({{"token", m_token_entry->get_text()}, {"translator", {{"type", "stub"}}}}, m_log_callback)) {
|
||||
if (settings->process({{"token", token}, {"translator", m_user_config.get_translator_settings(translator)}}, m_log_callback)) {
|
||||
try {
|
||||
m_bot.run(settings, true, false);
|
||||
m_start_button->set_sensitive(false);
|
||||
m_stop_button->set_sensitive(true);
|
||||
m_token_entry->set_sensitive(false);
|
||||
m_translator_configure_button->set_sensitive(false);
|
||||
m_translator_dropdown->set_sensitive(false);
|
||||
}
|
||||
catch (const std::exception &exception) {
|
||||
auto alert_dialog = Gtk::AlertDialog::create(exception.what());
|
||||
|
|
@ -124,4 +167,29 @@ void user_interface::terminate() {
|
|||
bool token_valid = bot::regex::verify_discord_bot_token(m_token_entry->get_text());
|
||||
m_start_button->set_sensitive(token_valid);
|
||||
m_stop_button->set_sensitive(false);
|
||||
m_token_entry->set_sensitive(true);
|
||||
bool translator_configureable = m_translator_dropdown->get_selected() > 0;
|
||||
m_translator_configure_button->set_sensitive(translator_configureable);
|
||||
m_translator_dropdown->set_sensitive(true);
|
||||
}
|
||||
|
||||
void user_interface::on_log_dispatched() {
|
||||
const std::lock_guard<std::mutex> guard(m_log_buffer_mutex);
|
||||
m_log->insert(m_log->end(), m_log->begin() != m_log->end() ? m_log_buffer : m_log_buffer.substr(1));
|
||||
m_log_buffer.clear();
|
||||
Glib::signal_idle().connect_once(sigc::mem_fun(*this, &user_interface::log_scroll_down));
|
||||
}
|
||||
|
||||
void user_interface::on_token_entry_changed() {
|
||||
bool token_valid = bot::regex::verify_discord_bot_token(m_token_entry->get_text());
|
||||
m_start_button->set_sensitive(!m_bot.is_running() ? token_valid : false);
|
||||
}
|
||||
|
||||
void user_interface::on_translator_configure_pressed() {
|
||||
translator_dialog::configure(*this, translators[m_translator_dropdown->get_selected()], m_user_config);
|
||||
}
|
||||
|
||||
void user_interface::on_translator_dropdown_changed() {
|
||||
bool translator_configureable = m_translator_dropdown->get_selected() > 0;
|
||||
m_translator_configure_button->set_sensitive(translator_configureable);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,11 +18,13 @@
|
|||
|
||||
#include <glibmm/dispatcher.h>
|
||||
#include <gtkmm/button.h>
|
||||
#include <gtkmm/dropdown.h>
|
||||
#include <gtkmm/passwordentry.h>
|
||||
#include <gtkmm/textbuffer.h>
|
||||
#include <gtkmm/textview.h>
|
||||
#include <gtkmm/window.h>
|
||||
#include <mutex>
|
||||
#include "../core/discord_bot.h"
|
||||
#include "user_config.h"
|
||||
|
||||
namespace bot {
|
||||
namespace gui {
|
||||
|
|
@ -30,19 +32,28 @@ namespace bot {
|
|||
public:
|
||||
explicit user_interface();
|
||||
void log_append(const std::string &message, const std::string &type = "Log", bool is_error = false);
|
||||
void log_scroll_down();
|
||||
void run();
|
||||
void terminate();
|
||||
void on_log_dispatched();
|
||||
void on_token_entry_changed();
|
||||
void on_translator_configure_pressed();
|
||||
void on_translator_dropdown_changed();
|
||||
|
||||
private:
|
||||
bot::discord_bot m_bot;
|
||||
Glib::RefPtr<Gtk::TextBuffer> m_log;
|
||||
Gtk::Button* m_start_button;
|
||||
Gtk::Button* m_stop_button;
|
||||
Gtk::PasswordEntry* m_token_entry;
|
||||
std::string m_log_buffer;
|
||||
Glib::Dispatcher m_log_dispatcher;
|
||||
std::mutex m_log_buffer_mutex;
|
||||
bot::log::log_message_callback m_log_callback;
|
||||
Gtk::TextView* m_log_textview;
|
||||
Gtk::Button* m_start_button;
|
||||
Gtk::Button* m_stop_button;
|
||||
Gtk::PasswordEntry* m_token_entry;
|
||||
Gtk::Button* m_translator_configure_button;
|
||||
Gtk::DropDown* m_translator_dropdown;
|
||||
user_config m_user_config;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue