| Index: mash/browser/browser.cc
|
| diff --git a/mash/browser/browser.cc b/mash/browser/browser.cc
|
| index 5094674b278692b92b142b20bfdfcc038bd56f69..c746ef0e5a76a0620c74c29df4ad8780c6ca063a 100644
|
| --- a/mash/browser/browser.cc
|
| +++ b/mash/browser/browser.cc
|
| @@ -5,11 +5,13 @@
|
| #include "mash/browser/browser.h"
|
|
|
| #include "base/macros.h"
|
| +#include "base/memory/ptr_util.h"
|
| #include "base/memory/weak_ptr.h"
|
| #include "base/message_loop/message_loop.h"
|
| #include "base/strings/string16.h"
|
| #include "base/strings/string_util.h"
|
| #include "base/strings/utf_string_conversions.h"
|
| +#include "base/threading/thread_task_runner_handle.h"
|
| #include "base/timer/timer.h"
|
| #include "components/mus/public/cpp/window.h"
|
| #include "components/mus/public/cpp/window_tree_client.h"
|
| @@ -22,12 +24,15 @@
|
| #include "services/shell/public/cpp/shell_client.h"
|
| #include "services/tracing/public/cpp/tracing_impl.h"
|
| #include "ui/aura/mus/mus_util.h"
|
| +#include "ui/base/models/menu_model.h"
|
| #include "ui/gfx/canvas.h"
|
| #include "ui/gfx/paint_throbber.h"
|
| #include "ui/gfx/text_constants.h"
|
| #include "ui/native_theme/native_theme.h"
|
| #include "ui/views/background.h"
|
| #include "ui/views/controls/button/label_button.h"
|
| +#include "ui/views/controls/menu/menu_model_adapter.h"
|
| +#include "ui/views/controls/menu/menu_runner.h"
|
| #include "ui/views/controls/textfield/textfield.h"
|
| #include "ui/views/controls/textfield/textfield_controller.h"
|
| #include "ui/views/mus/aura_init.h"
|
| @@ -43,6 +48,175 @@ void EnableButton(views::CustomButton* button, bool enabled) {
|
| : views::Button::STATE_DISABLED);
|
| }
|
|
|
| +class NavMenuModel : public ui::MenuModel {
|
| + public:
|
| + class Delegate {
|
| + public:
|
| + virtual void NavigateToOffset(int offset) = 0;
|
| + };
|
| +
|
| + struct Entry {
|
| + Entry(const base::string16& title, int offset)
|
| + : title(title), offset(offset) {}
|
| + ~Entry() {}
|
| +
|
| + // Title of the entry in the menu.
|
| + base::string16 title;
|
| + // Offset from the currently visible page to navigate to this item.
|
| + int offset;
|
| + };
|
| +
|
| + NavMenuModel(const std::vector<Entry>& entries, Delegate* delegate)
|
| + : navigation_delegate_(delegate), entries_(entries) {}
|
| + ~NavMenuModel() override {}
|
| +
|
| + private:
|
| + bool HasIcons() const override { return false; }
|
| + int GetItemCount() const override {
|
| + return static_cast<int>(entries_.size());
|
| + }
|
| + ui::MenuModel::ItemType GetTypeAt(int index) const override {
|
| + return ui::MenuModel::TYPE_COMMAND;
|
| + }
|
| + ui::MenuSeparatorType GetSeparatorTypeAt(int index) const override {
|
| + return ui::NORMAL_SEPARATOR;
|
| + }
|
| + int GetCommandIdAt(int index) const override {
|
| + return index;
|
| + }
|
| + base::string16 GetLabelAt(int index) const override {
|
| + return entries_[index].title;
|
| + }
|
| + base::string16 GetSublabelAt(int index) const override {
|
| + return base::string16();
|
| + }
|
| + base::string16 GetMinorTextAt(int index) const override {
|
| + return base::string16();
|
| + }
|
| + bool IsItemDynamicAt(int index) const override { return false; }
|
| + bool GetAcceleratorAt(int index,
|
| + ui::Accelerator* accelerator) const override {
|
| + return false;
|
| + }
|
| + bool IsItemCheckedAt(int index) const override { return false; }
|
| + int GetGroupIdAt(int index) const override { return -1; }
|
| + bool GetIconAt(int index, gfx::Image* icon) override { return false; }
|
| + ui::ButtonMenuItemModel* GetButtonMenuItemAt(int index) const override {
|
| + return nullptr;
|
| + }
|
| + bool IsEnabledAt(int index) const override { return true; }
|
| + bool IsVisibleAt(int index) const override { return true; }
|
| + ui::MenuModel* GetSubmenuModelAt(int index) const override { return nullptr; }
|
| + void HighlightChangedTo(int index) override {}
|
| + void ActivatedAt(int index) override {
|
| + ActivatedAt(index, 0);
|
| + }
|
| + void ActivatedAt(int index, int event_flags) override {
|
| + navigation_delegate_->NavigateToOffset(entries_[index].offset);
|
| + }
|
| + void SetMenuModelDelegate(ui::MenuModelDelegate* delegate) override {
|
| + delegate_ = delegate;
|
| + }
|
| + ui::MenuModelDelegate* GetMenuModelDelegate() const override {
|
| + return delegate_;
|
| + }
|
| +
|
| + ui::MenuModelDelegate* delegate_ = nullptr;
|
| + Delegate* navigation_delegate_;
|
| + std::vector<Entry> entries_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(NavMenuModel);
|
| +};
|
| +
|
| +class NavButton : public views::LabelButton {
|
| + public:
|
| + enum class Type {
|
| + BACK,
|
| + FORWARD
|
| + };
|
| +
|
| + class ModelProvider {
|
| + public:
|
| + virtual std::unique_ptr<ui::MenuModel> CreateMenuModel(Type type) = 0;
|
| + };
|
| +
|
| + NavButton(Type type,
|
| + ModelProvider* model_provider,
|
| + views::ButtonListener* listener,
|
| + const base::string16& label)
|
| + : views::LabelButton(listener, label),
|
| + type_(type),
|
| + model_provider_(model_provider),
|
| + show_menu_factory_(this) {}
|
| + ~NavButton() override {}
|
| +
|
| + private:
|
| + // views::LabelButton overrides:
|
| + bool OnMousePressed(const ui::MouseEvent& event) override {
|
| + if (IsTriggerableEvent(event) && enabled() &&
|
| + HitTestPoint(event.location())) {
|
| + y_pos_on_lbuttondown_ = event.y();
|
| + base::ThreadTaskRunnerHandle::Get()->PostDelayedTask(
|
| + FROM_HERE,
|
| + base::Bind(&NavButton::ShowMenu, show_menu_factory_.GetWeakPtr(),
|
| + ui::GetMenuSourceTypeForEvent(event)),
|
| + base::TimeDelta::FromMilliseconds(500));
|
| + }
|
| + return LabelButton::OnMousePressed(event);
|
| + }
|
| + bool OnMouseDragged(const ui::MouseEvent& event) override {
|
| + bool result = LabelButton::OnMouseDragged(event);
|
| + if (show_menu_factory_.HasWeakPtrs()) {
|
| + if (event.y() > y_pos_on_lbuttondown_ + GetHorizontalDragThreshold()) {
|
| + show_menu_factory_.InvalidateWeakPtrs();
|
| + ShowMenu(ui::GetMenuSourceTypeForEvent(event));
|
| + }
|
| + }
|
| + return result;
|
| + }
|
| + void OnMouseReleased(const ui::MouseEvent& event) override {
|
| + if (IsTriggerableEvent(event))
|
| + show_menu_factory_.InvalidateWeakPtrs();
|
| + LabelButton::OnMouseReleased(event);
|
| + }
|
| +
|
| + void ShowMenu(ui::MenuSourceType source_type) {
|
| + gfx::Rect local = GetLocalBounds();
|
| + gfx::Point menu_position(local.origin());
|
| + menu_position.Offset(0, local.height() - 1);
|
| + View::ConvertPointToScreen(this, &menu_position);
|
| +
|
| + model_ = model_provider_->CreateMenuModel(type_);
|
| + menu_model_adapter_.reset(new views::MenuModelAdapter(
|
| + model_.get(),
|
| + base::Bind(&NavButton::OnMenuClosed, base::Unretained(this))));
|
| + menu_model_adapter_->set_triggerable_event_flags(triggerable_event_flags());
|
| + menu_runner_.reset(new views::MenuRunner(
|
| + menu_model_adapter_->CreateMenu(),
|
| + views::MenuRunner::HAS_MNEMONICS | views::MenuRunner::ASYNC));
|
| + ignore_result(menu_runner_->RunMenuAt(
|
| + GetWidget(), nullptr, gfx::Rect(menu_position, gfx::Size(0, 0)),
|
| + views::MENU_ANCHOR_TOPLEFT, source_type));
|
| + }
|
| +
|
| + void OnMenuClosed() {
|
| + SetMouseHandler(nullptr);
|
| + model_.reset();
|
| + menu_runner_.reset();
|
| + menu_model_adapter_.reset();
|
| + }
|
| +
|
| + Type type_;
|
| + ModelProvider* model_provider_;
|
| + int y_pos_on_lbuttondown_ = 0;
|
| + std::unique_ptr<ui::MenuModel> model_;
|
| + std::unique_ptr<views::MenuModelAdapter> menu_model_adapter_;
|
| + std::unique_ptr<views::MenuRunner> menu_runner_;
|
| + base::WeakPtrFactory<NavButton> show_menu_factory_;
|
| +
|
| + DISALLOW_COPY_AND_ASSIGN(NavButton);
|
| +};
|
| +
|
| class ProgressBar : public views::View {
|
| public:
|
| ProgressBar() {}
|
| @@ -115,7 +289,9 @@ class Throbber : public views::View {
|
| class UI : public views::WidgetDelegateView,
|
| public views::ButtonListener,
|
| public views::TextfieldController,
|
| - public navigation::mojom::ViewClient {
|
| + public navigation::mojom::ViewClient,
|
| + public NavButton::ModelProvider,
|
| + public NavMenuModel::Delegate {
|
| public:
|
| enum class Type { WINDOW, POPUP };
|
|
|
| @@ -125,9 +301,10 @@ class UI : public views::WidgetDelegateView,
|
| navigation::mojom::ViewClientRequest request)
|
| : browser_(browser),
|
| type_(type),
|
| - back_button_(new views::LabelButton(this, base::ASCIIToUTF16("Back"))),
|
| - forward_button_(
|
| - new views::LabelButton(this, base::ASCIIToUTF16("Forward"))),
|
| + back_button_(new NavButton(NavButton::Type::BACK, this, this,
|
| + base::ASCIIToUTF16("Back"))),
|
| + forward_button_(new NavButton(NavButton::Type::FORWARD, this, this,
|
| + base::ASCIIToUTF16("Forward"))),
|
| reload_button_(
|
| new views::LabelButton(this, base::ASCIIToUTF16("Reload"))),
|
| prompt_(new views::Textfield),
|
| @@ -321,6 +498,66 @@ class UI : public views::WidgetDelegateView,
|
| browser_->AddWindow(window);
|
| }
|
| void Close() override { GetWidget()->Close(); }
|
| + void NavigationPending(navigation::mojom::NavigationEntryPtr entry) override {
|
| + pending_nav_ = std::move(entry);
|
| + }
|
| + void NavigationCommitted(
|
| + navigation::mojom::NavigationCommittedDetailsPtr details,
|
| + int current_index) override {
|
| + switch (details->type) {
|
| + case navigation::mojom::NavigationType::NEW_PAGE: {
|
| + navigation_list_.push_back(std::move(pending_nav_));
|
| + navigation_list_position_ = current_index;
|
| + break;
|
| + }
|
| + case navigation::mojom::NavigationType::EXISTING_PAGE:
|
| + navigation_list_position_ = current_index;
|
| + break;
|
| + default:
|
| + break;
|
| + }
|
| + }
|
| + void NavigationEntryChanged(navigation::mojom::NavigationEntryPtr entry,
|
| + int entry_index) override {
|
| + navigation_list_[entry_index] = std::move(entry);
|
| + }
|
| + void NavigationListPruned(bool from_front, int count) override {
|
| + DCHECK(count < static_cast<int>(navigation_list_.size()));
|
| + if (from_front) {
|
| + auto it = navigation_list_.begin() + count;
|
| + navigation_list_.erase(navigation_list_.begin(), it);
|
| + } else {
|
| + auto it = navigation_list_.end() - count;
|
| + navigation_list_.erase(it, navigation_list_.end());
|
| + }
|
| + }
|
| +
|
| + // NavButton::ModelProvider:
|
| + std::unique_ptr<ui::MenuModel> CreateMenuModel(
|
| + NavButton::Type type) override {
|
| + std::vector<NavMenuModel::Entry> entries;
|
| + if (type == NavButton::Type::BACK) {
|
| + for (int i = navigation_list_position_ - 1, offset = -1;
|
| + i >= 0; --i, --offset) {
|
| + std::string title = navigation_list_[i]->title;
|
| + entries.push_back(
|
| + NavMenuModel::Entry(base::UTF8ToUTF16(title), offset));
|
| + }
|
| + } else {
|
| + for (int i = navigation_list_position_ + 1, offset = 1;
|
| + i < static_cast<int>(navigation_list_.size()); ++i, ++offset) {
|
| + std::string title = navigation_list_[i]->title;
|
| + entries.push_back(
|
| + NavMenuModel::Entry(base::UTF8ToUTF16(title), offset));
|
| + }
|
| + }
|
| + return base::WrapUnique(new NavMenuModel(entries, this));
|
| + }
|
| +
|
| + // NavMenuModel::Delegate:
|
| + void NavigateToOffset(int offset) override {
|
| + view_->NavigateToOffset(offset);
|
| + }
|
|
|
| void ToggleDebugView() {
|
| showing_debug_view_ = !showing_debug_view_;
|
| @@ -350,6 +587,10 @@ class UI : public views::WidgetDelegateView,
|
| base::string16 current_title_;
|
| GURL current_url_;
|
|
|
| + navigation::mojom::NavigationEntryPtr pending_nav_;
|
| + std::vector<navigation::mojom::NavigationEntryPtr> navigation_list_;
|
| + int navigation_list_position_ = 0;
|
| +
|
| bool showing_debug_view_ = false;
|
|
|
| DISALLOW_COPY_AND_ASSIGN(UI);
|
|
|