1 module ws.gui.text; 2 3 import 4 std.utf, 5 std.conv, 6 ws.io, 7 ws.list, 8 ws.gl.gl, 9 ws.gl.draw, 10 ws.gl.font, 11 ws.gl.shader, 12 ws.gui.base; 13 14 15 class Text: Base { 16 17 Font font; 18 String text; 19 Shader shader; 20 21 this(){ 22 style.bg.normal = [0, 0, 0, 0.5]; 23 style.fg.normal = [1, 1, 1, 1]; 24 text = new String; 25 shader = Shader.load("2d_texture", [gl.attributeVertex: "vVertex", gl.attributeTexture: "vTexture0"], null, TEXTURE_VERT, TEXTURE_FRAG); 26 setFont("sans", 11); 27 } 28 29 30 void setFont(string f, int size){ 31 font = Font.load(f, size); 32 text.set(text.toString()); 33 } 34 35 36 override void resize(int[2] size){ 37 super.resize(size); 38 text.set(text.toString()); 39 } 40 41 42 override void onDraw(){ 43 if(text.queue.length){ 44 text ~= text.queue; 45 text.queue = ""; 46 } 47 glActiveTexture(GL_TEXTURE0); 48 shader.use(); 49 shader["Screen"].set(Draw.screen); 50 shader["Image"].set(0); 51 shader["Color"].set(style.fg.normal); 52 float[3] scale = [1,1,0]; 53 shader["Scale"].set(scale); 54 float[3] fp; 55 foreach(g; text){ 56 if( 57 g.c == '\n' || g.pos.x > size.x || 58 g.pos.y < 0 - cast(int)(font.size*1.4) || 59 g.pos.y > size.y || g.pos.x < -g.glyph.advance 60 ) 61 continue; 62 glBindTexture(GL_TEXTURE_2D, g.glyph.tex); 63 fp = [cast(int)g.pos.x + pos.x + font.size, cast(int)g.pos.y + pos.y, 0]; 64 shader["Offset"].set(fp); 65 g.glyph.vao.draw(); 66 } 67 } 68 69 70 /++ 71 List of characters (dchar + screen position + OpenGL glyph) 72 +/ 73 class String: List!Character { 74 75 void opOpAssign(string op)(string s) if(op=="~") { 76 foreach(dchar c; s) 77 this ~= c; 78 //return s.toUTF32(); 79 } 80 81 void opOpAssign(string op)(dchar c) if(op=="~"){ 82 if(c == '\n') 83 lines++; 84 if(gl.active()){ 85 auto character = new Character(c); 86 if(!length || !cursor.next){ 87 push(character); 88 cursor.prev = end; 89 }else{ 90 auto it = super.insert(cursor.next, character, true); 91 cursor.prev = it; 92 cursor.next = ++it; 93 } 94 update(cursor.prev); 95 }else 96 queue ~= c; 97 } 98 99 void set(string s){ 100 clear(); 101 this ~= s; 102 } 103 104 override void clear(){ 105 super.clear(); 106 cursor.prev = begin(); 107 cursor.next = end(); 108 } 109 110 override string toString(){ 111 string s; 112 foreach(g; text) 113 s ~= g.c; 114 return s; 115 } 116 117 Cursor cursor; 118 119 void update(Iterator it){ 120 if(!begin) 121 return; 122 it = begin;//(it ? it : begin()); 123 Point start = Point(font.size.to!int, (font.size*1.4*lines + font.size*0.4).to!int); 124 if(it.prev){ 125 start = 126 it.prev.get().c == '\n' 127 ? Point(cast(int)(font.size), it.prev.get().pos.y - cast(int)(font.size*1.4)) 128 : it.prev.get().pos + Point(cast(int)it.prev.get().glyph.advance, 0); 129 } 130 while(it){ 131 it.get().pos = start; 132 if(it.get().c=='\n'){ 133 start.x = cast(int)(font.size); 134 start.y -= cast(int)(font.size*1.4); 135 }else{ 136 start.x += it.get().glyph.advance; 137 } 138 it = it.next; 139 } 140 } 141 142 struct Cursor { 143 Iterator prev; 144 Iterator next; 145 void opUnary(string s)() if(s == "--") { 146 if(prev){ 147 next = prev; 148 prev = prev.prev; 149 } 150 } 151 void opUnary(string s)() if(s == "++") { 152 if(next){ 153 prev = next; 154 next = next.next; 155 } 156 } 157 } 158 159 string queue; 160 161 protected: 162 long lines; 163 164 } 165 166 class Character { 167 dchar c; 168 Point pos; 169 Font.Glyph glyph; 170 this(dchar c){ 171 this.c = c; 172 glyph = font[c]; 173 } 174 } 175 176 177 }