def __init__(self, parent, giface, title=_("GRASS GIS Animation tool"), rasters=None, timeseries=None): wx.Frame.__init__(self, parent, title=title, style=wx.DEFAULT_FRAME_STYLE, size=(800, 600)) self._giface = giface self.SetClientSize(self.GetSize()) self.iconsize = (16, 16) self.SetIcon( wx.Icon( os.path.join( globalvar.ICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO)) # Make sure the temporal database exists tgis.init() # create temporal directory and ensure it's deleted after programs ends # (stored in MAPSET/.tmp/) global TMP_DIR TMP_DIR = gcore.tempdir() self.animations = [Animation() for i in range(MAX_COUNT)] self.windows = [] self.animationPanel = AnimationsPanel( self, self.windows, initialCount=MAX_COUNT) bitmapPool = BitmapPool() mapFilesPool = MapFilesPool() self._progressDlg = None self._progressDlgMax = None self.provider = BitmapProvider( bitmapPool=bitmapPool, mapFilesPool=mapFilesPool, tempDir=TMP_DIR) self.animationSliders = {} self.animationSliders['nontemporal'] = SimpleAnimationSlider(self) self.animationSliders['temporal'] = TimeAnimationSlider(self) self.controller = AnimationController(frame=self, sliders=self.animationSliders, animations=self.animations, mapwindows=self.windows, provider=self.provider, bitmapPool=bitmapPool, mapFilesPool=mapFilesPool) for win in self.windows: win.Bind(wx.EVT_SIZE, self.FrameSizeChanged) self.provider.mapsLoaded.connect(lambda: self.SetStatusText('')) self.provider.renderingStarted.connect(self._showRenderingProgress) self.provider.renderingContinues.connect(self._updateProgress) self.provider.renderingFinished.connect(self._closeProgress) self.provider.compositionStarted.connect( self._showRenderingProgress) self.provider.compositionContinues.connect(self._updateProgress) self.provider.compositionFinished.connect(self._closeProgress) self.InitStatusbar() self._mgr = wx.aui.AuiManager(self) # toolbars self.toolbars = {} tb = ['miscToolbar', 'animationToolbar', 'mainToolbar'] if sys.platform == 'win32': tb.reverse() for toolb in tb: self._addToolbar(toolb) self._addPanes() self._mgr.Update() self.dialogs = dict() self.dialogs['speed'] = None self.dialogs['preferences'] = None self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
class AnimationFrame(wx.Frame): def __init__(self, parent, giface, title=_("GRASS GIS Animation tool"), rasters=None, timeseries=None): wx.Frame.__init__(self, parent, title=title, style=wx.DEFAULT_FRAME_STYLE, size=(800, 600)) self._giface = giface self.SetClientSize(self.GetSize()) self.iconsize = (16, 16) self.SetIcon( wx.Icon( os.path.join( globalvar.ICONDIR, 'grass_map.ico'), wx.BITMAP_TYPE_ICO)) # Make sure the temporal database exists tgis.init() # create temporal directory and ensure it's deleted after programs ends # (stored in MAPSET/.tmp/) global TMP_DIR TMP_DIR = gcore.tempdir() self.animations = [Animation() for i in range(MAX_COUNT)] self.windows = [] self.animationPanel = AnimationsPanel( self, self.windows, initialCount=MAX_COUNT) bitmapPool = BitmapPool() mapFilesPool = MapFilesPool() self._progressDlg = None self._progressDlgMax = None self.provider = BitmapProvider( bitmapPool=bitmapPool, mapFilesPool=mapFilesPool, tempDir=TMP_DIR) self.animationSliders = {} self.animationSliders['nontemporal'] = SimpleAnimationSlider(self) self.animationSliders['temporal'] = TimeAnimationSlider(self) self.controller = AnimationController(frame=self, sliders=self.animationSliders, animations=self.animations, mapwindows=self.windows, provider=self.provider, bitmapPool=bitmapPool, mapFilesPool=mapFilesPool) for win in self.windows: win.Bind(wx.EVT_SIZE, self.FrameSizeChanged) self.provider.mapsLoaded.connect(lambda: self.SetStatusText('')) self.provider.renderingStarted.connect(self._showRenderingProgress) self.provider.renderingContinues.connect(self._updateProgress) self.provider.renderingFinished.connect(self._closeProgress) self.provider.compositionStarted.connect( self._showRenderingProgress) self.provider.compositionContinues.connect(self._updateProgress) self.provider.compositionFinished.connect(self._closeProgress) self.InitStatusbar() self._mgr = wx.aui.AuiManager(self) # toolbars self.toolbars = {} tb = ['miscToolbar', 'animationToolbar', 'mainToolbar'] if sys.platform == 'win32': tb.reverse() for toolb in tb: self._addToolbar(toolb) self._addPanes() self._mgr.Update() self.dialogs = dict() self.dialogs['speed'] = None self.dialogs['preferences'] = None self.Bind(wx.EVT_CLOSE, self.OnCloseWindow) def InitStatusbar(self): """Init statusbar.""" self.CreateStatusBar(number=1, style=0) def _addPanes(self): self._mgr.AddPane(self.animationPanel, wx.aui.AuiPaneInfo().CentrePane(). Name('animPanel').CentrePane().CaptionVisible(False).PaneBorder(False). Floatable(False).BestSize((-1, -1)). CloseButton(False).DestroyOnClose(True).Layer(0)) for name, slider in six.iteritems(self.animationSliders): self._mgr.AddPane( slider, wx.aui.AuiPaneInfo().PaneBorder(False).Name( 'slider_' + name). Layer(1).CaptionVisible(False).BestSize( slider.GetBestSize()). DestroyOnClose(True).CloseButton(False).Bottom()) self._mgr.GetPane('slider_' + name).Hide() def _addToolbar(self, name): """Add defined toolbar to the window Currently known toolbars are: - 'mainToolbar' - data management - 'animationToolbar' - animation controls - 'miscToolbar' - help, close """ if name == "mainToolbar": self.toolbars[name] = MainToolbar(self) self._mgr.AddPane(self.toolbars[name], wx.aui.AuiPaneInfo(). Name('mainToolbar').Caption(_("Main Toolbar")). ToolbarPane().Top(). LeftDockable(False).RightDockable(False). BottomDockable(True).TopDockable(True). CloseButton(False).Layer(2).Row(1). BestSize((self.toolbars['mainToolbar'].GetBestSize()))) elif name == 'animationToolbar': self.toolbars[name] = AnimationToolbar(self) self._mgr.AddPane(self.toolbars[name], wx.aui.AuiPaneInfo(). Name('animationToolbar').Caption(_("Animation Toolbar")). ToolbarPane().Top(). LeftDockable(False).RightDockable(False). BottomDockable(True).TopDockable(True). CloseButton(False).Layer(2).Row(1). BestSize((self.toolbars['animationToolbar'].GetBestSize()))) self.controller.SetAnimationToolbar( self.toolbars['animationToolbar']) elif name == 'miscToolbar': self.toolbars[name] = MiscToolbar(self) self._mgr.AddPane(self.toolbars[name], wx.aui.AuiPaneInfo(). Name('miscToolbar').Caption(_("Misc Toolbar")). ToolbarPane().Top(). LeftDockable(False).RightDockable(False). BottomDockable(True).TopDockable(True). CloseButton(False).Layer(2).Row(1). BestSize((self.toolbars['miscToolbar'].GetBestSize()))) def SetAnimations(self, layerLists): """Set animation data :param layerLists: list of layerLists """ self.controller.SetAnimations(layerLists) def OnAddAnimation(self, event): self.controller.AddAnimation() def AddWindow(self, index): self.animationPanel.AddWindow(index) def RemoveWindow(self, index): self.animationPanel.RemoveWindow(index) def IsWindowShown(self, index): return self.animationPanel.IsWindowShown(index) def OnEditAnimation(self, event): self.controller.EditAnimations() def SetSlider(self, name): if name == 'nontemporal': self._mgr.GetPane('slider_nontemporal').Show() self._mgr.GetPane('slider_temporal').Hide() elif name == 'temporal': self._mgr.GetPane('slider_temporal').Show() self._mgr.GetPane('slider_nontemporal').Hide() else: self._mgr.GetPane('slider_temporal').Hide() self._mgr.GetPane('slider_nontemporal').Hide() self._mgr.Update() def OnPlayForward(self, event): self.controller.SetOrientation(Orientation.FORWARD) self.controller.StartAnimation() def OnPlayBack(self, event): self.controller.SetOrientation(Orientation.BACKWARD) self.controller.StartAnimation() def OnPause(self, event): self.controller.PauseAnimation(paused=event.IsChecked()) def OnStop(self, event): self.controller.EndAnimation() def OnOneDirectionReplay(self, event): if event.IsChecked(): mode = ReplayMode.REPEAT else: mode = ReplayMode.ONESHOT self.controller.SetReplayMode(mode) def OnBothDirectionReplay(self, event): if event.IsChecked(): mode = ReplayMode.REVERSE else: mode = ReplayMode.ONESHOT self.controller.SetReplayMode(mode) def OnAdjustSpeed(self, event): win = self.dialogs['speed'] if win: win.SetTemporalMode(self.controller.GetTemporalMode()) win.SetTimeGranularity(self.controller.GetTimeGranularity()) win.InitTimeSpin(self.controller.GetTimeTick()) if win.IsShown(): win.SetFocus() else: win.Show() else: # start win = SpeedDialog( self, temporalMode=self.controller.GetTemporalMode(), timeGranularity=self.controller.GetTimeGranularity(), initialSpeed=self.controller.timeTick) win.CenterOnParent() self.dialogs['speed'] = win win.speedChanged.connect(self.ChangeSpeed) win.Show() def ChangeSpeed(self, ms): self.controller.timeTick = ms def Reload(self, event): self.controller.Reload() def _showRenderingProgress(self, count): # the message is not really visible, it's there for the initial dlg # size self._progressDlg = wx.ProgressDialog( title=_("Loading data"), message="Loading data started, please be patient.", maximum=count, parent=self, style=wx.PD_CAN_ABORT | wx.PD_APP_MODAL | wx.PD_AUTO_HIDE | wx.PD_SMOOTH) self._progressDlgMax = count def _updateProgress(self, current, text): text += _(" ({c} out of {p})").format(c=current, p=self._progressDlgMax) keepGoing, skip = self._progressDlg.Update(current, text) if not keepGoing: self.provider.RequestStopRendering() def _closeProgress(self): self._progressDlg.Destroy() self._progressDlg = None def OnExportAnimation(self, event): self.controller.Export() def FrameSizeChanged(self, event): maxWidth = maxHeight = 0 for win in self.windows: w, h = win.GetClientSize() if w >= maxWidth and h >= maxHeight: maxWidth, maxHeight = w, h self.provider.WindowSizeChanged(maxWidth, maxHeight) event.Skip() def OnPreferences(self, event): if not self.dialogs['preferences']: dlg = PreferencesDialog(parent=self, giface=self._giface) self.dialogs['preferences'] = dlg dlg.formatChanged.connect( lambda: self.controller.UpdateAnimations()) dlg.CenterOnParent() self.dialogs['preferences'].ShowModal() def OnHelp(self, event): RunCommand('g.manual', quiet=True, entry='wxGUI.animation') def OnCloseWindow(self, event): if self.controller.timer.IsRunning(): self.controller.timer.Stop() CleanUp(TMP_DIR)() self._mgr.UnInit() self.Destroy() def __del__(self): """It might not be called, therefore we try to clean it all in OnCloseWindow.""" if hasattr(self, 'controller') and hasattr(self.controller, 'timer'): if self.controller.timer.IsRunning(): self.controller.timer.Stop() CleanUp(TMP_DIR)()