Update text editor

This commit is contained in:
daleclack 2022-07-08 13:46:12 +08:00
parent a1edd10fc6
commit 0533c96cfe
4 changed files with 297 additions and 108 deletions

View File

@ -43,6 +43,7 @@ set(RESOURCE_LIST
STRIPBLANKS game1.ui STRIPBLANKS game1.ui
STRIPBLANKS game24.ui STRIPBLANKS game24.ui
STRIPBLANKS calcapp.ui STRIPBLANKS calcapp.ui
STRIPBLANKS text_menu.xml
style.css style.css
reset.css reset.css
dock_style.css dock_style.css

View File

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="text_menu">
<section>
<item>
<attribute name="label">Open</attribute>
<attribute name="action">win.text_open</attribute>
<attribute name="accel">&lt;Control&gt;o</attribute>
</item>
<item>
<attribute name="label">Save</attribute>
<attribute name="action">win.text_save</attribute>
<attribute name="accel">&lt;Control&gt;s</attribute>
</item>
<item>
<attribute name="label">Save As</attribute>
<attribute name="action">win.text_saveas</attribute>
<attribute name="accel">&lt;Control&gt;&lt;Shift&gt;s</attribute>
</item>
<item>
<attribute name="label">Copy</attribute>
<attribute name="action">win.text_copy</attribute>
<attribute name="accel">&lt;Control&gt;c</attribute>
</item>
<item>
<attribute name="label">Paste</attribute>
<attribute name="action">win.text_paste</attribute>
<attribute name="accel">&lt;Control&gt;v</attribute>
</item>
<item>
<attribute name="label">Close</attribute>
<attribute name="action">win.text_close</attribute>
</item>
<item>
<attribute name="label">About</attribute>
<attribute name="action">win.text_about</attribute>
</item>
</section>
</menu>
</interface>

View File

@ -2,29 +2,57 @@
#include <gtkmm.h> #include <gtkmm.h>
class TextEditor : public Gtk::Window{ class TextEditor : public Gtk::ApplicationWindow{
public: public:
TextEditor(); TextEditor();
private: private:
//Child widgets //Header widgets
Gtk::Box vbox,hbox,btnbox,*infobox; Gtk::HeaderBar header;
Gtk::MenuButton menubtn;
Gtk::Popover popover;
Gtk::ToggleButton search_button;
Glib::RefPtr<Gtk::Builder> menu_builder;
//SearchBar
Gtk::SearchBar searchbar;
Gtk::SearchEntry search_entry;
Gtk::Box searchbox;
Gtk::Button search_up, search_down;
Glib::RefPtr<Glib::Binding> search_binding;
Gtk::TextIter curr_iter_up, curr_iter_down;
//Window widgets
Gtk::Box vbox,hbox,*infobox;
Gtk::ScrolledWindow sw1,sw2; Gtk::ScrolledWindow sw1,sw2;
Glib::RefPtr<Gtk::TextBuffer> buffer1; Glib::RefPtr<Gtk::TextBuffer> buffer1;
Gtk::TextView textview1; Gtk::TextView textview1;
Gtk::Button btn_copy,btn_paste,btn_open,btn_save,btn_clear;
Gtk::InfoBar infobar; Gtk::InfoBar infobar;
Gtk::Label label1; Gtk::Label label1;
//File Dialog //File Dialog
Glib::RefPtr<Gtk::FileChooserNative> dialog; Glib::RefPtr<Gtk::FileChooserNative> dialog;
Glib::ustring curr_filename;
bool file_opened;
//Signal Handlers //Signal Handlers
// File Operation functions
void btnopen_clicked(); void btnopen_clicked();
void opendialog_response(int response); void opendialog_response(int response);
void btnsave_clicked(); void btnsave_clicked();
void btnsaveas_clicked();
void savedialog_response(int response); void savedialog_response(int response);
// Copy, Paste and text operations
void btncopy_clicked(); void btncopy_clicked();
void btnpaste_clicked(); void btnpaste_clicked();
void btnclear_clicked(); void btnclose_clicked();
void buffer1_changed(); void buffer1_changed();
void clipboard_receive(const Glib::ustring &text); void clipboard_receive(const Glib::ustring &text);
void infobar_response(int response); void infobar_response(int response);
// Search funtion
void search_entry_changed();
void search_forward();
void search_backward();
}; };

View File

@ -2,81 +2,112 @@
#include "text_types.hh" #include "text_types.hh"
#include <fstream> #include <fstream>
// Only for build in this repository
// #define text_globs supported_globs
TextEditor::TextEditor() TextEditor::TextEditor()
:vbox(Gtk::ORIENTATION_VERTICAL,5), : vbox(Gtk::ORIENTATION_VERTICAL, 5),
hbox(Gtk::ORIENTATION_HORIZONTAL,5), hbox(Gtk::ORIENTATION_HORIZONTAL, 5),
btnbox(Gtk::ORIENTATION_VERTICAL,5), searchbox(Gtk::ORIENTATION_HORIZONTAL, 5),
btn_copy("Copy"), file_opened(false)
btn_paste("Paste"),
btn_open("Open"),
btn_save("Save"),
btn_clear("Clear")
{ {
//Initalize Window // Initalize Window
set_default_size(800,450); set_default_size(800, 450);
set_icon_name("my_textedit"); set_icon_name("my_textedit");
set_title("Simple Text Editor");
//Initalize Text Buffers
buffer1=textview1.get_buffer();
buffer1->signal_changed().connect(sigc::mem_fun(*this,&TextEditor::buffer1_changed));
//Pack Widgets // Initalize HeaderBar
sw1.set_policy(Gtk::POLICY_AUTOMATIC,Gtk::POLICY_AUTOMATIC); 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); sw1.add(textview1);
btnbox.set_valign(Gtk::ALIGN_CENTER);
btnbox.pack_start(btn_copy,Gtk::PACK_SHRINK);
btnbox.pack_start(btn_paste,Gtk::PACK_SHRINK);
btnbox.pack_start(btn_open,Gtk::PACK_SHRINK);
btnbox.pack_start(btn_save,Gtk::PACK_SHRINK);
btnbox.pack_start(btn_clear,Gtk::PACK_SHRINK);
hbox.pack_start(sw1); hbox.pack_start(sw1);
hbox.pack_start(btnbox,Gtk::PACK_SHRINK);
btn_open.signal_clicked().connect(sigc::mem_fun(*this,&TextEditor::btnopen_clicked));
btn_save.signal_clicked().connect(sigc::mem_fun(*this,&TextEditor::btnsave_clicked));
btn_copy.signal_clicked().connect(sigc::mem_fun(*this,&TextEditor::btncopy_clicked));
btn_paste.signal_clicked().connect(sigc::mem_fun(*this,&TextEditor::btnpaste_clicked));
btn_clear.signal_clicked().connect(sigc::mem_fun(*this,&TextEditor::btnclear_clicked));
//A InfoBar // Add actions and signal handlers
infobar.add_button("OK",Gtk::RESPONSE_OK); add_action("text_open", sigc::mem_fun(*this, &TextEditor::btnopen_clicked));
infobar.signal_response().connect(sigc::mem_fun(*this,&TextEditor::infobar_response)); add_action("text_save", sigc::mem_fun(*this, &TextEditor::btnsave_clicked));
infobox=dynamic_cast<Gtk::Box*>(infobar.get_content_area()); 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 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); infobox->pack_start(label1);
vbox.pack_start(infobar,Gtk::PACK_SHRINK); vbox.pack_start(infobar, Gtk::PACK_SHRINK);
//Disable Copy button // Show everything
btn_copy.set_sensitive(false);
//Show everything
vbox.pack_start(hbox); vbox.pack_start(hbox);
add(vbox); add(vbox);
show_all_children(); show_all_children();
infobar.hide(); infobar.hide();
} }
void TextEditor::btnopen_clicked(){ void TextEditor::btnopen_clicked()
//Create a dialog {
dialog=Gtk::FileChooserNative::create("Open a text file",*this, // Create a dialog
Gtk::FILE_CHOOSER_ACTION_OPEN,"OK","Cancel"); 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 dialog->signal_response().connect(sigc::mem_fun(*this, &TextEditor::opendialog_response));
auto filter=Gtk::FileFilter::create();
// Add Filters
auto filter = Gtk::FileFilter::create();
filter->set_name("Text Files"); filter->set_name("Text Files");
if(mimetype_supported()){ if (mimetype_supported())
{
filter->add_mime_type("text/*"); filter->add_mime_type("text/*");
}else{ }
for(int i = 0; text_globs != NULL && text_globs[i] != NULL; i++){ else
{
for (int i = 0; text_globs != NULL && text_globs[i] != NULL; i++)
{
const char *glob = text_globs[i]; const char *glob = text_globs[i];
filter->add_pattern(glob); filter->add_pattern(glob);
} }
} }
dialog->add_filter(filter); dialog->add_filter(filter);
auto filter_any=Gtk::FileFilter::create(); auto filter_any = Gtk::FileFilter::create();
filter_any->set_name("Any Files"); filter_any->set_name("Any Files");
filter_any->add_pattern("*"); filter_any->add_pattern("*");
dialog->add_filter(filter_any); dialog->add_filter(filter_any);
@ -84,40 +115,67 @@ void TextEditor::btnopen_clicked(){
dialog->show(); dialog->show();
} }
void TextEditor::opendialog_response(int response){ void TextEditor::opendialog_response(int response)
if(response==Gtk::RESPONSE_ACCEPT){ {
//Load Contents of a file if (response == Gtk::RESPONSE_ACCEPT)
auto file=dialog->get_file(); {
char * contents; // Load Contents of a file
auto file = dialog->get_file();
curr_filename = file->get_path();
file_opened = true;
char *contents;
gsize length; gsize length;
if(file->load_contents(contents,length)){ if (file->load_contents(contents, length))
{
buffer1->set_text(contents); buffer1->set_text(contents);
} }
} }
dialog.reset(); dialog.reset();
} }
void TextEditor::btnsave_clicked(){ void TextEditor::btnsave_clicked()
//Create a dialog {
dialog=Gtk::FileChooserNative::create("Save file",*this, if (file_opened)
Gtk::FILE_CHOOSER_ACTION_SAVE,"OK","Cancel"); {
// Get Text
dialog->signal_response().connect(sigc::mem_fun(*this,&TextEditor::savedialog_response)); 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();
}
}
//Add Filters void TextEditor::btnsaveas_clicked()
auto filter=Gtk::FileFilter::create(); {
// 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"); filter->set_name("Text Files");
if(mimetype_supported()){ if (mimetype_supported())
{
filter->add_mime_type("text/*"); filter->add_mime_type("text/*");
}else{ }
for(int i = 0; text_globs != NULL && text_globs[i] != NULL; i++){ else
{
for (int i = 0; text_globs != NULL && text_globs[i] != NULL; i++)
{
const char *glob = text_globs[i]; const char *glob = text_globs[i];
filter->add_pattern(glob); filter->add_pattern(glob);
} }
} }
dialog->add_filter(filter); dialog->add_filter(filter);
auto filter_any=Gtk::FileFilter::create(); auto filter_any = Gtk::FileFilter::create();
filter_any->set_name("Any Files"); filter_any->set_name("Any Files");
filter_any->add_pattern("*"); filter_any->add_pattern("*");
dialog->add_filter(filter_any); dialog->add_filter(filter_any);
@ -125,69 +183,131 @@ void TextEditor::btnsave_clicked(){
dialog->show(); dialog->show();
} }
void TextEditor::savedialog_response(int response){ void TextEditor::savedialog_response(int response)
if(response==Gtk::RESPONSE_ACCEPT){ {
//Get Filename if (response == Gtk::RESPONSE_ACCEPT)
auto file=dialog->get_file(); {
std::string filename=file->get_path(); // Get Filename
//Get Text auto file = dialog->get_file();
std::string filename = file->get_path();
// Get Text
Glib::ustring text; Glib::ustring text;
text=buffer1->get_text(); text = buffer1->get_text();
//Save to a file // Save to a file
std::ofstream outfile; std::ofstream outfile;
outfile.open(filename,std::ios_base::out); outfile.open(filename, std::ios_base::out);
outfile<<text; outfile << text;
outfile.close(); outfile.close();
} }
dialog.reset(); dialog.reset();
} }
void TextEditor::buffer1_changed(){ void TextEditor::buffer1_changed()
//When the text changed,enable the copy button {
btn_copy.set_sensitive(); // When the text changed,enable the copy button
} }
void TextEditor::btncopy_clicked(){ void TextEditor::search_entry_changed()
//Get Text {
// 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 (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 (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 (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; Glib::ustring text;
Gtk::TextBuffer::iterator start,end; Gtk::TextBuffer::iterator start, end;
if(buffer1->get_selection_bounds(start,end)){ if (buffer1->get_selection_bounds(start, end))
text=buffer1->get_text(start,end); {
}else{ text = buffer1->get_text(start, end);
text=buffer1->get_text(); }
else
{
text = buffer1->get_text();
} }
//Get Clipboard and set text // Get Clipboard and set text
auto refClipboard=Gtk::Clipboard::get(); auto refClipboard = Gtk::Clipboard::get();
refClipboard->set_text(text); refClipboard->set_text(text);
//Show InfoBar // Show InfoBar
label1.set_label("The Text is copyed"); label1.set_label("The Text is copyed");
infobar.show(); infobar.show();
} }
void TextEditor::btnpaste_clicked(){ void TextEditor::btnpaste_clicked()
//Get ClipBoard {
auto refClipboard=Gtk::Clipboard::get(); // Get ClipBoard
refClipboard->request_text(sigc::mem_fun(*this,&TextEditor::clipboard_receive)); auto refClipboard = Gtk::Clipboard::get();
refClipboard->request_text(sigc::mem_fun(*this, &TextEditor::clipboard_receive));
} }
void TextEditor::clipboard_receive(const Glib::ustring &text){ void TextEditor::clipboard_receive(const Glib::ustring &text)
if(buffer1->insert_interactive_at_cursor(text)){ {
//Show InfoBar if (buffer1->insert_interactive_at_cursor(text))
{
// Show InfoBar
label1.set_label("The Text is Pasted at cursor position"); label1.set_label("The Text is Pasted at cursor position");
infobar.show(); infobar.show();
}else{ }
//Show InfoBar else
{
// Show InfoBar
label1.set_label("Text Paste Error!"); label1.set_label("Text Paste Error!");
infobar.show(); infobar.show();
} }
} }
void TextEditor::btnclear_clicked(){ void TextEditor::btnclose_clicked()
{
buffer1->set_text(""); buffer1->set_text("");
file_opened = false;
} }
void TextEditor::infobar_response(int response){ void TextEditor::infobar_response(int response)
{
infobar.hide(); infobar.hide();
} }