| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  | // SPDX-License-Identifier: LGPL-3.0-or-later
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import QtQuick 2.12 | 
					
						
							|  |  |  | import QtQuick.Controls 2.12 | 
					
						
							| 
									
										
										
										
											2020-07-15 15:10:34 -04:00
										 |  |  | import Clipboard 0.1 | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | TextArea { | 
					
						
							|  |  |  |     id: textArea | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     property string saveName: "" | 
					
						
							|  |  |  |     property var saveId: "ALL" | 
					
						
							|  |  |  |     property var saveProperties: ["text"] | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-06 21:54:13 -04:00
										 |  |  |     property bool error: false | 
					
						
							|  |  |  |     property alias radius: textAreaBackground.radius | 
					
						
							|  |  |  |     property bool bordered: true | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  |     property var focusItemOnTab: null | 
					
						
							| 
									
										
										
										
											2020-07-20 12:40:38 -04:00
										 |  |  |     property bool menuKeySpawnsMenu: true | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  |     property var disabledText: null | 
					
						
							| 
									
										
										
										
											2020-07-01 12:10:40 -04:00
										 |  |  |     property var defaultText: null  // XXX test me
 | 
					
						
							|  |  |  |     readonly property bool changed: text !== (defaultText || "") | 
					
						
							| 
									
										
										
										
											2020-08-22 01:47:53 -04:00
										 |  |  |     readonly property string displayText: text + preeditText | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     property alias backgroundColor: textAreaBackground.color | 
					
						
							| 
									
										
										
										
											2020-06-06 21:54:13 -04:00
										 |  |  |     property color borderColor: theme.controls.textArea.border | 
					
						
							|  |  |  |     property color errorBorder: theme.controls.textArea.errorBorder | 
					
						
							|  |  |  |     property color focusedBorderColor: theme.controls.textArea.focusedBorder | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-25 09:46:26 -04:00
										 |  |  |     property string previousDefaultText: ""  // private
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-15 15:10:34 -04:00
										 |  |  |     property bool enableCustomImagePaste: false | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     signal customImagePaste() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-21 04:44:55 -04:00
										 |  |  |     function reset() { | 
					
						
							|  |  |  |         clear() | 
					
						
							|  |  |  |         text = Qt.binding(() => defaultText || "") | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function insertAtCursor(text) { | 
					
						
							|  |  |  |         insert(cursorPosition, text) | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function getWordAt(position) { | 
					
						
							| 
									
										
										
										
											2020-08-22 01:47:53 -04:00
										 |  |  |         return utils.getWordAtPosition(displayText, position) | 
					
						
							| 
									
										
										
										
											2020-08-21 04:44:55 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     function getWordBehindCursor() { | 
					
						
							|  |  |  |         return cursorPosition === 0 ? null : getWordAt(cursorPosition - 1) | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-01 12:10:40 -04:00
										 |  |  |     text: defaultText || "" | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  |     opacity: enabled ? 1 : theme.disabledElementsOpacity | 
					
						
							|  |  |  |     selectByMouse: true | 
					
						
							|  |  |  |     leftPadding: theme.spacing | 
					
						
							|  |  |  |     rightPadding: leftPadding | 
					
						
							|  |  |  |     topPadding: theme.spacing / 1.5 | 
					
						
							|  |  |  |     bottomPadding: topPadding | 
					
						
							|  |  |  |     readOnly: ! visible | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     wrapMode: TextEdit.Wrap | 
					
						
							|  |  |  |     font.family: theme.fontFamily.sans | 
					
						
							|  |  |  |     font.pixelSize: theme.fontSize.normal | 
					
						
							|  |  |  |     font.pointSize: -1 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     placeholderTextColor: theme.controls.textArea.placeholderText | 
					
						
							|  |  |  |     color: theme.controls.textArea.text | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     background: Rectangle { | 
					
						
							|  |  |  |         id: textAreaBackground | 
					
						
							|  |  |  |         radius: theme.radius | 
					
						
							| 
									
										
										
										
											2020-06-06 21:54:13 -04:00
										 |  |  |         color: theme.controls.textArea.background | 
					
						
							| 
									
										
										
										
											2020-07-17 05:29:25 -04:00
										 |  |  |         opacity: textArea.opacity | 
					
						
							| 
									
										
										
										
											2020-06-06 21:54:13 -04:00
										 |  |  | 
 | 
					
						
							|  |  |  |         border.width: bordered ? theme.controls.textArea.borderWidth : 0 | 
					
						
							|  |  |  |         border.color: borderColor | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-23 08:44:58 -04:00
										 |  |  |         HBottomFocusLine { | 
					
						
							|  |  |  |             show: textArea.activeFocus | 
					
						
							| 
									
										
										
										
											2020-06-06 21:54:13 -04:00
										 |  |  |             borderHeight: theme.controls.textArea.borderWidth | 
					
						
							|  |  |  |             color: error ? errorBorder : focusedBorderColor | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-25 09:46:26 -04:00
										 |  |  |     Component.onCompleted: { | 
					
						
							|  |  |  |         // Break binding
 | 
					
						
							|  |  |  |         previousDefaultText = previousDefaultText | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-25 09:46:26 -04:00
										 |  |  |         // Set it only on component creation to avoid binding loops
 | 
					
						
							|  |  |  |         if (! text) { | 
					
						
							|  |  |  |             text           = window.getState(this, "text", "") | 
					
						
							|  |  |  |             cursorPosition = text.length | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-06-03 03:41:30 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  |     onTextChanged: window.saveState(this) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-01 12:10:40 -04:00
										 |  |  |     onActiveFocusChanged: | 
					
						
							|  |  |  |         if (defaultText !== null) text = text  // Break binding
 | 
					
						
							| 
									
										
										
										
											2020-06-25 09:46:26 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-01 12:10:40 -04:00
										 |  |  |     onDefaultTextChanged: if (defaultText !== null) { | 
					
						
							| 
									
										
										
										
											2020-06-25 09:46:26 -04:00
										 |  |  |         if (text === previousDefaultText) | 
					
						
							|  |  |  |             text = Qt.binding(() => defaultText) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         previousDefaultText = defaultText | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-08-23 15:41:20 -04:00
										 |  |  |     onPressed: ev => { if (ev.button === Qt.RightButton) contextMenu.spawn() } | 
					
						
							|  |  |  |     onPressAndHold: ev => contextMenu.spawn() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-15 15:10:34 -04:00
										 |  |  |     Keys.onPressed: ev => { | 
					
						
							|  |  |  |         // Prevent alt/super+any key from typing text
 | 
					
						
							|  |  |  |         if ( | 
					
						
							|  |  |  |             ev.modifiers & Qt.AltModifier || | 
					
						
							|  |  |  |             ev.modifiers & Qt.MetaModifier | 
					
						
							|  |  |  |         ) ev.accepted = true | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         if ( | 
					
						
							|  |  |  |             ev.matches(StandardKey.Paste) && | 
					
						
							|  |  |  |             textArea.enableCustomImagePaste && | 
					
						
							|  |  |  |             Clipboard.hasImage | 
					
						
							|  |  |  |         ) { | 
					
						
							|  |  |  |             ev.accepted = true | 
					
						
							|  |  |  |             textArea.customImagePaste() | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-20 12:40:38 -04:00
										 |  |  |     Keys.onMenuPressed: if (menuKeySpawnsMenu) contextMenu.spawn(false) | 
					
						
							| 
									
										
										
										
											2020-07-10 00:02:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-06-23 06:17:52 -04:00
										 |  |  |     // Prevent leaking arrow presses to parent elements when the carret is at
 | 
					
						
							|  |  |  |     // the beginning or end of the text
 | 
					
						
							| 
									
										
										
										
											2020-07-11 16:10:21 -04:00
										 |  |  |     Keys.onLeftPressed: | 
					
						
							|  |  |  |         event.accepted = readOnly || (cursorPosition === 0 && ! selectedText) | 
					
						
							| 
									
										
										
										
											2020-07-07 10:03:35 -04:00
										 |  |  |     Keys.onRightPressed: | 
					
						
							| 
									
										
										
										
											2020-07-11 16:10:21 -04:00
										 |  |  |         event.accepted = | 
					
						
							|  |  |  |             readOnly || (cursorPosition === length && ! selectedText) | 
					
						
							| 
									
										
										
										
											2020-06-23 06:17:52 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  |     KeyNavigation.priority: KeyNavigation.BeforeItem | 
					
						
							|  |  |  |     KeyNavigation.tab: focusItemOnTab | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Binding on color { | 
					
						
							|  |  |  |         value: "transparent" | 
					
						
							|  |  |  |         when: disabledText !== null && ! textArea.enabled | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Binding on placeholderTextColor { | 
					
						
							|  |  |  |         value: "transparent" | 
					
						
							|  |  |  |         when: disabledText !== null && ! textArea.enabled | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Binding on implicitHeight { | 
					
						
							|  |  |  |         value: disabledTextLabel.implicitHeight | 
					
						
							|  |  |  |         when: disabledText !== null && ! textArea.enabled | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     Behavior on opacity { HNumberAnimation {} } | 
					
						
							|  |  |  |     Behavior on color { HColorAnimation {} } | 
					
						
							|  |  |  |     Behavior on placeholderTextColor { HColorAnimation {} } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     HLabel { | 
					
						
							|  |  |  |         id: disabledTextLabel | 
					
						
							|  |  |  |         anchors.fill: parent | 
					
						
							|  |  |  |         visible: opacity > 0 | 
					
						
							|  |  |  |         opacity: disabledText !== null && parent.enabled ? 0 : 1 | 
					
						
							|  |  |  |         text: disabledText || "" | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         leftPadding: parent.leftPadding | 
					
						
							|  |  |  |         rightPadding: parent.rightPadding | 
					
						
							|  |  |  |         topPadding: parent.topPadding | 
					
						
							|  |  |  |         bottomPadding: parent.bottomPadding | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         wrapMode: | 
					
						
							| 
									
										
										
										
											2020-07-17 01:45:02 -04:00
										 |  |  |             parent.wrapMode === TextEdit.Wrap ? HLabel.Wrap : | 
					
						
							|  |  |  |             parent.wrapMode === TextEdit.WordWrap ? HLabel.WordWrap : | 
					
						
							|  |  |  |             parent.wrapMode === TextEdit.WrapAnywhere ? HLabel.WrapAnywhere : | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  |             Text.NoWrap | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         font.family: parent.font.family | 
					
						
							|  |  |  |         font.pixelSize: parent.font.pixelSize | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Behavior on opacity { HNumberAnimation {} } | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-07-10 00:02:43 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-07-15 15:10:34 -04:00
										 |  |  |     HTextContextMenu { | 
					
						
							|  |  |  |         id: contextMenu | 
					
						
							|  |  |  |         enableCustomImagePaste: textArea.enableCustomImagePaste | 
					
						
							| 
									
										
										
										
											2020-09-02 13:41:31 -04:00
										 |  |  |         onCustomImagePaste: textArea.customImagePaste() | 
					
						
							| 
									
										
										
										
											2020-07-15 15:10:34 -04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-05-29 16:22:53 -04:00
										 |  |  | } |