Adapt the remaining plugins to put the greyscale isr on cop. Now they can be used...
[Rockbox.git] / apps / plugins / text_editor.c
blob75bbccf8206555bac6cdcfe3cccebbf2a0730b4c
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Jonathan Gordon
12 * All files in this archive are subject to the GNU General Public License.
13 * See the file COPYING in the source tree root for full license agreement.
15 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
16 * KIND, either express or implied.
18 ****************************************************************************/
19 #include "plugin.h"
20 #include "playback_control.h"
22 #if PLUGIN_BUFFER_SIZE > 0x45000
23 #define MAX_CHARS 0x40000 /* 128 kiB */
24 #else
25 #define MAX_CHARS 0x6000 /* 24 kiB */
26 #endif
27 #define MAX_LINE_LEN 2048
28 PLUGIN_HEADER
29 static struct plugin_api* rb;
31 static char buffer[MAX_CHARS];
32 static char eol[3];
33 static int char_count = 0;
34 static int line_count = 0;
35 static int last_action_line = 0;
36 static int last_char_index = 0;
38 #define ACTION_INSERT 0
39 #define ACTION_GET 1
40 #define ACTION_REMOVE 2
41 #define ACTION_UPDATE 3
42 #define ACTION_CONCAT 4
44 int _do_action(int action, char* str, int line);
45 #ifndef HAVE_ADJUSTABLE_CPU_FREQ
46 #define do_action _do_action
47 #else
48 int do_action(int action, char* str, int line)
50 int r;
51 rb->cpu_boost(1);
52 r = _do_action(action,str,line);
53 rb->cpu_boost(0);
54 return r;
56 #endif
58 int _do_action(int action, char* str, int line)
60 int len;
61 int i=0,c=0;
62 if (line>=last_action_line)
64 i = last_action_line;
65 c = last_char_index;
67 while (i<line && i<line_count)
69 c += rb->strlen(&buffer[c])+1;
70 i++;
72 switch (action)
74 case ACTION_INSERT:
75 len = rb->strlen(str)+1;
76 if ( char_count+ len > MAX_CHARS )
77 return 0;
78 rb->memmove(&buffer[c+len],&buffer[c],char_count);
79 rb->strcpy(&buffer[c],str);
80 char_count += len;
81 line_count++;
82 break;
83 case ACTION_GET:
84 if (line > line_count)
85 return 0;
86 last_action_line = i;
87 last_char_index = c;
88 return c;
89 break;
90 case ACTION_REMOVE:
91 if (line > line_count)
92 return 0;
93 len = rb->strlen(&buffer[c])+1;
94 char_count -= len;
95 rb->memmove(&buffer[c],&buffer[c+len],char_count);
96 line_count--;
97 break;
98 case ACTION_UPDATE:
99 if (line > line_count)
100 return 0;
101 len = rb->strlen(&buffer[c])+1;
102 rb->memmove(&buffer[c+rb->strlen(str)+1],&buffer[c+len],char_count);
103 rb->strcpy(&buffer[c],str);
104 char_count += rb->strlen(str)+1-len;
105 break;
106 case ACTION_CONCAT:
107 if (line > line_count)
108 return 0;
109 rb->memmove(&buffer[c-1],&buffer[c],char_count);
110 break;
111 default:
112 return 0;
114 last_action_line = i;
115 last_char_index = c;
116 return 1;
118 char *list_get_name_cb(int selected_item,void* data,char* buf)
120 char *b = &buffer[do_action(ACTION_GET,0,selected_item)];
121 (void)data;
122 if (rb->strlen(b) >= MAX_PATH)
124 char t = b[MAX_PATH-10];
125 b[MAX_PATH-10] = '\0';
126 rb->snprintf(buf,MAX_PATH,"%s ...",b);
127 b[MAX_PATH-10] = t;
129 else rb->strcpy(buf,b);
130 return buf;
132 char filename[MAX_PATH];
133 int get_eol_string(char* fn)
135 int fd=-1;
136 char t;
137 if (!fn)
138 return 0;
139 else if (!fn[0])
140 return 0;
141 fd = rb->PREFIX(open(fn,O_RDONLY));
142 if (fd<0)
143 return 0;
144 eol[0] = '\0';
145 while (!eol[0])
147 if (!rb->read(fd,&t,1))
149 rb->strcpy(eol,"\n");
150 return 0;
152 if (t == '\r')
154 if (rb->read(fd,&t,1) && t=='\n')
155 rb->strcpy(eol,"\r\n");
156 else rb->strcpy(eol,"\r");
158 else if (t == '\n')
160 rb->strcpy(eol,"\n");
163 rb->close(fd);
164 return 1;
167 void save_changes(int overwrite)
169 int fd;
170 int i;
172 if (!filename[0] || !overwrite)
174 rb->strcpy(filename,"/");
175 rb->kbd_input(filename,MAX_PATH);
178 fd = rb->open(filename,O_WRONLY|O_CREAT|O_TRUNC);
179 if (fd < 0)
181 rb->splash(HZ*2, "Changes NOT saved");
182 return;
185 if (!overwrite)
186 /* current directory may have changed */
187 rb->reload_directory();
189 rb->lcd_clear_display();
190 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
191 rb->cpu_boost(1);
192 #endif
193 for (i=0;i<line_count;i++)
195 rb->fdprintf(fd,"%s%s",&buffer[do_action(ACTION_GET,0,i)],eol);
197 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
198 rb->cpu_boost(0);
199 #endif
200 rb->close(fd);
203 void setup_lists(struct gui_synclist *lists, int sel)
205 rb->gui_synclist_init(lists,list_get_name_cb,0, false, 1, NULL);
206 rb->gui_synclist_set_icon_callback(lists,NULL);
207 rb->gui_synclist_set_nb_items(lists,line_count);
208 rb->gui_synclist_limit_scroll(lists,true);
209 rb->gui_synclist_select_item(lists, sel);
210 rb->gui_synclist_draw(lists);
212 enum {
213 MENU_RET_SAVE = -1,
214 MENU_RET_NO_UPDATE,
215 MENU_RET_UPDATE,
217 int do_item_menu(int cur_sel, char* copy_buffer)
219 int ret = 0;
220 MENUITEM_STRINGLIST(menu, "Line Options", NULL,
221 "Cut/Delete", "Copy",
222 "Insert Above", "Insert Below",
223 "Concat To Above", "Save");
225 switch (rb->do_menu(&menu, NULL, NULL, false))
227 case 0: /* cut */
228 rb->strcpy(copy_buffer,&buffer[do_action(ACTION_GET,0,cur_sel)]);
229 do_action(ACTION_REMOVE,0,cur_sel);
230 ret = MENU_RET_UPDATE;
231 break;
232 case 1: /* copy */
233 rb->strcpy(copy_buffer,&buffer[do_action(ACTION_GET,0,cur_sel)]);
234 ret = MENU_RET_NO_UPDATE;
235 break;
236 case 2: /* insert above */
237 if (!rb->kbd_input(copy_buffer,MAX_LINE_LEN))
239 do_action(ACTION_INSERT,copy_buffer,cur_sel);
240 copy_buffer[0]='\0';
241 ret = MENU_RET_UPDATE;
243 break;
244 case 3: /* insert below */
245 if (!rb->kbd_input(copy_buffer,MAX_LINE_LEN))
247 do_action(ACTION_INSERT,copy_buffer,cur_sel+1);
248 copy_buffer[0]='\0';
249 ret = MENU_RET_UPDATE;
251 break;
252 case 4: /* cat to above */
253 if (cur_sel>0)
255 do_action(ACTION_CONCAT,0,cur_sel);
256 ret = MENU_RET_UPDATE;
258 break;
259 case 5: /* save */
260 ret = MENU_RET_SAVE;
261 break;
262 default:
263 ret = MENU_RET_NO_UPDATE;
264 break;
266 return ret;
269 #ifdef HAVE_LCD_COLOR
270 /* in misc.h but no need to polute the api */
271 #define toupper(c) (((c >= 'a') && (c <= 'z'))?c+'A':c)
272 #define isxdigit(c) ((c>='a' && c<= 'f') || (c>='A' && c<= 'F') \
273 || (c>='0' && c<= '9'))
274 #define hex2dec(c) (((c) >= '0' && ((c) <= '9')) ? (toupper(c)) - '0' : \
275 (toupper(c)) - 'A' + 10)
276 int hex_to_rgb(const char* hex, int* color)
277 { int ok = 1;
278 int i;
279 int red, green, blue;
281 if (rb->strlen(hex) == 6) {
282 for (i=0; i < 6; i++ ) {
283 if (!isxdigit(hex[i])) {
284 ok=0;
285 break;
289 if (ok) {
290 red = (hex2dec(hex[0]) << 4) | hex2dec(hex[1]);
291 green = (hex2dec(hex[2]) << 4) | hex2dec(hex[3]);
292 blue = (hex2dec(hex[4]) << 4) | hex2dec(hex[5]);
293 *color = LCD_RGBPACK(red,green,blue);
294 return 0;
298 return -1;
300 #endif /* HAVE_LCD_COLOR */
302 /* this is the plugin entry point */
303 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
305 int fd;
306 static char temp_line[MAX_LINE_LEN];
308 struct gui_synclist lists;
309 bool exit = false;
310 int button;
311 bool changed = false;
312 int cur_sel=0;
313 static char copy_buffer[MAX_LINE_LEN];
314 bool prev_show_statusbar;
315 #ifdef HAVE_LCD_COLOR
316 bool edit_colors_file = false;
317 #endif
319 rb = api;
321 copy_buffer[0]='\0';
322 prev_show_statusbar = rb->global_settings->statusbar;
323 rb->global_settings->statusbar = false;
325 #if LCD_DEPTH > 1
326 rb->lcd_set_backdrop(NULL);
327 #endif
329 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
330 rb->cpu_boost(1);
331 #endif
332 if (parameter)
334 #ifdef HAVE_LCD_COLOR
335 char *c = NULL;
336 #endif
337 rb->strcpy(filename,(char*)parameter);
338 if (!get_eol_string(filename))
340 rb->strcpy(eol,"\n");
342 fd = rb->open(filename,O_RDONLY);
343 if (fd<0)
345 rb->splash(HZ*2,"Couldnt open file: %s",(char*)parameter);
346 return PLUGIN_ERROR;
348 #ifdef HAVE_LCD_COLOR
349 c = rb->strrchr(filename, '.');
350 if (c && !rb->strcmp(c, ".colours"))
351 edit_colors_file = true;
352 #endif
353 /* read in the file */
354 while (rb->read_line(fd,temp_line,MAX_LINE_LEN))
356 if (!do_action(ACTION_INSERT,temp_line,line_count))
358 rb->splash(HZ*2,"Error reading file: %s",(char*)parameter);
359 rb->close(fd);
360 return PLUGIN_ERROR;
363 rb->close(fd);
365 else
367 filename[0] = '\0';
368 rb->strcpy(eol,"\n");
370 #ifdef HAVE_ADJUSTABLE_CPU_FREQ
371 rb->cpu_boost(0);
372 #endif
373 /* now dump it in the list */
374 setup_lists(&lists,0);
375 rb->lcd_update();
376 while (!exit)
378 rb->gui_synclist_draw(&lists);
379 cur_sel = rb->gui_synclist_get_sel_pos(&lists);
380 button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
381 if (rb->gui_synclist_do_button(&lists,&button,LIST_WRAP_UNLESS_HELD))
382 continue;
383 switch (button)
385 case ACTION_STD_OK:
387 bool edit_text = true;
388 #ifdef HAVE_LCD_COLOR
389 int color;
390 #endif
391 if (line_count)
392 rb->strcpy(temp_line,&buffer[do_action(ACTION_GET,0,cur_sel)]);
393 #ifdef HAVE_LCD_COLOR
394 if (edit_colors_file)
396 char *name = temp_line, *value = NULL;
397 char extension[MAX_LINE_LEN];
398 rb->settings_parseline(temp_line, &name, &value);
399 if (line_count)
401 MENUITEM_STRINGLIST(menu, "Edit What?", NULL,
402 "Extension", "Color",);
403 switch (rb->do_menu(&menu, NULL, NULL, false))
405 case 0:
406 edit_text = true;
407 break;
408 case 1:
409 edit_text = false;
410 if (value)
411 hex_to_rgb(value, &color);
412 else color = 0;
413 rb->strcpy(extension, name);
414 rb->set_color(rb->screens[SCREEN_MAIN], name, &color, -1);
415 rb->snprintf(temp_line, MAX_LINE_LEN, "%s: %02X%02X%02X",
416 extension, RGB_UNPACK_RED(color),
417 RGB_UNPACK_GREEN(color),
418 RGB_UNPACK_BLUE(color));
419 if (line_count)
421 do_action(ACTION_UPDATE,temp_line,cur_sel);
423 else do_action(ACTION_INSERT,temp_line,cur_sel);
424 changed = true;
425 break;
429 #endif
430 if (edit_text &&!rb->kbd_input(temp_line,MAX_LINE_LEN))
432 if (line_count)
434 do_action(ACTION_UPDATE,temp_line,cur_sel);
436 else do_action(ACTION_INSERT,temp_line,cur_sel);
437 changed = true;
440 break;
441 case ACTION_STD_CONTEXT:
442 if (!line_count) break;
443 rb->strcpy(copy_buffer,&buffer[do_action(ACTION_GET,0,cur_sel)]);
444 do_action(ACTION_REMOVE,0,cur_sel);
445 changed = true;
446 break;
447 case ACTION_STD_MENU:
448 { /* do the item menu */
449 switch (do_item_menu(cur_sel, copy_buffer))
451 case MENU_RET_SAVE:
452 save_changes(1);
453 changed = false;
454 break;
455 case MENU_RET_UPDATE:
456 changed = true;
457 break;
458 case MENU_RET_NO_UPDATE:
459 break;
462 break;
463 case ACTION_STD_CANCEL:
464 if (changed)
466 MENUITEM_STRINGLIST(menu, "Do What?", NULL,
467 "Return",
468 "Show Playback Menu", "Save Changes",
469 "Save As...", "Save and Exit",
470 "Ignore Changes and Exit");
471 switch (rb->do_menu(&menu, NULL, NULL, false))
473 case 0:
474 break;
475 case 1:
476 playback_control(rb);
477 break;
478 case 2: //save to disk
479 save_changes(1);
480 changed = 0;
481 break;
482 case 3:
483 save_changes(0);
484 changed = 0;
485 break;
487 case 4:
488 save_changes(1);
489 exit=1;
490 break;
491 case 5:
492 exit=1;
493 break;
496 else exit=1;
497 break;
499 rb->gui_synclist_set_nb_items(&lists,line_count);
501 rb->global_settings->statusbar = prev_show_statusbar;
502 return PLUGIN_OK;