| // Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "ui/views/touchui/touch_editing_menu.h" |
| |
| #include "base/strings/utf_string_conversions.h" |
| #include "ui/base/l10n/l10n_util.h" |
| #include "ui/base/resource/resource_bundle.h" |
| #include "ui/gfx/canvas.h" |
| #include "ui/gfx/font_list.h" |
| #include "ui/gfx/insets.h" |
| #include "ui/gfx/text_utils.h" |
| #include "ui/strings/grit/ui_strings.h" |
| #include "ui/views/bubble/bubble_border.h" |
| #include "ui/views/bubble/bubble_frame_view.h" |
| #include "ui/views/controls/button/custom_button.h" |
| #include "ui/views/controls/button/label_button.h" |
| #include "ui/views/controls/button/label_button_border.h" |
| #include "ui/views/layout/box_layout.h" |
| #include "ui/views/widget/widget.h" |
| |
| namespace { |
| |
| const int kMenuCommands[] = {IDS_APP_CUT, |
| IDS_APP_COPY, |
| IDS_APP_PASTE}; |
| const int kSpacingBetweenButtons = 2; |
| const int kButtonSeparatorColor = SkColorSetARGB(13, 0, 0, 0); |
| const int kMenuButtonHeight = 38; |
| const int kMenuButtonWidth = 63; |
| const int kMenuMargin = 1; |
| |
| const char* kEllipsesButtonText = "..."; |
| const int kEllipsesButtonTag = -1; |
| } // namespace |
| |
| namespace views { |
| |
| TouchEditingMenuView::TouchEditingMenuView( |
| TouchEditingMenuController* controller, |
| const gfx::Rect& anchor_rect, |
| const gfx::Size& handle_image_size, |
| gfx::NativeView context) |
| : BubbleDelegateView(NULL, views::BubbleBorder::BOTTOM_CENTER), |
| controller_(controller) { |
| set_shadow(views::BubbleBorder::SMALL_SHADOW); |
| set_parent_window(context); |
| set_margins(gfx::Insets(kMenuMargin, kMenuMargin, kMenuMargin, kMenuMargin)); |
| set_can_activate(false); |
| set_adjust_if_offscreen(true); |
| |
| SetLayoutManager(new BoxLayout(BoxLayout::kHorizontal, 0, 0, |
| kSpacingBetweenButtons)); |
| CreateButtons(); |
| |
| // After buttons are created, check if there is enough room between handles to |
| // show the menu and adjust anchor rect properly if needed, just in case the |
| // menu is needed to be shown under the selection. |
| gfx::Rect adjusted_anchor_rect(anchor_rect); |
| int menu_width = GetPreferredSize().width(); |
| if (menu_width > anchor_rect.width() - handle_image_size.width()) |
| adjusted_anchor_rect.Inset(0, 0, 0, -handle_image_size.height()); |
| SetAnchorRect(adjusted_anchor_rect); |
| |
| views::BubbleDelegateView::CreateBubble(this); |
| GetWidget()->Show(); |
| } |
| |
| TouchEditingMenuView::~TouchEditingMenuView() { |
| } |
| |
| // static |
| TouchEditingMenuView* TouchEditingMenuView::Create( |
| TouchEditingMenuController* controller, |
| const gfx::Rect& anchor_rect, |
| const gfx::Size& handle_image_size, |
| gfx::NativeView context) { |
| if (controller) { |
| for (size_t i = 0; i < arraysize(kMenuCommands); i++) { |
| if (controller->IsCommandIdEnabled(kMenuCommands[i])) { |
| return new TouchEditingMenuView(controller, anchor_rect, |
| handle_image_size, context); |
| } |
| } |
| } |
| return NULL; |
| } |
| |
| void TouchEditingMenuView::Close() { |
| if (GetWidget()) { |
| controller_ = NULL; |
| GetWidget()->Close(); |
| } |
| } |
| |
| void TouchEditingMenuView::WindowClosing() { |
| views::BubbleDelegateView::WindowClosing(); |
| if (controller_) |
| controller_->OnMenuClosed(this); |
| } |
| |
| void TouchEditingMenuView::ButtonPressed(Button* sender, |
| const ui::Event& event) { |
| if (controller_) { |
| if (sender->tag() != kEllipsesButtonTag) |
| controller_->ExecuteCommand(sender->tag(), event.flags()); |
| else |
| controller_->OpenContextMenu(); |
| } |
| } |
| |
| void TouchEditingMenuView::OnPaint(gfx::Canvas* canvas) { |
| BubbleDelegateView::OnPaint(canvas); |
| |
| // Draw separator bars. |
| for (int i = 0; i < child_count() - 1; ++i) { |
| View* child = child_at(i); |
| int x = child->bounds().right() + kSpacingBetweenButtons / 2; |
| canvas->FillRect(gfx::Rect(x, 0, 1, child->height()), |
| kButtonSeparatorColor); |
| } |
| } |
| |
| void TouchEditingMenuView::CreateButtons() { |
| RemoveAllChildViews(true); |
| for (size_t i = 0; i < arraysize(kMenuCommands); i++) { |
| int command_id = kMenuCommands[i]; |
| if (controller_ && controller_->IsCommandIdEnabled(command_id)) { |
| Button* button = CreateButton(l10n_util::GetStringUTF16(command_id), |
| command_id); |
| AddChildView(button); |
| } |
| } |
| |
| // Finally, add ellipses button. |
| AddChildView(CreateButton( |
| base::UTF8ToUTF16(kEllipsesButtonText), kEllipsesButtonTag)); |
| Layout(); |
| } |
| |
| Button* TouchEditingMenuView::CreateButton(const base::string16& title, |
| int tag) { |
| base::string16 label = gfx::RemoveAcceleratorChar(title, '&', NULL, NULL); |
| LabelButton* button = new LabelButton(this, label); |
| button->SetFocusable(true); |
| button->set_request_focus_on_press(false); |
| const gfx::FontList& font_list = |
| ui::ResourceBundle::GetSharedInstance().GetFontList( |
| ui::ResourceBundle::SmallFont); |
| scoped_ptr<LabelButtonBorder> button_border( |
| new LabelButtonBorder(button->style())); |
| int v_border = (kMenuButtonHeight - font_list.GetHeight()) / 2; |
| int h_border = (kMenuButtonWidth - gfx::GetStringWidth(label, font_list)) / 2; |
| button_border->set_insets( |
| gfx::Insets(v_border, h_border, v_border, h_border)); |
| button->SetBorder(button_border.Pass()); |
| button->SetFontList(font_list); |
| button->set_tag(tag); |
| return button; |
| } |
| |
| } // namespace views |