#include "diadef.h" #include "dialog.h" #include "../diajava/proto.h" class FIELD_TEXTAREA: public FIELD{ int width; SSTRING &text; SSTRING backup; char *buf; char *yank; int start_line; // Line visible in the dialogs int end_line; // We learn this from drawtxt and reuse it // while in edit mode protected: int save_x; enum cursor_dir { CURSOR_UP, CURSOR_DOWN, CURSOR_LEFT, CURSOR_RIGHT, CURSOR_EOL, CURSOR_BOL }; struct { int input_x; int input_y; int real_x; int real_y; int hscroll; int vscroll; int buf; } pos; struct { int size; int len; } buf_info; /*~PROTOBEG~ FIELD_TEXTAREA */ public: FIELD_TEXTAREA (const char *prompt, SSTRING&_text, int _width, int height); protected: void clearall (WINDOW *dialog); public: MENU_STATUS dokey (WINDOW *dialog, int key, FIELD_MSG&msg, bool&grab); void drawtxt (WINDOW *dialog, int , int _start_line, int _end_line); const char *get_registry_value (void); char getidprefix (void); void gui_draw (int nofield, SSTRINGS&); MENU_STATUS gui_get (int nofield, const char *, const char *); void html_draw (int nofield); int html_validate (int nof); protected: void insert_char (char c); int insert_point (void); void insert_string (char *str); int line_length (int line); bool move_cursor (cursor_dir dir); public: void reload (const char *dianame, int nof); void restore (void); void save (void); protected: void sendlines (void); public: void set_registry_value (const char *v); private: void setbuf (const char *s); protected: void setcursor (WINDOW *dialog, int); public: void xul_draw (int , SSTRINGS&); /*~PROTOEND~ FIELD_TEXTAREA */ }; PUBLIC FIELD_TEXTAREA::FIELD_TEXTAREA( const char *prompt, SSTRING &_text, int _width, // How many visible character horizontally // (a hint) int height) // How many lines to show : FIELD (prompt), text(_text) { width = _width; vsize = height; box.width = _width; backup.setfrom (text); buf = NULL; setbuf (text.get()); pos.hscroll = pos.input_x = pos.real_x = 0; pos.vscroll = pos.input_y = pos.real_y = 0; save_x = 0; yank = NULL; } PRIVATE void FIELD_TEXTAREA::setbuf(const char *s) { free (buf); buf = strdup(s); buf_info.len = strlen(buf); buf_info.size = buf_info.len; } PUBLIC void FIELD_TEXTAREA::set_registry_value(const char *v) { setbuf (v); } PUBLIC const char *FIELD_TEXTAREA::get_registry_value() { return buf; } PROTECTED void FIELD_TEXTAREA::setcursor(WINDOW *dialog, int) { wmove (dialog, box.y+pos.input_y, box.x+pos.input_x); } PUBLIC void FIELD_TEXTAREA::drawtxt( WINDOW *dialog, int, int _start_line, int _end_line) { start_line = _start_line; end_line = _end_line; wattrset (dialog, inputbox_attr); SSTRINGS lines; str_cnv2lines (buf,lines); for (int i=start_line; i<=end_line; i++){ int posy = i; // -pos.vscroll; SSTRING *line = lines.getitem(i+pos.vscroll); int posx = 0; if (line != NULL){ char tmp[line->getlen()*8+1+box.width]; str_exptab (line->get(),8,tmp); int len = strlen(tmp); if (len > pos.hscroll){ char *s = tmp + pos.hscroll; s[box.width] = '\0'; wmove (dialog, posy+box.y, posx+box.x); waddstr (dialog, s); posx = strlen(s); } } if (posx < box.width){ char blank[box.width+1]; memset (blank,' ',box.width); blank[box.width-posx] = 0; wmove (dialog, posy+box.y, posx+box.x); waddstr (dialog, blank); } } } PROTECTED int FIELD_TEXTAREA::line_length(int line) { const char *s = buf; for (int i=0; i < line; s++){ if (*s == '\n') i++; else if (*s == 0) return -1; } int len = 0; while (*s != '\n' && *s != 0){ s++; len++; } return len; } PROTECTED int FIELD_TEXTAREA::insert_point(void) { char *s = buf; for (int x=0,y=0; x!=pos.real_x || y!=pos.real_y; s++,x++){ if (*s == '\n'){ x = -1; y++; } } return s-buf; } PROTECTED void FIELD_TEXTAREA::clearall(WINDOW *dialog) { wattrset(dialog,inputbox_attr); for (int i=0; i < box.width; i++){ for (int j=start_line; j <= end_line; j++){ wmove (dialog,box.y+j,box.x+i); waddch (dialog,' '); } } } PROTECTED bool FIELD_TEXTAREA::move_cursor(cursor_dir dir) { bool redraw = false; static int x_backup = 0; bool goto_x_backup = false; switch (dir){ case CURSOR_UP: pos.real_y--; goto_x_backup = true; break; case CURSOR_DOWN: pos.real_y++; goto_x_backup = true; break; case CURSOR_LEFT: if (pos.input_x == 0){ if (pos.hscroll > 0){ pos.real_x--; }else if (pos.real_y > 0){ pos.real_y--; int len = line_length(pos.real_y); pos.real_x = len==0?len:len+1; } }else{ pos.real_x--; } break; case CURSOR_RIGHT: { int len = line_length(pos.real_y); if (pos.real_x < len){ pos.real_x++; }else{ len = line_length(pos.real_y+1); if (len != -1){ pos.real_y++; pos.real_x = 0; } } break; } case CURSOR_BOL: pos.hscroll = pos.input_x = pos.real_x = save_x = 0; redraw = true; break; case CURSOR_EOL: pos.real_x = line_length(pos.real_y); redraw = true; break; } char *s = buf; // Verify if real_y is valid and find the current buffer position. char *last_y = s; if (pos.real_y < 0){ pos.real_y = 0; }else{ for (int y=0; y vsize-1){ pos.vscroll = pos.real_y-vsize+1; pos.input_y = pos.real_y-pos.vscroll; redraw = true; }else if (pos.real_y < pos.vscroll){ pos.vscroll = pos.real_y; pos.input_y = 0; redraw = true; }else{ pos.input_y = pos.real_y-pos.vscroll; } // Handle line length int len = 0; for (char *l = s; *l != '\n' && *l != 0; l++, len++); // Find the correct horizontal input position pos.input_x = 0; if (goto_x_backup){ int x = 0; for (; x len){ pos.real_x = len; redraw = true; } for (int x=0; x box.width-1){ pos.hscroll = pos.input_x-box.width+1; pos.input_x -= pos.hscroll; redraw = true; }else if (pos.input_x < pos.hscroll){ pos.hscroll = pos.input_x; pos.input_x = 0; redraw = true; }else{ pos.input_x -= pos.hscroll; } return redraw; } PROTECTED void FIELD_TEXTAREA::insert_string(char *str) { int len = strlen(str); if (buf_info.len+len > buf_info.size){ buf_info.size = (buf_info.size*2)+256+len; buf = (char*) realloc(buf,buf_info.size); } int ip = insert_point(); char *s = buf+ip; memmove(s+len,s,buf_info.len-ip+1); buf_info.len+=len; memcpy(s,str,len); for (int i=0; i buf_info.size){ buf_info.size = (buf_info.size*2)+256; buf = (char*) realloc(buf,buf_info.size); } int ip = insert_point(); char *s = buf+ip; memmove(s+1,s,buf_info.len-ip+1); buf_info.len++; *s = c; if (c == '\n'){ move_cursor (CURSOR_DOWN); move_cursor (CURSOR_BOL); }else{ move_cursor (CURSOR_RIGHT); } } PUBLIC MENU_STATUS FIELD_TEXTAREA::dokey( WINDOW *dialog, int key, FIELD_MSG &msg, bool &grab) { bool redraw = false; if (readonly) return MENU_NULL; if (!grab){ if (key == ' '){ grab = true; } return MENU_NULL; } static bool killing = false; switch (key){ case 16: // ^P case KEY_UP: redraw = move_cursor(CURSOR_UP); killing = false; break; case 14: // ^N case KEY_DOWN: redraw = move_cursor(CURSOR_DOWN); killing = false; break; case 2: // ^B case KEY_LEFT: redraw = move_cursor(CURSOR_LEFT); killing = false; break; case 6: // ^F case KEY_RIGHT: redraw = move_cursor(CURSOR_RIGHT); killing = false; break; case 1: // ^A case KEY_HOME: redraw = move_cursor(CURSOR_BOL); killing = false; break; case 5: // ^E: case KEY_END: redraw = move_cursor(CURSOR_EOL); killing = false; break; case KEY_BACKSPACE: { int ip = insert_point(); if (ip > 0){ move_cursor(CURSOR_LEFT); memmove(buf+ip-1,buf+ip,buf_info.len-ip+1); buf_info.len--; redraw = true; } killing = false; break; } case 4: // ^D case DEL: { int ip = insert_point(); if (ip < buf_info.len){ memmove(buf+ip,buf+ip+1,buf_info.len-ip+1); buf_info.len--; redraw = true; } killing = false; break; } case 11: // ^K { int ip = insert_point(); char *s = buf+ip; int len = 0; int yank_len = 0; if (*s != 0){ if (*s != '\n'){ for (;*s!='\n' && *s!=0;s++); len = s-(buf+ip); }else{ len = 1; } if (killing && yank != NULL){ yank_len = (yank != NULL) ? strlen(yank) : 0; yank = (char*) realloc(yank,yank_len+len+1); }else{ free(yank); yank = NULL; if (len > 0){ yank = (char*) malloc(len+1); } } memcpy (yank+yank_len,buf+ip,len); *(yank+yank_len+len) = 0; memmove (buf+ip,buf+ip+len,buf_info.len-(ip+len)+1); buf_info.len -= len; redraw = true; killing = true; } break; } case 25: // ^Y insert_string (yank); redraw = true; killing = false; break; default: insert_char(key); redraw = true; killing = false; break; } if (redraw){ clearall (dialog); drawtxt (dialog,0,start_line,end_line); } return MENU_NULL; } PUBLIC void FIELD_TEXTAREA::save() { text.setfrom(buf); } PUBLIC void FIELD_TEXTAREA::restore() { text.setfrom(backup); } PUBLIC void FIELD_TEXTAREA::reload(const char *dianame, int nof) { free(buf); buf = strdup(text.get()); buf_info.len = strlen(buf); buf_info.size = buf_info.len; if (dianame != NULL){ char tmp1[1000]; diagui_sendcmd (P_Setval,"%s T%d reset\n" ,formatpath(tmp1,dianame),nof); sendlines(); } } /* Send the text to the GUI front-end line by line */ PROTECTED void FIELD_TEXTAREA::sendlines() { const char *pt = buf; while (*pt != '\0'){ char line[1000]; char *dst = line; while (*pt != '\r' && *pt != '\n' && *pt != '\0' && (unsigned)(dst-line)%s",prompt); if (readonly){ html_printf ("%s\n",buf); }else{ char key[100]; format_htmlkey (key,nofield); html_defvarcur (key,backup.get()); html_printf ("\n"); } } PUBLIC void FIELD_TEXTAREA::xul_draw(int, SSTRINGS &) { } PUBLIC void FIELD_TEXTAREA::gui_draw(int nofield, SSTRINGS &) { guisendprompt(); if (readonly){ diagui_send_Label (buf); }else{ diagui_sendcmd (P_Textarea,"T%d %d %d\n",nofield,width,vsize); sendlines(); } } PUBLIC MENU_STATUS FIELD_TEXTAREA::gui_get(int nofield, const char *, const char *) { SSTRINGS tb; int nb = diagui_getvals('T',nofield,tb); int len = 0; for (int i=0; igetlen()+1; } char tmp[len+1]; char *acc = tmp; for (int i=0; icopy (acc); acc += strlen(acc); *acc ++ = '\n'; } *acc = '\0'; free(buf); buf = strdup(tmp); buf_info.len = strlen(buf); buf_info.size = buf_info.len; return MENU_NULL; } PUBLIC char FIELD_TEXTAREA::getidprefix () { return 'T'; } /* Copy but discard the \r's */ static void textarea_copystripr (char *dst, const char *src) { while (*src != '\0'){ if (*src != '\r') *dst++ = *src; src++; } *dst = '\0'; } PUBLIC int FIELD_TEXTAREA::html_validate(int nof) { int ret = -1; char key[100]; format_htmlkey (key,nof); const char *old_val = html_getoldval (key); // Remove the \r inserted by the browser char buf_old_val[strlen(old_val)+1]; textarea_copystripr (buf_old_val,old_val); const char *new_val = html_getval (key); fprintf (stderr,"validate %s val :%s: old :%s: backup :%s:\n",key,new_val,buf_old_val,backup.get()); if (backup.cmp(buf_old_val)==0){ char buf_new_val[strlen(new_val)+1]; textarea_copystripr (buf_new_val,new_val); setbuf (buf_new_val); ret = 0; } return ret; } PUBLIC void DIALOG::newf_textarea ( const char *prompt, SSTRING &text, int width, // How many visible character horizontally // (a hint) int height) // How many lines to show { add (new FIELD_TEXTAREA(prompt,text,width,height)); }