[Kst] branches/work/kst/portto4/kst/src/libkstapp

Barth Netterfield netterfield at astro.utoronto.ca
Thu Apr 21 15:25:37 CEST 2011


SVN commit 1228662 by netterfield:

Major re-write of the auto-layout rmb command: it works much better now!
Note: no change has yet been made to *insertion* of new plots.  That is next.



 M  +185 -18   viewitem.cpp  
 M  +14 -1     viewitem.h  


--- branches/work/kst/portto4/kst/src/libkstapp/viewitem.cpp #1228661:1228662
@@ -35,6 +35,7 @@
 #include <QInputDialog>
 #include <QDrag>
 #include <QMimeData>
+#include <QtAlgorithms>
 
 static const double ONE_PI = 3.14159265358979323846264338327950288419717;
 static double TWO_PI = 2.0 * ONE_PI;
@@ -2054,15 +2055,189 @@
   _layout->apply();
 }
 
+/*****************************************************************************/
+/************** local helper functions for auto layout ***********************/
+void appendEdge(QList<struct AutoFormatEdges> &edges, double pos, double size, double grid, ViewItem *item) {
+  struct AutoFormatEdges edge;
 
+  edge.edge_number = -1;
+  edge.item = item;
+
+  // FIXME: do we really want to do this, or should we re-scale the lists at the end instead?
+  //size = qMax(size, grid);
+  //size = qMin(1.0, size);
+  //pos =  qMax(pos - size, 0.0);
+  //if (pos + size>1.0) {
+  //  pos = 1.0 - size;
+  //}
+
+  edge.edge = pos; // left edge
+  edge.left_or_top = true;
+  edges.append(edge);
+  edge.edge = pos+size; // right edge
+  edge.left_or_top = false;
+  edges.append(edge);
+
+}
+
+/*****************************************************************************/
+/************** local helper functions for auto layout ***********************/
+bool findNextEdgeLocation(QList<struct AutoFormatEdges> &edges, QList<qreal> &locations, qreal grid_resolution) {
+  int n_edges = edges.size();
+
+  int i_best_edge = -1;
+  int this_edge_count = 0;
+  int best_edge_count = 0;
+
+  for (int i_edge = 0; i_edge<n_edges; ++i_edge) {
+    this_edge_count = 0;
+    if (edges.at(i_edge).edge_number == -1) {
+      // count edges that are near this edge
+      for (int j_edge = 0; j_edge<n_edges; ++j_edge) {
+        if (edges.at(j_edge).edge_number == -1) {
+          if ((edges.at(j_edge).edge >= edges.at(i_edge).edge) &&
+              (edges.at(j_edge).edge <= edges.at(i_edge).edge+grid_resolution)) {
+            this_edge_count++;
+          }
+        }
+      }
+      if (this_edge_count > best_edge_count) {
+        i_best_edge = i_edge;
+        best_edge_count = this_edge_count;
+      }
+    }
+  }
+  // now i_best_edge holds the index of the edge with the most other edges
+  // 'close' to it (ie, between edge and edge + grid_resolution)
+  if (i_best_edge >= 0 ) {
+    int edge_location = locations.size();
+    qreal sum_edge = 0.0; // to get the mean of this edge
+    // Set edge_number of all of the edges which are in this area
+    qreal best_edge = edges.at(i_best_edge).edge;
+    for (int i_edge = best_edge; i_edge < n_edges; i_edge++) {
+      if ((edges.at(i_edge).edge >= best_edge) &&
+          (edges.at(i_edge).edge <= best_edge+grid_resolution)) {
+        edges[i_edge].edge_number = edge_location;
+        sum_edge += edges.at(i_edge).edge;
+      }
+    }
+    best_edge = sum_edge/qreal(best_edge_count);
+
+    locations.append(best_edge);
+    return true;
+  } else {
+    return false;
+  }
+}
+
+/*****************************************************************************/
+/************** local helper functions for auto layout ***********************/
+void convertEdgeLocationsToGrid(const QList<qreal> &locations, QList<int> &grid_locations) {
+
+  QList<qreal> sorted_locations(locations);
+  qSort(sorted_locations);
+
+  int n_loc = locations.size();
+  for (int i_unsorted = 0; i_unsorted<n_loc; i_unsorted++) {
+    for (int i_sorted = 0; i_sorted<n_loc; i_sorted++) {
+      if (locations.at(i_unsorted) == sorted_locations.at(i_sorted)) {
+        grid_locations.append(i_sorted);
+        break;
+      }
+    }
+  }
+}
+
+/*****************************************************************************/
+/************** local helper functions for auto layout ***********************/
+void generateRCList(const QList<ViewItem*> &viewItems, QList<struct AutoFormatRC> &rcList) {
+  const double min_size_limit = 0.05;
+
+  double min_height = 1.0;
+  double min_width = 1.0;
+
+  // Find the smallest plots, to determine the grid resolution
+  int n_view = viewItems.size();
+  for (int i_view = 0; i_view<n_view; i_view++) {
+    ViewItem *item = viewItems.at(i_view);
+    if ((item->relativeWidth()<min_width) && (item->relativeWidth()>min_size_limit)) {
+      min_width = item->relativeWidth();
+    }
+    if ((item->relativeHeight()<min_height) && (item->relativeHeight()>min_size_limit)) {
+      min_height = item->relativeHeight();
+    }
+  }
+  double grid_x_tolerance = min_height*0.3;
+  double grid_y_tolerance = min_width*0.3;
+
+  // Find all the edges
+  QList<struct AutoFormatEdges> x_edges;
+  QList<struct AutoFormatEdges> y_edges;
+  for (int i_view = 0; i_view<n_view; i_view++) {
+    ViewItem *item = viewItems.at(i_view);
+
+    appendEdge(x_edges, item->relativeCenter().x() - 0.5*item->relativeWidth(), item->relativeWidth(), grid_x_tolerance, item);
+    appendEdge(y_edges, item->relativeCenter().y() - 0.5*item->relativeHeight(), item->relativeHeight(), grid_y_tolerance, item);
+  }
+
+  // find edge concentrations
+  QList<qreal> x_edge_locations;
+  QList<qreal> y_edge_locations;
+  while (findNextEdgeLocation(x_edges, x_edge_locations, grid_x_tolerance)) {
+  }
+  while (findNextEdgeLocation(y_edges, y_edge_locations, grid_y_tolerance)) {
+  }
+
+  QList<int> x_edge_grid;
+  QList<int> y_edge_grid;
+  convertEdgeLocationsToGrid(x_edge_locations, x_edge_grid);
+  convertEdgeLocationsToGrid(y_edge_locations, y_edge_grid);
+  // x_edges: list of edges, each of which points to a x_edge_location and to a view item
+  // x_edge_location: a list of where the edge concentrations are.
+  // x_edge_grid: a list of grid indicies; same order as x_edge_location
+
+  foreach (ViewItem *v, viewItems) {
+    int left_gpos = 0;
+    int right_gpos = 1;
+    int top_gpos = 0;
+    int bottom_gpos = 1;
+    struct AutoFormatRC rc;
+    foreach (const AutoFormatEdges &edge, x_edges) {
+      if (edge.item == v) {
+        if (edge.left_or_top) {
+          left_gpos = x_edge_grid.at(edge.edge_number);
+        } else {
+          right_gpos = x_edge_grid.at(edge.edge_number);
+        }
+      }
+    }
+    foreach (const AutoFormatEdges &edge, y_edges) {
+      if (edge.item == v) {
+        if (edge.left_or_top) {
+          top_gpos = y_edge_grid.at(edge.edge_number);
+        } else {
+          bottom_gpos = y_edge_grid.at(edge.edge_number);
+        }
+      }
+    }
+    rc.row = top_gpos;
+    rc.col = left_gpos;
+    rc.row_span = bottom_gpos - top_gpos;
+    rc.col_span = right_gpos - left_gpos;
+    rcList.append(rc);
+  }
+}
+/*****************************************************************************/
+
 void LayoutCommand::createLayout(int columns) {
   Q_ASSERT(_item);
   Q_ASSERT(_item->view());
 
   QList<ViewItem*> viewItems;
   QList<QGraphicsItem*> list = _item->QGraphicsItem::children();
-  if (list.isEmpty())
+  if (list.isEmpty()) {
     return; //not added to undostack
+  }
 
   foreach (QGraphicsItem *item, list) {
     ViewItem *viewItem = qgraphicsitem_cast<ViewItem*>(item);
@@ -2071,28 +2246,20 @@
     viewItems.append(viewItem);
   }
 
-  if (viewItems.isEmpty())
+  if (viewItems.isEmpty()) {
     return; //not added to undostack
+  }
 
-  Grid *grid = Grid::buildGrid(viewItems, columns);
-  Q_ASSERT(grid);
-
   _layout = new ViewGridLayout(_item);
 
-  foreach (ViewItem *v, viewItems) {
-    int r = 0, c = 0, rs = 0, cs = 0;
-    if (grid->locateWidget(v, r, c, rs, cs)) {
-      _layout->addViewItem(v, r, c, rs, cs);
-    } else {
-      grid->appendItem(v);
-      if (grid->locateWidget(v, r, c, rs, cs)) {
-        _layout->addViewItem(v, r, c, rs, cs);
-      } else {
-        qDebug() << "ooops, viewItem does not fit in layout" << endl;
+  QList<struct AutoFormatRC> rcList;
+  generateRCList(viewItems, rcList);
+  int n_views = viewItems.size();
+  for (int i_view = 0; i_view<n_views; i_view++) {
+    ViewItem *v = viewItems.at(i_view);
+    struct AutoFormatRC rc = rcList.at(i_view);
+    _layout->addViewItem(v, rc.row, rc.col, rc.row_span, rc.col_span);
       }
-    }
-  }
-  delete grid;
 
   if (qobject_cast<LayoutBoxItem*>(_item)) {
     QObject::connect(_layout, SIGNAL(enabledChanged(bool)),
--- branches/work/kst/portto4/kst/src/libkstapp/viewitem.h #1228661:1228662
@@ -397,7 +397,6 @@
     virtual void undo();
     virtual void redo();
     void createLayout(int columns = 0);
-
   private:
     QPointer<ViewGridLayout> _layout;
 };
@@ -568,6 +567,20 @@
   static const MimeDataViewItem* downcast(const QMimeData*);
 };
 
+struct AutoFormatEdges {
+  int edge_number;
+  qreal edge;
+  bool left_or_top;
+  ViewItem *item;
+};
+
+struct AutoFormatRC {
+  int row;
+  int row_span;
+  int col;
+  int col_span;
+};
+
 }
 
 #endif


More information about the Kst mailing list