// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "ui/views/examples/menu_example.h"

#include <memory>
#include <set>
#include <string>
#include <utility>
#include <vector>

#include "base/logging.h"
#include "base/no_destructor.h"
#include "base/pickle.h"
#include "base/strings/utf_string_conversions.h"
#include "ui/base/clipboard/clipboard_format_type.h"
#include "ui/base/dragdrop/mojom/drag_drop_types.mojom.h"
#include "ui/base/l10n/l10n_util.h"
#include "ui/base/metadata/metadata_header_macros.h"
#include "ui/base/metadata/metadata_impl_macros.h"
#include "ui/base/models/image_model.h"
#include "ui/base/mojom/menu_source_type.mojom.h"
#include "ui/color/color_id.h"
#include "ui/compositor/layer_tree_owner.h"
#include "ui/menus/simple_menu_model.h"
#include "ui/views/border.h"
#include "ui/views/controls/button/button.h"
#include "ui/views/controls/button/menu_button.h"
#include "ui/views/controls/label.h"
#include "ui/views/controls/menu/menu_delegate.h"
#include "ui/views/controls/menu/menu_item_view.h"
#include "ui/views/controls/menu/menu_runner.h"
#include "ui/views/controls/menu/submenu_view.h"
#include "ui/views/examples/examples_color_id.h"
#include "ui/views/examples/examples_window.h"
#include "ui/views/examples/grit/views_examples_resources.h"
#include "ui/views/layout/flex_layout.h"
#include "ui/views/layout/layout_provider.h"
#include "ui/views/metadata/view_factory.h"
#include "ui/views/vector_icons.h"
#include "ui/views/view.h"
#include "ui/views/widget/widget.h"

using l10n_util::GetStringUTF16;
using l10n_util::GetStringUTF8;

namespace views::examples {

enum CommandID {
  COMMAND_ROOT = -1,

  COMMAND_DO_SOMETHING,
  COMMAND_SECONDARY_LABEL_DEMO,
  COMMAND_MINOR_LABEL_DEMO,
  COMMAND_SELECT_ASCII,
  COMMAND_SELECT_UTF8,
  COMMAND_SELECT_UTF16,
  COMMAND_CHECK_APPLE,
  COMMAND_CHECK_ORANGE,
  COMMAND_CHECK_KIWI,
  COMMAND_GO_HOME,
  COMMAND_SELECT_ITEM_2,
  COMMAND_SELECT_ITEM_3,
};

// The base class for creating a menu runner.
class MenuRunnerFactory {
 public:
  MenuRunnerFactory();
  virtual ~MenuRunnerFactory();

  virtual std::unique_ptr<views::MenuRunner> CreateMenuRunner() = 0;
};

class CommandExecutor {
 public:
  explicit CommandExecutor(ui::SimpleMenuModel* menu_model);
  virtual ~CommandExecutor();

  bool IsCommandIdChecked(int command_id) const;
  bool IsCommandIdEnabled(int command_id) const;
  virtual void ExecuteCommand(int command_id, int event_flags);

 private:
  raw_ptr<ui::SimpleMenuModel> menu_model_;
  std::set<int> checked_fruits_;
  int current_encoding_command_id_ = COMMAND_SELECT_ASCII;
};

class ExampleMenuModel : public ui::SimpleMenuModel,
                         public ui::SimpleMenuModel::Delegate {
 public:
  ExampleMenuModel();

  ExampleMenuModel(const ExampleMenuModel&) = delete;
  ExampleMenuModel& operator=(const ExampleMenuModel&) = delete;

  // ui::SimpleMenuModel::Delegate:
  bool IsCommandIdChecked(int command_id) const override;
  bool IsCommandIdEnabled(int command_id) const override;
  void ExecuteCommand(int command_id, int event_flags) override;

 private:
  enum GroupID {
    GROUP_MAKE_DECISION,
  };

  std::unique_ptr<ui::SimpleMenuModel> submenu_;
  CommandExecutor executor_{this};
};

class ExampleMenuButton : public MenuButton {
  METADATA_HEADER(ExampleMenuButton, MenuButton)

 public:
  explicit ExampleMenuButton(const std::u16string& test = std::u16string());

  ExampleMenuButton(const ExampleMenuButton&) = delete;
  ExampleMenuButton& operator=(const ExampleMenuButton&) = delete;

  ~ExampleMenuButton() override;

  void set_menu_runner_factory(
      std::unique_ptr<MenuRunnerFactory> menu_runner_factory) {
    menu_runner_factory_ = std::move(menu_runner_factory);
  }

 private:
  void ButtonPressed();

  // The factory for creating a menu runner.
  std::unique_ptr<MenuRunnerFactory> menu_runner_factory_;

  // The menu runner created by `menu_runner_factory`.
  std::unique_ptr<MenuRunner> menu_runner_;
};

BEGIN_METADATA(ExampleMenuButton)
END_METADATA

BEGIN_VIEW_BUILDER(/* no export */, ExampleMenuButton, MenuButton)
END_VIEW_BUILDER

// Shows a simple menu using `ui::SimpleMenuModel`.
class ExampleMenuRunnerFactory : public MenuRunnerFactory {
 public:
  ExampleMenuRunnerFactory();
  ~ExampleMenuRunnerFactory() override;

 protected:
  // MenuRunnerFactory:
  std::unique_ptr<views::MenuRunner> CreateMenuRunner() override;

 private:
  ui::SimpleMenuModel* GetMenuModel();

  std::unique_ptr<ExampleMenuModel> menu_model_;
};

// Shows a menu with draggable items using `views::MenuItemView`.
class DraggableMenuRunnerFactory : public MenuRunnerFactory,
                                   public views::MenuDelegate {
 public:
  DraggableMenuRunnerFactory();
  ~DraggableMenuRunnerFactory() override;

 protected:
  // MenuRunnerFactory:
  std::unique_ptr<views::MenuRunner> CreateMenuRunner() override;

  // views::MenuDelegate:
  bool CanDrag(MenuItemView* menu) override;
  bool CanDrop(MenuItemView* menu, const OSExchangeData& data) override;
  ui::mojom::DragOperation GetDropOperation(MenuItemView* item,
                                            const ui::DropTargetEvent& event,
                                            DropPosition* position) override;
  int GetDragOperations(MenuItemView* sender) override;
  void WriteDragData(MenuItemView* sender, OSExchangeData* data) override;
  views::View::DropCallback GetDropCallback(
      MenuItemView* menu,
      DropPosition position,
      const ui::DropTargetEvent& event) override;
  bool AreDropTypesRequired(MenuItemView* menu) override;
  bool GetDropFormats(views::MenuItemView* menu,
                      int* formats,
                      std::set<ui::ClipboardFormatType>* format_types) override;
  bool ShouldCloseOnDragDropCompleted() override;
  bool IsCommandEnabled(int id) const override;
  bool IsItemChecked(int id) const override;
  void ExecuteCommand(int id) override;

 private:
  struct Model {
    int command_id;
    int message_id;
    views::MenuItemView::Type type;
  };

  // Gets the clipboard format type for draggable menu items. It is only a
  // format type used in this example, and should not be used in production.
  static ui::ClipboardFormatType MenuItemClipboardFormatType();

  void BuildMenuItems(views::MenuItemView* menu);

  // Moves the model element at `from` to `to`. If `before` is true, the
  // element is moved before `to`, otherwise after.
  void MoveModelElement(size_t from, size_t to, bool before);
  void PerformDrop(MenuItemView* menu,
                   DropPosition position,
                   const ui::DropTargetEvent& event,
                   ui::mojom::DragOperation& output_drag_op,
                   std::unique_ptr<ui::LayerTreeOwner> drag_image_layer_owner);

  std::vector<Model> models_;
  CommandExecutor executor_{nullptr};
};

}  // namespace views::examples

DEFINE_VIEW_BUILDER(/* no export */, views::examples::ExampleMenuButton)

namespace views::examples {

void CommandExecutor::ExecuteCommand(int command_id, int event_flags) {
  switch (command_id) {
    case COMMAND_DO_SOMETHING: {
      PrintStatus("Done something");
      break;
    }
    case COMMAND_SECONDARY_LABEL_DEMO: {
      PrintStatus("Done something with secondary label");
      break;
    }
    case COMMAND_MINOR_LABEL_DEMO: {
      PrintStatus("Done something with minor label");
      break;
    }

    // Radio items.
    case COMMAND_SELECT_ASCII: {
      current_encoding_command_id_ = COMMAND_SELECT_ASCII;
      PrintStatus("Selected ASCII");
      break;
    }
    case COMMAND_SELECT_UTF8: {
      current_encoding_command_id_ = COMMAND_SELECT_UTF8;
      PrintStatus("Selected UTF-8");
      break;
    }
    case COMMAND_SELECT_UTF16: {
      current_encoding_command_id_ = COMMAND_SELECT_UTF16;
      PrintStatus("Selected UTF-16");
      break;
    }

    // Check items.
    case COMMAND_CHECK_APPLE:
    case COMMAND_CHECK_ORANGE:
    case COMMAND_CHECK_KIWI: {
      // Print what fruit is checked.
      const char* checked_fruit = "";
      if (command_id == COMMAND_CHECK_APPLE) {
        checked_fruit = "Apple";
      } else if (command_id == COMMAND_CHECK_ORANGE) {
        checked_fruit = "Orange";
      } else if (command_id == COMMAND_CHECK_KIWI) {
        checked_fruit = "Kiwi";
      }

      // Update the check status.
      auto iter = checked_fruits_.find(command_id);
      if (iter == checked_fruits_.end()) {
        PrintStatus(std::string("Checked ") + checked_fruit);
        checked_fruits_.insert(command_id);
      } else {
        PrintStatus(std::string("Unchecked ") + checked_fruit);
        checked_fruits_.erase(iter);
      }
      break;
    }

    // Select Items.
    case COMMAND_SELECT_ITEM_2:
    case COMMAND_SELECT_ITEM_3: {
      if (!menu_model_) {
        break;
      }
      ui::SimpleMenuModel* sub_menu = static_cast<ui::SimpleMenuModel*>(
          menu_model_->GetSubmenuModelAt(menu_model_->GetItemCount() - 1));
      CHECK(sub_menu);
      auto index = sub_menu->GetIndexOfCommandId(command_id);
      CHECK(index.has_value());
      sub_menu->SetMinorIcon(
          index.value(),
          ui::ImageModel::FromVectorIcon(views::kCheckboxCheckCr2023OldIcon));
      PrintStatus(std::string("Selected Item ") +
                  (command_id == COMMAND_SELECT_ITEM_2 ? "2" : "3"));
      break;
    }
  }
}

CommandExecutor::CommandExecutor(ui::SimpleMenuModel* menu_model)
    : menu_model_(menu_model) {}

CommandExecutor::~CommandExecutor() = default;

bool CommandExecutor::IsCommandIdChecked(int command_id) const {
  // Radio items.
  if (command_id == current_encoding_command_id_) {
    return true;
  }

  // Check items.
  if (checked_fruits_.find(command_id) != checked_fruits_.end()) {
    return true;
  }

  return false;
}

bool CommandExecutor::IsCommandIdEnabled(int command_id) const {
  // All commands are enabled except for COMMAND_GO_HOME.
  return command_id != COMMAND_GO_HOME;
}

// ExampleMenuModel ---------------------------------------------------------

ExampleMenuModel::ExampleMenuModel() : ui::SimpleMenuModel(this) {
  AddItem(COMMAND_DO_SOMETHING, GetStringUTF16(IDS_MENU_DO_SOMETHING_LABEL));
  AddItem(COMMAND_SECONDARY_LABEL_DEMO, u"Item with secondary label");
  SetSecondaryLabel(GetItemCount() - 1, u"secondary label");
  AddItem(COMMAND_MINOR_LABEL_DEMO, u"Item with minor label");
  SetMinorText(GetItemCount() - 1, u"minor label");
  AddSeparator(ui::NORMAL_SEPARATOR);
  AddRadioItem(COMMAND_SELECT_ASCII, GetStringUTF16(IDS_MENU_ASCII_LABEL),
               GROUP_MAKE_DECISION);
  AddRadioItem(COMMAND_SELECT_UTF8, GetStringUTF16(IDS_MENU_UTF8_LABEL),
               GROUP_MAKE_DECISION);
  AddRadioItem(COMMAND_SELECT_UTF16, GetStringUTF16(IDS_MENU_UTF16_LABEL),
               GROUP_MAKE_DECISION);
  AddSeparator(ui::NORMAL_SEPARATOR);
  AddCheckItem(COMMAND_CHECK_APPLE, GetStringUTF16(IDS_MENU_APPLE_LABEL));
  AddCheckItem(COMMAND_CHECK_ORANGE, GetStringUTF16(IDS_MENU_ORANGE_LABEL));
  AddCheckItem(COMMAND_CHECK_KIWI, GetStringUTF16(IDS_MENU_KIWI_LABEL));
  AddSeparator(ui::NORMAL_SEPARATOR);
  AddItem(COMMAND_GO_HOME, GetStringUTF16(IDS_MENU_GO_HOME_LABEL));

  submenu_ = std::make_unique<ui::SimpleMenuModel>(this);
  submenu_->AddItem(COMMAND_DO_SOMETHING,
                    GetStringUTF16(IDS_MENU_DO_SOMETHING_2_LABEL));
  submenu_->AddItem(COMMAND_SELECT_ITEM_2, u"Sub Item #2");
  submenu_->SetMinorIcon(
      submenu_->GetItemCount() - 1,
      ui::ImageModel::FromVectorIcon(views::kCheckboxCheckCr2023OldIcon));
  submenu_->SetMinorIconOnRight(ui::SimpleMenuModel::MinorIconOnRightPasskey(
                                    submenu_->GetItemCount() - 1),
                                true);
  submenu_->SetMinorText(submenu_->GetItemCount() - 1, u"Current tab");

  submenu_->AddItem(COMMAND_SELECT_ITEM_3, u"Sub Item #3");
  submenu_->SetMinorIcon(
      submenu_->GetItemCount() - 1,
      ui::ImageModel::FromVectorIcon(views::kMenuRadioEmptyOldIcon,
                                     ui::kColorRadioButtonForegroundUnchecked,
                                     kMenuCheckSize));
  submenu_->SetMinorIconOnRight(ui::SimpleMenuModel::MinorIconOnRightPasskey(
                                    submenu_->GetItemCount() - 1),
                                true);

  AddSubMenu(0, GetStringUTF16(IDS_MENU_SUBMENU_LABEL), submenu_.get());
}

bool ExampleMenuModel::IsCommandIdChecked(int command_id) const {
  return executor_.IsCommandIdChecked(command_id);
}

bool ExampleMenuModel::IsCommandIdEnabled(int command_id) const {
  return executor_.IsCommandIdEnabled(command_id);
}

void ExampleMenuModel::ExecuteCommand(int command_id, int event_flags) {
  executor_.ExecuteCommand(command_id, event_flags);
}

// ExampleMenuButton ---------------------------------------------------------

ExampleMenuButton::ExampleMenuButton(const std::u16string& test)
    : MenuButton(base::BindRepeating(&ExampleMenuButton::ButtonPressed,
                                     base::Unretained(this)),
                 test) {}

ExampleMenuButton::~ExampleMenuButton() = default;

void ExampleMenuButton::ButtonPressed() {
  CHECK(menu_runner_factory_);
  menu_runner_ = menu_runner_factory_->CreateMenuRunner();

  gfx::Point screen_loc;
  views::View::ConvertPointToScreen(this, &screen_loc);
  gfx::Rect bounds(screen_loc, this->size());

  menu_runner_->RunMenuAt(GetWidget()->GetTopLevelWidget(), button_controller(),
                          bounds, MenuAnchorPosition::kTopLeft,
                          ui::mojom::MenuSourceType::kNone);
}

// MenuRunnerFactory ---------------------------------------------------

MenuRunnerFactory::MenuRunnerFactory() = default;
MenuRunnerFactory::~MenuRunnerFactory() = default;

// ExampleMenuRunnerFactory --------------------------------------------

ExampleMenuRunnerFactory::ExampleMenuRunnerFactory() = default;
ExampleMenuRunnerFactory::~ExampleMenuRunnerFactory() = default;

ui::SimpleMenuModel* ExampleMenuRunnerFactory::GetMenuModel() {
  if (!menu_model_) {
    menu_model_ = std::make_unique<ExampleMenuModel>();
  }
  return menu_model_.get();
}

std::unique_ptr<views::MenuRunner>
ExampleMenuRunnerFactory::CreateMenuRunner() {
  return std::make_unique<MenuRunner>(GetMenuModel(),
                                      MenuRunner::HAS_MNEMONICS);
}

// DraggableMenuRunnerFactory -------------------------------------------------

DraggableMenuRunnerFactory::DraggableMenuRunnerFactory() = default;
DraggableMenuRunnerFactory::~DraggableMenuRunnerFactory() = default;

std::unique_ptr<views::MenuRunner>
DraggableMenuRunnerFactory::CreateMenuRunner() {
  auto menu_item_view = std::make_unique<views::MenuItemView>(this);
  menu_item_view->SetCommand(COMMAND_ROOT);

  if (models_.empty()) {
    models_.emplace_back(COMMAND_DO_SOMETHING, IDS_MENU_DO_SOMETHING_LABEL,
                         views::MenuItemView::Type::kNormal);
    models_.emplace_back(Model{.type = views::MenuItemView::Type::kSeparator});
    models_.emplace_back(COMMAND_SELECT_ASCII, IDS_MENU_ASCII_LABEL,
                         views::MenuItemView::Type::kRadio);
    models_.emplace_back(COMMAND_SELECT_UTF8, IDS_MENU_UTF8_LABEL,
                         views::MenuItemView::Type::kRadio);
    models_.emplace_back(COMMAND_SELECT_UTF16, IDS_MENU_UTF16_LABEL,
                         views::MenuItemView::Type::kRadio);
    models_.emplace_back(Model{.type = views::MenuItemView::Type::kSeparator});
    models_.emplace_back(COMMAND_CHECK_APPLE, IDS_MENU_APPLE_LABEL,
                         views::MenuItemView::Type::kCheckbox);
    models_.emplace_back(COMMAND_CHECK_ORANGE, IDS_MENU_ORANGE_LABEL,
                         views::MenuItemView::Type::kCheckbox);
    models_.emplace_back(COMMAND_CHECK_KIWI, IDS_MENU_KIWI_LABEL,
                         views::MenuItemView::Type::kCheckbox);
    models_.emplace_back(Model{.type = views::MenuItemView::Type::kSeparator});
    models_.emplace_back(COMMAND_GO_HOME, IDS_MENU_GO_HOME_LABEL,
                         views::MenuItemView::Type::kNormal);
  }
  BuildMenuItems(menu_item_view.get());
  return std::make_unique<MenuRunner>(std::move(menu_item_view),
                                      MenuRunner::HAS_MNEMONICS);
}

bool DraggableMenuRunnerFactory::CanDrag(views::MenuItemView* menu) {
  if (menu->GetType() == views::MenuItemView::Type::kSeparator) {
    return false;
  }

  return true;
}

bool DraggableMenuRunnerFactory::CanDrop(views::MenuItemView* menu,
                                         const OSExchangeData& data) {
  return data.HasCustomFormat(MenuItemClipboardFormatType());
}

ui::mojom::DragOperation DraggableMenuRunnerFactory::GetDropOperation(
    MenuItemView* item,
    const ui::DropTargetEvent& event,
    DropPosition* position) {
  return ui::mojom::DragOperation::kMove;
}

int DraggableMenuRunnerFactory::GetDragOperations(MenuItemView* sender) {
  return ui::DragDropTypes::DRAG_MOVE;
}

void DraggableMenuRunnerFactory::WriteDragData(MenuItemView* sender,
                                               OSExchangeData* data) {
  // Simply write the command ID of the menu item to be moved.
  base::Pickle pickle;
  pickle.WriteInt(sender->GetCommand());
  data->SetPickledData(MenuItemClipboardFormatType(), pickle);
}

views::View::DropCallback DraggableMenuRunnerFactory::GetDropCallback(
    MenuItemView* menu,
    DropPosition position,
    const ui::DropTargetEvent& event) {
  return base::BindOnce(&DraggableMenuRunnerFactory::PerformDrop,
                        base::Unretained(this), menu, position);
}

bool DraggableMenuRunnerFactory::AreDropTypesRequired(MenuItemView* menu) {
  return true;
}

bool DraggableMenuRunnerFactory::GetDropFormats(
    views::MenuItemView* menu,
    int* formats,
    std::set<ui::ClipboardFormatType>* format_types) {
  format_types->insert(MenuItemClipboardFormatType());
  return true;
}

bool DraggableMenuRunnerFactory::ShouldCloseOnDragDropCompleted() {
  return false;
}

bool DraggableMenuRunnerFactory::IsCommandEnabled(int id) const {
  return executor_.IsCommandIdEnabled(id);
}
bool DraggableMenuRunnerFactory::IsItemChecked(int id) const {
  return executor_.IsCommandIdChecked(id);
}

void DraggableMenuRunnerFactory::ExecuteCommand(int id) {
  executor_.ExecuteCommand(id, 0);
}

void DraggableMenuRunnerFactory::BuildMenuItems(views::MenuItemView* menu) {
  CHECK(menu);
  if (menu->HasSubmenu()) {
    menu->RemoveAllMenuItems();
  }

  size_t index = 0u;
  for (const auto& model : models_) {
    menu->AddMenuItemAt(
        index++, model.command_id,
        model.message_id ? GetStringUTF16(model.message_id) : std::u16string(),
        std::u16string(), std::u16string(), ui::ImageModel(), ui::ImageModel(),
        model.type, ui::NORMAL_SEPARATOR, std::nullopt, std::nullopt,
        std::nullopt);
  }
  menu->InvalidateLayout();
}

void DraggableMenuRunnerFactory::MoveModelElement(size_t from,
                                                  size_t to,
                                                  bool before) {
  if (from == to) {
    return;
  }

  CHECK(from < models_.size());
  Model model = models_[from];

  if (before) {
    if (from < to) {
      models_.insert(models_.begin() + to, model);
      models_.erase(models_.begin() + from);
    } else {
      models_.erase(models_.begin() + from);
      models_.insert(models_.begin() + to, model);
    }
  } else {
    if (to >= models_.size()) {
      models_.push_back(model);
      models_.erase(models_.begin() + from);
    } else if (from < to) {
      models_.insert(models_.begin() + to + 1, model);
      models_.erase(models_.begin() + from);
    } else {
      models_.erase(models_.begin() + from);
      models_.insert(models_.begin() + to + 1, model);
    }
  }
}

void DraggableMenuRunnerFactory::PerformDrop(
    MenuItemView* menu,
    DropPosition position,
    const ui::DropTargetEvent& event,
    ui::mojom::DragOperation& output_drag_op,
    std::unique_ptr<ui::LayerTreeOwner> drag_image_layer_owner) {
  output_drag_op = ui::mojom::DragOperation::kNone;

  // Get the command ID of the menu item to be moved.
  std::optional<base::Pickle> pickle =
      event.data().GetPickledData(MenuItemClipboardFormatType());
  CHECK(pickle);
  int command_id;
  CHECK(base::PickleIterator(*pickle).ReadInt(&command_id));
  if (command_id == menu->GetCommand()) {
    PrintStatus("The menu item needn't be moved");
    return;
  }

  // Get the index of the drop target menu item.
  auto* parent_menu_item = menu->GetParentMenuItem();
  CHECK(parent_menu_item);
  auto* parent_submenu = parent_menu_item->GetSubmenu();
  CHECK(parent_submenu);

  // Get the index of the dragged menu item.
  auto* dragged_item = parent_menu_item->GetMenuItemByID(command_id);
  CHECK(dragged_item);
  auto drag_index = parent_submenu->GetIndexOf(dragged_item);
  CHECK(drag_index);

  // Get the index of the drop target menu item.
  auto drop_index = parent_submenu->GetIndexOf(menu);
  CHECK(drop_index);

  // Calculate the index to move the dragged menu item.
  if (position == DropPosition::kBefore || position == DropPosition::kAfter) {
    const size_t index_from = *drag_index;
    const size_t index_to = *drop_index;
    MoveModelElement(index_from, index_to, position == DropPosition::kBefore);
    BuildMenuItems(parent_menu_item);
    std::string status = base::StringPrintf(
        "Moved item %d to %d %s", index_from, index_to,
        position == DropPosition::kBefore ? "(before)" : "(after)");
    PrintStatus(status);
    output_drag_op = ui::mojom::DragOperation::kMove;
  } else {
    PrintStatus("Drop cancelled.");
  }
}

ui::ClipboardFormatType
DraggableMenuRunnerFactory::MenuItemClipboardFormatType() {
  constexpr char kDraggableItemType[] = "draggable-item-type";
  static base::NoDestructor<ui::ClipboardFormatType> type(
      ui::ClipboardFormatType::CustomPlatformType(kDraggableItemType));
  return *type;
}

MenuExample::MenuExample()
    : ExampleBase(GetStringUTF8(IDS_MENU_SELECT_LABEL).c_str()) {}

MenuExample::~MenuExample() = default;

void MenuExample::CreateExampleView(View* container) {
  container->SetLayoutManager(std::make_unique<FlexLayout>())
      ->SetInteriorMargin(gfx::Insets(10))
      .SetOrientation(LayoutOrientation::kVertical)
      .SetDefault(views::kMarginsKey, gfx::Insets(10))
      .SetCrossAxisAlignment(LayoutAlignment::kStart);

  // We add a button to open a simple menu.
  auto example_menu_button = Builder<ExampleMenuButton>()
                                 .SetText(GetStringUTF16(IDS_MENU_BUTTON_LABEL))
                                 .Build();
  example_menu_button->set_menu_runner_factory(
      std::make_unique<ExampleMenuRunnerFactory>());

  example_menu_button->SetBorder(CreatePaddedBorder(
      CreateRoundedRectBorder(1, 5, kColorMenuButtonExampleBorder),
      LayoutProvider::Get()->GetInsetsMetric(
          InsetsMetric::INSETS_LABEL_BUTTON)));

  container->AddChildView(std::move(example_menu_button));

  // We add a button to open a menu with draggable items.
  auto draggable_menu_button =
      Builder<ExampleMenuButton>()
          .SetText(GetStringUTF16(IDS_DRAGGABLE_MENU_BUTTON_LABEL))
          .Build();
  draggable_menu_button->set_menu_runner_factory(
      std::make_unique<DraggableMenuRunnerFactory>());

  draggable_menu_button->SetBorder(CreatePaddedBorder(
      CreateRoundedRectBorder(1, 5, kColorMenuButtonExampleBorder),
      LayoutProvider::Get()->GetInsetsMetric(
          InsetsMetric::INSETS_LABEL_BUTTON)));

  container->AddChildView(std::move(draggable_menu_button));
}

}  // namespace views::examples
