[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