Recreate the navit git/gerrit project that vanished
[profile/ivi/navit.git] / navit / gui / qml / gui_qml.cpp
1 #include <glib.h>
2 #include <QtCore>
3 #include <QtGui>
4 #include <QtDeclarative>
5 #include <QtXml>
6 #include "config.h"
7 #ifdef HAVE_API_WIN32_BASE
8 #include <windows.h>
9 #endif
10 #include "plugin.h"
11 #include "item.h"
12 #include "attr.h"
13 #include "color.h"
14 #include "gui.h"
15 #include "callback.h"
16 #include "debug.h"
17 #include "navit.h"
18 #include "point.h"
19 #include "graphics.h"
20 #include "event.h"
21 #include "map.h"
22 #include "coord.h"
23 #include "vehicle.h"
24 #include "coord.h"
25 #include "transform.h"
26 #include "mapset.h"
27 #include "route.h"
28 #include "country.h"
29 #include "track.h"
30 #include "search.h"
31 #include "bookmarks.h"
32 #include "command.h"
33 #include "keys.h"
34
35 //WORKAOUND for the c/c++ compatibility issues.
36 //range is defined inside of struct attr so it is invisible in c++
37 struct range {
38         short min, max;
39 } range;
40
41 #include "layout.h"
42
43 struct gui_priv {
44         struct navit *nav;
45         struct gui *gui;
46         struct attr self;
47         struct vehicle* currVehicle;
48         
49         //configuration items
50         int fullscreen;
51         int menu_on_map_click;
52         int signal_on_map_click;
53         int w;
54         int h;
55         char *source;
56         char *skin;
57         char* icon_src;
58         int radius;
59         int pitch;
60         int lazy; //When TRUE - menu state will not be changed during map/menu switches, FALSE - menu will be always reset to main.qml
61         
62         //Interface stuff
63         struct callback_list *cbl;
64         QCoreApplication *app;
65         struct window *win;
66         struct graphics *gra;
67         QWidget *mainWindow;
68         QWidget *graphicsWidget;
69         QDeclarativeView *guiWidget;
70         QDeclarativeView *prevGuiWidget;
71         QStackedLayout *switcherWidget;
72         struct callback *button_cb;
73         struct callback *motion_cb;
74         struct callback *resize_cb;
75         struct callback *keypress_cb;
76         struct callback *window_closed_cb;
77
78         //Proxy objects
79         class NGQProxyGui* guiProxy;
80         class NGQProxyNavit* navitProxy;
81         class NGQProxyVehicle* vehicleProxy;
82         class NGQProxySearch* searchProxy;
83         class NGQProxyBookmarks* bookmarksProxy;
84         class NGQProxyRoute* routeProxy;
85         class NGQPoint* currentPoint;
86 };
87
88 #include "proxy.h"
89 #include "ngqpoint.h"
90 #include "searchProxy.h"
91 #include "routeProxy.h"
92 #include "bookmarksProxy.h"
93 #include "vehicleProxy.h"
94 #include "navitProxy.h"
95 #include "guiProxy.h"
96
97 //Main window class for resizeEvent handling
98 #ifdef Q_WS_X11 
99 #include <QX11EmbedWidget>
100 class NGQMainWindow : public QX11EmbedWidget 
101 {
102 #else
103 class NGQMainWindow : public QWidget 
104 {
105 #endif /* Q_WS_X11 */
106 public:
107
108 #ifdef Q_WS_X11 
109         NGQMainWindow(struct gui_priv* this_,QWidget *parent) : QX11EmbedWidget(parent) {
110 #else
111         NGQMainWindow(struct gui_priv* this_,QWidget *parent) : QWidget(parent) {
112 #endif /* Q_WS_X11  */
113                 this->object=this_;
114         }
115 protected:
116         void resizeEvent(QResizeEvent *) {
117                 this->object->w=this->width();
118                 this->object->h=this->height();
119                 //YES, i KNOW about signal/slot thing
120                 this->object->guiProxy->setWidth(this->width());
121                 this->object->guiProxy->setHeight(this->height());
122         }
123         void closeEvent(QCloseEvent* event) {
124         this->object->graphicsWidget->close();
125         }
126 private:
127         struct gui_priv* object;
128 };
129
130 //Meta object
131 #include "gui_qml.moc"
132
133 static void gui_qml_dbus_signal(struct gui_priv *this_, struct point *p)
134 {
135         struct displaylist_handle *dlh;
136         struct displaylist *display;
137         struct displayitem *di;
138
139         display=navit_get_displaylist(this_->nav);
140         dlh=graphics_displaylist_open(display);
141         while ((di=graphics_displaylist_next(dlh))) {
142                 struct item *item=graphics_displayitem_get_item(di);
143                 if (item_is_point(*item) && graphics_displayitem_get_displayed(di) &&
144                         graphics_displayitem_within_dist(display, di, p, 10)) {
145                         struct map_rect *mr=map_rect_new(item->map, NULL);
146                         struct item *itemo=map_rect_get_item_byid(mr, item->id_hi, item->id_lo);
147                         struct attr attr;
148                         if (item_attr_get(itemo, attr_data, &attr)) {
149                                 struct attr cb,*attr_list[2];
150                                 int valid=0;
151                                 attr.type=attr_data;
152                                 attr_list[0]=&attr;
153                                 attr_list[1]=NULL;
154                                 if (navit_get_attr(this_->nav, attr_callback_list, &cb, NULL)) 
155                                         callback_list_call_attr_4(cb.u.callback_list, attr_command, "dbus_send_signal", attr_list, NULL, &valid);
156                         }
157                         map_rect_destroy(mr);
158                 }
159         }
160         graphics_displaylist_close(dlh);
161 }
162
163 static void gui_qml_button(void *data, int pressed, int button, struct point *p)
164 {
165         struct gui_priv *this_=(struct gui_priv*)data;
166
167         // check whether the position of the mouse changed during press/release OR if it is the scrollwheel
168         if (!navit_handle_button(this_->nav, pressed, button, p, NULL)) {
169                 dbg(1,"navit has handled button\n");
170                 return;
171         }
172
173         dbg(1,"enter %d %d\n", pressed, button);
174         if (this_->signal_on_map_click) {
175                 gui_qml_dbus_signal(this_, p);
176                 return;
177         }
178
179         if ( button == 1 && this_->menu_on_map_click ) {
180                 this_->guiProxy->switchToMenu(p);
181         }
182 }
183
184 static void gui_qml_motion(void *data, struct point *p)
185 {
186         struct gui_priv *this_=(struct gui_priv*)data;
187         navit_handle_motion(this_->nav, p);
188         return;
189 }
190 static void gui_qml_resize(void *data, int w, int h)
191 {
192         struct gui_priv *this_=(struct gui_priv*)data;
193         navit_handle_resize(this_->nav, w, h);
194 }
195
196 static void gui_qml_keypress(void *data, char *key)
197 {
198         struct gui_priv *this_=(struct gui_priv*) data;
199         int w,h;
200         struct point p;
201         transform_get_size(navit_get_trans(this_->nav), &w, &h);
202         switch (*key) {
203         case NAVIT_KEY_UP:
204                 p.x=w/2;
205                 p.y=0;
206                 navit_set_center_screen(this_->nav, &p, 1);
207                 break;
208         case NAVIT_KEY_DOWN:
209                 p.x=w/2;
210                 p.y=h;
211                 navit_set_center_screen(this_->nav, &p, 1);
212                 break;
213         case NAVIT_KEY_LEFT:
214                 p.x=0;
215                 p.y=h/2;
216                 navit_set_center_screen(this_->nav, &p, 1);
217                 break;
218         case NAVIT_KEY_RIGHT:
219                 p.x=w;
220                 p.y=h/2;
221                 navit_set_center_screen(this_->nav, &p, 1);
222                 break;
223         case NAVIT_KEY_ZOOM_IN:
224                 navit_zoom_in(this_->nav, 2, NULL);
225                 break;
226         case NAVIT_KEY_ZOOM_OUT:
227                 navit_zoom_out(this_->nav, 2, NULL);
228                 break;
229         case NAVIT_KEY_RETURN:
230         case NAVIT_KEY_MENU:
231                 p.x=w/2;
232                 p.y=h/2;
233                 this_->guiProxy->switchToMenu(&p);
234                 break;
235         }
236         return;
237 }
238
239 static void
240 gui_qml_window_closed(struct gui_priv *data)
241 {
242         struct gui_priv *this_=(struct gui_priv*) data;
243         this_->navitProxy->quit();
244 }
245 //GUI interface calls
246 static int argc=1;
247 static char *argv[]={(char *)"navit",NULL};
248
249 static int gui_qml_set_graphics(struct gui_priv *this_, struct graphics *gra)
250 {
251         QString xid;
252         NGQMainWindow* _mainWindow;
253         bool ok;
254
255         this_->gra=gra;
256
257         //Check if we are already in Qt environment
258         if (QApplication::instance()==NULL) {
259             //Not yet
260             this_->app=new QApplication(argc,argv);
261         } else {
262             this_->app=QApplication::instance();
263         }
264
265         //Link graphics events
266         this_->button_cb=callback_new_attr_1(callback_cast(gui_qml_button), attr_button, this_);
267         graphics_add_callback(gra, this_->button_cb);
268         this_->motion_cb=callback_new_attr_1(callback_cast(gui_qml_motion), attr_motion, this_);
269         graphics_add_callback(gra, this_->motion_cb);
270         this_->resize_cb=callback_new_attr_1(callback_cast(gui_qml_resize), attr_resize, this_);
271         graphics_add_callback(gra, this_->resize_cb);
272         this_->keypress_cb=callback_new_attr_1(callback_cast(gui_qml_keypress), attr_keypress, this_);
273         graphics_add_callback(gra, this_->keypress_cb);
274         this_->window_closed_cb=callback_new_attr_1(callback_cast(gui_qml_window_closed), attr_window_closed, this_);
275         graphics_add_callback(gra, this_->window_closed_cb);
276         
277                 
278         //Create main window
279         this_->switcherWidget = new QStackedLayout();
280         _mainWindow = new NGQMainWindow(this_, NULL);
281 #ifdef Q_WS_X11
282                 xid=getenv("NAVIT_XID");
283                 if (xid.length()>0) {
284                         _mainWindow->embedInto(xid.toULong(&ok,0));
285                 }
286 #endif /* Q_WS_X11  */
287         this_->mainWindow=_mainWindow;
288         if ( this_->w && this_->h ) {
289             this_->mainWindow->resize(this_->w,this_->h);
290         }
291         if ( this_->fullscreen ) {
292             this_->mainWindow->showFullScreen();
293         }
294         
295         this_->mainWindow->setLayout(this_->switcherWidget);
296         
297         //Create proxy object and bind them to gui widget
298         this_->guiProxy = new NGQProxyGui(this_,this_->mainWindow);
299         this_->navitProxy = new NGQProxyNavit(this_,this_->mainWindow);
300         this_->vehicleProxy = new NGQProxyVehicle(this_,this_->mainWindow);
301         this_->searchProxy = new NGQProxySearch(this_,this_->mainWindow);
302         this_->bookmarksProxy = new NGQProxyBookmarks(this_,this_->mainWindow);
303         this_->routeProxy = new NGQProxyRoute(this_,this_->mainWindow);
304                 
305         //Check, if we have compatible graphics
306         this_->graphicsWidget = (QWidget*)graphics_get_data(gra,"qt_widget");
307         if (this_->graphicsWidget == NULL ) {
308             this_->graphicsWidget = new QLabel(QString("Sorry, current graphics type is incompatible with this gui."));
309         }
310     this_->switcherWidget->addWidget(this_->graphicsWidget);
311         
312         //Instantiate qml components
313     this_->guiWidget = new QDeclarativeView(NULL);
314         this_->guiWidget->setResizeMode(QDeclarativeView::SizeRootObjectToView);
315                 
316         this_->guiWidget->rootContext()->setContextProperty("gui",this_->guiProxy);
317         this_->guiWidget->rootContext()->setContextProperty("navit",this_->navitProxy);
318         this_->guiWidget->rootContext()->setContextProperty("vehicle",this_->vehicleProxy);
319         this_->guiWidget->rootContext()->setContextProperty("search",this_->searchProxy);
320         this_->guiWidget->rootContext()->setContextProperty("bookmarks",this_->bookmarksProxy);
321         this_->guiWidget->rootContext()->setContextProperty("route",this_->routeProxy);
322         this_->guiWidget->rootContext()->setContextProperty("point",this_->currentPoint);
323
324         this_->guiWidget->setSource(QUrl::fromLocalFile(QString(this_->source)+"/"+this_->skin+"/main.qml"));
325         this_->switcherWidget->addWidget(this_->guiWidget);
326
327         //Switch to graphics
328         navit_draw(this_->nav);
329         this_->switcherWidget->setCurrentWidget(this_->graphicsWidget);
330
331         this_->mainWindow->show();
332
333         return 0;
334 }
335
336 static int
337 gui_qml_get_attr(struct gui_priv *this_, enum attr_type type, struct attr *attr)
338 {
339         switch (type) {
340         case attr_fullscreen:
341                 attr->u.num=this_->fullscreen;
342                 break;
343         case attr_skin:
344                 attr->u.str=this_->skin;
345                 break;
346         case attr_pitch:
347                 attr->u.num=this_->pitch;
348                 break;
349         case attr_radius:
350                 attr->u.num=this_->radius;
351                 break;
352         default:
353                 return 0;
354         }
355         attr->type=type;
356         return 1;
357 }
358
359 static int
360 gui_qml_set_attr(struct gui_priv *this_, struct attr *attr)
361 {
362         switch (attr->type) {
363         case attr_fullscreen:
364                 if (!(this_->fullscreen) && (attr->u.num)) {
365                         this_->mainWindow->showFullScreen();
366                 }
367                 if ((this_->fullscreen) && !(attr->u.num)) {
368                         this_->mainWindow->showNormal();
369                 }
370                 this_->fullscreen=attr->u.num;
371                 return 1;
372         case attr_pitch:
373                 this_->pitch=attr->u.num;
374                 return 1;
375         case attr_radius:
376                 this_->radius=attr->u.num;
377                 return 1;
378         default:
379                 dbg(0,"unknown attr: %s\n",attr_to_name(attr->type));
380                 return 1;
381         }
382 }
383
384 struct gui_methods gui_qml_methods = {
385         NULL,
386         NULL,
387     gui_qml_set_graphics,
388         NULL,
389         NULL,
390         NULL,
391         NULL,
392         gui_qml_get_attr,
393         NULL,
394         gui_qml_set_attr,
395 };
396
397 static void
398 gui_qml_command(struct gui_priv *this_, char *function, struct attr **in, struct attr ***out, int *valid) {
399         this_->guiProxy->processCommand(function);
400 }
401
402 static struct command_table commands[] = {
403         {"*",command_cast(gui_qml_command)},
404 };
405
406 static struct gui_priv * gui_qml_new(struct navit *nav, struct gui_methods *meth, struct attr **attrs, struct gui *gui)
407 {
408         struct gui_priv *this_;
409         struct attr *attr;
410         *meth=gui_qml_methods;
411         this_=g_new0(struct gui_priv, 1);
412
413         this_->nav=nav;
414         this_->gui=gui;
415
416         this_->self.type=attr_gui;
417         this_->self.u.gui=gui;  
418
419         navit_ignore_graphics_events(this_->nav, 1);
420
421         this_->fullscreen = 0; //NO by default
422         if( (attr=attr_search(attrs,NULL,attr_fullscreen)))
423               this_->fullscreen=attr->u.num;
424         this_->menu_on_map_click = 1; //YES by default;
425         if( (attr=attr_search(attrs,NULL,attr_menu_on_map_click)))
426                           this_->menu_on_map_click=attr->u.num;
427         this_->signal_on_map_click = 0; //YES by default;
428         if( (attr=attr_search(attrs,NULL,attr_signal_on_map_click)))
429                           this_->signal_on_map_click=attr->u.num;
430         this_->radius = 10; //Default value
431         if( (attr=attr_search(attrs,NULL,attr_radius)))
432                           this_->radius=attr->u.num;
433         this_->pitch = 20; //Default value
434         if( (attr=attr_search(attrs,NULL,attr_pitch)))
435                           this_->pitch=attr->u.num;
436         this_->lazy = 1; //YES by default
437         if( (attr=attr_search(attrs,NULL,attr_lazy)))
438                           this_->lazy=attr->u.num;
439         this_->w=800; //Default value
440         if( (attr=attr_search(attrs,NULL,attr_width)))
441               this_->w=attr->u.num;
442         this_->h=600; //Default value
443         if( (attr=attr_search(attrs,NULL,attr_height)))
444               this_->h=attr->u.num;
445         if( (attr=attr_search(attrs,NULL,attr_source)))
446               this_->source=attr->u.str;
447         if( (attr=attr_search(attrs,NULL,attr_skin)))
448               this_->skin=attr->u.str;
449         if( (attr=attr_search(attrs,NULL,attr_icon_src)))
450                           this_->icon_src=attr->u.str;
451
452         if ( this_->source==NULL ) {
453             this_->source=g_strjoin(NULL,getenv("NAVIT_SHAREDIR"),"/gui/qml/skins",NULL);
454         }
455         if ( this_->skin==NULL ) {
456                 this_->skin=g_strdup("navit");
457         }
458         if ( this_->icon_src==NULL ) {
459                 this_->icon_src=g_strjoin(NULL,getenv("NAVIT_SHAREDIR"),"/xpm/",NULL);
460         }
461
462         if ((attr=attr_search(attrs, NULL, attr_callback_list))) {
463                 command_add_table(attr->u.callback_list, commands, sizeof(commands)/sizeof(struct command_table), this_);
464         }
465
466         this_->cbl=callback_list_new();
467
468         return this_;
469 }
470
471 void plugin_init(void) {
472     plugin_register_gui_type("qml",gui_qml_new);
473 }