use the list context in credits which has to be defined for every target
[Rockbox.git] / apps / plugins / rockpaint.c
blob41519f66e1af61b1ddfaaef662b97fed6e854525
1 /***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
10 * Copyright (C) 2006 Antoine Cellerier <dionoea -at- videolan -dot- org>
11 * Based on parts of rockpaint 0.45, Copyright (C) 2005 Eli Sherer
13 * All files in this archive are subject to the GNU General Public License.
14 * See the file COPYING in the source tree root for full license agreement.
16 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
17 * KIND, either express or implied.
19 ****************************************************************************/
21 /**
22 * TODO:
23 * - implement 2 layers with alpha colors
24 * - take brush width into account when drawing shapes
25 * - handle bigger than screen bitmaps
26 * - cache fonts when building the font preview (else it only works well on simulators because they have "fast" disk read)
29 #include "plugin.h"
30 #include "errno.h"
31 #include "lib/bmp.h"
32 #include "lib/rgb_hsv.h"
34 PLUGIN_HEADER
36 /***********************************************************************
37 * Buttons
38 ***********************************************************************/
40 #if CONFIG_KEYPAD == IRIVER_H300_PAD
41 #define ROCKPAINT_QUIT BUTTON_OFF
42 #define ROCKPAINT_DRAW BUTTON_SELECT
43 #define ROCKPAINT_MENU BUTTON_ON
44 #define ROCKPAINT_TOOLBAR BUTTON_REC
45 #define ROCKPAINT_TOOLBAR2 BUTTON_MODE
46 #define ROCKPAINT_UP BUTTON_UP
47 #define ROCKPAINT_DOWN BUTTON_DOWN
48 #define ROCKPAINT_LEFT BUTTON_LEFT
49 #define ROCKPAINT_RIGHT BUTTON_RIGHT
51 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
52 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
53 #define ROCKPAINT_QUIT ( ~BUTTON_MAIN )
54 #define ROCKPAINT_DRAW BUTTON_SELECT
55 #define ROCKPAINT_MENU ( BUTTON_SELECT | BUTTON_MENU )
56 #define ROCKPAINT_TOOLBAR ( BUTTON_MENU | BUTTON_LEFT )
57 #define ROCKPAINT_TOOLBAR2 ( BUTTON_MENU | BUTTON_RIGHT )
58 #define ROCKPAINT_UP BUTTON_MENU
59 #define ROCKPAINT_DOWN BUTTON_PLAY
60 #define ROCKPAINT_LEFT BUTTON_LEFT
61 #define ROCKPAINT_RIGHT BUTTON_RIGHT
63 #elif ( CONFIG_KEYPAD == IAUDIO_X5M5_PAD )
64 #define ROCKPAINT_QUIT BUTTON_POWER
65 #define ROCKPAINT_DRAW BUTTON_SELECT
66 #define ROCKPAINT_MENU BUTTON_PLAY
67 #define ROCKPAINT_TOOLBAR BUTTON_REC
68 #define ROCKPAINT_TOOLBAR2 ( BUTTON_REC | BUTTON_LEFT )
69 #define ROCKPAINT_UP BUTTON_UP
70 #define ROCKPAINT_DOWN BUTTON_DOWN
71 #define ROCKPAINT_LEFT BUTTON_LEFT
72 #define ROCKPAINT_RIGHT BUTTON_RIGHT
74 #elif CONFIG_KEYPAD == GIGABEAT_PAD
75 #define ROCKPAINT_QUIT BUTTON_POWER
76 #define ROCKPAINT_DRAW BUTTON_SELECT
77 #define ROCKPAINT_MENU BUTTON_MENU
78 #define ROCKPAINT_TOOLBAR BUTTON_A
79 #define ROCKPAINT_TOOLBAR2 ( BUTTON_A | BUTTON_LEFT )
80 #define ROCKPAINT_UP BUTTON_UP
81 #define ROCKPAINT_DOWN BUTTON_DOWN
82 #define ROCKPAINT_LEFT BUTTON_LEFT
83 #define ROCKPAINT_RIGHT BUTTON_RIGHT
85 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
86 (CONFIG_KEYPAD == SANSA_C200_PAD)
87 #define ROCKPAINT_QUIT BUTTON_POWER
88 #define ROCKPAINT_DRAW BUTTON_SELECT
89 #define ROCKPAINT_MENU ( BUTTON_SELECT | BUTTON_POWER )
90 #define ROCKPAINT_TOOLBAR BUTTON_REC
91 #define ROCKPAINT_TOOLBAR2 ( BUTTON_REC | BUTTON_LEFT )
92 #define ROCKPAINT_UP BUTTON_UP
93 #define ROCKPAINT_DOWN BUTTON_DOWN
94 #define ROCKPAINT_LEFT BUTTON_LEFT
95 #define ROCKPAINT_RIGHT BUTTON_RIGHT
97 #elif ( CONFIG_KEYPAD == IRIVER_H10_PAD )
98 #define ROCKPAINT_QUIT BUTTON_POWER
99 #define ROCKPAINT_DRAW BUTTON_FF
100 #define ROCKPAINT_MENU BUTTON_PLAY
101 #define ROCKPAINT_TOOLBAR BUTTON_REW
102 #define ROCKPAINT_TOOLBAR2 ( BUTTON_REW | BUTTON_LEFT )
103 #define ROCKPAINT_UP BUTTON_SCROLL_UP
104 #define ROCKPAINT_DOWN BUTTON_SCROLL_DOWN
105 #define ROCKPAINT_LEFT BUTTON_LEFT
106 #define ROCKPAINT_RIGHT BUTTON_RIGHT
108 #else
109 #error "Please define keys for this keypad"
110 #endif
112 /***********************************************************************
113 * Palette Default Colors
114 ***********************************************************************/
115 #define COLOR_BLACK LCD_RGBPACK(0,0,0)
116 #define COLOR_WHITE LCD_RGBPACK(255,255,255)
117 #define COLOR_DARKGRAY LCD_RGBPACK(128,128,128)
118 #define COLOR_LIGHTGRAY LCD_RGBPACK(192,192,192)
119 #define COLOR_RED LCD_RGBPACK(128,0,0)
120 #define COLOR_LIGHTRED LCD_RGBPACK(255,0,0)
121 #define COLOR_DARKYELLOW LCD_RGBPACK(128,128,0)
122 #define COLOR_YELLOW LCD_RGBPACK(255,255,0)
123 #define COLOR_GREEN LCD_RGBPACK(0,128,0)
124 #define COLOR_LIGHTGREN LCD_RGBPACK(0,255,0)
125 #define COLOR_CYAN LCD_RGBPACK(0,128,128)
126 #define COLOR_LIGHTCYAN LCD_RGBPACK(0,255,255)
127 #define COLOR_BLUE LCD_RGBPACK(0,0,128)
128 #define COLOR_LIGHTBLUE LCD_RGBPACK(0,0,255)
129 #define COLOR_PURPLE LCD_RGBPACK(128,0,128)
130 #define COLOR_PINK LCD_RGBPACK(255,0,255)
131 #define COLOR_BROWN LCD_RGBPACK(128,64,0)
132 #define COLOR_LIGHTBROWN LCD_RGBPACK(255,128,64)
134 #define SPLASH_SCREEN PLUGIN_APPS_DIR "/rockpaint/splash.bmp"
135 #define ROCKPAINT_TITLE_FONT 2
137 /***********************************************************************
138 * Program Colors
139 ***********************************************************************/
140 #define ROCKPAINT_PALETTE LCD_RGBPACK(0,64,128)
141 #define ROCKPAINT_SELECTED LCD_RGBPACK(128,192,255)
143 #define ROWS LCD_HEIGHT
144 #define COLS LCD_WIDTH
147 * Toolbar positioning stuff ... don't read this unless you really need to
149 * TB Toolbar
150 * SP Separator
151 * SC Selected Color
152 * PL Palette
153 * TL Tools
156 /* Separator sizes */
157 #define TB_SP_MARGIN 3
158 #define TB_SP_WIDTH (2+2*TB_SP_MARGIN)
160 /* Selected color sizes */
161 #define TB_SC_SIZE 12
163 /* Palette sizes */
164 #define TB_PL_COLOR_SIZE 7
165 #define TB_PL_COLOR_SPACING 2
166 #define TB_PL_WIDTH ( 9 * TB_PL_COLOR_SIZE + 8 * TB_PL_COLOR_SPACING )
167 #define TB_PL_HEIGHT ( TB_PL_COLOR_SIZE * 2 + TB_PL_COLOR_SPACING )
169 /* Tools sizes */
170 #define TB_TL_SIZE 8
171 #define TB_TL_SPACING 2
172 #define TB_TL_WIDTH ( 7 * ( TB_TL_SIZE + TB_TL_SPACING ) - TB_TL_SPACING )
173 #define TB_TL_HEIGHT ( 2 * TB_TL_SIZE + TB_TL_SPACING )
175 /* Menu button size ... gruik */
176 #define TB_MENU_MIN_WIDTH 30
178 /* Selected colors position */
179 #define TB_SC_FG_TOP 2
180 #define TB_SC_FG_LEFT 2
181 #define TB_SC_BG_TOP (TB_SC_FG_TOP+TB_PL_COLOR_SIZE*2+TB_PL_COLOR_SPACING-TB_SC_SIZE)
182 #define TB_SC_BG_LEFT (TB_SC_FG_LEFT+TB_PL_COLOR_SIZE*2+TB_PL_COLOR_SPACING-TB_SC_SIZE)
184 /* Palette position */
185 #define TB_PL_TOP TB_SC_FG_TOP
186 #define TB_PL_LEFT (TB_SC_BG_LEFT + TB_SC_SIZE + TB_PL_COLOR_SPACING)
188 /* Tools position */
189 #define TB_TL_TOP TB_SC_FG_TOP
190 #define TB_TL_LEFT ( TB_PL_LEFT + TB_PL_WIDTH-1 + TB_SP_WIDTH )
192 #if TB_TL_LEFT + TB_TL_WIDTH + TB_MENU_MIN_WIDTH >= LCD_WIDTH
193 #undef TB_TL_TOP
194 #undef TB_TL_LEFT
195 #define TB_TL_TOP ( TB_PL_TOP + TB_PL_HEIGHT + 4 )
196 #define TB_TL_LEFT TB_SC_FG_LEFT
197 #endif
199 /* Menu button position */
200 #define TB_MENU_TOP ( TB_TL_TOP + (TB_TL_HEIGHT-8)/2 )
201 #define TB_MENU_LEFT ( TB_TL_LEFT + TB_TL_WIDTH-1 + TB_SP_WIDTH )
203 #define TB_HEIGHT ( TB_TL_TOP + TB_TL_HEIGHT + 1 )
206 static void draw_pixel(int x,int y);
207 static void draw_line( int x1, int y1, int x2, int y2 );
208 static void draw_rect( int x1, int y1, int x2, int y2 );
209 static void draw_toolbars(bool update);
210 static void inv_cursor(bool update);
211 static void restore_screen(void);
212 static void clear_drawing(void);
213 static void goto_menu(void);
214 static int load_bitmap( char *filename );
215 static int save_bitmap( char *filename );
216 static void draw_rect_full( int x1, int y1, int x2, int y2 );
217 extern int errno;
219 /***********************************************************************
220 * Global variables
221 ***********************************************************************/
223 #if !defined(SIMULATOR) || defined(__MINGW32__) || defined(__CYGWIN__)
224 int errno;
225 #endif
227 static struct plugin_api* rb;
229 MEM_FUNCTION_WRAPPERS(rb);
231 static int drawcolor=0; /* Current color (in palette) */
232 static int bgdrawcolor=9; /* Current background color (in palette) */
233 bool isbg = false; /* gruik ugly hack alert */
235 static int preview=false; /* Is preview mode on ? */
237 /* TODO: clean this up */
238 static int x=0, y=0; /* cursor position */
239 static int prev_x=-1, prev_y=-1; /* previous saved cursor position */
240 static int prev_x2=-1, prev_y2=-1;
241 static int prev_x3=-1, prev_y3=-1;
242 static int tool_mode=-1;
245 static int bsize=1; /* brush size */
246 static int bspeed=1; /* brush speed */
248 enum Tools { Brush = 0, /* Regular brush */
249 Fill = 1, /* Fill a shape with current color */
250 SelectRectangle = 2,
251 ColorPicker = 3, /* Pick a color */
252 Line = 4, /* Draw a line between two points */
253 Unused = 5, /* THIS IS UNUSED ... */
254 Curve = 6,
255 Text = 7,
256 Rectangle = 8, /* Draw a rectangle */
257 RectangleFull = 9,
258 Oval = 10, /* Draw an oval */
259 OvalFull = 11,
260 LinearGradient = 12,
261 RadialGradient = 13
264 enum Tools tool = Brush;
266 static bool quit=false;
267 static int gridsize=0;
269 static fb_data rp_colors[18] =
271 COLOR_BLACK, COLOR_DARKGRAY, COLOR_RED, COLOR_DARKYELLOW,
272 COLOR_GREEN, COLOR_CYAN, COLOR_BLUE, COLOR_PURPLE, COLOR_BROWN,
273 COLOR_WHITE, COLOR_LIGHTGRAY, COLOR_LIGHTRED, COLOR_YELLOW,
274 COLOR_LIGHTGREN, COLOR_LIGHTCYAN, COLOR_LIGHTBLUE, COLOR_PINK,
275 COLOR_LIGHTBROWN
278 static fb_data save_buffer[ ROWS*COLS ];
280 extern fb_data rockpaint[];
281 extern fb_data rockpaint_hsvrgb[];
283 /* Maximum string size allowed for the text tool */
284 #define MAX_TEXT 255
286 static union
288 /* Used by fill and gradient algorithms */
289 struct
291 short x;
292 short y;
293 } coord[ ROWS*COLS ];
295 /* Used by bezier curve algorithms */
296 struct
298 short x1, y1;
299 short x2, y2;
300 short x3, y3;
301 short x4, y4;
302 short depth;
303 } bezier[ (ROWS*COLS)/5 ]; /* We have 4.5 times more data per struct
304 * than coord ... so we divide to take
305 * less memory. */
307 /* Used to cut/copy/paste data */
308 fb_data clipboard[ ROWS*COLS ];
310 /* Used for text mode */
311 struct
313 char text[MAX_TEXT+1];
314 char font[MAX_PATH+1];
315 char old_font[MAX_PATH+1];
316 int fh_buf[30];
317 int fw_buf[30];
318 char fontname_buf[30][MAX_PATH];
319 } text;
320 } buffer;
322 /* Current filename */
323 static char filename[MAX_PATH+1];
325 /* Font preview buffer */
326 //#define FONT_PREVIEW_WIDTH ((LCD_WIDTH-30)/8)
327 //#define FONT_PREVIEW_HEIGHT 1000
328 //static unsigned char fontpreview[FONT_PREVIEW_WIDTH*FONT_PREVIEW_HEIGHT];
330 /***********************************************************************
331 * Offscreen buffer/Text/Fonts handling
333 * Parts of code taken from firmware/drivers/lcd-16bit.c
334 ***********************************************************************/
335 static void buffer_mono_bitmap_part(
336 fb_data *buf, int buf_width, int buf_height,
337 const unsigned char *src, int src_x, int src_y,
338 int stride, int x, int y, int width, int height )
339 /* this function only draws the foreground part of the bitmap */
341 const unsigned char *src_end;
342 fb_data *dst, *dst_end;
343 unsigned fgcolor = rb->lcd_get_foreground();
345 /* nothing to draw? */
346 if( ( width <= 0 ) || ( height <= 0 ) || ( x >= buf_width )
347 || ( y >= buf_height ) || ( x + width <= 0 ) || ( y + height <= 0 ) )
348 return;
350 /* clipping */
351 if( x < 0 )
353 width += x;
354 src_x -= x;
355 x = 0;
357 if( y < 0 )
359 height += y;
360 src_y -= y;
361 y = 0;
363 if( x + width > buf_width )
364 width = buf_width - x;
365 if( y + height > buf_height )
366 height = buf_height - y;
368 src += stride * (src_y >> 3) + src_x; /* move starting point */
369 src_y &= 7;
370 src_end = src + width;
372 dst = buf + y*buf_width + x;
376 const unsigned char *src_col = src++;
377 unsigned data = *src_col >> src_y;
378 fb_data *dst_col = dst++;
379 int numbits = 8 - src_y;
381 dst_end = dst_col + height * buf_width;
384 if( data & 0x01 )
385 *dst_col = fgcolor; /* FIXME ? */
387 dst_col += buf_width;
389 data >>= 1;
390 if( --numbits == 0 )
392 src_col += stride;
393 data = *src_col;
394 numbits = 8;
396 } while( dst_col < dst_end );
397 } while( src < src_end );
400 static void buffer_putsxyofs( fb_data *buf, int buf_width, int buf_height,
401 int x, int y, int ofs, const unsigned char *str )
403 unsigned short ch;
404 unsigned short *ucs;
406 struct font *pf = rb->font_get( FONT_UI );
407 if( !pf ) pf = rb->font_get( FONT_SYSFIXED );
409 ucs = rb->bidi_l2v( str, 1 );
411 while( (ch = *ucs++) != 0 && x < buf_width )
413 int width;
414 const unsigned char *bits;
416 /* get proportional width and glyph bits */
417 width = rb->font_get_width( pf, ch );
419 if( ofs > width )
421 ofs -= width;
422 continue;
425 bits = rb->font_get_bits( pf, ch );
427 buffer_mono_bitmap_part( buf, buf_width, buf_height, bits, ofs, 0, width, x, y, width - ofs, pf->height);
429 x += width - ofs;
430 ofs = 0;
434 /***********************************************************************
435 * Menu handling
436 ***********************************************************************/
437 struct menu_items
439 int value;
440 char label[16]; /* GRUIK ? */
443 #define MENU_ESC -1242
444 enum {
445 /* Generic menu items */
446 MENU_END = -42, MENU_TITLE = -12,
447 /* Main menu */
448 MAIN_MENU_RESUME,
449 MAIN_MENU_NEW, MAIN_MENU_LOAD, MAIN_MENU_SAVE,
450 MAIN_MENU_BRUSH_SIZE, MAIN_MENU_BRUSH_SPEED, MAIN_MENU_COLOR,
451 MAIN_MENU_GRID_SIZE,
452 MAIN_MENU_EXIT,
453 /* Select action menu */
454 SELECT_MENU_CUT, SELECT_MENU_COPY, SELECT_MENU_INVERT,
455 SELECT_MENU_HFLIP, SELECT_MENU_VFLIP, SELECT_MENU_ROTATE90,
456 SELECT_MENU_ROTATE180, SELECT_MENU_ROTATE270,
457 SELECT_MENU_CANCEL,
458 /* Text menu */
459 TEXT_MENU_TEXT, TEXT_MENU_FONT,
460 TEXT_MENU_PREVIEW, TEXT_MENU_APPLY, TEXT_MENU_CANCEL,
463 static struct menu_items main_menu[]=
464 { { MENU_TITLE, "RockPaint" },
465 { MAIN_MENU_RESUME, "Resume" },
466 { MAIN_MENU_NEW, "New" },
467 { MAIN_MENU_LOAD, "Load" },
468 { MAIN_MENU_SAVE, "Save" },
469 { MAIN_MENU_BRUSH_SIZE, "Brush Size" },
470 { MAIN_MENU_BRUSH_SPEED, "Brush Speed" },
471 { MAIN_MENU_COLOR, "Choose Color" },
472 { MAIN_MENU_GRID_SIZE, "Grid Size" },
473 { MAIN_MENU_EXIT, "Exit" },
474 { MENU_END, "" } };
476 static struct menu_items size_menu[] =
477 { { MENU_TITLE, "Choose Size" },
478 { 1, "1x" },
479 { 2, "2x" },
480 { 4, "4x" },
481 { 8, "8x" },
482 { MENU_END, "" } };
484 static struct menu_items speed_menu[] =
485 { { MENU_TITLE, "Choose Speed" },
486 { 1, "1x" },
487 { 2, "2x" },
488 { 4, "4x" },
489 { MENU_END, "" } };
491 static struct menu_items gridsize_menu[] =
492 { { MENU_TITLE, "Grid Size" },
493 { 0, "No grid" },
494 { 5, "5px" },
495 { 10, "10px" },
496 { 20, "20px" },
497 { MENU_END, "" } };
499 static struct menu_items select_menu[] =
500 { { MENU_TITLE, "Select..." },
501 { SELECT_MENU_CUT, "Cut" },
502 { SELECT_MENU_COPY, "Copy" },
503 { SELECT_MENU_INVERT, "Invert" },
504 { SELECT_MENU_HFLIP, "Horizontal flip" },
505 { SELECT_MENU_VFLIP, "Vertical flip" },
506 // { SELECT_MENU_ROTATE90, "Rotate 90°" },
507 { SELECT_MENU_ROTATE180, "Rotate 180°" },
508 // { SELECT_MENU_ROTATE270, "Rotate 270°" },
509 { SELECT_MENU_CANCEL, "Cancel" },
510 { MENU_END, "" } };
512 static struct menu_items text_menu[] =
513 { { MENU_TITLE, "Text" },
514 { TEXT_MENU_TEXT, "Set text" },
515 { TEXT_MENU_FONT, "Change font" },
516 { TEXT_MENU_PREVIEW, "Preview" },
517 { TEXT_MENU_APPLY, "Apply" },
518 { TEXT_MENU_CANCEL, "Cancel" },
519 { MENU_END, "" } };
521 static int draw_window( int height, int width,
522 int *top, int *left,
523 const char *title )
525 int fh;
526 rb->lcd_getstringsize( title, NULL, &fh );
527 fh++;
529 const int _top = ( LCD_HEIGHT - height ) / 2;
530 const int _left = ( LCD_WIDTH - width ) / 2;
531 if( top ) *top = _top;
532 if( left ) *left = _left;
533 rb->lcd_set_background(COLOR_BLUE);
534 rb->lcd_set_foreground(COLOR_LIGHTGRAY);
535 rb->lcd_fillrect( _left, _top, width, height );
536 rb->lcd_set_foreground(COLOR_BLUE);
537 rb->lcd_fillrect( _left, _top, width, fh+4 );
538 rb->lcd_set_foreground(COLOR_WHITE);
539 rb->lcd_putsxy( _left+2, _top+2, title );
540 rb->lcd_set_foreground(COLOR_BLACK);
541 rb->lcd_drawrect( _left, _top, width, height );
542 return _top+fh+4;
545 static int menu_display( struct menu_items menu[], int prev_value )
547 int i,
548 fh, /* font height */
549 width, height,
550 a, b,
551 selection=1,
552 menu_length,
553 top, left;
554 int scroll = 0, onscreen = 0;
556 rb->lcd_getstringsize( menu[0].label, &width, &fh );
557 for( i=1; menu[i].value != MENU_END; i++ )
559 if( prev_value == menu[i].value )
561 selection = i;
563 rb->lcd_getstringsize( menu[i].label, &a, &b );
564 if( a > width ) width = a;
565 if( b > fh ) fh = b;
567 menu_length = i;
568 fh++;
569 width += 10;
571 height = menu_length * fh + 4 + 2 + 2;
572 if( height >= LCD_HEIGHT )
574 scroll = 1;
575 onscreen = ( LCD_HEIGHT - 4 - 2 - 2 )/fh;
576 height = onscreen * fh + 4 + 2 + 2;
577 width += 5;
579 else
581 onscreen = menu_length;
584 draw_window( height, width, &top, &left, menu[0].label );
586 while( 1 )
588 for( i = (scroll == 0 ? 1 : scroll);
589 i < (scroll ? scroll + onscreen - 1:onscreen);
590 i++ )
592 if( i == selection )
594 rb->lcd_set_foreground( COLOR_WHITE );
595 rb->lcd_set_background( COLOR_BLUE );
597 else
599 rb->lcd_set_foreground( COLOR_BLACK );
600 rb->lcd_set_background( COLOR_LIGHTGRAY );
602 rb->lcd_putsxy( left+2,
603 top+6+fh*(i-(scroll == 0 ? 0 : scroll-1 )),
604 menu[i].label );
606 if( scroll )
608 int scroll_height = ((height-fh-4-2)*onscreen)/menu_length;
609 rb->lcd_set_foreground( COLOR_BLACK );
610 rb->lcd_vline( left+width-5, top+fh+4, top+height-2 );
611 rb->lcd_fillrect( left+width-4,
612 top+fh+4+((height-4-2-fh-scroll_height)*(scroll-1))/(menu_length-onscreen),
613 3, scroll_height );
615 rb->lcd_update();
617 switch( rb->button_get(true) )
619 case ROCKPAINT_UP:
620 case ROCKPAINT_UP|BUTTON_REPEAT:
621 selection = (selection + menu_length-1)%menu_length;
622 if( !selection ) selection = menu_length-1;
623 break;
625 case ROCKPAINT_DOWN:
626 case ROCKPAINT_DOWN|BUTTON_REPEAT:
627 selection = (selection + 1)%menu_length;
628 if( !selection ) selection++;
629 break;
631 case ROCKPAINT_LEFT:
632 restore_screen();
633 return MENU_ESC;
635 case ROCKPAINT_RIGHT:
636 case ROCKPAINT_DRAW:
637 restore_screen();
638 return menu[selection].value;
640 if( scroll )
642 if( selection < scroll )
644 scroll = selection;
645 draw_window( height, width, NULL, NULL, menu[0].label );
647 if( selection >= scroll + onscreen - 1 )
649 scroll++;
650 draw_window( height, width, NULL, NULL, menu[0].label );
656 /***********************************************************************
657 * File browser
658 ***********************************************************************/
660 char bbuf[MAX_PATH+1]; /* used by file and font browsers */
661 char bbuf_s[MAX_PATH+1]; /* used by file and font browsers */
663 static bool browse( char *dst, int dst_size, const char *start )
665 #define WIDTH ( LCD_WIDTH - 20 )
666 #define HEIGHT ( LCD_HEIGHT - 20 )
667 #define LINE_SPACE 2
668 int top, top_inside, left;
670 DIR *d;
671 struct dirent *de;
672 int fvi = 0; /* first visible item */
673 int lvi = 0; /* last visible item */
674 int si = 0; /* selected item */
675 int li = 0; /* last item */
676 int i;
678 int fh;
679 char *a;
681 rb->lcd_getstringsize( "Ap", NULL, &fh );
683 rb->strcpy( bbuf, start );
684 a = bbuf+rb->strlen(bbuf)-1;
685 if( *a != '/' )
687 a[1] = '/';
688 a[2] = '\0';
691 while( 1 )
693 d = rb->opendir( bbuf );
694 if( !d )
697 if( errno == ENOTDIR )
699 /* this is a file */
700 bbuf[rb->strlen(bbuf)-1] = '\0';
701 rb->strncpy( dst, bbuf, dst_size );
702 return true;
704 else if( errno == EACCES || errno == ENOENT )
706 bbuf[0] = '/'; bbuf[1] = '\0';
707 d = rb->opendir( "/" );
709 else
711 return false;
714 top_inside = draw_window( HEIGHT, WIDTH, &top, &left, bbuf );
715 i = 0;
716 li = -1;
717 while( i < fvi )
719 rb->readdir( d );
720 i++;
722 while( top_inside+(i-fvi)*(fh+LINE_SPACE) < HEIGHT )
724 de = rb->readdir( d );
725 if( !de )
727 li = i-1;
728 break;
730 rb->lcd_set_foreground((si==i?COLOR_WHITE:COLOR_BLACK));
731 rb->lcd_set_background((si==i?COLOR_BLUE:COLOR_LIGHTGRAY));
732 rb->lcd_putsxy( left+10,
733 top_inside+(i-fvi)*(fh+LINE_SPACE),
734 de->d_name );
735 if( si == i )
736 rb->strcpy( bbuf_s, de->d_name );
737 i++;
739 lvi = i-1;
740 if( li == -1 )
742 if( !rb->readdir( d ) )
744 li = lvi;
747 rb->closedir( d );
749 rb->lcd_update();
751 switch( rb->button_get(true) )
753 case ROCKPAINT_UP:
754 case ROCKPAINT_UP|BUTTON_REPEAT:
755 if( si > 0 )
757 si--;
758 if( si<fvi )
760 fvi--;
763 break;
765 case ROCKPAINT_DOWN:
766 case ROCKPAINT_DOWN|BUTTON_REPEAT:
767 if( li == -1 || si < li )
769 si++;
770 if( si>lvi )
772 fvi++;
775 break;
777 case ROCKPAINT_LEFT:
778 if( bbuf[0] == '/' && !bbuf[1] ) return false;
779 bbuf_s[0] = '.';
780 bbuf_s[1] = '.';
781 bbuf_s[2] = '\0';
782 case ROCKPAINT_RIGHT:
783 case ROCKPAINT_DRAW:
784 if( *bbuf_s == '.' && !bbuf_s[1] ) break;
785 a = bbuf;
786 while( *a ) a++;
787 if( *bbuf_s == '.' && bbuf_s[1] == '.' && !bbuf_s[2] )
789 a--;
790 if( a == bbuf ) break;
791 if( *a == '/' ) a--;
792 while( *a != '/' ) a--;
793 *++a = '\0';
794 break;
796 rb->strcpy( a, bbuf_s );
797 while( *a ) a++;
798 *a++ = '/';
799 *a = '\0';
800 fvi = si = 0;
801 break;
805 #undef WIDTH
806 #undef HEIGHT
807 #undef LINE_SPACE
810 /***********************************************************************
811 * Font browser
813 * FIXME: This still needs some work ... it currently only works fine
814 * on the simulators, disk spins too much on real targets -> rendered
815 * font buffer needed.
816 ***********************************************************************/
817 static bool browse_fonts( char *dst, int dst_size )
819 char old_font[MAX_PATH];
820 #define WIDTH ( LCD_WIDTH - 20 )
821 #define HEIGHT ( LCD_HEIGHT - 20 )
822 #define LINE_SPACE 2
823 int top, top_inside = 0, left;
825 DIR *d;
826 struct dirent *de;
827 int fvi = 0; /* first visible item */
828 int lvi = 0; /* last visible item */
829 int si = 0; /* selected item */
830 int osi = 0; /* old selected item */
831 int li = 0; /* last item */
832 int nvih = 0; /* next visible item height */
833 int i;
834 int b_need_redraw = 1; /* Do we need to redraw ? */
836 int cp = 0; /* current position */
837 int fh; /* font height */
839 #define fh_buf buffer.text.fh_buf /* 30 might not be enough ... */
840 #define fw_buf buffer.text.fw_buf
841 int fw;
842 #define fontname_buf buffer.text.fontname_buf
844 rb->snprintf( old_font, MAX_PATH,
845 FONT_DIR "/%s.fnt",
846 rb->global_settings->font_file );
848 while( 1 )
850 if( !b_need_redraw )
852 /* we don't need to redraw ... but we need to unselect
853 * the previously selected item */
854 cp = top_inside + LINE_SPACE;
855 for( i = 0; i+fvi < osi; i++ )
857 cp += fh_buf[i] + LINE_SPACE;
859 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
860 rb->lcd_fillrect( left+10, cp, fw_buf[i], fh_buf[i] );
861 rb->lcd_set_drawmode(DRMODE_SOLID);
864 if( b_need_redraw )
866 b_need_redraw = 0;
868 d = rb->opendir( FONT_DIR "/" );
869 if( !d )
871 return false;
873 top_inside = draw_window( HEIGHT, WIDTH, &top, &left, "Fonts" );
874 i = 0;
875 li = -1;
876 while( i < fvi )
878 rb->readdir( d );
879 i++;
881 cp = top_inside+LINE_SPACE;
883 rb->lcd_set_foreground(COLOR_BLACK);
884 rb->lcd_set_background(COLOR_LIGHTGRAY);
886 while( cp < top+HEIGHT )
888 de = rb->readdir( d );
889 if( !de )
891 li = i-1;
892 break;
894 if( rb->strlen( de->d_name ) < 4
895 || rb->strcmp( de->d_name + rb->strlen( de->d_name ) - 4,
896 ".fnt" ) )
897 continue;
898 rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s",
899 de->d_name );
900 rb->font_load( bbuf );
901 rb->font_getstringsize( de->d_name, &fw, &fh, FONT_UI );
902 if( nvih > 0 )
904 nvih -= fh;
905 fvi++;
906 if( nvih < 0 ) nvih = 0;
907 i++;
908 continue;
910 if( cp + fh >= top+HEIGHT )
912 nvih = fh;
913 break;
915 rb->lcd_putsxy( left+10, cp, de->d_name );
916 fh_buf[i-fvi] = fh;
917 fw_buf[i-fvi] = fw;
918 cp += fh + LINE_SPACE;
919 rb->strcpy( fontname_buf[i-fvi], bbuf );
920 i++;
922 lvi = i-1;
923 if( li == -1 )
925 if( !(de = rb->readdir( d ) ) )
927 li = lvi;
929 else if( !nvih && !rb->strlen( de->d_name ) < 4
930 && !rb->strcmp( de->d_name + rb->strlen( de->d_name ) - 4,
931 ".fnt" ) )
933 rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s",
934 de->d_name );
935 rb->font_load( bbuf );
936 rb->font_getstringsize( de->d_name, NULL, &fh, FONT_UI );
937 nvih = fh;
940 rb->font_load( old_font );
941 rb->closedir( d );
944 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
945 cp = top_inside + LINE_SPACE;
946 for( i = 0; i+fvi < si; i++ )
948 cp += fh_buf[i] + LINE_SPACE;
950 rb->lcd_fillrect( left+10, cp, fw_buf[i], fh_buf[i] );
951 rb->lcd_set_drawmode(DRMODE_SOLID);
953 rb->lcd_update_rect( left, top, WIDTH, HEIGHT );
955 osi = si;
956 i = fvi;
957 switch( rb->button_get(true) )
959 case ROCKPAINT_UP:
960 case ROCKPAINT_UP|BUTTON_REPEAT:
961 if( si > 0 )
963 si--;
964 if( si<fvi )
966 fvi = si;
969 break;
971 case ROCKPAINT_DOWN:
972 case ROCKPAINT_DOWN|BUTTON_REPEAT:
973 if( li == -1 || si < li )
975 si++;
977 break;
979 case ROCKPAINT_LEFT:
980 return false;
982 case ROCKPAINT_RIGHT:
983 case ROCKPAINT_DRAW:
984 rb->snprintf( dst, dst_size, "%s", fontname_buf[si-fvi] );
985 return true;
988 if( i != fvi || si > lvi )
990 b_need_redraw = 1;
993 if( si<=lvi )
995 nvih = 0;
998 #undef fh_buf
999 #undef fw_buf
1000 #undef fontname_buf
1001 #undef WIDTH
1002 #undef HEIGHT
1003 #undef LINE_SPACE
1006 /***********************************************************************
1007 * HSVRGB Color chooser
1008 ***********************************************************************/
1009 static unsigned int color_chooser( unsigned int color )
1011 int red = RGB_UNPACK_RED( color );
1012 int green = RGB_UNPACK_GREEN( color );
1013 int blue = RGB_UNPACK_BLUE( color );
1014 int hue, saturation, value;
1015 int r, g, b; /* temp variables */
1016 int i, top, left;
1018 enum BaseColor { Hue = 0, Saturation = 1, Value = 2,
1019 Red = 3, Green = 4, Blue = 5 };
1020 enum BaseColor current = Red;
1021 bool has_changed;
1023 char str[6] = "";
1025 restore_screen();
1027 rgb2hsv( red, green, blue, &hue, &saturation, &value );
1029 while( 1 )
1031 has_changed = false;
1032 color = LCD_RGBPACK( red, green, blue );
1034 #define HEIGHT ( 100 )
1035 #define WIDTH ( 150 )
1037 top = draw_window( HEIGHT, WIDTH, NULL, &left, "Color chooser" );
1038 top -= 15;
1040 for( i=0; i<100; i++ )
1042 hsv2rgb( i*36, saturation, value, &r, &g, &b );
1043 rb->lcd_set_foreground( LCD_RGBPACK( r, g, b ) );
1044 rb->lcd_vline( left+15+i, top+20, top+27 );
1045 hsv2rgb( hue, i*255/100, value, &r, &g, &b );
1046 rb->lcd_set_foreground( LCD_RGBPACK( r, g, b ) );
1047 rb->lcd_vline( left+15+i, top+30, top+37 );
1048 hsv2rgb( hue, saturation, i*255/100, &r, &g, &b );
1049 rb->lcd_set_foreground( LCD_RGBPACK( r, g, b ) );
1050 rb->lcd_vline( left+15+i, top+40, top+47 );
1051 rb->lcd_set_foreground( LCD_RGBPACK( i*255/100, green, blue ) );
1052 rb->lcd_vline( left+15+i, top+50, top+57 );
1053 rb->lcd_set_foreground( LCD_RGBPACK( red, i*255/100, blue ) );
1054 rb->lcd_vline( left+15+i, top+60, top+67 );
1055 rb->lcd_set_foreground( LCD_RGBPACK( red, green, i*255/100 ) );
1056 rb->lcd_vline( left+15+i, top+70, top+77 );
1059 rb->lcd_set_foreground(COLOR_BLACK);
1060 #define POSITION( a, i ) \
1061 rb->lcd_drawpixel( left+14+i, top + 19 + a ); \
1062 rb->lcd_drawpixel( left+16+i, top + 19 + a ); \
1063 rb->lcd_drawpixel( left+14+i, top + 28 + a ); \
1064 rb->lcd_drawpixel( left+16+i, top + 28 + a );
1065 POSITION( 0, hue/36 );
1066 POSITION( 10, saturation*99/255 );
1067 POSITION( 20, value*99/255 );
1068 POSITION( 30, red*99/255 );
1069 POSITION( 40, green*99/255 );
1070 POSITION( 50, blue*99/255 );
1071 #undef POSITION
1072 rb->lcd_set_background(COLOR_LIGHTGRAY);
1073 rb->lcd_setfont( FONT_SYSFIXED );
1074 rb->snprintf( str, 6, "%d", hue/10 );
1075 rb->lcd_putsxy( left + 117, top + 20, str );
1076 rb->snprintf( str, 6, "%d.%d", saturation/255, ((saturation*100)/255)%100 );
1077 rb->lcd_putsxy( left + 117, top + 30, str );
1078 rb->snprintf( str, 6, "%d.%d", value/255, ((value*100)/255)%100 );
1079 rb->lcd_putsxy( left + 117, top + 40, str );
1080 rb->snprintf( str, 6, "%d", red );
1081 rb->lcd_putsxy( left + 117, top + 50, str );
1082 rb->snprintf( str, 6, "%d", green );
1083 rb->lcd_putsxy( left + 117, top + 60, str );
1084 rb->snprintf( str, 6, "%d", blue );
1085 rb->lcd_putsxy( left + 117, top + 70, str );
1086 rb->lcd_setfont( FONT_UI );
1088 #define CURSOR( l ) \
1089 rb->lcd_bitmap_transparent_part( rockpaint_hsvrgb, 1, 1, 16, left+l+1, top+20, 6, 58 ); \
1090 rb->lcd_bitmap_transparent_part( rockpaint_hsvrgb, 8, 10*current, 16, left+l, top+19+10*current, 8, 10 );
1091 CURSOR( 5 );
1092 #undef CURSOR
1094 rb->lcd_set_foreground( color );
1095 rb->lcd_fillrect( left+15, top+85, 100, 8 );
1097 rb->lcd_update();
1099 switch( rb->button_get(true) )
1101 case ROCKPAINT_UP:
1102 current = ( current + 5 )%6;
1103 break;
1105 case ROCKPAINT_DOWN:
1106 current = (current + 1 )%6;
1107 break;
1109 case ROCKPAINT_LEFT:
1110 has_changed = true;
1111 switch( current )
1113 case Hue:
1114 hue = ( hue + 3600 - 10 )%3600;
1115 break;
1116 case Saturation:
1117 if( saturation ) saturation--;
1118 break;
1119 case Value:
1120 if( value ) value--;
1121 break;
1122 case Red:
1123 if( red ) red--;
1124 break;
1125 case Green:
1126 if( green ) green--;
1127 break;
1128 case Blue:
1129 if( blue ) blue--;
1130 break;
1132 break;
1134 case ROCKPAINT_LEFT|BUTTON_REPEAT:
1135 has_changed = true;
1136 switch( current )
1138 case Hue:
1139 hue = ( hue + 3600 - 100 )%3600;
1140 break;
1141 case Saturation:
1142 if( saturation >= 8 ) saturation-=8;
1143 else saturation = 0;
1144 break;
1145 case Value:
1146 if( value >= 8 ) value-=8;
1147 else value = 0;
1148 break;
1149 case Red:
1150 if( red >= 8 ) red-=8;
1151 else red = 0;
1152 break;
1153 case Green:
1154 if( green >= 8 ) green-=8;
1155 else green = 0;
1156 break;
1157 case Blue:
1158 if( blue >= 8 ) blue-=8;
1159 else blue = 0;
1160 break;
1162 break;
1164 case ROCKPAINT_RIGHT:
1165 has_changed = true;
1166 switch( current )
1168 case Hue:
1169 hue = ( hue + 10 )%3600;
1170 break;
1171 case Saturation:
1172 if( saturation < 0xff ) saturation++;
1173 break;
1174 case Value:
1175 if( value < 0xff ) value++;
1176 break;
1177 case Red:
1178 if( red < 0xff ) red++;
1179 break;
1180 case Green:
1181 if( green < 0xff ) green++;
1182 break;
1183 case Blue:
1184 if( blue < 0xff ) blue++;
1185 break;
1187 break;
1189 case ROCKPAINT_RIGHT|BUTTON_REPEAT:
1190 has_changed = true;
1191 switch( current )
1193 case Hue:
1194 hue = ( hue + 100 )%3600;
1195 break;
1196 case Saturation:
1197 if( saturation < 0xff - 8 ) saturation+=8;
1198 else saturation = 0xff;
1199 break;
1200 case Value:
1201 if( value < 0xff - 8 ) value+=8;
1202 else value = 0xff;
1203 break;
1204 case Red:
1205 if( red < 0xff - 8 ) red+=8;
1206 else red = 0xff;
1207 break;
1208 case Green:
1209 if( green < 0xff - 8 ) green+=8;
1210 else green = 0xff;
1211 break;
1212 case Blue:
1213 if( blue < 0xff - 8 ) blue+=8;
1214 else blue = 0xff;
1215 break;
1217 break;
1219 case ROCKPAINT_DRAW:
1220 return color;
1222 if( has_changed )
1224 switch( current )
1226 case Hue:
1227 case Saturation:
1228 case Value:
1229 hsv2rgb( hue, saturation, value, &red, &green, &blue );
1230 break;
1232 case Red:
1233 case Green:
1234 case Blue:
1235 rgb2hsv( red, green, blue, &hue, &saturation, &value );
1236 break;
1239 #undef HEIGHT
1240 #undef WIDTH
1244 /***********************************************************************
1245 * Misc routines
1246 ***********************************************************************/
1247 static void init_buffer(void)
1249 int i;
1250 fb_data color = rp_colors[ bgdrawcolor ];
1251 for( i = 0; i < ROWS*COLS; i++ )
1253 save_buffer[i] = color;
1257 static void draw_pixel(int x,int y)
1259 if( !preview )
1261 if( x < 0 || x >= COLS || y < 0 || y >= ROWS ) return;
1262 if( isbg )
1264 save_buffer[ x+y*COLS ] = rp_colors[bgdrawcolor];
1266 else
1268 save_buffer[ x+y*COLS ] = rp_colors[drawcolor];
1271 rb->lcd_drawpixel(x,y);
1274 static void color_picker( int x, int y )
1276 if( preview )
1278 rb->lcd_set_foreground( save_buffer[ x+y*COLS ] );
1279 #define PSIZE 12
1280 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1281 rb->lcd_drawrect( x<COLS-PSIZE ? x + 2 : x - PSIZE, y<ROWS-PSIZE ? y + 2: y - PSIZE, PSIZE - 2, PSIZE - 2 );
1282 rb->lcd_set_drawmode(DRMODE_SOLID);
1283 rb->lcd_fillrect( x<COLS-PSIZE ? x+3 : x - PSIZE+1, y<ROWS-PSIZE ? y +3: y - PSIZE+1, PSIZE-4, PSIZE-4 );
1284 #undef PSIZE
1285 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1287 else
1289 rp_colors[ drawcolor ] = save_buffer[ x+y*COLS ];
1293 static void draw_select_rectangle( int x1, int y1, int x2, int y2 )
1294 /* This is a preview mode only function */
1296 int i,a;
1297 if( x1 > x2 )
1299 i = x1;
1300 x1 = x2;
1301 x2 = i;
1303 if( y1 > y2 )
1305 i = y1;
1306 y1 = y2;
1307 y2 = i;
1309 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1310 i = 0;
1311 for( a = x1; a < x2; a++, i++ )
1312 if( i%2 )
1313 rb->lcd_drawpixel( a, y1 );
1314 for( a = y1; a < y2; a++, i++ )
1315 if( i%2 )
1316 rb->lcd_drawpixel( x2, a );
1317 if( y2 != y1 )
1318 for( a = x2; a > x1; a--, i++ )
1319 if( i%2 )
1320 rb->lcd_drawpixel( a, y2 );
1321 if( x2 != x1 )
1322 for( a = y2; a > y1; a--, i++ )
1323 if( i%2 )
1324 rb->lcd_drawpixel( x1, a );
1325 rb->lcd_set_drawmode(DRMODE_SOLID);
1328 static void copy_to_clipboard( void )
1330 /* This needs to be optimised ... but i'm lazy ATM */
1331 rb->memcpy( buffer.clipboard, save_buffer, COLS*ROWS*sizeof( fb_data ) );
1334 /* no preview mode handling atm ... do we need it ? (one if) */
1335 static void draw_invert( int x1, int y1, int x2, int y2 )
1337 int i;
1338 if( x1 > x2 )
1340 i = x1;
1341 x1 = x2;
1342 x2 = i;
1344 if( y1 > y2 )
1346 i = y1;
1347 y1 = y2;
1348 y2 = i;
1351 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1352 rb->lcd_fillrect( x1, y1, x2-x1+1, y2-y1+1 );
1353 rb->lcd_set_drawmode(DRMODE_SOLID);
1355 for( ; y1<=y2; y1++ )
1357 for( i = x1; i<=x2; i++ )
1359 save_buffer[ y1*COLS + i ] = ~save_buffer[ y1*COLS + i ];
1362 /*if( update )*/ rb->lcd_update();
1365 static void draw_hflip( int x1, int y1, int x2, int y2 )
1367 int i;
1368 if( x1 > x2 )
1370 i = x1;
1371 x1 = x2;
1372 x2 = i;
1374 if( y1 > y2 )
1376 i = y1;
1377 y1 = y2;
1378 y2 = i;
1381 copy_to_clipboard();
1383 for( i = 0; i <= y2 - y1; i++ )
1385 rb->memcpy( save_buffer+(y1+i)*COLS+x1,
1386 buffer.clipboard+(y2-i)*COLS+x1,
1387 (x2-x1+1)*sizeof( fb_data ) );
1389 restore_screen();
1390 rb->lcd_update();
1393 static void draw_vflip( int x1, int y1, int x2, int y2 )
1395 int i;
1396 if( x1 > x2 )
1398 i = x1;
1399 x1 = x2;
1400 x2 = i;
1402 if( y1 > y2 )
1404 i = y1;
1405 y1 = y2;
1406 y2 = i;
1409 copy_to_clipboard();
1411 for( ; y1 <= y2; y1++ )
1413 for( i = 0; i <= x2 - x1; i++ )
1415 save_buffer[y1*COLS+x1+i] = buffer.clipboard[y1*COLS+x2-i];
1418 restore_screen();
1419 rb->lcd_update();
1422 static void draw_paste_rectangle( int src_x1, int src_y1, int src_x2,
1423 int src_y2, int x1, int y1, int mode )
1425 int i;
1426 if( mode == SELECT_MENU_CUT )
1428 i = drawcolor;
1429 drawcolor = bgdrawcolor;
1430 draw_rect_full( src_x1, src_y1, src_x2, src_y2 );
1431 drawcolor = i;
1433 if( src_x1 > src_x2 )
1435 i = src_x1;
1436 src_x1 = src_x2;
1437 src_x2 = i;
1439 if( src_y1 > src_y2 )
1441 i = src_y1;
1442 src_y1 = src_y2;
1443 src_y2 = i;
1445 rb->lcd_bitmap_part( buffer.clipboard, src_x1, src_y1, COLS,
1446 x1, y1, src_x2-src_x1+1, src_y2-src_y1+1 );
1447 if( !preview )
1449 for( i = 0; i <= src_y2 - src_y1; i++ )
1451 rb->memcpy( save_buffer+(y1+i)*COLS+x1,
1452 buffer.clipboard+(src_y1+i)*COLS+src_x1,
1453 (src_x2 - src_x1 + 1)*sizeof( fb_data ) );
1458 static void show_grid( bool update )
1460 int i;
1461 if( gridsize > 0 )
1463 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1464 for( i = gridsize; i < COLS; i+= gridsize )
1466 rb->lcd_vline( i, 0, ROWS-1 );
1468 for( i = gridsize; i < ROWS; i+= gridsize )
1470 rb->lcd_hline( 0, COLS-1, i );
1472 rb->lcd_set_drawmode(DRMODE_SOLID);
1473 if( update ) rb->lcd_update();
1477 static void draw_text( int x, int y )
1479 buffer.text.text[0] = '\0';
1480 rb->snprintf( buffer.text.old_font, MAX_PATH,
1481 FONT_DIR "/%s.fnt",
1482 rb->global_settings->font_file );
1483 while( 1 )
1485 int m = TEXT_MENU_TEXT;
1486 switch( m = menu_display( text_menu, m ) )
1488 case TEXT_MENU_TEXT:
1489 rb->kbd_input( buffer.text.text, MAX_TEXT );
1490 restore_screen();
1491 break;
1493 case TEXT_MENU_FONT:
1494 if( browse_fonts( buffer.text.font, MAX_PATH ) )
1496 rb->font_load( buffer.text.font );
1498 break;
1500 case TEXT_MENU_PREVIEW:
1501 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1502 while( 1 )
1504 unsigned int button;
1505 restore_screen();
1506 rb->lcd_putsxy( x, y, buffer.text.text );
1507 rb->lcd_update();
1508 switch( button = rb->button_get( true ) )
1510 case ROCKPAINT_LEFT:
1511 case ROCKPAINT_LEFT | BUTTON_REPEAT:
1512 x-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1513 if (x<0) x=COLS-1;
1514 break;
1516 case ROCKPAINT_RIGHT:
1517 case ROCKPAINT_RIGHT | BUTTON_REPEAT:
1518 x+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1519 if (x>=COLS) x=0;
1520 break;
1522 case ROCKPAINT_UP:
1523 case ROCKPAINT_UP | BUTTON_REPEAT:
1524 y-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1525 if (y<0) y=ROWS-1;
1526 break;
1528 case ROCKPAINT_DOWN:
1529 case ROCKPAINT_DOWN | BUTTON_REPEAT:
1530 y+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1531 if (y>=ROWS-1) y=0;
1532 break;
1534 case ROCKPAINT_DRAW:
1535 button = 1242;
1536 break;
1538 if( button == 1242 ) break;
1540 break;
1542 case TEXT_MENU_APPLY:
1543 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1544 buffer_putsxyofs( save_buffer, COLS, ROWS, x, y, 0,
1545 buffer.text.text );
1546 case TEXT_MENU_CANCEL:
1547 restore_screen();
1548 rb->font_load( buffer.text.old_font );
1549 return;
1554 static void draw_brush( int x, int y )
1556 int i,j;
1557 for( i=-bsize/2+(bsize+1)%2; i<=bsize/2; i++ )
1559 for( j=-bsize/2+(bsize+1)%2; j<=bsize/2; j++ )
1561 draw_pixel( x+i, y+j );
1566 static void draw_line( int x1, int y1, int x2, int y2 )
1568 x1 = x1<<1;
1569 y1 = y1<<1;
1570 x2 = x2<<1;
1571 y2 = y2<<1;
1572 int w = x1 - x2;
1573 int h = y1 - y2;
1575 int x, y;
1577 if( w == 0 && h == 0 )
1579 draw_pixel( x1>>1, y1>>1 );
1580 return;
1583 if( w < 0 ) w *= -1;
1584 if( h < 0 ) h *= -1;
1586 if( w > h )
1588 if( x1 > x2 )
1590 x = x2;
1591 y = y2;
1592 x2 = x1;
1593 y2 = y1;
1594 x1 = x;
1595 y1 = y;
1597 w = x1 - x2;
1598 h = y1 - y2;
1599 while( x1 <= x2 )
1601 draw_pixel( (x1+1)>>1, (y1+1)>>1 );
1602 x1+=2;
1603 y1 = y2 - ( x2 - x1 ) * h / w;
1606 else /* h > w */
1608 if( y1 > y2 )
1610 x = x2;
1611 y = y2;
1612 x2 = x1;
1613 y2 = y1;
1614 x1 = x;
1615 y1 = y;
1617 w = x1 - x2;
1618 h = y1 - y2;
1619 while( y1 <= y2 )
1621 draw_pixel( (x1+1)>>1, (y1+1)>>1 );
1622 y1+=2;
1623 x1 = x2 - ( y2 - y1 ) * w / h;
1628 static void draw_curve( int x1, int y1, int x2, int y2,
1629 int xa, int ya, int xb, int yb )
1631 int i = 0;
1632 short xl1, yl1;
1633 short xl2, yl2;
1634 short xl3, yl3;
1635 short xl4, yl4;
1636 short xr1, yr1;
1637 short xr2, yr2;
1638 short xr3, yr3;
1639 short xr4, yr4;
1640 short depth;
1641 short xh, yh;
1643 if( x1 == x2 && y1 == y2 )
1645 draw_pixel( x1, y1 );
1646 return;
1649 // if( preview )
1651 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1652 if( xa == -1 || ya == -1 )
1654 rb->lcd_drawline( x1, y1, xb, yb );
1655 rb->lcd_drawline( x2, y2, xb, yb );
1657 else
1659 rb->lcd_drawline( x1, y1, xa, ya );
1660 rb->lcd_drawline( x2, y2, xb, yb );
1662 rb->lcd_set_drawmode(DRMODE_SOLID);
1665 if( xa == -1 || ya == -1 )
1666 /* We only have 3 of the points
1667 * This will currently only be used in preview mode */
1669 #define PUSH( a1, b1, a2, b2, a3, b3, d ) \
1670 buffer.bezier[i].x1 = a1; \
1671 buffer.bezier[i].y1 = b1; \
1672 buffer.bezier[i].x2 = a2; \
1673 buffer.bezier[i].y2 = b2; \
1674 buffer.bezier[i].x3 = a3; \
1675 buffer.bezier[i].y3 = b3; \
1676 buffer.bezier[i].depth = d; \
1677 i++;
1678 #define POP( a1, b1, a2, b2, a3, b3, d ) \
1679 i--; \
1680 a1 = buffer.bezier[i].x1; \
1681 b1 = buffer.bezier[i].y1; \
1682 a2 = buffer.bezier[i].x2; \
1683 b2 = buffer.bezier[i].y2; \
1684 a3 = buffer.bezier[i].x3; \
1685 b3 = buffer.bezier[i].y3; \
1686 d = buffer.bezier[i].depth;
1687 PUSH( x1<<4, y1<<4, xb<<4, yb<<4, x2<<4, y2<<4, 0 );
1688 while( i )
1690 /* de Casteljau's algorithm (see wikipedia) */
1691 POP( xl1, yl1, xb, yb, xr3, yr3, depth );
1692 if( depth < 10 ) /* check that the stack's 'i' doesn't overflow */
1694 xl2 = ( xl1 + xb )>>1;
1695 yl2 = ( yl1 + yb )>>1;
1696 xr2 = ( xb + xr3 )>>1;
1697 yr2 = ( yb + yr3 )>>1;
1698 xr1 = ( xl2 + xr2 )>>1;
1699 yr1 = ( yl2 + yr2 )>>1;
1700 xl3 = xr1;
1701 yl3 = yr1;
1702 PUSH( xl1, yl1, xl2, yl2, xl3, yl3, depth+1 );
1703 PUSH( xr1, yr1, xr2, yr2, xr3, yr3, depth+1 );
1705 else
1707 draw_line( ((xl1>>3)+1)>>1, ((yl1>>3)+1)>>1,
1708 ((xr3>>3)+1)>>1, ((yr3>>3)+1)>>1 );
1711 #undef PUSH
1712 #undef POP
1714 else /* We have the 4 points */
1716 #define PUSH( a1, b1, a2, b2, a3, b3, a4, b4, d ) \
1717 buffer.bezier[i].x1 = a1; \
1718 buffer.bezier[i].y1 = b1; \
1719 buffer.bezier[i].x2 = a2; \
1720 buffer.bezier[i].y2 = b2; \
1721 buffer.bezier[i].x3 = a3; \
1722 buffer.bezier[i].y3 = b3; \
1723 buffer.bezier[i].x4 = a4; \
1724 buffer.bezier[i].y4 = b4; \
1725 buffer.bezier[i].depth = d; \
1726 i++;
1727 #define POP( a1, b1, a2, b2, a3, b3, a4, b4, d ) \
1728 i--; \
1729 a1 = buffer.bezier[i].x1; \
1730 b1 = buffer.bezier[i].y1; \
1731 a2 = buffer.bezier[i].x2; \
1732 b2 = buffer.bezier[i].y2; \
1733 a3 = buffer.bezier[i].x3; \
1734 b3 = buffer.bezier[i].y3; \
1735 a4 = buffer.bezier[i].x4; \
1736 b4 = buffer.bezier[i].y4; \
1737 d = buffer.bezier[i].depth;
1739 PUSH( x1<<4, y1<<4, xa<<4, ya<<4, xb<<4, yb<<4, x2<<4, y2<<4, 0 );
1740 while( i )
1742 /* de Casteljau's algorithm (see wikipedia) */
1743 POP( xl1, yl1, xa, ya, xb, yb, xr4, yr4, depth );
1744 if( depth < 10 ) /* check that the stack's 'i' doesn't overflow */
1746 xl2 = ( xl1 + xa )>>1;
1747 yl2 = ( yl1 + ya )>>1;
1748 xh = ( xa + xb )>>1;
1749 yh = ( ya + yb )>>1;
1750 xr3 = ( xb + xr4 )>>1;
1751 yr3 = ( yb + yr4 )>>1;
1752 xl3 = ( xl2 + xh )>>1;
1753 yl3 = ( yl2 + yh )>>1;
1754 xr2 = ( xr3 + xh )>>1;
1755 yr2 = ( yr3 + yh )>>1;
1756 xl4 = ( xl3 + xr2 )>>1;
1757 yl4 = ( yl3 + yr2 )>>1;
1758 xr1 = xl4;
1759 yr1 = yl4;
1760 PUSH( xl1, yl1, xl2, yl2, xl3, yl3, xl4, yl4, depth+1 );
1761 PUSH( xr1, yr1, xr2, yr2, xr3, yr3, xr4, yr4, depth+1 );
1763 else
1765 draw_line( ((xl1>>3)+1)>>1, ((yl1>>3)+1)>>1,
1766 ((xr4>>3)+1)>>1, ((yr4>>3)+1)>>1 );
1769 #undef PUSH
1770 #undef POP
1774 static void draw_rect( int x1, int y1, int x2, int y2 )
1776 draw_line( x1, y1, x1, y2 );
1777 draw_line( x1, y1, x2, y1 );
1778 draw_line( x1, y2, x2, y2 );
1779 draw_line( x2, y1, x2, y2 );
1782 static void togglebg( void )
1784 if( isbg )
1786 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1788 else
1790 rb->lcd_set_foreground( rp_colors[ bgdrawcolor ] );
1792 isbg = !isbg;
1795 static void draw_rect_full( int x1, int y1, int x2, int y2 )
1797 /* GRUIK */
1798 int x = x1;
1799 togglebg();
1800 if( x < x2 )
1802 do {
1803 draw_line( x, y1, x, y2 );
1804 } while( ++x <= x2 );
1806 else
1808 do {
1809 draw_line( x, y1, x, y2 );
1810 } while( --x >= x2 );
1812 togglebg();
1813 draw_rect( x1, y1, x2, y2 );
1816 static void draw_oval( int x1, int y1, int x2, int y2, bool full )
1818 /* TODO: simplify :) */
1819 int cx = (x1+x2)>>1;
1820 int cy = (y1+y2)>>1;
1822 int rx = (x1-x2)>>1;
1823 int ry = (y1-y2)>>1;
1824 if( rx < 0 ) rx *= -1;
1825 if( ry < 0 ) ry *= -1;
1827 if( rx == 0 || ry == 0 )
1829 draw_line( x1, y1, x2, y2 );
1830 return;
1833 int x,y;
1834 int dst, old_dst;
1836 for( x = 0; x < rx; x++ )
1838 y = 0;
1839 dst = -0xfff;
1840 do {
1841 old_dst = dst;
1842 dst = ry * ry * x * x + rx * rx * y * y - rx * rx * ry * ry;
1843 y++;
1844 } while( dst < 0 );
1845 if( -old_dst < dst ) y--;
1846 if( full )
1848 draw_line( cx+x, cy, cx+x, cy+y );
1849 draw_line( cx+x, cy, cx+x, cy-y );
1850 draw_line( cx-x, cy, cx-x, cy+y );
1851 draw_line( cx-x, cy, cx-x, cy-y );
1853 else
1855 draw_pixel( cx+x, cy+y );
1856 draw_pixel( cx+x, cy-y );
1857 draw_pixel( cx-x, cy+y );
1858 draw_pixel( cx-x, cy-y );
1861 for( y = 0; y < ry; y++ )
1863 x = 0;
1864 dst = -0xfff;
1865 do {
1866 old_dst = dst;
1867 dst = ry * ry * x * x + rx * rx * y * y - rx * rx * ry * ry;
1868 x++;
1869 } while( dst < 0 );
1870 if( -old_dst < dst ) x--;
1871 if( full )
1873 draw_line( cx+x, cy, cx+x, cy+y );
1874 draw_line( cx+x, cy, cx+x, cy-y );
1875 draw_line( cx-x, cy, cx-x, cy+y );
1876 draw_line( cx-x, cy, cx-x, cy-y );
1878 else
1880 draw_pixel( cx+x, cy+y );
1881 draw_pixel( cx+x, cy-y );
1882 draw_pixel( cx-x, cy+y );
1883 draw_pixel( cx-x, cy-y );
1888 static void draw_oval_empty( int x1, int y1, int x2, int y2 )
1890 draw_oval( x1, y1, x2, y2, false );
1893 static void draw_oval_full( int x1, int y1, int x2, int y2 )
1895 togglebg();
1896 draw_oval( x1, y1, x2, y2, true );
1897 togglebg();
1898 draw_oval( x1, y1, x2, y2, false );
1901 static void draw_fill( int x0, int y0 )
1903 #define PUSH( a, b ) \
1904 draw_pixel( (int)a, (int)b ); \
1905 buffer.coord[i].x = a; \
1906 buffer.coord[i].y = b; \
1907 i++;
1908 #define POP( a, b ) \
1909 i--; \
1910 a = buffer.coord[i].x; \
1911 b = buffer.coord[i].y;
1913 unsigned int i=0;
1914 short x = x0;
1915 short y = y0;
1916 unsigned int prev_color = save_buffer[ x0+y0*COLS ];
1918 if( prev_color == rp_colors[ drawcolor ] ) return;
1920 PUSH( x, y );
1922 while( i != 0 )
1924 POP( x, y );
1925 if( x > 0 && save_buffer[x-1+y*COLS] == prev_color )
1927 PUSH( x-1, y );
1929 if( x < COLS-1 && save_buffer[x+1+y*COLS] == prev_color )
1931 PUSH( x+1, y );
1933 if( y > 0 && save_buffer[x+(y-1)*COLS] == prev_color )
1935 PUSH( x, y-1 );
1937 if( y < ROWS - 1 && save_buffer[x+(y+1)*COLS] == prev_color )
1939 PUSH( x, y+1 );
1942 #undef PUSH
1943 #undef POP
1947 /* For preview purposes only */
1948 static void line_gradient( int x1, int y1, int x2, int y2 )
1950 int r1, g1, b1;
1951 int r2, g2, b2;
1952 int h1, s1, v1, h2, s2, v2, r, g, b;
1953 int w, h, x, y;
1955 bool a = false;
1957 x1 <<= 1;
1958 y1 <<= 1;
1959 x2 <<= 1;
1960 y2 <<= 1;
1962 w = x1 - x2;
1963 h = y1 - y2;
1965 if( w == 0 && h == 0 )
1967 draw_pixel( x1>>1, y1>>1 );
1968 return;
1971 r1 = RGB_UNPACK_RED( rp_colors[ bgdrawcolor ] );
1972 g1 = RGB_UNPACK_GREEN( rp_colors[ bgdrawcolor ] );
1973 b1 = RGB_UNPACK_BLUE( rp_colors[ bgdrawcolor ] );
1974 r2 = RGB_UNPACK_RED( rp_colors[ drawcolor ] );
1975 g2 = RGB_UNPACK_GREEN( rp_colors[ drawcolor ] );
1976 b2 = RGB_UNPACK_BLUE( rp_colors[ drawcolor ] );
1978 if( w < 0 )
1980 w *= -1;
1981 a = true;
1983 if( h < 0 )
1985 h *= -1;
1986 a = !a;
1988 if( a )
1990 r = r1;
1991 r1 = r2;
1992 r2 = r;
1993 g = g1;
1994 g1 = g2;
1995 g2 = g;
1996 b = b1;
1997 b1 = b2;
1998 b2 = b;
2001 rgb2hsv( r1, g1, b1, &h1, &s1, &v1 );
2002 rgb2hsv( r2, g2, b2, &h2, &s2, &v2 );
2004 if( w > h )
2006 if( x1 > x2 )
2008 x = x2;
2009 y = y2;
2010 x2 = x1;
2011 y2 = y1;
2012 x1 = x;
2013 y1 = y;
2015 w = x1 - x2;
2016 h = y1 - y2;
2017 while( x1 <= x2 )
2019 hsv2rgb( h1+((h2-h1)*(x1-x2))/w,
2020 s1+((s2-s1)*(x1-x2))/w,
2021 v1+((v2-v1)*(x1-x2))/w,
2022 &r, &g, &b );
2023 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2024 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2025 draw_pixel( (x1+1)>>1, (y1+1)>>1 );
2026 x1+=2;
2027 y1 = y2 - ( x2 - x1 ) * h / w;
2030 else /* h > w */
2032 if( y1 > y2 )
2034 x = x2;
2035 y = y2;
2036 x2 = x1;
2037 y2 = y1;
2038 x1 = x;
2039 y1 = y;
2041 w = x1 - x2;
2042 h = y1 - y2;
2043 while( y1 <= y2 )
2045 hsv2rgb( h1+((h2-h1)*(y1-y2))/h,
2046 s1+((s2-s1)*(y1-y2))/h,
2047 v1+((v2-v1)*(y1-y2))/h,
2048 &r, &g, &b );
2049 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2050 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2051 draw_pixel( (x1+1)>>1, (y1+1)>>1 );
2052 y1+=2;
2053 x1 = x2 - ( y2 - y1 ) * w / h;
2056 if( a )
2058 rp_colors[ drawcolor ] = LCD_RGBPACK( r1, g1, b1 );
2060 else
2062 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2066 static void linear_gradient( int x1, int y1, int x2, int y2 )
2068 int r1 = RGB_UNPACK_RED( rp_colors[ bgdrawcolor ] );
2069 int g1 = RGB_UNPACK_GREEN( rp_colors[ bgdrawcolor ] );
2070 int b1 = RGB_UNPACK_BLUE( rp_colors[ bgdrawcolor ] );
2071 int r2 = RGB_UNPACK_RED( rp_colors[ drawcolor ] );
2072 int g2 = RGB_UNPACK_GREEN( rp_colors[ drawcolor ] );
2073 int b2 = RGB_UNPACK_BLUE( rp_colors[ drawcolor ] );
2075 int h1, s1, v1, h2, s2, v2, r, g, b;
2077 /* radius^2 */
2078 int radius2 = ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 );
2079 int dist2, i=0;
2081 /* We only propagate the gradient to neighboring pixels with the same
2082 * color as ( x1, y1 ) */
2083 unsigned int prev_color = save_buffer[ x1+y1*COLS ];
2085 int x = x1;
2086 int y = y1;
2088 if( radius2 == 0 ) return;
2089 if( preview )
2091 line_gradient( x1, y1, x2, y2 );
2094 rgb2hsv( r1, g1, b1, &h1, &s1, &v1 );
2095 rgb2hsv( r2, g2, b2, &h2, &s2, &v2 );
2097 #define PUSH( x0, y0 ) \
2098 buffer.coord[i].x = (short)(x0); \
2099 buffer.coord[i].y = (short)(y0); \
2100 i++;
2101 #define POP( a, b ) \
2102 i--; \
2103 a = (int)buffer.coord[i].x; \
2104 b = (int)buffer.coord[i].y;
2106 PUSH( x, y );
2108 while( i != 0 )
2110 POP( x, y );
2112 dist2 = ( x2 - x1 ) * ( x - x1 ) + ( y2 - y1 ) * ( y - y1 );
2113 if( dist2 <= 0 )
2115 rp_colors[ drawcolor ] = rp_colors[ bgdrawcolor ];
2117 else if( dist2 < radius2 )
2119 hsv2rgb( h1+((h2-h1)*dist2)/radius2,
2120 s1+((s2-s1)*dist2)/radius2,
2121 v1+((v2-v1)*dist2)/radius2,
2122 &r, &g, &b );
2123 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2125 else
2127 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2129 if( rp_colors[ drawcolor ] == prev_color )
2131 if( rp_colors[ drawcolor ])
2132 rp_colors[ drawcolor ]--; /* GRUIK */
2133 else
2134 rp_colors[ drawcolor ]++; /* GRUIK */
2136 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2137 draw_pixel( x, y );
2139 if( x > 0 && save_buffer[x-1+y*COLS] == prev_color )
2141 PUSH( x-1, y );
2143 if( x < COLS-1 && save_buffer[x+1+y*COLS] == prev_color )
2145 PUSH( x+1, y );
2147 if( y > 0 && save_buffer[x+(y-1)*COLS] == prev_color )
2149 PUSH( x, y-1 );
2151 if( y < ROWS - 1 && save_buffer[x+(y+1)*COLS] == prev_color )
2153 PUSH( x, y+1 );
2156 #undef PUSH
2157 #undef POP
2159 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2162 static void radial_gradient( int x1, int y1, int x2, int y2 )
2164 int r1 = RGB_UNPACK_RED( rp_colors[ bgdrawcolor ] );
2165 int g1 = RGB_UNPACK_GREEN( rp_colors[ bgdrawcolor ] );
2166 int b1 = RGB_UNPACK_BLUE( rp_colors[ bgdrawcolor ] );
2167 int r2 = RGB_UNPACK_RED( rp_colors[ drawcolor ] );
2168 int g2 = RGB_UNPACK_GREEN( rp_colors[ drawcolor ] );
2169 int b2 = RGB_UNPACK_BLUE( rp_colors[ drawcolor ] );
2171 int h1, s1, v1, h2, s2, v2, r, g, b;
2173 /* radius^2 */
2174 int radius2 = ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 );
2175 int dist2, i=0;
2177 /* We only propagate the gradient to neighboring pixels with the same
2178 * color as ( x1, y1 ) */
2179 unsigned int prev_color = save_buffer[ x1+y1*COLS ];
2181 int x = x1;
2182 int y = y1;
2184 if( radius2 == 0 ) return;
2185 if( preview )
2187 line_gradient( x1, y1, x2, y2 );
2190 rgb2hsv( r1, g1, b1, &h1, &s1, &v1 );
2191 rgb2hsv( r2, g2, b2, &h2, &s2, &v2 );
2193 #define PUSH( x0, y0 ) \
2194 buffer.coord[i].x = (short)(x0); \
2195 buffer.coord[i].y = (short)(y0); \
2196 i++;
2197 #define POP( a, b ) \
2198 i--; \
2199 a = (int)buffer.coord[i].x; \
2200 b = (int)buffer.coord[i].y;
2202 PUSH( x, y );
2204 while( i != 0 )
2206 POP( x, y );
2208 if( ( dist2 = (x1-(x))*(x1-(x))+(y1-(y))*(y1-(y)) ) < radius2 )
2210 hsv2rgb( h1+((h2-h1)*dist2)/radius2,
2211 s1+((s2-s1)*dist2)/radius2,
2212 v1+((v2-v1)*dist2)/radius2,
2213 &r, &g, &b );
2214 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2216 else
2218 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2220 if( rp_colors[ drawcolor ] == prev_color )
2222 if( rp_colors[ drawcolor ])
2223 rp_colors[ drawcolor ]--; /* GRUIK */
2224 else
2225 rp_colors[ drawcolor ]++; /* GRUIK */
2227 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2228 draw_pixel( x, y );
2230 if( x > 0 && save_buffer[x-1+y*COLS] == prev_color )
2232 PUSH( x-1, y );
2234 if( x < COLS-1 && save_buffer[x+1+y*COLS] == prev_color )
2236 PUSH( x+1, y );
2238 if( y > 0 && save_buffer[x+(y-1)*COLS] == prev_color )
2240 PUSH( x, y-1 );
2242 if( y < ROWS - 1 && save_buffer[x+(y+1)*COLS] == prev_color )
2244 PUSH( x, y+1 );
2247 #undef PUSH
2248 #undef POP
2250 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2253 static void draw_toolbars(bool update)
2255 int i;
2256 #define TOP (LCD_HEIGHT-TB_HEIGHT)
2257 rb->lcd_set_background( COLOR_LIGHTGRAY );
2258 rb->lcd_set_foreground( COLOR_LIGHTGRAY );
2259 rb->lcd_fillrect( 0, TOP, LCD_WIDTH, TB_HEIGHT );
2260 rb->lcd_set_foreground( COLOR_BLACK );
2261 rb->lcd_drawrect( 0, TOP, LCD_WIDTH, TB_HEIGHT );
2263 rb->lcd_set_foreground( rp_colors[ bgdrawcolor ] );
2264 rb->lcd_fillrect( TB_SC_BG_LEFT, TOP+TB_SC_BG_TOP,
2265 TB_SC_SIZE, TB_SC_SIZE );
2266 rb->lcd_set_foreground(ROCKPAINT_PALETTE);
2267 rb->lcd_drawrect( TB_SC_BG_LEFT, TOP+TB_SC_BG_TOP,
2268 TB_SC_SIZE, TB_SC_SIZE );
2269 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2270 rb->lcd_fillrect( TB_SC_FG_LEFT, TOP+TB_SC_FG_TOP,
2271 TB_SC_SIZE, TB_SC_SIZE );
2272 rb->lcd_set_foreground(ROCKPAINT_PALETTE);
2273 rb->lcd_drawrect( TB_SC_FG_LEFT, TOP+TB_SC_FG_TOP,
2274 TB_SC_SIZE, TB_SC_SIZE );
2276 for( i=0; i<18; i++ )
2278 rb->lcd_set_foreground( rp_colors[i] );
2279 rb->lcd_fillrect(
2280 TB_PL_LEFT+(i%9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING ),
2281 TOP+TB_PL_TOP+(i/9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING),
2282 TB_PL_COLOR_SIZE, TB_PL_COLOR_SIZE );
2283 rb->lcd_set_foreground( ROCKPAINT_PALETTE );
2284 rb->lcd_drawrect(
2285 TB_PL_LEFT+(i%9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING ),
2286 TOP+TB_PL_TOP+(i/9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING),
2287 TB_PL_COLOR_SIZE, TB_PL_COLOR_SIZE );
2290 #define SEPARATOR( x, y ) \
2291 rb->lcd_set_foreground( COLOR_WHITE ); \
2292 rb->lcd_vline( x, TOP+y, TOP+y+TB_PL_HEIGHT-1 ); \
2293 rb->lcd_set_foreground( COLOR_DARKGRAY ); \
2294 rb->lcd_vline( x+1, TOP+y, TOP+y+TB_PL_HEIGHT-1 );
2295 SEPARATOR( TB_PL_LEFT + TB_PL_WIDTH - 1 + TB_SP_MARGIN, TB_PL_TOP );
2297 rb->lcd_bitmap_transparent( rockpaint, TB_TL_LEFT, TOP+TB_TL_TOP,
2298 TB_TL_WIDTH, TB_TL_HEIGHT );
2299 rb->lcd_set_foreground(ROCKPAINT_PALETTE);
2300 rb->lcd_drawrect( TB_TL_LEFT+(TB_TL_SIZE+TB_TL_SPACING)*(tool/2),
2301 TOP+TB_TL_TOP+(TB_TL_SIZE+TB_TL_SPACING)*(tool%2),
2302 TB_TL_SIZE, TB_TL_SIZE );
2304 SEPARATOR( TB_TL_LEFT + TB_TL_WIDTH - 1 + TB_SP_MARGIN, TB_TL_TOP );
2306 rb->lcd_setfont( FONT_SYSFIXED );
2307 rb->lcd_putsxy( TB_MENU_LEFT, TOP+TB_MENU_TOP, "Menu" );
2308 rb->lcd_setfont( FONT_UI );
2309 #undef TOP
2311 if( update ) rb->lcd_update();
2314 static void toolbar( void )
2316 int button, i, j;
2317 restore_screen();
2318 draw_toolbars( false );
2319 y = LCD_HEIGHT-TB_HEIGHT/2;
2320 inv_cursor( true );
2321 while( 1 )
2323 switch( button = rb->button_get( true ) )
2325 case ROCKPAINT_DRAW:
2326 #define TOP ( LCD_HEIGHT - TB_HEIGHT )
2327 if( y >= TOP + TB_SC_FG_TOP
2328 && y < TOP + TB_SC_FG_TOP + TB_SC_SIZE
2329 && x >= TB_SC_FG_LEFT
2330 && x < TB_SC_FG_LEFT + TB_SC_SIZE )
2332 /* click on the foreground color */
2333 rp_colors[drawcolor] = color_chooser( rp_colors[drawcolor] );
2335 else if( y >= TOP + TB_SC_BG_TOP
2336 && y < TOP + TB_SC_BG_TOP + TB_SC_SIZE
2337 && x >= TB_SC_BG_LEFT
2338 && x < TB_SC_BG_LEFT + TB_SC_SIZE )
2340 /* click on the background color */
2341 i = drawcolor;
2342 drawcolor = bgdrawcolor;
2343 bgdrawcolor = i;
2345 else if( y >= TOP + TB_PL_TOP
2346 && y < TOP + TB_PL_TOP + TB_PL_HEIGHT
2347 && x >= TB_PL_LEFT
2348 && x < TB_PL_LEFT + TB_PL_WIDTH )
2350 /* click on the palette */
2351 i = (x - TB_PL_LEFT)%(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2352 j = (y - (TOP+TB_PL_TOP) )%(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2353 if( i >= TB_PL_COLOR_SIZE || j >= TB_PL_COLOR_SIZE )
2354 break;
2355 i = ( x - TB_PL_LEFT )/(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2356 j = ( y - (TOP+TB_PL_TOP) )/(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2357 drawcolor = j*(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING)+i;
2359 else if( y >= TOP+TB_TL_TOP
2360 && y < TOP + TB_TL_TOP + TB_TL_HEIGHT
2361 && x >= TB_TL_LEFT
2362 && x <= TB_TL_LEFT + TB_TL_WIDTH )
2364 /* click on the tools */
2365 i = (x - TB_TL_LEFT ) % (TB_TL_SIZE+TB_TL_SPACING);
2366 j = (y - (TOP+TB_TL_TOP) ) %(TB_TL_SIZE+TB_TL_SPACING);
2367 if( i >= TB_TL_SIZE || j >= TB_TL_SIZE ) break;
2368 i = ( x - TB_TL_LEFT )/(TB_TL_SIZE+TB_TL_SPACING);
2369 j = ( y - (TOP+TB_TL_TOP) )/(TB_TL_SIZE+TB_TL_SPACING);
2370 tool = i*2+j;
2371 prev_x = -1;
2372 prev_y = -1;
2373 prev_x2 = -1;
2374 prev_y2 = -1;
2375 prev_x3 = -1;
2376 prev_y3 = -1;
2377 preview = false;
2379 else if( x >= TB_MENU_LEFT && y >= TOP+TB_MENU_TOP-2)
2381 /* menu button */
2382 goto_menu();
2384 #undef TOP
2385 restore_screen();
2386 draw_toolbars( false );
2387 inv_cursor( true );
2388 break;
2390 case ROCKPAINT_LEFT:
2391 case ROCKPAINT_LEFT | BUTTON_REPEAT:
2392 inv_cursor(false);
2393 x-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2394 if (x<0) x=COLS-1;
2395 inv_cursor(true);
2396 break;
2398 case ROCKPAINT_RIGHT:
2399 case ROCKPAINT_RIGHT | BUTTON_REPEAT:
2400 inv_cursor(false);
2401 x+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2402 if (x>=COLS) x=0;
2403 inv_cursor(true);
2404 break;
2406 case ROCKPAINT_UP:
2407 case ROCKPAINT_UP | BUTTON_REPEAT:
2408 inv_cursor(false);
2409 y-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2410 if (y<LCD_HEIGHT-TB_HEIGHT)
2412 return;
2414 inv_cursor(true);
2415 break;
2417 case ROCKPAINT_DOWN:
2418 case ROCKPAINT_DOWN | BUTTON_REPEAT:
2419 inv_cursor(false);
2420 y+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2421 if (y>=LCD_HEIGHT)
2423 y = 0;
2424 return;
2426 inv_cursor(true);
2427 break;
2429 case ROCKPAINT_TOOLBAR:
2430 case ROCKPAINT_TOOLBAR2:
2431 return;
2433 if( quit ) return;
2437 static void inv_cursor(bool update)
2439 rb->lcd_set_foreground(COLOR_BLACK);
2440 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
2441 /* cross painting */
2442 rb->lcd_drawline(x-4,y,x-1,y);
2443 rb->lcd_drawline(x+1,y,x+4,y);
2444 rb->lcd_drawline(x,y-4,x,y-1);
2445 rb->lcd_drawline(x,y+1,x,y+4);
2446 rb->lcd_set_foreground(rp_colors[drawcolor]);
2447 rb->lcd_set_drawmode(DRMODE_SOLID);
2449 if( update ) rb->lcd_update();
2452 static void restore_screen(void)
2454 rb->lcd_bitmap( save_buffer, 0, 0, COLS, ROWS );
2457 static void clear_drawing(void)
2459 init_buffer();
2460 rb->lcd_set_foreground( rp_colors[ bgdrawcolor ] );
2461 rb->lcd_fillrect( 0, 0, COLS, ROWS );
2462 rb->lcd_update();
2465 static void goto_menu(void)
2467 int multi;
2469 while( 1 )
2471 switch( menu_display( main_menu, 1 ) )
2473 case MAIN_MENU_NEW:
2474 clear_drawing();
2475 return;
2477 case MAIN_MENU_LOAD:
2478 if( browse( filename, MAX_PATH, "/" ) )
2480 if( load_bitmap( filename ) <= 0 )
2482 rb->splash( 1*HZ, "Error while loading %s",
2483 filename );
2485 else
2487 rb->splash( 1*HZ, "Image loaded (%s)", filename );
2488 restore_screen();
2489 inv_cursor(true);
2490 return;
2493 break;
2495 case MAIN_MENU_SAVE:
2496 if (!filename[0])
2497 rb->strcpy(filename,"/");
2498 if( !rb->kbd_input( filename, MAX_PATH ) )
2500 if(rb->strlen(filename) <= 4 ||
2501 rb->strcasecmp(&filename[rb->strlen(filename)-4], ".bmp"))
2502 rb->strcat(filename, ".bmp");
2503 save_bitmap( filename );
2504 rb->splash( 1*HZ, "File saved (%s)", filename );
2506 break;
2508 case MAIN_MENU_BRUSH_SIZE:
2509 multi = menu_display( size_menu, bsize );
2510 if( multi != - 1 )
2511 bsize = multi;
2512 break;
2514 case MAIN_MENU_BRUSH_SPEED:
2515 multi = menu_display( speed_menu, bspeed );
2516 if( multi != -1 )
2517 bspeed = multi;
2518 break;
2520 case MAIN_MENU_COLOR:
2521 rp_colors[drawcolor] = color_chooser( rp_colors[drawcolor] );
2522 break;
2524 case MAIN_MENU_GRID_SIZE:
2525 multi = menu_display( gridsize_menu, gridsize );
2526 if( multi != - 1 )
2527 gridsize = multi;
2528 break;
2530 case MAIN_MENU_EXIT:
2531 quit=true;
2532 return;
2534 case MAIN_MENU_RESUME:
2535 case MENU_ESC:
2536 return;
2537 }/* end switch */
2538 }/* end while */
2541 static void reset_tool( void )
2543 prev_x = -1;
2544 prev_y = -1;
2545 prev_x2 = -1;
2546 prev_y2 = -1;
2547 prev_x3 = -1;
2548 prev_y3 = -1;
2549 tool_mode = -1;
2550 preview = false;
2553 static bool rockpaint_loop( void )
2555 int button=0,i,j;
2556 int accelaration;
2558 while (!quit) {
2559 button = rb->button_get(true);
2561 if( tool == Brush && prev_x != -1 )
2563 accelaration = 1;
2565 else if( button & BUTTON_REPEAT )
2567 accelaration = 4;
2569 else
2571 accelaration = 1;
2574 switch(button)
2576 case ROCKPAINT_QUIT:
2577 rb->lcd_set_drawmode(DRMODE_SOLID);
2578 return PLUGIN_OK;
2580 case ROCKPAINT_MENU:
2581 inv_cursor(false);
2582 goto_menu();
2583 inv_cursor(true);
2584 break;
2586 case ROCKPAINT_DRAW:
2587 inv_cursor(false);
2588 switch( tool )
2590 case Brush:
2591 if( prev_x == -1 ) prev_x = 1;
2592 else prev_x = -1;
2593 break;
2595 case SelectRectangle:
2596 case Line:
2597 case Curve:
2598 case Rectangle:
2599 case RectangleFull:
2600 case Oval:
2601 case OvalFull:
2602 case LinearGradient:
2603 case RadialGradient:
2604 /* Curve uses 4 points, others use 2 */
2605 if( prev_x == -1 || prev_y == -1 )
2607 prev_x = x;
2608 prev_y = y;
2609 preview = true;
2611 else if( tool == Curve
2612 && ( prev_x2 == -1 || prev_y2 == -1 ) )
2614 prev_x2 = x;
2615 prev_y2 = y;
2617 else if( tool == SelectRectangle
2618 && ( prev_x2 == -1 || prev_y2 == -1 ) )
2620 tool_mode = menu_display( select_menu,
2621 SELECT_MENU_CUT );
2622 switch( tool_mode )
2624 case SELECT_MENU_CUT:
2625 case SELECT_MENU_COPY:
2626 prev_x2 = x;
2627 prev_y2 = y;
2628 copy_to_clipboard();
2629 if( prev_x < x ) x = prev_x;
2630 if( prev_y < y ) y = prev_y;
2631 break;
2633 case SELECT_MENU_INVERT:
2634 draw_invert( prev_x, prev_y, x, y );
2635 reset_tool();
2636 break;
2638 case SELECT_MENU_HFLIP:
2639 draw_hflip( prev_x, prev_y, x, y );
2640 reset_tool();
2641 break;
2643 case SELECT_MENU_VFLIP:
2644 draw_vflip( prev_x, prev_y, x, y );
2645 reset_tool();
2646 break;
2648 case SELECT_MENU_ROTATE90:
2649 break;
2650 case SELECT_MENU_ROTATE180:
2651 draw_hflip( prev_x, prev_y, x, y );
2652 draw_vflip( prev_x, prev_y, x, y );
2653 reset_tool();
2654 break;
2655 case SELECT_MENU_ROTATE270:
2656 break;
2658 case SELECT_MENU_CANCEL:
2659 reset_tool();
2660 break;
2662 case MENU_ESC:
2663 break;
2666 else if( tool == Curve
2667 && ( prev_x3 == -1 || prev_y3 == -1 ) )
2669 prev_x3 = x;
2670 prev_y3 = y;
2672 else
2674 preview = false;
2675 switch( tool )
2677 case SelectRectangle:
2678 draw_paste_rectangle( prev_x, prev_y,
2679 prev_x2, prev_y2,
2680 x, y, tool_mode );
2681 break;
2682 case Line:
2683 draw_line( prev_x, prev_y, x, y );
2684 break;
2685 case Curve:
2686 draw_curve( prev_x, prev_y,
2687 prev_x2, prev_y2,
2688 prev_x3, prev_y3,
2689 x, y );
2690 break;
2691 case Rectangle:
2692 draw_rect( prev_x, prev_y, x, y );
2693 break;
2694 case RectangleFull:
2695 draw_rect_full( prev_x, prev_y, x, y );
2696 break;
2697 case Oval:
2698 draw_oval_empty( prev_x, prev_y, x, y );
2699 break;
2700 case OvalFull:
2701 draw_oval_full( prev_x, prev_y, x, y );
2702 break;
2703 case LinearGradient:
2704 linear_gradient( prev_x, prev_y, x, y );
2705 break;
2706 case RadialGradient:
2707 radial_gradient( prev_x, prev_y, x, y );
2708 break;
2709 default:
2710 break;
2712 reset_tool();
2714 break;
2716 case Fill:
2717 draw_fill( x, y );
2718 break;
2720 case ColorPicker:
2721 color_picker( x, y );
2722 break;
2724 case Text:
2725 draw_text( x, y );
2726 break;
2728 default:
2729 break;
2731 inv_cursor(true);
2732 break;
2734 case ROCKPAINT_DRAW|BUTTON_REPEAT:
2735 if( tool == Curve )
2737 /* 3 point bezier curve */
2738 preview = false;
2739 draw_curve( prev_x, prev_y,
2740 prev_x2, prev_y2,
2741 -1, -1,
2742 x, y );
2743 reset_tool();
2744 restore_screen();
2745 inv_cursor( true );
2747 break;
2749 case ROCKPAINT_TOOLBAR:
2750 i = x; j = y;
2751 x = 10;
2752 toolbar();
2753 x = i; y = j;
2754 restore_screen();
2755 inv_cursor(true);
2756 break;
2758 case ROCKPAINT_TOOLBAR2:
2759 i = x; j = y;
2760 x = 110;
2761 toolbar();
2762 x = i; y = j;
2763 restore_screen();
2764 inv_cursor(true);
2765 break;
2767 case ROCKPAINT_LEFT:
2768 case ROCKPAINT_LEFT | BUTTON_REPEAT:
2769 inv_cursor(false);
2770 x-=bspeed * accelaration;
2771 if (x<0) x=COLS-1;
2772 inv_cursor(true);
2773 break;
2775 case ROCKPAINT_RIGHT:
2776 case ROCKPAINT_RIGHT | BUTTON_REPEAT:
2777 inv_cursor(false);
2778 x+=bspeed * accelaration;
2779 if (x>=COLS) x=0;
2780 inv_cursor(true);
2781 break;
2783 case ROCKPAINT_UP:
2784 case ROCKPAINT_UP | BUTTON_REPEAT:
2785 inv_cursor(false);
2786 y-=bspeed * accelaration;
2787 if (y<0) y=ROWS-1;
2788 inv_cursor(true);
2789 break;
2791 case ROCKPAINT_DOWN:
2792 case ROCKPAINT_DOWN | BUTTON_REPEAT:
2793 inv_cursor(false);
2794 y+=bspeed * accelaration;
2795 if (y>=ROWS)
2797 toolbar();
2798 restore_screen();
2800 inv_cursor(true);
2801 break;
2803 default:
2804 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
2805 return PLUGIN_USB_CONNECTED;
2806 break;
2808 if( tool == Brush && prev_x == 1 )
2810 inv_cursor(false);
2811 draw_brush( x, y );
2812 inv_cursor(true);
2814 if( preview || tool == ColorPicker )
2815 /* always preview color picker */
2817 restore_screen();
2818 switch( tool )
2820 case SelectRectangle:
2821 if( prev_x2 == -1 || prev_y2 == -1 )
2823 /* we are defining the selection */
2824 draw_select_rectangle( prev_x, prev_y, x, y );
2826 else
2828 /* we are pasting the selected data */
2829 draw_paste_rectangle( prev_x, prev_y, prev_x2,
2830 prev_y2, x, y, tool_mode );
2831 prev_x3 = prev_x2-prev_x;
2832 if( prev_x3 < 0 ) prev_x3 *= -1;
2833 prev_y3 = prev_y2-prev_y;
2834 if( prev_y3 < 0 ) prev_y3 *= -1;
2835 draw_select_rectangle( x, y, x+prev_x3, y+prev_y3 );
2836 prev_x3 = -1;
2837 prev_y3 = -1;
2839 break;
2841 case Brush:
2842 break;
2844 case Line:
2845 draw_line( prev_x, prev_y, x, y );
2846 break;
2848 case Curve:
2849 if( prev_x2 == -1 || prev_y2 == -1 )
2851 draw_line( prev_x, prev_y, x, y );
2853 else
2855 draw_curve( prev_x, prev_y,
2856 prev_x2, prev_y2,
2857 prev_x3, prev_y3,
2858 x, y );
2860 break;
2862 case Rectangle:
2863 draw_rect( prev_x, prev_y, x, y );
2864 break;
2866 case RectangleFull:
2867 draw_rect_full( prev_x, prev_y, x, y );
2868 break;
2870 case Oval:
2871 draw_oval_empty( prev_x, prev_y, x, y );
2872 break;
2874 case OvalFull:
2875 draw_oval_full( prev_x, prev_y, x, y );
2876 break;
2878 case Fill:
2879 break;
2881 case ColorPicker:
2882 preview = true;
2883 color_picker( x, y );
2884 preview = false;
2885 break;
2887 case LinearGradient:
2888 line_gradient( prev_x, prev_y, x, y );
2889 break;
2891 case RadialGradient:
2892 line_gradient( prev_x, prev_y, x, y );
2893 break;
2895 case Text:
2896 default:
2897 break;
2899 inv_cursor( true );
2901 if( gridsize > 0 )
2903 show_grid( true );
2904 show_grid( false );
2908 return PLUGIN_OK;
2911 static int load_bitmap( char *file )
2913 struct bitmap bm;
2914 bool ret;
2915 int l;
2917 bm.data = (char*)save_buffer;
2918 ret = rb->read_bmp_file( file, &bm, ROWS*COLS*sizeof( fb_data ),
2919 FORMAT_NATIVE );
2921 if((bm.width > COLS ) || ( bm.height > ROWS ))
2922 return -1;
2924 for( l = bm.height-1; l > 0; l-- )
2926 rb->memmove( save_buffer+l*COLS, save_buffer+l*bm.width,
2927 sizeof( fb_data )*bm.width );
2929 for( l = 0; l < bm.height; l++ )
2931 rb->memset( save_buffer+l*COLS+bm.width, rp_colors[ bgdrawcolor ],
2932 sizeof( fb_data )*(COLS-bm.width) );
2934 rb->memset( save_buffer+COLS*bm.height, rp_colors[ bgdrawcolor ],
2935 sizeof( fb_data )*COLS*(ROWS-bm.height) );
2937 return ret;
2940 static int save_bitmap( char *file )
2942 struct bitmap bm;
2943 bm.data = (char*)save_buffer;
2944 bm.height = ROWS;
2945 bm.width = COLS;
2946 bm.format = FORMAT_NATIVE;
2947 return save_bmp_file( file, &bm, rb );
2950 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
2952 /** must have stuff **/
2953 rb = api;
2955 rb->lcd_set_foreground(COLOR_WHITE);
2956 rb->lcd_set_backdrop(NULL);
2957 rb->lcd_fillrect(0,0,LCD_WIDTH,LCD_HEIGHT);
2958 rb->splash( HZ/2, "Rock Paint");
2960 rb->lcd_clear_display();
2962 filename[0] = '\0';
2964 if( parameter )
2966 if( load_bitmap( parameter ) <= 0 )
2968 rb->splash( 1*HZ, "File Open Error");
2969 clear_drawing();
2971 else
2973 rb->splash( 1*HZ, "Image loaded (%s)", (char *)parameter );
2974 restore_screen();
2975 rb->strcpy( filename, parameter );
2978 else
2980 clear_drawing();
2982 inv_cursor(true);
2984 return rockpaint_loop();