blob: 34ea1ba3f35867baf5d37e0147fe6fc82d787937 [file] [log] [blame] [view]
ellyjonesdc3cb5d2016-05-09 13:55:531# Views Platform Styling
2
3## Overview
4
5Views controls may have different appearances on different platforms, so that
6Views UIs can fit better into the platform's native styling. This document
7describes how to build Views UIs that will look good on all platforms with a
8minimum of manual intervention.
9
10UIs looking good happens at two levels: first, the individual controls must look
11and act appropriately for their platform, and second, the overall layout of the
12controls in a dialog or UI surface must match what users of the platform would
13expect. There are differences at both of these layers between desktop platforms,
14and mobile platforms have still more differences.
15
16## Controls
17
18Individual controls have different looks and behaviors on different platforms.
19If you're adding a new control or a subclass of an existing control, there are
20some best practices you should follow in designing it so that it works well
21everywhere:
22
23### Use PlatformStyle for stylistic elements
24
25PlatformStyle exposes factory functions that produce different subclasses of
26Border, Background, and so on that are appropriate to the current platform. If
27your class needs a special kind of border or another stylistic element, creating
28it through a factory function in PlatformStyle will make per-platform styling
29for it easier, and will make which parts of the appearance are platform-specific
30more apparent. For example, if you were adding a Foo control that had a special
31FooBackground background, you might add a function to PlatformStyle:
32
33 unique_ptr<FooBackground> CreateFooBackground();
34
35and a default implementation in PlatformStyle. This way, in future a
36platform-specific implementation can go in PlatformStyleBar and change the
37background of that control on platform Bar without changing the implementation
38of the Foo control at all.
39
40### Use PlatformStyle to add simple behavior switches
41
42When adding platform-specific behavior for an existing control, if possible, it
43is useful to implement the switch using a const boolean exported from
44PlatformStyle, instead of ifdefs inside the control's implementation. For
45example, instead of:
46
47 #if defined(OS_BAR)
48 void Foo::DoThing() { ... }
49 #else
50 void Foo::DoThing() { ... }
51 #endif
52
53It's better to do this:
54
55 Foo::Foo() : does_thing_that_way_(PlatformStyle::kFooDoesThingThatWay)
56
57 void Foo::DoThing() {
58 if (does_thing_that_way_)
59 ...
60 else
61 ...
62 }
63
64This pattern makes it possible to unit-test all the different platform behaviors
65on one platform.
66
67### Use subclassing to add complex behavior switches
68
69If a lot of the behavior of Foo needs to change per-platform, creating
70platform-specific subclasses of Foo and a factory method on Foo that creates the
71appropriate subclass for the platform is easier to read and understand than
72having ifdefs or lots of control flow inside Foo to implement per-platform
73behavior.
74
75Note that it's best only to do this when no other alternative presents itself,
76because having multiple subclasses to do different behaviors per-platform makes
77subclassing a control require one subclass per platform as well. It's better to
78abstract the per-platform behavior into a separate model class, with a factory
79that produces the right model for the current platform.
80
81## UI Layout / Controls
82
83TODO(ellyjones): This section needs a bit more thought.
84
85Some platforms have conventions about the ordering of buttons in dialogs, or the
86presence or absence of certain common controls. For example, on Mac, dialogs are
87expected to have their "default" button at the bottom right, and expected not to
88have a "close" button in their top corner if they have a "Cancel"/"Dismiss"
89button in the dialog body. If you can design a layout that follows all
90platforms' conventions simultaneously, that is the lowest-effort route to
91follow, but if not, there are static booleans in PlatformStyle that hold the
92appropriate values for these decisions on the current platform, like:
93
94 static const bool PlatformStyle::kDialogsShouldHaveCloseButton;
95
96You can then condition your dialog creation code like this:
97
98 if (PlatformStyle::kDialogsShouldHaveCloseButton)
99 views::Button* close_button = ...;
100
101TODO(ellyjones): Actually add these variables to PlatformStyle