diff options
Diffstat (limited to 'navit/gui/qml/gui_qml.cpp')
-rw-r--r-- | navit/gui/qml/gui_qml.cpp | 475 |
1 files changed, 475 insertions, 0 deletions
diff --git a/navit/gui/qml/gui_qml.cpp b/navit/gui/qml/gui_qml.cpp new file mode 100644 index 00000000..e00b353c --- /dev/null +++ b/navit/gui/qml/gui_qml.cpp @@ -0,0 +1,475 @@ +#include <glib.h> +#include <QtCore> +#include <QtGui> +#include <QtDeclarative> +#include <QtXml> +#include "config.h" +#ifdef HAVE_API_WIN32_BASE +#include <windows.h> +#endif +#include "plugin.h" +#include "item.h" +#include "attr.h" +#include "color.h" +#include "gui.h" +#include "callback.h" +#include "debug.h" +#include "navit.h" +#include "point.h" +#include "graphics.h" +#include "event.h" +#include "map.h" +#include "coord.h" +#include "vehicle.h" +#include "coord.h" +#include "transform.h" +#include "mapset.h" +#include "route.h" +#include "country.h" +#include "track.h" +#include "search.h" +#include "bookmarks.h" +#include "command.h" +#include "keys.h" + +//WORKAOUND for the c/c++ compatibility issues. +//range is defined inside of struct attr so it is invisible in c++ +struct range { + short min, max; +} range; + +#include "layout.h" + +struct gui_priv { + struct navit *nav; + struct gui *gui; + struct attr self; + struct vehicle* currVehicle; + + //configuration items + int fullscreen; + int menu_on_map_click; + int signal_on_map_click; + int w; + int h; + char *source; + char *skin; + char* icon_src; + int radius; + int pitch; + int lazy; //When TRUE - menu state will not be changed during map/menu switches, FALSE - menu will be always reset to main.qml + + //Interface stuff + struct callback_list *cbl; + QCoreApplication *app; + struct window *win; + struct graphics *gra; + QWidget *mainWindow; + QWidget *graphicsWidget; + QDeclarativeView *guiWidget; + QDeclarativeView *prevGuiWidget; + QStackedLayout *switcherWidget; + struct callback *button_cb; + struct callback *motion_cb; + struct callback *resize_cb; + struct callback *keypress_cb; + struct callback *window_closed_cb; + + //Proxy objects + class NGQProxyGui* guiProxy; + class NGQProxyNavit* navitProxy; + class NGQProxyVehicle* vehicleProxy; + class NGQProxySearch* searchProxy; + class NGQProxyBookmarks* bookmarksProxy; + class NGQProxyRoute* routeProxy; + class NGQPoint* currentPoint; +}; + +#include "proxy.h" +#include "ngqpoint.h" +#include "searchProxy.h" +#include "routeProxy.h" +#include "bookmarksProxy.h" +#include "vehicleProxy.h" +#include "navitProxy.h" +#include "guiProxy.h" + +//Main window class for resizeEvent handling +#ifdef Q_WS_X11 +#include <QX11EmbedWidget> +class NGQMainWindow : public QX11EmbedWidget +{ +#else +class NGQMainWindow : public QWidget +{ +#endif /* Q_WS_X11 */ +public: + +#ifdef Q_WS_X11 + NGQMainWindow(struct gui_priv* this_,QWidget *parent) : QX11EmbedWidget(parent) { +#else + NGQMainWindow(struct gui_priv* this_,QWidget *parent) : QWidget(parent) { +#endif /* Q_WS_X11 */ + this->object=this_; + } +protected: + void resizeEvent(QResizeEvent *) { + this->object->w=this->width(); + this->object->h=this->height(); + //YES, i KNOW about signal/slot thing + this->object->guiProxy->setWidth(this->width()); + this->object->guiProxy->setHeight(this->height()); + } + void closeEvent(QCloseEvent* event) { + this->object->graphicsWidget->close(); + } +private: + struct gui_priv* object; +}; + +//Meta object +#include "gui_qml.moc" + +static void gui_qml_dbus_signal(struct gui_priv *this_, struct point *p) +{ + struct displaylist_handle *dlh; + struct displaylist *display; + struct displayitem *di; + + display=navit_get_displaylist(this_->nav); + dlh=graphics_displaylist_open(display); + while ((di=graphics_displaylist_next(dlh))) { + struct item *item=graphics_displayitem_get_item(di); + if (item_is_point(*item) && graphics_displayitem_get_displayed(di) && + graphics_displayitem_within_dist(display, di, p, 10)) { + struct map_rect *mr=map_rect_new(item->map, NULL); + struct item *itemo=map_rect_get_item_byid(mr, item->id_hi, item->id_lo); + struct attr attr; + if (item_attr_get(itemo, attr_data, &attr)) { + struct attr cb,*attr_list[2]; + int valid=0; + attr.type=attr_data; + attr_list[0]=&attr; + attr_list[1]=NULL; + if (navit_get_attr(this_->nav, attr_callback_list, &cb, NULL)) + callback_list_call_attr_4(cb.u.callback_list, attr_command, "dbus_send_signal", attr_list, NULL, &valid); + } + map_rect_destroy(mr); + } + } + graphics_displaylist_close(dlh); +} + +static void gui_qml_button(void *data, int pressed, int button, struct point *p) +{ + struct gui_priv *this_=(struct gui_priv*)data; + + // check whether the position of the mouse changed during press/release OR if it is the scrollwheel + if (!navit_handle_button(this_->nav, pressed, button, p, NULL)) { + dbg(1,"navit has handled button\n"); + return; + } + + dbg(1,"enter %d %d\n", pressed, button); + if (this_->signal_on_map_click) { + gui_qml_dbus_signal(this_, p); + return; + } + + if ( button == 1 && this_->menu_on_map_click ) { + this_->guiProxy->switchToMenu(p); + } +} + +static void gui_qml_motion(void *data, struct point *p) +{ + struct gui_priv *this_=(struct gui_priv*)data; + navit_handle_motion(this_->nav, p); + return; +} +static void gui_qml_resize(void *data, int w, int h) +{ + struct gui_priv *this_=(struct gui_priv*)data; + navit_handle_resize(this_->nav, w, h); +} + +static void gui_qml_keypress(void *data, char *key) +{ + struct gui_priv *this_=(struct gui_priv*) data; + int w,h; + struct point p; + transform_get_size(navit_get_trans(this_->nav), &w, &h); + switch (*key) { + case NAVIT_KEY_UP: + p.x=w/2; + p.y=0; + navit_set_center_screen(this_->nav, &p, 1); + break; + case NAVIT_KEY_DOWN: + p.x=w/2; + p.y=h; + navit_set_center_screen(this_->nav, &p, 1); + break; + case NAVIT_KEY_LEFT: + p.x=0; + p.y=h/2; + navit_set_center_screen(this_->nav, &p, 1); + break; + case NAVIT_KEY_RIGHT: + p.x=w; + p.y=h/2; + navit_set_center_screen(this_->nav, &p, 1); + break; + case NAVIT_KEY_ZOOM_IN: + navit_zoom_in(this_->nav, 2, NULL); + break; + case NAVIT_KEY_ZOOM_OUT: + navit_zoom_out(this_->nav, 2, NULL); + break; + case NAVIT_KEY_RETURN: + case NAVIT_KEY_MENU: + p.x=w/2; + p.y=h/2; + this_->guiProxy->switchToMenu(&p); + break; + } + return; +} + +static void +gui_qml_window_closed(struct gui_priv *data) +{ + struct gui_priv *this_=(struct gui_priv*) data; + this_->navitProxy->quit(); +} +//GUI interface calls +static int argc=1; +static char *argv[]={(char *)"navit",NULL}; + +static int gui_qml_set_graphics(struct gui_priv *this_, struct graphics *gra) +{ + QString xid; + NGQMainWindow* _mainWindow; + bool ok; + + this_->gra=gra; + + //Check if we are already in Qt environment + if (QApplication::instance()==NULL) { + //Not yet + this_->app=new QApplication(argc,argv); + } else { + this_->app=QApplication::instance(); + } + + //Link graphics events + this_->button_cb=callback_new_attr_1(callback_cast(gui_qml_button), attr_button, this_); + graphics_add_callback(gra, this_->button_cb); + this_->motion_cb=callback_new_attr_1(callback_cast(gui_qml_motion), attr_motion, this_); + graphics_add_callback(gra, this_->motion_cb); + this_->resize_cb=callback_new_attr_1(callback_cast(gui_qml_resize), attr_resize, this_); + graphics_add_callback(gra, this_->resize_cb); + this_->keypress_cb=callback_new_attr_1(callback_cast(gui_qml_keypress), attr_keypress, this_); + graphics_add_callback(gra, this_->keypress_cb); + this_->window_closed_cb=callback_new_attr_1(callback_cast(gui_qml_window_closed), attr_window_closed, this_); + graphics_add_callback(gra, this_->window_closed_cb); + + + //Create main window + this_->switcherWidget = new QStackedLayout(); + _mainWindow = new NGQMainWindow(this_, NULL); +#ifdef Q_WS_X11 + xid=getenv("NAVIT_XID"); + if (xid.length()>0) { + _mainWindow->embedInto(xid.toULong(&ok,0)); + } +#endif /* Q_WS_X11 */ + this_->mainWindow=_mainWindow; + if ( this_->w && this_->h ) { + this_->mainWindow->resize(this_->w,this_->h); + } + if ( this_->fullscreen ) { + this_->mainWindow->showFullScreen(); + } + + this_->mainWindow->setLayout(this_->switcherWidget); + + //Create proxy object and bind them to gui widget + this_->guiProxy = new NGQProxyGui(this_,this_->mainWindow); + this_->navitProxy = new NGQProxyNavit(this_,this_->mainWindow); + this_->vehicleProxy = new NGQProxyVehicle(this_,this_->mainWindow); + this_->searchProxy = new NGQProxySearch(this_,this_->mainWindow); + this_->bookmarksProxy = new NGQProxyBookmarks(this_,this_->mainWindow); + this_->routeProxy = new NGQProxyRoute(this_,this_->mainWindow); + + //Check, if we have compatible graphics + this_->graphicsWidget = (QWidget*)graphics_get_data(gra,"qt_widget"); + if (this_->graphicsWidget == NULL ) { + this_->graphicsWidget = new QLabel(QString("Sorry, current graphics type is incompatible with this gui.")); + } + this_->switcherWidget->addWidget(this_->graphicsWidget); + + //Instantiate qml components + this_->guiWidget = new QDeclarativeView(NULL); + this_->guiWidget->setResizeMode(QDeclarativeView::SizeRootObjectToView); + + this_->guiWidget->rootContext()->setContextProperty("gui",this_->guiProxy); + this_->guiWidget->rootContext()->setContextProperty("navit",this_->navitProxy); + this_->guiWidget->rootContext()->setContextProperty("vehicle",this_->vehicleProxy); + this_->guiWidget->rootContext()->setContextProperty("search",this_->searchProxy); + this_->guiWidget->rootContext()->setContextProperty("bookmarks",this_->bookmarksProxy); + this_->guiWidget->rootContext()->setContextProperty("route",this_->routeProxy); + this_->guiWidget->rootContext()->setContextProperty("point",this_->currentPoint); + + this_->guiWidget->setSource(QUrl::fromLocalFile(QString(this_->source)+"/"+this_->skin+"/main.qml")); + this_->switcherWidget->addWidget(this_->guiWidget); + + //Switch to graphics + navit_draw(this_->nav); + this_->switcherWidget->setCurrentWidget(this_->graphicsWidget); + + this_->mainWindow->show(); + + return 0; +} + +static int +gui_qml_get_attr(struct gui_priv *this_, enum attr_type type, struct attr *attr) +{ + switch (type) { + case attr_fullscreen: + attr->u.num=this_->fullscreen; + break; + case attr_skin: + attr->u.str=this_->skin; + break; + case attr_pitch: + attr->u.num=this_->pitch; + break; + case attr_radius: + attr->u.num=this_->radius; + break; + default: + return 0; + } + attr->type=type; + return 1; +} + +static int +gui_qml_set_attr(struct gui_priv *this_, struct attr *attr) +{ + switch (attr->type) { + case attr_fullscreen: + if (!(this_->fullscreen) && (attr->u.num)) { + this_->mainWindow->showFullScreen(); + } + if ((this_->fullscreen) && !(attr->u.num)) { + this_->mainWindow->showNormal(); + } + this_->fullscreen=attr->u.num; + return 1; + case attr_pitch: + this_->pitch=attr->u.num; + return 1; + case attr_radius: + this_->radius=attr->u.num; + return 1; + default: + dbg(0,"unknown attr: %s\n",attr_to_name(attr->type)); + return 1; + } +} + +struct gui_methods gui_qml_methods = { + NULL, + NULL, + gui_qml_set_graphics, + NULL, + NULL, + NULL, + NULL, + gui_qml_get_attr, + NULL, + gui_qml_set_attr, +}; + +static void +gui_qml_command(struct gui_priv *this_, char *function, struct attr **in, struct attr ***out, int *valid) { + struct attr **curr=in; + struct attr *attr; + this_->guiProxy->processCommand(function); +} + +static struct command_table commands[] = { + {"*",command_cast(gui_qml_command)}, +}; + +static struct gui_priv * gui_qml_new(struct navit *nav, struct gui_methods *meth, struct attr **attrs, struct gui *gui) +{ + struct gui_priv *this_; + struct attr *attr; + *meth=gui_qml_methods; + this_=g_new0(struct gui_priv, 1); + + this_->nav=nav; + this_->gui=gui; + + this_->self.type=attr_gui; + this_->self.u.gui=gui; + + navit_ignore_graphics_events(this_->nav, 1); + + this_->fullscreen = 0; //NO by default + if( (attr=attr_search(attrs,NULL,attr_fullscreen))) + this_->fullscreen=attr->u.num; + this_->menu_on_map_click = 1; //YES by default; + if( (attr=attr_search(attrs,NULL,attr_menu_on_map_click))) + this_->menu_on_map_click=attr->u.num; + this_->signal_on_map_click = 0; //YES by default; + if( (attr=attr_search(attrs,NULL,attr_signal_on_map_click))) + this_->signal_on_map_click=attr->u.num; + this_->radius = 10; //Default value + if( (attr=attr_search(attrs,NULL,attr_radius))) + this_->radius=attr->u.num; + this_->pitch = 20; //Default value + if( (attr=attr_search(attrs,NULL,attr_pitch))) + this_->pitch=attr->u.num; + this_->lazy = 1; //YES by default + if( (attr=attr_search(attrs,NULL,attr_lazy))) + this_->lazy=attr->u.num; + this_->w=800; //Default value + if( (attr=attr_search(attrs,NULL,attr_width))) + this_->w=attr->u.num; + this_->h=600; //Default value + if( (attr=attr_search(attrs,NULL,attr_height))) + this_->h=attr->u.num; + if( (attr=attr_search(attrs,NULL,attr_source))) + this_->source=attr->u.str; + if( (attr=attr_search(attrs,NULL,attr_skin))) + this_->skin=attr->u.str; + if( (attr=attr_search(attrs,NULL,attr_icon_src))) + this_->icon_src=attr->u.str; + + if ( this_->source==NULL ) { + this_->source=g_strjoin(NULL,getenv("NAVIT_SHAREDIR"),"/gui/qml/skins",NULL); + } + if ( this_->skin==NULL ) { + this_->skin=g_strdup("navit"); + } + if ( this_->icon_src==NULL ) { + this_->icon_src=g_strjoin(NULL,getenv("NAVIT_SHAREDIR"),"/xpm/",NULL); + } + + if ((attr=attr_search(attrs, NULL, attr_callback_list))) { + command_add_table(attr->u.callback_list, commands, sizeof(commands)/sizeof(struct command_table), this_); + } + + this_->cbl=callback_list_new(); + + return this_; +} + +void plugin_init(void) { + plugin_register_gui_type("qml",gui_qml_new); +} |