77#include < QPoint>
88#include < QScreen>
99
10+ #include < algorithm>
11+ #include < numeric>
12+
1013// ButtonHandler is a handler for every active button. It makes easier to
1114// manipulate the buttons as a unit.
1215
@@ -67,7 +70,7 @@ size_t ButtonHandler::size() const
6770// selection area. Ignores the sides blocked by the end of the screen.
6871// When the selection is too small, it works on a virtual selection with
6972// the original in the center.
70- void ButtonHandler::updatePosition (const QRect& selection)
73+ void ButtonHandler::updatePosition (const QRect& selection, const QPoint& anchor )
7174{
7275 resetRegionTrack ();
7376 const int vecLength = m_vectorButtons.size ();
@@ -80,13 +83,18 @@ void ButtonHandler::updatePosition(const QRect& selection)
8083 ensureSelectionMinimumSize ();
8184 // Indicates the actual button to be moved
8285 int elemIndicator = 0 ;
86+ // Collect the available slots before assigning buttons. This keeps the
87+ // existing screen-edge layout while allowing primary actions to follow
88+ // the pointer.
89+ QVector<QPoint> buttonPositions;
90+ buttonPositions.reserve (vecLength);
8391
8492 while (elemIndicator < vecLength) {
8593
8694 // Add them inside the area when there is no more space
8795 if (m_allSidesBlocked) {
8896 m_selection = selection;
89- positionButtonsInside (elemIndicator);
97+ positionButtonsInside (elemIndicator, buttonPositions );
9098 break ; // the while
9199 }
92100 // Number of buttons per row column
@@ -119,9 +127,10 @@ void ButtonHandler::updatePosition(const QRect& selection)
119127 adjustHorizontalCenter (center);
120128 }
121129 // ElemIndicator, elemsAtCorners
122- QVector<QPoint> positions =
130+ const QVector<QPoint> sidePositions =
123131 horizontalPoints (center, addCounter, true );
124- moveButtonsToPoints (positions, elemIndicator);
132+ appendButtonPositions (
133+ sidePositions, buttonPositions, elemIndicator);
125134 }
126135 // Add buttons to the right side of the selection
127136 if (!m_blockedRight && elemIndicator < vecLength) {
@@ -130,9 +139,10 @@ void ButtonHandler::updatePosition(const QRect& selection)
130139
131140 QPoint center = QPoint (m_selection.right () + m_separator,
132141 m_selection.center ().y ());
133- QVector<QPoint> positions =
142+ const QVector<QPoint> sidePositions =
134143 verticalPoints (center, addCounter, false );
135- moveButtonsToPoints (positions, elemIndicator);
144+ appendButtonPositions (
145+ sidePositions, buttonPositions, elemIndicator);
136146 }
137147 // Add buttons at the top of the selection
138148 if (!m_blockedTop && elemIndicator < vecLength) {
@@ -143,9 +153,10 @@ void ButtonHandler::updatePosition(const QRect& selection)
143153 if (addCounter == 1 + buttonsPerRow) {
144154 adjustHorizontalCenter (center);
145155 }
146- QVector<QPoint> positions =
156+ const QVector<QPoint> sidePositions =
147157 horizontalPoints (center, addCounter, false );
148- moveButtonsToPoints (positions, elemIndicator);
158+ appendButtonPositions (
159+ sidePositions, buttonPositions, elemIndicator);
149160 }
150161 // Add buttons to the left side of the selection
151162 if (!m_blockedLeft && elemIndicator < vecLength) {
@@ -154,9 +165,10 @@ void ButtonHandler::updatePosition(const QRect& selection)
154165
155166 QPoint center = QPoint (m_selection.left () - m_buttonExtendedSize,
156167 m_selection.center ().y ());
157- QVector<QPoint> positions =
168+ const QVector<QPoint> sidePositions =
158169 verticalPoints (center, addCounter, true );
159- moveButtonsToPoints (positions, elemIndicator);
170+ appendButtonPositions (
171+ sidePositions, buttonPositions, elemIndicator);
160172 }
161173 // If there are elements for the next cycle, increase the size of the
162174 // base area
@@ -165,6 +177,8 @@ void ButtonHandler::updatePosition(const QRect& selection)
165177 }
166178 updateBlockedSides ();
167179 }
180+
181+ assignButtonsToPositions (buttonPositions, anchor);
168182}
169183
170184int ButtonHandler::calculateShift (int elements, bool reverse) const
@@ -289,7 +303,7 @@ void ButtonHandler::expandSelection()
289303 m_selection = intersectWithAreas (m_selection);
290304}
291305
292- void ButtonHandler::positionButtonsInside (int index)
306+ void ButtonHandler::positionButtonsInside (int index, QVector<QPoint>& positions )
293307{
294308 // Position the buttons in the botton-center of the main but inside of the
295309 // selection.
@@ -305,8 +319,9 @@ void ButtonHandler::positionButtonsInside(int index)
305319 while (m_vectorButtons.size () > index) {
306320 int addCounter = buttonsPerRow;
307321 addCounter = qBound (0 , addCounter, m_vectorButtons.size () - index);
308- QVector<QPoint> positions = horizontalPoints (center, addCounter, true );
309- moveButtonsToPoints (positions, index);
322+ const QVector<QPoint> rowPositions =
323+ horizontalPoints (center, addCounter, true );
324+ appendButtonPositions (rowPositions, positions, index);
310325 center.setY (center.y () - m_buttonExtendedSize);
311326 }
312327
@@ -334,16 +349,96 @@ void ButtonHandler::ensureSelectionMinimumSize()
334349 }
335350}
336351
337- void ButtonHandler::moveButtonsToPoints (const QVector<QPoint>& points,
338- int & index)
352+ void ButtonHandler::appendButtonPositions (const QVector<QPoint>& points,
353+ QVector<QPoint>& positions,
354+ int & index)
339355{
340356 for (const QPoint& p : points) {
341- auto * button = m_vectorButtons[index];
342- button->move (p);
357+ positions.append (p);
343358 ++index;
344359 }
345360}
346361
362+ void ButtonHandler::assignButtonsToPositions (const QVector<QPoint>& positions,
363+ const QPoint& anchor)
364+ {
365+ if (positions.isEmpty ()) {
366+ return ;
367+ }
368+
369+ QVector<CaptureToolButton*> primaryButtons;
370+ QVector<CaptureToolButton*> remainingButtons;
371+ primaryButtons.reserve (m_vectorButtons.size ());
372+ remainingButtons.reserve (m_vectorButtons.size ());
373+
374+ const auto primaryRank = [](const CaptureToolButton* button) {
375+ switch (button->tool ()->type ()) {
376+ case CaptureTool::TYPE_COPY :
377+ case CaptureTool::TYPE_ACCEPT :
378+ return 0 ;
379+ case CaptureTool::TYPE_SAVE :
380+ return 1 ;
381+ case CaptureTool::TYPE_PIN :
382+ return 2 ;
383+ case CaptureTool::TYPE_PLUGIN :
384+ return 3 ;
385+ default :
386+ return -1 ;
387+ }
388+ };
389+
390+ for (CaptureToolButton* button : m_vectorButtons) {
391+ if (primaryRank (button) >= 0 ) {
392+ primaryButtons.append (button);
393+ } else {
394+ remainingButtons.append (button);
395+ }
396+ }
397+ std::stable_sort (primaryButtons.begin (),
398+ primaryButtons.end (),
399+ [&primaryRank](const CaptureToolButton* left,
400+ const CaptureToolButton* right) {
401+ return primaryRank (left) < primaryRank (right);
402+ });
403+
404+ // The first primary action gets the slot whose center is closest to the
405+ // release point, followed by the other primary actions.
406+ QVector<int > positionsByDistance (positions.size ());
407+ std::iota (positionsByDistance.begin (), positionsByDistance.end (), 0 );
408+ const QPoint buttonCenterOffset (m_buttonBaseSize / 2 , m_buttonBaseSize / 2 );
409+ const auto distanceSquared = [&](int positionIndex) {
410+ const QPoint delta =
411+ positions[positionIndex] + buttonCenterOffset - anchor;
412+ return static_cast <qint64>(delta.x ()) * delta.x () +
413+ static_cast <qint64>(delta.y ()) * delta.y ();
414+ };
415+ std::stable_sort (positionsByDistance.begin (),
416+ positionsByDistance.end (),
417+ [&distanceSquared](int left, int right) {
418+ return distanceSquared (left) < distanceSquared (right);
419+ });
420+
421+ QVector<bool > usedPositions (positions.size (), false );
422+ int primaryIndex = 0 ;
423+ for (; primaryIndex < primaryButtons.size () &&
424+ primaryIndex < positionsByDistance.size ();
425+ ++primaryIndex) {
426+ const int positionIndex = positionsByDistance[primaryIndex];
427+ primaryButtons[primaryIndex]->move (positions[positionIndex]);
428+ usedPositions[positionIndex] = true ;
429+ }
430+
431+ int remainingIndex = 0 ;
432+ for (int positionIndex = 0 ; positionIndex < positions.size () &&
433+ remainingIndex < remainingButtons.size ();
434+ ++positionIndex) {
435+ if (!usedPositions[positionIndex]) {
436+ remainingButtons[remainingIndex]->move (positions[positionIndex]);
437+ ++remainingIndex;
438+ }
439+ }
440+ }
441+
347442void ButtonHandler::adjustHorizontalCenter (QPoint& center)
348443{
349444 if (m_blockedLeft) {
@@ -373,15 +468,15 @@ bool ButtonHandler::contains(const QPoint& p) const
373468 if (m_vectorButtons.isEmpty ()) {
374469 return false ;
375470 }
376- QPoint first (m_vectorButtons. first ()-> pos ());
377- QPoint last (m_vectorButtons. last ()-> pos ()) ;
378- bool firstIsTopLeft = (first. x () <= last. x () && first. y () <= last. y () );
379- QPoint topLeft = firstIsTopLeft ? first : last;
380- QPoint bottonRight = firstIsTopLeft ? last : first;
381- topLeft += QPoint (- m_separator, - m_separator);
382- bottonRight += QPoint (m_buttonExtendedSize, m_buttonExtendedSize );
383- QRegion r ( QRect (topLeft, bottonRight). normalized ());
384- return r .contains (p);
471+
472+ QRegion buttonRegion ;
473+ const QSize hitArea (m_buttonExtendedSize, m_buttonExtendedSize );
474+ for ( const CaptureToolButton* button : m_vectorButtons) {
475+ const QPoint topLeft =
476+ button-> pos () - QPoint ( m_separator, m_separator);
477+ buttonRegion += QRect (topLeft, hitArea );
478+ }
479+ return buttonRegion .contains (p);
385480}
386481
387482void ButtonHandler::updateScreenRegions (const QVector<QRect>& rects)
0 commit comments