1
    2
    3
    4
    5
    6
    7
    8
    9
   10
   11
   12
   13
   14
   15
   16
   17
   18
   19
   20
   21
   22
   23
   24
   25
   26
   27
   28
   29
   30
   31
   32
   33
   34
   35
   36
   37
   38
   39
   40
   41
   42
   43
   44
   45
   46
   47
   48
   49
   50
   51
   52
   53
   54
   55
   56
   57
   58
   59
   60
   61
   62
   63
   64
   65
   66
   67
   68
   69
   70
   71
   72
   73
   74
   75
   76
   77
   78
   79
   80
   81
   82
   83
   84
   85
   86
   87
   88
   89
   90
   91
   92
   93
   94
   95
   96
   97
   98
   99
  100
  101
  102
  103
  104
  105
  106
  107
  108
  109
  110
  111
  112
  113
  114
  115
  116
  117
  118
  119
  120
  121
  122
  123
  124
  125
  126
  127
  128
  129
  130
  131
  132
  133
  134
  135
  136
  137
  138
  139
  140
  141
  142
  143
  144
  145
  146
  147
  148
  149
  150
  151
  152
  153
  154
  155
  156
  157
  158
  159
  160
  161
  162
  163
  164
  165
  166
  167

ash / public / cpp / pagination / pagination_model.h [blame]

// Copyright 2012 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef ASH_PUBLIC_CPP_PAGINATION_PAGINATION_MODEL_H_
#define ASH_PUBLIC_CPP_PAGINATION_PAGINATION_MODEL_H_

#include <memory>

#include "ash/public/cpp/ash_public_export.h"
#include "base/compiler_specific.h"
#include "base/observer_list.h"
#include "base/time/time.h"
#include "ui/views/animation/animation_delegate_views.h"

namespace gfx {
class SlideAnimation;
}

namespace ash {

class PaginationModelObserver;
// A simple pagination model that consists of two numbers: the total pages and
// the currently selected page. The model is a single selection model that at
// the most one page can become selected at any time.
class ASH_PUBLIC_EXPORT PaginationModel : public views::AnimationDelegateViews {
 public:
  // Holds info for transition animation and touch scroll.
  struct Transition {
    Transition(int target_page, double progress)
        : target_page(target_page), progress(progress) {}

    bool Equals(const Transition& rhs) const {
      return target_page == rhs.target_page && progress == rhs.progress;
    }

    std::string ToString() const {
      std::stringstream ss;
      ss << "Target Page: " << target_page << ", Progess: " << progress;
      return ss.str();
    }

    // Target page for the transition or -1 if there is no target page. For
    // page switcher, this is the target selected page. For touch scroll,
    // this is usually the previous or next page (or -1 when there is no
    // previous or next page).
    int target_page;

    // A [0, 1] progress indicates how much of the current page is being
    // transitioned.
    double progress;
  };

  explicit PaginationModel(views::View* owner_view);

  PaginationModel(const PaginationModel&) = delete;
  PaginationModel& operator=(const PaginationModel&) = delete;

  ~PaginationModel() override;

  void SetTotalPages(int total_pages);

  // Selects a page. |animate| is true if the transition should be animated.
  void SelectPage(int page, bool animate);

  // Selects a page by relative |delta|.
  void SelectPageRelative(int delta, bool animate);

  // Whether the page relative |delta| is valid.
  bool IsValidPageRelative(int delta) const;

  // Immediately completes all queued animations, jumping directly to the
  // final target page.
  void FinishAnimation();

  void SetTransition(const Transition& transition);
  void SetTransitionDurations(base::TimeDelta duration,
                              base::TimeDelta overscroll_duration);

  // Starts a scroll transition. If there is a running transition animation,
  // cancels it but keeps the transition info.
  void StartScroll();

  // Updates transition progress from |delta|. |delta| > 0 means transit to
  // previous page (moving pages to the right). |delta| < 0 means transit
  // to next page (moving pages to the left).
  void UpdateScroll(double delta);

  // Finishes the current scroll transition if |cancel| is false. Otherwise,
  // reverses it.
  void EndScroll(bool cancel);

  // Returns true if current transition is being reverted.
  bool IsRevertingCurrentTransition() const;

  void AddObserver(PaginationModelObserver* observer);
  void RemoveObserver(PaginationModelObserver* observer);

  int total_pages() const { return total_pages_; }
  int selected_page() const { return selected_page_; }
  const Transition& transition() const { return transition_; }

  bool is_valid_page(int page) const {
    return page >= 0 && page < total_pages_;
  }

  bool has_transition() const {
    return transition_.target_page != -1 || transition_.progress != 0;
  }

  // Gets the page that the animation will eventually land on. If there is no
  // active animation, just returns selected_page().
  int SelectedTargetPage() const;

  base::TimeDelta GetTransitionAnimationSlideDuration() const;

 private:
  void NotifySelectedPageChanged(int old_selected, int new_selected);
  void NotifyTransitionAboutToStart();
  void NotifyTransitionStarted();
  void NotifyTransitionChanged();
  void NotifyTransitionEnded();
  void NotifyScrollStarted();
  void NotifyScrollEnded();

  void clear_transition() { SetTransition(Transition(-1, 0)); }

  // Calculates a target page number by combining current page and |delta|.
  // When there is no transition, current page is the currently selected page.
  // If there is a transition, current page is the transition target page or the
  // pending transition target page. When current page + |delta| goes beyond
  // valid range and |selected_page_| is at the range ends, invalid page number
  // -1 or |total_pages_| is returned to indicate the situation.
  int CalculateTargetPage(int delta) const;

  void StartTransitionAnimation(const Transition& transition);
  void ResetTransitionAnimation();

  // gfx::AnimationDelegate overrides:
  void AnimationProgressed(const gfx::Animation* animation) override;
  void AnimationEnded(const gfx::Animation* animation) override;

  int total_pages_;
  int selected_page_;

  Transition transition_;

  // Whether a transition has started, but not yet ended.
  bool is_transition_started_ = false;

  // Pending selected page when SelectedPage is called during a transition. If
  // multiple SelectPage is called while a transition is in progress, only the
  // last target page is remembered here.
  int pending_selected_page_;

  std::unique_ptr<gfx::SlideAnimation> transition_animation_;
  base::TimeDelta transition_duration_;
  base::TimeDelta overscroll_transition_duration_;

  base::TimeTicks last_overscroll_animation_start_time_;

  base::ObserverList<PaginationModelObserver>::Unchecked observers_;
};

}  // namespace ash

#endif  // ASH_PUBLIC_CPP_PAGINATION_PAGINATION_MODEL_H_