diff options
-rw-r--r-- | chrome/app/generated_resources.grd | 13 | ||||
-rw-r--r-- | chrome/app/theme/caps_lock_icon.png | 0 | ||||
-rw-r--r-- | chrome/app/theme/theme_resources.grd | 1 | ||||
-rw-r--r-- | chrome/browser/chromeos/status/caps_lock_menu_button.cc | 168 | ||||
-rw-r--r-- | chrome/browser/chromeos/status/caps_lock_menu_button.h | 26 |
5 files changed, 195 insertions, 13 deletions
diff --git a/chrome/app/generated_resources.grd b/chrome/app/generated_resources.grd index 3ee5fb4..829e6c8 100644 --- a/chrome/app/generated_resources.grd +++ b/chrome/app/generated_resources.grd @@ -12926,10 +12926,19 @@ Keep your key file in a safe place. You will need it to create new versions of y Searching for Wi-Fi networks... </message> <message name="IDS_STATUSBAR_CAPS_LOCK_ENABLED" desc="The tooltip for the caps lock indicator button."> - CAPS LOCK is on\nPress both Shift keys to cancel + CAPS LOCK is on + </message> + <message name="IDS_STATUSBAR_PRESS_SHIFT_KEYS" desc="The tooltip for the caps lock indicator button."> + Press both Shift keys to cancel + </message> + <message name="IDS_STATUSBAR_PRESS_SEARCH" desc="The tooltip for the caps lock indicator button."> + Press Search key to cancel + </message> + <message name="IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SHIFT_KEYS" desc="The tooltip for the caps lock indicator button."> + CAPS LOCK is on. Press both Shift keys to cancel </message> <message name="IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SEARCH" desc="The tooltip for the caps lock indicator button."> - CAPS LOCK is on\nPress Search key to cancel + CAPS LOCK is on. Press Search key to cancel </message> <message name="IDS_STATUSBAR_CLOCK_OPEN_OPTIONS_DIALOG" desc="The menu item in the clock menu button for opening the options dialog"> Open date and time options... diff --git a/chrome/app/theme/caps_lock_icon.png b/chrome/app/theme/caps_lock_icon.png new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/chrome/app/theme/caps_lock_icon.png diff --git a/chrome/app/theme/theme_resources.grd b/chrome/app/theme/theme_resources.grd index f0b35c9..4b7931f 100644 --- a/chrome/app/theme/theme_resources.grd +++ b/chrome/app/theme/theme_resources.grd @@ -508,6 +508,7 @@ <include name="IDR_SHUTDOWN_ICON" file="shutdown_icon.png" type="BINDATA" /> <include name="IDR_SPINNER" file="spinner.png" type="BINDATA" /> <include name="IDR_STATUSBAR_ACCESSIBILITY" file="statusbar_accessibility.png" type="BINDATA" /> + <include name="IDR_CAPS_LOCK_ICON" file="caps_lock_icon.png" type="BINDATA" /> <include name="IDR_STATUSBAR_BATTERY_LARGE_ALL" file="statusbar_battery_large_all.png" type="BINDATA" /> <include name="IDR_STATUSBAR_BATTERY_SMALL_ALL" file="statusbar_battery_small_all.png" type="BINDATA" /> <include name="IDR_STATUSBAR_CAPS_LOCK" file="statusbar_caps_lock.png" type="BINDATA" /> 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 diff --git a/chrome/browser/chromeos/status/caps_lock_menu_button.h b/chrome/browser/chromeos/status/caps_lock_menu_button.h index 2960116..f0ca1cd 100644 --- a/chrome/browser/chromeos/status/caps_lock_menu_button.h +++ b/chrome/browser/chromeos/status/caps_lock_menu_button.h @@ -12,8 +12,13 @@ #include "chrome/browser/chromeos/system_key_event_listener.h" #include "chrome/browser/prefs/pref_member.h" #include "content/common/notification_observer.h" +#include "views/controls/menu/menu_delegate.h" #include "views/controls/menu/view_menu_delegate.h" +namespace views { +class MenuRunner; +} + namespace chromeos { class StatusAreaHost; @@ -22,6 +27,7 @@ class StatusAreaHost; // lock is active. class CapsLockMenuButton : public NotificationObserver, public StatusAreaButton, + public views::MenuDelegate, public views::ViewMenuDelegate, public SystemKeyEventListener::CapsLockObserver { public: @@ -31,6 +37,10 @@ class CapsLockMenuButton : public NotificationObserver, // views::View implementation. virtual void OnLocaleChanged(); + // views::MenuDelegate implementation. + virtual string16 GetLabel(int id) const; + virtual bool IsCommandEnabled(int id) const; + // views::ViewMenuDelegate implementation. virtual void RunMenu(views::View* unused_source, const gfx::Point& pt); @@ -42,15 +52,27 @@ class CapsLockMenuButton : public NotificationObserver, const NotificationSource& source, const NotificationDetails& details); - // Updates the tooltip text and the accessible name. - void UpdateTooltip(); + // Updates the accessible name. + void UpdateAccessibleName(); + + // Gets the text for the drop-down menu. + string16 GetText() const; + // Updates the UI from the current state. void UpdateUIFromCurrentCapsLock(bool enabled); private: + class StatusView; + PrefService* prefs_; IntegerPrefMember remap_search_key_to_; + // The currently showing status view. NULL if menu is not being displayed. + StatusView* status_; + + // If non-null the menu is showing. + scoped_ptr<views::MenuRunner> menu_runner_; + DISALLOW_COPY_AND_ASSIGN(CapsLockMenuButton); }; |