321 lines
8.2 KiB
C++
321 lines
8.2 KiB
C++
|
#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();
|
|||
|
}
|
|||
|
}
|
|||
|
|