ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 1 | # Views Overview |
| 2 | |
| 3 | This document is an overview of Views concepts, terminology, and architecture. |
| 4 | The target audience is engineers using or working on Views. |
| 5 | |
| 6 | ## General Things |
| 7 | |
| 8 | Points in this document are written as `(x,y)`, and rectangles are written as |
| 9 | `[(x,y) wxh]`. For example, the rectangle `[(100,100) 50x20]` contains the point |
| 10 | `(130,110)`. |
| 11 | |
| 12 | Views uses a coordinate system with `(0,0)` at the top-left, with increasing |
| 13 | x-coordinates moving rightwards and increasing y-coordinates moving downwards. |
| 14 | This is the same as the Windows and GTK coordinate systems, but *different from* |
sdy | f6f8f66f | 2017-05-22 16:24:56 | [diff] [blame] | 15 | the Cocoa coordinate system, which has `(0,0)` at the bottom-left. Coordinates |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 16 | in this document use the Views coordinate system. |
| 17 | |
| 18 | Views generally *take ownership* of objects passed to them even via raw |
| 19 | pointers, although there are some exceptions, such as delegates. |
| 20 | |
| 21 | ## Views |
| 22 | |
| 23 | A **View** is a UI element, similar to an HTML DOM element. Each View occupies a |
| 24 | rectangle, called its **bounds**, which is expressed in the coordinate system of |
| 25 | its parent View. Views may have child Views, which are laid out according to the |
| 26 | View's **layout manager**, although individual Views may also override |
| 27 | `View::Layout` to implement their own layout logic. Each View may also have a |
| 28 | **border** and/or a **background**. |
| 29 | |
| 30 | Each View can calculate different sizes, which are used by the View's parent |
| 31 | View to decide how to position and size it. Views may have any or all of a |
| 32 | preferred size, a minimum size, and a maximum size. These may instead be |
| 33 | calculated by the View's LayoutManager, and may be used by the parent View's |
| 34 | LayoutManager. |
| 35 | |
| 36 | It is generally not a good idea to explicitly change the bounds of a View. |
| 37 | Typically, bounds are computed by the parent View's Layout method or the parent |
| 38 | View's LayoutManager. It is better to build a LayoutManager that does what you |
| 39 | want than to hand-layout Views by changing their bounds. |
| 40 | |
| 41 | For more details about Views, see [view.h]. |
| 42 | |
| 43 | ### Border |
| 44 | |
| 45 | The **border** is conventionally drawn around the edges of the View's bounding |
| 46 | rectangle, and also defines the View's **content bounds**, which are the area |
| 47 | inside which the View's content is drawn. For example, a View that is at |
| 48 | `[(0,0) 100x100]` which has a solid border of thickness 2 will have content |
| 49 | bounds of `[(2,2) 96x96]`. |
| 50 | |
| 51 | For more details, see [border.h]. |
| 52 | |
| 53 | ### Background |
| 54 | |
| 55 | The **background** is drawn below any other part of the View, including the |
| 56 | border. Any View can have a background, but most Views do not. A background is |
| 57 | usually responsible for filling the View's entire bounds. Backgrounds are |
| 58 | usually a color, but can be a gradient or something else entirely. |
| 59 | |
| 60 | For more details, see [background.h]. |
| 61 | |
| 62 | ### Content |
| 63 | |
| 64 | The **content** is the area inside the content bounds of the View. A View's |
| 65 | child Views, if it has any, are also positioned and drawn inside the content |
| 66 | bounds of a View. There is no class representing the content area of a View; it |
| 67 | only exists as the space enclosed by the View's border, and its shape is defined |
| 68 | by the border's insets. |
| 69 | |
| 70 | ### Layout & Layout Managers |
| 71 | |
| 72 | A View's **layout manager** defines how the View's child views should be laid |
| 73 | out within the View's content bounds. There are a few layout managers supplied |
| 74 | with Views. The simplest is [FillLayout], which lays out all a View's children |
Dana Fried | 9ddbafc | 2020-06-15 19:20:52 | [diff] [blame] | 75 | occupying the View's entire content bounds. [FlexLayout] provides a CSS-like |
| 76 | layout for horizontal and vertical arrangements of views. |
| 77 | |
| 78 | Other commonly-used layouts managers are [BoxLayout], a predecessor of |
Peter Kasting | 2ead0ee | 2021-10-20 16:55:27 | [diff] [blame] | 79 | FlexLayout, and [TableLayout], which provides a flexible row-and-column |
Dana Fried | 9ddbafc | 2020-06-15 19:20:52 | [diff] [blame] | 80 | system. |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 81 | |
| 82 | ### Painting |
| 83 | |
| 84 | Views are painted by pre-order traversal of the View tree - i.e., a parent View |
| 85 | is painted before its child Views are. Each View paints all its children in |
| 86 | z-order, as determined by `View::GetChildrenInZOrder()`, so the last child in |
| 87 | z-order is painted last and therefore over the previous children. The default |
| 88 | z-order is the order in which children were added to the parent View. |
| 89 | |
| 90 | Different View subclasses implement their own painting logic inside |
| 91 | `View::OnPaint`, which by default simply calls `View::OnPaintBackground` and |
| 92 | `View::OnPaintBorder`. Generally, subclass implementations of `View::OnPaint` |
| 93 | begin by calling the superclass `View::OnPaint`. |
| 94 | |
| 95 | If you need a special background or border for a View subclass, it is better to |
| 96 | create a subclass of `Background` or `Border` and install that, rather than |
| 97 | overriding `::OnPaintBackground` or `::OnPaintBorder`. Doing this helps preserve |
| 98 | the separation of Views into the three parts described above and makes painting |
| 99 | code easier to understand. |
| 100 | |
Erik Chen | 14380c4 | 2024-01-16 21:27:52 | [diff] [blame] | 101 | ### Debugging |
| 102 | |
| 103 | See [page](../ui_devtools/index.md) for details. |
| 104 | |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 105 | ## Widgets |
| 106 | |
| 107 | Views need an underlying canvas to paint onto. This has to be supplied by the |
| 108 | operating system, usually by creating a native drawing surface of some kind. |
| 109 | Views calls these **widgets**. A Widget is the bridge between a tree of Views |
| 110 | and a native window of some sort, which Views calls a **native widget**. Each |
| 111 | Widget has a **root view**, which is a special subclass of View that helps with |
| 112 | this bridging; the root view in turn has a single child view, called the |
| 113 | Widget's **contents view**, which fills the entire root view. All other Views |
sdy | f6f8f66f | 2017-05-22 16:24:56 | [diff] [blame] | 114 | inside a given Widget are children of that Widget's contents view. |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 115 | |
| 116 | Widgets have many responsibilities, including but not limited to: |
| 117 | |
| 118 | 1. Keyboard focus management, via [FocusManager] |
| 119 | 2. Window resizing/minimization/maximization |
| 120 | 3. Window shaping, for non-rectangular windows |
| 121 | 4. Input event routing |
| 122 | |
| 123 | For more details, see [widget.h]. |
| 124 | |
| 125 | ### Client and Non-Client Views |
| 126 | |
sdy | f6f8f66f | 2017-05-22 16:24:56 | [diff] [blame] | 127 | The contents view of most Widgets is a **Non-Client View**, which is either a |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 128 | [NonClientView] or one of its descendants. The Non-Client View has two children, |
| 129 | which are the **Non-Client Frame View** (a [NonClientFrameView]) and the |
| 130 | **Client View** (a [ClientView]). The non-client frame view is responsible for |
| 131 | painting window decorations, the Widget's border, the shadow, and so on; the |
| 132 | client view is responsible for painting the Widget's contents. The area the |
| 133 | client view occupies is sometimes referred to as the Widget's "client area". The |
| 134 | non-client frame view may be swapped out as the system theme changes without |
| 135 | affecting the client view. |
| 136 | |
Elly Fong-Jones | 8f74ca1 | 2019-01-09 17:54:38 | [diff] [blame] | 137 | The overall structure of a Widget and its helper Views looks like this: |
| 138 | |
Keren Zhu | 5f2e01b6 | 2022-12-14 17:28:38 | [diff] [blame] | 139 |  |
Elly Fong-Jones | 8f74ca1 | 2019-01-09 17:54:38 | [diff] [blame] | 140 | |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 141 | ## Dialogs |
| 142 | |
| 143 | A commonly-used type of client view is a **dialog client view**, which has a |
sdy | f6f8f66f | 2017-05-22 16:24:56 | [diff] [blame] | 144 | **contents view**, optional buttons on the lower-right, and an optional extra |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 145 | view on the lower-left. Dialogs are usually created by subclassing |
| 146 | [DialogDelegate] or [DialogDelegateView] and then calling |
sdy | f6f8f66f | 2017-05-22 16:24:56 | [diff] [blame] | 147 | `DialogDelegate::CreateDialogWidget`. The dialog's contents view fills the |
| 148 | entire top part of the widget's client view, and the bottom part is taken over |
| 149 | by the dialog's buttons and extra view. |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 150 | |
| 151 | ## Bubbles |
| 152 | |
| 153 | A common type of dialog is a **bubble**, which is a dialog that is anchored to a |
| 154 | parent View and moves as the parent View moves. Bubbles are usually created by |
| 155 | subclassing [BubbleDialogDelegateView] and then calling |
| 156 | `BubbleDialogDelegateView::CreateBubble`. Bubbles can have a title, which is |
| 157 | drawn alongside the window controls as part of the Bubble's Widget's |
| 158 | NonClientFrameView. |
| 159 | |
| 160 | [BoxLayout]: https://cs.chromium.org/chromium/src/ui/views/layout/box_layout.h |
Takashi Toyoshima | 33928e7 | 2023-11-27 06:41:05 | [diff] [blame] | 161 | [BubbleDialogDelegateView]: https://cs.chromium.org/chromium/src/ui/views/bubble/bubble_dialog_delegate_view.h |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 162 | [ClientView]: https://cs.chromium.org/chromium/src/ui/views/window/client_view.h |
| 163 | [DialogDelegate]: https://cs.chromium.org/chromium/src/ui/views/window/dialog_delegate.h |
| 164 | [DialogDelegateView]: https://cs.chromium.org/chromium/src/ui/views/window/dialog_delegate.h |
| 165 | [FillLayout]: https://cs.chromium.org/chromium/src/ui/views/layout/fill_layout.h |
Peter Kasting | 2ead0ee | 2021-10-20 16:55:27 | [diff] [blame] | 166 | [FlexLayout]: https://cs.chromium.org/chromium/src/ui/views/layout/flex_layout.h |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 167 | [FocusManager]: https://cs.chromium.org/chromium/src/ui/views/focus/focus_manager.h |
Peter Kasting | 2ead0ee | 2021-10-20 16:55:27 | [diff] [blame] | 168 | [TableLayout]: https://cs.chromium.org/chromium/src/ui/views/layout/table_layout.h |
ellyjones | fbb55498 | 2017-05-19 14:43:28 | [diff] [blame] | 169 | |
| 170 | [NonClientView]: https://cs.chromium.org/chromium/src/ui/views/window/non_client_view.h |
| 171 | [NonClientFrameView]: https://cs.chromium.org/chromium/src/ui/views/window/non_client_view.h |
| 172 | [background.h]: https://cs.chromium.org/chromium/src/ui/views/background.h |
| 173 | [border.h]: https://cs.chromium.org/chromium/src/ui/views/border.h |
| 174 | [canvas.h]: https://cs.chromium.org/chromium/src/ui/gfx/canvas.h |
| 175 | [view.h]: https://cs.chromium.org/chromium/src/ui/views/view.h |
| 176 | [widget.h]: https://cs.chromium.org/chromium/src/ui/views/widget/widget.h |