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 : }
|