[GRASS-SVN] r53611 - grass-addons/grass7/gui/wxpython/wx.animation/animation

svn_grass at osgeo.org svn_grass at osgeo.org
Mon Oct 29 14:48:12 PDT 2012


Author: annakrat
Date: 2012-10-29 14:48:11 -0700 (Mon, 29 Oct 2012)
New Revision: 53611

Modified:
   grass-addons/grass7/gui/wxpython/wx.animation/animation/animation.py
   grass-addons/grass7/gui/wxpython/wx.animation/animation/controller.py
   grass-addons/grass7/gui/wxpython/wx.animation/animation/dialogs.py
   grass-addons/grass7/gui/wxpython/wx.animation/animation/frame.py
   grass-addons/grass7/gui/wxpython/wx.animation/animation/mapwindow.py
   grass-addons/grass7/gui/wxpython/wx.animation/animation/toolbars.py
   grass-addons/grass7/gui/wxpython/wx.animation/animation/utils.py
Log:
wx.animation: export animation to image sequence added

Modified: grass-addons/grass7/gui/wxpython/wx.animation/animation/animation.py
===================================================================
--- grass-addons/grass7/gui/wxpython/wx.animation/animation/animation.py	2012-10-29 17:52:19 UTC (rev 53610)
+++ grass-addons/grass7/gui/wxpython/wx.animation/animation/animation.py	2012-10-29 21:48:11 UTC (rev 53611)
@@ -48,6 +48,10 @@
         """
         self.frames = frames
 
+    def GetFrame(self, index):
+        """!Returns animation frame"""
+        return self.frames[index]
+
     def GetCount(self):
         """!Get frame count."""
         return len(self.frames)

Modified: grass-addons/grass7/gui/wxpython/wx.animation/animation/controller.py
===================================================================
--- grass-addons/grass7/gui/wxpython/wx.animation/animation/controller.py	2012-10-29 17:52:19 UTC (rev 53610)
+++ grass-addons/grass7/gui/wxpython/wx.animation/animation/controller.py	2012-10-29 21:48:11 UTC (rev 53611)
@@ -13,14 +13,15 @@
 
 @author Anna Kratochvilova <kratochanna gmail.com>
 """
+import os
 import wx
 
 from core.gcmd import GException, GError, GMessage
 import grass.script as grass
 
 from temporal_manager import TemporalManager
-from dialogs import InputDialog, EditDialog, AnimationData
-from utils import TemporalMode, Orientation
+from dialogs import InputDialog, EditDialog, AnimationData, ExportDialog
+from utils import TemporalMode, Orientation, RenderText
 
 class AnimationController(wx.EvtHandler):
     def __init__(self, frame, sliders, animations, mapwindows, providers, bitmapPool):
@@ -448,8 +449,105 @@
                 region['cols'], region['rows'] = loadSize
                 self.mapwindows[anim.windowIndex].SetRegion(region)
 
+    def Export(self):
+        if not self.animationData:
+            GMessage(parent = self.frame, message = _("No animation to export."))
+            return
+        dlg = ExportDialog(self.frame, temporal = self.temporalMode)
+        if dlg.ShowModal() == wx.ID_OK:
+            decorations = dlg.GetDecorations()
+            exportInfo = dlg.GetExportInformation()
+            dlg.Destroy()
+        else:
+            dlg.Destroy()
+            return
 
+        self._export(exportInfo, decorations)
 
+    def _export(self, exportInfo, decorations):
+        size = self.frame.animationPanel.GetSize()
+        if self.temporalMode == TemporalMode.TEMPORAL:
+            timeLabels, mapNamesDict = self.temporalManager.GetLabelsAndMaps()
+            frameCount = len(timeLabels)
+        else:
+            frameCount = len(self.animationData[0].mapData) # should be the same for all
+
+        animWinSize = []
+        animWinPos = []
+        animWinIndex = []
+        # determine position and sizes of bitmaps
+        for i, (win, anim) in enumerate(zip(self.mapwindows, self.animations)):
+            if anim.IsActive():
+                pos = tuple([pos1 + pos2 for pos1, pos2 in zip(win.GetPosition(), win.GetAdjustedPosition())])
+                animWinPos.append(pos)
+                animWinSize.append(win.GetAdjustedSize())
+                animWinIndex.append(i)
+        
+        images = []
+        for frameIndex in range(frameCount):
+            image = wx.EmptyImage(*size)
+            image.Replace(0, 0, 0, 255, 255, 255)
+            # collect bitmaps of all windows and paste them into the one
+            for i in range(len(animWinSize)):
+                frameId = self.animations[animWinIndex[i]].GetFrame(frameIndex)
+                bitmap = self.bitmapProviders[animWinIndex[i]].GetBitmap(frameId)
+                im = wx.ImageFromBitmap(bitmap)
+                if im.GetSize() != animWinSize[i]:
+                    im.Rescale(*animWinSize[i])
+                image.Paste(im, *animWinPos[i])
+            # paste decorations
+            for decoration in decorations:
+                # add image
+                x = decoration['pos'][0] / 100. * size[0]
+                y = decoration['pos'][1] / 100. * size[1]
+                if decoration['name'] == 'image':
+                    decImage = wx.Image(decoration['file'])
+                elif decoration['name'] == 'time':
+                    timeLabel = timeLabels[frameIndex]
+                    if timeLabel[1]:
+                        text = _("%(from)s %(dash)s %(to)s") % \
+                                {'from': timeLabel[0], 'dash': u"\u2013", 'to': timeLabel[1]}
+                    else:
+                        text = _("%(start)s %(unit)s") % \
+                                {'start': timeLabel[0], 'unit': timeLabel[2]}
+                    
+                    decImage = RenderText(text, decoration['font']).ConvertToImage()
+                elif decoration['name'] == 'text':
+                    text = decoration['text']
+                    decImage = RenderText(text, decoration['font']).ConvertToImage()
+
+                image.Paste(decImage, x, y)
+
+            images.append(image)
+
+        # export
+        if exportInfo['method'] == 'sequence':
+            busy = wx.BusyInfo(message = _("Exporting images, please wait..."), parent = self.frame)
+            wx.Yield()
+            zeroPadding = len(str(len(images)))
+            for i, image in enumerate(images):
+                filename = "%s_%s.%s" % (exportInfo['prefix'], str(i + 1).zfill(zeroPadding),
+                                         exportInfo['format']['ext'])
+                image.SaveFile(os.path.join(exportInfo['directory'], filename), exportInfo['format']['type'])
+
+            busy.Destroy()
+
+
+
+            # image.SaveFile('/home/anna/testy/grass/export/export_%s.png' % frameIndex, wx.BITMAP_TYPE_PNG)
+
+
+            
+
+
+        
+
+        # for anim in self.animationData
+
+
+        
+
+
 #def test():
 #    import gettext
 #    gettext.install('grasswxpy', os.path.join(os.getenv("GISBASE"), 'locale'), unicode = True)

Modified: grass-addons/grass7/gui/wxpython/wx.animation/animation/dialogs.py
===================================================================
--- grass-addons/grass7/gui/wxpython/wx.animation/animation/dialogs.py	2012-10-29 17:52:19 UTC (rev 53610)
+++ grass-addons/grass7/gui/wxpython/wx.animation/animation/dialogs.py	2012-10-29 21:48:11 UTC (rev 53611)
@@ -33,7 +33,7 @@
 from core.gcmd import GMessage, GError, GException
 from core import globalvar
 from gui_core import gselect
-from gui_core.dialogs import MapLayersDialog, EVT_APPLY_MAP_LAYERS
+from gui_core.dialogs import MapLayersDialog, EVT_APPLY_MAP_LAYERS, GetImageHandlers
 from core.settings import UserSettings
 
 from utils import TemporalMode, validateTimeseriesName, validateMapNames
@@ -782,6 +782,381 @@
         return "%s(%r)" % (self.__class__, self.__dict__)
 
 
+
+class ExportDialog(wx.Dialog):
+    def __init__(self, parent, temporal):
+        wx.Dialog.__init__(self, parent = parent, id = wx.ID_ANY, title = _("Export animation"),
+                           style = wx.DEFAULT_DIALOG_STYLE)
+        self.decorations = []
+
+        self.temporal = temporal
+        self._layout()
+
+        self.OnFormatRadio(event = None)
+        wx.CallAfter(self._hideAll)
+
+    def _layout(self):
+        notebook = wx.Notebook(self, id = wx.ID_ANY)
+        mainSizer = wx.BoxSizer(wx.VERTICAL)
+
+        notebook.AddPage(page = self._createExportFormatPanel(notebook), text = _("Format"))
+        notebook.AddPage(page = self._createDecorationsPanel(notebook), text = _("Decorations"))
+        mainSizer.Add(item = notebook, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border = 5)
+
+
+        self.btnExport = wx.Button(self, wx.ID_OK)
+        self.btnExport.SetLabel(_("Export"))
+        self.btnCancel = wx.Button(self, wx.ID_CANCEL)
+        self.btnExport.SetDefault()
+
+        self.btnExport.Bind(wx.EVT_BUTTON, self.OnExport)
+
+        # button sizer
+        btnStdSizer = wx.StdDialogButtonSizer()
+        btnStdSizer.AddButton(self.btnExport)
+        btnStdSizer.AddButton(self.btnCancel)
+        btnStdSizer.Realize()
+        
+        mainSizer.Add(item = btnStdSizer, proportion = 0,
+                      flag = wx.EXPAND | wx.ALL | wx.ALIGN_RIGHT, border = 5)
+        self.SetSizer(mainSizer)
+
+        # set the longest option to fit
+        self.hidevbox.Show(self.fontBox, True)
+        self.hidevbox.Show(self.imageBox, False)
+        self.hidevbox.Show(self.textBox, True)
+        self.hidevbox.Show(self.posBox, True)
+        self.hidevbox.Show(self.informBox, False)
+        mainSizer.Fit(self)
+
+    def _createDecorationsPanel(self, notebook):
+        panel = wx.Panel(notebook, id = wx.ID_ANY)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        sizer.Add(self._createDecorationsList(panel), proportion = 0, flag = wx.ALL | wx.EXPAND, border = 10)
+        sizer.Add(self._createDecorationsProperties(panel), proportion = 0, flag = wx.ALL | wx.EXPAND, border = 10)
+        panel.SetSizer(sizer)
+        sizer.Fit(panel)
+        return panel
+
+    def _createDecorationsList(self, panel):
+        gridBagSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+
+        gridBagSizer.AddGrowableCol(0)
+        
+        self.listbox = wx.ListBox(panel, id = wx.ID_ANY, choices = [], style = wx.LB_SINGLE|wx.LB_NEEDED_SB)
+        self.listbox.Bind(wx.EVT_LISTBOX, self.OnSelectionChanged)
+
+        gridBagSizer.Add(self.listbox, pos = (0, 0), span = (4, 1),
+                         flag = wx.ALIGN_CENTER_VERTICAL| wx.EXPAND, border = 0)
+
+        buttonNames = ['time', 'image', 'text']
+        buttonLabels = [_("Add time stamp"), _("Add image"), _("Add text")]
+        i = 0
+        for buttonName, buttonLabel in zip(buttonNames, buttonLabels):
+            if buttonName == 'time' and self.temporal == TemporalMode.NONTEMPORAL:
+                continue
+            btn = wx.Button(panel, id = wx.ID_ANY, name = buttonName, label = buttonLabel)
+            btn.Bind(wx.EVT_BUTTON, lambda evt, temp = buttonName: self.OnAddDecoration(evt, temp))
+            gridBagSizer.Add(btn, pos = (i ,1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+            i += 1
+        removeButton = wx.Button(panel, id = wx.ID_ANY, label = _("Remove"))
+        removeButton.Bind(wx.EVT_BUTTON, self.OnRemove)
+        gridBagSizer.Add(removeButton, pos = (i, 1), flag = wx.ALIGN_CENTER_VERTICAL|wx.EXPAND, border = 0)
+        
+        return gridBagSizer
+
+    def _createDecorationsProperties(self, panel):
+        self.hidevbox = wx.BoxSizer(wx.VERTICAL)
+        # inform label
+        self.informBox = wx.BoxSizer(wx.HORIZONTAL)
+        if self.temporal == TemporalMode.TEMPORAL:
+            label = _("Add time stamp, image or text decoration by one of the buttons above.")
+        else:
+            label = _("Add image or text decoration by one of the buttons above.")
+
+        label = wx.StaticText(panel, id = wx.ID_ANY, label = label)
+        label.Wrap(400)
+        self.informBox.Add(label, proportion = 1, flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border = 5)
+        self.hidevbox.Add(self.informBox, proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
+        
+        # font
+        self.fontBox = wx.BoxSizer(wx.HORIZONTAL)
+        self.fontBox.Add(wx.StaticText(panel, id = wx.ID_ANY, label = _("Font settings:")),
+                         proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border = 5)
+        self.sampleLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("Sample text"))
+        self.fontBox.Add(self.sampleLabel, proportion = 1,
+                         flag = wx.ALIGN_CENTER | wx.RIGHT | wx.LEFT, border = 5)
+        fontButton = wx.Button(panel, id = wx.ID_ANY, label = _("Set font"))
+        fontButton.Bind(wx.EVT_BUTTON, self.OnFont)
+        self.fontBox.Add(fontButton, proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL)
+        self.hidevbox.Add(self.fontBox, proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
+
+        # image
+        self.imageBox = wx.BoxSizer(wx.HORIZONTAL)
+        filetype, ltype = GetImageHandlers(wx.EmptyImage(10, 10))
+        self.browse = filebrowse.FileBrowseButton(parent = panel, id = wx.ID_ANY, fileMask = filetype,
+                                                  labelText = _("Image file:"),
+                                                  dialogTitle = _('Choose image file'),
+                                                  buttonText = _('Browse'),
+                                                  startDirectory = os.getcwd(), fileMode = wx.OPEN,
+                                                  changeCallback = self.OnSetImage)
+        self.imageBox.Add(self.browse, proportion = 1, flag = wx.EXPAND)
+        self.hidevbox.Add(self.imageBox, proportion = 0, flag = wx.EXPAND | wx.BOTTOM, border = 5)
+        # text
+        self.textBox = wx.BoxSizer(wx.HORIZONTAL)
+        self.textBox.Add(wx.StaticText(panel, id = wx.ID_ANY, label = _("Text:")),
+                         proportion = 0, flag = wx.ALIGN_CENTER_VERTICAL | wx.RIGHT, border = 5)
+        self.textCtrl = wx.TextCtrl(panel, id = wx.ID_ANY)
+        self.textCtrl.Bind(wx.EVT_TEXT, self.OnText)
+        self.textBox.Add(self.textCtrl, proportion = 1, flag = wx.EXPAND)
+        self.hidevbox.Add(self.textBox, proportion = 0, flag = wx.EXPAND)
+
+        self.posBox = self._positionWidget(panel)
+        self.hidevbox.Add(self.posBox, proportion = 0, flag = wx.EXPAND | wx.TOP, border = 5)
+        return self.hidevbox
+
+    def _positionWidget(self, panel):
+        grid = wx.GridBagSizer(vgap = 5, hgap = 5)
+        label = wx.StaticText(panel, id = wx.ID_ANY, label = _("Placement as percentage of"
+                              " screen coordinates (X: 0, Y: 0 is top left):"))
+        label.Wrap(400)
+        self.spinX = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 0, max = 100, initial = 10)
+        self.spinY = wx.SpinCtrl(panel, id = wx.ID_ANY, min = 0, max = 100, initial = 10)
+        self.spinX.Bind(wx.EVT_SPINCTRL,  lambda evt, temp = 'X': self.OnPosition(evt, temp))
+        self.spinY.Bind(wx.EVT_SPINCTRL,  lambda evt, temp = 'Y': self.OnPosition(evt, temp))
+        
+        grid.Add(label, pos = (0, 0), span = (1, 4), flag = wx.EXPAND)
+        grid.Add(wx.StaticText(panel, id = wx.ID_ANY, label = _("X:")), pos = (1, 0),
+                 flag = wx.ALIGN_CENTER_VERTICAL)
+        grid.Add(wx.StaticText(panel, id = wx.ID_ANY, label = _("Y:")), pos = (1, 2),
+                 flag = wx.ALIGN_CENTER_VERTICAL)
+        grid.Add(self.spinX, pos = (1, 1))
+        grid.Add(self.spinY, pos = (1, 3))
+
+        return grid
+
+    def _createExportFormatPanel(self, notebook):
+        panel = wx.Panel(notebook, id = wx.ID_ANY)
+        borderSizer = wx.BoxSizer(wx.VERTICAL)
+        sizer = wx.BoxSizer(wx.VERTICAL)
+        self.gifRadio = wx.RadioButton(panel, id = wx.ID_ANY, 
+                                       label = _("Export to animated GIF (not supported yet):"),
+                                       style = wx.RB_GROUP)
+
+        self.dirRadio = wx.RadioButton(panel, id = wx.ID_ANY, label = _("Export as image sequence:"))
+        self.dirRadio.SetValue(True)
+        self.gifRadio.Bind(wx.EVT_RADIOBUTTON, self.OnFormatRadio)
+        self.dirRadio.Bind(wx.EVT_RADIOBUTTON, self.OnFormatRadio)
+
+        prefixLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("File prefix:"))
+        self.prefixCtrl = wx.TextCtrl(panel, id = wx.ID_ANY, value = _("animation"))
+        
+        formatLabel = wx.StaticText(panel, id = wx.ID_ANY, label = _("File format:"))
+        self.formatChoice = wx.Choice(panel, id = wx.ID_ANY)
+        wildcard, ltype = GetImageHandlers(wx.EmptyImage(10, 10))
+        formats = [format for format in wildcard.split('|') if 'file' in format]
+        for format, cdata in zip(formats, ltype):
+            self.formatChoice.Append(format, cdata)
+
+        self.formatChoice.SetSelection(0)
+        
+        self.dirBrowse = filebrowse.DirBrowseButton(parent = panel, id = wx.ID_ANY,
+                                                    labelText = _("Export directory:"),
+                                                     dialogTitle = _("Choose directory for export"),
+                                                     buttonText = _("Browse"),
+                                                     startDirectory = os.getcwd())
+        self.gifBrowse = filebrowse.FileBrowseButton(parent = panel, id = wx.ID_ANY,
+                                                     fileMask = "GIF file (*.gif)|*.gif",
+                                                     labelText = _("GIF file:"),
+                                                     dialogTitle = _("Choose image file"),
+                                                     buttonText = _("Browse"),
+                                                     startDirectory = os.getcwd(), fileMode = wx.SAVE)
+
+        sizer.Add(self.gifRadio, proportion = 0, flag = wx.EXPAND)
+        gifSizer = wx.BoxSizer(wx.HORIZONTAL)
+        gifSizer.AddStretchSpacer(prop = 1)
+        gifSizer.Add(self.gifBrowse, proportion = 6, flag = wx.EXPAND)
+        sizer.Add(gifSizer, proportion = 0, flag = wx.EXPAND)
+
+        sizer.Add(self.dirRadio, proportion = 0, flag = wx.EXPAND)
+
+        dirSizer = wx.BoxSizer(wx.HORIZONTAL)
+        dirSizer.AddStretchSpacer(prop = 1)
+        self.dirGridSizer = wx.GridBagSizer(hgap = 5, vgap = 5)
+        self.dirGridSizer.AddGrowableCol(1)
+        self.dirGridSizer.Add(prefixLabel, pos = (0, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        self.dirGridSizer.Add(self.prefixCtrl, pos = (0, 1), flag = wx.EXPAND)
+        self.dirGridSizer.Add(formatLabel, pos = (1, 0), flag = wx.ALIGN_CENTER_VERTICAL)
+        self.dirGridSizer.Add(self.formatChoice, pos = (1, 1), flag = wx.EXPAND)
+        self.dirGridSizer.Add(self.dirBrowse, pos = (2, 0), flag = wx.EXPAND, span = (1, 2))
+        dirSizer.Add(self.dirGridSizer, proportion = 6, flag = wx.EXPAND)
+
+        sizer.Add(dirSizer, proportion = 0, flag = wx.EXPAND)
+        borderSizer.Add(sizer, proportion = 0, flag = wx.EXPAND | wx.ALL, border = 10)
+        panel.SetSizer(borderSizer)
+        borderSizer.Fit(panel)
+
+        return panel
+
+    def OnFormatRadio(self, event):
+        self.gifBrowse.Enable(self.gifRadio.GetValue())
+        for child in self.dirGridSizer.GetChildren():
+            child.GetWindow().Enable(self.dirRadio.GetValue())
+
+    def OnFont(self, event):
+        index = self.listbox.GetSelection()
+        # should not happen
+        if index == wx.NOT_FOUND:
+            return
+        cdata = self.listbox.GetClientData(index)
+        font = cdata['font']
+        
+        fontdata = wx.FontData()
+        fontdata.EnableEffects(True)
+        fontdata.SetColour('black')
+        fontdata.SetInitialFont(font)
+        
+        dlg = wx.FontDialog(self, fontdata)
+        
+        if dlg.ShowModal() == wx.ID_OK:
+            newfontdata = dlg.GetFontData()
+            font = newfontdata.GetChosenFont()
+            self.sampleLabel.SetFont(font)
+            cdata['font'] = font
+            self.Layout()
+
+
+    def OnPosition(self, event, coord):
+        index = self.listbox.GetSelection()
+        # should not happen
+        if index == wx.NOT_FOUND:
+            return
+        cdata = self.listbox.GetClientData(index)
+        cdata['pos'][coord == 'Y'] = event.GetInt()
+
+    def OnSetImage(self, event):
+        index = self.listbox.GetSelection()
+        # should not happen
+        if index == wx.NOT_FOUND:
+            return
+        cdata = self.listbox.GetClientData(index)
+        cdata['file'] = event.GetString()
+
+    def OnAddDecoration(self, event, name):
+        if name == 'time':
+            timeInfo = {'name': name, 'font': self.GetFont(), 'pos': [10, 10]}
+            self.decorations.append(timeInfo)
+        elif name == 'image':
+            imageInfo = {'name': name, 'file': '', 'pos': [10, 10]}
+            self.decorations.append(imageInfo)
+        elif name == 'text':
+            textInfo = {'name': name, 'font': self.GetFont(), 'text': '', 'pos': [10, 10]}
+            self.decorations.append(textInfo)
+
+        self._updateListBox()
+        self.listbox.SetSelection(self.listbox.GetCount() - 1)
+        self.OnSelectionChanged(event = None)
+
+    def OnSelectionChanged(self, event):
+        index = self.listbox.GetSelection()
+        if index == wx.NOT_FOUND:
+            self._hideAll()
+            return
+        cdata = self.listbox.GetClientData(index)
+        self.hidevbox.Show(self.fontBox, (cdata['name'] in ('time', 'text')))
+        self.hidevbox.Show(self.imageBox, (cdata['name'] == 'image'))
+        self.hidevbox.Show(self.textBox, (cdata['name'] == 'text'))
+        self.hidevbox.Show(self.posBox, True)
+        self.hidevbox.Show(self.informBox, False)
+
+        self.spinX.SetValue(cdata['pos'][0])
+        self.spinY.SetValue(cdata['pos'][1])
+        if cdata['name'] == 'image':
+            self.browse.SetValue(cdata['file'])
+        elif cdata['name'] in ('time', 'text'):
+            self.sampleLabel.SetFont(cdata['font'])
+            if cdata['name'] == 'text':
+                self.textCtrl.SetValue(cdata['text'])
+
+        self.hidevbox.Layout()
+        # self.Layout()
+
+    def OnText(self, event):
+        index = self.listbox.GetSelection()
+        # should not happen
+        if index == wx.NOT_FOUND:
+            return
+        cdata = self.listbox.GetClientData(index)
+        cdata['text'] = event.GetString()
+
+    def OnRemove(self, event):
+        index = self.listbox.GetSelection()
+        if index == wx.NOT_FOUND:
+            return
+
+        decData = self.listbox.GetClientData(index)
+        self.decorations.remove(decData)
+        
+        self._updateListBox()
+        if self.listbox.GetCount():
+            self.listbox.SetSelection(0)
+            self.OnSelectionChanged(event = None)
+
+    def OnExport(self, event):
+        for decor in self.decorations:
+            if decor['name'] == 'image':
+                if not os.path.exists(decor['file']):
+                    if decor['file']:
+                        GError(parent = self, message = _("File %s not found.") % decor['file'])
+                    else:
+                        GError(parent = self, message = _("Decoration image file is missing."))
+                    return
+
+        if self.dirRadio.GetValue():
+            name = self.dirBrowse.GetValue()
+            if not os.path.exists(name):
+                if name:
+                    GError(parent = self, message = _("Directory %s not found.") % name)
+                else:
+                    GError(parent = self, message = _("Export directory is missing."))
+                return
+        elif self.gifRadio.GetValue():
+            if not self.gifBrowse.GetValue():
+                GError(parent = self, message = _("Export file is missing."))
+                return
+
+        self.EndModal(wx.ID_OK)
+           
+    def GetDecorations(self):
+        return self.decorations
+
+    def GetExportInformation(self):
+        info = {}
+        if self.gifRadio.GetValue():
+            info['method'] = 'gif'
+            info['file'] = self.gifBrowse.GetValue()
+        else:
+            info['method'] = 'sequence'
+            info['directory'] = self.dirBrowse.GetValue()
+            info['prefix'] = self.prefixCtrl.GetValue()
+            info['format'] = self.formatChoice.GetClientData(self.formatChoice.GetSelection())
+        return info
+
+    def _updateListBox(self):
+        self.listbox.Clear()
+        names = {'time': _("Time stamp"), 'image': _("Image"), 'text': _("Text")}
+        for decor in self.decorations:
+            self.listbox.Append(names[decor['name']], clientData = decor)
+
+    def _hideAll(self):
+        self.hidevbox.Show(self.fontBox, False)
+        self.hidevbox.Show(self.imageBox, False)
+        self.hidevbox.Show(self.textBox, False)
+        self.hidevbox.Show(self.posBox, False)
+        self.hidevbox.Show(self.informBox, True)
+        self.hidevbox.Layout()
+
 def test():
     import wx.lib.inspection
     import gettext
@@ -790,22 +1165,38 @@
     import grass.script as grass
 
     app = wx.PySimpleApp()
+
+    testExport()
+    # wx.lib.inspection.InspectionTool().Show()
+
+    
+
+    app.MainLoop()
+
+def testAnimInput():
     anim = AnimationData()
     anim.SetDefaultValues(animationIndex = 0, windowIndex = 0)
 
     dlg = InputDialog(parent = None, mode = 'add', animationData = anim)
-    # dlg = EditDialog(parent = None, animationData = [anim])
-    wx.lib.inspection.InspectionTool().Show()
+    dlg.Show()
 
+def testAnimEdit():
+    anim = AnimationData()
+    anim.SetDefaultValues(animationIndex = 0, windowIndex = 0)
+
+    dlg = EditDialog(parent = None, animationData = [anim])
     dlg.Show()
-    # if val == wx.ID_OK:
-    #     dlg.Update()
-    #     # print anim
-    
-    # dlg.Destroy()
-    print anim
-    app.MainLoop()
 
+def testExport():
+    dlg = ExportDialog(parent = None, temporal = TemporalMode.TEMPORAL)
+    if dlg.ShowModal() == wx.ID_OK:
+        print dlg.GetDecorations()
+        print dlg.GetExportInformation()
+        dlg.Destroy()
+    else:
+        dlg.Destroy()
+
+
 if __name__ == '__main__':
 
     test()
\ No newline at end of file

Modified: grass-addons/grass7/gui/wxpython/wx.animation/animation/frame.py
===================================================================
--- grass-addons/grass7/gui/wxpython/wx.animation/animation/frame.py	2012-10-29 17:52:19 UTC (rev 53610)
+++ grass-addons/grass7/gui/wxpython/wx.animation/animation/frame.py	2012-10-29 21:48:11 UTC (rev 53611)
@@ -64,7 +64,8 @@
                                               providers = self.providers,
                                               bitmapPool = bitmapPool)
         for win, provider in zip(self.windows, self.providers):
-            win.Bind(wx.EVT_SIZE, lambda event, prov = provider: prov.WindowSizeChanged(event))
+            win.Bind(wx.EVT_SIZE, lambda event, prov = provider,
+                     sizeMethod = win.GetClientSize: prov.WindowSizeChanged(event, sizeMethod))
 
         self.InitStatusbar()
         self._mgr = wx.aui.AuiManager(self)
@@ -228,6 +229,9 @@
     def Reload(self, event):
         self.controller.Reload()
 
+    def OnExportAnimation(self, event):
+        self.controller.Export()
+
     def OnHelp(self, event):
         RunCommand('g.manual',
                    quiet = True,
@@ -283,6 +287,8 @@
         return self.mainSizer.IsShown(self.windows[index])
 
 
+
+
 class AnimationSliderBase(wx.Panel):
     def __init__(self, parent):
         wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)

Modified: grass-addons/grass7/gui/wxpython/wx.animation/animation/mapwindow.py
===================================================================
--- grass-addons/grass7/gui/wxpython/wx.animation/animation/mapwindow.py	2012-10-29 17:52:19 UTC (rev 53610)
+++ grass-addons/grass7/gui/wxpython/wx.animation/animation/mapwindow.py	2012-10-29 21:48:11 UTC (rev 53611)
@@ -21,6 +21,7 @@
 
 import grass.script as grass
 from core.gcmd import RunCommand
+from utils import ComputeScaledRect
 
 class BufferedWindow(wx.Window):
     """
@@ -163,23 +164,10 @@
 
         cols = self.region['cols']
         rows = self.region['rows']
-        
-        ratioB = cols / float(rows)
-        ww, wh = self.GetClientSize()
-        try:
-            ratioW = ww / float(wh)
-        except ZeroDivisionError:
-            self.x = self.y = 0
-            self.size = (0, 0)
-            return
-        if ratioW > ratioB:
-            self.size = (wh * ratioB, wh)
-            self.y = 0
-            self.x = (ww - wh * ratioB) / 2
-        else:
-            self.size = (ww, ww / ratioB)
-            self.x = 0
-            self.y = (wh - ww / ratioB) / 2
+        params = ComputeScaledRect((cols, rows), self.GetClientSize())
+        self.x = params['x']
+        self.y = params['y']
+        self.size = (params['width'], params['height'])
 
     def SetRegion(self, region):
         """!Sets region for size computations.
@@ -188,6 +176,12 @@
         self.region = region
         self._computeBitmapCoordinates()
 
+    def GetAdjustedSize(self):
+        return self.size
+
+    def GetAdjustedPosition(self):
+        return self.x, self.y
+
 class BitmapProvider(object):
     """!Class responsible for loading data and providing bitmaps"""
     def __init__(self, frame, bitmapPool):
@@ -245,9 +239,10 @@
     def GetLoadSize(self):
         return self.loadSize
 
-    def WindowSizeChanged(self, event):
+    def WindowSizeChanged(self, event, sizeMethod):
         """!Sets size when size of related window changes."""
-        self.size = event.GetSize()
+        # sizeMethod is GetClientSize, must be used instead of GetSize
+        self.size = sizeMethod()
         event.Skip()
 
     def _createNoDataBitmap(self, ncols, nrows):
@@ -310,22 +305,10 @@
         """!Computes parameters for creating bitmaps."""
         region = grass.region()
         ncols, nrows = region['cols'], region['rows']
-        if nrows > ncols:
-            longdim = nrows
-            size = self.size[1]
-        else:
-            longdim = ncols
-            size = self.size[0]
-        scale = 1.0
+        params = ComputeScaledRect((ncols, nrows), self.size)
 
-        if longdim > size:
-            scale = float(size) / longdim
-        elif longdim < size:
-            scale = float(size) / longdim
-        size = (int(ncols * scale), int(nrows * scale))
+        return ((params['width'], params['height']), params['scale'])
 
-        return (size, scale)
-
     def _dryLoad(self, rasters, names, force):
         """!Tries how many bitmaps will be loaded.
         Used for progress dialog.
@@ -359,12 +342,15 @@
         region = grass.region()
         for key in ('rows', 'cols', 'cells'):
             region.pop(key)
+        # sometimes it renderes nonsense - depends on resolution
+        # should we set the resolution of the raster?
         region['nsres'] /= scale
         region['ewres'] /= scale
         os.environ['GRASS_REGION'] = grass.region_env(**region)
         ncols, nrows = size
         self.loadSize = size
         count = 0
+
         # create no data bitmap
         if None not in self.bitmapPool or force:
             self.bitmapPool[None] = self._createNoDataBitmap(ncols, nrows)

Modified: grass-addons/grass7/gui/wxpython/wx.animation/animation/toolbars.py
===================================================================
--- grass-addons/grass7/gui/wxpython/wx.animation/animation/toolbars.py	2012-10-29 17:52:19 UTC (rev 53610)
+++ grass-addons/grass7/gui/wxpython/wx.animation/animation/toolbars.py	2012-10-29 21:48:11 UTC (rev 53611)
@@ -35,6 +35,8 @@
                                  desc = _("Add new animation")),
         'editAnimation': MetaIcon(img = 'layer-more', label = _("Add, edit or remove animation"),
                                   desc = _("Add, edit or remove animation")),
+        'exportAnimation': MetaIcon(img = 'layer-export', label = _("Export animation"),
+                                    desc = _("Export animation"))
         }
 
 class MainToolbar(BaseToolbar):
@@ -60,7 +62,9 @@
                                      ("editAnimation", icons["editAnimation"],
                                       self.parent.OnEditAnimation),
                                      ("reload", BaseIcons["render"],
-                                      self.parent.Reload)
+                                      self.parent.Reload),
+                                     ("exportAnimation", icons["exportAnimation"],
+                                      self.parent.OnExportAnimation),
                                     ))
 class AnimationToolbar(BaseToolbar):
     """!Animation toolbar (to control animation)

Modified: grass-addons/grass7/gui/wxpython/wx.animation/animation/utils.py
===================================================================
--- grass-addons/grass7/gui/wxpython/wx.animation/animation/utils.py	2012-10-29 17:52:19 UTC (rev 53610)
+++ grass-addons/grass7/gui/wxpython/wx.animation/animation/utils.py	2012-10-29 21:48:11 UTC (rev 53611)
@@ -17,6 +17,7 @@
 
 @author Anna Kratochvilova <kratochanna gmail.com>
 """
+import wx
 import grass.temporal as tgis
 import grass.script as grass
 
@@ -84,3 +85,49 @@
             if not found:
                 raise GException(_("Map <%s> not found.") % name)
     return newNames
+
+def ComputeScaledRect(sourceSize, destSize):
+    """!Fits source rectangle into destination rectangle
+    by scaling and centering.
+
+    @code
+   
+    >>> ComputeScaledRect(sourceSize = (10, 40), destSize = (100, 50))
+    {'height': 50, 'scale': 1.25, 'width': 13, 'x': 44, 'y': 0}
+    
+    @endcode
+
+    @param sourceSize size of source rectangle
+    @param destSize size of destination rectangle
+    """
+    ratio1 = destSize[0] / float(sourceSize[0])
+    ratio2 = destSize[1] / float(sourceSize[1])
+    if ratio1 < ratio2:
+        scale = ratio1
+        width = int(sourceSize[0] * scale + 0.5)
+        height = int(sourceSize[1] * scale + 0.5)
+        x = 0
+        y = int((destSize[1] - height) / 2. + 0.5)
+    else:
+        scale = ratio2
+        width = int(sourceSize[0] * scale + 0.5)
+        height = int(sourceSize[1] * scale + 0.5)
+        y = 0
+        x = int((destSize[0] - width) / 2. + 0.5)
+
+    return {'width': width, 'height': height, 'x': x, 'y': y, 'scale': scale}
+
+def RenderText(text, font):
+    """!Renderes text with given font to bitmap."""
+    dc = wx.MemoryDC()
+    dc.SetFont(font)
+    w, h = dc.GetTextExtent(text)
+    bmp = wx.EmptyBitmap(w + 2, h + 2)
+    dc.SelectObject(bmp)
+    dc.SetBrush(wx.TRANSPARENT_BRUSH)
+    dc.SetBackgroundMode(wx.TRANSPARENT)
+    dc.Clear()
+    dc.DrawText(text, 1, 1)
+    dc.SelectObject(wx.NullBitmap)
+
+    return bmp



More information about the grass-commit mailing list