URI:
       teenter.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       teenter.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 }