/* vim:expandtab:ts=2 sw=2: */ /* Grafx2 - The Ultimate 256-color bitmap paint program Copyright 2008 Yves Rizoud Copyright 2007 Adrien Destugues Copyright 1996-2001 Sunset Design (Guillaume Dorme & Karl Maritaud) Grafx2 is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; version 2 of the License. Grafx2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with Grafx2; if not, see */ /************************************************************************ * * * READLINE (procédure permettant de saisir une chaîne de caractères) * * * ************************************************************************/ #include #include #include #include "const.h" #include "struct.h" #include "global.h" #include "misc.h" #include "errors.h" #include "const.h" #include "sdlscreen.h" #include "readline.h" #include "windows.h" #include "input.h" #define TEXT_COLOR MC_Black #define BACKGROUND_COLOR MC_Light #define CURSOR_COLOR MC_Black #define CURSOR_BACKGROUND_COLOR MC_Dark // Suppresion d'un caractère à une certaine POSITION dans une CHAINE. void Remove_character(char * str, byte position) { for (;str[position]!='\0';position++) str[position]=str[position+1]; } void Insert_character(char * str, char letter, byte position) // Insertion d'une LETTRE à une certaine POSITION // dans une CHAINE d'une certaine TAILLE. { char temp_char; for (;letter!='\0';position++) { // On mémorise le caractère qui se trouve en "position" temp_char=str[position]; // On splotch la lettre à insérer str[position]=letter; // On place le caractère mémorisé dans "letter" comme nouvelle lettre à insérer letter=temp_char; } // On termine la chaine str[position]='\0'; } int Valid_character(int c) { // Sous Linux: Seul le / est strictement interdit, mais beaucoup // d'autres poseront des problèmes au shell, alors on évite. // Sous Windows : c'est moins grave car le fopen() échouerait de toutes façons. // AmigaOS4: Pas de ':' car utilisé pour les volumes. #if defined(__WIN32__) char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':', '\\'}; #elif defined (__amigaos4__) char forbidden_char[] = {'/', '|', '?', '*', '<', '>', ':'}; #else char forbidden_char[] = {'/', '|', '?', '*', '<', '>'}; #endif int position; if (c < ' ' || c > 255) return 0; for (position=0; position<(long)sizeof(forbidden_char); position++) if (c == forbidden_char[position]) return 0; return 1; } void Display_whole_string(word x_pos,word y_pos,char * str,byte position) { char cursor[2]; Print_general(x_pos,y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); cursor[0]=str[position] ? str[position] : ' '; cursor[1]='\0'; Print_general(x_pos+(position<<3)*Menu_factor_X,y_pos,cursor,CURSOR_COLOR,CURSOR_BACKGROUND_COLOR); } /**************************************************************************** * Enhanced super scanf deluxe pro plus giga mieux :-) * ****************************************************************************/ byte Readline(word x_pos,word y_pos,char * str,byte visible_size,byte input_type) // Paramètres: // x_pos, y_pos : Coordonnées de la saisie dans la fenêtre // str : Chaîne recevant la saisie (et contenant éventuellement une valeur initiale) // max_size : Nombre de caractères logeant dans la zone de saisie // input_type : 0=Chaîne, 1=Nombre, 2=Nom de fichier // Sortie: // 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) { byte max_size; // Grosse astuce pour les noms de fichiers: La taille affichée est différente // de la taille maximum gérée. if (input_type == 2) max_size = 255; else max_size = visible_size; return Readline_ex(x_pos,y_pos,str,visible_size,max_size,input_type,0); } /**************************************************************************** * Enhanced super scanf deluxe pro plus giga mieux :-) * ****************************************************************************/ byte Readline_ex(word x_pos,word y_pos,char * str,byte visible_size,byte max_size, byte input_type, byte decimal_places) // Paramètres: // x_pos, y_pos : Coordonnées de la saisie dans la fenêtre // str : Chaîne recevant la saisie (et contenant éventuellement une valeur initiale) // max_size : Nombre de caractères logeant dans la zone de saisie // input_type : 0=String, 1=Unsigned int, 2=Filename 3=Signed Double // decimal_places: Number of decimal places for a double // Sortie: // 0: Sortie par annulation (Esc.) / 1: sortie par acceptation (Return) { char initial_string[256]; char display_string[256]; byte position; byte size; word input_key=0; byte is_authorized; word window_x=Window_pos_X; word window_y=Window_pos_Y; // Virtual keyboard byte use_virtual_keyboard=0; static byte caps_lock=0; word keymapping[] = { SDLK_CLEAR,SDLK_BACKSPACE,SDLK_RETURN,KEY_ESC, '0','1','2','3','4','5','6','7','8','9','.',',', 'Q','W','E','R','T','Y','U','I','O','P', 'A','S','D','F','G','H','J','K','L', SDLK_CAPSLOCK,'Z','X','C','V','B','N','M',' ', '-','+','*','/','|','\\', '(',')','{','}','[',']', '_','=','<','>','%','@', ':',';','`','\'','"','~', '!','?','^','&','#','$' }; byte offset=0; // index du premier caractère affiché // Si on a commencé à editer par un clic-droit, on vide la chaine. if (Mouse_K==RIGHT_SIDE) str[0]='\0'; else if (input_type==INPUT_TYPE_INTEGER && str[0]!='\0') snprintf(str,10,"%d",atoi(str)); // On tasse la chaine à gauche else if (input_type==INPUT_TYPE_DECIMAL) { // Nothing. The caller should have used Sprint_double, with min_positions // at zero, so there's no spaces on the left and no useless 0s on the right. } else if (input_type==INPUT_TYPE_HEXA) { // Nothing. The caller should have initialized a valid hexa number. } // Virtual keyboards if (input_type == INPUT_TYPE_STRING || input_type == INPUT_TYPE_FILENAME ) { // Full keyboard const int keyboard_width=320; const int keyboard_height=87; int h_pos; int x,y; h_pos= Window_pos_X+(keyboard_width-Window_width)/-2; if (h_pos<0) h_pos=0; else if (h_pos+keyboard_width>Screen_width) h_pos=Screen_width-keyboard_width; use_virtual_keyboard=1; Hide_cursor(); Open_popup(h_pos,Window_pos_Y+(y_pos+9)*Menu_factor_Y,keyboard_width,keyboard_height); Window_rectangle(0,0,Window_width, Window_height-2, MC_Light); Window_rectangle(2,Window_height-3,Window_width, 2, MC_Black); // The order is important, see the array Window_set_normal_button( 7,67,43,15,"Clr", 0,1,KEY_NONE); Window_set_normal_button( 51,67,43,15,"Del", 0,1,KEY_NONE); Window_set_normal_button( 95,67,43,15,"OK", 0,1,KEY_NONE); Window_set_normal_button(139,67,43,15,"Esc", 0,1,KEY_NONE); Window_display_frame_in(5,65,179,19); Window_set_normal_button(193,63,17,19,"0", 0,1,KEY_NONE); Window_set_normal_button(193,43,17,19,"1", 0,1,KEY_NONE); Window_set_normal_button(211,43,17,19,"2", 0,1,KEY_NONE); Window_set_normal_button(229,43,17,19,"3", 0,1,KEY_NONE); Window_set_normal_button(193,23,17,19,"4", 0,1,KEY_NONE); Window_set_normal_button(211,23,17,19,"5", 0,1,KEY_NONE); Window_set_normal_button(229,23,17,19,"6", 0,1,KEY_NONE); Window_set_normal_button(193, 3,17,19,"7", 0,1,KEY_NONE); Window_set_normal_button(211, 3,17,19,"8", 0,1,KEY_NONE); Window_set_normal_button(229, 3,17,19,"9", 0,1,KEY_NONE); Window_set_normal_button(211,63,17,19,".", 0,1,KEY_NONE); Window_set_normal_button(229,63,17,19,",", 0,1,KEY_NONE); Window_set_normal_button( 3, 3,18,19,"Q", 0,1,KEY_NONE); Window_set_normal_button( 22, 3,18,19,"W", 0,1,KEY_NONE); Window_set_normal_button( 41, 3,18,19,"E", 0,1,KEY_NONE); Window_set_normal_button( 60, 3,18,19,"R", 0,1,KEY_NONE); Window_set_normal_button( 79, 3,18,19,"T", 0,1,KEY_NONE); Window_set_normal_button( 98, 3,18,19,"Y", 0,1,KEY_NONE); Window_set_normal_button(117, 3,18,19,"U", 0,1,KEY_NONE); Window_set_normal_button(136, 3,18,19,"I", 0,1,KEY_NONE); Window_set_normal_button(155, 3,18,19,"O", 0,1,KEY_NONE); Window_set_normal_button(174, 3,18,19,"P", 0,1,KEY_NONE); Window_set_normal_button( 12,23,18,19,"A", 0,1,KEY_NONE); Window_set_normal_button( 31,23,18,19,"S", 0,1,KEY_NONE); Window_set_normal_button( 50,23,18,19,"D", 0,1,KEY_NONE); Window_set_normal_button( 69,23,18,19,"F", 0,1,KEY_NONE); Window_set_normal_button( 88,23,18,19,"G", 0,1,KEY_NONE); Window_set_normal_button(107,23,18,19,"H", 0,1,KEY_NONE); Window_set_normal_button(126,23,18,19,"J", 0,1,KEY_NONE); Window_set_normal_button(145,23,18,19,"K", 0,1,KEY_NONE); Window_set_normal_button(164,23,18,19,"L", 0,1,KEY_NONE); Window_set_normal_button( 3,43,18,19,caps_lock?"\036":"\037", 0,1,KEY_NONE); Window_set_normal_button( 22,43,18,19,"Z", 0,1,KEY_NONE); Window_set_normal_button( 41,43,18,19,"X", 0,1,KEY_NONE); Window_set_normal_button( 60,43,18,19,"C", 0,1,KEY_NONE); Window_set_normal_button( 79,43,18,19,"V", 0,1,KEY_NONE); Window_set_normal_button( 98,43,18,19,"B", 0,1,KEY_NONE); Window_set_normal_button(117,43,18,19,"N", 0,1,KEY_NONE); Window_set_normal_button(136,43,18,19,"M", 0,1,KEY_NONE); Window_set_normal_button(155,43,18,19," ", 0,1,KEY_NONE); for (y=0; y<5; y++) { for (x=0; x<6; x++) { char label[2]=" "; label[0]=keymapping[x+y*6+44]; Window_set_normal_button(247+x*12, 3+y*16,11,15,label, 0,1,KEY_NONE); } } Update_window_area(0,0,Window_width, Window_height); Display_cursor(); } Keyboard_click_allowed = 0; Hide_cursor(); // Effacement de la chaîne Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); // Mise à jour des variables se rapportant à la chaîne en fonction de la chaîne initiale strcpy(initial_string,str); size=strlen(str); position=(size=visible_size) offset=position-visible_size+1; // Formatage d'une partie de la chaine (si trop longue pour tenir) strncpy(display_string, str + offset, visible_size); display_string[visible_size]='\0'; if (offset>0) display_string[0]=LEFT_TRIANGLE_CHARACTER; if (visible_size + offset + 1 < size ) display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; Display_whole_string(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y),display_string,position - offset); Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); Flush_update(); if (Mouse_K) { Display_cursor(); Wait_end_of_click(); Hide_cursor(); } while ((input_key!=SDLK_RETURN) && (input_key!=KEY_ESC)) { Display_cursor(); if (use_virtual_keyboard) { int clicked_button; clicked_button=Window_clicked_button(); input_key=Key_ANSI; if (clicked_button==-1) input_key=SDLK_RETURN; else if (clicked_button>0) { input_key=keymapping[clicked_button-1]; if (input_key==SDLK_CAPSLOCK) { // toggle uppercase caps_lock=!caps_lock; Hide_cursor(); Print_in_window(8, 49,caps_lock?"\036":"\037", MC_Black,MC_Light); Display_cursor(); } else if (input_key>='A' && input_key<='Z' && !caps_lock) { input_key+='a'-'A'; } } } else { do { Get_input(20); input_key=Key_ANSI; if (Mouse_K) input_key=SDLK_RETURN; } while(input_key==0); } Hide_cursor(); switch (input_key) { case SDLK_DELETE : // Suppr. if (position0) { // Effacement de la chaîne if (position==size) Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); position--; if (offset > 0 && (position == 0 || position < (offset + 1))) offset--; goto affichage; } break; case SDLK_RIGHT : // Droite if ((position visible_size + offset - 2) //if (offset + visible_size < max_size && (position == size || (position > visible_size + offset - 2))) if (display_string[position-offset]==RIGHT_TRIANGLE_CHARACTER || position-offset>=visible_size) offset++; goto affichage; } break; case SDLK_HOME : // Home if (position) { // Effacement de la chaîne if (position==size) Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); position = 0; offset = 0; goto affichage; } break; case SDLK_END : // End if ((position=visible_size) offset=position-visible_size+1; goto affichage; } break; case SDLK_BACKSPACE : // Backspace : combinaison de gauche + suppr if (position) { position--; if (offset > 0 && (position == 0 || position < (offset + 1))) offset--; Remove_character(str,position); size--; // Effacement de la chaîne Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); goto affichage; } break; case SDLK_CLEAR : // Clear str[0]='\0'; position=offset=0; // Effacement de la chaîne Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); goto affichage; case SDLK_RETURN : break; case KEY_ESC : // On restaure la chaine initiale strcpy(str,initial_string); size=strlen(str); break; default : if (size=' ' && input_key<= 255) is_authorized=1; break; case INPUT_TYPE_INTEGER : if ( (input_key>='0') && (input_key<='9') ) is_authorized=1; break; case INPUT_TYPE_DECIMAL: if ( (input_key>='0') && (input_key<='9') ) is_authorized=1; else if (input_key=='-' && position==0 && str[0]!='-') is_authorized=1; else if (input_key=='.') is_authorized=1; break; case INPUT_TYPE_FILENAME: // On regarde si la touche est autorisée if ( Valid_character(input_key)) is_authorized=1; case INPUT_TYPE_HEXA: if ( (input_key>='0') && (input_key<='9') ) is_authorized=1; else if ( (input_key>='A') && (input_key<='F') ) is_authorized=1; else if ( (input_key>='a') && (input_key<='f') ) is_authorized=1; break; } // End du "switch(input_type)" // Si la touche était autorisée... if (is_authorized) { // ... alors on l'insère ... Insert_character(str,input_key,position/*,size*/); // ce qui augmente la taille de la chaine size++; // et qui risque de déplacer le curseur vers la droite if (size=visible_size) offset++; } // Enfin, on raffiche la chaine goto affichage; } // End du test d'autorisation de touche } // End du test de place libre break; affichage: size=strlen(str); // Formatage d'une partie de la chaine (si trop longue pour tenir) strncpy(display_string, str + offset, visible_size); display_string[visible_size]='\0'; if (offset>0) display_string[0]=LEFT_TRIANGLE_CHARACTER; if (visible_size + offset + 0 < size ) display_string[visible_size-1]=RIGHT_TRIANGLE_CHARACTER; Display_whole_string(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y),display_string,position - offset); Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); } // End du "switch(input_key)" Flush_update(); } // End du "while" Keyboard_click_allowed = 1; if (use_virtual_keyboard) { byte old_mouse_k = Mouse_K; Close_popup(); Mouse_K=old_mouse_k; Input_sticky_control=0; } // Effacement de la chaîne Block(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3),BACKGROUND_COLOR); // On raffiche la chaine correctement if (input_type==INPUT_TYPE_INTEGER) { if (str[0]=='\0') { strcpy(str,"0"); size=1; } Print_in_window(x_pos+((max_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); } else if (input_type==INPUT_TYPE_DECIMAL) { double value; // Discard extra digits value = Fround(atof(str), decimal_places); Sprint_double(str,value,decimal_places,visible_size); // Recompute updated size size = strlen(str); if (size<=visible_size) Print_in_window(x_pos+((visible_size-size)<<3),y_pos,str,TEXT_COLOR,BACKGROUND_COLOR); else Print_in_window_limited(x_pos,y_pos,str,visible_size,TEXT_COLOR,BACKGROUND_COLOR); } else { Print_in_window_limited(x_pos,y_pos,str,visible_size,TEXT_COLOR,BACKGROUND_COLOR); } Update_rect(window_x+(x_pos*Menu_factor_X),window_y+(y_pos*Menu_factor_Y), visible_size*(Menu_factor_X<<3),(Menu_factor_Y<<3)); return (input_key==SDLK_RETURN); } void Sprint_double(char *str, double value, byte decimal_places, byte min_positions) { int i; int length; sprintf(str,"%.*f",decimal_places, value); length=strlen(str); for (i=0; i= 0 && decimals[j]=='0'; j--) { decimals[j] = '\0'; } // If all decimals were removed, remove the dot too if (str[i+1]=='\0') str[i]='\0'; // Update string length length=strlen(str); // Ends the parent loop break; } } // Now try add spaces at beginning if (length