Development/Tutorials/Plasma2/QML2/API: Difference between revisions
(Containments removed in Plasma 2) |
m (fix typos, bump QML imports, fix code formatting, add explicit arguments to handlers using arrow function notation) |
||
(20 intermediate revisions by 9 users not shown) | |||
Line 10: | Line 10: | ||
To denote that this Plasmoid is a Declarative widget, ensure that in the metadata.desktop file there is this line: | To denote that this Plasmoid is a Declarative widget, ensure that in the metadata.desktop file there is this line: | ||
X-Plasma-API=declarativeappletscript | X-Plasma-API=declarativeappletscript | ||
What follows is a description of the Plasma declarative classes instantiable from QML. | What follows is a description of the Plasma declarative classes instantiable from QML. | ||
== | == Fetching Data from the Plasmoid Package == | ||
If you have a file in your plasmoid package under contents, let's say an image, you can access it with the plasmapackage url protocol: | If you have a file in your plasmoid package under contents, let's say an image, you can access it with the plasmapackage url protocol: | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
Line 32: | Line 33: | ||
Similarly, the above code will import a javascript file from the folder contents/code of your plasmoid package. | Similarly, the above code will import a javascript file from the folder contents/code of your plasmoid package. | ||
= | = Attached Plasmoid object = | ||
The root qml 2.0 item can export some properties to influence its behavior: | The root qml 2.0 item can export some properties to influence its behavior: | ||
FIXME [http://notmart.org/blog/2014/02/making-plasmoids-qml-api-better/ See here in the meanwhile] | |||
= Main Plasma QML Classes = | |||
== | |||
The main documentation for the QML components can be found [https://api.kde.org/frameworks/plasma-framework/html/index.html here]. | |||
== Data Engines == | == Data Engines == | ||
Line 117: | Line 46: | ||
=== DataSource === | === DataSource === | ||
DataSource is a receiver for a | [http://api.kde.org/frameworks-api/frameworks5-apidocs/plasma-framework/html/classPlasma_1_1DataSource.html DataSource] is a receiver for a [http://api.kde.org/frameworks-api/frameworks5-apidocs/plasma-framework/html/classPlasma_1_1DataEngine.html DataEngine] and can be declared inside QML: | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
Line 145: | Line 74: | ||
It has the following signals: | It has the following signals: | ||
Note that javascript/qml applies the 'on' prefix to signals. So the actual signal name in C++ which is e.g. '''newData'''( | Note that javascript/qml applies the 'on' prefix to signals. So the actual signal name in C++ which is e.g. '''newData'''(arg1, …) becomes '''onNewData''': (arg1, …) => {/*…*/} | ||
* ''' | * '''newData'''(string sourceName, Plasma::DataEngine::Data data) | ||
* ''' | * '''sourceAdded'''(string source) | ||
* ''' | * '''sourceRemoved'''(string source) | ||
* ''' | * '''sourceConnected'''(string source) | ||
* ''' | * '''sourceDisconnected'''(string source) | ||
* ''' | * '''intervalChanged'''() | ||
* ''' | * '''engineChanged'''() | ||
* ''' | * '''dataChanged'''() | ||
* '''connectedSourcesChanged'''() | |||
* '''sourcesChanged'''() | |||
You normally want to use '''onNewData''' (that is the equivalent to '''dataUpdated''' in other languages). Here is a sample with the time dataengine: | |||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
import QtQuick 2. | import QtQuick 2.15 | ||
import org.kde.plasma.core 2. | import org.kde.plasma.core 2.1 as PlasmaCore | ||
Item { | Item { | ||
PlasmaCore.DataSource { | |||
id: dataSource | |||
engine: "time" | |||
connectedSources: ["Local", "UTC"] | |||
interval: 500 | |||
onNewData: (sourceName, data) => { | |||
if (sourceName === "Local"){ | |||
local.text = data.Time; | |||
} else if (sourceName === "UTC") { | |||
label_utc.text = data.Timezone; | |||
} | |||
} | |||
} | |||
Grid { | |||
columns: 2 | |||
spacing: 5 | |||
Text { | |||
text: dataSource.data.Local.Timezone | |||
} | |||
Text { | |||
id: local | |||
text: "XX:XX:XX" | |||
} | |||
Text { | |||
id: label_utc | |||
text: "XXXX" | |||
} | } | ||
Text { | |||
id: utc | |||
text: dataSource.data.UTC.Time | |||
} | } | ||
} | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
You see two different | You see two different approaches to get to the data: | ||
* One is to act on ''onNewData'' | * One is to act on ''onNewData'' | ||
Line 217: | Line 151: | ||
=== Service === | === Service === | ||
Due to their imperative nature, Plasma Services are not instantiated as QML classes, but rather created out of a '''DataSource''' with the method '''serviceForSource''' and used in the JavaScript portions of the QML files. | Due to their imperative nature, [http://api.kde.org/frameworks-api/frameworks5-apidocs/plasma-framework/html/classPlasma_1_1Service.html Plasma Services] are not instantiated as QML classes, but rather created out of a [http://api.kde.org/frameworks-api/frameworks5-apidocs/plasma-framework/html/classPlasma_1_1DataSource.html '''DataSource'''] with the method '''serviceForSource''' and used in the JavaScript portions of the QML files. | ||
This following example is a simplified version from the | This following example is a simplified version from the Media Controller QML widget in the kde-workspace git repository: | ||
<syntaxhighlight lang="javascript"> | <syntaxhighlight lang="javascript"> | ||
var service = mpris2Source.serviceForSource(activeSource); | |||
var operation = service.operationDescription("Play"); | |||
service.startOperationCall(operation); | |||
</syntaxhighlight> | </syntaxhighlight> | ||
Here | Here mpris2Source is the id of a DataSource object, and activeSource is a source contained in one of its '''connectedSources'''. | ||
The service provides an operation called " | The service provides an operation called "Play", that executes the operation for "Play" when service.startOperationCall(operation) is called. | ||
=== ServiceJob === | === ServiceJob === | ||
Line 281: | Line 213: | ||
A special reserved role will always be present: '''"DataEngineSource"''': it will contain the name of the data engine source that gave origin to this item. Therefore, if you want merely the string of the current source that the model is at...do model["DataEngineSource"]. | A special reserved role will always be present: '''"DataEngineSource"''': it will contain the name of the data engine source that gave origin to this item. Therefore, if you want merely the string of the current source that the model is at...do model["DataEngineSource"]. | ||
=== SortFilterModel === | === SortFilterModel === | ||
Line 533: | Line 463: | ||
* real '''bottom''' (read only) | * real '''bottom''' (read only) | ||
=== | === ToolTipArea === | ||
Declaring a ToolTip instance makes it possible to use Plasma tooltips with any QML item. | Declaring a [http://api.kde.org/frameworks-api/frameworks5-apidocs/plasma-framework/html/classToolTip.html ToolTip] instance makes it possible to use Plasma tooltips with any QML item. | ||
Properties: | Properties: | ||
* String '''mainText''' | * String '''mainText''' | ||
* String '''subText''' | * String '''subText''' | ||
* String ''' | * String '''icon''': freedesktop compliant icon name as image of the tooltip | ||
* ... | |||
example: | |||
{{Input|<syntaxhighlight lang="cpp-qt" line> | |||
PlasmaCore.IconItem { | |||
... | |||
PlasmaCore.ToolTipArea { | |||
mainText: i18n("Tooltip Title") | |||
subText: i18n("Some explanation.") | |||
icon: "plasma" | |||
// alternatively, you can specify your own component | |||
// to be loaded when the tooltip shows | |||
mainItem: Component { | |||
YourCustomItem { ... } | |||
} | |||
... } | |||
</syntaxhighlight>}} | |||
= Plasma QtComponents = | = Plasma QtComponents = |
Latest revision as of 14:09, 2 November 2022
Introduction to the Plasmoid QML 2 Declarative API
This document provides an overview/reference of the Declarative QML 2 API for Plasmoids. It isn't a full binding to all of Qt 5.2 or KDE's libraries, but a focused set of bindings designed to make writing Plasmoids fast and easy, while remaining powerful.
The API in this documentation covers the API of the Plasma specific QML components, so only the Declarative part of the API.
What Is a Declarative Plasmoid?
To denote that this Plasmoid is a Declarative widget, ensure that in the metadata.desktop file there is this line:
X-Plasma-API=declarativeappletscript
What follows is a description of the Plasma declarative classes instantiable from QML.
Fetching Data from the Plasmoid Package
If you have a file in your plasmoid package under contents, let's say an image, you can access it with the plasmapackage url protocol:
Image {
source: "plasmapackage:/images/foo.png"
}
The above code will load in the Image component the file foo.png located in contents/images of your plasmoid package.
import "plasmapackage:/code/foo.js" as Foo
Similarly, the above code will import a javascript file from the folder contents/code of your plasmoid package.
Attached Plasmoid object
The root qml 2.0 item can export some properties to influence its behavior:
FIXME See here in the meanwhile
Main Plasma QML Classes
The main documentation for the QML components can be found here.
Data Engines
While it's possible to fetch data from a Plasma DataEngine in the same way as the JavaScript API, it is preferrable to use the following declarative classes:
DataSource
DataSource is a receiver for a DataEngine and can be declared inside QML:
import org.kde.plasma.core 2.0 as PlasmaCore
PlasmaCore.DataSource {
id: dataSource
engine: "time"
connectedSources: ["Local"]
interval: 500
}
Properties
It has the following properties:
- bool valid (read only): true when the DataSource is successfully connected to a data engine
- int interval: interval of polling of the dataengine, if 0 (default value, so no need to specify if you don't need it) no polling will be executed
- string engine: the plugin name of the dataengine to load, e.g. "nowplaying", etc.
- Array(string) connectedSources: all the sources of the dataengine we are connected to (and whose data will appear in the data property)
- Array(string) sources (read only): all the sources available from the dataengine
- variant map data (read only): It's the most important property, it's a map of all the data available from the dataengine: its structure will be as follows:
- each key of the map will be a source name, in connectedSources
- each value will be a variant hash, so an hash with strings as keys and any variant as value
- example: dataSource.data["Local"]["Time"] indicates the Time key of the dataengine source called "Local"
Signals
It has the following signals:
Note that javascript/qml applies the 'on' prefix to signals. So the actual signal name in C++ which is e.g. newData(arg1, …) becomes onNewData: (arg1, …) => {/*…*/}
- newData(string sourceName, Plasma::DataEngine::Data data)
- sourceAdded(string source)
- sourceRemoved(string source)
- sourceConnected(string source)
- sourceDisconnected(string source)
- intervalChanged()
- engineChanged()
- dataChanged()
- connectedSourcesChanged()
- sourcesChanged()
You normally want to use onNewData (that is the equivalent to dataUpdated in other languages). Here is a sample with the time dataengine:
import QtQuick 2.15
import org.kde.plasma.core 2.1 as PlasmaCore
Item {
PlasmaCore.DataSource {
id: dataSource
engine: "time"
connectedSources: ["Local", "UTC"]
interval: 500
onNewData: (sourceName, data) => {
if (sourceName === "Local"){
local.text = data.Time;
} else if (sourceName === "UTC") {
label_utc.text = data.Timezone;
}
}
}
Grid {
columns: 2
spacing: 5
Text {
text: dataSource.data.Local.Timezone
}
Text {
id: local
text: "XX:XX:XX"
}
Text {
id: label_utc
text: "XXXX"
}
Text {
id: utc
text: dataSource.data.UTC.Time
}
}
}
You see two different approaches to get to the data:
- One is to act on onNewData
- Use the data parameter from dataSource
Methods
It has the following methods:
- StringList keysForSource(String source): lists all the keys corresponding to a certain source: for instance in the "time" dataengine, for the "Local" source, keys will be:
- "Timezone Continent"
- "Offset"
- "Timezone"
- "Time"
- "Date"
- "Timezone City"
- Service serviceForSource(String source): returns a Plasma service that corresponds a given source: see the section about services for how to use it.
- void connectSource(String source): adds to connectedSources the new source
- void disconnectSource(String source): removes that source from connectedSources
Service
Due to their imperative nature, Plasma Services are not instantiated as QML classes, but rather created out of a DataSource with the method serviceForSource and used in the JavaScript portions of the QML files. This following example is a simplified version from the Media Controller QML widget in the kde-workspace git repository:
var service = mpris2Source.serviceForSource(activeSource);
var operation = service.operationDescription("Play");
service.startOperationCall(operation);
Here mpris2Source is the id of a DataSource object, and activeSource is a source contained in one of its connectedSources. The service provides an operation called "Play", that executes the operation for "Play" when service.startOperationCall(operation) is called.
ServiceJob
It is necessary to monitor the result of a Service operation, it's possible to connect to the finished signal provided by the job return paramenter of the startOperationCall service method. The finished signal has the same job as parameter, from which is possible to check the variant result property, to check the result.
var service = messagesDataSource.serviceForSource(src)
var operation = "auth";
function result(job) {
statusItem.authorizationStatus = job.result;
print("ServiceJob result: " + job.result + " op: " + job.operationName);
}
var operation = service.operationDescription(operation);
operation.user = userName;
operation.password = password;
var serviceJob = service.startOperationCall(operation);
serviceJob.finished.connect(result);
DataModel
Some data engines return a list of items as their DataSources; for example the hotplug DataEngine lists all devices currently plugged in and the microblog engine lists all tweets/dents visible to a given account. QML provides some item views such as ListView, GridView and Repeater. Using a DataSource, the DataModel QML object can provide a suitable model for those QML item views.
It has the following properties:
- DataSource dataSource: the id of an existing (and connected) DataSource
- String sourceFilter: it's a regular expression. If the DataSource is connected to more than one source, only inserts data from sources matching this filter expression in the model. To, for example, have a source watch all sources beginning with say "name:", the required regexp would be sourceFilter: "name:.*"
- String keyRoleFilter: it's a regular expression. Only data with keys that match this filter expression will be inserted in the model. If you need all data inserted in the mode, you must explicitly request it using the regular expression ".*"
- int count (read only): how many items are in the model
Example:
ListView {
model: PlasmaCore.DataModel {
dataSource: microblogSource
keyRoleFilter: "[\\d]*"
}
delegate: Text {
text: title
}
}
In the example, microblogSource is the id of a DataSource, and inserts in the model only entries that have a number as the key name (matched with [\\d]*, in this case tweets ids)
Each item in the model will have the form of a variant hash: all the keys of the hash will be registered as model role names, in the example, "title" is a role of the model containing a string (also reachable with model["title"]).
A special reserved role will always be present: "DataEngineSource": it will contain the name of the data engine source that gave origin to this item. Therefore, if you want merely the string of the current source that the model is at...do model["DataEngineSource"].
SortFilterModel
SortFilterModel is a proxy model for easy sorting and/or filtering of the items in a DataModel (or any other QAbstractItemModel subclass that has been registered in QML with setContextProperty from a C++ application) Properties:
- model sourceModel
- String filterRegExp
- String filterRole
- String sortRole
- Qt::SortOrder sortOrder
- Qt::CaseSensitivity sortCaseSensitivity
- int count (read only)
This is an example from the feed widget:
model: PlasmaCore.SortFilterModel {
id: postTitleFilter
filterRole: "title"
sortRole: "time"
sortOrder: "DescendingOrder"
filterRegExp: toolbarFrame.searchQuery
sourceModel: PlasmaCore.SortFilterModel {
id: feedCategoryFilter
filterRole: "feed_url"
sourceModel: PlasmaCore.DataModel {
dataSource: feedSource
keyRoleFilter: "items"
}
}
}
Plasma Themes
Theme
This class instantiable from QML provides access to the Plasma Theme colors and other facilities such as fonts. Theme instance is always present given the org.kde.plasma.core plugin was imported, is not necessary to create it by hand. It has the following properties:
- String themeName (read only)
- bool windowTranslucentEnabled (read only)
- bool useGlobalSettings (read only)
- QString wallpaperPath (read only)
- KPluginInfo pluginInfo (read only)
- color textColor (read only)
- color highlightColor (read only)
- color backgroundColor (read only)
- color buttonTextColor (read only)
- color buttonBackgroundColor (read only)
- color linkColor (read only)
- color visitedLinkColor (read only)
- color visitedLinkColor (read only)
- color buttonHoverColor (read only)
- color buttonFocusColor (read only)
- color viewTextColor (read only)
- color viewBackgroundColor (read only)
- color viewHoverColor (read only)
- color viewFocusColor (read only)
- String styleSheet (read only)
- Font defaultFont (read only)
- Font desktopFont (read only)
- Font smallestFont (read only)
- int smallIconSize (read only)
- int smallMediumIconSize (read only)
- int mediumIconSize (read only)
- int largeIconSize (read only)
- int hugeIconSize (read only)
- int enormousIconSize (read only)
- int defaultIconSize (read only)
Methods:
- QSizeF mSize(QFont font)
Each Font element has the following properties:
- bool bold
- Capitalization capitalization (MixedCase, AllUppercase, AllLowercase, SmallCaps, Capitalize) (read only)
- String family (read only)
- bool italic (read only)
- real letterSpacing (read only)
- int pixelSize (read only)
- real pointSize (read only)
- bool strikeout (read only)
- bool underline (read only)
- Weight weight (Light, Normal, DemiBold, Bold, Black) (read only)
- real wordSpacing (read only)
Theme is also used to control icon sizes, with the property iconSizes. it is an Object, that has the following properties:
- int desktop: size of icons suited for the workspace
- int toolbar: icons to be put in a ToolBar component
- int small: smallest size for still "readable" icons
- int dialog: icons to be put in popup dialogs
Svg
Declaring a Svg element instantiates a Plasma Svg instance. This class doesn't draw anything. For drawing, SvgItem is used. Properties:
- QSize size
- bool multipleImages
- String imagePath can be anything in the desktoptheme/ folder. For more information on what is available, see Plasma Theme Elements. Make sure to strip the final extension from this string, so you should for example use
"dialogs/background"
to get the standard background. - bool usingRenderingCache
Methods:
- QPixmap pixmap(QString elementID)
- void resize(qreal width, qreal height)
- void resize(): resets the image to its default dimension
- QSize elementSize(QString elementId)
- QRectF elementRect(QString elementId)
- bool hasElement(QString elementId)
- bool isValid(): true if valid svg file
FrameSvg
Declaring a FrameSvg element instantiates a Plasma FrameSvg instance. This class doesn't draw anything. For drawing, FrameSvgItem is used. This is to be used when you need informations about the framesvg, such as hasElementPrefix().
Properties:
- All properties from Svg
- EnabledBorders enabledBorders: flag combination of:
- NoBorder
- TopBorder
- BottomBorder
- LeftBorder
- RightBorder
Methods:
- All methods from Svg
- void setImagePath(QString path)
- void resizeFrame(QSize size)
- QSize frameSize()
- qreal marginSize(Plasma::MarginEdge edge)
- void getMargins(qreal left, qreal top, qreal right, qreal bottom): parameters are output, they get set with the margins from the FrameSvg
- QRectF contentsRect(): the rectangle of the center element, taking the margins into account.
- void setElementPrefix(QString prefix)
- bool hasElementPrefix(const QString prefix)
- QString prefix()
- void setCacheAllRenderedFrames(bool cache)
- bool cacheAllRenderedFrames()
- void clearCache()
- QPixmap framePixmap()
Sample Code:
PlasmaCore.FrameSvg {
id: myFrameSvg
imagePath: "widgets/button"
prefix: "pressed"
}
SvgItem
It's a graphical element that will actually paint a Svg instance. Properties:
- String elementId: what element to render. If null, the whole svg will be rendered
- Svg svg: instance of the Svg class mentioned above
- QSizeF naturalSize (read only): default size of the Svg
- bool smooth: paint with antialias (default false)
Sample Code:
PlasmaCore.SvgItem {
id: mySvgItem
anchors {
top: parent.top
left: parent.left
}
width: 300
height: 3
svg: mySvg
elementId: "horizontal-line"
}
FrameSvgItem
It's a graphical element that paints a Plasma::FrameSvg, so a rectangular image composed by 9 elements contained in a Svg file, useful for things like buttons and frames.
Flags
- EnabledBorders: combination of TopBorder | BottomBorder | LeftBorder | RightBorder, NoBorder if no border of the frame is enabled
Properties:
- String imagePath: path of the file relative to the Plasma Theme, for instance "widgets/background"
- String prefix: a FrameSvg can contain multiple frames, for instance a button contains "normal", "raised" and "pressed"
- Margins margins (read only): the margins of the frame, see documentation below
- EnabledBorders enabledBorders: what borders are enabled
Margins
Properties:
- real left (read only)
- real top (read only)
- real right (read only)
- real bottom (read only)
Sample Code:
PlasmaCore.FrameSvgItem {
id: myFrameSvgItem
anchors.fill: parent
imagePath: "translucent/dialogs/background"
}
Top Level windows
Dialog
Dialog instantiates a Plasma::Dialog, it will be a Plasma themed top level window that can contain any QML component.
Properties:
- Item mainItem: the Item contained in the Dialog, it can be any QML Item instance
- bool visible: if the window (not the mainItem) is visible
- int x: x position of the window in screen coordinates
- int y: y position of the window in screen coordinates
- int width (read only): total width of the dialog, including margins
- int height (read only): total height of the dialog, including margins.
- int windowFlags: Qt window flags of the Dialog
- Margins margins (read only): margins of the Dialog
import QtQuick 2.0
import org.kde.plasma.core 2.0 as PlasmaCore
Item {
PlasmaCore.Dialog {
visible: true
mainItem: Item {
width: 500
height: 500
Text {
anchors.centerIn: parent
color: "red"
text: qsTr("text")
}
}
}
}
Methods:
- QPoint popupPosition(Item item, Qt::Alignment alignment=Qt::AlignLeft): the suggested position for the Dialog if it has to be correctly placed as popup of the QML item passed as parameter.
- void setAttribute(Qt::WindowAttribute attribute, bool on): set an attribute for the dialog window
Margins
Properties:
- real left (read only)
- real top (read only)
- real right (read only)
- real bottom (read only)
ToolTipArea
Declaring a ToolTip instance makes it possible to use Plasma tooltips with any QML item.
Properties:
- String mainText
- String subText
- String icon: freedesktop compliant icon name as image of the tooltip
- ...
example:
PlasmaCore.IconItem { ... PlasmaCore.ToolTipArea { mainText: i18n("Tooltip Title") subText: i18n("Some explanation.") icon: "plasma" // alternatively, you can specify your own component // to be loaded when the tooltip shows mainItem: Component { YourCustomItem { ... } } ... }
Plasma QtComponents
Plasma components documentation online at api.kde.org
QtExtraComponents
The QtExtraComponents make some very convenient Qt classes usable from within QML.
They can be imported in your code with:
import org.kde.qtextracomponents 2.0
QPixmapItem
This one wraps around a QPixmap class and allows you to send a QPixmap directly to QPixmapItem.
Properties:
- QPixmap pixmap: The QPixmap object.
- bool smooth: Set to true to render smooth.
- int nativeWidth: (verification needed) The QPixmap width
- int nativeHeight: (verification needed) The QPixmap height
- FillMode fillMode: see below
QImageItem
This one wraps around a QImage class and allows you to send a QImage directly to QImageItem.
Properties:
- QImage image: The QImage object.
- bool smooth: Set to true to render smooth.
- int nativeWidth: (verification needed) The QImage width
- int nativeHeight: (verification needed) The QImage height
- FillMode fillMode: see below
FillMode
Both QPixmapItem and QImageItem expose a FillMode enum. This enum defines how the image is going to be used to fill the item.
For QPixmapItem, possible values are:
- QPixmapItem.Stretch: the image is scaled to fit
- QPixmapItem.PreserveAspectFit: the image is scaled uniformly to fit without cropping
- QPixmapItem.PreserveAspectCrop: the image is scaled uniformly to fill, cropping if necessary
- QPixmapItem.Tile: the image is duplicated horizontally and vertically
- QPixmapItem.TileVertically: the image is stretched horizontally and tiled vertically
- QPixmapItem.TileHorizontally : the image is stretched vertically and tiled horizontally
QImageItem defines the same values, you just need to replace QPixmapItem with QImageItem.
QIconItem
This one wraps around a QPixmap class and allows you to send a QIcon directly to QIconItem.
Properties:
- QIcon/QString icon: If you provide a QIcon it uses that directly. If you provide a string it uses a KIcon internally!
- bool smooth: Set to true to render smooth.
- int implicitWidth: Default width of as set in SystemSettings->Applications Appearance->Icons
- int implicitHeight: Default height of as set in SystemSettings->Applications Appearance->Icons
- State state: Icon state (DefaultState, ActiveState, DisabledState)