chromium/ui/views/layout/flex_layout_types.h

// Copyright 2018 The Chromium Authors
// 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 <algorithm>
#include <memory>
#include <string>

#include "base/functional/callback.h"
#include "ui/views/layout/layout_types.h"
#include "ui/views/views_export.h"

namespace gfx {
class Size;
}

namespace views {

class View;

// Specifies whether flex space is allocated in the same order as the children
// in the host view, or in reverse order. Reverse order is useful when you want
// child views to drop out from left to right instead of right to left if there
// isn't enough space to display them.
enum class FlexAllocationOrder {};

// 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.
FlexRule;

// 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 {};

// Describes a simple rule for how a child view should grow in a layout when
// there is extra size available for that view to occupy.
enum class MaximumFlexSizeRule {};

// 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 each individual child will deviate
//    from its preferred size; larger weights will deviate more either when
//    shrinking or growing. The deviation is proportional to the weight divided
//    by the total weight of all views at this |order|.
//  - An |order| which specifies the priority with which available space is
//    allocated (lower numbers -> higher priority).
//
// Space allocation works as follows:
// 1. All views are given the smallest possible size that |rule| allows (which
//    might be zero.)
// 2. Going by |order|, we attempt to allocate the preferred size of each view.
// 3. If there is insufficient size, the deficit is allocated across all views
//    at this |order| whose |rule| allows them to shrink, proportional to
//    |weight|.
// 4. Once all orders have been allocated this way, repeat the process by
//    |order| allocating any excess space among views whose |rule| allows them
//    to exceed their preferred size.
//
// For example, say there are three child views in a horizontal layout, each
// of which has a flex rule that allows it to be between 10 and 40 DIP with a
// preferred width of 20 DIP. 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 with weight 1.
//
// At 30 DIP (the parent's minimum size):
// [10][10][10]
//
// At 40 DIP:
// [10][20][10] (B hits its preferred size)
//
// At 48 DIP:
// [12][20][16] (deficit is spread across A and C by weight)
//
// At 57 DIP:
// [18][20][19]
//
// At 60 DIP:
// [20][20][20] (all views at preferred size)
//
// At 80 DIP:
// [20][40][20] (B hits its maximum size)
//
// At 110 DIP:
// [40][40][30] (A scales faster than C)
//
// At 120 DIP (the parent's maximum size):
// [40][40][40]
//
// NOTE(dfried): the behavior of |weight| may seem backwards when views shrink
// below their preferred size, but it works the way it does because:
//  (a) It's consistent with BoxLayout, making upgrading to FlexLayout easier.
//  (b) It allows smooth scaling across a view's preferred size.
// If this gets too confusing we could add an option to make weights reciprocal
// when allocating deficit.
class VIEWS_EXPORT FlexSpecification {};

// Represents insets in a single dimension.
class VIEWS_EXPORT Inset1D {};

// Represents a line segment in one dimension with a starting point and length.
class VIEWS_EXPORT Span {};

// These are declared here for use in gtest-based unit tests but is defined in
// the views_test_support target. Depend on that to use this in your unit test.
// This should not be used in production code - call ToString() instead.
void PrintTo(MinimumFlexSizeRule minimum_flex_size_rule, ::std::ostream* os);
void PrintTo(MaximumFlexSizeRule maximum_flex_size_rule, ::std::ostream* os);

}  // namespace views

#endif  // UI_VIEWS_LAYOUT_FLEX_LAYOUT_TYPES_H_