Skip to content

AppStudio sample style guide

Gareth Walters edited this page Nov 26, 2015 · 5 revisions

In an effort to try and standardize the look and feel of all of the samples in the QML sample app, we have created a checklist of things to consider while writing and reviewing your samples. Following these guidelines will make the samples look cleaner and consistent. It is also an opportunity for us to deliver a consistent message on styling and best practices with writing ArcGIS Runtime apps with the QML API. Many of the coding guidelines are taken from The Qt Company

This guide is consistent with the samples created for the Qt SDK also. By following this pattern, its possible your sample could be used by the SDK team too.

Style Guide

  • When importing plugins, make sure to use the most recent version of the plugin. This will help make sure that our API works with the latest and greatest plugins from The Qt Company
  • Generally every AppStudio sample will have a primary component of App. This defines the size of the application and also provides a hook into the app properties that you might need.
    App {
        id: app
        width: 640
        height: 480
        
        Map {
        id: map
        }
    }
  • Avoid placing elements like text boxes, buttons, etc in the bottom right, covering the Esri logo.
  • Test sample on all platforms, including low and high DPI devices to ensure that
    • all elements fit on screen
    • all elements scale properly
    • text inside of rectangles, buttons, etc does not extend beyond the element
  • Properties that take a pixel value should be multiplied by display scale factor to adjust for different DPI devices. The exception to this rule appears to be with our API- it seems that Runtime Core already scales the size of things like Simple Marker Symbols for you, so this step is not needed. A property can be declared at the top of the qml file to use throughout the sample. Be sure to have imported ArcGIS.AppFramework 1.0:
import ArcGIS.AppFramework 1.0

property double scaleFactor: AppFramework.displayScaleFactor
  • Items anchored on the side, top, or bottom should have margins set to 10 * scaleFactor
  • If you need a panel of 'controls', preferred anchoring is top left corner. Use a column for the controls, and anchor a background grey box to it. In order to maintain the anchoring of 10, you need ot set the anchoring of the column to 20 and then the margin of the background to -10. eg:
   Rectangle {
        color: "lightgrey"
        radius: 5
        border.color: "black"
        opacity: 0.77
        anchors {
            fill: controlsColumn
            margins: -10 * scaleFactor
        }
    }

    Column {
        id: controlsColumn
        anchors {
            right: parent.right
            top: parent.top
            margins: 20 * scaleFactor
        }
        spacing: 10 * scaleFactor

        CheckBox {
            text: "Wrap Around Enabled"
            checked: true
        }

        CheckBox {
            text: "Esri Logo Visible"
            checked: true
        }
    }
  • Always import the most recent version of the plugin (e.g. QtQuick 2.3 and not 2.0)
  • Try to order your import statements alphabetically. However, ArcGIS plugins will go at the bottom of the list:
import QtQuick 2.3
import QtQuick.Controls 1.2
import ArcGIS.AppFramework 1.10
import ArcGIS.AppFramework.Runtime 1.0
  • Source code should always start with our copyright information
// Copyright 2015 ESRI
//
// All rights reserved under the copyright laws of the United States
// and applicable international laws, treaties, and conventions.
//
// You may freely redistribute and use this sample code, with or
// without modification, provided you include the original copyright
// notice and use restrictions.
//
// See the Sample code usage restrictions document for further information.
//
  • Highlight everything and hit ctrl + i to get auto formatting
  • Properties should have the colon directly after the property name with no space
* Right
width: 100

* Wrong
width : 100
  • JavaScript functions should be camelCase with a lower case first letter (e.g. thisIsMyFunction())
  • Each child component should be proceeded with an empty line above it. This will help improve readability:
* Right
    Column {
        width: 150 * scaleFactor
        anchors {
            top: parent.top
            left: parent.left
            margins: 20 * scaleFactor
        }
        spacing: 7 * scaleFactor

        Text {
            text: qsTr("Click on a graphic to select it. Then, click on another location on the map to move the graphic to the new location.  Right-click to clear selections.")
            font.pixelSize: 14 * scaleFactor
            width: 150 * scaleFactor
            wrapMode: Text.WordWrap
        }
    }

* Wrong
    Column {
        width: 150 * scaleFactor
        anchors {
            top: parent.top
            left: parent.left
            margins: 20 * scaleFactor
        }
        spacing: 7 * scaleFactor
        Text {
            text: qsTr("Click on a graphic to select it. Then, click on another location on the map to move the graphic to the new location.  Right-click to clear selections.")
            font.pixelSize: 14 * scaleFactor
            width: 150 * scaleFactor
            wrapMode: Text.WordWrap
        }
    }
  • For component declaration and JavaScript functions, curly braces go on the same line with one space between the name and the curly brace. Curly brace does not go on next line. This is the more common style for JavaScript as opposed to C++:
* Right

function myFunction() {
    console.log("This is how it's done");
}

* Wrong

function myFunction() 
{
    console.log("Try to avoid this");
}
  • If components are not being referenced from other components or imperative code, no ID is needed
  • The id of the Map component should always be “Map” e.g. mainMap, overviewMap.
  • Avoid assignment of default values to properties (ex setting magnifierOnPressAndHold to false)
  • Every component should have an id if it is referenced to do something. There are so many components that the Hungarian notation doesn't suit anymore. Please use .
    • titleText -
    • gpsOnOffButton -
    • birdsFeatureLayer -

There are always exceptions, things where items are used only once in an application such as PortalSignInDialog and are hard to describe with any other name. Using the component name only be the best practice.

  • The first property listed in your component should always be id. If the component contains custom properties, these should be the second item. Otherwise, the second item should be anchors, absolute location, or size.
  • JavaScript functions will go at the end of the component:
* Right

Map {
     id: mainMap
     anchors.fill: parent
     function addMyLayers() {
     } 
}

* Wrong

Map {
     function addMyLayers() {
     } 
     id: mapMain
     anchors.fill: parent
}
  • If using a property like anchors or font that can be grouped, utilize this to make your code cleaner:
* Right

anchors {
    left: parent.left
    right: parent.right
    top: parent.top
}

* Wrong

anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
  • each property should go on its own line, and should not span a line:
* Right

Rectangle { 
    width: 100 
    height: 100 
}

* Wrong

Rectangle { width: 100; height: 100 }
  • Blocks of code that are commented out should be removed from the sample.
  • If comments are needed, make sure they are useful and not stating the obvious.
  • Unused or unnecessary code should be removed from the sample.
  • Unless relevant, console.log() messages should be removed from the final sample.
  • If using States, the states names should be written in CamelCase
  • JavaScript lines need to end in semi-colon.
  • When using the equal operator in JavaScript, make sure to always use === instead of ==. This ensures value and type are compared, not just value.
  • When accessing a component's property inside of a signal handler, use the id to access the property instead of just stating the property name
* Right

Item {  
    x: 1
    y: x // somewhat ok, if small qml file and access nearby  
    ....  
    +200 lines  
    ....  
    onZChanged: { 
        itemTest.y = 5 
    } 
}

* Wrong

Item {  
    x: 1
    y: x
    ....  
    +200 lines  
    ....  
    onZChanged: { 
        y = 5 //wrong  
    } 
}
  • For if/else statements, only use curly bracket if more than 1 line. If there is more than one line inside of your if statement, the opening curly brace goes on the same line as the if statement:
*  Right

if (flickableItem === null)  
    return undefined; 
if (orientation === Qt.Vertical) {  
    if (anchors.topMargin > 0 || anchors.bottomMargin > 0)  
        return flickableItem.height - style.current.get("thickness")  ;
    else  
        return flickableItem.height  
} else if (orientation === Qt.Horizontal) {  
    return style.current.get("thickness")  ;
}

*  Wrong

if (flickableItem == null)  
    return undefined  
if (orientation == Qt.Vertical) {  
    if (anchors.topMargin > 0 || anchors.bottomMargin > 0) {  
        return flickableItem.height - style.current.get("thickness")  
    }  
    else {  
        return flickableItem.height  
        }  
}  
else if (orientation == Qt.Horizontal) {  
    return style.current.get("thickness")  
}

Description

  • Make sure there is a clear description with proper spelling/grammar
  • Make sure any reference to a component/class name is exactly correct and matches the API/Documentation
  • For URLs, use an href so that they are hyperlinked

General consistencies

  • Esri and not ESRI nor esri
  • WrapAround should not be set to true
  • ArcGIS Runtime SDK for Qt and not ArcGIS Runtime SDK for QML