Change spelling to British English in the filetype colours section
[maemo-rb.git] / apps / plugins / text_editor.c
blobc5515026dcfd2065436f524872134778fbff032b
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Jonathan Gordon
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
20 ****************************************************************************/
21 #include "plugin.h"
22 #include "lib/playback_control.h"
24 #if PLUGIN_BUFFER_SIZE > 0x45000
25 #define MAX_CHARS 0x40000 /* 128 kiB */
26 #else
27 #define MAX_CHARS 0x6000 /* 24 kiB */
28 #endif
29 #define MAX_LINE_LEN 2048
30 PLUGIN_HEADER
32 static char buffer[MAX_CHARS];
33 static char eol[3];
34 static int char_count = 0;
35 static int line_count = 0;
36 static int last_action_line = 0;
37 static int last_char_index = 0;
39 #define ACTION_INSERT 0
40 #define ACTION_GET 1
41 #define ACTION_REMOVE 2
42 #define ACTION_UPDATE 3
43 #define ACTION_CONCAT 4
45 int _do_action(int action, char* str, int line);
46 #ifndef HAVE_ADJUSTABLE_CPU_FREQ
47 #define do_action _do_action
48 #else
49 int do_action(int action, char* str, int line)
51 int r;
52 rb->cpu_boost(1);
53 r = _do_action(action,str,line);
54 rb->cpu_boost(0);
55 return r;
57 #endif
59 int _do_action(int action, char* str, int line)
61 int len;
62 int i=0,c=0;
63 if (line>=last_action_line)
65 i = last_action_line;
66 c = last_char_index;
68 while (i<line && i<line_count)
70 c += rb->strlen(&buffer[c])+1;
71 i++;
73 switch (action)
75 case ACTION_INSERT:
76 len = rb->strlen(str)+1;
77 if ( char_count+ len > MAX_CHARS )
78 return 0;
79 rb->memmove(&buffer[c+len],&buffer[c],char_count);
80 rb->strcpy(&buffer[c],str);
81 char_count += len;
82 line_count++;
83 break;
84 case ACTION_GET:
85 if (line > line_count)
86 return 0;
87 last_action_line = i;
88 last_char_index = c;
89 return c;
90 break;
91 case ACTION_REMOVE:
92 if (line > line_count)
93 return 0;
94 len = rb->strlen(&buffer[c])+1;
95 char_count -= len;
96 rb->memmove(&buffer[c],&buffer[c+len],char_count);
97 line_count--;
98 break;
99 case ACTION_UPDATE:
100 if (line > line_count)
101 return 0;
102 len = rb->strlen(&buffer[c])+1;
103 rb->memmove(&buffer[c+rb->strlen(str)+1],&buffer[c+len],char_count);
104 rb->strcpy(&buffer[c],str);
105 char_count += rb->strlen(str)+1-len;
106 break;
107 case ACTION_CONCAT:
108 if (line > line_count)
109 return 0;
110 rb->memmove(&buffer[c-1],&buffer[c],char_count);
111 break;
112 default:
113 return 0;
115 last_action_line = i;
116 last_char_index = c;
117 return 1;
119 char *list_get_name_cb(int selected_item, void* data,
120 char* buf, size_t buf_len)
122 (void)data;
123 char *b = &buffer[do_action(ACTION_GET,0,selected_item)];
124 if (rb->strlen(b) >= buf_len)
126 char t = b[buf_len-10];
127 b[buf_len-10] = '\0';
128 rb->snprintf(buf , buf_len, "%s ...", b);
129 b[buf_len-10] = t;
131 else rb->strncpy(buf, b, buf_len);
132 return buf;
134 char filename[MAX_PATH];
135 int get_eol_string(char* fn)
137 int fd=-1;
138 char t;
139 if (!fn)
140 return 0;
141 else if (!fn[0])
142 return 0;
143 fd = rb->open(fn,O_RDONLY);
144 if (fd<0)
145 return 0;
146 eol[0] = '\0';
147 while (!eol[0])
149 if (!rb->read(fd,&t,1))
151 rb->strcpy(eol,"\n");
152 return 0;
154 if (t == '\r')
156 if (rb->read(fd,&t,1) && t=='\n')
157 rb->strcpy(eol,"\r\n");
158 else rb->strcpy(eol,"\r");
160 else if (t == '\n')
162 rb->strcpy(eol,"\n");
165 rb->close(fd);
166 return 1;
169 void save_changes(int overwrite)
171 int fd;
172 int i;
174 if (!filename[0] || !overwrite)
176 rb->strcpy(filename,"/");
177 rb->kbd_input(filename,MAX_PATH);
180 fd = rb->open(filename,O_WRONLY|O_CREAT|O_TRUNC);
181 if (fd < 0)
183 rb->splash(HZ*2, "Changes NOT saved");
184 return;
187 if (!overwrite)
188 /* current directory may have changed */
189 rb->reload_directory();
191 rb->lcd_clear_display();
192 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
193 rb->cpu_boost(1);
194 #endif
195 for (i=0;i<line_count;i++)
197 rb->fdprintf(fd,"%s%s",&buffer[do_action(ACTION_GET,0,i)],eol);
199 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
200 rb->cpu_boost(0);
201 #endif
202 rb->close(fd);
205 void setup_lists(struct gui_synclist *lists, int sel)
207 rb->gui_synclist_init(lists,list_get_name_cb,0, false, 1, NULL);
208 rb->gui_synclist_set_icon_callback(lists,NULL);
209 rb->gui_synclist_set_nb_items(lists,line_count);
210 rb->gui_synclist_limit_scroll(lists,true);
211 rb->gui_synclist_select_item(lists, sel);
212 rb->gui_synclist_draw(lists);
214 enum {
215 MENU_RET_SAVE = -1,
216 MENU_RET_NO_UPDATE,
217 MENU_RET_UPDATE,
219 int do_item_menu(int cur_sel, char* copy_buffer)
221 int ret = 0;
222 MENUITEM_STRINGLIST(menu, "Line Options", NULL,
223 "Cut/Delete", "Copy",
224 "Insert Above", "Insert Below",
225 "Concat To Above", "Save",
226 "Show Playback Menu",);
228 switch (rb->do_menu(&menu, NULL, NULL, false))
230 case 0: /* cut */
231 rb->strcpy(copy_buffer,&buffer[do_action(ACTION_GET,0,cur_sel)]);
232 do_action(ACTION_REMOVE,0,cur_sel);
233 ret = MENU_RET_UPDATE;
234 break;
235 case 1: /* copy */
236 rb->strcpy(copy_buffer,&buffer[do_action(ACTION_GET,0,cur_sel)]);
237 ret = MENU_RET_NO_UPDATE;
238 break;
239 case 2: /* insert above */
240 if (!rb->kbd_input(copy_buffer,MAX_LINE_LEN))
242 do_action(ACTION_INSERT,copy_buffer,cur_sel);
243 copy_buffer[0]='\0';
244 ret = MENU_RET_UPDATE;
246 break;
247 case 3: /* insert below */
248 if (!rb->kbd_input(copy_buffer,MAX_LINE_LEN))
250 do_action(ACTION_INSERT,copy_buffer,cur_sel+1);
251 copy_buffer[0]='\0';
252 ret = MENU_RET_UPDATE;
254 break;
255 case 4: /* cat to above */
256 if (cur_sel>0)
258 do_action(ACTION_CONCAT,0,cur_sel);
259 ret = MENU_RET_UPDATE;
261 break;
262 case 5: /* save */
263 ret = MENU_RET_SAVE;
264 break;
265 case 6: /* playback menu */
266 playback_control(NULL);
267 ret = MENU_RET_UPDATE;
268 break;
269 default:
270 ret = MENU_RET_NO_UPDATE;
271 break;
273 return ret;
276 #ifdef HAVE_LCD_COLOR
277 /* in misc.h but no need to polute the api */
278 #define toupper(c) (((c >= 'a') && (c <= 'z'))?c+'A':c)
279 #define isxdigit(c) ((c>='a' && c<= 'f') || (c>='A' && c<= 'F') \
280 || (c>='0' && c<= '9'))
281 #define hex2dec(c) (((c) >= '0' && ((c) <= '9')) ? (toupper(c)) - '0' : \
282 (toupper(c)) - 'A' + 10)
283 int hex_to_rgb(const char* hex, int* color)
284 { int ok = 1;
285 int i;
286 int red, green, blue;
288 if (rb->strlen(hex) == 6) {
289 for (i=0; i < 6; i++ ) {
290 if (!isxdigit(hex[i])) {
291 ok=0;
292 break;
296 if (ok) {
297 red = (hex2dec(hex[0]) << 4) | hex2dec(hex[1]);
298 green = (hex2dec(hex[2]) << 4) | hex2dec(hex[3]);
299 blue = (hex2dec(hex[4]) << 4) | hex2dec(hex[5]);
300 *color = LCD_RGBPACK(red,green,blue);
301 return 0;
305 return -1;
307 #endif /* HAVE_LCD_COLOR */
309 /* this is the plugin entry point */
310 enum plugin_status plugin_start(const void* parameter)
312 int fd;
313 static char temp_line[MAX_LINE_LEN];
315 struct gui_synclist lists;
316 bool exit = false;
317 int button;
318 bool changed = false;
319 int cur_sel=0;
320 static char copy_buffer[MAX_LINE_LEN];
321 bool prev_show_statusbar;
322 #ifdef HAVE_LCD_COLOR
323 bool edit_colors_file = false;
324 #endif
326 copy_buffer[0]='\0';
327 prev_show_statusbar = rb->global_settings->statusbar;
328 rb->global_settings->statusbar = false;
330 #if LCD_DEPTH > 1
331 rb->lcd_set_backdrop(NULL);
332 #endif
334 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
335 rb->cpu_boost(1);
336 #endif
337 if (parameter)
339 #ifdef HAVE_LCD_COLOR
340 char *c = NULL;
341 #endif
342 rb->strcpy(filename,(char*)parameter);
343 if (!get_eol_string(filename))
345 rb->strcpy(eol,"\n");
347 fd = rb->open(filename,O_RDONLY);
348 if (fd<0)
350 rb->splashf(HZ*2,"Couldnt open file: %s",(char*)parameter);
351 return PLUGIN_ERROR;
353 #ifdef HAVE_LCD_COLOR
354 c = rb->strrchr(filename, '.');
355 if (c && !rb->strcmp(c, ".colours"))
356 edit_colors_file = true;
357 #endif
358 /* read in the file */
359 while (rb->read_line(fd,temp_line,MAX_LINE_LEN))
361 if (!do_action(ACTION_INSERT,temp_line,line_count))
363 rb->splashf(HZ*2,"Error reading file: %s",(char*)parameter);
364 rb->close(fd);
365 return PLUGIN_ERROR;
368 rb->close(fd);
370 else
372 filename[0] = '\0';
373 rb->strcpy(eol,"\n");
375 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
376 rb->cpu_boost(0);
377 #endif
378 /* now dump it in the list */
379 setup_lists(&lists,0);
380 rb->lcd_update();
381 while (!exit)
383 rb->gui_synclist_draw(&lists);
384 cur_sel = rb->gui_synclist_get_sel_pos(&lists);
385 button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
386 if (rb->gui_synclist_do_button(&lists,&button,LIST_WRAP_UNLESS_HELD))
387 continue;
388 switch (button)
390 case ACTION_STD_OK:
392 bool edit_text = true;
393 #ifdef HAVE_LCD_COLOR
394 int color;
395 #endif
396 if (line_count)
397 rb->strcpy(temp_line,&buffer[do_action(ACTION_GET,0,cur_sel)]);
398 #ifdef HAVE_LCD_COLOR
399 if (edit_colors_file)
401 char *name = temp_line, *value = NULL;
402 char extension[MAX_LINE_LEN];
403 rb->settings_parseline(temp_line, &name, &value);
404 if (line_count)
406 MENUITEM_STRINGLIST(menu, "Edit What?", NULL,
407 "Extension", "Colour",);
408 switch (rb->do_menu(&menu, NULL, NULL, false))
410 case 0:
411 edit_text = true;
412 break;
413 case 1:
414 edit_text = false;
415 if (value)
416 hex_to_rgb(value, &color);
417 else color = 0;
418 rb->strcpy(extension, name);
419 rb->set_color(rb->screens[SCREEN_MAIN], name, &color, -1);
420 rb->snprintf(temp_line, MAX_LINE_LEN, "%s: %02X%02X%02X",
421 extension, RGB_UNPACK_RED(color),
422 RGB_UNPACK_GREEN(color),
423 RGB_UNPACK_BLUE(color));
424 if (line_count)
426 do_action(ACTION_UPDATE,temp_line,cur_sel);
428 else do_action(ACTION_INSERT,temp_line,cur_sel);
429 changed = true;
430 break;
434 #endif
435 if (edit_text &&!rb->kbd_input(temp_line,MAX_LINE_LEN))
437 if (line_count)
439 do_action(ACTION_UPDATE,temp_line,cur_sel);
441 else do_action(ACTION_INSERT,temp_line,cur_sel);
442 changed = true;
445 break;
446 case ACTION_STD_CONTEXT:
447 if (!line_count) break;
448 rb->strcpy(copy_buffer,&buffer[do_action(ACTION_GET,0,cur_sel)]);
449 do_action(ACTION_REMOVE,0,cur_sel);
450 changed = true;
451 break;
452 case ACTION_STD_MENU:
453 { /* do the item menu */
454 switch (do_item_menu(cur_sel, copy_buffer))
456 case MENU_RET_SAVE:
457 save_changes(1);
458 changed = false;
459 break;
460 case MENU_RET_UPDATE:
461 changed = true;
462 break;
463 case MENU_RET_NO_UPDATE:
464 break;
467 break;
468 case ACTION_STD_CANCEL:
469 if (changed)
471 MENUITEM_STRINGLIST(menu, "Do What?", NULL,
472 "Return",
473 "Show Playback Menu", "Save Changes",
474 "Save As...", "Save and Exit",
475 "Ignore Changes and Exit");
476 switch (rb->do_menu(&menu, NULL, NULL, false))
478 case 0:
479 break;
480 case 1:
481 playback_control(NULL);
482 break;
483 case 2: //save to disk
484 save_changes(1);
485 changed = 0;
486 break;
487 case 3:
488 save_changes(0);
489 changed = 0;
490 break;
492 case 4:
493 save_changes(1);
494 exit=1;
495 break;
496 case 5:
497 exit=1;
498 break;
501 else exit=1;
502 break;
504 rb->gui_synclist_set_nb_items(&lists,line_count);
506 rb->global_settings->statusbar = prev_show_statusbar;
507 return PLUGIN_OK;