Add gtk135

This commit is contained in:
daleclack 2022-07-22 13:35:37 +08:00
parent f85d430a5f
commit f9fa84b639
9 changed files with 591 additions and 0 deletions

View File

@ -0,0 +1,3 @@
{
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
}

View File

@ -0,0 +1,75 @@
set(CMAKE_CXX_STANDARD 17)
cmake_minimum_required(VERSION 3.0.0)
project(gtk129_drawing2 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/drawing.cc)
#Compile Resource
set(RESOURCE_LIST
icons/scalable/status/circle.svg
icons/scalable/status/freehand.svg
icons/scalable/status/line.svg
icons/scalable/status/rectangle.svg)
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 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)

View File

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#363636;
}
</style>
</defs>
<path style="fill:currentColor;fill-opacity:1;stroke:none"
d="M8 2A6 6 0 0 0 2 8 6 6 0 0 0 8 14 6 6 0 0 0 14 8 6 6 0 0 0 8 2M8 3A5 5 0 0 1 13 8 5 5 0 0 1 8 13 5 5 0 0 1 3 8 5 5 0 0 1 8 3"
class="ColorScheme-Text"
/>
</svg>

After

Width:  |  Height:  |  Size: 460 B

View File

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#363636;
}
</style>
</defs>
<path style="fill:currentColor;fill-opacity:1;stroke:none"
d="M 9.15625 2 L 2 9.125 L 2 12 C 3.075 12.019 4.84375 12 4.84375 12 L 12 4.84375 L 9.15625 2 z M 8.4375 4.15625 L 9.84375 5.5625 L 6.9980469 8.4375 L 5.5605469 6.9980469 L 8.4375 4.15625 z M 4.84375 7.71875 L 6.28125 9.125 L 5.5625 9.84375 L 4.15625 8.4375 L 4.84375 7.71875 z M 12.123047 9 C 11.927047 9.001 11.392547 9.0455 10.560547 9.5625 C 10.300547 9.7245 10.107547 9.9089531 9.8105469 10.126953 C 9.6525469 10.242953 9.0850469 10.620953 8.8730469 10.751953 C 8.2540469 11.134953 8.0320469 11.231953 7.4980469 11.501953 C 6.9810469 11.762953 6.4395469 12.000453 6.0605469 12.189453 C 4.4685469 12.984453 1.9960937 13.001953 1.9960938 13.001953 L 1.9960938 14.001953 C 1.9960938 14.001953 4.4935469 14.033953 6.3105469 13.126953 C 6.5515469 13.006953 6.9790469 12.808953 7.3730469 12.626953 C 7.3730469 12.626953 8.4920469 12.034203 8.4980469 12.033203 C 8.6940469 11.924203 8.8592969 11.841203 9.1542969 11.658203 C 9.3822969 11.517203 9.9292969 11.166953 10.154297 11.001953 C 10.484297 10.758953 10.697047 10.579703 10.873047 10.470703 C 11.258047 10.168703 11.693047 9.9889531 12.123047 10.001953 C 12.089047 10.001953 12.253297 10.011703 12.404297 10.095703 C 12.555297 10.179703 12.714797 10.329703 12.841797 10.470703 C 13.086797 10.802703 13.198047 11.055953 13.248047 11.501953 C 13.212047 12.808953 11.968047 13.006953 10.998047 13.001953 L 10.998047 14.001953 C 12.977047 14.090953 13.998047 13.167703 13.998047 11.470703 C 13.994047 11.182703 13.947797 10.945953 13.841797 10.626953 C 13.735797 10.307953 13.575797 9.9514531 13.341797 9.6894531 C 12.980797 9.2664531 12.799047 9.0809531 12.123047 9.0019531 L 12.123047 9 z "
class="ColorScheme-Text"
/>
</svg>

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#363636;
}
</style>
</defs>
<path style="fill:currentColor;fill-opacity:1;stroke:none"
d="M 11 2 L 11 4.3125 L 4.3125 11.001953 L 2.0019531 11.001953 L 2.0019531 14.001953 L 5.0019531 14.001953 L 5.0019531 11.6875 L 11.6875 5 L 14 5 L 14 2 L 11 2 z M 12 3 L 13 3 L 13 4 L 12 4 L 12 3 z M 3 12 L 4 12 L 4 13 L 3 13 L 3 12 z "
class="ColorScheme-Text"
/>
</svg>

After

Width:  |  Height:  |  Size: 569 B

View File

@ -0,0 +1,13 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16">
<defs id="defs3051">
<style type="text/css" id="current-color-scheme">
.ColorScheme-Text {
color:#363636;
}
</style>
</defs>
<path style="fill:currentColor;fill-opacity:1;stroke:none"
d="m2 2v12h12v-12zm1 1h10v10h-10z"
class="ColorScheme-Text"
/>
</svg>

After

Width:  |  Height:  |  Size: 366 B

View File

@ -0,0 +1,365 @@
#include "drawing.hh"
#include <algorithm>
#include <iostream>
#include <fstream>
#include "../../json_nlohmann/json.hpp"
using json = nlohmann::json;
Drawing::Drawing()
: fill_check("Enable Fill Color"),
main_label("Select a color"),
size_label("Pen Size"),
left_box(Gtk::ORIENTATION_VERTICAL, 5),
main_box(Gtk::ORIENTATION_HORIZONTAL, 5),
btn_box(Gtk::ORIENTATION_VERTICAL, 5),
btn_clear("Clear Board"),
btn_save("Save to png"),
btn_exit("Exit")
{
// load config from json file
int width = 640, height = 480;
std::ifstream file1("config.json");
if (file1.is_open())
{
json data = json::parse(file1);
width = data["width"];
height = data["height"];
}
// Initalize window
set_icon_name("org.gtk.daleclack");
set_title("Drawing");
set_default_size(width, height);
// Set the buttons grouped and set normal draw mode
auto group = btn_free.get_group();
btn_free.set_mode(false);
btn_circle.set_group(group);
btn_circle.set_mode(false);
btn_line.set_group(group);
btn_line.set_mode(false);
btn_rectangle.set_group(group);
btn_rectangle.set_mode(false);
// Add images to the button
btn_free.set_image_from_icon_name("freehand");
btn_free.set_always_show_image();
btn_free.signal_clicked().connect(sigc::mem_fun(*this, &Drawing::btnfree_clicked));
btn_circle.set_image_from_icon_name("circle");
btn_circle.set_always_show_image();
btn_circle.signal_clicked().connect(sigc::mem_fun(*this, &Drawing::btncircle_clicked));
btn_line.set_image_from_icon_name("line");
btn_line.set_always_show_image();
btn_line.signal_clicked().connect(sigc::mem_fun(*this, &Drawing::btnline_clicked));
btn_rectangle.set_image_from_icon_name("rectangle");
btn_rectangle.set_always_show_image();
btn_rectangle.signal_clicked().connect(sigc::mem_fun(*this, &Drawing::btnrectangle_clicked));
// Left Panel
left_box.pack_start(btn_free, Gtk::PACK_SHRINK);
left_box.pack_start(btn_circle, Gtk::PACK_SHRINK);
left_box.pack_start(btn_line, Gtk::PACK_SHRINK);
left_box.pack_start(btn_rectangle, Gtk::PACK_SHRINK);
left_box.set_valign(Gtk::ALIGN_START);
// Color set panel
size_adj = Gtk::Adjustment::create(3.0, 1.0, 20.0);
scale.set_adjustment(size_adj);
scale.set_value_pos(Gtk::POS_BOTTOM);
btn_box.pack_start(fill_check, Gtk::PACK_SHRINK);
btn_box.pack_start(fill_btn, Gtk::PACK_SHRINK);
btn_box.pack_start(main_label, Gtk::PACK_SHRINK);
btn_box.pack_start(color_btn, Gtk::PACK_SHRINK);
btn_box.pack_start(size_label, Gtk::PACK_SHRINK);
btn_box.pack_start(scale, Gtk::PACK_SHRINK);
btn_box.pack_start(btn_save, Gtk::PACK_SHRINK);
btn_box.pack_start(btn_clear, Gtk::PACK_SHRINK);
btn_box.pack_start(btn_exit, Gtk::PACK_SHRINK);
btn_box.set_halign(Gtk::ALIGN_CENTER);
btn_box.set_valign(Gtk::ALIGN_CENTER);
// Add Gesture
btn_clear.signal_clicked().connect(sigc::mem_fun(*this, &Drawing::btnclear_clicked));
btn_save.signal_clicked().connect(sigc::mem_fun(*this, &Drawing::btnsave_clicked));
btn_exit.signal_clicked().connect(sigc::mem_fun(*this, &Drawing::hide));
drag = Gtk::GestureDrag::create(draw_area);
drag->set_button(GDK_BUTTON_PRIMARY);
drag->signal_drag_begin().connect(sigc::mem_fun(*this, &Drawing::drag_begin));
drag->signal_drag_update().connect(sigc::mem_fun(*this, &Drawing::drag_progress));
drag->signal_drag_end().connect(sigc::mem_fun(*this, &Drawing::drag_end));
press = Gtk::GestureMultiPress::create(draw_area);
press->set_button();
press->signal_pressed().connect(sigc::mem_fun(*this, &Drawing::button_press));
// Create a Surface
surface = Cairo::ImageSurface::create(Cairo::FORMAT_ARGB32, 600, 480);
// Set Default Color
m_color.set_blue(0);
m_color.set_green(0);
m_color.set_red(0);
m_color.set_alpha(1);
color_btn.set_rgba(m_color);
color_btn.signal_color_set().connect(sigc::mem_fun(*this, &Drawing::color_set));
fill_color = m_color;
fill_btn.set_rgba(fill_color);
fill_btn.signal_color_set().connect(sigc::mem_fun(*this, &Drawing::color_set));
// Initalial draw
auto cr = Cairo::Context::create(surface);
cr->set_source_rgb(1, 1, 1);
cr->paint();
cr.clear();
draw_area.queue_draw();
// Set Draw mode to default
drawing_mode = DrawMode::Default;
// Initalize main widget
draw_area.set_size_request(width - 40, height);
draw_area.signal_draw().connect(sigc::mem_fun(*this, &Drawing::draw_event));
main_box.pack_start(left_box, Gtk::PACK_SHRINK);
main_box.pack_start(draw_area);
main_box.pack_start(btn_box, Gtk::PACK_SHRINK);
main_box.set_border_width(10);
add(main_box);
show_all_children();
}
void Drawing::btnsave_clicked()
{
// Create a dialog
dialog = Gtk::FileChooserNative::create("Save to png file", *this,
Gtk::FILE_CHOOSER_ACTION_SAVE, "OK", "Cancel");
// Link Signal
dialog->signal_response().connect(sigc::mem_fun(*this, &Drawing::dialog_response));
// Create Filters
auto filter_png = Gtk::FileFilter::create();
filter_png->set_name("Png files");
filter_png->add_pattern("*.png");
dialog->add_filter(filter_png);
auto filter_any = Gtk::FileFilter::create();
filter_any->set_name("Any Files");
filter_any->add_pattern("*");
dialog->add_filter(filter_any);
dialog->show();
}
void Drawing::dialog_response(int response_id)
{
// Save cairo surface to png file
if (response_id == Gtk::RESPONSE_ACCEPT)
{
// Get file name
std::string filename;
auto file = dialog->get_file();
filename = file->get_path();
// Auto complete the extension of the image file
size_t length = filename.length();
std::string extension = filename.substr(length - 3, length - 1);
std::transform(extension.begin(), extension.end(), extension.begin(), ::tolower);
if (extension != "png")
{
filename += ".png";
}
// Write surface data to the file
surface->write_to_png(filename);
}
dialog.reset();
}
void Drawing::btnfree_clicked()
{
// Mode1: Free Drawing
drawing_mode = DrawMode::Default;
}
void Drawing::btnline_clicked()
{
// Mode2: Draw line, click for start point and end point
drawing_mode = DrawMode::Line;
}
void Drawing::btncircle_clicked()
{
// Mode3: Draw circle, click for radius
drawing_mode = DrawMode::Circle;
}
void Drawing::btnrectangle_clicked()
{
// Mode4: Draw a rectangle
drawing_mode = DrawMode::Rectangle;
}
void Drawing::btnclear_clicked()
{
if (surface)
{
// Clear the content in draw area
auto cr = Cairo::Context::create(surface);
cr->set_source_rgb(1, 1, 1);
cr->paint();
cr.clear();
draw_area.queue_draw();
}
}
// Signal Handlers
bool Drawing::draw_event(const Cairo::RefPtr<Cairo::Context> &context)
{
// Show context
context->set_source(surface, 0, 0);
context->paint();
return true;
}
void Drawing::draw_brush(double x, double y, DrawProcess process)
{
brush_size = scale.get_value();
auto cr = Cairo::Context::create(surface);
// Create Draw Brush with specificed size
cr->set_line_width(brush_size * 2);
switch (drawing_mode)
{
case DrawMode::Default:
// Use Line for main drawing
if (process == DrawProcess::Begin)
{
rel_x = x;
rel_y = y;
}
else
{
cr->move_to(rel_x - 0.1, rel_y - 0.1);
cr->line_to(x, y);
rel_x = x;
rel_y = y;
}
// Set Color
cr->set_source_rgba(m_color.get_red(), m_color.get_green(),
m_color.get_blue(), m_color.get_alpha());
// Fill Color and Delete the brush
cr->stroke();
cr.clear();
break;
case DrawMode::Line:
cr->move_to(rel_x, rel_y);
cr->line_to(x, y);
// Set Color
cr->set_source_rgba(m_color.get_red(), m_color.get_green(),
m_color.get_blue(), m_color.get_alpha());
// Fill Color and Delete the brush
cr->stroke();
cr.clear();
break;
case DrawMode::Circle:
// Fill Color and Delete the brush
if (fill_check.get_active())
{
cr->arc(rel_x, rel_y, sqrt((x - rel_x) * (x - rel_x) + (y - rel_y) * (y - rel_y)), 0.0, 2 * G_PI);
// Fill Color
draw_fill_color(cr);
}
cr->arc(rel_x, rel_y, sqrt((x - rel_x) * (x - rel_x) + (y - rel_y) * (y - rel_y)), 0.0, 2 * G_PI);
cr->set_source_rgba(m_color.get_red(), m_color.get_green(),
m_color.get_blue(), m_color.get_alpha());
cr->stroke();
cr.clear();
break;
case DrawMode::Rectangle:
// Fill Color and Delete the brush
if (fill_check.get_active())
{
// Fill Color
cr->rectangle(rel_x, rel_y, abs(x - rel_x), abs(y - rel_y));
draw_fill_color(cr);
}
cr->rectangle(rel_x, rel_y, abs(x - rel_x), abs(y - rel_y));
cr->set_source_rgba(m_color.get_red(), m_color.get_green(),
m_color.get_blue(), m_color.get_alpha());
cr->stroke();
cr.clear();
break;
}
draw_area.queue_draw();
}
void Drawing::draw_fill_color(const Cairo::RefPtr<Cairo::Context> &cr)
{
cr->set_source_rgba(fill_color.get_red(), fill_color.get_green(),
fill_color.get_blue(), fill_color.get_alpha());
cr->fill();
}
void Drawing::button_press(int n_press, double x, double y)
{
auto button = press->get_current_button();
// std::cout<<button<<std::endl;
switch (button)
{
case 1:
if (drawing_mode != DrawMode::Default)
{
if (begin)
{
begin = !begin;
rel_x = x;
rel_y = y;
}
else
{
begin = !begin;
draw_brush(x, y, DrawProcess::End);
}
}
break;
case 3:
btnclear_clicked();
break;
}
}
void Drawing::drag_begin(double x, double y)
{
start_x = x;
start_y = y;
draw_brush(x, y, DrawProcess::Begin);
}
void Drawing::drag_progress(double x, double y)
{
// Progress and end
draw_brush(x + start_x, y + start_y, DrawProcess::Update);
}
void Drawing::drag_end(double x, double y)
{
// Progress and end
draw_brush(x + start_x, y + start_y, DrawProcess::End);
}
void Drawing::color_set()
{
m_color = color_btn.get_rgba();
fill_color = fill_btn.get_rgba();
}

View File

@ -0,0 +1,89 @@
#pragma once
#include <gtkmm.h>
// 4 Draw modes: default(free draw), circle, line, rectangle
enum class DrawMode{
Default,
Circle,
Line,
Rectangle
};
// Flage for process of drawing
enum class DrawProcess{
Begin, // The beginning of draw
Update, // The Process(Position update)
End // The end of draw
};
class Drawing : public Gtk::Window
{
// Drawing Mode
DrawMode drawing_mode;
// Child Widgets
Gtk::DrawingArea draw_area;
Gtk::ColorButton color_btn, fill_btn;
Gtk::CheckButton fill_check;
Gtk::Label main_label, size_label;
Gtk::Box left_box, main_box, btn_box;
Gtk::Button btn_clear, btn_save, btn_exit;
Gtk::RadioButton btn_free, btn_line, btn_circle, btn_rectangle;
Gtk::Scale scale;
// Color Setting
Gdk::RGBA m_color, fill_color;
Cairo::RefPtr<Cairo::ImageSurface> surface;
// Image Save Dialog
Glib::RefPtr<Gtk::FileChooserNative> dialog;
void dialog_response(int response_id);
// Draw Brush Settings
double brush_size;
double rel_x, rel_y;
bool begin = true;
// Gesture to draw
Glib::RefPtr<Gtk::GestureDrag> drag;
Glib::RefPtr<Gtk::GestureMultiPress> press;
Glib::RefPtr<Gtk::Adjustment> size_adj;
double start_x, start_y;
// Signal Handlers
// Part 1: Drawing signal handlers
bool draw_event(const Cairo::RefPtr<Cairo::Context> &context);
void draw_brush(double x, double y, DrawProcess process = DrawProcess::Update);
void draw_fill_color(const Cairo::RefPtr<Cairo::Context> &cr);
// Part 2: Signal handler for gestures
void button_press(int n_press, double x, double y);
void drag_begin(double x, double y);
void drag_progress(double x, double y);
void drag_end(double x, double y);
// Part 3: Signal Hanlders for normal buttons on the UI
void color_set();
void btnfree_clicked();
void btnline_clicked();
void btncircle_clicked();
void btnrectangle_clicked();
void btnclear_clicked();
void btnsave_clicked();
public:
Drawing();
};

View File

@ -0,0 +1,7 @@
#include "drawing.hh"
int main(int argc,char **argv){
auto app=Gtk::Application::create(argc,argv,"org.gtk.daleclack");
Drawing window;
return app->run(window);
}