diff options
Diffstat (limited to 'chrome/browser/chromeos/status/caps_lock_menu_button.cc')
-rw-r--r-- | chrome/browser/chromeos/status/caps_lock_menu_button.cc | 168 |
1 files changed, 159 insertions, 9 deletions
diff --git a/chrome/browser/chromeos/status/caps_lock_menu_button.cc b/chrome/browser/chromeos/status/caps_lock_menu_button.cc index 9b32dbc..a4a8c6c 100644 --- a/chrome/browser/chromeos/status/caps_lock_menu_button.cc +++ b/chrome/browser/chromeos/status/caps_lock_menu_button.cc @@ -6,6 +6,7 @@ #include <string> +#include "base/utf_string_conversions.h" #include "chrome/browser/chromeos/input_method/xkeyboard.h" #include "chrome/browser/prefs/pref_service.h" #include "chrome/browser/profiles/profile.h" @@ -15,9 +16,26 @@ #include "grit/theme_resources.h" #include "ui/base/l10n/l10n_util.h" #include "ui/base/resource/resource_bundle.h" +#include "ui/gfx/canvas.h" +#include "ui/gfx/canvas_skia.h" +#include "ui/gfx/font.h" +#include "views/controls/menu/menu_item_view.h" +#include "views/controls/menu/menu_runner.h" +#include "views/controls/menu/submenu_view.h" +#include "views/widget/widget.h" namespace { +// Spacing between lines of text. +const int kSpacing = 3; +// Width and height of the image. +const int kImageWidth = 22, kImageHeight = 21; +// Constants for status displayed when user clicks button. +// Padding around status. +const int kPadLeftX = 10, kPadRightX = 10, kPadY = 5; +// Padding between image and text. +const int kTextPadX = 10; + // Returns PrefService object associated with |host|. PrefService* GetPrefService(chromeos::StatusAreaHost* host) { if (host->GetProfile()) @@ -29,19 +47,108 @@ PrefService* GetPrefService(chromeos::StatusAreaHost* host) { namespace chromeos { +class CapsLockMenuButton::StatusView : public View { + public: + explicit StatusView(CapsLockMenuButton* menu_button) + : menu_button_(menu_button), + font_(ResourceBundle::GetSharedInstance().GetFont( + ResourceBundle::BaseFont)) { + } + + virtual ~StatusView() { + } + + gfx::Size GetPreferredSize() { + // TODO(yusukes): For better string localization, we should use either + // IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SHIFT_KEYS or + // IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SEARCH here instead of just + // concatenating IDS_STATUSBAR_CAPS_LOCK_ENABLED and GetText(). Find a good + // way to break the long text into lines and stop concatenating strings. + const string16 first_line_text = l10n_util::GetStringUTF16( + IDS_STATUSBAR_CAPS_LOCK_ENABLED); + const string16 second_line_text = menu_button_->GetText(); + + int first_line_width = 0; + int second_line_width = 0; + int height = 0; + gfx::CanvasSkia::SizeStringInt( + first_line_text, font_, &first_line_width, &height, 0); + gfx::CanvasSkia::SizeStringInt( + second_line_text, font_, &second_line_width, &height, 0); + + const gfx::Size size = gfx::Size( + kPadLeftX + kImageWidth + kTextPadX + kPadRightX + + std::max(first_line_width, second_line_width), + (2 * kPadY) + + std::max(kImageHeight, kSpacing + (2 * font_.GetHeight()))); + return size; + } + + void Update() { + PreferredSizeChanged(); + // Force a paint even if the size didn't change. + SchedulePaint(); + } + + protected: + void OnPaint(gfx::Canvas* canvas) { + SkBitmap* image = + ResourceBundle::GetSharedInstance().GetBitmapNamed(IDR_CAPS_LOCK_ICON); + const int image_x = kPadLeftX; + const int image_y = (height() - image->height()) / 2; + canvas->DrawBitmapInt(*image, image_x, image_y); + + const string16 first_line_text = l10n_util::GetStringUTF16( + IDS_STATUSBAR_CAPS_LOCK_ENABLED); + const string16 second_line_text = menu_button_->GetText(); + + const int text_height = font_.GetHeight(); + const int text_x = image_x + kImageWidth + kTextPadX; + const int first_line_text_y = + (height() - (kSpacing + (2 * text_height))) / 2; + const int second_line_text_y = first_line_text_y + text_height + kSpacing; + canvas->DrawStringInt(first_line_text, font_, SK_ColorBLACK, + text_x, first_line_text_y, + width() - text_x, text_height, + gfx::Canvas::TEXT_ALIGN_LEFT); + canvas->DrawStringInt(second_line_text, font_, SK_ColorBLACK, + text_x, second_line_text_y, + width() - text_x, text_height, + gfx::Canvas::TEXT_ALIGN_LEFT); + } + + bool OnMousePressed(const views::MouseEvent& event) { + return true; + } + + void OnMouseReleased(const views::MouseEvent& event) { + if (event.IsLeftMouseButton()) { + DCHECK(menu_button_->menu_runner_.get()); + menu_button_->menu_runner_->Cancel(); + } + } + + private: + CapsLockMenuButton* menu_button_; + gfx::Font font_; + + DISALLOW_COPY_AND_ASSIGN(StatusView); +}; + //////////////////////////////////////////////////////////////////////////////// // CapsLockMenuButton CapsLockMenuButton::CapsLockMenuButton(StatusAreaHost* host) : StatusAreaButton(host, this), - prefs_(GetPrefService(host)) { + prefs_(GetPrefService(host)), + status_(NULL) { if (prefs_) remap_search_key_to_.Init( prefs::kLanguageXkbRemapSearchKeyTo, prefs_, this); SetIcon(*ResourceBundle::GetSharedInstance().GetBitmapNamed( IDR_STATUSBAR_CAPS_LOCK)); - UpdateTooltip(); + UpdateAccessibleName(); UpdateUIFromCurrentCapsLock(input_method::XKeyboard::CapsLockIsEnabled()); if (SystemKeyEventListener::GetInstance()) SystemKeyEventListener::GetInstance()->AddCapsLockObserver(this); @@ -62,9 +169,41 @@ void CapsLockMenuButton::OnLocaleChanged() { //////////////////////////////////////////////////////////////////////////////// // views::ViewMenuDelegate implementation: -void CapsLockMenuButton::RunMenu(views::View* unused_source, - const gfx::Point& pt) { - // This button is just an indicator, and therefore does not have a menu. +string16 CapsLockMenuButton::GetLabel(int id) const { + return string16(); +} + +bool CapsLockMenuButton::IsCommandEnabled(int id) const { + return false; +} + +void CapsLockMenuButton::RunMenu(views::View* source, const gfx::Point& pt) { + static const int kDummyCommandId = 1000; + + views::MenuItemView* menu = new views::MenuItemView(this); + // MenuRunner takes ownership of |menu|. + menu_runner_.reset(new views::MenuRunner(menu)); + views::MenuItemView* submenu = menu->AppendMenuItem( + kDummyCommandId, + L"", + views::MenuItemView::NORMAL); + status_ = new CapsLockMenuButton::StatusView(this); + submenu->AddChildView(status_); + menu->CreateSubmenu()->set_resize_open_menu(true); + menu->SetMargins(0, 0); + submenu->SetMargins(0, 0); + menu->ChildrenChanged(); + + gfx::Point screen_location; + views::View::ConvertPointToScreen(source, &screen_location); + gfx::Rect bounds(screen_location, source->size()); + if (menu_runner_->RunMenuAt( + source->GetWidget()->GetTopLevelWidget(), this, bounds, + views::MenuItemView::TOPRIGHT, views::MenuRunner::HAS_MNEMONICS) == + views::MenuRunner::MENU_DELETED) + return; + status_ = NULL; + menu_runner_.reset(NULL); } //////////////////////////////////////////////////////////////////////////////// @@ -81,19 +220,30 @@ void CapsLockMenuButton::Observe(int type, const NotificationSource& source, const NotificationDetails& details) { if (type == chrome::NOTIFICATION_PREF_CHANGED) - UpdateTooltip(); + UpdateAccessibleName(); } -void CapsLockMenuButton::UpdateTooltip() { - int id = IDS_STATUSBAR_CAPS_LOCK_ENABLED; +void CapsLockMenuButton::UpdateAccessibleName() { + int id = IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SHIFT_KEYS; if (prefs_ && (remap_search_key_to_.GetValue() == input_method::kCapsLockKey)) id = IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SEARCH; - SetTooltipText(l10n_util::GetStringUTF16(id)); SetAccessibleName(l10n_util::GetStringUTF16(id)); } +string16 CapsLockMenuButton::GetText() const { + int id = IDS_STATUSBAR_PRESS_SHIFT_KEYS; + if (prefs_ && (remap_search_key_to_.GetValue() == input_method::kCapsLockKey)) + id = IDS_STATUSBAR_PRESS_SEARCH; + return l10n_util::GetStringUTF16(id); +} + void CapsLockMenuButton::UpdateUIFromCurrentCapsLock(bool enabled) { SetVisible(enabled); + SchedulePaint(); + if (enabled && status_) + status_->Update(); + if (!enabled && menu_runner_.get()) + menu_runner_->Cancel(); } } // namespace chromeos |