diff --git a/Applications/Browser/BookmarksBarWidget.cpp b/Applications/Browser/BookmarksBarWidget.cpp new file mode 100644 index 0000000000..f51bfe0e69 --- /dev/null +++ b/Applications/Browser/BookmarksBarWidget.cpp @@ -0,0 +1,164 @@ +/* + * Copyright (c) 2020, Emanuel Sprung + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "BookmarksBarWidget.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +BookmarksBarWidget::BookmarksBarWidget(const String& bookmarks_file, bool enabled) +{ + set_layout(); + layout()->set_spacing(0); + + set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); + set_preferred_size(0, 20); + + if (!enabled) + set_visible(false); + + m_additional = GUI::Button::construct(); + m_additional->set_button_style(Gfx::ButtonStyle::CoolBar); + m_additional->set_text(">"); + m_additional->set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed); + m_additional->set_preferred_size(14, 20); + m_additional->on_click = [&] { + if (m_additional_menu) { + m_additional_menu->popup(m_additional->relative_position().translated(relative_position().translated(m_additional->window()->position()))); + } + }; + + m_separator = GUI::Widget::construct(); + + Vector fields; + fields.empend("title", "Title", Gfx::TextAlignment::CenterLeft); + fields.empend("url", "Url", Gfx::TextAlignment::CenterRight); + set_model(GUI::JsonArrayModel::create(bookmarks_file, move(fields))); + model()->update(); +} + +BookmarksBarWidget::~BookmarksBarWidget() +{ +} + +void BookmarksBarWidget::set_model(RefPtr model) +{ + if (model == m_model) + return; + m_model = move(model); + m_model->on_update = [&]() { + did_update_model(); + }; +} + +void BookmarksBarWidget::resize_event(GUI::ResizeEvent& event) +{ + Widget::resize_event(event); + update_content_size(); +} + +void BookmarksBarWidget::did_update_model() +{ + for (auto* child : child_widgets()) { + child->remove_from_parent(); + } + child_widgets().clear(); + + m_bookmarks.clear(); + + int width = 0; + for (int item_index = 0; item_index < model()->row_count(); ++item_index) { + + auto title = model()->data(model()->index(item_index, 0)).to_string(); + auto url = model()->data(model()->index(item_index, 1)).to_string(); + + Gfx::Rect rect { width, 0, font().width(title) + 32, height() }; + + auto& button = add(); + m_bookmarks.append(button); + + button.set_button_style(Gfx::ButtonStyle::CoolBar); + button.set_text(title); + button.set_size_policy(GUI::SizePolicy::Fixed, GUI::SizePolicy::Fixed); + button.set_icon(Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-html.png")); + button.set_preferred_size(font().width(title) + 32, 20); + button.set_relative_rect(rect); + + button.on_click = [title, url, this] { + if (on_bookmark_click) + on_bookmark_click(title, url); + }; + + width += rect.width(); + } + + add_child(*m_separator); + add_child(*m_additional); + + update_content_size(); + update(); +} + +void BookmarksBarWidget::update_content_size() +{ + int x_position = 0; + m_last_visible_index = -1; + + for (size_t i = 0; i < m_bookmarks.size(); ++i) { + auto& bookmark = m_bookmarks.at(i); + if (x_position + bookmark.width() > width()) { + m_last_visible_index = i; + break; + } + bookmark.set_x(x_position); + bookmark.set_visible(true); + x_position += bookmark.width(); + } + + if (m_last_visible_index < 0) { + m_additional->set_visible(false); + } else { + // hide all items > m_last_visible_index and create new bookmarks menu for them + m_additional->set_visible(true); + m_additional_menu = GUI::Menu::construct("Additional Bookmarks"); + for (size_t i = m_last_visible_index; i < m_bookmarks.size(); ++i) { + auto& bookmark = m_bookmarks.at(i); + bookmark.set_visible(false); + m_additional_menu->add_action(GUI::Action::create(bookmark.text(), + Gfx::Bitmap::load_from_file("/res/icons/16x16/filetype-html.png"), + [&](auto&) { + bookmark.on_click(); + })); + } + } +} diff --git a/Applications/Browser/BookmarksBarWidget.h b/Applications/Browser/BookmarksBarWidget.h new file mode 100644 index 0000000000..c9135d6549 --- /dev/null +++ b/Applications/Browser/BookmarksBarWidget.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2020, Emanuel Sprung + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, this + * list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#pragma once + +#include +#include + +class BookmarksBarWidget final : public GUI::Widget { + C_OBJECT(BookmarksBarWidget) +public: + virtual ~BookmarksBarWidget() override; + + void set_model(RefPtr); + GUI::Model* model() { return m_model.ptr(); } + const GUI::Model* model() const { return m_model.ptr(); } + + Function on_bookmark_click; + Function on_bookmark_hover; + +private: + BookmarksBarWidget(const String&, bool enabled); + + virtual void did_update_model(); + virtual void resize_event(GUI::ResizeEvent&) override; + + void update_content_size(); + + RefPtr m_model; + RefPtr m_additional; + RefPtr m_separator; + RefPtr m_additional_menu; + + NonnullRefPtrVector m_bookmarks; + + int m_last_visible_index { -1 }; +}; diff --git a/Applications/Browser/Makefile b/Applications/Browser/Makefile index 962266dacc..ce65632cd4 100755 --- a/Applications/Browser/Makefile +++ b/Applications/Browser/Makefile @@ -1,6 +1,7 @@ OBJS = \ main.o \ - InspectorWidget.o + InspectorWidget.o \ + BookmarksBarWidget.o PROGRAM = Browser diff --git a/Applications/Browser/main.cpp b/Applications/Browser/main.cpp index e2bfa9e890..441d8ddfb7 100644 --- a/Applications/Browser/main.cpp +++ b/Applications/Browser/main.cpp @@ -24,6 +24,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "BookmarksBarWidget.h" #include "History.h" #include "InspectorWidget.h" #include @@ -53,6 +54,7 @@ #include static const char* home_url = "file:///home/anon/www/welcome.html"; +static const char* bookmarks_filename = "/home/anon/bookmarks.json"; int main(int argc, char** argv) { @@ -71,7 +73,6 @@ int main(int argc, char** argv) return 1; } - auto window = GUI::Window::construct(); window->set_rect(100, 100, 640, 480); @@ -80,14 +81,15 @@ int main(int argc, char** argv) widget.set_layout(); widget.layout()->set_spacing(0); + bool bookmarksbar_enabled = true; + auto& toolbar = widget.add(); - auto& bookmarksbar = widget.add(); + auto& bookmarksbar = widget.add(bookmarks_filename, bookmarksbar_enabled); auto& html_widget = widget.add(); - bool bookmarksbar_enabled = true; - bookmarksbar.set_layout(); - bookmarksbar.set_size_policy(GUI::SizePolicy::Fill, GUI::SizePolicy::Fixed); - bookmarksbar.set_preferred_size(0, bookmarksbar_enabled ? 20 : 0); + bookmarksbar.on_bookmark_click = [&](auto&, auto& url) { + html_widget.load(url); + }; History history; @@ -163,6 +165,10 @@ int main(int argc, char** argv) statusbar.set_text(href); }; + bookmarksbar.on_bookmark_hover = [&](auto&, auto& url) { + statusbar.set_text(url); + }; + Web::ResourceLoader::the().on_load_counter_change = [&] { if (Web::ResourceLoader::the().pending_loads() == 0) { statusbar.set_text(""); @@ -241,7 +247,7 @@ int main(int argc, char** argv) auto bookmarks_menu = GUI::Menu::construct("Bookmarks"); auto show_bookmarksbar_action = GUI::Action::create("Show bookmarks bar", [&](auto& action) { action.set_checked(!action.is_checked()); - bookmarksbar.set_preferred_size(0, action.is_checked() ? 20 : 0); + bookmarksbar.set_visible(action.is_checked()); bookmarksbar.update(); }); show_bookmarksbar_action->set_checkable(true); diff --git a/Base/home/anon/bookmarks.json b/Base/home/anon/bookmarks.json new file mode 100644 index 0000000000..0ca1f3eab7 --- /dev/null +++ b/Base/home/anon/bookmarks.json @@ -0,0 +1,6 @@ +[ + { + "title": "SerenityOS.org", + "url": "http://www.serenityos.org/" + } +]