Beispiel #1
0
    def testMapWindowApi(self, giface, map_):
        self.frame = wx.Frame(parent=None,
                              title=_("Map window API test frame"))
        panel = wx.Panel(parent=self.frame, id=wx.ID_ANY)
        sizer = wx.BoxSizer(wx.VERTICAL)

        mapWindowProperties = MapWindowProperties()
        mapWindowProperties.setValuesFromUserSettings()
        mapWindowProperties.showRegion = True

        width, height = self.frame.GetClientSize()
        copyOfInitMap(map_, width, height)
        window = BufferedMapWindow(parent=panel,
                                   giface=giface,
                                   Map=map_,
                                   properties=mapWindowProperties)

        giface.mapWindow = window

        sizer.Add(window, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        panel.SetSizer(sizer)
        panel.Layout()

        window.ZoomToWind()

        self.frame.Show()
Beispiel #2
0
    def testMapWindowDistance(self, giface, map_):
        self.frame = wx.Frame(
            parent=None, title=_("Map window distance measurement test frame"))
        panel = wx.Panel(parent=self.frame, id=wx.ID_ANY)
        sizer = wx.BoxSizer(wx.VERTICAL)

        mapWindowProperties = MapWindowProperties()
        mapWindowProperties.setValuesFromUserSettings()
        mapWindowProperties.showRegion = True

        width, height = self.frame.GetClientSize()
        copyOfInitMap(map_, width, height)
        window = BufferedMapWindow(parent=panel,
                                   giface=giface,
                                   Map=map_,
                                   properties=mapWindowProperties)

        giface.mapWindow = window

        sizer.Add(window, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        panel.SetSizer(sizer)
        panel.Layout()

        window.ZoomToWind()

        self._listenToAllMapWindowSignals(window)

        self.frame.Show()

        from mapwin.analysis import MeasureDistanceController
        self.controller = MeasureDistanceController(giface, window)
        self.controller.Start()
Beispiel #3
0
    def testMapWindowDistance(self, giface, map_):
        self.frame = wx.Frame(parent=None, title=_(
            "Map window distance measurement test frame"))
        panel = wx.Panel(parent=self.frame, id=wx.ID_ANY)
        sizer = wx.BoxSizer(wx.VERTICAL)

        mapWindowProperties = MapWindowProperties()
        mapWindowProperties.setValuesFromUserSettings()
        mapWindowProperties.showRegion = True

        width, height = self.frame.GetClientSize()
        copyOfInitMap(map_, width, height)
        window = BufferedMapWindow(parent=panel, giface=giface, Map=map_,
                                   properties=mapWindowProperties)

        giface.mapWindow = window

        sizer.Add(item=window, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        panel.SetSizer(sizer)
        panel.Layout()

        window.ZoomToWind()

        self._listenToAllMapWindowSignals(window)

        self.frame.Show()

        from mapwin.analysis import MeasureDistanceController
        self.controller = MeasureDistanceController(giface, window)
        self.controller.Start()
Beispiel #4
0
    def testMapWindowProfile(self, giface, map_):
        self.frame = wx.Frame(parent=None,
                              title=_("Map window profile tool test frame"))
        panel = wx.Panel(parent=self.frame, id=wx.ID_ANY)
        sizer = wx.BoxSizer(wx.VERTICAL)

        mapWindowProperties = MapWindowProperties()
        mapWindowProperties.setValuesFromUserSettings()
        mapWindowProperties.showRegion = True

        width, height = self.frame.GetClientSize()
        copyOfInitMap(map_, width, height)
        window = BufferedMapWindow(parent=panel,
                                   giface=giface,
                                   Map=map_,
                                   properties=mapWindowProperties)

        giface.mapWindow = window

        sizer.Add(window, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        panel.SetSizer(sizer)
        panel.Layout()

        window.ZoomToWind()

        self._listenToAllMapWindowSignals(window)

        self.frame.Show()

        from mapwin.analysis import ProfileController

        self.controller = ProfileController(giface, window)
        self.controller.Start()

        rasters = []
        for layer in giface.GetLayerList().GetSelectedLayers():
            if layer.maplayer.GetType() == "raster":
                rasters.append(layer.maplayer.GetName())

        from wxplot.profile import ProfileFrame

        profileWindow = ProfileFrame(
            parent=self.frame,
            giface=giface,
            controller=self.controller,
            units=map_.projinfo["units"],
            rasterList=rasters,
        )
        profileWindow.CentreOnParent()
        profileWindow.Show()
        # Open raster select dialog to make sure that a raster (and
        # the desired raster) is selected to be profiled
        profileWindow.OnSelectRaster(None)
Beispiel #5
0
 def testMapWindow(self, giface, map_):
     self.frame = wx.Frame(parent=None, title=_("Map window test frame"))
     panel = wx.Panel(parent=self.frame, id=wx.ID_ANY)
     sizer = wx.BoxSizer(wx.VERTICAL)
     mapWindowProperties = MapWindowProperties()
     mapWindowProperties.setValuesFromUserSettings()
     width, height = self.frame.GetClientSize()
     copyOfInitMap(map_, width, height)
     window = BufferedMapWindow(parent=panel, giface=giface, Map=map_,
                                properties=mapWindowProperties)
     sizer.Add(item=window, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
     panel.SetSizer(sizer)
     panel.Layout()
     self.frame.Show()
Beispiel #6
0
    def testMapWindowProfile(self, giface, map_):
        self.frame = wx.Frame(parent=None,
                              title=_("Map window profile tool test frame"))
        panel = wx.Panel(parent=self.frame, id=wx.ID_ANY)
        sizer = wx.BoxSizer(wx.VERTICAL)

        mapWindowProperties = MapWindowProperties()
        mapWindowProperties.setValuesFromUserSettings()
        mapWindowProperties.showRegion = True

        width, height = self.frame.GetClientSize()
        copyOfInitMap(map_, width, height)
        window = BufferedMapWindow(parent=panel, giface=giface, Map=map_,
                                   properties=mapWindowProperties)

        giface.mapWindow = window

        sizer.Add(item=window, proportion=1, flag=wx.EXPAND | wx.ALL, border=5)
        panel.SetSizer(sizer)
        panel.Layout()

        window.ZoomToWind()

        self._listenToAllMapWindowSignals(window)

        self.frame.Show()

        from mapwin.analysis import ProfileController
        self.controller = ProfileController(giface, window)
        self.controller.Start()

        rasters = []
        for layer in giface.GetLayerList().GetSelectedLayers():
            if layer.maplayer.GetType() == 'raster':
                rasters.append(layer.maplayer.GetName())

        from wxplot.profile import ProfileFrame
        profileWindow = ProfileFrame(parent=self.frame,
                                     controller=self.controller,
                                     units=map_.projinfo['units'],
                                     rasterList=rasters)
        profileWindow.CentreOnParent()
        profileWindow.Show()
        # Open raster select dialog to make sure that a raster (and
        # the desired raster) is selected to be profiled
        profileWindow.OnSelectRaster(None)
Beispiel #7
0
class SwipeMapFrame(DoubleMapFrame):

    def __init__(self, parent=None, giface=None,
                 title=_("GRASS GIS Map Swipe"), name="swipe", **kwargs):
        DoubleMapFrame.__init__(self, parent=parent, title=title, name=name,
                                firstMap=Map(), secondMap=Map(), **kwargs)
        Debug.msg(1, "SwipeMapFrame.__init__()")
        #
        # Add toolbars
        #
        self.AddToolbars()
        self._giface = giface
        #
        # create widgets
        #
        self.splitter = MapSplitter(parent=self, id=wx.ID_ANY)

        self.sliderH = wx.Slider(self, id=wx.ID_ANY, style=wx.SL_HORIZONTAL)
        self.sliderV = wx.Slider(self, id=wx.ID_ANY, style=wx.SL_VERTICAL)

        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        self.mapWindowProperties.autoRenderChanged.connect(
            self.OnAutoRenderChanged)
        self.firstMapWindow = SwipeBufferedWindow(
            parent=self.splitter, giface=self._giface,
            properties=self.mapWindowProperties, Map=self.firstMap)
        self.secondMapWindow = SwipeBufferedWindow(
            parent=self.splitter, giface=self._giface,
            properties=self.mapWindowProperties, Map=self.secondMap)
        # bind query signal
        self.firstMapWindow.mapQueried.connect(self.Query)
        self.secondMapWindow.mapQueried.connect(self.Query)

        # bind tracking cursosr to mirror it
        self.firstMapWindow.Bind(
            wx.EVT_MOTION,
            lambda evt: self.TrackCursor(evt))
        self.secondMapWindow.Bind(
            wx.EVT_MOTION,
            lambda evt: self.TrackCursor(evt))

        self.MapWindow = self.firstMapWindow  # current by default
        self.firstMapWindow.zoomhistory = self.secondMapWindow.zoomhistory
        self.SetBindRegions(True)

        self._mode = 'swipe'

        self._addPanes()
        self._bindWindowsActivation()
        self._setUpMapWindow(self.firstMapWindow)
        self._setUpMapWindow(self.secondMapWindow)

        self._mgr.GetPane('sliderV').Hide()
        self._mgr.GetPane('sliderH').Show()
        self.slider = self.sliderH

        self.InitStatusbar()

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_IDLE, self.OnIdle)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

        self.SetSize((800, 600))

        self._mgr.Update()

        self.rasters = {'first': None, 'second': None}

        self._inputDialog = None
        self._preferencesDialog = None
        self._queryDialog = None

        # default action in map toolbar
        self.GetMapToolbar().SelectDefault()

        self.resize = False

        wx.CallAfter(self.CallAfterInit)

    def TrackCursor(self, event):
        """Track cursor in one window and show cross in the other.

        Only for mirror mode.
        """
        if self._mode == 'swipe':
            event.Skip()
            return
        coords = event.GetPosition()
        if event.GetId() == self.secondMapWindow.GetId():
            self.firstMapWindow.DrawMouseCursor(coords=coords)
        else:
            self.secondMapWindow.DrawMouseCursor(coords=coords)

        event.Skip()

    def ActivateFirstMap(self, event=None):
        """Switch tracking direction"""
        super(SwipeMapFrame, self).ActivateFirstMap(event)

        self.firstMapWindow.ClearLines()
        self.firstMapWindow.Refresh()

    def ActivateSecondMap(self, event=None):
        """Switch tracking direction"""
        super(SwipeMapFrame, self).ActivateSecondMap(event)

        self.secondMapWindow.ClearLines()
        self.secondMapWindow.Refresh()

    def CallAfterInit(self):
        self.InitSliderBindings()
        self.splitter.SplitVertically(
            self.firstMapWindow, self.secondMapWindow, 0)
        self.splitter.Init()
        if not (self.rasters['first'] and self.rasters['second']):
            self.OnSelectLayers(event=None)

    def InitStatusbar(self):
        """Init statusbar (default items)."""
        # items for choice
        self.statusbarItems = [sb.SbCoordinates,
                               sb.SbRegionExtent,
                               sb.SbCompRegionExtent,
                               sb.SbShowRegion,
                               sb.SbAlignExtent,
                               sb.SbResolution,
                               sb.SbDisplayGeometry,
                               sb.SbMapScale,
                               sb.SbGoTo,
                               sb.SbProjection]

        # create statusbar and its manager
        statusbar = self.CreateStatusBar(number=4, style=0)
        statusbar.SetMinHeight(24)
        statusbar.SetStatusWidths([-5, -2, -1, -1])
        self.statusbarManager = sb.SbManager(
            mapframe=self, statusbar=statusbar)

        # fill statusbar manager
        self.statusbarManager.AddStatusbarItemsByClass(
            self.statusbarItems, mapframe=self, statusbar=statusbar)
        self.statusbarManager.AddStatusbarItem(
            sb.SbMask(self, statusbar=statusbar, position=2))
        sbRender = sb.SbRender(self, statusbar=statusbar, position=3)
        self.statusbarManager.AddStatusbarItem(sbRender)

        self.statusbarManager.Update()

    def ResetSlider(self):
        if self.splitter.GetSplitMode() == wx.SPLIT_VERTICAL:
            size = self.splitter.GetSize()[0]
        else:
            size = self.splitter.GetSize()[1]
        self.slider.SetRange(0, size)
        self.slider.SetValue(self.splitter.GetSashPosition())

    def InitSliderBindings(self):
        self.sliderH.Bind(wx.EVT_SPIN, self.OnSliderPositionChanging)
        self.sliderH.Bind(
            wx.EVT_SCROLL_THUMBRELEASE,
            self.OnSliderPositionChanged)
        self.sliderV.Bind(wx.EVT_SPIN, self.OnSliderPositionChanging)
        self.sliderV.Bind(
            wx.EVT_SCROLL_THUMBRELEASE,
            self.OnSliderPositionChanged)
        self.splitter.Bind(
            wx.EVT_SPLITTER_SASH_POS_CHANGING,
            self.OnSashChanging)
        self.splitter.Bind(
            wx.EVT_SPLITTER_SASH_POS_CHANGED,
            self.OnSashChanged)

    def OnSliderPositionChanging(self, event):
        """Slider changes its position, sash must be moved too."""
        Debug.msg(5, "SwipeMapFrame.OnSliderPositionChanging()")

        self.GetFirstWindow().movingSash = True
        self.GetSecondWindow().movingSash = True
        pos = event.GetPosition()

        if pos > 0:
            self.splitter.SetSashPosition(pos)
            self.splitter.OnSashChanging(None)

    def OnSliderPositionChanged(self, event):
        """Slider position changed, sash must be moved too."""
        Debug.msg(5, "SwipeMapFrame.OnSliderPositionChanged()")

        self.splitter.SetSashPosition(event.GetPosition())
        self.splitter.OnSashChanged(None)

    def OnSashChanging(self, event):
        """Sash position is changing, slider must be moved too."""
        Debug.msg(5, "SwipeMapFrame.OnSashChanging()")

        self.slider.SetValue(self.splitter.GetSashPosition())
        event.Skip()

    def OnSashChanged(self, event):
        """Sash position changed, slider must be moved too."""
        Debug.msg(5, "SwipeMapFrame.OnSashChanged()")

        self.OnSashChanging(event)
        event.Skip()

    def OnSize(self, event):
        Debug.msg(4, "SwipeMapFrame.OnSize()")
        self.resize = grass.clock()
        super(SwipeMapFrame, self).OnSize(event)

    def OnIdle(self, event):
        if self.resize and grass.clock() - self.resize > 0.2:
            w1 = self.GetFirstWindow()
            w2 = self.GetSecondWindow()

            sizeAll = self.splitter.GetSize()
            w1.SetClientSize(sizeAll)
            w2.SetClientSize(sizeAll)

            w1.OnSize(event)
            w2.OnSize(event)
            self.ResetSlider()
            self.resize = False

    def OnAutoRenderChanged(self, value):
        """Auto rendering state changed."""
        style = self.splitter.GetWindowStyle()
        style ^= wx.SP_LIVE_UPDATE
        self.splitter.SetWindowStyle(style)

    def AddToolbars(self):
        """Add defined toolbar to the window

        Currently known toolbars are:
         - 'swipeMap'          - basic map toolbar
         - 'swipeMain'         - swipe functionality
         - 'swipeMisc'         - misc (settings, help)
        """
        self.toolbars["swipeMap"] = SwipeMapToolbar(self, self._toolSwitcher)
        self._mgr.AddPane(self.toolbars["swipeMap"],
                          wx.aui.AuiPaneInfo().
                          Name("swipeMap").Caption(_("Map Toolbar")).
                          ToolbarPane().Top().
                          LeftDockable(False).RightDockable(False).
                          BottomDockable(False).TopDockable(True).
                          CloseButton(False).Layer(2).Row(1).Position(1).
                          BestSize((self.toolbars["swipeMap"].GetBestSize())))

        self.toolbars["swipeMain"] = SwipeMainToolbar(self)

        self._mgr.AddPane(self.toolbars["swipeMain"],
                          wx.aui.AuiPaneInfo().
                          Name("swipeMain").Caption(_("Main Toolbar")).
                          ToolbarPane().Top().
                          LeftDockable(False).RightDockable(False).
                          BottomDockable(False).TopDockable(True).
                          CloseButton(False).Layer(2).Row(1).Position(0).
                          BestSize((self.toolbars["swipeMain"].GetBestSize())))

        self.toolbars["swipeMisc"] = SwipeMiscToolbar(self)

        self._mgr.AddPane(self.toolbars["swipeMisc"],
                          wx.aui.AuiPaneInfo().
                          Name("swipeMisc").Caption(_("Misc Toolbar")).
                          ToolbarPane().Top().
                          LeftDockable(False).RightDockable(False).
                          BottomDockable(False).TopDockable(True).
                          CloseButton(False).Layer(2).Row(1).Position(2).
                          BestSize((self.toolbars["swipeMisc"].GetBestSize())))

    def _addPanes(self):
        """Add splitter window and sliders to aui manager"""
        # splitter window
        self._mgr.AddPane(self.splitter, wx.aui.AuiPaneInfo().
                          Name('splitter').CaptionVisible(False).PaneBorder(True).
                          Dockable(False).Floatable(False).CloseButton(False).
                          Center().Layer(1).BestSize((self.splitter.GetBestSize())))

        # sliders
        self._mgr.AddPane(self.sliderH, wx.aui.AuiPaneInfo().
                          Name('sliderH').CaptionVisible(False).PaneBorder(False).
                          CloseButton(False).Gripper(True).GripperTop(False).
                          BottomDockable(True).TopDockable(True).
                          LeftDockable(False).RightDockable(False).
                          Bottom().Layer(1).BestSize((self.sliderH.GetBestSize())))

        self._mgr.AddPane(self.sliderV, wx.aui.AuiPaneInfo().
                          Name('sliderV').CaptionVisible(False).PaneBorder(False).
                          CloseButton(False).Gripper(True).GripperTop(True).
                          BottomDockable(False).TopDockable(False).
                          LeftDockable(True).RightDockable(True).
                          Right().Layer(1).BestSize((self.sliderV.GetBestSize())))

    def ZoomToMap(self):
        """
        Set display extents to match selected raster (including NULLs)
        or vector map.
        """
        layers = []
        if self.rasters['first']:
            layers += self.firstMap.GetListOfLayers()
        if self.rasters['second']:
            layers += self.secondMap.GetListOfLayers()

        if layers:
            self.GetFirstWindow().ZoomToMap(layers=layers)
            self.GetSecondWindow().ZoomToMap(layers=layers)

    def OnZoomToMap(self, event):
        """Zoom to map"""
        self.ZoomToMap()

    def OnZoomBack(self, event):
        self.GetFirstWindow().ZoomBack()
        self.secondMap.region = self.firstMap.region
        self.Render(self.GetSecondWindow())

    def OnSelectLayers(self, event):
        if self._inputDialog is None:
            dlg = SwipeMapDialog(self, first=self.rasters['first'],
                                 second=self.rasters['second'],
                                 firstLayerList=None, secondLayerList=None)
            dlg.applyChanges.connect(self.OnApplyInputChanges)
            # connect to convertor object to convert to Map
            # store reference to convertor is needed otherwise it would be
            # discarded
            self._firstConverter = self._connectSimpleLmgr(
                dlg.GetFirstSimpleLmgr(), self.GetFirstMap())
            self._secondConverter = self._connectSimpleLmgr(
                dlg.GetSecondSimpleLmgr(), self.GetSecondMap())
            self._inputDialog = dlg
            dlg.CentreOnParent()
            dlg.Show()
        else:
            if self._inputDialog.IsShown():
                self._inputDialog.Raise()
                self._inputDialog.SetFocus()
            else:
                self._inputDialog.Show()

    def _connectSimpleLmgr(self, lmgr, renderer):
        converter = LayerListToRendererConverter(renderer)
        lmgr.opacityChanged.connect(converter.ChangeLayerOpacity)
        lmgr.cmdChanged.connect(converter.ChangeLayerCmd)
        lmgr.layerAdded.connect(converter.AddLayer)
        lmgr.layerRemoved.connect(converter.RemoveLayer)
        lmgr.layerActivated.connect(converter.ChangeLayerActive)
        lmgr.layerMovedUp.connect(converter.MoveLayerUp)
        lmgr.layerMovedDown.connect(converter.MoveLayerDown)
        lmgr.anyChange.connect(self._simpleLmgrChanged)
        return converter

    def _simpleLmgrChanged(self):
        if self.IsAutoRendered():
            self.OnRender(event=None)

    def OnApplyInputChanges(self):
        first, second = self._inputDialog.GetValues()
        if self._inputDialog.IsSimpleMode():
            self.rasters['first'], self.rasters['second'] = first, second
            res1 = self.SetFirstRaster(name=self.rasters['first'])
            res2 = self.SetSecondRaster(name=self.rasters['second'])
            if not (res1 and res2) and first and second:
                message = ''
                if not res1:
                    message += _("Map <%s> not found. ") % self.rasters[
                        'first']
                if not res2:
                    message += _("Map <%s> not found.") % self.rasters[
                        'second']
                    GError(parent=self, message=message)
                    return
            self.ZoomToMap()
        else:
            LayerListToRendererConverter(self.GetFirstMap()).ConvertAll(first)
            LayerListToRendererConverter(
                self.GetSecondMap()).ConvertAll(second)

        self.SetRasterNames()
        if self.IsAutoRendered():
            self.OnRender(event=None)

    def SetFirstRaster(self, name):
        """Set raster map to first Map"""
        raster = grass.find_file(name=name, element='cell')
        if raster['fullname']:
            self.rasters['first'] = raster['fullname']
            self.SetLayer(
                name=raster['fullname'],
                mapInstance=self.GetFirstMap())
            return True

        return False

    def SetSecondRaster(self, name):
        """Set raster map to second Map"""
        raster = grass.find_file(name=name, element='cell')
        if raster['fullname']:
            self.rasters['second'] = raster['fullname']
            self.SetLayer(
                name=raster['fullname'],
                mapInstance=self.GetSecondMap())
            return True

        return False

    def SetLayer(self, name, mapInstance):
        """Sets layer in Map.

        :param name: layer (raster) name
        """
        Debug.msg(3, "SwipeMapFrame.SetLayer(): name=%s" % name)

        # this simple application enables to keep only one raster
        mapInstance.DeleteAllLayers()
        cmdlist = ['d.rast', 'map=%s' % name]
        # add layer to Map instance (core.render)
        newLayer = mapInstance.AddLayer(
            ltype='raster',
            command=cmdlist,
            active=True,
            name=name,
            hidden=False,
            opacity=1.0,
            render=True)

    def OnSwitchWindows(self, event):
        """Switch windows position."""
        Debug.msg(3, "SwipeMapFrame.OnSwitchWindows()")

        splitter = self.splitter
        w1, w2 = splitter.GetWindow1(), splitter.GetWindow2()
        splitter.ReplaceWindow(w1, w2)
        splitter.ReplaceWindow(w2, w1)
        # self.OnSize(None)
        splitter.OnSashChanged(None)

    def _saveToFile(self, fileName, fileType):
        """Creates composite image by rendering both images and
        pasting them into the new one.

        .. todo::
            specify size of the new image (problem is inaccurate scaling)
        .. todo::
            make dividing line width and color optional
        """
        w1 = self.splitter.GetWindow1()
        w2 = self.splitter.GetWindow2()
        lineWidth = 1
        # render to temporary files
        filename1 = grass.tempfile(False) + '1'
        filename2 = grass.tempfile(False) + '2'
        width, height = self.splitter.GetClientSize()
        if self._mode == 'swipe':
            x, y = w2.GetImageCoords()
            w1.SaveToFile(filename1, fileType, width, height)
            w2.SaveToFile(filename2, fileType, width, height)
        else:
            fw, fh = w1.GetClientSize()
            w1.SaveToFile(filename1, fileType, fw, fh)
            sw, sh = w2.GetClientSize()
            w2.SaveToFile(filename2, fileType, sw, sh)

        # create empty white image  - needed for line
        im = wx.EmptyImage(width, height)
        im.Replace(0, 0, 0, 255, 255, 255)

        # paste images
        if self._mode == 'swipe':
            if self.splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
                im1 = wx.Image(filename1).GetSubImage((0, 0, width, -y))
                im.Paste(im1, 0, 0)
                im.Paste(wx.Image(filename2), -x, -y + lineWidth)
            else:
                im1 = wx.Image(filename1).GetSubImage((0, 0, -x, height))
                im.Paste(im1, 0, 0)
                im.Paste(wx.Image(filename2), -x + lineWidth, -y)
        else:
            if self.splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
                im1 = wx.Image(filename1)
                im.Paste(im1, 0, 0)
                im.Paste(wx.Image(filename2), 0, fh + lineWidth)
            else:
                im1 = wx.Image(filename1)
                im.Paste(im1, 0, 0)
                im.Paste(wx.Image(filename2), fw + lineWidth, 0)
        im.SaveFile(fileName, fileType)

        # remove temporary files
        grass.try_remove(filename1)
        grass.try_remove(filename2)

    def SaveToFile(self, event):
        """Save map to image
        """
        img = self.firstMapWindow.img or self.secondMapWindow.img
        if not img:
            GMessage(parent=self, message=_(
                "Nothing to render (empty map). Operation canceled."))
            return
        filetype, ltype = GetImageHandlers(img)

        # get filename
        dlg = wx.FileDialog(parent=self,
                            message=_("Choose a file name to save the image "
                                      "(no need to add extension)"),
                            wildcard=filetype,
                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            if not path:
                dlg.Destroy()
                return

            base, ext = os.path.splitext(path)
            fileType = ltype[dlg.GetFilterIndex()]['type']
            extType = ltype[dlg.GetFilterIndex()]['ext']
            if ext != extType:
                path = base + '.' + extType

            self._saveToFile(path, fileType)

        dlg.Destroy()

    def OnSwitchOrientation(self, event):
        """Switch orientation of the sash."""
        Debug.msg(3, "SwipeMapFrame.OnSwitchOrientation()")

        splitter = self.splitter
        splitter.Unsplit()
        if splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
            splitter.SplitVertically(
                self.firstMapWindow, self.secondMapWindow, 0)
            self.slider = self.sliderH
            if self._mode == 'swipe':
                self._mgr.GetPane('sliderH').Show()
                self._mgr.GetPane('sliderV').Hide()
        else:
            splitter.SplitHorizontally(
                self.firstMapWindow, self.secondMapWindow, 0)
            self.slider = self.sliderV
            if self._mode == 'swipe':
                self._mgr.GetPane('sliderV').Show()
                self._mgr.GetPane('sliderH').Hide()
        self._mgr.Update()
        splitter.OnSashChanged(None)
        self.OnSize(None)
        self.SetRasterNames()

    def OnAddText(self, event):
        """Double click on text overlay

        So far not implemented.
        """
        pass

    def SetViewMode(self, mode):
        """Sets view mode.

        :param mode: view mode ('swipe', 'mirror')
        """
        if self._mode == mode:
            return
        self._mode = mode
        self.toolbars['swipeMain'].SetMode(mode)
        # set window mode
        self.GetFirstWindow().SetMode(mode)
        self.GetSecondWindow().SetMode(mode)
        # hide/show slider
        if self.splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
            self._mgr.GetPane('sliderV').Show(mode == 'swipe')
            size = self.splitter.GetSize()[1] / 2
        else:
            self._mgr.GetPane('sliderH').Show(mode == 'swipe')
            size = self.splitter.GetSize()[0] / 2
        # set sash in the middle
        self.splitter.SetSashPosition(size)
        self.slider.SetValue(size)
        self._mgr.Update()
        # enable / disable sash
        self.splitter.EnableSash(mode == 'swipe')
        # hack to make it work
        self.splitter.OnSashChanged(None)
        self.SendSizeEvent()

    def SetRasterNames(self):
        if not self._inputDialog or self._inputDialog.IsSimpleMode():
            if self.rasters['first']:
                self.GetFirstWindow().SetRasterNameText(
                    self.rasters['first'], 101)
            if self.rasters['second']:
                self.GetSecondWindow().SetRasterNameText(
                    self.rasters['second'], 102)
        else:
            self.GetFirstWindow().SetRasterNameText('', 101)
            self.GetSecondWindow().SetRasterNameText('', 102)

    def Query(self, x, y):
        """Query active layers from both mapwindows.

        :param x,y: coordinates
        """
        rasters = (
            [layer.GetName()
             for layer in self.GetFirstMap().GetListOfLayers(
                 ltype='raster', active=True)],
            [layer.GetName()
             for layer in self.GetSecondMap().GetListOfLayers(
                 ltype='raster', active=True)])
        vectors = (
            [layer.GetName()
             for layer in self.GetFirstMap().GetListOfLayers(
                 ltype='vector', active=True)],
            [layer.GetName()
             for layer in self.GetSecondMap().GetListOfLayers(
                 ltype='vector', active=True)])

        if not (rasters[0] + rasters[1] + vectors[0] + vectors[1]):
            GMessage(
                parent=self,
                message=_(
                    'No raster or vector map layer selected for querying.'))
            return

        # set query snap distance for v.what at map unit equivalent of 10
        # pixels
        qdist = 10.0 * (
            (self.GetFirstMap().region['e'] - self.GetFirstMap().region['w']) /
            self.GetFirstMap().width)

        east, north = self.GetFirstWindow().Pixel2Cell((x, y))

        # use display region settings instead of computation region settings
        self.tmpreg = os.getenv("GRASS_REGION")
        os.environ["GRASS_REGION"] = self.GetFirstMap(
        ).SetRegion(windres=False)

        result = []
        if rasters[0]:
            result.extend(
                grass.raster_what(
                    map=rasters[0],
                    coord=(east, north),
                    localized=True))
        if vectors[0]:
            result.extend(
                grass.vector_what(
                    map=vectors[0],
                    coord=(east, north),
                    distance=qdist))
        if rasters[1]:
            result.extend(
                grass.raster_what(
                    map=rasters[1],
                    coord=(east, north),
                    localized=True))
        if vectors[1]:
            result.extend(
                grass.vector_what(
                    map=vectors[1],
                    coord=(east, north),
                    distance=qdist))

        self._QueryMapDone()

        result = PrepareQueryResults(coordinates=(east, north), result=result)
        if self._queryDialog:
            self._queryDialog.Raise()
            self._queryDialog.SetData(result)
        else:
            self._queryDialog = QueryDialog(parent=self, data=result)
            self._queryDialog.Bind(wx.EVT_CLOSE, self._oncloseQueryDialog)
            self._queryDialog.redirectOutput.connect(
                lambda output: self._giface.WriteLog(output))
            self._queryDialog.Show()

    def _oncloseQueryDialog(self, event):
        self._queryDialog = None
        event.Skip()

    def _QueryMapDone(self):
        """Restore settings after querying (restore GRASS_REGION)
        """
        if hasattr(self, "tmpreg"):
            if self.tmpreg:
                os.environ["GRASS_REGION"] = self.tmpreg
            elif 'GRASS_REGION' in os.environ:
                del os.environ["GRASS_REGION"]
        elif 'GRASS_REGION' in os.environ:
            del os.environ["GRASS_REGION"]

        if hasattr(self, "tmpreg"):
            del self.tmpreg

    def GetMapToolbar(self):
        """Returns toolbar with zooming tools"""
        return self.toolbars['swipeMap']

    def IsStandalone(self):
        """Since we do not need layer manager, we are standalone"""
        return True

    def OnHelp(self, event):
        self._giface.Help(entry='wxGUI.mapswipe')

    def OnPreferences(self, event):
        if not self._preferencesDialog:
            dlg = PreferencesDialog(parent=self, giface=self._giface)
            self._preferencesDialog = dlg
            self._preferencesDialog.CenterOnParent()

        self._preferencesDialog.ShowModal()

    def OnCloseWindow(self, event):
        self.GetFirstMap().Clean()
        self.GetSecondMap().Clean()
        self._mgr.UnInit()
        if self._inputDialog:
            self._inputDialog.UnInit()
        self.Destroy()
Beispiel #8
0
class RLiSetupMapPanel(wx.Panel):
    """Panel with mapwindow used in r.li.setup"""
    def __init__(self, parent, samplingType, icon=None, map_=None):
        wx.Panel.__init__(self, parent=parent)

        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        giface = StandaloneGrassInterface()
        self.samplingtype = samplingType
        self.parent = parent

        if map_:
            self.map_ = map_
        else:
            self.map_ = Map()
        self.map_.region = self.map_.GetRegion()

        self._mgr = wx.aui.AuiManager(self)
        self.mapWindow = BufferedMapWindow(parent=self, giface=giface,
                                           Map=self.map_,
                                           properties=self.mapWindowProperties)
        self._mgr.AddPane(self.mapWindow, wx.aui.AuiPaneInfo().CentrePane().
                          Dockable(True).BestSize((-1, -1)).Name('mapwindow').
                          CloseButton(False).DestroyOnClose(True).
                          Layer(0))
        self._toolSwitcher = ToolSwitcher()
        self._toolSwitcher.toggleToolChanged.connect(self._onToolChanged)
        self.toolbar = RLiSetupToolbar(self, self._toolSwitcher)

        self.catId = 1

        self._mgr.AddPane(self.toolbar,
                          wx.aui.AuiPaneInfo().
                          Name("maptoolbar").Caption(_("Map Toolbar")).
                          ToolbarPane().Left().Name('mapToolbar').
                          CloseButton(False).Layer(1).Gripper(False).
                          BestSize((self.toolbar.GetBestSize())))
        self._mgr.Update()

        if self.samplingtype == SamplingType.REGIONS:
            self.afterRegionDrawn = Signal('RLiSetupMapPanel.afterRegionDrawn')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='line')
        elif self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
            self.sampleFrameChanged = Signal('RLiSetupMapPanel.sampleFrameChanged')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='rectangle')
        elif self.samplingtype in [SamplingType.MUNITSC, SamplingType.MMVWINC]:
            self.afterCircleDrawn = Signal('RLiSetupMapPanel.afterCircleDrawn')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='line')
        else:
            self.sampleFrameChanged = Signal('RLiSetupMapPanel.sampleFrameChanged')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(graphicsType='rectangle')

        self._registeredGraphics.AddPen('rlisetup', wx.Pen(wx.GREEN, width=2,
                                                           style=wx.SOLID))
        self._registeredGraphics.AddItem(coords=[[0, 0], [0, 0]],
                                         penName='rlisetup', hide=True)

        if self.samplingtype != SamplingType.VECT:
            self.toolbar.SelectDefault()

    def GetMap(self):
        return self.map_

    def OnPan(self, event):
        """Panning, set mouse to drag."""
        self.mapWindow.SetModePan()

    def OnZoomIn(self, event):
        """Zoom in the map."""
        self.mapWindow.SetModeZoomIn()

    def OnZoomOut(self, event):
        """Zoom out the map."""
        self.mapWindow.SetModeZoomOut()

    def OnZoomToMap(self, event):
        layers = self.map_.GetListOfLayers()
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)

    def OnDrawRadius(self, event):
        """Start draw mode"""
        self.mapWindow.mouse['use'] = "None"
        self.mapWindow.mouse['box'] = "line"
        self.mapWindow.pen = wx.Pen(colour=wx.RED, width=1,
                                    style=wx.SHORT_DASH)
        self.mapWindow.SetNamedCursor('cross')
        self.mapWindow.mouseLeftUp.connect(self._radiusDrawn)

    def OnDigitizeRegion(self, event):
        """Start draw mode"""
        self.mapWindow.mouse['use'] = "None"
        self.mapWindow.mouse['box'] = "line"
        self.mapWindow.pen = wx.Pen(colour=wx.RED, width=1,
                                    style=wx.SHORT_DASH)
        self.mapWindow.SetNamedCursor('cross')
        self.mapWindow.mouseLeftUp.connect(self._lineSegmentDrawn)
        self.mapWindow.mouseDClick.connect(self._mouseDbClick)

        self._registeredGraphics.GetItem(0).SetCoords([])

    def OnDraw(self, event):
        """Start draw mode"""
        self.mapWindow.mouse['use'] = "None"
        self.mapWindow.mouse['box'] = "box"
        self.mapWindow.pen = wx.Pen(colour=wx.RED, width=2,
                                    style=wx.SHORT_DASH)
        self.mapWindow.SetNamedCursor('cross')
        self.mapWindow.mouseLeftUp.connect(self._rectangleDrawn)

    def _lineSegmentDrawn(self, x, y):
        item = self._registeredGraphics.GetItem(0)
        coords = item.GetCoords()
        if len(coords) == 0:
            coords.extend([self.mapWindow.Pixel2Cell(self.mapWindow.mouse['begin'])])
        coords.extend([[x, y]])

        item.SetCoords(coords)
        item.SetPropertyVal('hide', False)
        self.mapWindow.ClearLines()
        self._registeredGraphics.Draw(self.mapWindow.pdcTmp)

    def _mouseDbClick(self, x, y):
        item = self._registeredGraphics.GetItem(0)
        coords = item.GetCoords()
        coords.extend([[x, y]])
        item.SetCoords(coords)
        item.SetPropertyVal('hide', False)
        self.mapWindow.ClearLines()
        self._registeredGraphics.Draw(self.mapWindow.pdc)
        self.createRegion()

    def createRegion(self):
        dlg = wx.TextEntryDialog(None, 'Name of sample region',
                                 'Create region', 'region' + str(self.catId))
        ret = dlg.ShowModal()
        while True:
            if ret == wx.ID_OK:
                raster = dlg.GetValue()
                if checkMapExists(raster):
                    GMessage(parent=self, message=_("The raster file %s already"
                             " exists, please change name") % raster)
                    ret = dlg.ShowModal()
                else:
                    dlg.Destroy()
                    marea = self.writeArea(self._registeredGraphics.GetItem(0).GetCoords(), raster)
                    self.nextRegion(next=True, area=marea)
                    break
            else:
                self.nextRegion(next=False)
                break

    def nextRegion(self, next=True, area=None):
        self.mapWindow.ClearLines()
        item = self._registeredGraphics.GetItem(0)
        item.SetCoords([])
        item.SetPropertyVal('hide', True)

        layers = self.map_.GetListOfLayers()
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
        if next is True:
            self.afterRegionDrawn.emit(marea=area)
        else:
            gcmd.GMessage(parent=self.parent,
                          message=_("Raster map not created. Please redraw region."))

    def writeArea(self, coords, rasterName):
        polyfile = tempfile.NamedTemporaryFile(delete=False)
        polyfile.write("AREA\n")
        for coor in coords:
            east, north = coor
            point = " %s %s\n" % (east, north)
            polyfile.write(point)

        catbuf = "=%d a\n" % self.catId
        polyfile.write(catbuf)
        self.catId = self.catId + 1

        polyfile.close()
        region_settings = grass.parse_command('g.region', flags='p',
                                              delimiter=':')
        pname = polyfile.name.split('/')[-1]
        tmpraster = "rast_" + pname
        tmpvector = "vect_" + pname
        wx.BeginBusyCursor()
        wx.Yield()
        RunCommand('r.in.poly', input=polyfile.name, output=tmpraster,
                   rows=region_settings['rows'], overwrite=True)

        RunCommand('r.to.vect', input=tmpraster, output=tmpvector,
                   type='area', overwrite=True)

        RunCommand('v.to.rast', input=tmpvector, output=rasterName,
                   value=1, use='val')
        wx.EndBusyCursor()
        grass.use_temp_region()
        grass.run_command('g.region', vector=tmpvector)
        region = grass.region()

        marea = MaskedArea(region, rasterName)

        RunCommand('g.remove', flags='f', type='raster', name=tmpraster)
        RunCommand('g.remove', flags='f', type='vector', name=tmpvector)

        os.unlink(polyfile.name)
        return marea

    def _onToolChanged(self):
        """Helper function to disconnect drawing"""
        try:
            self.mapWindow.mouseLeftUp.disconnect(self._rectangleDrawn)
            self.mapWindow.mouseLeftUp.disconnect(self._radiusDrawn)
            self.mapWindow.mouseMoving.disconnect(self._mouseMoving)
            self.mapWindow.mouseLeftDown.disconnect(self._mouseLeftDown)
            self.mapWindow.mouseDClick.disconnect(self._mouseDbClick)
        except DispatcherKeyError:
            pass

    def _radiusDrawn(self, x, y):
        """When drawing finished, get region values"""
        mouse = self.mapWindow.mouse
        item = self._registeredGraphics.GetItem(0)
        p1 = mouse['begin']
        p2 = mouse['end']
        dist, (north, east) = self.mapWindow.Distance(p1, p2, False)
        circle = Circle(p1, dist)
        self.mapWindow.ClearLines()
        self.mapWindow.pdcTmp.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
        pen = wx.Pen(colour=wx.RED, width=2)
        self.mapWindow.pdcTmp.SetPen(pen)
        self.mapWindow.pdcTmp.DrawCircle(circle.point[0], circle.point[1],
                                         circle.radius)
        self._registeredGraphics.Draw(self.mapWindow.pdcTmp)
        self.createCricle(circle)

    def createCricle(self, c):
        dlg = wx.TextEntryDialog(None, 'Name of sample circle region',
                                 'Create circle region', 'circle' + str(self.catId))
        ret = dlg.ShowModal()
        while True:        
            if ret == wx.ID_OK:
                raster = dlg.GetValue()
                if checkMapExists(raster):
                    GMessage(parent=self, message=_("The raster file %s already"
                             " exists, please change name") % raster)
                    ret = dlg.ShowModal()
                else:
                    dlg.Destroy()
                    circle = self.writeCircle(c, raster)
                    self.nextCircle(next=True, circle=circle)
                    break
            else:
                self.nextCircle(next=False)
                break

    def nextCircle(self, next=True, circle=None):
        self.mapWindow.ClearLines()
        item = self._registeredGraphics.GetItem(0)
        item.SetPropertyVal('hide', True)
        layers = self.map_.GetListOfLayers()
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
        if next is True:
            self.afterCircleDrawn.emit(region=circle)
        else:
            gcmd.GMessage(parent=self.parent,
                          message=_("Raster map not created. redraw region again."))

    def writeCircle(self, circle, rasterName):
        coords = self.mapWindow.Pixel2Cell(circle.point)
        RunCommand('r.circle', output=rasterName, max=circle.radius,
                   coordinate=coords, flags="b")
        grass.use_temp_region()
        grass.run_command('g.region', zoom=rasterName)
        region = grass.region()
        marea = MaskedArea(region, rasterName, circle.radius)
        return marea

    def _rectangleDrawn(self):
        """When drawing finished, get region values"""
        mouse = self.mapWindow.mouse
        item = self._registeredGraphics.GetItem(0)
        p1 = self.mapWindow.Pixel2Cell(mouse['begin'])
        p2 = self.mapWindow.Pixel2Cell(mouse['end'])
        item.SetCoords([p1, p2])
        region = {'n': max(p1[1], p2[1]),
                  's': min(p1[1], p2[1]),
                  'w': min(p1[0], p2[0]),
                  'e': max(p1[0], p2[0])}
        item.SetPropertyVal('hide', False)
        self.mapWindow.ClearLines()
        self._registeredGraphics.Draw(self.mapWindow.pdcTmp)
        if self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
            dlg = wx.MessageDialog(self, "Is this area ok?",
                                   "select sampling unit",
                                   wx.YES_NO | wx.ICON_QUESTION)
            ret = dlg.ShowModal()
            if ret == wx.ID_YES:
                grass.use_temp_region()
                grass.run_command('g.region', n=region['n'], s=region['s'],
                                  e=region['e'], w=region['w'])
                tregion = grass.region()
                self.sampleFrameChanged.emit(region=tregion)
                self.mapWindow.ClearLines()
                item = self._registeredGraphics.GetItem(0)
                item.SetPropertyVal('hide', True)
                layers = self.map_.GetListOfLayers()
                self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False,
                                         render=True)
            else:
                self.nextRegion(next=False)
            dlg.Destroy()

        elif self.samplingtype != SamplingType.WHOLE:
            """When drawing finished, get region values"""
            self.sampleFrameChanged.emit(region=region)
Beispiel #9
0
class MapPanelBase(wx.Panel):
    """Base class for map display window

    Derived class must use (create and initialize) \c statusbarManager
    or override
    GetProperty(), SetProperty() and HasProperty() methods.

    Several methods has to be overridden or
    \c NotImplementedError("MethodName") will be raised.

    If derived class enables and disables auto-rendering,
    it should override IsAutoRendered method.

    It is expected that derived class will call _setUpMapWindow().

    Derived class can has one or more map windows (and map renders)
    but implementation of MapPanelBase expects that one window and
    one map will be current.
    Current instances of map window and map renderer should be returned
    by methods GetWindow() and GetMap() respectively.

    AUI manager is stored in \c self._mgr.
    """
    def __init__(
        self,
        parent=None,
        id=wx.ID_ANY,
        title="",
        auimgr=None,
        name="",
        **kwargs,
    ):
        """

        .. warning::
            Use \a auimgr parameter only if you know what you are doing.

        :param parent: gui parent
        :param id: wx id
        :param title: window title
        :param toolbars: array of activated toolbars, e.g. ['map', 'digit']
        :param auimgr: AUI manager (if \c None, wx.aui.AuiManager is used)
        :param name: panel name
        :param kwargs: arguments passed to \c wx.Panel
        """

        self.parent = parent

        wx.Panel.__init__(self, parent, id, name=name, **kwargs)

        # toolbars
        self.toolbars = {}
        self.iconsize = (16, 16)

        # properties are shared in other objects, so defining here
        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        # update statusbar when user-defined projection changed
        self.mapWindowProperties.useDefinedProjectionChanged.connect(
            self.StatusbarUpdate)

        #
        # Fancy gui
        #
        if auimgr is None:
            from wx.aui import AuiManager

            self._mgr = AuiManager(self)
        else:
            self._mgr = auimgr

        # handles switching between tools in different toolbars
        self._toolSwitcher = ToolSwitcher()
        self._toolSwitcher.toggleToolChanged.connect(self._onToggleTool)

        # set accelerator table
        self.shortcuts_table = [
            (self.OnCloseWindow, wx.ACCEL_CTRL, ord("W")),
            (self.OnRender, wx.ACCEL_CTRL, ord("R")),
            (self.OnRender, wx.ACCEL_NORMAL, wx.WXK_F5),
        ]

        self._initShortcuts()

    def _initShortcuts(self):
        """init shortcuts to acceleration table"""
        accelTable = []
        for handler, entry, kdb in self.shortcuts_table:
            wxId = NewId()
            self.Bind(wx.EVT_MENU, handler, id=wxId)
            accelTable.append((entry, kdb, wxId))
        self.SetAcceleratorTable(wx.AcceleratorTable(accelTable))

    def _initMap(self, Map):
        """Initialize map display, set dimensions and map region"""
        if not grass.find_program("g.region", "--help"):
            sys.exit(
                _("GRASS module '%s' not found. Unable to start map "
                  "display window.") % "g.region")

        Debug.msg(2, "MapPanel._initMap():")
        Map.ChangeMapSize(self.GetClientSize())
        Map.region = Map.GetRegion()  # g.region -upgc
        # self.Map.SetRegion() # adjust region to match display window

    def _resize(self):
        Debug.msg(1, "MapPanel_resize():")
        wm, hw = self.MapWindow.GetClientSize()
        wf, hf = self.GetSize()
        dw = wf - wm
        dh = hf - hw
        self.SetSize((wf + dw, hf + dh))

    def _onToggleTool(self, id):
        if self._toolSwitcher.IsToolInGroup(id, "mouseUse"):
            self.GetWindow().UnregisterAllHandlers()

    def OnSize(self, event):
        """Adjust statusbar on changing size"""
        # reposition checkbox in statusbar
        self.StatusbarReposition()

        # update statusbar
        self.StatusbarUpdate()

    def OnCloseWindow(self, event):
        self.Destroy()

    def GetToolSwitcher(self):
        return self._toolSwitcher

    def SetProperty(self, name, value):
        """Sets property"""
        if hasattr(self.mapWindowProperties, name):
            setattr(self.mapWindowProperties, name, value)
        else:
            self.statusbarManager.SetProperty(name, value)

    def GetProperty(self, name):
        """Returns property"""
        if hasattr(self.mapWindowProperties, name):
            return getattr(self.mapWindowProperties, name)
        else:
            return self.statusbarManager.GetProperty(name)

    def HasProperty(self, name):
        """Checks whether object has property"""
        return self.statusbarManager.HasProperty(name)

    def GetPPM(self):
        """Get pixel per meter

        .. todo::
            now computed every time, is it necessary?

        .. todo::
            enable user to specify ppm (and store it in UserSettings)
        """
        # TODO: need to be fixed...
        # screen X region problem
        # user should specify ppm
        dc = wx.ScreenDC()
        dpSizePx = wx.DisplaySize()  # display size in pixels
        dpSizeMM = wx.DisplaySizeMM()  # display size in mm (system)
        dpSizeIn = (dpSizeMM[0] / 25.4, dpSizeMM[1] / 25.4)  # inches
        sysPpi = dc.GetPPI()
        comPpi = (dpSizePx[0] / dpSizeIn[0], dpSizePx[1] / dpSizeIn[1])

        ppi = comPpi  # pixel per inch
        ppm = ((ppi[0] / 2.54) * 100, (ppi[1] / 2.54) * 100)  # pixel per meter

        Debug.msg(
            4,
            "MapPanelBase.GetPPM(): size: px=%d,%d mm=%f,%f "
            "in=%f,%f ppi: sys=%d,%d com=%d,%d; ppm=%f,%f" % (
                dpSizePx[0],
                dpSizePx[1],
                dpSizeMM[0],
                dpSizeMM[1],
                dpSizeIn[0],
                dpSizeIn[1],
                sysPpi[0],
                sysPpi[1],
                comPpi[0],
                comPpi[1],
                ppm[0],
                ppm[1],
            ),
        )

        return ppm

    def SetMapScale(self, value, map=None):
        """Set current map scale

        :param value: scale value (n if scale is 1:n)
        :param map: Map instance (if none self.Map is used)
        """
        if not map:
            map = self.Map

        region = self.Map.region
        dEW = value * (region["cols"] / self.GetPPM()[0])
        dNS = value * (region["rows"] / self.GetPPM()[1])
        region["n"] = region["center_northing"] + dNS / 2.0
        region["s"] = region["center_northing"] - dNS / 2.0
        region["w"] = region["center_easting"] - dEW / 2.0
        region["e"] = region["center_easting"] + dEW / 2.0

        # add to zoom history
        self.GetWindow().ZoomHistory(region["n"], region["s"], region["e"],
                                     region["w"])

    def GetMapScale(self, map=None):
        """Get current map scale

        :param map: Map instance (if none self.Map is used)
        """
        if not map:
            map = self.GetMap()

        region = map.region
        ppm = self.GetPPM()

        heightCm = region["rows"] / ppm[1] * 100
        widthCm = region["cols"] / ppm[0] * 100

        Debug.msg(
            4, "MapPanel.GetMapScale(): width_cm=%f, height_cm=%f" %
            (widthCm, heightCm))

        xscale = (region["e"] - region["w"]) / (region["cols"] / ppm[0])
        yscale = (region["n"] - region["s"]) / (region["rows"] / ppm[1])
        scale = (xscale + yscale) / 2.0

        Debug.msg(
            3,
            "MapPanel.GetMapScale(): xscale=%f, yscale=%f -> scale=%f" %
            (xscale, yscale, scale),
        )

        return scale

    def GetProgressBar(self):
        """Returns progress bar

        Progress bar can be used by other classes.
        """
        return self.statusbarManager.GetProgressBar()

    def GetMap(self):
        """Returns current map (renderer) instance"""
        raise NotImplementedError("GetMap")

    def GetWindow(self):
        """Returns current map window"""
        raise NotImplementedError("GetWindow")

    def GetWindows(self):
        """Returns list of map windows"""
        raise NotImplementedError("GetWindows")

    def GetMapToolbar(self):
        """Returns toolbar with zooming tools"""
        raise NotImplementedError("GetMapToolbar")

    def GetToolbar(self, name):
        """Returns toolbar if exists and is active, else None."""
        if name in self.toolbars and self.toolbars[name].IsShown():
            return self.toolbars[name]

        return None

    def StatusbarUpdate(self):
        """Update statusbar content"""
        if self.statusbarManager:
            Debug.msg(5, "MapPanelBase.StatusbarUpdate()")
            self.statusbarManager.Update()

    def IsAutoRendered(self):
        """Check if auto-rendering is enabled"""
        # TODO: this is now not the right place to access this attribute
        # TODO: add mapWindowProperties to init parameters
        # and pass the right object in the init of derived class?
        # or do not use this method at all, let mapwindow decide
        return self.mapWindowProperties.autoRender

    def CoordinatesChanged(self):
        """Shows current coordinates on statusbar."""
        # assuming that the first mode is coordinates
        # probably shold not be here but good solution is not available now
        if self.statusbarManager:
            if self.statusbarManager.GetMode() == 0:
                self.statusbarManager.ShowItem("coordinates")

    def CreateStatusbar(self, statusbarItems):
        """Create statusbar (default items)."""
        # create statusbar and its manager
        statusbar = wx.StatusBar(self, id=wx.ID_ANY)
        statusbar.SetMinHeight(24)
        statusbar.SetFieldsCount(3)
        statusbar.SetStatusWidths([-6, -2, -1])
        self.statusbarManager = sb.SbManager(mapframe=self,
                                             statusbar=statusbar)

        # fill statusbar manager
        self.statusbarManager.AddStatusbarItemsByClass(statusbarItems,
                                                       mapframe=self,
                                                       statusbar=statusbar)
        self.statusbarManager.AddStatusbarItem(
            sb.SbRender(self, statusbar=statusbar, position=2))
        self.statusbarManager.Update()
        return statusbar

    def AddStatusbarPane(self):
        """Add statusbar as a pane"""
        self._mgr.AddPane(
            self.statusbar,
            wx.aui.AuiPaneInfo().Bottom().MinSize(
                30, 30).Fixed().Name("statusbar").CloseButton(
                    False).DestroyOnClose(True).ToolbarPane().Dockable(
                        False).PaneBorder(False).Gripper(False),
        )

    def SetStatusText(self, *args):
        """Overide wx.StatusBar method"""
        self.statusbar.SetStatusText(*args)

    def ShowStatusbar(self, show):
        """Show/hide statusbar and associated pane"""
        self._mgr.GetPane("statusbar").Show(show)
        self._mgr.Update()

    def IsStatusbarShown(self):
        """Check if statusbar is shown"""
        return self._mgr.GetPane("statusbar").IsShown()

    def StatusbarReposition(self):
        """Reposition items in statusbar"""
        if self.statusbarManager:
            self.statusbarManager.Reposition()

    def StatusbarEnableLongHelp(self, enable=True):
        """Enable/disable toolbars long help"""
        for toolbar in six.itervalues(self.toolbars):
            if toolbar:
                toolbar.EnableLongHelp(enable)

    def ShowAllToolbars(self, show=True):
        if not show:  # hide
            action = self.RemoveToolbar
        else:
            action = self.AddToolbar
        for toolbar in self.GetToolbarNames():
            action(toolbar)

    def AreAllToolbarsShown(self):
        return self.GetMapToolbar().IsShown()

    def GetToolbarNames(self):
        """Return toolbar names"""
        return list(self.toolbars.keys())

    def AddToolbar(self):
        """Add defined toolbar to the window"""
        raise NotImplementedError("AddToolbar")

    def RemoveToolbar(self, name, destroy=False):
        """Removes defined toolbar from the window

        :param name toolbar to remove
        :param destroy True to destroy otherwise toolbar is only hidden
        """
        self._mgr.DetachPane(self.toolbars[name])
        if destroy:
            self._toolSwitcher.RemoveToolbarFromGroup("mouseUse",
                                                      self.toolbars[name])
            self.toolbars[name].Destroy()
            self.toolbars.pop(name)
        else:
            self.toolbars[name].Hide()

        self._mgr.Update()

    def IsPaneShown(self, name):
        """Check if pane (toolbar, mapWindow ...) of given name is currently shown"""
        if self._mgr.GetPane(name).IsOk():
            return self._mgr.GetPane(name).IsShown()
        return False

    def OnRender(self, event):
        """Re-render map composition (each map layer)"""
        raise NotImplementedError("OnRender")

    def OnDraw(self, event):
        """Re-display current map composition"""
        self.MapWindow.UpdateMap(render=False)

    def OnErase(self, event):
        """Erase the canvas"""
        self.MapWindow.EraseMap()

    def OnZoomIn(self, event):
        """Zoom in the map."""
        self.MapWindow.SetModeZoomIn()

    def OnZoomOut(self, event):
        """Zoom out the map."""
        self.MapWindow.SetModeZoomOut()

    def _setUpMapWindow(self, mapWindow):
        """Binds map windows' zoom history signals to map toolbar."""
        # enable or disable zoom history tool
        if self.GetMapToolbar():
            mapWindow.zoomHistoryAvailable.connect(
                lambda: self.GetMapToolbar().Enable("zoomBack", enable=True))
            mapWindow.zoomHistoryUnavailable.connect(
                lambda: self.GetMapToolbar().Enable("zoomBack", enable=False))
        mapWindow.mouseMoving.connect(self.CoordinatesChanged)

    def OnPointer(self, event):
        """Sets mouse mode to pointer."""
        self.MapWindow.SetModePointer()

    def OnPan(self, event):
        """Panning, set mouse to drag"""
        self.MapWindow.SetModePan()

    def OnZoomBack(self, event):
        """Zoom last (previously stored position)"""
        self.MapWindow.ZoomBack()

    def OnZoomToMap(self, event):
        """
        Set display extents to match selected raster (including NULLs)
        or vector map.
        """
        self.MapWindow.ZoomToMap(layers=self.Map.GetListOfLayers())

    def OnZoomToWind(self, event):
        """Set display geometry to match computational region
        settings (set with g.region)
        """
        self.MapWindow.ZoomToWind()

    def OnZoomToDefault(self, event):
        """Set display geometry to match default region settings"""
        self.MapWindow.ZoomToDefault()

    def OnMapDisplayProperties(self, event):
        """Show Map Display Properties dialog"""
        from mapdisp.properties import MapDisplayPropertiesDialog

        dlg = MapDisplayPropertiesDialog(parent=self,
                                         mapframe=self,
                                         properties=self.mapWindowProperties)
        dlg.CenterOnParent()
        dlg.Show()
Beispiel #10
0
class RLiSetupMapPanel(wx.Panel):
    """Panel with mapwindow used in r.li.setup"""

    def __init__(self, parent, samplingType, icon=None, map_=None):
        wx.Panel.__init__(self, parent=parent)

        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        giface = StandaloneGrassInterface()
        self.samplingtype = samplingType
        self.parent = parent

        if map_:
            self.map_ = map_
        else:
            self.map_ = Map()
        self.map_.region = self.map_.GetRegion()

        self._mgr = wx.aui.AuiManager(self)
        self.mapWindow = BufferedMapWindow(parent=self, giface=giface,
                                           Map=self.map_,
                                           properties=self.mapWindowProperties)
        self._mgr.AddPane(self.mapWindow, wx.aui.AuiPaneInfo().CentrePane().
                          Dockable(True).BestSize((-1, -1)).Name('mapwindow').
                          CloseButton(False).DestroyOnClose(True).
                          Layer(0))
        self._toolSwitcher = ToolSwitcher()
        self._toolSwitcher.toggleToolChanged.connect(self._onToolChanged)
        self.toolbar = RLiSetupToolbar(self, self._toolSwitcher)

        self.catId = 1

        self._mgr.AddPane(self.toolbar,
                          wx.aui.AuiPaneInfo().
                          Name("maptoolbar").Caption(_("Map Toolbar")).
                          ToolbarPane().Left().Name('mapToolbar').
                          CloseButton(False).Layer(1).Gripper(False).
                          BestSize((self.toolbar.GetBestSize())))
        self._mgr.Update()

        if self.samplingtype == SamplingType.REGIONS:
            self.afterRegionDrawn = Signal('RLiSetupMapPanel.afterRegionDrawn')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType='line')
        elif self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
            self.sampleFrameChanged = Signal(
                'RLiSetupMapPanel.sampleFrameChanged')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType='rectangle')
        elif self.samplingtype in [SamplingType.MUNITSC, SamplingType.MMVWINC]:
            self.afterCircleDrawn = Signal('RLiSetupMapPanel.afterCircleDrawn')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType='line')
        else:
            self.sampleFrameChanged = Signal(
                'RLiSetupMapPanel.sampleFrameChanged')
            self._registeredGraphics = self.mapWindow.RegisterGraphicsToDraw(
                graphicsType='rectangle')

        self._registeredGraphics.AddPen('rlisetup', wx.Pen(wx.GREEN, width=2,
                                                           style=wx.SOLID))
        self._registeredGraphics.AddItem(coords=[[0, 0], [0, 0]],
                                         penName='rlisetup', hide=True)

        if self.samplingtype != SamplingType.VECT:
            self.toolbar.SelectDefault()

    def GetMap(self):
        return self.map_

    def OnPan(self, event):
        """Panning, set mouse to drag."""
        self.mapWindow.SetModePan()

    def OnZoomIn(self, event):
        """Zoom in the map."""
        self.mapWindow.SetModeZoomIn()

    def OnZoomOut(self, event):
        """Zoom out the map."""
        self.mapWindow.SetModeZoomOut()

    def OnZoomToMap(self, event):
        layers = self.map_.GetListOfLayers()
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)

    def OnDrawRadius(self, event):
        """Start draw mode"""
        self.mapWindow.mouse['use'] = "None"
        self.mapWindow.mouse['box'] = "line"
        self.mapWindow.pen = wx.Pen(colour=wx.RED, width=1,
                                    style=wx.SHORT_DASH)
        self.mapWindow.SetNamedCursor('cross')
        self.mapWindow.mouseLeftUp.connect(self._radiusDrawn)

    def OnDigitizeRegion(self, event):
        """Start draw mode"""
        self.mapWindow.mouse['use'] = "None"
        self.mapWindow.mouse['box'] = "line"
        self.mapWindow.pen = wx.Pen(colour=wx.RED, width=1,
                                    style=wx.SHORT_DASH)
        self.mapWindow.SetNamedCursor('cross')
        self.mapWindow.mouseLeftUp.connect(self._lineSegmentDrawn)
        self.mapWindow.mouseDClick.connect(self._mouseDbClick)

        self._registeredGraphics.GetItem(0).SetCoords([])

    def OnDraw(self, event):
        """Start draw mode"""
        self.mapWindow.mouse['use'] = "None"
        self.mapWindow.mouse['box'] = "box"
        self.mapWindow.pen = wx.Pen(colour=wx.RED, width=2,
                                    style=wx.SHORT_DASH)
        self.mapWindow.SetNamedCursor('cross')
        self.mapWindow.mouseLeftUp.connect(self._rectangleDrawn)

    def _lineSegmentDrawn(self, x, y):
        item = self._registeredGraphics.GetItem(0)
        coords = item.GetCoords()
        if len(coords) == 0:
            coords.extend([self.mapWindow.Pixel2Cell(
                self.mapWindow.mouse['begin'])])
        coords.extend([[x, y]])

        item.SetCoords(coords)
        item.SetPropertyVal('hide', False)
        self.mapWindow.ClearLines()
        self._registeredGraphics.Draw()

    def _mouseDbClick(self, x, y):
        item = self._registeredGraphics.GetItem(0)
        coords = item.GetCoords()
        coords.extend([[x, y]])
        item.SetCoords(coords)
        item.SetPropertyVal('hide', False)
        self.mapWindow.ClearLines()
        self._registeredGraphics.Draw()
        self.createRegion()

    def createRegion(self):
        dlg = wx.TextEntryDialog(None, 'Name of sample region',
                                 'Create region', 'region' + str(self.catId))
        ret = dlg.ShowModal()
        while True:
            if ret == wx.ID_OK:
                raster = dlg.GetValue()
                if checkMapExists(raster):
                    GMessage(
                        parent=self, message=_(
                            "The raster file %s already"
                            " exists, please change name") %
                        raster)
                    ret = dlg.ShowModal()
                else:
                    dlg.Destroy()
                    marea = self.writeArea(
                        self._registeredGraphics.GetItem(0).GetCoords(), raster)
                    self.nextRegion(next=True, area=marea)
                    break
            else:
                self.nextRegion(next=False)
                break

    def nextRegion(self, next=True, area=None):
        self.mapWindow.ClearLines()
        item = self._registeredGraphics.GetItem(0)
        item.SetCoords([])
        item.SetPropertyVal('hide', True)

        layers = self.map_.GetListOfLayers()
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
        if next is True:
            self.afterRegionDrawn.emit(marea=area)
        else:
            gcmd.GMessage(parent=self.parent, message=_(
                "Raster map not created. Please redraw region."))

    def writeArea(self, coords, rasterName):
        polyfile = tempfile.NamedTemporaryFile(delete=False)
        polyfile.write("AREA\n")
        for coor in coords:
            east, north = coor
            point = " %s %s\n" % (east, north)
            polyfile.write(point)

        catbuf = "=%d a\n" % self.catId
        polyfile.write(catbuf)
        self.catId = self.catId + 1

        polyfile.close()
        region_settings = grass.parse_command('g.region', flags='p',
                                              delimiter=':')
        pname = polyfile.name.split('/')[-1]
        tmpraster = "rast_" + pname
        tmpvector = "vect_" + pname
        wx.BeginBusyCursor()
        wx.GetApp().Yield()
        RunCommand('r.in.poly', input=polyfile.name, output=tmpraster,
                   rows=region_settings['rows'], overwrite=True)

        RunCommand('r.to.vect', input=tmpraster, output=tmpvector,
                   type='area', overwrite=True)

        RunCommand('v.to.rast', input=tmpvector, output=rasterName,
                   value=1, use='val')
        wx.EndBusyCursor()
        grass.use_temp_region()
        grass.run_command('g.region', vector=tmpvector)
        region = grass.region()

        marea = MaskedArea(region, rasterName)

        RunCommand('g.remove', flags='f', type='raster', name=tmpraster)
        RunCommand('g.remove', flags='f', type='vector', name=tmpvector)

        os.unlink(polyfile.name)
        return marea

    def _onToolChanged(self):
        """Helper function to disconnect drawing"""
        try:
            self.mapWindow.mouseLeftUp.disconnect(self._rectangleDrawn)
            self.mapWindow.mouseLeftUp.disconnect(self._radiusDrawn)
            self.mapWindow.mouseMoving.disconnect(self._mouseMoving)
            self.mapWindow.mouseLeftDown.disconnect(self._mouseLeftDown)
            self.mapWindow.mouseDClick.disconnect(self._mouseDbClick)
        except DispatcherKeyError:
            pass

    def _radiusDrawn(self, x, y):
        """When drawing finished, get region values"""
        mouse = self.mapWindow.mouse
        item = self._registeredGraphics.GetItem(0)
        p1 = mouse['begin']
        p2 = mouse['end']
        dist, (north, east) = self.mapWindow.Distance(p1, p2, False)
        circle = Circle(p1, dist)
        self.mapWindow.ClearLines()
        self.mapWindow.pdcTmp.SetBrush(wx.Brush(wx.CYAN, wx.TRANSPARENT))
        pen = wx.Pen(colour=wx.RED, width=2)
        self.mapWindow.pdcTmp.SetPen(pen)
        self.mapWindow.pdcTmp.DrawCircle(circle.point[0], circle.point[1],
                                         circle.radius)
        self._registeredGraphics.Draw()
        self.createCricle(circle)

    def createCricle(self, c):
        dlg = wx.TextEntryDialog(None,
                                 'Name of sample circle region',
                                 'Create circle region',
                                 'circle' + str(self.catId))
        ret = dlg.ShowModal()
        while True:
            if ret == wx.ID_OK:
                raster = dlg.GetValue()
                if checkMapExists(raster):
                    GMessage(
                        parent=self, message=_(
                            "The raster file %s already"
                            " exists, please change name") %
                        raster)
                    ret = dlg.ShowModal()
                else:
                    dlg.Destroy()
                    circle = self.writeCircle(c, raster)
                    self.nextCircle(next=True, circle=circle)
                    break
            else:
                self.nextCircle(next=False)
                break

    def nextCircle(self, next=True, circle=None):
        self.mapWindow.ClearLines()
        item = self._registeredGraphics.GetItem(0)
        item.SetPropertyVal('hide', True)
        layers = self.map_.GetListOfLayers()
        self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False, render=True)
        if next is True:
            self.afterCircleDrawn.emit(region=circle)
        else:
            gcmd.GMessage(parent=self.parent, message=_(
                "Raster map not created. redraw region again."))

    def writeCircle(self, circle, rasterName):
        coords = self.mapWindow.Pixel2Cell(circle.point)
        RunCommand('r.circle', output=rasterName, max=circle.radius,
                   coordinate=coords, flags="b")
        grass.use_temp_region()
        grass.run_command('g.region', zoom=rasterName)
        region = grass.region()
        marea = MaskedArea(region, rasterName, circle.radius)
        return marea

    def _rectangleDrawn(self):
        """When drawing finished, get region values"""
        mouse = self.mapWindow.mouse
        item = self._registeredGraphics.GetItem(0)
        p1 = self.mapWindow.Pixel2Cell(mouse['begin'])
        p2 = self.mapWindow.Pixel2Cell(mouse['end'])
        item.SetCoords([p1, p2])
        region = {'n': max(p1[1], p2[1]),
                  's': min(p1[1], p2[1]),
                  'w': min(p1[0], p2[0]),
                  'e': max(p1[0], p2[0])}
        item.SetPropertyVal('hide', False)
        self.mapWindow.ClearLines()
        self._registeredGraphics.Draw()
        if self.samplingtype in [SamplingType.MUNITSR, SamplingType.MMVWINR]:
            dlg = wx.MessageDialog(self, "Is this area ok?",
                                   "select sampling unit",
                                   wx.YES_NO | wx.ICON_QUESTION)
            ret = dlg.ShowModal()
            if ret == wx.ID_YES:
                grass.use_temp_region()
                grass.run_command('g.region', n=region['n'], s=region['s'],
                                  e=region['e'], w=region['w'])
                tregion = grass.region()
                self.sampleFrameChanged.emit(region=tregion)
                self.mapWindow.ClearLines()
                item = self._registeredGraphics.GetItem(0)
                item.SetPropertyVal('hide', True)
                layers = self.map_.GetListOfLayers()
                self.mapWindow.ZoomToMap(layers=layers, ignoreNulls=False,
                                         render=True)
            else:
                self.nextRegion(next=False)
            dlg.Destroy()

        elif self.samplingtype != SamplingType.WHOLE:
            """When drawing finished, get region values"""
            self.sampleFrameChanged.emit(region=region)
Beispiel #11
0
class MapFrame(SingleMapFrame):
    """Main frame for map display window. Drawing takes place in
    child double buffered drawing window.
    """
    def __init__(
            self,
            parent,
            giface,
            title=_(
                "GRASS GIS Manage Location of Tick Points on a Scanned Photo"),
            toolbars=["gcpdisp"],
            Map=None,
            auimgr=None,
            name='GCPMapWindow',
            **kwargs):
        """Main map display window with toolbars, statusbar and
        DrawWindow

        :param giface: GRASS interface instance
        :param title: window title
        :param toolbars: array of activated toolbars, e.g. ['map', 'digit']
        :param map: instance of render.Map
        :param auimgs: AUI manager
        :param kwargs: wx.Frame attribures
        """

        SingleMapFrame.__init__(self,
                                parent=parent,
                                giface=giface,
                                title=title,
                                Map=Map,
                                auimgr=auimgr,
                                name=name,
                                **kwargs)

        self._giface = giface
        # properties are shared in other objects, so defining here
        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        self.mapWindowProperties.alignExtent = True

        #
        # Add toolbars
        #
        for toolb in toolbars:
            self.AddToolbar(toolb)

        self.activemap = self.toolbars['gcpdisp'].togglemap
        self.activemap.SetSelection(0)

        self.SrcMap = self.grwiz.SrcMap  # instance of render.Map
        self.TgtMap = self.grwiz.TgtMap  # instance of render.Map
        self._mgr.SetDockSizeConstraint(0.5, 0.5)

        #
        # Add statusbar
        #

        # items for choice
        self.statusbarItems = [
            sb.SbCoordinates, sb.SbRegionExtent, sb.SbCompRegionExtent,
            sb.SbShowRegion, sb.SbResolution, sb.SbDisplayGeometry,
            sb.SbMapScale, sb.SbProjection, sbgcp.SbGoToGCP, sbgcp.SbRMSError
        ]

        # create statusbar and its manager
        statusbar = self.CreateStatusBar(number=4, style=0)
        statusbar.SetStatusWidths([-5, -2, -1, -1])
        self.statusbarManager = sb.SbManager(mapframe=self,
                                             statusbar=statusbar)

        # fill statusbar manager
        self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems,
                                                       mapframe=self,
                                                       statusbar=statusbar)
        self.statusbarManager.AddStatusbarItem(
            sb.SbMask(self, statusbar=statusbar, position=2))
        self.statusbarManager.AddStatusbarItem(
            sb.SbRender(self, statusbar=statusbar, position=3))

        self.statusbarManager.SetMode(8)  # goto GCP

        #
        # Init map display (buffered DC & set default cursor)
        #
        self.grwiz.SwitchEnv('source')
        self.SrcMapWindow = BufferedMapWindow(
            parent=self,
            giface=self._giface,
            id=wx.ID_ANY,
            properties=self.mapWindowProperties,
            Map=self.SrcMap)

        self.grwiz.SwitchEnv('target')
        self.TgtMapWindow = BufferedMapWindow(
            parent=self,
            giface=self._giface,
            id=wx.ID_ANY,
            properties=self.mapWindowProperties,
            Map=self.TgtMap)
        self.MapWindow = self.SrcMapWindow
        self.Map = self.SrcMap
        self._setUpMapWindow(self.SrcMapWindow)
        self._setUpMapWindow(self.TgtMapWindow)
        self.SrcMapWindow.SetNamedCursor('cross')
        self.TgtMapWindow.SetNamedCursor('cross')
        # used to switch current map (combo box in toolbar)
        self.SrcMapWindow.mouseEntered.connect(
            lambda: self._setActiveMapWindow(self.SrcMapWindow))
        self.TgtMapWindow.mouseEntered.connect(
            lambda: self._setActiveMapWindow(self.TgtMapWindow))

        #
        # initialize region values
        #
        self._initMap(Map=self.SrcMap)
        self._initMap(Map=self.TgtMap)

        self.GetMapToolbar().SelectDefault()

        #
        # Bind various events
        #
        self.activemap.Bind(wx.EVT_CHOICE, self.OnUpdateActive)
        self.Bind(wx.EVT_SIZE, self.OnSize)

        #
        # Update fancy gui style
        #
        # AuiManager wants a CentrePane, workaround to get two equally sized
        # windows
        self.list = self.CreateGCPList()

        #self.SrcMapWindow.SetSize((300, 300))
        #self.TgtMapWindow.SetSize((300, 300))
        self.list.SetSize((100, 150))
        self._mgr.AddPane(
            self.list,
            wx.aui.AuiPaneInfo().Name("gcplist").Caption(
                _("GCP List")).LeftDockable(False).RightDockable(
                    False).PinButton().FloatingSize((600, 200)).CloseButton(
                        False).DestroyOnClose(True).Top().Layer(1).MinSize(
                            (200, 100)))
        self._mgr.AddPane(
            self.SrcMapWindow,
            wx.aui.AuiPaneInfo().Name("source").Caption(
                _("Source Display")).Dockable(False).CloseButton(
                    False).DestroyOnClose(True).Floatable(False).Centre())
        self._mgr.AddPane(
            self.TgtMapWindow,
            wx.aui.AuiPaneInfo().Name("target").Caption(
                _("Target Display")).Dockable(False).CloseButton(False).
            DestroyOnClose(True).Floatable(False).Right().Layer(0))

        srcwidth, srcheight = self.SrcMapWindow.GetSize()
        tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
        srcwidth = (srcwidth + tgtwidth) / 2
        self._mgr.GetPane("target").Hide()
        self._mgr.Update()
        self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
        self._mgr.GetPane("target").BestSize((srcwidth, srcheight))
        if self.show_target:
            self._mgr.GetPane("target").Show()
        else:
            self.activemap.Enable(False)
        # needed by Mac OS, does not harm on Linux, breaks display on Windows
        if platform.system() != 'Windows':
            self._mgr.Update()

        #
        # Init print module and classes
        #
        self.printopt = PrintOptions(self, self.MapWindow)

        #
        # Initialization of digitization tool
        #
        self.digit = None

        # set active map
        self.MapWindow = self.SrcMapWindow
        self.Map = self.SrcMap

        # do not init zoom history here, that happens when zooming to map(s)

        #
        # Re-use dialogs
        #
        self.dialogs = {}
        self.dialogs['attributes'] = None
        self.dialogs['category'] = None
        self.dialogs['barscale'] = None
        self.dialogs['legend'] = None

        self.decorationDialog = None  # decoration/overlays

        # doing nice things in statusbar when other things are ready
        self.statusbarManager.Update()

    def _setUpMapWindow(self, mapWindow):
        # TODO: almost the smae implementation as for MapFrameBase (only names differ)
        # enable or disable zoom history tool
        mapWindow.zoomHistoryAvailable.connect(
            lambda: self.GetMapToolbar().Enable('zoomback', enable=True))
        mapWindow.zoomHistoryUnavailable.connect(
            lambda: self.GetMapToolbar().Enable('zoomback', enable=False))
        mapWindow.mouseMoving.connect(self.CoordinatesChanged)

    def AddToolbar(self, name):
        """Add defined toolbar to the window

        Currently known toolbars are:
         - 'map'     - basic map toolbar
         - 'gcpdisp' - GCP Manager, Display
         - 'gcpman'  - GCP Manager, points management
         - 'nviz'    - 3D view mode
        """
        # default toolbar
        if name == "map":
            self.toolbars['map'] = MapToolbar(self, self._toolSwitcher)

            self._mgr.AddPane(
                self.toolbars['map'],
                wx.aui.AuiPaneInfo().Name("maptoolbar").Caption(
                    _("Map Toolbar")).ToolbarPane().Top().LeftDockable(False).
                RightDockable(False).BottomDockable(False).TopDockable(
                    True).CloseButton(False).Layer(2).BestSize(
                        (self.toolbars['map'].GetSize())))

        # GCP display
        elif name == "gcpdisp":
            self.toolbars['gcpdisp'] = GCPDisplayToolbar(
                self, self._toolSwitcher)

            self._mgr.AddPane(
                self.toolbars['gcpdisp'],
                wx.aui.AuiPaneInfo().Name("gcpdisplaytoolbar").Caption(
                    _("GCP Display toolbar")).ToolbarPane().Top().LeftDockable(
                        False).RightDockable(False).BottomDockable(False).
                TopDockable(True).CloseButton(False).Layer(2))

            if self.show_target == False:
                self.toolbars['gcpdisp'].Enable('zoommenu', enable=False)

            self.toolbars['gcpman'] = GCPManToolbar(self)

            self._mgr.AddPane(
                self.toolbars['gcpman'],
                wx.aui.AuiPaneInfo().Name("gcpmanagertoolbar").Caption(
                    _("GCP Manager toolbar")).ToolbarPane().Top().Row(1).
                LeftDockable(False).RightDockable(False).BottomDockable(
                    False).TopDockable(True).CloseButton(False).Layer(2))

        self._mgr.Update()

    def OnUpdateProgress(self, event):
        """
        Update progress bar info
        """
        self.GetProgressBar().UpdateProgress(event.layer, event.map)

        event.Skip()

    def OnFocus(self, event):
        """
        Change choicebook page to match display.
        Or set display for georectifying
        """
        # was in if layer manager but considering the state it was executed
        # always, moreover, there is no layer manager dependent code

        # in GCP Management, set focus to current MapWindow for mouse actions
        self.OnPointer(event)
        self.MapWindow.SetFocus()

        event.Skip()

    def OnDraw(self, event):
        """Re-display current map composition
        """
        self.MapWindow.UpdateMap(render=False)

    def OnRender(self, event):
        """Re-render map composition (each map layer)
        """
        # FIXME: remove qlayer code or use RemoveQueryLayer() now in mapdisp.frame
        # delete tmp map layers (queries)
        qlayer = self.Map.GetListOfLayers(name=globalvar.QUERYLAYER)
        for layer in qlayer:
            self.Map.DeleteLayer(layer)

        self.SrcMapWindow.UpdateMap(render=True)
        if self.show_target:
            self.TgtMapWindow.UpdateMap(render=True)

        # update statusbar
        self.StatusbarUpdate()

    def OnPointer(self, event):
        """Pointer button clicked
        """
        self.SrcMapWindow.SetModePointer()
        self.TgtMapWindow.SetModePointer()
        # change the default cursor
        self.SrcMapWindow.SetNamedCursor('cross')
        self.TgtMapWindow.SetNamedCursor('cross')

    def OnZoomIn(self, event):
        """Zoom in the map."""
        self.SrcMapWindow.SetModeZoomIn()
        self.TgtMapWindow.SetModeZoomIn()

    def OnZoomOut(self, event):
        """Zoom out the map."""
        self.SrcMapWindow.SetModeZoomOut()
        self.TgtMapWindow.SetModeZoomOut()

    def OnPan(self, event):
        """Panning, set mouse to drag"""
        self.SrcMapWindow.SetModePan()
        self.TgtMapWindow.SetModePan()

    def OnErase(self, event):
        """
        Erase the canvas
        """
        self.MapWindow.EraseMap()

        if self.MapWindow == self.SrcMapWindow:
            win = self.TgtMapWindow
        elif self.MapWindow == self.TgtMapWindow:
            win = self.SrcMapWindow

        win.EraseMap()

    def SaveToFile(self, event):
        """Save map to image
        """
        img = self.MapWindow.img
        if not img:
            GMessage(parent=self,
                     message=_(
                         "Nothing to render (empty map). Operation canceled."))
            return
        filetype, ltype = GetImageHandlers(img)

        # get size
        dlg = ImageSizeDialog(self)
        dlg.CentreOnParent()
        if dlg.ShowModal() != wx.ID_OK:
            dlg.Destroy()
            return
        width, height = dlg.GetValues()
        dlg.Destroy()

        # get filename
        dlg = wx.FileDialog(parent=self,
                            message=_("Choose a file name to save the image "
                                      "(no need to add extension)"),
                            wildcard=filetype,
                            style=wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)

        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            if not path:
                dlg.Destroy()
                return

            base, ext = os.path.splitext(path)
            fileType = ltype[dlg.GetFilterIndex()]['type']
            extType = ltype[dlg.GetFilterIndex()]['ext']
            if ext != extType:
                path = base + '.' + extType

            self.MapWindow.SaveToFile(path, fileType, width, height)

        dlg.Destroy()

    def PrintMenu(self, event):
        """
        Print options and output menu for map display
        """
        point = wx.GetMousePosition()
        printmenu = wx.Menu()
        # Add items to the menu
        setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
        printmenu.AppendItem(setup)
        self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)

        preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
        printmenu.AppendItem(preview)
        self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)

        doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
        printmenu.AppendItem(doprint)
        self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)

        # Popup the menu.  If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(printmenu)
        printmenu.Destroy()

    def OnZoomToRaster(self, event):
        """
        Set display extents to match selected raster map (ignore NULLs)
        """
        self.MapWindow.ZoomToMap(ignoreNulls=True)

    def OnZoomToSaved(self, event):
        """Set display geometry to match extents in
        saved region file
        """
        self.MapWindow.SetRegion(zoomOnly=True)

    def OnDisplayToWind(self, event):
        """Set computational region (WIND file) to match display
        extents
        """
        self.MapWindow.DisplayToWind()

    def SaveDisplayRegion(self, event):
        """Save display extents to named region file.
        """
        self.MapWindow.SaveDisplayRegion()

    def OnZoomMenu(self, event):
        """Popup Zoom menu
        """
        point = wx.GetMousePosition()
        zoommenu = wx.Menu()
        # Add items to the menu

        zoomwind = wx.MenuItem(
            zoommenu, wx.ID_ANY,
            _('Zoom to computational region (set with g.region)'))
        zoommenu.AppendItem(zoomwind)
        self.Bind(wx.EVT_MENU, self.OnZoomToWind, zoomwind)

        zoomdefault = wx.MenuItem(zoommenu, wx.ID_ANY,
                                  _('Zoom to default region'))
        zoommenu.AppendItem(zoomdefault)
        self.Bind(wx.EVT_MENU, self.OnZoomToDefault, zoomdefault)

        zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
        zoommenu.AppendItem(zoomsaved)
        self.Bind(wx.EVT_MENU, self.OnZoomToSaved, zoomsaved)

        savewind = wx.MenuItem(zoommenu, wx.ID_ANY,
                               _('Set computational region from display'))
        zoommenu.AppendItem(savewind)
        self.Bind(wx.EVT_MENU, self.OnDisplayToWind, savewind)

        savezoom = wx.MenuItem(zoommenu, wx.ID_ANY,
                               _('Save display geometry to named region'))
        zoommenu.AppendItem(savezoom)
        self.Bind(wx.EVT_MENU, self.SaveDisplayRegion, savezoom)

        # Popup the menu. If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(zoommenu)
        zoommenu.Destroy()

    def IsStandalone(self):
        """Check if Map display is standalone"""
        # we do not know and we do not care, so always False
        return True

    def GetLayerManager(self):
        """Get reference to Layer Manager

        :return: always None
        """
        return None

    def GetSrcWindow(self):
        return self.SrcMapWindow

    def GetTgtWindow(self):
        return self.TgtMapWindow

    def GetShowTarget(self):
        return self.show_target

    def GetMapToolbar(self):
        """Returns toolbar with zooming tools"""
        return self.toolbars['gcpdisp']

    def _setActiveMapWindow(self, mapWindow):
        if not self.MapWindow == mapWindow:
            self.MapWindow = mapWindow
            self.Map = mapWindow.Map
            self.UpdateActive(mapWindow)
            # needed for wingrass
            self.SetFocus()
Beispiel #12
0
class ExampleMapFrame(SingleMapFrame):
    """! Main frame of example tool.

    Inherits from SingleMapFrame, so map is displayed in one map widow.
    In case two map windows are needed, use DoubleMapFrame from (gui_core.mapdisp).

    @see IClassMapFrame in iclass.frame
    """

    def __init__(
        self,
        parent,
        giface,
        title=_("Example Tool"),
        toolbars=["MiscToolbar", "MapToolbar", "MainToolbar"],
        size=(800, 600),
        name="exampleWindow",
        **kwargs,
    ):
        """!Map Frame constructor

        @param parent (no parent is expected)
        @param title window title
        @param toolbars list of active toolbars (default value represents all toolbars)
        @param size default size
        """
        SingleMapFrame.__init__(
            self, parent=parent, title=title, name=name, Map=Map(), **kwargs
        )

        # Place debug message where appropriate
        # and set debug level from 1 to 5 (higher to lower level functions).
        # To enable debug mode write:
        # > g.gisenv set=WX_DEBUG=5
        Debug.msg(1, "ExampleMapFrame.__init__()")

        #
        # Add toolbars to aui manager
        #
        toolbarsCopy = toolbars[:]
        # workaround to have the same toolbar order on all platforms
        if sys.platform == "win32":
            toolbarsCopy.reverse()

        for toolbar in toolbarsCopy:
            self.AddToolbar(toolbar)

        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        self.mapWindowProperties.autoRenderChanged.connect(
            lambda value: self.OnRender(None) if value else None
        )
        #
        # Add statusbar
        #

        # choose items in statusbar choice, which makes sense for your application
        self.statusbarItems = [
            sb.SbCoordinates,
            sb.SbRegionExtent,
            sb.SbCompRegionExtent,
            sb.SbShowRegion,
            sb.SbAlignExtent,
            sb.SbResolution,
            sb.SbDisplayGeometry,
            sb.SbMapScale,
            sb.SbGoTo,
            sb.SbProjection,
        ]

        # create statusbar and its manager
        statusbar = self.CreateStatusBar(number=4, style=0)
        statusbar.SetStatusWidths([-5, -2, -1, -1])
        self.statusbarManager = sb.SbManager(mapframe=self, statusbar=statusbar)

        # fill statusbar manager
        self.statusbarManager.AddStatusbarItemsByClass(
            self.statusbarItems, mapframe=self, statusbar=statusbar
        )
        self.statusbarManager.AddStatusbarItem(
            sb.SbMask(self, statusbar=statusbar, position=2)
        )
        self.statusbarManager.AddStatusbarItem(
            sb.SbRender(self, statusbar=statusbar, position=3)
        )

        self.statusbarManager.Update()

        # create map window
        self.MapWindow = BufferedMapWindow(
            parent=self,
            Map=self.GetMap(),
            properties=self.mapWindowProperties,
            giface=self,
        )
        self._setUpMapWindow(self.MapWindow)
        self.MapWindow.InitZoomHistory()

        # create whatever you want, here it is a widget for displaying raster info
        self.info = ExampleInfoTextManager(self)

        # add map window (and other widgets) to aui manager
        self._addPanes()
        self._mgr.Update()

        # initialize variables related to your application functionality
        self.InitVariables()

        # default action
        self.GetMapToolbar().SelectDefault()

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

        self.SetSize(size)

    def __del__(self):
        """!Destructor deletes temporary region"""
        gcore.del_temp_region()

    def OnCloseWindow(self, event):
        """!Destroy frame"""
        self.Destroy()

    def IsStandalone(self):
        """!Check if application is standalone.

        Standalone application can work without parent.
        Parent can be e.g. Layer Manager.
        """
        if self.parent:
            return False

        return True

    def InitVariables(self):
        """!Initialize any variables nneded by application"""
        self.currentRaster = None
        self.statitistics = dict()

        # use WIND_OVERRIDE region not to affect current region
        gcore.use_temp_region()

    def _addPanes(self):
        """!Add mapwindow (and other widgets) to aui manager"""
        window = self.GetWindow()
        name = "mainWindow"
        self._mgr.AddPane(
            window,
            wx.aui.AuiPaneInfo()
            .Name(name)
            .CentrePane()
            .Dockable(False)
            .CloseButton(False)
            .DestroyOnClose(True)
            .Layer(0),
        )

        window = self.info.GetControl()
        name = "infoText"
        self._mgr.AddPane(
            window,
            wx.aui.AuiPaneInfo()
            .Name(name)
            .Caption(_("Raster Info"))
            .MinSize((250, -1))
            .Dockable(True)
            .CloseButton(False)
            .Layer(0)
            .Left(),
        )

    def AddToolbar(self, name):
        """!Add defined toolbar to the window

        Currently known toolbars are:
         - 'ExampleMapToolbar'        - basic map toolbar
         - 'ExampleMainToolbar'       - toolbar with application specific tools
         - 'ExampleMiscToolbar'       - toolbar with common tools (help, quit, ...)
        """
        # see wx.aui.AuiPaneInfo documentation for understanding all options
        if name == "MapToolbar":
            self.toolbars[name] = ExampleMapToolbar(self, self._toolSwitcher)

            self._mgr.AddPane(
                self.toolbars[name],
                wx.aui.AuiPaneInfo()
                .Name(name)
                .Caption(_("Map Toolbar"))
                .ToolbarPane()
                .Top()
                .LeftDockable(False)
                .RightDockable(False)
                .BottomDockable(False)
                .TopDockable(True)
                .CloseButton(False)
                .Layer(1)
                .Row(1)
                .BestSize((self.toolbars[name].GetBestSize())),
            )

        if name == "MiscToolbar":
            self.toolbars[name] = ExampleMiscToolbar(self)

            self._mgr.AddPane(
                self.toolbars[name],
                wx.aui.AuiPaneInfo()
                .Name(name)
                .Caption(_("Misc Toolbar"))
                .ToolbarPane()
                .Top()
                .LeftDockable(False)
                .RightDockable(False)
                .BottomDockable(False)
                .TopDockable(True)
                .CloseButton(False)
                .Layer(1)
                .Row(1)
                .BestSize((self.toolbars[name].GetBestSize())),
            )

        if name == "MainToolbar":
            self.toolbars[name] = ExampleMainToolbar(self)

            self._mgr.AddPane(
                self.toolbars[name],
                wx.aui.AuiPaneInfo()
                .Name(name)
                .Caption(_("Main Toolbar"))
                .ToolbarPane()
                .Top()
                .LeftDockable(False)
                .RightDockable(False)
                .BottomDockable(False)
                .TopDockable(True)
                .CloseButton(False)
                .Layer(1)
                .Row(1)
                .BestSize((self.toolbars[name].GetBestSize())),
            )

    def GetMapToolbar(self):
        """!Returns toolbar with zooming tools"""
        return self.toolbars["MapToolbar"]

    def OnHelp(self, event):
        """!Show help page"""
        RunCommand("g.manual", entry="wxGUI.Example")

    def OnSelectRaster(self, event):
        """!Opens dialog to select raster map"""
        dlg = ExampleMapDialog(self)

        if dlg.ShowModal() == wx.ID_OK:
            raster = gcore.find_file(name=dlg.GetRasterMap(), element="cell")
            if raster["fullname"]:
                self.SetLayer(name=raster["fullname"])
            else:
                # show user that the map name is incorrect
                GError(
                    parent=self,
                    message=_("Raster map <{raster}> not found").format(
                        raster=dlg.GetRasterMap()
                    ),
                )

        dlg.Destroy()

    def SetLayer(self, name):
        """!Sets layer in Map and updates statistics.

        @param name layer (raster) name
        """
        Debug.msg(3, "ExampleMapFrame.SetLayer(): name=%s" % name)

        # this simple application enables to keep only one raster
        self.GetMap().DeleteAllLayers()
        cmdlist = ["d.rast", "map=%s" % name]
        # add layer to Map instance (core.render)
        newLayer = self.GetMap().AddLayer(
            ltype="raster",
            command=cmdlist,
            active=True,
            name=name,
            hidden=False,
            opacity=1.0,
            render=True,
        )
        self.GetWindow().ZoomToMap(
            layers=[
                newLayer,
            ],
            render=True,
        )
        self.currentRaster = name

        # change comp. region to match new raster, so that the statistics
        # are computed for the entire raster
        RunCommand("g.region", rast=self.currentRaster, parent=self)

        self.UpdateStatistics()

    def ComputeStatitistics(self):
        """!Computes statistics for raster map using 'r.univar' module.

        @return statistic in form of dictionary
        """
        # RunCommand enables to run GRASS module
        res = RunCommand(
            "r.univar",  # module name
            flags="g",  # command flags
            map=self.currentRaster,  # module parameters
            read=True,
        )  # get command output

        return gcore.parse_key_val(res, val_type=float)

    def UpdateStatistics(self):
        """!Upadate statistic information.

        Called after changing raster map.
        """
        stats = self.ComputeStatitistics()
        self.info.WriteStatistics(name=self.currentRaster, statDict=stats)
Beispiel #13
0
class ExampleMapFrame(SingleMapFrame):
    """! Main frame of example tool.

    Inherits from SingleMapFrame, so map is displayed in one map widow.
    In case two map windows are needed, use DoubleMapFrame from (gui_core.mapdisp).

    @see IClassMapFrame in iclass.frame
    """
    def __init__(self, parent, giface, title=_("Example Tool"),
                 toolbars=["MiscToolbar", "MapToolbar", "MainToolbar"],
                 size=(800, 600), name='exampleWindow', **kwargs):
        """!Map Frame constructor

        @param parent (no parent is expected)
        @param title window title
        @param toolbars list of active toolbars (default value represents all toolbars)
        @param size default size
        """
        SingleMapFrame.__init__(self, parent=parent, title=title,
                                name=name, Map=Map(), **kwargs)

        # Place debug message where appropriate
        # and set debug level from 1 to 5 (higher to lower level functions).
        # To enable debug mode write:
        # > g.gisenv set=WX_DEBUG=5
        Debug.msg(1, "ExampleMapFrame.__init__()")

        #
        # Add toolbars to aui manager
        #
        toolbarsCopy = toolbars[:]
        # workaround to have the same toolbar order on all platforms
        if sys.platform == 'win32':
            toolbarsCopy.reverse()

        for toolbar in toolbarsCopy:
            self.AddToolbar(toolbar)

        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        self.mapWindowProperties.autoRenderChanged.connect(
            lambda value: self.OnRender(None) if value else None)
        #
        # Add statusbar
        #

        # choose items in statusbar choice, which makes sense for your application
        self.statusbarItems = [sb.SbCoordinates,
                               sb.SbRegionExtent,
                               sb.SbCompRegionExtent,
                               sb.SbShowRegion,
                               sb.SbAlignExtent,
                               sb.SbResolution,
                               sb.SbDisplayGeometry,
                               sb.SbMapScale,
                               sb.SbGoTo,
                               sb.SbProjection]

        # create statusbar and its manager
        statusbar = self.CreateStatusBar(number=4, style=0)
        statusbar.SetStatusWidths([-5, -2, -1, -1])
        self.statusbarManager = sb.SbManager(mapframe=self, statusbar=statusbar)

        # fill statusbar manager
        self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems,
                                                       mapframe=self, statusbar=statusbar)
        self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar=statusbar, position=2))
        self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar=statusbar, position=3))

        self.statusbarManager.Update()

        # create map window
        self.MapWindow = BufferedMapWindow(parent=self, Map=self.GetMap(),
                                           properties=self.mapWindowProperties, giface=self)
        self._setUpMapWindow(self.MapWindow)
        self.MapWindow.InitZoomHistory()

        # create whatever you want, here it is a widget for displaying raster info
        self.info = ExampleInfoTextManager(self)

        # add map window (and other widgets) to aui manager
        self._addPanes()
        self._mgr.Update()

        # initialize variables related to your application functionality
        self.InitVariables()

        # default action
        self.GetMapToolbar().SelectDefault()

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

        self.SetSize(size)

    def __del__(self):
        """!Destructor deletes temporary region"""
        gcore.del_temp_region()

    def OnCloseWindow(self, event):
        """!Destroy frame"""
        self.Destroy()

    def IsStandalone(self):
        """!Check if application is standalone.

        Standalone application can work without parent.
        Parent can be e.g. Layer Manager.
        """
        if self.parent:
            return False

        return True

    def InitVariables(self):
        """!Initialize any variables nneded by application"""
        self.currentRaster = None
        self.statitistics = dict()

        # use WIND_OVERRIDE region not to affect current region
        gcore.use_temp_region()

    def _addPanes(self):
        """!Add mapwindow (and other widgets) to aui manager"""
        window = self.GetWindow()
        name = "mainWindow"
        self._mgr.AddPane(window, wx.aui.AuiPaneInfo().
                          Name(name).CentrePane().
                          Dockable(False).CloseButton(False).DestroyOnClose(True).
                          Layer(0))

        window = self.info.GetControl()
        name = "infoText"
        self._mgr.AddPane(window, wx.aui.AuiPaneInfo().
                          Name(name).Caption(_("Raster Info")).MinSize((250, -1)).
                          Dockable(True).CloseButton(False).
                          Layer(0).Left())

    def AddToolbar(self, name):
        """!Add defined toolbar to the window

        Currently known toolbars are:
         - 'ExampleMapToolbar'        - basic map toolbar
         - 'ExampleMainToolbar'       - toolbar with application specific tools
         - 'ExampleMiscToolbar'       - toolbar with common tools (help, quit, ...)
        """
        # see wx.aui.AuiPaneInfo documentation for understanding all options
        if name == "MapToolbar":
            self.toolbars[name] = ExampleMapToolbar(self, self._toolSwitcher)

            self._mgr.AddPane(self.toolbars[name],
                              wx.aui.AuiPaneInfo().
                              Name(name).Caption(_("Map Toolbar")).
                              ToolbarPane().Top().
                              LeftDockable(False).RightDockable(False).
                              BottomDockable(False).TopDockable(True).
                              CloseButton(False).Layer(1).Row(1).
                              BestSize((self.toolbars[name].GetBestSize())))

        if name == "MiscToolbar":
            self.toolbars[name] = ExampleMiscToolbar(self)

            self._mgr.AddPane(self.toolbars[name],
                              wx.aui.AuiPaneInfo().
                              Name(name).Caption(_("Misc Toolbar")).
                              ToolbarPane().Top().
                              LeftDockable(False).RightDockable(False).
                              BottomDockable(False).TopDockable(True).
                              CloseButton(False).Layer(1).Row(1).
                              BestSize((self.toolbars[name].GetBestSize())))

        if name == "MainToolbar":
            self.toolbars[name] = ExampleMainToolbar(self)

            self._mgr.AddPane(self.toolbars[name],
                              wx.aui.AuiPaneInfo().
                              Name(name).Caption(_("Main Toolbar")).
                              ToolbarPane().Top().
                              LeftDockable(False).RightDockable(False).
                              BottomDockable(False).TopDockable(True).
                              CloseButton(False).Layer(1).Row(1).
                              BestSize((self.toolbars[name].GetBestSize())))

    def GetMapToolbar(self):
        """!Returns toolbar with zooming tools"""
        return self.toolbars['MapToolbar']

    def OnHelp(self, event):
        """!Show help page"""
        RunCommand('g.manual', entry='wxGUI.Example')

    def OnSelectRaster(self, event):
        """!Opens dialog to select raster map"""
        dlg = ExampleMapDialog(self)

        if dlg.ShowModal() == wx.ID_OK:
            raster = gcore.find_file(name=dlg.GetRasterMap(), element='cell')
            if raster['fullname']:
                self.SetLayer(name=raster['fullname'])
            else:
                # show user that the map name is incorrect
                GError(parent=self,
                       message=_("Raster map <{raster}> not found").format(raster=dlg.GetRasterMap()))

        dlg.Destroy()

    def SetLayer(self, name):
        """!Sets layer in Map and updates statistics.

        @param name layer (raster) name
        """
        Debug.msg (3, "ExampleMapFrame.SetLayer(): name=%s" % name)

        # this simple application enables to keep only one raster
        self.GetMap().DeleteAllLayers()
        cmdlist = ['d.rast', 'map=%s' % name]
        # add layer to Map instance (core.render)
        newLayer = self.GetMap().AddLayer(ltype='raster', command=cmdlist, active=True,
                                          name=name, hidden=False, opacity=1.0,
                                          render=True)
        self.GetWindow().ZoomToMap(layers=[newLayer, ], render=True)
        self.currentRaster = name

        # change comp. region to match new raster, so that the statistics
        # are computed for the entire raster
        RunCommand('g.region',
                   rast=self.currentRaster,
                   parent=self)

        self.UpdateStatistics()

    def ComputeStatitistics(self):
        """!Computes statistics for raster map using 'r.univar' module.

        @return statistic in form of dictionary
        """
        # RunCommand enables to run GRASS module
        res = RunCommand('r.univar',  # module name
                         flags='g',  # command flags
                         map=self.currentRaster,  # module parameters
                         read=True)  # get command output

        return gcore.parse_key_val(res, val_type=float)

    def UpdateStatistics(self):
        """!Upadate statistic information.

        Called after changing raster map.
        """
        stats = self.ComputeStatitistics()
        self.info.WriteStatistics(name=self.currentRaster, statDict=stats)
Beispiel #14
0
class SwipeMapFrame(DoubleMapFrame):
    def __init__(self, parent  = None, giface = None, 
                 title = _("GRASS GIS Map Swipe"), name = "swipe", **kwargs):
        DoubleMapFrame.__init__(self, parent = parent, title = title, name = name,
                                firstMap = Map(), secondMap = Map(), **kwargs)
        Debug.msg (1, "SwipeMapFrame.__init__()")
        #
        # Add toolbars
        #
        toolbars = ['swipeMisc', 'swipeMap', 'swipeMain']
        if sys.platform == 'win32':
            self.AddToolbar(toolbars.pop(1))
            toolbars.reverse()
        else:
            self.AddToolbar(toolbars.pop(0))
        for toolb in toolbars:
            self.AddToolbar(toolb)
        self._giface = giface
        #
        # create widgets
        #
        self.splitter = MapSplitter(parent = self, id = wx.ID_ANY)

        self.sliderH = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_HORIZONTAL)
        self.sliderV = wx.Slider(self, id = wx.ID_ANY, style = wx.SL_VERTICAL)
        
        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        self.mapWindowProperties.autoRenderChanged.connect(self.OnAutoRenderChanged)
        self.firstMapWindow = SwipeBufferedWindow(parent = self.splitter, giface = self._giface,
                                                  properties=self.mapWindowProperties,
                                                  Map = self.firstMap)
        self.secondMapWindow = SwipeBufferedWindow(parent = self.splitter, giface = self._giface,
                                                   properties=self.mapWindowProperties,
                                                   Map = self.secondMap)
        # bind query signal
        self.firstMapWindow.mapQueried.connect(self.Query)
        self.secondMapWindow.mapQueried.connect(self.Query)

        # bind tracking cursosr to mirror it
        self.firstMapWindow.Bind(wx.EVT_MOTION, lambda evt: self.TrackCursor(evt))
        self.secondMapWindow.Bind(wx.EVT_MOTION, lambda evt: self.TrackCursor(evt))

        self.MapWindow = self.firstMapWindow # current by default
        self.firstMapWindow.zoomhistory = self.secondMapWindow.zoomhistory
        self.SetBindRegions(True)

        self._mode = 'swipe'

        self._addPanes()
        self._bindWindowsActivation()
        self._setUpMapWindow(self.firstMapWindow)
        self._setUpMapWindow(self.secondMapWindow)

        self._mgr.GetPane('sliderV').Hide()
        self._mgr.GetPane('sliderH').Show()
        self.slider = self.sliderH

        self.InitStatusbar()

        self.Bind(wx.EVT_SIZE, self.OnSize)
        self.Bind(wx.EVT_IDLE, self.OnIdle)
        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)

        self.SetSize((800, 600))
        
        self._mgr.Update()

        self.rasters = {'first': None, 'second': None}

        self._inputDialog = None
        self._preferencesDialog = None
        self._queryDialog = None

        # default action in map toolbar
        self.GetMapToolbar().SelectDefault()

        self.resize = False

        wx.CallAfter(self.CallAfterInit)

    def TrackCursor(self, event):
        """Track cursor in one window and show cross in the other.

        Only for mirror mode.
        """
        if self._mode == 'swipe':
            event.Skip()
            return
        coords = event.GetPosition()
        if event.GetId() == self.secondMapWindow.GetId():
            self.firstMapWindow.DrawMouseCursor(coords=coords)
        else:
            self.secondMapWindow.DrawMouseCursor(coords=coords)

        event.Skip()

    def ActivateFirstMap(self, event = None):
        """Switch tracking direction"""
        super(SwipeMapFrame, self).ActivateFirstMap(event)

        self.firstMapWindow.ClearLines()
        self.firstMapWindow.Refresh()

    def ActivateSecondMap(self, event = None):
        """Switch tracking direction"""
        super(SwipeMapFrame, self).ActivateSecondMap(event)

        self.secondMapWindow.ClearLines()
        self.secondMapWindow.Refresh()

    def CallAfterInit(self):
        self.InitSliderBindings()
        self.splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
        self.splitter.Init()
        if not (self.rasters['first'] and self.rasters['second']):
            self.OnSelectLayers(event=None)
        
    def InitStatusbar(self):
        """Init statusbar (default items)."""
        # items for choice
        self.statusbarItems = [sb.SbCoordinates,
                               sb.SbRegionExtent,
                               sb.SbCompRegionExtent,
                               sb.SbShowRegion,
                               sb.SbAlignExtent,
                               sb.SbResolution,
                               sb.SbDisplayGeometry,
                               sb.SbMapScale,
                               sb.SbGoTo,
                               sb.SbProjection]
        
        # create statusbar and its manager
        statusbar = self.CreateStatusBar(number = 4, style = 0)
        statusbar.SetStatusWidths([-5, -2, -1, -1])
        self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
        
        # fill statusbar manager
        self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
        self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
        sbRender = sb.SbRender(self, statusbar = statusbar, position = 3)
        self.statusbarManager.AddStatusbarItem(sbRender)
        
        self.statusbarManager.Update()

    def ResetSlider(self):
        if self.splitter.GetSplitMode() == wx.SPLIT_VERTICAL:
            size = self.splitter.GetSize()[0]
        else:
            size = self.splitter.GetSize()[1]
        self.slider.SetRange(0, size)
        self.slider.SetValue(self.splitter.GetSashPosition())


    def InitSliderBindings(self):
        self.sliderH.Bind(wx.EVT_SPIN, self.OnSliderPositionChanging)
        self.sliderH.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSliderPositionChanged)
        self.sliderV.Bind(wx.EVT_SPIN, self.OnSliderPositionChanging)
        self.sliderV.Bind(wx.EVT_SCROLL_THUMBRELEASE, self.OnSliderPositionChanged)
        self.splitter.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGING, self.OnSashChanging)
        self.splitter.Bind(wx.EVT_SPLITTER_SASH_POS_CHANGED, self.OnSashChanged)


    def OnSliderPositionChanging(self, event):
        """Slider changes its position, sash must be moved too."""
        Debug.msg (5, "SwipeMapFrame.OnSliderPositionChanging()")

        self.GetFirstWindow().movingSash = True
        self.GetSecondWindow().movingSash = True
        pos = event.GetPosition()

        if pos > 0:
            self.splitter.SetSashPosition(pos)
            self.splitter.OnSashChanging(None)

    def OnSliderPositionChanged(self, event):
        """Slider position changed, sash must be moved too."""
        Debug.msg (5, "SwipeMapFrame.OnSliderPositionChanged()")

        self.splitter.SetSashPosition(event.GetPosition())
        self.splitter.OnSashChanged(None)

    def OnSashChanging(self, event):
        """Sash position is changing, slider must be moved too."""
        Debug.msg (5, "SwipeMapFrame.OnSashChanging()")

        self.slider.SetValue(self.splitter.GetSashPosition())
        event.Skip()

    def OnSashChanged(self, event):
        """Sash position changed, slider must be moved too."""
        Debug.msg (5, "SwipeMapFrame.OnSashChanged()")

        self.OnSashChanging(event)
        event.Skip()

    def OnSize(self, event):
        Debug.msg (4, "SwipeMapFrame.OnSize()")
        self.resize = time.clock()
        super(SwipeMapFrame, self).OnSize(event)

    def OnIdle(self, event):
        if self.resize and time.clock() - self.resize > 0.2:
            w1 = self.GetFirstWindow()
            w2 = self.GetSecondWindow()

            sizeAll = self.splitter.GetSize()
            w1.SetClientSize(sizeAll)
            w2.SetClientSize(sizeAll)
            
            w1.OnSize(event)
            w2.OnSize(event)
            self.ResetSlider()
            self.resize = False

    def OnAutoRenderChanged(self, value):
        """Auto rendering state changed."""
        style = self.splitter.GetWindowStyle()
        style ^= wx.SP_LIVE_UPDATE
        self.splitter.SetWindowStyle(style)

    def AddToolbar(self, name):
        """Add defined toolbar to the window
        
        Currently known toolbars are:
         - 'swipeMap'          - basic map toolbar
         - 'swipeMain'         - swipe functionality
        """
        if name == "swipeMap":
            self.toolbars[name] = SwipeMapToolbar(self, self._toolSwitcher)
            self._mgr.AddPane(self.toolbars[name],
                      wx.aui.AuiPaneInfo().
                      Name(name).Caption(_("Map Toolbar")).
                      ToolbarPane().Top().
                      LeftDockable(False).RightDockable(False).
                      BottomDockable(False).TopDockable(True).
                      CloseButton(False).Layer(2).Row(1).
                      BestSize((self.toolbars[name].GetBestSize())))

        if name == "swipeMain":
            self.toolbars[name] = SwipeMainToolbar(self)

            self._mgr.AddPane(self.toolbars[name],
                      wx.aui.AuiPaneInfo().
                      Name(name).Caption(_("Main Toolbar")).
                      ToolbarPane().Top().
                      LeftDockable(False).RightDockable(False).
                      BottomDockable(False).TopDockable(True).
                      CloseButton(False).Layer(2).Row(1).
                      BestSize((self.toolbars[name].GetBestSize())))

        if name == "swipeMisc":
            self.toolbars[name] = SwipeMiscToolbar(self)

            self._mgr.AddPane(self.toolbars[name],
                      wx.aui.AuiPaneInfo().
                      Name(name).Caption(_("Misc Toolbar")).
                      ToolbarPane().Top().
                      LeftDockable(False).RightDockable(False).
                      BottomDockable(False).TopDockable(True).
                      CloseButton(False).Layer(2).Row(1).
                      BestSize((self.toolbars[name].GetBestSize())))

    def _addPanes(self):
        """Add splitter window and sliders to aui manager"""
        # splitter window
        self._mgr.AddPane(self.splitter, wx.aui.AuiPaneInfo().
                  Name('splitter').CaptionVisible(False).PaneBorder(True).
                  Dockable(False).Floatable(False).CloseButton(False).
                  Center().Layer(1).BestSize((self.splitter.GetBestSize())))

        # sliders
        self._mgr.AddPane(self.sliderH, wx.aui.AuiPaneInfo().
                  Name('sliderH').CaptionVisible(False).PaneBorder(False).
                  CloseButton(False).Gripper(True).GripperTop(False).
                  BottomDockable(True).TopDockable(True).
                  LeftDockable(False).RightDockable(False).
                  Bottom().Layer(1).BestSize((self.sliderH.GetBestSize())))

        self._mgr.AddPane(self.sliderV, wx.aui.AuiPaneInfo().
                  Name('sliderV').CaptionVisible(False).PaneBorder(False).
                  CloseButton(False).Gripper(True).GripperTop(True).
                  BottomDockable(False).TopDockable(False).
                  LeftDockable(True).RightDockable(True).
                  Right().Layer(1).BestSize((self.sliderV.GetBestSize())))

    def ZoomToMap(self):
        """
        Set display extents to match selected raster (including NULLs)
        or vector map.
        """
        layers = []
        if self.rasters['first']:
            layers += self.firstMap.GetListOfLayers()
        if self.rasters['second']:
            layers += self.secondMap.GetListOfLayers()

        if layers:
            self.GetFirstWindow().ZoomToMap(layers=layers)
            self.GetSecondWindow().ZoomToMap(layers=layers)

    def OnZoomToMap(self, event):
        """Zoom to map"""
        self.ZoomToMap()

    def OnZoomBack(self, event):
        self.GetFirstWindow().ZoomBack()
        self.secondMap.region = self.firstMap.region
        self.Render(self.GetSecondWindow())

    def OnSelectLayers(self, event):
        if self._inputDialog is None:
            dlg = SwipeMapDialog(self, first=self.rasters['first'],
                                 second=self.rasters['second'],
                                 firstLayerList=None, secondLayerList=None)
            dlg.applyChanges.connect(self.OnApplyInputChanges)
            # connect to convertor object to convert to Map
            # store reference to convertor is needed otherwise it would be discarded
            self._firstConverter = self._connectSimpleLmgr(dlg.GetFirstSimpleLmgr(),
                                                           self.GetFirstMap())
            self._secondConverter = self._connectSimpleLmgr(dlg.GetSecondSimpleLmgr(),
                                                            self.GetSecondMap())
            self._inputDialog = dlg
            dlg.CentreOnParent()
            dlg.Show()
        else:
            if self._inputDialog.IsShown():
                self._inputDialog.Raise()
                self._inputDialog.SetFocus()
            else:
                self._inputDialog.Show()

    def _connectSimpleLmgr(self, lmgr, renderer):
        converter = LayerListToRendererConverter(renderer)
        lmgr.opacityChanged.connect(converter.ChangeLayerOpacity)
        lmgr.cmdChanged.connect(converter.ChangeLayerCmd)
        lmgr.layerAdded.connect(converter.AddLayer)
        lmgr.layerRemoved.connect(converter.RemoveLayer)
        lmgr.layerActivated.connect(converter.ChangeLayerActive)
        lmgr.layerMovedUp.connect(converter.MoveLayerUp)
        lmgr.layerMovedDown.connect(converter.MoveLayerDown)
        lmgr.anyChange.connect(self._simpleLmgrChanged)
        return converter

    def _simpleLmgrChanged(self):
        if self.IsAutoRendered():
            self.OnRender(event=None)

    def OnApplyInputChanges(self):
        first, second = self._inputDialog.GetValues()
        if self._inputDialog.IsSimpleMode():
            self.rasters['first'], self.rasters['second'] = first, second
            res1 = self.SetFirstRaster(name=self.rasters['first'])
            res2 = self.SetSecondRaster(name=self.rasters['second'])
            if not (res1 and res2) and first and second:
                message = ''
                if not res1:
                    message += _("Map <%s> not found. ") % self.rasters['first']
                if not res2:
                    message += _("Map <%s> not found.") % self.rasters['second']
                    GError(parent = self, message = message)
                    return
            self.ZoomToMap()
        else:
            LayerListToRendererConverter(self.GetFirstMap()).ConvertAll(first)
            LayerListToRendererConverter(self.GetSecondMap()).ConvertAll(second)

        self.SetRasterNames()
        if self.IsAutoRendered():
            self.OnRender(event=None)

    def SetFirstRaster(self, name):
        """Set raster map to first Map"""
        raster = grass.find_file(name = name, element = 'cell')
        if raster['fullname']:
            self.rasters['first'] = raster['fullname']
            self.SetLayer(name = raster['fullname'], mapInstance = self.GetFirstMap())
            return True

        return False

    def SetSecondRaster(self, name):
        """Set raster map to second Map"""
        raster = grass.find_file(name = name, element = 'cell')
        if raster['fullname']:
            self.rasters['second'] = raster['fullname']
            self.SetLayer(name = raster['fullname'], mapInstance = self.GetSecondMap())
            return True

        return False

    def SetLayer(self, name, mapInstance):
        """Sets layer in Map.
        
        :param name: layer (raster) name
        """
        Debug.msg (3, "SwipeMapFrame.SetLayer(): name=%s" % name)
        
        # this simple application enables to keep only one raster
        mapInstance.DeleteAllLayers()
        cmdlist = ['d.rast', 'map=%s' % name]
        # add layer to Map instance (core.render)
        newLayer = mapInstance.AddLayer(ltype = 'raster', command = cmdlist, active = True,
                                        name = name, hidden = False, opacity = 1.0,
                                        render = True)

    def OnSwitchWindows(self, event):
        """Switch windows position."""
        Debug.msg(3, "SwipeMapFrame.OnSwitchWindows()")

        splitter = self.splitter
        w1, w2 = splitter.GetWindow1(), splitter.GetWindow2()
        splitter.ReplaceWindow(w1, w2)
        splitter.ReplaceWindow(w2, w1)
        # self.OnSize(None)
        splitter.OnSashChanged(None)

    def _saveToFile(self, fileName, fileType):
        """Creates composite image by rendering both images and
        pasting them into the new one.

        .. todo::
            specify size of the new image (problem is inaccurate scaling)
        .. todo::
            make dividing line width and color optional
        """
        w1 = self.splitter.GetWindow1()
        w2 = self.splitter.GetWindow2()
        lineWidth = 1
        # render to temporary files
        filename1 = grass.tempfile(False) + '1'
        filename2 = grass.tempfile(False) + '2'
        width, height = self.splitter.GetClientSize()
        if self._mode == 'swipe':
            x, y = w2.GetImageCoords()
            w1.SaveToFile(filename1, fileType, width, height)
            w2.SaveToFile(filename2, fileType, width, height)
        else:
            fw, fh = w1.GetClientSize()
            w1.SaveToFile(filename1, fileType, fw, fh)
            sw, sh = w2.GetClientSize()
            w2.SaveToFile(filename2, fileType, sw, sh)

        # create empty white image  - needed for line
        im = wx.EmptyImage(width, height)
        im.Replace(0, 0, 0, 255, 255, 255)

        # paste images
        if self._mode == 'swipe':
            if self.splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
                im1 = wx.Image(filename1).GetSubImage((0, 0, width, -y))
                im.Paste(im1, 0, 0)
                im.Paste(wx.Image(filename2), -x, -y + lineWidth)
            else:
                im1 = wx.Image(filename1).GetSubImage((0, 0, -x, height))
                im.Paste(im1, 0, 0)
                im.Paste(wx.Image(filename2), -x + lineWidth, -y)
        else:
            if self.splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
                im1 = wx.Image(filename1)
                im.Paste(im1, 0, 0)
                im.Paste(wx.Image(filename2), 0, fh + lineWidth)
            else:
                im1 = wx.Image(filename1)
                im.Paste(im1, 0, 0)
                im.Paste(wx.Image(filename2), fw + lineWidth, 0)
        im.SaveFile(fileName, fileType)

        # remove temporary files
        grass.try_remove(filename1)
        grass.try_remove(filename2)

    def SaveToFile(self, event):
        """Save map to image
        """
        img = self.firstMapWindow.img or self.secondMapWindow.img
        if not img:
            GMessage(parent = self,
                     message = _("Nothing to render (empty map). Operation canceled."))
            return
        filetype, ltype = GetImageHandlers(img)
        
        # get filename
        dlg = wx.FileDialog(parent = self,
                            message = _("Choose a file name to save the image "
                                        "(no need to add extension)"),
                            wildcard = filetype,
                            style = wx.FD_SAVE | wx.FD_OVERWRITE_PROMPT)
        
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            if not path:
                dlg.Destroy()
                return
            
            base, ext = os.path.splitext(path)
            fileType = ltype[dlg.GetFilterIndex()]['type']
            extType  = ltype[dlg.GetFilterIndex()]['ext']
            if ext != extType:
                path = base + '.' + extType
            
            self._saveToFile(path, fileType)
            
        dlg.Destroy()

    def OnSwitchOrientation(self, event):
        """Switch orientation of the sash."""
        Debug.msg(3, "SwipeMapFrame.OnSwitchOrientation()")

        splitter = self.splitter
        splitter.Unsplit()
        if splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
            splitter.SplitVertically(self.firstMapWindow, self.secondMapWindow, 0)
            self.slider = self.sliderH
            if self._mode == 'swipe':
                self._mgr.GetPane('sliderH').Show()
                self._mgr.GetPane('sliderV').Hide()
        else:
            splitter.SplitHorizontally(self.firstMapWindow, self.secondMapWindow, 0)
            self.slider = self.sliderV
            if self._mode == 'swipe':
                self._mgr.GetPane('sliderV').Show()
                self._mgr.GetPane('sliderH').Hide()
        self._mgr.Update()
        splitter.OnSashChanged(None)
        self.OnSize(None)
        self.SetRasterNames()

    def OnAddText(self, event):
        """Double click on text overlay

        So far not implemented.
        """
        pass

    def SetViewMode(self, mode):
        """Sets view mode.

        :param mode: view mode ('swipe', 'mirror')
        """
        if self._mode == mode:
            return
        self._mode = mode
        self.toolbars['swipeMain'].SetMode(mode)
        # set window mode
        self.GetFirstWindow().SetMode(mode)
        self.GetSecondWindow().SetMode(mode)
        # hide/show slider
        if self.splitter.GetSplitMode() == wx.SPLIT_HORIZONTAL:
            self._mgr.GetPane('sliderV').Show(mode == 'swipe')
            size = self.splitter.GetSize()[1] / 2
        else:
            self._mgr.GetPane('sliderH').Show(mode == 'swipe')
            size = self.splitter.GetSize()[0] / 2
        # set sash in the middle
        self.splitter.SetSashPosition(size)
        self.slider.SetValue(size)
        self._mgr.Update()
        # enable / disable sash
        self.splitter.EnableSash(mode == 'swipe')
        # hack to make it work
        self.splitter.OnSashChanged(None)
        self.SendSizeEvent()

    def SetRasterNames(self):
        if not self._inputDialog or self._inputDialog.IsSimpleMode():
            if self.rasters['first']:
                self.GetFirstWindow().SetRasterNameText(self.rasters['first'], 101)
            if self.rasters['second']:
                self.GetSecondWindow().SetRasterNameText(self.rasters['second'], 102)
        else:
            self.GetFirstWindow().SetRasterNameText('', 101)
            self.GetSecondWindow().SetRasterNameText('', 102)

    def Query(self, x, y):
        """Query active layers from both mapwindows.

        :param x,y: coordinates
        """
        rasters = ([layer.GetName() for layer in
                    self.GetFirstMap().GetListOfLayers(ltype='raster', active=True)],
                   [layer.GetName() for layer in
                    self.GetSecondMap().GetListOfLayers(ltype='raster', active=True)])
        vectors = ([layer.GetName() for layer in
                    self.GetFirstMap().GetListOfLayers(ltype='vector', active=True)],
                   [layer.GetName() for layer in
                    self.GetSecondMap().GetListOfLayers(ltype='vector', active=True)])

        if not (rasters[0] + rasters[1] + vectors[0] + vectors[1]):
            GMessage(parent=self,
                     message=_('No raster or vector map layer selected for querying.'))
            return

        # set query snap distance for v.what at map unit equivalent of 10 pixels
        qdist = 10.0 * ((self.GetFirstMap().region['e'] -
                         self.GetFirstMap().region['w']) / self.GetFirstMap().width)

        east, north = self.GetFirstWindow().Pixel2Cell((x, y))

        # use display region settings instead of computation region settings
        self.tmpreg = os.getenv("GRASS_REGION")
        os.environ["GRASS_REGION"] = self.GetFirstMap().SetRegion(windres=False)

        result = []
        if rasters[0]:
            result.extend(grass.raster_what(map=rasters[0], coord=(east, north),
                                            localized=True))
        if vectors[0]:
            result.extend(grass.vector_what(map=vectors[0], coord=(east, north), distance=qdist))
        if rasters[1]:
            result.extend(grass.raster_what(map=rasters[1], coord=(east, north),
                                            localized=True))
        if vectors[1]:
            result.extend(grass.vector_what(map=vectors[1], coord=(east, north), distance=qdist))

        self._QueryMapDone()

        result = PrepareQueryResults(coordinates=(east, north), result=result)
        if self._queryDialog:
            self._queryDialog.Raise()
            self._queryDialog.SetData(result)
        else:
            self._queryDialog = QueryDialog(parent=self, data=result)
            self._queryDialog.Bind(wx.EVT_CLOSE, self._oncloseQueryDialog)
            self._queryDialog.redirectOutput.connect(lambda output: self._giface.WriteLog(output))
            self._queryDialog.Show()

    def _oncloseQueryDialog(self, event):
        self._queryDialog = None
        event.Skip()

    def _QueryMapDone(self):
        """Restore settings after querying (restore GRASS_REGION)
        """
        if hasattr(self, "tmpreg"):
            if self.tmpreg:
                os.environ["GRASS_REGION"] = self.tmpreg
            elif 'GRASS_REGION' in os.environ:
                del os.environ["GRASS_REGION"]
        elif 'GRASS_REGION' in os.environ:
            del os.environ["GRASS_REGION"]

        if hasattr(self, "tmpreg"):
            del self.tmpreg

    def GetMapToolbar(self):
        """Returns toolbar with zooming tools"""
        return self.toolbars['swipeMap']

    def IsStandalone(self):
        """Since we do not need layer manager, we are standalone"""
        return True

    def OnHelp(self, event):
        self._giface.Help(entry = 'wxGUI.mapswipe')

    def OnPreferences(self, event):
        if not self._preferencesDialog:
            dlg = PreferencesDialog(parent=self, giface=self._giface)
            self._preferencesDialog = dlg
            self._preferencesDialog.CenterOnParent()

        self._preferencesDialog.ShowModal()

    def OnCloseWindow(self, event):
        self.GetFirstMap().Clean()
        self.GetSecondMap().Clean()
        self.Destroy()
Beispiel #15
0
class MapFrame(SingleMapFrame):
    """Main frame for map display window. Drawing takes place in
    child double buffered drawing window.
    """
    def __init__(self, parent, giface,
                 title=_("GRASS GIS Manage Ground Control Points"),
                 toolbars=["gcpdisp"], Map=None, auimgr=None,
                 name='GCPMapWindow', **kwargs):
        """Main map display window with toolbars, statusbar and
        DrawWindow

        :param giface: GRASS interface instance
        :param title: window title
        :param toolbars: array of activated toolbars, e.g. ['map', 'digit']
        :param map: instance of render.Map
        :param auimgs: AUI manager
        :param kwargs: wx.Frame attribures
        """
        
        SingleMapFrame.__init__(self, parent = parent, giface = giface, title = title,
                              Map = Map, auimgr = auimgr, name = name, **kwargs)

        self._giface = giface
        # properties are shared in other objects, so defining here
        self.mapWindowProperties = MapWindowProperties()
        self.mapWindowProperties.setValuesFromUserSettings()
        self.mapWindowProperties.alignExtent = True

        #
        # Add toolbars
        #
        for toolb in toolbars:
            self.AddToolbar(toolb)

        self.activemap = self.toolbars['gcpdisp'].togglemap
        self.activemap.SetSelection(0)
        
        self.SrcMap        = self.grwiz.SrcMap       # instance of render.Map
        self.TgtMap        = self.grwiz.TgtMap       # instance of render.Map
        self._mgr.SetDockSizeConstraint(0.5, 0.5)

        #
        # Add statusbar
        #
        
        # items for choice
        self.statusbarItems = [sb.SbCoordinates,
                               sb.SbRegionExtent,
                               sb.SbCompRegionExtent,
                               sb.SbShowRegion,
                               sb.SbResolution,
                               sb.SbDisplayGeometry,
                               sb.SbMapScale,
                               sb.SbProjection,
                               sbgcp.SbGoToGCP,
                               sbgcp.SbRMSError]
                            
        
        # create statusbar and its manager
        statusbar = self.CreateStatusBar(number = 4, style = 0)
        statusbar.SetStatusWidths([-5, -2, -1, -1])
        self.statusbarManager = sb.SbManager(mapframe = self, statusbar = statusbar)
        
        # fill statusbar manager
        self.statusbarManager.AddStatusbarItemsByClass(self.statusbarItems, mapframe = self, statusbar = statusbar)
        self.statusbarManager.AddStatusbarItem(sb.SbMask(self, statusbar = statusbar, position = 2))
        self.statusbarManager.AddStatusbarItem(sb.SbRender(self, statusbar = statusbar, position = 3))
        
        self.statusbarManager.SetMode(8) # goto GCP

        #
        # Init map display (buffered DC & set default cursor)
        #
        self.grwiz.SwitchEnv('source')
        self.SrcMapWindow = BufferedMapWindow(parent=self, giface=self._giface, id=wx.ID_ANY,
                                              properties=self.mapWindowProperties,
                                              Map=self.SrcMap)

        self.grwiz.SwitchEnv('target')
        self.TgtMapWindow = BufferedMapWindow(parent=self, giface=self._giface, id=wx.ID_ANY,
                                              properties=self.mapWindowProperties,
                                              Map=self.TgtMap)
        self.MapWindow = self.SrcMapWindow
        self.Map = self.SrcMap
        self._setUpMapWindow(self.SrcMapWindow)
        self._setUpMapWindow(self.TgtMapWindow)
        self.SrcMapWindow.SetNamedCursor('cross')
        self.TgtMapWindow.SetNamedCursor('cross')
        # used to switch current map (combo box in toolbar)
        self.SrcMapWindow.mouseEntered.connect(
            lambda:
            self._setActiveMapWindow(self.SrcMapWindow))
        self.TgtMapWindow.mouseEntered.connect(
            lambda:
            self._setActiveMapWindow(self.TgtMapWindow))

        #
        # initialize region values
        #
        self._initMap(Map = self.SrcMap) 
        self._initMap(Map = self.TgtMap) 
        
        self.GetMapToolbar().SelectDefault()

        #
        # Bind various events
        #
        self.activemap.Bind(wx.EVT_CHOICE, self.OnUpdateActive)
        self.Bind(wx.EVT_SIZE, self.OnSize)
        
        #
        # Update fancy gui style
        #
        # AuiManager wants a CentrePane, workaround to get two equally sized windows
        self.list = self.CreateGCPList()

        #self.SrcMapWindow.SetSize((300, 300))
        #self.TgtMapWindow.SetSize((300, 300))
        self.list.SetSize((100, 150))
        self._mgr.AddPane(self.list, wx.aui.AuiPaneInfo().
                  Name("gcplist").Caption(_("GCP List")).LeftDockable(False).
                  RightDockable(False).PinButton().FloatingSize((600,200)).
                  CloseButton(False).DestroyOnClose(True).
                  Top().Layer(1).MinSize((200,100)))
        self._mgr.AddPane(self.SrcMapWindow, wx.aui.AuiPaneInfo().
                  Name("source").Caption(_("Source Display")).Dockable(False).
                  CloseButton(False).DestroyOnClose(True).Floatable(False).
                  Centre())
        self._mgr.AddPane(self.TgtMapWindow, wx.aui.AuiPaneInfo().
                  Name("target").Caption(_("Target Display")).Dockable(False).
                  CloseButton(False).DestroyOnClose(True).Floatable(False).
                  Right().Layer(0))

        srcwidth, srcheight = self.SrcMapWindow.GetSize()
        tgtwidth, tgtheight = self.TgtMapWindow.GetSize()
        srcwidth = (srcwidth + tgtwidth) / 2
        self._mgr.GetPane("target").Hide()
        self._mgr.Update()
        self._mgr.GetPane("source").BestSize((srcwidth, srcheight))
        self._mgr.GetPane("target").BestSize((srcwidth, srcheight))
        if self.show_target:
            self._mgr.GetPane("target").Show()
        else:
            self.activemap.Enable(False)
        # needed by Mac OS, does not harm on Linux, breaks display on Windows
        if platform.system() != 'Windows':
            self._mgr.Update()

        #
        # Init print module and classes
        #
        self.printopt = PrintOptions(self, self.MapWindow)
        
        #
        # Initialization of digitization tool
        #
        self.digit = None

        # set active map
        self.MapWindow = self.SrcMapWindow
        self.Map = self.SrcMap
        
        # do not init zoom history here, that happens when zooming to map(s)

        #
        # Re-use dialogs
        #
        self.dialogs = {}
        self.dialogs['attributes'] = None
        self.dialogs['category'] = None
        self.dialogs['barscale'] = None
        self.dialogs['legend'] = None

        self.decorationDialog = None # decoration/overlays

        # doing nice things in statusbar when other things are ready
        self.statusbarManager.Update()

    def _setUpMapWindow(self, mapWindow):
        # TODO: almost the smae implementation as for MapFrameBase (only names differ)
        # enable or disable zoom history tool
        mapWindow.zoomHistoryAvailable.connect(
            lambda:
            self.GetMapToolbar().Enable('zoomback', enable=True))
        mapWindow.zoomHistoryUnavailable.connect(
            lambda:
            self.GetMapToolbar().Enable('zoomback', enable=False))
        mapWindow.mouseMoving.connect(self.CoordinatesChanged)

    def AddToolbar(self, name):
        """Add defined toolbar to the window
        
        Currently known toolbars are:
         - 'map'     - basic map toolbar
         - 'vdigit'  - vector digitizer
         - 'gcpdisp' - GCP Manager, Display
         - 'gcpman'  - GCP Manager, points management
         - 'nviz'    - 3D view mode
        """
        # default toolbar
        if name == "map":
            self.toolbars['map'] = MapToolbar(self, self._toolSwitcher)

            self._mgr.AddPane(self.toolbars['map'],
                              wx.aui.AuiPaneInfo().
                              Name("maptoolbar").Caption(_("Map Toolbar")).
                              ToolbarPane().Top().
                              LeftDockable(False).RightDockable(False).
                              BottomDockable(False).TopDockable(True).
                              CloseButton(False).Layer(2).
                              BestSize((self.toolbars['map'].GetSize())))

        # GCP display
        elif name == "gcpdisp":
            self.toolbars['gcpdisp'] = GCPDisplayToolbar(self, self._toolSwitcher)

            self._mgr.AddPane(self.toolbars['gcpdisp'],
                              wx.aui.AuiPaneInfo().
                              Name("gcpdisplaytoolbar").Caption(_("GCP Display toolbar")).
                              ToolbarPane().Top().
                              LeftDockable(False).RightDockable(False).
                              BottomDockable(False).TopDockable(True).
                              CloseButton(False).Layer(2))

            if self.show_target == False:
                self.toolbars['gcpdisp'].Enable('zoommenu', enable = False)

            self.toolbars['gcpman'] = GCPManToolbar(self)

            self._mgr.AddPane(self.toolbars['gcpman'],
                              wx.aui.AuiPaneInfo().
                              Name("gcpmanagertoolbar").Caption(_("GCP Manager toolbar")).
                              ToolbarPane().Top().Row(1).
                              LeftDockable(False).RightDockable(False).
                              BottomDockable(False).TopDockable(True).
                              CloseButton(False).Layer(2))
            
        self._mgr.Update()

    def OnUpdateProgress(self, event):
        """
        Update progress bar info
        """
        self.GetProgressBar().UpdateProgress(event.layer, event.map)
        
        event.Skip()
        
    def OnFocus(self, event):
        """
        Change choicebook page to match display.
        Or set display for georectifying
        """
        # was in if layer manager but considering the state it was executed
        # always, moreover, there is no layer manager dependent code

        # in GCP Management, set focus to current MapWindow for mouse actions
        self.OnPointer(event)
        self.MapWindow.SetFocus()

        event.Skip()

    def OnDraw(self, event):
        """Re-display current map composition
        """
        self.MapWindow.UpdateMap(render = False)
        
    def OnRender(self, event):
        """Re-render map composition (each map layer)
        """
        # FIXME: remove qlayer code or use RemoveQueryLayer() now in mapdisp.frame
        # delete tmp map layers (queries)
        qlayer = self.Map.GetListOfLayers(name=globalvar.QUERYLAYER)
        for layer in qlayer:
            self.Map.DeleteLayer(layer)

        self.SrcMapWindow.UpdateMap(render=True)
        if self.show_target:
            self.TgtMapWindow.UpdateMap(render=True)
        
        # update statusbar
        self.StatusbarUpdate()

    def OnPointer(self, event):
        """Pointer button clicked
        """      
        self.SrcMapWindow.SetModePointer()
        self.TgtMapWindow.SetModePointer()
        # change the default cursor
        self.SrcMapWindow.SetNamedCursor('cross')
        self.TgtMapWindow.SetNamedCursor('cross')

    def OnZoomIn(self, event):
        """Zoom in the map."""
        self.SrcMapWindow.SetModeZoomIn()
        self.TgtMapWindow.SetModeZoomIn()

    def OnZoomOut(self, event):
        """Zoom out the map."""
        self.SrcMapWindow.SetModeZoomOut()
        self.TgtMapWindow.SetModeZoomOut()

    def OnPan(self, event):
        """Panning, set mouse to drag"""
        self.SrcMapWindow.SetModePan()
        self.TgtMapWindow.SetModePan()

    def OnErase(self, event):
        """
        Erase the canvas
        """
        self.MapWindow.EraseMap()

        if self.MapWindow == self.SrcMapWindow:
            win = self.TgtMapWindow
        elif self.MapWindow == self.TgtMapWindow:
            win = self.SrcMapWindow

        win.EraseMap()

    def SaveToFile(self, event):
        """Save map to image
        """
        img = self.MapWindow.img
        if not img:
            GMessage(parent = self,
                     message = _("Nothing to render (empty map). Operation canceled."))
            return
        filetype, ltype = GetImageHandlers(img)

        # get size
        dlg = ImageSizeDialog(self)
        dlg.CentreOnParent()
        if dlg.ShowModal() != wx.ID_OK:
            dlg.Destroy()
            return
        width, height = dlg.GetValues()
        dlg.Destroy()
        
        # get filename
        dlg = wx.FileDialog(parent = self,
                            message = _("Choose a file name to save the image "
                                        "(no need to add extension)"),
                            wildcard = filetype,
                            style=wx.SAVE | wx.FD_OVERWRITE_PROMPT)
        
        if dlg.ShowModal() == wx.ID_OK:
            path = dlg.GetPath()
            if not path:
                dlg.Destroy()
                return
            
            base, ext = os.path.splitext(path)
            fileType = ltype[dlg.GetFilterIndex()]['type']
            extType  = ltype[dlg.GetFilterIndex()]['ext']
            if ext != extType:
                path = base + '.' + extType
            
            self.MapWindow.SaveToFile(path, fileType,
                                      width, height)
            
        dlg.Destroy()

    def PrintMenu(self, event):
        """
        Print options and output menu for map display
        """
        point = wx.GetMousePosition()
        printmenu = wx.Menu()
        # Add items to the menu
        setup = wx.MenuItem(printmenu, wx.ID_ANY, _('Page setup'))
        printmenu.AppendItem(setup)
        self.Bind(wx.EVT_MENU, self.printopt.OnPageSetup, setup)

        preview = wx.MenuItem(printmenu, wx.ID_ANY, _('Print preview'))
        printmenu.AppendItem(preview)
        self.Bind(wx.EVT_MENU, self.printopt.OnPrintPreview, preview)

        doprint = wx.MenuItem(printmenu, wx.ID_ANY, _('Print display'))
        printmenu.AppendItem(doprint)
        self.Bind(wx.EVT_MENU, self.printopt.OnDoPrint, doprint)

        # Popup the menu.  If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(printmenu)
        printmenu.Destroy()

    def OnZoomToRaster(self, event):
        """
        Set display extents to match selected raster map (ignore NULLs)
        """
        self.MapWindow.ZoomToMap(ignoreNulls = True)
        
    def OnZoomToSaved(self, event):
        """Set display geometry to match extents in
        saved region file
        """
        self.MapWindow.SetRegion(zoomOnly=True)
        
    def OnDisplayToWind(self, event):
        """Set computational region (WIND file) to match display
        extents
        """
        self.MapWindow.DisplayToWind()
 
    def SaveDisplayRegion(self, event):
        """Save display extents to named region file.
        """
        self.MapWindow.SaveDisplayRegion()
        
    def OnZoomMenu(self, event):
        """Popup Zoom menu
        """
        point = wx.GetMousePosition()
        zoommenu = wx.Menu()
        # Add items to the menu

        zoomwind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to computational region (set with g.region)'))
        zoommenu.AppendItem(zoomwind)
        self.Bind(wx.EVT_MENU, self.OnZoomToWind, zoomwind)

        zoomdefault = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to default region'))
        zoommenu.AppendItem(zoomdefault)
        self.Bind(wx.EVT_MENU, self.OnZoomToDefault, zoomdefault)

        zoomsaved = wx.MenuItem(zoommenu, wx.ID_ANY, _('Zoom to saved region'))
        zoommenu.AppendItem(zoomsaved)
        self.Bind(wx.EVT_MENU, self.OnZoomToSaved, zoomsaved)

        savewind = wx.MenuItem(zoommenu, wx.ID_ANY, _('Set computational region from display'))
        zoommenu.AppendItem(savewind)
        self.Bind(wx.EVT_MENU, self.OnDisplayToWind, savewind)

        savezoom = wx.MenuItem(zoommenu, wx.ID_ANY, _('Save display geometry to named region'))
        zoommenu.AppendItem(savezoom)
        self.Bind(wx.EVT_MENU, self.SaveDisplayRegion, savezoom)

        # Popup the menu. If an item is selected then its handler
        # will be called before PopupMenu returns.
        self.PopupMenu(zoommenu)
        zoommenu.Destroy()
        
        
    def IsStandalone(self):
        """Check if Map display is standalone"""
        # we do not know and we do not care, so always False
        return True
    
    def GetLayerManager(self):
        """Get reference to Layer Manager

        :return: always None
        """
        return None

    def GetSrcWindow(self):
        return self.SrcMapWindow
        
    def GetTgtWindow(self):
        return self.TgtMapWindow
    
    def GetShowTarget(self):
        return self.show_target
        
    def GetMapToolbar(self):
        """Returns toolbar with zooming tools"""
        return self.toolbars['gcpdisp']

    def _setActiveMapWindow(self, mapWindow):
        if not self.MapWindow == mapWindow:
            self.MapWindow = mapWindow
            self.Map = mapWindow.Map
            self.UpdateActive(mapWindow)
            # needed for wingrass
            self.SetFocus()