class ModRana(object): """ core modRana functionality """ def __init__(self, modrana, gui): self.modrana = modrana self.gui = gui self.modrana.watch("mode", self._modeChangedCB) self.modrana.watch("theme", self._themeChangedCB) self._theme = Theme(gui) # mode def _getMode(self): return self.modrana.get('mode', "car") def _setMode(self, mode): self.modrana.set('mode', mode) modeChanged = signal.Signal() def _modeChangedCB(self, *args): """notify when the mode key changes in options""" self.modeChanged()
class Theme(object): """modRana theme handling""" def __init__(self, gui): self.gui = gui # connect to the first time signal self.gui.firstTimeSignal.connect(self._firstTimeCB) self.themeModule = None self._themeDict = {} self.colors = None self.modrana = self.gui.modrana self.themeChanged.connect(self._notifyQMLCB) themeChanged = signal.Signal() def _firstTimeCB(self): # we need the theme module self.themeModule = self.gui.m.get('theme') theme = self.themeModule.theme # reload the theme dict so that # the dict is up to date and # then trigger the changed signal # and give it the current theme dict self.themeChanged(self._reloadTheme(theme)) # connect to the core theme-modules theme-changed signal self.themeModule.themeChanged.connect(self._themeChangedCB) def _themeChangedCB(self, newTheme): """ Callback from the core theme module - reload theme and trigger our own themeChanged signal :param newTheme: new theme from the core theme module :type newTheme: Theme """ self.themeChanged(self._reloadTheme(newTheme)) def _notifyQMLCB(self, newTheme): """ Notify the QML context that the modRana theme changed :param newTheme: the new theme :type newTheme: dict """ pyotherside.send("themeChanged", newTheme) @property def themeId(self): return self._themeDict.get("id") @themeId.setter def themeId(self, themeId): self.modrana.set('theme', themeId) @property def theme(self): return self._themeDict def _reloadTheme(self, theme): """Recreate the theme dict from the new theme object :param theme: new modRana Theme object instance :type theme: Theme """ themeDict = { "id": theme.id, "name": theme.name, "color": { "main_fill": theme.getColor("main_fill", "#92aaf3"), "main_highlight_fill": theme.getColor("main_highlight_fill", "#f5f5f5"), "icon_grid_toggled": theme.getColor("icon_grid_toggled", "#c6d1f3"), "icon_button_normal": theme.getColor("icon_button_normal", "#c6d1f3"), "icon_button_toggled": theme.getColor("icon_button_toggled", "#3c60fa"), "icon_button_text": theme.getColor("icon_button_text", "black"), "page_background": theme.getColor("page_background", "black"), "list_view_background": theme.getColor("list_view_background", "#d2d2d2d"), "page_header_text": theme.getColor("page_header_text", "black"), } } self._themeDict = themeDict return themeDict
class _Search(object): _addressSignal = signal.Signal() changed = signal.Signal() test = signal.Signal() def __init__(self, gui): self.gui = gui self._addressSearchResults = None self._addressSearchStatus = "Searching..." self._addressSearchInProgress = False self._addressSearchThreadName = None self._localSearchResults = None self._wikipediaSearchResults = None self._routeSearchResults = None self._POIDBSearchResults = None # why are wee keeping our own dictionary of wrapped # objects and not just returning a newly wrapped object on demand ? # -> because PySide (1.1.1) segfaults if we don't hold any reference # on the object returned :) # register the thread status changed callback threadMgr.threadStatusChanged.connect(self._threadStatusCB) def _threadStatusCB(self, threadName, threadStatus): if threadName == self._addressSearchThreadName: self._addressSearchStatus = threadStatus self._addressSignal() def address(self, address): """Trigger an asynchronous address search for the given term :param address: address search query :type address: str """ online = self.gui.m.get("onlineServices", None) if online: self._addressSearchThreadName = online.geocodeAsync( address, self._addressSearchCB) self._addressSearchInProgress = True self._addressSignal() def addressCancel(self): """Cancel the asynchronous address search""" threadMgr.cancel_thread(self._addressSearchThreadName) self._addressSearchInProgress = False self._addressSearchStatus = "Searching..." self._addressSignal() def _addressSearchCB(self, results): """Replace old address search results (if any) with new (wrapped) results :param results: address search results :type results: list """ #self.gui._addressSearchListModel.set_objects( # wrapList(results, wrappers.PointWrapper) #) self._addressSearchInProgress = False self._addressSignal.emit()
def __init__(self, *args, **kwargs): GUIModule.__init__(self, *args, **kwargs) # some constants self.msLongPress = 400 self.centeringDisableThreshold = 2048 self.firstTimeSignal = signal.Signal() size = (800, 480) # initial window size self._screen_size = None # positioning related self._pythonPositioning = False # we handle notifications by forwarding them to the QML context self.modrana.notificationTriggered.connect( self._dispatchNotificationCB) # register exit handler #pyotherside.atexit(self._shutdown) # FIXME: for some reason the exit handler is never # called on Sailfish OS, so we use a onDestruction # handler on the QML side to trigger shutdown # window state self._fullscreen = False # get screen resolution # TODO: implement this #screenWH = self.getScreenWH() #self.log.debug(" @ screen size: %dx%d" % screenWH) #if self.highDPI: # self.log.debug(" @ high DPI") #else: # self.log.debug(" @ normal DPI") # NOTE: what about multi-display devices ? :) ## add image providers self._imageProviders = { "icon": IconImageProvider(self), "tile": TileImageProvider(self), } # log what version of PyOtherSide we are using # - we log this without prefix as this shows up early # during startup, so it looks nicer that way :-) no_prefix_log.info("using PyOtherSide %s", pyotherside.version) ## register the actual callback, that ## will call the appropriate provider base on ## image id prefix pyotherside.set_image_provider(self._selectImageProviderCB) # initialize theming self._theme = Theme(self) ## make constants accessible #self.constants = self.getConstants() #rc.setContextProperty("C", self.constants) ## connect to the close event #self.window.closeEvent = self._qtWindowClosed ##self.window.show() self._notificationQueue = [] # provides easy access to modRana modules from QML self.modules = Modules(self) # search functionality for the QML context self.search = Search(self) # POI handling for the QML context self.POI = POI(self) # make the log manager easily accessible self.log_manager = modrana_log.log_manager # log for log messages from the QML context self.qml_log = qml_log # queue a notification to QML context that # a Python loggers is available pyotherside.send("loggerAvailable") # tracklogs self.tracklogs = Tracklogs(self) #routing self.routing = Routing(self) # turn by turn navigation self.navigation = Navigation(self)
def __init__(self, *args, **kwargs): GUIModule.__init__(self, *args, **kwargs) # some constants self.msLongPress = 400 self.centeringDisableThreshold = 2048 self.firstTimeSignal = signal.Signal() size = (800, 480) # initial window size # window state self.fullscreen = False # Create Qt application and the QDeclarative view class ModifiedQDeclarativeView(QDeclarativeView): def __init__(self, modrana): QDeclarativeView.__init__(self) self.modrana = modrana def closeEvent(self, event): print("shutting down") self.modrana.shutdown() self.app = QApplication(sys.argv) startDragDistance = self.modrana.dmod.getStartDragDistance() if startDragDistance: self.app.setStartDragDistance(startDragDistance) # get screen resolution screenWH = self.getScreenWH() print(" @ screen size: %dx%d" % screenWH) if self.highDPI: print(" @ high DPI") else: print(" @ normal DPI") # NOTE: what about multi-display devices ? :) # register custom modRana types # NOTE: custom types need to be registered AFTER # QApplication is created but BEFORE QDeclarativeView # is instantiated, or else horrible breakage occurs :) qmlRegisterType(drawing.PieChart, 'Charts', 1, 0, 'PieChart') qmlRegisterType(drawing.PieSlice, "Charts", 1, 0, "PieSlice") # m-declarative stuff implemented in Python qmlRegisterType(Screen, "mpBackend", 1, 0, "Screen") qmlRegisterType(Snapshot, "mpBackend", 1, 0, "Snapshot") self.view = ModifiedQDeclarativeView(self.modrana) self.window = QMainWindow() self.window.setWindowTitle("modRana") self.window.resize(*size) self.window.setCentralWidget(self.view) self.view.setResizeMode(QDeclarativeView.SizeRootObjectToView) # self.view.setResizeMode(QDeclarativeView.SizeViewToRootObject) # add image providers self.iconProvider = IconImageProvider(self) self.view.engine().addImageProvider("icons", self.iconProvider) # add tiles provider self.tilesProvider = TileImageProvider(self) self.view.engine().addImageProvider("tiles", self.tilesProvider) rc = self.view.rootContext() # make core modRana functionality accessible from QML modRanaCore = ModRana(self.modrana, self) rc.setContextProperty("modrana", modRanaCore) # make options accessible from QML options = Options(self.modrana) rc.setContextProperty("options", options) # make GPS accessible from QML gps = GPSDataWrapper(self.modrana, self) rc.setContextProperty("gps", gps) # make the platform accessible from QML platform = Platform(self.modrana) rc.setContextProperty("platform", platform) # make the modules accessible from QML modules = Modules(self.modrana) rc.setContextProperty("modules", modules) # make tile loading accessible from QML tiles = MapTiles(self) rc.setContextProperty("mapTiles", tiles) # make map layers accessible from QML layers = MapLayers(self) rc.setContextProperty("mapLayers", layers) # make search accessible from QML search = Search(self) rc.setContextProperty("search", search) # make constants accessible self.constants = self.getConstants() rc.setContextProperty("C", self.constants) # connect to the close event self.window.closeEvent = self._qtWindowClosed #self.window.show() self.rootObject = None self._location = None # location module self._mapTiles = None # map tiles module self._mapLayers = None # map tiles module self._notificationQueue = [] # list models self._addressSearchListModel = None self._layersListModel = None