1import QtQuick 2.7 2import QtQuick.Controls 1.4 3import QtQuick.Controls.Styles 1.4 4import QtQuick.Layouts 1.2 5import QtQuick.Window 2.1 6import QtQuick.Dialogs 1.2 7import radiance 1.0 8import "." 9 10ApplicationWindow { 11 id: window 12 title: "GLSL Editor" 13 property string file 14 property var afterSave 15 property int line 16 property int col 17 signal saved() 18 19 menuBar: MenuBar { 20 Menu { 21 title: "&File" 22 MenuItem { 23 action: newAction 24 } 25 MenuItem { 26 action: openAction 27 } 28 MenuItem { 29 action: saveAction 30 } 31 MenuItem { 32 action: saveAsAction 33 } 34 MenuSeparator { } 35 MenuItem { 36 action: revertAction 37 } 38 MenuSeparator { } 39 MenuItem { 40 action: closeAction 41 } 42 } 43 } 44 45 statusBar: StatusBar { 46 RowLayout { 47 Label { text: glslDocument.message } 48 } 49 } 50 51 Action { 52 id: newAction 53 text: "&New..." 54 shortcut: "Ctrl+N" 55 onTriggered: { 56 tryClear(); 57 } 58 } 59 60 Action { 61 id: openAction 62 text: "&Open..." 63 shortcut: "Ctrl+O" 64 onTriggered: { 65 showOpenDialog(); 66 } 67 } 68 69 Action { 70 id: saveAction 71 text: "&Save" 72 shortcut: "Ctrl+S" 73 onTriggered: { 74 if (window.file) { 75 save(); 76 } else { 77 showSaveDialog(); 78 } 79 } 80 } 81 82 Action { 83 id: saveAsAction 84 text: "Save &As..." 85 onTriggered: { 86 showSaveDialog(); 87 } 88 } 89 90 Action { 91 id: revertAction 92 text: "Revert" 93 shortcut: "Ctrl+R" 94 onTriggered: { 95 revert(); 96 } 97 } 98 99 Action { 100 id: closeAction 101 text: "E&xit" 102 shortcut: "Ctrl+Q" 103 onTriggered: { 104 tryClose() 105 } 106 } 107 108 onClosing: { 109 closeAction.trigger(); 110 close.accepted = false; 111 } 112 113 function urlToPath(url) { 114 var path = url.toString(); 115 // remove prefixed "file://" 116 path = path.replace(/^(file:\/{2})/,""); 117 return path; 118 } 119 120 function showOpenDialog() { 121 openDialog.folder = glslDocument.loadDirectory(window.file); 122 openDialog.open(); 123 } 124 125 function showSaveDialog() { 126 saveAsDialog.folder = glslDocument.saveDirectory(window.file); 127 saveAsDialog.open(); 128 } 129 130 FileDialog { 131 id: saveAsDialog 132 title: "Save As" 133 selectExisting: false 134 nameFilters: [ "GLSL files (*.glsl)", "All files (*)" ] 135 onAccepted: { 136 var path = urlToPath(saveAsDialog.fileUrl); 137 if (path) { 138 window.file = glslDocument.contractLibraryPath(path); 139 save(); 140 } 141 afterSave = null; 142 } 143 onRejected: { 144 afterSave = null; 145 } 146 } 147 148 FileDialog { 149 id: openDialog 150 title: "Open" 151 nameFilters: [ "GLSL files (*.glsl)", "All files (*)" ] 152 onAccepted: { 153 var path = urlToPath(openDialog.fileUrl); 154 if (path) { 155 window.file = glslDocument.contractLibraryPath(path); 156 load(); 157 } 158 } 159 onRejected: { 160 } 161 } 162 163 MessageDialog { 164 id: saveChangesBeforeClose 165 title: "Save changes?" 166 icon: StandardIcon.Question 167 text: window.file ? "Save changes to \"" + window.file + "\" before closing?" : "Save changes before closing?" 168 standardButtons: StandardButton.Discard | StandardButton.Cancel | StandardButton.Save 169 onDiscard: { 170 window.close(); 171 } 172 onAccepted: { 173 afterSave = window.close; 174 saveAction.trigger(); 175 } 176 } 177 178 MessageDialog { 179 id: saveChangesBeforeClear 180 title: "Save changes?" 181 icon: StandardIcon.Question 182 text: window.file ? "Save changes to \"" + window.file + "\" before clearing?" : "Save changes before clearing?" 183 standardButtons: StandardButton.Discard | StandardButton.Cancel | StandardButton.Save 184 onDiscard: { 185 window.clear(); 186 } 187 onAccepted: { 188 afterSave = window.clear; 189 saveAction.trigger(); 190 } 191 } 192 193 TextArea { 194 id: textArea 195 anchors.top: parent.top 196 anchors.bottom: parent.bottom 197 anchors.left: parent.left 198 anchors.right: parent.right 199 textFormat: Qt.RichText 200 Component.onCompleted: forceActiveFocus() 201 font.family: "Monospace" 202 style: TextAreaStyle { 203 textColor: RadianceStyle.editorTextColor 204 backgroundColor: RadianceStyle.editorBackgroundColor 205 } 206 frameVisible: false 207 wrapMode: TextEdit.NoWrap 208 209 Keys.onPressed: { 210 if (event.key == Qt.Key_Tab) { 211 textArea.remove(textArea.selectionStart, textArea.selectionEnd); 212 textArea.insert(textArea.cursorPosition, " "); 213 event.accepted = true; 214 } 215 } 216 } 217 218 GlslDocument { 219 id: glslDocument 220 document: textArea.textDocument 221 } 222 223 GlslHighlighter { 224 document: textArea.textDocument 225 } 226 227 function load() { 228 if (glslDocument.load(window.file)) { 229 setCursor(); 230 } 231 } 232 233 function setCursor() { 234 var pos = glslDocument.cursorPositionAt(line, col); 235 textArea.cursorPosition = pos; 236 } 237 238 function save() { 239 if (glslDocument.save(window.file)) { 240 window.saved(); 241 if (afterSave) { 242 afterSave(); 243 } 244 } 245 afterSave = null; 246 } 247 248 function close() { 249 window.visible = false; 250 } 251 252 function clear() { 253 window.file = "" 254 glslDocument.clear(); 255 } 256 257 function open(file) { 258 if (window.visible && file == window.file) { 259 setCursor(); 260 } else { 261 window.file = file; 262 if (window.file) { 263 load(); 264 } 265 window.visible = true; 266 } 267 window.afterSave = null; 268 } 269 270 function tryClear() { 271 if (glslDocument.modified) { 272 saveChangesBeforeClear.open(); 273 } else { 274 clear(); 275 } 276 } 277 278 function tryClose() { 279 if (glslDocument.modified) { 280 saveChangesBeforeClose.open(); 281 } else { 282 close(); 283 } 284 } 285 286 function revert() { 287 glslDocument.revert(window.file); 288 saved(); // Not actually but effectively 289 } 290} 291