blob: f018d6ab1661f17a4450fc75ca3a778682e58988 [file] [log] [blame]
// Copyright 2018 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.
#ifndef UI_VIEWS_LAYOUT_FLEX_LAYOUT_TYPES_H_
#define UI_VIEWS_LAYOUT_FLEX_LAYOUT_TYPES_H_
#include <memory>
#include <string>
#include "base/callback.h"
#include "base/optional.h"
#include "ui/views/views_export.h"
namespace gfx {
class Size;
}
namespace views {
class View;
// Whether a layout is oriented horizontally or vertically.
enum class LayoutOrientation {
kHorizontal,
kVertical,
};
// Describes how elements should be aligned within a layout.
enum class LayoutAlignment { kStart, kCenter, kEnd, kStretch };
// Stores an optional width and height upper bound. Used when calculating the
// preferred size of a layout pursuant to a maximum available size.
class VIEWS_EXPORT SizeBounds {
public:
SizeBounds();
SizeBounds(const base::Optional<int>& width,
const base::Optional<int>& height);
explicit SizeBounds(const gfx::Size& size);
SizeBounds(const SizeBounds& other);
const base::Optional<int>& width() const { return width_; }
void set_width(const base::Optional<int>& width) { width_ = width; }
const base::Optional<int>& height() const { return height_; }
void set_height(const base::Optional<int>& height) { height_ = height; }
// Enlarges (or shrinks, if negative) each upper bound that is present by the
// specified amounts.
void Enlarge(int width, int height);
bool operator==(const SizeBounds& other) const;
bool operator!=(const SizeBounds& other) const;
bool operator<(const SizeBounds& other) const;
std::string ToString() const;
private:
base::Optional<int> width_;
base::Optional<int> height_;
};
// Callback used to specify the size of a child view based on its size bounds.
// Create your own custom rules, or use the Minimum|MaximumFlexSizeRule
// constants below for common behaviors.
//
// This callback takes two parameters: a child view, and a set of size bounds
// representing the available space for that child view to occupy. The function
// returns the preferred size of the view within those bounds, which may exceed
// them if the child is not capable of shrinking to the specified size. The
// callback may also return an empty size, which means the child view can drop
// out of the layout. Not specifying either bound means there is an unlimited
// amount of room for the child view in that dimension (and the child view
// should probably use its preferred size).
//
// We provide the ability to use an arbitrary function here because some views
// have complex sizing behavior; for example, they may shrink stepwise as their
// internal elements drop out due to lack of space.
using FlexRule =
base::RepeatingCallback<gfx::Size(const View*, const SizeBounds&)>;
// Describes a simple rule for how a child view should shrink in a layout when
// the available size for that view decreases.
enum class MinimumFlexSizeRule {
kScaleToZero, // Ignore minimum size and scale all the way down.
kScaleToMinimumSnapToZero, // Scale to minimum then snap to zero.
kPreferredSnapToZero, // Use preferred, then snap to zero.
kScaleToMinimum, // Resize down to minimum then stop.
kPreferredSnapToMinimum, // Use preferred, then snap to minimum.
kPreferred // Always use preferred size.
};
// Describes a simple rule for how a child view should grow in a layout when
// there is extra size avaialble for that view to occupy.
enum MaximumFlexSizeRule {
kPreferred, // Don't resize above preferred size.
kUnbounded // Allow resize to arbitrary size.
};
// Specifies how a view should flex (i.e. grow or shrink) within its parent as
// the available space changes. Flex specifications have three components:
// - A |rule| which tells the layout manager how the child view resizes with
// available space.
// - A |weight| which specifies how much of the available space is allocated to
// a child view that can flex. The percentage of space allocated is the
// weight divided by the total weight of all views at this order (see below).
// - An |order| which specifies the priority with which available space is
// allocated. All available space is offered to child views at order 1, then
// any remaining space is offered to order 2, and so forth.
//
// For example, say there are three child controls in a horizontal layout, each
// of which has a flex rule that allows it to be between 0 and 20 DIPs wide.
// Child A is at order 2 with weight 2, child B is at order 1 with weight 1, and
// child C is at order 2 and weight 1. The parent control is 50 DIPs across and
// has no margins.
//
// All 50 DIPs are offered to child B, since it is first in order. It consumes
// 20 DIPs, its maximum size. Of the remaining 30, 20 are offered to child A and
// 10 are offered to child C, each of which they take - the 2:1 ratio is due to
// the different weights. (Also note that, if there were another child at order
// 3, it would be offered zero DIPs and might choose not to display itself.)
class VIEWS_EXPORT FlexSpecification {
public:
// Creates a flex specification with the default rule (no flex, always use the
// view's preferred size).
FlexSpecification();
FlexSpecification(const FlexSpecification& other);
FlexSpecification& operator=(const FlexSpecification& other);
~FlexSpecification();
// Creates a flex specification with a custom flex rule. Note that any copies
// or mutations of this specification will also inherit the rule.
static FlexSpecification ForCustomRule(FlexRule rule);
// Creates a flex specification using the specififed minimum size and size
// bounds rules.
static FlexSpecification ForSizeRule(MinimumFlexSizeRule minimum_size_rule,
MaximumFlexSizeRule maximum_size_rule);
// Makes a copy of this specification with a different order.
FlexSpecification WithOrder(int order) const;
// Makes a copy of this specification with a different weight.
// Specifying |weight| of zero means the view will take as much space as it
// needs.
FlexSpecification WithWeight(int weight) const;
const FlexRule& rule() const { return rule_; }
int weight() const { return weight_; }
int order() const { return order_; }
private:
FlexSpecification(FlexRule rule, int order, int weight);
FlexRule rule_;
int order_ = 1;
int weight_ = 0;
};
} // namespace views
#endif // UI_VIEWS_LAYOUT_FLEX_LAYOUT_TYPES_H_