+
+ for (TWindow w: windows) {
+ if (w.isModal()) {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Close all open windows.
+ */
+ private void closeAllWindows() {
+ // Don't do anything if we are in the menu
+ if (activeMenu != null) {
+ return;
+ }
+ while (windows.size() > 0) {
+ closeWindow(windows.get(0));
+ }
+ }
+
+ /**
+ * Re-layout the open windows as non-overlapping tiles. This produces
+ * almost the same results as Turbo Pascal 7.0's IDE.
+ */
+ private void tileWindows() {
+ synchronized (windows) {
+ // Don't do anything if we are in the menu
+ if (activeMenu != null) {
+ return;
+ }
+ int z = windows.size();
+ if (z == 0) {
+ return;
+ }
+ int a = 0;
+ int b = 0;
+ a = (int)(Math.sqrt(z));
+ int c = 0;
+ while (c < a) {
+ b = (z - c) / a;
+ if (((a * b) + c) == z) {
+ break;
+ }
+ c++;
+ }
+ assert (a > 0);
+ assert (b > 0);
+ assert (c < a);
+ int newWidth = (getScreen().getWidth() / a);
+ int newHeight1 = ((getScreen().getHeight() - 1) / b);
+ int newHeight2 = ((getScreen().getHeight() - 1) / (b + c));
+
+ List<TWindow> sorted = new LinkedList<TWindow>(windows);
+ Collections.sort(sorted);
+ Collections.reverse(sorted);
+ for (int i = 0; i < sorted.size(); i++) {
+ int logicalX = i / b;
+ int logicalY = i % b;
+ if (i >= ((a - 1) * b)) {
+ logicalX = a - 1;
+ logicalY = i - ((a - 1) * b);
+ }
+
+ TWindow w = sorted.get(i);
+ w.setX(logicalX * newWidth);
+ w.setWidth(newWidth);
+ if (i >= ((a - 1) * b)) {
+ w.setY((logicalY * newHeight2) + 1);
+ w.setHeight(newHeight2);
+ } else {
+ w.setY((logicalY * newHeight1) + 1);
+ w.setHeight(newHeight1);
+ }
+ }
+ }
+ }
+
+ /**
+ * Re-layout the open windows as overlapping cascaded windows.
+ */
+ private void cascadeWindows() {
+ synchronized (windows) {
+ // Don't do anything if we are in the menu
+ if (activeMenu != null) {
+ return;
+ }
+ int x = 0;
+ int y = 1;
+ List<TWindow> sorted = new LinkedList<TWindow>(windows);
+ Collections.sort(sorted);
+ Collections.reverse(sorted);
+ for (TWindow window: sorted) {
+ window.setX(x);
+ window.setY(y);
+ x++;
+ y++;
+ if (x > getScreen().getWidth()) {
+ x = 0;
+ }
+ if (y >= getScreen().getHeight()) {
+ y = 1;
+ }
+ }
+ }
+ }
+
+ /**
+ * Place a window to minimize its overlap with other windows.
+ *
+ * @param window the window to place
+ */
+ public final void doSmartPlacement(final TWindow window) {
+ // This is a pretty dumb algorithm, but seems to work. The hardest
+ // part is computing these "overlap" values seeking a minimum average
+ // overlap.
+ int xMin = 0;
+ int yMin = desktopTop;
+ int xMax = getScreen().getWidth() - window.getWidth() + 1;
+ int yMax = desktopBottom - window.getHeight() + 1;
+ if (xMax < xMin) {
+ xMax = xMin;
+ }
+ if (yMax < yMin) {
+ yMax = yMin;
+ }
+
+ if ((xMin == xMax) && (yMin == yMax)) {
+ // No work to do, bail out.
+ return;
+ }
+
+ // Compute the overlap matrix without the new window.
+ int width = getScreen().getWidth();
+ int height = getScreen().getHeight();
+ int overlapMatrix[][] = new int[width][height];
+ for (TWindow w: windows) {
+ if (window == w) {
+ continue;
+ }
+ for (int x = w.getX(); x < w.getX() + w.getWidth(); x++) {
+ if (x == width) {
+ continue;
+ }
+ for (int y = w.getY(); y < w.getY() + w.getHeight(); y++) {
+ if (y == height) {
+ continue;
+ }
+ overlapMatrix[x][y]++;
+ }
+ }
+ }
+
+ long oldOverlapTotal = 0;
+ long oldOverlapN = 0;
+ for (int x = 0; x < width; x++) {
+ for (int y = 0; y < height; y++) {
+ oldOverlapTotal += overlapMatrix[x][y];
+ if (overlapMatrix[x][y] > 0) {
+ oldOverlapN++;
+ }
+ }
+ }
+
+
+ double oldOverlapAvg = (double) oldOverlapTotal / (double) oldOverlapN;
+ boolean first = true;
+ int windowX = window.getX();
+ int windowY = window.getY();
+
+ // For each possible (x, y) position for the new window, compute a
+ // new overlap matrix.
+ for (int x = xMin; x < xMax; x++) {
+ for (int y = yMin; y < yMax; y++) {
+
+ // Start with the matrix minus this window.
+ int newMatrix[][] = new int[width][height];
+ for (int mx = 0; mx < width; mx++) {
+ for (int my = 0; my < height; my++) {
+ newMatrix[mx][my] = overlapMatrix[mx][my];
+ }
+ }
+
+ // Add this window's values to the new overlap matrix.
+ long newOverlapTotal = 0;
+ long newOverlapN = 0;
+ // Start by adding each new cell.
+ for (int wx = x; wx < x + window.getWidth(); wx++) {
+ if (wx == width) {
+ continue;
+ }
+ for (int wy = y; wy < y + window.getHeight(); wy++) {
+ if (wy == height) {
+ continue;
+ }
+ newMatrix[wx][wy]++;
+ }
+ }
+ // Now figure out the new value for total coverage.
+ for (int mx = 0; mx < width; mx++) {
+ for (int my = 0; my < height; my++) {
+ newOverlapTotal += newMatrix[x][y];
+ if (newMatrix[mx][my] > 0) {
+ newOverlapN++;
+ }
+ }
+ }
+ double newOverlapAvg = (double) newOverlapTotal / (double) newOverlapN;
+
+ if (first) {
+ // First time: just record what we got.
+ oldOverlapAvg = newOverlapAvg;
+ first = false;
+ } else {
+ // All other times: pick a new best (x, y) and save the
+ // overlap value.
+ if (newOverlapAvg < oldOverlapAvg) {
+ windowX = x;
+ windowY = y;
+ oldOverlapAvg = newOverlapAvg;
+ }
+ }
+
+ } // for (int x = xMin; x < xMax; x++)
+
+ } // for (int y = yMin; y < yMax; y++)
+
+ // Finally, set the window's new coordinates.
+ window.setX(windowX);
+ window.setY(windowY);