Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(420)

Side by Side Diff: chrome/browser/chromeos/status/caps_lock_menu_button.cc

Issue 8330016: Implement the final UI for the CAPS LOCK indicator (part 3 of 3) (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: rebase Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « chrome/browser/chromeos/status/caps_lock_menu_button.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be 2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file. 3 // found in the LICENSE file.
4 4
5 #include "chrome/browser/chromeos/status/caps_lock_menu_button.h" 5 #include "chrome/browser/chromeos/status/caps_lock_menu_button.h"
6 6
7 #include <string> 7 #include <string>
8 8
9 #include "base/utf_string_conversions.h" 9 #include "base/utf_string_conversions.h"
10 #include "chrome/browser/chromeos/input_method/xkeyboard.h" 10 #include "chrome/browser/chromeos/input_method/xkeyboard.h"
11 #include "chrome/browser/chromeos/system/runtime_environment.h"
11 #include "chrome/browser/prefs/pref_service.h" 12 #include "chrome/browser/prefs/pref_service.h"
12 #include "chrome/browser/profiles/profile.h" 13 #include "chrome/browser/profiles/profile.h"
14 #include "chrome/browser/ui/views/bubble/bubble.h"
13 #include "chrome/common/chrome_notification_types.h" 15 #include "chrome/common/chrome_notification_types.h"
14 #include "chrome/common/pref_names.h" 16 #include "chrome/common/pref_names.h"
15 #include "grit/generated_resources.h" 17 #include "grit/generated_resources.h"
16 #include "grit/theme_resources.h" 18 #include "grit/theme_resources.h"
17 #include "ui/base/l10n/l10n_util.h" 19 #include "ui/base/l10n/l10n_util.h"
18 #include "ui/base/resource/resource_bundle.h" 20 #include "ui/base/resource/resource_bundle.h"
19 #include "ui/gfx/canvas.h" 21 #include "ui/gfx/canvas.h"
20 #include "ui/gfx/canvas_skia.h" 22 #include "ui/gfx/canvas_skia.h"
21 #include "ui/gfx/font.h" 23 #include "ui/gfx/font.h"
22 #include "views/controls/menu/menu_item_view.h" 24 #include "views/controls/menu/menu_item_view.h"
23 #include "views/controls/menu/menu_runner.h" 25 #include "views/controls/menu/menu_runner.h"
24 #include "views/controls/menu/submenu_view.h" 26 #include "views/controls/menu/submenu_view.h"
25 #include "views/widget/widget.h" 27 #include "views/widget/widget.h"
26 28
27 namespace { 29 namespace {
28 30
29 // Spacing between lines of text. 31 // Spacing between lines of text.
30 const int kSpacing = 3; 32 const int kSpacing = 3;
31 // Width and height of the image. 33 // Width and height of the image.
32 const int kImageWidth = 22, kImageHeight = 21; 34 const int kImageWidth = 22, kImageHeight = 21;
33 // Constants for status displayed when user clicks button. 35 // Constants for status displayed when user clicks button.
34 // Padding around status. 36 // Padding around status.
35 const int kPadLeftX = 10, kPadRightX = 10, kPadY = 5; 37 const int kPadLeftX = 10, kPadRightX = 10, kPadY = 5;
36 // Padding between image and text. 38 // Padding between image and text.
37 const int kTextPadX = 10; 39 const int kTextPadX = 10;
38 40
41 const size_t kMaxBubbleCount = 3;
42 const size_t kCloseBubbleTimerInSec = 5;
43
39 // Returns PrefService object associated with |host|. 44 // Returns PrefService object associated with |host|.
40 PrefService* GetPrefService(chromeos::StatusAreaHost* host) { 45 PrefService* GetPrefService(chromeos::StatusAreaHost* host) {
41 if (host->GetProfile()) 46 if (host->GetProfile())
42 return host->GetProfile()->GetPrefs(); 47 return host->GetProfile()->GetPrefs();
43 return NULL; 48 return NULL;
44 } 49 }
45 50
46 } // namespace 51 } // namespace
47 52
48 namespace chromeos { 53 namespace chromeos {
49 54
50 class CapsLockMenuButton::StatusView : public View { 55 class CapsLockMenuButton::StatusView : public View {
51 public: 56 public:
52 explicit StatusView(CapsLockMenuButton* menu_button) 57 explicit StatusView(CapsLockMenuButton* menu_button)
53 : menu_button_(menu_button), 58 : menu_button_(menu_button),
54 font_(ResourceBundle::GetSharedInstance().GetFont( 59 font_(ResourceBundle::GetSharedInstance().GetFont(
55 ResourceBundle::BaseFont)) { 60 ResourceBundle::BaseFont)) {
56 } 61 }
57 62
58 virtual ~StatusView() { 63 virtual ~StatusView() {
59 } 64 }
60 65
61 gfx::Size GetPreferredSize() { 66 virtual gfx::Size GetPreferredSize() OVERRIDE {
62 // TODO(yusukes): For better string localization, we should use either 67 // TODO(yusukes): For better string localization, we should use either
63 // IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SHIFT_KEYS or 68 // IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SHIFT_KEYS or
64 // IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SEARCH here instead of just 69 // IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SEARCH here instead of just
65 // concatenating IDS_STATUSBAR_CAPS_LOCK_ENABLED and GetText(). Find a good 70 // concatenating IDS_STATUSBAR_CAPS_LOCK_ENABLED and GetText(). Find a good
66 // way to break the long text into lines and stop concatenating strings. 71 // way to break the long text into lines and stop concatenating strings.
67 const string16 first_line_text = l10n_util::GetStringUTF16( 72 const string16 first_line_text = l10n_util::GetStringUTF16(
68 IDS_STATUSBAR_CAPS_LOCK_ENABLED); 73 IDS_STATUSBAR_CAPS_LOCK_ENABLED);
69 const string16 second_line_text = menu_button_->GetText(); 74 const string16 second_line_text = menu_button_->GetText();
70 75
71 int first_line_width = 0; 76 int first_line_width = 0;
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after
115 text_x, second_line_text_y, 120 text_x, second_line_text_y,
116 width() - text_x, text_height, 121 width() - text_x, text_height,
117 gfx::Canvas::TEXT_ALIGN_LEFT); 122 gfx::Canvas::TEXT_ALIGN_LEFT);
118 } 123 }
119 124
120 bool OnMousePressed(const views::MouseEvent& event) { 125 bool OnMousePressed(const views::MouseEvent& event) {
121 return true; 126 return true;
122 } 127 }
123 128
124 void OnMouseReleased(const views::MouseEvent& event) { 129 void OnMouseReleased(const views::MouseEvent& event) {
125 if (event.IsLeftMouseButton()) { 130 if (!event.IsLeftMouseButton())
126 DCHECK(menu_button_->menu_runner_.get()); 131 return;
127 menu_button_->menu_runner_->Cancel(); 132 if (menu_button_->IsMenuShown())
128 } 133 menu_button_->HideMenu();
134 if (menu_button_->IsBubbleShown())
135 menu_button_->HideBubble();
129 } 136 }
130 137
131 private: 138 private:
132 CapsLockMenuButton* menu_button_; 139 CapsLockMenuButton* menu_button_;
133 gfx::Font font_; 140 gfx::Font font_;
134 141
135 DISALLOW_COPY_AND_ASSIGN(StatusView); 142 DISALLOW_COPY_AND_ASSIGN(StatusView);
136 }; 143 };
137 144
138 //////////////////////////////////////////////////////////////////////////////// 145 ////////////////////////////////////////////////////////////////////////////////
139 // CapsLockMenuButton 146 // CapsLockMenuButton
140 147
141 CapsLockMenuButton::CapsLockMenuButton(StatusAreaHost* host) 148 CapsLockMenuButton::CapsLockMenuButton(StatusAreaHost* host)
142 : StatusAreaButton(host, this), 149 : StatusAreaButton(host, this),
143 prefs_(GetPrefService(host)), 150 prefs_(GetPrefService(host)),
144 status_(NULL) { 151 status_(NULL),
152 bubble_(NULL),
153 should_show_bubble_(true),
154 bubble_count_(0) {
145 if (prefs_) 155 if (prefs_)
146 remap_search_key_to_.Init( 156 remap_search_key_to_.Init(
147 prefs::kLanguageXkbRemapSearchKeyTo, prefs_, this); 157 prefs::kLanguageXkbRemapSearchKeyTo, prefs_, this);
148 158
149 SetIcon(*ResourceBundle::GetSharedInstance().GetBitmapNamed( 159 SetIcon(*ResourceBundle::GetSharedInstance().GetBitmapNamed(
150 IDR_STATUSBAR_CAPS_LOCK)); 160 IDR_STATUSBAR_CAPS_LOCK));
151 UpdateAccessibleName(); 161 UpdateAccessibleName();
152 UpdateUIFromCurrentCapsLock(input_method::XKeyboard::CapsLockIsEnabled()); 162 UpdateUIFromCurrentCapsLock(input_method::XKeyboard::CapsLockIsEnabled());
153 if (SystemKeyEventListener::GetInstance()) 163 if (SystemKeyEventListener::GetInstance())
154 SystemKeyEventListener::GetInstance()->AddCapsLockObserver(this); 164 SystemKeyEventListener::GetInstance()->AddCapsLockObserver(this);
(...skipping 18 matching lines...) Expand all
173 return string16(); 183 return string16();
174 } 184 }
175 185
176 bool CapsLockMenuButton::IsCommandEnabled(int id) const { 186 bool CapsLockMenuButton::IsCommandEnabled(int id) const {
177 return false; 187 return false;
178 } 188 }
179 189
180 void CapsLockMenuButton::RunMenu(views::View* source, const gfx::Point& pt) { 190 void CapsLockMenuButton::RunMenu(views::View* source, const gfx::Point& pt) {
181 static const int kDummyCommandId = 1000; 191 static const int kDummyCommandId = 1000;
182 192
193 if (IsBubbleShown())
194 HideBubble();
195
183 views::MenuItemView* menu = new views::MenuItemView(this); 196 views::MenuItemView* menu = new views::MenuItemView(this);
184 // MenuRunner takes ownership of |menu|. 197 // MenuRunner takes ownership of |menu|.
185 menu_runner_.reset(new views::MenuRunner(menu)); 198 menu_runner_.reset(new views::MenuRunner(menu));
186 views::MenuItemView* submenu = menu->AppendMenuItem( 199 views::MenuItemView* submenu = menu->AppendMenuItem(
187 kDummyCommandId, 200 kDummyCommandId,
188 L"", 201 L"",
189 views::MenuItemView::NORMAL); 202 views::MenuItemView::NORMAL);
190 status_ = new CapsLockMenuButton::StatusView(this); 203 status_ = new CapsLockMenuButton::StatusView(this);
191 submenu->AddChildView(status_); 204 submenu->AddChildView(status_);
192 menu->CreateSubmenu()->set_resize_open_menu(true); 205 menu->CreateSubmenu()->set_resize_open_menu(true);
(...skipping 10 matching lines...) Expand all
203 views::MenuRunner::MENU_DELETED) 216 views::MenuRunner::MENU_DELETED)
204 return; 217 return;
205 status_ = NULL; 218 status_ = NULL;
206 menu_runner_.reset(NULL); 219 menu_runner_.reset(NULL);
207 } 220 }
208 221
209 //////////////////////////////////////////////////////////////////////////////// 222 ////////////////////////////////////////////////////////////////////////////////
210 // SystemKeyEventListener::CapsLockObserver implementation 223 // SystemKeyEventListener::CapsLockObserver implementation
211 224
212 void CapsLockMenuButton::OnCapsLockChange(bool enabled) { 225 void CapsLockMenuButton::OnCapsLockChange(bool enabled) {
226 if (!enabled && !HasCapsLock() && bubble_count_ > 0) {
227 // Both shift keys are pressed. We can assume that the user now recognizes
228 // how to turn off Caps Lock.
229 should_show_bubble_ = false;
230 }
231
232 // Update the indicator.
213 UpdateUIFromCurrentCapsLock(enabled); 233 UpdateUIFromCurrentCapsLock(enabled);
234
235 // Update the drop-down menu and bubble. Since the constructor also calls
236 // UpdateUIFromCurrentCapsLock, we shouldn't do this in the function.
237 if (enabled && IsMenuShown())
238 status_->Update(); // Update the drop-down menu if it's already shown.
239 else if (!enabled && IsMenuShown())
240 HideMenu();
241 if (enabled)
242 MaybeShowBubble();
243 else if (!enabled && IsBubbleShown())
244 HideBubble();
214 } 245 }
215 246
216 //////////////////////////////////////////////////////////////////////////////// 247 ////////////////////////////////////////////////////////////////////////////////
217 // content::NotificationObserver implementation 248 // content::NotificationObserver implementation
218 249
219 void CapsLockMenuButton::Observe(int type, 250 void CapsLockMenuButton::Observe(int type,
220 const content::NotificationSource& source, 251 const content::NotificationSource& source,
221 const content::NotificationDetails& details) { 252 const content::NotificationDetails& details) {
222 if (type == chrome::NOTIFICATION_PREF_CHANGED) 253 if (type == chrome::NOTIFICATION_PREF_CHANGED)
223 UpdateAccessibleName(); 254 UpdateAccessibleName();
224 } 255 }
225 256
226 void CapsLockMenuButton::UpdateAccessibleName() { 257 void CapsLockMenuButton::UpdateAccessibleName() {
227 int id = IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SHIFT_KEYS; 258 int id = IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SHIFT_KEYS;
228 if (prefs_ && (remap_search_key_to_.GetValue() == input_method::kCapsLockKey)) 259 if (HasCapsLock())
229 id = IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SEARCH; 260 id = IDS_STATUSBAR_CAPS_LOCK_ENABLED_PRESS_SEARCH;
230 SetAccessibleName(l10n_util::GetStringUTF16(id)); 261 SetAccessibleName(l10n_util::GetStringUTF16(id));
231 } 262 }
232 263
233 string16 CapsLockMenuButton::GetText() const { 264 string16 CapsLockMenuButton::GetText() const {
234 int id = IDS_STATUSBAR_PRESS_SHIFT_KEYS; 265 int id = IDS_STATUSBAR_PRESS_SHIFT_KEYS;
235 if (prefs_ && (remap_search_key_to_.GetValue() == input_method::kCapsLockKey)) 266 if (HasCapsLock())
236 id = IDS_STATUSBAR_PRESS_SEARCH; 267 id = IDS_STATUSBAR_PRESS_SEARCH;
237 return l10n_util::GetStringUTF16(id); 268 return l10n_util::GetStringUTF16(id);
238 } 269 }
239 270
240 void CapsLockMenuButton::UpdateUIFromCurrentCapsLock(bool enabled) { 271 void CapsLockMenuButton::UpdateUIFromCurrentCapsLock(bool enabled) {
241 SetVisible(enabled); 272 SetVisible(enabled);
242 SchedulePaint(); 273 SchedulePaint();
243 if (enabled && status_) 274 }
244 status_->Update(); 275
245 if (!enabled && menu_runner_.get()) 276 bool CapsLockMenuButton::IsMenuShown() const {
246 menu_runner_->Cancel(); 277 return menu_runner_.get() && status_;
278 }
279
280 void CapsLockMenuButton::HideMenu() {
281 if (!IsMenuShown())
282 return;
283 menu_runner_->Cancel();
284 }
285
286 bool CapsLockMenuButton::IsBubbleShown() const {
287 return bubble_;
288 }
289
290 void CapsLockMenuButton::MaybeShowBubble() {
291 if (IsBubbleShown() ||
292 // We've already shown the bubble |kMaxBubbleCount| times.
293 !should_show_bubble_ ||
294 // Don't show the bubble when Caps Lock key is available.
295 HasCapsLock())
296 return;
297
298 ++bubble_count_;
299 if (bubble_count_ > kMaxBubbleCount) {
300 should_show_bubble_ = false;
301 } else {
302 CreateAndShowBubble();
303 bubble_timer_.Start(FROM_HERE,
304 base::TimeDelta::FromSeconds(kCloseBubbleTimerInSec),
305 this,
306 &CapsLockMenuButton::HideBubble);
307 }
308 }
309
310 void CapsLockMenuButton::CreateAndShowBubble() {
311 if (IsBubbleShown()) {
312 NOTREACHED();
313 return;
314 }
315
316 gfx::Rect button_bounds = GetScreenBounds();
317 button_bounds.set_y(button_bounds.y() + 1); // See login/message_bubble.cc.
318
319 bubble_ = Bubble::ShowFocusless(GetWidget(),
320 button_bounds,
321 views::BubbleBorder::TOP_RIGHT,
322 new CapsLockMenuButton::StatusView(this),
323 NULL /* no delegate */,
324 true /* show_while_screen_is_locked */);
325 }
326
327 void CapsLockMenuButton::HideBubble() {
328 if (!IsBubbleShown())
329 return;
330 bubble_timer_.Stop(); // no-op if it's not running.
331 bubble_->Close();
332 bubble_ = NULL;
333 }
334
335 bool CapsLockMenuButton::HasCapsLock() const {
336 return (prefs_ &&
337 (remap_search_key_to_.GetValue() == input_method::kCapsLockKey)) ||
338 // A keyboard for Linux usually has Caps Lock.
339 !system::runtime_environment::IsRunningOnChromeOS();
247 } 340 }
248 341
249 } // namespace chromeos 342 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/status/caps_lock_menu_button.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698