[GRASS-SVN] r57654 - sandbox/turek/scatter_plot

svn_grass at osgeo.org svn_grass at osgeo.org
Fri Sep 13 08:26:44 PDT 2013


Author: turek
Date: 2013-09-13 08:26:44 -0700 (Fri, 13 Sep 2013)
New Revision: 57654

Modified:
   sandbox/turek/scatter_plot/testing_patch.diff
Log:
scatter plot: integration into main gui

Modified: sandbox/turek/scatter_plot/testing_patch.diff
===================================================================
--- sandbox/turek/scatter_plot/testing_patch.diff	2013-09-13 15:24:57 UTC (rev 57653)
+++ sandbox/turek/scatter_plot/testing_patch.diff	2013-09-13 15:26:44 UTC (rev 57654)
@@ -1,6 +1,50 @@
+Index: include/defs/vedit.h
+===================================================================
+--- include/defs/vedit.h	(revision 57652)
++++ include/defs/vedit.h	(working copy)
+@@ -33,6 +33,8 @@
+ int Vedit_merge_lines(struct Map_info *, struct ilist *);
+ 
+ /* move.c */
++int Vedit_move_areas(struct Map_info *, struct Map_info **, int,
++		     		 struct ilist *, double, double, double, int, double);
+ int Vedit_move_lines(struct Map_info *, struct Map_info **, int,
+ 		     struct ilist *, double, double, double, int, double);
+ 
+Index: include/defs/imagery.h
+===================================================================
+--- include/defs/imagery.h	(revision 57652)
++++ include/defs/imagery.h	(working copy)
+@@ -110,6 +110,26 @@
+ FILE *I_fopen_subgroup_ref_new(const char *, const char *);
+ FILE *I_fopen_subgroup_ref_old(const char *, const char *);
+ 
++/* scatt_sccats.c */
++void I_sc_init_cats(struct scCats *, int, int);
++void I_sc_free_cats(struct scCats *);
++int I_sc_add_cat(struct scCats *);
++int I_sc_insert_scatt_data(struct scCats *, struct scdScattData *, int, int);
++
++void I_scd_init_scatt_data(struct scdScattData *, int, int, void *);
++
++/* scatt.c */
++int I_compute_scatts(struct Cell_head *, struct scCats *, const char **, 
++	                 const char **, int, struct scCats *, const char **);
++
++int I_create_cat_rast(struct Cell_head *, const char *);
++int I_insert_patch_to_cat_rast(const char *, struct Cell_head *,  const char *);
++
++int I_id_scatt_to_bands(const int, const int, int *, int *);
++int I_bands_to_id_scatt(const int, const int, const int, int *);
++int I_merge_arrays(unsigned char *, unsigned char *, unsigned, unsigned, double);
++int I_apply_colormap(unsigned char *, unsigned char *, unsigned,  unsigned char *, unsigned char *);
++
+ /* sig.c */
+ int I_init_signatures(struct Signature *, int);
+ int I_new_signature(struct Signature *);
 Index: include/imagery.h
 ===================================================================
---- include/imagery.h	(revision 57644)
+--- include/imagery.h	(revision 57652)
 +++ include/imagery.h	(working copy)
 @@ -135,6 +135,56 @@
      
@@ -59,57 +103,13 @@
  #define SIGNATURE_TYPE_MIXED 1
  
  #define GROUPFILE "CURGROUP"
-Index: include/defs/vedit.h
-===================================================================
---- include/defs/vedit.h	(revision 57644)
-+++ include/defs/vedit.h	(working copy)
-@@ -33,6 +33,8 @@
- int Vedit_merge_lines(struct Map_info *, struct ilist *);
- 
- /* move.c */
-+int Vedit_move_areas(struct Map_info *, struct Map_info **, int,
-+		     		 struct ilist *, double, double, double, int, double);
- int Vedit_move_lines(struct Map_info *, struct Map_info **, int,
- 		     struct ilist *, double, double, double, int, double);
- 
-Index: include/defs/imagery.h
-===================================================================
---- include/defs/imagery.h	(revision 57644)
-+++ include/defs/imagery.h	(working copy)
-@@ -110,6 +110,26 @@
- FILE *I_fopen_subgroup_ref_new(const char *, const char *);
- FILE *I_fopen_subgroup_ref_old(const char *, const char *);
- 
-+/* scatt_sccats.c */
-+void I_sc_init_cats(struct scCats *, int, int);
-+void I_sc_free_cats(struct scCats *);
-+int I_sc_add_cat(struct scCats *);
-+int I_sc_insert_scatt_data(struct scCats *, struct scdScattData *, int, int);
-+
-+void I_scd_init_scatt_data(struct scdScattData *, int, int, void *);
-+
-+/* scatt.c */
-+int I_compute_scatts(struct Cell_head *, struct scCats *, const char **, 
-+	                 const char **, int, struct scCats *, const char **);
-+
-+int I_create_cat_rast(struct Cell_head *, const char *);
-+int I_insert_patch_to_cat_rast(const char *, struct Cell_head *,  const char *);
-+
-+int I_id_scatt_to_bands(const int, const int, int *, int *);
-+int I_bands_to_id_scatt(const int, const int, const int, int *);
-+int I_merge_arrays(unsigned char *, unsigned char *, unsigned, unsigned, double);
-+int I_apply_colormap(unsigned char *, unsigned char *, unsigned,  unsigned char *, unsigned char *);
-+
- /* sig.c */
- int I_init_signatures(struct Signature *, int);
- int I_new_signature(struct Signature *);
 Index: gui/icons/grass/polygon.png
 ===================================================================
 Cannot display: file marked as a binary type.
 svn:mime-type = application/octet-stream
 Index: gui/icons/grass/polygon.png
 ===================================================================
---- gui/icons/grass/polygon.png	(revision 57644)
+--- gui/icons/grass/polygon.png	(revision 57652)
 +++ gui/icons/grass/polygon.png	(working copy)
 
 Property changes on: gui/icons/grass/polygon.png
@@ -118,1122 +118,6 @@
 ## -0,0 +1 ##
 +application/octet-stream
 \ No newline at end of property
-Index: gui/wxpython/vdigit/wxdigit.py
-===================================================================
---- gui/wxpython/vdigit/wxdigit.py	(revision 57644)
-+++ gui/wxpython/vdigit/wxdigit.py	(working copy)
-@@ -17,7 +17,7 @@
- (and NumPy would be an excellent candidate for acceleration via
- e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
- 
--(C) 2007-2011 by the GRASS Development Team
-+(C) 2007-2011, 2013 by the GRASS Development Team
- 
- This program is free software under the GNU General Public License
- (>=v2). Read the file COPYING that comes with GRASS for details.
-@@ -27,6 +27,8 @@
- 
- import grass.script.core as grass
- 
-+from grass.pydispatch.signal import Signal
-+
- from core.gcmd        import GError
- from core.debug       import Debug
- from core.settings    import UserSettings
-@@ -176,7 +178,21 @@
-         
-         if self.poMapInfo:
-             self.InitCats()
--        
-+
-+        self.emit_signals = False
-+
-+        # signals which describes features changes during digitization, 
-+        # activate them using EmitSignals method 
-+        #TODO signal for errors?
-+        self.featureAdded = Signal('IVDigit.featureAdded')
-+        self.areasDeleted = Signal('IVDigit.areasDeleted')
-+        self.vertexMoved = Signal('IVDigit.vertexMoved')
-+        self.vertexAdded = Signal('IVDigit.vertexAdded')
-+        self.vertexRemoved = Signal('IVDigit.vertexRemoved')
-+        self.featuresDeleted = Signal('IVDigit.featuresDeleted')
-+        self.featuresMoved = Signal('IVDigit.featuresMoved')
-+        self.lineEdited = Signal('IVDigit.lineEdited')
-+
-     def __del__(self):
-         Debug.msg(1, "IVDigit.__del__()")
-         Vect_destroy_line_struct(self.poPoints)
-@@ -188,7 +204,12 @@
-             Vect_close(self.poBgMapInfo)
-             self.poBgMapInfo = self.popoBgMapInfo = None
-             del self.bgMapInfo
--        
-+     
-+    def EmitSignals(self, emit):
-+        """!Activate/deactivate signals which describes features changes during digitization.
-+        """
-+        self.emit_signals = emit
-+
-     def CloseBackgroundMap(self):
-         """!Close background vector map"""
-         if not self.poBgMapInfo:
-@@ -394,7 +415,6 @@
-         
-         @return tuple (number of added features, feature ids)
-         """
--        
-         layer = self._getNewFeaturesLayer()
-         cat = self._getNewFeaturesCat()
-         
-@@ -419,10 +439,14 @@
-             return (-1, None)
-         
-         self.toolbar.EnableUndo()
--        
--        return self._addFeature(vtype, points, layer, cat,
--                                self._getSnapMode(), self._display.GetThreshold())
--    
-+
-+        ret = self._addFeature(vtype, points, layer, cat,
-+                               self._getSnapMode(), self._display.GetThreshold())
-+        if ret[0] > -1 and self.emit_signals:
-+            self.featureAdded.emit(new_bboxs = [self._createBbox(points)], new_areas_cats = [[{layer : [cat]}, None]])
-+
-+        return ret
-+
-     def DeleteSelectedLines(self):
-         """!Delete selected features
- 
-@@ -434,16 +458,27 @@
-         # collect categories for deleting if requested
-         deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
-         catDict = dict()
-+
-+        old_bboxs = []
-+        old_areas_cats = []
-         if deleteRec:
-             for i in self._display.selected['ids']:
-+                
-                 if Vect_read_line(self.poMapInfo, None, self.poCats, i) < 0:
-                     self._error.ReadLine(i)
-                 
--                cats = self.poCats.contents
--                for j in range(cats.n_cats):
--                    if cats.field[j] not in catDict.keys():
--                        catDict[cats.field[j]] = list()
--                    catDict[cats.field[j]].append(cats.cat[j])
-+                if self.emit_signals:
-+                    ret = self._getLineAreaBboxCats(i)
-+                    if ret:
-+                        old_bboxs += ret[0]
-+                        old_areas_cats += ret[1]
-+                
-+                # catDict was not used -> put into comment
-+                #cats = self.poCats.contents
-+                #for j in range(cats.n_cats):
-+                #    if cats.field[j] not in catDict.keys():
-+                #        catDict[cats.field[j]] = list()
-+                #    catDict[cats.field[j]].append(cats.cat[j])
-         
-         poList = self._display.GetSelectedIList()
-         nlines = Vedit_delete_lines(self.poMapInfo, poList)
-@@ -456,7 +491,10 @@
-                 self._deleteRecords(catDict)
-             self._addChangeset()
-             self.toolbar.EnableUndo()
--        
-+
-+            if self.emit_signals:
-+                self.featuresDeleted.emit(old_bboxs = old_bboxs, old_areas_cats = old_areas_cats)
-+
-         return nlines
-             
-     def _deleteRecords(self, cats):
-@@ -512,22 +550,173 @@
- 
-         @return number of deleted 
-         """
-+        if len(self._display.selected['ids']) < 1:
-+            return 0
-+        
-         poList = self._display.GetSelectedIList()
-         cList  = poList.contents
-         
-         nareas = 0
-+        old_bboxs = []
-+        old_areas_cats = []
-+
-         for i in range(cList.n_values):
-+
-             if Vect_get_line_type(self.poMapInfo, cList.value[i]) != GV_CENTROID:
-                 continue
--            
-+
-+            if self.emit_signals:
-+                area = Vect_get_centroid_area(self.poMapInfo, cList.value[i]);
-+                if area > 0: 
-+                    bbox, cats = self._getaAreaBboxCats(area)
-+                    old_bboxs += bbox
-+                    old_areas_cats += cats
-+
-             nareas += Vedit_delete_area_centroid(self.poMapInfo, cList.value[i])
-         
-         if nareas > 0:
-             self._addChangeset()
-             self.toolbar.EnableUndo()
-+            if self.emit_signals:
-+                self.areasDeleted.emit(old_bboxs = old_bboxs, old_areas_cats = old_areas_cats)        
-+
-+        return nareas
-+   
-+    def _getLineAreaBboxCats(self, ln_id):
-+        ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
-+
-+        if ltype == GV_CENTROID:
-+            #TODO centroid opttimization, can be adited also its area -> it will appear two times in new_ lists
-+            return self._getCentroidAreaBboxCats(ln_id)
-+        else: 
-+            return [self._getBbox(ln_id)], [self._getLineAreasCategories(ln_id)]
-+
-+
-+    def _getCentroidAreaBboxCats(self, centroid):
-+        if not Vect_line_alive(self.poMapInfo, centroid):
-+            return None
-+
-+        area = Vect_get_centroid_area(self.poMapInfo, centroid)  
-+        if area > 0:
-+            return self._getaAreaBboxCats(area)
-+        else:
-+            return None
-+
-+    def _getaAreaBboxCats(self, area):
-+
-+        po_b_list = Vect_new_list()
-+        Vect_get_area_boundaries(self.poMapInfo, area, po_b_list);
-+        b_list = po_b_list.contents
-+
-+        geoms = []
-+        areas_cats = []
-+
-+        if b_list.n_values > 0:
-+            for i_line in range(b_list.n_values):
-+
-+                line = b_list.value[i_line];
-+
-+                geoms.append(self._getBbox(abs(line)))
-+                areas_cats.append(self._getLineAreasCategories(abs(line)))
-         
--        return nareas
-+        Vect_destroy_list(po_b_list);
-+
-+        return geoms, areas_cats
-+
-+    def _getLineAreasCategories(self, ln_id):
-+        if not Vect_line_alive (self.poMapInfo, ln_id):
-+            return []
-+
-+        ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
-+        if ltype != GV_BOUNDARY:
-+            return []
-+
-+        cats = [None, None]
-+
-+        left = c_int()
-+        right = c_int()
-+
-+        if Vect_get_line_areas(self.poMapInfo, ln_id, pointer(left), pointer(right)) == 1:
-+            areas = [left.value, right.value]
-+
-+            for i, a in enumerate(areas):
-+                if a > 0: 
-+                    centroid = Vect_get_area_centroid(self.poMapInfo, a)
-+                    if centroid <= 0:
-+                        continue
-+                    c = self._getCategories(centroid)
-+                    if c:
-+                        cats[i] = c
-+
-+        return cats
-+
-+    def _getCategories(self, ln_id):
-+        if not Vect_line_alive (self.poMapInfo, ln_id):
-+            return none
-+
-+        poCats = Vect_new_cats_struct()
-+        if Vect_read_line(self.poMapInfo, None, poCats, ln_id) < 0:
-+            Vect_destroy_cats_struct(poCats)
-+            return None
-+
-+        cCats = poCats.contents
-+
-+        cats = {}
-+        for j in range(cCats.n_cats):
-+            if cats.has_key(cCats.field[j]):
-+                cats[cCats.field[j]].append(cCats.cat[j])
-+            else:
-+                cats[cCats.field[j]] = [cCats.cat[j]]
-     
-+        Vect_destroy_cats_struct(poCats)
-+        return cats
-+
-+    def _getBbox(self, ln_id):
-+        if not Vect_line_alive (self.poMapInfo, ln_id):
-+            return None
-+
-+        poPoints = Vect_new_line_struct()
-+        if Vect_read_line(self.poMapInfo, poPoints, None, ln_id) < 0:
-+            Vect_destroy_line_struct(poPoints)
-+            return []
-+
-+        geom = self._convertGeom(poPoints)
-+        bbox = self._createBbox(geom)
-+        Vect_destroy_line_struct(poPoints)
-+        return bbox
-+
-+    def _createBbox(self, points):
-+
-+        bbox = {}
-+        for pt in points:
-+            if not bbox.has_key('maxy'):
-+                bbox['maxy'] = pt[1]
-+                bbox['miny'] = pt[1]
-+                bbox['maxx'] = pt[0]
-+                bbox['minx'] = pt[0]
-+                continue
-+                
-+            if   bbox['maxy'] < pt[1]:
-+                bbox['maxy'] = pt[1]
-+            elif bbox['miny'] > pt[1]:
-+                bbox['miny'] = pt[1]
-+                
-+            if   bbox['maxx'] < pt[0]:
-+                bbox['maxx'] = pt[0]
-+            elif bbox['minx'] > pt[0]:
-+                bbox['minx'] = pt[0]
-+        return bbox
-+
-+    def _convertGeom(self, poPoints):
-+
-+        Points = poPoints.contents
-+
-+        pts_geom = []
-+        for j in range(Points.n_points):
-+            pts_geom.append((Points.x[j], Points.y[j]))
-+
-+        return pts_geom
-+
-     def MoveSelectedLines(self, move):
-         """!Move selected features
- 
-@@ -536,16 +725,45 @@
-         if not self._checkMap():
-             return -1
-         
-+        nsel = len(self._display.selected['ids'])
-+        if nsel < 1:
-+            return -1   
-+        
-         thresh = self._display.GetThreshold()
-         snap   = self._getSnapMode()
-         
-         poList = self._display.GetSelectedIList()
-+
-+        if self.emit_signals:
-+            old_bboxs = []
-+            old_areas_cats = []
-+            for sel_id in self._display.selected['ids']:
-+                ret = self._getLineAreaBboxCats(sel_id)
-+                if ret:
-+                    old_bboxs += ret[0]
-+                    old_areas_cats += ret[1]
-+        
-+            Vect_set_updated(self.poMapInfo, 1)
-+            n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
-+        
-         nlines = Vedit_move_lines(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
-                                   poList,
-                                   move[0], move[1], 0,
-                                   snap, thresh)
-+
-         Vect_destroy_list(poList)
--        
-+
-+        if nlines > 0 and self.emit_signals:
-+            new_bboxs = []
-+            new_areas_cats = []
-+            n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
-+            for i in range(n_up_lines_old, n_up_lines):
-+                new_id = Vect_get_updated_line(self.poMapInfo, i)
-+                ret = self._getLineAreaBboxCats(new_id)
-+                if ret:
-+                    new_bboxs += ret[0]
-+                    new_areas_cats += ret[1]
-+
-         if nlines > 0 and self._settings['breakLines']:
-             for i in range(1, nlines):
-                 self._breakLineAtIntersection(nlines + i, None, changeset)
-@@ -553,7 +771,13 @@
-         if nlines > 0:
-             self._addChangeset()
-             self.toolbar.EnableUndo()
--        
-+            
-+            if self.emit_signals:
-+                self.featuresMoved.emit(new_bboxs = new_bboxs,
-+                                        old_bboxs = old_bboxs, 
-+                                        old_areas_cats = old_areas_cats, 
-+                                        new_areas_cats = new_areas_cats)
-+
-         return nlines
- 
-     def MoveSelectedVertex(self, point, move):
-@@ -571,12 +795,21 @@
-         
-         if len(self._display.selected['ids']) != 1:
-             return -1
--        
-+
-+        # move only first found vertex in bbox 
-+        poList = self._display.GetSelectedIList()
-+
-+        if self.emit_signals:
-+            cList = poList.contents
-+            old_bboxs = [self._getBbox(cList.value[0])]
-+            old_areas_cats = [self._getLineAreasCategories(cList.value[0])]
-+
-+            Vect_set_updated(self.poMapInfo, 1)
-+            n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
-+
-         Vect_reset_line(self.poPoints)
-         Vect_append_point(self.poPoints, point[0], point[1], 0.0)
--        
--        # move only first found vertex in bbox 
--        poList = self._display.GetSelectedIList()
-+
-         moved = Vedit_move_vertex(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
-                                   poList, self.poPoints,
-                                   self._display.GetThreshold(type = 'selectThresh'),
-@@ -584,7 +817,17 @@
-                                   move[0], move[1], 0.0,
-                                   1, self._getSnapMode())
-         Vect_destroy_list(poList)
--        
-+
-+        if moved > 0 and self.emit_signals:
-+            n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
-+
-+            new_bboxs = []
-+            new_areas_cats = []
-+            for i in range(n_up_lines_old, n_up_lines):
-+                new_id = Vect_get_updated_line(self.poMapInfo, i)
-+                new_bboxs.append(self._getBbox(new_id))
-+                new_areas_cats.append(self._getLineAreasCategories(new_id))
-+
-         if moved > 0 and self._settings['breakLines']:
-             self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
-                                           None)
-@@ -592,7 +835,13 @@
-         if moved > 0:
-             self._addChangeset()
-             self.toolbar.EnableUndo()
--        
-+
-+            if self.emit_signals:
-+                self.vertexMoved.emit(new_bboxs = new_bboxs,  
-+                                      new_areas_cats = new_areas_cats, 
-+                                      old_areas_cats = old_areas_cats, 
-+                                      old_bboxs = old_bboxs)
-+
-         return moved
- 
-     def AddVertex(self, coords):
-@@ -681,6 +930,10 @@
-             self._error.ReadLine(line)
-             return -1
-         
-+        if self.emit_signals:
-+            old_bboxs = [self._getBbox(line)]
-+            old_areas_cats = [self._getLineAreasCategories(line)]
-+
-         # build feature geometry
-         Vect_reset_line(self.poPoints)
-         for p in coords:
-@@ -696,6 +949,9 @@
-         
-         newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
-                                     self.poPoints, self.poCats)
-+        if newline > 0 and self.emit_signals:
-+            new_geom = [self._getBbox(newline)]
-+            new_areas_cats = [self._getLineAreasCategories(newline)]
-         
-         if newline > 0 and self._settings['breakLines']:
-             self._breakLineAtIntersection(newline, None)
-@@ -703,7 +959,13 @@
-         if newline > 0:
-             self._addChangeset()
-             self.toolbar.EnableUndo()
--        
-+    
-+            if self.emit_signals:
-+                self.lineEdited.emit(old_bboxs = old_bboxs, 
-+                                     old_areas_cats = old_areas_cats, 
-+                                     new_bboxs = new_bboxs, 
-+                                     new_areas_cats = new_areas_cats)
-+
-         return newline
- 
-     def FlipLine(self):
-@@ -1514,6 +1776,16 @@
-             return 0
-         
-         poList  = self._display.GetSelectedIList()
-+
-+        if self.emit_signals:
-+            cList = poList.contents
-+            
-+            old_bboxs = [self._getBbox(cList.value[0])]
-+            old_areas_cats = [self._getLineAreasCategories(cList.value[0])]
-+
-+            Vect_set_updated(self.poMapInfo, 1)
-+            n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
-+
-         Vect_reset_line(self.poPoints)
-         Vect_append_point(self.poPoints, coords[0], coords[1], 0.0)
-         
-@@ -1525,15 +1797,35 @@
-         else:
-             ret = Vedit_remove_vertex(self.poMapInfo, poList,
-                                       self.poPoints, thresh)
-+
-         Vect_destroy_list(poList)
-+
-+        if ret > 0 and self.emit_signals:
-+            new_bboxs = []
-+            new_areas_cats = []
-+
-+            n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
-+            for i in range(n_up_lines_old, n_up_lines):
-+                new_id = Vect_get_updated_line(self.poMapInfo, i)
-+                new_areas_cats.append(self._getLineAreasCategories(new_id))
-+                new_bboxs.append(self._getBbox(new_id))
-         
-         if not add and ret > 0 and self._settings['breakLines']:
-             self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
-                                           None)
--        
-+
-         if ret > 0:
-             self._addChangeset()
--                
-+
-+        if ret > 0 and self.emit_signals:
-+            if add:
-+                self.vertexAdded.emit(old_bboxs = old_bboxs, new_bboxs = new_bboxs)
-+            else:
-+                self.vertexRemoved.emit(old_bboxs = old_bboxs, 
-+                                        new_bboxs = new_bboxs,
-+                                        old_areas_cats = old_areas_cats,
-+                                        new_areas_cats = new_areas_cats)
-+
-         return 1
-     
-     def GetLineCats(self, line):
-Index: gui/wxpython/vdigit/toolbars.py
-===================================================================
---- gui/wxpython/vdigit/toolbars.py	(revision 57644)
-+++ gui/wxpython/vdigit/toolbars.py	(working copy)
-@@ -17,6 +17,7 @@
- import wx
- 
- from grass.script import core as grass
-+from grass.pydispatch.signal import Signal
- 
- from gui_core.toolbars  import BaseToolbar, BaseIcons
- from gui_core.dialogs   import CreateNewVector
-@@ -42,6 +43,8 @@
-         self.digit         = None
-         self._giface       = giface
-         
-+        self.editingStarted = Signal("VDigitToolbar.editingStarted")
-+
-         # currently selected map layer for editing (reference to MapLayer instance)
-         self.mapLayer = None
-         # list of vector layers from Layer Manager (only in the current mapset)
-@@ -860,6 +863,7 @@
-             alpha = int(opacity * 255)
-             self.digit.GetDisplay().UpdateSettings(alpha = alpha)
-         
-+        self.editingStarted.emit(vectMap = mapLayer.GetName(), digit = self.digit)
-         return True
- 
-     def StopEditing(self):
-Index: gui/wxpython/vnet/dialogs.py
-===================================================================
---- gui/wxpython/vnet/dialogs.py	(revision 57644)
-+++ gui/wxpython/vnet/dialogs.py	(working copy)
-@@ -1218,7 +1218,7 @@
-                       pos = (row, 1))
- 
-         row += 1
--        gridSizer.Add(item = self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
-+        gridSizer.Add(item=self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
- 
-         gridSizer.AddGrowableCol(1)
-         styleBoxSizer.Add(item = gridSizer, flag = wx.EXPAND)
-Index: gui/wxpython/vnet/toolbars.py
-===================================================================
---- gui/wxpython/vnet/toolbars.py	(revision 57644)
-+++ gui/wxpython/vnet/toolbars.py	(working copy)
-@@ -19,9 +19,9 @@
- 
- import wx
- 
--from icon              import MetaIcon
-+from icons.icon import MetaIcon
- from gui_core.toolbars import BaseToolbar, BaseIcons
--from core.gcmd         import RunCommand
-+from core.gcmd import RunCommand
- from core.utils import _
- 
- class PointListToolbar(BaseToolbar):
-Index: gui/wxpython/Makefile
-===================================================================
---- gui/wxpython/Makefile	(revision 57644)
-+++ gui/wxpython/Makefile	(working copy)
-@@ -13,7 +13,7 @@
- 	$(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
- 	gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
- 	mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* timeline/* vdigit/* \
--	vnet/*.py web_services/*.py wxplot/*.py) \
-+	vnet/*.py web_services/*.py wxplot/*.py scatt_plot/*.py) \
- 	gis_set.py gis_set_error.py wxgui.py README
- 
- DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) \
-@@ -21,8 +21,9 @@
- 
- PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
- 	gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
--	mapswipe vdigit wxplot web_services rlisetup vnet timeline)
-+	mapswipe vdigit wxplot web_services rlisetup vnet timeline scatt_plot)
- 
-+
- DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
- 
- default: $(DSTFILES)
-Index: gui/wxpython/mapdisp/toolbars.py
-===================================================================
---- gui/wxpython/mapdisp/toolbars.py	(revision 57644)
-+++ gui/wxpython/mapdisp/toolbars.py	(working copy)
-@@ -239,7 +239,8 @@
-                       (MapIcons["scatter"],     self.parent.OnScatterplot),
-                       (MapIcons["histogram"],   self.parent.OnHistogramPyPlot),
-                       (BaseIcons["histogramD"], self.parent.OnHistogram),
--                      (MapIcons["vnet"],        self.parent.OnVNet)))
-+                      (MapIcons["vnet"],        self.parent.OnVNet),
-+                      (MapIcons["scatter"],     self.parent.OnScatterplot2)))
-         
-     def OnDecoration(self, event):
-         """!Decorations overlay menu
-Index: gui/wxpython/mapdisp/frame.py
-===================================================================
---- gui/wxpython/mapdisp/frame.py	(revision 57644)
-+++ gui/wxpython/mapdisp/frame.py	(working copy)
-@@ -225,6 +225,7 @@
-         #
-         self.dialogs = {}
-         self.dialogs['attributes'] = None
-+        self.dialogs['scatt_plot'] = None
-         self.dialogs['category'] = None
-         self.dialogs['barscale'] = None
-         self.dialogs['legend'] = None
-@@ -1168,6 +1169,19 @@
-         """!Returns toolbar with zooming tools"""
-         return self.toolbars['map']
- 
-+    def OnScatterplot2(self, event):
-+        """!Init interactive scatterplot tools
-+        """
-+        if self.dialogs['scatt_plot']:
-+            self.dialogs['scatt_plot'].Raise()
-+            return
-+
-+        from scatt_plot.dialogs import ScattPlotMainDialog
-+        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface)
-+        
-+        self.dialogs['scatt_plot'].CenterOnScreen()
-+        self.dialogs['scatt_plot'].Show()
-+
-     def OnVNet(self, event):
-         """!Dialog for v.net* modules 
-         """
-Index: gui/wxpython/iclass/dialogs.py
-===================================================================
---- gui/wxpython/iclass/dialogs.py	(revision 57644)
-+++ gui/wxpython/iclass/dialogs.py	(working copy)
-@@ -333,13 +333,19 @@
-         toolbar.SetCategories(catNames = catNames, catIdx = cats)
-         if name in catNames:
-             toolbar.choice.SetStringSelection(name)
-+            cat = toolbar.GetSelectedCategoryIdx()
-         elif catNames:
-             toolbar.choice.SetSelection(0)
--            
-+            cat = toolbar.GetSelectedCategoryIdx()
-+        else:
-+            cat = None
-+
-         if toolbar.choice.IsEmpty():
-             toolbar.EnableControls(False)
-         else:
-             toolbar.EnableControls(True)
-+
-+        self.mapWindow.CategoryChanged(cat)
-         # don't forget to update maps, histo, ...
-         
-     def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
-Index: gui/wxpython/iclass/toolbars.py
-===================================================================
---- gui/wxpython/iclass/toolbars.py	(revision 57644)
-+++ gui/wxpython/iclass/toolbars.py	(working copy)
-@@ -46,9 +46,7 @@
-         'importAreas' : MetaIcon(img = 'layer-import',
-                             label = _('Import training areas from vector map')),
-         'addRgb' : MetaIcon(img = 'layer-rgb-add',
--                            label = _('Add RGB map layer')),
--        'scatt_plot'    : MetaIcon(img = 'layer-raster-analyze',
--                                   label = _('Open Scatter Plot Tool (EXPERIMENTAL GSoC 2013)')),
-+                            label = _('Add RGB map layer'))
-         }
-         
- class IClassMapToolbar(BaseToolbar):
-@@ -117,10 +115,7 @@
-                                      ("zoomBack", icons["zoomBack"],
-                                       self.parent.OnZoomBack),
-                                      ("zoomToMap", icons["zoomExtent"],
--                                      self.parent.OnZoomToMap),
--                                     (None, ),
--                                     ("scatt_plot", iClassIcons["scatt_plot"],
--                                      self.parent.OnScatterplot)
-+                                      self.parent.OnZoomToMap)
-                                     ))
- class IClassToolbar(BaseToolbar):
-     """!IClass toolbar
-@@ -156,7 +151,7 @@
-         """!Toolbar data"""
-         icons = iClassIcons
-         return self._getToolbarData((("selectGroup", icons['selectGroup'],
--                                      self.parent.OnAddBands),
-+                                      lambda event : self.parent.AddBands()),
-                                       (None, ),
-                                       ("classManager", icons['classManager'],
-                                       self.parent.OnCategoryManager),
-Index: gui/wxpython/iclass/frame.py
-===================================================================
---- gui/wxpython/iclass/frame.py	(revision 57644)
-+++ gui/wxpython/iclass/frame.py	(working copy)
-@@ -64,6 +64,8 @@
-                                IClassExportAreasDialog, IClassMapDialog
- from iclass.plots       import PlotPanel
- 
-+from grass.pydispatch.signal import Signal
-+
- class IClassMapFrame(DoubleMapFrame):
-     """! wxIClass main frame
-     
-@@ -114,6 +116,10 @@
-             lambda:
-             self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
-         self.SetSize(size)
-+
-+        self.groupSet = Signal("IClassMapFrame.groupSet")
-+        self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
-+
-         #
-         # Add toolbars
-         #
-@@ -177,7 +183,7 @@
-         self.dialogs['category']   = None
-         
-         # PyPlot init
--        self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
-+        self.plotPanel = PlotPanel(self, giface = self._giface, stats_data = self.stats_data)
-                                    
-         self._addPanes()
-         self._mgr.Update()
-@@ -237,7 +243,7 @@
-             return False
-         
-         return vectorName
--        
-+    
-     def RemoveTempVector(self):
-         """!Removes temporary vector map with training areas"""
-         ret = RunCommand(prog = 'g.remove',
-@@ -334,11 +340,12 @@
-             self._addPaneMapWindow(name = 'preview')
-             self._addPaneToolbar(name = 'iClassTrainingMapManager')
-             self._addPaneMapWindow(name = 'training')
--        
-+
-+        self._mgr.SetDockSizeConstraint(0.5, 0.5) 
-         self._mgr.AddPane(self.plotPanel, wx.aui.AuiPaneInfo().
-                   Name("plots").Caption(_("Plots")).
-                   Dockable(False).Floatable(False).CloseButton(False).
--                  Left().Layer(1).BestSize((400, -1)))
-+                  Left().Layer(1).BestSize((300, -1)))
-         
-     def _addPaneToolbar(self, name):
-         if name == 'iClassPreviewMapManager':
-@@ -477,21 +484,47 @@
-         
-         self.Render(self.GetFirstWindow())
-         
--    def OnAddBands(self, event):
-+    def AddBands(self):
-         """!Add imagery group"""
-         dlg = IClassGroupDialog(self, group = self.group)
--        if dlg.ShowModal() == wx.ID_OK:
--            self.SetGroup(dlg.GetGroup())
-+        
-+        while True:
-+            if dlg.ShowModal() == wx.ID_OK:
-+                if self.SetGroup(dlg.GetGroup()):
-+                    break
-+            else: 
-+                break
-+        
-         dlg.Destroy()
-         
-     def SetGroup(self, name):
-         """!Set imagery group"""
-         group = grass.find_file(name = name, element = 'group')
-         if group['name']:
-+            if not self.GroupData(group['name']):
-+                GError(_("No data found in group <%s>.\n" \
-+                         "Please create subgroup with same name as group and add the data there.") \
-+                           % name, parent = self)
-+                return False
-             self.group = group['name']
-+            self.groupSet.emit(group = group['name'])
-         else:
-             GError(_("Group <%s> not found") % name, parent = self)
--    
-+            return False
-+
-+        return True
-+
-+    def GroupData(self, group):
-+        res = RunCommand('i.group',
-+                         flags = 'g',
-+                         group = group, subgroup = group,
-+                         read = True).strip()
-+        bands = None
-+        if res.split('\n')[0]:
-+            bands = res.split('\n')
-+            
-+        return bands
-+
-     def OnImportAreas(self, event):
-         """!Import training areas"""
-         # check if we have any changes
-@@ -768,17 +801,20 @@
-         
-         Updates number of stddev, histograms, layer in preview display. 
-         """
--        stat = self.stats_data.GetStatistics(currentCat)
--        nstd = stat.nstd
--        self.toolbars['iClass'].UpdateStddev(nstd)
--        
--        self.plotPanel.UpdateCategory(currentCat)
--        self.plotPanel.OnPlotTypeSelected(None)
-+        if currentCat:
-+          stat = self.stats_data.GetStatistics(currentCat)
-+          nstd = stat.nstd
-+          self.toolbars['iClass'].UpdateStddev(nstd)
-+          
-+          self.plotPanel.UpdateCategory(currentCat)
-+          self.plotPanel.OnPlotTypeSelected(None)
-                                    
--        name = stat.rasterName
--        name = self.previewMapManager.GetAlias(name)
--        if name:
--            self.previewMapManager.SelectLayer(name)
-+          name = stat.rasterName
-+          name = self.previewMapManager.GetAlias(name)
-+          if name:
-+              self.previewMapManager.SelectLayer(name)
-+
-+        self.categoryChanged.emit(cat = currentCat)
-         
-     def DeleteAreas(self, cats):
-         """!Removes all training areas of given categories
-@@ -805,12 +841,12 @@
-     def UpdateRasterName(self, newName, cat):
-         """!Update alias of raster map when category name is changed"""
-         origName = self.stats_data.GetStatistics(cat).rasterName
--        self.previewMapManager.SetAlias(origName, newName)
-+        self.previewMapManager.SetAlias(origName, self._addSuffix(newName))
-         
-     def StddevChanged(self, cat, nstd):
-         """!Standard deviation multiplier changed, rerender map, histograms"""
-         stat = self.stats_data.GetStatistics(cat)
--        stat.nstd = nstd
-+        stat.SetStatistics({"nstd" : nstd})
-         
-         if not stat.IsReady():
-             return
-@@ -923,7 +959,7 @@
-                 
-                 self.ConvertToNull(name = stats.rasterName)
-                 self.previewMapManager.AddLayer(name = stats.rasterName,
--                                                alias = stats.name, resultsLayer = True)
-+                                                alias = self._addSuffix(stats.name), resultsLayer = True)
-                 # write statistics
-                 I_iclass_add_signature(self.signatures, statistics)
-                 
-@@ -936,7 +972,11 @@
-         
-         self.UpdateChangeState(changes = False)
-         return True
--        
-+
-+    def _addSuffix(self, name):
-+        suffix = _('results')
-+        return '_'.join((name, suffix))
-+
-     def OnSaveSigFile(self, event):
-         """!Asks for signature file name and saves it."""
-         if not self.group:
-@@ -1105,27 +1145,13 @@
-         self.GetFirstWindow().SetModePointer()
-         self.GetSecondWindow().SetModePointer()
- 
--    def OnScatterplot(self, event):
--        """!Init interactive scatterplot tools
--        """
--        if self.dialogs['scatt_plot']:
--            self.dialogs['scatt_plot'].Raise()
--            return
-+    def GetMapManagers(self):
-+      """!Get map managers of wxIClass 
- 
--        try:
--          from scatt_plot.dialogs import ScattPlotMainDialog
--        except:
--          GError(parent  = self, message = _("The Scatter Plot Tool is not installed."))
--          return
-+      @return trainingMapManager, previewMapManager 
-+      """
-+      return self.trainingMapManager, self.previewMapManager
- 
--        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
--
--        scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
--        scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().GetDigit())
--
--        self.dialogs['scatt_plot'].CenterOnScreen()
--        self.dialogs['scatt_plot'].Show()
--
- class MapManager:
-     """! Class for managing map renderer.
-     
-@@ -1168,7 +1194,6 @@
-         self.frame.Render(self.mapWindow)
-         
-         if alias is not None:
--            alias = self._addSuffix(alias)
-             self.layerName[alias] = name
-             name = alias
-         else:
-@@ -1225,7 +1250,11 @@
-                 self.toolbar.choice.SetSelection(0)
-         
-         self.frame.Render(self.mapWindow)
--        
-+    
-+    def Render(self):
-+        """@todo giface shoud be used instead of this method"""
-+        self.frame.Render(self.mapWindow)
-+
-     def RemoveLayer(self, name, idx):
-         """!Removes layer from Map and update toolbar"""
-         name = self.layerName[name]
-@@ -1281,11 +1310,7 @@
-     def _changeOpacity(self, layer, opacity):
-         self.map.ChangeOpacity(layer=layer, opacity=opacity)
-         self.frame.Render(self.mapWindow)
--        
--    def _addSuffix(self, name):
--        suffix = _('results')
--        return '_'.join((name, suffix))
--        
-+                
-     def GetAlias(self, name):
-         """!Returns alias for layer"""
-         name =  [k for k, v in self.layerName.iteritems() if v == name]
-@@ -1296,11 +1321,11 @@
-     def SetAlias(self, original, alias):
-         name = self.GetAlias(original)
-         if name:
--            self.layerName[self._addSuffix(alias)] = original
-+            self.layerName[alias] = original
-             del self.layerName[name]
-             idx = self.toolbar.choice.FindString(name)
-             if idx != wx.NOT_FOUND:
--                self.toolbar.choice.SetString(idx, self._addSuffix(alias))
-+                self.toolbar.choice.SetString(idx, alias)
- 
- def test():
-     import core.render as render
-Index: gui/wxpython/iclass/plots.py
-===================================================================
---- gui/wxpython/iclass/plots.py	(revision 57644)
-+++ gui/wxpython/iclass/plots.py	(working copy)
-@@ -19,6 +19,7 @@
- import wx.lib.plot as plot
- import wx.lib.scrolledpanel as scrolled
- from core.utils import _
-+from core.gcmd import GError
- 
- class PlotPanel(scrolled.ScrolledPanel):
-     """!Panel for drawing multiple plots.
-@@ -28,7 +29,7 @@
-     for each band and for one category. Coincidence plots show min max range
-     of classes for each band.
-     """
--    def __init__(self, parent, stats_data):
-+    def __init__(self, parent, giface, stats_data):
-         scrolled.ScrolledPanel.__init__(self, parent)
-         
-         self.SetupScrolling(scroll_x = False, scroll_y = True)
-@@ -38,26 +39,71 @@
-         self.stats_data = stats_data
-         self.currentCat = None
-         
-+        self._giface = giface
-+
-         self.mainSizer = wx.BoxSizer(wx.VERTICAL)
--        
-+
-         self._createControlPanel()
--        
-+        self._createPlotPanel()
-+        self._createScatterPlotPanel()
-+
-         self.SetSizer(self.mainSizer)
-         self.mainSizer.Fit(self)
-         self.Layout()
--        
-+
-+    def _createPlotPanel(self):
-+
-+        self.canvasPanel = wx.Panel(parent=self)
-+        self.mainSizer.Add(item = self.canvasPanel, proportion = 1, flag = wx.EXPAND, border = 0)
-+        self.canvasSizer = wx.BoxSizer(wx.VERTICAL)
-+        self.canvasPanel.SetSizer(self.canvasSizer)
-+
-     def _createControlPanel(self):
-         self.plotSwitch = wx.Choice(self, id = wx.ID_ANY,
-                                      choices = [_("Histograms"),
--                                                _("Coincident plots")])
-+                                                _("Coincident plots"),
-+                                                _("Scatter plots")])
-         self.mainSizer.Add(self.plotSwitch, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
-         self.plotSwitch.Bind(wx.EVT_CHOICE, self.OnPlotTypeSelected)
--        
-+    
-+    def _createScatterPlotPanel(self):
-+        """!Init interactive scatterplot tools
-+        """
-+        try:
-+            from scatt_plot.frame import IClassScatterPlotsPanel
-+            self.scatt_plot_panel = IClassScatterPlotsPanel(parent=self, 
-+                                                            giface=self._giface, 
-+                                                            iclass_mapwin = self.parent.GetFirstWindow())
-+            self.mainSizer.Add(self.scatt_plot_panel, proportion = 1, flag = wx.EXPAND, border = 0)
-+            self.scatt_plot_panel.Hide()
-+        except ImportError as e:#TODO
-+            self.scatt_error = _("Scatter plot functionality is disabled. Reason:\n" \
-+                                 "Unable to import packages needed for scatter plot.\n%s" % e)
-+            GError(self.scatt_error)
-+            self.scatt_plot_panel = None
-+
-     def OnPlotTypeSelected(self, event):
-         """!Plot type selected"""
-+
-+        if self.plotSwitch.GetSelection() in [0, 1]:
-+            self.SetupScrolling(scroll_x = False, scroll_y = True)
-+            if self.scatt_plot_panel:
-+                self.scatt_plot_panel.Hide()
-+            self.canvasPanel.Show()
-+            self.Layout()
-+
-+        elif self.plotSwitch.GetSelection() == 2:
-+            self.SetupScrolling(scroll_x = False, scroll_y = False)
-+            if self.scatt_plot_panel:
-+                self.scatt_plot_panel.Show()
-+            else:
-+                GError(self.scatt_error)
-+            self.canvasPanel.Hide()
-+            self.Layout()
-+
-         if self.currentCat is None:
-             return
--        
-+
-         if self.plotSwitch.GetSelection() == 0:
-             stat = self.stats_data.GetStatistics(self.currentCat)
-             if not stat.IsReady():
-@@ -66,7 +112,10 @@
-             self.DrawHistograms(stat)
-         else:
-             self.DrawCoincidencePlots()
--            
-+
-+        self.Layout()
-+
-+
-     def StddevChanged(self):
-         """!Standard deviation multiplier changed, redraw histograms"""
-         if self.plotSwitch.GetSelection() == 0:
-@@ -89,7 +138,7 @@
-             panel.Destroy()
-             
-         self.canvasList = []
--            
-+
-     def ClearPlots(self):
-         """!Clears plot canvases"""
-         for bandIdx in range(len(self.bandList)):
-@@ -104,15 +153,15 @@
-     def CreatePlotCanvases(self):
-         """!Create plot canvases according to the number of bands"""
-         for band in self.bandList:
--            canvas = plot.PlotCanvas(self)
-+            canvas = plot.PlotCanvas(self.canvasPanel)
-             canvas.SetMinSize((-1, 140))
-             canvas.SetFontSizeTitle(10)
-             canvas.SetFontSizeAxis(8)
-             self.canvasList.append(canvas)
-             
--            self.mainSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
--
--        self.SetVirtualSize(self.GetBestVirtualSize()) 
-+            self.canvasSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
-+        
-+        self.SetVirtualSize(self.GetBestVirtualSize())
-         self.Layout()
-         
-     def UpdatePlots(self, group, currentCat, stats_data):
-@@ -138,7 +187,7 @@
-         
-     def UpdateCategory(self, cat):
-         self.currentCat = cat
--        
-+    
-     def DrawCoincidencePlots(self):
-         """!Draw coincidence plots"""
-         for bandIdx in range(len(self.bandList)):
 Index: gui/wxpython/scatt_plot/core_c.py
 ===================================================================
 --- gui/wxpython/scatt_plot/core_c.py	(revision 0)
@@ -1446,7 +330,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/frame.py	(revision 0)
 +++ gui/wxpython/scatt_plot/frame.py	(working copy)
-@@ -0,0 +1,636 @@
+@@ -0,0 +1,714 @@
 +"""!
 + at package scatt_plot.dialogs
 +
@@ -1475,7 +359,7 @@
 +from gui_core.dialogs import SetOpacityDialog
 +
 +from scatt_plot.controllers import ScattsManager
-+from scatt_plot.toolbars import MainToolbar, EditingToolbar
++from scatt_plot.toolbars import MainToolbar, EditingToolbar, CategoryToolbar
 +from scatt_plot.scatt_core import idScattToidBands
 +from scatt_plot.plots import ScatterPlotWidget
 +from vnet.dialogs import VnetStatusbar
@@ -1485,42 +369,44 @@
 +except ImportError:
 +    import wx.lib.agw.aui as aui
 +
-+class IClassScatterPlotsPanel(wx.Panel):
++
++class IClassIScattPanel(wx.Panel):
 +    def __init__(self, parent, giface, iclass_mapwin = None,
 +                 id = wx.ID_ANY, style = wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
 +
 +        #wx.SplitterWindow.__init__(self, parent = parent, id = id,
 +        #                           style = wx.SP_LIVE_UPDATE)
-+        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY)
++        wx.Panel.__init__(self, parent = parent, id = wx.ID_ANY, **kwargs)
 +
-+        #self.head_panel = wx.Panel(parent = self, id = wx.ID_ANY)
-+        self.scatt_mgr = ScattsManager(guiparent = self, giface = giface, iclass_mapwin = iclass_mapwin)
++        self.scatt_mgr = self._createScattMgr(guiparent=parent, giface=giface, 
++                                              iclass_mapwin=iclass_mapwin)
 +
 +        # toobars
 +        self.toolbars = {}
-+        self.toolbars['mainToolbar'] = MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
++        self.toolbars['mainToolbar'] = self._createMainToolbar()
 +        self.toolbars['editingToolbar'] = EditingToolbar(parent = self, scatt_mgr = self.scatt_mgr)
 +        
 +        self._createCategoryPanel(self)
 +
-+        self.plot_panel = IClassPlotPanel(self, self.scatt_mgr)
++        self.plot_panel = ScatterPlotsPanel(self, self.scatt_mgr)
 +
 +        # statusbar
 +        self.stPriors = {'high' : 5, 'info' : 1}
 +        self.stBar = VnetStatusbar(parent = self, style = 0)
 +        self.stBar.SetFieldsCount(number = 1)
 +
-+        mainsizer = wx.BoxSizer(wx.VERTICAL)
-+        mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
-+        mainsizer.Add(item = self.toolbars['editingToolbar'], proportion = 0, flag = wx.EXPAND)
-+        mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
-+        mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
-+        mainsizer.Add(item = self.stBar, proportion = 0)
++        self.mainsizer = wx.BoxSizer(wx.VERTICAL)
++        self.mainsizer.Add(item = self.toolbars['mainToolbar'], proportion = 0, flag = wx.EXPAND)
++        self.mainsizer.Add(item = self.toolbars['editingToolbar'], proportion = 0, flag = wx.EXPAND)
++        self.mainsizer.Add(item = self.catsPanel, proportion = 0, flag = wx.EXPAND | wx.LEFT | wx.RIGHT , border = 5)
++        self.mainsizer.Add(item = self.plot_panel, proportion = 1, flag = wx.EXPAND)
 +
++        self.mainsizer.Add(item = self.stBar, proportion = 0)
++
 +        self.catsPanel.Hide()
 +        self.toolbars['editingToolbar'].Hide()
 +
-+        self.SetSizer(mainsizer)
++        self.SetSizer(self.mainsizer)
 +        
 +        self.scatt_mgr.cursorPlotMove.connect(self.CursorPlotMove)
 +        self.scatt_mgr.renderingStarted.connect(lambda : self.stBar.AddStatusItem(text=_("Rendering..."), 
@@ -1536,15 +422,22 @@
 +        #self.SplitHorizontally(self.head_panel, self.plot_panel, -50)
 +        self.Layout()
 +
++    def _selCatInIScatt(self):
++         return False
++
++    def _createMainToolbar(self):
++         return MainToolbar(parent = self, scatt_mgr = self.scatt_mgr)
++
++    def _createScattMgr(self, guiparent, giface, iclass_mapwin):
++        return ScattsManager(guiparent=self, giface=giface, iclass_mapwin=iclass_mapwin)
++
 +    def CursorPlotMove(self, x, y):
-+
 +        x = int(round(x))
 +        y = int(round(y))
 +        self.stBar.AddStatusItem(text="%d; %d" % (x, y), 
 +                                 key='coords', 
 +                                 priority=self.stPriors['info'])
 +
-+
 +    def NewScatterPlot(self, scatt_id, transpose):
 +        return self.plot_panel.NewScatterPlot(scatt_id, transpose)
 +
@@ -1563,21 +456,73 @@
 +        self.Layout()
 +
 +    def _createCategoryPanel(self, parent):
-+        self.catsPanel = wx.Panel(parent = parent)
-+        self.cats_list = CategoryListCtrl(parent = self.catsPanel, 
-+                                          cats_mgr = self.scatt_mgr.GetCategoriesManager())
++        self.catsPanel = wx.Panel(parent=parent)
++        self.cats_list = CategoryListCtrl(parent=self.catsPanel, 
++                                          cats_mgr=self.scatt_mgr.GetCategoriesManager(),
++                                          sel_cats_in_iscatt=self._selCatInIScatt())
 +
 +        self.catsPanel.SetMaxSize((-1, 150))
 +
-+        box_capt = wx.StaticBox(parent = self.catsPanel, id = wx.ID_ANY,
-+                             label = ' %s ' % _("Classes manager for scatter plots"))
++        box_capt = wx.StaticBox(parent=self.catsPanel, id=wx.ID_ANY,
++                             label=' %s ' % _("Classes manager for scatter plots"),)
 +        catsSizer = wx.StaticBoxSizer(box_capt, wx.VERTICAL)
 +
-+        catsSizer.Add(item = self.cats_list, proportion = 1, flag = wx.EXPAND | wx.ALL)
++        self.toolbars['categoryToolbar'] = self._createCategoryToolbar(self.catsPanel)
++
++        catsSizer.Add(item=self.cats_list, proportion=1,  flag=wx.EXPAND)
++        if self.toolbars['categoryToolbar']:
++            catsSizer.Add(item=self.toolbars['categoryToolbar'], proportion=0)
++
 +        self.catsPanel.SetSizer(catsSizer)
 +
++    def CleanUp(self):
++        pass
 +
-+class IClassPlotPanel(scrolled.ScrolledPanel):
++    def _createCategoryToolbar(self, parent):
++        return None
++
++class IScattDialog(wx.Dialog):
++    def __init__(self, parent, giface, title=_("GRASS GIS Interactive Scatter Plot Tool"),
++                 id=wx.ID_ANY, style=wx.DEFAULT_FRAME_STYLE, **kwargs):
++        wx.Dialog.__init__(self, parent, id, style=style, title = title, **kwargs)
++        self.SetIcon(wx.Icon(os.path.join(globalvar.ETCICONDIR, 'grass.ico'), wx.BITMAP_TYPE_ICO))
++
++        self.iscatt_panel = MapDispIScattPanel(self, giface)
++
++        mainsizer = wx.BoxSizer(wx.VERTICAL)
++        mainsizer.Add(item=self.iscatt_panel, proportion=1, flag=wx.EXPAND)
++
++        self.SetSizer(mainsizer)
++
++        self.Bind(wx.EVT_CLOSE, self.OnCloseWindow)
++
++        self.SetMinSize((300, 300))
++
++    def OnCloseWindow(self, event):
++        event.Skip()
++        #self.
++
++class MapDispIScattPanel(IClassIScattPanel):
++    def __init__(self, parent, giface,
++                 id=wx.ID_ANY, style=wx.DEFAULT_DIALOG_STYLE | wx.RESIZE_BORDER, **kwargs):
++        IClassIScattPanel.__init__(self, parent=parent, giface=giface,
++                                         id=id, style=style, **kwargs)
++
++    def _createCategoryToolbar(self, parent):
++        return CategoryToolbar(parent=parent,
++                               scatt_mgr=self.scatt_mgr, 
++                               cats_list=self.cats_list)
++
++    def _createScattMgr(self, guiparent, giface, iclass_mapwin):
++        return ScattsManager(guiparent = self, giface = giface)
++
++    def _createMainToolbar(self):
++         return MainToolbar(parent = self, scatt_mgr = self.scatt_mgr, opt_tools=['add_group'])
++
++    def _selCatInIScatt(self):
++         return True
++
++class ScatterPlotsPanel(scrolled.ScrolledPanel):
 +    def __init__(self, parent, scatt_mgr, id = wx.ID_ANY):
 +    
 +        scrolled.ScrolledPanel.__init__(self, parent)
@@ -1613,6 +558,8 @@
 +        self.scatt_i = 1
 +        self.scatt_id_scatt_i = {}
 +
++        self.Bind(wx.EVT_CLOSE, self.OnClose)
++
 +    def ScatterPlotClosed(self, scatt_id):
 +
 +        scatt_i = self.scatt_id_scatt_i[scatt_id]
@@ -1658,8 +605,10 @@
 +        self.Layout()
 +        self.SetupScrolling()
 +
-+    def OnCloseDialog(self, event):
++    def OnClose(self, event):
 +        """!Close dialog"""
++        #TODO
++        print "closed"
 +        self.scatt_mgr.CleanUp()
 +        self.Destroy()
 +
@@ -1722,12 +671,16 @@
 +                       listmix.ListCtrlAutoWidthMixin,
 +                       listmix.TextEditMixin):
 +
-+    def __init__(self, parent, cats_mgr, id = wx.ID_ANY):
++    def __init__(self, parent, cats_mgr, sel_cats_in_iscatt, id = wx.ID_ANY):
 +
 +        wx.ListCtrl.__init__(self, parent, id,
-+                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|wx.LC_VRULES)
++                             style = wx.LC_REPORT|wx.LC_VIRTUAL|wx.LC_HRULES|
++                                     wx.LC_VRULES|wx.LC_SINGLE_SEL)
 +        self.columns = ((_('Class name'), 'name'),
 +                        (_('Color'), 'color'))
++
++        self.sel_cats_in_iscatt = sel_cats_in_iscatt
++
 +        self.Populate(columns = self.columns)
 +        
 +        self.cats_mgr = cats_mgr
@@ -1807,7 +760,16 @@
 +            
 +        self.SetItemCount(len(self.cats_mgr.GetCategories()))
 +        
-+    def OnSel(self, event): 
++    def OnSel(self, event):
++        if self.sel_cats_in_iscatt:
++            indexList = self.GetSelectedIndices()
++            sel_cats = []
++            cats = self.cats_mgr.GetCategories()
++            for i in indexList:
++                sel_cats.append(cats[i])       
++
++            if sel_cats:
++                self.cats_mgr.SetSelectedCat(sel_cats[0])
 +        event.Skip()
 +
 +    def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
@@ -3052,7 +2014,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/controllers.py	(revision 0)
 +++ gui/wxpython/scatt_plot/controllers.py	(working copy)
-@@ -0,0 +1,815 @@
+@@ -0,0 +1,883 @@
 +"""!
 + at package scatt_plot.controllers
 +
@@ -3077,20 +2039,18 @@
 +import wx
 +
 +from core.gcmd import GException, GError, GMessage, RunCommand
-+
++from core.gconsole import EVT_CMD_DONE
++from core.settings import UserSettings
++from scatt_plot.gthreading import gThread
 +from scatt_plot.scatt_core import Core, idBandsToidScatt
++from scatt_plot.dialogs import AddScattPlotDialog, ExportCategoryRaster
++from iclass.dialogs import IClassGroupDialog 
 +
-+from scatt_plot.dialogs import AddScattPlotDialog, ExportCategoryRaster
-+from scatt_plot.gthreading import gThread
-+from core.gconsole import EVT_CMD_DONE
-+from core.settings import UserSettings
-+from grass.pydispatch.signal import Signal
 +import grass.script as grass
-+
 +from grass.pydispatch.signal import Signal
 +
 +class ScattsManager(wx.EvtHandler):
-+    def __init__(self, guiparent, giface, iclass_mapwin):
++    def __init__(self, guiparent, giface, iclass_mapwin = None):
 +        #TODO remove iclass parameter
 +
 +        wx.EvtHandler.__init__(self)
@@ -3114,8 +2074,6 @@
 +        self.thread = gThread(self);
 +        
 +        self.plots = {}
-+        self.added_cats_rasts = []
-+
 +        self.cats_to_update = []
 +
 +        self.plot_mode =  None
@@ -3131,11 +2089,11 @@
 +        self.computingStarted = Signal("ScattsManager.computingStarted")
 +
 +        if iclass_mapwin: 
-+            self.mapWin_conn = MapWinConnection(self, self.mapWin, self.core.CatRastUpdater())
++            self.digit_conn = IClassDigitConnection(self, self.mapWin, self.core.CatRastUpdater())
 +            self.iclass_conn = IClassConnection(self, iclass_mapwin.parent, self.cats_mgr)
 +        else:
-+            self.mapWin_conn = None
-+            self.iclass_conn = None
++            self.digit_conn = IMapWinDigitConnection()
++            self.iclass_conn = IMapDispConnection(scatt_mgr=self, cats_mgr=self.cats_mgr, giface=self.giface)
 +
 +        self.tasks_pids = {
 +                            'add_scatt' : [],
@@ -3237,7 +2195,11 @@
 +            self.cats_mgr.OnExportCatRastDone(event)
 +            return
 +
-+    def SetData(self, bands):
++
++    def SetData(self):
++        self.iclass_conn.SetData()
++
++    def SetBands(self, bands):
 +        self.CleanUp()
 +        self.data_set = False
 +        
@@ -3295,7 +2257,7 @@
 +        
 +        dlg.Destroy()
 +
-+        self.mapWin_conn.Update()
++        self.digit_conn.Update()
 +         
 +    def _addScattPlot(self, scatt_id, transpose):
 +        if self.plots.has_key(scatt_id):
@@ -3304,7 +2266,9 @@
 +
 +        self.tasks_pids['add_scatt'].append(self.thread.GetId())
 +        
-+        self.thread.Run(callable = self.core.AddScattPlot, scatt_id = scatt_id, userdata = {'transpose' : transpose})
++        self.thread.Run(callable = self.core.AddScattPlot,
++                        scatt_id = scatt_id, 
++                        userdata = {'transpose' : transpose})
 +
 +    def RenderScattPlts(self, scatt_ids = None):
 +        if len(self.tasks_pids['render']) > 1:
@@ -3455,52 +2419,12 @@
 +        cat_id = event.ret
 +
 +        self.RenderScattPlts()
-+
-+        cat_id = event.kwds["cat_id"]
-+        train_mgr, preview_mgr = self.iclass_conn.iclass_frame.GetMapManagers()
-+        
-+        if not cat_id in self.added_cats_rasts:
-+            cat_rast = self.core.GetCatRast(cat_id)
-+
-+            cat_name = self.cats_mgr.GetCategoryAttrs(cat_id)['name']
-+            self.UpdateCategoryRaster(cat_id, ['color'], render = False)
-+            train_mgr.AddLayer(cat_rast, alias = cat_name)
-+
-+            self.added_cats_rasts.append(cat_id)
-+        else: #TODO settings
-+            train_mgr.Render()
++        self.iclass_conn.RenderCatRast(cat_id)
 +            
-+    def UpdateCategoryRaster(self, cat_id, attrs, render = True):
-+
-+        cat_rast = self.core.GetCatRast(cat_id)
-+        if not grass.find_file(cat_rast, element = 'cell', mapset = '.')['file']:
-+            return
-+        cats_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
-+        train_mgr, preview_mgr = self.iclass_conn.iclass_frame.GetMapManagers()
-+
-+        if "color" in attrs:
-+            ret, err_msg = RunCommand('r.colors',
-+                                      map=cat_rast,
-+                                      rules="-",
-+                                      stdin="1 %s" % cats_attrs["color"],
-+                                      getErrorMsg=True)
-+
-+            if ret != 0:
-+                GError("r.colors failed\n%s" % err_msg)
-+            if render:
-+                train_mgr.Render()
-+
-+        if "name" in attrs:
-+            cat_rast = self.core.GetCatRast(cat_id)
-+
-+            train_mgr.SetAlias(original=cat_rast, alias=cats_attrs['name'])
-+            cats_attrs["name"]
-+
-+
 +    def DigitDataChanged(self, vectMap, digit):
 +        
-+        if self.mapWin_conn:
-+            self.mapWin_conn.DigitDataChanged(vectMap, digit)
++        if self.digit_conn:
++            self.digit_conn.DigitDataChanged(vectMap, digit)
 +            return 1
 +        else:
 +            return 0
@@ -3533,14 +2457,7 @@
 +        del self.cats_ids[:]
 +
 +        self.sel_cat_id = None  
-+    """
-+    def InitCoreCats(self):
-+        if self.scatt_mgr.data_set:
-+            for cat_id in self.cats_ids:
-+                self._addCategory(cat_id)
 +
-+        self.scatt_mgr.mapWin_conn.Update()
-+    """
 +    def ChangePosition(self, cat_id, new_pos):
 +        if new_pos >= len(self.cats_ids):
 +            return False
@@ -3580,7 +2497,7 @@
 +            #    return -1;
 +
 +        self.cats[cat_id] = {
-+                                'name' : _('Category %s' % cat_id ),
++                                'name' : _('Class %s' % cat_id ),
 +                                'color' : "0:0:0",
 +                                'opacity' : 1.0,
 +                                'show' : True,
@@ -3619,7 +2536,7 @@
 +            self.scatt_mgr.RenderScattPlts()
 +        
 +        if update_cat_rast:
-+            self.scatt_mgr.UpdateCategoryRaster(cat_id, update_cat_rast)
++            self.scatt_mgr.iclass_conn.UpdateCategoryRaster(cat_id, update_cat_rast)
 +
 +        self.setCategoryAttrs.emit(cat_id = cat_id, attrs_dict = attrs_dict)
 +
@@ -3688,7 +2605,11 @@
 +                      (event.userdata['name'], event.kwds['rast_name'], err))
 +
 +
-+class MapWinConnection:
++class IMapWinDigitConnection:
++    def Update(self):
++        pass
++
++class IClassDigitConnection:
 +    def __init__(self, scatt_mgr, mapWin, scatt_rast_updater):
 +        self.mapWin = mapWin
 +        self.vectMap = None
@@ -3701,15 +2622,6 @@
 +        #TODO
 +        self.mapWin.parent.toolbars["vdigit"].editingStarted.connect(self.DigitDataChanged)
 +
-+        #def ChangeMap(self, vectMap, layers_cats):
-+        #     self.vectMap = vectMap
-+        #     self.layers_cats = layers_cats
-+
-+        #ret, region, msg = RunCommand("v.to.rast",
-+        #                              flags = "gp",
-+        #                              getErrorMsg = True,
-+        #                              read = True)
-+
 +    def Update(self):
 +        self.thread.Run(callable=self.scatt_rast_updater.SynchWithMap)
 +
@@ -3746,7 +2658,6 @@
 +                        old_areas_cats = old_areas_cats,
 +                        new_areas_cats = [])
 +
-+
 +    def EditedFeature(self, new_bboxs, new_areas_cats, old_bboxs, old_areas_cats):
 +        if not self.scatt_mgr.data_set:
 +            return
@@ -3770,13 +2681,91 @@
 +
 +        self._connectSignals()
 +
++class IMapDispConnection:
++    def __init__(self, scatt_mgr, cats_mgr, giface):
++        self.scatt_mgr = scatt_mgr
++        self.cats_mgr = cats_mgr
++        self.set_group = None
++        self.giface = giface
++        self.added_cats_rasts = {}
 +
++    def SetData(self):
++        dlg = IClassGroupDialog(self.scatt_mgr.guiparent, group=self.set_group)
++        
++        bands = []
++        while True:
++            if dlg.ShowModal() == wx.ID_OK:
++                
++                bands = dlg.GetGroupBandsErr(parent=self.scatt_mgr.guiparent)
++                if bands:
++                    name = dlg.GetGroup()
++                    group = grass.find_file(name = name, element = 'group')
++                    self.set_group = group['name']
++                    break
++            else: 
++                break
++        
++        dlg.Destroy()
++        
++        if bands:
++            self.scatt_mgr.SetBands(bands)
++
++    def EmptyCategories(self):
++        pass
++
++    def SyncCats(self, cats_ids = None):
++        pass
++
++    def UpdateCategoryRaster(self, cat_id, attrs, render = True):
++
++        cat_rast = self.scatt_mgr.core.GetCatRast(cat_id)
++        if not grass.find_file(cat_rast, element = 'cell', mapset = '.')['file']:
++            return
++        cats_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
++
++        if "color" in attrs:
++            ret, err_msg = RunCommand('r.colors',
++                                      map=cat_rast,
++                                      rules="-",
++                                      stdin="1 %s" % cats_attrs["color"],
++                                      getErrorMsg=True)
++
++            if ret != 0:
++                GError("r.colors failed\n%s" % err_msg)
++            if render:
++                self.giface.updateMap.emit()
++
++        if "name" in attrs:
++            #TODO hack
++            self.giface.GetLayerList()._tree.SetItemText(self.added_cats_rasts[cat_id], 
++                                                         cats_attrs['name'])
++            cats_attrs["name"]
++
++    def RenderCatRast(self, cat_id):
++
++        if not cat_id in self.added_cats_rasts.iterkeys():
++            cat_rast = self.scatt_mgr.core.GetCatRast(cat_id)
++
++            cat_name = self.cats_mgr.GetCategoryAttrs(cat_id)['name']
++            self.UpdateCategoryRaster(cat_id, ['color'], render = False)
++
++            cmd = ['d.rast', 'map=%s' % cat_rast]
++            #HACK
++            layer = self.giface.GetLayerList()._tree.AddLayer(ltype="raster",
++                                                         lname=cat_name,
++                                                         lcmd=cmd,
++                                                         lchecked=True)
++            self.added_cats_rasts[cat_id] = layer
++        else: #TODO settings
++            self.giface.updateMap.emit()
++
 +class IClassConnection:
 +    def __init__(self, scatt_mgr, iclass_frame, cats_mgr):
 +        self.iclass_frame = iclass_frame
 +        self.stats_data = self.iclass_frame.stats_data
 +        self.cats_mgr = cats_mgr
 +        self.scatt_mgr= scatt_mgr
++        self.added_cats_rasts = []
 +
 +        self.stats_data.statisticsAdded.connect(self.AddCategory)
 +        self.stats_data.statisticsDeleted.connect(self.DeleteCategory)
@@ -3793,6 +2782,46 @@
 +
 +        self.SyncCats()
 +
++    def UpdateCategoryRaster(self, cat_id, attrs, render = True):
++
++        cat_rast = self.scatt_mgr.core.GetCatRast(cat_id)
++        if not grass.find_file(cat_rast, element = 'cell', mapset = '.')['file']:
++            return
++        cats_attrs = self.cats_mgr.GetCategoryAttrs(cat_id)
++        train_mgr, preview_mgr = self.iclass_frame.GetMapManagers()
++
++        if "color" in attrs:
++            ret, err_msg = RunCommand('r.colors',
++                                      map=cat_rast,
++                                      rules="-",
++                                      stdin="1 %s" % cats_attrs["color"],
++                                      getErrorMsg=True)
++
++            if ret != 0:
++                GError("r.colors failed\n%s" % err_msg)
++            if render:
++                train_mgr.Render()
++
++        if "name" in attrs:
++            cat_rast = self.scatt_mgr.core.GetCatRast(cat_id)
++
++            train_mgr.SetAlias(original=cat_rast, alias=cats_attrs['name'])
++            cats_attrs["name"]
++
++    def RenderCatRast(self, cat_id):
++
++        train_mgr, preview_mgr = self.iclass_frame.GetMapManagers()
++        if not cat_id in self.added_cats_rasts:
++            cat_rast = self.scatt_mgr.core.GetCatRast(cat_id)
++
++            cat_name = self.cats_mgr.GetCategoryAttrs(cat_id)['name']
++            self.UpdateCategoryRaster(cat_id, ['color'], render = False)
++            train_mgr.AddLayer(cat_rast, alias = cat_name)
++
++            self.added_cats_rasts.append(cat_id)
++        else: #TODO settings
++            train_mgr.Render()
++
 +    def SetData(self):
 +        self.iclass_frame.AddBands()
 +
@@ -3865,9 +2894,10 @@
 +                         flags = 'g',
 +                         group = group, subgroup = group,
 +                         read = True).strip()
++
 +        if res.split('\n')[0]:
 +            bands = res.split('\n')
-+            self.scatt_mgr.SetData(bands)
++            self.scatt_mgr.SetBands(bands)
 \ No newline at end of file
 Index: gui/wxpython/scatt_plot/gthreading.py
 ===================================================================
@@ -4438,7 +3468,7 @@
 ===================================================================
 --- gui/wxpython/scatt_plot/toolbars.py	(revision 0)
 +++ gui/wxpython/scatt_plot/toolbars.py	(working copy)
-@@ -0,0 +1,224 @@
+@@ -0,0 +1,264 @@
 +"""!
 + at package scatt_plot.toolbars
 +
@@ -4466,9 +3496,10 @@
 +class MainToolbar(BaseToolbar):
 +    """!Main toolbar
 +    """
-+    def __init__(self, parent, scatt_mgr):
++    def __init__(self, parent, scatt_mgr, opt_tools=None):
 +        BaseToolbar.__init__(self, parent)
 +        self.scatt_mgr = scatt_mgr
++        self.opt_tools = opt_tools
 +
 +        self.InitToolbar(self._toolbarData())
 +        
@@ -4479,6 +3510,8 @@
 +    def _toolbarData(self):
 +
 +        icons = {
++                'selectGroup' : MetaIcon(img = 'layer-group-add',
++                                 label = _('Select imagery group')),
 +                'settings'   : BaseIcons['settings'].SetLabel( _('Settings')),
 +                'help'       : MetaIcon(img = 'help',
 +                                         label = _('Show manual')),
@@ -4495,34 +3528,40 @@
 +                'cats_mgr' : MetaIcon(img = 'table-manager',
 +                                          label = _('Show/hide class manager'))
 +                }
++            
++        tools = [
++                    ('add_scatt', icons["add_scatt_pl"],
++                    lambda event : self.scatt_mgr.AddScattPlot()),
++                    (None, ),
++                    ("cats_mgr", icons['cats_mgr'],
++                    lambda event: self.parent.ShowCategoryPanel(event.Checked()), wx.ITEM_CHECK),
++                    (None, ),
++                    ("pan", icons["pan"],
++                    lambda event: self.SetPloltsMode(event, 'pan'),
++                    wx.ITEM_CHECK),
++                    ("zoom", icons["zoomIn"],
++                    lambda event: self.SetPloltsMode(event, 'zoom'),
++                    wx.ITEM_CHECK),
++                    ("zoom_extend", icons["zoomExtent"],
++                    lambda event: self.SetPloltsMode(event, 'zoom_extend'),
++                    wx.ITEM_CHECK),
++                    (None, ),
++                    ('sel_pol_mode', icons['selCatPol'],
++                    self.ActivateSelectionPolygonMode,
++                    wx.ITEM_CHECK),
++                    (None, ),
++                    ('settings', icons["settings"],
++                    self.OnSettings)
++                    #('help', icons["help"],
++                    # self.OnHelp),                    
++                ]
 +
-+        return self._getToolbarData((
-+                                     ('add_scatt', icons["add_scatt_pl"],
-+                                     lambda event : self.scatt_mgr.AddScattPlot()),
-+                                     (None, ),
-+                                     ("cats_mgr", icons['cats_mgr'],
-+                                     lambda event: self.parent.ShowCategoryPanel(event.Checked()), wx.ITEM_CHECK),
-+                                     (None, ),
-+                                     ("pan", icons["pan"],
-+                                     lambda event: self.SetPloltsMode(event, 'pan'),
-+                                      wx.ITEM_CHECK),
-+                                     ("zoom", icons["zoomIn"],
-+                                     lambda event: self.SetPloltsMode(event, 'zoom'),
-+                                      wx.ITEM_CHECK),
-+                                     ("zoom_extend", icons["zoomExtent"],
-+                                     lambda event: self.SetPloltsMode(event, 'zoom_extend'),
-+                                      wx.ITEM_CHECK),
-+                                     (None, ),
-+                                     ('sel_pol_mode', icons['selCatPol'],
-+                                      self.ActivateSelectionPolygonMode,
-+                                     wx.ITEM_CHECK),
-+                                     (None, ),
-+                                     ('settings', icons["settings"],
-+                                      self.OnSettings)
-+                                     #('help', icons["help"],
-+                                     # self.OnHelp),                    
-+                                    ))
++        if self.opt_tools and "add_group" in self.opt_tools:
++            tools.insert(0, ("selectGroup", icons['selectGroup'],
++                             lambda event : self.scatt_mgr.SetData()))
 +
++        return self._getToolbarData(tools)
++
 +    def GetToolId(self, toolName): #TODO can be useful in base
 +        return vars(self)[toolName]            
 +
@@ -4662,7 +3701,39 @@
 +                self.ToggleTool(i_tool_id, False)
 +
 +    def GetToolId(self, toolName):
-+        return vars(self)[toolName]            
++        return vars(self)[toolName]
++
++class CategoryToolbar(BaseToolbar):
++    """!Main toolbar
++    """
++    def __init__(self, parent, scatt_mgr, cats_list):
++        BaseToolbar.__init__(self, parent)
++        self.scatt_mgr = scatt_mgr
++        self.cats_mgr = self.scatt_mgr.GetCategoriesManager()
++        self.cats_list = cats_list
++
++        self.InitToolbar(self._toolbarData())
++        
++        # realize the toolbar
++        self.Realize()
++
++    def _toolbarData(self):
++        """!Toolbar data
++        """
++        self.icons = {
++            'add_class'     : MetaIcon(img = 'layer-add',
++                                       label = _('Add class.')),
++            'remove_class'  : MetaIcon(img = 'layer-remove',
++                                       label = _('Remove selected class.'))
++            }
++
++        return self._getToolbarData((
++                                    ("add_class", self.icons["add_class"],
++                                     lambda event: self.cats_mgr.AddCategory()),
++                                     ("remove_class", self.icons['remove_class'],
++                                     lambda event: self.cats_list.DeleteCategory()),
++                                    ))
+\ No newline at end of file
 Index: gui/wxpython/scatt_plot/scatt_core.py
 ===================================================================
 --- gui/wxpython/scatt_plot/scatt_core.py	(revision 0)
@@ -5381,9 +4452,9 @@
 +        for tmp in self.cats_rasts_conds.itervalues():
 +            grass.try_remove(tmp) 
 +        for tmp in self.cats_rasts.itervalues():
-+            print RunCommand("g.remove",
-+                            rast=tmp,
-+                           getErrorMsg=True)
++            RunCommand("g.remove",
++                       rast=tmp,
++                       getErrorMsg=True)
 +
 +        self.cats_rasts = {}
 +        self.cats_rasts_conds = {}
@@ -5463,9 +4534,1196 @@
 +
 +    return scatt_id
 +
+Index: gui/wxpython/vnet/dialogs.py
+===================================================================
+--- gui/wxpython/vnet/dialogs.py	(revision 57652)
++++ gui/wxpython/vnet/dialogs.py	(working copy)
+@@ -1218,7 +1218,7 @@
+                       pos = (row, 1))
+ 
+         row += 1
+-        gridSizer.Add(item = self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
++        gridSizer.Add(item=self.settings["invert_colors"], flag=wx.ALIGN_CENTER_VERTICAL, pos=(row, 0))
+ 
+         gridSizer.AddGrowableCol(1)
+         styleBoxSizer.Add(item = gridSizer, flag = wx.EXPAND)
+Index: gui/wxpython/vnet/toolbars.py
+===================================================================
+--- gui/wxpython/vnet/toolbars.py	(revision 57652)
++++ gui/wxpython/vnet/toolbars.py	(working copy)
+@@ -19,9 +19,9 @@
+ 
+ import wx
+ 
+-from icon              import MetaIcon
++from icons.icon import MetaIcon
+ from gui_core.toolbars import BaseToolbar, BaseIcons
+-from core.gcmd         import RunCommand
++from core.gcmd import RunCommand
+ from core.utils import _
+ 
+ class PointListToolbar(BaseToolbar):
+Index: gui/wxpython/Makefile
+===================================================================
+--- gui/wxpython/Makefile	(revision 57652)
++++ gui/wxpython/Makefile	(working copy)
+@@ -13,7 +13,7 @@
+ 	$(wildcard animation/* core/*.py dbmgr/* gcp/*.py gmodeler/* \
+ 	gui_core/*.py iclass/* lmgr/*.py location_wizard/*.py mapwin/*.py mapdisp/*.py \
+ 	mapswipe/* modules/*.py nviz/*.py psmap/* rlisetup/* timeline/* vdigit/* \
+-	vnet/*.py web_services/*.py wxplot/*.py) \
++	vnet/*.py web_services/*.py wxplot/*.py scatt_plot/*.py) \
+ 	gis_set.py gis_set_error.py wxgui.py README
+ 
+ DSTFILES := $(patsubst %,$(ETCDIR)/%,$(SRCFILES)) \
+@@ -21,8 +21,9 @@
+ 
+ PYDSTDIRS := $(patsubst %,$(ETCDIR)/%,animation core dbmgr gcp gmodeler \
+ 	gui_core iclass lmgr location_wizard mapwin mapdisp modules nviz psmap \
+-	mapswipe vdigit wxplot web_services rlisetup vnet timeline)
++	mapswipe vdigit wxplot web_services rlisetup vnet timeline scatt_plot)
+ 
++
+ DSTDIRS := $(patsubst %,$(ETCDIR)/%,icons scripts xml)
+ 
+ default: $(DSTFILES)
+Index: gui/wxpython/vdigit/wxdigit.py
+===================================================================
+--- gui/wxpython/vdigit/wxdigit.py	(revision 57652)
++++ gui/wxpython/vdigit/wxdigit.py	(working copy)
+@@ -17,7 +17,7 @@
+ (and NumPy would be an excellent candidate for acceleration via
+ e.g. OpenCL or CUDA; I'm surprised it hasn't happened already).
+ 
+-(C) 2007-2011 by the GRASS Development Team
++(C) 2007-2011, 2013 by the GRASS Development Team
+ 
+ This program is free software under the GNU General Public License
+ (>=v2). Read the file COPYING that comes with GRASS for details.
+@@ -27,6 +27,8 @@
+ 
+ import grass.script.core as grass
+ 
++from grass.pydispatch.signal import Signal
++
+ from core.gcmd        import GError
+ from core.debug       import Debug
+ from core.settings    import UserSettings
+@@ -176,7 +178,21 @@
+         
+         if self.poMapInfo:
+             self.InitCats()
+-        
++
++        self.emit_signals = False
++
++        # signals which describes features changes during digitization, 
++        # activate them using EmitSignals method 
++        #TODO signal for errors?
++        self.featureAdded = Signal('IVDigit.featureAdded')
++        self.areasDeleted = Signal('IVDigit.areasDeleted')
++        self.vertexMoved = Signal('IVDigit.vertexMoved')
++        self.vertexAdded = Signal('IVDigit.vertexAdded')
++        self.vertexRemoved = Signal('IVDigit.vertexRemoved')
++        self.featuresDeleted = Signal('IVDigit.featuresDeleted')
++        self.featuresMoved = Signal('IVDigit.featuresMoved')
++        self.lineEdited = Signal('IVDigit.lineEdited')
++
+     def __del__(self):
+         Debug.msg(1, "IVDigit.__del__()")
+         Vect_destroy_line_struct(self.poPoints)
+@@ -188,7 +204,12 @@
+             Vect_close(self.poBgMapInfo)
+             self.poBgMapInfo = self.popoBgMapInfo = None
+             del self.bgMapInfo
+-        
++     
++    def EmitSignals(self, emit):
++        """!Activate/deactivate signals which describes features changes during digitization.
++        """
++        self.emit_signals = emit
++
+     def CloseBackgroundMap(self):
+         """!Close background vector map"""
+         if not self.poBgMapInfo:
+@@ -394,7 +415,6 @@
+         
+         @return tuple (number of added features, feature ids)
+         """
+-        
+         layer = self._getNewFeaturesLayer()
+         cat = self._getNewFeaturesCat()
+         
+@@ -419,10 +439,14 @@
+             return (-1, None)
+         
+         self.toolbar.EnableUndo()
+-        
+-        return self._addFeature(vtype, points, layer, cat,
+-                                self._getSnapMode(), self._display.GetThreshold())
+-    
++
++        ret = self._addFeature(vtype, points, layer, cat,
++                               self._getSnapMode(), self._display.GetThreshold())
++        if ret[0] > -1 and self.emit_signals:
++            self.featureAdded.emit(new_bboxs = [self._createBbox(points)], new_areas_cats = [[{layer : [cat]}, None]])
++
++        return ret
++
+     def DeleteSelectedLines(self):
+         """!Delete selected features
+ 
+@@ -434,16 +458,27 @@
+         # collect categories for deleting if requested
+         deleteRec = UserSettings.Get(group = 'vdigit', key = 'delRecord', subkey = 'enabled')
+         catDict = dict()
++
++        old_bboxs = []
++        old_areas_cats = []
+         if deleteRec:
+             for i in self._display.selected['ids']:
++                
+                 if Vect_read_line(self.poMapInfo, None, self.poCats, i) < 0:
+                     self._error.ReadLine(i)
+                 
+-                cats = self.poCats.contents
+-                for j in range(cats.n_cats):
+-                    if cats.field[j] not in catDict.keys():
+-                        catDict[cats.field[j]] = list()
+-                    catDict[cats.field[j]].append(cats.cat[j])
++                if self.emit_signals:
++                    ret = self._getLineAreaBboxCats(i)
++                    if ret:
++                        old_bboxs += ret[0]
++                        old_areas_cats += ret[1]
++                
++                # catDict was not used -> put into comment
++                #cats = self.poCats.contents
++                #for j in range(cats.n_cats):
++                #    if cats.field[j] not in catDict.keys():
++                #        catDict[cats.field[j]] = list()
++                #    catDict[cats.field[j]].append(cats.cat[j])
+         
+         poList = self._display.GetSelectedIList()
+         nlines = Vedit_delete_lines(self.poMapInfo, poList)
+@@ -456,7 +491,10 @@
+                 self._deleteRecords(catDict)
+             self._addChangeset()
+             self.toolbar.EnableUndo()
+-        
++
++            if self.emit_signals:
++                self.featuresDeleted.emit(old_bboxs = old_bboxs, old_areas_cats = old_areas_cats)
++
+         return nlines
+             
+     def _deleteRecords(self, cats):
+@@ -512,22 +550,173 @@
+ 
+         @return number of deleted 
+         """
++        if len(self._display.selected['ids']) < 1:
++            return 0
++        
+         poList = self._display.GetSelectedIList()
+         cList  = poList.contents
+         
+         nareas = 0
++        old_bboxs = []
++        old_areas_cats = []
++
+         for i in range(cList.n_values):
++
+             if Vect_get_line_type(self.poMapInfo, cList.value[i]) != GV_CENTROID:
+                 continue
+-            
++
++            if self.emit_signals:
++                area = Vect_get_centroid_area(self.poMapInfo, cList.value[i]);
++                if area > 0: 
++                    bbox, cats = self._getaAreaBboxCats(area)
++                    old_bboxs += bbox
++                    old_areas_cats += cats
++
+             nareas += Vedit_delete_area_centroid(self.poMapInfo, cList.value[i])
+         
+         if nareas > 0:
+             self._addChangeset()
+             self.toolbar.EnableUndo()
++            if self.emit_signals:
++                self.areasDeleted.emit(old_bboxs = old_bboxs, old_areas_cats = old_areas_cats)        
++
++        return nareas
++   
++    def _getLineAreaBboxCats(self, ln_id):
++        ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
++
++        if ltype == GV_CENTROID:
++            #TODO centroid opttimization, can be adited also its area -> it will appear two times in new_ lists
++            return self._getCentroidAreaBboxCats(ln_id)
++        else: 
++            return [self._getBbox(ln_id)], [self._getLineAreasCategories(ln_id)]
++
++
++    def _getCentroidAreaBboxCats(self, centroid):
++        if not Vect_line_alive(self.poMapInfo, centroid):
++            return None
++
++        area = Vect_get_centroid_area(self.poMapInfo, centroid)  
++        if area > 0:
++            return self._getaAreaBboxCats(area)
++        else:
++            return None
++
++    def _getaAreaBboxCats(self, area):
++
++        po_b_list = Vect_new_list()
++        Vect_get_area_boundaries(self.poMapInfo, area, po_b_list);
++        b_list = po_b_list.contents
++
++        geoms = []
++        areas_cats = []
++
++        if b_list.n_values > 0:
++            for i_line in range(b_list.n_values):
++
++                line = b_list.value[i_line];
++
++                geoms.append(self._getBbox(abs(line)))
++                areas_cats.append(self._getLineAreasCategories(abs(line)))
+         
+-        return nareas
++        Vect_destroy_list(po_b_list);
++
++        return geoms, areas_cats
++
++    def _getLineAreasCategories(self, ln_id):
++        if not Vect_line_alive (self.poMapInfo, ln_id):
++            return []
++
++        ltype = Vect_read_line(self.poMapInfo, None, None, ln_id)
++        if ltype != GV_BOUNDARY:
++            return []
++
++        cats = [None, None]
++
++        left = c_int()
++        right = c_int()
++
++        if Vect_get_line_areas(self.poMapInfo, ln_id, pointer(left), pointer(right)) == 1:
++            areas = [left.value, right.value]
++
++            for i, a in enumerate(areas):
++                if a > 0: 
++                    centroid = Vect_get_area_centroid(self.poMapInfo, a)
++                    if centroid <= 0:
++                        continue
++                    c = self._getCategories(centroid)
++                    if c:
++                        cats[i] = c
++
++        return cats
++
++    def _getCategories(self, ln_id):
++        if not Vect_line_alive (self.poMapInfo, ln_id):
++            return none
++
++        poCats = Vect_new_cats_struct()
++        if Vect_read_line(self.poMapInfo, None, poCats, ln_id) < 0:
++            Vect_destroy_cats_struct(poCats)
++            return None
++
++        cCats = poCats.contents
++
++        cats = {}
++        for j in range(cCats.n_cats):
++            if cats.has_key(cCats.field[j]):
++                cats[cCats.field[j]].append(cCats.cat[j])
++            else:
++                cats[cCats.field[j]] = [cCats.cat[j]]
+     
++        Vect_destroy_cats_struct(poCats)
++        return cats
++
++    def _getBbox(self, ln_id):
++        if not Vect_line_alive (self.poMapInfo, ln_id):
++            return None
++
++        poPoints = Vect_new_line_struct()
++        if Vect_read_line(self.poMapInfo, poPoints, None, ln_id) < 0:
++            Vect_destroy_line_struct(poPoints)
++            return []
++
++        geom = self._convertGeom(poPoints)
++        bbox = self._createBbox(geom)
++        Vect_destroy_line_struct(poPoints)
++        return bbox
++
++    def _createBbox(self, points):
++
++        bbox = {}
++        for pt in points:
++            if not bbox.has_key('maxy'):
++                bbox['maxy'] = pt[1]
++                bbox['miny'] = pt[1]
++                bbox['maxx'] = pt[0]
++                bbox['minx'] = pt[0]
++                continue
++                
++            if   bbox['maxy'] < pt[1]:
++                bbox['maxy'] = pt[1]
++            elif bbox['miny'] > pt[1]:
++                bbox['miny'] = pt[1]
++                
++            if   bbox['maxx'] < pt[0]:
++                bbox['maxx'] = pt[0]
++            elif bbox['minx'] > pt[0]:
++                bbox['minx'] = pt[0]
++        return bbox
++
++    def _convertGeom(self, poPoints):
++
++        Points = poPoints.contents
++
++        pts_geom = []
++        for j in range(Points.n_points):
++            pts_geom.append((Points.x[j], Points.y[j]))
++
++        return pts_geom
++
+     def MoveSelectedLines(self, move):
+         """!Move selected features
+ 
+@@ -536,16 +725,45 @@
+         if not self._checkMap():
+             return -1
+         
++        nsel = len(self._display.selected['ids'])
++        if nsel < 1:
++            return -1   
++        
+         thresh = self._display.GetThreshold()
+         snap   = self._getSnapMode()
+         
+         poList = self._display.GetSelectedIList()
++
++        if self.emit_signals:
++            old_bboxs = []
++            old_areas_cats = []
++            for sel_id in self._display.selected['ids']:
++                ret = self._getLineAreaBboxCats(sel_id)
++                if ret:
++                    old_bboxs += ret[0]
++                    old_areas_cats += ret[1]
++        
++            Vect_set_updated(self.poMapInfo, 1)
++            n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
++        
+         nlines = Vedit_move_lines(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
+                                   poList,
+                                   move[0], move[1], 0,
+                                   snap, thresh)
++
+         Vect_destroy_list(poList)
+-        
++
++        if nlines > 0 and self.emit_signals:
++            new_bboxs = []
++            new_areas_cats = []
++            n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
++            for i in range(n_up_lines_old, n_up_lines):
++                new_id = Vect_get_updated_line(self.poMapInfo, i)
++                ret = self._getLineAreaBboxCats(new_id)
++                if ret:
++                    new_bboxs += ret[0]
++                    new_areas_cats += ret[1]
++
+         if nlines > 0 and self._settings['breakLines']:
+             for i in range(1, nlines):
+                 self._breakLineAtIntersection(nlines + i, None, changeset)
+@@ -553,7 +771,13 @@
+         if nlines > 0:
+             self._addChangeset()
+             self.toolbar.EnableUndo()
+-        
++            
++            if self.emit_signals:
++                self.featuresMoved.emit(new_bboxs = new_bboxs,
++                                        old_bboxs = old_bboxs, 
++                                        old_areas_cats = old_areas_cats, 
++                                        new_areas_cats = new_areas_cats)
++
+         return nlines
+ 
+     def MoveSelectedVertex(self, point, move):
+@@ -571,12 +795,21 @@
+         
+         if len(self._display.selected['ids']) != 1:
+             return -1
+-        
++
++        # move only first found vertex in bbox 
++        poList = self._display.GetSelectedIList()
++
++        if self.emit_signals:
++            cList = poList.contents
++            old_bboxs = [self._getBbox(cList.value[0])]
++            old_areas_cats = [self._getLineAreasCategories(cList.value[0])]
++
++            Vect_set_updated(self.poMapInfo, 1)
++            n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
++
+         Vect_reset_line(self.poPoints)
+         Vect_append_point(self.poPoints, point[0], point[1], 0.0)
+-        
+-        # move only first found vertex in bbox 
+-        poList = self._display.GetSelectedIList()
++
+         moved = Vedit_move_vertex(self.poMapInfo, self.popoBgMapInfo, int(self.poBgMapInfo is not None),
+                                   poList, self.poPoints,
+                                   self._display.GetThreshold(type = 'selectThresh'),
+@@ -584,7 +817,17 @@
+                                   move[0], move[1], 0.0,
+                                   1, self._getSnapMode())
+         Vect_destroy_list(poList)
+-        
++
++        if moved > 0 and self.emit_signals:
++            n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
++
++            new_bboxs = []
++            new_areas_cats = []
++            for i in range(n_up_lines_old, n_up_lines):
++                new_id = Vect_get_updated_line(self.poMapInfo, i)
++                new_bboxs.append(self._getBbox(new_id))
++                new_areas_cats.append(self._getLineAreasCategories(new_id))
++
+         if moved > 0 and self._settings['breakLines']:
+             self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
+                                           None)
+@@ -592,7 +835,13 @@
+         if moved > 0:
+             self._addChangeset()
+             self.toolbar.EnableUndo()
+-        
++
++            if self.emit_signals:
++                self.vertexMoved.emit(new_bboxs = new_bboxs,  
++                                      new_areas_cats = new_areas_cats, 
++                                      old_areas_cats = old_areas_cats, 
++                                      old_bboxs = old_bboxs)
++
+         return moved
+ 
+     def AddVertex(self, coords):
+@@ -681,6 +930,10 @@
+             self._error.ReadLine(line)
+             return -1
+         
++        if self.emit_signals:
++            old_bboxs = [self._getBbox(line)]
++            old_areas_cats = [self._getLineAreasCategories(line)]
++
+         # build feature geometry
+         Vect_reset_line(self.poPoints)
+         for p in coords:
+@@ -696,6 +949,9 @@
+         
+         newline = Vect_rewrite_line(self.poMapInfo, line, ltype,
+                                     self.poPoints, self.poCats)
++        if newline > 0 and self.emit_signals:
++            new_geom = [self._getBbox(newline)]
++            new_areas_cats = [self._getLineAreasCategories(newline)]
+         
+         if newline > 0 and self._settings['breakLines']:
+             self._breakLineAtIntersection(newline, None)
+@@ -703,7 +959,13 @@
+         if newline > 0:
+             self._addChangeset()
+             self.toolbar.EnableUndo()
+-        
++    
++            if self.emit_signals:
++                self.lineEdited.emit(old_bboxs = old_bboxs, 
++                                     old_areas_cats = old_areas_cats, 
++                                     new_bboxs = new_bboxs, 
++                                     new_areas_cats = new_areas_cats)
++
+         return newline
+ 
+     def FlipLine(self):
+@@ -1514,6 +1776,16 @@
+             return 0
+         
+         poList  = self._display.GetSelectedIList()
++
++        if self.emit_signals:
++            cList = poList.contents
++            
++            old_bboxs = [self._getBbox(cList.value[0])]
++            old_areas_cats = [self._getLineAreasCategories(cList.value[0])]
++
++            Vect_set_updated(self.poMapInfo, 1)
++            n_up_lines_old = Vect_get_num_updated_lines(self.poMapInfo)
++
+         Vect_reset_line(self.poPoints)
+         Vect_append_point(self.poPoints, coords[0], coords[1], 0.0)
+         
+@@ -1525,15 +1797,35 @@
+         else:
+             ret = Vedit_remove_vertex(self.poMapInfo, poList,
+                                       self.poPoints, thresh)
++
+         Vect_destroy_list(poList)
++
++        if ret > 0 and self.emit_signals:
++            new_bboxs = []
++            new_areas_cats = []
++
++            n_up_lines = Vect_get_num_updated_lines(self.poMapInfo)
++            for i in range(n_up_lines_old, n_up_lines):
++                new_id = Vect_get_updated_line(self.poMapInfo, i)
++                new_areas_cats.append(self._getLineAreasCategories(new_id))
++                new_bboxs.append(self._getBbox(new_id))
+         
+         if not add and ret > 0 and self._settings['breakLines']:
+             self._breakLineAtIntersection(Vect_get_num_lines(self.poMapInfo),
+                                           None)
+-        
++
+         if ret > 0:
+             self._addChangeset()
+-                
++
++        if ret > 0 and self.emit_signals:
++            if add:
++                self.vertexAdded.emit(old_bboxs = old_bboxs, new_bboxs = new_bboxs)
++            else:
++                self.vertexRemoved.emit(old_bboxs = old_bboxs, 
++                                        new_bboxs = new_bboxs,
++                                        old_areas_cats = old_areas_cats,
++                                        new_areas_cats = new_areas_cats)
++
+         return 1
+     
+     def GetLineCats(self, line):
+Index: gui/wxpython/vdigit/toolbars.py
+===================================================================
+--- gui/wxpython/vdigit/toolbars.py	(revision 57652)
++++ gui/wxpython/vdigit/toolbars.py	(working copy)
+@@ -17,6 +17,7 @@
+ import wx
+ 
+ from grass.script import core as grass
++from grass.pydispatch.signal import Signal
+ 
+ from gui_core.toolbars  import BaseToolbar, BaseIcons
+ from gui_core.dialogs   import CreateNewVector
+@@ -42,6 +43,8 @@
+         self.digit         = None
+         self._giface       = giface
+         
++        self.editingStarted = Signal("VDigitToolbar.editingStarted")
++
+         # currently selected map layer for editing (reference to MapLayer instance)
+         self.mapLayer = None
+         # list of vector layers from Layer Manager (only in the current mapset)
+@@ -860,6 +863,7 @@
+             alpha = int(opacity * 255)
+             self.digit.GetDisplay().UpdateSettings(alpha = alpha)
+         
++        self.editingStarted.emit(vectMap = mapLayer.GetName(), digit = self.digit)
+         return True
+ 
+     def StopEditing(self):
+Index: gui/wxpython/mapdisp/toolbars.py
+===================================================================
+--- gui/wxpython/mapdisp/toolbars.py	(revision 57652)
++++ gui/wxpython/mapdisp/toolbars.py	(working copy)
+@@ -49,6 +49,8 @@
+                             label = _('Create histogram of raster map')),
+     'vnet'       : MetaIcon(img = 'vector-tools',
+                             label = _('Vector network analysis tool')),
++    'interact_scatter' : MetaIcon(img = 'layer-raster-profile',
++                            label = _("Interactive scatter plot tool")),
+     }
+ 
+ NvizIcons = {
+@@ -239,7 +241,9 @@
+                       (MapIcons["scatter"],     self.parent.OnScatterplot),
+                       (MapIcons["histogram"],   self.parent.OnHistogramPyPlot),
+                       (BaseIcons["histogramD"], self.parent.OnHistogram),
+-                      (MapIcons["vnet"],        self.parent.OnVNet)))
++                      (MapIcons["vnet"],        self.parent.OnVNet),
++                      (MapIcons["interact_scatter"], 
++                       self.parent.OnIScatt)))
+         
+     def OnDecoration(self, event):
+         """!Decorations overlay menu
+Index: gui/wxpython/mapdisp/frame.py
+===================================================================
+--- gui/wxpython/mapdisp/frame.py	(revision 57652)
++++ gui/wxpython/mapdisp/frame.py	(working copy)
+@@ -225,6 +225,7 @@
+         #
+         self.dialogs = {}
+         self.dialogs['attributes'] = None
++        self.dialogs['scatt_plot'] = None
+         self.dialogs['category'] = None
+         self.dialogs['barscale'] = None
+         self.dialogs['legend'] = None
+@@ -1168,6 +1169,19 @@
+         """!Returns toolbar with zooming tools"""
+         return self.toolbars['map']
+ 
++    def OnIScatt(self, event):
++        """!Init interactive scatterplot tools
++        """
++        if self.dialogs['scatt_plot']:
++            self.dialogs['scatt_plot'].Raise()
++            return
++
++        from scatt_plot.frame import IScattDialog
++        self.dialogs['scatt_plot'] = IScattDialog(parent=self, giface=self._giface)
++        
++        self.dialogs['scatt_plot'].CenterOnScreen()
++        self.dialogs['scatt_plot'].Show()
++
+     def OnVNet(self, event):
+         """!Dialog for v.net* modules 
+         """
+Index: gui/wxpython/iclass/dialogs.py
+===================================================================
+--- gui/wxpython/iclass/dialogs.py	(revision 57652)
++++ gui/wxpython/iclass/dialogs.py	(working copy)
+@@ -25,14 +25,14 @@
+ import wx.lib.mixins.listctrl as listmix
+ import wx.lib.scrolledpanel as scrolled
+ 
+-from core               import globalvar
++from core import globalvar
+ from core.utils import _
+-from core.settings      import UserSettings
+-from core.gcmd          import GMessage
+-from gui_core.dialogs   import SimpleDialog, GroupDialog
+-from gui_core           import gselect
+-from gui_core.widgets   import SimpleValidator
+-from iclass.statistics  import Statistics, BandStatistics
++from core.settings import UserSettings
++from core.gcmd import GMessage, GError, RunCommand
++from gui_core.dialogs import SimpleDialog, GroupDialog
++from gui_core import gselect
++from gui_core.widgets import SimpleValidator
++from iclass.statistics import Statistics, BandStatistics
+ 
+ import grass.script as grass
+ 
+@@ -88,7 +88,52 @@
+         if gr in dlg.GetExistGroups():
+             self.element.SetValue(gr)
+         dlg.Destroy()
++
++    def AddBands(self):
++        """!Add imagery group"""
++        dlg = IClassGroupDialog(self, group = self.group)
+         
++        while True:
++            if dlg.ShowModal() == wx.ID_OK:
++                if self.SetGroup(dlg.GetGroup()):
++                    break
++            else: 
++                break
++        
++        dlg.Destroy()
++    
++    def GetGroupBandsErr(self, parent):
++        """!Get list of raster bands which are in the soubgroup of group with both having same name.
++           If the group does not exists or it does not contain any bands in subgoup with same name, 
++           error dialog is shown.
++        """
++        name = self.GetGroup()
++        group = grass.find_file(name=name, element='group')
++
++        bands = []
++        if group['name']:
++            bands = self.GetGroupBands(group['name'])
++            if not bands:
++                GError(_("No data found in group <%s>.\n" \
++                         "Please create subgroup with same name as group and add the data there.") \
++                           % name, parent=parent)
++        else:
++            GError(_("Group <%s> not found") % name, parent=parent)
++
++        return bands
++
++    def GetGroupBands(self, group):
++        """!Get list of raster bands which are in the soubgroup of group with both having same name."""
++        res = RunCommand('i.group',
++                         flags='g',
++                         group=group, subgroup=group,
++                         read = True).strip()
++        bands = None
++        if res.split('\n')[0]:
++            bands = res.split('\n')
++            
++        return bands
++
+ class IClassMapDialog(SimpleDialog):
+     """!Dialog for adding raster/vector map"""
+     def __init__(self, parent, title, element):
+@@ -333,13 +378,19 @@
+         toolbar.SetCategories(catNames = catNames, catIdx = cats)
+         if name in catNames:
+             toolbar.choice.SetStringSelection(name)
++            cat = toolbar.GetSelectedCategoryIdx()
+         elif catNames:
+             toolbar.choice.SetSelection(0)
+-            
++            cat = toolbar.GetSelectedCategoryIdx()
++        else:
++            cat = None
++
+         if toolbar.choice.IsEmpty():
+             toolbar.EnableControls(False)
+         else:
+             toolbar.EnableControls(True)
++
++        self.mapWindow.CategoryChanged(cat)
+         # don't forget to update maps, histo, ...
+         
+     def GetSelectedIndices(self, state =  wx.LIST_STATE_SELECTED):
+Index: gui/wxpython/iclass/toolbars.py
+===================================================================
+--- gui/wxpython/iclass/toolbars.py	(revision 57652)
++++ gui/wxpython/iclass/toolbars.py	(working copy)
+@@ -46,9 +46,7 @@
+         'importAreas' : MetaIcon(img = 'layer-import',
+                             label = _('Import training areas from vector map')),
+         'addRgb' : MetaIcon(img = 'layer-rgb-add',
+-                            label = _('Add RGB map layer')),
+-        'scatt_plot'    : MetaIcon(img = 'layer-raster-analyze',
+-                                   label = _('Open Scatter Plot Tool (EXPERIMENTAL GSoC 2013)')),
++                            label = _('Add RGB map layer'))
+         }
+         
+ class IClassMapToolbar(BaseToolbar):
+@@ -117,10 +115,7 @@
+                                      ("zoomBack", icons["zoomBack"],
+                                       self.parent.OnZoomBack),
+                                      ("zoomToMap", icons["zoomExtent"],
+-                                      self.parent.OnZoomToMap),
+-                                     (None, ),
+-                                     ("scatt_plot", iClassIcons["scatt_plot"],
+-                                      self.parent.OnScatterplot)
++                                      self.parent.OnZoomToMap)
+                                     ))
+ class IClassToolbar(BaseToolbar):
+     """!IClass toolbar
+@@ -156,7 +151,7 @@
+         """!Toolbar data"""
+         icons = iClassIcons
+         return self._getToolbarData((("selectGroup", icons['selectGroup'],
+-                                      self.parent.OnAddBands),
++                                      lambda event : self.parent.AddBands()),
+                                       (None, ),
+                                       ("classManager", icons['classManager'],
+                                       self.parent.OnCategoryManager),
+Index: gui/wxpython/iclass/frame.py
+===================================================================
+--- gui/wxpython/iclass/frame.py	(revision 57652)
++++ gui/wxpython/iclass/frame.py	(working copy)
+@@ -64,6 +64,8 @@
+                                IClassExportAreasDialog, IClassMapDialog
+ from iclass.plots       import PlotPanel
+ 
++from grass.pydispatch.signal import Signal
++
+ class IClassMapFrame(DoubleMapFrame):
+     """! wxIClass main frame
+     
+@@ -114,6 +116,10 @@
+             lambda:
+             self.statusbarManager.statusbarItems['coordinates'].SetAdditionalInfo(None))
+         self.SetSize(size)
++
++        self.groupSet = Signal("IClassMapFrame.groupSet")
++        self.categoryChanged = Signal('IClassMapFrame.categoryChanged')
++
+         #
+         # Add toolbars
+         #
+@@ -177,7 +183,7 @@
+         self.dialogs['category']   = None
+         
+         # PyPlot init
+-        self.plotPanel = PlotPanel(self, stats_data = self.stats_data)
++        self.plotPanel = PlotPanel(self, giface = self._giface, stats_data = self.stats_data)
+                                    
+         self._addPanes()
+         self._mgr.Update()
+@@ -237,7 +243,7 @@
+             return False
+         
+         return vectorName
+-        
++    
+     def RemoveTempVector(self):
+         """!Removes temporary vector map with training areas"""
+         ret = RunCommand(prog = 'g.remove',
+@@ -334,11 +340,12 @@
+             self._addPaneMapWindow(name = 'preview')
+             self._addPaneToolbar(name = 'iClassTrainingMapManager')
+             self._addPaneMapWindow(name = 'training')
+-        
++
++        self._mgr.SetDockSizeConstraint(0.5, 0.5) 
+         self._mgr.AddPane(self.plotPanel, wx.aui.AuiPaneInfo().
+                   Name("plots").Caption(_("Plots")).
+                   Dockable(False).Floatable(False).CloseButton(False).
+-                  Left().Layer(1).BestSize((400, -1)))
++                  Left().Layer(1).BestSize((300, -1)))
+         
+     def _addPaneToolbar(self, name):
+         if name == 'iClassPreviewMapManager':
+@@ -477,21 +484,24 @@
+         
+         self.Render(self.GetFirstWindow())
+         
+-    def OnAddBands(self, event):
++    def AddBands(self):
+         """!Add imagery group"""
+-        dlg = IClassGroupDialog(self, group = self.group)
+-        if dlg.ShowModal() == wx.ID_OK:
+-            self.SetGroup(dlg.GetGroup())
++        dlg = IClassGroupDialog(self, group=self.group)
++        
++        while True:
++            if dlg.ShowModal() == wx.ID_OK:
++                
++                if dlg.GetGroupBandsErr(parent=self):
++                    name = dlg.GetGroup()
++                    group = grass.find_file(name = name, element = 'group')
++                    self.group = group['name']
++                    self.groupSet.emit(group=self.group)
++                    break
++            else: 
++                break
++        
+         dlg.Destroy()
+-        
+-    def SetGroup(self, name):
+-        """!Set imagery group"""
+-        group = grass.find_file(name = name, element = 'group')
+-        if group['name']:
+-            self.group = group['name']
+-        else:
+-            GError(_("Group <%s> not found") % name, parent = self)
+-    
++
+     def OnImportAreas(self, event):
+         """!Import training areas"""
+         # check if we have any changes
+@@ -768,17 +778,20 @@
+         
+         Updates number of stddev, histograms, layer in preview display. 
+         """
+-        stat = self.stats_data.GetStatistics(currentCat)
+-        nstd = stat.nstd
+-        self.toolbars['iClass'].UpdateStddev(nstd)
+-        
+-        self.plotPanel.UpdateCategory(currentCat)
+-        self.plotPanel.OnPlotTypeSelected(None)
++        if currentCat:
++          stat = self.stats_data.GetStatistics(currentCat)
++          nstd = stat.nstd
++          self.toolbars['iClass'].UpdateStddev(nstd)
++          
++          self.plotPanel.UpdateCategory(currentCat)
++          self.plotPanel.OnPlotTypeSelected(None)
+                                    
+-        name = stat.rasterName
+-        name = self.previewMapManager.GetAlias(name)
+-        if name:
+-            self.previewMapManager.SelectLayer(name)
++          name = stat.rasterName
++          name = self.previewMapManager.GetAlias(name)
++          if name:
++              self.previewMapManager.SelectLayer(name)
++
++        self.categoryChanged.emit(cat = currentCat)
+         
+     def DeleteAreas(self, cats):
+         """!Removes all training areas of given categories
+@@ -805,12 +818,12 @@
+     def UpdateRasterName(self, newName, cat):
+         """!Update alias of raster map when category name is changed"""
+         origName = self.stats_data.GetStatistics(cat).rasterName
+-        self.previewMapManager.SetAlias(origName, newName)
++        self.previewMapManager.SetAlias(origName, self._addSuffix(newName))
+         
+     def StddevChanged(self, cat, nstd):
+         """!Standard deviation multiplier changed, rerender map, histograms"""
+         stat = self.stats_data.GetStatistics(cat)
+-        stat.nstd = nstd
++        stat.SetStatistics({"nstd" : nstd})
+         
+         if not stat.IsReady():
+             return
+@@ -923,7 +936,7 @@
+                 
+                 self.ConvertToNull(name = stats.rasterName)
+                 self.previewMapManager.AddLayer(name = stats.rasterName,
+-                                                alias = stats.name, resultsLayer = True)
++                                                alias = self._addSuffix(stats.name), resultsLayer = True)
+                 # write statistics
+                 I_iclass_add_signature(self.signatures, statistics)
+                 
+@@ -936,7 +949,11 @@
+         
+         self.UpdateChangeState(changes = False)
+         return True
+-        
++
++    def _addSuffix(self, name):
++        suffix = _('results')
++        return '_'.join((name, suffix))
++
+     def OnSaveSigFile(self, event):
+         """!Asks for signature file name and saves it."""
+         if not self.group:
+@@ -1105,27 +1122,13 @@
+         self.GetFirstWindow().SetModePointer()
+         self.GetSecondWindow().SetModePointer()
+ 
+-    def OnScatterplot(self, event):
+-        """!Init interactive scatterplot tools
+-        """
+-        if self.dialogs['scatt_plot']:
+-            self.dialogs['scatt_plot'].Raise()
+-            return
++    def GetMapManagers(self):
++      """!Get map managers of wxIClass 
+ 
+-        try:
+-          from scatt_plot.dialogs import ScattPlotMainDialog
+-        except:
+-          GError(parent  = self, message = _("The Scatter Plot Tool is not installed."))
+-          return
++      @return trainingMapManager, previewMapManager 
++      """
++      return self.trainingMapManager, self.previewMapManager
+ 
+-        self.dialogs['scatt_plot'] = ScattPlotMainDialog(parent=self, giface=self._giface, iclass_mapwin = self.GetFirstWindow())
+-
+-        scatt_mgr = self.dialogs['scatt_plot'].GetScattMgr()
+-        scatt_mgr.DigitDataChanged(self.toolbars['vdigit'].mapLayer.GetName(), self.GetFirstWindow().GetDigit())
+-
+-        self.dialogs['scatt_plot'].CenterOnScreen()
+-        self.dialogs['scatt_plot'].Show()
+-
+ class MapManager:
+     """! Class for managing map renderer.
+     
+@@ -1168,7 +1171,6 @@
+         self.frame.Render(self.mapWindow)
+         
+         if alias is not None:
+-            alias = self._addSuffix(alias)
+             self.layerName[alias] = name
+             name = alias
+         else:
+@@ -1225,7 +1227,11 @@
+                 self.toolbar.choice.SetSelection(0)
+         
+         self.frame.Render(self.mapWindow)
+-        
++    
++    def Render(self):
++        """@todo giface shoud be used instead of this method"""
++        self.frame.Render(self.mapWindow)
++
+     def RemoveLayer(self, name, idx):
+         """!Removes layer from Map and update toolbar"""
+         name = self.layerName[name]
+@@ -1281,11 +1287,7 @@
+     def _changeOpacity(self, layer, opacity):
+         self.map.ChangeOpacity(layer=layer, opacity=opacity)
+         self.frame.Render(self.mapWindow)
+-        
+-    def _addSuffix(self, name):
+-        suffix = _('results')
+-        return '_'.join((name, suffix))
+-        
++                
+     def GetAlias(self, name):
+         """!Returns alias for layer"""
+         name =  [k for k, v in self.layerName.iteritems() if v == name]
+@@ -1296,11 +1298,11 @@
+     def SetAlias(self, original, alias):
+         name = self.GetAlias(original)
+         if name:
+-            self.layerName[self._addSuffix(alias)] = original
++            self.layerName[alias] = original
+             del self.layerName[name]
+             idx = self.toolbar.choice.FindString(name)
+             if idx != wx.NOT_FOUND:
+-                self.toolbar.choice.SetString(idx, self._addSuffix(alias))
++                self.toolbar.choice.SetString(idx, alias)
+ 
+ def test():
+     import core.render as render
+Index: gui/wxpython/iclass/plots.py
+===================================================================
+--- gui/wxpython/iclass/plots.py	(revision 57652)
++++ gui/wxpython/iclass/plots.py	(working copy)
+@@ -19,6 +19,7 @@
+ import wx.lib.plot as plot
+ import wx.lib.scrolledpanel as scrolled
+ from core.utils import _
++from core.gcmd import GError
+ 
+ class PlotPanel(scrolled.ScrolledPanel):
+     """!Panel for drawing multiple plots.
+@@ -28,7 +29,7 @@
+     for each band and for one category. Coincidence plots show min max range
+     of classes for each band.
+     """
+-    def __init__(self, parent, stats_data):
++    def __init__(self, parent, giface, stats_data):
+         scrolled.ScrolledPanel.__init__(self, parent)
+         
+         self.SetupScrolling(scroll_x = False, scroll_y = True)
+@@ -38,26 +39,71 @@
+         self.stats_data = stats_data
+         self.currentCat = None
+         
++        self._giface = giface
++
+         self.mainSizer = wx.BoxSizer(wx.VERTICAL)
+-        
++
+         self._createControlPanel()
+-        
++        self._createPlotPanel()
++        self._createScatterPlotPanel()
++
+         self.SetSizer(self.mainSizer)
+         self.mainSizer.Fit(self)
+         self.Layout()
+-        
++
++    def _createPlotPanel(self):
++
++        self.canvasPanel = wx.Panel(parent=self)
++        self.mainSizer.Add(item = self.canvasPanel, proportion = 1, flag = wx.EXPAND, border = 0)
++        self.canvasSizer = wx.BoxSizer(wx.VERTICAL)
++        self.canvasPanel.SetSizer(self.canvasSizer)
++
+     def _createControlPanel(self):
+         self.plotSwitch = wx.Choice(self, id = wx.ID_ANY,
+                                      choices = [_("Histograms"),
+-                                                _("Coincident plots")])
++                                                _("Coincident plots"),
++                                                _("Scatter plots")])
+         self.mainSizer.Add(self.plotSwitch, proportion = 0, flag = wx.EXPAND|wx.ALL, border = 5)
+         self.plotSwitch.Bind(wx.EVT_CHOICE, self.OnPlotTypeSelected)
+-        
++    
++    def _createScatterPlotPanel(self):
++        """!Init interactive scatterplot tools
++        """
++        try:
++            from scatt_plot.frame import IClassIScattPanel
++            self.scatt_plot_panel = IClassIScattPanel(parent=self, 
++                                                      giface=self._giface, 
++                                                      iclass_mapwin = self.parent.GetFirstWindow())
++            self.mainSizer.Add(self.scatt_plot_panel, proportion = 1, flag = wx.EXPAND, border = 0)
++            self.scatt_plot_panel.Hide()
++        except ImportError as e:#TODO
++            self.scatt_error = _("Scatter plot functionality is disabled. Reason:\n" \
++                                 "Unable to import packages needed for scatter plot.\n%s" % e)
++            GError(self.scatt_error)
++            self.scatt_plot_panel = None
++
+     def OnPlotTypeSelected(self, event):
+         """!Plot type selected"""
++
++        if self.plotSwitch.GetSelection() in [0, 1]:
++            self.SetupScrolling(scroll_x = False, scroll_y = True)
++            if self.scatt_plot_panel:
++                self.scatt_plot_panel.Hide()
++            self.canvasPanel.Show()
++            self.Layout()
++
++        elif self.plotSwitch.GetSelection() == 2:
++            self.SetupScrolling(scroll_x = False, scroll_y = False)
++            if self.scatt_plot_panel:
++                self.scatt_plot_panel.Show()
++            else:
++                GError(self.scatt_error)
++            self.canvasPanel.Hide()
++            self.Layout()
++
+         if self.currentCat is None:
+             return
+-        
++
+         if self.plotSwitch.GetSelection() == 0:
+             stat = self.stats_data.GetStatistics(self.currentCat)
+             if not stat.IsReady():
+@@ -66,7 +112,10 @@
+             self.DrawHistograms(stat)
+         else:
+             self.DrawCoincidencePlots()
+-            
++
++        self.Layout()
++
++
+     def StddevChanged(self):
+         """!Standard deviation multiplier changed, redraw histograms"""
+         if self.plotSwitch.GetSelection() == 0:
+@@ -89,7 +138,7 @@
+             panel.Destroy()
+             
+         self.canvasList = []
+-            
++
+     def ClearPlots(self):
+         """!Clears plot canvases"""
+         for bandIdx in range(len(self.bandList)):
+@@ -104,15 +153,15 @@
+     def CreatePlotCanvases(self):
+         """!Create plot canvases according to the number of bands"""
+         for band in self.bandList:
+-            canvas = plot.PlotCanvas(self)
++            canvas = plot.PlotCanvas(self.canvasPanel)
+             canvas.SetMinSize((-1, 140))
+             canvas.SetFontSizeTitle(10)
+             canvas.SetFontSizeAxis(8)
+             self.canvasList.append(canvas)
+             
+-            self.mainSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
+-
+-        self.SetVirtualSize(self.GetBestVirtualSize()) 
++            self.canvasSizer.Add(item = canvas, proportion = 1, flag = wx.EXPAND, border = 0)
++        
++        self.SetVirtualSize(self.GetBestVirtualSize())
+         self.Layout()
+         
+     def UpdatePlots(self, group, currentCat, stats_data):
+@@ -138,7 +187,7 @@
+         
+     def UpdateCategory(self, cat):
+         self.currentCat = cat
+-        
++    
+     def DrawCoincidencePlots(self):
+         """!Draw coincidence plots"""
+         for bandIdx in range(len(self.bandList)):
 Index: lib/vector/Vlib/open.c
 ===================================================================
---- lib/vector/Vlib/open.c	(revision 57644)
+--- lib/vector/Vlib/open.c	(revision 57652)
 +++ lib/vector/Vlib/open.c	(working copy)
 @@ -240,7 +240,9 @@
          }
@@ -5478,6 +5736,416 @@
              /* temporary map: reduce to current mapset if search path
               * was set */
              if (strcmp(Map->mapset, "") == 0)
+Index: lib/imagery/scatt_sccats.c
+===================================================================
+--- lib/imagery/scatt_sccats.c	(revision 0)
++++ lib/imagery/scatt_sccats.c	(working copy)
+@@ -0,0 +1,405 @@
++/*!
++   \file lib/imagery/scatt_cat_rast.c
++
++   \brief Imagery library - functions for manipulation with scatter plot structs.
++
++   Copyright (C) 2013 by the GRASS Development Team
++
++   This program is free software under the GNU General Public License
++   (>=v2).  Read the file COPYING that comes with GRASS for details.
++
++   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
++ */
++
++#include <grass/raster.h>
++#include <grass/imagery.h>
++#include <grass/gis.h>
++
++#include <stdio.h>
++#include <stdlib.h>
++#include <math.h>
++#include <string.h>
++
++/*!
++   \brief Compute band ids from scatter plot id.
++
++    Scatter plot id describes which bands defines the scatter plot.
++
++    Let say we have 3 bands, their ids are 0, 1 and 2.
++    Scatter plot with id 0 consists of band 1 (b_1_id) 0 and  band 2 (b_2_id) 1.
++    All scatter plots:
++    scatt_id b_1_id b_2_id
++    0        0      1
++    1        0      2
++    2        1      2
++
++   \param scatt_id scatter plot id
++   \param n_bands number of bands
++   \param [out] b_1_id id of band1
++   \param[out] b_2_id id of band2
++
++   \return 0
++ */
++int I_id_scatt_to_bands(const int scatt_id, const int n_bands, int * b_1_id, int * b_2_id)
++{   
++    int n_b1 = n_bands - 1;
++
++    * b_1_id = (int) ((2 * n_b1 + 1 - sqrt((double)((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2);
++
++    * b_2_id = scatt_id - ((* b_1_id) * (2 * n_b1 + 1) - (* b_1_id) * (* b_1_id)) / 2 + (* b_1_id) + 1;
++
++    return 0;
++}
++
++
++/*!
++   \brief Compute scatter plot id from band ids.
++
++    See also I_id_scatt_to_bands().
++
++   \param n_bands number of bands
++   \param b_1_id id of band1
++   \param b_1_id id of band2
++   \param [out] scatt_id scatter plot id
++
++   \return 0
++ */
++int I_bands_to_id_scatt(const int b_1_id, const int b_2_id, const int n_bands, int * scatt_id)
++{   
++    int n_b1 = n_bands - 1;
++
++    * scatt_id = (b_1_id * (2 * n_b1 + 1) - b_1_id * b_1_id) / 2 + b_2_id - b_1_id - 1;
++
++    return 0;
++}
++
++/*!
++   \brief Initialize structure for storing scatter plots data.
++
++   \param cats pointer to scCats struct 
++   \param n_bands number of bands
++   \param type SC_SCATT_DATA - stores scatter plots 
++   \param type SC_SCATT_CONDITIONS - stores selected areas in scatter plots
++ */
++void I_sc_init_cats(struct scCats * cats, int n_bands, int type)
++{
++    int i_cat;
++
++    cats->type = type;
++
++    cats->n_cats = 100;
++    cats->n_a_cats = 0;
++
++    cats->n_bands = n_bands;
++    cats->n_scatts = (n_bands - 1) * n_bands / 2;
++
++    cats->cats_arr = (struct scScatts **) G_malloc(cats->n_cats * sizeof(struct scScatts *));
++    memset(cats->cats_arr, 0, cats-> n_cats * sizeof(struct scScatts *));
++
++    cats->cats_ids = (int *)  G_malloc(cats->n_cats * sizeof(int));
++    cats->cats_idxs =(int *)  G_malloc(cats->n_cats * sizeof(int));
++
++    for(i_cat = 0; i_cat < cats->n_cats; i_cat++)
++        cats->cats_idxs[i_cat] = -1;
++
++    return;
++}
++
++/*!
++   \brief Free data of struct scCats, the structure itself remains alocated.
++
++   \param cats pointer to existing scCats struct
++ */
++void I_sc_free_cats(struct scCats * cats)
++{
++    int i_cat;
++
++    for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
++    {        
++        if(cats->cats_arr[i_cat])
++        {   
++            G_free(cats->cats_arr[i_cat]->scatt_idxs);
++            G_free(cats->cats_arr[i_cat]->scatts_bands);
++            G_free(cats->cats_arr[i_cat]->scatts_arr);
++            G_free(cats->cats_arr[i_cat]);
++        }
++    }
++
++    G_free(cats->cats_ids);
++    G_free(cats->cats_idxs);
++    G_free(cats->cats_arr);
++
++    cats->n_cats = 0;
++    cats->n_a_cats = 0;
++    cats->n_bands = 0;
++    cats->n_scatts = 0;
++    cats->type = -1;
++
++    return;
++}
++
++#if 0
++void I_sc_get_active_categories(int * a_cats_ids, int * n_a_cats, struct scCats * cats)
++{
++    a_cats_ids = cats->cats_ids;
++    * n_a_cats = cats->n_a_cats;
++}
++#endif
++
++/*!
++   \brief Add category.
++    
++    Category represents group of scatter plots.
++
++   \param cats pointer to scCats struct
++
++   \return assigned category id (starts with 0)
++   \return -1 if maximum nuber of categories was reached
++ */
++int I_sc_add_cat(struct scCats * cats)
++{
++    int i_scatt, i_cat_id, cat_id;
++    int n_a_cats = cats->n_a_cats;
++
++    if(cats->n_a_cats >= cats->n_cats)
++        return -1;
++
++    for(i_cat_id = 0; i_cat_id < cats->n_cats; i_cat_id++)
++        if(cats->cats_idxs[i_cat_id] < 0) {
++            cat_id = i_cat_id;
++            break;
++        }
++
++    cats->cats_ids[n_a_cats] = cat_id;
++    cats->cats_idxs[cat_id] = n_a_cats;
++    
++    cats->cats_arr[n_a_cats] = (struct scScatts *) G_malloc(sizeof(struct scScatts));
++
++    cats->cats_arr[n_a_cats]->scatts_arr = (struct scdScattData **) G_malloc(cats->n_scatts * sizeof(struct scdScattData *));
++    memset((cats->cats_arr[n_a_cats]->scatts_arr), 0, cats->n_scatts * sizeof(struct scdScattData *));
++    
++    cats->cats_arr[n_a_cats]->n_a_scatts = 0;
++
++    cats->cats_arr[n_a_cats]->scatts_bands = (int *) G_malloc(cats->n_scatts * 2 * sizeof(int));
++     
++    cats->cats_arr[n_a_cats]->scatt_idxs = (int *) G_malloc(cats->n_scatts * sizeof(int));
++    for(i_scatt = 0; i_scatt < cats->n_scatts; i_scatt++)
++        cats->cats_arr[n_a_cats]->scatt_idxs[i_scatt] = -1;
++    
++    ++cats->n_a_cats;
++
++    return cat_id;
++}
++
++#if 0
++int I_sc_delete_cat(struct scCats * cats, int cat_id)
++{
++    int cat_idx, i_cat;
++
++    if(cat_id < 0 || cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    G_free(cats->cats_arr[cat_idx]->scatt_idxs);
++    G_free(cats->cats_arr[cat_idx]->scatts_bands);
++    G_free(cats->cats_arr[cat_idx]->scatts_arr);
++    G_free(cats->cats_arr[cat_idx]);
++
++    for(i_cat = cat_idx; i_cat < cats->n_a_cats - 1; i_cat++)
++    {
++        cats->cats_arr[i_cat] = cats->cats_arr[i_cat + 1];
++        cats->cats_ids[i_cat] = cats->cats_ids[i_cat + 1];
++    }
++    cats->cats_idxs[cat_id] = -1; 
++
++    --cats->n_a_cats;
++    
++    return 0;
++}
++#endif
++
++/*!
++   \brief Insert scatter plot data .
++    Inserted scatt_data struct must have same type as cats struct (SC_SCATT_DATA or SC_SCATT_CONDITIONS).
++
++   \param cats pointer to scCats struct
++   \param cat_id id number of category.
++   \param scatt_id id number of scatter plot.
++
++   \return  0 on success
++   \return -1 on failure
++ */
++int I_sc_insert_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
++{
++    int band_1, band_2, cat_idx, n_a_scatts;
++    struct scScatts * scatts;
++
++    if(cat_id < 0 || cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    if(scatt_id < 0 && scatt_id >= cats->n_scatts)
++        return -1;
++
++    scatts = cats->cats_arr[cat_idx];
++    if(scatts->scatt_idxs[scatt_id] >= 0)
++        return -1;
++
++    if(!scatt_data->b_conds_arr && cats->type == SC_SCATT_CONDITIONS)
++        return -1;
++
++    if(!scatt_data->scatt_vals_arr && cats->type == SC_SCATT_DATA)
++        return -1;
++
++    n_a_scatts = scatts->n_a_scatts;
++
++    scatts->scatt_idxs[scatt_id] = n_a_scatts;
++
++    I_id_scatt_to_bands(scatt_id, cats->n_bands, &band_1, &band_2);
++
++    scatts->scatts_bands[n_a_scatts * 2] = band_1;
++    scatts->scatts_bands[n_a_scatts * 2 + 1] = band_2;
++
++    scatts->scatts_arr[n_a_scatts] = scatt_data;
++    ++scatts->n_a_scatts;
++
++    return 0;
++}
++
++#if 0
++int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
++{
++    int cat_idx, scatt_idx, n_init_scatts, i_scatt;
++    struct scScatts * scatts;
++
++    if(cat_id < 0 && cat_id >= cats->n_cats)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++
++    if(scatt_id < 0 || scatt_id >= cats->n_scatts)
++        return -1;
++
++    scatts = cats->cats_arr[cat_idx];
++    if(scatts->scatt_idxs[scatt_id] < 0)
++        return -1;
++
++    scatt_data = scatts->scatts_arr[scatt_idx];
++
++    for(i_scatt = scatt_idx; i_scatt < scatts->n_a_scatts - 1; i_scatt++)
++    {
++        scatts->scatts_arr[i_scatt] = scatts->scatts_arr[i_scatt + 1];
++        scatts->scatts_bands[i_scatt * 2] = scatts->scatts_bands[(i_scatt + 1)* 2];
++        scatts->scatts_bands[i_scatt * 2 + 1] = scatts->scatts_bands[(i_scatt + 1) * 2 + 1];
++    }
++    scatts->scatts_arr[scatts->n_a_scatts] = NULL;
++
++    scatts->scatt_idxs[scatt_id] = -1;
++
++    scatt_data = scatts->scatts_arr[scatt_id];
++    scatts->n_a_scatts--;
++
++    return 0;
++}
++
++int I_sc_set_value(struct scCats * cats, int cat_id, int scatt_id, int value_idx, int value)
++{
++    int n_a_scatts = cats->cats_arr[cat_id]->n_a_scatts;
++    int cat_idx, scatt_idx, ret;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    if(cat_idx < 0)
++        return -1;
++    
++    if(cats->cats_arr[cat_idx]->scatt_idxs[scatt_id] < 0)
++        return -1;
++
++    cat_idx = cats->cats_idxs[cat_id];
++    scatt_idx = cats->cats_arr[cat_idx]->scatt_idxs[scatt_id];
++
++    I_scd_set_value(cats->cats_arr[cat_idx]->scatts_arr[scatt_idx], value_idx, value);
++
++    return 0;
++}
++#endif
++
++/*!
++   \brief Insert scatter plot data.
++    
++   \param scatt_data pointer to existing struct scdScattData
++   \param type SC_SCATT_DATA for scatter plots or SC_SCATT_CONDITIONS for selected areas in scatter plot
++   \param n_vals number of data values
++   \param data array of values (unsigned char for SC_SCATT_CONDITIONS, unsigned int for SC_SCATT_DATA)
++ */
++void I_scd_init_scatt_data(struct scdScattData * scatt_data, int type, int n_vals, void * data)
++{
++    scatt_data->n_vals = n_vals;
++
++    if(type == SC_SCATT_DATA)
++    {   
++        if(data)
++            scatt_data->scatt_vals_arr = (unsigned int *) data;
++        else {
++            scatt_data->scatt_vals_arr = (unsigned int *) G_malloc(n_vals * sizeof(unsigned int));
++            memset(scatt_data->scatt_vals_arr, 0, n_vals * sizeof(unsigned int)); 
++        }
++        scatt_data->b_conds_arr = NULL;
++    }
++    else if(type == SC_SCATT_CONDITIONS)
++    {
++        if(data)
++            scatt_data->b_conds_arr = (unsigned char *) data;
++        else {
++            scatt_data->b_conds_arr = (unsigned char *) G_malloc(n_vals * sizeof(unsigned char));
++            memset(scatt_data->b_conds_arr, 0, n_vals * sizeof(unsigned char));
++        }
++        scatt_data->scatt_vals_arr = NULL;
++    }
++
++    return;
++}
++
++
++#if 0
++void I_scd_get_range_min_max(struct scdScattData * scatt_data, CELL * band_1_min, CELL * band_1_max, CELL * band_2_min, CELL * band_2_max)
++{
++
++    Rast_get_range_min_max(&(scatt_data->band_1_range), band_1_min, band_2_min);
++    Rast_get_range_min_max(&(scatt_data->band_2_range), band_2_min, band_2_max);
++
++    return;
++}
++s
++void * I_scd_get_data_ptr(struct scdScattData * scatt_data)
++{
++    if(!scatt_data->b_conds_arr)
++        return scatt_data->b_conds_arr;
++    else if(!scatt_data->scatt_vals_arr)
++        return scatt_data->scatt_vals_arr;
++
++    return NULL;
++}
++
++int I_scd_set_value(struct scdScattData * scatt_data, unsigned int val_idx, unsigned int val)
++{
++    if(val_idx < 0 && val_idx >  scatt_data->n_vals)
++        return -1;
++
++    if(scatt_data->b_conds_arr)
++        scatt_data->b_conds_arr[val_idx] = val;
++    else if(scatt_data->scatt_vals_arr)
++        scatt_data->scatt_vals_arr[val_idx] = val;
++    else
++        return -1;
++
++    return 0;
++}
++#endif
 Index: lib/imagery/scatt.c
 ===================================================================
 --- lib/imagery/scatt.c	(revision 0)
@@ -6282,413 +6950,3 @@
 +    }
 +    return 0;
 +}
-Index: lib/imagery/scatt_sccats.c
-===================================================================
---- lib/imagery/scatt_sccats.c	(revision 0)
-+++ lib/imagery/scatt_sccats.c	(working copy)
-@@ -0,0 +1,405 @@
-+/*!
-+   \file lib/imagery/scatt_cat_rast.c
-+
-+   \brief Imagery library - functions for manipulation with scatter plot structs.
-+
-+   Copyright (C) 2013 by the GRASS Development Team
-+
-+   This program is free software under the GNU General Public License
-+   (>=v2).  Read the file COPYING that comes with GRASS for details.
-+
-+   \author Stepan Turek <stepan.turek at seznam.cz> (Mentor: Martin Landa)
-+ */
-+
-+#include <grass/raster.h>
-+#include <grass/imagery.h>
-+#include <grass/gis.h>
-+
-+#include <stdio.h>
-+#include <stdlib.h>
-+#include <math.h>
-+#include <string.h>
-+
-+/*!
-+   \brief Compute band ids from scatter plot id.
-+
-+    Scatter plot id describes which bands defines the scatter plot.
-+
-+    Let say we have 3 bands, their ids are 0, 1 and 2.
-+    Scatter plot with id 0 consists of band 1 (b_1_id) 0 and  band 2 (b_2_id) 1.
-+    All scatter plots:
-+    scatt_id b_1_id b_2_id
-+    0        0      1
-+    1        0      2
-+    2        1      2
-+
-+   \param scatt_id scatter plot id
-+   \param n_bands number of bands
-+   \param [out] b_1_id id of band1
-+   \param[out] b_2_id id of band2
-+
-+   \return 0
-+ */
-+int I_id_scatt_to_bands(const int scatt_id, const int n_bands, int * b_1_id, int * b_2_id)
-+{   
-+    int n_b1 = n_bands - 1;
-+
-+    * b_1_id = (int) ((2 * n_b1 + 1 - sqrt((double)((2 * n_b1 + 1) * (2 * n_b1 + 1) - 8 * scatt_id))) / 2);
-+
-+    * b_2_id = scatt_id - ((* b_1_id) * (2 * n_b1 + 1) - (* b_1_id) * (* b_1_id)) / 2 + (* b_1_id) + 1;
-+
-+    return 0;
-+}
-+
-+
-+/*!
-+   \brief Compute scatter plot id from band ids.
-+
-+    See also I_id_scatt_to_bands().
-+
-+   \param n_bands number of bands
-+   \param b_1_id id of band1
-+   \param b_1_id id of band2
-+   \param [out] scatt_id scatter plot id
-+
-+   \return 0
-+ */
-+int I_bands_to_id_scatt(const int b_1_id, const int b_2_id, const int n_bands, int * scatt_id)
-+{   
-+    int n_b1 = n_bands - 1;
-+
-+    * scatt_id = (b_1_id * (2 * n_b1 + 1) - b_1_id * b_1_id) / 2 + b_2_id - b_1_id - 1;
-+
-+    return 0;
-+}
-+
-+/*!
-+   \brief Initialize structure for storing scatter plots data.
-+
-+   \param cats pointer to scCats struct 
-+   \param n_bands number of bands
-+   \param type SC_SCATT_DATA - stores scatter plots 
-+   \param type SC_SCATT_CONDITIONS - stores selected areas in scatter plots
-+ */
-+void I_sc_init_cats(struct scCats * cats, int n_bands, int type)
-+{
-+    int i_cat;
-+
-+    cats->type = type;
-+
-+    cats->n_cats = 100;
-+    cats->n_a_cats = 0;
-+
-+    cats->n_bands = n_bands;
-+    cats->n_scatts = (n_bands - 1) * n_bands / 2;
-+
-+    cats->cats_arr = (struct scScatts **) G_malloc(cats->n_cats * sizeof(struct scScatts *));
-+    memset(cats->cats_arr, 0, cats-> n_cats * sizeof(struct scScatts *));
-+
-+    cats->cats_ids = (int *)  G_malloc(cats->n_cats * sizeof(int));
-+    cats->cats_idxs =(int *)  G_malloc(cats->n_cats * sizeof(int));
-+
-+    for(i_cat = 0; i_cat < cats->n_cats; i_cat++)
-+        cats->cats_idxs[i_cat] = -1;
-+
-+    return;
-+}
-+
-+/*!
-+   \brief Free data of struct scCats, the structure itself remains alocated.
-+
-+   \param cats pointer to existing scCats struct
-+ */
-+void I_sc_free_cats(struct scCats * cats)
-+{
-+    int i_cat;
-+
-+    for(i_cat = 0; i_cat < cats->n_a_cats; i_cat++)
-+    {        
-+        if(cats->cats_arr[i_cat])
-+        {   
-+            G_free(cats->cats_arr[i_cat]->scatt_idxs);
-+            G_free(cats->cats_arr[i_cat]->scatts_bands);
-+            G_free(cats->cats_arr[i_cat]->scatts_arr);
-+            G_free(cats->cats_arr[i_cat]);
-+        }
-+    }
-+
-+    G_free(cats->cats_ids);
-+    G_free(cats->cats_idxs);
-+    G_free(cats->cats_arr);
-+
-+    cats->n_cats = 0;
-+    cats->n_a_cats = 0;
-+    cats->n_bands = 0;
-+    cats->n_scatts = 0;
-+    cats->type = -1;
-+
-+    return;
-+}
-+
-+#if 0
-+void I_sc_get_active_categories(int * a_cats_ids, int * n_a_cats, struct scCats * cats)
-+{
-+    a_cats_ids = cats->cats_ids;
-+    * n_a_cats = cats->n_a_cats;
-+}
-+#endif
-+
-+/*!
-+   \brief Add category.
-+    
-+    Category represents group of scatter plots.
-+
-+   \param cats pointer to scCats struct
-+
-+   \return assigned category id (starts with 0)
-+   \return -1 if maximum nuber of categories was reached
-+ */
-+int I_sc_add_cat(struct scCats * cats)
-+{
-+    int i_scatt, i_cat_id, cat_id;
-+    int n_a_cats = cats->n_a_cats;
-+
-+    if(cats->n_a_cats >= cats->n_cats)
-+        return -1;
-+
-+    for(i_cat_id = 0; i_cat_id < cats->n_cats; i_cat_id++)
-+        if(cats->cats_idxs[i_cat_id] < 0) {
-+            cat_id = i_cat_id;
-+            break;
-+        }
-+
-+    cats->cats_ids[n_a_cats] = cat_id;
-+    cats->cats_idxs[cat_id] = n_a_cats;
-+    
-+    cats->cats_arr[n_a_cats] = (struct scScatts *) G_malloc(sizeof(struct scScatts));
-+
-+    cats->cats_arr[n_a_cats]->scatts_arr = (struct scdScattData **) G_malloc(cats->n_scatts * sizeof(struct scdScattData *));
-+    memset((cats->cats_arr[n_a_cats]->scatts_arr), 0, cats->n_scatts * sizeof(struct scdScattData *));
-+    
-+    cats->cats_arr[n_a_cats]->n_a_scatts = 0;
-+
-+    cats->cats_arr[n_a_cats]->scatts_bands = (int *) G_malloc(cats->n_scatts * 2 * sizeof(int));
-+     
-+    cats->cats_arr[n_a_cats]->scatt_idxs = (int *) G_malloc(cats->n_scatts * sizeof(int));
-+    for(i_scatt = 0; i_scatt < cats->n_scatts; i_scatt++)
-+        cats->cats_arr[n_a_cats]->scatt_idxs[i_scatt] = -1;
-+    
-+    ++cats->n_a_cats;
-+
-+    return cat_id;
-+}
-+
-+#if 0
-+int I_sc_delete_cat(struct scCats * cats, int cat_id)
-+{
-+    int cat_idx, i_cat;
-+
-+    if(cat_id < 0 || cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    G_free(cats->cats_arr[cat_idx]->scatt_idxs);
-+    G_free(cats->cats_arr[cat_idx]->scatts_bands);
-+    G_free(cats->cats_arr[cat_idx]->scatts_arr);
-+    G_free(cats->cats_arr[cat_idx]);
-+
-+    for(i_cat = cat_idx; i_cat < cats->n_a_cats - 1; i_cat++)
-+    {
-+        cats->cats_arr[i_cat] = cats->cats_arr[i_cat + 1];
-+        cats->cats_ids[i_cat] = cats->cats_ids[i_cat + 1];
-+    }
-+    cats->cats_idxs[cat_id] = -1; 
-+
-+    --cats->n_a_cats;
-+    
-+    return 0;
-+}
-+#endif
-+
-+/*!
-+   \brief Insert scatter plot data .
-+    Inserted scatt_data struct must have same type as cats struct (SC_SCATT_DATA or SC_SCATT_CONDITIONS).
-+
-+   \param cats pointer to scCats struct
-+   \param cat_id id number of category.
-+   \param scatt_id id number of scatter plot.
-+
-+   \return  0 on success
-+   \return -1 on failure
-+ */
-+int I_sc_insert_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
-+{
-+    int band_1, band_2, cat_idx, n_a_scatts;
-+    struct scScatts * scatts;
-+
-+    if(cat_id < 0 || cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    if(scatt_id < 0 && scatt_id >= cats->n_scatts)
-+        return -1;
-+
-+    scatts = cats->cats_arr[cat_idx];
-+    if(scatts->scatt_idxs[scatt_id] >= 0)
-+        return -1;
-+
-+    if(!scatt_data->b_conds_arr && cats->type == SC_SCATT_CONDITIONS)
-+        return -1;
-+
-+    if(!scatt_data->scatt_vals_arr && cats->type == SC_SCATT_DATA)
-+        return -1;
-+
-+    n_a_scatts = scatts->n_a_scatts;
-+
-+    scatts->scatt_idxs[scatt_id] = n_a_scatts;
-+
-+    I_id_scatt_to_bands(scatt_id, cats->n_bands, &band_1, &band_2);
-+
-+    scatts->scatts_bands[n_a_scatts * 2] = band_1;
-+    scatts->scatts_bands[n_a_scatts * 2 + 1] = band_2;
-+
-+    scatts->scatts_arr[n_a_scatts] = scatt_data;
-+    ++scatts->n_a_scatts;
-+
-+    return 0;
-+}
-+
-+#if 0
-+int I_sc_remove_scatt_data(struct scCats * cats, struct scdScattData * scatt_data, int cat_id, int scatt_id)
-+{
-+    int cat_idx, scatt_idx, n_init_scatts, i_scatt;
-+    struct scScatts * scatts;
-+
-+    if(cat_id < 0 && cat_id >= cats->n_cats)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+
-+    if(scatt_id < 0 || scatt_id >= cats->n_scatts)
-+        return -1;
-+
-+    scatts = cats->cats_arr[cat_idx];
-+    if(scatts->scatt_idxs[scatt_id] < 0)
-+        return -1;
-+
-+    scatt_data = scatts->scatts_arr[scatt_idx];
-+
-+    for(i_scatt = scatt_idx; i_scatt < scatts->n_a_scatts - 1; i_scatt++)
-+    {
-+        scatts->scatts_arr[i_scatt] = scatts->scatts_arr[i_scatt + 1];
-+        scatts->scatts_bands[i_scatt * 2] = scatts->scatts_bands[(i_scatt + 1)* 2];
-+        scatts->scatts_bands[i_scatt * 2 + 1] = scatts->scatts_bands[(i_scatt + 1) * 2 + 1];
-+    }
-+    scatts->scatts_arr[scatts->n_a_scatts] = NULL;
-+
-+    scatts->scatt_idxs[scatt_id] = -1;
-+
-+    scatt_data = scatts->scatts_arr[scatt_id];
-+    scatts->n_a_scatts--;
-+
-+    return 0;
-+}
-+
-+int I_sc_set_value(struct scCats * cats, int cat_id, int scatt_id, int value_idx, int value)
-+{
-+    int n_a_scatts = cats->cats_arr[cat_id]->n_a_scatts;
-+    int cat_idx, scatt_idx, ret;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    if(cat_idx < 0)
-+        return -1;
-+    
-+    if(cats->cats_arr[cat_idx]->scatt_idxs[scatt_id] < 0)
-+        return -1;
-+
-+    cat_idx = cats->cats_idxs[cat_id];
-+    scatt_idx = cats->cats_arr[cat_idx]->scatt_idxs[scatt_id];
-+
-+    I_scd_set_value(cats->cats_arr[cat_idx]->scatts_arr[scatt_idx], value_idx, value);
-+
-+    return 0;
-+}
-+#endif
-+
-+/*!
-+   \brief Insert scatter plot data.
-+    
-+   \param scatt_data pointer to existing struct scdScattData
-+   \param type SC_SCATT_DATA for scatter plots or SC_SCATT_CONDITIONS for selected areas in scatter plot
-+   \param n_vals number of data values
-+   \param data array of values (unsigned char for SC_SCATT_CONDITIONS, unsigned int for SC_SCATT_DATA)
-+ */
-+void I_scd_init_scatt_data(struct scdScattData * scatt_data, int type, int n_vals, void * data)
-+{
-+    scatt_data->n_vals = n_vals;
-+
-+    if(type == SC_SCATT_DATA)
-+    {   
-+        if(data)
-+            scatt_data->scatt_vals_arr = (unsigned int *) data;
-+        else {
-+            scatt_data->scatt_vals_arr = (unsigned int *) G_malloc(n_vals * sizeof(unsigned int));
-+            memset(scatt_data->scatt_vals_arr, 0, n_vals * sizeof(unsigned int)); 
-+        }
-+        scatt_data->b_conds_arr = NULL;
-+    }
-+    else if(type == SC_SCATT_CONDITIONS)
-+    {
-+        if(data)
-+            scatt_data->b_conds_arr = (unsigned char *) data;
-+        else {
-+            scatt_data->b_conds_arr = (unsigned char *) G_malloc(n_vals * sizeof(unsigned char));
-+            memset(scatt_data->b_conds_arr, 0, n_vals * sizeof(unsigned char));
-+        }
-+        scatt_data->scatt_vals_arr = NULL;
-+    }
-+
-+    return;
-+}
-+
-+
-+#if 0
-+void I_scd_get_range_min_max(struct scdScattData * scatt_data, CELL * band_1_min, CELL * band_1_max, CELL * band_2_min, CELL * band_2_max)
-+{
-+
-+    Rast_get_range_min_max(&(scatt_data->band_1_range), band_1_min, band_2_min);
-+    Rast_get_range_min_max(&(scatt_data->band_2_range), band_2_min, band_2_max);
-+
-+    return;
-+}
-+s
-+void * I_scd_get_data_ptr(struct scdScattData * scatt_data)
-+{
-+    if(!scatt_data->b_conds_arr)
-+        return scatt_data->b_conds_arr;
-+    else if(!scatt_data->scatt_vals_arr)
-+        return scatt_data->scatt_vals_arr;
-+
-+    return NULL;
-+}
-+
-+int I_scd_set_value(struct scdScattData * scatt_data, unsigned int val_idx, unsigned int val)
-+{
-+    if(val_idx < 0 && val_idx >  scatt_data->n_vals)
-+        return -1;
-+
-+    if(scatt_data->b_conds_arr)
-+        scatt_data->b_conds_arr[val_idx] = val;
-+    else if(scatt_data->scatt_vals_arr)
-+        scatt_data->scatt_vals_arr[val_idx] = val;
-+    else
-+        return -1;
-+
-+    return 0;
-+}
-+#endif



More information about the grass-commit mailing list