Add context menu for gtk144

This commit is contained in:
daleclack 2023-01-17 15:41:12 +08:00
parent 2539baf345
commit fb5887815f
16 changed files with 492 additions and 0 deletions

View File

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

View File

@ -0,0 +1,76 @@
set(CMAKE_CXX_STANDARD 17)
cmake_minimum_required(VERSION 3.0.0)
project(gtk144_gtkui6 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 (GTKMM4 REQUIRED gtkmm-4.0)
include_directories (${GTKMM4_INCLUDE_DIRS})
link_directories (${GTKMM4_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/MenuWin.cc src/Win1.cc src/Win2.cc src/MenuBar.cc)
#Compile Resource
set(RESOURCE_LIST
STRIPBLANKS context_menu.xml
STRIPBLANKS default_menu.xml
STRIPBLANKS win1_menu.xml
STRIPBLANKS win2_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 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 ${GTKMM4_CFLAGS_OTHER})
target_link_libraries (${PROJECT_NAME} ${GTKMM4_LIBRARIES} -lpthread)

View File

@ -0,0 +1,13 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id="context_menu">
<section>
<item>
<attribute name="label">About</attribute>
</item>
<item>
<attribute name="label">Customize</attribute>
</item>
</section>
</menu>
</interface>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id = "default_menu">
<submenu>
<attribute name="label">Test</attribute>
<item>
<attribute name="label">About</attribute>
<attribute name="action">win.main_about</attribute>
</item>
</submenu>
<submenu>
<attribute name="label">Test1</attribute>
<item>
<attribute name="label">Cut</attribute>
</item>
</submenu>
</menu>
</interface>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id = "win1_menu">
<submenu>
<attribute name="label">Win1</attribute>
<item>
<attribute name="label">New Window</attribute>
<attribute name="action">win.new_win1</attribute>
</item>
<item>
<attribute name="label">Quit</attribute>
<attribute name="action">win.quit_win1</attribute>
</item>
<item>
<attribute name="label">About</attribute>
<attribute name="action">win.about_win1</attribute>
</item>
</submenu>
<submenu>
<attribute name="label">Test2</attribute>
<item>
<attribute name="label">Cut</attribute>
</item>
</submenu>
</menu>
</interface>

View File

@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<menu id = "win2_menu">
<submenu>
<attribute name="label">Win2</attribute>
<item>
<attribute name="label">New Window</attribute>
<attribute name="action">win.new_win2</attribute>
</item>
<item>
<attribute name="label">Quit</attribute>
<attribute name="action">win.quit_win2</attribute>
</item>
<item>
<attribute name="label">About</attribute>
<attribute name="action">win.about_win2</attribute>
</item>
</submenu>
<submenu>
<attribute name="label">Test3</attribute>
<item>
<attribute name="label">Cut</attribute>
</item>
</submenu>
</menu>
</interface>

View File

@ -0,0 +1,33 @@
#include "MenuBar.hh"
MenuBar::MenuBar()
{
// Create models
builder_def = Gtk::Builder::create_from_resource("/org/gtk/daleclack/default_menu.xml");
model_default = builder_def->get_object<Gio::MenuModel>("default_menu");
builder_win1 = Gtk::Builder::create_from_resource("/org/gtk/daleclack/win1_menu.xml");
model_win1 = builder_win1->get_object<Gio::MenuModel>("win1_menu");
builder_win2 = Gtk::Builder::create_from_resource("/org/gtk/daleclack/win2_menu.xml");
model_win2 = builder_win2->get_object<Gio::MenuModel>("win2_menu");
menubar = Gtk::make_managed<Gtk::PopoverMenuBar>(model_default);
}
void MenuBar::change_menu(WinShown win_id)
{
// Switch the menu for a window
switch (win_id)
{
case WinShown::DEFAULT:
menubar->set_menu_model(model_default);
break;
case WinShown::WIN_1:
menubar->set_menu_model(model_win1);
break;
case WinShown::WIN_2:
menubar->set_menu_model(model_win2);
break;
}
}
MenuBar::~MenuBar(){
}

View File

@ -0,0 +1,24 @@
#pragma once
#include <gtkmm.h>
enum class WinShown
{
DEFAULT,
WIN_1,
WIN_2
};
class MenuBar
{
public:
MenuBar();
~MenuBar();
void change_menu(WinShown win_id);
Gtk::PopoverMenuBar *menubar;
private:
// Menu Models
Glib::RefPtr<Gtk::Builder> builder_def, builder_win1, builder_win2;
Glib::RefPtr<Gio::MenuModel> model_default, model_win1, model_win2;
};

View File

@ -0,0 +1,156 @@
#include "MenuWin.hh"
#include "Win1.hh"
#include "Win2.hh"
#include "jsonfile.hh"
WinShown curr_win;
MenuWin::MenuWin()
: main_box(Gtk::Orientation::VERTICAL),
btn_box(Gtk::Orientation::HORIZONTAL),
btn_main("Main"),
btn_win1("Win1"),
btn_win2("Win2"),
label1(" ")
{
// Initalize window
set_icon_name("org.gtk.daleclack");
set_default_size(1024, 576);
// Add actions
add_action("new_win1", sigc::mem_fun(*this, &MenuWin::new_win1));
add_action("quit_win1", sigc::mem_fun(*this, &MenuWin::quit_win1));
add_action("new_win2", sigc::mem_fun(*this, &MenuWin::new_win2));
add_action("quit_win2", sigc::mem_fun(*this, &MenuWin::quit_win2));
add_action("about_win1", sigc::mem_fun(*this, &MenuWin::show_about_win1));
add_action("about_win2", sigc::mem_fun(*this, &MenuWin::show_about_win2));
// Add popover menu bar
//menu_bar = new Gtk::PopoverMenuBar(model_default);
main_box.append(*(menu_bar.menubar));
// (menu_bar.menubar)->show();
// Add context menu
// Gesture for right click
gesture_right = Gtk::GestureClick::create();
gesture_right->set_button(GDK_BUTTON_SECONDARY);
gesture_right->signal_pressed().connect(sigc::mem_fun(*this, &MenuWin::press));
overlay1.add_controller(gesture_right);
// The Context menu
context_builder = Gtk::Builder::create_from_resource("/org/gtk/daleclack/context_menu.xml");
auto gmenu = context_builder->get_object<Gio::MenuModel>("context_menu");
context_menu.set_menu_model(gmenu);
context_menu.set_parent(overlay1);
context_menu.set_has_arrow(false);
// Add a label
label1.set_expand();
label1.set_halign(Gtk::Align::FILL);
label1.set_valign(Gtk::Align::FILL);
main_box.append(label1);
// Add buttons
btn_box.append(btn_main);
btn_box.append(btn_win1);
btn_box.append(btn_win2);
btn_box.set_halign(Gtk::Align::CENTER);
btn_box.set_valign(Gtk::Align::END);
main_box.append(btn_box);
// Link signals
btn_main.signal_clicked().connect(sigc::mem_fun(*this, &MenuWin::btnmain_clicked));
btn_win1.signal_clicked().connect(sigc::mem_fun(*this, &MenuWin::btnwin1_clicked));
btn_win2.signal_clicked().connect(sigc::mem_fun(*this, &MenuWin::btnwin2_clicked));
window1.signal_close_request().connect(sigc::mem_fun(*this, &MenuWin::win1_closed),true);
window2.signal_close_request().connect(sigc::mem_fun(*this, &MenuWin::win2_closed),true);
window1.set_transient_for(*this);
window2.set_transient_for(*this);
// Add widgets to the window
main_box.set_halign(Gtk::Align::FILL);
main_box.set_valign(Gtk::Align::FILL);
overlay1.add_overlay(main_box);
set_child(overlay1);
}
void MenuWin::press(int n_press, double x, double y){
// g_print("%f %f\n", x, y);
Gdk::Rectangle point(x, y, 1, 1);
context_menu.set_pointing_to(point);
context_menu.popup();
}
// Return to main menu
void MenuWin::btnmain_clicked()
{
window1.hide();
window2.hide();
menu_bar.change_menu(WinShown::DEFAULT);
}
// Launch Window1
void MenuWin::btnwin1_clicked()
{
menu_bar.change_menu(WinShown::WIN_1);
window1.show();
}
// Launch Window2
void MenuWin::btnwin2_clicked()
{
menu_bar.change_menu(WinShown::WIN_2);
window2.show();
}
// New a window
void MenuWin::new_win1()
{
window1.show();
menu_bar.change_menu(WinShown::WIN_1);
}
// Quit a window
void MenuWin::quit_win1()
{
window1.hide();
menu_bar.change_menu(WinShown::DEFAULT);
}
//
bool MenuWin::win1_closed(){
window1.hide();
menu_bar.change_menu(WinShown::DEFAULT);
return true;
}
// New a window
void MenuWin::new_win2()
{
window2.show();
menu_bar.change_menu(WinShown::WIN_2);
}
// Quit a window
void MenuWin::quit_win2()
{
window2.hide();
menu_bar.change_menu(WinShown::DEFAULT);
}
//
bool MenuWin::win2_closed(){
window2.hide();
menu_bar.change_menu(WinShown::DEFAULT);
return true;
}
// Test to interact to the child class by global menu
void MenuWin::show_about_win1(){
window1.about_win1();
}
void MenuWin::show_about_win2(){
window2.about_win2();
}

View File

@ -0,0 +1,43 @@
#pragma once
#include <gtkmm.h>
#include "Win1.hh"
#include "Win2.hh"
#include "MenuBar.hh"
class MenuWin : public Gtk::ApplicationWindow
{
public:
MenuWin();
private:
// Child Widgets
MenuBar menu_bar;
Gtk::Box main_box, btn_box;
Gtk::Button btn_main, btn_win1, btn_win2;
Gtk::Label label1;
Gtk::Overlay overlay1;
// Menu for right click
Glib::RefPtr<Gtk::GestureClick> gesture_right;
Glib::RefPtr<Gtk::Builder> context_builder;
Gtk::PopoverMenu context_menu;
void press(int n_press, double x, double y);
// Windows
Win1 window1;
Win2 window2;
// Signal Handlers
void btnmain_clicked();
void btnwin1_clicked();
void btnwin2_clicked();
void new_win1();
void quit_win1();
bool win1_closed();
void new_win2();
void quit_win2();
bool win2_closed();
void show_about_win1();
void show_about_win2();
};

View File

@ -0,0 +1,14 @@
#include "Win1.hh"
#include "MenuWin.hh"
#include <iostream>
extern WinShown curr_win;
Win1::Win1(){
// Add action
}
void Win1::about_win1(){
std::cout << "Window 1" << std::endl;
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <gtkmm.h>
class Win1 : public Gtk::ApplicationWindow
{
public:
Win1();
void about_win1();
private:
};

View File

@ -0,0 +1,13 @@
#include "Win2.hh"
#include "MenuWin.hh"
#include <iostream>
extern WinShown curr_win;
Win2::Win2(){
}
void Win2::about_win2(){
std::cout << "Window 2" << std::endl;
}

View File

@ -0,0 +1,12 @@
#pragma once
#include <gtkmm.h>
class Win2 : public Gtk::ApplicationWindow
{
public:
Win2();
void about_win2();
private:
};

View File

@ -0,0 +1,5 @@
#pragma once
#include "../../json_nlohmann/json.hpp"
using json = nlohmann::json;

View File

@ -0,0 +1,18 @@
#include "MenuWin.hh"
/*
The test application for My GtkUi 6.0,
In this version of My Gtk UI, more features will be added.
Because the Gtkmm4 has major changes with the Gtkmm3,
so some test is needed.
This is the first test, hello Gtkmm4!
Written by dale clack, 2023/1/15
*/
int main(int argc, char **argv){
// Create a application
auto app = Gtk::Application::create("org.gtk.daleclack");
// Create a window and run the application
app->make_window_and_run<MenuWin>(argc, argv);
}