1 module editor;
2 
3 import pngtext.pngtext;
4 
5 import utils.misc;
6 
7 import qui.qui;
8 import qui.widgets;
9 
10 import std.stdio;
11 
12 /// The in-terminal text editor using qui.widgets.MemoWidget
13 class Editor{
14 private:
15 	/// the terminal
16 	QTerminal _terminal;
17 	/// the text editor
18 	MemoWidget _editor;
19 	/// to occupy space on left of 
20 	SplitterWidget _statusBarLeft;
21 	/// shows the shortcut keys, sits next to _statusLabel
22 	TextLabelWidget _shortcutLabel;
23 	/// Contains the and _shortcutLabel
24 	QLayout _statusBar;
25 	/// filename of original png
26 	string _inputPng;
27 	/// filename of output png
28 	string _outputPng;
29 public:
30 	/// constructor
31 	/// 
32 	/// if text only has to be displayed, use readOnly=true, and no need to specify saveAs, just leave it blank
33 	this(string image, string saveAs, bool readOnly=false){
34 		_inputPng = image;
35 		_outputPng = saveAs;
36 		// setup the terminal
37 		_terminal = new QTerminal(QLayout.Type.Vertical);
38 		_statusBar = new QLayout(QLayout.Type.Horizontal);
39 		_editor = new MemoWidget(!readOnly);
40 		_statusBarLeft = new SplitterWidget();
41 		_shortcutLabel = new TextLabelWidget();
42 		// set up each widget
43 		// first comes the editor:
44 		_editor.wantsTab = false;
45 		_editor.lines.loadArray(separateLines(cast(char[])readDataFromPng(_inputPng)));//load the lines
46 		// now comes the _statusLabel
47 		// now the _shortcutLabel
48 		_shortcutLabel.textColor = DEFAULT_BG;
49 		_shortcutLabel.backgroundColor = DEFAULT_FG;
50 		_shortcutLabel.caption = "Ctrl+C - Save & Exit";
51 		_shortcutLabel.size.maxWidth = _shortcutLabel.caption.length;
52 		// put both of these in _statusBar, and set it up too
53 		_statusBar.addWidget([_statusBarLeft, _shortcutLabel]);
54 		_statusBar.size.maxHeight = 1;
55 		_statusBar.size.minHeight = 1;
56 		// put all those in QTerminal
57 		_terminal.addWidget([_editor, _statusBar]);
58 		// register all widgets
59 		_terminal.registerWidget([_editor, _statusBar, _statusBarLeft, _shortcutLabel]);
60 		// and its done, ready to start*/
61 	}
62 	/// destructor
63 	~this(){
64 		.destroy(_terminal);
65 		.destroy(_editor);
66 		.destroy(_statusBar);
67 		.destroy(_statusBarLeft);
68 		.destroy(_shortcutLabel);
69 	}
70 	/// runs the editor
71 	/// 
72 	/// Returns: false if there were errors(s)
73 	bool run(){
74 		_terminal.run;
75 		// save
76 		const string[] lines = _editor.lines.toArray;
77 		ubyte[] data;
78 		uinteger writeTo = 0;
79 		foreach (line; lines){
80 			data.length += line.length+1;
81 			foreach (ch; line){
82 				data[writeTo] = cast(ubyte)ch;
83 				writeTo++;
84 			}
85 			data[writeTo] = '\n';
86 			writeTo++;
87 		}
88 		const string[] errors = writeDataToPng(_inputPng, _outputPng, data);
89 		if (errors.length){
90 			stderr.writeln("Errors while writing to image:");
91 			foreach (err; errors){
92 				stderr.writeln(err);
93 			}
94 			return false;
95 		}
96 		return true;
97 	}
98 
99 }
100 
101 /// reads a single string into string[], separating the lines
102 private string[] separateLines(string s){
103 	string[] r;
104 	for(uinteger i = 0, readFrom = 0; i < s.length; i ++){
105 		if (s[i] == '\n'){
106 			r ~= s[readFrom .. i].dup;
107 			readFrom = i+1;
108 		}else if (i+1 == s.length){
109 			r ~= s[readFrom .. i + 1].dup;
110 		}
111 	}
112 	return r;
113 }
114 /// ditto
115 private string[] separateLines(char[] s){
116 	return separateLines(cast(string)s);
117 }