1 /* coded by Ketmar // Invisible Vector <ketmar@ketmar.no-ip.org>
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 module miniedit
is aliced
;
20 import arsd
.simpledisplay
;
32 // ////////////////////////////////////////////////////////////////////////// //
33 public final class MiniEdit
{
34 private import iv
.utfutil
: Utf8Decoder
;
37 NVGGlyphPosition
[8192] glyphs
;
38 Utf8Decoder ec
; // encoder for clipboard gets
43 void putChar (char ch
) {
44 //if (ch <= ' ' || ch >= 127) conprintf("new char: 0x%02x\n", cast(ubyte)ch); else conprintf("char: '%s'\n", ch);
45 dchar dc
= ec
.decode(cast(ubyte)ch
);
46 if (dc
<= dchar.max
) {
48 if (dc
>= ' ' || dc
== '\n') {
50 glconPostScreenRepaint();
58 string
text () const nothrow {
59 import iv
.utfutil
: utf8Encode
;
61 res
.reserve(dtext
.length
*4);
62 foreach (dchar dc
; dtext
) {
64 auto len
= utf8Encode(buf
[], dc
);
73 dtext
.assumeSafeAppend
;
77 void setFont (NVGContext nvg
) {
80 nvg
.textAlign(NVGTextAlign
.H
.Left
, NVGTextAlign
.V
.Top
);
83 static struct HeightInfo
{
88 void newline () nothrow @safe @nogc { ++lines
; height
+= lineh
; }
91 // return `false` from delegate to stop
92 // `line` in delegate cannot be empty
93 // if `line` ends with '\n', this is hard newline, otherwise it is a wrap
94 void byLine (NVGContext nvg
, int width
, scope bool delegate (const(dchar)[] line
) dg
) {
99 if (width
< 1) width
= 1; // just for fun
102 while (curpos
< dtext
.length
) {
103 // new line; always here
105 nvg
.textGlyphPositions(0, 0, dtext
[curpos
..$], delegate (NVGGlyphPosition gpos
) {
106 if (gpos
.maxx
>= width
) return false; // doesn't fit: stop
107 if (dtext
[curpos
+gpos
.strpos
] == '\n') return false; // eol hit: stop
108 epos
= cast(uint)gpos
.strpos
+1; // swallow the glyph
109 return true; // continue
111 // no glyphs fit, but the line is not empty: swallow at least one glyph
112 if (epos
== 0 && dtext
[curpos
] != '\n') ++epos
;
113 // if we hit (or about to hit) EOL, swallow it too
114 if (epos
== 0) { assert(dtext
[curpos
] == '\n'); ++epos
; }
115 else if (curpos
+epos
< dtext
.length
&& dtext
[curpos
+epos
] == '\n') ++epos
;
116 if (dg(dtext
[curpos
..curpos
+epos
])) break;
121 // for the given width
122 HeightInfo
calcHeight (NVGContext nvg
, int width
) {
126 nvg
.textMetrics(null, null, &res
.lineh
);
128 byLine(nvg
, width
, delegate (line
) {
133 if (dtext
.length
&& dtext
[$-1] == '\n') res
.newline();
135 // we always has at least one line
136 if (res
.lines
== 0) res
.newline();
141 void draw (NVGContext nvg
, float x
, float y
, int width
, int height
) {
142 if (height
< 1) return;
147 nvg
.textMetrics(null, null, &lineh
);
150 nvg
.fillColor
= NVGColor
.k8orange
;
151 //nvg.text(x, y, text[0..repos]);
155 byLine(nvg
, width
, delegate (line
) {
156 if (line
[$-1] == '\n') {
160 nvg
.text(x
, y
, line
[0..$-1]);
163 ex
= nvg
.text(x
, y
, line
);
171 nvg
.strokeColor
= NVGColor
.yellow
;
172 nvg
.rect(cast(int)ex
, cast(int)ey
, 1, height
); // ensure that cursor looks a little blurry
176 bool onKey (KeyEvent event
) {
178 if (event
.key
== Key
.Enter
) {
181 glconPostScreenRepaint();
187 if (event
.key
== Key
.Backspace
) {
188 if (event
.pressed
&& dtext
.length
> 0) {
190 dtext
.assumeSafeAppend
;
191 glconPostScreenRepaint();
197 if (event
== "D-C-Y" || event
== "U-C-Y") {
198 if (event
.pressed
&& dtext
.length
> 0) {
200 glconPostScreenRepaint();
205 if (event
== "D-S-Insert" || event
== "U-S-Insert") {
206 if (event
.pressed
) glconCtlWindow
.getClipboardText(delegate (str) { foreach (immutable char ch
; str) putChar(ch
); });
210 if (event
== "D-C-Insert" || event
== "U-C-Insert") {
211 if (event
.pressed
) glconCtlWindow
.setClipboardText(text
);
218 bool onChar (dchar ch
) {
221 glconPostScreenRepaint();