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 : #pragma once
24 :
25 : #include <variant>
26 :
27 : #include "draw/fontmetrics.h"
28 :
29 : #include "modularity/ioc.h"
30 : #include "../iengravingfontsprovider.h"
31 :
32 : #include "engravingitem.h"
33 : #include "property.h"
34 : #include "../types/types.h"
35 :
36 : namespace mu::engraving {
37 : class TextBase;
38 : class TextBlock;
39 : class Transaction;
40 :
41 : static constexpr double SUBSCRIPT_SIZE = 0.6;
42 : static constexpr double SUBSCRIPT_OFFSET = 0.5; // of x-height
43 : static constexpr double SUPERSCRIPT_OFFSET = -0.9; // of x-height
44 :
45 : //---------------------------------------------------------
46 : // FrameType
47 : //---------------------------------------------------------
48 :
49 : enum class FrameType : char {
50 : NO_FRAME, RECTANGLE, CIRCLE
51 : };
52 :
53 : //---------------------------------------------------------
54 : // VerticalAlignment
55 : //---------------------------------------------------------
56 :
57 : enum class VerticalAlignment : signed char {
58 : AlignUndefined = -1, AlignNormal, AlignSuperScript, AlignSubScript
59 : };
60 :
61 : //---------------------------------------------------------
62 : // FormatId
63 : //---------------------------------------------------------
64 :
65 : enum class FormatId : char {
66 : Bold, Italic, Underline, Strike, Valign, FontSize, FontFamily
67 : };
68 :
69 : using FormatValue = std::variant<std::monostate, bool, int, double, String>;
70 :
71 : //---------------------------------------------------------
72 : // MultiClick
73 : //---------------------------------------------------------
74 :
75 : enum class SelectTextType : char {
76 : Word, All
77 : };
78 :
79 : //---------------------------------------------------------
80 : // CharFormat
81 : //---------------------------------------------------------
82 :
83 : class CharFormat
84 : {
85 : public:
86 164704 : CharFormat() {}
87 50246 : CharFormat(const CharFormat& cf) { *this = cf; }
88 : bool operator==(const CharFormat& cf) const;
89 0 : bool operator!=(const CharFormat& cf) const { return !(*this == cf); }
90 : CharFormat& operator=(const CharFormat& cf);
91 :
92 517774 : FontStyle style() const { return m_style; }
93 257379 : void setStyle(FontStyle s) { m_style = s; }
94 331902 : bool bold() const { return m_style & FontStyle::Bold; }
95 330626 : bool italic() const { return m_style & FontStyle::Italic; }
96 331922 : bool underline() const { return m_style & FontStyle::Underline; }
97 331939 : bool strike() const { return m_style & FontStyle::Strike; }
98 50682 : void setBold(bool val) { m_style = val ? m_style + FontStyle::Bold : m_style - FontStyle::Bold; }
99 50041 : void setItalic(bool val) { m_style = val ? m_style + FontStyle::Italic : m_style - FontStyle::Italic; }
100 49954 : void setUnderline(bool val) { m_style = val ? m_style + FontStyle::Underline : m_style - FontStyle::Underline; }
101 49530 : void setStrike(bool val) { m_style = val ? m_style + FontStyle::Strike : m_style - FontStyle::Strike; }
102 :
103 819624 : VerticalAlignment valign() const { return m_valign; }
104 780711 : double fontSize() const { return m_fontSize; }
105 1028688 : String fontFamily() const { return m_fontFamily; }
106 212084 : void setValign(VerticalAlignment val) { m_valign = val; }
107 256713 : void setFontSize(double val) { m_fontSize = val; }
108 259677 : void setFontFamily(const String& val) { m_fontFamily = val; }
109 :
110 : FormatValue formatValue(FormatId) const;
111 : void setFormatValue(FormatId, const FormatValue& val);
112 :
113 : private:
114 :
115 : FontStyle m_style = FontStyle::Normal;
116 : VerticalAlignment m_valign = VerticalAlignment::AlignNormal;
117 : double m_fontSize = 12.0;
118 : String m_fontFamily;
119 : };
120 :
121 : //---------------------------------------------------------
122 : // TextCursor
123 : // Contains current position and start of selection
124 : // during editing.
125 : //---------------------------------------------------------
126 :
127 : class TextCursor
128 : {
129 : public:
130 : enum class MoveOperation : unsigned char {
131 : Start,
132 : Up,
133 : StartOfLine,
134 : Left,
135 : WordLeft,
136 : End,
137 : Down,
138 : EndOfLine,
139 : NextWord,
140 : Right
141 : };
142 :
143 : enum class MoveMode : unsigned char {
144 : MoveAnchor,
145 : KeepAnchor
146 : };
147 :
148 30718 : TextCursor(TextBase* t)
149 30718 : : m_text(t) {}
150 :
151 31857 : TextBase* text() const { return m_text; }
152 541145 : bool hasSelection() const { return (m_selectLine != m_row) || (m_selectColumn != m_column); }
153 : void clearSelection();
154 : void endEdit();
155 : void startEdit();
156 539952 : bool editing() const { return m_editing; }
157 0 : bool visible() const { return m_visible; }
158 0 : void setVisible(bool val) { m_visible = val; }
159 0 : void toggleVisible() { setVisible(!m_visible); }
160 :
161 522958 : CharFormat* format() { return &m_format; }
162 5 : const CharFormat* format() const { return &m_format; }
163 5665 : void setFormat(const CharFormat& f) { m_format = f; }
164 :
165 567244 : size_t row() const { return m_row; }
166 387001 : size_t column() const { return m_column; }
167 31768 : size_t selectLine() const { return m_selectLine; }
168 31771 : size_t selectColumn() const { return m_selectColumn; }
169 69903 : void setRow(size_t val) { m_row = val; }
170 247506 : void setColumn(size_t val) { m_column = val; }
171 31774 : void setSelectLine(size_t val) { m_selectLine = val; }
172 31774 : void setSelectColumn(size_t val) { m_selectColumn = val; }
173 : size_t columns() const;
174 : void init();
175 :
176 : struct Range {
177 : int startPosition = 0;
178 : int endPosition = 0;
179 : String text;
180 : };
181 :
182 : std::pair<size_t, size_t> positionToLocalCoord(int position) const;
183 :
184 : int currentPosition() const;
185 : Range selectionRange() const;
186 :
187 : const TextBlock& curLine() const;
188 : TextBlock& curLine();
189 :
190 : RectF cursorRect() const;
191 : RectF cursorCanvasRect() const;
192 : bool movePosition(TextCursor::MoveOperation op, TextCursor::MoveMode mode = TextCursor::MoveMode::MoveAnchor, int count = 1);
193 : void selectWord();
194 1 : void moveCursorToEnd() { movePosition(TextCursor::MoveOperation::End); }
195 1 : void moveCursorToStart() { movePosition(TextCursor::MoveOperation::Start); }
196 : Char currentCharacter() const;
197 : bool set(const PointF& p, TextCursor::MoveMode mode = TextCursor::MoveMode::MoveAnchor);
198 : String selectedText(bool withFormat = false) const;
199 : String extractText(int r1, int c1, int r2, int c2, bool withFormat = false) const;
200 : void updateCursorFormat();
201 : void setFormat(FormatId, FormatValue val);
202 : void changeSelectionFormat(FormatId id, const FormatValue& val);
203 : const CharFormat selectedFragmentsFormat() const;
204 :
205 : private:
206 : Range range(int start, int end) const;
207 : int position(int row, int column) const;
208 :
209 : TextBase* m_text = nullptr;
210 : CharFormat m_format;
211 : size_t m_row = 0;
212 : size_t m_column = 0;
213 : size_t m_selectLine = 0; // start of selection
214 : size_t m_selectColumn = 0;
215 : bool m_editing = false;
216 : bool m_visible = false;
217 : };
218 :
219 : //---------------------------------------------------------
220 : // TextFragment
221 : // contains a styled text
222 : //---------------------------------------------------------
223 :
224 : class TextFragment
225 : {
226 : public:
227 : muse::GlobalInject<IEngravingFontsProvider> engravingFonts;
228 :
229 : public:
230 : mutable CharFormat format;
231 : PointF pos; // y is relative to TextBlock->y()
232 : mutable String text;
233 :
234 5687 : TextFragment() = default;
235 : TextFragment(const String& s);
236 : TextFragment(TextCursor*, const String&);
237 : TextFragment(const TextFragment& f);
238 :
239 : TextFragment& operator =(const TextFragment& f);
240 :
241 : bool operator ==(const TextFragment& f) const;
242 :
243 : TextFragment split(int column);
244 : muse::draw::Font font(const TextBase*) const;
245 : double calculatedFontSize(const TextBase*) const;
246 : int columns() const;
247 : void changeFormat(FormatId id, const FormatValue& data);
248 :
249 : private:
250 : void resolveFallback(muse::draw::Font::Type fontType, const muse::draw::FontMetrics& fm, String& family) const;
251 : };
252 :
253 : //---------------------------------------------------------
254 : // TextBlock
255 : // represents a block of formatted text
256 : //---------------------------------------------------------
257 :
258 : class TextBlock
259 : {
260 : public:
261 43445 : TextBlock() = default;
262 :
263 : bool operator ==(const TextBlock& x) const { return m_fragments == x.m_fragments; }
264 : bool operator !=(const TextBlock& x) const { return m_fragments != x.m_fragments; }
265 :
266 148443 : const std::list<TextFragment>& fragments() const { return m_fragments; }
267 140853 : std::list<TextFragment>& fragments() { return m_fragments; }
268 : std::list<TextFragment> fragmentsWithoutEmpty();
269 : const Shape& shape() const { return m_shape; }
270 202197 : Shape& shape() { return m_shape; }
271 202827 : const RectF& boundingRect() const { return m_shape.bbox(); }
272 : RectF boundingRect(int col1, int col2, const TextBase*) const;
273 : size_t columns() const;
274 : void insert(TextCursor*, const String&);
275 : void insertEmptyFragmentIfNeeded(TextCursor*);
276 : void removeEmptyFragment();
277 : String remove(int column, TextCursor*);
278 : String remove(int start, int n, TextCursor*);
279 : int column(double x, TextBase*) const;
280 : TextBlock split(int column, TextCursor* cursor);
281 : double xpos(size_t col, const TextBase*) const;
282 : const CharFormat* formatAt(int) const;
283 : const TextFragment* fragment(int col) const;
284 : std::list<TextFragment>::iterator fragment(int column, int* rcol, int* ridx);
285 191147 : double y() const { return m_y; }
286 134798 : void setY(double val) { m_y = val; }
287 117889 : double lineSpacing() const { return m_lineSpacing; }
288 67399 : void setLineSpacing(double val) { m_lineSpacing = val; }
289 : String text(int, int, const TextBase*, bool = false) const;
290 43918 : bool eol() const { return m_eol; }
291 294 : void setEol(bool val) { m_eol = val; }
292 : void changeFormat(FormatId, const FormatValue& val, int start, int n);
293 :
294 : private:
295 : void simplify();
296 :
297 : std::list<TextFragment> m_fragments;
298 : double m_y = 0.0;
299 : double m_lineSpacing = 0.0;
300 : Shape m_shape;
301 : bool m_eol = false;
302 : };
303 :
304 : //---------------------------------------------------------
305 : // TextBase
306 : //---------------------------------------------------------
307 :
308 : class TextBase : public EngravingItem
309 : {
310 66 : OBJECT_ALLOCATOR(engraving, TextBase)
311 :
312 4328 : M_PROPERTY2(bool, isTextLinkedToMaster, setTextLinkedToMaster, true)
313 :
314 : public:
315 :
316 : ~TextBase();
317 :
318 : Text& operator=(const Text&) = delete;
319 :
320 214312 : Align align() const { return m_align; }
321 58962 : void setAlign(Align a) { m_align = a; }
322 79081 : AlignH position() const { return m_position; }
323 56046 : void setPosition(AlignH val) { m_position = val; }
324 :
325 1326 : static String plainToXmlText(const String& s) { return s.toXmlEscaped(); }
326 1326 : void setPlainText(const String& t) { setXmlText(plainToXmlText(t)); }
327 : virtual void setXmlText(const String&);
328 143 : void setXmlText(const char* str) { setXmlText(String::fromUtf8(str)); }
329 : void checkCustomFormatting(const String&);
330 : String xmlText() const;
331 : String plainText() const;
332 : void resetFormatting();
333 :
334 : void insertText(const String&);
335 :
336 : double lineSpacing() const;
337 : double lineHeight() const;
338 : virtual double baseLine() const override;
339 :
340 15307 : bool empty() const { return xmlText().isEmpty(); }
341 : void clear() { setXmlText(String()); }
342 :
343 : virtual FontStyle fontStyle() const;
344 : virtual String family() const;
345 : virtual double size() const;
346 :
347 : virtual void setFontStyle(const FontStyle& val);
348 : virtual void setFamily(const String& val);
349 : virtual void setSize(const double& val);
350 :
351 2326 : bool anchorToEndOfPrevious() const { return m_anchorToEndOfPrevious; }
352 1 : void setAnchorToEndOfPrevious(bool v) { m_anchorToEndOfPrevious = v; }
353 :
354 4157 : bool hasParentSegment() const { return ownershipParent() && parent()->isSegment(); }
355 59 : virtual bool allowTimeAnchor() const override { return hasParentSegment(); }
356 : virtual void startEdit(EditData&) override;
357 : virtual bool isEditAllowed(EditData&) const override;
358 : virtual bool edit(EditData&) override;
359 : virtual void editCut(EditData&) override;
360 : virtual void editCopy(EditData&) override;
361 : virtual void endEdit(EditData&) override;
362 : virtual RectF drag(EditData&) override;
363 : virtual void endDrag(EditData&) override;
364 : void movePosition(TextCursor::MoveOperation);
365 :
366 : bool mousePress(EditData& ed);
367 : void dragTo(EditData& ed);
368 :
369 : bool deleteSelectedText();
370 :
371 : void selectAll();
372 : void select(SelectTextType);
373 : bool isPrimed() const { return m_primed; }
374 0 : void setPrimed(bool primed) { m_primed = primed; }
375 :
376 : virtual void paste(const String& txt);
377 :
378 : RectF pageRectangle() const;
379 :
380 4330 : const Shape& highResShape() const { return ldata()->highResShape.value(); }
381 :
382 : std::vector<LineF> dragAnchorLines() const override;
383 :
384 : virtual bool acceptDrop(EditData&) const override;
385 : virtual EngravingItem* drop(Transaction& tx, EditData&) override;
386 :
387 : friend class TextBlock;
388 : friend class TextFragment;
389 :
390 : static String unEscape(String s);
391 : static String escape(String s);
392 :
393 : String accessibleInfo() const override;
394 : String screenReaderInfo() const override;
395 :
396 : int subtype() const override;
397 : TranslatableString subtypeUserName() const override;
398 :
399 : std::list<TextFragment> fragmentList() const; // for MusicXML formatted export
400 :
401 : static bool validateText(String& s);
402 : bool inHexState() const { return m_hexState >= 0; }
403 : void endHexState();
404 :
405 : muse::draw::Font font() const;
406 : muse::draw::FontMetrics fontMetrics() const;
407 :
408 : bool isPropertyLinkedToMaster(Pid id) const override;
409 : bool isUnlinkedFromMaster() const override;
410 : PropertyValue getProperty(Pid propertyId) const override;
411 : bool setProperty(Pid propertyId, const PropertyValue& v) override;
412 : PropertyValue propertyDefault(Pid id) const override;
413 : void undoChangeProperty(Pid id, const PropertyValue& v, PropertyFlags ps) override;
414 : Sid getPropertyStyle(Pid) const override;
415 : void styleChanged() override;
416 : void editInsertText(TextCursor*, const String&);
417 :
418 168619 : TextCursor* cursor() const { return m_cursor; }
419 :
420 31758 : void setTextInvalid() { m_textInvalid = true; }
421 : bool isTextInvalid() const { return m_textInvalid; }
422 :
423 : // helper functions
424 86068 : bool hasFrame() const { return m_frameType != FrameType::NO_FRAME; }
425 19 : bool circle() const { return m_frameType == FrameType::CIRCLE; }
426 144 : bool rectangle() const { return m_frameType == FrameType::RECTANGLE; }
427 :
428 596379 : TextStyleType textStyleType() const { return m_textStyleType; }
429 18353 : void setTextStyleType(TextStyleType id) { m_textStyleType = id; }
430 : void initTextStyleType(TextStyleType id);
431 : void initTextStyleType(TextStyleType id, bool preserveDifferent);
432 : virtual void initElementStyle(const ElementStyle*) override;
433 :
434 : static const String UNDEFINED_FONT_FAMILY;
435 : static const double UNDEFINED_FONT_SIZE;
436 :
437 : static bool isSorted(size_t r1, size_t c1, size_t r2, size_t c2);
438 : static void sort(size_t& r1, size_t& c1, size_t& r2, size_t& c2);
439 :
440 27173 : bool bold() const { return fontStyle() & FontStyle::Bold; }
441 27173 : bool italic() const { return fontStyle() & FontStyle::Italic; }
442 27173 : bool underline() const { return fontStyle() & FontStyle::Underline; }
443 27173 : bool strike() const { return fontStyle() & FontStyle::Strike; }
444 6 : void setBold(bool val) { setFontStyle(val ? fontStyle() + FontStyle::Bold : fontStyle() - FontStyle::Bold); }
445 8 : void setItalic(bool val) { setFontStyle(val ? fontStyle() + FontStyle::Italic : fontStyle() - FontStyle::Italic); }
446 0 : void setUnderline(bool val)
447 : {
448 0 : setFontStyle(val ? fontStyle() + FontStyle::Underline : fontStyle() - FontStyle::Underline);
449 0 : }
450 :
451 0 : void setStrike(bool val)
452 : {
453 0 : setFontStyle(val ? fontStyle() + FontStyle::Strike : fontStyle() - FontStyle::Strike);
454 0 : }
455 :
456 : bool hasCustomFormatting() const;
457 :
458 : friend class TextCursor;
459 : using EngravingObject::undoChangeProperty;
460 :
461 : Color textColor(const rendering::PaintOptions& opt) const;
462 18497 : FrameType frameType() const { return m_frameType; }
463 42112 : void setFrameType(FrameType val) { m_frameType = val; }
464 67975 : double textLineSpacing() const { return m_textLineSpacing; }
465 42039 : void setTextLineSpacing(double val) { m_textLineSpacing = val; }
466 475 : Color bgColor() const { return m_bgColor; }
467 42039 : void setBgColor(const Color& val) { m_bgColor = val; }
468 42533 : Color frameColor() const { return m_frameColor; }
469 84094 : void setFrameColor(const Color& val) { m_frameColor = val; }
470 763 : Spatium frameWidth() const { return m_frameWidth; }
471 42039 : void setFrameWidth(Spatium val) { m_frameWidth = val; }
472 619 : Spatium paddingWidth() const { return m_paddingWidth; }
473 42039 : void setPaddingWidth(Spatium val) { m_paddingWidth = val; }
474 475 : Spatium frameRound() const { return m_frameRound; }
475 42040 : void setFrameRound(Spatium val) { m_frameRound = val; }
476 :
477 : struct LayoutData : public EngravingItem::LayoutData {
478 : std::vector<TextBlock> blocks;
479 : bool layoutInvalid = true;
480 :
481 : RectF frame;
482 :
483 33292 : size_t rows() const { return blocks.size(); }
484 1705 : const TextBlock& textBlock(size_t i) const { return blocks.at(i); }
485 0 : TextBlock& textBlock(size_t i) { return blocks[i]; }
486 :
487 : ld_field<Shape> highResShape = { "[TextBase] highResShape", Shape() };
488 : };
489 1884401 : DECLARE_LAYOUTDATA_METHODS(TextBase)
490 :
491 : void createBlocks();
492 : void createBlocks(LayoutData* ldata) const;
493 : void layoutFrame();
494 : void layoutFrame(LayoutData* ldata) const;
495 :
496 : //! NOTE It can only be set for some types of text, see who has the setter.
497 : //! At the moment it's: Text, Jump, Marker
498 211301 : bool layoutToParentWidth() const { return m_layoutToParentWidth; }
499 :
500 : virtual bool positionRelativeToNoteheadRest() const = 0;
501 :
502 73 : void setVoiceAssignment(VoiceAssignment v) { m_voiceAssignment = v; }
503 2493 : VoiceAssignment voiceAssignment() const { return m_voiceAssignment; }
504 149 : void setDirection(DirectionV v) { m_direction = v; }
505 1895 : DirectionV direction() const { return m_direction; }
506 52 : void setCenterBetweenStaves(AutoOnOff v) { m_centerBetweenStaves = v; }
507 2814 : AutoOnOff centerBetweenStaves() const { return m_centerBetweenStaves; }
508 : void genText();
509 :
510 4264 : double symbolSize() const { return m_symbolSize; }
511 46692 : void setSymbolSize(double v) { m_symbolSize = v; }
512 :
513 7498 : double symbolScale() const { return m_symbolScale; }
514 44557 : void setSymbolScale(double v) { m_symbolScale = v; }
515 :
516 : bool hasSymbolScale() const;
517 3789 : bool hasSymbolSize() const { return !hasSymbolScale(); }
518 :
519 : double spatiumScaling() const;
520 :
521 66841 : double textAngle() const { return m_textAngle; }
522 0 : void setTextAngle(double v) { m_textAngle = v; }
523 :
524 : PointF defaultPos() const override;
525 :
526 : protected:
527 : TextBase(const ElementType& type, EngravingObject* parent = 0, TextStyleType tid = TextStyleType::DEFAULT,
528 397 : ElementFlags = ElementFlag::NOTHING);
529 : TextBase(const ElementType& type, EngravingObject* parent, ElementFlags);
530 : TextBase(const TextBase&);
531 :
532 : bool nudge(const EditData& ed);
533 :
534 : void insertSym(SymId id);
535 : void prepareFormat(const String& token, TextCursor& cursor);
536 : bool prepareFormat(const String& token, CharFormat& format);
537 :
538 : virtual void commitText();
539 :
540 : bool textWasEdited(EditData& ed) const;
541 :
542 : bool m_layoutToParentWidth = false;
543 :
544 : private:
545 : void insert(TextCursor*, char32_t code, LayoutData* ldata) const;
546 : String genText(const LayoutData* ldata) const;
547 :
548 : virtual int getPropertyFlagsIdx(Pid id) const override;
549 : String stripText(bool, bool, bool) const;
550 :
551 : static String getHtmlStartTag(double, double&, const String&, String&, FontStyle, VerticalAlignment);
552 : static String getHtmlEndTag(FontStyle, VerticalAlignment);
553 :
554 : static void swap(size_t& r1, size_t& c1, size_t& r2, size_t& c2);
555 :
556 : Sid defaultPosSid() const override;
557 :
558 : #ifndef ENGRAVING_NO_ACCESSIBILITY
559 : AccessibleItemPtr createAccessible() override;
560 : #endif
561 :
562 : void notifyAboutTextCursorChanged();
563 : void notifyAboutTextInserted(int startPosition, int endPosition, const String& text);
564 : void notifyAboutTextRemoved(int startPosition, int endPosition, const String& text);
565 :
566 : Align m_align;
567 :
568 : AlignH m_position = AlignH::LEFT;
569 :
570 : FrameType m_frameType = FrameType::NO_FRAME;
571 : double m_textLineSpacing = 1.0;
572 : Color m_bgColor;
573 : Color m_frameColor;
574 : Spatium m_frameWidth;
575 : Spatium m_paddingWidth;
576 : Spatium m_frameRound;
577 :
578 : // there are two representations of text; only one
579 : // might be valid and the other can be constructed from it
580 :
581 : String m_text; // cached
582 : bool m_textInvalid = true;
583 :
584 : TextStyleType m_textStyleType = TextStyleType::DEFAULT; // text style id
585 :
586 : int m_hexState = -1;
587 : bool m_primed = 0;
588 :
589 : double m_symbolSize = 18.0;
590 : double m_symbolScale = 1.0;
591 :
592 : TextCursor* m_cursor = nullptr;
593 :
594 : VoiceAssignment m_voiceAssignment = VoiceAssignment::ALL_VOICE_IN_INSTRUMENT;
595 : DirectionV m_direction = DirectionV::AUTO;
596 : AutoOnOff m_centerBetweenStaves = AutoOnOff::AUTO;
597 : bool m_anchorToEndOfPrevious = false;
598 :
599 : double m_textAngle = 0.0;
600 : };
601 :
602 0 : inline bool isTextNavigationKey(int key, KeyboardModifiers modifiers)
603 : {
604 : // space + TextEditingControlModifier = insert nonbreaking space, so that's *not* a navigation key
605 0 : return (key == Key_Space && modifiers != TextEditingControlModifier) || key == Key_Tab;
606 : }
607 : } // namespace mu::engraving
|