Skip to content
bradsmithee edited this page Nov 10, 2016 · 6 revisions

Description (What is this?)

This addon provides the Unity Editor with adjustable, hot-swappable GUI themes across all elements using native and custom data formats.

Reason (Why was it made?)

The system was initially created to provide on-the-fly adjustable styling standards for custom editor windows/inspectors/properties. It was later extended for global editor usage. It's intended to allow users to establish general-purpose aesthetics that are adaptable to needs as well as uniform to their existing development applications.

Features (What can it do?)

* Supports swapping of editor themes globally or between individual custom editors. * Supports palette (color) adjustment. Palettes are usable between different themes. Alt+F1 and Alt+F2 are hotkeys for previous and next palette. * Supports system color usage (select Windows versions only) as well as manual adjustment. * Supports forced interval repainting as Responsive UI option to allow for global hover/interaction effects. * Supports theme variations and keywords within .unityTheme files. * Supports GUIStyle and GUIContent overriding in base skin as well as static style-container instances.

Approach (How was it done?)

Since the introduction of GUISkin data types (~Unity 2), it's been possible to retrieve and adjust the active GUI.skin for the sake of custom editors. These styles are used for the majority (if not all) of Unity's default immediate-mode-GUI elements. The downside is that many of these core styles are used as independent GUIStyle instances sprinkled through the assembly rather than referenced to the core styles. Below I detail the processes I use to locate, group, localize, and apply these elements as a centralized theme.
Advanced

Themes.SaveGUI

Locate and build assets for style/content data.
  • Reflect the entire UnityEditor assembly for common style/content storage classes. I've found that these are generally stored in Styles, styles, s_GOStyles, s_Current, s_Styles, m_Styles, ms_Styles, constants, and Constants. As this step needs to manually create instances in some cases (to retrieve default values), it can cause mild error warnings. You'll want to change your editor layout (top-right) after running to prevent render issues upon restart.
  • Dump all GUIStyle fields to their own path-named .guiSkin file as customStyles. Styles are labeled by variable name (with the base style in brackets).
  • Dump all GUIContent and GUIContent[] to a path-named .guiContent file. Contents are labeled by variable name. Currently, this step also will dump GUIContent assets to a respective GUIContent subfolder. This process will likely be offset to Themes.SaveAssets in the future.

Themes.SaveAssets

Create assets used by GUISkin.
  • Scan folder for GUISkin files. Save background images and fonts. A "Background" and "Font" folder are created in the path specified.

Themes.LocalizeAssets

Reference created assets.
  • Scan folder for GUISkin files. Override internal/existing background/font references with any name-matched local files from the Themes.SaveAssets step.

Themes.Apply

Load created style/content data.
  • Reflectively apply each saved guiSkin at their supplied fully qualified paths by either overriding or modifying their contents inline.
  • Overriding with a reference to the new GUIStyle is generally the better option. This greatly aids in realtime editing of GUISkin files for interface artists; however, due to some anomalies with load/refresh order when changing skins, inline loading is set by default for general use. Reference/Inline usage for GUIStyles can be toggled via `+2.
  • Each skin is applied by its variable name (rather than order) to give a modicum of cross-version compatibility without requiring specialized skin files for each. If a variable from a newer version is used with an older version of Unity where it does not exist, it will simply be ignored. In the event of missing variables (from newer Unity versions), the system will still load what is available, but new GUIskin/GUIStyle files will need to be built to accommodate the new style fields.
  • Some internal visual elements rely on defined colors, initialization calls/flags, and specialized styles. These are set manually during the Apply process. Manual style overriding is done to combat extreme cases, such as PreferencesWindow.sectionHeader, where the instanced GUIStyle is modified inline with local changes in code after being initialized.

Themes.RebuildData

Flush style data.
  • Due to the nature of instanced GUIStyles from the core GUI.skin, adjustments to the core typically require rebuilding of style caches for the local values to inherit properly.

Creation (How do you create a theme?)

Each theme is comprised of a .unityTheme configuration file, .guiSkin for adjusting builtin immediate-mode GUI styles, and .guiContent files for adjusting non-style editor graphics. Additionally, .unityPalette files may be used by any theme for unified color applications. Although building themes by using only instanced GUIStyles will offer the most per-element customization, using the core skin (to some degree) is recommended. From the @Default folder, it is recommended that @Default.guiskin (rename to your theme name) and UnityEditor.EditorStyles.s_Current.guiSkin (EditorStyles) are copied to get started.
Advanced

Themes (.unityTheme)

Each item of this configuration is parsed/distinguished by newlines. Style variants are marked by text enclosed in brackets []. Variants marked with a + at the start of their name are applied as toggles in the preference window. The first variant is used as the base theme. Usable keywords for variants are as follows :

  • **AllowCustomization**: Toggle the user's options for any customization.
  • **AllowColorCustomization**: Toggle the user's option for palettes and colors.
  • **AllowSystemColor**: Toggle the user's option to use their system's color for palettes.
  • **UseSystemColor**: Set the default state for using the system color. When this option is on, dark and light offsets are automatically calculated at a multiplicative value of 0.8 and 1.3 intensity respectively.
  • **UseColorAssets**: Toggle whether color textures need to be generated/maintained.
  • **WindowBackgroundOverride** : Define a texture by name to be used for window background overlays.
  • **Palette**: Set the default palette (by name) to be used.

Palettes (.unityPalette)

Each item of this configuration is parsed/distinguished by newlines. Each color is defined by a 6 digit (RGB) or 8 digit (RGBA) hex value or comma delimited decimal color (normalized if decimal points used). This file type defines important colors used by your theme. When UseColorAssets is enabled by a theme, a 1x1 solid texture as well as a 9x9 border texture is generated and updated per color for use in your theme's GUIStyle backgrounds. Besides texture usage, the color definitions below alter the following :

  • **Color** : Background used by windows.
  • **LightColor** : Cursor and curve property background.
  • **DarkColor** : Selected text and curve property foreground.

GUIContent (.guiContent)

Each item of this configuration is parsed/distinguished by newlines. The name of each .guiContent file should be a fully qualified namespace. This can be manually defined, but will often be generated by the Themes.SaveGUI reflection scan. Each file contains serialized definitions of GUIContent separated by bracket-enclosed [] field names. Each field has the following keywords available :

  • **text**: String value used for the element (if any).
  • **tooltip**: Text that will display after hovering for some time.
  • **image**: Name of texture to use. The theme's local GUIContent sub-folder will be searched for matching png files of the name chosen.

Skins (.guiSkin)

The name of each .guiSkin file should be a fully qualified namespace. This can be manually defined, but will often be generated by the Themes.SaveGUI reflection scan. These are normal Unity guiSkin files that can be edited natively. The main editor skin file will use the same name as your .unityTheme file. Only the main skin file will use the basic GUIStyles (box, button, etc.). All other skin files rely only on the GUIStyles defined in customStyles.

Future (What features are planned?)

* Additional interfaces/references for developers to unify their custom editor's styles. * Extension of color system to support user-defined names/values. * Support Linux/MacOS for useSystemColor field. * Support for quick overriding and adjustment of font family/sizes and text colors used by a theme. * Option to automatically inverse text colors for elements on backdrops with similar brightness. * Custom .guiContent editor/inspector for in-editor tweaking. * Custom .guiSkin editor with search and group replacement functionality. * Build foundation default skin reference files from all classes containing GUIStyle & GUIContent rather than just known style containers. * Allow Texture2D elements (such as the build window's platform icons) to be collected and replaced

Limitations (What cannot be done with themes?)

  • One of the biggest limiting factor of themes is caused by Unity's hard-coded (constant) vertical-spacing value of 16. Due to this, it's very difficult to create a theme that can use larger fonts or pad out with breathing room. While styles do have exposed parameters for margins/padding, these are used rarely in full degree by Unity.

    Developer Note
    One solution I briefly explored was using a base custom property drawer globally to inject spacing on all elements via an offset to the GetPropertyHeight method. While this worked for most components in the inspector, it proved somewhat limited since custom editors as well as many of Unity's internal editors/inspectors did not correctly not apply its effects -- breaking uniformity benefits.
  • Unlike IDEs such as Visual Studio, the main window decorator (application titlebar) along with the system menu bar are currently not tweakable.

    Developer Note
    I've ran a few traces internally with ILspy with the [MenuItem] attribute as a starting point, but these mostly have just led to internal calls -- meaning configuration data concerning these two aspects is locked down at a program level until Unity exposes them.

Compatibility (What environments will it function with?)

Although the system's premise could theoretically function as far back as Unity 2/3, many of the internal extensions used limit this due to their reliance on modern usage patterns. Currently, the system has been built and tested on Unity 5.0 through 5.4b21 on Windows/Mac. Back-porting to Unity 4 (or earlier) will require adjustments to account for Unity's internal functions changing significantly between major versions.

Issues (What problems are known?)

Bugs should be discussed/reported [here](https://github.com/zios/unity-themes/issues).
Developer Note
Issues with unstyled or incorrectly styled elements usually relate to the theme itself rather than the system. Bear in mind that there are 508 main GUIStyles (as of Unity 5.4b21) with 8 states each that have to be examined and altered. It's very difficult to assign a style if you cannot preview the scenarios where it's used, but this is compounded by sluggish editor inspector performance on large GUISkin as well as many styles having locally instanced overrides to account for.

Download (Where can I obtain it?)

You can obtain the latest release from [here](https://github.com/zios/unity-themes/releases). It includes a pre-built x64 dll for Unity 5, several palettes, and one (work-in-progress) example theme titled Simplicity. The source code is also available for usage/extension/contribution under an MIT license.

Usage (How do you use it?)

Extract the zip file to your project's Assets folder. Configure at Edit > Preferences > Themes.

Contact (How can I reach you?)

If you'd like to make a direct inquiry regarding my work or if you just want a friendly conversation, you can find me idling in the [Game Dev League](https://discordapp.com/invite/0TYNJfCU4De7YIk8) Discord server under the alias Bradical. Failing that, I'm also reachable via email at bradsmithee@gmail.com or (infrequently) on the [Unity Forums](http://forum.unity3d.com/threads/zios-editor-theme-support.411818/) or [Unity Subreddit](https://www.reddit.com/r/Unity3D/comments/4ooayr/unity_editor_theme_support/).

Preview (What does it look like?)

Visual Studio next to Unity Editor. ![Visual Studio and Unity](http://bradsmithee.com/shared/Uniformity.jpg)