-
Notifications
You must be signed in to change notification settings - Fork 415
Advanced Theming
UIID’s (User Interface IDentifier) are unique qualifiers given to UI components that associate a set of theme definitions with a specific set of components. E.g. we can associate the Button
UIID with a component and then define the look for the Button
in the theme.
One of the biggest advantages with UIID’s is the ability to change the UIID of a component. E.g. to create a multiline label, one can use something like:
TextArea t = …;
t.setUIID("Label");
t.setEditable(false);
Tip
|
This is pretty much how components such as SpanLabel are implemented internally. |
UIID’s can be customized via the GUI builder and allows for powerful customization of individual components.
Note
|
The class name of the component is commonly the same as the UIID, but they are in essence separate entities. |
There are two use cases in which you would want to use layering:
-
You want a slightly different theme in one platform
-
You want the ability to customize your theme for a specific use case, e.g. let a user select larger fonts
This is actually pretty easy to do and doesn’t require re-doing the entire theme. You can do something very similar to the cascading effect of CSS where a theme is applied "on top" of another theme. To do that just add a new theme using the Add Theme button.
Important
|
Make sure to remove the includeNativeBool constant in the new theme!
|
In the new theme define the changes e.g. if you just want a larger default font define only that property for all the relevant UIID’s and ignore all other properties!
For a non-gui builder app the theme loading looks like this by default:
theme = UIManager.initFirstTheme("/theme");
You should fix it to look like this:
theme = UIManager.initNamedTheme("/theme", "Theme");
Note
|
This assumes the name of your main theme is "Theme" (not the layer theme you just added). |
The original code relies on the theme being in the 0 position in the theme name array which might not be the case!
When you want to add the theme layer just use:
UIManager.getInstance().addThemeProps(theme.getTheme("NameOfLayerTheme"));
The addThemeProps
call will layer the secondary theme on top of the primary "Theme" and keep the original UIID’s defined in the "Theme" intact.
If you apply theme changes to a running application you can use Form’s `refreshTheme()
to update the UI instantly and provide visual feedback for the theme changes.
When we want to adapt the look of an application to different OS conventions one of the common requirements is to use different icons. Sometimes we want to change behavior based on device type e.g. have a different UI structure for a Tablet.
Codename One allows you to override a resource for a specific platform when doing this you can redefine a resource differently for that specific platform and also add platform specific resources.
Overriden
resources take precedence over embedded resources thus allowing us to change the look or even behavior (when overriding a GUI builder element) for a specific platform/OS.
Important
|
Overriding the theme is dangerous as a theme has external dependencies (e.g. image borders). The solution is to use theme layering and override the layer! |
To override select the platform where overriding is applicable
You can then click the green checkbox to define that this resource is specific to this platform. All resources added when the platform is selected will only apply to the selected platform. If you change your mind and are no longer interested in a particular override just delete it in the override mode and it will no longer be overridden.
The Codename One Designer has a tab for creating constants which can be used to add global values of various
types and behavior hints to Codename One and its components. Constants are always strings, there are some
conventions that allow the UI to adapt to input various types more easily e.g. if a constant ends with the word Bool it is treated as a boolean (true/false) value and will be displayed as a checkbox. Similarly Int
will display a numeric picker and Image
will show a combo box to pick an image.
Important
|
The combo box in the designer for adding a theme constant is editable, you can just type in any value you want! |
To use a constant one can use the UIManager's methods to get the appropriate constant type specifically:
-
getThemeConstant
-
isThemeConstant
-
getThemeImageConstant
Internally, Codename One has several built in constants and the list is constantly growing. As we add features to Codename One, we try to keep this list up to date but the very nature of theme constants is "adhoc" and some might not make it here.
Constant | Description/Argument |
---|---|
alwaysTensileBool |
Enables tensile drag even when there is no scrolling in the container (only for scrollable containers) |
backGestureThresholdInt |
The threshold for the back gesture in the SwipeBackSupport class, defaults to 5 |
backUsesTitleBool |
Indicates to the GUI builder that the back command should use the title of the previous form and not just the word "Back" |
defaultCommandImage |
Image to give a command with no icon |
dialogButtonCommandsBool |
Place commands in the dialogs as buttons |
dialogPosition |
Place the dialog in an arbitrary border layout position (e.g. North, South, Center, etc.) |
centeredPopupBool |
Popup of the combo box will appear in the center of the screen |
changeTabOnFocusBool |
Useful for feature phones, allows changing the tab when the focus changes immediately, without pressing a key |
checkBoxCheckDisImage |
CheckBox image to use instead of Codename One drawing it on its own |
checkBoxCheckedImage |
CheckBox image to use instead of Codename One drawing it on its own |
checkBoxOppositeSideBool |
Indicates the check box should be drawn on the opposite side to the text and not next to the text |
checkBoxUncheckDisImage |
CheckBox image to use instead of Codename One drawing it on its own |
checkBoxUncheckedImage |
CheckBox image to use instead of Codename One drawing it on its own |
comboImage |
Combo image to use instead of Codename One drawing it on its own |
commandBehavior |
Indicates how commands should act, as a touch menu, native menu etc. Possible values: SoftKey, Touch, Bar, Title, Right, Native |
ComponentGroupBool |
Enables component group, which allows components to be logically grouped together, so the UIID’s of components would be modified based on their group placement. This allows for some unique styling effects where the first/last elements have different styles from the rest of the elements. It’s disabled by default, thus leaving its usage up to the designer |
dialogTransitionIn |
Default transition for dialog |
dialogTransitionInImage |
Default transition Image for dialog, causes a Timeline transition effect |
dialogTransitionOut |
Default transition for dialog |
defaultCommandImage |
An image to place on a command if none is defined, only applies to touch commands |
defaultEmblemImage |
The emblem painted on the side of the multibutton, by default this is an arrow on some platforms |
dialogTransitionOutImage |
Default transition Image for dialog, causes a Timeline transition effect |
disabledColor |
Color to use when disabling entries by default |
dlgButtonCommandUIID |
The UIID used for dialog button commands |
dlgCommandButtonSizeInt |
Minimum size to give to command buttons in the dialog |
dlgCommandGridBool |
Places the dialog commands in a grid for uniform sizes |
dlgInvisibleButtons |
Includes an RRGGBB color for the line separating dialog buttons, as is the case with Android 4 and iOS 7 buttons in dialogs |
dlgSlideDirection |
Slide hints |
dlgSlideInDirBool |
Slide hints |
dlgSlideOutDirBool |
Slide hints |
drawMapPointerBool |
Indicates whether a pointer should appear in the center of the map component |
fadeScrollBarBool |
Boolean indicating if the scrollbar should fade when there is inactivity |
fadeScrollEdgeBool |
Places a fade effect at the edges of the screen to indicate that it’s possible to scroll until we reach the edge (common on Android) |
fadeScrollEdgeInt |
Amount of pixels to fade out at the edge |
firstCharRTLBool |
Indicates to the GenericListCellRenderer that it should determine RTL status based on the first character in the sentence |
noTextModeBool |
Indicates that the on/off switch in iOS shouldn’t draw text on top of the switch, which is the case for iOS 7+ but not for prior versions |
fixedSelectionInt |
Number corresponding to the fixed selection constants in List |
formTransitionIn |
Default transition for form |
formTransitionInImage |
Default transition Image for form, causes a Timeline transition effect |
formTransitionOut |
Default transition for form |
formTransitionOutImage |
Default transition Image for form, causes a Timeline transition effect |
hideBackCommandBool |
Hides the back command from the side menu when possible |
hideEmptyTitleBool |
Indicates that a title with no content should be hidden even if the border for the title occupies space |
hideLeftSideMenuBool |
Hides the side menu icon that appears on the left side of the UI |
ignorListFocusBool |
Hide the focus component of the list when the list doesn’t have focus |
infiniteImage |
The image used by the infinite progress component, the component will rotate it as needed |
includeNativeBool |
True to derive from the platform native theme, false to create a blank theme that only uses the basic defaults |
listItemGapInt |
Built-in item gap in the list, this defaults to 2, which predated padding/margin in Codename One |
listLongPressBool |
Indicates whether a list should handle long press events, defaults to true |
mapTileLoadingImage |
An image to preview while loading the MapComponent tile |
mapTileLoadingText |
The text of the tiles in the MapComponent during loading, defaults to "Loading…" |
mapZoomButtonsBool |
Indicates whether buttons should be drawn on the map component |
mediaBackImage |
Media icon used by the media player class |
mediaFwdImage |
Media icon used by the media player class |
mediaPauseImage |
Media icon used by the media player class |
mediaPlayImage |
Media icon used by the media player class |
menuButtonBottomBool |
When set to true this flag aligns the menu button to the bottom portion of the title. Defaults to false |
menuButtonTopBool |
When set to true this flag aligns the menu button to the top portion of the title. Defaults to false |
menuHeightPercent |
Allows positioning and sizing the menu |
menuImage |
The three dot menu image used in Android and the Toolbar to show additional command entries |
menuPrefSizeBool |
Allows positioning and sizing the menu |
menuSlideDirection |
Defines menu entrance effect |
menuSlideInDirBool |
Defines menu entrance effect |
menuSlideOutDirBool |
Defines menu entrance effect |
menuTransitionIn |
Defines menu entrance effect |
menuTransitionInImage |
Defines menu entrance effect |
menuTransitionOut |
Defines menu exit effect |
menuTransitionOutImage |
Defines menu entrance effect |
menuWidthPercent |
Allows positioning and sizing the menu |
minimizeOnBackBool |
Indicates whether the form should minimize the entire application when the physical back button is pressed (if available) and no command is defined as the back command. Defaults to true |
onOffIOSModeBool |
Indicates whether the on/off switch should use the iOS or Android mode |
otherPopupRendererBool |
Indicates that a separate renderer UIID/instance should be used to the list within the combo box popup |
PackTouchMenuBool |
Enables preferred sized packing of the touch menu (true by default), when set to false this allows manually determining the touch menu size using percentages |
paintsTitleBarBool |
Indicates that the StatusBar UIID should be added to the top of the form to space down the title area, as is the case on iOS 7+ where the status bar is painted on top of the UI |
popupCancelBodyBool |
Indicates that a cancel button should appear within the combo box popup |
PopupDialogArrowBool |
Indicates whether the popup dialog has an arrow, notice that this constant will change if you change UIID of the popup dialog |
PopupDialogArrowBottomImage |
Image of the popup dialog arrow, notice that this constant will change if you change UIID of the popup dialog |
PopupDialogArrowTopImage |
Image of the popup dialog arrow, notice that this constant will change if you change UIID of the popup dialog |
PopupDialogArrowLeftImage |
Image of the popup dialog arrow, notice that this constant will change if you change UIID of the popup dialog |
PopupDialogArrowRightImage |
Image of the popup dialog arrow, notice that this constant will change if you change UIID of the popup dialog |
popupNoTitleAddPaddingInt |
Adds padding to a popup when no title is present |
popupTitleBool |
Indicates that a title should appear within the combo box popup |
pullToRefreshImage |
The arrow image used to draw the |
pureTouchBool |
Indicates the pure touch mode |
radioOppositeSideBool |
Indicates the radio button should be drawn on the opposite side to the text and not next to the text |
radioSelectedDisImage |
Radio button image |
radioSelectedImage |
Radio button image |
radioUnselectedDisImage |
Radio button image |
radioUnselectedImage |
Radio button image |
releaseRadiusInt |
Indicates the distance from the button with dragging, in which the button should be released, defaults to 0 |
rendererShowsNumbersBool |
Indicates whether renderers should render the entry number |
reverseSoftButtonsBool |
Swaps the softbutton positions |
rightSideMenuImage |
Same as sideMenuImage only for the right side, optional and defaults to sideMenuImage |
rightSideMenuPressImage |
Same as sideMenuPressImage only for the right side, optional and defaults to sideMenuPressImage |
showBackCommandOnTitleBool |
Used by the Toolbar API to indicate whether the back button should appear on the title |
shrinkPopupTitleBool |
Indicates the title of the popup should be set to 0 if it’s missing |
sideMenuAnimSpeedInt |
The speed at which a sidemenu moves defaults to 300 milliseconds |
sideMenuFoldedSwipeBool |
Indicates the side menu could be opened via swiping |
sideMenuImage |
The image representing the side menu, three lines (Hamburger menu) |
sideMenuPressImage |
Optional pressed version of the sideMenuImage |
sideMenuShadowBool |
Indicates whether the shadow for the side menu should be drawn |
sideMenuShadowImage |
The image used when drawing the shadow (a default is used if this isn’t supplied) |
sideMenuSizeTabPortraitInt |
The size of the side menu when expanded in a tablet in portrait mode |
sideMenuSizePortraitInt |
The size of the side menu when expanded in a phone in portrait mode |
sideMenuSizeTabLandscapeInt |
The size of the side menu when expanded in a tablet in landscape mode |
sideMenuSizeLandscapeInt |
The size of the side menu when expanded in a phone in landscape mode |
sideMenuTensileDragBool |
Enables/disables the tensile drag behavior within the opened side menu |
sideSwipeActivationInt |
Indicates the threshold in the side menu bar at which a swipe should trigger activation, defaults to 15 (percent) |
sideSwipeSensitiveInt |
Indicates the region of the screen that is sensitive to side swipe in the side menu bar, defaults to 10 (percent) |
slideDirection |
Default slide transition settings |
slideInDirBool |
Default slide transition settings |
slideOutDirBool |
Default slide transition settings |
sliderThumbImage |
The thumb image that can appear on the sliders |
snapGridBool |
Snap to grid toggle |
statusBarScrollsUpBool |
Indicates that a tap on the status bar should scroll up the UI, only relevant in OS’s where paintsTitleBarBool is true |
switchButtonPadInt |
Indicates the padding in the on/off switch, defaults to 16 |
switchMaskImage |
Indicates the mask image used in iOS mode to draw on top of the switch |
switchOnImage |
Indicates the on image used in iOS mode to draw the on/off switch |
switchOffImage |
Indicates the off image used in iOS mode to draw the on/off switch |
TabEnableAutoImageBool |
Indicates images should be filled by default for tabs |
TabSelectedImage |
Default selected image for tabs (if TabEnableAutoImageBool=true) |
TabUnselectedImage |
Default unselected image for tabs (if TabEnableAutoImageBool=true) |
tabPlacementInt |
The placement of the tabs in the Tabs component: TOP = 0, LEFT = 1, BOTTOM = 2, RIGHT = 3 |
tabsFillRowsBool |
Indicates if the tabs should fill the row using flow layout |
tabsGridBool |
Indicates whether tabs should use a grid layout thus forcing all tabs to have identical sizes |
tabsOnTopBool |
Indicates the tabs should be drawn on top of their content in a layered UI, this allows a tab to intrude into the content of the tabs |
textCmpVAlignInt |
The vertical alignment of the text component: TOP = 0, CENTER = 4, BOTTOM = 2 |
textFieldCursorColorInt |
The color of the cursor as an integer (not hex) |
tickerSpeedInt |
The speed of label/button etc. (in milliseconds) |
tintColor |
The aarrggbb hex color to tint the screen when a dialog is shown |
topMenuSizeTabPortraitInt |
The size of the side menu when expanded and attached to the top in a tablet in portrait mode |
topMenuSizePortraitInt |
The size of the side menu when expanded and attached to the top in a phone in portrait mode |
topMenuSizeTabLandscapeInt |
The size of the side menu when expanded and attached to the top in a tablet in landscape mode |
topMenuSizeLandscapeInt |
The size of the side menu when expanded and attached to the top in a phone in landscape mode |
touchCommandFillBool |
Indicates how the touch menu should layout the commands within |
touchCommandFlowBool |
Indicates how the touch menu should layout the commands within |
transitionSpeedInt |
Indicates the default speed for transitions |
treeFolderImage |
Picture of a folder for the Tree class |
treeFolderOpenImage |
Picture of a folder expanded for the |
treeNodeImage |
Picture of a file node for the |
tensileDragBool |
Indicates that tensile drag should be enabled/disabled. This is usually set by platform themes |
Once a theme constant is set by a theme, it isn’t removed on a refresh when replacing the theme.
E.g. if one would set the comboImage
constant to a specific value in theme A and then switch to theme B, that doesn’t define the comboImage
, the original theme A comboImage
might remain!
The reason for this is simple: when extracting the constant values, components keep the values in cache locally and just don’t track the change in value. Furthermore, since the components allow manually setting values, it’s impractical for them to track whether a value was set by a constant or explicitly by the user.
The solution for this is to either manually reset undesired values before replacing a theme (e.g. for the case, above by calling the default look and feel method for setting the combo image with a null value), or defining a constant value to replace the existing value.
Codename One uses a theme constant called includeNativeBool
, when that constant is set to true
Codename One starts by loading the native theme first and then applying all the theme settings. This effectively means your theme "derives" the style of the native theme first, similar to the cascading effect of CSS. Internally this is exactly what the theme layering section covered.
By avoiding this flag you can create themes that look EXACTLY the same on all platforms.
Warning
|
If you avoid the native theming you you might be on your own. A few small device oddities such as the iOS status bar are abstracted by native theming. Without it you will need to do everything from scratch. |
You can simulate different OS platforms by using the native theme menu option
Developers can pick the platform of their liking and see how the theme will appear in that particular platform by selecting it and having the preview update on the fly.
To truly understand a theme we need to understand what it is. Internally a theme is just a Hashtable
key/value pair between UIID based keys and their respective values. E.g. the key:
Button.fgColor=ffffff
Will set the foreground color of the Button UIID to white.
When a Codename One Component is instantiated it requests a Style object from the UIManager class. The Style
object is based on the settings within the theme and can be modified thru code or by using the theme.
We can replace the theme dynamically in runtime and refresh the styles assigned to the various components using the refreshTheme() method.
Note
|
It’s a common mistake to invoke refreshTheme() without actually changing the theme. We see developers doing it when all they need is a repaint() or revalidate() . Since refreshTheme() is very expensive we recommend that you don’t use it unless you really need to…
|
A theme Hashtable
key is comprised of:
[UIID.][type#]attribute
The UIID, corresponds to the component’s UIID e.g. Button
, CheckBox etc. It is optional and may be omitted to address the global default style.
The type is omitted for the default unselected type, and may be one of sel (selected type), dis (disabled type) or press (pressed type). The attribute should be one of:
-
derive
- the value for this attribute should be a string representing the base component. -
bgColor
- represents the background color for the component, if applicable, in a web hex string format RRGGBB e.g. ff0000 for red. -
fgColor
- represents the foreground color, if applicable. -
border - an instance of the border class, used to display the border for the component.
-
bgImage
- an Image object used in the background of a component. -
transparency - a
String
containing a number between 0-255 representing the alpha value for the background. This only applies to the bgColor. -
margin
- the margin of the component as aString
containing 4 comma separated numbers for top,bottom,left,right. -
padding
- the padding of the component, it has an identical format to the margin attribute. -
font
- A Font object instance. -
alignment
- anInteger
object containing the LEFT/RIGHT/CENTER constant values defined in Component. -
textDecoration
- anInteger
value containing one of the TEXT_DECORATION_* constant values defined in Style. -
backgroundType
- aByte
object containing one of the constants for the background type defined in Style under BACKGROUND_*. -
backgroundGradient
- contains anObject
array containing 2 integers for the colors of the gradient. If the gradient is radial it contains 3 floating points defining the x, y & size of the gradient.
So to set the foreground color of a selected button to red, a theme will define a property like:
Button.sel#fgColor=ff0000
This information is mostly useful for understanding how things work within Codename One, but it can also be useful in runtime.
E.g. to increase the size of all fonts in the application, we can do something like:
Hashtable h = new Hashtable();
h.put("font", largeFont);
UIManager.getInstance().addThemeProps(h);
Display.getInstance().getCurrent().refreshTheme();
Note
|
This section provides a very high level overview of images. We dive deeper into the various types of images in the graphics section. |
When working with a theme, we often use images for borders or backgrounds. We also use images within the GUI for various purposes and most such images will be extracted from the resource file.
Adding a standard JPEG/PNG image to the resource file is straight forward, and the resulting image can be viewed within the images section. However, due to the wide difference between device types, an image that would be appropriate in size for an iPhone 3gs would not be appropriate in size for a Nexus device or an iPhone 4 (but perhaps, surprisingly, it will be just right for iPad 1 & iPad 2).
DPI (Dots Per Inch) & PPI (Pixels Per Inch) are two shorthand terms used to discuss the variety of device densities. Densities are confusing for first time Codename One developers who struggle with the notion that an iPad might get the same resolution image as a phone.
A first generation the iPad 2 device had a 160 PPI (160 pixels per inch density). The much smaller iPhone 4 from the same era had 320 PPI and modern devices already exceed 600+ PPI values. The contrast is staggering especially when compared to the desktop.
Mobile UI’s are expected to use all available pixels to their full extent. In that sense when an application runs on a tablet you don’t want it to just provide a larger image for the icons but rather have it cram more information into a single form. So we need to rethink image sizing not just in pixels but in millimeters/inches.
The density of the devices varies significantly and Codename One tries to simplify the process by unifying everything into one set of values to indicate density. For simplicity’s sake, density is sometimes expressed in terms of pixels, however it is mapped internally to actual screen measurements where possible.
A multi-image is an image that has multiple varieties for different densities, and thus looks sharp in all the densities. Since scaling on the device can’t interpolate the data (due to performance considerations), significant scaling on the device becomes impractical. However, a multi-image will just provide the “right” resolution image for the given device type.
From the programming perspective this is mostly seamless, a developer just accesses one image and has no ability to access the images in the different resolutions. Within the designer, however, we can explicitly define images for multiple resolutions and perform high quality scaling so the “right” image is available.
We can use two basic methods to add a multi-image: quick add & standard add.
Both methods rely on understanding the source resolution of the image, e.g. if you have an icon that you expect to be 128x128 pixels on iPhone 4, 102x102 on nexus one and 64x64 on iPhone 3gs. You can provide the source image as the 128 pixel image and just perform a quick add option while picking the Very High density option.
This will indicate to the algorithm that your source image is designed for the "very high" density and it will scale for the rest of the densities accordingly.
Tip
|
This relies on the common use case of asking your designer to design for one high end device (e.g. iPhone 6+) then you can just take the resources and add them as "HD" resources and they will automatically adapt to the lower resolutions. |
Alternatively, you can use the standard add multi-image dialog and set it like this:
Notice that we selected the square image option, essentially eliminating the height option. Setting values to 0 prevents the system from generating a multi-image entry for that resolution, which will mean a device in that category will fall on the closest alternative.
The percentage value will change the entire column, and it means the percentage of the screen. E.g. We know the icon is 128 for the very high resolution, we can just move the percentage until we reach something close to 128 in the “Very High” row and the other rows will represent a size that should be pretty close in terms of physical size to the 128 figure.
At runtime, you can always find the host device’s approximate pixel density using the Display.getDeviceDensity()
method. This will return one of:
Constant |
Density |
Example Device |
|
~ 88 ppi |
|
|
~ 120 ppi |
Android ldpi devices |
|
~ 160 ppi |
iPhone 3GS, iPad, Android mdpi devices |
|
~ 240 ppi |
Android hdpi devices |
|
~ 320 ppi |
iPhone 4, iPad Air 2, Android xhdpi devices |
|
~ 540 ppi |
iPhone 6+, Android xxhdpi devices |
|
~ 750 ppi |
Android xxxhdpi devices |
|
~ 1000 ppi |
|
|
~ 1250ppi |
When configuring your styles, you should almost never use "Pixels" as the unit for padding, margins, font size, and border thickness because the results will be inconsistent on different densities. Instead, you should use millimeters for all non-zero units of measurement.
As we now understand the complexities of DPI it should be clear why this is important.
Sometimes millimeters don’t give you enough precision for what you want to do. Currently the designer only allows you to specify integer values for most units. However, you can achieve more precise results when working directly in Java. The Display.convertToPixels()
method will allow you to convert millimeters (or DIPS) to pixels. It also only takes an integer input, but you can use it to obtain a multiplier that you can then use to convert any millimeter value you want into pixels.
E.g.
double pixelsPerMM = ((double)Display.getInstance().convertToPixels(10, true)) / 10.0;
And now you can set the padding on an element to 1.5mm. E.g.
myButton.getAllStyles().setPaddingUnit(Style.UNIT_TYPE_PIXELS);
int pixels = (int)(1.5 * pixelsPerMM);
myButton.getAllStyles().setPadding(pixels, pixels, pixels, pixels);
About This Guide
Introduction
Basics: Themes, Styles, Components & Layouts
Theme Basics
Advanced Theming
Working With The GUI Builder
The Components Of Codename One
Using ComponentSelector
Animations & Transitions
The EDT - Event Dispatch Thread
Monetization
Graphics, Drawing, Images & Fonts
Events
File-System,-Storage,-Network-&-Parsing
Miscellaneous Features
Performance, Size & Debugging
Advanced Topics/Under The Hood
Signing, Certificates & Provisioning
Appendix: Working With iOS
Appendix: Working with Mac OS X
Appendix: Working With Javascript
Appendix: Working With UWP
Security
cn1libs
Appendix: Casual Game Programming