[GRASS-SVN] r58551 - in grass/trunk/gui/wxpython: animation core lmgr

svn_grass at osgeo.org svn_grass at osgeo.org
Sun Dec 29 15:18:13 PST 2013


Author: annakrat
Date: 2013-12-29 15:18:13 -0800 (Sun, 29 Dec 2013)
New Revision: 58551

Modified:
   grass/trunk/gui/wxpython/animation/controller.py
   grass/trunk/gui/wxpython/animation/dialogs.py
   grass/trunk/gui/wxpython/animation/frame.py
   grass/trunk/gui/wxpython/animation/g.gui.animation.html
   grass/trunk/gui/wxpython/animation/g.gui.animation.py
   grass/trunk/gui/wxpython/animation/temporal_manager.py
   grass/trunk/gui/wxpython/animation/toolbars.py
   grass/trunk/gui/wxpython/animation/utils.py
   grass/trunk/gui/wxpython/core/settings.py
   grass/trunk/gui/wxpython/lmgr/frame.py
Log:
wxGUI/animation: create application settings (bgcolor, time format)

Modified: grass/trunk/gui/wxpython/animation/controller.py
===================================================================
--- grass/trunk/gui/wxpython/animation/controller.py	2013-12-29 23:09:07 UTC (rev 58550)
+++ grass/trunk/gui/wxpython/animation/controller.py	2013-12-29 23:18:13 UTC (rev 58551)
@@ -19,10 +19,11 @@
 from core.gcmd import GException, GError, GMessage
 from core.utils import _
 from grass.imaging import writeAvi, writeGif, writeIms, writeSwf
+from core.settings import UserSettings
 
 from animation.temporal_manager import TemporalManager
 from animation.dialogs import InputDialog, EditDialog, ExportDialog
-from animation.utils import TemporalMode, Orientation, RenderText, WxImageToPil, \
+from animation.utils import TemporalMode, TemporalType, Orientation, RenderText, WxImageToPil, \
     sampleCmdMatrixAndCreateNames, layerListToCmdsMatrix, HashCmds, getCpuCount
 from animation.data import AnimationData
 
@@ -131,10 +132,12 @@
 
     def UpdateFrame(self, index, win, dataId):
         bitmap = self.bitmapProvider.GetBitmap(dataId)
-        if dataId is None:
-            dataId = ''
-        win.DrawBitmap(bitmap)
-        # self.frame.SetStatusText(dataId)
+        if not UserSettings.Get(group='animation', key='temporal',
+                                subkey=['nodata', 'enable']):
+            if dataId is not None:
+                win.DrawBitmap(bitmap)
+        else:
+            win.DrawBitmap(bitmap)
         self.slider.UpdateFrame(index)
 
     def SliderChanging(self, index):
@@ -356,7 +359,8 @@
             else:
                 self._load3DData(animData)
             self._loadLegend(animData)
-        self.bitmapProvider.Load(nprocs=getCpuCount())
+        color = UserSettings.Get(group='animation', key='bgcolor', subkey='color')
+        self.bitmapProvider.Load(nprocs=getCpuCount(), bgcolor=color)
         # clear pools
         self.bitmapPool.Clear()
         self.mapFilesPool.Clear()
@@ -431,7 +435,8 @@
     def Reload(self):
         self.EndAnimation()
 
-        self.bitmapProvider.Load(nprocs=getCpuCount(), force=True)
+        color = UserSettings.Get(group='animation', key='bgcolor', subkey='color')
+        self.bitmapProvider.Load(nprocs=getCpuCount(), bgcolor=color, force=True)
 
         self.EndAnimation()
 
@@ -479,7 +484,12 @@
             # collect bitmaps of all windows and paste them into the one
             for i in animWinIndex:
                 frameId = self.animations[i].GetFrame(frameIndex)
-                bitmap = self.bitmapProvider.GetBitmap(frameId)
+                if not UserSettings.Get(group='animation', key='temporal',
+                                        subkey=['nodata', 'enable']):
+                    if frameId is not None:
+                        bitmap = self.bitmapProvider.GetBitmap(frameId)
+                else:
+                    bitmap = self.bitmapProvider.GetBitmap(frameId)
                 im = wx.ImageFromBitmap(bitmap)
 
                 # add legend if used
@@ -504,12 +514,15 @@
                     decImage = wx.Image(decoration['file'])
                 elif decoration['name'] == 'time':
                     timeLabel = timeLabels[frameIndex]
-                    if timeLabel[1]:
+                    if timeLabel[1]:  # interval
                         text = _("%(from)s %(dash)s %(to)s") % \
-                            {'from': timeLabel[0], 'dash': u"\u2013", 'to': timeLabel[1]}
+                                {'from': timeLabel[0], 'dash': u"\u2013", 'to': timeLabel[1]}
                     else:
-                        text = _("%(start)s %(unit)s") % \
-                            {'start': timeLabel[0], 'unit': timeLabel[2]}
+                        if self.temporalManager.GetTemporalType() == TemporalType.ABSOLUTE:
+                            text = timeLabel[0]
+                        else:
+                            text = _("%(start)s %(unit)s") % \
+                                    {'start': timeLabel[0], 'unit': timeLabel[2]}
 
                     decImage = RenderText(text, decoration['font']).ConvertToImage()
                 elif decoration['name'] == 'text':

Modified: grass/trunk/gui/wxpython/animation/dialogs.py
===================================================================
--- grass/trunk/gui/wxpython/animation/dialogs.py	2013-12-29 23:09:07 UTC (rev 58550)
+++ grass/trunk/gui/wxpython/animation/dialogs.py	2013-12-29 23:18:13 UTC (rev 58551)
@@ -25,6 +25,8 @@
 import copy
 import datetime
 import wx.lib.filebrowsebutton as filebrowse
+import wx.lib.scrolledpanel as SP
+import wx.lib.colourselect as csel
 
 if __name__ == '__main__':
     sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
@@ -32,6 +34,7 @@
 from core.gcmd import GMessage, GError, GException
 from core import globalvar
 from gui_core.dialogs import MapLayersDialog, GetImageHandlers
+from gui_core.preferences import PreferencesBaseDialog
 from gui_core.forms import GUI
 from core.settings import UserSettings
 from core.utils import _
@@ -1337,6 +1340,135 @@
         return self.layer
 
 
+class PreferencesDialog(PreferencesBaseDialog):
+    """!Animation preferences dialog"""
+    def __init__(self, parent, giface, title=_("Animation Tool settings"),
+                 settings=UserSettings):
+        PreferencesBaseDialog.__init__(self, parent=parent, giface=giface, title=title,
+                                       settings=settings, size=(-1, 270))
+
+        self._timeFormats = ['%Y-%m-%d %H:%M:%S',  # 2013-12-29 11:16:26
+                             '%Y-%m-%d',  # 2013-12-29
+                             '%c',  # Sun Dec 29 11:16:26 2013 (locale-dependent)
+                             '%x',  # 12/29/13 (locale-dependent)
+                             '%X',  # 11:16:26 (locale-dependent)
+                             '%b %d, %Y',  # Dec 29, 2013
+                             '%B %d, %Y',  # December 29, 2013
+                             '%B, %Y',  # December 2013
+                             '%I:%M %p',  # 11:16 AM
+                             '%I %p',  # 11 AM
+                             ]
+        self._format = None
+        # create notebook pages
+        self._createGeneralPage(self.notebook)
+        self._createTemporalPage(self.notebook)
+
+        self.SetMinSize(self.GetBestSize())
+        self.SetSize(self.size)
+
+    def _createGeneralPage(self, notebook):
+        """!Create notebook page for general settings"""
+        panel = SP.ScrolledPanel(parent=notebook)
+        panel.SetupScrolling(scroll_x=False, scroll_y=True)
+        notebook.AddPage(page=panel, text=_("General"))
+
+        border = wx.BoxSizer(wx.VERTICAL)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(hgap=3, vgap=3)
+
+        row = 0
+        gridSizer.Add(item=wx.StaticText(parent=panel,
+                                         label=_("Background color:")),
+                      flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+        color = csel.ColourSelect(parent=panel,
+                                  colour=UserSettings.Get(group='animation',
+                                                          key='bgcolor', subkey='color'),
+                                  size=globalvar.DIALOG_COLOR_SIZE)
+        color.SetName('GetColour')
+        self.winId['animation:bgcolor:color'] = color.GetId()
+
+        gridSizer.Add(item=color, pos=(row, 1), flag=wx.ALIGN_RIGHT)
+
+        gridSizer.AddGrowableCol(1)
+        sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=3)
+        border.Add(item=sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=3)
+        panel.SetSizer(border)
+
+        return panel
+
+    def _createTemporalPage(self, notebook):
+        """!Create notebook page for temporal settings"""
+        panel = SP.ScrolledPanel(parent=notebook)
+        panel.SetupScrolling(scroll_x=False, scroll_y=True)
+        notebook.AddPage(page=panel, text=_("Time"))
+
+        border = wx.BoxSizer(wx.VERTICAL)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        gridSizer = wx.GridBagSizer(hgap=5, vgap=5)
+
+        row = 0
+        gridSizer.Add(item=wx.StaticText(parent=panel,
+                                         label=_("Absolute time format:")),
+                      flag=wx.ALIGN_LEFT | wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+        self.tempFormat = wx.ComboBox(parent=panel, name='GetValue')
+        self.tempFormat.SetItems(self._timeFormats)
+        self.tempFormat.SetValue(self.settings.Get(group='animation', key='temporal',
+                                                   subkey='format'))
+        self.winId['animation:temporal:format'] = self.tempFormat.GetId()
+        gridSizer.Add(item=self.tempFormat, pos=(row, 1), flag=wx.ALIGN_RIGHT)
+        self.infoTimeLabel = wx.StaticText(parent=panel)
+        self.tempFormat.Bind(wx.EVT_COMBOBOX, lambda evt: self._setTimeFormat(self.tempFormat.GetValue()))
+        self.tempFormat.Bind(wx.EVT_TEXT, lambda evt: self._setTimeFormat(self.tempFormat.GetValue()))
+        self.tempFormat.SetToolTipString(_("Click and then press key up or down to preview "
+                                           "different date and time formats. "
+                                           "Type custom format string."))
+        row += 1
+        gridSizer.Add(item=self.infoTimeLabel, pos=(row, 0), span=(1, 2),
+                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+        self._setTimeFormat(self.tempFormat.GetValue())
+
+        row += 1
+        link = wx.HyperlinkCtrl(panel, id=wx.ID_ANY, label=_("Learn more about formatting options"),
+                                url="http://docs.python.org/2/library/datetime.html#"
+                                "strftime-and-strptime-behavior")
+        link.SetNormalColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT))
+        link.SetVisitedColour(wx.SystemSettings_GetColour(wx.SYS_COLOUR_GRAYTEXT))
+        gridSizer.Add(item=link, pos=(row, 0), span=(1, 2),
+                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+
+        row += 2
+        noDataCheck = wx.CheckBox(panel, label=_("Display instances with no data"))
+        noDataCheck.SetToolTipString(_("When animating instant-based data which have irregular timestamps "
+                                       "you can display 'no data frame' (checked option) or "
+                                       "keep last frame."))
+        noDataCheck.SetValue(self.settings.Get(group='animation', key='temporal',
+                                               subkey=['nodata', 'enable']))
+        self.winId['animation:temporal:nodata:enable'] = noDataCheck.GetId()
+        gridSizer.Add(item=noDataCheck, pos=(row, 0), span=(1, 2),
+                      flag=wx.ALIGN_CENTER_VERTICAL | wx.ALIGN_LEFT)
+
+        gridSizer.AddGrowableCol(1)
+        sizer.Add(item=gridSizer, proportion=1, flag=wx.ALL | wx.EXPAND, border=3)
+        border.Add(item=sizer, proportion=0, flag=wx.ALL | wx.EXPAND, border=3)
+        panel.SetSizer(border)
+
+        return panel
+
+    def _setTimeFormat(self, formatString):
+        now = datetime.datetime.now()
+        try:
+            label = datetime.datetime.strftime(now, formatString)
+            self._format = formatString
+        except ValueError:
+            label = _("Invalid")
+        self.infoTimeLabel.SetLabel(label)
+        self.infoTimeLabel.GetContainingSizer().Layout()
+
+    def _updateSettings(self):
+        self.tempFormat.SetValue(self._format)
+        return PreferencesBaseDialog._updateSettings(self)
+
+
 def test():
     import wx.lib.inspection
 

Modified: grass/trunk/gui/wxpython/animation/frame.py
===================================================================
--- grass/trunk/gui/wxpython/animation/frame.py	2013-12-29 23:09:07 UTC (rev 58550)
+++ grass/trunk/gui/wxpython/animation/frame.py	2013-12-29 23:18:13 UTC (rev 58551)
@@ -37,7 +37,7 @@
 from animation.controller import AnimationController
 from animation.anim import Animation
 from animation.toolbars import MainToolbar, AnimationToolbar, MiscToolbar
-from animation.dialogs import SpeedDialog
+from animation.dialogs import SpeedDialog, PreferencesDialog
 from animation.utils import Orientation, ReplayMode, TemporalType
 
 
@@ -48,11 +48,11 @@
 
 
 class AnimationFrame(wx.Frame):
-    def __init__(self, parent=None, title=_("Animation tool"),
+    def __init__(self, parent, giface, title=_("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)
 
@@ -108,6 +108,7 @@
 
         self.dialogs = dict()
         self.dialogs['speed'] = None
+        self.dialogs['preferences'] = None
 
         self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
 
@@ -286,6 +287,14 @@
         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.CenterOnParent()
+
+        self.dialogs['preferences'].ShowModal()
+
     def OnHelp(self, event):
         RunCommand('g.manual',
                    quiet=True,

Modified: grass/trunk/gui/wxpython/animation/g.gui.animation.html
===================================================================
--- grass/trunk/gui/wxpython/animation/g.gui.animation.html	2013-12-29 23:09:07 UTC (rev 58550)
+++ grass/trunk/gui/wxpython/animation/g.gui.animation.html	2013-12-29 23:18:13 UTC (rev 58551)
@@ -17,6 +17,8 @@
   <li>visualize space time datasets with unequally spaced intervals</li>
   <li>animate 3d view (partially implemented, not supported on Windows)</li>
   <li>export animation as a series of images, animated GIF, AVI or SWF</li>
+  <li>choose format of time labels in case of animating maps with absolute time</li>
+  <li>choose background color</li>
 </ul>
 
 <p>

Modified: grass/trunk/gui/wxpython/animation/g.gui.animation.py
===================================================================
--- grass/trunk/gui/wxpython/animation/g.gui.animation.py	2013-12-29 23:09:07 UTC (rev 58550)
+++ grass/trunk/gui/wxpython/animation/g.gui.animation.py	2013-12-29 23:18:13 UTC (rev 58551)
@@ -62,6 +62,7 @@
 
 from core.globalvar import CheckWxVersion
 from core.utils import _, GuiModuleMain
+from core.giface import StandaloneGrassInterface
 from core.layerlist import LayerList
 from animation.frame import AnimationFrame, MAX_COUNT
 from animation.data import AnimLayer
@@ -117,7 +118,7 @@
     if not CheckWxVersion([2, 9]):
         wx.InitAllImageHandlers()
 
-    frame = AnimationFrame(parent=None)
+    frame = AnimationFrame(parent=None, giface=StandaloneGrassInterface())
     frame.CentreOnScreen()
     frame.Show()
     if len(layerList) >= 1:

Modified: grass/trunk/gui/wxpython/animation/temporal_manager.py
===================================================================
--- grass/trunk/gui/wxpython/animation/temporal_manager.py	2013-12-29 23:09:07 UTC (rev 58550)
+++ grass/trunk/gui/wxpython/animation/temporal_manager.py	2013-12-29 23:18:13 UTC (rev 58551)
@@ -19,6 +19,7 @@
 
 import os
 import sys
+import datetime
 
 if __name__ == '__main__':
     sys.path.append(os.path.join(os.environ['GISBASE'], "etc", "gui", "wxpython"))
@@ -27,6 +28,7 @@
 import grass.temporal as tgis
 from core.gcmd import GException
 from core.utils import _
+from core.settings import UserSettings
 from animation.utils import validateTimeseriesName, TemporalType
 
 
@@ -191,12 +193,11 @@
         # no temporal overlap! We would need to sample all datasets
         # by a temporary dataset, I don't know how it would work with point data
         if self.temporalType == TemporalType.ABSOLUTE:
-            # ('1996-01-01 00:00:00', '1997-01-01 00:00:00', 'year'),
             timestamps = sorted(list(labelListSet), key=lambda x: x[0])
         else:
-            # ('15', '16', u'years'),
-            timestamps = sorted(list(labelListSet), key=lambda x: float(x[0]))
+            timestamps = sorted(list(labelListSet), key=lambda x: x[0])
 
+
         newMapLists = []
         for mapList, labelList in zip(mapLists, labelLists):
             newMapList = [None] * len(timestamps)
@@ -211,6 +212,15 @@
         for i, dataset in enumerate(self.timeseriesList):
             mapDict[dataset] = newMapLists[i]
 
+        if self.temporalType == TemporalType.ABSOLUTE:
+            # ('1996-01-01 00:00:00', '1997-01-01 00:00:00', 'year'),
+            formatString = UserSettings.Get(group='animation', key='temporal', subkey='format')
+            timestamps = [(datetime.datetime.strftime(st, formatString),
+                          datetime.datetime.strftime(end, formatString)
+                          if end is not None else None, unit) for (st, end, unit) in timestamps]
+        else:
+            # ('15', '16', u'years'),
+            timestamps = [(str(st), str(end), unit) for st, end, unit in timestamps]
         return timestamps, mapDict
 
     def _getLabelsAndMaps(self, timeseries):
@@ -264,7 +274,7 @@
                     lastTimeseries = series
                     end = None
                 else:
-                    end = str(end)
+                    end = end
                     # interval data
                     if series:
                         # map exists, stop point mode
@@ -284,7 +294,7 @@
                         else:
                             # append series which is None
                             listOfMaps.append(series)
-                timeLabels.append((str(start), end, unit))
+                timeLabels.append((start, end, unit))
 
         return timeLabels, listOfMaps
 

Modified: grass/trunk/gui/wxpython/animation/toolbars.py
===================================================================
--- grass/trunk/gui/wxpython/animation/toolbars.py	2013-12-29 23:09:07 UTC (rev 58550)
+++ grass/trunk/gui/wxpython/animation/toolbars.py	2013-12-29 23:18:13 UTC (rev 58551)
@@ -25,7 +25,7 @@
 from animation.anim import ReplayMode
 
 ganimIcons = {
-    'speed': MetaIcon(img='settings', label=_("Change animation speed")),
+    'speed': MetaIcon(img='move', label=_("Change animation speed")),
     'playForward': MetaIcon(img='execute', label=_("Play forward")),
     'playBack': MetaIcon(img='player-back', label=_("Play back")),
     'stop': MetaIcon(img='player-stop', label=_("Stop")),
@@ -215,7 +215,9 @@
 
     def _toolbarData(self):
         """!Toolbar data"""
-        return self._getToolbarData((("help", BaseIcons['help'],
+        return self._getToolbarData((("settings", BaseIcons['settings'],
+                                      self.parent.OnPreferences),
+                                     ("help", BaseIcons['help'],
                                       self.parent.OnHelp),
                                      ("quit", BaseIcons['quit'],
                                       self.parent.OnCloseWindow),

Modified: grass/trunk/gui/wxpython/animation/utils.py
===================================================================
--- grass/trunk/gui/wxpython/animation/utils.py	2013-12-29 23:09:07 UTC (rev 58550)
+++ grass/trunk/gui/wxpython/animation/utils.py	2013-12-29 23:18:13 UTC (rev 58551)
@@ -229,6 +229,7 @@
     dc.SetBackgroundMode(wx.TRANSPARENT)
     dc.Clear()
     dc.DrawText(text, 1, 1)
+    bmp.SetMaskColour(wx.WHITE)
     dc.SelectObject(wx.NullBitmap)
 
     return bmp

Modified: grass/trunk/gui/wxpython/core/settings.py
===================================================================
--- grass/trunk/gui/wxpython/core/settings.py	2013-12-29 23:09:07 UTC (rev 58550)
+++ grass/trunk/gui/wxpython/core/settings.py	2013-12-29 23:18:13 UTC (rev 58551)
@@ -799,6 +799,17 @@
                         }
                     },
                 },
+            'animation': {
+                'bgcolor': {
+                    'color': (255, 255, 255, 255),
+                    },
+                'temporal': {
+                    'format': '%Y-%m-%d %H:%M:%S',
+                    'nodata': {
+                        'enable': False
+                        },
+                    },
+                },
             }
 
         # quick fix, http://trac.osgeo.org/grass/ticket/1233

Modified: grass/trunk/gui/wxpython/lmgr/frame.py
===================================================================
--- grass/trunk/gui/wxpython/lmgr/frame.py	2013-12-29 23:09:07 UTC (rev 58550)
+++ grass/trunk/gui/wxpython/lmgr/frame.py	2013-12-29 23:18:13 UTC (rev 58551)
@@ -1457,7 +1457,7 @@
         """
         from animation.frame import AnimationFrame
 
-        frame = AnimationFrame(parent = self)
+        frame = AnimationFrame(parent=self, giface=self._giface)
         frame.CentreOnScreen()
         frame.Show()
 



More information about the grass-commit mailing list