From 8759e9ac653933a4180eec94e89172d76e9724c4 Mon Sep 17 00:00:00 2001 From: daleclack Date: Sat, 23 Jul 2022 10:35:35 +0800 Subject: [PATCH] Add gtk137 --- .../.vscode/settings.json | 3 + Gtkmm3/gtk137_editor_keyboard/CMakeLists.txt | 72 ++++ .../gtk137_editor_keyboard/res/text_menu.xml | 40 ++ .../gtk137_editor_keyboard/src/TextEditor.cc | 351 ++++++++++++++++++ .../gtk137_editor_keyboard/src/TextEditor.hh | 61 +++ Gtkmm3/gtk137_editor_keyboard/src/main.cc | 7 + 6 files changed, 534 insertions(+) create mode 100644 Gtkmm3/gtk137_editor_keyboard/.vscode/settings.json create mode 100644 Gtkmm3/gtk137_editor_keyboard/CMakeLists.txt create mode 100644 Gtkmm3/gtk137_editor_keyboard/res/text_menu.xml create mode 100644 Gtkmm3/gtk137_editor_keyboard/src/TextEditor.cc create mode 100644 Gtkmm3/gtk137_editor_keyboard/src/TextEditor.hh create mode 100644 Gtkmm3/gtk137_editor_keyboard/src/main.cc diff --git a/Gtkmm3/gtk137_editor_keyboard/.vscode/settings.json b/Gtkmm3/gtk137_editor_keyboard/.vscode/settings.json new file mode 100644 index 0000000..b4d8c35 --- /dev/null +++ b/Gtkmm3/gtk137_editor_keyboard/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools" +} \ No newline at end of file diff --git a/Gtkmm3/gtk137_editor_keyboard/CMakeLists.txt b/Gtkmm3/gtk137_editor_keyboard/CMakeLists.txt new file mode 100644 index 0000000..ecf2ed9 --- /dev/null +++ b/Gtkmm3/gtk137_editor_keyboard/CMakeLists.txt @@ -0,0 +1,72 @@ +set(CMAKE_CXX_STANDARD 17) +cmake_minimum_required(VERSION 3.0.0) +project(gtk137_editor5 VERSION 1.0.0) + +list(APPEND CMAKE_MODULE_PATH ${PROJECT_SOURCE_DIR}/../../GCR_CMake/macros) +include(GlibCompileResourcesSupport) + +include(CTest) +enable_testing() + +set(CPACK_PROJECT_NAME ${PROJECT_NAME}) +set(CPACK_PROJECT_VERSION ${PROJECT_VERSION}) + +include(CPack) +include_directories(.) +include_directories(..) + +#Find PkgConfig to use gtkmm3 +find_package (PkgConfig REQUIRED) +pkg_check_modules (GTKMM3 REQUIRED gtkmm-3.0) +include_directories (${GTKMM3_INCLUDE_DIRS}) +link_directories (${GTKMM3_LIBRARY_DIRS}) + +#Find Gettext +find_package (Gettext REQUIRED) +set(PO_DIR ${CMAKE_BINARY_DIR}/po/zh_CN/LC_MESSAGES) + +#Source files +set(SOURCE_FILE src/main.cc src/TextEditor.cc) + +#Compile Resource + +set(RESOURCE_LIST + text_menu.xml) + +compile_gresources(RESOURCE_FILE + XML_OUT + TYPE EMBED_C + RESOURCES ${RESOURCE_LIST} + PREFIX "/org/gtk/daleclack" + SOURCE_DIR ${PROJECT_SOURCE_DIR}/res) + +# Add a custom target to the makefile. Now make builds our resource file. +# It depends on the output RESOURCE_FILE. + +add_custom_target(resource ALL DEPENDS ${RESOURCE_FILE}) + +#For win32 platform,use rc resource and .ico icon +if(WIN32) + SET(CMAKE_RC_COMPILER x86_64-w64-mingw32-windres) + set(app_WINRC ../icon.rc) + set_property(SOURCE ../icon.rc APPEND PROPERTY + OBJECT_DEPENDS ${PROJECT_SOURCE_DIR}/../icon.ico + ) + add_executable(${PROJECT_NAME} WIN32 ${app_WINRC} ${SOURCE_FILE} ${RESOURCE_FILE}) + add_custom_command( TARGET ${PROJECT_NAME} + COMMAND echo * > ${CMAKE_BINARY_DIR}/.gitignore + COMMAND echo **/* > ${CMAKE_BINARY_DIR}/.hgignore) +else() + add_executable(${PROJECT_NAME} ${SOURCE_FILE} ${RESOURCE_FILE}) + add_custom_command( TARGET ${PROJECT_NAME} + COMMAND echo \"*\" > ${CMAKE_BINARY_DIR}/.gitignore + COMMAND echo \"**/*\" > ${CMAKE_BINARY_DIR}/.hgignore) +endif(WIN32) + +#Add command to generate .gitignore and .mo files +# add_custom_command( TARGET ${PROJECT_NAME} +# COMMAND mkdir -p ${PO_DIR} +# COMMAND ${GETTEXT_MSGFMT_EXECUTABLE} ${CMAKE_SOURCE_DIR}/po/zh_CN.po -o ${PO_DIR}/${PROJECT_NAME}.mo) + +SET (CMAKE_EXTRA_CXX_FLAGS ${GTKMM3_CFLAGS_OTHER}) +target_link_libraries (${PROJECT_NAME} ${GTKMM3_LIBRARIES} -lpthread) diff --git a/Gtkmm3/gtk137_editor_keyboard/res/text_menu.xml b/Gtkmm3/gtk137_editor_keyboard/res/text_menu.xml new file mode 100644 index 0000000..ae02db2 --- /dev/null +++ b/Gtkmm3/gtk137_editor_keyboard/res/text_menu.xml @@ -0,0 +1,40 @@ + + + +
+ + Open + win.text_open + <Control>o + + + Save + win.text_save + <Control>s + + + Save As + win.text_saveas + <Control><Shift>s + + + Copy + win.text_copy + <Control>c + + + Paste + win.text_paste + <Control>v + + + Close + win.text_close + + + About + win.text_about + +
+
+
\ No newline at end of file diff --git a/Gtkmm3/gtk137_editor_keyboard/src/TextEditor.cc b/Gtkmm3/gtk137_editor_keyboard/src/TextEditor.cc new file mode 100644 index 0000000..64bd8e9 --- /dev/null +++ b/Gtkmm3/gtk137_editor_keyboard/src/TextEditor.cc @@ -0,0 +1,351 @@ +#include "TextEditor.hh" +#include "text_types.hh" +#include +#include + +// 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) +{ + // Initalize Window + set_default_size(800, 450); + 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::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(infobar.get_content_area()); + infobox->pack_start(label1); + vbox.pack_start(infobar, Gtk::PACK_SHRINK); + + // Show everything + vbox.pack_start(hbox); + add(vbox); + show_all_children(); + infobar.hide(); +} + +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); +} diff --git a/Gtkmm3/gtk137_editor_keyboard/src/TextEditor.hh b/Gtkmm3/gtk137_editor_keyboard/src/TextEditor.hh new file mode 100644 index 0000000..f106654 --- /dev/null +++ b/Gtkmm3/gtk137_editor_keyboard/src/TextEditor.hh @@ -0,0 +1,61 @@ +#pragma once + +#include + +class TextEditor : public Gtk::ApplicationWindow{ +public: + TextEditor(); +private: + //Header widgets + Gtk::HeaderBar header; + Gtk::MenuButton menubtn; + Gtk::Popover popover; + Gtk::ToggleButton search_button; + Glib::RefPtr menu_builder; + + //SearchBar + Gtk::SearchBar searchbar; + Gtk::SearchEntry search_entry; + Gtk::Box searchbox; + Gtk::Button search_up, search_down; + Glib::RefPtr search_binding; + Gtk::TextIter curr_iter_up, curr_iter_down; + + //Window widgets + Gtk::Box vbox,hbox,*infobox; + Gtk::ScrolledWindow sw1,sw2; + Glib::RefPtr buffer1; + Gtk::TextView textview1; + Gtk::InfoBar infobar; + Gtk::Label label1; + + //File Dialog + Glib::RefPtr dialog; + Glib::ustring curr_filename; + bool file_opened; + + //Signal Handlers + + // File Operation functions + void btnopen_clicked(); + void opendialog_response(int response); + void btnsave_clicked(); + void btnsaveas_clicked(); + void savedialog_response(int response); + + // Copy, Paste and text operations + void btncopy_clicked(); + void btnpaste_clicked(); + void btnclose_clicked(); + void buffer1_changed(); + void clipboard_receive(const Glib::ustring &text); + void infobar_response(int response); + + // Search funtion + void search_entry_changed(); + void search_forward(); + void search_backward(); + + // Other Signal Handlers + void about_activated(); +}; diff --git a/Gtkmm3/gtk137_editor_keyboard/src/main.cc b/Gtkmm3/gtk137_editor_keyboard/src/main.cc new file mode 100644 index 0000000..9c33625 --- /dev/null +++ b/Gtkmm3/gtk137_editor_keyboard/src/main.cc @@ -0,0 +1,7 @@ +#include "TextEditor.hh" + +int main(int argc,char **argv){ + auto app = Gtk::Application::create(argc,argv,"org.gtk.daleclack"); + TextEditor textwin; + return app->run(textwin); +} \ No newline at end of file