gui: add configuration system

This commit is contained in:
Syping 2026-04-12 16:40:19 +02:00
parent 84b01d9ae1
commit 9971378f3c
8 changed files with 564 additions and 31 deletions

View file

@ -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()

View file

@ -37,6 +37,6 @@ namespace bot {
CURLcode m_error;
};
}
};
}
#endif // CURL_EXCEPTION_H

View 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();
}

View 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
View 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
View 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

View file

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

View file

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