Index: docs/ui/views/platform_style.md |
diff --git a/docs/ui/views/platform_style.md b/docs/ui/views/platform_style.md |
new file mode 100644 |
index 0000000000000000000000000000000000000000..34ea1ba3f35867baf5d37e0147fe6fc82d787937 |
--- /dev/null |
+++ b/docs/ui/views/platform_style.md |
@@ -0,0 +1,101 @@ |
+# Views Platform Styling |
+ |
+## Overview |
+ |
+Views controls may have different appearances on different platforms, so that |
+Views UIs can fit better into the platform's native styling. This document |
+describes how to build Views UIs that will look good on all platforms with a |
+minimum of manual intervention. |
+ |
+UIs looking good happens at two levels: first, the individual controls must look |
+and act appropriately for their platform, and second, the overall layout of the |
+controls in a dialog or UI surface must match what users of the platform would |
+expect. There are differences at both of these layers between desktop platforms, |
+and mobile platforms have still more differences. |
+ |
+## Controls |
+ |
+Individual controls have different looks and behaviors on different platforms. |
+If you're adding a new control or a subclass of an existing control, there are |
+some best practices you should follow in designing it so that it works well |
+everywhere: |
+ |
+### Use PlatformStyle for stylistic elements |
+ |
+PlatformStyle exposes factory functions that produce different subclasses of |
+Border, Background, and so on that are appropriate to the current platform. If |
+your class needs a special kind of border or another stylistic element, creating |
+it through a factory function in PlatformStyle will make per-platform styling |
+for it easier, and will make which parts of the appearance are platform-specific |
+more apparent. For example, if you were adding a Foo control that had a special |
+FooBackground background, you might add a function to PlatformStyle: |
+ |
+ unique_ptr<FooBackground> CreateFooBackground(); |
+ |
+and a default implementation in PlatformStyle. This way, in future a |
+platform-specific implementation can go in PlatformStyleBar and change the |
+background of that control on platform Bar without changing the implementation |
+of the Foo control at all. |
+ |
+### Use PlatformStyle to add simple behavior switches |
+ |
+When adding platform-specific behavior for an existing control, if possible, it |
+is useful to implement the switch using a const boolean exported from |
+PlatformStyle, instead of ifdefs inside the control's implementation. For |
+example, instead of: |
+ |
+ #if defined(OS_BAR) |
+ void Foo::DoThing() { ... } |
+ #else |
+ void Foo::DoThing() { ... } |
+ #endif |
+ |
+It's better to do this: |
+ |
+ Foo::Foo() : does_thing_that_way_(PlatformStyle::kFooDoesThingThatWay) |
+ |
+ void Foo::DoThing() { |
+ if (does_thing_that_way_) |
+ ... |
+ else |
+ ... |
+ } |
+ |
+This pattern makes it possible to unit-test all the different platform behaviors |
+on one platform. |
+ |
+### Use subclassing to add complex behavior switches |
+ |
+If a lot of the behavior of Foo needs to change per-platform, creating |
+platform-specific subclasses of Foo and a factory method on Foo that creates the |
+appropriate subclass for the platform is easier to read and understand than |
+having ifdefs or lots of control flow inside Foo to implement per-platform |
+behavior. |
+ |
+Note that it's best only to do this when no other alternative presents itself, |
+because having multiple subclasses to do different behaviors per-platform makes |
+subclassing a control require one subclass per platform as well. It's better to |
+abstract the per-platform behavior into a separate model class, with a factory |
+that produces the right model for the current platform. |
+ |
+## UI Layout / Controls |
+ |
+TODO(ellyjones): This section needs a bit more thought. |
+ |
+Some platforms have conventions about the ordering of buttons in dialogs, or the |
+presence or absence of certain common controls. For example, on Mac, dialogs are |
+expected to have their "default" button at the bottom right, and expected not to |
+have a "close" button in their top corner if they have a "Cancel"/"Dismiss" |
+button in the dialog body. If you can design a layout that follows all |
+platforms' conventions simultaneously, that is the lowest-effort route to |
+follow, but if not, there are static booleans in PlatformStyle that hold the |
+appropriate values for these decisions on the current platform, like: |
+ |
+ static const bool PlatformStyle::kDialogsShouldHaveCloseButton; |
+ |
+You can then condition your dialog creation code like this: |
+ |
+ if (PlatformStyle::kDialogsShouldHaveCloseButton) |
+ views::Button* close_button = ...; |
+ |
+TODO(ellyjones): Actually add these variables to PlatformStyle |