Vuo  2.4.0
VuoTextEditor.cc
Go to the documentation of this file.
1
10#include "VuoTextEditor.hh"
11
12extern "C"
13{
14 #include "VuoText.h"
15}
16
22{
23 textEdit = NULL;
24 isCodeEditor = false;
25}
26
31void VuoTextEditor::setUpDialog(QDialog &dialog, json_object *originalValue, json_object *details)
32{
33 isCodeEditor = getCodeEditor(details);
34 textEdit = new QPlainTextEdit(&dialog);
35
36 textEdit->setPlainText( convertToTextEditFormat(originalValue) );
37 textEdit->setFocus();
38
39 if (isCodeEditor)
40 {
41 textEdit->setStyleSheet(textEdit->styleSheet() + "QPlainTextEdit { font-family: Monaco; font-size: 10pt; } ");
42 }
43 else
44 {
45 textEdit->setTabChangesFocus(true);
48 }
49
50 resizeToFitText(); // Although the height may be adjusted later, the width needs to be set now so the dialog's position can be calculated.
51 connect(textEdit, &QPlainTextEdit::textChanged, this, &VuoTextEditor::resizeToFitText);
52
53 textEdit->setAcceptDrops(true);
54 textEdit->installEventFilter(this);
55 textEdit->viewport()->installEventFilter(this);
56}
57
62{
63 return convertFromTextEditFormat(textEdit->toPlainText());
64}
65
70{
71 return VuoText_makeFromJson(value);
72}
73
78{
79 return VuoText_getJson( valueAsString.toUtf8().constData() );
80}
81
86{
88}
89
96void VuoTextEditor::resizeToFitTextWithBaseline(int baselineWidth, int baselineHeight)
97{
98 int scrollbarWidth = 15; // textEdit->verticalScrollBar()->width() returns the wrong value the first couple times it's called…
99 int textEditWidth = ((baselineWidth > 0)? baselineWidth : (isCodeEditor ? 600 : 270)) - scrollbarWidth;
100
101 QTextDocument *document = textEdit->document();
102 qreal margin = document->documentMargin() + textEdit->frameWidth();
103
104 // Enforce positive text widths.
105 if (textEditWidth-2*margin-scrollbarWidth <= 0)
106 textEditWidth -= (textEditWidth-2*margin-scrollbarWidth);
107
108 int textWidth = textEditWidth - 2*margin;
109 document->setTextWidth(textWidth);
110 QFontMetrics fm(textEdit->font());
111 int textHeight = document->lineCount() * (fm.lineSpacing() + 1);
112 int textEditHeight = textHeight + 2*margin;
113
114 QRect screenRect = QApplication::desktop()->availableGeometry(textEdit);
115 QRect textEditRect(textEdit->mapToGlobal(textEdit->pos()), QSize(textEditWidth, textEditHeight));
116 QRect textEditInScreenRect = textEditRect.intersected(screenRect);
117 int minTextEditHeight = fm.lineSpacing() + 2*margin;
118 minTextEditHeight = max(minTextEditHeight, baselineHeight);
119 textEditHeight = qMax(textEditInScreenRect.height(), minTextEditHeight);
120
121 textEdit->viewport()->setFixedSize(textEditWidth, textEditHeight - 1);
122 textEdit->setFixedSize(textEditWidth + scrollbarWidth, textEditHeight + 3);
123 getDialog()->setFixedSize(getDialog()->sizeHint()); // adjustSize() limits to 2/3 of the screen's size (https://doc.qt.io/qt-5/qwidget.html#adjustSize)
124
125 textEdit->ensureCursorVisible();
126}
127
131bool VuoTextEditor::eventFilter(QObject *object, QEvent *event)
132{
133 // Handle the first part of drag-and-drop events.
134 // If the intercepted event is a drag-and-drop-related event destined for
135 // the text edit, re-route it to the input editor itself so that it may be
136 // intercepted by the window filtering input editor events.
137 // The window has access to more of the information (e.g., the
138 // composition storage directory) necessary to usefully handle the event.
139 if ((object == textEdit &&
140 (event->type() == QEvent::DragEnter ||
141 event->type() == QEvent::DragMove ||
142 event->type() == QEvent::DragLeave)) ||
143 (object == textEdit->viewport() &&
144 (event->type() == QEvent::Drop))) // drop events go to the viewport (https://bugreports.qt.io/browse/QTBUG-3748)
145 {
146 QApplication::sendEvent(this, event);
147 return true;
148 }
149
150 // Handle Return and Option-Return key presses.
151 // For regular text editors, this makes Return dismiss the input editor and Option-Return add a linebreak.
152 // For code editors, this makes Return (or Option-Return) add a linebreak and Command-Return dismiss the input editor.
153 if (object == textEdit && event->type() == QEvent::KeyPress)
154 {
155 QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
156 if (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter)
157 {
158 bool optionKeyPressed = (keyEvent->modifiers() & Qt::AltModifier);
159 bool commandKeyPressed = (keyEvent->modifiers() & Qt::ControlModifier);
160 bool shouldInsertLinebreak = (isCodeEditor ?
161 ! commandKeyPressed :
162 optionKeyPressed);
163 if (shouldInsertLinebreak)
164 textEdit->textCursor().insertText("\n");
165 else
166 QApplication::sendEvent(textEdit->parent(), event);
167 return true;
168 }
169 }
170
171 // When the input editor is shown, perform some final setup.
172 if (object == textEdit && event->type() == QEvent::Show)
173 {
174 // Set the tab width, which couldn't be done in setUpDialog() since textEdit->font() wasn't yet ready.
175 int spacesPerTab = 4;
176 QFontMetricsF fontMetrics(textEdit->font());
177 textEdit->setTabStopDistance(spacesPerTab * fontMetrics.horizontalAdvance(' '));
178
179 // Resize the input editor if needed so that its height fits within the screen.
181
182 if (textEdit->document()->lineCount() > 1)
183 {
184 // For multi-line text editors, set the cursor at the beginning and scroll to top.
185 textEdit->moveCursor(QTextCursor::Start);
186 textEdit->ensureCursorVisible();
187 }
188 else
189 {
190 // For one-line text editors, set the cursor at the end and select all.
191 textEdit->selectAll();
192 }
193
194 return false;
195 }
196
198}
199
203bool VuoTextEditor::event(QEvent *event)
204{
205 if (event->type() == QEvent::Drop)
206 {
207 // Handle the second part of drag-and-drop events.
208
209 // This input editor will receive drop events originally intended for
210 // the text edit, re-routed to allow the dropped data to be modified by
211 // the window filtering events on the input editor, and then passed back
212 // to the input editor. Here, we forward the modified drop event
213 // to the text edit for which it was originally intended.
214
215 // But first: If the text edit's full text was selected at the time
216 // of the drop, delete the old text before inserting the new text.
217 QTextCursor cursor = textEdit->textCursor();
218 if (cursor.selectionStart() == 0 && cursor.selectionEnd() == textEdit->toPlainText().length())
219 textEdit->setPlainText("");
220
221 textEdit->viewport()->removeEventFilter(this);
222 QApplication::sendEvent(textEdit, event);
223 textEdit->viewport()->installEventFilter(this);
224
225 return true;
226 }
227
228 return VuoInputEditorWithDialog::event(event);
229}
230
236{
237 if (details)
238 {
239 json_object *o = NULL;
240 if (json_object_object_get_ex(details, "isCodeEditor", &o))
241 return json_object_get_boolean(o);
242 }
243 return false;
244}
245
250{
251 return true;
252}