src/split.cpp

Go to the documentation of this file.
00001 // Copyright (c) 2003 - 2004 Anselm R. Garbe <anselmg at t-online.de>
00002 // See ../LICENSE.txt for license details.
00003 //
00004 // $Id: split.cpp 2 2007-05-16 10:38:27Z eg $
00005 
00006 extern "C" {
00007 #include <assert.h>
00008 }
00009 
00010 #include <cmath>
00011 
00012 #include "split.h"
00013 
00014 #include "frame.h"
00015 #include "logger.h"
00016 #include "rectangle.h"
00017 #include "tree.h"
00018 #include "util.h"
00019 
00020 Tree *Split::topMostRoot(Tree *first, Tree *last) {
00021 
00022     assert(first);
00023     assert(last);
00024 
00025     Tree *tmp = first;
00026     while (tmp->parent()) {
00027         tmp = tmp->parent();
00028         tmp->setVisit(tmp->visits() + 1);
00029     }
00030 
00031     tmp = last;
00032     while (tmp->parent()) {
00033         tmp = tmp->parent();
00034         tmp->setVisit(tmp->visits() + 1);
00035     }
00036 
00037     // now all tree nodes have been marked, let's
00038     // search for the first tree node with two visits,
00039     // this is the topmost root of first an last
00040 
00041     Tree *result = first;
00042     while (result->visits() < 2) {
00043         result = result->parent();
00044     }
00045 
00046     // we got the result, now cleanup on both paths
00047     tmp = first;
00048     while (tmp->parent()) {
00049         tmp = tmp->parent();
00050         tmp->setVisit(0);
00051     }
00052 
00053     tmp = last;
00054     while (tmp->parent()) {
00055         tmp = tmp->parent();
00056         tmp->setVisit(0);
00057     }
00058 
00059     return result;
00060 }
00061 
00062 // applied patch by Dr. J. Pfefferl
00063 void Split::resize(Tree *root, Tree *origin,
00064                    Direction dir, int stepW, int stepH)
00065 {
00066     int newW, newH;
00067 
00068     if (!origin->frame()) {
00069         return;
00070     }
00071 
00072     Tree *neighbor = Split::neighbor(root, origin, dir);
00073     if (!neighbor|| !neighbor->parent()) {
00074         return;
00075     }
00076 
00077     // Normalize stepH/W to positive numbers
00078     // This is necessary to guarantee that the boundary checks
00079     // for newW/newH later on work under all circumstances!
00080     if(0 > stepH || 0 > stepW) {
00081         stepH *= -1;
00082         stepW *= -1;
00083         // Reverse the grow/shrink directions accordingly
00084         switch(dir) {
00085         case LEFT:  dir = RIGHT; break;
00086         case RIGHT: dir = LEFT;  break;
00087         case UP:    dir = DOWN;  break;
00088         case DOWN:  dir = UP;    break;
00089         default: break; // Should not happen
00090         }
00091     }
00092 
00093     // neighbor is the nearest neighbor, but this can be
00094     // a subtree of the top-level neighbor, so we've to
00095     // determine the top-level neighbor
00096     Tree *parent = topMostRoot(origin, neighbor);
00097 
00098     // determine the correct root for resizing and if we
00099     // should grow or shrink the origin
00100     Tree *growTree, *shrinkTree;
00101     if ((dir == LEFT) || (dir == UP)) {
00102         // shrink
00103         growTree = parent->last();
00104         shrinkTree = parent->first();
00105     }
00106     else {
00107         // grow
00108         growTree = parent->first();
00109         shrinkTree = parent->last();
00110     }
00111 
00112     switch (dir) {
00113     case LEFT:
00114         newW = shrinkTree->width() - stepW;
00115         if (0 >= newW) {
00116             return;
00117         }
00118         growTree->setX(growTree->x() - stepW);
00119         growTree->setWidth(growTree->width() + stepW);
00120         shrinkTree->setWidth(newW);
00121         break;
00122     case RIGHT:
00123         newW = shrinkTree->width() - stepW;
00124         if (0 >= newW) {
00125             return;
00126         }
00127         growTree->setWidth(growTree->width() + stepW);
00128         shrinkTree->setX(shrinkTree->x() + stepW);
00129         shrinkTree->setWidth(newW);
00130         break;
00131     case UP:
00132         newH = shrinkTree->height() - stepH;
00133         if (0 >= newH) {
00134             return;
00135         }
00136         growTree->setY(growTree->y() - stepH);
00137         growTree->setHeight(growTree->height() + stepH);
00138         shrinkTree->setHeight(newH);
00139         break;
00140     case DOWN:
00141         newH = shrinkTree->height() - stepH;
00142         if(0 >= newH) {
00143             return;
00144         }
00145         growTree->setHeight(growTree->height() + stepH);
00146         shrinkTree->setY(shrinkTree->y() + stepH);
00147         shrinkTree->setHeight(newH);
00148         break;
00149     default:
00150         break;
00151     }
00152     adjustSize(growTree, ((dir == LEFT) || (dir == RIGHT)));
00153     adjustSize(shrinkTree, ((dir == LEFT) || (dir == RIGHT)));
00154 }
00155 
00156 int Split::distance(Tree *origin, Tree *target) {
00157 
00158     int ox = origin->x() + origin->width() / 2;
00159     int oy = origin->y() + origin->height() / 2;
00160     int tx = target->x() + target->width() / 2;
00161     int ty = target->y() + target->height() / 2;
00162 
00163     return (int)sqrt((double)(((ox - tx) * (ox - tx)) +
00164                               ((oy - ty) * (oy - ty))));
00165 }
00166 
00167 bool Split::isNeighbor(Tree *origin, Tree *target, Direction dir) {
00168 
00169     switch (dir) {
00170     case LEFT:
00171         return origin->x() >= (int)(target->x() + target->width());
00172         break;
00173     case RIGHT:
00174         return (int)(origin->x() + origin->width()) <= target->x();
00175         break;
00176     case UP:
00177         return origin->y() >= (int)(target->y() + target->height());
00178         break;
00179     case DOWN:
00180         return (int)(origin->y() + origin->height()) <= target->y();
00181         break;
00182     default:
00183         return false;
00184         break;
00185     }
00186 }
00187 
00188 Tree *Split::neighbor(Tree *root, Tree *origin, Direction dir) {
00189 
00190     if (root == 0) {
00191         return 0;
00192     }
00193 
00194     Tree *result1 = neighbor(root->first(), origin, dir);
00195     if (!result1 && root->first()) {
00196         result1 = root->first();
00197     }
00198 
00199     Tree *result2 = neighbor(root->last(), origin, dir);
00200     if (!result2 && root->last()) {
00201         result2 = root->last();
00202     }
00203 
00204     bool res1 = result1 && (result1 != origin)
00205                 && isNeighbor(origin, result1, dir);
00206     bool res2 = result2 && (result2 != origin)
00207                 && isNeighbor(origin, result2, dir);
00208 
00209     if (res1 && res2) {
00210 
00211         if (distance(origin, result1)
00212             < distance(origin, result2))
00213         {
00214             return result1;
00215         }
00216         else {
00217             return result2;
00218         }
00219     }
00220     else if (res1) {
00221         return result1;
00222     }
00223     else if (res2) {
00224         return result2;
00225     }
00226 
00227     return 0;
00228 }
00229 
00230 void Split::adjustSize(Tree *tree, bool ignoreVert) {
00231 
00232     Tree *first = tree->first();
00233     Tree *last = tree->last();
00234     if (first) {
00235         assert(last);
00236         if (tree->isHoriz()) {
00237             // horizontal split
00238             if (ignoreVert) {
00239                 first->copy(tree);
00240                 first->setWidth(tree->width() / 2);
00241                 last->copy(first);
00242                 last->setX(first->x() + first->width());
00243             }
00244             else {
00245                 // beware horiz order
00246                 first->setY(tree->y());
00247                 first->setHeight(tree->height());
00248                 last->setY(tree->y());
00249                 last->setHeight(tree->height());
00250             }
00251         }
00252         else {
00253             // vertical split
00254             if (!ignoreVert) {
00255                 first->copy(tree);
00256                 first->setHeight(tree->height() / 2);
00257                 last->copy(first);
00258                 last->setY(first->y() + first->height());
00259             }
00260             else {
00261                 // beware vert order
00262                 first->setX(tree->x());
00263                 first->setWidth(tree->width());
00264                 last->setX(tree->x());
00265                 last->setWidth(tree->width());
00266             }
00267         }
00268         adjustSize(first, ignoreVert);
00269         adjustSize(last, ignoreVert);
00270     }
00271     else {
00272         Frame *frame = tree->frame();
00273         if (frame) {
00274             frame->copy(tree);
00275             frame->resize();
00276         }
00277     }
00278 }
00279 
00280 void Split::detach(Tree *root, Tree *origin) {
00281 
00282     Tree *parent = origin->parent();
00283 
00284     if (parent) {
00285         Tree *child = (parent->first() != origin)
00286                       ? parent->first() : parent->last();
00287         delete origin;
00288         assert(child);
00289         if (child->first()) {
00290             assert(child->last());
00291             assert(!child->frame());
00292             parent->setChilds(child->first(), child->last());
00293             parent->setHoriz(child->isHoriz());
00294             adjustSize(parent, parent->isHoriz());
00295             delete child;
00296         }
00297         else {
00298             Frame *frame = child->frame();
00299             assert(frame);
00300             parent->setFrame(frame);
00301             parent->setChilds(0, 0);
00302             frame->resize();
00303             delete child;
00304         }
00305     }
00306     else {
00307         assert(origin == root);
00308         root->setFrame(0);
00309     }
00310 }
00311 
00312 Frame *Split::firstLeaf(Tree *tree) {
00313 
00314     if (tree->frame()) {
00315         return tree->frame();
00316     }
00317     if (tree->first() && tree->first()->frame()) {
00318         return tree->first()->frame();
00319     }
00320     if (tree->last() && tree->last()->frame()) {
00321         return tree->last()->frame();
00322     }
00323     if (tree->first()) {
00324         return firstLeaf(tree->first());
00325     }
00326     else if (tree->last()) {
00327         return firstLeaf(tree->last());
00328     }
00329     return 0;
00330 }
00331 
00332 void Split::attach(Tree *root, Frame *frame, Direction dir) {
00333 
00334     Rectangle rect;
00335     assert(root->first() == 0);
00336 
00337     Frame *oldFrame = root->frame();
00338     if (!oldFrame) {
00339         root->setFrame(frame);
00340     }
00341     else {
00342         root->setFrame(0);
00343         rect.copy(root);
00344 
00345         if ((dir == LEFT) || (dir == RIGHT)) {
00346             root->setHoriz(true);
00347             rect.setWidth(rect.width() / 2);
00348         }
00349         else {
00350             root->setHoriz(false);
00351             rect.setHeight(rect.height() / 2);
00352         }
00353 
00354         Tree *first = new Tree(root, &rect);
00355         Tree *last;
00356         if ((dir == LEFT) || (dir == UP)) {
00357             first->setFrame(frame);
00358             if (dir ==  LEFT) {
00359                 rect.setX(rect.x() + rect.width());
00360             }
00361             else { // UP
00362                 rect.setY(rect.y() + rect.height());
00363             }
00364             last = new Tree(root, &rect);
00365             last->setFrame(oldFrame);
00366         }
00367         else { // RIGHT || DOWN
00368             first->setFrame(oldFrame);
00369             if (dir ==  RIGHT) {
00370                 rect.setX(rect.x() + rect.width());
00371             }
00372             else { // DOWN
00373                 rect.setY(rect.y() + rect.height());
00374             }
00375             last = new Tree(root, &rect);
00376             last->setFrame(frame);
00377         }
00378         root->setChilds(first, last);
00379         oldFrame->resize();
00380     }
00381     frame->resize();
00382 }

Generated on Thu May 24 15:19:32 2007 for ncwm by  doxygen 1.5.1