RecordControlApplication/FocusWindow.cpp

321 lines
8.2 KiB
C++
Raw Normal View History

2024-08-12 11:26:42 +08:00
#include <qapplication.h>
#include "FocusWindow.h"
using namespace FW;
/**
* @brief <EFBFBD>ж<EFBFBD>ij<EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD><EFBFBD>Ƿ<EFBFBD>Ϊij<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵĺ<EFBFBD>ѡ<EFBFBD>ؼ<EFBFBD>
* @param focused <EFBFBD><EFBFBD>ǰ<EFBFBD>۽<EFBFBD><EFBFBD>Ŀؼ<EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>
* @param focusable <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӵ<EFBFBD>н<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ŀؼ<EFBFBD>ȫ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>
* @param direction <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return
*/
bool FocusWindow::isCandidate(QRect focused, QRect focusable, Direction direction)
{
switch (direction)
{
case Up:
return (focused.bottom() > focusable.bottom() || focused.top() >= focusable.bottom())
&& focused.top() > focusable.top();
case Down:
return (focused.top() < focusable.top() || focused.bottom() <= focusable.top())
&& focused.bottom() < focusable.bottom();
case Left:
return (focused.right() > focused.right() || focused.left() >= focusable.right())
&& focused.left() > focusable.left();
case Right:
return (focused.left() < focusable.left() || focused.right() <= focusable.left())
&& focused.right() < focusable.right();
default:
return false;
}
}
/**
* @brief <EFBFBD>ж<EFBFBD>rect1<EFBFBD><EFBFBD>rect2<EFBFBD><EFBFBD>direction<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD>ص<EFBFBD>
* @param direction <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param rect1 <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param rect2 <EFBFBD>ڶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return
*/
bool FocusWindow::beamsOverlap(Direction direction, QRect rect1, QRect rect2)
{
switch (direction)
{
case Left:
case Right:
return (rect2.bottom() >= rect1.top()) && (rect2.top() <= rect1.bottom());
case Up:
case Down:
return (rect2.right() >= rect1.left()) && (rect2.left() <= rect1.right());
}
}
/**
* @brief <EFBFBD>ж<EFBFBD>dest<EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD>source<EFBFBD><EFBFBD>direction<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param direction
* @param source
* @param dest
* @return
*/
bool FocusWindow::isToDirectionOf(Direction direction, QRect source, QRect dest)
{
switch (direction)
{
case Up:
return source.top() >= dest.bottom();
case Down:
return source.bottom() <= dest.top();
case Left:
return source.left() >= dest.right();
case Right:
return source.right() <= dest.left();
}
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵľ<EFBFBD><EFBFBD><EFBFBD>
* @param direction
* @param source
* @param dest
* @return
*/
int FocusWindow::majorAxisDistance(Direction direction, QRect source, QRect dest)
{
return qMax(0, majorAxisDistanceRaw(direction, source, dest));
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD>
* @param direction
* @param source
* @param dest
* @return
*/
int FocusWindow::majorAxisDistanceRaw(Direction direction, QRect source, QRect dest)
{
switch (direction)
{
case Up:
return source.top() - dest.bottom();
case Down:
return dest.top() - source.bottom();
case Left:
return source.left() - dest.right();
case Right:
return dest.left() - source.right();
default:
return 0;
}
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param dircetion
* @param source
* @param dest
* @return
*/
int FocusWindow::majorAxisDistanceToFarEdge(Direction dircetion, QRect source, QRect dest)
{
return qMax(1, majorAxisDistanceToFarEdgeRaw(dircetion, source, dest));
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ե<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param dircetion
* @param source
* @param dest
* @return
*/
int FocusWindow::majorAxisDistanceToFarEdgeRaw(Direction dircetion, QRect source, QRect dest)
{
switch (dircetion)
{
case Up:
return source.top() - dest.top();
case Down:
return dest.bottom() - source.bottom();
case Left:
return source.left() - dest.left();
case Right:
return dest.right() - source.right();
default:
return 0;
}
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵľ<EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD>ĵ<EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD>)
* @param direction
* @param source
* @param dest
* @return
*/
int FocusWindow::minorAxisDistance(Direction direction, QRect source, QRect dest)
{
switch (direction)
{
case Up:
case Down:
return qAbs((source.left() + source.width() / 2) - (dest.left() + dest.width() / 2));
case Left:
case Right:
return qAbs((source.top() + source.height() / 2) - (dest.top() + dest.height() / 2));
default:
return 0;
}
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ۺϾ<EFBFBD><EFBFBD><EFBFBD>, <EFBFBD><EFBFBD><EFBFBD>ʽ 13 * major^2 + minor ^ 2(13ΪȨ<EFBFBD><EFBFBD>)
* @param direction
* @param majorAxisDistance <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD>
* @param minorAxisDistance <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ľ<EFBFBD><EFBFBD><EFBFBD>
* @return
*/
int FocusWindow::getWeightDistanceFor(int majorAxisDistance, int minorAxisDistance)
{
return 13 * majorAxisDistance * majorAxisDistance + minorAxisDistance * minorAxisDistance;
}
/**
* @brief <EFBFBD>ж<EFBFBD>rect1<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>rect2<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>source<EFBFBD><EFBFBD>dircetion<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param dircetion <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param source <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param rect1 <EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param rect2 <EFBFBD>ڶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @return
*/
bool FocusWindow::beamBeats(Direction direction, QRect source, QRect rect1, QRect rect2)
{
bool rect1InSrcBeam = beamsOverlap(direction, source, rect1);
bool rect2InSrcBeam = beamsOverlap(direction, source, rect2);
// rect2<74><32><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD><D8B5><EFBFBD>rect1<74><31><EFBFBD>ص<EFBFBD>
if (rect2InSrcBeam || !rect1InSrcBeam)
{
return false;
}
// rect1<74><31><EFBFBD>ص<EFBFBD><D8B5><EFBFBD>rect2<74><32><EFBFBD>ص<EFBFBD>
// <20><>
// rect2<74>Ƿ<EFBFBD><C7B7><EFBFBD>direction<6F><6E><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (!isToDirectionOf(direction, source, rect2))
{
return true;
}
// ˮƽ<CBAE><C6BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (direction == Left || direction == Right)
{
return true;
}
return (majorAxisDistance(direction, source, rect1)
< majorAxisDistanceToFarEdge(direction, source, rect2));
}
/**
* @brief <EFBFBD>ж<EFBFBD><EFBFBD>Ƿ<EFBFBD><EFBFBD>Ǹ<EFBFBD><EFBFBD>õĺ<EFBFBD>ѡ<EFBFBD><EFBFBD>
* @param direction <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
* @param focused <EFBFBD><EFBFBD>ǰ<EFBFBD>۽<EFBFBD><EFBFBD>Ŀؼ<EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>
* @param focusable <EFBFBD><EFBFBD>ǰ<EFBFBD>۽<EFBFBD><EFBFBD>Ŀؼ<EFBFBD><EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>
* @param curCandidate <EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD>Ѻ<EFBFBD>ѡ<EFBFBD><EFBFBD>ȫ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD>
* @return
*/
bool FocusWindow::isBetterCandidate(Direction direction, QRect focused, QRect focusable, QRect curCandidate)
{
// <20><>ǰ<EFBFBD>Ŀؼ<C4BF><D8BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>direction<6F><6E><EFBFBD><EFBFBD>)
if (!isCandidate(focused, focusable, direction))
{
return false;
}
// <20><>ѡ<EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
if (!isCandidate(focused, curCandidate, direction))
return true;
// <20><>ǰ<EFBFBD>Ŀؼ<C4BF><D8BC><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD>ĺ<EFBFBD>ѡ<EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD>жԱ<D0B6>
if (beamBeats(direction, focused, focusable, curCandidate))
{
return true;
}
// <20><><EFBFBD><EFBFBD>ǰ<EFBFBD><C7B0>ѡ<EFBFBD>ؼ<EFBFBD><D8BC>뵱ǰ<EBB5B1>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD>жԱ<D0B6>
if (beamBeats(direction, focused, curCandidate, focusable))
{
return false;
}
// <20><><EFBFBD>㵱ǰ<E3B5B1>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD>۽<EFBFBD><DBBD>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD>ۺϾ<DBBA><CFBE><EFBFBD><EFBFBD>Ƿ<EFBFBD>С<EFBFBD>ں<EFBFBD>ѡ<EFBFBD>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD>۽<EFBFBD><DBBD>ؼ<EFBFBD><D8BC><EFBFBD><EFBFBD>ۺϾ<DBBA><CFBE><EFBFBD>
return (getWeightDistanceFor(majorAxisDistance(direction, focused, focusable),
minorAxisDistance(direction, focused, focusable))
< getWeightDistanceFor(majorAxisDistance(direction, focused, curCandidate),
minorAxisDistance(direction, focused, curCandidate)));
}
/**
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD>
* @param direction
* @return
*/
QWidget* FocusWindow::getNextFocusWidget(Direction direction)
{
focusableList = getAllFocusabelWidget();
QWidget* nextFocus = nullptr;
// <20><>ѡ<EFBFBD>б<EFBFBD>
QList<QWidget*> candidates;
QWidget* focusedWidget = QApplication::focusWidget();
if (!focusedWidget)
return nextFocus;
// <20><><EFBFBD>㵱ǰ<E3B5B1>۽<EFBFBD><DBBD>ؼ<EFBFBD><D8BC><EFBFBD>ȫ<EFBFBD><C8AB>λ<EFBFBD><CEBB>
QRect focusedRect = QRect(focusedWidget->mapToGlobal(QPoint(0, 0)), focusedWidget->size());
// <20>һ<E9B9B9><D2BB><EFBFBD><EFBFBD>ѡ<EFBFBD><D1A1><EFBFBD><EFBFBD>ԭ<EFBFBD><D4AD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><E0B7B4><EFBFBD><EFBFBD><EFBFBD>ƶ<EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD>
QRect betterCandidateRect = focusedRect;
switch (direction)
{
case Up:
betterCandidateRect = QRect(QPoint(focusedRect.x(), focusedRect.y() + 1), focusedRect.size());
break;
case Down:
betterCandidateRect = QRect(QPoint(focusedRect.x(), focusedRect.y() - 1), focusedRect.size());
break;
case Left:
betterCandidateRect = QRect(QPoint(focusedRect.x() + 1, focusedRect.y()), focusedRect.size());
break;
case Right:
betterCandidateRect = QRect(QPoint(focusedRect.x() - 1, focusedRect.y()), focusedRect.size());
break;
default:
break;
}
// ѭ<><D1AD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȽϿؼ<CFBF>λ<EFBFBD>ã<EFBFBD><C3A3>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD>к<EFBFBD>ѡ<EFBFBD>ؼ<EFBFBD>
for (int i = 0; i < focusableList.length(); i++)
{
QWidget* focusable = focusableList.at(i);
// <20><><EFBFBD><EFBFBD><EFBFBD>ɾ۽<C9BE><DBBD>ؼ<EFBFBD><D8BC>ǵ<EFBFBD>ǰ<EFBFBD><C7B0><EFBFBD>ý<EFBFBD><C3BD><EFBFBD><EFBFBD>Ŀؼ<C4BF><D8BC><EFBFBD><EFBFBD><EFBFBD>ת<EFBFBD>Ƚ<EFBFBD>
if (focusable == focusedWidget)
continue;
// <20><><EFBFBD>ɾ۽<C9BE><DBBD>ؼ<EFBFBD><D8BC><EFBFBD>λ<EFBFBD><CEBB>ת<EFBFBD><D7AA>Ϊȫ<CEAA>ֵ<EFBFBD>λ<EFBFBD><CEBB>
QRect focusableRect = QRect(focusable->mapToGlobal(QPoint(0, 0)), focusable->size());
// <20><><EFBFBD><EFBFBD><EFBFBD>Ƿ<EFBFBD>Ϊ<EFBFBD><CEAA><EFBFBD>ź<EFBFBD>ѡ
if (isBetterCandidate(direction, focusedRect, focusableRect, betterCandidateRect))
{
betterCandidateRect = focusableRect;
nextFocus = focusable;
}
}
return nextFocus;
}
/**
* @brief <EFBFBD>۽<EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD>
* @param direction
*/
void FocusWindow::focusNext(Direction direction)
{
QWidget* nextFocus = getNextFocusWidget(direction);
if (nextFocus)
{
nextFocus->setFocus();
}
}