LCOV - code coverage report
Current view: top level - src/palette/widgets - palettewidget.cpp Coverage Total Hit
Test: filtered_coverage.info Lines: 0.0 % 773 0
Test Date: 2026-11-05 04:07:02

            Line data    Source code
       1              : /*
       2              :  * SPDX-License-Identifier: GPL-3.0-only
       3              :  * MuseScore-Studio-CLA-applies
       4              :  *
       5              :  * MuseScore Studio
       6              :  * Music Composition & Notation
       7              :  *
       8              :  * Copyright (C) 2021 MuseScore Limited and others
       9              :  *
      10              :  * This program is free software: you can redistribute it and/or modify
      11              :  * it under the terms of the GNU General Public License version 3 as
      12              :  * published by the Free Software Foundation.
      13              :  *
      14              :  * This program is distributed in the hope that it will be useful,
      15              :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      16              :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      17              :  * GNU General Public License for more details.
      18              :  *
      19              :  * You should have received a copy of the GNU General Public License
      20              :  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
      21              :  */
      22              : 
      23              : #include "palettewidget.h"
      24              : 
      25              : #include <cmath>
      26              : 
      27              : #include <QAccessible>
      28              : #include <QAccessibleEvent>
      29              : #include <QAction>
      30              : #include <QApplication>
      31              : #include <QContextMenuEvent>
      32              : #include <QDrag>
      33              : #include <QFileInfo>
      34              : #include <QMenu>
      35              : #include <QMimeData>
      36              : #include <QResizeEvent>
      37              : #include <QToolTip>
      38              : #include <QWindow>
      39              : 
      40              : #include "modularity/ioc.h"
      41              : #include "translation.h"
      42              : #include "types/bytearray.h"
      43              : 
      44              : #include "draw/types/color.h"
      45              : #include "draw/types/pen.h"
      46              : 
      47              : #include "engraving/rw/rwregister.h"
      48              : 
      49              : #include "engraving/dom/actionicon.h"
      50              : #include "engraving/dom/chord.h"
      51              : #include "engraving/dom/engravingitem.h"
      52              : #include "engraving/dom/fret.h"
      53              : #include "engraving/dom/image.h"
      54              : #include "engraving/dom/masterscore.h"
      55              : #include "engraving/dom/note.h"
      56              : #include "engraving/dom/symbol.h"
      57              : #include "engraving/dom/factory.h"
      58              : #include "engraving/style/defaultstyle.h"
      59              : #include "engraving/style/style.h"
      60              : 
      61              : #include "notation/inotation.h"
      62              : #include "notation/inotationinteraction.h"
      63              : 
      64              : #include "notationscene/utilities/engravingitempreviewpainter.h"
      65              : 
      66              : #include "internal/palettecelliconengine.h"
      67              : 
      68              : #include "log.h"
      69              : 
      70              : using namespace mu;
      71              : using namespace muse;
      72              : using namespace muse::io;
      73              : using namespace mu::palette;
      74              : using namespace mu::engraving;
      75              : using namespace muse::draw;
      76              : 
      77            0 : PaletteWidget::PaletteWidget(QWidget* parent, bool setIocContext)
      78            0 :     : QWidget(parent), muse::Contextable(muse::iocCtxForQWidget(this))
      79              : {
      80            0 :     if (setIocContext) {
      81            0 :         m_palette = std::make_shared<Palette>(iocContext());
      82              :     } else {
      83            0 :         m_palette = std::make_shared<Palette>(nullptr);
      84              :     }
      85              : 
      86              :     //! NOTE: need for accessibility
      87            0 :     m_palette->setParent(this);
      88              : 
      89            0 :     setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Ignored);
      90              : 
      91            0 :     setReadOnly(false);
      92            0 :     setMouseTracking(true);
      93            0 : }
      94              : 
      95            0 : void PaletteWidget::setIocContext()
      96              : {
      97            0 :     m_palette->setContext(iocContext());
      98            0 : }
      99              : 
     100            0 : void PaletteWidget::setPalette(PalettePtr palette)
     101              : {
     102            0 :     if (!palette) {
     103            0 :         return;
     104              :     }
     105              : 
     106            0 :     m_palette = palette;
     107            0 :     setObjectName("PaletteWidget_" + name());
     108              : 
     109              :     //! NOTE: need for accessibility
     110            0 :     m_palette->setParent(this);
     111              : 
     112            0 :     update();
     113              : }
     114              : 
     115            0 : QAccessibleInterface* PaletteWidget::accessibleInterface(QObject* object)
     116              : {
     117            0 :     PaletteWidget* widget = qobject_cast<PaletteWidget*>(object);
     118            0 :     IF_ASSERT_FAILED(widget) {
     119            0 :         return nullptr;
     120              :     }
     121              : 
     122            0 :     return static_cast<QAccessibleInterface*>(new AccessiblePaletteWidget(widget));
     123              : }
     124              : 
     125            0 : QString PaletteWidget::name() const
     126              : {
     127            0 :     return m_palette->name();
     128              : }
     129              : 
     130            0 : void PaletteWidget::setName(const QString& name)
     131              : {
     132            0 :     m_palette->setName(name);
     133            0 : }
     134              : 
     135              : // ====================================================
     136              : // Cells & Elements
     137              : // ====================================================
     138              : 
     139            0 : const std::vector<PaletteCellPtr>& PaletteWidget::cells() const
     140              : {
     141            0 :     return m_palette->cells();
     142              : }
     143              : 
     144            0 : const std::vector<PaletteCellPtr>& PaletteWidget::actualCellsList() const
     145              : {
     146            0 :     return m_isFilterActive ? m_filteredCells : cells();
     147              : }
     148              : 
     149            0 : int PaletteWidget::actualCellCount() const
     150              : {
     151            0 :     return static_cast<int>(m_isFilterActive ? m_filteredCells.size() : cells().size());
     152              : }
     153              : 
     154            0 : PaletteCellPtr PaletteWidget::cellAt(size_t index) const
     155              : {
     156            0 :     if (index >= actualCellsList().size()) {
     157            0 :         return nullptr;
     158              :     }
     159              : 
     160            0 :     return actualCellsList().at(index);
     161              : }
     162              : 
     163            0 : ElementPtr PaletteWidget::elementForCellAt(int idx) const
     164              : {
     165            0 :     PaletteCellPtr cell = cellAt(idx);
     166            0 :     return cell ? cell->element : nullptr;
     167            0 : }
     168              : 
     169            0 : PaletteCellPtr PaletteWidget::insertElement(int idx, ElementPtr element, const QString& name, qreal mag, const QPointF offset,
     170              :                                             const QString& tag)
     171              : {
     172            0 :     PaletteCellPtr cell = m_palette->insertElement(idx, element, name, mag, offset, tag);
     173              : 
     174            0 :     update();
     175            0 :     updateGeometry();
     176              : 
     177            0 :     return cell;
     178            0 : }
     179              : 
     180            0 : PaletteCellPtr PaletteWidget::appendElement(ElementPtr element, const QString& name, qreal mag, const QPointF offset, const QString& tag)
     181              : {
     182            0 :     PaletteCellPtr cell = m_palette->appendElement(element, name, mag, offset, tag);
     183              : 
     184            0 :     setFixedHeight(heightForWidth(width()));
     185            0 :     updateGeometry();
     186            0 :     update();
     187              : 
     188            0 :     return cell;
     189            0 : }
     190              : 
     191            0 : PaletteCellPtr PaletteWidget::appendActionIcon(mu::engraving::ActionIconType type)
     192              : {
     193            0 :     PaletteCellPtr cell = m_palette->appendActionIcon(type);
     194              : 
     195            0 :     setFixedHeight(heightForWidth(width()));
     196            0 :     updateGeometry();
     197            0 :     update();
     198              : 
     199            0 :     return cell;
     200            0 : }
     201              : 
     202            0 : void PaletteWidget::clear()
     203              : {
     204            0 :     m_palette->clear();
     205            0 : }
     206              : 
     207              : // ====================================================
     208              : // Drawing
     209              : // ====================================================
     210              : 
     211            0 : qreal PaletteWidget::mag() const
     212              : {
     213            0 :     return m_palette->mag();
     214              : }
     215              : 
     216            0 : void PaletteWidget::setMag(qreal val)
     217              : {
     218            0 :     m_palette->setMag(val);
     219            0 : }
     220              : 
     221            0 : qreal PaletteWidget::yOffset() const
     222              : {
     223            0 :     return m_palette->yOffset();
     224              : }
     225              : 
     226            0 : void PaletteWidget::setYOffset(qreal val)
     227              : {
     228            0 :     m_palette->setYOffset(val);
     229            0 : }
     230              : 
     231              : // ====================================================
     232              : // Grid
     233              : // ====================================================
     234              : 
     235            0 : bool PaletteWidget::drawGrid() const
     236              : {
     237            0 :     return m_palette->drawGrid();
     238              : }
     239              : 
     240            0 : void PaletteWidget::setDrawGrid(bool val)
     241              : {
     242            0 :     m_palette->setDrawGrid(val);
     243            0 : }
     244              : 
     245            0 : int PaletteWidget::gridWidth() const
     246              : {
     247            0 :     return m_palette->gridSize().width();
     248              : }
     249              : 
     250            0 : int PaletteWidget::gridHeight() const
     251              : {
     252            0 :     return m_palette->gridSize().height();
     253              : }
     254              : 
     255            0 : void PaletteWidget::setGridSize(int width, int height)
     256              : {
     257            0 :     m_palette->setGridSize(width, height);
     258            0 :     QSize s = QSize(width, height) * paletteScaling();
     259            0 :     setSizeIncrement(s);
     260            0 :     setBaseSize(s);
     261            0 :     setMinimumSize(s);
     262            0 :     updateGeometry();
     263            0 : }
     264              : 
     265            0 : int PaletteWidget::gridWidthScaled() const
     266              : {
     267            0 :     return gridWidth() * paletteScaling();
     268              : }
     269              : 
     270            0 : int PaletteWidget::gridHeightScaled() const
     271              : {
     272            0 :     return gridHeight() * paletteScaling();
     273              : }
     274              : 
     275            0 : qreal PaletteWidget::paletteScaling() const
     276              : {
     277            0 :     return configuration()->paletteScaling();
     278              : }
     279              : 
     280              : // ====================================================
     281              : // Filter
     282              : // ====================================================
     283              : 
     284            0 : bool PaletteWidget::isFilterActive()
     285              : {
     286            0 :     return m_isFilterActive;
     287              : }
     288              : 
     289              : /// Returns `true` if all cells are filtered.
     290            0 : bool PaletteWidget::setFilterText(const QString& text)
     291              : {
     292            0 :     m_isFilterActive = false;
     293            0 :     setMouseTracking(true);
     294            0 :     QString t = text.toLower();
     295            0 :     bool res = true;
     296            0 :     m_filteredCells.clear();
     297              :     // if palette name is searched for, display all elements in the palette
     298            0 :     if (name().startsWith(t, Qt::CaseInsensitive)) {
     299            0 :         const PaletteCellPtr& c = cells().front();
     300            0 :         for (const PaletteCellPtr& cell : cells()) {
     301            0 :             m_filteredCells.push_back(cell);
     302              :         }
     303              : 
     304            0 :         const bool contains = t.isEmpty() || c;
     305            0 :         if (!contains) {
     306            0 :             m_isFilterActive = true;
     307              :         }
     308            0 :         if (contains && res) {
     309            0 :             res = false;
     310              :         }
     311              :     }
     312              : 
     313            0 :     for (const PaletteCellPtr& cell : cells()) {
     314            0 :         const QStringList h = cell->name.toLower().split(" ");
     315            0 :         const QStringList n = t.split(" ");
     316            0 :         bool c = false;
     317            0 :         for (const QString& hs : h) {
     318            0 :             for (const QString& ns : n) {
     319            0 :                 if (!ns.trimmed().isEmpty()) {
     320            0 :                     c = hs.trimmed().startsWith(ns.trimmed());
     321              :                 }
     322              :             }
     323            0 :             if (c) {
     324            0 :                 break;
     325              :             }
     326              :         }
     327            0 :         if (t.isEmpty() || c) {
     328            0 :             m_filteredCells.push_back(cell);
     329              :         }
     330            0 :         const bool contains = t.isEmpty() || c;
     331            0 :         if (!contains) {
     332            0 :             m_isFilterActive = true;
     333              :         }
     334            0 :         if (contains && res) {
     335            0 :             res = false;
     336              :         }
     337            0 :     }
     338            0 :     setFixedHeight(heightForWidth(width()));
     339            0 :     updateGeometry();
     340            0 :     return res;
     341            0 : }
     342              : 
     343              : // ====================================================
     344              : // Selection
     345              : // ====================================================
     346              : 
     347            0 : bool PaletteWidget::isSelectable() const
     348              : {
     349            0 :     return m_selectable;
     350              : }
     351              : 
     352            0 : void PaletteWidget::setSelectable(bool val)
     353              : {
     354            0 :     m_selectable = val;
     355            0 : }
     356              : 
     357            0 : int PaletteWidget::selectedIdx() const
     358              : {
     359            0 :     return m_selectedIdx;
     360              : }
     361              : 
     362            0 : void PaletteWidget::setSelected(int idx)
     363              : {
     364            0 :     if (m_selectedIdx == idx) {
     365            0 :         return;
     366              :     }
     367              : 
     368            0 :     int previous = m_selectedIdx;
     369            0 :     m_selectedIdx = idx;
     370            0 :     emit selectedChanged(idx, previous);
     371              : }
     372              : 
     373            0 : int PaletteWidget::currentIdx() const
     374              : {
     375            0 :     return m_currentIdx;
     376              : }
     377              : 
     378            0 : void PaletteWidget::setCurrentIdx(int idx)
     379              : {
     380            0 :     m_currentIdx = idx;
     381            0 : }
     382              : 
     383            0 : void PaletteWidget::nextPaletteElement()
     384              : {
     385            0 :     int i = m_currentIdx;
     386            0 :     if (i == -1) {
     387            0 :         return;
     388              :     }
     389            0 :     i++;
     390            0 :     if (i < actualCellCount() && cellAt(i)) {
     391            0 :         m_currentIdx = i;
     392              :     }
     393              : 
     394              :     // TODO: screenreader support
     395              :     //QString name = qApp->translate("palette", cellAt(i)->name.toUtf8());
     396              :     //ScoreAccessibility::makeReadable(name);
     397              : 
     398            0 :     update();
     399              : }
     400              : 
     401            0 : void PaletteWidget::prevPaletteElement()
     402              : {
     403            0 :     int i = m_currentIdx;
     404            0 :     if (i == -1) {
     405            0 :         return;
     406              :     }
     407            0 :     i--;
     408            0 :     if (i >= 0 && cellAt(i)) {
     409            0 :         m_currentIdx = i;
     410              :     }
     411              : 
     412              :     // TODO: screenreader support
     413              :     //QString name = qApp->translate("palette", cellAt(i)->name.toUtf8());
     414              :     //ScoreAccessibility::makeReadable(name);
     415              : 
     416            0 :     update();
     417              : }
     418              : 
     419              : // ====================================================
     420              : // Applying elements
     421              : // ====================================================
     422              : 
     423            0 : bool PaletteWidget::isApplyingElementsDisabled() const
     424              : {
     425            0 :     return m_isApplyingElementsDisabled;
     426              : }
     427              : 
     428            0 : void PaletteWidget::setApplyingElementsDisabled(bool val)
     429              : {
     430            0 :     m_isApplyingElementsDisabled = val;
     431            0 : }
     432              : 
     433            0 : bool PaletteWidget::useDoubleClickForApplyingElements() const
     434              : {
     435            0 :     return m_useDoubleClickForApplyingElements;
     436              : }
     437              : 
     438            0 : void PaletteWidget::setUseDoubleClickForApplyingElements(bool val)
     439              : {
     440            0 :     m_useDoubleClickForApplyingElements = val;
     441            0 : }
     442              : 
     443            0 : bool PaletteWidget::ignoreInputEvents() const
     444              : {
     445            0 :     return m_ignoreInputEvents;
     446              : }
     447              : 
     448            0 : void PaletteWidget::setIgnoreInputEvents(bool val)
     449              : {
     450            0 :     m_ignoreInputEvents = val;
     451            0 : }
     452              : 
     453            0 : void PaletteWidget::applyCurrentElementToScore()
     454              : {
     455            0 :     applyElementAtIndex(m_currentIdx);
     456            0 : }
     457              : 
     458            0 : void PaletteWidget::applyElementAtPosition(const QPointF& pos, Qt::KeyboardModifiers modifiers)
     459              : {
     460            0 :     applyElementAtIndex(cellIndexForPoint(pos), modifiers);
     461            0 : }
     462              : 
     463            0 : void PaletteWidget::applyElementAtIndex(int index, Qt::KeyboardModifiers modifiers)
     464              : {
     465            0 :     if (m_isApplyingElementsDisabled) {
     466            0 :         return;
     467              :     }
     468              : 
     469            0 :     notation::INotationPtr notation = projectSession()->currentNotation();
     470            0 :     if (!notation) {
     471            0 :         return;
     472              :     }
     473              : 
     474            0 :     const PaletteCellPtr cell = cellAt(index);
     475            0 :     if (!cell || !cell->element) {
     476            0 :         return;
     477              :     }
     478              : 
     479            0 :     notation->interaction()->applyPaletteElement(cell->element.get(), modifiers);
     480            0 :     mainWindow()->qWindow()->requestActivate();
     481            0 : }
     482              : 
     483              : // ====================================================
     484              : // Settings
     485              : // ====================================================
     486              : 
     487            0 : bool PaletteWidget::readOnly() const
     488              : {
     489            0 :     return m_isReadOnly;
     490              : }
     491              : 
     492            0 : void PaletteWidget::setReadOnly(bool val)
     493              : {
     494            0 :     m_isReadOnly = val;
     495            0 :     setAcceptDrops(!val);
     496            0 : }
     497              : 
     498            0 : void PaletteWidget::setCellReadOnly(int cellIndex, bool readonly)
     499              : {
     500            0 :     cells()[cellIndex]->readOnly = readonly;
     501            0 : }
     502              : 
     503            0 : void PaletteWidget::setShowContextMenu(bool val)
     504              : {
     505            0 :     m_showContextMenu = val;
     506            0 : }
     507              : 
     508              : // ====================================================
     509              : // Helpers
     510              : // ====================================================
     511              : 
     512            0 : int PaletteWidget::columns() const
     513              : {
     514            0 :     return width() / gridWidthScaled();
     515              : }
     516              : 
     517            0 : int PaletteWidget::rows() const
     518              : {
     519            0 :     int c = columns();
     520            0 :     if (c == 0) {
     521            0 :         return 0;
     522              :     }
     523            0 :     return (actualCellCount() + c - 1) / c;
     524              : }
     525              : 
     526            0 : int PaletteWidget::cellIndexForPoint(const QPointF& p) const
     527              : {
     528            0 :     int idx = theoreticalCellIndexForPoint(p);
     529            0 :     if (idx < 0 || idx >= actualCellCount()) {
     530            0 :         return -1;
     531              :     }
     532            0 :     return idx;
     533              : }
     534              : 
     535            0 : int PaletteWidget::theoreticalCellIndexForPoint(const QPointF& p) const
     536              : {
     537            0 :     int hgridM = gridWidthScaled();
     538            0 :     int vgridM = gridHeightScaled();
     539            0 :     if (columns() == 0) {
     540            0 :         return -1;
     541              :     }
     542            0 :     int rightBorder = width() % hgridM;
     543            0 :     int hhgrid      = hgridM + (rightBorder / columns());
     544              : 
     545            0 :     int col = p.x() / hhgrid;
     546            0 :     int row = p.y() / vgridM;
     547              : 
     548            0 :     int nc = columns();
     549            0 :     if (col > nc) {
     550            0 :         return -1;
     551              :     }
     552              : 
     553            0 :     int idx = row * nc + col;
     554            0 :     if (idx < 0 || idx > columns() * rows()) {
     555            0 :         return -1;
     556              :     }
     557            0 :     return idx;
     558              : }
     559              : 
     560            0 : QRect PaletteWidget::rectForCellAt(int idx) const
     561              : {
     562            0 :     int hgridM = gridWidthScaled();
     563            0 :     int vgridM = gridHeightScaled();
     564            0 :     if (idx == -1) {
     565            0 :         return QRect();
     566              :     }
     567            0 :     if (columns() == 0) {
     568            0 :         return QRect();
     569              :     }
     570              : 
     571            0 :     int rightBorder = width() % hgridM;
     572            0 :     int hhgrid = hgridM + (rightBorder / columns());
     573              : 
     574            0 :     int cc = idx % columns();
     575            0 :     int cr = idx / columns();
     576            0 :     return QRect(cc * hhgrid, cr * vgridM, hhgrid, vgridM);
     577              : }
     578              : 
     579            0 : QPixmap PaletteWidget::pixmapForCellAt(int paletteIdx) const
     580              : {
     581            0 :     qreal _spatium = paletteScoreProvider()->paletteScore()->style().spatium();
     582            0 :     qreal magS     = configuration()->paletteSpatium() * mag() * paletteScaling();
     583            0 :     qreal mag      = magS / _spatium;
     584              : 
     585            0 :     PaletteCellPtr cell = cellAt(paletteIdx);
     586            0 :     if (!cell || !cell->element) {
     587            0 :         return QPixmap();
     588              :     }
     589              : 
     590            0 :     qreal cellMag = cell->mag * mag;
     591            0 :     ElementPtr element = cell->element;
     592              : 
     593            0 :     engravingRender()->layoutItem(element.get());
     594              : 
     595            0 :     RectF r = element->ldata()->bbox();
     596            0 :     int w = lrint(r.width() * cellMag);
     597            0 :     int h = lrint(r.height() * cellMag);
     598              : 
     599            0 :     if (w * h == 0) {
     600            0 :         LOGD("zero pixmap %d %d %s", w, h, element->typeName());
     601            0 :         return QPixmap();
     602              :     }
     603              : 
     604            0 :     QPixmap pm(w, h);
     605            0 :     pm.fill(configuration()->elementsBackgroundColor());
     606              : 
     607            0 :     muse::draw::Painter painter(&pm, "palette");
     608            0 :     painter.setAntialiasing(true);
     609              : 
     610            0 :     painter.scale(cellMag, cellMag);
     611              : 
     612            0 :     painter.translate(-r.topLeft());
     613            0 :     PointF pos = element->ldata()->pos();
     614            0 :     element->setPos(0, 0);
     615              : 
     616            0 :     QColor color;
     617              :     // show voice colors for notes
     618            0 :     if (element->isChord()) {
     619            0 :         const Chord* chord = toChord(element.get());
     620            0 :         for (Note* note : chord->notes()) {
     621            0 :             note->setSelected(true);
     622              :         }
     623            0 :         color = element->curColor({}).toQColor();
     624              :     } else {
     625            0 :         color = palette().color(QPalette::Normal, QPalette::Text);
     626              :     }
     627              : 
     628            0 :     painter.setPen(Pen(color));
     629              : 
     630            0 :     notation::EngravingItemPreviewPainter::PaintParams params;
     631            0 :     params.painter = &painter;
     632            0 :     params.color = configuration()->elementsColor();
     633              : 
     634            0 :     notation::EngravingItemPreviewPainter::paintItem(engravingRender(), element.get(), params);
     635              : 
     636            0 :     element->setPos(pos);
     637            0 :     return pm;
     638            0 : }
     639              : 
     640              : // ====================================================
     641              : // Sizing
     642              : // ====================================================
     643              : 
     644            0 : int PaletteWidget::heightForWidth(int w) const
     645              : {
     646            0 :     int hgridM = gridWidthScaled();
     647            0 :     int vgridM = gridHeightScaled();
     648            0 :     int c = w / hgridM;
     649            0 :     if (c <= 0) {
     650            0 :         c = 1;
     651              :     }
     652            0 :     int rows = (actualCellCount() + c - 1) / c;
     653            0 :     if (rows <= 0) {
     654            0 :         rows = 1;
     655              :     }
     656            0 :     qreal magS = configuration()->paletteSpatium() * mag() * paletteScaling();
     657            0 :     int h = lrint(yOffset() * 2 * magS);
     658            0 :     return rows * vgridM + h;
     659              : }
     660              : 
     661            0 : QSize PaletteWidget::sizeHint() const
     662              : {
     663            0 :     int h = heightForWidth(width());
     664            0 :     int hgridM = gridWidthScaled();
     665            0 :     return QSize((width() / hgridM) * hgridM, h);
     666              : }
     667              : 
     668              : // ====================================================
     669              : // Event handling
     670              : // ====================================================
     671              : 
     672            0 : bool PaletteWidget::event(QEvent* ev)
     673              : {
     674            0 :     if (!m_palette) {
     675            0 :         return false;
     676              :     }
     677              : 
     678            0 :     if (m_ignoreInputEvents && ev->isInputEvent()) {
     679            0 :         return false;
     680              :     }
     681              : 
     682            0 :     int hgridM = gridWidthScaled();
     683            0 :     int vgridM = gridHeightScaled();
     684              :     // disable mouse hover when keyboard navigation is enabled
     685            0 :     if (m_isFilterActive && (ev->type() == QEvent::MouseMove || ev->type() == QEvent::ToolTip
     686            0 :                              || ev->type() == QEvent::WindowDeactivate)) {
     687            0 :         return true;
     688            0 :     } else if (columns() && (ev->type() == QEvent::ToolTip)) {
     689            0 :         int rightBorder = width() % hgridM;
     690            0 :         int hhgrid = hgridM + (rightBorder / columns());
     691            0 :         QHelpEvent* he = (QHelpEvent*)ev;
     692            0 :         int x = he->pos().x();
     693            0 :         int y = he->pos().y();
     694              : 
     695            0 :         int row = y / vgridM;
     696            0 :         int col = x / hhgrid;
     697              : 
     698            0 :         if (row < 0 || row >= rows()) {
     699            0 :             return false;
     700              :         }
     701            0 :         if (col < 0 || col >= columns()) {
     702            0 :             return false;
     703              :         }
     704            0 :         int idx = row * columns() + col;
     705            0 :         if (idx >= int(cells().size())) {
     706            0 :             return false;
     707              :         }
     708            0 :         if (cellAt(idx) == 0) {
     709            0 :             return false;
     710              :         }
     711            0 :         QToolTip::showText(he->globalPos(), cellAt(idx)->translatedName(), this);
     712            0 :         return false;
     713              :     }
     714            0 :     return QWidget::event(ev);
     715              : }
     716              : 
     717            0 : void PaletteWidget::mousePressEvent(QMouseEvent* ev)
     718              : {
     719            0 :     m_dragStartPosition = ev->pos();
     720            0 :     m_dragIdx           = cellIndexForPoint(m_dragStartPosition);
     721              : 
     722            0 :     m_pressedIndex = m_dragIdx;
     723              : 
     724            0 :     if (m_dragIdx == -1) {
     725            0 :         return;
     726              :     }
     727              : 
     728            0 :     if (m_selectable) {
     729            0 :         if (m_dragIdx != m_selectedIdx) {
     730            0 :             update(rectForCellAt(m_dragIdx) | rectForCellAt(m_selectedIdx));
     731              :         }
     732              : 
     733            0 :         emit boxClicked(m_dragIdx);
     734            0 :         m_selectedIdx = m_dragIdx;
     735              :     }
     736              : 
     737            0 :     update();
     738              : }
     739              : 
     740            0 : void PaletteWidget::mouseDoubleClickEvent(QMouseEvent* ev)
     741              : {
     742            0 :     if (m_useDoubleClickForApplyingElements) {
     743            0 :         applyElementAtPosition(ev->pos(), ev->modifiers());
     744              :     }
     745            0 : }
     746              : 
     747            0 : void PaletteWidget::mouseMoveEvent(QMouseEvent* ev)
     748              : {
     749            0 :     if ((m_currentIdx != -1) && (m_dragIdx == m_currentIdx) && (ev->buttons() & Qt::LeftButton)
     750            0 :         && (ev->pos() - m_dragStartPosition).manhattanLength() > QApplication::startDragDistance()) {
     751            0 :         PaletteCellPtr cell = cellAt(m_currentIdx);
     752            0 :         if (cell && cell->element) {
     753            0 :             QDrag* drag         = new QDrag(this);
     754            0 :             QMimeData* mimeData = new QMimeData;
     755            0 :             const ElementPtr el   = cell->element;
     756              : 
     757            0 :             mimeData->setData(mimeSymbolFormat, el->mimeData().toQByteArray());
     758            0 :             drag->setMimeData(mimeData);
     759              : 
     760            0 :             drag->setPixmap(pixmapForCellAt(m_currentIdx));
     761              : 
     762            0 :             QPoint hotsp(drag->pixmap().rect().bottomRight());
     763            0 :             drag->setHotSpot(hotsp);
     764              : 
     765            0 :             Qt::DropActions da;
     766            0 :             if (!(m_isReadOnly || m_isFilterActive) && (ev->modifiers() & Qt::ShiftModifier)) {
     767            0 :                 m_filteredCells = cells(); // backup
     768            0 :                 da = Qt::MoveAction;
     769              :             } else {
     770            0 :                 da = Qt::CopyAction;
     771              :             }
     772            0 :             Qt::DropAction a = drag->exec(da);
     773            0 :             if (da == Qt::MoveAction && a != da) {
     774              :                 // restore on a failed move action
     775            0 :                 m_palette->clear();
     776            0 :                 m_palette->insertCells(0, m_filteredCells);
     777              :             }
     778            0 :             update();
     779            0 :         }
     780            0 :     } else {
     781            0 :         m_currentIdx = cellIndexForPoint(ev->pos());
     782            0 :         if (m_currentIdx != -1 && cellAt(m_currentIdx) == 0) {
     783            0 :             m_currentIdx = -1;
     784              :         }
     785            0 :         update();
     786              :     }
     787            0 : }
     788              : 
     789            0 : void PaletteWidget::mouseReleaseEvent(QMouseEvent* event)
     790              : {
     791            0 :     m_pressedIndex = -1;
     792              : 
     793            0 :     update();
     794              : 
     795            0 :     if (!m_useDoubleClickForApplyingElements) {
     796            0 :         applyElementAtPosition(event->position(), event->modifiers());
     797              :     }
     798            0 : }
     799              : 
     800            0 : void PaletteWidget::leaveEvent(QEvent*)
     801              : {
     802            0 :     if (m_currentIdx != -1) {
     803            0 :         QRect r = rectForCellAt(m_currentIdx);
     804            0 :         if (!(QGuiApplication::keyboardModifiers() & Qt::ShiftModifier)) {
     805            0 :             m_currentIdx = -1;
     806              :         }
     807            0 :         update(r);
     808              :     }
     809            0 : }
     810              : 
     811            0 : void PaletteWidget::dragEnterEvent(QDragEnterEvent* event)
     812              : {
     813            0 :     const QMimeData* dta = event->mimeData();
     814            0 :     if (dta->hasUrls()) {
     815            0 :         QList<QUrl> ul = event->mimeData()->urls();
     816            0 :         QUrl u = ul.front();
     817              : 
     818            0 :         if (u.scheme() == "file") {
     819            0 :             QFileInfo fi(u.path());
     820            0 :             QString suffix(fi.suffix().toLower());
     821            0 :             if (suffix == "svg"
     822            0 :                 || suffix == "svgz"
     823            0 :                 || suffix == "jpg"
     824            0 :                 || suffix == "jpeg"
     825            0 :                 || suffix == "png"
     826            0 :                 || suffix == "bmp"
     827            0 :                 || suffix == "tif"
     828            0 :                 || suffix == "tiff"
     829              :                 ) {
     830            0 :                 event->acceptProposedAction();
     831              :             }
     832            0 :         }
     833            0 :     } else if (dta->hasFormat(mimeSymbolFormat)) {
     834            0 :         event->accept();
     835            0 :         update();
     836              :     } else {
     837            0 :         event->ignore();
     838              : #ifndef NDEBUG
     839            0 :         LOGD("dragEnterEvent: formats:");
     840            0 :         for (const QString& s : event->mimeData()->formats()) {
     841            0 :             LOGD("   %s", qPrintable(s));
     842            0 :         }
     843              : #endif
     844              :     }
     845            0 : }
     846              : 
     847            0 : void PaletteWidget::dragMoveEvent(QDragMoveEvent* event)
     848              : {
     849            0 :     if (event->source() == this) {
     850            0 :         if (m_currentIdx != -1 && event->proposedAction() == Qt::MoveAction) {
     851            0 :             int targetIdx = cellIndexForPoint(event->position());
     852            0 :             if (targetIdx != -1 && targetIdx != m_currentIdx) {
     853            0 :                 PaletteCellPtr cell = m_palette->takeCell(m_currentIdx);
     854            0 :                 m_palette->insertCell(targetIdx, cell);
     855            0 :                 m_currentIdx = targetIdx;
     856            0 :                 update();
     857            0 :             }
     858            0 :             event->accept();
     859            0 :             return;
     860              :         }
     861            0 :         event->ignore();
     862              :     } else {
     863            0 :         event->accept();
     864              :     }
     865              : }
     866              : 
     867            0 : void PaletteWidget::dropEvent(QDropEvent* event)
     868              : {
     869            0 :     ElementPtr element = nullptr;
     870            0 :     QString name;
     871              : 
     872            0 :     const QMimeData* datap = event->mimeData();
     873            0 :     if (datap->hasUrls()) {
     874            0 :         QList<QUrl> ul = event->mimeData()->urls();
     875            0 :         QUrl u = ul.front();
     876            0 :         if (u.scheme() == "file") {
     877            0 :             auto image = std::make_shared<Image>(paletteScoreProvider()->paletteScore()->dummy());
     878            0 :             QString filePath(u.toLocalFile());
     879            0 :             image->loadFromFile(filePath);
     880            0 :             element = image;
     881            0 :             QFileInfo file(filePath);
     882            0 :             name = file.completeBaseName();
     883            0 :         }
     884            0 :     } else if (datap->hasFormat(mimeSymbolFormat)) {
     885            0 :         QByteArray dta(event->mimeData()->data(mimeSymbolFormat));
     886            0 :         muse::ByteArray ba = muse::ByteArray::fromQByteArrayNoCopy(dta);
     887            0 :         XmlReader xml(ba);
     888            0 :         PointF dragOffset;
     889            0 :         Fraction duration;
     890            0 :         ElementType type = EngravingItem::readType(xml, &dragOffset, &duration);
     891              : 
     892            0 :         if (type == ElementType::SYMBOL) {
     893            0 :             auto symbol = std::make_shared<Symbol>(paletteScoreProvider()->paletteScore()->dummy());
     894            0 :             rw::RWRegister::reader()->readItem(symbol.get(), xml);
     895            0 :             element = symbol;
     896            0 :         } else {
     897            0 :             element = std::shared_ptr<EngravingItem>(Factory::createItem(type, paletteScoreProvider()->paletteScore()->dummy()));
     898            0 :             if (element) {
     899            0 :                 rw::RWRegister::reader()->readItem(element.get(), xml);
     900            0 :                 element->setTrack(0);
     901              :             }
     902              :         }
     903            0 :     }
     904              : 
     905            0 :     if (!element) {
     906            0 :         event->ignore();
     907            0 :         return;
     908              :     }
     909              : 
     910            0 :     if (event->source() == this) {
     911            0 :         if (event->proposedAction() == Qt::MoveAction) {
     912            0 :             event->accept();
     913            0 :             emit changed();
     914            0 :             return;
     915              :         }
     916            0 :         event->ignore();
     917            0 :         return;
     918              :     }
     919              : 
     920            0 :     if (element->isFretDiagram()) {
     921            0 :         name = toFretDiagram(element.get())->harmonyPlainText();
     922              :     }
     923              : 
     924            0 :     element->setSelected(false);
     925              : 
     926            0 :     int i = cellIndexForPoint(event->position());
     927            0 :     if (i == -1 || cells()[i]) {
     928            0 :         appendElement(element, name);
     929              :     } else {
     930            0 :         insertElement(i, element, name);
     931              :     }
     932            0 :     event->accept();
     933              : 
     934            0 :     setFixedHeight(heightForWidth(width()));
     935            0 :     updateGeometry();
     936            0 :     update();
     937            0 :     emit changed();
     938            0 : }
     939              : 
     940            0 : void PaletteWidget::resizeEvent(QResizeEvent* e)
     941              : {
     942            0 :     setFixedHeight(heightForWidth(e->size().width()));
     943            0 : }
     944              : 
     945            0 : void PaletteWidget::paintEvent(QPaintEvent* /*event*/)
     946              : {
     947            0 :     auto paletteScore = paletteScoreProvider()->paletteScore();
     948            0 :     qreal _spatium = paletteScore->style().spatium();
     949            0 :     qreal magS     = configuration()->paletteSpatium() * mag() * paletteScaling();
     950            0 :     qreal mag      = magS / _spatium;
     951            0 :     paletteScore->style().setSpatium(paletteScore->style().defaultSpatium());
     952              : 
     953            0 :     muse::draw::Painter painter(this, "palette");
     954            0 :     painter.setAntialiasing(true);
     955              : 
     956            0 :     if (m_paintOptions.backgroundColor.isValid()) {
     957            0 :         painter.setBrush(m_paintOptions.backgroundColor);
     958              :     }
     959              : 
     960            0 :     painter.setPen(configuration()->gridColor());
     961            0 :     painter.drawRoundedRect(RectF(0, 0, width(), height()), 2, 2);
     962              : 
     963              :     //
     964              :     // draw grid
     965              :     //
     966            0 :     int hgridM = gridWidthScaled();
     967            0 :     int vgridM = gridHeightScaled();
     968              : 
     969            0 :     if (columns() == 0) {
     970            0 :         return;
     971              :     }
     972            0 :     int rightBorder = width() % hgridM;
     973            0 :     int hhgrid = hgridM + (rightBorder / columns());
     974              : 
     975            0 :     if (drawGrid()) {
     976            0 :         for (int row = 1; row < rows(); ++row) {
     977            0 :             int x2 = row < rows() - 1 ? columns() * hhgrid : width();
     978            0 :             int y  = row * vgridM;
     979            0 :             painter.drawLine(0, y, x2, y);
     980              :         }
     981            0 :         for (int column = 1; column < columns(); ++column) {
     982            0 :             int x = hhgrid * column;
     983            0 :             painter.drawLine(x, 0, x, rows() * vgridM);
     984              :         }
     985              :     }
     986              : 
     987            0 :     qreal dy = lrint(2 * magS);
     988              : 
     989            0 :     Color linesColor = m_paintOptions.linesColor.isValid() ? m_paintOptions.linesColor
     990            0 :                        : configuration()->elementsColor();
     991              : 
     992            0 :     Color selectionColor = m_paintOptions.selectionColor.isValid() ? m_paintOptions.selectionColor
     993            0 :                            : configuration()->accentColor();
     994              : 
     995              :     //
     996              :     // draw symbols
     997              :     //
     998            0 :     for (int idx = 0; idx < int(actualCellsList().size()); ++idx) {
     999            0 :         int yoffset = _spatium * yOffset();
    1000            0 :         RectF r = RectF::fromQRectF(rectForCellAt(idx));
    1001            0 :         RectF rShift = r.translated(0, yoffset);
    1002            0 :         QColor c = selectionColor.toQColor();
    1003              : 
    1004            0 :         PaletteCellPtr currentCell = actualCellsList().at(idx);
    1005            0 :         if (!currentCell) {
    1006            0 :             continue;
    1007              :         }
    1008              : 
    1009            0 :         if (currentCell->focused) {
    1010            0 :             painter.setPen(QColor(uiConfiguration()->currentTheme().values[muse::ui::FONT_PRIMARY_COLOR].toString()));
    1011            0 :             painter.setBrush(QColor(Qt::transparent));
    1012              : 
    1013            0 :             int borderWidth = uiConfiguration()->currentTheme().values[muse::ui::NAVIGATION_CONTROL_BORDER_WIDTH].toInt();
    1014            0 :             qreal border = borderWidth / 2;
    1015              : 
    1016            0 :             painter.drawRoundedRect(r.adjusted(border, border, -border, -border), borderWidth, borderWidth);
    1017            0 :             r.adjust(borderWidth, borderWidth, -borderWidth, -borderWidth);
    1018              :         }
    1019              : 
    1020            0 :         if (idx == m_selectedIdx) {
    1021            0 :             c.setAlphaF(0.5f);
    1022            0 :             painter.fillRect(r, c);
    1023            0 :         } else if (idx == m_pressedIndex) {
    1024            0 :             c.setAlphaF(0.75f);
    1025            0 :             painter.fillRect(r, c);
    1026            0 :         } else if (idx == m_currentIdx) {
    1027            0 :             c.setAlphaF(0.2f);
    1028            0 :             painter.fillRect(r, c);
    1029              :         }
    1030              : 
    1031            0 :         QString tag = currentCell->tag;
    1032            0 :         if (!tag.isEmpty()) {
    1033            0 :             painter.setPen(QColor(Qt::darkGray));
    1034            0 :             Font font(painter.font());
    1035            0 :             font.setPixelSize(uiConfiguration()->fontSize(muse::ui::FontSizeType::BODY));
    1036            0 :             painter.setFont(font);
    1037            0 :             painter.drawText(rShift, AlignLeft | AlignTop, {}, tag);
    1038            0 :         }
    1039              : 
    1040            0 :         muse::draw::Pen pen(linesColor);
    1041            0 :         pen.setWidthF(engraving::DefaultStyle::defaultStyle().styleS(Sid::staffLineWidth).val() * magS);
    1042            0 :         painter.setPen(pen);
    1043              : 
    1044            0 :         ElementPtr el = currentCell->element;
    1045            0 :         if (!el) {
    1046            0 :             continue;
    1047              :         }
    1048              : 
    1049            0 :         bool drawStaff = currentCell->drawStaff;
    1050            0 :         int row    = idx / columns();
    1051            0 :         int column = idx % columns();
    1052              : 
    1053            0 :         qreal cellMag = currentCell->mag * mag;
    1054              : 
    1055            0 :         engravingRender()->layoutItem(el.get());
    1056              : 
    1057            0 :         if (drawStaff) {
    1058            0 :             qreal y = r.y() + vgridM * .5 - dy + yOffset() * _spatium * cellMag;
    1059            0 :             qreal x = r.x() + 3;
    1060            0 :             qreal w = hhgrid - 6;
    1061            0 :             for (int i = 0; i < 5; ++i) {
    1062            0 :                 qreal yy = y + i * magS;
    1063            0 :                 painter.setPen(linesColor);
    1064            0 :                 painter.drawLine(LineF(x, yy, x + w, yy));
    1065              :             }
    1066              :         }
    1067            0 :         painter.save();
    1068            0 :         painter.scale(cellMag, cellMag);
    1069              : 
    1070            0 :         double gw = hhgrid / cellMag;
    1071            0 :         double gh = vgridM / cellMag;
    1072            0 :         double gx = column * gw + currentCell->xoffset * _spatium;
    1073            0 :         double gy = row * gh + currentCell->yoffset * _spatium;
    1074              : 
    1075            0 :         double sw = el->width();
    1076            0 :         double sh = el->height();
    1077            0 :         double sy = 0;
    1078              : 
    1079            0 :         if (drawStaff) {
    1080            0 :             sy = gy + gh * .5 - 2.0 * _spatium;
    1081              :         } else {
    1082            0 :             sy  = gy + (gh - sh) * .5 - el->ldata()->bbox().y();
    1083              :         }
    1084            0 :         double sx  = gx + (gw - sw) * .5 - el->ldata()->bbox().x();
    1085              : 
    1086            0 :         sy += yOffset() * _spatium;
    1087              : 
    1088            0 :         painter.translate(sx, sy);
    1089              : 
    1090            0 :         QColor color;
    1091            0 :         if (idx != m_selectedIdx) {
    1092              :             // show voice colors for notes
    1093            0 :             if (el->isChord()) {
    1094            0 :                 color = el->curColor({}).toQColor();
    1095              :             } else {
    1096            0 :                 color = palette().color(QPalette::Normal, QPalette::Text);
    1097              :             }
    1098              :         } else {
    1099            0 :             color = palette().color(QPalette::Normal, QPalette::HighlightedText);
    1100              :         }
    1101              : 
    1102            0 :         painter.setPen(Pen(color));
    1103              : 
    1104            0 :         notation::EngravingItemPreviewPainter::PaintParams params;
    1105            0 :         params.painter = &painter;
    1106            0 :         params.color = configuration()->elementsColor();
    1107              : 
    1108            0 :         params.useElementColors = m_paintOptions.useElementColors;
    1109            0 :         params.colorsInversionEnabled = m_paintOptions.colorsInversionEnabled;
    1110              : 
    1111            0 :         notation::EngravingItemPreviewPainter::paintItem(engravingRender(), el.get(), params);
    1112              : 
    1113            0 :         painter.restore();
    1114            0 :     }
    1115            0 : }
    1116              : 
    1117            0 : void PaletteWidget::contextMenuEvent(QContextMenuEvent* event)
    1118              : {
    1119            0 :     if (!m_showContextMenu) {
    1120            0 :         return;
    1121              :     }
    1122            0 :     int i = cellIndexForPoint(event->pos());
    1123            0 :     if (i == -1) {
    1124              :         // palette context menu
    1125            0 :         return;
    1126              :     }
    1127              : 
    1128            0 :     QMenu menu;
    1129            0 :     QAction* deleteCellAction = menu.addAction(muse::qtrc("palette", "Delete"));
    1130            0 :     QAction* contextAction = menu.addAction(muse::qtrc("palette", "Properties…"));
    1131            0 :     deleteCellAction->setEnabled(!m_isReadOnly);
    1132            0 :     contextAction->setEnabled(!m_isReadOnly);
    1133              : 
    1134            0 :     if (m_isFilterActive || (cellAt(i) && cellAt(i)->readOnly)) {
    1135            0 :         deleteCellAction->setEnabled(false);
    1136              :     }
    1137              : 
    1138            0 :     if (!deleteCellAction->isEnabled() && !contextAction->isEnabled()) {
    1139            0 :         return;
    1140              :     }
    1141              : 
    1142            0 :     const QAction* action = menu.exec(mapToGlobal(event->pos()));
    1143              : 
    1144            0 :     if (action == deleteCellAction) {
    1145            0 :         PaletteCellPtr cell = cellAt(i);
    1146            0 :         if (cell) {
    1147            0 :             std::string title = muse::trc("palette", "Delete palette cell");
    1148            0 :             std::string question = muse::qtrc("palette", "Are you sure you want to delete palette cell “%1”?")
    1149            0 :                                    .arg(cell->name).toStdString();
    1150              : 
    1151            0 :             auto promise = interactive()->question(title, question, {
    1152              :                 muse::IInteractive::Button::Yes,
    1153              :                 muse::IInteractive::Button::No
    1154            0 :             }, muse::IInteractive::Button::Yes);
    1155              : 
    1156            0 :             promise.onResolve(this, [this, i](const IInteractive::Result& res) {
    1157            0 :                 if (res.isButton(IInteractive::Button::Yes)) {
    1158            0 :                     m_palette->takeCell(i);
    1159            0 :                     emit changed();
    1160              :                 }
    1161            0 :             });
    1162            0 :         }
    1163            0 :     } else {
    1164            0 :         bool sizeChanged = false;
    1165            0 :         for (size_t j = 0; j < cells().size(); ++j) {
    1166            0 :             if (!cellAt(j)) {
    1167            0 :                 m_palette->takeCells(i, 1);
    1168            0 :                 sizeChanged = true;
    1169              :             }
    1170              :         }
    1171            0 :         if (sizeChanged) {
    1172            0 :             setFixedHeight(heightForWidth(width()));
    1173            0 :             updateGeometry();
    1174              :         }
    1175            0 :         update();
    1176              :     }
    1177            0 : }
    1178              : 
    1179              : // ====================================================
    1180              : // Read/write
    1181              : // ====================================================
    1182              : 
    1183            0 : void PaletteWidget::read(XmlReader& e, bool pasteMode)
    1184              : {
    1185            0 :     m_palette->read(e, pasteMode);
    1186            0 : }
    1187              : 
    1188            0 : void PaletteWidget::write(XmlWriter& xml, bool pasteMode) const
    1189              : {
    1190            0 :     m_palette->write(xml, pasteMode);
    1191            0 : }
    1192              : 
    1193            0 : bool PaletteWidget::readFromFile(const QString& path)
    1194              : {
    1195            0 :     return m_palette->readFromFile(path);
    1196              : }
    1197              : 
    1198              : /// Write as compressed zip file and include images as needed
    1199            0 : void PaletteWidget::writeToFile(const QString& path) const
    1200              : {
    1201            0 :     m_palette->writeToFile(path);
    1202            0 : }
    1203              : 
    1204            0 : bool PaletteWidget::handleEvent(QEvent* event)
    1205              : {
    1206            0 :     return QWidget::event(event);
    1207              : }
    1208              : 
    1209            0 : const PaletteWidget::PaintOptions& PaletteWidget::paintOptions() const
    1210              : {
    1211            0 :     return m_paintOptions;
    1212              : }
    1213              : 
    1214            0 : void PaletteWidget::setPaintOptions(const PaintOptions& options)
    1215              : {
    1216            0 :     m_paintOptions = options;
    1217            0 : }
    1218              : 
    1219              : // ====================================================
    1220              : // PaletteScrollArea
    1221              : // ====================================================
    1222              : 
    1223            0 : PaletteScrollArea::PaletteScrollArea(PaletteWidget* w, QWidget* parent)
    1224            0 :     : QScrollArea(parent)
    1225              : {
    1226            0 :     setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
    1227            0 :     setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
    1228            0 :     setWidget(w);
    1229            0 :     setWidgetResizable(false);
    1230            0 :     m_restrictHeight = true;
    1231            0 :     setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
    1232            0 : }
    1233              : 
    1234            0 : bool PaletteScrollArea::restrictHeight() const
    1235              : {
    1236            0 :     return m_restrictHeight;
    1237              : }
    1238              : 
    1239            0 : void PaletteScrollArea::setRestrictHeight(bool val)
    1240              : {
    1241            0 :     m_restrictHeight = val;
    1242            0 : }
    1243              : 
    1244            0 : void PaletteScrollArea::keyPressEvent(QKeyEvent* event)
    1245              : {
    1246            0 :     PaletteWidget* p = qobject_cast<PaletteWidget*>(widget());
    1247            0 :     int pressedKey = event->key();
    1248            0 :     switch (pressedKey) {
    1249            0 :     case Qt::Key_Right:
    1250              :     case Qt::Key_Left:
    1251              :     case Qt::Key_Up:
    1252              :     case Qt::Key_Down:
    1253              :     {
    1254            0 :         int idx = p->selectedIdx();
    1255            0 :         if (pressedKey == Qt::Key_Left || pressedKey == Qt::Key_Up) {
    1256            0 :             idx--;
    1257              :         } else {
    1258            0 :             idx++;
    1259              :         }
    1260            0 :         if (idx < 0) {
    1261            0 :             idx = p->actualCellCount() - 1;
    1262            0 :         } else if (idx >= p->actualCellCount()) {
    1263            0 :             idx = 0;
    1264              :         }
    1265              : 
    1266            0 :         p->setSelected(idx);
    1267            0 :         p->setCurrentIdx(idx);
    1268              : 
    1269            0 :         p->update();
    1270            0 :         return;
    1271              :     }
    1272            0 :     case Qt::Key_Enter:
    1273              :     case Qt::Key_Return:
    1274            0 :         if (!p->isApplyingElementsDisabled()) {
    1275            0 :             p->applyCurrentElementToScore();
    1276              :         }
    1277            0 :         return;
    1278            0 :     default:
    1279            0 :         break;
    1280              :     }
    1281            0 :     QScrollArea::keyPressEvent(event);
    1282              : }
    1283              : 
    1284            0 : void PaletteScrollArea::resizeEvent(QResizeEvent* re)
    1285              : {
    1286            0 :     QScrollArea::resizeEvent(re);
    1287              : 
    1288            0 :     PaletteWidget* palette = qobject_cast<PaletteWidget*>(widget());
    1289            0 :     int h = palette->heightForWidth(width());
    1290            0 :     palette->resize(QSize(width() - 6, h));
    1291            0 :     if (m_restrictHeight) {
    1292            0 :         setMaximumHeight(h + 6);
    1293              :     }
    1294            0 : }
    1295              : 
    1296            0 : AccessiblePaletteWidget::AccessiblePaletteWidget(PaletteWidget* palette)
    1297            0 :     : QAccessibleWidget(palette)
    1298              : {
    1299            0 :     m_palette = palette;
    1300              : 
    1301            0 :     connect(m_palette, &PaletteWidget::selectedChanged, this, [this](int index, int previous) {
    1302            0 :         PaletteCellPtr curCell = m_palette->cellAt(index);
    1303            0 :         PaletteCellPtr previousCell = m_palette->cellAt(previous);
    1304              : 
    1305            0 :         if (previousCell) {
    1306            0 :             previousCell->focused = false;
    1307              : 
    1308            0 :             QAccessible::State qstate;
    1309            0 :             qstate.active = false;
    1310            0 :             qstate.focused = false;
    1311            0 :             qstate.selected = false;
    1312              : 
    1313            0 :             QAccessibleEvent ev(previousCell.get(), QAccessible::Focus);
    1314            0 :             QAccessible::updateAccessibility(&ev);
    1315            0 :         }
    1316              : 
    1317            0 :         if (curCell) {
    1318            0 :             curCell->focused = true;
    1319              : 
    1320            0 :             QAccessible::State qstate;
    1321            0 :             qstate.active = true;
    1322            0 :             qstate.focused = true;
    1323            0 :             qstate.selected = true;
    1324              : 
    1325            0 :             QAccessibleEvent ev(curCell.get(), QAccessible::Focus);
    1326            0 :             QAccessible::updateAccessibility(&ev);
    1327            0 :         }
    1328            0 :     });
    1329            0 : }
    1330              : 
    1331            0 : QObject* AccessiblePaletteWidget::object() const
    1332              : {
    1333            0 :     return m_palette;
    1334              : }
    1335              : 
    1336            0 : QAccessibleInterface* AccessiblePaletteWidget::child(int index) const
    1337              : {
    1338            0 :     PaletteCellPtr cell = m_palette->cellAt(index);
    1339            0 :     if (!cell) {
    1340            0 :         return nullptr;
    1341              :     }
    1342              : 
    1343            0 :     return QAccessible::queryAccessibleInterface(cell.get());
    1344            0 : }
    1345              : 
    1346            0 : int AccessiblePaletteWidget::childCount() const
    1347              : {
    1348            0 :     return m_palette->actualCellCount();
    1349              : }
    1350              : 
    1351            0 : int AccessiblePaletteWidget::indexOfChild(const QAccessibleInterface* child) const
    1352              : {
    1353            0 :     for (int i = 0; i < childCount(); ++i) {
    1354            0 :         auto childAccessible = QAccessible::queryAccessibleInterface(m_palette->cellAt(i).get());
    1355            0 :         if (childAccessible == child) {
    1356            0 :             return i;
    1357              :         }
    1358              :     }
    1359              : 
    1360            0 :     return -1;
    1361              : }
    1362              : 
    1363            0 : QAccessible::Role AccessiblePaletteWidget::role() const
    1364              : {
    1365            0 :     return QAccessible::StaticText;
    1366              : }
    1367              : 
    1368            0 : QAccessible::State AccessiblePaletteWidget::state() const
    1369              : {
    1370            0 :     QAccessible::State state = QAccessibleWidget::state();
    1371            0 :     state.selectable = true;
    1372            0 :     state.active = true;
    1373            0 :     state.focusable = true;
    1374            0 :     state.focused = m_palette->hasFocus();
    1375              : 
    1376            0 :     return state;
    1377              : }
    1378              : 
    1379            0 : QAccessibleInterface* AccessiblePaletteWidget::focusChild() const
    1380              : {
    1381            0 :     int selectIndex = m_palette->selectedIdx();
    1382            0 :     return QAccessible::queryAccessibleInterface(m_palette->cellAt(selectIndex).get());
    1383              : }
        

Generated by: LCOV version 2.0-1