void WindowArea::_MoveToSAT(SATWindow* triggerWindow) { SATWindow* topWindow = TopWindow(); // if there is no window in the group we are done if (topWindow == NULL) return; BRect frameSAT(LeftVar()->Value() - kMakePositiveOffset, TopVar()->Value() - kMakePositiveOffset, RightVar()->Value() - kMakePositiveOffset, BottomVar()->Value() - kMakePositiveOffset); topWindow->AdjustSizeLimits(frameSAT); BRect frame = topWindow->CompleteWindowFrame(); float deltaToX = round(frameSAT.left - frame.left); float deltaToY = round(frameSAT.top - frame.top); frame.OffsetBy(deltaToX, deltaToY); float deltaByX = round(frameSAT.right - frame.right); float deltaByY = round(frameSAT.bottom - frame.bottom); int32 workspace = triggerWindow->GetWindow()->CurrentWorkspace(); Desktop* desktop = triggerWindow->GetWindow()->Desktop(); desktop->MoveWindowBy(topWindow->GetWindow(), deltaToX, deltaToY, workspace); // Update frame to the new position desktop->ResizeWindowBy(topWindow->GetWindow(), deltaByX, deltaByY); UpdateSizeConstaints(frameSAT); }
void WindowArea::DoGroupLayout() { SATWindow* parentWindow = fWindowLayerOrder.ItemAt(0); if (parentWindow == NULL) return; BRect frame = parentWindow->CompleteWindowFrame(); // Make it also work for solver which don't support negative variables frame.OffsetBy(kMakePositiveOffset, kMakePositiveOffset); // adjust window size soft constraints fWidthConstraint->SetRightSide(frame.Width()); fHeightConstraint->SetRightSide(frame.Height()); LinearSpec* linearSpec = fGroup->GetLinearSpec(); Constraint* leftConstraint = linearSpec->AddConstraint(1.0, LeftVar(), kEQ, frame.left); Constraint* topConstraint = linearSpec->AddConstraint(1.0, TopVar(), kEQ, frame.top); // give soft constraints a high penalty fWidthConstraint->SetPenaltyNeg(kHighPenalty); fWidthConstraint->SetPenaltyPos(kHighPenalty); fHeightConstraint->SetPenaltyNeg(kHighPenalty); fHeightConstraint->SetPenaltyPos(kHighPenalty); // After we set the new parameter solve and apply the new layout. ResultType result; for (int32 tries = 0; tries < 15; tries++) { result = fGroup->GetLinearSpec()->Solve(); if (result == kInfeasible) { debug_printf("can't solve constraints!\n"); break; } if (result == kOptimal) { const WindowAreaList& areas = fGroup->GetAreaList(); for (int32 i = 0; i < areas.CountItems(); i++) { WindowArea* area = areas.ItemAt(i); area->_MoveToSAT(parentWindow); } break; } } // set penalties back to normal fWidthConstraint->SetPenaltyNeg(kExtentPenalty); fWidthConstraint->SetPenaltyPos(kExtentPenalty); fHeightConstraint->SetPenaltyNeg(kExtentPenalty); fHeightConstraint->SetPenaltyPos(kExtentPenalty); linearSpec->RemoveConstraint(leftConstraint); linearSpec->RemoveConstraint(topConstraint); }
void WindowArea::_UpdateConstraintValues() { SATWindow* topWindow = TopWindow(); if (topWindow == NULL) return; int32 minWidth, maxWidth; int32 minHeight, maxHeight; SATWindow* window = fWindowList.ItemAt(0); window->GetSizeLimits(&minWidth, &maxWidth, &minHeight, &maxHeight); for (int32 i = 1; i < fWindowList.CountItems(); i++) { window = fWindowList.ItemAt(i); // size limit constraints int32 minW, maxW; int32 minH, maxH; window->GetSizeLimits(&minW, &maxW, &minH, &maxH); if (minWidth < minW) minWidth = minW; if (minHeight < minH) minHeight = minH; if (maxWidth < maxW) maxWidth = maxW; if (maxHeight < maxH) maxHeight = maxH; } // the current solver don't like big values const int32 kMaxSolverValue = 5000; if (minWidth > kMaxSolverValue) minWidth = kMaxSolverValue; if (minHeight > kMaxSolverValue) minHeight = kMaxSolverValue; if (maxWidth > kMaxSolverValue) maxWidth = kMaxSolverValue; if (maxHeight > kMaxSolverValue) maxHeight = kMaxSolverValue; topWindow->AddDecorator(&minWidth, &maxWidth, &minHeight, &maxHeight); fMinWidthConstraint->SetRightSide(minWidth); fMinHeightConstraint->SetRightSide(minHeight); fMaxWidthConstraint->SetRightSide(maxWidth); fMaxHeightConstraint->SetRightSide(maxHeight); BRect frame = topWindow->CompleteWindowFrame(); fWidthConstraint->SetRightSide(frame.Width()); fHeightConstraint->SetRightSide(frame.Height()); }
void SATGroup::_EnsureGroupIsOnScreen(SATGroup* group) { STRACE_SAT("SATGroup::_EnsureGroupIsOnScreen\n"); if (!group) return; if (group->CountItems() < 1) return; SATWindow* window = group->WindowAt(0); Desktop* desktop = window->GetWindow()->Desktop(); if (!desktop) return; const float kBigDistance = 1E+10; float minLeftDistance = kBigDistance; BRect leftRect; float minTopDistance = kBigDistance; BRect topRect; float minRightDistance = kBigDistance; BRect rightRect; float minBottomDistance = kBigDistance; BRect bottomRect; BRect screen = window->GetWindow()->Screen()->Frame(); BRect reducedScreen = screen; reducedScreen.InsetBy(kMinOverlap, kMinOverlap); for (int i = 0; i < group->CountItems(); i++) { SATWindow* window = group->WindowAt(i); BRect frame = window->CompleteWindowFrame(); if (reducedScreen.Intersects(frame)) return; if (frame.right < screen.left + kMinOverlap) { float dist = fabs(screen.left - frame.right); if (dist < minLeftDistance) { minLeftDistance = dist; leftRect = frame; } else if (dist == minLeftDistance) leftRect = leftRect | frame; } if (frame.top > screen.bottom - kMinOverlap) { float dist = fabs(frame.top - screen.bottom); if (dist < minBottomDistance) { minBottomDistance = dist; bottomRect = frame; } else if (dist == minBottomDistance) bottomRect = bottomRect | frame; } if (frame.left > screen.right - kMinOverlap) { float dist = fabs(frame.left - screen.right); if (dist < minRightDistance) { minRightDistance = dist; rightRect = frame; } else if (dist == minRightDistance) rightRect = rightRect | frame; } if (frame.bottom < screen.top + kMinOverlap) { float dist = fabs(frame.bottom - screen.top); if (dist < minTopDistance) { minTopDistance = dist; topRect = frame; } else if (dist == minTopDistance) topRect = topRect | frame; } } BPoint offset; if (minLeftDistance < kBigDistance) { offset.x = screen.left - leftRect.right + kMoveToScreen; _CallculateYOffset(offset, leftRect, screen); } else if (minTopDistance < kBigDistance) { offset.y = screen.top - topRect.bottom + kMoveToScreen; _CallculateXOffset(offset, topRect, screen); } else if (minRightDistance < kBigDistance) { offset.x = screen.right - rightRect.left - kMoveToScreen; _CallculateYOffset(offset, rightRect, screen); } else if (minBottomDistance < kBigDistance) { offset.y = screen.bottom - bottomRect.top - kMoveToScreen; _CallculateXOffset(offset, bottomRect, screen); } if (offset.x == 0. && offset.y == 0.) return; STRACE_SAT("move group back to screen: offset x: %f offset y: %f\n", offset.x, offset.y); desktop->MoveWindowBy(window->GetWindow(), offset.x, offset.y); window->DoGroupLayout(); }