<commit_before>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/status/power_menu_button.h"

#include <algorithm>

#include "base/auto_reset.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/status/status_area_bubble.h"
#include "chrome/browser/chromeos/view_ids.h"
#include "grit/generated_resources.h"
#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 "ui/gfx/image/image.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 {

// Menu item ids.
enum {
  POWER_BATTERY_PERCENTAGE_ITEM = 1000,
  POWER_BATTERY_IS_CHARGED_ITEM,
  POWER_NO_BATTERY,
};

enum ImageType {
  DISCHARGING,
  CHARGING,
  BOLT
};

enum ImageSize {
  SMALL,
  LARGE
};

// Initialize time deltas to large values so they will be replaced when set
// to small values.
const int64 kInitialMS = 0x7fffffff;
// Width and height of small images.
const int kSmallImageWidth = 26, kSmallImageHeight = 24;
// Width and height of large images.
const int kLargeImageWidth = 57, kLargeImageHeight = 35;
// Number of different power states.
const int kNumPowerImages = 20;

// Color of text embedded within battery.
const SkColor kPercentageColor = 0xFF333333;
// Used for embossing text.
const SkColor kPercentageShadowColor = 0x80ffffff;
// Size of percentage w/in battery.
const int kBatteryFontSizeDelta = 3;

// Battery images come from two collections (small and large). In each there
// are |kNumPowerImages| battery states for both on and off charge, followed
// by the missing battery image and the unknown image.
// They are layed out like this:
// Discharging Charging Bolt
// |           |        +
// ||          ||        +
// ...
// |||||       |||||        +
// ||X||       ||?||
SkBitmap GetImage(ImageSize size, ImageType type, int index) {
  int image_width, image_height, image_index;

  if (size == SMALL) {
    image_index = IDR_STATUSBAR_BATTERY_SMALL_ALL;
    image_width = kSmallImageWidth;
    image_height = kSmallImageHeight;
  } else {
    image_index = IDR_STATUSBAR_BATTERY_LARGE_ALL;
    image_width = kLargeImageWidth;
    image_height = kLargeImageHeight;
  }
  const SkBitmap* all_images = ResourceBundle::GetSharedInstance().
      GetImageNamed(image_index).ToSkBitmap();
  SkIRect subset =
      SkIRect::MakeXYWH(
          static_cast<int>(type) * image_width,
          index * image_height,
          image_width,
          image_height);

  SkBitmap image;
  all_images->extractSubset(&image, subset);
  return image;
}

SkBitmap GetImageWithPercentage(ImageSize size, ImageType type,
                                double battery_percentage) {
  // Preserve the fully charged icon for 100% only.
  int battery_index = 0;
  if (battery_percentage >= 100) {
    battery_index = kNumPowerImages - 1;
  } else {
    battery_index = static_cast<int> (
        battery_percentage / 100.0 *
        nextafter(static_cast<double>(kNumPowerImages - 1), 0));
    battery_index =
        std::max(std::min(battery_index, kNumPowerImages - 2), 0);
  }
  return GetImage(size, type, battery_index);
}

SkBitmap GetMissingImage(ImageSize size) {
  return GetImage(size, DISCHARGING, kNumPowerImages);
}

SkBitmap GetUnknownImage(ImageSize size) {
  return GetImage(size, CHARGING, kNumPowerImages);
}

class BatteryIconView : public views::View {
 public:
  BatteryIconView()
      : battery_percentage_(0),
        battery_is_present_(false),
        line_power_on_(false),
        percentage_font_(ResourceBundle::GetSharedInstance().
                         GetFont(ResourceBundle::BaseFont).
                         DeriveFont(kBatteryFontSizeDelta, gfx::Font::BOLD)) {
  }

  virtual gfx::Size GetPreferredSize() OVERRIDE {
    return gfx::Size(kLargeImageWidth, kLargeImageHeight);
  }

  void set_battery_percentage(double battery_percentage) {
    battery_percentage_ = battery_percentage;
    SchedulePaint();
  }

  void set_battery_is_present(bool battery_is_present) {
    battery_is_present_ = battery_is_present;
    SchedulePaint();
  }

  void set_line_power_on(bool line_power_on) {
    line_power_on_ = line_power_on;
    SchedulePaint();
  }

 protected:
  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    SkBitmap image;
    if (!battery_is_present_) {
      image = GetMissingImage(LARGE);
    } else {
      image = GetImageWithPercentage(LARGE,
                                     line_power_on_ ? CHARGING : DISCHARGING,
                                     battery_percentage_);
    }
    const int image_x = 0;
    const int image_y = (height() - image.height()) / 2;
    canvas->DrawBitmapInt(image, image_x, image_y);

    if (battery_is_present_ && (battery_percentage_ < 100 || !line_power_on_)) {
      const string16 text = UTF8ToUTF16(base::StringPrintf(
          "%d%%", static_cast<int>(battery_percentage_)));
      const int text_h = percentage_font_.GetHeight();
      const int text_y = ((height() - text_h) / 2);
      canvas->DrawStringInt(
          text, percentage_font_, kPercentageShadowColor,
          image_x, text_y + 1, image.width(), text_h,
          gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_ELLIPSIS);
      canvas->DrawStringInt(
          text, percentage_font_, kPercentageColor,
          image_x, text_y, image.width(), text_h,
          gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_ELLIPSIS);
      if (line_power_on_)
        canvas->DrawBitmapInt(
            GetImageWithPercentage(LARGE, BOLT, battery_percentage_),
            image_x, image_y);
    }
  }

 private:
  double battery_percentage_;
  bool battery_is_present_;
  bool line_power_on_;
  gfx::Font percentage_font_;

  DISALLOW_COPY_AND_ASSIGN(BatteryIconView);
};

}  // namespace

namespace chromeos {

using base::TimeDelta;

////////////////////////////////////////////////////////////////////////////////
// PowerMenuButton

PowerMenuButton::PowerMenuButton(StatusAreaButton::Delegate* delegate)
    : StatusAreaButton(delegate, this),
      battery_is_present_(false),
      line_power_on_(false),
      battery_percentage_(0.0),
      battery_time_to_full_(TimeDelta::FromMicroseconds(kInitialMS)),
      battery_time_to_empty_(TimeDelta::FromMicroseconds(kInitialMS)),
      status_(NULL) {
  set_id(VIEW_ID_STATUS_BUTTON_POWER);
  UpdateIconAndLabelInfo();
  DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
}

PowerMenuButton::~PowerMenuButton() {
  DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
}

// PowerMenuButton, views::MenuDelegate implementation:<commit_msg>Revert 109813 - Revert 109777 - Request power status update from power manager when power button view gets created.<commit_after>// Copyright (c) 2011 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "chrome/browser/chromeos/status/power_menu_button.h"

#include <algorithm>

#include "base/auto_reset.h"
#include "base/string_number_conversions.h"
#include "base/stringprintf.h"
#include "base/time.h"
#include "base/utf_string_conversions.h"
#include "chrome/browser/chromeos/dbus/dbus_thread_manager.h"
#include "chrome/browser/chromeos/status/status_area_bubble.h"
#include "chrome/browser/chromeos/view_ids.h"
#include "grit/generated_resources.h"
#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 "ui/gfx/image/image.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 {

// Menu item ids.
enum {
  POWER_BATTERY_PERCENTAGE_ITEM = 1000,
  POWER_BATTERY_IS_CHARGED_ITEM,
  POWER_NO_BATTERY,
};

enum ImageType {
  DISCHARGING,
  CHARGING,
  BOLT
};

enum ImageSize {
  SMALL,
  LARGE
};

// Initialize time deltas to large values so they will be replaced when set
// to small values.
const int64 kInitialMS = 0x7fffffff;
// Width and height of small images.
const int kSmallImageWidth = 26, kSmallImageHeight = 24;
// Width and height of large images.
const int kLargeImageWidth = 57, kLargeImageHeight = 35;
// Number of different power states.
const int kNumPowerImages = 20;

// Color of text embedded within battery.
const SkColor kPercentageColor = 0xFF333333;
// Used for embossing text.
const SkColor kPercentageShadowColor = 0x80ffffff;
// Size of percentage w/in battery.
const int kBatteryFontSizeDelta = 3;

// Battery images come from two collections (small and large). In each there
// are |kNumPowerImages| battery states for both on and off charge, followed
// by the missing battery image and the unknown image.
// They are layed out like this:
// Discharging Charging Bolt
// |           |        +
// ||          ||        +
// ...
// |||||       |||||        +
// ||X||       ||?||
SkBitmap GetImage(ImageSize size, ImageType type, int index) {
  int image_width, image_height, image_index;

  if (size == SMALL) {
    image_index = IDR_STATUSBAR_BATTERY_SMALL_ALL;
    image_width = kSmallImageWidth;
    image_height = kSmallImageHeight;
  } else {
    image_index = IDR_STATUSBAR_BATTERY_LARGE_ALL;
    image_width = kLargeImageWidth;
    image_height = kLargeImageHeight;
  }
  const SkBitmap* all_images = ResourceBundle::GetSharedInstance().
      GetImageNamed(image_index).ToSkBitmap();
  SkIRect subset =
      SkIRect::MakeXYWH(
          static_cast<int>(type) * image_width,
          index * image_height,
          image_width,
          image_height);

  SkBitmap image;
  all_images->extractSubset(&image, subset);
  return image;
}

SkBitmap GetImageWithPercentage(ImageSize size, ImageType type,
                                double battery_percentage) {
  // Preserve the fully charged icon for 100% only.
  int battery_index = 0;
  if (battery_percentage >= 100) {
    battery_index = kNumPowerImages - 1;
  } else {
    battery_index = static_cast<int> (
        battery_percentage / 100.0 *
        nextafter(static_cast<double>(kNumPowerImages - 1), 0));
    battery_index =
        std::max(std::min(battery_index, kNumPowerImages - 2), 0);
  }
  return GetImage(size, type, battery_index);
}

SkBitmap GetMissingImage(ImageSize size) {
  return GetImage(size, DISCHARGING, kNumPowerImages);
}

SkBitmap GetUnknownImage(ImageSize size) {
  return GetImage(size, CHARGING, kNumPowerImages);
}

class BatteryIconView : public views::View {
 public:
  BatteryIconView()
      : battery_percentage_(0),
        battery_is_present_(false),
        line_power_on_(false),
        percentage_font_(ResourceBundle::GetSharedInstance().
                         GetFont(ResourceBundle::BaseFont).
                         DeriveFont(kBatteryFontSizeDelta, gfx::Font::BOLD)) {
  }

  virtual gfx::Size GetPreferredSize() OVERRIDE {
    return gfx::Size(kLargeImageWidth, kLargeImageHeight);
  }

  void set_battery_percentage(double battery_percentage) {
    battery_percentage_ = battery_percentage;
    SchedulePaint();
  }

  void set_battery_is_present(bool battery_is_present) {
    battery_is_present_ = battery_is_present;
    SchedulePaint();
  }

  void set_line_power_on(bool line_power_on) {
    line_power_on_ = line_power_on;
    SchedulePaint();
  }

 protected:
  virtual void OnPaint(gfx::Canvas* canvas) OVERRIDE {
    SkBitmap image;
    if (!battery_is_present_) {
      image = GetMissingImage(LARGE);
    } else {
      image = GetImageWithPercentage(LARGE,
                                     line_power_on_ ? CHARGING : DISCHARGING,
                                     battery_percentage_);
    }
    const int image_x = 0;
    const int image_y = (height() - image.height()) / 2;
    canvas->DrawBitmapInt(image, image_x, image_y);

    if (battery_is_present_ && (battery_percentage_ < 100 || !line_power_on_)) {
      const string16 text = UTF8ToUTF16(base::StringPrintf(
          "%d%%", static_cast<int>(battery_percentage_)));
      const int text_h = percentage_font_.GetHeight();
      const int text_y = ((height() - text_h) / 2);
      canvas->DrawStringInt(
          text, percentage_font_, kPercentageShadowColor,
          image_x, text_y + 1, image.width(), text_h,
          gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_ELLIPSIS);
      canvas->DrawStringInt(
          text, percentage_font_, kPercentageColor,
          image_x, text_y, image.width(), text_h,
          gfx::Canvas::TEXT_ALIGN_CENTER | gfx::Canvas::NO_ELLIPSIS);
      if (line_power_on_)
        canvas->DrawBitmapInt(
            GetImageWithPercentage(LARGE, BOLT, battery_percentage_),
            image_x, image_y);
    }
  }

 private:
  double battery_percentage_;
  bool battery_is_present_;
  bool line_power_on_;
  gfx::Font percentage_font_;

  DISALLOW_COPY_AND_ASSIGN(BatteryIconView);
};

}  // namespace

namespace chromeos {

using base::TimeDelta;

////////////////////////////////////////////////////////////////////////////////
// PowerMenuButton

PowerMenuButton::PowerMenuButton(StatusAreaButton::Delegate* delegate)
    : StatusAreaButton(delegate, this),
      battery_is_present_(false),
      line_power_on_(false),
      battery_percentage_(0.0),
      battery_time_to_full_(TimeDelta::FromMicroseconds(kInitialMS)),
      battery_time_to_empty_(TimeDelta::FromMicroseconds(kInitialMS)),
      status_(NULL) {
  set_id(VIEW_ID_STATUS_BUTTON_POWER);
  UpdateIconAndLabelInfo();
  DBusThreadManager::Get()->GetPowerManagerClient()->AddObserver(this);
  DBusThreadManager::Get()->GetPowerManagerClient()->RequestStatusUpdate();
}

PowerMenuButton::~PowerMenuButton() {
  DBusThreadManager::Get()->GetPowerManagerClient()->RemoveObserver(this);
}

// PowerMenuButton, views::MenuDelegate implementation:
{'fraction_non_alphanumeric': 0.11665739710789766, 'fraction_numerical': 0.010289210233592881, 'mean_word_length': 3.488299531981279, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 35, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 2, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '5101879', 'n_tokens_mistral': 4716, 'n_tokens_neox': 4585, 'n_words': 954}