diff --git a/README.md b/README.md index 7bdd53e..ec69b45 100644 --- a/README.md +++ b/README.md @@ -49,8 +49,7 @@ For the build you need at least: * CMake (Package: `cmake`) * Ninja build system (Package: `ninja-build`) * GTK & Cairo & Pango (including C++ bindings): - - Package: `libgtkmm-3.0-dev` under Debian based distros - + * Package: `libgtkmm-3.0-dev` under Debian based distros ### Documentation diff --git a/src/draw.cc b/src/draw.cc index 373c49a..48286ad 100644 --- a/src/draw.cc +++ b/src/draw.cc @@ -295,13 +295,88 @@ void Draw::newDocument() this->clearBuffer(); enableEdit(); grab_focus(); // Claim focus on text view - insertLinkTemplate(); } -void Draw::insertLinkTemplate() +/************************************************************* + * Editor signals + *************************************************************/ + +void Draw::make_bold() { auto buffer = get_buffer(); - buffer->insert_at_cursor("[link](ipfs://yourserver)"); + buffer->insert_at_cursor("**text**"); +} + +void Draw::make_italic() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("*text*"); +} + +void Draw::make_strikethrough() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("~~text~~"); +} + +void Draw::make_super() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("^text^"); +} + +void Draw::make_sub() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("~text~"); +} + +void Draw::make_inline_code() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("`code`"); +} + +void Draw::make_quote() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("\n> text"); +} + +void Draw::make_code_block() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("\n\n```python\ncode\n```\n\n"); +} + +void Draw::insert_link() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("[link](ipfs://youraddress)"); +} + +void Draw::insert_image() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("![alt](ipfs://image.jpg)"); +} + +void Draw::insert_bullet_list() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("\n* item"); +} + +void Draw::insert_numbered_list() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("\n1. item"); +} + +void Draw::make_highlight() +{ + auto buffer = get_buffer(); + buffer->insert_at_cursor("==text=="); } /** diff --git a/src/draw.h b/src/draw.h index 3fed805..c571527 100644 --- a/src/draw.h +++ b/src/draw.h @@ -33,7 +33,21 @@ public: void paste(); void del(); void newDocument(); - void insertLinkTemplate(); + + // Signals editor calls + void make_bold(); + void make_italic(); + void make_strikethrough(); + void make_super(); + void make_sub(); + void make_inline_code(); + void make_quote(); + void make_code_block(); + void insert_link(); + void insert_image(); + void insert_bullet_list(); + void insert_numbered_list(); + void make_highlight(); protected: // Signals diff --git a/src/mainwindow.cc b/src/mainwindow.cc index 8b37add..5b93c3c 100644 --- a/src/mainwindow.cc +++ b/src/mainwindow.cc @@ -15,15 +15,16 @@ MainWindow::MainWindow() m_menu(accelGroup), m_draw(*this), m_vbox(Gtk::ORIENTATION_VERTICAL, 0), - m_hboxBar(Gtk::ORIENTATION_HORIZONTAL, 0), + m_hboxToolbar(Gtk::ORIENTATION_HORIZONTAL, 0), m_hboxBottom(Gtk::ORIENTATION_HORIZONTAL, 0), + m_appName("DWeb Browser"), m_requestThread(nullptr), requestPath(""), finalRequestPath(""), currentContent(""), currentHistoryIndex(0) { - set_title("DWeb Browser"); + set_title(m_appName); set_default_size(1000, 800); set_position(Gtk::WIN_POS_CENTER); add_accel_group(accelGroup); @@ -46,15 +47,73 @@ MainWindow::MainWindow() m_menu.about.connect(sigc::mem_fun(m_about, &About::show_about)); /*!< Display about dialog */ m_draw.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_backButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::back)); /*!< Button for previous page */ m_forwardButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::forward)); /*!< Button for next page */ m_refreshButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::refresh)); /*!< Button for reloading the page */ m_homeButton.signal_clicked().connect(sigc::mem_fun(this, &MainWindow::go_home)); /*!< Button for home page */ - m_addressBar.signal_activate().connect(sigc::mem_fun(this, &MainWindow::address_bar_activate)); /*!< User pressed enter the address bar */ m_searchEntry.signal_activate().connect(sigc::mem_fun(this, &MainWindow::do_search)); /*!< Execute the text search */ m_vbox.pack_start(m_menu, false, false, 0); + // Editor buttons + m_boldButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::make_bold)); + m_italicButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::make_italic)); + m_strikethroughButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::make_strikethrough)); + m_superButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::make_super)); + m_subButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::make_sub)); + m_inlineCodeButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::make_inline_code)); + m_quoteButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::make_quote)); + m_codeBlockButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::make_code_block)); + m_linkButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::insert_link)); + m_imageButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::insert_image)); + m_bulletListButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::insert_bullet_list)); + m_numberedListButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::insert_numbered_list)); + m_highlightButton.signal_clicked().connect(sigc::mem_fun(m_draw, &Draw::make_highlight)); + + // Add icons to the editor buttons + boldIcon.set_from_icon_name("format-text-bold-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_boldButton.add(boldIcon); + italicIcon.set_from_icon_name("format-text-italic-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_italicButton.add(italicIcon); + strikethroughIcon.set_from_icon_name("format-text-strikethrough-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_strikethroughButton.add(strikethroughIcon); + superIcon.set_from_icon_name("format-text-bold-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_superButton.add(superIcon); + subIcon.set_from_icon_name("format-text-bold-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_subButton.add(subIcon); + inlineCodeIcon.set_from_icon_name("format-text-bold-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_inlineCodeButton.add(inlineCodeIcon); + quoteIcon.set_from_icon_name("format-text-bold-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_quoteButton.add(quoteIcon); + codeBlockIcon.set_from_icon_name("format-text-bold-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_codeBlockButton.add(codeBlockIcon); + linkIcon.set_from_icon_name("insert-link-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_linkButton.add(linkIcon); + imageIcon.set_from_icon_name("insert-image-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_imageButton.add(imageIcon); + bulletIcon.set_from_icon_name("view-list-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_bulletListButton.add(bulletIcon); + numberedIcon.set_from_icon_name("view-list-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_numberedListButton.add(numberedIcon); + hightlightIcon.set_from_icon_name("format-text-bold-symbolic", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); + m_highlightButton.add(hightlightIcon); + + // Disable focus on editor buttons + m_boldButton.set_can_focus(false); + m_italicButton.set_can_focus(false); + m_strikethroughButton.set_can_focus(false); + m_superButton.set_can_focus(false); + m_subButton.set_can_focus(false); + m_inlineCodeButton.set_can_focus(false); + m_quoteButton.set_can_focus(false); + m_codeBlockButton.set_can_focus(false); + m_linkButton.set_can_focus(false); + m_imageButton.set_can_focus(false); + m_bulletListButton.set_can_focus(false); + m_numberedListButton.set_can_focus(false); + m_highlightButton.set_can_focus(false); + // Horizontal bar auto styleBack = m_backButton.get_style_context(); styleBack->add_class("circular"); @@ -67,7 +126,7 @@ MainWindow::MainWindow() m_refreshButton.set_relief(Gtk::RELIEF_NONE); m_homeButton.set_relief(Gtk::RELIEF_NONE); - // Add icons to buttons + // Add icons to the toolbar buttons backIcon.set_from_icon_name("go-previous", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); m_backButton.add(backIcon); forwardIcon.set_from_icon_name("go-next", Gtk::IconSize(Gtk::ICON_SIZE_MENU)); @@ -81,12 +140,29 @@ MainWindow::MainWindow() m_backButton.set_sensitive(false); m_forwardButton.set_sensitive(false); - m_hboxBar.pack_start(m_backButton, false, false, 0); - m_hboxBar.pack_start(m_forwardButton, false, false, 0); - m_hboxBar.pack_start(m_refreshButton, false, false, 0); - m_hboxBar.pack_start(m_homeButton, false, false, 0); - m_hboxBar.pack_start(m_addressBar, true, true, 8); - m_vbox.pack_start(m_hboxBar, false, false, 6); + // Toolbar + m_hboxToolbar.pack_start(m_backButton, false, false, 0); + m_hboxToolbar.pack_start(m_forwardButton, false, false, 0); + m_hboxToolbar.pack_start(m_refreshButton, false, false, 0); + m_hboxToolbar.pack_start(m_homeButton, false, false, 0); + m_hboxToolbar.pack_start(m_addressBar, true, true, 8); + m_vbox.pack_start(m_hboxToolbar, false, false, 6); + + // Editor bar + m_hboxEditor.pack_start(m_boldButton, false, false, 2); + m_hboxEditor.pack_start(m_italicButton, false, false, 2); + m_hboxEditor.pack_start(m_strikethroughButton, false, false, 2); + m_hboxEditor.pack_start(m_superButton, false, false, 2); + m_hboxEditor.pack_start(m_subButton, false, false, 2); + m_hboxEditor.pack_start(m_inlineCodeButton, false, false, 2); + m_hboxEditor.pack_start(m_quoteButton, false, false, 2); + m_hboxEditor.pack_start(m_codeBlockButton, false, false, 2); + m_hboxEditor.pack_start(m_linkButton, false, false, 2); + m_hboxEditor.pack_start(m_imageButton, false, false, 2); + m_hboxEditor.pack_start(m_bulletListButton, false, false, 2); + m_hboxEditor.pack_start(m_numberedListButton, false, false, 2); + m_hboxEditor.pack_start(m_highlightButton, false, false, 2); + m_vbox.pack_start(m_hboxEditor, false, false, 6); // Browser text drawing area m_scrolledWindow.add(m_draw); @@ -104,8 +180,9 @@ MainWindow::MainWindow() add(m_vbox); show_all_children(); - // Hide bottom horizontal bar by default + // Hide by default the bottom & editor box m_hboxBottom.hide(); + m_hboxEditor.hide(); // Grap focus to input field by default m_addressBar.grab_focus(); @@ -135,7 +212,7 @@ void MainWindow::doRequest(const std::string &path, bool setAddressBar, bool isH if (m_requestThread == nullptr) { m_requestThread = new std::thread(&MainWindow::processRequest, this, path); - postDoRequest(path, setAddressBar, isHistoryRequest); + this->postDoRequest(path, setAddressBar, isHistoryRequest); } } @@ -147,6 +224,8 @@ void MainWindow::postDoRequest(const std::string &path, bool setAddressBar, bool if (setAddressBar) m_addressBar.set_text(path); + this->disableEditing(); + // Do not insert history back/forward calls into the history (again) if (!isHistoryRequest) { @@ -171,8 +250,10 @@ void MainWindow::postDoRequest(const std::string &path, bool setAddressBar, bool void MainWindow::new_doc() { - // Inform about new document in draw + // Inform the Draw class about the new document m_draw.newDocument(); + // Enable editing mode + this->enableEditing(); } void MainWindow::go_home() @@ -181,6 +262,7 @@ void MainWindow::go_home() this->finalRequestPath = ""; this->currentContent = ""; this->m_addressBar.set_text(""); + this->disableEditing(); m_draw.showStartPage(); } @@ -237,6 +319,20 @@ void MainWindow::refresh() doRequest(); } +void MainWindow::enableEditing() +{ + this->m_hboxEditor.show(); + set_title("Untitled * - " + m_appName); +} + +void MainWindow::disableEditing() +{ + if (m_hboxEditor.is_visible()) + { + this->m_hboxEditor.hide(); + set_title(m_appName); + } +} /** * Get the file from disk or IPFS network, from the provided path, * parse the content, and display the document diff --git a/src/mainwindow.h b/src/mainwindow.h index 66865d2..d41f8ee 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -51,21 +51,49 @@ protected: Gtk::SearchBar m_search; Gtk::SearchEntry m_searchEntry; Gtk::Box m_vbox; - Gtk::Box m_hboxBar; + Gtk::Box m_hboxToolbar; + Gtk::Box m_hboxEditor; Gtk::Box m_hboxBottom; + Gtk::Entry m_addressBar; Gtk::Button m_backButton; Gtk::Button m_forwardButton; Gtk::Button m_refreshButton; Gtk::Button m_homeButton; - Gtk::Entry m_addressBar; + Gtk::Button m_boldButton; + Gtk::Button m_italicButton; + Gtk::Button m_strikethroughButton; + Gtk::Button m_superButton; + Gtk::Button m_subButton; + Gtk::Button m_inlineCodeButton; + Gtk::Button m_quoteButton; + Gtk::Button m_codeBlockButton; + Gtk::Button m_linkButton; + Gtk::Button m_imageButton; + Gtk::Button m_bulletListButton; + Gtk::Button m_numberedListButton; + Gtk::Button m_highlightButton; Gtk::Image backIcon; Gtk::Image forwardIcon; Gtk::Image refreshIcon; Gtk::Image homeIcon; + Gtk::Image boldIcon; + Gtk::Image italicIcon; + Gtk::Image strikethroughIcon; + Gtk::Image superIcon; + Gtk::Image subIcon; + Gtk::Image inlineCodeIcon; + Gtk::Image quoteIcon; + Gtk::Image codeBlockIcon; + Gtk::Image linkIcon; + Gtk::Image imageIcon; + Gtk::Image bulletIcon; + Gtk::Image numberedIcon; + Gtk::Image hightlightIcon; Gtk::ScrolledWindow m_scrolledWindow; Gtk::Button m_exitBottomButton; private: + std::string m_appName; File m_file; std::thread *m_requestThread; std::string requestPath; @@ -74,10 +102,12 @@ private: std::size_t currentHistoryIndex; std::vector history; + void enableEditing(); + void disableEditing(); void postDoRequest(const std::string &path, bool setAddressBar, bool isHistoryRequest); void processRequest(const std::string &path); void fetchFromIPFS(); void openFromDisk(); }; -#endif \ No newline at end of file +#endif