| |
| |
|
|
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| inline QRect toRect(const QRectF &rect) |
| { |
| |
| return QRect(rect.topLeft().toPoint(), rect.bottomRight().toPoint() -= QPoint(1, 1)); |
| } |
| |
| |
| |
| |
| |
| |
| |
| DockLayout::DockLayout() |
| : m_maximizedDock(0), m_decoAllocator(new DockDecoAllocator()) |
| { |
| } |
| |
| |
| |
| DockLayout::~DockLayout() |
| { |
| |
| unsigned int i; |
| for (i = 0; i < m_regions.size(); ++i) |
| delete m_regions[i]; |
| |
| |
| for (i = 0; i < m_items.size(); ++i) { |
| |
| delete m_items[i]; |
| } |
| |
| |
| delete m_decoAllocator; |
| } |
| |
| |
| |
| inline int DockLayout::count() const |
| { |
| return m_items.size(); |
| } |
| |
| |
| |
| inline void DockLayout::addItem(QLayoutItem *item) |
| { |
| DockWidget *addedItem = dynamic_cast<DockWidget *>(item->widget()); |
| |
| |
| assert(addedItem); |
| |
| |
| if (find(addedItem)) |
| return; |
| |
| |
| |
| addedItem->m_parentLayout = this; |
| addedItem->setParent(parentWidget()); |
| |
| |
| |
| |
| addedItem->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); |
| addedItem->setFloatingAppearance(); |
| |
| m_items.push_back(item); |
| } |
| |
| |
| |
| inline QLayoutItem *DockLayout::takeAt(int idx) |
| { |
| if (idx < 0 || idx >= (int)m_items.size()) |
| return 0; |
| |
| QLayoutItem *item = m_items[idx]; |
| DockWidget *dw = static_cast<DockWidget *>(item->widget()); |
| |
| |
| if (!dw->isFloating()) |
| undockItem(dw); |
| |
| |
| dw->m_parentLayout = 0; |
| |
| m_items.erase(m_items.begin() + idx); |
| |
| return item; |
| } |
| |
| |
| |
| inline QLayoutItem *DockLayout::itemAt(int idx) const |
| { |
| if (idx >= (int)m_items.size()) |
| return 0; |
| return m_items[idx]; |
| } |
| |
| |
| |
| QWidget *DockLayout::widgetAt(int idx) const |
| { |
| return itemAt(idx)->widget(); |
| } |
| |
| |
| |
| inline QSize DockLayout::minimumSize() const |
| { |
| if (!m_regions.empty()) { |
| Region *r = m_regions.front(); |
| r->calculateExtremalSizes(); |
| return QSize(r->m_minimumSize[0], r->m_minimumSize[1]); |
| } |
| |
| return QSize(0, 0); |
| } |
| |
| |
| |
| inline QSize DockLayout::maximumSize() const |
| { |
| if (!m_regions.empty()) { |
| Region *r = m_regions.front(); |
| r->calculateExtremalSizes(); |
| return QSize(r->m_maximumSize[0], r->m_maximumSize[1]); |
| } |
| |
| return QSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX); |
| } |
| |
| |
| |
| inline QSize DockLayout::sizeHint() const |
| { |
| QSize s(0, 0); |
| int n = m_items.size(); |
| if (n > 0) |
| s = QSize(100, 70); |
| int i = 0; |
| while (i < n) { |
| QLayoutItem *o = m_items[i]; |
| s = s.expandedTo(o->sizeHint()); |
| ++i; |
| } |
| return s + n * QSize(spacing(), spacing()); |
| |
| |
| } |
| |
| |
| |
| |
| |
| |
| |
| QWidget *DockLayout::containerOf(QPoint point) const |
| { |
| |
| int i; |
| unsigned int j; |
| for (i = m_regions.size() - 1; i >= 0; --i) { |
| Region *currRegion = m_regions[i]; |
| DockWidget *item = currRegion->getItem(); |
| |
| |
| if (item && item->geometry().contains(point)) |
| return currRegion->getItem(); |
| |
| |
| for (j = 0; j < currRegion->separators().size(); ++j) |
| if (currRegion->separator(j)->geometry().contains(point)) |
| return currRegion->separator(j); |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| inline void DockLayout::setMaximized(DockWidget *item, bool state) |
| { |
| if (item && state != item->m_maximized) { |
| if (state) { |
| |
| if (m_maximizedDock) { |
| |
| Region *r = find(m_maximizedDock); |
| m_maximizedDock->setGeometry(toRect(r->getGeometry())); |
| m_maximizedDock->m_maximized = false; |
| } |
| |
| |
| QSize minimumSize = item->minimumSize(); |
| QSize maximumSize = item->maximumSize(); |
| |
| if (contentsRect().width() > minimumSize.width() && contentsRect().height() > minimumSize.height() && |
| contentsRect().width() < maximumSize.width() && contentsRect().height() < maximumSize.height()) { |
| |
| item->setGeometry(contentsRect()); |
| item->raise(); |
| item->m_maximized = true; |
| m_maximizedDock = item; |
| |
| |
| |
| DockWidget *currWidget; |
| for (int i = 0; i < count(); ++i) { |
| currWidget = (DockWidget *)itemAt(i)->widget(); |
| if (currWidget != item && !currWidget->isFloating()) |
| currWidget->hide(); |
| } |
| } |
| } else { |
| |
| Region *r = find(m_maximizedDock); |
| if (r) |
| m_maximizedDock->setGeometry(toRect(r->getGeometry())); |
| |
| m_maximizedDock->m_maximized = false; |
| m_maximizedDock = 0; |
| |
| |
| DockWidget *currWidget; |
| for (int i = 0; i < count(); ++i) { |
| currWidget = (DockWidget *)itemAt(i)->widget(); |
| if (currWidget != item && !currWidget->isFloating()) |
| currWidget->show(); |
| } |
| } |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| void DockLayout::setGeometry(const QRect &rect) |
| { |
| |
| QLayout::setGeometry(rect); |
| } |
| |
| |
| |
| |
| |
| inline void DockLayout::updateSeparatorCursors() |
| { |
| Region *r, *child; |
| |
| unsigned int i, j; |
| int k, jInt; |
| for (i = 0; i < m_regions.size(); ++i) { |
| r = m_regions[i]; |
| bool orientation = r->getOrientation(); |
| |
| |
| |
| QSize size = toRect(r->getGeometry()).size(); |
| bool isExtremeSize = (orientation == Region::horizontal) ? size.width() == r->getMinimumSize(Region::horizontal) || size.width() == r->getMaximumSize(Region::horizontal) : size.height() == r->getMinimumSize(Region::vertical) || size.height() == r->getMaximumSize(Region::vertical); |
| if (isExtremeSize) { |
| for (j = 0; j < r->separators().size(); ++j) |
| r->separator(j)->setCursor(Qt::ArrowCursor); |
| continue; |
| } |
| |
| |
| |
| |
| |
| for (j = 0; j < r->getChildList().size(); ++j) { |
| child = r->childRegion(j); |
| |
| if (child->getMaximumSize(orientation) == child->getMinimumSize(orientation)) |
| r->separator(j)->setCursor(Qt::ArrowCursor); |
| else |
| break; |
| } |
| |
| jInt = j; |
| |
| for (k = r->getChildList().size() - 1; k > jInt; --k) { |
| child = r->childRegion(k); |
| |
| if (child->getMaximumSize(orientation) == child->getMinimumSize(orientation)) |
| r->separator(k - 1)->setCursor(Qt::ArrowCursor); |
| else |
| break; |
| } |
| |
| |
| Qt::CursorShape shape = (orientation == Region::horizontal) ? Qt::SplitHCursor : Qt::SplitVCursor; |
| for (; jInt < k; ++jInt) |
| r->separator(jInt)->setCursor(shape); |
| } |
| } |
| |
| |
| |
| |
| void DockLayout::applyGeometry() |
| { |
| |
| unsigned int i, j; |
| for (i = 0; i < m_regions.size(); ++i) { |
| Region *r = m_regions[i]; |
| const std::deque<Region *> &childList = r->getChildList(); |
| std::deque<DockSeparator *> &sepList = r->m_separators; |
| |
| if (m_regions[i]->getItem()) { |
| m_regions[i]->getItem()->setGeometry(toRect(m_regions[i]->getGeometry())); |
| } else { |
| for (j = 0; j < sepList.size(); ++j) { |
| QRect leftAdjRect = toRect(childList[j]->getGeometry()); |
| if (r->getOrientation() == Region::horizontal) { |
| leftAdjRect.adjust(0, 0, 1, 0); |
| sepList[j]->setGeometry(QRect(leftAdjRect.topRight(), QSize(spacing(), leftAdjRect.height()))); |
| sepList[j]->m_index = j; |
| } else { |
| leftAdjRect.adjust(0, 0, 0, 1); |
| sepList[j]->setGeometry(QRect(leftAdjRect.bottomLeft(), QSize(leftAdjRect.width(), spacing()))); |
| sepList[j]->m_index = j; |
| } |
| } |
| } |
| } |
| |
| |
| if (m_maximizedDock) { |
| m_maximizedDock->setGeometry(toRect(m_regions[0]->getGeometry())); |
| m_maximizedDock->raise(); |
| } |
| |
| |
| updateSeparatorCursors(); |
| } |
| |
| |
| |
| void DockLayout::applyTransform(const QTransform &transform) |
| { |
| unsigned int i; |
| for (i = 0; i < m_regions.size(); ++i) |
| m_regions[i]->setGeometry(transform.mapRect(m_regions[i]->getGeometry())); |
| } |
| |
| |
| |
| void DockLayout::redistribute() |
| { |
| if (!m_regions.empty()) { |
| |
| |
| m_regions.front()->calculateExtremalSizes(); |
| |
| int parentWidth = contentsRect().width(); |
| int parentHeight = contentsRect().height(); |
| |
| |
| if (m_regions.front()->getMinimumSize(Region::horizontal) > parentWidth || |
| m_regions.front()->getMinimumSize(Region::vertical) > parentHeight || |
| m_regions.front()->getMaximumSize(Region::horizontal) < parentWidth || |
| m_regions.front()->getMaximumSize(Region::vertical) < parentHeight) |
| return; |
| |
| |
| m_regions.front()->setGeometry(contentsRect()); |
| m_regions.front()->redistribute(); |
| } |
| |
| |
| applyGeometry(); |
| } |
| |
| |
| |
| |
| |
| |
| |
| Region::~Region() |
| { |
| |
| unsigned int i; |
| for (i = 0; i < m_separators.size(); ++i) |
| delete m_separators[i]; |
| } |
| |
| |
| |
| |
| inline void Region::insertSeparator(DockSeparator *sep) |
| { |
| m_separators.push_back(sep); |
| } |
| |
| |
| |
| |
| inline void Region::removeSeparator() |
| { |
| delete m_separators.back(); |
| m_separators.pop_back(); |
| } |
| |
| |
| |
| inline void Region::insertSubRegion(Region *subRegion, int idx) |
| { |
| m_childList.insert(m_childList.begin() + idx, subRegion); |
| subRegion->m_parent = this; |
| subRegion->m_orientation = !m_orientation; |
| } |
| |
| |
| |
| |
| inline Region *Region::insertItem(DockWidget *item, int idx) |
| { |
| Region *newRegion = new Region(m_owner, item); |
| |
| if (this) |
| insertSubRegion(newRegion, idx); |
| |
| return newRegion; |
| } |
| |
| |
| |
| unsigned int Region::find(const Region *subRegion) const |
| { |
| unsigned int i; |
| |
| for (i = 0; i < m_childList.size(); ++i) |
| if (m_childList[i] == subRegion) |
| return i; |
| |
| return -1; |
| } |
| |
| |
| |
| Region *DockLayout::find(DockWidget *item) const |
| { |
| unsigned int i; |
| |
| for (i = 0; i < m_regions.size(); ++i) |
| if (m_regions[i]->getItem() == item) |
| return m_regions[i]; |
| |
| return 0; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void DockLayout::calculateDockPlaceholders(DockWidget *item) |
| { |
| assert(item); |
| |
| |
| if (!parentWidget()->isVisible()) |
| return; |
| |
| if (!m_regions.size()) { |
| if (isPossibleInsertion(item, 0, 0)) { |
| |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, 0, 0, DockPlaceholder::root)); |
| return; |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| if (isPossibleInsertion(item, 0, 0)) { |
| QRect contRect = contentsRect(); |
| if (m_regions.front()->getOrientation() == Region::horizontal) { |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, 0, 0, DockPlaceholder::top)); |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, 0, 1, DockPlaceholder::bottom)); |
| } else { |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, 0, 0, DockPlaceholder::left)); |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, 0, 1, DockPlaceholder::right)); |
| } |
| } |
| |
| unsigned int i; |
| for (i = 0; i < m_regions.size(); ++i) { |
| Region *r = m_regions[i]; |
| r->m_placeholders.clear(); |
| |
| if (isPossibleInsertion(item, r, 0)) { |
| unsigned int j; |
| QRect cellRect; |
| |
| |
| if (r->getOrientation() == Region::horizontal) { |
| |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, 0, DockPlaceholder::left)); |
| r->m_placeholders.push_back(item->m_placeholders.back()); |
| |
| |
| for (j = 1; j < r->getChildList().size(); ++j) { |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, j, DockPlaceholder::sepVert)); |
| r->m_placeholders.push_back(item->m_placeholders.back()); |
| } |
| |
| |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, j, DockPlaceholder::right)); |
| r->m_placeholders.push_back(item->m_placeholders.back()); |
| } else { |
| |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, 0, DockPlaceholder::top)); |
| r->m_placeholders.push_back(item->m_placeholders.back()); |
| |
| for (j = 1; j < r->getChildList().size(); ++j) { |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, j, DockPlaceholder::sepHor)); |
| r->m_placeholders.push_back(item->m_placeholders.back()); |
| } |
| |
| |
| item->m_placeholders.push_back(item->m_decoAllocator->newPlaceBuilt(item, r, j, DockPlaceholder::bottom)); |
| r->m_placeholders.push_back(item->m_placeholders.back()); |
| } |
| } |
| } |
| |
| |
| |
| |
| } |
| |
| |
| |
| |
| |
| |
| void DockLayout::dockItem(DockWidget *item, DockPlaceholder *place) |
| { |
| place->hide(); |
| item->hide(); |
| dockItemPrivate(item, place->m_region, place->m_idx); |
| redistribute(); |
| parentWidget()->repaint(); |
| item->setWindowFlags(Qt::SubWindow); |
| item->show(); |
| } |
| |
| |
| |
| |
| |
| void DockLayout::dockItem(DockWidget *item, DockWidget *target, int regionSide) |
| { |
| Region *targetRegion = find(target); |
| |
| short var = regionSide >> 2 * (int)targetRegion->getOrientation(); |
| bool pos = regionSide & 0xa; |
| |
| item->setWindowFlags(Qt::SubWindow); |
| item->show(); |
| |
| if (var & 0x3) { |
| |
| dockItemPrivate(item, targetRegion, pos); |
| } else { |
| |
| Region *parentRegion = targetRegion->getParent(); |
| unsigned int idx = parentRegion ? parentRegion->find(targetRegion) + pos : pos; |
| dockItemPrivate(item, parentRegion, idx); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| Region *DockLayout::dockItem(DockWidget *item, Region *r, int idx) |
| { |
| item->setWindowFlags(Qt::SubWindow); |
| item->show(); |
| return dockItemPrivate(item, r, idx); |
| } |
| |
| |
| |
| |
| |
| |
| inline Region *DockLayout::dockItemPrivate(DockWidget *item, Region *r, int idx) |
| { |
| |
| item->onDock(true); |
| |
| item->setDockedAppearance(); |
| item->m_floating = false; |
| |
| if (!r) { |
| |
| Region *newRoot = new Region(this); |
| |
| m_regions.push_front(newRoot); |
| |
| newRoot->setSize(item->size()); |
| |
| if (m_regions.size() == 1) { |
| newRoot->setItem(item); |
| return newRoot; |
| } |
| |
| newRoot->setOrientation(!m_regions[1]->getOrientation()); |
| newRoot->insertSubRegion(m_regions[1], 0); |
| |
| r = newRoot; |
| } else if (r->getItem()) { |
| |
| Region *regionForOldItem = r->insertItem(r->getItem(), 0); |
| regionForOldItem->setSize(r->getItem()->size()); |
| |
| r->setItem(0); |
| m_regions.push_back(regionForOldItem); |
| } |
| |
| Region *newRegion = r->insertItem(item, idx); |
| m_regions.push_back(newRegion); |
| |
| newRegion->setSize(item->size()); |
| |
| |
| r->insertSeparator(m_decoAllocator->newSeparator(this, r->getOrientation(), r)); |
| |
| return newRegion; |
| } |
| |
| |
| |
| |
| inline bool isEmptyRegion(Region *r) |
| { |
| if ((!r->getItem()) && (r->getChildList().size() == 0)) { |
| delete r; |
| return true; |
| } |
| return false; |
| } |
| |
| |
| |
| |
| inline void Region::removeItem(DockWidget *item) |
| { |
| if (item == 0) |
| return; |
| |
| unsigned int i; |
| for (i = 0; i < m_childList.size(); ++i) |
| if (item == m_childList[i]->getItem()) { |
| m_childList.erase(m_childList.begin() + i); |
| |
| removeSeparator(); |
| |
| |
| if (m_childList.size() == 1) { |
| Region *parent = getParent(); |
| if (parent) { |
| Region *remainingSon = m_childList[0]; |
| if (!remainingSon->m_childList.size()) { |
| |
| setItem(remainingSon->getItem()); |
| remainingSon->setItem(0); |
| } else { |
| |
| |
| |
| |
| unsigned int j = parent->find(this); |
| |
| parent->m_childList.erase(parent->m_childList.begin() + j); |
| parent->m_childList.insert(parent->m_childList.begin() + j, remainingSon->m_childList.begin(), |
| remainingSon->m_childList.end()); |
| parent->m_separators.insert(parent->m_separators.begin() + j, remainingSon->m_separators.begin(), |
| remainingSon->m_separators.end()); |
| |
| |
| for (j = 0; j < remainingSon->m_childList.size(); ++j) |
| remainingSon->m_childList[j]->m_parent = parent; |
| |
| for (j = 0; j < remainingSon->m_separators.size(); ++j) |
| remainingSon->m_separators[j]->m_parentRegion = parent; |
| |
| remainingSon->m_childList.clear(); |
| remainingSon->m_separators.clear(); |
| } |
| } else { |
| |
| m_childList[0]->setParent(0); |
| } |
| |
| m_childList.clear(); |
| } |
| |
| break; |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| bool DockLayout::undockItem(DockWidget *item) |
| { |
| |
| Region *itemCarrier = find(item); |
| |
| Region *parent = itemCarrier->getParent(); |
| if (parent) { |
| int removalIdx = 0; |
| |
| |
| unsigned int j; |
| for (j = 0; j < parent->getChildList().size(); ++j) |
| if (parent->getChildList()[j]->getItem() == item) |
| break; |
| |
| if (isPossibleRemoval(item, parent, removalIdx)) |
| parent->removeItem(item); |
| else |
| return false; |
| } |
| |
| |
| |
| itemCarrier->setItem(0); |
| |
| std::deque<Region *>::iterator j; |
| j = std::remove_if(m_regions.begin(), m_regions.end(), isEmptyRegion); |
| m_regions.resize(j - m_regions.begin()); |
| |
| |
| |
| item->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); |
| |
| |
| |
| item->setFloatingAppearance(); |
| item->m_floating = true; |
| |
| |
| item->onDock(false); |
| |
| setMaximized(item, false); |
| |
| redistribute(); |
| |
| return true; |
| } |
| |
| |
| |
| |
| |
| inline void calculateNearest(std::vector<double> target, std::vector<double> &nearest, |
| std::vector<std::pair<int, int>> intervals, double sum) |
| { |
| |
| assert(target.size() == intervals.size()); |
| |
| unsigned int i; |
| |
| double targetSum = 0; |
| for (i = 0; i < target.size(); ++i) |
| targetSum += target[i]; |
| |
| double multiplier = (sum - targetSum) / (double)target.size(); |
| |
| nearest.resize(target.size()); |
| for (i = 0; i < target.size(); ++i) |
| nearest[i] = target[i] + multiplier; |
| |
| |
| |
| |
| |
| |
| |
| unsigned int max; |
| double distance, maxDistance = 0; |
| |
| for (i = 0; i < target.size(); ++i) { |
| if (nearest[i] < intervals[i].first || nearest[i] > intervals[i].second) { |
| distance = nearest[i] < intervals[i].first ? intervals[i].first - nearest[i] : nearest[i] - intervals[i].second; |
| nearest[i] = nearest[i] < intervals[i].first ? intervals[i].first : intervals[i].second; |
| if (maxDistance < distance) { |
| maxDistance = distance; |
| max = i; |
| } |
| } |
| } |
| |
| std::vector<double> newTarget = target; |
| std::vector<double> newNearest; |
| std::vector<std::pair<int, int>> newIntervals = intervals; |
| |
| if (maxDistance) { |
| newTarget.erase(newTarget.begin() + max); |
| newIntervals.erase(newIntervals.begin() + max); |
| sum -= nearest[max]; |
| calculateNearest(newTarget, newNearest, newIntervals, sum); |
| for (i = 0; i < max; ++i) |
| nearest[i] = newNearest[i]; |
| for (i = max + 1; i < nearest.size(); ++i) |
| nearest[i] = newNearest[i - 1]; |
| } else |
| return; |
| } |
| |
| |
| |
| |
| |
| void Region::redistribute() |
| { |
| if (!m_childList.size()) |
| return; |
| |
| bool expansion = |
| m_minimumSize[Region::horizontal] > m_rect.width() || |
| m_minimumSize[Region::vertical] > m_rect.height(); |
| |
| double regionSize[2]; |
| |
| |
| regionSize[Region::horizontal] = expansion ? m_minimumSize[Region::horizontal] : m_rect.width(); |
| regionSize[Region::vertical] = expansion ? m_minimumSize[Region::vertical] : m_rect.height(); |
| |
| |
| if (m_parent != 0) |
| regionSize[m_orientation] = std::min((double)m_parent->m_maximumSize[m_orientation], regionSize[m_orientation]); |
| |
| |
| unsigned int i; |
| |
| |
| std::vector<double> targetSizes(m_childList.size()); |
| for (i = 0; i < m_childList.size(); ++i) { |
| |
| targetSizes[i] = (m_orientation == Region::horizontal) ? m_childList[i]->m_rect.width() : m_childList[i]->m_rect.height(); |
| } |
| |
| |
| std::vector<std::pair<int, int>> sizeIntervals(m_childList.size()); |
| for (i = 0; i < m_childList.size(); ++i) { |
| sizeIntervals[i].first = m_childList[i]->m_minimumSize[m_orientation]; |
| sizeIntervals[i].second = m_childList[i]->m_maximumSize[m_orientation]; |
| } |
| |
| |
| int separatorWidth = m_owner->spacing(); |
| double sum = regionSize[m_orientation] - (m_childList.size() - 1) * separatorWidth; |
| |
| std::vector<double> nearestSizes; |
| calculateNearest(targetSizes, nearestSizes, sizeIntervals, sum); |
| |
| |
| QPointF topLeftCorner = m_rect.topLeft(); |
| if (m_orientation == horizontal) { |
| for (i = 0; i < m_childList.size(); ++i) { |
| QSizeF currSize = QSizeF(nearestSizes[i], regionSize[vertical]); |
| m_childList[i]->setGeometry(QRectF(topLeftCorner, currSize)); |
| topLeftCorner = m_childList[i]->getGeometry().topRight() + QPointF(separatorWidth, 0); |
| } |
| } else { |
| for (i = 0; i < m_childList.size(); ++i) { |
| QSizeF currSize = QSizeF(regionSize[horizontal], nearestSizes[i]); |
| m_childList[i]->setGeometry(QRectF(topLeftCorner, currSize)); |
| topLeftCorner = m_childList[i]->getGeometry().bottomLeft() + QPointF(0, separatorWidth); |
| } |
| } |
| |
| |
| for (i = 0; i < m_childList.size(); ++i) |
| m_childList[i]->redistribute(); |
| } |
| |
| |
| |
| |
| void Region::calculateExtremalSizes() |
| { |
| calculateMinimumSize(horizontal, true); |
| calculateMinimumSize(vertical, true); |
| calculateMaximumSize(horizontal, true); |
| calculateMaximumSize(vertical, true); |
| } |
| |
| |
| |
| |
| int Region::calculateMinimumSize(bool direction, bool recalcChildren) |
| { |
| int sumMinSizes = 0, maxMinSizes = 0; |
| |
| if (m_item) { |
| sumMinSizes = maxMinSizes = (direction == horizontal) ? m_item->minimumSize().width() : m_item->minimumSize().height(); |
| } else { |
| unsigned int i; |
| int currMinSize; |
| |
| |
| if (recalcChildren) { |
| for (i = 0; i < m_childList.size(); ++i) |
| m_childList[i]->calculateMinimumSize(direction, true); |
| } |
| |
| for (i = 0; i < m_childList.size(); ++i) { |
| sumMinSizes += currMinSize = m_childList[i]->getMinimumSize(direction); |
| if (maxMinSizes < currMinSize) |
| maxMinSizes = currMinSize; |
| } |
| |
| |
| sumMinSizes += m_separators.size() * m_owner->spacing(); |
| } |
| |
| |
| |
| if (m_orientation == direction) { |
| return m_minimumSize[direction] = sumMinSizes; |
| } else { |
| return m_minimumSize[direction] = maxMinSizes; |
| } |
| } |
| |
| |
| |
| |
| |
| int Region::calculateMaximumSize(bool direction, bool recalcChildren) |
| { |
| const int inf = 1000000; |
| |
| int sumMaxSizes = 0, minMaxSizes = inf; |
| |
| if (m_item) { |
| sumMaxSizes = minMaxSizes = (direction == horizontal) ? m_item->maximumSize().width() : m_item->maximumSize().height(); |
| } else { |
| unsigned int i; |
| int currMaxSize; |
| |
| |
| if (recalcChildren) { |
| for (i = 0; i < m_childList.size(); ++i) |
| m_childList[i]->calculateMaximumSize(direction, true); |
| } |
| |
| for (i = 0; i < m_childList.size(); ++i) { |
| sumMaxSizes += currMaxSize = m_childList[i]->getMaximumSize(direction); |
| if (minMaxSizes > currMaxSize) |
| minMaxSizes = currMaxSize; |
| } |
| |
| |
| sumMaxSizes += m_separators.size() * m_owner->spacing(); |
| } |
| |
| |
| |
| if (m_orientation == direction) { |
| return m_maximumSize[direction] = sumMaxSizes; |
| } else { |
| return m_maximumSize[direction] = minMaxSizes; |
| } |
| } |
| |
| |
| |
| inline bool Region::addItemSize(DockWidget *item) |
| { |
| int sepWidth = m_owner->spacing(); |
| |
| if (m_orientation == horizontal) { |
| |
| m_minimumSize[horizontal] += item->getDockedMinimumSize().width() + sepWidth; |
| m_maximumSize[horizontal] += item->getDockedMaximumSize().width() + sepWidth; |
| |
| |
| m_minimumSize[vertical] = std::max(m_minimumSize[vertical], item->getDockedMinimumSize().height()); |
| m_maximumSize[vertical] = std::min(m_maximumSize[vertical], item->getDockedMaximumSize().height()); |
| } else { |
| |
| m_minimumSize[vertical] += item->getDockedMinimumSize().height() + sepWidth; |
| m_maximumSize[vertical] += item->getDockedMaximumSize().height() + sepWidth; |
| |
| m_minimumSize[horizontal] = std::max(m_minimumSize[horizontal], item->getDockedMinimumSize().width()); |
| m_maximumSize[horizontal] = std::min(m_maximumSize[horizontal], item->getDockedMaximumSize().width()); |
| } |
| |
| if (m_minimumSize[horizontal] > m_maximumSize[horizontal] || |
| m_minimumSize[vertical] > m_maximumSize[vertical]) |
| return false; |
| |
| |
| Region *r = m_parent; |
| while (r) { |
| r->calculateMinimumSize(horizontal, false); |
| r->calculateMinimumSize(vertical, false); |
| r->calculateMaximumSize(horizontal, false); |
| r->calculateMaximumSize(vertical, false); |
| |
| if (r->getMinimumSize(horizontal) > r->getMaximumSize(horizontal) || |
| r->getMinimumSize(vertical) > r->getMaximumSize(vertical)) |
| return false; |
| |
| r = r->m_parent; |
| } |
| |
| return true; |
| } |
| |
| |
| |
| inline bool Region::subItemSize(DockWidget *item) |
| { |
| int sepWidth = m_owner->spacing(); |
| |
| if (m_orientation == horizontal) { |
| |
| m_minimumSize[horizontal] -= item->minimumSize().width() + sepWidth; |
| m_maximumSize[horizontal] -= item->maximumSize().width() + sepWidth; |
| |
| |
| unsigned int i; |
| for (i = 0; i < m_childList.size(); ++i) |
| if (m_childList[i]->getItem() != item) { |
| m_minimumSize[vertical] = std::max(m_minimumSize[vertical], m_childList[i]->getMinimumSize(vertical)); |
| m_maximumSize[vertical] = std::min(m_maximumSize[vertical], m_childList[i]->getMaximumSize(vertical)); |
| } |
| } else { |
| |
| m_minimumSize[vertical] -= item->minimumSize().height() + sepWidth; |
| m_maximumSize[vertical] -= item->maximumSize().height() + sepWidth; |
| |
| |
| unsigned int i; |
| for (i = 0; i < m_childList.size(); ++i) |
| if (m_childList[i]->getItem() != item) { |
| m_minimumSize[horizontal] = std::max(m_minimumSize[horizontal], m_childList[i]->getMinimumSize(horizontal)); |
| m_maximumSize[horizontal] = std::min(m_maximumSize[horizontal], m_childList[i]->getMaximumSize(horizontal)); |
| } |
| } |
| |
| if (m_minimumSize[horizontal] > m_maximumSize[horizontal] || |
| m_minimumSize[vertical] > m_maximumSize[vertical]) |
| return false; |
| |
| |
| Region *r = m_parent; |
| while (r) { |
| r->calculateMinimumSize(horizontal, false); |
| r->calculateMinimumSize(vertical, false); |
| r->calculateMaximumSize(horizontal, false); |
| r->calculateMaximumSize(vertical, false); |
| |
| if (r->getMinimumSize(horizontal) > r->getMaximumSize(horizontal) || |
| r->getMinimumSize(vertical) > r->getMaximumSize(vertical)) |
| return false; |
| |
| r = r->m_parent; |
| } |
| |
| return true; |
| } |
| |
| |
| |
| |
| inline bool DockLayout::isPossibleInsertion(DockWidget *item, Region *parentRegion, int insertionIdx) |
| { |
| const int inf = 1000000; |
| |
| int mainWindowWidth = contentsRect().width(); |
| int mainWindowHeight = contentsRect().height(); |
| std::deque<Region *>::iterator i; |
| bool result = true; |
| |
| if (m_regions.size()) { |
| |
| m_regions.front()->calculateExtremalSizes(); |
| |
| if (parentRegion) |
| { |
| |
| result &= parentRegion->addItemSize(item); |
| } else |
| { |
| |
| bool frontOrientation = m_regions.front()->getOrientation(); |
| m_regions.front()->setOrientation(!frontOrientation); |
| result &= m_regions.front()->addItemSize(item); |
| m_regions.front()->setOrientation(frontOrientation); |
| } |
| } |
| |
| QSize rootMinSize; |
| QSize rootMaxSize; |
| if (m_regions.size()) { |
| rootMinSize = |
| QSize(m_regions[0]->getMinimumSize(Region::horizontal), m_regions[0]->getMinimumSize(Region::vertical)); |
| rootMaxSize = |
| QSize(m_regions[0]->getMaximumSize(Region::horizontal), m_regions[0]->getMaximumSize(Region::vertical)); |
| } else { |
| |
| rootMinSize = item->minimumSize(); |
| rootMaxSize = item->maximumSize(); |
| } |
| |
| |
| if (rootMinSize.width() > mainWindowWidth || |
| rootMinSize.height() > mainWindowHeight || |
| rootMaxSize.width() < mainWindowWidth || |
| rootMaxSize.height() < mainWindowHeight) { |
| result = false; |
| } |
| |
| return result; |
| } |
| |
| |
| |
| |
| inline bool DockLayout::isPossibleRemoval(DockWidget *item, Region *parentRegion, int removalIdx) |
| { |
| |
| if (!parentRegion) |
| return true; |
| |
| const int inf = 1000000; |
| |
| int mainWindowWidth = contentsRect().width(); |
| int mainWindowHeight = contentsRect().height(); |
| std::deque<Region *>::iterator i; |
| bool result = true; |
| |
| |
| m_regions.front()->calculateExtremalSizes(); |
| |
| |
| result &= parentRegion->subItemSize(item); |
| |
| QSize rootMinSize; |
| QSize rootMaxSize; |
| |
| rootMinSize = |
| QSize(m_regions[0]->getMinimumSize(Region::horizontal), m_regions[0]->getMinimumSize(Region::vertical)); |
| rootMaxSize = |
| QSize(m_regions[0]->getMaximumSize(Region::horizontal), m_regions[0]->getMaximumSize(Region::vertical)); |
| |
| |
| if (rootMinSize.width() > mainWindowWidth || |
| rootMinSize.height() > mainWindowHeight || |
| rootMaxSize.width() < mainWindowWidth || |
| rootMaxSize.height() < mainWindowHeight) { |
| result = false; |
| } |
| |
| return result; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| DockLayout::State DockLayout::saveState() |
| { |
| QString hierarchy; |
| |
| |
| unsigned int i; |
| for (i = 0; i < m_regions.size(); ++i) |
| m_regions[i]->m_saveIndex = i; |
| |
| DockWidget *item; |
| for (i = 0; i < m_items.size(); ++i) { |
| item = static_cast<DockWidget *>(m_items[i]->widget()); |
| item->m_saveIndex = i; |
| } |
| |
| |
| std::vector<QRect> geometries; |
| for (i = 0; i < m_items.size(); ++i) |
| geometries.push_back(m_items[i]->geometry()); |
| |
| QTextStream stream(&hierarchy, QIODevice::WriteOnly); |
| |
| |
| stream << QString::number(m_maximizedDock ? m_maximizedDock->m_saveIndex : -1) << " "; |
| if (m_maximizedDock) { |
| Region *r = find(m_maximizedDock); |
| geometries[m_maximizedDock->m_saveIndex] = toRect(r->getGeometry()); |
| } |
| |
| |
| Region *r = rootRegion(); |
| if (r) { |
| stream << QString::number(r->getOrientation()) << " "; |
| writeRegion(r, hierarchy); |
| } |
| |
| return std::pair<std::vector<QRect>, QString>(geometries, hierarchy); |
| } |
| |
| |
| |
| void DockLayout::writeRegion(Region *r, QString &hierarchy) |
| { |
| DockWidget *item = static_cast<DockWidget *>(r->getItem()); |
| |
| |
| if (item) { |
| hierarchy.append(QString::number(item->m_saveIndex) + " "); |
| } else { |
| hierarchy.append("[ "); |
| |
| |
| unsigned int i, size = r->getChildList().size(); |
| for (i = 0; i < size; ++i) { |
| writeRegion(r->childRegion(i), hierarchy); |
| } |
| |
| hierarchy.append("] "); |
| } |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| bool DockLayout::restoreState(const State &state) |
| { |
| QStringList vars = state.second.split(" ", QString::SkipEmptyParts); |
| if (vars.size() < 1) |
| return 0; |
| |
| |
| unsigned int count = state.first.size(); |
| |
| if (m_items.size() != count) |
| return false; |
| |
| |
| std::deque<Region *> newHierarchy; |
| |
| |
| int maximizedItem = vars[0].toInt(); |
| |
| if (vars.size() > 1) { |
| |
| Region *r = 0, *newRegion; |
| int orientation = !vars[1].toInt(); |
| |
| int i; |
| for (i = 2; i < vars.size(); ++i) { |
| if (vars[i] == "]") { |
| |
| r = r->getParent(); |
| } else { |
| |
| newRegion = new Region(this); |
| newHierarchy.push_back(newRegion); |
| newRegion->m_orientation = !orientation; |
| |
| if (r) |
| r->insertSubRegion(newRegion, r->getChildList().size()); |
| |
| if (vars[i] == "[") { |
| |
| r = newRegion; |
| } else { |
| |
| newRegion->m_item = static_cast<DockWidget *>(m_items[vars[i].toInt()]->widget()); |
| } |
| } |
| } |
| |
| |
| newHierarchy[0]->calculateExtremalSizes(); |
| } |
| |
| unsigned int j; |
| for (j = 0; j < newHierarchy.size(); ++j) { |
| |
| Region *r = newHierarchy[j]; |
| if (r->getMinimumSize(Region::horizontal) > r->getMaximumSize(Region::horizontal) || |
| r->getMinimumSize(Region::vertical) > r->getMaximumSize(Region::vertical)) { |
| |
| for (j = 0; j < newHierarchy.size(); ++j) |
| delete newHierarchy[j]; |
| return false; |
| } |
| } |
| |
| |
| for (j = 0; j < m_regions.size(); ++j) |
| delete m_regions[j]; |
| m_regions = newHierarchy; |
| |
| |
| const std::vector<QRect> &geoms = state.first; |
| DockWidget *item; |
| for (j = 0; j < m_items.size(); ++j) { |
| item = static_cast<DockWidget *>(m_items[j]->widget()); |
| item->setGeometry(geoms[j]); |
| item->m_maximized = false; |
| item->m_saveIndex = j; |
| } |
| |
| |
| for (j = 0; j < m_regions.size(); ++j) |
| if (item = m_regions[j]->m_item) { |
| item->setWindowFlags(Qt::SubWindow); |
| item->setDockedAppearance(); |
| item->m_floating = false; |
| item->m_saveIndex = -1; |
| item->show(); |
| } |
| |
| |
| |
| int recoverX = 0, recoverY = 0; |
| |
| |
| for (j = 0; j < m_items.size(); ++j) { |
| item = static_cast<DockWidget *>(m_items[j]->widget()); |
| |
| if (item->m_saveIndex > 0) { |
| |
| |
| if ((geoms[j] & QApplication::desktop()->availableGeometry(item)).isEmpty()) |
| item->move(recoverX += 50, recoverY += 50); |
| |
| |
| item->setWindowFlags(Qt::Tool | Qt::FramelessWindowHint); |
| item->setFloatingAppearance(); |
| item->m_floating = true; |
| } |
| } |
| |
| |
| unsigned int k; |
| for (j = 0; j < m_regions.size(); ++j) { |
| Region *r = m_regions[j]; |
| for (k = 1; k < r->m_childList.size(); ++k) { |
| r->insertSeparator(m_decoAllocator->newSeparator(this, r->getOrientation(), r)); |
| } |
| } |
| |
| |
| if (m_regions.size()) |
| m_regions[0]->restoreGeometry(); |
| |
| |
| |
| |
| |
| |
| |
| |
| applyGeometry(); |
| |
| |
| if (maximizedItem != -1) { |
| item = static_cast<DockWidget *>(m_items[maximizedItem]->widget()); |
| |
| |
| |
| |
| |
| |
| m_maximizedDock = item; |
| item->m_maximized = true; |
| item->raise(); |
| |
| |
| QWidget *currWidget; |
| for (int i = 0; i < this->count(); ++i) |
| if ((currWidget = itemAt(i)->widget()) != item) |
| currWidget->hide(); |
| } |
| |
| return true; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| void Region::restoreGeometry() |
| { |
| |
| |
| if (m_item) { |
| |
| setGeometry(m_item->geometry()); |
| return; |
| } |
| |
| |
| unsigned int i; |
| for (i = 0; i < m_childList.size(); ++i) |
| m_childList[i]->restoreGeometry(); |
| |
| |
| unsigned int last = m_childList.size() - 1; |
| QPoint topLeft(m_childList[0]->getGeometry().left(), m_childList[0]->getGeometry().top()); |
| QPoint bottomRight(m_childList[last]->getGeometry().right(), m_childList[last]->getGeometry().bottom()); |
| setGeometry(QRect(topLeft, bottomRight)); |
| |
| return; |
| } |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| inline DockSeparator *DockDecoAllocator::newSeparator(DockLayout *owner, bool orientation, Region *parentRegion) |
| { |
| return new DockSeparator(owner, orientation, parentRegion); |
| } |
| |
| |
| |
| |
| inline DockPlaceholder *DockDecoAllocator::newPlaceholder(DockWidget *owner, Region *r, int idx, int attributes) |
| { |
| return new DockPlaceholder(owner, r, idx, attributes); |
| } |
| |
| |
| |
| |
| |
| inline DockPlaceholder *DockDecoAllocator::newPlaceBuilt(DockWidget *owner, Region *r, int idx, int attributes) |
| { |
| DockPlaceholder *res = newPlaceholder(owner, r, idx, attributes); |
| res->buildGeometry(); |
| return res; |
| } |
| |
| |
| |
| |
| |
| |
| |
| void DockLayout::setDecoAllocator(DockDecoAllocator *decoAllocator) |
| { |
| |
| if (m_decoAllocator) |
| delete m_decoAllocator; |
| |
| |
| m_decoAllocator = decoAllocator; |
| } |
| |
| |
| |
| |
| |
| |
| |
| void DockWidget::setDecoAllocator(DockDecoAllocator *decoAllocator) |
| { |
| |
| if (m_decoAllocator) |
| delete m_decoAllocator; |
| |
| |
| m_decoAllocator = decoAllocator; |
| } |
| |