summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryusukes@chromium.org <yusukes@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-18 02:32:13 +0000
committeryusukes@chromium.org <yusukes@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2011-10-18 02:32:13 +0000
commit0db70f67b5bb0c70c45ed85a983ab9a9188445be (patch)
tree50a45524cb0fb2652916ae28377f3196053e73ae
parent4f4f3f6bdb8ac5461298923757970e071230c810 (diff)
downloadchromium_src-0db70f67b5bb0c70c45ed85a983ab9a9188445be.zip
chromium_src-0db70f67b5bb0c70c45ed85a983ab9a9188445be.tar.gz
chromium_src-0db70f67b5bb0c70c45ed85a983ab9a9188445be.tar.bz2
Implement the final UI for the CAPS LOCK indicator.
- Remove the tooltip - Insted, add a drop-down menu which looks like http://crosbug.com/11690#c18 - Split the string resource for the indicator into two since gfx canvas can not handle a string containing "\n" correctly. - The bubble in the UI mock is NOT implemented yet. BUG=chromium-os:11690 TEST=ran browser_tests Review URL: http://codereview.chromium.org/8249014 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@106006 0039d316-1c4b-4281-b951-d872f2087c98
-rw-r--r--chrome/app/generated_resources.grd13
-rw-r--r--chrome/app/theme/caps_lock_icon.png0
-rw-r--r--chrome/app/theme/theme_resources.grd1
-rw-r--r--chrome/browser/chromeos/status/caps_lock_menu_button.cc168
-rw-r--r--chrome/browser/chromeos/status/caps_lock_menu_button.h26
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);
};