Home | History | Annotate | Download | only in controls
      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
      3 // found in the LICENSE file.
      4 
      5 #ifndef UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
      6 #define UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
      7 
      8 #include "base/gtest_prod_util.h"
      9 #include "ui/views/view.h"
     10 
     11 namespace views {
     12 
     13 class SingleSplitViewListener;
     14 
     15 // SingleSplitView lays out two views next to each other, either horizontally
     16 // or vertically. A splitter exists between the two views that the user can
     17 // drag around to resize the views.
     18 // SingleSplitViewListener's SplitHandleMoved notification helps to monitor user
     19 // initiated layout changes.
     20 class VIEWS_EXPORT SingleSplitView : public View {
     21  public:
     22   enum Orientation {
     23     HORIZONTAL_SPLIT,
     24     VERTICAL_SPLIT
     25   };
     26 
     27   static const char kViewClassName[];
     28 
     29   SingleSplitView(View* leading,
     30                   View* trailing,
     31                   Orientation orientation,
     32                   SingleSplitViewListener* listener);
     33 
     34   virtual void Layout() OVERRIDE;
     35   virtual const char* GetClassName() const OVERRIDE;
     36 
     37   virtual void GetAccessibleState(ui::AccessibleViewState* state) OVERRIDE;
     38 
     39   // SingleSplitView's preferred size is the sum of the preferred widths
     40   // and the max of the heights.
     41   virtual gfx::Size GetPreferredSize() OVERRIDE;
     42 
     43   // Overriden to return a resize cursor when over the divider.
     44   virtual gfx::NativeCursor GetCursor(const ui::MouseEvent& event) OVERRIDE;
     45 
     46   Orientation orientation() const {
     47     return is_horizontal_ ? HORIZONTAL_SPLIT : VERTICAL_SPLIT;
     48   }
     49 
     50   void set_orientation(Orientation orientation) {
     51     is_horizontal_ = orientation == HORIZONTAL_SPLIT;
     52   }
     53 
     54   void set_divider_offset(int divider_offset) {
     55     divider_offset_ = divider_offset;
     56   }
     57   int divider_offset() const { return divider_offset_; }
     58 
     59   int GetDividerSize() const;
     60 
     61   void set_resize_disabled(bool resize_disabled) {
     62     resize_disabled_ = resize_disabled;
     63   }
     64   bool is_resize_disabled() const { return resize_disabled_; }
     65 
     66   // Sets whether the leading component is resized when the split views size
     67   // changes. The default is true. A value of false results in the trailing
     68   // component resizing on a bounds change.
     69   void set_resize_leading_on_bounds_change(bool resize) {
     70     resize_leading_on_bounds_change_ = resize;
     71   }
     72 
     73   // Calculates ideal leading and trailing view bounds according to the given
     74   // split view |bounds|, current divider offset and children visiblity.
     75   // Does not change children view bounds.
     76   void CalculateChildrenBounds(const gfx::Rect& bounds,
     77                                gfx::Rect* leading_bounds,
     78                                gfx::Rect* trailing_bounds) const;
     79 
     80   void SetAccessibleName(const string16& name);
     81 
     82  protected:
     83   // View overrides.
     84   virtual bool OnMousePressed(const ui::MouseEvent& event) OVERRIDE;
     85   virtual bool OnMouseDragged(const ui::MouseEvent& event) OVERRIDE;
     86   virtual void OnMouseCaptureLost() OVERRIDE;
     87   virtual void OnBoundsChanged(const gfx::Rect& previous_bounds) OVERRIDE;
     88 
     89  private:
     90   // This test calls OnMouse* functions.
     91   FRIEND_TEST_ALL_PREFIXES(SingleSplitViewTest, MouseDrag);
     92 
     93   // Returns true if |x| or |y| is over the divider.
     94   bool IsPointInDivider(const gfx::Point& p);
     95 
     96   // Calculates the new |divider_offset| based on the changes of split view
     97   // bounds.
     98   int CalculateDividerOffset(int divider_offset,
     99                              const gfx::Rect& previous_bounds,
    100                              const gfx::Rect& new_bounds) const;
    101 
    102   // Returns divider offset within primary axis size range for given split
    103   // view |bounds|.
    104   int NormalizeDividerOffset(int divider_offset, const gfx::Rect& bounds) const;
    105 
    106   // Returns width in case of horizontal split and height otherwise.
    107   int GetPrimaryAxisSize() const {
    108     return GetPrimaryAxisSize(width(), height());
    109   }
    110 
    111   int GetPrimaryAxisSize(int h, int v) const {
    112     return is_horizontal_ ? h : v;
    113   }
    114 
    115   // Used to track drag info.
    116   struct DragInfo {
    117     // The initial coordinate of the mouse when the user started the drag.
    118     int initial_mouse_offset;
    119     // The initial position of the divider when the user started the drag.
    120     int initial_divider_offset;
    121   };
    122 
    123   DragInfo drag_info_;
    124 
    125   // Orientation of the split view.
    126   bool is_horizontal_;
    127 
    128   // Position of the divider.
    129   int divider_offset_;
    130 
    131   bool resize_leading_on_bounds_change_;
    132 
    133   // Whether resizing is disabled.
    134   bool resize_disabled_;
    135 
    136   // Listener to notify about user initiated handle movements. Not owned.
    137   SingleSplitViewListener* listener_;
    138 
    139   // The accessible name of this view.
    140   string16 accessible_name_;
    141 
    142   DISALLOW_COPY_AND_ASSIGN(SingleSplitView);
    143 };
    144 
    145 }  // namespace views
    146 
    147 #endif  // UI_VIEWS_CONTROLS_SINGLE_SPLIT_VIEW_H_
    148