Difference between revisions of "QML GUI"

From Navit's Wiki
Jump to: navigation, search
(Added manual on gui commands)
(NGQPoint doc improved)
Line 149: Line 149:
 
==The current point concept==
 
==The current point concept==
  
There are special object 'point' of type NGQPoint that represents a 'current point'. Current point is a point in space (with coordinates and may be with name and other attributes) which is used by other proxy objects. So you don't pass the coordinates or something to navit.setDestination or bookmarks.AddBookmark. You set current point object to their values and and call a function, that processes it. Right now current point object is set in two cases:
+
There are special object 'point' of type NGQPoint that represents a 'current point'. Current point is a point on map (with coordinates and may be with name and other attributes) which is used by other proxy objects. So you don't pass the coordinates or something to navit.setDestination or bookmarks.AddBookmark. You set current point object to their values and call a function, that processes it. The current point object is set in following cases:
 
   * Right click on map
 
   * Right click on map
 +
  * navit.getPosition/navit.getDestination call
 
   * bookmarks.setPoint call
 
   * bookmarks.setPoint call
 +
  * point.setNewPoint call
 +
 +
Point could have a type:
 +
 +
<pre>
 +
    enum NGQPointTypes {MapPoint,Bookmark,Position,Destination,PointOfInterest};
 +
</pre>
 +
 +
which could be used for conditional rendering etc
 +
 +
Point object provides three properties:
 +
    * coordString - Formatted textual representation of point's coordinates.
 +
    * pointName - Name of a point, either specified during point creation/setting or calculated from map data.
 +
    * pointType - Name of point's type.
  
 
==The listModel==
 
==The listModel==

Revision as of 15:38, 4 April 2010

QML gui is designed to be a modern and flexible replacement of internal gui. It is based on Qt's Declarative UI framework, therefore it could be run on any Qt platform, including mobile platforms with touchscreens etc

Building it

First of all - you have to install Qt 4.6 and a SNAPSHOT of a Declarative UI for it, or use a Qt version 4.7 with Declarative UI included.

When you have prepared your Qt environment, it's time to build Navit:

./configure --enable-gui-qml

At the script output you should have the following lines:

Graphics types: yes (default)
  qt_qpainter:       yes (default)
GUI types:
  qml:               yes (configure parameter)

both of them are required for gui qml. So if those lines present, do your usual make && make install/dpkg-buildpackage/your platform specific thing.

Configuring it

Right now QML gui is compatible only with qt_qpainter graphics type. I hope there will be more graphics types in the future, but right now you have to switch to qt_qpainter:

    <graphics type="qt_qpainter"/>

And enable qml gui:

    <gui type="qml" enabled="yes"/>

All other gui modules MUST be disabled by setting

    enabled="no"

in their configuration stanzas.

QML gui doesn't requires any special configuration, but it could be tuned. It supports the following parameters:

   * fullscreen - "1"-Default is fullscreen mode,"0"-Default is windowed mode
   * menu_on_map_click - "1"-single click on map will switch to gui,"0"-Gui could be switched only by command (not yet implemented)
   * signal_on_map_click - "1"-DBus signal will be sent on single click on map,"0"-map click processing will be controlled bu menu_on_map_click
   * radius - Distance in meters for searching point name. Default is 10
   * pitch - Initial pitch for 3D view. Default is 20
   * lazy - "1"-Gui should be lazy and keep it state between calls,"0"-Gui is always reset to main page when called
   * width #height - Width and height for gui window. Default values are 800 and 600
   * source - Directory with qml skins. Default value is NAVIT_SHAREDIR/gui/qml/skins
   * skin - Skin for gui. Default skin is navit
   * icon_src - Directory with icons for gui.Default value is NAVIT_SHAREDIR/xpm/

Using it

I can't give any advices on using this gui, cause it is very flexible by it's nature, so there could be a lot of variations and customizations on it, but there are exists some hardcoded things. With LEFT click on map (or touchscreen tap) gui is usually switched on. This behavior could be controlled by two attributes:

   * menu_on_map_click - controls whether menu should be called on map click or not

and

   * signal_on_map_click - controls whether signal should be sent on map click or usual click processing should be used

RIGHT click on map (or loooong tap on touch screen) turns on the gui with special point screen.

Redesigning it

The gui qml skin is just a directory containing qml application of any kind of complexity (yes, you CAN add twitter client into gui, no problem at all). Navit requires that qml app must contain two files:

   * main.qml
   * point.qml
   * command.qml

main.qml will be instantiated when calling a gui for the first time (or every time when "lazy" set to "0") and point.qml is used for a special point screen mentioned above and command.qml is used to handle a OSD command. Every other aspect of gui structure and desigg is controlled by you, but gui qml module provides some helper functions.

gui object

Gui qml module injects a 'gui' object into global qml namespace. This object contains following properties:

   * width - current width of gui's window
   * height - current height of gui's window
   * localeName *langName *ctryName - Name of POSIX locale and WIN32 language and country names (READ ONLY)
   * iconPath - Directory for icons (READ ONLY)
   * commandFunction - name of a command to execute, see commands section for details (READ ONLY)
   * returnSource - Tree of visited pages (see below)

gui object also have some slots:

   * setPage
   * backToMap
   * backToPrevPage

All of those slots and returnSource property are related to 'page switch helper'. The idea behind them is to encapsulate every dialog into different qml file and switch them programatically directly from qml. So you may define a button for maps and call gui.setPage("maps.qml") when it is clicked. Every setPage call modifies returnSource property, storing the history of your setPage calls, so when you done with your maps.qml from the example above, you could just call gui.backToPrevPage() (in maps.qml) and it will work like a back button. gui.backToMap() switches from gui to map, it's obvious. But what if you want to return to your starting point? You could use the following code:

    gui.returnSource=""; gui.setPage("main.qml");

in you qml application. Even more - you could use returnSource any way you like - for returning to the every odd page for exmaple or inserting some new pages into history on some even. You may also not use this functionality at all and implement navigation right in the QML app.

Proxy objects

The gui object above is a kind of a proxy object Navit is written in pure C and QML is based on Qt, so there are no direct way of exposing Navit's data to qml engine, so we have to use proxies between them. Generic proxy object is based on NGQProxy class

class NGQProxy : public QObject {
	Q_OBJECT;

public:
    NGQProxy(struct gui_priv* this_,QObject *parent) : QObject(parent);
public slots:
	//Attribute read/write
	QString getAttr(const QString &attr_name);
	void setAttr(const QString &attr_name, const QString &attr_string);
};

NGQProxy provides generic setAttr/getAttr functions, that are mediating between QML and Navit's attributes system. I have to metion specially here - setAttr will convert "true" and "false" in attr_string variable to "1" and "0". It's not a bug :-)

NGQProxy inherited by the following classes:

NGQProxySearch

not yet ready

NGQProxyGui

Object of this class is injected into qml namespace as a gui and described above.

NGQProxyBookmarks

Object of this class is injected into qml namespace as a bookmarks. This object provides access to the bookmark manager. It have following slots:

   * getAttrList
   * AddBookmark(name)
   * Cut(name)
   * Copy(name)
   * Paste(name)
   * Delete(name)
   * setPoint(name)

and single property:

   * currentPath

It doesn't provides valid setAttr/getAttr functions! They will always fail. For AddBookmark/Cut/Copy/Page/Delete/setPoint you MUST specify full bookmark name, with path, but for Paste just a PATH, without name part, should be specified. AddBookmark uses coordinates from a current 'point' object (see below) and setPoint sets the current 'point' object to point in the bookmark. currentPath property used for traversing the bookmarks tree and positioning in it. getAttrList provides QML namespace with 'listModel' object of type NGQStandardItemModel (see below) for bookmarks list view.

NGQProxyNavit

Object of this class is injected into qml namespace as a navit. This object provides access to the global navit object. Slots are:

   * quit - quits the Navit immediately
   * setObjectByName(name,value) - sets the current values of various objects by their name (only 'layout' and 'vehicle' supported right now)
   * setDestination/setPosition - sets the destination/position to the current point
   * getAttrList - Proveds QML nameSpaces with 'listModel' object (see below) containing lists of different types of attributes ('layout' and 'vehicle' only at the moment)


The current point concept

There are special object 'point' of type NGQPoint that represents a 'current point'. Current point is a point on map (with coordinates and may be with name and other attributes) which is used by other proxy objects. So you don't pass the coordinates or something to navit.setDestination or bookmarks.AddBookmark. You set current point object to their values and call a function, that processes it. The current point object is set in following cases:

  * Right click on map
  * navit.getPosition/navit.getDestination call
  * bookmarks.setPoint call
  * point.setNewPoint call

Point could have a type:

    enum NGQPointTypes {MapPoint,Bookmark,Position,Destination,PointOfInterest};

which could be used for conditional rendering etc

Point object provides three properties:

   * coordString - Formatted textual representation of point's coordinates.
   * pointName - Name of a point, either specified during point creation/setting or calculated from map data.
   * pointType - Name of point's type.

The listModel

In a few words - listModel is a way to represent list data to qml. It is a variation of QStandardItemModel, but with several new roles defined:

	enum listRoles {ItemId=Qt::UserRole+1,ItemName=Qt::UserRole+2,ItemIcon=Qt::UserRole+3,ItemPath=Qt::UserRole+4};

the listModel is filled by getAttrList call andstored in global QML namespace. That also means, that you only can use a single list on a page :-)

Commands

Navit supports scriptable commands, usually found in OSD, but not limited to and those commands are another one way of user interaction with gui. Commands are usually defined in a form of a:

    object.command(attribute=value,attribute=value,...,attribute=value)

so gui (our object) gets a call from navit to execute a command with some parameters. In qml gui we delegate execution function to command.qml which should read the current command from a gui.commandFunction and execute it somehow. It is designed to be very flexible, so command to this gui should be in form of:

    gui.command(command=fullscreen,attribute=value)

The intenrnal callback handler expected to read the command attribute and store it in the gui.commandFunction properties, so adding a new command will not require a c++ coding. But right now the attribute processing code in commands engine is buggy, so there are exists two hardcoded commands:

  • gui.quit() - quit the Navit immediately
  • gui.fullscreen() - switches between fullscreen/windowed modes

Those commands should be processed in command.qml in usual way, the only difference, that adding a new command requires editing the source code and adding another one name for callback function. I hope it will be fixed soon.