better quoting
[bioacid.git] / fonts.d
blobe2c057cdae19088e2dd694c9ca1f8852c045cd26
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, version 3 of the License ONLY.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 module fonts is aliced;
18 import iv.cmdcon;
19 import iv.nanovega;
20 import iv.nanovega.textlayouter;
23 // ////////////////////////////////////////////////////////////////////////// //
24 alias LayTextClass = LayTextD;
27 // ////////////////////////////////////////////////////////////////////////// //
28 enum TTFontStyle : ubyte { Normal = 0, Italic = 1, Bold = 2 }
30 __gshared FONSContext fstash;
31 __gshared LayFontStash laf;
33 __gshared string[4] textFontNames = [
34 "PT Sans", //"Arial:noaa", //"~/ttf/ms/arial.ttf:noaa", // normal
35 "PT Sans:italic", //"~/ttf/ms/ariali.ttf:noaa", // italic
36 "PT Sans:bold", //"~/ttf/ms/arialbd.ttf:noaa", // bold
37 "PT Sans:italic:bold", //"~/ttf/ms/arialbi.ttf:noaa", // italic+bold
39 __gshared string[4] monoFontNames = [
40 //"/usr/share/fonts/ms/andalemo.ttf:noaa", // normal
41 "PT Mono", //"Courier New:noaa", //"~/ttf/ms/cour.ttf:noaa", // normal
42 "PT Mono:italic", //"~/ttf/ms/couri.ttf:noaa", // italic
43 "PT Mono:bold", //"~/ttf/ms/courbd.ttf:noaa", // bold
44 "PT Mono:italic:bold", //"~/ttf/ms/courbi.ttf:noaa", // italic+bold
46 __gshared string[4] uiFontNames = [
47 "PT Sans", //"Arial:noaa", //"~/ttf/ms/verdana.ttf:noaa", // normal
48 "PT Sans:italic", //"~/ttf/ms/ariali.ttf:noaa", // italic
49 "PT Sans:bold", //"~/ttf/ms/arialbd.ttf:noaa", // bold
50 "PT Sans:italic:bold", //"~/ttf/ms/arialbi.ttf:noaa", // italic+bold
54 // ////////////////////////////////////////////////////////////////////////// //
55 void fixFontForStyleEx (string normalFontPfx, LayFontStash laf, ref LayFontStyle st) nothrow @trusted @nogc {
56 //{ import core.stdc.stdio; printf("monospace=%d; italic=%d; bold=%d\n", (st.monospace ? 1 : 0), (st.italic ? 1 : 0), (st.bold ? 1 : 0)); }
57 char[12] tbuf;
58 int tbufpos = 0;
59 void put (const(char)[] s...) nothrow @trusted @nogc {
60 if (s.length == 0) return;
61 if (tbuf.length-tbufpos < s.length) assert(0, "wtf?!");
62 tbuf.ptr[tbufpos..tbufpos+s.length] = s[];
63 tbufpos += cast(int)s.length;
65 put(st.monospace ? "mono" : normalFontPfx);
66 if (st.italic) put("i");
67 if (st.bold) put("b");
68 st.fontface = laf.fontFaceId(tbuf[0..tbufpos]);
71 void fixFontForStyleText (LayFontStash laf, ref LayFontStyle st) nothrow @trusted @nogc { fixFontForStyleEx("text", laf, st); }
72 void fixFontForStyleUI (LayFontStash laf, ref LayFontStyle st) nothrow @trusted @nogc { fixFontForStyleEx("ui", laf, st); }
74 private void loadFmtFonts () {
75 import std.functional : toDelegate;
77 laf = new LayFontStash();
78 laf.fs.addFontsFrom(fstash);
79 laf.fixFontDG = toDelegate(&fixFontForStyleText);
83 // ////////////////////////////////////////////////////////////////////////// //
84 // create dummy fontstash and load fonts
85 void loadAllFonts () {
86 assert(fstash is null);
87 fstash = FONSContext.create(FONSParams.init);
88 if (fstash is null) assert(0, "error creating font stash");
90 void loadFont (string name, string path) {
91 auto fid = fstash.addFont(name, path, false); // no AA
92 if (fid < 0) assert(0, "can't load font '"~name~"' from '"~path~"'");
93 //conwriteln("created font [", name, "] (", path, "): ", fid);
96 void loadFontSet (string namebase, string[] pathes) {
97 static immutable string[4] pfx = ["", "i", "b", "ib"];
98 assert(pathes.length >= 4);
99 foreach (immutable idx; 0..4) loadFont(namebase~pfx[idx], pathes[idx]);
102 loadFontSet("text", textFontNames[]);
103 loadFontSet("mono", monoFontNames[]);
104 loadFontSet("ui", uiFontNames[]);
106 //loadFont("arial", "arial");
107 loadFont("arial", "/home/ketmar/sofonts/arialn.ttf");
108 loadFont("tahoma", "tahoma");
109 loadFont("verdana", "verdana");
111 //loadFont("test", "/mnt/bigfoot/dprj/bioacid/_ttf/ms/ttc/Sitka.ttc");
113 loadFmtFonts();
117 // ////////////////////////////////////////////////////////////////////////// //
118 //vg.fillColor(NVGColor.orange);
119 void drawLayouter(LT) (NVGContext vg, LT lay, int layTopY, int x0, int y0, int hgt)
120 if (is(LT : LayTextImpl!CT, CT))
122 if (vg is null || lay is null || hgt < 1 || lay.lineCount == 0 || lay.width < 1) return;
123 int drawY = y0;
124 //FIXME: not GHeight!
125 int lidx = lay.findLineAtY(layTopY);
126 if (lidx >= 0 && lidx < lay.lineCount) {
127 vg.save();
128 scope(exit) vg.restore();
129 vg.strokeWidth = 1;
130 vg.beginPath();
131 vg.intersectScissor(x0, y0, lay.width, hgt);
132 drawY -= layTopY-lay.line(lidx).y;
133 vg.textAlign(NVGTextAlign.H.Left, NVGTextAlign.V.Baseline);
134 LayFontStyle lastStyle;
135 int startx = x0;
136 bool setColor = true;
137 while (lidx < lay.lineCount && hgt > 0) {
138 auto ln = lay.line(lidx);
139 foreach (ref LayWord w; lay.lineWords(lidx)) {
140 if (lastStyle != w.style || setColor) {
141 if (w.style.fontface != lastStyle.fontface) vg.fontFace = lay.fontFace(w.style.fontface);
142 vg.fontSize(w.style.fontsize);
143 auto c = NVGColor(w.style.color);
144 vg.fillColor = c;
145 vg.strokeColor = c;
146 lastStyle = w.style;
147 setColor = false;
148 //conprintfln("new color: 0x%08x; fontid=%d; fontsize=%d", w.style.color, w.style.fontface, w.style.fontsize);
150 // background color
152 auto c = NVGColor(w.style.bgcolor);
153 if (!c.isTransparent) {
155 vg.save();
156 scope(exit) vg.restore();
157 vg.beginPath();
158 vg.fillColor(c);
159 vg.rect(cast(int)(startx+w.x)+0.5f, cast(int)drawY+0.5, cast(int)w.fullwidth, cast(int)ln.h);
160 //vg.rect(startx+w.x+0.5f, drawY+0.5, w.fullwidth, ln.h);
161 vg.fill();
163 vg.beginPath();
166 // marked words
167 if (lay.isMarkedWord(w.wordNum)) {
168 vg.save();
169 scope(exit) vg.restore();
170 vg.beginPath();
171 vg.fillColor(nvgRGB(0, 0, 255));
172 vg.rect(cast(int)(startx+w.x)+0.5f, cast(int)drawY+0.5,
173 (lay.isMarkedWord(w.wordNum+1) ? cast(int)w.fullwidth : cast(int)w.width),
174 cast(int)ln.h);
175 //vg.rect(startx+w.x+0.5f, drawY+0.5, w.fullwidth, ln.h);
176 vg.fill();
177 setColor = true;
179 // element
180 auto oid = w.objectIdx;
181 if (oid >= 0) {
182 //vg.fill();
184 vg.save();
185 scope(exit) vg.restore();
186 vg.beginPath();
187 lay.objectAtIndex(oid).draw(vg, startx+w.x, drawY+ln.h+ln.desc);
189 vg.beginPath();
190 } else if (!w.expander) {
191 vg.text(startx+w.x, drawY+ln.h+ln.desc, lay.wordText(w));
193 //TODO: draw lines over whitespace
194 bool doStroke = false;
195 if (lastStyle.underline || lastStyle.href) { doStroke = true; vg.rect(startx+w.x+0.5f, drawY+ln.h+ln.desc+1+0.5f, w.w, 1); }
196 if (lastStyle.strike) { doStroke = true; vg.rect(startx+w.x+0.5f, drawY+ln.h+ln.desc-w.asc/3+0.5f, w.w, 2); }
197 if (lastStyle.overline) { doStroke = true; vg.rect(startx+w.x+0.5f, drawY+ln.h+ln.desc-w.asc-1+0.5f, w.w, 1); }
198 if (doStroke) {
199 vg.stroke();
200 vg.beginPath();
203 drawY += ln.h;
204 hgt -= ln.h;
205 ++lidx;