plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

eenter.c (5734B)


      1 /*
      2 This code was taken from 9front repository (https://code.9front.org/hg/plan9front).
      3 It is subject to license from 9front, below is a reproduction of the license.
      4 
      5 Copyright (c) 20XX 9front
      6 
      7 Permission is hereby granted, free of charge, to any person obtaining a copy
      8 of this software and associated documentation files (the "Software"), to deal
      9 in the Software without restriction, including without limitation the rights
     10 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
     11 copies of the Software, and to permit persons to whom the Software is
     12 furnished to do so, subject to the following conditions:
     13 
     14 The above copyright notice and this permission notice shall be included in all
     15 copies or substantial portions of the Software.
     16 
     17 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     18 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     19 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     20 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     21 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
     22 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
     23 SOFTWARE.
     24 */
     25 #include <u.h>
     26 #include <libc.h>
     27 #include <draw.h>
     28 #include <event.h>
     29 #include <keyboard.h>
     30 
     31 /* additional keyboard codes needed - defined here to avoid API change */
     32 enum {
     33 	Spec=   0xF800,
     34 	Knack=  0x15,
     35 	Ksoh=   0x01,
     36 	Kenq=   0x05,
     37 	Ketb=   0x17
     38 };
     39 
     40 int
     41 eenter(char *ask, char *buf, int len, Mouse *m)
     42 {
     43 	int done, down, tick, n, h, w, l, i;
     44 	Image *b, *save, *backcol, *bordcol;
     45 	Point p, o, t;
     46 	Rectangle r, sc;
     47 	Event ev;
     48 	Rune k;
     49 
     50 	o = screen->r.min;
     51 	backcol = allocimagemix(display, DPurpleblue, DWhite);
     52 	bordcol = allocimage(display, Rect(0,0,1,1), screen->chan, 1, DPurpleblue);
     53 	if(backcol == nil || bordcol == nil)
     54 		return -1;
     55 
     56 	while(ecankbd())
     57 		ekbd();
     58 
     59 	if(m) o = m->xy;
     60 
     61 	if(buf && len > 0)
     62 		n = strlen(buf);
     63 	else {
     64 		buf = nil;
     65 		len = 0;
     66 		n = 0;
     67 	}
     68 
     69 	k = -1;
     70 	tick = n;
     71 	save = nil;
     72 	done = down = 0;
     73 
     74 	p = stringsize(font, " ");
     75 	h = p.y;
     76 	w = p.x;
     77 
     78 	b = screen;
     79 	sc = b->clipr;
     80 	replclipr(b, 0, b->r);
     81 	t = ZP;
     82 
     83 	while(!done){
     84 		p = stringsize(font, buf ? buf : "");
     85 		if(ask && ask[0]){
     86 			if(buf) p.x += w;
     87 			p.x += stringwidth(font, ask);
     88 		}
     89 		r = rectaddpt(insetrect(Rpt(ZP, p), -4), o);
     90 		p.x = 0;
     91 		r = rectsubpt(r, p);
     92 
     93 		p = ZP;
     94 		if(r.min.x < screen->r.min.x)
     95 			p.x = screen->r.min.x - r.min.x;
     96 		if(r.min.y < screen->r.min.y)
     97 			p.y = screen->r.min.y - r.min.y;
     98 		r = rectaddpt(r, p);
     99 		p = ZP;
    100 		if(r.max.x > screen->r.max.x)
    101 			p.x = r.max.x - screen->r.max.x;
    102 		if(r.max.y > screen->r.max.y)
    103 			p.y = r.max.y - screen->r.max.y;
    104 		r = rectsubpt(r, p);
    105 
    106 		r = insetrect(r, -2);
    107 		if(save == nil){
    108 			save = allocimage(display, r, b->chan, 0, DNofill);
    109 			if(save == nil){
    110 				n = -1;
    111 				break;
    112 			}
    113 			draw(save, r, b, nil, r.min);
    114 		}
    115 		draw(b, r, backcol, nil, ZP);
    116 		border(b, r, 2, bordcol, ZP);
    117 		p = addpt(r.min, Pt(6, 6));
    118 		if(ask && ask[0]){
    119 			p = string(b, p, bordcol, ZP, font, ask);
    120 			if(buf) p.x += w;
    121 		}
    122 		if(buf){
    123 			t = p;
    124 			p = stringn(b, p, display->black, ZP, font, buf, utfnlen(buf, tick));
    125 			draw(b, Rect(p.x-1, p.y, p.x+2, p.y+3), display->black, nil, ZP);
    126 			draw(b, Rect(p.x, p.y, p.x+1, p.y+h), display->black, nil, ZP);
    127 			draw(b, Rect(p.x-1, p.y+h-3, p.x+2, p.y+h), display->black, nil, ZP);
    128 			p = string(b, p, display->black, ZP, font, buf+tick);
    129 		}
    130 		flushimage(display, 1);
    131 
    132 nodraw:
    133 		i = Ekeyboard;
    134 		if(m != nil)
    135 			i |= Emouse;
    136 
    137 		replclipr(b, 0, sc);
    138 		i = eread(i, &ev);
    139 
    140 		/* screen might have been resized */
    141 		if(b != screen || !eqrect(screen->clipr, sc)){
    142 			freeimage(save);
    143 			save = nil;
    144 		}
    145 		b = screen;
    146 		sc = b->clipr;
    147 		replclipr(b, 0, b->r);
    148 
    149 		switch(i){
    150 		default:
    151 			done = 1;
    152 			n = -1;
    153 			break;
    154 		case Ekeyboard:
    155 			k = ev.kbdc;
    156 			if(buf == nil || k == Keof || k == '\n'){
    157 				done = 1;
    158 				break;
    159 			}
    160 			if(k == Knack || k == Kesc){
    161 				done = !n;
    162 				buf[n = tick = 0] = 0;
    163 				break;
    164 			}
    165 			if(k == Ksoh || k == Khome){
    166 				tick = 0;
    167 				continue;
    168 			}
    169 			if(k == Kenq || k == Kend){
    170 				tick = n;
    171 				continue;
    172 			}
    173 			if(k == Kright){
    174 				if(tick < n)
    175 					tick += chartorune(&k, buf+tick);
    176 				continue;
    177 			}
    178 			if(k == Kleft){
    179 				for(i = 0; i < n; i += l){
    180 					l = chartorune(&k, buf+tick);
    181 					if(i+l >= tick){
    182 						tick = i;
    183 						break;
    184 					}
    185 				}
    186 				continue;
    187 			}
    188 			if(k == Ketb){
    189 				while(tick > 0){
    190 					tick--;
    191 					if(tick == 0 ||
    192 					   strchr(" !\"#$%&'()*+,-./:;<=>?@`[\\]^{|}~", buf[tick-1]))
    193 						break;
    194 				}
    195 				buf[n = tick] = 0;
    196 				break;
    197 			}
    198 			if(k == Kbs){
    199 				if(tick <= 0)
    200 					continue;
    201 				for(i = 0; i < n; i += l){
    202 					l = chartorune(&k, buf+i);
    203 					if(i+l >= tick){
    204 						memmove(buf+i, buf+i+l, n - (i+l));
    205 						buf[n -= l] = 0;
    206 						tick -= l;
    207 						break;
    208 					}
    209 				}
    210 				break;
    211 			}
    212 			if(k < 0x20 || k == Kdel || (k & 0xFF00) == KF || (k & 0xFF00) == Spec)
    213 				continue;
    214 			if((len-n) <= (l = runelen(k)))
    215 				continue;
    216 			memmove(buf+tick+l, buf+tick, n - tick);
    217 			runetochar(buf+tick, &k);
    218 			buf[n += l] = 0;
    219 			tick += l;
    220 			break;
    221 		case Emouse:
    222 			*m = ev.mouse;
    223 			if(!ptinrect(m->xy, r)){
    224 				down = 0;
    225 				goto nodraw;
    226 			}
    227 			if(m->buttons & 7){
    228 				down = 1;
    229 				if(buf && m->xy.x >= (t.x - w)){
    230 					down = 0;
    231 					for(i = 0; i < n; i += l){
    232 						l = chartorune(&k, buf+i);
    233 						t.x += stringnwidth(font, buf+i, 1);
    234 						if(t.x > m->xy.x)
    235 							break;
    236 					}
    237 					tick = i;
    238 				}
    239 				continue;
    240 			}
    241 			done = down;
    242 			break;
    243 		}
    244 		if(save){
    245 			draw(b, save->r, save, nil, save->r.min);
    246 			freeimage(save);
    247 			save = nil;
    248 		}
    249 	}
    250 
    251 	replclipr(b, 0, sc);
    252 
    253 	freeimage(backcol);
    254 	freeimage(bordcol);
    255 	flushimage(display, 1);
    256 
    257 	return n;
    258 }