Add gtk137
This commit is contained in:
parent
be99278186
commit
8759e9ac65
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
|
||||
}
|
|
@ -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)
|
|
@ -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"><Control>o</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Save</attribute>
|
||||
<attribute name="action">win.text_save</attribute>
|
||||
<attribute name="accel"><Control>s</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Save As</attribute>
|
||||
<attribute name="action">win.text_saveas</attribute>
|
||||
<attribute name="accel"><Control><Shift>s</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Copy</attribute>
|
||||
<attribute name="action">win.text_copy</attribute>
|
||||
<attribute name="accel"><Control>c</attribute>
|
||||
</item>
|
||||
<item>
|
||||
<attribute name="label">Paste</attribute>
|
||||
<attribute name="action">win.text_paste</attribute>
|
||||
<attribute name="accel"><Control>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>
|
|
@ -0,0 +1,351 @@
|
|||
#include "TextEditor.hh"
|
||||
#include "text_types.hh"
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
|
||||
// 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<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);
|
||||
|
||||
// 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);
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
#include <gtkmm.h>
|
||||
|
||||
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<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;
|
||||
Glib::RefPtr<Gtk::TextBuffer> buffer1;
|
||||
Gtk::TextView textview1;
|
||||
Gtk::InfoBar infobar;
|
||||
Gtk::Label label1;
|
||||
|
||||
//File Dialog
|
||||
Glib::RefPtr<Gtk::FileChooserNative> 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();
|
||||
};
|
|
@ -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);
|
||||
}
|
Loading…
Reference in New Issue