Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include "docklayout.h"
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <assert.h></assert.h>
Toshihiro Shimizu 890ddd
#include <math.h></math.h>
Toshihiro Shimizu 890ddd
#include <algorithm></algorithm>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
#include <qtextstream></qtextstream>
Toshihiro Shimizu 890ddd
#include <qapplication></qapplication>
Toshihiro Shimizu 890ddd
#include <qdesktopwidget></qdesktopwidget>
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// TO DO:
Toshihiro Shimizu 890ddd
//  * Usa la macro QWIDGETSIZE_MAX per max grandezza settabile per una widget
Shinya Kitaoka 120a6e
//      => Dopodiche', basterebbe troncare tutte le somme che eccedono quel
Shinya Kitaoka 120a6e
//      valore... Comunque...
Shinya Kitaoka 120a6e
//  * Il ricalcolo delle extremal sizes e' inutile nei resize events... Cerca di
Shinya Kitaoka 120a6e
//  tagliare cose di questo tipo - ottimizza!
Shinya Kitaoka 120a6e
//      => Pero' e' sensato in generale che redistribute possa ricalcolarle -
Shinya Kitaoka 120a6e
//      forse si potrebbe fare una redistribute
Shinya Kitaoka 120a6e
//         con un bool di ingresso. Se l'operazione contenitrice non puo'
Shinya Kitaoka 120a6e
//         cambiare le extremal sizes, allora metti false..
Toshihiro Shimizu 890ddd
//  * Implementa gli stretch factors
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//  * Nascondere le finestre dockate...? Molto rognoso...
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//  * Una dock widget potrebbe non avere i soli stati docked e floating... Che
Shinya Kitaoka 120a6e
//  succede se e' una subwindow
Toshihiro Shimizu 890ddd
//    non dockata in un dockLayout??
Toshihiro Shimizu 890ddd
//  * Spezzare tdockwindows.h in tmainwindow.h e tdockwidget.h, come in Qt?
Shinya Kitaoka 120a6e
//  * Muovere o fare operazioni su una dockWidget allo stato attuale non e'
Shinya Kitaoka 120a6e
//  sicuro se quella non e' assegnata ad
Shinya Kitaoka 120a6e
//    un DockLayout!! Comunque, si puo' assumere che il parente di una
Shinya Kitaoka 120a6e
//    DockWidget non sia nemmeno una QWidget
Shinya Kitaoka 120a6e
//    che implementa un DockLayout. Questa cosa puo' venire meno in
Shinya Kitaoka 120a6e
//    un'implementazione specifica come TDockWidget?
Shinya Kitaoka 120a6e
//      Esempio: vedi calculateDockPlaceholders ad un drag, viene lanciato
Shinya Kitaoka 120a6e
//      comunque...
Shinya Kitaoka 120a6e
//  * Ha senso mettere DockLayout e DockWidget nella DVAPI? Forse se definissi
Shinya Kitaoka 120a6e
//  delle inline opportune in TDockWidget...
Shinya Kitaoka 120a6e
//  * Quanto contenuto in DockSeparator::mousePress e mouseMove dovrebbe essere
Shinya Kitaoka 120a6e
//  reso pubblico. Anche la geometria
Shinya Kitaoka 120a6e
//    delle regioni potrebbe essere editabile dall'utente... ma prima si
Shinya Kitaoka 120a6e
//    dovrebbero fare gli stretch factors!!
Shinya Kitaoka 120a6e
//      > Ossia: se si vuole esplicitamente settare la geometria di una regione,
Shinya Kitaoka 120a6e
//      si potrebbe fare che quella
Toshihiro Shimizu 890ddd
//        si prende stretch factor infinito (o quasi), e gli altri 1...
Shinya Kitaoka 120a6e
//  * Dovrebbe esistere un modo per specificare la posizione dei separatori da
Shinya Kitaoka 120a6e
//  codice?
Shinya Kitaoka 120a6e
//    Rognoso. Comunque, ora basta specificare la geometria delle widget prima
Shinya Kitaoka 120a6e
//    del dock;
Toshihiro Shimizu 890ddd
//    la redistribute cerca di adattarsi.
Shinya Kitaoka 120a6e
//  * Capita spesso di considerare l'ipotetica nuova radice della struttura.
Shinya Kitaoka 120a6e
//  Perche' non metterla direttamente??
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//  X Non e' possibile coprire tutte le possibilita' di docking con il sistema
Shinya Kitaoka 120a6e
//  attuale, anche se e' comunque piu'
Toshihiro Shimizu 890ddd
//    esteso di quello di Qt.
Toshihiro Shimizu 890ddd
//      Esempio:           |
Toshihiro Shimizu 890ddd
//                    -----|
Toshihiro Shimizu 890ddd
//                      |  |        => !!
Toshihiro Shimizu 890ddd
//                      |-----
Toshihiro Shimizu 890ddd
//                      |
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------
Toshihiro Shimizu 890ddd
//    Geometry inlines
Toshihiro Shimizu 890ddd
//------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// QRectF::toRect seems to work in the commented way inside the following
Shinya Kitaoka 120a6e
// function.
Shinya Kitaoka 120a6e
// Of course that way the rect borders are *not* approximated to the nearest
Shinya Kitaoka 120a6e
// integer
Shinya Kitaoka 120a6e
// coordinates:
Shinya Kitaoka 120a6e
//  e.g.:   topLeft= (1/3, 1/3); width= 4/3, height= 4/3 => left= top= right=
Shinya Kitaoka 120a6e
//  bottom= 0.
Shinya Kitaoka 120a6e
inline QRect toRect(const QRectF &rect) {
Shinya Kitaoka 120a6e
  // return QRect(qRound(rect.left()), qRound(rect.top()), qRound(rect.width()),
Shinya Kitaoka 120a6e
  // qRound(rect.height()));
Shinya Kitaoka 120a6e
  return QRect(rect.topLeft().toPoint(),
Shinya Kitaoka 120a6e
               rect.bottomRight().toPoint() -= QPoint(1, 1));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-----------------
Toshihiro Shimizu 890ddd
//    Dock Layout
Toshihiro Shimizu 890ddd
//-----------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
DockLayout::DockLayout()
Shinya Kitaoka 120a6e
    : m_maximizedDock(0), m_decoAllocator(new DockDecoAllocator()) {}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
DockLayout::~DockLayout() {
Shinya Kitaoka 120a6e
  // Deleting Regions (separators are Widgets with parent, so they are
Shinya Kitaoka 120a6e
  // recursively deleted)
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_regions.size(); ++i) delete m_regions[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Deleting dockWidgets
Shinya Kitaoka 120a6e
  for (i = 0; i < m_items.size(); ++i) {
Shinya Kitaoka 120a6e
    // delete m_items[i]->widget();
Shinya Kitaoka 120a6e
    delete m_items[i];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Delete deco allocator
Shinya Kitaoka 120a6e
  delete m_decoAllocator;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
int DockLayout::count() const { return m_items.size(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
void DockLayout::addItem(QLayoutItem *item) {
Shinya Kitaoka 120a6e
  DockWidget *addedItem = dynamic_cast<dockwidget *="">(item->widget());</dockwidget>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Ensure that added item is effectively a DockWidget type;
Shinya Kitaoka 120a6e
  assert(addedItem);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Check if item is already under layout's control. If so, quit.
Shinya Kitaoka 120a6e
  if (find(addedItem)) return;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Force reparentation. This is required in order to ensure that all items
Shinya Kitaoka 120a6e
  // possess
Shinya Kitaoka 120a6e
  // the same geometry() reference. Also store parentLayout for convenience.
Shinya Kitaoka 120a6e
  addedItem->m_parentLayout = this;
Shinya Kitaoka 120a6e
  addedItem->setParent(parentWidget());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Remember that reparenting a widget produces a window flags reset if the new
Shinya Kitaoka 120a6e
  // parent is not the current one (see Qt's manual). So, first reassign
Shinya Kitaoka 120a6e
  // standard
Shinya Kitaoka 120a6e
  // floating flags, then call for custom appearance (which may eventually
Shinya Kitaoka 120a6e
  // reassign the flags).
Shinya Kitaoka 120a6e
  addedItem->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
Shinya Kitaoka 120a6e
  addedItem->setFloatingAppearance();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_items.push_back(item);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
QLayoutItem *DockLayout::takeAt(int idx) {
Shinya Kitaoka 120a6e
  if (idx < 0 || idx >= (int)m_items.size()) return 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  QLayoutItem *item = m_items[idx];
Shinya Kitaoka 120a6e
  DockWidget *dw    = static_cast<dockwidget *="">(item->widget());</dockwidget>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // If docked, undock item
Shinya Kitaoka 120a6e
  if (!dw->isFloating()) undockItem(dw);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Reset item's parentLayout
Shinya Kitaoka 120a6e
  dw->m_parentLayout = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  m_items.erase(m_items.begin() + idx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return item;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
QLayoutItem *DockLayout::itemAt(int idx) const {
Shinya Kitaoka 120a6e
  if (idx >= (int)m_items.size()) return 0;
Shinya Kitaoka 120a6e
  return m_items[idx];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QWidget *DockLayout::widgetAt(int idx) const { return itemAt(idx)->widget(); }
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
QSize DockLayout::minimumSize() const {
Shinya Kitaoka 120a6e
  if (!m_regions.empty()) {
Shinya Kitaoka 120a6e
    Region *r = m_regions.front();
Shinya Kitaoka 120a6e
    r->calculateExtremalSizes();
Shinya Kitaoka 120a6e
    return QSize(r->m_minimumSize[0], r->m_minimumSize[1]);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return QSize(0, 0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
QSize DockLayout::maximumSize() const {
Shinya Kitaoka 120a6e
  if (!m_regions.empty()) {
Shinya Kitaoka 120a6e
    Region *r = m_regions.front();
Shinya Kitaoka 120a6e
    r->calculateExtremalSizes();
Shinya Kitaoka 120a6e
    return QSize(r->m_maximumSize[0], r->m_maximumSize[1]);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
QSize DockLayout::sizeHint() const {
Shinya Kitaoka 120a6e
  QSize s(0, 0);
Shinya Kitaoka 120a6e
  int n        = m_items.size();
Shinya Kitaoka 120a6e
  if (n > 0) s = QSize(100, 70);  // start with a nice default size
Shinya Kitaoka 120a6e
  int i        = 0;
Shinya Kitaoka 120a6e
  while (i < n) {
Shinya Kitaoka 120a6e
    QLayoutItem *o = m_items[i];
Shinya Kitaoka 120a6e
    s              = s.expandedTo(o->sizeHint());
Shinya Kitaoka 120a6e
    ++i;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return s + n * QSize(spacing(), spacing());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // return QSize(0,0);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//----------------------
Toshihiro Shimizu 890ddd
//    Custom methods
Toshihiro Shimizu 890ddd
//----------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
QWidget *DockLayout::containerOf(QPoint point) const {
Shinya Kitaoka 120a6e
  // Search among regions, from leaf regions to root.
Shinya Kitaoka 120a6e
  int i;
Shinya Kitaoka 120a6e
  unsigned int j;
Shinya Kitaoka 120a6e
  for (i = m_regions.size() - 1; i >= 0; --i) {
Shinya Kitaoka 120a6e
    Region *currRegion = m_regions[i];
Shinya Kitaoka 120a6e
    DockWidget *item   = currRegion->getItem();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // First check if item contains it
Shinya Kitaoka 120a6e
    if (item && item->geometry().contains(point)) return currRegion->getItem();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Then, search among separators
Shinya Kitaoka 120a6e
    for (j = 0; j < currRegion->separators().size(); ++j)
Shinya Kitaoka 120a6e
      if (currRegion->separator(j)->geometry().contains(point))
Shinya Kitaoka 120a6e
        return currRegion->separator(j);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//-------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
void DockLayout::setMaximized(DockWidget *item, bool state) {
Shinya Kitaoka 120a6e
  if (item && state != item->m_maximized) {
Shinya Kitaoka 120a6e
    if (state) {
Shinya Kitaoka 120a6e
      // Maximize
Shinya Kitaoka 120a6e
      if (m_maximizedDock) {
Shinya Kitaoka 120a6e
        // If maximized already exists, normalize it
Shinya Kitaoka 120a6e
        Region *r = find(m_maximizedDock);
Shinya Kitaoka 120a6e
        m_maximizedDock->setGeometry(toRect(r->getGeometry()));
Shinya Kitaoka 120a6e
        m_maximizedDock->m_maximized = false;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Now, attempt requested item maximization
Shinya Kitaoka 120a6e
      QSize minimumSize = item->minimumSize();
Shinya Kitaoka 120a6e
      QSize maximumSize = item->maximumSize();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (contentsRect().width() > minimumSize.width() &&
Shinya Kitaoka 120a6e
          contentsRect().height() > minimumSize.height() &&
Shinya Kitaoka 120a6e
          contentsRect().width() < maximumSize.width() &&
Shinya Kitaoka 120a6e
          contentsRect().height() < maximumSize.height()) {
Shinya Kitaoka 120a6e
        // Maximization succeeds
Shinya Kitaoka 120a6e
        item->setGeometry(contentsRect());
Shinya Kitaoka 120a6e
        item->raise();
Shinya Kitaoka 120a6e
        item->m_maximized = true;
Shinya Kitaoka 120a6e
        m_maximizedDock   = item;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Hide all the other docked widgets (no need to update them. Moreover,
Shinya Kitaoka 120a6e
        // doing so
Shinya Kitaoka 120a6e
        // could eventually result in painting over the newly maximized widget)
Shinya Kitaoka 120a6e
        DockWidget *currWidget;
Shinya Kitaoka 120a6e
        for (int i = 0; i < count(); ++i) {
Shinya Kitaoka 120a6e
          currWidget = (DockWidget *)itemAt(i)->widget();
Shinya Kitaoka 120a6e
          if (currWidget != item && !currWidget->isFloating())
Shinya Kitaoka 120a6e
            currWidget->hide();
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      // Normalize
Shinya Kitaoka 120a6e
      Region *r = find(m_maximizedDock);
Shinya Kitaoka 120a6e
      if (r) m_maximizedDock->setGeometry(toRect(r->getGeometry()));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      m_maximizedDock->m_maximized = false;
Shinya Kitaoka 120a6e
      m_maximizedDock              = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Show all other docked widgets
Shinya Kitaoka 120a6e
      DockWidget *currWidget;
Shinya Kitaoka 120a6e
      for (int i = 0; i < count(); ++i) {
Shinya Kitaoka 120a6e
        currWidget = (DockWidget *)itemAt(i)->widget();
Shinya Kitaoka 120a6e
        if (currWidget != item && !currWidget->isFloating()) currWidget->show();
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================
Toshihiro Shimizu 890ddd
//      Layout Geometry Handler
Toshihiro Shimizu 890ddd
//======================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! NOTE: This method is currently unused by DockLayout implementation...
Shinya Kitaoka 120a6e
void DockLayout::setGeometry(const QRect &rect) {
Shinya Kitaoka 120a6e
  // Just pass the info to the widget (it's somehow necessary...)
Shinya Kitaoka 120a6e
  QLayout::setGeometry(rect);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Defines cursors for separators of the layout: if it is not possible to
Shinya Kitaoka 120a6e
//! move a separator, its cursor must be an arrow.
Shinya Kitaoka d1f6c4
void DockLayout::updateSeparatorCursors() {
Shinya Kitaoka 120a6e
  Region *r, *child;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  unsigned int i, j;
Shinya Kitaoka 120a6e
  int k, jInt;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_regions.size(); ++i) {
Shinya Kitaoka 120a6e
    r                = m_regions[i];
Shinya Kitaoka 120a6e
    bool orientation = r->getOrientation();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // If region geometry is minimal or maximal, its separators are blocked
Shinya Kitaoka 120a6e
    // NOTE: If this update follows only from a dock/undock, this should be
Shinya Kitaoka 120a6e
    // disabled 'til 'Otherwise'
Shinya Kitaoka 120a6e
    QSize size = toRect(r->getGeometry()).size();
Shinya Kitaoka 120a6e
    bool isExtremeSize =
Shinya Kitaoka 120a6e
        (orientation == Region::horizontal)
Shinya Kitaoka 120a6e
            ? size.width() == r->getMinimumSize(Region::horizontal) ||
Shinya Kitaoka 120a6e
                  size.width() == r->getMaximumSize(Region::horizontal)
Shinya Kitaoka 120a6e
            : size.height() == r->getMinimumSize(Region::vertical) ||
Shinya Kitaoka 120a6e
                  size.height() == r->getMaximumSize(Region::vertical);
Shinya Kitaoka 120a6e
    if (isExtremeSize) {
Shinya Kitaoka 120a6e
      for (j = 0; j < r->separators().size(); ++j)
Shinya Kitaoka 120a6e
        r->separator(j)->setCursor(Qt::ArrowCursor);
Shinya Kitaoka 120a6e
      continue;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Otherwise...
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Arrowize all separators as long as the preceding region has equal
Shinya Kitaoka 120a6e
    // maximum and minimum sizes
Shinya Kitaoka 120a6e
    for (j = 0; j < r->getChildList().size(); ++j) {
Shinya Kitaoka 120a6e
      child = r->childRegion(j);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (child->getMaximumSize(orientation) ==
Shinya Kitaoka 120a6e
          child->getMinimumSize(orientation))
Shinya Kitaoka 120a6e
        r->separator(j)->setCursor(Qt::ArrowCursor);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    jInt = j;
Shinya Kitaoka 120a6e
    // The same as above in reverse order
Shinya Kitaoka 120a6e
    for (k = r->getChildList().size() - 1; k > jInt; --k) {
Shinya Kitaoka 120a6e
      child = r->childRegion(k);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      if (child->getMaximumSize(orientation) ==
Shinya Kitaoka 120a6e
          child->getMinimumSize(orientation))
Shinya Kitaoka 120a6e
        r->separator(k - 1)->setCursor(Qt::ArrowCursor);
Shinya Kitaoka 120a6e
      else
Shinya Kitaoka 120a6e
        break;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Middle separators have a split cursor
Shinya Kitaoka 120a6e
    Qt::CursorShape shape = (orientation == Region::horizontal)
Shinya Kitaoka 120a6e
                                ? Qt::SplitHCursor
Shinya Kitaoka 120a6e
                                : Qt::SplitVCursor;
Shinya Kitaoka 120a6e
    for (; jInt < k; ++jInt) r->separator(jInt)->setCursor(shape);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//--------------------------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Applies Regions geometry to dock widgets and separators.
Shinya Kitaoka 120a6e
void DockLayout::applyGeometry() {
Shinya Kitaoka 120a6e
  // Update docked window's geometries
Shinya Kitaoka 120a6e
  unsigned int i, j;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_regions.size(); ++i) {
Shinya Kitaoka 120a6e
    Region *r                             = m_regions[i];
Shinya Kitaoka 120a6e
    const std::deque<region *=""> &childList = r->getChildList();</region>
Shinya Kitaoka 120a6e
    std::deque<dockseparator *=""> &sepList  = r->m_separators;</dockseparator>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_regions[i]->getItem()) {
Shinya Kitaoka 120a6e
      m_regions[i]->getItem()->setGeometry(toRect(m_regions[i]->getGeometry()));
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      for (j = 0; j < sepList.size(); ++j) {
Shinya Kitaoka 120a6e
        QRect leftAdjRect = toRect(childList[j]->getGeometry());
Shinya Kitaoka 120a6e
        if (r->getOrientation() == Region::horizontal) {
Shinya Kitaoka 120a6e
          leftAdjRect.adjust(0, 0, 1, 0);  // Take adjacent-to topRight pixel
Shinya Kitaoka 120a6e
          sepList[j]->setGeometry(QRect(
Shinya Kitaoka 120a6e
              leftAdjRect.topRight(), QSize(spacing(), leftAdjRect.height())));
Shinya Kitaoka 120a6e
          sepList[j]->m_index = j;
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          leftAdjRect.adjust(0, 0, 0, 1);
Shinya Kitaoka 120a6e
          sepList[j]->setGeometry(QRect(leftAdjRect.bottomLeft(),
Shinya Kitaoka 120a6e
                                        QSize(leftAdjRect.width(), spacing())));
Shinya Kitaoka 120a6e
          sepList[j]->m_index = j;
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If there is a maximized widget, reset its geometry to that of the main
Shinya Kitaoka 120a6e
  // region
Shinya Kitaoka 120a6e
  if (m_maximizedDock) {
Shinya Kitaoka 120a6e
    m_maximizedDock->setGeometry(toRect(m_regions[0]->getGeometry()));
Shinya Kitaoka 120a6e
    m_maximizedDock->raise();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, update separator cursors.
Shinya Kitaoka 120a6e
  updateSeparatorCursors();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DockLayout::applyTransform(const QTransform &transform) {
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_regions.size(); ++i)
Shinya Kitaoka 120a6e
    m_regions[i]->setGeometry(transform.mapRect(m_regions[i]->getGeometry()));
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DockLayout::redistribute() {
Shinya Kitaoka 120a6e
  if (!m_regions.empty()) {
Shinya Kitaoka 120a6e
    // Recompute extremal region sizes
Shinya Kitaoka 120a6e
    // NOTA: Sarebbe da fare solo se un certo flag lo richiede; altrimenti tipo
Shinya Kitaoka 120a6e
    // per resize events e' inutile...
Shinya Kitaoka 120a6e
    m_regions.front()->calculateExtremalSizes();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int parentWidth  = contentsRect().width();
Shinya Kitaoka 120a6e
    int parentHeight = contentsRect().height();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Always check main window consistency before effective redistribution. DO
Shinya Kitaoka 120a6e
    // NOT ERASE or crashes may occur...
Shinya Kitaoka 120a6e
    if (m_regions.front()->getMinimumSize(Region::horizontal) > parentWidth ||
Shinya Kitaoka 120a6e
        m_regions.front()->getMinimumSize(Region::vertical) > parentHeight ||
Shinya Kitaoka 120a6e
        m_regions.front()->getMaximumSize(Region::horizontal) < parentWidth ||
Shinya Kitaoka 120a6e
        m_regions.front()->getMaximumSize(Region::vertical) < parentHeight)
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Recompute Layout geometry
Shinya Kitaoka 120a6e
    m_regions.front()->setGeometry(contentsRect());
Shinya Kitaoka 120a6e
    m_regions.front()->redistribute();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, apply Region geometries found
Shinya Kitaoka 120a6e
  applyGeometry();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//======================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================
Toshihiro Shimizu 890ddd
//    Region implementation
Toshihiro Shimizu 890ddd
//=============================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
Region::~Region() {
Shinya Kitaoka 120a6e
  // Delete separators
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_separators.size(); ++i) delete m_separators[i];
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Inserts DockSeparator \b sep in \b this Region
Shinya Kitaoka d1f6c4
void Region::insertSeparator(DockSeparator *sep) {
Shinya Kitaoka 120a6e
  m_separators.push_back(sep);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Removes a DockSeparator from \b this Region
Shinya Kitaoka d1f6c4
void Region::removeSeparator() {
Shinya Kitaoka 120a6e
  delete m_separators.back();
Shinya Kitaoka 120a6e
  m_separators.pop_back();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
void Region::insertSubRegion(Region *subRegion, int idx) {
Shinya Kitaoka 120a6e
  m_childList.insert(m_childList.begin() + idx, subRegion);
Shinya Kitaoka 120a6e
  subRegion->m_parent      = this;
Shinya Kitaoka 120a6e
  subRegion->m_orientation = !m_orientation;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Inserts input \b item before position \b idx. Returns associated new region.
Shinya Kitaoka d1f6c4
Region *Region::insertItem(DockWidget *item, int idx) {
Shinya Kitaoka 120a6e
  Region *newRegion = new Region(m_owner, item);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  if (this) insertSubRegion(newRegion, idx);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return newRegion;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
unsigned int Region::find(const Region *subRegion) const {
Shinya Kitaoka 120a6e
  unsigned int i;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (i = 0; i < m_childList.size(); ++i)
Shinya Kitaoka 120a6e
    if (m_childList[i] == subRegion) return i;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return -1;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
Region *DockLayout::find(DockWidget *item) const {
Shinya Kitaoka 120a6e
  unsigned int i;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  for (i = 0; i < m_regions.size(); ++i)
Shinya Kitaoka 120a6e
    if (m_regions[i]->getItem() == item) return m_regions[i];
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return 0;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Calculates possible docking solutions for \b this
Shinya Kitaoka 120a6e
//! dock widget. They are stored into the dock widget.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: Placeholders are here calculated by decreasing importance;
Shinya Kitaoka 120a6e
//! in other words, if two rects are part of the layout, and the first
Shinya Kitaoka 120a6e
//! contains the second, placeholders of the first are found before
Shinya Kitaoka 120a6e
//! those of the second. This fact may be exploited when selecting an
Shinya Kitaoka 120a6e
//! appropriate placeholder for docking.
Shinya Kitaoka 120a6e
void DockLayout::calculateDockPlaceholders(DockWidget *item) {
Shinya Kitaoka 120a6e
  assert(item);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If the DockLayout's owner widget is hidden, avoid
Shinya Kitaoka 120a6e
  if (!parentWidget()->isVisible()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!m_regions.size()) {
Shinya Kitaoka 120a6e
    if (isPossibleInsertion(item, 0, 0)) {
Shinya Kitaoka 120a6e
      // Then insert a root placeholder only
Shinya Kitaoka 120a6e
      item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
          item, 0, 0, DockPlaceholder::root));
Shinya Kitaoka 120a6e
      return;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // For all regions (and for all insertion index), check if
Shinya Kitaoka 120a6e
  // insertion may succeed.
Shinya Kitaoka 120a6e
  // NOTE: Insertion chance is just the same for all indexes in a given
Shinya Kitaoka 120a6e
  // parent region...
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // First check parentRegion=0 (under a new Root - External cases)
Shinya Kitaoka 120a6e
  if (isPossibleInsertion(item, 0, 0)) {
Shinya Kitaoka 120a6e
    QRect contRect = contentsRect();
Shinya Kitaoka 120a6e
    if (m_regions.front()->getOrientation() == Region::horizontal) {
Shinya Kitaoka 120a6e
      item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
          item, 0, 0, DockPlaceholder::top));
Shinya Kitaoka 120a6e
      item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
          item, 0, 1, DockPlaceholder::bottom));
Shinya Kitaoka 120a6e
    } else {
Shinya Kitaoka 120a6e
      item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
          item, 0, 0, DockPlaceholder::left));
Shinya Kitaoka 120a6e
      item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
          item, 0, 1, DockPlaceholder::right));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_regions.size(); ++i) {
Shinya Kitaoka 120a6e
    Region *r = m_regions[i];
Shinya Kitaoka 120a6e
    r->m_placeholders.clear();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (isPossibleInsertion(item, r, 0)) {
Shinya Kitaoka 120a6e
      unsigned int j;
Shinya Kitaoka 120a6e
      QRect cellRect;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // For all indices, insert a placeholder
Shinya Kitaoka 120a6e
      if (r->getOrientation() == Region::horizontal) {
Shinya Kitaoka 120a6e
        // Left side
Shinya Kitaoka 120a6e
        item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
            item, r, 0, DockPlaceholder::left));
Shinya Kitaoka 120a6e
        r->m_placeholders.push_back(item->m_placeholders.back());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Separators
Shinya Kitaoka 120a6e
        for (j = 1; j < r->getChildList().size(); ++j) {
Shinya Kitaoka 120a6e
          item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
              item, r, j, DockPlaceholder::sepVert));
Shinya Kitaoka 120a6e
          r->m_placeholders.push_back(item->m_placeholders.back());
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Right side
Shinya Kitaoka 120a6e
        item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
            item, r, j, DockPlaceholder::right));
Shinya Kitaoka 120a6e
        r->m_placeholders.push_back(item->m_placeholders.back());
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        // Top side
Shinya Kitaoka 120a6e
        item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
            item, r, 0, DockPlaceholder::top));
Shinya Kitaoka 120a6e
        r->m_placeholders.push_back(item->m_placeholders.back());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        for (j = 1; j < r->getChildList().size(); ++j) {
Shinya Kitaoka 120a6e
          item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
              item, r, j, DockPlaceholder::sepHor));
Shinya Kitaoka 120a6e
          r->m_placeholders.push_back(item->m_placeholders.back());
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        // Bottom side
Shinya Kitaoka 120a6e
        item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(
Shinya Kitaoka 120a6e
            item, r, j, DockPlaceholder::bottom));
Shinya Kitaoka 120a6e
        r->m_placeholders.push_back(item->m_placeholders.back());
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Disable all placeholders
Shinya Kitaoka 120a6e
  // for(i=0; i<item->m_placeholders.size(); ++i)</item->
Shinya Kitaoka 120a6e
  //  item->m_placeholders[i]->setDisabled(true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Docks input \b item before position \b idx of region \b r. Deals with
Shinya Kitaoka 120a6e
//! overall region hierarchy.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: Docked items are forcedly shown.
Shinya Kitaoka 120a6e
void DockLayout::dockItem(DockWidget *item, DockPlaceholder *place) {
Shinya Kitaoka 120a6e
  place->hide();
Shinya Kitaoka 120a6e
  item->hide();
Shinya Kitaoka 120a6e
  dockItemPrivate(item, place->m_region, place->m_idx);
Shinya Kitaoka 120a6e
  redistribute();
Shinya Kitaoka 120a6e
  parentWidget()->repaint();
Shinya Kitaoka 120a6e
  item->setWindowFlags(Qt::SubWindow);
Shinya Kitaoka 120a6e
  item->show();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Docks input \b item at side \b regionside of \b target dock widget.
Shinya Kitaoka 120a6e
//! RegionSide can be Region::left, right, top or bottom.
Shinya Kitaoka 120a6e
void DockLayout::dockItem(DockWidget *item, DockWidget *target,
Shinya Kitaoka 120a6e
                          int regionSide) {
Shinya Kitaoka 120a6e
  Region *targetRegion = find(target);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  short var = regionSide >> 2 * (int)targetRegion->getOrientation();
Shinya Kitaoka 120a6e
  bool pos  = regionSide & 0xa;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  item->setWindowFlags(Qt::SubWindow);
Shinya Kitaoka 120a6e
  item->show();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (var & 0x3) {
Shinya Kitaoka 120a6e
    // Side is coherent with orientation => Direct insertion at position 0 or 1
Shinya Kitaoka 120a6e
    dockItemPrivate(item, targetRegion, pos);
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // Side is not coherent - have to find target's index in parent region
Shinya Kitaoka 120a6e
    Region *parentRegion = targetRegion->getParent();
Shinya Kitaoka 120a6e
    unsigned int idx =
Shinya Kitaoka 120a6e
        parentRegion ? parentRegion->find(targetRegion) + pos : pos;
Shinya Kitaoka 120a6e
    dockItemPrivate(item, parentRegion, idx);
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Docks input \b item into Region \b r, at position \b idx; returns region
Shinya Kitaoka 120a6e
//! corresponding to
Shinya Kitaoka 120a6e
//! newly inserted item.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: Unlike dockItem(DockWidget*,DockPlaceholder*) and undockItem, this
Shinya Kitaoka 120a6e
//! method is supposedly called directly into application code; therefore, no \b
Shinya Kitaoka 120a6e
//! redistribution
Shinya Kitaoka 120a6e
//! is done after a single dock - you are supposed to manually call
Shinya Kitaoka 120a6e
//! redistribute() after
Shinya Kitaoka 120a6e
//! all widgets have been docked.
Shinya Kitaoka 120a6e
Region *DockLayout::dockItem(DockWidget *item, Region *r, int idx) {
Shinya Kitaoka 120a6e
  item->setWindowFlags(Qt::SubWindow);
Shinya Kitaoka 120a6e
  item->show();
Shinya Kitaoka 120a6e
  return dockItemPrivate(item, r, idx);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// Internal docking function. Contains raw docking code, excluded reparenting
Shinya Kitaoka 120a6e
// (setWindowFlags)
Shinya Kitaoka 120a6e
// which may slow down a bit - should be done only after a redistribute() and a
Shinya Kitaoka 120a6e
// repaint() on
Shinya Kitaoka 120a6e
// real-time docking.
Shinya Kitaoka d1f6c4
Region *DockLayout::dockItemPrivate(DockWidget *item, Region *r,
Shinya Kitaoka 120a6e
                                           int idx) {
Shinya Kitaoka 120a6e
  // hide minimize button in FlipboolPanel
Shinya Kitaoka 120a6e
  item->onDock(true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  item->setDockedAppearance();
Shinya Kitaoka 120a6e
  item->m_floating = false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (!r) {
Shinya Kitaoka 120a6e
    // Insert new root region
Shinya Kitaoka 120a6e
    Region *newRoot = new Region(this);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_regions.push_front(newRoot);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    newRoot->setSize(item->size());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (m_regions.size() == 1) {
Shinya Kitaoka 120a6e
      newRoot->setItem(item);
Shinya Kitaoka 120a6e
      return newRoot;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    newRoot->setOrientation(!m_regions[1]->getOrientation());
Shinya Kitaoka 120a6e
    newRoot->insertSubRegion(m_regions[1], 0);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    r = newRoot;
Shinya Kitaoka 120a6e
  } else if (r->getItem()) {
Shinya Kitaoka 120a6e
    // Then the Layout gets further subdived - r's item has to be moved
Shinya Kitaoka 120a6e
    Region *regionForOldItem = r->insertItem(r->getItem(), 0);
Shinya Kitaoka 120a6e
    regionForOldItem->setSize(r->getItem()->size());
Shinya Kitaoka 120a6e
    // regionForOldItem->setSize(r->getItem()->frameSize());
Shinya Kitaoka 120a6e
    r->setItem(0);
Shinya Kitaoka 120a6e
    m_regions.push_back(regionForOldItem);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  Region *newRegion = r->insertItem(item, idx);
Shinya Kitaoka 120a6e
  m_regions.push_back(newRegion);
Shinya Kitaoka 120a6e
  // Temporarily setting suggested size for newly inserted region
Shinya Kitaoka 120a6e
  newRegion->setSize(item->size());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, insert a new DockSeparator in parent region r.
Shinya Kitaoka 120a6e
  r->insertSeparator(
Shinya Kitaoka 120a6e
      m_decoAllocator->newSeparator(this, r->getOrientation(), r));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return newRegion;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! A region is empty, if contains no item and no children.
Shinya Kitaoka d1f6c4
bool isEmptyRegion(Region *r) {
Shinya Kitaoka 120a6e
  if ((!r->getItem()) && (r->getChildList().size() == 0)) {
Shinya Kitaoka 120a6e
    delete r;  // Be', e' un po' improprio, ma funziona...
Shinya Kitaoka 120a6e
    return true;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
  return false;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Removes input item from region
Shinya Kitaoka d1f6c4
void Region::removeItem(DockWidget *item) {
Shinya Kitaoka 120a6e
  if (item == 0) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_childList.size(); ++i)
Shinya Kitaoka 120a6e
    if (item == m_childList[i]->getItem()) {
Shinya Kitaoka 120a6e
      m_childList.erase(m_childList.begin() + i);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      removeSeparator();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // parent Region may collapse; then move item back to parent and update
Shinya Kitaoka 120a6e
      // its parent
Shinya Kitaoka 120a6e
      if (m_childList.size() == 1) {
Shinya Kitaoka 120a6e
        Region *parent = getParent();
Shinya Kitaoka 120a6e
        if (parent) {
Shinya Kitaoka 120a6e
          Region *remainingSon = m_childList[0];
Shinya Kitaoka 120a6e
          if (!remainingSon->m_childList.size()) {
Shinya Kitaoka 120a6e
            // remainingSon is a leaf: better keep this and move son's item and
Shinya Kitaoka 120a6e
            // childList
Shinya Kitaoka 120a6e
            setItem(remainingSon->getItem());
Shinya Kitaoka 120a6e
            remainingSon->setItem(0);
Shinya Kitaoka 120a6e
          } else {
Shinya Kitaoka 120a6e
            // remainingSon is a branch: append remainingSon childList to parent
Shinya Kitaoka 120a6e
            // one and
Shinya Kitaoka 120a6e
            // sign this and remainingSon nodes for destruction.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            // First find this position in parent
Shinya Kitaoka 120a6e
            unsigned int j = parent->find(this);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            parent->m_childList.erase(parent->m_childList.begin() + j);
Shinya Kitaoka 120a6e
            parent->m_childList.insert(parent->m_childList.begin() + j,
Shinya Kitaoka 120a6e
                                       remainingSon->m_childList.begin(),
Shinya Kitaoka 120a6e
                                       remainingSon->m_childList.end());
Shinya Kitaoka 120a6e
            parent->m_separators.insert(parent->m_separators.begin() + j,
Shinya Kitaoka 120a6e
                                        remainingSon->m_separators.begin(),
Shinya Kitaoka 120a6e
                                        remainingSon->m_separators.end());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            // Update remainingSon children's and DockSeparator's parent
Shinya Kitaoka 120a6e
            for (j = 0; j < remainingSon->m_childList.size(); ++j)
Shinya Kitaoka 120a6e
              remainingSon->m_childList[j]->m_parent = parent;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            for (j = 0; j < remainingSon->m_separators.size(); ++j)
Shinya Kitaoka 120a6e
              remainingSon->m_separators[j]->m_parentRegion = parent;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
            remainingSon->m_childList.clear();
Shinya Kitaoka 120a6e
            remainingSon->m_separators.clear();
Shinya Kitaoka 120a6e
          }
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          // Root case; better keep the remaining child
Shinya Kitaoka 120a6e
          m_childList[0]->setParent(0);
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        m_childList.clear();
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      break;
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Undocks \b item and updates geometry.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//!\b NOTE: Window flags are resetted to floating appearance (thus hiding the
Shinya Kitaoka 38fd86
//! widget). Since the geometry
Shinya Kitaoka 120a6e
//! reference changes a geometry() update may be needed - so item's show() is
Shinya Kitaoka 120a6e
//! not forced here. You should
Shinya Kitaoka 120a6e
//! eventually remember to call it manually after this.
Shinya Kitaoka 120a6e
bool DockLayout::undockItem(DockWidget *item) {
Shinya Kitaoka 120a6e
  // Find item's region index in m_regions
Shinya Kitaoka 120a6e
  Region *itemCarrier = find(item);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  Region *parent = itemCarrier->getParent();
Shinya Kitaoka 120a6e
  if (parent) {
Shinya Kitaoka 120a6e
    int removalIdx = 0;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Find removal index in parent's childList
Shinya Kitaoka 120a6e
    unsigned int j;
Shinya Kitaoka 120a6e
    for (j = 0; j < parent->getChildList().size(); ++j)
Shinya Kitaoka 120a6e
      if (parent->getChildList()[j]->getItem() == item) break;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    if (isPossibleRemoval(item, parent, removalIdx))
Shinya Kitaoka 120a6e
      parent->removeItem(item);
Shinya Kitaoka 120a6e
    else
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Remove region in regions list
Shinya Kitaoka 120a6e
  // m_regions.erase(i);   //Don't - m_regions is cleaned before the end by
Shinya Kitaoka 120a6e
  // remove_if
Shinya Kitaoka 120a6e
  itemCarrier->setItem(0);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  std::deque<region *="">::iterator j;</region>
Shinya Kitaoka 120a6e
  j = std::remove_if(m_regions.begin(), m_regions.end(), isEmptyRegion);
Shinya Kitaoka 120a6e
  m_regions.resize(j - m_regions.begin());
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // Update status
Shinya Kitaoka 120a6e
  // qDebug("Undock");
Shinya Kitaoka 120a6e
  item->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
Shinya Kitaoka 120a6e
  // NOTA: Usando la flag Qt::Window il focus viene automaticamente riassegnato,
Shinya Kitaoka 120a6e
  // con un po' di ritardo.
Shinya Kitaoka 120a6e
  // Usando Tool questo non accade. In questo caso, i placeholder devono essere
Shinya Kitaoka 120a6e
  // disattivati...
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  item->setFloatingAppearance();
Shinya Kitaoka 120a6e
  item->m_floating = true;
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // show minimize button in FlipbookPanel
Shinya Kitaoka 120a6e
  item->onDock(false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  setMaximized(item, false);
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  redistribute();
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Search for the \b nearest n-ple from a \b target one, under conditions:
Shinya Kitaoka 120a6e
//!\b 1) nearest elements belong to \b fixed \b intervals; \b 2) their \b sum is
Shinya Kitaoka 120a6e
//!\b fixed too.
Shinya Kitaoka d1f6c4
void calculateNearest(std::vector<double> target,</double>
Shinya Kitaoka d1f6c4
                      std::vector<double> &nearest,</double>
Shinya Kitaoka d1f6c4
                      std::vector<std::pair<int, int="">> intervals,</std::pair<int,>
Shinya Kitaoka d1f6c4
                      double sum) {
Shinya Kitaoka 120a6e
  // Solving a small Lagrange multipliers problem to find solution on constraint
Shinya Kitaoka 120a6e
  // (2)
Shinya Kitaoka 120a6e
  assert(target.size() == intervals.size());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double targetSum = 0;
Shinya Kitaoka 120a6e
  for (i = 0; i < target.size(); ++i) targetSum += target[i];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double multiplier = (sum - targetSum) / (double)target.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  nearest.resize(target.size());
Shinya Kitaoka 120a6e
  for (i = 0; i < target.size(); ++i) nearest[i] = target[i] + multiplier;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Now, constraint (1) is not met; however, satisfying also (2) yields a
Shinya Kitaoka 120a6e
  // hyperRect
Shinya Kitaoka 120a6e
  // on which we must find the nearest point to our above partial solution. In
Shinya Kitaoka 120a6e
  // particular,
Shinya Kitaoka 120a6e
  // it can be demonstrated that at least one coordinate of the current partial
Shinya Kitaoka 120a6e
  // solution is related
Shinya Kitaoka 120a6e
  // to the final one (...). This mean that we may have to solve sub-problems of
Shinya Kitaoka 120a6e
  // this same kind,
Shinya Kitaoka 120a6e
  // with less variable coordinates.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  unsigned int max;
Shinya Kitaoka 120a6e
  double distance, maxDistance = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  for (i = 0; i < target.size(); ++i) {
Shinya Kitaoka 120a6e
    if (nearest[i] < intervals[i].first || nearest[i] > intervals[i].second) {
Shinya Kitaoka 120a6e
      distance = nearest[i] < intervals[i].first
Shinya Kitaoka 120a6e
                     ? intervals[i].first - nearest[i]
Shinya Kitaoka 120a6e
                     : nearest[i] - intervals[i].second;
Shinya Kitaoka 120a6e
      nearest[i] = nearest[i] < intervals[i].first ? intervals[i].first
Shinya Kitaoka 120a6e
                                                   : intervals[i].second;
Shinya Kitaoka 120a6e
      if (maxDistance < distance) {
Shinya Kitaoka 120a6e
        maxDistance = distance;
Shinya Kitaoka 120a6e
        max         = i;
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<double> newTarget = target;</double>
Shinya Kitaoka 120a6e
  std::vector<double> newNearest;</double>
Shinya Kitaoka 120a6e
  std::vector<std::pair<int, int="">> newIntervals = intervals;</std::pair<int,>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (maxDistance) {
Shinya Kitaoka 120a6e
    newTarget.erase(newTarget.begin() + max);
Shinya Kitaoka 120a6e
    newIntervals.erase(newIntervals.begin() + max);
Shinya Kitaoka 120a6e
    sum -= nearest[max];
Shinya Kitaoka 120a6e
    calculateNearest(newTarget, newNearest, newIntervals, sum);
Shinya Kitaoka 120a6e
    for (i = 0; i < max; ++i) nearest[i] = newNearest[i];
Shinya Kitaoka 120a6e
    for (i = max + 1; i < nearest.size(); ++i) nearest[i] = newNearest[i - 1];
Shinya Kitaoka 120a6e
  } else
Shinya Kitaoka 120a6e
    return;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Equally redistribute separators and children regions' internal geometry
Shinya Kitaoka 120a6e
//! according to current subregion sizes.
Shinya Kitaoka 120a6e
void Region::redistribute() {
Shinya Kitaoka 120a6e
  if (!m_childList.size()) return;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  bool expansion = m_minimumSize[Region::horizontal] > m_rect.width() ||
Shinya Kitaoka 120a6e
                   m_minimumSize[Region::vertical] > m_rect.height();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  double regionSize[2];
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If there is no need to expand this region, maintain current geometry;
Shinya Kitaoka 120a6e
  // otherwise, expand at minimum.
Shinya Kitaoka 120a6e
  regionSize[Region::horizontal] =
Shinya Kitaoka 120a6e
      expansion ? m_minimumSize[Region::horizontal] : m_rect.width();
Shinya Kitaoka 120a6e
  regionSize[Region::vertical] =
Shinya Kitaoka 120a6e
      expansion ? m_minimumSize[Region::vertical] : m_rect.height();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // However, expansion in the oriented direction has to take care of parent's
Shinya Kitaoka 120a6e
  // consense.
Shinya Kitaoka 120a6e
  if (m_parent != 0)
Shinya Kitaoka 120a6e
    regionSize[m_orientation] =
Shinya Kitaoka 120a6e
        std::min((double)m_parent->m_maximumSize[m_orientation],
Shinya Kitaoka 120a6e
                 regionSize[m_orientation]);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Now find nearest-to-preferred window sizes, according to size constraints.
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // First build target sizes vector
Shinya Kitaoka 120a6e
  std::vector<double> targetSizes(m_childList.size());</double>
Shinya Kitaoka 120a6e
  for (i = 0; i < m_childList.size(); ++i) {
Shinya Kitaoka 120a6e
    // Assuming preferred sizes are those already present before redistribution.
Shinya Kitaoka 120a6e
    targetSizes[i] = (m_orientation == Region::horizontal)
Shinya Kitaoka 120a6e
                         ? m_childList[i]->m_rect.width()
Shinya Kitaoka 120a6e
                         : m_childList[i]->m_rect.height();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build minimum and maximum size constraints
Shinya Kitaoka 120a6e
  std::vector<std::pair<int, int="">> sizeIntervals(m_childList.size());</std::pair<int,>
Shinya Kitaoka 120a6e
  for (i = 0; i < m_childList.size(); ++i) {
Shinya Kitaoka 120a6e
    sizeIntervals[i].first  = m_childList[i]->m_minimumSize[m_orientation];
Shinya Kitaoka 120a6e
    sizeIntervals[i].second = m_childList[i]->m_maximumSize[m_orientation];
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Build width sum
Shinya Kitaoka 120a6e
  int separatorWidth = m_owner->spacing();
Shinya Kitaoka 120a6e
  double sum =
Shinya Kitaoka 120a6e
      regionSize[m_orientation] - (m_childList.size() - 1) * separatorWidth;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  std::vector<double> nearestSizes;</double>
Shinya Kitaoka 120a6e
  calculateNearest(targetSizes, nearestSizes, sizeIntervals, sum);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // NearestSizes stores optimal subregion sizes; calculate their geometries and
Shinya Kitaoka 120a6e
  // assign them.
Shinya Kitaoka 120a6e
  QPointF topLeftCorner = m_rect.topLeft();
Shinya Kitaoka 120a6e
  if (m_orientation == horizontal) {
Shinya Kitaoka 120a6e
    for (i = 0; i < m_childList.size(); ++i) {
Shinya Kitaoka 120a6e
      QSizeF currSize = QSizeF(nearestSizes[i], regionSize[vertical]);
Shinya Kitaoka 120a6e
      m_childList[i]->setGeometry(QRectF(topLeftCorner, currSize));
Shinya Kitaoka 120a6e
      topLeftCorner =
Shinya Kitaoka 120a6e
          m_childList[i]->getGeometry().topRight() + QPointF(separatorWidth, 0);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    for (i = 0; i < m_childList.size(); ++i) {
Shinya Kitaoka 120a6e
      QSizeF currSize = QSizeF(regionSize[horizontal], nearestSizes[i]);
Shinya Kitaoka 120a6e
      m_childList[i]->setGeometry(QRectF(topLeftCorner, currSize));
Shinya Kitaoka 120a6e
      topLeftCorner = m_childList[i]->getGeometry().bottomLeft() +
Shinya Kitaoka 120a6e
                      QPointF(0, separatorWidth);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, redistribute region's children
Shinya Kitaoka 120a6e
  for (i = 0; i < m_childList.size(); ++i) m_childList[i]->redistribute();
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Calculates maximum and minimum sizes for each sub-region.
Shinya Kitaoka 120a6e
void Region::calculateExtremalSizes() {
Shinya Kitaoka 120a6e
  calculateMinimumSize(horizontal, true);
Shinya Kitaoka 120a6e
  calculateMinimumSize(vertical, true);
Shinya Kitaoka 120a6e
  calculateMaximumSize(horizontal, true);
Shinya Kitaoka 120a6e
  calculateMaximumSize(vertical, true);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Calculates minimum occupiable space in \b this region on given \b direction.
Shinya Kitaoka 120a6e
//! Also stores cache for it.
Shinya Kitaoka 120a6e
int Region::calculateMinimumSize(bool direction, bool recalcChildren) {
Shinya Kitaoka 120a6e
  int sumMinSizes = 0, maxMinSizes = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_item) {
Shinya Kitaoka 120a6e
    sumMinSizes = maxMinSizes = (direction == horizontal)
Shinya Kitaoka 120a6e
                                    ? m_item->minimumSize().width()
Shinya Kitaoka 120a6e
                                    : m_item->minimumSize().height();
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    unsigned int i;
Shinya Kitaoka 120a6e
    int currMinSize;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // If required, recalculate children sizes along our direction.
Shinya Kitaoka 120a6e
    if (recalcChildren) {
Shinya Kitaoka 120a6e
      for (i = 0; i < m_childList.size(); ++i)
Shinya Kitaoka 120a6e
        m_childList[i]->calculateMinimumSize(direction, true);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < m_childList.size(); ++i) {
Shinya Kitaoka 120a6e
      sumMinSizes += currMinSize = m_childList[i]->getMinimumSize(direction);
Shinya Kitaoka 120a6e
      if (maxMinSizes < currMinSize) maxMinSizes = currMinSize;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Add separators width
Shinya Kitaoka 120a6e
    sumMinSizes += m_separators.size() * m_owner->spacing();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If m_orientation is coherent with input direction, minimum occupied space
Shinya Kitaoka 120a6e
  // is the sum
Shinya Kitaoka 120a6e
  // of childs' minimumSizes. Otherwise, the maximum is taken.
Shinya Kitaoka 120a6e
  if (m_orientation == direction) {
Shinya Kitaoka 120a6e
    return m_minimumSize[direction] = sumMinSizes;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    return m_minimumSize[direction] = maxMinSizes;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Calculates maximum occupiable space in \b this region on given \b direction.
Shinya Kitaoka 120a6e
//! Also stores cache for it.
Shinya Kitaoka 120a6e
// NOTE: Effectively the dual of calculateMinimumSize(int).
Shinya Kitaoka 120a6e
int Region::calculateMaximumSize(bool direction, bool recalcChildren) {
Shinya Kitaoka 120a6e
  const int inf = 1000000;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int sumMaxSizes = 0, minMaxSizes = inf;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_item) {
Shinya Kitaoka 120a6e
    sumMaxSizes = minMaxSizes = (direction == horizontal)
Shinya Kitaoka 120a6e
                                    ? m_item->maximumSize().width()
Shinya Kitaoka 120a6e
                                    : m_item->maximumSize().height();
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    unsigned int i;
Shinya Kitaoka 120a6e
    int currMaxSize;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // If required, recalculate children sizes along our direction.
Shinya Kitaoka 120a6e
    if (recalcChildren) {
Shinya Kitaoka 120a6e
      for (i = 0; i < m_childList.size(); ++i)
Shinya Kitaoka 120a6e
        m_childList[i]->calculateMaximumSize(direction, true);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    for (i = 0; i < m_childList.size(); ++i) {
Shinya Kitaoka 120a6e
      sumMaxSizes += currMaxSize = m_childList[i]->getMaximumSize(direction);
Shinya Kitaoka 120a6e
      if (minMaxSizes > currMaxSize) minMaxSizes = currMaxSize;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Add separators width
Shinya Kitaoka 120a6e
    sumMaxSizes += m_separators.size() * m_owner->spacing();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // If m_orientation is coherent with input direction, maximum occupied space
Shinya Kitaoka 120a6e
  // is the sum
Shinya Kitaoka 120a6e
  // of childs' maximumSizes. Otherwise, the minimum is taken.
Shinya Kitaoka 120a6e
  if (m_orientation == direction) {
Shinya Kitaoka 120a6e
    return m_maximumSize[direction] = sumMaxSizes;
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    return m_maximumSize[direction] = minMaxSizes;
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
bool Region::addItemSize(DockWidget *item) {
Shinya Kitaoka 120a6e
  int sepWidth = m_owner->spacing();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_orientation == horizontal) {
Shinya Kitaoka 120a6e
    // Add minimum and maximum horizontal sizes
Shinya Kitaoka 120a6e
    m_minimumSize[horizontal] +=
Shinya Kitaoka 120a6e
        item->getDockedMinimumSize().width() + sepWidth;
Shinya Kitaoka 120a6e
    m_maximumSize[horizontal] +=
Shinya Kitaoka 120a6e
        item->getDockedMaximumSize().width() + sepWidth;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Make max and min with vertical extremal sizes
Shinya Kitaoka 120a6e
    m_minimumSize[vertical] = std::max(m_minimumSize[vertical],
Shinya Kitaoka 120a6e
                                       item->getDockedMinimumSize().height());
Shinya Kitaoka 120a6e
    m_maximumSize[vertical] = std::min(m_maximumSize[vertical],
Shinya Kitaoka 120a6e
                                       item->getDockedMaximumSize().height());
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // Viceversa
Shinya Kitaoka 120a6e
    m_minimumSize[vertical] += item->getDockedMinimumSize().height() + sepWidth;
Shinya Kitaoka 120a6e
    m_maximumSize[vertical] += item->getDockedMaximumSize().height() + sepWidth;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_minimumSize[horizontal] = std::max(m_minimumSize[horizontal],
Shinya Kitaoka 120a6e
                                         item->getDockedMinimumSize().width());
Shinya Kitaoka 120a6e
    m_maximumSize[horizontal] = std::min(m_maximumSize[horizontal],
Shinya Kitaoka 120a6e
                                         item->getDockedMaximumSize().width());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_minimumSize[horizontal] > m_maximumSize[horizontal] ||
Shinya Kitaoka 120a6e
      m_minimumSize[vertical] > m_maximumSize[vertical])
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Now, climb parent hierarchy and update extremal sizes. If minSizes get >
Shinya Kitaoka 120a6e
  // maxSizes, return failed insertion
Shinya Kitaoka 120a6e
  Region *r = m_parent;
Shinya Kitaoka 120a6e
  while (r) {
Shinya Kitaoka 120a6e
    r->calculateMinimumSize(horizontal, false);
Shinya Kitaoka 120a6e
    r->calculateMinimumSize(vertical, false);
Shinya Kitaoka 120a6e
    r->calculateMaximumSize(horizontal, false);
Shinya Kitaoka 120a6e
    r->calculateMaximumSize(vertical, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (r->getMinimumSize(horizontal) > r->getMaximumSize(horizontal) ||
Shinya Kitaoka 120a6e
        r->getMinimumSize(vertical) > r->getMaximumSize(vertical))
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    r = r->m_parent;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka d1f6c4
bool Region::subItemSize(DockWidget *item) {
Shinya Kitaoka 120a6e
  int sepWidth = m_owner->spacing();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_orientation == horizontal) {
Shinya Kitaoka 120a6e
    // Subtract minimum and maximum horizontal sizes
Shinya Kitaoka 120a6e
    m_minimumSize[horizontal] -= item->minimumSize().width() + sepWidth;
Shinya Kitaoka 120a6e
    m_maximumSize[horizontal] -= item->maximumSize().width() + sepWidth;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Recalculate opposite extremal sizes (without considering item)
Shinya Kitaoka 120a6e
    unsigned int i;
Shinya Kitaoka 120a6e
    for (i = 0; i < m_childList.size(); ++i)
Shinya Kitaoka 120a6e
      if (m_childList[i]->getItem() != item) {
Shinya Kitaoka 120a6e
        m_minimumSize[vertical] = std::max(
Shinya Kitaoka 120a6e
            m_minimumSize[vertical], m_childList[i]->getMinimumSize(vertical));
Shinya Kitaoka 120a6e
        m_maximumSize[vertical] = std::min(
Shinya Kitaoka 120a6e
            m_maximumSize[vertical], m_childList[i]->getMaximumSize(vertical));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // Viceversa
Shinya Kitaoka 120a6e
    m_minimumSize[vertical] -= item->minimumSize().height() + sepWidth;
Shinya Kitaoka 120a6e
    m_maximumSize[vertical] -= item->maximumSize().height() + sepWidth;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Recalculate opposite extremal sizes (without considering item)
Shinya Kitaoka 120a6e
    unsigned int i;
Shinya Kitaoka 120a6e
    for (i = 0; i < m_childList.size(); ++i)
Shinya Kitaoka 120a6e
      if (m_childList[i]->getItem() != item) {
Shinya Kitaoka 120a6e
        m_minimumSize[horizontal] =
Shinya Kitaoka 120a6e
            std::max(m_minimumSize[horizontal],
Shinya Kitaoka 120a6e
                     m_childList[i]->getMinimumSize(horizontal));
Shinya Kitaoka 120a6e
        m_maximumSize[horizontal] =
Shinya Kitaoka 120a6e
            std::min(m_maximumSize[horizontal],
Shinya Kitaoka 120a6e
                     m_childList[i]->getMaximumSize(horizontal));
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_minimumSize[horizontal] > m_maximumSize[horizontal] ||
Shinya Kitaoka 120a6e
      m_minimumSize[vertical] > m_maximumSize[vertical])
Shinya Kitaoka 120a6e
    return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Now, climb parent hierarchy and update extremal sizes. If minSizes get >
Shinya Kitaoka 120a6e
  // maxSizes, return failed insertion
Shinya Kitaoka 120a6e
  Region *r = m_parent;
Shinya Kitaoka 120a6e
  while (r) {
Shinya Kitaoka 120a6e
    r->calculateMinimumSize(horizontal, false);
Shinya Kitaoka 120a6e
    r->calculateMinimumSize(vertical, false);
Shinya Kitaoka 120a6e
    r->calculateMaximumSize(horizontal, false);
Shinya Kitaoka 120a6e
    r->calculateMaximumSize(vertical, false);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (r->getMinimumSize(horizontal) > r->getMaximumSize(horizontal) ||
Shinya Kitaoka 120a6e
        r->getMinimumSize(vertical) > r->getMaximumSize(vertical))
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    r = r->m_parent;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//=============================================================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Checks insertion validity of \b item inside \b parentRegion at position \b
Shinya Kitaoka 120a6e
//! insertionIdx.
Shinya Kitaoka d1f6c4
bool DockLayout::isPossibleInsertion(DockWidget *item,
Shinya Kitaoka d1f6c4
                                     Region *parentRegion,
Shinya Kitaoka d1f6c4
                                     int insertionIdx) {
Shinya Kitaoka 120a6e
  const int inf = 1000000;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int mainWindowWidth  = contentsRect().width();
Shinya Kitaoka 120a6e
  int mainWindowHeight = contentsRect().height();
Shinya Kitaoka 120a6e
  std::deque<region *="">::iterator i;</region>
Shinya Kitaoka 120a6e
  bool result = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_regions.size()) {
Shinya Kitaoka 120a6e
    // Calculate original extremal sizes
Shinya Kitaoka 120a6e
    m_regions.front()->calculateExtremalSizes();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (parentRegion)  // Common case
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      // And update parent region extremal size after hypothetic insertion took
Shinya Kitaoka 120a6e
      // place
Shinya Kitaoka 120a6e
      result &= parentRegion->addItemSize(item);
Shinya Kitaoka 120a6e
    } else  // With root insertion
Shinya Kitaoka 120a6e
    {
Shinya Kitaoka 120a6e
      // Insertion under new root: simulated by adding with m_regions.front() on
Shinya Kitaoka 120a6e
      // its opposite direction;
Shinya Kitaoka 120a6e
      bool frontOrientation = m_regions.front()->getOrientation();
Shinya Kitaoka 120a6e
      m_regions.front()->setOrientation(!frontOrientation);
Shinya Kitaoka 120a6e
      result &= m_regions.front()->addItemSize(item);
Shinya Kitaoka 120a6e
      m_regions.front()->setOrientation(frontOrientation);
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QSize rootMinSize;
Shinya Kitaoka 120a6e
  QSize rootMaxSize;
Shinya Kitaoka 120a6e
  if (m_regions.size()) {
Shinya Kitaoka 120a6e
    rootMinSize = QSize(m_regions[0]->getMinimumSize(Region::horizontal),
Shinya Kitaoka 120a6e
                        m_regions[0]->getMinimumSize(Region::vertical));
Shinya Kitaoka 120a6e
    rootMaxSize = QSize(m_regions[0]->getMaximumSize(Region::horizontal),
Shinya Kitaoka 120a6e
                        m_regions[0]->getMaximumSize(Region::vertical));
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    // New Root
Shinya Kitaoka 120a6e
    rootMinSize = item->minimumSize();
Shinya Kitaoka 120a6e
    rootMaxSize = item->maximumSize();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, check updated root against main window sizes
Shinya Kitaoka 120a6e
  if (rootMinSize.width() > mainWindowWidth ||
Shinya Kitaoka 120a6e
      rootMinSize.height() > mainWindowHeight ||
Shinya Kitaoka 120a6e
      rootMaxSize.width() < mainWindowWidth ||
Shinya Kitaoka 120a6e
      rootMaxSize.height() < mainWindowHeight) {
Shinya Kitaoka 120a6e
    result = false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Checks insertion validity of \b item inside \b parentRegion at position \b
Shinya Kitaoka 120a6e
//! insertionIdx.
Shinya Kitaoka d1f6c4
bool DockLayout::isPossibleRemoval(DockWidget *item,
Shinya Kitaoka d1f6c4
                                   Region *parentRegion,
Shinya Kitaoka d1f6c4
                                   int removalIdx) {
Shinya Kitaoka 120a6e
  // NOTE: parentRegion is necessarily !=0 or there's no need to check anything
Shinya Kitaoka 120a6e
  if (!parentRegion) return true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  const int inf = 1000000;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  int mainWindowWidth  = contentsRect().width();
Shinya Kitaoka 120a6e
  int mainWindowHeight = contentsRect().height();
Shinya Kitaoka 120a6e
  std::deque<region *="">::iterator i;</region>
Shinya Kitaoka 120a6e
  bool result = true;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Calculate original extremal sizes
Shinya Kitaoka 120a6e
  m_regions.front()->calculateExtremalSizes();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // And update parent region extremal size after hypothetic insertion took
Shinya Kitaoka 120a6e
  // place
Shinya Kitaoka 120a6e
  result &= parentRegion->subItemSize(item);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QSize rootMinSize;
Shinya Kitaoka 120a6e
  QSize rootMaxSize;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  rootMinSize = QSize(m_regions[0]->getMinimumSize(Region::horizontal),
Shinya Kitaoka 120a6e
                      m_regions[0]->getMinimumSize(Region::vertical));
Shinya Kitaoka 120a6e
  rootMaxSize = QSize(m_regions[0]->getMaximumSize(Region::horizontal),
Shinya Kitaoka 120a6e
                      m_regions[0]->getMaximumSize(Region::vertical));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, check updated root against main window sizes
Shinya Kitaoka 120a6e
  if (rootMinSize.width() > mainWindowWidth ||
Shinya Kitaoka 120a6e
      rootMinSize.height() > mainWindowHeight ||
Shinya Kitaoka 120a6e
      rootMaxSize.width() < mainWindowWidth ||
Shinya Kitaoka 120a6e
      rootMaxSize.height() < mainWindowHeight) {
Shinya Kitaoka 120a6e
    result = false;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return result;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//===================
Toshihiro Shimizu 890ddd
//    Save & Load
Toshihiro Shimizu 890ddd
//===================
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Returns the current \b State of the layout. A State is a typedef
Shinya Kitaoka 120a6e
//! for a pair containing the (normal) geometries of all layout items,
Shinya Kitaoka 120a6e
//! and a string indicating their hierarchycal structure.
Shinya Kitaoka 120a6e
DockLayout::State DockLayout::saveState() {
Shinya Kitaoka 120a6e
  QString hierarchy;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Set save indices so we don't need to find anything
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_regions.size(); ++i) m_regions[i]->m_saveIndex = i;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  DockWidget *item;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_items.size(); ++i) {
Shinya Kitaoka 120a6e
    item              = static_cast<dockwidget *="">(m_items[i]->widget());</dockwidget>
Shinya Kitaoka 120a6e
    item->m_saveIndex = i;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Write item geometries
Shinya Kitaoka 120a6e
  std::vector<qrect> geometries;</qrect>
Shinya Kitaoka 120a6e
  for (i = 0; i < m_items.size(); ++i)
Shinya Kitaoka 120a6e
    geometries.push_back(m_items[i]->geometry());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  QTextStream stream(&hierarchy, QIODevice::WriteOnly);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Save maximimized Dock index and geometry
Shinya Kitaoka 120a6e
  stream << QString::number(m_maximizedDock ? m_maximizedDock->m_saveIndex : -1)
Shinya Kitaoka 120a6e
         << " ";
Shinya Kitaoka 120a6e
  if (m_maximizedDock) {
Shinya Kitaoka 120a6e
    Region *r                                = find(m_maximizedDock);
Shinya Kitaoka 120a6e
    geometries[m_maximizedDock->m_saveIndex] = toRect(r->getGeometry());
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Save regions
Shinya Kitaoka 120a6e
  Region *r = rootRegion();
Shinya Kitaoka 120a6e
  if (r) {
Shinya Kitaoka 120a6e
    stream << QString::number(r->getOrientation()) << " ";
Shinya Kitaoka 120a6e
    writeRegion(r, hierarchy);
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return std::pair<std::vector<qrect>, QString>(geometries, hierarchy);</std::vector<qrect>
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
void DockLayout::writeRegion(Region *r, QString &hierarchy) {
Shinya Kitaoka 120a6e
  DockWidget *item = static_cast<dockwidget *="">(r->getItem());</dockwidget>
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
  // If Region has item, write it.
Shinya Kitaoka 120a6e
  if (item) {
Shinya Kitaoka 120a6e
    hierarchy.append(QString::number(item->m_saveIndex) + " ");
Shinya Kitaoka 120a6e
  } else {
Shinya Kitaoka 120a6e
    hierarchy.append("[ ");
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    // Scan childList
Shinya Kitaoka 120a6e
    unsigned int i, size = r->getChildList().size();
Shinya Kitaoka 120a6e
    for (i = 0; i < size; ++i) {
Shinya Kitaoka 120a6e
      writeRegion(r->childRegion(i), hierarchy);
Shinya Kitaoka 120a6e
    }
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
    hierarchy.append("] ");
Shinya Kitaoka 120a6e
  }
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Restores the given internal structure of the layout.
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! This method is intended to restore the
Shinya Kitaoka 120a6e
//! geometry of a set of items that was handled by the layout
Shinya Kitaoka 120a6e
//! at the time the state was saved. Input are the geometries of
Shinya Kitaoka 120a6e
//! the items involved and the dock hierarchy in form of a string.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b IMPORTANT \b NOTE: No check is performed on the item themselves,
Shinya Kitaoka 120a6e
//! except for the consistency of their geometrical constraints
Shinya Kitaoka 120a6e
//! inside the layout. Furthermore, this method does not ensure the
Shinya Kitaoka 120a6e
//! identity of the items involved, assuming that the set of dock
Shinya Kitaoka 120a6e
//! widget has ever been left unchanged or completely restored
Shinya Kitaoka 120a6e
//! as it were when saved. In particular, their ordering must be preserved.
Shinya Kitaoka 120a6e
bool DockLayout::restoreState(const State &state) {
Shinya Kitaoka 120a6e
  QStringList vars = state.second.split(" ", QString::SkipEmptyParts);
Shinya Kitaoka 120a6e
  if (vars.size() < 1) return 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Check number of items
Shinya Kitaoka 120a6e
  unsigned int count = state.first.size();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (m_items.size() != count) return false;  // Items list is not coherent
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Initialize new Regions hierarchy
Shinya Kitaoka 120a6e
  std::deque<region *=""> newHierarchy;</region>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Load it
Shinya Kitaoka 120a6e
  int maximizedItem = vars[0].toInt();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  if (vars.size() > 1) {
Shinya Kitaoka 120a6e
    // Scan hierarchy
Shinya Kitaoka 120a6e
    Region *r       = 0, *newRegion;
Shinya Kitaoka 120a6e
    int orientation = !vars[1].toInt();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    int i;
Shinya Kitaoka 120a6e
    for (i = 2; i < vars.size(); ++i) {
Shinya Kitaoka 120a6e
      if (vars[i] == "]") {
Shinya Kitaoka 120a6e
        // End region and get parent
Shinya Kitaoka 120a6e
        r = r->getParent();
Shinya Kitaoka 120a6e
      } else {
Shinya Kitaoka 120a6e
        // Allocate new Region
Shinya Kitaoka 120a6e
        newRegion = new Region(this);
Shinya Kitaoka 120a6e
        newHierarchy.push_back(newRegion);
Shinya Kitaoka 120a6e
        newRegion->m_orientation = !orientation;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (r) r->insertSubRegion(newRegion, r->getChildList().size());
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
        if (vars[i] == "[") {
Shinya Kitaoka 120a6e
          // Current region has children
Shinya Kitaoka 120a6e
          r = newRegion;
Shinya Kitaoka 120a6e
        } else {
Shinya Kitaoka 120a6e
          // newRegion has item
Shinya Kitaoka 120a6e
          newRegion->m_item =
Shinya Kitaoka 120a6e
              static_cast<dockwidget *="">(m_items[vars[i].toInt()]->widget());</dockwidget>
Shinya Kitaoka 120a6e
        }
Shinya Kitaoka 120a6e
      }
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Check if size constraints are satisfied
Shinya Kitaoka 120a6e
    newHierarchy[0]->calculateExtremalSizes();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  unsigned int j;
Shinya Kitaoka 120a6e
  for (j = 0; j < newHierarchy.size(); ++j) {
Shinya Kitaoka 120a6e
    // Check if their extremal sizes are valid
Shinya Kitaoka 120a6e
    Region *r = newHierarchy[j];
Shinya Kitaoka 120a6e
    if (r->getMinimumSize(Region::horizontal) >
Shinya Kitaoka 120a6e
            r->getMaximumSize(Region::horizontal) ||
Shinya Kitaoka 120a6e
        r->getMinimumSize(Region::vertical) >
Shinya Kitaoka 120a6e
            r->getMaximumSize(Region::vertical)) {
Shinya Kitaoka 120a6e
      // If not, deallocate attempted hierarchy and quit
Shinya Kitaoka 120a6e
      for (j = 0; j < newHierarchy.size(); ++j) delete newHierarchy[j];
Shinya Kitaoka 120a6e
      return false;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Else, deallocate old regions and substitute with new ones
Shinya Kitaoka 120a6e
  for (j    = 0; j < m_regions.size(); ++j) delete m_regions[j];
Shinya Kitaoka 120a6e
  m_regions = newHierarchy;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Now re-initialize dock widgets' infos.
Shinya Kitaoka 120a6e
  const std::vector<qrect> &geoms = state.first;</qrect>
Shinya Kitaoka 120a6e
  DockWidget *item;
Shinya Kitaoka 120a6e
  for (j = 0; j < m_items.size(); ++j) {
Shinya Kitaoka 120a6e
    item = static_cast<dockwidget *="">(m_items[j]->widget());</dockwidget>
Shinya Kitaoka 120a6e
    item->setGeometry(geoms[j]);
Shinya Kitaoka 120a6e
    item->m_maximized = false;
Shinya Kitaoka 120a6e
    item->m_saveIndex = j;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Docked widgets are found in hierarchy
Shinya Kitaoka 120a6e
  for (j = 0; j < m_regions.size(); ++j)
Shinya Kitaoka 120a6e
    if ((item = m_regions[j]->m_item)) {
Shinya Kitaoka 120a6e
      item->setWindowFlags(Qt::SubWindow);
Shinya Kitaoka 120a6e
      item->setDockedAppearance();
Shinya Kitaoka 120a6e
      item->m_floating  = false;
Shinya Kitaoka 120a6e
      item->m_saveIndex = -1;
Shinya Kitaoka 120a6e
      item->show();
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Recover available geometry infos
Shinya Kitaoka 120a6e
  // QRect availableRect= QApplication::desktop()->availableGeometry();
Shinya Kitaoka 120a6e
  int recoverX = 0, recoverY = 0;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Deal with floating panels
Shinya Kitaoka 120a6e
  for (j = 0; j < m_items.size(); ++j) {
Shinya Kitaoka 120a6e
    item = static_cast<dockwidget *="">(m_items[j]->widget());</dockwidget>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    if (item->m_saveIndex > 0) {
Shinya Kitaoka 120a6e
      // Ensure that floating panels are not placed in
Shinya Kitaoka 120a6e
      // unavailable positions
Shinya Kitaoka 120a6e
      if ((geoms[j] & QApplication::desktop()->availableGeometry(item))
Shinya Kitaoka 120a6e
              .isEmpty())
Shinya Kitaoka 120a6e
        item->move(recoverX += 50, recoverY += 50);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
      // Set floating appearances
Shinya Kitaoka 120a6e
      item->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint);
Shinya Kitaoka 120a6e
      item->setFloatingAppearance();
Shinya Kitaoka 120a6e
      item->m_floating = true;
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Allocate region separators
Shinya Kitaoka 120a6e
  unsigned int k;
Shinya Kitaoka 120a6e
  for (j = 0; j < m_regions.size(); ++j) {
Shinya Kitaoka 120a6e
    Region *r = m_regions[j];
Shinya Kitaoka 120a6e
    for (k = 1; k < r->m_childList.size(); ++k) {
Shinya Kitaoka 120a6e
      r->insertSeparator(
Shinya Kitaoka 120a6e
          m_decoAllocator->newSeparator(this, r->getOrientation(), r));
Shinya Kitaoka 120a6e
    }
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Calculate regions' geometry starting from leaves (items)
Shinya Kitaoka 120a6e
  if (m_regions.size()) m_regions[0]->restoreGeometry();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Then, ensure the result is correctly fitting the contents rect
Shinya Kitaoka 120a6e
  // redistribute();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // NOTE: The previous might be tempting to ensure all is right -
Shinya Kitaoka 120a6e
  // unfortunately, it may
Shinya Kitaoka 120a6e
  // be that the main window's content rect is not yet defined before it is
Shinya Kitaoka 120a6e
  // shown the first
Shinya Kitaoka 120a6e
  // time (like on MAC), and that is needed to redistribute. Se we force the
Shinya Kitaoka 120a6e
  // saved values
Shinya Kitaoka 120a6e
  //(assuming they are right)...
Shinya Kitaoka 120a6e
  applyGeometry();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Finally, set maximized dock widget
Shinya Kitaoka 120a6e
  if (maximizedItem != -1) {
Shinya Kitaoka 120a6e
    item = static_cast<dockwidget *="">(m_items[maximizedItem]->widget());</dockwidget>
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Problema: Puo' essere, in fase di caricamento dati, che la contentsRect
Shinya Kitaoka 120a6e
    // del layout
Shinya Kitaoka 120a6e
    // venga sballata! (vv. lo ctor di TMainWindow) Allora, evitiamo il
Shinya Kitaoka 120a6e
    // controllo fatto
Shinya Kitaoka 120a6e
    // in setMazimized, e assumiamo sia per forza corretto...
Shinya Kitaoka 120a6e
    // setMaximized(item, true);
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    m_maximizedDock   = item;
Shinya Kitaoka 120a6e
    item->m_maximized = true;
Shinya Kitaoka 120a6e
    item->raise();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
    // Hide all other widgets
Shinya Kitaoka 120a6e
    QWidget *currWidget;
Shinya Kitaoka 120a6e
    for (int i = 0; i < this->count(); ++i)
Shinya Kitaoka 120a6e
      if ((currWidget = itemAt(i)->widget()) != item) currWidget->hide();
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return true;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Recalculates the geometry of \b this Region and of its branches,
Shinya Kitaoka 120a6e
//! assuming those of 'leaf items' are correct.
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
//! Regions always tend to keep their geometry by default. However,
Shinya Kitaoka 120a6e
//! it may be useful (for example, when restoring the state of a DockLayout)
Shinya Kitaoka 120a6e
//! the possibility of recalculating its current geometry directly from the
Shinya Kitaoka 120a6e
//! items that are contained in the branches.
Shinya Kitaoka 120a6e
void Region::restoreGeometry() {
Shinya Kitaoka 120a6e
  // Applying a head-recursive algorithm to update the geometry of a Region
Shinya Kitaoka 120a6e
  // after those of its children have been updated
Shinya Kitaoka 120a6e
  if (m_item) {
Shinya Kitaoka 120a6e
    // Place item's geometry
Shinya Kitaoka 120a6e
    setGeometry(m_item->geometry());
Shinya Kitaoka 120a6e
    return;
Shinya Kitaoka 120a6e
  }
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // First do children
Shinya Kitaoka 120a6e
  unsigned int i;
Shinya Kitaoka 120a6e
  for (i = 0; i < m_childList.size(); ++i) m_childList[i]->restoreGeometry();
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Then, update this one: just take the edges of its children.
Shinya Kitaoka 120a6e
  unsigned int last = m_childList.size() - 1;
Shinya Kitaoka 120a6e
  QPoint topLeft(m_childList[0]->getGeometry().left(),
Shinya Kitaoka 120a6e
                 m_childList[0]->getGeometry().top());
Shinya Kitaoka 120a6e
  QPoint bottomRight(m_childList[last]->getGeometry().right(),
Shinya Kitaoka 120a6e
                     m_childList[last]->getGeometry().bottom());
Shinya Kitaoka 120a6e
  setGeometry(QRect(topLeft, bottomRight));
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  return;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//========================================================================
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//---------------------------
Toshihiro Shimizu 890ddd
//    Dock Deco Allocator
Toshihiro Shimizu 890ddd
//---------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Allocates a new DockSeparator with input parameters. This function can be
Shinya Kitaoka 120a6e
//! re-implemented
Shinya Kitaoka 120a6e
//! to allocate derived DockSeparator classes.
Shinya Kitaoka d1f6c4
DockSeparator *DockDecoAllocator::newSeparator(DockLayout *owner,
Shinya Kitaoka d1f6c4
                                               bool orientation,
Shinya Kitaoka d1f6c4
                                               Region *parentRegion) {
Shinya Kitaoka 120a6e
  return new DockSeparator(owner, orientation, parentRegion);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! When inheriting a DockLayout class, new custom placeholders gets allocated
Shinya Kitaoka 120a6e
//! by this method.
Shinya Kitaoka d1f6c4
DockPlaceholder *DockDecoAllocator::newPlaceholder(DockWidget *owner,
Shinya Kitaoka d1f6c4
                                                   Region *r, int idx,
Shinya Kitaoka d1f6c4
                                                   int attributes) {
Shinya Kitaoka 120a6e
  return new DockPlaceholder(owner, r, idx, attributes);
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
// BuildGeometry() method should not be called inside the base contructor -
Shinya Kitaoka 120a6e
// because it's a virtual method.
Shinya Kitaoka 120a6e
// So we provide this little inline...
Shinya Kitaoka d1f6c4
DockPlaceholder *DockDecoAllocator::newPlaceBuilt(DockWidget *owner,
Shinya Kitaoka d1f6c4
                                                  Region *r, int idx,
Shinya Kitaoka d1f6c4
                                                  int attributes) {
Shinya Kitaoka 120a6e
  DockPlaceholder *res = newPlaceholder(owner, r, idx, attributes);
Shinya Kitaoka 120a6e
  res->buildGeometry();
Shinya Kitaoka 120a6e
  return res;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Sets current deco allocator to decoAllocator. A default deco allocator
Shinya Kitaoka 120a6e
//! is already provided at construction.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: DockLayout takes ownership of the allocator.
Shinya Kitaoka 120a6e
void DockLayout::setDecoAllocator(DockDecoAllocator *decoAllocator) {
Shinya Kitaoka 120a6e
  // Delete old one
Shinya Kitaoka 120a6e
  if (m_decoAllocator) delete m_decoAllocator;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Place new one
Shinya Kitaoka 120a6e
  m_decoAllocator = decoAllocator;
Toshihiro Shimizu 890ddd
}
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//------------------------------------------------------
Toshihiro Shimizu 890ddd
Shinya Kitaoka 120a6e
//! Sets current deco allocator to decoAllocator. A default deco allocator
Shinya Kitaoka 120a6e
//! is already provided at construction.
Toshihiro Shimizu 890ddd
Toshihiro Shimizu 890ddd
//!\b NOTE: DockWidget takes ownership of the allocator.
Shinya Kitaoka 120a6e
void DockWidget::setDecoAllocator(DockDecoAllocator *decoAllocator) {
Shinya Kitaoka 120a6e
  // Delete old one
Shinya Kitaoka 120a6e
  if (m_decoAllocator) delete m_decoAllocator;
Shinya Kitaoka 120a6e
Shinya Kitaoka 120a6e
  // Place a copy of new one
Shinya Kitaoka 120a6e
  m_decoAllocator = decoAllocator;
Toshihiro Shimizu 890ddd
}