| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324 |
- /******************************************************************************
- Copyright (C) 2025 by Taylor Giampaolo <[email protected]>
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 2 of the License, or
- (at your option) any later version.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- You should have received a copy of the GNU General Public License
- along with this program. If not, see <http://www.gnu.org/licenses/>.
- ******************************************************************************/
- #include "AlignmentSelector.hpp"
- #include <util/base.h>
- #include <QAccessible>
- #include <QMouseEvent>
- #include <QPainter>
- #include <QStyleOptionButton>
- AlignmentSelector::AlignmentSelector(QWidget *parent) : QWidget(parent)
- {
- setFocusPolicy(Qt::StrongFocus);
- setMouseTracking(true);
- setAttribute(Qt::WA_Hover);
- }
- QSize AlignmentSelector::sizeHint() const
- {
- int base = fontMetrics().height() * 2;
- return QSize(base, base);
- }
- QSize AlignmentSelector::minimumSizeHint() const
- {
- return QSize(16, 16);
- }
- Qt::Alignment AlignmentSelector::value() const
- {
- return cellAlignment(selectedCell);
- }
- int AlignmentSelector::currentIndex() const
- {
- return selectedCell;
- }
- void AlignmentSelector::setAlignment(Qt::Alignment value)
- {
- alignment = value;
- }
- void AlignmentSelector::setCurrentIndex(int index)
- {
- selectCell(index);
- }
- void AlignmentSelector::paintEvent(QPaintEvent *)
- {
- QPainter painter(this);
- QStyle *style = this->style();
- int cellW = gridRect().width() / 3;
- int cellH = gridRect().height() / 3;
- for (int i = 0; i < 9; ++i) {
- QRect rect = cellRect(i);
- rect = rect.adjusted(0, 0, -1, -1);
- QStyleOptionFrame frameOpt;
- frameOpt.rect = rect;
- frameOpt.state = isEnabled() ? QStyle::State_Enabled : QStyle::State_None;
- frameOpt.lineWidth = 1;
- frameOpt.midLineWidth = 0;
- if (i == hoveredCell) {
- frameOpt.state |= QStyle::State_MouseOver;
- }
- if (i == selectedCell) {
- frameOpt.state |= QStyle::State_On;
- }
- if (i == focusedCell && hasFocus()) {
- frameOpt.state |= QStyle::State_HasFocus;
- }
- QStyleOptionButton radioOpt;
- radioOpt.state = isEnabled() ? QStyle::State_Enabled : QStyle::State_None;
- radioOpt.rect = rect.adjusted(cellW / 6, cellH / 6, -cellW / 6, -cellH / 6);
- if (i == hoveredCell) {
- radioOpt.state |= QStyle::State_MouseOver;
- }
- if (i == selectedCell) {
- radioOpt.state |= QStyle::State_On;
- }
- if (i == focusedCell && hasFocus()) {
- radioOpt.state |= QStyle::State_HasFocus;
- }
- style->drawPrimitive(QStyle::PE_IndicatorRadioButton, &radioOpt, &painter, this);
- style->drawPrimitive(QStyle::PE_Frame, &frameOpt, &painter, this);
- if (i == focusedCell && hasFocus()) {
- QStyleOptionFocusRect focusOpt;
- focusOpt.initFrom(this);
- focusOpt.rect = rect.adjusted(1, 1, -1, -1);
- focusOpt.state = isEnabled() ? QStyle::State_Enabled : QStyle::State_None;
- focusOpt.state |= QStyle::State_HasFocus;
- style->drawPrimitive(QStyle::PE_FrameFocusRect, &focusOpt, &painter, this);
- }
- }
- }
- QRect AlignmentSelector::cellRect(int index) const
- {
- int col = index % 3;
- int row = index / 3;
- QRect gridRect = this->gridRect();
- int cellW = gridRect.width() / 3;
- int cellH = gridRect.height() / 3;
- return QRect(col * cellW + gridRect.left(), row * cellH + gridRect.top(), cellW, cellH);
- }
- Qt::Alignment AlignmentSelector::cellAlignment(int index) const
- {
- Qt::Alignment hAlign;
- Qt::Alignment vAlign;
- switch (index % 3) {
- case 0:
- hAlign = Qt::AlignLeft;
- break;
- case 1:
- hAlign = Qt::AlignHCenter;
- break;
- case 2:
- hAlign = Qt::AlignRight;
- break;
- }
- switch (index / 3) {
- case 0:
- vAlign = Qt::AlignTop;
- break;
- case 1:
- vAlign = Qt::AlignVCenter;
- break;
- case 2:
- vAlign = Qt::AlignBottom;
- break;
- }
- return hAlign | vAlign;
- }
- void AlignmentSelector::leaveEvent(QEvent *)
- {
- hoveredCell = -1;
- update();
- }
- void AlignmentSelector::mouseMoveEvent(QMouseEvent *event)
- {
- QRect grid = gridRect();
- int cellW = grid.width() / 3;
- int cellH = grid.height() / 3;
- QPoint pos = event->position().toPoint();
- if (!grid.contains(pos)) {
- hoveredCell = -1;
- return;
- }
- int col = (pos.x() - grid.left()) / cellW;
- int row = (pos.y() - grid.top()) / cellH;
- int cell = row * 3 + col;
- if (hoveredCell != cell) {
- hoveredCell = cell;
- update();
- }
- }
- void AlignmentSelector::mousePressEvent(QMouseEvent *event)
- {
- QRect grid = gridRect();
- int cellW = grid.width() / 3;
- int cellH = grid.height() / 3;
- QPoint pos = event->position().toPoint();
- if (!grid.contains(pos)) {
- return;
- }
- int col = (pos.x() - grid.left()) / cellW;
- int row = (pos.y() - grid.top()) / cellH;
- int cell = row * 3 + col;
- selectCell(cell);
- }
- void AlignmentSelector::keyPressEvent(QKeyEvent *event)
- {
- int moveX = 0;
- int moveY = 0;
- switch (event->key()) {
- case Qt::Key_Left:
- moveX = -1;
- break;
- case Qt::Key_Right:
- moveX = 1;
- break;
- case Qt::Key_Up:
- moveY = -1;
- break;
- case Qt::Key_Down:
- moveY = 1;
- break;
- case Qt::Key_Space:
- case Qt::Key_Return:
- case Qt::Key_Enter:
- selectCell(focusedCell);
- return;
- default:
- QWidget::keyPressEvent(event);
- return;
- }
- moveFocusedCell(moveX, moveY);
- }
- QRect AlignmentSelector::gridRect() const
- {
- int side = std::min(width(), height());
- int x = 0;
- int y = 0;
- if (alignment & Qt::AlignHCenter) {
- x = (width() - side) / 2;
- } else if (alignment & Qt::AlignRight) {
- x = width() - side;
- }
- if (alignment & Qt::AlignVCenter) {
- y = (height() - side) / 2;
- } else if (alignment & Qt::AlignBottom) {
- y = height() - side;
- }
- return QRect(x, y, side, side);
- }
- void AlignmentSelector::moveFocusedCell(int moveX, int moveY)
- {
- int row = focusedCell / 3;
- int col = focusedCell % 3;
- row = std::clamp(row + moveY, 0, 2);
- col = std::clamp(col + moveX, 0, 2);
- int newCell = row * 3 + col;
- setFocusedCell(newCell);
- }
- void AlignmentSelector::setFocusedCell(int cell)
- {
- if (cell != focusedCell) {
- focusedCell = cell;
- update();
- if (AccessibleAlignmentSelector *interface =
- dynamic_cast<AccessibleAlignmentSelector *>(QAccessible::queryAccessibleInterface(this))) {
- if (QAccessibleInterface *child = interface->child(cell)) {
- QAccessibleEvent event(child, QAccessible::Focus);
- QAccessible::updateAccessibility(&event);
- }
- }
- }
- }
- void AlignmentSelector::selectCell(int cell)
- {
- setFocusedCell(cell);
- if (cell != selectedCell) {
- selectedCell = cell;
- emit valueChanged(cellAlignment(cell));
- emit currentIndexChanged(cell);
- }
- update();
- if (AccessibleAlignmentSelector *interface =
- dynamic_cast<AccessibleAlignmentSelector *>(QAccessible::queryAccessibleInterface(this))) {
- if (QAccessibleInterface *child = interface->child(cell)) {
- QAccessible::State state;
- state.checked = true;
- QAccessibleStateChangeEvent event(child, state);
- QAccessible::updateAccessibility(&event);
- }
- }
- }
- void AlignmentSelector::focusInEvent(QFocusEvent *)
- {
- setFocusedCell(selectedCell);
- update();
- }
- void AlignmentSelector::focusOutEvent(QFocusEvent *)
- {
- hoveredCell = -1;
- setFocusedCell(-1);
- update();
- }
|