Home | History | Annotate | Download | only in controls
      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 "ui/views/controls/throbber.h"
      6 
      7 #include "base/time/time.h"
      8 #include "grit/ui_resources.h"
      9 #include "ui/base/resource/resource_bundle.h"
     10 #include "ui/gfx/canvas.h"
     11 #include "ui/gfx/image/image.h"
     12 #include "ui/gfx/image/image_skia.h"
     13 
     14 using base::Time;
     15 using base::TimeDelta;
     16 
     17 namespace views {
     18 
     19 Throbber::Throbber(int frame_time_ms,
     20                    bool paint_while_stopped)
     21     : running_(false),
     22       paint_while_stopped_(paint_while_stopped),
     23       frames_(NULL),
     24       frame_time_(TimeDelta::FromMilliseconds(frame_time_ms)) {
     25   SetFrames(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
     26       IDR_THROBBER).ToImageSkia());
     27 }
     28 
     29 Throbber::~Throbber() {
     30   Stop();
     31 }
     32 
     33 void Throbber::Start() {
     34   if (running_)
     35     return;
     36 
     37   start_time_ = Time::Now();
     38 
     39   timer_.Start(FROM_HERE, frame_time_ - TimeDelta::FromMilliseconds(10),
     40                this, &Throbber::Run);
     41 
     42   running_ = true;
     43 
     44   SchedulePaint();  // paint right away
     45 }
     46 
     47 void Throbber::Stop() {
     48   if (!running_)
     49     return;
     50 
     51   timer_.Stop();
     52 
     53   running_ = false;
     54   SchedulePaint();  // Important if we're not painting while stopped
     55 }
     56 
     57 void Throbber::SetFrames(const gfx::ImageSkia* frames) {
     58   frames_ = frames;
     59   DCHECK(frames_->width() > 0 && frames_->height() > 0);
     60   DCHECK(frames_->width() % frames_->height() == 0);
     61   frame_count_ = frames_->width() / frames_->height();
     62   PreferredSizeChanged();
     63 }
     64 
     65 void Throbber::Run() {
     66   DCHECK(running_);
     67 
     68   SchedulePaint();
     69 }
     70 
     71 gfx::Size Throbber::GetPreferredSize() {
     72   return gfx::Size(frames_->height(), frames_->height());
     73 }
     74 
     75 void Throbber::OnPaint(gfx::Canvas* canvas) {
     76   if (!running_ && !paint_while_stopped_)
     77     return;
     78 
     79   const TimeDelta elapsed_time = Time::Now() - start_time_;
     80   const int current_frame =
     81       static_cast<int>(elapsed_time / frame_time_) % frame_count_;
     82 
     83   int image_size = frames_->height();
     84   int image_offset = current_frame * image_size;
     85   canvas->DrawImageInt(*frames_,
     86                        image_offset, 0, image_size, image_size,
     87                        0, 0, image_size, image_size,
     88                        false);
     89 }
     90 
     91 
     92 
     93 // Smoothed throbber ---------------------------------------------------------
     94 
     95 
     96 // Delay after work starts before starting throbber, in milliseconds.
     97 static const int kStartDelay = 200;
     98 
     99 // Delay after work stops before stopping, in milliseconds.
    100 static const int kStopDelay = 50;
    101 
    102 
    103 SmoothedThrobber::SmoothedThrobber(int frame_time_ms)
    104     : Throbber(frame_time_ms, /* paint_while_stopped= */ false),
    105       start_delay_ms_(kStartDelay),
    106       stop_delay_ms_(kStopDelay) {
    107 }
    108 
    109 SmoothedThrobber::~SmoothedThrobber() {}
    110 
    111 void SmoothedThrobber::Start() {
    112   stop_timer_.Stop();
    113 
    114   if (!running_ && !start_timer_.IsRunning()) {
    115     start_timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(start_delay_ms_),
    116                        this, &SmoothedThrobber::StartDelayOver);
    117   }
    118 }
    119 
    120 void SmoothedThrobber::StartDelayOver() {
    121   Throbber::Start();
    122 }
    123 
    124 void SmoothedThrobber::Stop() {
    125   if (!running_)
    126     start_timer_.Stop();
    127 
    128   stop_timer_.Stop();
    129   stop_timer_.Start(FROM_HERE, TimeDelta::FromMilliseconds(stop_delay_ms_),
    130                     this, &SmoothedThrobber::StopDelayOver);
    131 }
    132 
    133 void SmoothedThrobber::StopDelayOver() {
    134   Throbber::Stop();
    135 }
    136 
    137 // Checkmark throbber ---------------------------------------------------------
    138 
    139 CheckmarkThrobber::CheckmarkThrobber()
    140     : Throbber(kFrameTimeMs, false),
    141       checked_(false),
    142       checkmark_(ui::ResourceBundle::GetSharedInstance().GetImageNamed(
    143           IDR_CHECKMARK).ToImageSkia()) {
    144 }
    145 
    146 void CheckmarkThrobber::SetChecked(bool checked) {
    147   bool changed = checked != checked_;
    148   if (changed) {
    149     checked_ = checked;
    150     SchedulePaint();
    151   }
    152 }
    153 
    154 void CheckmarkThrobber::OnPaint(gfx::Canvas* canvas) {
    155   if (running_) {
    156     // Let the throbber throb...
    157     Throbber::OnPaint(canvas);
    158     return;
    159   }
    160   // Otherwise we paint our tick mark or nothing depending on our state.
    161   if (checked_) {
    162     int checkmark_x = (width() - checkmark_->width()) / 2;
    163     int checkmark_y = (height() - checkmark_->height()) / 2;
    164     canvas->DrawImageInt(*checkmark_, checkmark_x, checkmark_y);
    165   }
    166 }
    167 
    168 }  // namespace views
    169