testing-repository/Gtkmm3/gtk137_editor_keyboard/src/TextEditor.cc

437 lines
13 KiB
C++
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "TextEditor.hh"
#include "text_types.hh"
#include "../json_nlohmann/json.hpp"
#include <fstream>
#include <iostream>
#include <string>
using json = nlohmann::json;
// Only for build in this repository
#define text_globs supported_globs
TextEditor::TextEditor()
: vbox(Gtk::ORIENTATION_VERTICAL, 5),
hbox(Gtk::ORIENTATION_HORIZONTAL, 5),
searchbox(Gtk::ORIENTATION_HORIZONTAL, 5),
file_opened(false)
{
// Load window config from json file
int width = 800, height = 450;
std::ifstream json_file("config.json");
if (json_file.is_open())
{
json data = json::parse(json_file);
width = data["width"];
height = data["height"];
}
json_file.close();
// Initalize Window
set_default_size(width, height);
set_icon_name("my_textedit");
// Initalize HeaderBar
header.set_decoration_layout("close,minimize,maximize:menu");
header.set_show_close_button();
menubtn.set_image_from_icon_name("open-menu");
search_button.set_image_from_icon_name("find");
header.pack_end(menubtn);
header.pack_end(search_button);
header.set_title("Simple Text Editor");
set_titlebar(header);
// Add a menu
menu_builder = Gtk::Builder::create_from_resource("/org/gtk/daleclack/text_menu.xml");
auto object = menu_builder->get_object("text_menu");
auto gmenu = Glib::RefPtr<Gio::Menu>::cast_dynamic(object);
popover.bind_model(gmenu);
menubtn.set_popover(popover);
// Initalize Text Buffers
buffer1 = textview1.get_buffer();
buffer1->signal_changed().connect(sigc::mem_fun(*this, &TextEditor::buffer1_changed));
// Pack Widgets
sw1.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
sw1.add(textview1);
hbox.pack_start(sw1);
// Add actions and signal handlers
add_action("text_open", sigc::mem_fun(*this, &TextEditor::btnopen_clicked));
add_action("text_save", sigc::mem_fun(*this, &TextEditor::btnsave_clicked));
add_action("text_saveas", sigc::mem_fun(*this, &TextEditor::btnsaveas_clicked));
add_action("text_copy", sigc::mem_fun(*this, &TextEditor::btncopy_clicked));
add_action("text_paste", sigc::mem_fun(*this, &TextEditor::btnpaste_clicked));
add_action("text_close", sigc::mem_fun(*this, &TextEditor::btnclose_clicked));
add_action("text_about", sigc::mem_fun(*this, &TextEditor::about_activated));
// Add searchbar and search up and down buttons
search_up.set_image_from_icon_name("up");
search_down.set_image_from_icon_name("down");
// Bind property and signals
search_binding = Glib::Binding::bind_property(search_button.property_active(),
searchbar.property_search_mode_enabled(),
Glib::BINDING_BIDIRECTIONAL);
search_entry.signal_changed().connect(sigc::mem_fun(*this, &TextEditor::search_entry_changed));
search_up.signal_clicked().connect(sigc::mem_fun(*this, &TextEditor::search_backward));
search_down.signal_clicked().connect(sigc::mem_fun(*this, &TextEditor::search_forward));
// Pack widgets
searchbox.pack_start(search_entry, Gtk::PACK_SHRINK);
searchbox.pack_start(search_up, Gtk::PACK_SHRINK);
searchbox.pack_start(search_down, Gtk::PACK_SHRINK);
searchbar.add(searchbox);
vbox.pack_start(searchbar, Gtk::PACK_SHRINK);
// A InfoBar
infobar.add_button("OK", Gtk::RESPONSE_OK);
infobar.signal_response().connect(sigc::mem_fun(*this, &TextEditor::infobar_response));
infobox = dynamic_cast<Gtk::Box *>(infobar.get_content_area());
infobox->pack_start(label1);
vbox.pack_start(infobar, Gtk::PACK_SHRINK);
vbox.pack_start(hbox);
// Save config when the window is closed
signal_delete_event().connect(sigc::mem_fun(*this, &TextEditor::window_delete_event));
// Add Intergated keyboard
expend_builder = Gtk::Builder::create_from_resource("/org/gtk/daleclack/expender.ui");
expend_builder->get_widget("key_expend", expender);
expend_builder->get_widget("btnshift", btnshift);
expend_builder->get_widget("btn_caps", btncaps);
expend_builder->get_widget("btntab", btntab);
expend_builder->get_widget("btnenter", btnenter);
vbox.pack_start(*expender, Gtk::PACK_SHRINK);
// Get alphabet buttons
for(int i = 0; i < 26; i++){
char name[10];
sprintf(name, "btn%d", i);
expend_builder->get_widget(name, btns[i]);
btns[i]->signal_clicked().connect(sigc::bind(
sigc::mem_fun(*this, &TextEditor::key_pressed),
btns[i]
));
}
btntab->signal_clicked().connect(sigc::mem_fun(*this, &TextEditor::btntab_clicked));
btnenter->signal_clicked().connect(sigc::mem_fun(*this, &TextEditor::btnenter_clicked));
// Show everything
add(vbox);
show_all_children();
infobar.hide();
}
void TextEditor::key_pressed(Gtk::Button *button){
auto label = button->get_label();
Glib::ustring::size_type pos = 0,len = 1;
char buf[2];
if(btncaps->get_active() || btnshift->get_active()){
btnshift->set_active(false);
}else{
sprintf(buf, "%c", label[0] + 32);
label.replace(pos, len, buf);
}
//std::cout << label << std::endl;
buffer1->insert_at_cursor(label);
}
void TextEditor::btntab_clicked(){
buffer1->insert_at_cursor("\t");
}
void TextEditor::btnenter_clicked(){
buffer1->insert_at_cursor("\n");
}
bool TextEditor::window_delete_event(GdkEventAny *event)
{
// Create json raw data
json data = json::parse(R"({
"width":800,
"height":450
})");
// Override config in json file
data["width"] = sw1.get_width();
data["height"] = sw1.get_height();
// Output json data to file
std::fstream outfile;
outfile.open("config.json", std::ios_base::out);
if (outfile.is_open())
{
outfile << data;
}
outfile.close();
return false;
}
void TextEditor::btnopen_clicked()
{
// Create a dialog
dialog = Gtk::FileChooserNative::create("Open a text file", *this,
Gtk::FILE_CHOOSER_ACTION_OPEN, "OK", "Cancel");
dialog->signal_response().connect(sigc::mem_fun(*this, &TextEditor::opendialog_response));
// Add Filters
auto filter = Gtk::FileFilter::create();
filter->set_name("Text Files");
if (mimetype_supported())
{
filter->add_mime_type("text/*");
}
else
{
for (int i = 0; text_globs != NULL && text_globs[i] != NULL; i++)
{
const char *glob = text_globs[i];
filter->add_pattern(glob);
}
}
dialog->add_filter(filter);
auto filter_any = Gtk::FileFilter::create();
filter_any->set_name("Any Files");
filter_any->add_pattern("*");
dialog->add_filter(filter_any);
dialog->show();
}
void TextEditor::opendialog_response(int response)
{
if (response == Gtk::RESPONSE_ACCEPT)
{
// Load Contents of a file
auto file = dialog->get_file();
curr_filename = file->get_path();
file_opened = true;
char *contents;
gsize length;
if (file->load_contents(contents, length))
{
buffer1->set_text(contents);
}
}
dialog.reset();
}
void TextEditor::btnsave_clicked()
{
if (file_opened)
{
// Get Text
Glib::ustring text;
text = buffer1->get_text();
// Set file opened to true to use save mode
file_opened = true;
// Save to a file
std::ofstream outfile;
outfile.open(curr_filename, std::ios_base::out);
outfile << text;
outfile.close();
}
}
void TextEditor::btnsaveas_clicked()
{
// Create a dialog
dialog = Gtk::FileChooserNative::create("Save file", *this,
Gtk::FILE_CHOOSER_ACTION_SAVE, "OK", "Cancel");
dialog->signal_response().connect(sigc::mem_fun(*this, &TextEditor::savedialog_response));
// Add Filters
auto filter = Gtk::FileFilter::create();
filter->set_name("Text Files");
if (mimetype_supported())
{
filter->add_mime_type("text/*");
}
else
{
for (int i = 0; text_globs != NULL && text_globs[i] != NULL; i++)
{
const char *glob = text_globs[i];
filter->add_pattern(glob);
}
}
dialog->add_filter(filter);
auto filter_any = Gtk::FileFilter::create();
filter_any->set_name("Any Files");
filter_any->add_pattern("*");
dialog->add_filter(filter_any);
dialog->show();
}
void TextEditor::savedialog_response(int response)
{
if (response == Gtk::RESPONSE_ACCEPT)
{
// Get Filename
auto file = dialog->get_file();
std::string filename = file->get_path();
// Get Text
Glib::ustring text;
text = buffer1->get_text();
// Save to a file
std::ofstream outfile;
outfile.open(filename, std::ios_base::out);
outfile << text;
outfile.close();
}
dialog.reset();
}
void TextEditor::buffer1_changed()
{
// When the text changed,enable the copy button
}
void TextEditor::search_entry_changed()
{
// Get Text to search
const Glib::ustring text = search_entry.get_text();
Gtk::TextIter start, end;
// If get text to search, select the text and storage the position
if (text.length() != 0)
{
if (buffer1->begin().forward_search(text, Gtk::TEXT_SEARCH_CASE_INSENSITIVE, start, end))
{
curr_iter_up = start;
curr_iter_down = end;
buffer1->select_range(start, end);
textview1.scroll_to(start);
}
}
}
void TextEditor::search_forward()
{
// Get Text to search
const Glib::ustring search_text = search_entry.get_text();
Gtk::TextIter start, end;
// Get Text to search, down to the end of text
if (search_text.length() != 0)
{
if (curr_iter_down.forward_search(search_text, Gtk::TEXT_SEARCH_CASE_INSENSITIVE, start, end))
{
curr_iter_up = start;
curr_iter_down = end;
buffer1->select_range(start, end);
textview1.scroll_to(start);
}
}
}
void TextEditor::search_backward()
{
// Get Text to search, up to the start of text
const Glib::ustring search_text = search_entry.get_text();
Gtk::TextIter start, end;
// Get Text to search
if (search_text.length() != 0)
{
if (curr_iter_up.backward_search(search_text, Gtk::TEXT_SEARCH_CASE_INSENSITIVE, start, end))
{
curr_iter_up = start;
curr_iter_down = end;
buffer1->select_range(start, end);
textview1.scroll_to(start);
}
}
}
void TextEditor::btncopy_clicked()
{
// Get Text
Glib::ustring text;
Gtk::TextBuffer::iterator start, end;
if (buffer1->get_selection_bounds(start, end))
{
text = buffer1->get_text(start, end);
}
else
{
text = buffer1->get_text();
}
// Get Clipboard and set text
auto refClipboard = Gtk::Clipboard::get();
refClipboard->set_text(text);
// Show InfoBar
label1.set_label("The Text is copyed");
infobar.show();
}
void TextEditor::btnpaste_clicked()
{
// Get ClipBoard
auto refClipboard = Gtk::Clipboard::get();
refClipboard->request_text(sigc::mem_fun(*this, &TextEditor::clipboard_receive));
}
void TextEditor::clipboard_receive(const Glib::ustring &text)
{
if (buffer1->insert_interactive_at_cursor(text))
{
// Show InfoBar
label1.set_label("The Text is Pasted at cursor position");
infobar.show();
}
else
{
// Show InfoBar
label1.set_label("Text Paste Error!");
infobar.show();
}
}
void TextEditor::btnclose_clicked()
{
buffer1->set_text("");
file_opened = false;
}
void TextEditor::infobar_response(int response)
{
infobar.hide();
}
void TextEditor::about_activated()
{
char *version, *copyright;
// The Gtkmm Version
version = g_strdup_printf("1.0\nRunning Against Gtkmm %d.%d.%d",
GTKMM_MAJOR_VERSION,
GTKMM_MINOR_VERSION,
GTKMM_MICRO_VERSION);
const char *authors[] = {"Dale Clack", NULL};
// Copyright Informaion
copyright = g_strdup_printf("©2019—2022 The Xe Project");
// Show the about dialog
gtk_show_about_dialog(GTK_WINDOW(this->gobj()),
"program-name", "Text Editot",
"version", version,
"copyright", copyright,
"comments", "A simple text editor",
"authors", authors,
"license-type", GTK_LICENSE_GPL_3_0,
"logo-icon-name", "org.gtk.daleclack",
"title", "About Simple text editor",
(char *)NULL);
// Free memory
g_free(version);
g_free(copyright);
}