Implement toc in editor mode as well

master
Melroy van den Berg 2022-02-04 22:58:55 +01:00
parent ba8dbbfe05
commit 6333e12731
No known key found for this signature in database
GPG Key ID: 71D11FF23454B9D7
5 changed files with 227 additions and 217 deletions

View File

@ -277,7 +277,7 @@ void Draw::setMessage(const Glib::ustring& message, const Glib::ustring& details
/**
* \brief Draw homepage
*/
void Draw::showStartPage()
void Draw::showHomepage()
{
if (get_editable())
this->disableEdit();

View File

@ -39,7 +39,7 @@ public:
explicit Draw(MiddlewareInterface& middleware);
void setMessage(const Glib::ustring& message, const Glib::ustring& details = "");
void showStartPage();
void showHomepage();
void setDocument(cmark_node* rootNode);
void setViewSourceMenuItem(bool isEnabled);
void newDocument();

View File

@ -28,7 +28,7 @@ MainWindow::MainWindow(const std::string& timeout)
m_indentAdjustment(Gtk::Adjustment::create(0, 0, 1000, 5, 10)),
m_drawCSSProvider(Gtk::CssProvider::create()),
m_menu(m_accelGroup),
m_draw_main(middleware_),
m_draw_primary(middleware_),
m_draw_secondary(middleware_),
m_about(*this),
m_vboxMain(Gtk::ORIENTATION_VERTICAL, 0),
@ -117,24 +117,24 @@ MainWindow::MainWindow(const std::string& timeout)
initSignals();
// Add custom CSS Provider to draw textviews
auto styleMain = m_draw_main.get_style_context();
auto stylePrimary = m_draw_primary.get_style_context();
auto styleSecondary = m_draw_secondary.get_style_context();
styleMain->add_provider(m_drawCSSProvider, GTK_STYLE_PROVIDER_PRIORITY_USER);
stylePrimary->add_provider(m_drawCSSProvider, GTK_STYLE_PROVIDER_PRIORITY_USER);
styleSecondary->add_provider(m_drawCSSProvider, GTK_STYLE_PROVIDER_PRIORITY_USER);
// Load the default font family and font size
updateCSS();
// Browser main drawing area
m_scrolledWindowMain.add(m_draw_main);
m_scrolledWindowMain.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
// Primary drawing area
m_scrolledWindowPrimary.add(m_draw_primary);
m_scrolledWindowPrimary.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
// Secondary drawing area
m_draw_secondary.setViewSourceMenuItem(false);
m_scrolledWindowSecondary.add(m_draw_secondary);
m_scrolledWindowSecondary.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
m_panedDraw.pack1(m_scrolledWindowMain, true, false);
m_panedDraw.pack1(m_scrolledWindowPrimary, true, false);
m_panedDraw.pack2(m_scrolledWindowSecondary, true, true);
// Left the vbox for the table of contents,
// right the main drawing paned windows (primary/secondary).
// right the drawing paned windows (primary/secondary).
m_panedRoot.pack1(m_vboxToc, true, false);
m_panedRoot.pack2(m_panedDraw, true, false);
// Main virtual box
@ -251,11 +251,11 @@ void MainWindow::refreshRequest()
}
/**
* \brief Show startpage
* \brief Show home page
*/
void MainWindow::showStartpage()
void MainWindow::showHomepage()
{
m_draw_main.showStartPage();
m_draw_primary.showHomepage();
}
/**
@ -264,155 +264,18 @@ void MainWindow::showStartpage()
*/
void MainWindow::setText(const Glib::ustring& content)
{
m_draw_main.setText(content);
m_draw_primary.setText(content);
}
/**
* \brief Set markdown document (cmark). cmark_node pointer will be freed automatically.
* \brief Set markdown document (common mark) on primary window. cmark_node pointer will be freed automatically.
* And set the ToC.
* \param rootNode cmark root data struct
*/
void MainWindow::setDocument(cmark_node* rootNode)
{
m_draw_main.setDocument(rootNode);
// Retrieve headings for ToC
auto headings = m_draw_main.getHeadings();
Gtk::TreeRow heading1Row, heading2Row, heading3Row, heading4Row, heading5Row;
int previousLevel = 1; // Default heading 1
for (const Glib::RefPtr<Gtk::TextMark> headerMark : headings)
{
Glib::ustring heading = static_cast<char*>(headerMark->get_data("name"));
auto level = reinterpret_cast<std::intptr_t>(headerMark->get_data("level"));
switch (level)
{
case 1:
{
heading1Row = *(m_tocTreeModel->append());
heading1Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading1Row[m_tocColumns.m_col_level] = level;
heading1Row[m_tocColumns.m_col_heading] = heading;
heading1Row[m_tocColumns.m_col_valid] = true;
// Reset
if (previousLevel > 1)
{
heading2Row = Gtk::TreeRow();
heading3Row = Gtk::TreeRow();
heading4Row = Gtk::TreeRow();
heading5Row = Gtk::TreeRow();
}
break;
}
case 2:
{
if (heading1Row->get_model_gobject() == nullptr)
{
// Add missing heading as top-level
heading1Row = *(m_tocTreeModel->append());
heading1Row[m_tocColumns.m_col_level] = 1;
heading1Row[m_tocColumns.m_col_heading] = "-Missing heading-";
heading1Row[m_tocColumns.m_col_valid] = false;
}
heading2Row = *(m_tocTreeModel->append(heading1Row.children()));
heading2Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading2Row[m_tocColumns.m_col_level] = level;
heading2Row[m_tocColumns.m_col_heading] = heading;
heading2Row[m_tocColumns.m_col_valid] = true;
// Reset
if (previousLevel > 2)
{
heading3Row = Gtk::TreeRow();
heading4Row = Gtk::TreeRow();
heading5Row = Gtk::TreeRow();
}
break;
}
case 3:
{
if (heading2Row->get_model_gobject() == nullptr)
{
// Add missing heading as top-level
heading2Row = *(m_tocTreeModel->append(heading1Row.children()));
heading2Row[m_tocColumns.m_col_level] = 2;
heading2Row[m_tocColumns.m_col_heading] = "-Missing heading-";
heading2Row[m_tocColumns.m_col_valid] = false;
}
heading3Row = *(m_tocTreeModel->append(heading2Row.children()));
heading3Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading3Row[m_tocColumns.m_col_level] = level;
heading3Row[m_tocColumns.m_col_heading] = heading;
heading3Row[m_tocColumns.m_col_valid] = true;
// Reset
if (previousLevel > 3)
{
heading4Row = Gtk::TreeRow();
heading5Row = Gtk::TreeRow();
}
break;
}
case 4:
{
if (heading3Row->get_model_gobject() == nullptr)
{
// Add missing heading as top-level
heading3Row = *(m_tocTreeModel->append(heading2Row.children()));
heading3Row[m_tocColumns.m_col_level] = 3;
heading3Row[m_tocColumns.m_col_heading] = "-Missing heading-";
heading3Row[m_tocColumns.m_col_valid] = false;
}
heading4Row = *(m_tocTreeModel->append(heading3Row.children()));
heading4Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading4Row[m_tocColumns.m_col_level] = level;
heading4Row[m_tocColumns.m_col_heading] = heading;
heading4Row[m_tocColumns.m_col_valid] = true;
// Reset
if (previousLevel > 4)
{
heading5Row = Gtk::TreeRow();
}
break;
}
case 5:
{
if (heading4Row->get_model_gobject() == nullptr)
{
// Add missing heading as top-level
heading4Row = *(m_tocTreeModel->append(heading3Row.children()));
heading4Row[m_tocColumns.m_col_level] = 4;
heading4Row[m_tocColumns.m_col_heading] = "-Missing heading-";
heading4Row[m_tocColumns.m_col_valid] = false;
}
heading5Row = *(m_tocTreeModel->append(heading4Row.children()));
heading5Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading5Row[m_tocColumns.m_col_level] = level;
heading5Row[m_tocColumns.m_col_heading] = heading;
heading5Row[m_tocColumns.m_col_valid] = true;
break;
}
case 6:
{
if (heading5Row->get_model_gobject() == nullptr)
{
// Add missing heading as top-level
heading5Row = *(m_tocTreeModel->append(heading4Row.children()));
heading5Row[m_tocColumns.m_col_level] = 5;
heading5Row[m_tocColumns.m_col_heading] = "- Missing heading -";
heading5Row[m_tocColumns.m_col_valid] = false;
}
auto heading6Row = *(m_tocTreeModel->append(heading5Row.children()));
heading6Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading6Row[m_tocColumns.m_col_level] = level;
heading6Row[m_tocColumns.m_col_heading] = heading;
heading6Row[m_tocColumns.m_col_valid] = true;
break;
}
default:
std::cerr << "ERROR: Out of range heading level detected." << std::endl;
break;
}
previousLevel = level;
}
tocTreeView.columns_autosize();
tocTreeView.expand_all();
m_draw_primary.setDocument(rootNode);
setTableofContents(m_draw_primary.getHeadings());
}
/**
@ -422,7 +285,7 @@ void MainWindow::setDocument(cmark_node* rootNode)
*/
void MainWindow::setMessage(const Glib::ustring& message, const Glib::ustring& details)
{
m_draw_main.setMessage(message, details);
m_draw_primary.setMessage(message, details);
}
/**
@ -501,9 +364,9 @@ void MainWindow::loadStoredSettings()
m_spacingAdjustment->set_value(fontSpacing_);
m_marginsAdjustment->set_value(margins);
m_indentAdjustment->set_value(indent);
m_draw_main.set_left_margin(margins);
m_draw_main.set_right_margin(margins);
m_draw_main.set_indent(indent);
m_draw_primary.set_left_margin(margins);
m_draw_primary.set_right_margin(margins);
m_draw_primary.set_indent(indent);
int tocDividerPosition = m_settings->get_int("position-divider-toc");
m_panedRoot.set_position(tocDividerPosition);
iconTheme_ = m_settings->get_string("icon-theme");
@ -521,9 +384,9 @@ void MainWindow::loadStoredSettings()
m_marginsAdjustment->set_value(margins);
m_indentAdjustment->set_value(indent);
// For drawing
m_draw_main.set_left_margin(margins);
m_draw_main.set_right_margin(margins);
m_draw_main.set_indent(indent);
m_draw_primary.set_left_margin(margins);
m_draw_primary.set_right_margin(margins);
m_draw_primary.set_indent(indent);
// ToC paned divider
m_panedRoot.set_position(300);
}
@ -1052,8 +915,8 @@ void MainWindow::initSignals()
m_menu.save_as.connect(sigc::mem_fun(this, &MainWindow::save_as)); /*!< Menu item for save document as */
m_menu.publish.connect(sigc::mem_fun(this, &MainWindow::publish)); /*!< Menu item for publishing */
m_menu.quit.connect(sigc::mem_fun(this, &MainWindow::close)); /*!< close main window and therefor closes the app */
m_menu.undo.connect(sigc::mem_fun(m_draw_main, &Draw::undo)); /*!< Menu item for undo text */
m_menu.redo.connect(sigc::mem_fun(m_draw_main, &Draw::redo)); /*!< Menu item for redo text */
m_menu.undo.connect(sigc::mem_fun(m_draw_primary, &Draw::undo)); /*!< Menu item for undo text */
m_menu.redo.connect(sigc::mem_fun(m_draw_primary, &Draw::redo)); /*!< Menu item for redo text */
m_menu.cut.connect(sigc::mem_fun(this, &MainWindow::cut)); /*!< Menu item for cut text */
m_menu.copy.connect(sigc::mem_fun(this, &MainWindow::copy)); /*!< Menu item for copy text */
m_menu.paste.connect(sigc::mem_fun(this, &MainWindow::paste)); /*!< Menu item for paste text */
@ -1069,7 +932,7 @@ void MainWindow::initSignals()
m_menu.source_code.connect(sigc::mem_fun(this, &MainWindow::show_source_code_dialog)); /*!< Source code dialog */
m_sourceCodeDialog.signal_response().connect(sigc::mem_fun(m_sourceCodeDialog, &SourceCodeDialog::hide_dialog)); /*!< Close source code dialog */
m_menu.about.connect(sigc::mem_fun(m_about, &About::show_about)); /*!< Display about dialog */
m_draw_main.source_code.connect(sigc::mem_fun(this, &MainWindow::show_source_code_dialog)); /*!< Open source code dialog */
m_draw_primary.source_code.connect(sigc::mem_fun(this, &MainWindow::show_source_code_dialog)); /*!< Open source code dialog */
m_about.signal_response().connect(sigc::mem_fun(m_about, &About::hide_about)); /*!< Close about dialog */
m_addressBar.signal_activate().connect(sigc::mem_fun(this, &MainWindow::address_bar_activate)); /*!< User pressed enter the address bar */
m_openTocButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::show_toc)); /*!< Button for showing Table of Contents */
@ -1086,22 +949,22 @@ void MainWindow::initSignals()
m_cutButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::cut));
m_copyButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::copy));
m_pasteButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::paste));
m_undoButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::undo));
m_redoButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::redo));
m_undoButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::undo));
m_redoButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::redo));
m_headingsComboBox.signal_changed().connect(sigc::mem_fun(this, &MainWindow::get_heading));
m_boldButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::make_bold));
m_italicButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::make_italic));
m_strikethroughButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::make_strikethrough));
m_superButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::make_super));
m_subButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::make_sub));
m_linkButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::insert_link));
m_imageButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::insert_image));
m_boldButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::make_bold));
m_italicButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::make_italic));
m_strikethroughButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::make_strikethrough));
m_superButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::make_super));
m_subButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::make_sub));
m_linkButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::insert_link));
m_imageButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::insert_image));
m_emojiButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::insert_emoji));
m_quoteButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::make_quote));
m_codeButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::make_code));
m_bulletListButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::insert_bullet_list));
m_numberedListButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::insert_numbered_list));
m_highlightButton.signal_clicked().connect(sigc::mem_fun(m_draw_main, &Draw::make_highlight));
m_quoteButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::make_quote));
m_codeButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::make_code));
m_bulletListButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::insert_bullet_list));
m_numberedListButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::insert_numbered_list));
m_highlightButton.signal_clicked().connect(sigc::mem_fun(m_draw_primary, &Draw::make_highlight));
// Status pop-over buttons
m_copyIDButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::copy_client_id));
m_copyPublicKeyButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::copy_client_public_key));
@ -1159,9 +1022,9 @@ bool MainWindow::delete_window(GdkEventAny* any_event __attribute__((unused)))
*/
void MainWindow::cut()
{
if (m_draw_main.has_focus())
if (m_draw_primary.has_focus())
{
m_draw_main.cut();
m_draw_primary.cut();
}
else if (m_draw_secondary.has_focus())
{
@ -1183,9 +1046,9 @@ void MainWindow::cut()
void MainWindow::copy()
{
if (m_draw_main.has_focus())
if (m_draw_primary.has_focus())
{
m_draw_main.copy();
m_draw_primary.copy();
}
else if (m_draw_secondary.has_focus())
{
@ -1207,9 +1070,9 @@ void MainWindow::copy()
void MainWindow::paste()
{
if (m_draw_main.has_focus())
if (m_draw_primary.has_focus())
{
m_draw_main.paste();
m_draw_primary.paste();
}
else if (m_draw_secondary.has_focus())
{
@ -1231,9 +1094,9 @@ void MainWindow::paste()
void MainWindow::del()
{
if (m_draw_main.has_focus())
if (m_draw_primary.has_focus())
{
m_draw_main.del();
m_draw_primary.del();
}
else if (m_draw_secondary.has_focus())
{
@ -1282,9 +1145,9 @@ void MainWindow::del()
void MainWindow::selectAll()
{
if (m_draw_main.has_focus())
if (m_draw_primary.has_focus())
{
m_draw_main.selectAll();
m_draw_primary.selectAll();
}
else if (m_draw_secondary.has_focus())
{
@ -1317,7 +1180,10 @@ void MainWindow::on_toc_row_activated(const Gtk::TreeModel::Path& path, __attrib
{
Gtk::TextIter textIter = row[m_tocColumns.m_col_iter];
// Scroll to to mark iterator
m_draw_main.scroll_to(textIter);
if (isEditorEnabled())
m_draw_secondary.scroll_to(textIter);
else
m_draw_primary.scroll_to(textIter);
}
}
}
@ -1472,7 +1338,7 @@ void MainWindow::edit()
if (!isEditorEnabled())
enableEdit();
m_draw_main.setText(middleware_.getContent());
m_draw_primary.setText(middleware_.getContent());
// Set title
set_title("Untitled * - " + appName_);
}
@ -1711,7 +1577,7 @@ void MainWindow::on_search()
{
// Forward search, find and select
std::string text = m_searchEntry.get_text();
auto buffer = m_draw_main.get_buffer();
auto buffer = m_draw_primary.get_buffer();
Gtk::TextBuffer::iterator iter = buffer->get_iter_at_mark(buffer->get_mark("insert"));
Gtk::TextBuffer::iterator start, end;
bool matchCase = m_searchMatchCase.get_active();
@ -1723,7 +1589,7 @@ void MainWindow::on_search()
if (iter.forward_search(text, flags, start, end))
{
buffer->select_range(end, start);
m_draw_main.scroll_to(start);
m_draw_primary.scroll_to(start);
}
else
{
@ -1733,7 +1599,7 @@ void MainWindow::on_search()
if (secondIter.forward_search(text, flags, start, end))
{
buffer->select_range(end, start);
m_draw_main.scroll_to(start);
m_draw_primary.scroll_to(start);
}
}
}
@ -1743,9 +1609,9 @@ void MainWindow::on_search()
*/
void MainWindow::on_replace()
{
if (m_draw_main.get_editable())
if (m_draw_primary.get_editable())
{
auto buffer = m_draw_main.get_buffer();
auto buffer = m_draw_primary.get_buffer();
Gtk::TextBuffer::iterator startIter = buffer->get_iter_at_mark(buffer->get_mark("insert"));
Gtk::TextBuffer::iterator endIter = buffer->get_iter_at_mark(buffer->get_mark("selection_bound"));
if (startIter != endIter)
@ -1767,8 +1633,8 @@ void MainWindow::on_replace()
void MainWindow::address_bar_activate()
{
middleware_.doRequest(m_addressBar.get_text(), false);
// When user actually entered the address bar, focus on the main draw
m_draw_main.grab_focus();
// When user actually entered the address bar, focus on the primary draw
m_draw_primary.grab_focus();
}
/**
@ -1836,6 +1702,149 @@ void MainWindow::forward()
}
}
/**
* \brief Fill-in table of contents and show
*/
void MainWindow::setTableofContents(std::vector<Glib::RefPtr<Gtk::TextMark>> headings)
{
Gtk::TreeRow heading1Row, heading2Row, heading3Row, heading4Row, heading5Row;
int previousLevel = 1; // Default heading 1
for (const Glib::RefPtr<Gtk::TextMark> headerMark : headings)
{
Glib::ustring heading = static_cast<char*>(headerMark->get_data("name"));
auto level = reinterpret_cast<std::intptr_t>(headerMark->get_data("level"));
switch (level)
{
case 1:
{
heading1Row = *(m_tocTreeModel->append());
heading1Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading1Row[m_tocColumns.m_col_level] = level;
heading1Row[m_tocColumns.m_col_heading] = heading;
heading1Row[m_tocColumns.m_col_valid] = true;
// Reset
if (previousLevel > 1)
{
heading2Row = Gtk::TreeRow();
heading3Row = Gtk::TreeRow();
heading4Row = Gtk::TreeRow();
heading5Row = Gtk::TreeRow();
}
break;
}
case 2:
{
if (heading1Row->get_model_gobject() == nullptr)
{
// Add missing heading as top-level
heading1Row = *(m_tocTreeModel->append());
heading1Row[m_tocColumns.m_col_level] = 1;
heading1Row[m_tocColumns.m_col_heading] = "-Missing heading-";
heading1Row[m_tocColumns.m_col_valid] = false;
}
heading2Row = *(m_tocTreeModel->append(heading1Row.children()));
heading2Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading2Row[m_tocColumns.m_col_level] = level;
heading2Row[m_tocColumns.m_col_heading] = heading;
heading2Row[m_tocColumns.m_col_valid] = true;
// Reset
if (previousLevel > 2)
{
heading3Row = Gtk::TreeRow();
heading4Row = Gtk::TreeRow();
heading5Row = Gtk::TreeRow();
}
break;
}
case 3:
{
if (heading2Row->get_model_gobject() == nullptr)
{
// Add missing heading as top-level
heading2Row = *(m_tocTreeModel->append(heading1Row.children()));
heading2Row[m_tocColumns.m_col_level] = 2;
heading2Row[m_tocColumns.m_col_heading] = "-Missing heading-";
heading2Row[m_tocColumns.m_col_valid] = false;
}
heading3Row = *(m_tocTreeModel->append(heading2Row.children()));
heading3Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading3Row[m_tocColumns.m_col_level] = level;
heading3Row[m_tocColumns.m_col_heading] = heading;
heading3Row[m_tocColumns.m_col_valid] = true;
// Reset
if (previousLevel > 3)
{
heading4Row = Gtk::TreeRow();
heading5Row = Gtk::TreeRow();
}
break;
}
case 4:
{
if (heading3Row->get_model_gobject() == nullptr)
{
// Add missing heading as top-level
heading3Row = *(m_tocTreeModel->append(heading2Row.children()));
heading3Row[m_tocColumns.m_col_level] = 3;
heading3Row[m_tocColumns.m_col_heading] = "-Missing heading-";
heading3Row[m_tocColumns.m_col_valid] = false;
}
heading4Row = *(m_tocTreeModel->append(heading3Row.children()));
heading4Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading4Row[m_tocColumns.m_col_level] = level;
heading4Row[m_tocColumns.m_col_heading] = heading;
heading4Row[m_tocColumns.m_col_valid] = true;
// Reset
if (previousLevel > 4)
{
heading5Row = Gtk::TreeRow();
}
break;
}
case 5:
{
if (heading4Row->get_model_gobject() == nullptr)
{
// Add missing heading as top-level
heading4Row = *(m_tocTreeModel->append(heading3Row.children()));
heading4Row[m_tocColumns.m_col_level] = 4;
heading4Row[m_tocColumns.m_col_heading] = "-Missing heading-";
heading4Row[m_tocColumns.m_col_valid] = false;
}
heading5Row = *(m_tocTreeModel->append(heading4Row.children()));
heading5Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading5Row[m_tocColumns.m_col_level] = level;
heading5Row[m_tocColumns.m_col_heading] = heading;
heading5Row[m_tocColumns.m_col_valid] = true;
break;
}
case 6:
{
if (heading5Row->get_model_gobject() == nullptr)
{
// Add missing heading as top-level
heading5Row = *(m_tocTreeModel->append(heading4Row.children()));
heading5Row[m_tocColumns.m_col_level] = 5;
heading5Row[m_tocColumns.m_col_heading] = "- Missing heading -";
heading5Row[m_tocColumns.m_col_valid] = false;
}
auto heading6Row = *(m_tocTreeModel->append(heading5Row.children()));
heading6Row[m_tocColumns.m_col_iter] = headerMark->get_iter();
heading6Row[m_tocColumns.m_col_level] = level;
heading6Row[m_tocColumns.m_col_heading] = heading;
heading6Row[m_tocColumns.m_col_valid] = true;
break;
}
default:
std::cerr << "ERROR: Out of range heading level detected." << std::endl;
break;
}
previousLevel = level;
}
tocTreeView.columns_autosize();
tocTreeView.expand_all();
}
/**
* \brief Determing if browser is installed to the installation directory at runtime
* \return true if the current running process is installed (to the installed prefix path)
@ -1878,7 +1887,7 @@ bool MainWindow::isInstalled()
void MainWindow::enableEdit()
{
// Inform the Draw class that we are creating a new document
m_draw_main.newDocument();
m_draw_primary.newDocument();
// Show editor toolbars
m_hboxStandardEditorToolbar.show();
m_hboxFormattingEditorToolbar.show();
@ -1901,15 +1910,12 @@ void MainWindow::enableEdit()
}
m_panedDraw.set_position(location);
// Disable Table of Contents during edit & clear ToC
m_vboxToc.hide();
m_tocTreeModel->clear();
// Enabled secondary text view (on the right)
m_scrolledWindowSecondary.show();
// Disable "view source" menu item
m_draw_main.setViewSourceMenuItem(false);
m_draw_primary.setViewSourceMenuItem(false);
// Connect changed signal
textChangedSignalHandler_ = m_draw_main.get_buffer()->signal_changed().connect(sigc::mem_fun(this, &MainWindow::editor_changed_text));
textChangedSignalHandler_ = m_draw_primary.get_buffer()->signal_changed().connect(sigc::mem_fun(this, &MainWindow::editor_changed_text));
// Enable publish menu item
m_menu.setPublishMenuSensitive(true);
// Disable edit menu item (you are already editing)
@ -1931,7 +1937,7 @@ void MainWindow::disableEdit()
// Disconnect text changed signal
textChangedSignalHandler_.disconnect();
// Show "view source" menu item again
m_draw_main.setViewSourceMenuItem(true);
m_draw_primary.setViewSourceMenuItem(true);
m_draw_secondary.clear();
// Disable publish menu item
m_menu.setPublishMenuSensitive(false);
@ -1985,7 +1991,7 @@ std::string MainWindow::getIconImageFromTheme(const std::string& iconName, const
}
/**
* \brief Update the CSS provider data on the main draw text view
* \brief Update the CSS provider data
*/
void MainWindow::updateCSS()
{
@ -2044,14 +2050,17 @@ void MainWindow::editor_changed_text()
// TODO: Just execute the code below in a signal_idle call?
// So it will never block the GUI thread. Or is this already running in another context
// Clear table of contents (ToC)
m_tocTreeModel->clear();
// Retrieve text from editor and parse the markdown contents
middleware_.setContent(m_draw_main.getText());
middleware_.setContent(m_draw_primary.getText());
cmark_node* doc = middleware_.parseContent();
/* // Can be enabled to show the markdown format in terminal:
std::string md = Parser::renderMarkdown(doc);
std::cout << "Markdown:\n" << md << std::endl;*/
// Show the document as a preview on the right side text-view panel
m_draw_secondary.setDocument(doc);
setTableofContents(m_draw_secondary.getHeadings());
}
/**
@ -2077,7 +2086,7 @@ void MainWindow::get_heading()
try
{
int headingLevel = std::stoi(active, &sz, 10);
m_draw_main.make_heading(headingLevel);
m_draw_primary.make_heading(headingLevel);
}
catch (const std::invalid_argument&)
{
@ -2094,7 +2103,7 @@ void MainWindow::get_heading()
void MainWindow::insert_emoji()
{
// Note: The "insert-emoji" signal is not exposed in Gtkmm library (at least not in gtk3)
g_signal_emit_by_name(m_draw_main.gobj(), "insert-emoji");
g_signal_emit_by_name(m_draw_primary.gobj(), "insert-emoji");
}
void MainWindow::on_zoom_out()
@ -2134,18 +2143,18 @@ void MainWindow::on_spacing_changed()
void MainWindow::on_margins_changed()
{
m_draw_main.set_left_margin(m_marginsSpinButton.get_value_as_int());
m_draw_main.set_right_margin(m_marginsSpinButton.get_value_as_int());
m_draw_primary.set_left_margin(m_marginsSpinButton.get_value_as_int());
m_draw_primary.set_right_margin(m_marginsSpinButton.get_value_as_int());
}
void MainWindow::on_indent_changed()
{
m_draw_main.set_indent(m_indentSpinButton.get_value_as_int());
m_draw_primary.set_indent(m_indentSpinButton.get_value_as_int());
}
void MainWindow::on_wrap_toggled(Gtk::WrapMode mode)
{
m_draw_main.set_wrap_mode(mode);
m_draw_primary.set_wrap_mode(mode);
}
void MainWindow::on_brightness_changed()

View File

@ -58,7 +58,7 @@ public:
void startedRequest();
void finishedRequest();
void refreshRequest();
void showStartpage();
void showHomepage();
void setText(const Glib::ustring& content);
void setDocument(cmark_node* rootNode);
void setMessage(const Glib::ustring& message, const Glib::ustring& details = "");
@ -122,7 +122,7 @@ protected:
// Child widgets
Menu m_menu;
Draw m_draw_main;
Draw m_draw_primary;
Draw m_draw_secondary;
SourceCodeDialog m_sourceCodeDialog;
About m_about;
@ -268,7 +268,7 @@ protected:
Gtk::Label m_iconThemeLabel;
std::unique_ptr<Gtk::MessageDialog> m_contentPublishedDialog;
Gtk::ScrolledWindow m_scrolledToc;
Gtk::ScrolledWindow m_scrolledWindowMain;
Gtk::ScrolledWindow m_scrolledWindowPrimary;
Gtk::ScrolledWindow m_scrolledWindowSecondary;
Gtk::SeparatorMenuItem m_separator1;
Gtk::SeparatorMenuItem m_separator2;
@ -310,6 +310,7 @@ private:
void initTableofContents();
void initSignals();
bool isInstalled();
void setTableofContents(std::vector<Glib::RefPtr<Gtk::TextMark>> headings);
void enableEdit();
void disableEdit();
bool isEditorEnabled();

View File

@ -254,7 +254,7 @@ void Middleware::processRequest(const std::string& path, bool isParseContent)
// Handle homepage
else if (requestPath_.compare("about:home") == 0)
{
Glib::signal_idle().connect_once(sigc::mem_fun(mainWindow, &MainWindow::showStartpage));
Glib::signal_idle().connect_once(sigc::mem_fun(mainWindow, &MainWindow::showHomepage));
}
// Handle disk or IPFS file paths
else