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

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

Issue 10056001: chromeos: Remove old status-area related code. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years, 8 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
OLDNEW
(Empty)
1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "chrome/browser/chromeos/status/power_menu_button.h"
6
7 #include <algorithm>
8
9 #include "base/auto_reset.h"
10 #include "base/string_number_conversions.h"
11 #include "base/stringprintf.h"
12 #include "base/time.h"
13 #include "base/utf_string_conversions.h"
14 #include "chrome/browser/chromeos/status/status_area_bubble.h"
15 #include "chrome/browser/chromeos/view_ids.h"
16 #include "chromeos/dbus/dbus_thread_manager.h"
17 #include "grit/generated_resources.h"
18 #include "grit/theme_resources.h"
19 #include "ui/base/l10n/l10n_util.h"
20 #include "ui/base/resource/resource_bundle.h"
21 #include "ui/gfx/canvas.h"
22 #include "ui/gfx/font.h"
23 #include "ui/gfx/image/image.h"
24 #include "ui/views/controls/menu/menu_item_view.h"
25 #include "ui/views/controls/menu/menu_runner.h"
26 #include "ui/views/controls/menu/submenu_view.h"
27 #include "ui/views/widget/widget.h"
28
29 namespace {
30
31 // Menu item ids.
32 enum {
33 POWER_BATTERY_PERCENTAGE_ITEM = 1000,
34 POWER_BATTERY_IS_CHARGED_ITEM,
35 POWER_NO_BATTERY,
36 };
37
38 enum ImageType {
39 DISCHARGING,
40 CHARGING,
41 BOLT
42 };
43
44 enum ImageSize {
45 SMALL,
46 LARGE
47 };
48
49 // Initialize time deltas to large values so they will be replaced when set
50 // to small values.
51 const int64 kInitialMS = 0x7fffffff;
52 // Width and height of small images.
53 const int kSmallImageWidth = 26, kSmallImageHeight = 24;
54 // Width and height of large images.
55 const int kLargeImageWidth = 57, kLargeImageHeight = 35;
56 // Number of different power states.
57 const int kNumPowerImages = 20;
58
59 // Color of text embedded within battery.
60 const SkColor kPercentageColor = 0xFF333333;
61 // Used for embossing text.
62 const SkColor kPercentageShadowColor = 0x80ffffff;
63 // Size of percentage w/in battery.
64 const int kBatteryFontSizeDelta = 3;
65
66 // Battery images come from two collections (small and large). In each there
67 // are |kNumPowerImages| battery states for both on and off charge, followed
68 // by the missing battery image and the unknown image.
69 // They are layed out like this:
70 // Discharging Charging Bolt
71 // | | +
72 // || || +
73 // ...
74 // ||||| ||||| +
75 // ||X|| ||?||
76 SkBitmap GetImage(ImageSize size, ImageType type, int index) {
77 int image_width, image_height, image_index;
78
79 if (size == SMALL) {
80 image_index = IDR_STATUSBAR_BATTERY_SMALL_ALL;
81 image_width = kSmallImageWidth;
82 image_height = kSmallImageHeight;
83 } else {
84 image_index = IDR_STATUSBAR_BATTERY_LARGE_ALL;
85 image_width = kLargeImageWidth;
86 image_height = kLargeImageHeight;
87 }
88 const SkBitmap* all_images = ResourceBundle::GetSharedInstance().
89 GetImageNamed(image_index).ToSkBitmap();
90 SkIRect subset =
91 SkIRect::MakeXYWH(
92 static_cast<int>(type) * image_width,
93 index * image_height,
94 image_width,
95 image_height);
96
97 SkBitmap image;
98 all_images->extractSubset(&image, subset);
99 return image;
100 }
101
102 SkBitmap GetImageWithPercentage(ImageSize size, ImageType type,
103 double battery_percentage) {
104 // Preserve the fully charged icon for 100% only.
105 int battery_index = 0;
106 if (battery_percentage >= 100) {
107 battery_index = kNumPowerImages - 1;
108 } else {
109 battery_index = static_cast<int> (
110 battery_percentage / 100.0 *
111 nextafter(static_cast<double>(kNumPowerImages - 1), 0));
112 battery_index =
113 std::max(std::min(battery_index, kNumPowerImages - 2), 0);
114 }
115 return GetImage(size, type, battery_index);
116 }
117
118 SkBitmap GetUnknownImage(ImageSize size) {
119 return GetImage(size, CHARGING, kNumPowerImages);
120 }
121
122 class BatteryIconView : public views::View {
123 public:
124 BatteryIconView()
125 : battery_percentage_(0),
126 battery_is_present_(false),
127 line_power_on_(false),
128 percentage_font_(ResourceBundle::GetSharedInstance().
129 GetFont(ResourceBundle::BaseFont).
130 DeriveFont(kBatteryFontSizeDelta, gfx::Font::BOLD)) {
131 }
132
133 virtual gfx::Size GetPreferredSize() OVERRIDE {
134 return gfx::Size(kLargeImageWidth, kLargeImageHeight);
135 }
136
137 void set_battery_percentage(double battery_percentage) {
138 battery_percentage_ = battery_percentage;
139 SchedulePaint();
140 }
141
142 void set_battery_is_present(bool battery_is_present) {
143 battery_is_present_ = battery_is_present;
144 SchedulePaint();
145 }
146
147 void set_line_power_on(bool line_power_on) {
148 line_power_on_ = line_power_on;
149 SchedulePaint();
150 }
151
152 protected:
153 virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
154 SkBitmap image;
155 if (battery_is_present_) {
156 image = GetImageWithPercentage(LARGE,
157 line_power_on_ ? CHARGING : DISCHARGING,
158 battery_percentage_);
159 } else {
160 NOTREACHED();
161 return;
162 }
163 const int image_x = 0;
164 const int image_y = (height() - image.height()) / 2;
165 canvas->DrawBitmapInt(image, image_x, image_y);
166
167 if (battery_is_present_ && (battery_percentage_ < 100 || !line_power_on_)) {
168 const string16 text = UTF8ToUTF16(base::StringPrintf(
169 "%d%%", static_cast<int>(battery_percentage_)));
170 const int text_h = percentage_font_.GetHeight();
171 const int text_y = ((height() - text_h) / 2);
172 canvas->DrawStringInt(
173 text, percentage_font_, kPercentageShadowColor,
174 image_x, text_y + 1, image.width(), text_h,
175 gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_ELLIPSIS);
176 canvas->DrawStringInt(
177 text, percentage_font_, kPercentageColor,
178 image_x, text_y, image.width(), text_h,
179 gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_ELLIPSIS);
180 if (line_power_on_)
181 canvas->DrawBitmapInt(
182 GetImageWithPercentage(LARGE, BOLT, battery_percentage_),
183 image_x, image_y);
184 }
185 }
186
187 private:
188 double battery_percentage_;
189 bool battery_is_present_;
190 bool line_power_on_;
191 gfx::Font percentage_font_;
192
193 DISALLOW_COPY_AND_ASSIGN(BatteryIconView);
194 };
195
196 } // namespace
197
198 namespace chromeos {
199
200 using base::TimeDelta;
201
202 ////////////////////////////////////////////////////////////////////////////////
203 // PowerMenuButton
204
205 PowerMenuButton::PowerMenuButton(StatusAreaButton::Delegate* delegate)
206 : StatusAreaButton(delegate, this),
207 battery_is_present_(false),
208 line_power_on_(false),
209 battery_percentage_(0.0),
210 battery_time_to_full_(TimeDelta::FromMicroseconds(kInitialMS)),
211 battery_time_to_empty_(TimeDelta::FromMicroseconds(kInitialMS)),
212 status_(NULL) {
213 set_id(VIEW_ID_STATUS_BUTTON_POWER);
214 UpdateIconAndLabelInfo();
215 DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
216 DBusThreadManager::Get()->GetPowerManagerClient()->RequestStatusUpdate(
217 PowerManagerClient::UPDATE_INITIAL);
218 }
219
220 PowerMenuButton::~PowerMenuButton() {
221 DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
222 }
223
224 string16 PowerMenuButton::GetBatteryIsChargedText() const {
225 // The second item shows the battery is charged if it is.
226 if (battery_percentage_ >= 100 && line_power_on_)
227 return l10n_util::GetStringUTF16(IDS_STATUSBAR_BATTERY_IS_CHARGED);
228
229 // If battery is in an intermediate charge state, show how much time left.
230 TimeDelta time = line_power_on_ ? battery_time_to_full_ :
231 battery_time_to_empty_;
232 if (time.InSeconds() == 0) {
233 // If time is 0, then that means we are still calculating how much time.
234 // Depending if line power is on, we either show a message saying that we
235 // are calculating time until full or calculating remaining time.
236 int msg = line_power_on_ ?
237 IDS_STATUSBAR_BATTERY_CALCULATING_TIME_UNTIL_FULL :
238 IDS_STATUSBAR_BATTERY_CALCULATING_TIME_UNTIL_EMPTY;
239 return l10n_util::GetStringUTF16(msg);
240 } else {
241 // Depending if line power is on, we either show a message saying XX:YY
242 // until full or XX:YY remaining where XX is number of hours and YY is
243 // number of minutes.
244 int msg = line_power_on_ ? IDS_STATUSBAR_BATTERY_TIME_UNTIL_FULL :
245 IDS_STATUSBAR_BATTERY_TIME_UNTIL_EMPTY;
246 int hour = time.InHours();
247 int min = (time - TimeDelta::FromHours(hour)).InMinutes();
248 string16 hour_str = base::IntToString16(hour);
249 string16 min_str = base::IntToString16(min);
250 // Append a "0" before the minute if it's only a single digit.
251 if (min < 10)
252 min_str = ASCIIToUTF16("0") + min_str;
253 return l10n_util::GetStringFUTF16(msg, hour_str, min_str);
254 }
255 }
256
257 int PowerMenuButton::icon_width() {
258 return 26;
259 }
260
261 ////////////////////////////////////////////////////////////////////////////////
262 // PowerMenuButton, views::View implementation:
263 void PowerMenuButton::OnLocaleChanged() {
264 UpdateIconAndLabelInfo();
265 }
266
267 ////////////////////////////////////////////////////////////////////////////////
268 // PowerMenuButton, views::MenuButtonListener implementation:
269
270 void PowerMenuButton::OnMenuButtonClicked(views::View* source,
271 const gfx::Point& point) {
272 // Explicitly query the power status.
273 DBusThreadManager::Get()->GetPowerManagerClient()->RequestStatusUpdate(
274 PowerManagerClient::UPDATE_USER);
275
276 views::MenuItemView* menu = new views::MenuItemView(this);
277 // MenuRunner takes ownership of |menu|.
278 menu_runner_.reset(new views::MenuRunner(menu));
279 views::MenuItemView* submenu = menu->AppendMenuItem(
280 POWER_BATTERY_PERCENTAGE_ITEM,
281 string16(),
282 views::MenuItemView::NORMAL);
283 status_ = new StatusAreaBubbleContentView(new BatteryIconView, string16());
284 UpdateStatusView();
285 submenu->AddChildView(status_);
286 menu->CreateSubmenu()->set_resize_open_menu(true);
287 menu->SetMargins(0, 0);
288 submenu->SetMargins(0, 0);
289 menu->ChildrenChanged();
290
291 gfx::Point screen_location;
292 views::View::ConvertPointToScreen(source, &screen_location);
293 gfx::Rect bounds(screen_location, source->size());
294 if (menu_runner_->RunMenuAt(
295 source->GetWidget()->GetTopLevelWidget(), this, bounds,
296 views::MenuItemView::TOPRIGHT, views::MenuRunner::HAS_MNEMONICS) ==
297 views::MenuRunner::MENU_DELETED)
298 return;
299 status_ = NULL;
300 menu_runner_.reset(NULL);
301 }
302
303 ////////////////////////////////////////////////////////////////////////////////
304 // PowerMenuButton, PowerManagerClient::Observer implementation:
305
306 void PowerMenuButton::PowerChanged(const PowerSupplyStatus& power_status) {
307 power_status_ = power_status;
308 UpdateIconAndLabelInfo();
309 }
310
311 ////////////////////////////////////////////////////////////////////////////////
312 // PowerMenuButton, StatusAreaButton implementation:
313
314 void PowerMenuButton::UpdateIconAndLabelInfo() {
315 battery_is_present_ = power_status_.battery_is_present;
316 line_power_on_ = power_status_.line_power_on;
317
318 bool should_be_visible = battery_is_present_;
319 if (should_be_visible != visible())
320 SetVisible(should_be_visible);
321
322 if (!should_be_visible)
323 return;
324
325 // If fully charged, always show 100% even if internal number is a bit less.
326 if (power_status_.battery_is_full)
327 battery_percentage_ = 100.0;
328 else
329 battery_percentage_ = power_status_.battery_percentage;
330
331 UpdateBatteryTime(&battery_time_to_full_,
332 TimeDelta::FromSeconds(
333 power_status_.battery_seconds_to_full));
334 UpdateBatteryTime(&battery_time_to_empty_,
335 TimeDelta::FromSeconds(
336 power_status_.battery_seconds_to_empty));
337
338 SetIcon(GetImageWithPercentage(
339 SMALL, line_power_on_ ? CHARGING : DISCHARGING, battery_percentage_));
340 const int message_id = line_power_on_ ?
341 IDS_STATUSBAR_BATTERY_CHARGING_PERCENTAGE :
342 IDS_STATUSBAR_BATTERY_USING_PERCENTAGE;
343 string16 tooltip_text = l10n_util::GetStringFUTF16(
344 message_id, base::IntToString16(static_cast<int>(battery_percentage_)));
345 SetTooltipText(tooltip_text);
346 SetAccessibleName(tooltip_text);
347 SchedulePaint();
348 UpdateStatusView();
349 }
350
351 void PowerMenuButton::UpdateStatusView() {
352 if (status_) {
353 string16 charging_text;
354 if (battery_is_present_) {
355 charging_text = GetBatteryIsChargedText();
356 } else {
357 charging_text = l10n_util::GetStringUTF16(IDS_STATUSBAR_NO_BATTERY);
358 }
359 status_->SetMessage(charging_text);
360 BatteryIconView* battery_icon_view =
361 static_cast<BatteryIconView*>(status_->icon_view());
362 battery_icon_view->set_battery_percentage(battery_percentage_);
363 battery_icon_view->set_battery_is_present(battery_is_present_);
364 battery_icon_view->set_line_power_on(line_power_on_);
365 }
366 }
367
368 void PowerMenuButton::UpdateBatteryTime(TimeDelta* previous,
369 const TimeDelta& current) {
370 static const TimeDelta kMaxDiff(TimeDelta::FromMinutes(10));
371 static const TimeDelta kMinDiff(TimeDelta::FromMinutes(0));
372 const TimeDelta diff = current - *previous;
373 // If the diff is small and positive, ignore it in favor of
374 // keeping time monotonically decreasing.
375 // If previous is 0, then it either was never set (initial condition)
376 // or got down to 0.
377 if (*previous == TimeDelta::FromMicroseconds(kInitialMS) ||
378 diff < kMinDiff ||
379 diff > kMaxDiff) {
380 *previous = current;
381 }
382 }
383
384 } // namespace chromeos
OLDNEW
« no previous file with comments | « chrome/browser/chromeos/status/power_menu_button.h ('k') | chrome/browser/chromeos/status/status_area_bubble.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698