forked from chromium/chromium
-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
This document provides a high level overview of Views architecture and key concepts. It is aimed at engineers using or working on Views. BUG= Review-Url: https://codereview.chromium.org/2889223002 Cr-Commit-Position: refs/heads/master@{#473184}
- Loading branch information
ellyjones
authored and
Commit bot
committed
May 19, 2017
1 parent
55d390c
commit fbb5549
Showing
1 changed file
with
164 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,164 @@ | ||
# Views Overview | ||
|
||
This document is an overview of Views concepts, terminology, and architecture. | ||
The target audience is engineers using or working on Views. | ||
|
||
## General Things | ||
|
||
Points in this document are written as `(x,y)`, and rectangles are written as | ||
`[(x,y) wxh]`. For example, the rectangle `[(100,100) 50x20]` contains the point | ||
`(130,110)`. | ||
|
||
Views uses a coordinate system with `(0,0)` at the top-left, with increasing | ||
x-coordinates moving rightwards and increasing y-coordinates moving downwards. | ||
This is the same as the Windows and GTK coordinate systems, but *different from* | ||
the Cocoa coordinate system, which has `(0,0)` at the bottom-right. Coordinates | ||
in this document use the Views coordinate system. | ||
|
||
Views generally *take ownership* of objects passed to them even via raw | ||
pointers, although there are some exceptions, such as delegates. | ||
|
||
## Views | ||
|
||
A **View** is a UI element, similar to an HTML DOM element. Each View occupies a | ||
rectangle, called its **bounds**, which is expressed in the coordinate system of | ||
its parent View. Views may have child Views, which are laid out according to the | ||
View's **layout manager**, although individual Views may also override | ||
`View::Layout` to implement their own layout logic. Each View may also have a | ||
**border** and/or a **background**. | ||
|
||
Each View can calculate different sizes, which are used by the View's parent | ||
View to decide how to position and size it. Views may have any or all of a | ||
preferred size, a minimum size, and a maximum size. These may instead be | ||
calculated by the View's LayoutManager, and may be used by the parent View's | ||
LayoutManager. | ||
|
||
It is generally not a good idea to explicitly change the bounds of a View. | ||
Typically, bounds are computed by the parent View's Layout method or the parent | ||
View's LayoutManager. It is better to build a LayoutManager that does what you | ||
want than to hand-layout Views by changing their bounds. | ||
|
||
For more details about Views, see [view.h]. | ||
|
||
### Border | ||
|
||
The **border** is conventionally drawn around the edges of the View's bounding | ||
rectangle, and also defines the View's **content bounds**, which are the area | ||
inside which the View's content is drawn. For example, a View that is at | ||
`[(0,0) 100x100]` which has a solid border of thickness 2 will have content | ||
bounds of `[(2,2) 96x96]`. | ||
|
||
For more details, see [border.h]. | ||
|
||
### Background | ||
|
||
The **background** is drawn below any other part of the View, including the | ||
border. Any View can have a background, but most Views do not. A background is | ||
usually responsible for filling the View's entire bounds. Backgrounds are | ||
usually a color, but can be a gradient or something else entirely. | ||
|
||
For more details, see [background.h]. | ||
|
||
### Content | ||
|
||
The **content** is the area inside the content bounds of the View. A View's | ||
child Views, if it has any, are also positioned and drawn inside the content | ||
bounds of a View. There is no class representing the content area of a View; it | ||
only exists as the space enclosed by the View's border, and its shape is defined | ||
by the border's insets. | ||
|
||
### Layout & Layout Managers | ||
|
||
A View's **layout manager** defines how the View's child views should be laid | ||
out within the View's content bounds. There are a few layout managers supplied | ||
with Views. The simplest is [FillLayout], which lays out all a View's children | ||
occupying the View's entire content bounds. Other commonly-used layouts managers | ||
are [BoxLayout], which lays out all child views along an axis, and [GridLayout], | ||
which provides a flexible row-and-column system. | ||
|
||
### Painting | ||
|
||
Views are painted by pre-order traversal of the View tree - i.e., a parent View | ||
is painted before its child Views are. Each View paints all its children in | ||
z-order, as determined by `View::GetChildrenInZOrder()`, so the last child in | ||
z-order is painted last and therefore over the previous children. The default | ||
z-order is the order in which children were added to the parent View. | ||
|
||
Different View subclasses implement their own painting logic inside | ||
`View::OnPaint`, which by default simply calls `View::OnPaintBackground` and | ||
`View::OnPaintBorder`. Generally, subclass implementations of `View::OnPaint` | ||
begin by calling the superclass `View::OnPaint`. | ||
|
||
If you need a special background or border for a View subclass, it is better to | ||
create a subclass of `Background` or `Border` and install that, rather than | ||
overriding `::OnPaintBackground` or `::OnPaintBorder`. Doing this helps preserve | ||
the separation of Views into the three parts described above and makes painting | ||
code easier to understand. | ||
|
||
## Widgets | ||
|
||
Views need an underlying canvas to paint onto. This has to be supplied by the | ||
operating system, usually by creating a native drawing surface of some kind. | ||
Views calls these **widgets**. A Widget is the bridge between a tree of Views | ||
and a native window of some sort, which Views calls a **native widget**. Each | ||
Widget has a **root view**, which is a special subclass of View that helps with | ||
this bridging; the root view in turn has a single child view, called the | ||
Widget's **contents view**, which fills the entire root view. All other Views | ||
inside a given Widget are children of that Widget's content view. | ||
|
||
Widgets have many responsibilities, including but not limited to: | ||
|
||
1. Keyboard focus management, via [FocusManager] | ||
2. Window resizing/minimization/maximization | ||
3. Window shaping, for non-rectangular windows | ||
4. Input event routing | ||
|
||
For more details, see [widget.h]. | ||
|
||
### Client and Non-Client Views | ||
|
||
The content view of most Widgets is a **Non-Client View**, which is either a | ||
[NonClientView] or one of its descendants. The Non-Client View has two children, | ||
which are the **Non-Client Frame View** (a [NonClientFrameView]) and the | ||
**Client View** (a [ClientView]). The non-client frame view is responsible for | ||
painting window decorations, the Widget's border, the shadow, and so on; the | ||
client view is responsible for painting the Widget's contents. The area the | ||
client view occupies is sometimes referred to as the Widget's "client area". The | ||
non-client frame view may be swapped out as the system theme changes without | ||
affecting the client view. | ||
|
||
## Dialogs | ||
|
||
A commonly-used type of client view is a **dialog client view**, which has a | ||
**content view**, optional buttons on the lower-right, and an optional extra | ||
view on the lower-left. Dialogs are usually created by subclassing | ||
[DialogDelegate] or [DialogDelegateView] and then calling | ||
`DialogDelegate::CreateDialogWidget`. The dialog's content view fills the entire | ||
top part of the widget's client view, and the bottom part is taken over by the | ||
dialog's buttons and extra view. | ||
|
||
## Bubbles | ||
|
||
A common type of dialog is a **bubble**, which is a dialog that is anchored to a | ||
parent View and moves as the parent View moves. Bubbles are usually created by | ||
subclassing [BubbleDialogDelegateView] and then calling | ||
`BubbleDialogDelegateView::CreateBubble`. Bubbles can have a title, which is | ||
drawn alongside the window controls as part of the Bubble's Widget's | ||
NonClientFrameView. | ||
|
||
[BoxLayout]: https://cs.chromium.org/chromium/src/ui/views/layout/box_layout.h | ||
[BubbleDialogDelegateView]: https://cs.chromium.org/chromium/src/ui/views/bubble/bubble_dialog_delegate.h | ||
[ClientView]: https://cs.chromium.org/chromium/src/ui/views/window/client_view.h | ||
[DialogDelegate]: https://cs.chromium.org/chromium/src/ui/views/window/dialog_delegate.h | ||
[DialogDelegateView]: https://cs.chromium.org/chromium/src/ui/views/window/dialog_delegate.h | ||
[FillLayout]: https://cs.chromium.org/chromium/src/ui/views/layout/fill_layout.h | ||
[FocusManager]: https://cs.chromium.org/chromium/src/ui/views/focus/focus_manager.h | ||
[GridLayout]: https://cs.chromium.org/chromium/src/ui/views/layout/grid_layout.h | ||
|
||
[NonClientView]: https://cs.chromium.org/chromium/src/ui/views/window/non_client_view.h | ||
[NonClientFrameView]: https://cs.chromium.org/chromium/src/ui/views/window/non_client_view.h | ||
[background.h]: https://cs.chromium.org/chromium/src/ui/views/background.h | ||
[border.h]: https://cs.chromium.org/chromium/src/ui/views/border.h | ||
[canvas.h]: https://cs.chromium.org/chromium/src/ui/gfx/canvas.h | ||
[view.h]: https://cs.chromium.org/chromium/src/ui/views/view.h | ||
[widget.h]: https://cs.chromium.org/chromium/src/ui/views/widget/widget.h |