[gnote/tabbed: 1/19] Use tabs to display notes
- From: Aurimas Černius <aurimasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnote/tabbed: 1/19] Use tabs to display notes
- Date: Tue, 2 Nov 2021 14:34:33 +0000 (UTC)
commit a3078c35bff2f3063b79e51cf11fef1dd6e9e652
Author: Aurimas Černius <aurisc4 gmail com>
Date: Sat Sep 4 16:29:11 2021 +0300
Use tabs to display notes
src/mainwindow.cpp | 55 +++------
src/mainwindow.hpp | 1 -
src/recentchanges.cpp | 291 ++++++++++++++++++++++++++++++----------------
src/recentchanges.hpp | 9 +-
src/searchnoteswidget.cpp | 3 +-
5 files changed, 215 insertions(+), 144 deletions(-)
---
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index bdd5ca9f..31a6a7ec 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -50,30 +50,17 @@ void MainWindow::present_in(MainWindow & win, const Note::Ptr & note)
win.present();
}
-MainWindow *MainWindow::present_active(const Note::Ptr & note)
-{
- if(note && note->has_window() && note->get_window()->host()
- && note->get_window()->host()->is_foreground(*note->get_window())) {
- MainWindow *win = dynamic_cast<MainWindow*>(note->get_window()->host());
- win->present();
- return win;
- }
-
- return NULL;
-}
-
MainWindow *MainWindow::present_in_new_window(IGnote & g, const Note::Ptr & note, bool close_on_esc)
{
if(!note) {
return NULL;
}
- if(!MainWindow::present_active(note)) {
- MainWindow & window = g.new_main_window();
- window.present_note(note);
- window.present();
- window.close_on_escape(close_on_esc);
- return &window;
- }
+
+ MainWindow & window = g.new_main_window();
+ window.present_note(note);
+ window.present();
+ window.close_on_escape(close_on_esc);
+ return &window;
return NULL;
}
@@ -83,25 +70,21 @@ MainWindow *MainWindow::present_default(IGnote & g, const Note::Ptr & note)
if(!note) {
return NULL;
}
- MainWindow *win = MainWindow::present_active(note);
- if(win) {
- return win;
- }
- if(false == g.preferences().open_notes_in_new_window()) {
- if (note->has_window()) {
- win = dynamic_cast<MainWindow*>(note->get_window()->host());
- }
- else {
- win = &g.get_window_for_note();
+ if(note->has_window()) {
+ auto note_window = note->get_window();
+ if(note_window->host()) {
+ MainWindow *win = dynamic_cast<MainWindow*>(note_window->host());
+ if(win) {
+ win->present_note(note);
+ return win;
+ }
}
}
- if(!win) {
- win = &g.new_main_window();
- win->close_on_escape(g.preferences().enable_close_note_on_escape());
- }
- win->present_note(note);
- win->present();
- return win;
+
+ MainWindow & win = g.get_window_for_note();
+ win.present_note(note);
+ win.present();
+ return &win;
}
bool MainWindow::use_client_side_decorations(Preferences & prefs)
diff --git a/src/mainwindow.hpp b/src/mainwindow.hpp
index a5066217..f328b147 100644
--- a/src/mainwindow.hpp
+++ b/src/mainwindow.hpp
@@ -37,7 +37,6 @@ class MainWindow
public:
static MainWindow *get_owning(Gtk::Widget & widget);
static void present_in(MainWindow & win, const Note::Ptr & note);
- static MainWindow *present_active(const Note::Ptr & note);
static MainWindow *present_in_new_window(IGnote & g, const Note::Ptr & note, bool close_on_esacpe);
static MainWindow *present_default(IGnote & g, const Note::Ptr & note);
static bool use_client_side_decorations(Preferences & prefs);
diff --git a/src/recentchanges.cpp b/src/recentchanges.cpp
index e2a0847b..5f5c7558 100644
--- a/src/recentchanges.cpp
+++ b/src/recentchanges.cpp
@@ -46,6 +46,42 @@ namespace gnote {
namespace {
const char *MAIN_MENU_PRIMARY_ICON = "open-menu-symbolic";
const char *MAIN_MENU_SECONDARY_ICON = "view-more-symbolic";
+
+ class TabLabel
+ : public Gtk::Box
+ {
+ public:
+ TabLabel(const Glib::ustring & label, EmbeddableWidget & widget, bool show_button)
+ : m_embed(widget)
+ , m_label(label)
+ {
+ m_label.show();
+
+ pack_start(m_label);
+ if (show_button) {
+ m_close_button.set_image_from_icon_name("window-close-symbolic");
+ m_close_button.set_relief(Gtk::RELIEF_NONE);
+ m_close_button.set_focus_on_click(false);
+ m_close_button.set_tooltip_text(_("Close"));
+ m_close_button.show();
+ pack_start(m_close_button);
+ m_close_button.signal_clicked().connect([this] { signal_close(m_embed); });
+ }
+
+ widget.signal_name_changed.connect(sigc::mem_fun(*this, &TabLabel::on_embedded_name_changed));
+ }
+
+ sigc::signal<void, EmbeddableWidget&> signal_close;
+ private:
+ void on_embedded_name_changed(const Glib::ustring & name)
+ {
+ m_label.set_text(name);
+ }
+
+ EmbeddableWidget & m_embed;
+ Gtk::Label m_label;
+ Gtk::Button m_close_button;
+ };
}
NoteRecentChanges::NoteRecentChanges(IGnote & g, NoteManagerBase & m)
@@ -56,7 +92,6 @@ namespace gnote {
, m_search_box(nullptr)
, m_find_next_prev_box(nullptr)
, m_search_entry(nullptr)
- , m_embedded_widget(nullptr)
, m_mapped(false)
, m_entry_changed_timeout(NULL)
, m_window_menu_embedded(NULL)
@@ -65,11 +100,18 @@ namespace gnote {
, m_keybinder(m_accel_group)
{
add_accel_group(m_accel_group);
- set_default_size(450,400);
set_resizable(true);
if(g.preferences().main_window_maximized()) {
maximize();
}
+ int width = m_gnote.preferences().search_window_width();
+ int height = m_gnote.preferences().search_window_height();
+ if(width && height) {
+ set_default_size(width, height);
+ }
+ else {
+ set_default_size(450,400);
+ }
set_icon_name(IconManager::GNOTE);
@@ -91,11 +133,14 @@ namespace gnote {
else {
content->attach(*m_header_bar, 0, content_y_attach++, 1, 1);
}
- content->attach(m_embed_box, 0, content_y_attach++, 1, 1);
- m_embed_box.set_hexpand(true);
- m_embed_box.set_vexpand(true);
- m_embed_box.show();
+ content->attach(m_embed_book, 0, content_y_attach++, 1, 1);
+ m_embed_book.set_hexpand(true);
+ m_embed_book.set_vexpand(true);
+ m_embed_book.show();
content->show();
+ m_embed_book.signal_switch_page().connect(sigc::mem_fun(*this,
&NoteRecentChanges::on_current_page_changed), false);
+ m_search_notes_widget->show();
+ embed_widget(*m_search_notes_widget);
add(*content);
signal_delete_event().connect(sigc::mem_fun(*this, &NoteRecentChanges::on_delete));
@@ -130,13 +175,22 @@ namespace gnote {
}
find_action("close-window")->signal_activate()
.connect(sigc::mem_fun(*this, &NoteRecentChanges::on_close_window));
-
- embed_widget(*m_search_notes_widget);
+ set_title(_("Gnote"));
}
NoteRecentChanges::~NoteRecentChanges()
{
+ int page_idx = m_embed_book.get_current_page();
+ if(page_idx >= 0) {
+ // to avoid page switching, first remove all pages prior to current, then remove from the end
+ for(int i = 0; i < page_idx; ++i) {
+ m_embed_book.remove_page(0);
+ }
+ while(m_embed_book.get_n_pages() > 0) {
+ m_embed_book.remove_page(-1);
+ }
+ }
if(m_entry_changed_timeout) {
delete m_entry_changed_timeout;
}
@@ -260,9 +314,9 @@ namespace gnote {
m_search_box->set_halign(Gtk::ALIGN_CENTER);
m_search_box->show();
- auto content = dynamic_cast<Gtk::Grid*>(m_embed_box.get_parent());
+ auto content = dynamic_cast<Gtk::Grid*>(m_embed_book.get_parent());
if(content) {
- content->attach_next_to(*m_search_box, m_embed_box, Gtk::POS_TOP);
+ content->attach_next_to(*m_search_box, m_embed_book, Gtk::POS_TOP);
}
else {
ERR_OUT(_("Parent of embed box is not a Gtk::Grid, please report a bug!"));
@@ -395,14 +449,23 @@ namespace gnote {
void NoteRecentChanges::present_note(const Note::Ptr & note)
{
- embed_widget(*note->create_window());
+ if(note && note->has_window()) {
+ auto win = note->get_window();
+ if(win->host()) {
+ win->host()->unembed_widget(*win);
+ }
+ embed_widget(*win);
+ }
+ else {
+ embed_widget(*note->create_window());
+ }
}
void NoteRecentChanges::new_note()
{
- std::vector<Gtk::Widget*> current = m_embed_box.get_children();
- SearchNotesWidget *search_wgt = dynamic_cast<SearchNotesWidget*>(current.size() > 0 ? current[0] : NULL);
+ auto current = m_embed_book.get_nth_page(0);
+ SearchNotesWidget *search_wgt = dynamic_cast<SearchNotesWidget*>(current);
if(search_wgt) {
search_wgt->new_note();
}
@@ -434,7 +497,33 @@ namespace gnote {
m_search_notes_widget->delete_selected_notes();
}
+ bool NoteRecentChanges::present_active(const Note::Ptr & note)
+ {
+ if(note && note->has_window()) {
+ auto note_window = note->get_window();
+ auto win = dynamic_cast<NoteRecentChanges*>(note_window->host());
+ if(!win) {
+ return false;
+ }
+ if(win == this) {
+ int n_pages = m_embed_book.get_n_pages();
+ for(int i = 0; i < n_pages; ++i) {
+ if(m_embed_book.get_nth_page(i) == note_window) {
+ m_embed_book.set_current_page(i);
+ break;
+ }
+ }
+ }
+ else {
+ win->present_active(note);
+ win->present();
+ }
+
+ return true;
+ }
+ return false;
+ }
void NoteRecentChanges::close_window()
{
@@ -443,17 +532,20 @@ namespace gnote {
if(win) {
m_preferences.main_window_maximized(win->get_state() & Gdk::WINDOW_STATE_MAXIMIZED);
}
- std::vector<Gtk::Widget*> current = m_embed_box.get_children();
- for(std::vector<Gtk::Widget*>::iterator iter = current.begin();
- iter != current.end(); ++iter) {
- EmbeddableWidget *widget = dynamic_cast<EmbeddableWidget*>(*iter);
+
+ if(m_embed_book.get_n_pages() > 0) {
+ EmbeddableWidget *widget =
dynamic_cast<EmbeddableWidget*>(m_embed_book.get_nth_page(m_embed_book.get_current_page()));
if(widget) {
background_embedded(*widget);
}
- }
- if(m_embedded_widget) {
- m_embedded_widget->unembed();
- m_embedded_widget = nullptr;
+
+ int n_pages = m_embed_book.get_n_pages();
+ for(int i = 0; i < n_pages; ++i) {
+ EmbeddableWidget *widget = dynamic_cast<EmbeddableWidget*>(m_embed_book.get_nth_page(i));
+ if(widget) {
+ widget->unembed();
+ }
+ }
}
hide();
@@ -515,8 +607,8 @@ namespace gnote {
// Select "All Notes" in the notebooks list
m_search_notes_widget->select_all_notes_notebook();
- EmbeddableWidget *widget = m_embedded_widget ? m_embedded_widget : m_search_notes_widget;
- foreground_embedded(*widget);
+ int current_page = m_embed_book.get_current_page();
+ EmbeddableWidget *widget = current_page >= 0 ?
dynamic_cast<EmbeddableWidget*>(m_embed_book.get_nth_page(current_page)) : nullptr;
MainWindow::on_show();
@@ -546,75 +638,67 @@ namespace gnote {
void NoteRecentChanges::embed_widget(EmbeddableWidget & widget)
{
- EmbeddableWidget *current = currently_foreground();
- if(current == &widget) {
+ auto win = dynamic_cast<Gtk::Widget*>(&widget);
+ if(!win) {
return;
}
- if(m_embedded_widget) {
- unembed_widget(*m_embedded_widget);
- }
- m_embedded_widget = &widget;
+ win->show();
widget.embed(this);
- if(get_visible()) {
- foreground_embedded(widget);
+ bool allow_close = &widget != m_search_notes_widget;
+ auto tab_label = manage(new TabLabel(widget.get_name(), widget, allow_close));
+ if (allow_close) {
+ tab_label->signal_close.connect(sigc::mem_fun(*this, &NoteRecentChanges::unembed_widget));
}
+ tab_label->show();
+ int idx = m_embed_book.append_page(*win, *tab_label);
+ m_embed_book.set_current_page(idx);
}
void NoteRecentChanges::unembed_widget(EmbeddableWidget & widget)
{
- bool show_search = false;
- if(&widget == m_embedded_widget) {
- if(is_foreground(widget)) {
- background_embedded(widget);
- show_search = true;
+ int n_pages = m_embed_book.get_n_pages();
+ int page_to_remove = -1;
+ Gtk::Widget *wid = dynamic_cast<Gtk::Widget*>(&widget);
+ for(int i = 0; i < n_pages; ++i) {
+ if(m_embed_book.get_nth_page(i) == wid) {
+ page_to_remove = i;
+ break;
}
- m_embedded_widget = nullptr;
- widget.unembed();
}
- if(show_search) {
- foreground_embedded(*m_search_notes_widget);
+ if(page_to_remove < 0) {
+ return;
+ }
+ if(n_pages > 1 && page_to_remove == m_embed_book.get_current_page()) {
+ int new_page = (page_to_remove == n_pages - 1) ? page_to_remove - 1 : page_to_remove + 1;
+ m_embed_book.set_current_page(new_page);
}
+
+ m_embed_book.remove_page(page_to_remove);
+ widget.unembed();
}
void NoteRecentChanges::foreground_embedded(EmbeddableWidget & widget)
{
try {
- EmbeddableWidget *current_foreground = currently_foreground();
- if(current_foreground == &widget) {
+ int idx = m_embed_book.page_num(dynamic_cast<Gtk::Widget&>(widget));
+ if(idx < 0) {
+ ERR_OUT(_("Attempt to foreground a widget, that is not embedded in the window"));
return;
}
- else if(current_foreground) {
- background_embedded(*current_foreground);
- }
- Gtk::Widget &wid = dynamic_cast<Gtk::Widget&>(widget);
- m_embed_box.add(wid);
- wid.show();
- widget.foreground();
- bool maximized = m_preferences.main_window_maximized();
- if(get_realized()) {
- //if window is showing, use actual state
- maximized = get_window()->get_state() & Gdk::WINDOW_STATE_MAXIMIZED;
- }
- int width = 0, height = 0;
- widget.hint_size(width, height);
- if(width && height) {
- set_default_size(width, height);
- if(!maximized && get_visible()) {
- resize(width, height);
- }
- }
+ m_embed_book.set_current_page(idx);
+ }
+ catch(std::bad_cast&) {
+ ERR_OUT(_("Attempt to foreground a widget, that is not Gtk::Widget"));
+ }
+ }
+
+ void NoteRecentChanges::on_foreground_embedded(EmbeddableWidget & widget)
+ {
+ try {
+ widget.foreground();
widget.size_internals();
-
update_toolbar(widget);
- if(&widget == m_search_notes_widget) {
- set_title(_("Gnote"));
- }
- else {
- set_title(widget.get_name());
- m_current_embedded_name_slot = widget.signal_name_changed
- .connect(sigc::mem_fun(*this, &NoteRecentChanges::on_embedded_name_changed));
- }
}
catch(std::bad_cast&) {
}
@@ -633,21 +717,11 @@ namespace gnote {
void NoteRecentChanges::background_embedded(EmbeddableWidget & widget)
{
- try {
- if(currently_foreground() != &widget) {
- return;
- }
- Gtk::Widget &wid = dynamic_cast<Gtk::Widget&>(widget);
- widget.background();
- m_embed_box.remove(wid);
- m_signal_popover_widgets_changed_cid.disconnect();
- m_current_embedded_name_slot.disconnect();
+ widget.background();
+ m_signal_popover_widgets_changed_cid.disconnect();
- if(m_window_menu_embedded) {
- m_window_menu_embedded = NULL;
- }
- }
- catch(std::bad_cast&) {
+ if(m_window_menu_embedded) {
+ m_window_menu_embedded = NULL;
}
auto children = m_embedded_toolbar.get_children();
@@ -656,24 +730,40 @@ namespace gnote {
}
}
- bool NoteRecentChanges::contains(EmbeddableWidget & widget)
+ void NoteRecentChanges::on_current_page_changed(Gtk::Widget *new_page, guint)
{
- if(&widget == m_search_notes_widget) {
- return true;
+ int idx = m_embed_book.get_current_page();
+ if(idx >= 0) {
+ EmbeddableWidget *w = dynamic_cast<EmbeddableWidget*>(m_embed_book.get_nth_page(idx));
+ if(w) {
+ background_embedded(*w);
+ }
}
- return &widget == m_embedded_widget;
+ auto widget = dynamic_cast<EmbeddableWidget*>(new_page);
+ if(widget) {
+ on_foreground_embedded(*widget);
+ }
+ }
+
+ bool NoteRecentChanges::contains(EmbeddableWidget & widget)
+ {
+ try {
+ return m_embed_book.page_num(dynamic_cast<Gtk::Widget&>(widget)) >= 0;
+ }
+ catch(std::bad_cast &) {
+ return false;
+ }
}
bool NoteRecentChanges::is_foreground(EmbeddableWidget & widget)
{
- for(Gtk::Widget *wgt : m_embed_box.get_children()) {
- if(dynamic_cast<EmbeddableWidget*>(wgt) == &widget) {
- return true;
- }
+ int idx = m_embed_book.get_current_page();
+ if(idx < 0) {
+ return false;
}
- return false;
+ return m_embed_book.get_nth_page(idx) == dynamic_cast<Gtk::Widget*>(&widget);
}
void NoteRecentChanges::add_action(const MainWindowAction::Ptr & action)
@@ -702,8 +792,12 @@ namespace gnote {
EmbeddableWidget *NoteRecentChanges::currently_foreground()
{
- std::vector<Gtk::Widget*> children = m_embed_box.get_children();
- return children.size() ? dynamic_cast<EmbeddableWidget*>(children[0]) : NULL;
+ auto n = m_embed_book.get_current_page();
+ if(n < 0) {
+ return nullptr;
+ }
+
+ return dynamic_cast<EmbeddableWidget*>(m_embed_book.get_nth_page(n));
}
bool NoteRecentChanges::on_map_event(GdkEventAny *evt)
@@ -875,11 +969,6 @@ namespace gnote {
return menu;
}
- void NoteRecentChanges::on_embedded_name_changed(const Glib::ustring & name)
- {
- set_title(name);
- }
-
void NoteRecentChanges::on_popover_widgets_changed()
{
if(m_window_menu_embedded) {
diff --git a/src/recentchanges.hpp b/src/recentchanges.hpp
index baea9a39..8d56062d 100644
--- a/src/recentchanges.hpp
+++ b/src/recentchanges.hpp
@@ -26,6 +26,7 @@
#include <gtkmm/applicationwindow.h>
#include <gtkmm/grid.h>
+#include <gtkmm/notebook.h>
#include <gtkmm/popovermenu.h>
#include "mainwindowaction.hpp"
@@ -77,6 +78,8 @@ private:
bool on_delete(GdkEventAny *);
bool on_key_pressed(GdkEventKey *);
EmbeddableWidget *currently_foreground();
+ void on_current_page_changed(Gtk::Widget *new_page, guint page_number);
+ void on_foreground_embedded(EmbeddableWidget & widget);
void make_header_bar();
void make_search_box();
void make_find_next_prev();
@@ -93,11 +96,11 @@ private:
void on_find_next_button_clicked();
void on_find_prev_button_clicked();
Gtk::PopoverMenu *make_window_menu(Gtk::Button *button, std::vector<PopoverWidget> && items);
- void on_embedded_name_changed(const Glib::ustring & name);
bool on_notes_widget_key_press(GdkEventKey*);
void on_close_window(const Glib::VariantBase&);
void add_action(const MainWindowAction::Ptr & action);
void on_popover_widgets_changed();
+ bool present_active(const Note::Ptr & note);
IGnote &m_gnote;
NoteManagerBase &m_note_manager;
@@ -113,13 +116,11 @@ private:
};
Gtk::ToggleButton m_search_button;
Gtk::Grid m_embedded_toolbar;
- Gtk::Grid m_embed_box;
+ Gtk::Notebook m_embed_book;
Gtk::Button *m_all_notes_button;
Gtk::Button *m_new_note_button;
Gtk::Button *m_window_actions_button;
- EmbeddableWidget* m_embedded_widget;
bool m_mapped;
- sigc::connection m_current_embedded_name_slot;
sigc::connection m_signal_popover_widgets_changed_cid;
utils::InterruptableTimeout *m_entry_changed_timeout;
Gtk::PopoverMenu *m_window_menu_embedded;
diff --git a/src/searchnoteswidget.cpp b/src/searchnoteswidget.cpp
index ff8b9329..6eeab098 100644
--- a/src/searchnoteswidget.cpp
+++ b/src/searchnoteswidget.cpp
@@ -131,8 +131,7 @@ SearchNotesWidget::~SearchNotesWidget()
Glib::ustring SearchNotesWidget::get_name() const
{
notebooks::Notebook::Ptr selected_notebook = get_selected_notebook();
- if(!selected_notebook
- || std::dynamic_pointer_cast<notebooks::AllNotesNotebook>(selected_notebook)) {
+ if(!selected_notebook) {
return "";
}
return selected_notebook->get_name();
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]