Fix some quotation marks. Thanks to Alexander Levin for pointing it out.
[Rockbox.git] / apps / plugins / rockpaint.c
blob7d5b5cbaa88277d9dd698ca9151c8696c726457f
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 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
109 #define ROCKPAINT_QUIT BUTTON_BACK
110 #define ROCKPAINT_DRAW BUTTON_SELECT
111 #define ROCKPAINT_MENU BUTTON_MENU
112 #define ROCKPAINT_TOOLBAR BUTTON_PLAY
113 #define ROCKPAINT_TOOLBAR2 ( BUTTON_PLAY | BUTTON_LEFT )
114 #define ROCKPAINT_UP BUTTON_UP
115 #define ROCKPAINT_DOWN BUTTON_DOWN
116 #define ROCKPAINT_LEFT BUTTON_LEFT
117 #define ROCKPAINT_RIGHT BUTTON_RIGHT
119 #elif ( CONFIG_KEYPAD == COWOND2_PAD )
120 #define ROCKPAINT_QUIT BUTTON_POWER
121 #define ROCKPAINT_DRAW BUTTON_SELECT
122 #define ROCKPAINT_MENU BUTTON_MENU
123 #define ROCKPAINT_TOOLBAR BUTTON_PLUS
124 #define ROCKPAINT_TOOLBAR2 BUTTON_MINUS
125 #define ROCKPAINT_UP BUTTON_UP
126 #define ROCKPAINT_DOWN BUTTON_DOWN
127 #define ROCKPAINT_LEFT BUTTON_LEFT
128 #define ROCKPAINT_RIGHT BUTTON_RIGHT
130 #else
131 #error "Please define keys for this keypad"
132 #endif
134 /***********************************************************************
135 * Palette Default Colors
136 ***********************************************************************/
137 #define COLOR_BLACK LCD_RGBPACK(0,0,0)
138 #define COLOR_WHITE LCD_RGBPACK(255,255,255)
139 #define COLOR_DARKGRAY LCD_RGBPACK(128,128,128)
140 #define COLOR_LIGHTGRAY LCD_RGBPACK(192,192,192)
141 #define COLOR_RED LCD_RGBPACK(128,0,0)
142 #define COLOR_LIGHTRED LCD_RGBPACK(255,0,0)
143 #define COLOR_DARKYELLOW LCD_RGBPACK(128,128,0)
144 #define COLOR_YELLOW LCD_RGBPACK(255,255,0)
145 #define COLOR_GREEN LCD_RGBPACK(0,128,0)
146 #define COLOR_LIGHTGREN LCD_RGBPACK(0,255,0)
147 #define COLOR_CYAN LCD_RGBPACK(0,128,128)
148 #define COLOR_LIGHTCYAN LCD_RGBPACK(0,255,255)
149 #define COLOR_BLUE LCD_RGBPACK(0,0,128)
150 #define COLOR_LIGHTBLUE LCD_RGBPACK(0,0,255)
151 #define COLOR_PURPLE LCD_RGBPACK(128,0,128)
152 #define COLOR_PINK LCD_RGBPACK(255,0,255)
153 #define COLOR_BROWN LCD_RGBPACK(128,64,0)
154 #define COLOR_LIGHTBROWN LCD_RGBPACK(255,128,64)
156 #define SPLASH_SCREEN PLUGIN_APPS_DIR "/rockpaint/splash.bmp"
157 #define ROCKPAINT_TITLE_FONT 2
159 /***********************************************************************
160 * Program Colors
161 ***********************************************************************/
162 #define ROCKPAINT_PALETTE LCD_RGBPACK(0,64,128)
163 #define ROCKPAINT_SELECTED LCD_RGBPACK(128,192,255)
165 #define ROWS LCD_HEIGHT
166 #define COLS LCD_WIDTH
169 * Toolbar positioning stuff ... don't read this unless you really need to
171 * TB Toolbar
172 * SP Separator
173 * SC Selected Color
174 * PL Palette
175 * TL Tools
178 /* Separator sizes */
179 #define TB_SP_MARGIN 3
180 #define TB_SP_WIDTH (2+2*TB_SP_MARGIN)
182 /* Selected color sizes */
183 #define TB_SC_SIZE 12
185 /* Palette sizes */
186 #define TB_PL_COLOR_SIZE 7
187 #define TB_PL_COLOR_SPACING 2
188 #define TB_PL_WIDTH ( 9 * TB_PL_COLOR_SIZE + 8 * TB_PL_COLOR_SPACING )
189 #define TB_PL_HEIGHT ( TB_PL_COLOR_SIZE * 2 + TB_PL_COLOR_SPACING )
191 /* Tools sizes */
192 #define TB_TL_SIZE 8
193 #define TB_TL_SPACING 2
194 #define TB_TL_WIDTH ( 7 * ( TB_TL_SIZE + TB_TL_SPACING ) - TB_TL_SPACING )
195 #define TB_TL_HEIGHT ( 2 * TB_TL_SIZE + TB_TL_SPACING )
197 /* Menu button size ... gruik */
198 #define TB_MENU_MIN_WIDTH 30
200 /* Selected colors position */
201 #define TB_SC_FG_TOP 2
202 #define TB_SC_FG_LEFT 2
203 #define TB_SC_BG_TOP (TB_SC_FG_TOP+TB_PL_COLOR_SIZE*2+TB_PL_COLOR_SPACING-TB_SC_SIZE)
204 #define TB_SC_BG_LEFT (TB_SC_FG_LEFT+TB_PL_COLOR_SIZE*2+TB_PL_COLOR_SPACING-TB_SC_SIZE)
206 /* Palette position */
207 #define TB_PL_TOP TB_SC_FG_TOP
208 #define TB_PL_LEFT (TB_SC_BG_LEFT + TB_SC_SIZE + TB_PL_COLOR_SPACING)
210 /* Tools position */
211 #define TB_TL_TOP TB_SC_FG_TOP
212 #define TB_TL_LEFT ( TB_PL_LEFT + TB_PL_WIDTH-1 + TB_SP_WIDTH )
214 #if TB_TL_LEFT + TB_TL_WIDTH + TB_MENU_MIN_WIDTH >= LCD_WIDTH
215 #undef TB_TL_TOP
216 #undef TB_TL_LEFT
217 #define TB_TL_TOP ( TB_PL_TOP + TB_PL_HEIGHT + 4 )
218 #define TB_TL_LEFT TB_SC_FG_LEFT
219 #endif
221 /* Menu button position */
222 #define TB_MENU_TOP ( TB_TL_TOP + (TB_TL_HEIGHT-8)/2 )
223 #define TB_MENU_LEFT ( TB_TL_LEFT + TB_TL_WIDTH-1 + TB_SP_WIDTH )
225 #define TB_HEIGHT ( TB_TL_TOP + TB_TL_HEIGHT + 1 )
228 static void draw_pixel(int x,int y);
229 static void draw_line( int x1, int y1, int x2, int y2 );
230 static void draw_rect( int x1, int y1, int x2, int y2 );
231 static void draw_toolbars(bool update);
232 static void inv_cursor(bool update);
233 static void restore_screen(void);
234 static void clear_drawing(void);
235 static void goto_menu(void);
236 static int load_bitmap( char *filename );
237 static int save_bitmap( char *filename );
238 static void draw_rect_full( int x1, int y1, int x2, int y2 );
239 extern int errno;
241 /***********************************************************************
242 * Global variables
243 ***********************************************************************/
245 #if !defined(SIMULATOR) || defined(__MINGW32__) || defined(__CYGWIN__)
246 int errno;
247 #endif
249 static struct plugin_api* rb;
251 MEM_FUNCTION_WRAPPERS(rb);
253 static int drawcolor=0; /* Current color (in palette) */
254 static int bgdrawcolor=9; /* Current background color (in palette) */
255 bool isbg = false; /* gruik ugly hack alert */
257 static int preview=false; /* Is preview mode on ? */
259 /* TODO: clean this up */
260 static int x=0, y=0; /* cursor position */
261 static int prev_x=-1, prev_y=-1; /* previous saved cursor position */
262 static int prev_x2=-1, prev_y2=-1;
263 static int prev_x3=-1, prev_y3=-1;
264 static int tool_mode=-1;
267 static int bsize=1; /* brush size */
268 static int bspeed=1; /* brush speed */
270 enum Tools { Brush = 0, /* Regular brush */
271 Fill = 1, /* Fill a shape with current color */
272 SelectRectangle = 2,
273 ColorPicker = 3, /* Pick a color */
274 Line = 4, /* Draw a line between two points */
275 Unused = 5, /* THIS IS UNUSED ... */
276 Curve = 6,
277 Text = 7,
278 Rectangle = 8, /* Draw a rectangle */
279 RectangleFull = 9,
280 Oval = 10, /* Draw an oval */
281 OvalFull = 11,
282 LinearGradient = 12,
283 RadialGradient = 13
286 enum Tools tool = Brush;
288 static bool quit=false;
289 static int gridsize=0;
291 static fb_data rp_colors[18] =
293 COLOR_BLACK, COLOR_DARKGRAY, COLOR_RED, COLOR_DARKYELLOW,
294 COLOR_GREEN, COLOR_CYAN, COLOR_BLUE, COLOR_PURPLE, COLOR_BROWN,
295 COLOR_WHITE, COLOR_LIGHTGRAY, COLOR_LIGHTRED, COLOR_YELLOW,
296 COLOR_LIGHTGREN, COLOR_LIGHTCYAN, COLOR_LIGHTBLUE, COLOR_PINK,
297 COLOR_LIGHTBROWN
300 static fb_data save_buffer[ ROWS*COLS ];
302 extern fb_data rockpaint[];
303 extern fb_data rockpaint_hsvrgb[];
305 /* Maximum string size allowed for the text tool */
306 #define MAX_TEXT 255
308 static union
310 /* Used by fill and gradient algorithms */
311 struct
313 short x;
314 short y;
315 } coord[ ROWS*COLS ];
317 /* Used by bezier curve algorithms */
318 struct
320 short x1, y1;
321 short x2, y2;
322 short x3, y3;
323 short x4, y4;
324 short depth;
325 } bezier[ (ROWS*COLS)/5 ]; /* We have 4.5 times more data per struct
326 * than coord ... so we divide to take
327 * less memory. */
329 /* Used to cut/copy/paste data */
330 fb_data clipboard[ ROWS*COLS ];
332 /* Used for text mode */
333 struct
335 char text[MAX_TEXT+1];
336 char font[MAX_PATH+1];
337 char old_font[MAX_PATH+1];
338 int fh_buf[30];
339 int fw_buf[30];
340 char fontname_buf[30][MAX_PATH];
341 } text;
342 } buffer;
344 /* Current filename */
345 static char filename[MAX_PATH+1];
347 /* Font preview buffer */
348 //#define FONT_PREVIEW_WIDTH ((LCD_WIDTH-30)/8)
349 //#define FONT_PREVIEW_HEIGHT 1000
350 //static unsigned char fontpreview[FONT_PREVIEW_WIDTH*FONT_PREVIEW_HEIGHT];
352 /***********************************************************************
353 * Offscreen buffer/Text/Fonts handling
355 * Parts of code taken from firmware/drivers/lcd-16bit.c
356 ***********************************************************************/
357 static void buffer_mono_bitmap_part(
358 fb_data *buf, int buf_width, int buf_height,
359 const unsigned char *src, int src_x, int src_y,
360 int stride, int x, int y, int width, int height )
361 /* this function only draws the foreground part of the bitmap */
363 const unsigned char *src_end;
364 fb_data *dst, *dst_end;
365 unsigned fgcolor = rb->lcd_get_foreground();
367 /* nothing to draw? */
368 if( ( width <= 0 ) || ( height <= 0 ) || ( x >= buf_width )
369 || ( y >= buf_height ) || ( x + width <= 0 ) || ( y + height <= 0 ) )
370 return;
372 /* clipping */
373 if( x < 0 )
375 width += x;
376 src_x -= x;
377 x = 0;
379 if( y < 0 )
381 height += y;
382 src_y -= y;
383 y = 0;
385 if( x + width > buf_width )
386 width = buf_width - x;
387 if( y + height > buf_height )
388 height = buf_height - y;
390 src += stride * (src_y >> 3) + src_x; /* move starting point */
391 src_y &= 7;
392 src_end = src + width;
394 dst = buf + y*buf_width + x;
398 const unsigned char *src_col = src++;
399 unsigned data = *src_col >> src_y;
400 fb_data *dst_col = dst++;
401 int numbits = 8 - src_y;
403 dst_end = dst_col + height * buf_width;
406 if( data & 0x01 )
407 *dst_col = fgcolor; /* FIXME ? */
409 dst_col += buf_width;
411 data >>= 1;
412 if( --numbits == 0 )
414 src_col += stride;
415 data = *src_col;
416 numbits = 8;
418 } while( dst_col < dst_end );
419 } while( src < src_end );
422 static void buffer_putsxyofs( fb_data *buf, int buf_width, int buf_height,
423 int x, int y, int ofs, const unsigned char *str )
425 unsigned short ch;
426 unsigned short *ucs;
428 struct font *pf = rb->font_get( FONT_UI );
429 if( !pf ) pf = rb->font_get( FONT_SYSFIXED );
431 ucs = rb->bidi_l2v( str, 1 );
433 while( (ch = *ucs++) != 0 && x < buf_width )
435 int width;
436 const unsigned char *bits;
438 /* get proportional width and glyph bits */
439 width = rb->font_get_width( pf, ch );
441 if( ofs > width )
443 ofs -= width;
444 continue;
447 bits = rb->font_get_bits( pf, ch );
449 buffer_mono_bitmap_part( buf, buf_width, buf_height, bits, ofs, 0, width, x, y, width - ofs, pf->height);
451 x += width - ofs;
452 ofs = 0;
456 /***********************************************************************
457 * Menu handling
458 ***********************************************************************/
459 struct menu_items
461 int value;
462 char label[16]; /* GRUIK ? */
465 #define MENU_ESC -1242
466 enum {
467 /* Generic menu items */
468 MENU_END = -42, MENU_TITLE = -12,
469 /* Main menu */
470 MAIN_MENU_RESUME,
471 MAIN_MENU_NEW, MAIN_MENU_LOAD, MAIN_MENU_SAVE,
472 MAIN_MENU_BRUSH_SIZE, MAIN_MENU_BRUSH_SPEED, MAIN_MENU_COLOR,
473 MAIN_MENU_GRID_SIZE,
474 MAIN_MENU_EXIT,
475 /* Select action menu */
476 SELECT_MENU_CUT, SELECT_MENU_COPY, SELECT_MENU_INVERT,
477 SELECT_MENU_HFLIP, SELECT_MENU_VFLIP, SELECT_MENU_ROTATE90,
478 SELECT_MENU_ROTATE180, SELECT_MENU_ROTATE270,
479 SELECT_MENU_CANCEL,
480 /* Text menu */
481 TEXT_MENU_TEXT, TEXT_MENU_FONT,
482 TEXT_MENU_PREVIEW, TEXT_MENU_APPLY, TEXT_MENU_CANCEL,
485 static struct menu_items main_menu[]=
486 { { MENU_TITLE, "RockPaint" },
487 { MAIN_MENU_RESUME, "Resume" },
488 { MAIN_MENU_NEW, "New" },
489 { MAIN_MENU_LOAD, "Load" },
490 { MAIN_MENU_SAVE, "Save" },
491 { MAIN_MENU_BRUSH_SIZE, "Brush Size" },
492 { MAIN_MENU_BRUSH_SPEED, "Brush Speed" },
493 { MAIN_MENU_COLOR, "Choose Color" },
494 { MAIN_MENU_GRID_SIZE, "Grid Size" },
495 { MAIN_MENU_EXIT, "Exit" },
496 { MENU_END, "" } };
498 static struct menu_items size_menu[] =
499 { { MENU_TITLE, "Choose Size" },
500 { 1, "1x" },
501 { 2, "2x" },
502 { 4, "4x" },
503 { 8, "8x" },
504 { MENU_END, "" } };
506 static struct menu_items speed_menu[] =
507 { { MENU_TITLE, "Choose Speed" },
508 { 1, "1x" },
509 { 2, "2x" },
510 { 4, "4x" },
511 { MENU_END, "" } };
513 static struct menu_items gridsize_menu[] =
514 { { MENU_TITLE, "Grid Size" },
515 { 0, "No grid" },
516 { 5, "5px" },
517 { 10, "10px" },
518 { 20, "20px" },
519 { MENU_END, "" } };
521 static struct menu_items select_menu[] =
522 { { MENU_TITLE, "Select..." },
523 { SELECT_MENU_CUT, "Cut" },
524 { SELECT_MENU_COPY, "Copy" },
525 { SELECT_MENU_INVERT, "Invert" },
526 { SELECT_MENU_HFLIP, "Horizontal flip" },
527 { SELECT_MENU_VFLIP, "Vertical flip" },
528 // { SELECT_MENU_ROTATE90, "Rotate 90°" },
529 { SELECT_MENU_ROTATE180, "Rotate 180°" },
530 // { SELECT_MENU_ROTATE270, "Rotate 270°" },
531 { SELECT_MENU_CANCEL, "Cancel" },
532 { MENU_END, "" } };
534 static struct menu_items text_menu[] =
535 { { MENU_TITLE, "Text" },
536 { TEXT_MENU_TEXT, "Set text" },
537 { TEXT_MENU_FONT, "Change font" },
538 { TEXT_MENU_PREVIEW, "Preview" },
539 { TEXT_MENU_APPLY, "Apply" },
540 { TEXT_MENU_CANCEL, "Cancel" },
541 { MENU_END, "" } };
543 static int draw_window( int height, int width,
544 int *top, int *left,
545 const char *title )
547 int fh;
548 rb->lcd_getstringsize( title, NULL, &fh );
549 fh++;
551 const int _top = ( LCD_HEIGHT - height ) / 2;
552 const int _left = ( LCD_WIDTH - width ) / 2;
553 if( top ) *top = _top;
554 if( left ) *left = _left;
555 rb->lcd_set_background(COLOR_BLUE);
556 rb->lcd_set_foreground(COLOR_LIGHTGRAY);
557 rb->lcd_fillrect( _left, _top, width, height );
558 rb->lcd_set_foreground(COLOR_BLUE);
559 rb->lcd_fillrect( _left, _top, width, fh+4 );
560 rb->lcd_set_foreground(COLOR_WHITE);
561 rb->lcd_putsxy( _left+2, _top+2, title );
562 rb->lcd_set_foreground(COLOR_BLACK);
563 rb->lcd_drawrect( _left, _top, width, height );
564 return _top+fh+4;
567 static int menu_display( struct menu_items menu[], int prev_value )
569 int i,
570 fh, /* font height */
571 width, height,
572 a, b,
573 selection=1,
574 menu_length,
575 top, left;
576 int scroll = 0, onscreen = 0;
578 rb->lcd_getstringsize( menu[0].label, &width, &fh );
579 for( i=1; menu[i].value != MENU_END; i++ )
581 if( prev_value == menu[i].value )
583 selection = i;
585 rb->lcd_getstringsize( menu[i].label, &a, &b );
586 if( a > width ) width = a;
587 if( b > fh ) fh = b;
589 menu_length = i;
590 fh++;
591 width += 10;
593 height = menu_length * fh + 4 + 2 + 2;
594 if( height >= LCD_HEIGHT )
596 scroll = 1;
597 onscreen = ( LCD_HEIGHT - 4 - 2 - 2 )/fh;
598 height = onscreen * fh + 4 + 2 + 2;
599 width += 5;
601 else
603 onscreen = menu_length;
606 draw_window( height, width, &top, &left, menu[0].label );
608 while( 1 )
610 for( i = (scroll == 0 ? 1 : scroll);
611 i < (scroll ? scroll + onscreen - 1:onscreen);
612 i++ )
614 if( i == selection )
616 rb->lcd_set_foreground( COLOR_WHITE );
617 rb->lcd_set_background( COLOR_BLUE );
619 else
621 rb->lcd_set_foreground( COLOR_BLACK );
622 rb->lcd_set_background( COLOR_LIGHTGRAY );
624 rb->lcd_putsxy( left+2,
625 top+6+fh*(i-(scroll == 0 ? 0 : scroll-1 )),
626 menu[i].label );
628 if( scroll )
630 int scroll_height = ((height-fh-4-2)*onscreen)/menu_length;
631 rb->lcd_set_foreground( COLOR_BLACK );
632 rb->lcd_vline( left+width-5, top+fh+4, top+height-2 );
633 rb->lcd_fillrect( left+width-4,
634 top+fh+4+((height-4-2-fh-scroll_height)*(scroll-1))/(menu_length-onscreen),
635 3, scroll_height );
637 rb->lcd_update();
639 switch( rb->button_get(true) )
641 case ROCKPAINT_UP:
642 case ROCKPAINT_UP|BUTTON_REPEAT:
643 selection = (selection + menu_length-1)%menu_length;
644 if( !selection ) selection = menu_length-1;
645 break;
647 case ROCKPAINT_DOWN:
648 case ROCKPAINT_DOWN|BUTTON_REPEAT:
649 selection = (selection + 1)%menu_length;
650 if( !selection ) selection++;
651 break;
653 case ROCKPAINT_LEFT:
654 restore_screen();
655 return MENU_ESC;
657 case ROCKPAINT_RIGHT:
658 case ROCKPAINT_DRAW:
659 restore_screen();
660 return menu[selection].value;
662 if( scroll )
664 if( selection < scroll )
666 scroll = selection;
667 draw_window( height, width, NULL, NULL, menu[0].label );
669 if( selection >= scroll + onscreen - 1 )
671 scroll++;
672 draw_window( height, width, NULL, NULL, menu[0].label );
678 /***********************************************************************
679 * File browser
680 ***********************************************************************/
682 char bbuf[MAX_PATH+1]; /* used by file and font browsers */
683 char bbuf_s[MAX_PATH+1]; /* used by file and font browsers */
685 static bool browse( char *dst, int dst_size, const char *start )
687 #define WIDTH ( LCD_WIDTH - 20 )
688 #define HEIGHT ( LCD_HEIGHT - 20 )
689 #define LINE_SPACE 2
690 int top, top_inside, left;
692 DIR *d;
693 struct dirent *de;
694 int fvi = 0; /* first visible item */
695 int lvi = 0; /* last visible item */
696 int si = 0; /* selected item */
697 int li = 0; /* last item */
698 int i;
700 int fh;
701 char *a;
703 rb->lcd_getstringsize( "Ap", NULL, &fh );
705 rb->strcpy( bbuf, start );
706 a = bbuf+rb->strlen(bbuf)-1;
707 if( *a != '/' )
709 a[1] = '/';
710 a[2] = '\0';
713 while( 1 )
715 d = rb->opendir( bbuf );
716 if( !d )
719 if( errno == ENOTDIR )
721 /* this is a file */
722 bbuf[rb->strlen(bbuf)-1] = '\0';
723 rb->strncpy( dst, bbuf, dst_size );
724 return true;
726 else if( errno == EACCES || errno == ENOENT )
728 bbuf[0] = '/'; bbuf[1] = '\0';
729 d = rb->opendir( "/" );
731 else
733 return false;
736 top_inside = draw_window( HEIGHT, WIDTH, &top, &left, bbuf );
737 i = 0;
738 li = -1;
739 while( i < fvi )
741 rb->readdir( d );
742 i++;
744 while( top_inside+(i-fvi)*(fh+LINE_SPACE) < HEIGHT )
746 de = rb->readdir( d );
747 if( !de )
749 li = i-1;
750 break;
752 rb->lcd_set_foreground((si==i?COLOR_WHITE:COLOR_BLACK));
753 rb->lcd_set_background((si==i?COLOR_BLUE:COLOR_LIGHTGRAY));
754 rb->lcd_putsxy( left+10,
755 top_inside+(i-fvi)*(fh+LINE_SPACE),
756 de->d_name );
757 if( si == i )
758 rb->strcpy( bbuf_s, de->d_name );
759 i++;
761 lvi = i-1;
762 if( li == -1 )
764 if( !rb->readdir( d ) )
766 li = lvi;
769 rb->closedir( d );
771 rb->lcd_update();
773 switch( rb->button_get(true) )
775 case ROCKPAINT_UP:
776 case ROCKPAINT_UP|BUTTON_REPEAT:
777 if( si > 0 )
779 si--;
780 if( si<fvi )
782 fvi--;
785 break;
787 case ROCKPAINT_DOWN:
788 case ROCKPAINT_DOWN|BUTTON_REPEAT:
789 if( li == -1 || si < li )
791 si++;
792 if( si>lvi )
794 fvi++;
797 break;
799 case ROCKPAINT_LEFT:
800 if( bbuf[0] == '/' && !bbuf[1] ) return false;
801 bbuf_s[0] = '.';
802 bbuf_s[1] = '.';
803 bbuf_s[2] = '\0';
804 case ROCKPAINT_RIGHT:
805 case ROCKPAINT_DRAW:
806 if( *bbuf_s == '.' && !bbuf_s[1] ) break;
807 a = bbuf;
808 while( *a ) a++;
809 if( *bbuf_s == '.' && bbuf_s[1] == '.' && !bbuf_s[2] )
811 a--;
812 if( a == bbuf ) break;
813 if( *a == '/' ) a--;
814 while( *a != '/' ) a--;
815 *++a = '\0';
816 break;
818 rb->strcpy( a, bbuf_s );
819 while( *a ) a++;
820 *a++ = '/';
821 *a = '\0';
822 fvi = si = 0;
823 break;
827 #undef WIDTH
828 #undef HEIGHT
829 #undef LINE_SPACE
832 /***********************************************************************
833 * Font browser
835 * FIXME: This still needs some work ... it currently only works fine
836 * on the simulators, disk spins too much on real targets -> rendered
837 * font buffer needed.
838 ***********************************************************************/
839 static bool browse_fonts( char *dst, int dst_size )
841 char old_font[MAX_PATH];
842 #define WIDTH ( LCD_WIDTH - 20 )
843 #define HEIGHT ( LCD_HEIGHT - 20 )
844 #define LINE_SPACE 2
845 int top, top_inside = 0, left;
847 DIR *d;
848 struct dirent *de;
849 int fvi = 0; /* first visible item */
850 int lvi = 0; /* last visible item */
851 int si = 0; /* selected item */
852 int osi = 0; /* old selected item */
853 int li = 0; /* last item */
854 int nvih = 0; /* next visible item height */
855 int i;
856 int b_need_redraw = 1; /* Do we need to redraw ? */
858 int cp = 0; /* current position */
859 int fh; /* font height */
861 #define fh_buf buffer.text.fh_buf /* 30 might not be enough ... */
862 #define fw_buf buffer.text.fw_buf
863 int fw;
864 #define fontname_buf buffer.text.fontname_buf
866 rb->snprintf( old_font, MAX_PATH,
867 FONT_DIR "/%s.fnt",
868 rb->global_settings->font_file );
870 while( 1 )
872 if( !b_need_redraw )
874 /* we don't need to redraw ... but we need to unselect
875 * the previously selected item */
876 cp = top_inside + LINE_SPACE;
877 for( i = 0; i+fvi < osi; i++ )
879 cp += fh_buf[i] + LINE_SPACE;
881 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
882 rb->lcd_fillrect( left+10, cp, fw_buf[i], fh_buf[i] );
883 rb->lcd_set_drawmode(DRMODE_SOLID);
886 if( b_need_redraw )
888 b_need_redraw = 0;
890 d = rb->opendir( FONT_DIR "/" );
891 if( !d )
893 return false;
895 top_inside = draw_window( HEIGHT, WIDTH, &top, &left, "Fonts" );
896 i = 0;
897 li = -1;
898 while( i < fvi )
900 rb->readdir( d );
901 i++;
903 cp = top_inside+LINE_SPACE;
905 rb->lcd_set_foreground(COLOR_BLACK);
906 rb->lcd_set_background(COLOR_LIGHTGRAY);
908 while( cp < top+HEIGHT )
910 de = rb->readdir( d );
911 if( !de )
913 li = i-1;
914 break;
916 if( rb->strlen( de->d_name ) < 4
917 || rb->strcmp( de->d_name + rb->strlen( de->d_name ) - 4,
918 ".fnt" ) )
919 continue;
920 rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s",
921 de->d_name );
922 rb->font_load( bbuf );
923 rb->font_getstringsize( de->d_name, &fw, &fh, FONT_UI );
924 if( nvih > 0 )
926 nvih -= fh;
927 fvi++;
928 if( nvih < 0 ) nvih = 0;
929 i++;
930 continue;
932 if( cp + fh >= top+HEIGHT )
934 nvih = fh;
935 break;
937 rb->lcd_putsxy( left+10, cp, de->d_name );
938 fh_buf[i-fvi] = fh;
939 fw_buf[i-fvi] = fw;
940 cp += fh + LINE_SPACE;
941 rb->strcpy( fontname_buf[i-fvi], bbuf );
942 i++;
944 lvi = i-1;
945 if( li == -1 )
947 if( !(de = rb->readdir( d ) ) )
949 li = lvi;
951 else if( !nvih && !rb->strlen( de->d_name ) < 4
952 && !rb->strcmp( de->d_name + rb->strlen( de->d_name ) - 4,
953 ".fnt" ) )
955 rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s",
956 de->d_name );
957 rb->font_load( bbuf );
958 rb->font_getstringsize( de->d_name, NULL, &fh, FONT_UI );
959 nvih = fh;
962 rb->font_load( old_font );
963 rb->closedir( d );
966 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
967 cp = top_inside + LINE_SPACE;
968 for( i = 0; i+fvi < si; i++ )
970 cp += fh_buf[i] + LINE_SPACE;
972 rb->lcd_fillrect( left+10, cp, fw_buf[i], fh_buf[i] );
973 rb->lcd_set_drawmode(DRMODE_SOLID);
975 rb->lcd_update_rect( left, top, WIDTH, HEIGHT );
977 osi = si;
978 i = fvi;
979 switch( rb->button_get(true) )
981 case ROCKPAINT_UP:
982 case ROCKPAINT_UP|BUTTON_REPEAT:
983 if( si > 0 )
985 si--;
986 if( si<fvi )
988 fvi = si;
991 break;
993 case ROCKPAINT_DOWN:
994 case ROCKPAINT_DOWN|BUTTON_REPEAT:
995 if( li == -1 || si < li )
997 si++;
999 break;
1001 case ROCKPAINT_LEFT:
1002 return false;
1004 case ROCKPAINT_RIGHT:
1005 case ROCKPAINT_DRAW:
1006 rb->snprintf( dst, dst_size, "%s", fontname_buf[si-fvi] );
1007 return true;
1010 if( i != fvi || si > lvi )
1012 b_need_redraw = 1;
1015 if( si<=lvi )
1017 nvih = 0;
1020 #undef fh_buf
1021 #undef fw_buf
1022 #undef fontname_buf
1023 #undef WIDTH
1024 #undef HEIGHT
1025 #undef LINE_SPACE
1028 /***********************************************************************
1029 * HSVRGB Color chooser
1030 ***********************************************************************/
1031 static unsigned int color_chooser( unsigned int color )
1033 int red = RGB_UNPACK_RED( color );
1034 int green = RGB_UNPACK_GREEN( color );
1035 int blue = RGB_UNPACK_BLUE( color );
1036 int hue, saturation, value;
1037 int r, g, b; /* temp variables */
1038 int i, top, left;
1040 enum BaseColor { Hue = 0, Saturation = 1, Value = 2,
1041 Red = 3, Green = 4, Blue = 5 };
1042 enum BaseColor current = Red;
1043 bool has_changed;
1045 char str[6] = "";
1047 restore_screen();
1049 rgb2hsv( red, green, blue, &hue, &saturation, &value );
1051 while( 1 )
1053 has_changed = false;
1054 color = LCD_RGBPACK( red, green, blue );
1056 #define HEIGHT ( 100 )
1057 #define WIDTH ( 150 )
1059 top = draw_window( HEIGHT, WIDTH, NULL, &left, "Color chooser" );
1060 top -= 15;
1062 for( i=0; i<100; i++ )
1064 hsv2rgb( i*36, saturation, value, &r, &g, &b );
1065 rb->lcd_set_foreground( LCD_RGBPACK( r, g, b ) );
1066 rb->lcd_vline( left+15+i, top+20, top+27 );
1067 hsv2rgb( hue, i*255/100, value, &r, &g, &b );
1068 rb->lcd_set_foreground( LCD_RGBPACK( r, g, b ) );
1069 rb->lcd_vline( left+15+i, top+30, top+37 );
1070 hsv2rgb( hue, saturation, i*255/100, &r, &g, &b );
1071 rb->lcd_set_foreground( LCD_RGBPACK( r, g, b ) );
1072 rb->lcd_vline( left+15+i, top+40, top+47 );
1073 rb->lcd_set_foreground( LCD_RGBPACK( i*255/100, green, blue ) );
1074 rb->lcd_vline( left+15+i, top+50, top+57 );
1075 rb->lcd_set_foreground( LCD_RGBPACK( red, i*255/100, blue ) );
1076 rb->lcd_vline( left+15+i, top+60, top+67 );
1077 rb->lcd_set_foreground( LCD_RGBPACK( red, green, i*255/100 ) );
1078 rb->lcd_vline( left+15+i, top+70, top+77 );
1081 rb->lcd_set_foreground(COLOR_BLACK);
1082 #define POSITION( a, i ) \
1083 rb->lcd_drawpixel( left+14+i, top + 19 + a ); \
1084 rb->lcd_drawpixel( left+16+i, top + 19 + a ); \
1085 rb->lcd_drawpixel( left+14+i, top + 28 + a ); \
1086 rb->lcd_drawpixel( left+16+i, top + 28 + a );
1087 POSITION( 0, hue/36 );
1088 POSITION( 10, saturation*99/255 );
1089 POSITION( 20, value*99/255 );
1090 POSITION( 30, red*99/255 );
1091 POSITION( 40, green*99/255 );
1092 POSITION( 50, blue*99/255 );
1093 #undef POSITION
1094 rb->lcd_set_background(COLOR_LIGHTGRAY);
1095 rb->lcd_setfont( FONT_SYSFIXED );
1096 rb->snprintf( str, 6, "%d", hue/10 );
1097 rb->lcd_putsxy( left + 117, top + 20, str );
1098 rb->snprintf( str, 6, "%d.%d", saturation/255, ((saturation*100)/255)%100 );
1099 rb->lcd_putsxy( left + 117, top + 30, str );
1100 rb->snprintf( str, 6, "%d.%d", value/255, ((value*100)/255)%100 );
1101 rb->lcd_putsxy( left + 117, top + 40, str );
1102 rb->snprintf( str, 6, "%d", red );
1103 rb->lcd_putsxy( left + 117, top + 50, str );
1104 rb->snprintf( str, 6, "%d", green );
1105 rb->lcd_putsxy( left + 117, top + 60, str );
1106 rb->snprintf( str, 6, "%d", blue );
1107 rb->lcd_putsxy( left + 117, top + 70, str );
1108 rb->lcd_setfont( FONT_UI );
1110 #define CURSOR( l ) \
1111 rb->lcd_bitmap_transparent_part( rockpaint_hsvrgb, 1, 1, 16, left+l+1, top+20, 6, 58 ); \
1112 rb->lcd_bitmap_transparent_part( rockpaint_hsvrgb, 8, 10*current, 16, left+l, top+19+10*current, 8, 10 );
1113 CURSOR( 5 );
1114 #undef CURSOR
1116 rb->lcd_set_foreground( color );
1117 rb->lcd_fillrect( left+15, top+85, 100, 8 );
1119 rb->lcd_update();
1121 switch( rb->button_get(true) )
1123 case ROCKPAINT_UP:
1124 current = ( current + 5 )%6;
1125 break;
1127 case ROCKPAINT_DOWN:
1128 current = (current + 1 )%6;
1129 break;
1131 case ROCKPAINT_LEFT:
1132 has_changed = true;
1133 switch( current )
1135 case Hue:
1136 hue = ( hue + 3600 - 10 )%3600;
1137 break;
1138 case Saturation:
1139 if( saturation ) saturation--;
1140 break;
1141 case Value:
1142 if( value ) value--;
1143 break;
1144 case Red:
1145 if( red ) red--;
1146 break;
1147 case Green:
1148 if( green ) green--;
1149 break;
1150 case Blue:
1151 if( blue ) blue--;
1152 break;
1154 break;
1156 case ROCKPAINT_LEFT|BUTTON_REPEAT:
1157 has_changed = true;
1158 switch( current )
1160 case Hue:
1161 hue = ( hue + 3600 - 100 )%3600;
1162 break;
1163 case Saturation:
1164 if( saturation >= 8 ) saturation-=8;
1165 else saturation = 0;
1166 break;
1167 case Value:
1168 if( value >= 8 ) value-=8;
1169 else value = 0;
1170 break;
1171 case Red:
1172 if( red >= 8 ) red-=8;
1173 else red = 0;
1174 break;
1175 case Green:
1176 if( green >= 8 ) green-=8;
1177 else green = 0;
1178 break;
1179 case Blue:
1180 if( blue >= 8 ) blue-=8;
1181 else blue = 0;
1182 break;
1184 break;
1186 case ROCKPAINT_RIGHT:
1187 has_changed = true;
1188 switch( current )
1190 case Hue:
1191 hue = ( hue + 10 )%3600;
1192 break;
1193 case Saturation:
1194 if( saturation < 0xff ) saturation++;
1195 break;
1196 case Value:
1197 if( value < 0xff ) value++;
1198 break;
1199 case Red:
1200 if( red < 0xff ) red++;
1201 break;
1202 case Green:
1203 if( green < 0xff ) green++;
1204 break;
1205 case Blue:
1206 if( blue < 0xff ) blue++;
1207 break;
1209 break;
1211 case ROCKPAINT_RIGHT|BUTTON_REPEAT:
1212 has_changed = true;
1213 switch( current )
1215 case Hue:
1216 hue = ( hue + 100 )%3600;
1217 break;
1218 case Saturation:
1219 if( saturation < 0xff - 8 ) saturation+=8;
1220 else saturation = 0xff;
1221 break;
1222 case Value:
1223 if( value < 0xff - 8 ) value+=8;
1224 else value = 0xff;
1225 break;
1226 case Red:
1227 if( red < 0xff - 8 ) red+=8;
1228 else red = 0xff;
1229 break;
1230 case Green:
1231 if( green < 0xff - 8 ) green+=8;
1232 else green = 0xff;
1233 break;
1234 case Blue:
1235 if( blue < 0xff - 8 ) blue+=8;
1236 else blue = 0xff;
1237 break;
1239 break;
1241 case ROCKPAINT_DRAW:
1242 return color;
1244 if( has_changed )
1246 switch( current )
1248 case Hue:
1249 case Saturation:
1250 case Value:
1251 hsv2rgb( hue, saturation, value, &red, &green, &blue );
1252 break;
1254 case Red:
1255 case Green:
1256 case Blue:
1257 rgb2hsv( red, green, blue, &hue, &saturation, &value );
1258 break;
1261 #undef HEIGHT
1262 #undef WIDTH
1266 /***********************************************************************
1267 * Misc routines
1268 ***********************************************************************/
1269 static void init_buffer(void)
1271 int i;
1272 fb_data color = rp_colors[ bgdrawcolor ];
1273 for( i = 0; i < ROWS*COLS; i++ )
1275 save_buffer[i] = color;
1279 static void draw_pixel(int x,int y)
1281 if( !preview )
1283 if( x < 0 || x >= COLS || y < 0 || y >= ROWS ) return;
1284 if( isbg )
1286 save_buffer[ x+y*COLS ] = rp_colors[bgdrawcolor];
1288 else
1290 save_buffer[ x+y*COLS ] = rp_colors[drawcolor];
1293 rb->lcd_drawpixel(x,y);
1296 static void color_picker( int x, int y )
1298 if( preview )
1300 rb->lcd_set_foreground( save_buffer[ x+y*COLS ] );
1301 #define PSIZE 12
1302 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1303 rb->lcd_drawrect( x<COLS-PSIZE ? x + 2 : x - PSIZE, y<ROWS-PSIZE ? y + 2: y - PSIZE, PSIZE - 2, PSIZE - 2 );
1304 rb->lcd_set_drawmode(DRMODE_SOLID);
1305 rb->lcd_fillrect( x<COLS-PSIZE ? x+3 : x - PSIZE+1, y<ROWS-PSIZE ? y +3: y - PSIZE+1, PSIZE-4, PSIZE-4 );
1306 #undef PSIZE
1307 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1309 else
1311 rp_colors[ drawcolor ] = save_buffer[ x+y*COLS ];
1315 static void draw_select_rectangle( int x1, int y1, int x2, int y2 )
1316 /* This is a preview mode only function */
1318 int i,a;
1319 if( x1 > x2 )
1321 i = x1;
1322 x1 = x2;
1323 x2 = i;
1325 if( y1 > y2 )
1327 i = y1;
1328 y1 = y2;
1329 y2 = i;
1331 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1332 i = 0;
1333 for( a = x1; a < x2; a++, i++ )
1334 if( i%2 )
1335 rb->lcd_drawpixel( a, y1 );
1336 for( a = y1; a < y2; a++, i++ )
1337 if( i%2 )
1338 rb->lcd_drawpixel( x2, a );
1339 if( y2 != y1 )
1340 for( a = x2; a > x1; a--, i++ )
1341 if( i%2 )
1342 rb->lcd_drawpixel( a, y2 );
1343 if( x2 != x1 )
1344 for( a = y2; a > y1; a--, i++ )
1345 if( i%2 )
1346 rb->lcd_drawpixel( x1, a );
1347 rb->lcd_set_drawmode(DRMODE_SOLID);
1350 static void copy_to_clipboard( void )
1352 /* This needs to be optimised ... but i'm lazy ATM */
1353 rb->memcpy( buffer.clipboard, save_buffer, COLS*ROWS*sizeof( fb_data ) );
1356 /* no preview mode handling atm ... do we need it ? (one if) */
1357 static void draw_invert( int x1, int y1, int x2, int y2 )
1359 int i;
1360 if( x1 > x2 )
1362 i = x1;
1363 x1 = x2;
1364 x2 = i;
1366 if( y1 > y2 )
1368 i = y1;
1369 y1 = y2;
1370 y2 = i;
1373 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1374 rb->lcd_fillrect( x1, y1, x2-x1+1, y2-y1+1 );
1375 rb->lcd_set_drawmode(DRMODE_SOLID);
1377 for( ; y1<=y2; y1++ )
1379 for( i = x1; i<=x2; i++ )
1381 save_buffer[ y1*COLS + i ] = ~save_buffer[ y1*COLS + i ];
1384 /*if( update )*/ rb->lcd_update();
1387 static void draw_hflip( int x1, int y1, int x2, int y2 )
1389 int i;
1390 if( x1 > x2 )
1392 i = x1;
1393 x1 = x2;
1394 x2 = i;
1396 if( y1 > y2 )
1398 i = y1;
1399 y1 = y2;
1400 y2 = i;
1403 copy_to_clipboard();
1405 for( i = 0; i <= y2 - y1; i++ )
1407 rb->memcpy( save_buffer+(y1+i)*COLS+x1,
1408 buffer.clipboard+(y2-i)*COLS+x1,
1409 (x2-x1+1)*sizeof( fb_data ) );
1411 restore_screen();
1412 rb->lcd_update();
1415 static void draw_vflip( int x1, int y1, int x2, int y2 )
1417 int i;
1418 if( x1 > x2 )
1420 i = x1;
1421 x1 = x2;
1422 x2 = i;
1424 if( y1 > y2 )
1426 i = y1;
1427 y1 = y2;
1428 y2 = i;
1431 copy_to_clipboard();
1433 for( ; y1 <= y2; y1++ )
1435 for( i = 0; i <= x2 - x1; i++ )
1437 save_buffer[y1*COLS+x1+i] = buffer.clipboard[y1*COLS+x2-i];
1440 restore_screen();
1441 rb->lcd_update();
1444 static void draw_paste_rectangle( int src_x1, int src_y1, int src_x2,
1445 int src_y2, int x1, int y1, int mode )
1447 int i;
1448 if( mode == SELECT_MENU_CUT )
1450 i = drawcolor;
1451 drawcolor = bgdrawcolor;
1452 draw_rect_full( src_x1, src_y1, src_x2, src_y2 );
1453 drawcolor = i;
1455 if( src_x1 > src_x2 )
1457 i = src_x1;
1458 src_x1 = src_x2;
1459 src_x2 = i;
1461 if( src_y1 > src_y2 )
1463 i = src_y1;
1464 src_y1 = src_y2;
1465 src_y2 = i;
1467 rb->lcd_bitmap_part( buffer.clipboard, src_x1, src_y1, COLS,
1468 x1, y1, src_x2-src_x1+1, src_y2-src_y1+1 );
1469 if( !preview )
1471 for( i = 0; i <= src_y2 - src_y1; i++ )
1473 rb->memcpy( save_buffer+(y1+i)*COLS+x1,
1474 buffer.clipboard+(src_y1+i)*COLS+src_x1,
1475 (src_x2 - src_x1 + 1)*sizeof( fb_data ) );
1480 static void show_grid( bool update )
1482 int i;
1483 if( gridsize > 0 )
1485 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1486 for( i = gridsize; i < COLS; i+= gridsize )
1488 rb->lcd_vline( i, 0, ROWS-1 );
1490 for( i = gridsize; i < ROWS; i+= gridsize )
1492 rb->lcd_hline( 0, COLS-1, i );
1494 rb->lcd_set_drawmode(DRMODE_SOLID);
1495 if( update ) rb->lcd_update();
1499 static void draw_text( int x, int y )
1501 buffer.text.text[0] = '\0';
1502 rb->snprintf( buffer.text.old_font, MAX_PATH,
1503 FONT_DIR "/%s.fnt",
1504 rb->global_settings->font_file );
1505 while( 1 )
1507 int m = TEXT_MENU_TEXT;
1508 switch( m = menu_display( text_menu, m ) )
1510 case TEXT_MENU_TEXT:
1511 rb->kbd_input( buffer.text.text, MAX_TEXT );
1512 restore_screen();
1513 break;
1515 case TEXT_MENU_FONT:
1516 if( browse_fonts( buffer.text.font, MAX_PATH ) )
1518 rb->font_load( buffer.text.font );
1520 break;
1522 case TEXT_MENU_PREVIEW:
1523 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1524 while( 1 )
1526 unsigned int button;
1527 restore_screen();
1528 rb->lcd_putsxy( x, y, buffer.text.text );
1529 rb->lcd_update();
1530 switch( button = rb->button_get( true ) )
1532 case ROCKPAINT_LEFT:
1533 case ROCKPAINT_LEFT | BUTTON_REPEAT:
1534 x-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1535 if (x<0) x=COLS-1;
1536 break;
1538 case ROCKPAINT_RIGHT:
1539 case ROCKPAINT_RIGHT | BUTTON_REPEAT:
1540 x+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1541 if (x>=COLS) x=0;
1542 break;
1544 case ROCKPAINT_UP:
1545 case ROCKPAINT_UP | BUTTON_REPEAT:
1546 y-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1547 if (y<0) y=ROWS-1;
1548 break;
1550 case ROCKPAINT_DOWN:
1551 case ROCKPAINT_DOWN | BUTTON_REPEAT:
1552 y+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1553 if (y>=ROWS-1) y=0;
1554 break;
1556 case ROCKPAINT_DRAW:
1557 button = 1242;
1558 break;
1560 if( button == 1242 ) break;
1562 break;
1564 case TEXT_MENU_APPLY:
1565 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1566 buffer_putsxyofs( save_buffer, COLS, ROWS, x, y, 0,
1567 buffer.text.text );
1568 case TEXT_MENU_CANCEL:
1569 restore_screen();
1570 rb->font_load( buffer.text.old_font );
1571 return;
1576 static void draw_brush( int x, int y )
1578 int i,j;
1579 for( i=-bsize/2+(bsize+1)%2; i<=bsize/2; i++ )
1581 for( j=-bsize/2+(bsize+1)%2; j<=bsize/2; j++ )
1583 draw_pixel( x+i, y+j );
1588 static void draw_line( int x1, int y1, int x2, int y2 )
1590 x1 = x1<<1;
1591 y1 = y1<<1;
1592 x2 = x2<<1;
1593 y2 = y2<<1;
1594 int w = x1 - x2;
1595 int h = y1 - y2;
1597 int x, y;
1599 if( w == 0 && h == 0 )
1601 draw_pixel( x1>>1, y1>>1 );
1602 return;
1605 if( w < 0 ) w *= -1;
1606 if( h < 0 ) h *= -1;
1608 if( w > h )
1610 if( x1 > x2 )
1612 x = x2;
1613 y = y2;
1614 x2 = x1;
1615 y2 = y1;
1616 x1 = x;
1617 y1 = y;
1619 w = x1 - x2;
1620 h = y1 - y2;
1621 while( x1 <= x2 )
1623 draw_pixel( (x1+1)>>1, (y1+1)>>1 );
1624 x1+=2;
1625 y1 = y2 - ( x2 - x1 ) * h / w;
1628 else /* h > w */
1630 if( y1 > y2 )
1632 x = x2;
1633 y = y2;
1634 x2 = x1;
1635 y2 = y1;
1636 x1 = x;
1637 y1 = y;
1639 w = x1 - x2;
1640 h = y1 - y2;
1641 while( y1 <= y2 )
1643 draw_pixel( (x1+1)>>1, (y1+1)>>1 );
1644 y1+=2;
1645 x1 = x2 - ( y2 - y1 ) * w / h;
1650 static void draw_curve( int x1, int y1, int x2, int y2,
1651 int xa, int ya, int xb, int yb )
1653 int i = 0;
1654 short xl1, yl1;
1655 short xl2, yl2;
1656 short xl3, yl3;
1657 short xl4, yl4;
1658 short xr1, yr1;
1659 short xr2, yr2;
1660 short xr3, yr3;
1661 short xr4, yr4;
1662 short depth;
1663 short xh, yh;
1665 if( x1 == x2 && y1 == y2 )
1667 draw_pixel( x1, y1 );
1668 return;
1671 // if( preview )
1673 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1674 if( xa == -1 || ya == -1 )
1676 rb->lcd_drawline( x1, y1, xb, yb );
1677 rb->lcd_drawline( x2, y2, xb, yb );
1679 else
1681 rb->lcd_drawline( x1, y1, xa, ya );
1682 rb->lcd_drawline( x2, y2, xb, yb );
1684 rb->lcd_set_drawmode(DRMODE_SOLID);
1687 if( xa == -1 || ya == -1 )
1688 /* We only have 3 of the points
1689 * This will currently only be used in preview mode */
1691 #define PUSH( a1, b1, a2, b2, a3, b3, d ) \
1692 buffer.bezier[i].x1 = a1; \
1693 buffer.bezier[i].y1 = b1; \
1694 buffer.bezier[i].x2 = a2; \
1695 buffer.bezier[i].y2 = b2; \
1696 buffer.bezier[i].x3 = a3; \
1697 buffer.bezier[i].y3 = b3; \
1698 buffer.bezier[i].depth = d; \
1699 i++;
1700 #define POP( a1, b1, a2, b2, a3, b3, d ) \
1701 i--; \
1702 a1 = buffer.bezier[i].x1; \
1703 b1 = buffer.bezier[i].y1; \
1704 a2 = buffer.bezier[i].x2; \
1705 b2 = buffer.bezier[i].y2; \
1706 a3 = buffer.bezier[i].x3; \
1707 b3 = buffer.bezier[i].y3; \
1708 d = buffer.bezier[i].depth;
1709 PUSH( x1<<4, y1<<4, xb<<4, yb<<4, x2<<4, y2<<4, 0 );
1710 while( i )
1712 /* de Casteljau's algorithm (see wikipedia) */
1713 POP( xl1, yl1, xb, yb, xr3, yr3, depth );
1714 if( depth < 10 ) /* check that the stack's 'i' doesn't overflow */
1716 xl2 = ( xl1 + xb )>>1;
1717 yl2 = ( yl1 + yb )>>1;
1718 xr2 = ( xb + xr3 )>>1;
1719 yr2 = ( yb + yr3 )>>1;
1720 xr1 = ( xl2 + xr2 )>>1;
1721 yr1 = ( yl2 + yr2 )>>1;
1722 xl3 = xr1;
1723 yl3 = yr1;
1724 PUSH( xl1, yl1, xl2, yl2, xl3, yl3, depth+1 );
1725 PUSH( xr1, yr1, xr2, yr2, xr3, yr3, depth+1 );
1727 else
1729 draw_line( ((xl1>>3)+1)>>1, ((yl1>>3)+1)>>1,
1730 ((xr3>>3)+1)>>1, ((yr3>>3)+1)>>1 );
1733 #undef PUSH
1734 #undef POP
1736 else /* We have the 4 points */
1738 #define PUSH( a1, b1, a2, b2, a3, b3, a4, b4, d ) \
1739 buffer.bezier[i].x1 = a1; \
1740 buffer.bezier[i].y1 = b1; \
1741 buffer.bezier[i].x2 = a2; \
1742 buffer.bezier[i].y2 = b2; \
1743 buffer.bezier[i].x3 = a3; \
1744 buffer.bezier[i].y3 = b3; \
1745 buffer.bezier[i].x4 = a4; \
1746 buffer.bezier[i].y4 = b4; \
1747 buffer.bezier[i].depth = d; \
1748 i++;
1749 #define POP( a1, b1, a2, b2, a3, b3, a4, b4, d ) \
1750 i--; \
1751 a1 = buffer.bezier[i].x1; \
1752 b1 = buffer.bezier[i].y1; \
1753 a2 = buffer.bezier[i].x2; \
1754 b2 = buffer.bezier[i].y2; \
1755 a3 = buffer.bezier[i].x3; \
1756 b3 = buffer.bezier[i].y3; \
1757 a4 = buffer.bezier[i].x4; \
1758 b4 = buffer.bezier[i].y4; \
1759 d = buffer.bezier[i].depth;
1761 PUSH( x1<<4, y1<<4, xa<<4, ya<<4, xb<<4, yb<<4, x2<<4, y2<<4, 0 );
1762 while( i )
1764 /* de Casteljau's algorithm (see wikipedia) */
1765 POP( xl1, yl1, xa, ya, xb, yb, xr4, yr4, depth );
1766 if( depth < 10 ) /* check that the stack's 'i' doesn't overflow */
1768 xl2 = ( xl1 + xa )>>1;
1769 yl2 = ( yl1 + ya )>>1;
1770 xh = ( xa + xb )>>1;
1771 yh = ( ya + yb )>>1;
1772 xr3 = ( xb + xr4 )>>1;
1773 yr3 = ( yb + yr4 )>>1;
1774 xl3 = ( xl2 + xh )>>1;
1775 yl3 = ( yl2 + yh )>>1;
1776 xr2 = ( xr3 + xh )>>1;
1777 yr2 = ( yr3 + yh )>>1;
1778 xl4 = ( xl3 + xr2 )>>1;
1779 yl4 = ( yl3 + yr2 )>>1;
1780 xr1 = xl4;
1781 yr1 = yl4;
1782 PUSH( xl1, yl1, xl2, yl2, xl3, yl3, xl4, yl4, depth+1 );
1783 PUSH( xr1, yr1, xr2, yr2, xr3, yr3, xr4, yr4, depth+1 );
1785 else
1787 draw_line( ((xl1>>3)+1)>>1, ((yl1>>3)+1)>>1,
1788 ((xr4>>3)+1)>>1, ((yr4>>3)+1)>>1 );
1791 #undef PUSH
1792 #undef POP
1796 static void draw_rect( int x1, int y1, int x2, int y2 )
1798 draw_line( x1, y1, x1, y2 );
1799 draw_line( x1, y1, x2, y1 );
1800 draw_line( x1, y2, x2, y2 );
1801 draw_line( x2, y1, x2, y2 );
1804 static void togglebg( void )
1806 if( isbg )
1808 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1810 else
1812 rb->lcd_set_foreground( rp_colors[ bgdrawcolor ] );
1814 isbg = !isbg;
1817 static void draw_rect_full( int x1, int y1, int x2, int y2 )
1819 /* GRUIK */
1820 int x = x1;
1821 togglebg();
1822 if( x < x2 )
1824 do {
1825 draw_line( x, y1, x, y2 );
1826 } while( ++x <= x2 );
1828 else
1830 do {
1831 draw_line( x, y1, x, y2 );
1832 } while( --x >= x2 );
1834 togglebg();
1835 draw_rect( x1, y1, x2, y2 );
1838 static void draw_oval( int x1, int y1, int x2, int y2, bool full )
1840 /* TODO: simplify :) */
1841 int cx = (x1+x2)>>1;
1842 int cy = (y1+y2)>>1;
1844 int rx = (x1-x2)>>1;
1845 int ry = (y1-y2)>>1;
1846 if( rx < 0 ) rx *= -1;
1847 if( ry < 0 ) ry *= -1;
1849 if( rx == 0 || ry == 0 )
1851 draw_line( x1, y1, x2, y2 );
1852 return;
1855 int x,y;
1856 int dst, old_dst;
1858 for( x = 0; x < rx; x++ )
1860 y = 0;
1861 dst = -0xfff;
1862 do {
1863 old_dst = dst;
1864 dst = ry * ry * x * x + rx * rx * y * y - rx * rx * ry * ry;
1865 y++;
1866 } while( dst < 0 );
1867 if( -old_dst < dst ) y--;
1868 if( full )
1870 draw_line( cx+x, cy, cx+x, cy+y );
1871 draw_line( cx+x, cy, cx+x, cy-y );
1872 draw_line( cx-x, cy, cx-x, cy+y );
1873 draw_line( cx-x, cy, cx-x, cy-y );
1875 else
1877 draw_pixel( cx+x, cy+y );
1878 draw_pixel( cx+x, cy-y );
1879 draw_pixel( cx-x, cy+y );
1880 draw_pixel( cx-x, cy-y );
1883 for( y = 0; y < ry; y++ )
1885 x = 0;
1886 dst = -0xfff;
1887 do {
1888 old_dst = dst;
1889 dst = ry * ry * x * x + rx * rx * y * y - rx * rx * ry * ry;
1890 x++;
1891 } while( dst < 0 );
1892 if( -old_dst < dst ) x--;
1893 if( full )
1895 draw_line( cx+x, cy, cx+x, cy+y );
1896 draw_line( cx+x, cy, cx+x, cy-y );
1897 draw_line( cx-x, cy, cx-x, cy+y );
1898 draw_line( cx-x, cy, cx-x, cy-y );
1900 else
1902 draw_pixel( cx+x, cy+y );
1903 draw_pixel( cx+x, cy-y );
1904 draw_pixel( cx-x, cy+y );
1905 draw_pixel( cx-x, cy-y );
1910 static void draw_oval_empty( int x1, int y1, int x2, int y2 )
1912 draw_oval( x1, y1, x2, y2, false );
1915 static void draw_oval_full( int x1, int y1, int x2, int y2 )
1917 togglebg();
1918 draw_oval( x1, y1, x2, y2, true );
1919 togglebg();
1920 draw_oval( x1, y1, x2, y2, false );
1923 static void draw_fill( int x0, int y0 )
1925 #define PUSH( a, b ) \
1926 draw_pixel( (int)a, (int)b ); \
1927 buffer.coord[i].x = a; \
1928 buffer.coord[i].y = b; \
1929 i++;
1930 #define POP( a, b ) \
1931 i--; \
1932 a = buffer.coord[i].x; \
1933 b = buffer.coord[i].y;
1935 unsigned int i=0;
1936 short x = x0;
1937 short y = y0;
1938 unsigned int prev_color = save_buffer[ x0+y0*COLS ];
1940 if( prev_color == rp_colors[ drawcolor ] ) return;
1942 PUSH( x, y );
1944 while( i != 0 )
1946 POP( x, y );
1947 if( x > 0 && save_buffer[x-1+y*COLS] == prev_color )
1949 PUSH( x-1, y );
1951 if( x < COLS-1 && save_buffer[x+1+y*COLS] == prev_color )
1953 PUSH( x+1, y );
1955 if( y > 0 && save_buffer[x+(y-1)*COLS] == prev_color )
1957 PUSH( x, y-1 );
1959 if( y < ROWS - 1 && save_buffer[x+(y+1)*COLS] == prev_color )
1961 PUSH( x, y+1 );
1964 #undef PUSH
1965 #undef POP
1969 /* For preview purposes only */
1970 static void line_gradient( int x1, int y1, int x2, int y2 )
1972 int r1, g1, b1;
1973 int r2, g2, b2;
1974 int h1, s1, v1, h2, s2, v2, r, g, b;
1975 int w, h, x, y;
1977 bool a = false;
1979 x1 <<= 1;
1980 y1 <<= 1;
1981 x2 <<= 1;
1982 y2 <<= 1;
1984 w = x1 - x2;
1985 h = y1 - y2;
1987 if( w == 0 && h == 0 )
1989 draw_pixel( x1>>1, y1>>1 );
1990 return;
1993 r1 = RGB_UNPACK_RED( rp_colors[ bgdrawcolor ] );
1994 g1 = RGB_UNPACK_GREEN( rp_colors[ bgdrawcolor ] );
1995 b1 = RGB_UNPACK_BLUE( rp_colors[ bgdrawcolor ] );
1996 r2 = RGB_UNPACK_RED( rp_colors[ drawcolor ] );
1997 g2 = RGB_UNPACK_GREEN( rp_colors[ drawcolor ] );
1998 b2 = RGB_UNPACK_BLUE( rp_colors[ drawcolor ] );
2000 if( w < 0 )
2002 w *= -1;
2003 a = true;
2005 if( h < 0 )
2007 h *= -1;
2008 a = !a;
2010 if( a )
2012 r = r1;
2013 r1 = r2;
2014 r2 = r;
2015 g = g1;
2016 g1 = g2;
2017 g2 = g;
2018 b = b1;
2019 b1 = b2;
2020 b2 = b;
2023 rgb2hsv( r1, g1, b1, &h1, &s1, &v1 );
2024 rgb2hsv( r2, g2, b2, &h2, &s2, &v2 );
2026 if( w > h )
2028 if( x1 > x2 )
2030 x = x2;
2031 y = y2;
2032 x2 = x1;
2033 y2 = y1;
2034 x1 = x;
2035 y1 = y;
2037 w = x1 - x2;
2038 h = y1 - y2;
2039 while( x1 <= x2 )
2041 hsv2rgb( h1+((h2-h1)*(x1-x2))/w,
2042 s1+((s2-s1)*(x1-x2))/w,
2043 v1+((v2-v1)*(x1-x2))/w,
2044 &r, &g, &b );
2045 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2046 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2047 draw_pixel( (x1+1)>>1, (y1+1)>>1 );
2048 x1+=2;
2049 y1 = y2 - ( x2 - x1 ) * h / w;
2052 else /* h > w */
2054 if( y1 > y2 )
2056 x = x2;
2057 y = y2;
2058 x2 = x1;
2059 y2 = y1;
2060 x1 = x;
2061 y1 = y;
2063 w = x1 - x2;
2064 h = y1 - y2;
2065 while( y1 <= y2 )
2067 hsv2rgb( h1+((h2-h1)*(y1-y2))/h,
2068 s1+((s2-s1)*(y1-y2))/h,
2069 v1+((v2-v1)*(y1-y2))/h,
2070 &r, &g, &b );
2071 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2072 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2073 draw_pixel( (x1+1)>>1, (y1+1)>>1 );
2074 y1+=2;
2075 x1 = x2 - ( y2 - y1 ) * w / h;
2078 if( a )
2080 rp_colors[ drawcolor ] = LCD_RGBPACK( r1, g1, b1 );
2082 else
2084 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2088 static void linear_gradient( int x1, int y1, int x2, int y2 )
2090 int r1 = RGB_UNPACK_RED( rp_colors[ bgdrawcolor ] );
2091 int g1 = RGB_UNPACK_GREEN( rp_colors[ bgdrawcolor ] );
2092 int b1 = RGB_UNPACK_BLUE( rp_colors[ bgdrawcolor ] );
2093 int r2 = RGB_UNPACK_RED( rp_colors[ drawcolor ] );
2094 int g2 = RGB_UNPACK_GREEN( rp_colors[ drawcolor ] );
2095 int b2 = RGB_UNPACK_BLUE( rp_colors[ drawcolor ] );
2097 int h1, s1, v1, h2, s2, v2, r, g, b;
2099 /* radius^2 */
2100 int radius2 = ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 );
2101 int dist2, i=0;
2103 /* We only propagate the gradient to neighboring pixels with the same
2104 * color as ( x1, y1 ) */
2105 unsigned int prev_color = save_buffer[ x1+y1*COLS ];
2107 int x = x1;
2108 int y = y1;
2110 if( radius2 == 0 ) return;
2111 if( preview )
2113 line_gradient( x1, y1, x2, y2 );
2116 rgb2hsv( r1, g1, b1, &h1, &s1, &v1 );
2117 rgb2hsv( r2, g2, b2, &h2, &s2, &v2 );
2119 #define PUSH( x0, y0 ) \
2120 buffer.coord[i].x = (short)(x0); \
2121 buffer.coord[i].y = (short)(y0); \
2122 i++;
2123 #define POP( a, b ) \
2124 i--; \
2125 a = (int)buffer.coord[i].x; \
2126 b = (int)buffer.coord[i].y;
2128 PUSH( x, y );
2130 while( i != 0 )
2132 POP( x, y );
2134 dist2 = ( x2 - x1 ) * ( x - x1 ) + ( y2 - y1 ) * ( y - y1 );
2135 if( dist2 <= 0 )
2137 rp_colors[ drawcolor ] = rp_colors[ bgdrawcolor ];
2139 else if( dist2 < radius2 )
2141 hsv2rgb( h1+((h2-h1)*dist2)/radius2,
2142 s1+((s2-s1)*dist2)/radius2,
2143 v1+((v2-v1)*dist2)/radius2,
2144 &r, &g, &b );
2145 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2147 else
2149 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2151 if( rp_colors[ drawcolor ] == prev_color )
2153 if( rp_colors[ drawcolor ])
2154 rp_colors[ drawcolor ]--; /* GRUIK */
2155 else
2156 rp_colors[ drawcolor ]++; /* GRUIK */
2158 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2159 draw_pixel( x, y );
2161 if( x > 0 && save_buffer[x-1+y*COLS] == prev_color )
2163 PUSH( x-1, y );
2165 if( x < COLS-1 && save_buffer[x+1+y*COLS] == prev_color )
2167 PUSH( x+1, y );
2169 if( y > 0 && save_buffer[x+(y-1)*COLS] == prev_color )
2171 PUSH( x, y-1 );
2173 if( y < ROWS - 1 && save_buffer[x+(y+1)*COLS] == prev_color )
2175 PUSH( x, y+1 );
2178 #undef PUSH
2179 #undef POP
2181 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2184 static void radial_gradient( int x1, int y1, int x2, int y2 )
2186 int r1 = RGB_UNPACK_RED( rp_colors[ bgdrawcolor ] );
2187 int g1 = RGB_UNPACK_GREEN( rp_colors[ bgdrawcolor ] );
2188 int b1 = RGB_UNPACK_BLUE( rp_colors[ bgdrawcolor ] );
2189 int r2 = RGB_UNPACK_RED( rp_colors[ drawcolor ] );
2190 int g2 = RGB_UNPACK_GREEN( rp_colors[ drawcolor ] );
2191 int b2 = RGB_UNPACK_BLUE( rp_colors[ drawcolor ] );
2193 int h1, s1, v1, h2, s2, v2, r, g, b;
2195 /* radius^2 */
2196 int radius2 = ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 );
2197 int dist2, i=0;
2199 /* We only propagate the gradient to neighboring pixels with the same
2200 * color as ( x1, y1 ) */
2201 unsigned int prev_color = save_buffer[ x1+y1*COLS ];
2203 int x = x1;
2204 int y = y1;
2206 if( radius2 == 0 ) return;
2207 if( preview )
2209 line_gradient( x1, y1, x2, y2 );
2212 rgb2hsv( r1, g1, b1, &h1, &s1, &v1 );
2213 rgb2hsv( r2, g2, b2, &h2, &s2, &v2 );
2215 #define PUSH( x0, y0 ) \
2216 buffer.coord[i].x = (short)(x0); \
2217 buffer.coord[i].y = (short)(y0); \
2218 i++;
2219 #define POP( a, b ) \
2220 i--; \
2221 a = (int)buffer.coord[i].x; \
2222 b = (int)buffer.coord[i].y;
2224 PUSH( x, y );
2226 while( i != 0 )
2228 POP( x, y );
2230 if( ( dist2 = (x1-(x))*(x1-(x))+(y1-(y))*(y1-(y)) ) < radius2 )
2232 hsv2rgb( h1+((h2-h1)*dist2)/radius2,
2233 s1+((s2-s1)*dist2)/radius2,
2234 v1+((v2-v1)*dist2)/radius2,
2235 &r, &g, &b );
2236 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2238 else
2240 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2242 if( rp_colors[ drawcolor ] == prev_color )
2244 if( rp_colors[ drawcolor ])
2245 rp_colors[ drawcolor ]--; /* GRUIK */
2246 else
2247 rp_colors[ drawcolor ]++; /* GRUIK */
2249 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2250 draw_pixel( x, y );
2252 if( x > 0 && save_buffer[x-1+y*COLS] == prev_color )
2254 PUSH( x-1, y );
2256 if( x < COLS-1 && save_buffer[x+1+y*COLS] == prev_color )
2258 PUSH( x+1, y );
2260 if( y > 0 && save_buffer[x+(y-1)*COLS] == prev_color )
2262 PUSH( x, y-1 );
2264 if( y < ROWS - 1 && save_buffer[x+(y+1)*COLS] == prev_color )
2266 PUSH( x, y+1 );
2269 #undef PUSH
2270 #undef POP
2272 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2275 static void draw_toolbars(bool update)
2277 int i;
2278 #define TOP (LCD_HEIGHT-TB_HEIGHT)
2279 rb->lcd_set_background( COLOR_LIGHTGRAY );
2280 rb->lcd_set_foreground( COLOR_LIGHTGRAY );
2281 rb->lcd_fillrect( 0, TOP, LCD_WIDTH, TB_HEIGHT );
2282 rb->lcd_set_foreground( COLOR_BLACK );
2283 rb->lcd_drawrect( 0, TOP, LCD_WIDTH, TB_HEIGHT );
2285 rb->lcd_set_foreground( rp_colors[ bgdrawcolor ] );
2286 rb->lcd_fillrect( TB_SC_BG_LEFT, TOP+TB_SC_BG_TOP,
2287 TB_SC_SIZE, TB_SC_SIZE );
2288 rb->lcd_set_foreground(ROCKPAINT_PALETTE);
2289 rb->lcd_drawrect( TB_SC_BG_LEFT, TOP+TB_SC_BG_TOP,
2290 TB_SC_SIZE, TB_SC_SIZE );
2291 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2292 rb->lcd_fillrect( TB_SC_FG_LEFT, TOP+TB_SC_FG_TOP,
2293 TB_SC_SIZE, TB_SC_SIZE );
2294 rb->lcd_set_foreground(ROCKPAINT_PALETTE);
2295 rb->lcd_drawrect( TB_SC_FG_LEFT, TOP+TB_SC_FG_TOP,
2296 TB_SC_SIZE, TB_SC_SIZE );
2298 for( i=0; i<18; i++ )
2300 rb->lcd_set_foreground( rp_colors[i] );
2301 rb->lcd_fillrect(
2302 TB_PL_LEFT+(i%9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING ),
2303 TOP+TB_PL_TOP+(i/9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING),
2304 TB_PL_COLOR_SIZE, TB_PL_COLOR_SIZE );
2305 rb->lcd_set_foreground( ROCKPAINT_PALETTE );
2306 rb->lcd_drawrect(
2307 TB_PL_LEFT+(i%9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING ),
2308 TOP+TB_PL_TOP+(i/9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING),
2309 TB_PL_COLOR_SIZE, TB_PL_COLOR_SIZE );
2312 #define SEPARATOR( x, y ) \
2313 rb->lcd_set_foreground( COLOR_WHITE ); \
2314 rb->lcd_vline( x, TOP+y, TOP+y+TB_PL_HEIGHT-1 ); \
2315 rb->lcd_set_foreground( COLOR_DARKGRAY ); \
2316 rb->lcd_vline( x+1, TOP+y, TOP+y+TB_PL_HEIGHT-1 );
2317 SEPARATOR( TB_PL_LEFT + TB_PL_WIDTH - 1 + TB_SP_MARGIN, TB_PL_TOP );
2319 rb->lcd_bitmap_transparent( rockpaint, TB_TL_LEFT, TOP+TB_TL_TOP,
2320 TB_TL_WIDTH, TB_TL_HEIGHT );
2321 rb->lcd_set_foreground(ROCKPAINT_PALETTE);
2322 rb->lcd_drawrect( TB_TL_LEFT+(TB_TL_SIZE+TB_TL_SPACING)*(tool/2),
2323 TOP+TB_TL_TOP+(TB_TL_SIZE+TB_TL_SPACING)*(tool%2),
2324 TB_TL_SIZE, TB_TL_SIZE );
2326 SEPARATOR( TB_TL_LEFT + TB_TL_WIDTH - 1 + TB_SP_MARGIN, TB_TL_TOP );
2328 rb->lcd_setfont( FONT_SYSFIXED );
2329 rb->lcd_putsxy( TB_MENU_LEFT, TOP+TB_MENU_TOP, "Menu" );
2330 rb->lcd_setfont( FONT_UI );
2331 #undef TOP
2333 if( update ) rb->lcd_update();
2336 static void toolbar( void )
2338 int button, i, j;
2339 restore_screen();
2340 draw_toolbars( false );
2341 y = LCD_HEIGHT-TB_HEIGHT/2;
2342 inv_cursor( true );
2343 while( 1 )
2345 switch( button = rb->button_get( true ) )
2347 case ROCKPAINT_DRAW:
2348 #define TOP ( LCD_HEIGHT - TB_HEIGHT )
2349 if( y >= TOP + TB_SC_FG_TOP
2350 && y < TOP + TB_SC_FG_TOP + TB_SC_SIZE
2351 && x >= TB_SC_FG_LEFT
2352 && x < TB_SC_FG_LEFT + TB_SC_SIZE )
2354 /* click on the foreground color */
2355 rp_colors[drawcolor] = color_chooser( rp_colors[drawcolor] );
2357 else if( y >= TOP + TB_SC_BG_TOP
2358 && y < TOP + TB_SC_BG_TOP + TB_SC_SIZE
2359 && x >= TB_SC_BG_LEFT
2360 && x < TB_SC_BG_LEFT + TB_SC_SIZE )
2362 /* click on the background color */
2363 i = drawcolor;
2364 drawcolor = bgdrawcolor;
2365 bgdrawcolor = i;
2367 else if( y >= TOP + TB_PL_TOP
2368 && y < TOP + TB_PL_TOP + TB_PL_HEIGHT
2369 && x >= TB_PL_LEFT
2370 && x < TB_PL_LEFT + TB_PL_WIDTH )
2372 /* click on the palette */
2373 i = (x - TB_PL_LEFT)%(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2374 j = (y - (TOP+TB_PL_TOP) )%(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2375 if( i >= TB_PL_COLOR_SIZE || j >= TB_PL_COLOR_SIZE )
2376 break;
2377 i = ( x - TB_PL_LEFT )/(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2378 j = ( y - (TOP+TB_PL_TOP) )/(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2379 drawcolor = j*(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING)+i;
2381 else if( y >= TOP+TB_TL_TOP
2382 && y < TOP + TB_TL_TOP + TB_TL_HEIGHT
2383 && x >= TB_TL_LEFT
2384 && x <= TB_TL_LEFT + TB_TL_WIDTH )
2386 /* click on the tools */
2387 i = (x - TB_TL_LEFT ) % (TB_TL_SIZE+TB_TL_SPACING);
2388 j = (y - (TOP+TB_TL_TOP) ) %(TB_TL_SIZE+TB_TL_SPACING);
2389 if( i >= TB_TL_SIZE || j >= TB_TL_SIZE ) break;
2390 i = ( x - TB_TL_LEFT )/(TB_TL_SIZE+TB_TL_SPACING);
2391 j = ( y - (TOP+TB_TL_TOP) )/(TB_TL_SIZE+TB_TL_SPACING);
2392 tool = i*2+j;
2393 prev_x = -1;
2394 prev_y = -1;
2395 prev_x2 = -1;
2396 prev_y2 = -1;
2397 prev_x3 = -1;
2398 prev_y3 = -1;
2399 preview = false;
2401 else if( x >= TB_MENU_LEFT && y >= TOP+TB_MENU_TOP-2)
2403 /* menu button */
2404 goto_menu();
2406 #undef TOP
2407 restore_screen();
2408 draw_toolbars( false );
2409 inv_cursor( true );
2410 break;
2412 case ROCKPAINT_LEFT:
2413 case ROCKPAINT_LEFT | BUTTON_REPEAT:
2414 inv_cursor(false);
2415 x-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2416 if (x<0) x=COLS-1;
2417 inv_cursor(true);
2418 break;
2420 case ROCKPAINT_RIGHT:
2421 case ROCKPAINT_RIGHT | BUTTON_REPEAT:
2422 inv_cursor(false);
2423 x+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2424 if (x>=COLS) x=0;
2425 inv_cursor(true);
2426 break;
2428 case ROCKPAINT_UP:
2429 case ROCKPAINT_UP | BUTTON_REPEAT:
2430 inv_cursor(false);
2431 y-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2432 if (y<LCD_HEIGHT-TB_HEIGHT)
2434 return;
2436 inv_cursor(true);
2437 break;
2439 case ROCKPAINT_DOWN:
2440 case ROCKPAINT_DOWN | BUTTON_REPEAT:
2441 inv_cursor(false);
2442 y+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2443 if (y>=LCD_HEIGHT)
2445 y = 0;
2446 return;
2448 inv_cursor(true);
2449 break;
2451 case ROCKPAINT_TOOLBAR:
2452 case ROCKPAINT_TOOLBAR2:
2453 return;
2455 if( quit ) return;
2459 static void inv_cursor(bool update)
2461 rb->lcd_set_foreground(COLOR_BLACK);
2462 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
2463 /* cross painting */
2464 rb->lcd_drawline(x-4,y,x-1,y);
2465 rb->lcd_drawline(x+1,y,x+4,y);
2466 rb->lcd_drawline(x,y-4,x,y-1);
2467 rb->lcd_drawline(x,y+1,x,y+4);
2468 rb->lcd_set_foreground(rp_colors[drawcolor]);
2469 rb->lcd_set_drawmode(DRMODE_SOLID);
2471 if( update ) rb->lcd_update();
2474 static void restore_screen(void)
2476 rb->lcd_bitmap( save_buffer, 0, 0, COLS, ROWS );
2479 static void clear_drawing(void)
2481 init_buffer();
2482 rb->lcd_set_foreground( rp_colors[ bgdrawcolor ] );
2483 rb->lcd_fillrect( 0, 0, COLS, ROWS );
2484 rb->lcd_update();
2487 static void goto_menu(void)
2489 int multi;
2491 while( 1 )
2493 switch( menu_display( main_menu, 1 ) )
2495 case MAIN_MENU_NEW:
2496 clear_drawing();
2497 return;
2499 case MAIN_MENU_LOAD:
2500 if( browse( filename, MAX_PATH, "/" ) )
2502 if( load_bitmap( filename ) <= 0 )
2504 rb->splash( 1*HZ, "Error while loading %s",
2505 filename );
2507 else
2509 rb->splash( 1*HZ, "Image loaded (%s)", filename );
2510 restore_screen();
2511 inv_cursor(true);
2512 return;
2515 break;
2517 case MAIN_MENU_SAVE:
2518 if (!filename[0])
2519 rb->strcpy(filename,"/");
2520 if( !rb->kbd_input( filename, MAX_PATH ) )
2522 if(rb->strlen(filename) <= 4 ||
2523 rb->strcasecmp(&filename[rb->strlen(filename)-4], ".bmp"))
2524 rb->strcat(filename, ".bmp");
2525 save_bitmap( filename );
2526 rb->splash( 1*HZ, "File saved (%s)", filename );
2528 break;
2530 case MAIN_MENU_BRUSH_SIZE:
2531 multi = menu_display( size_menu, bsize );
2532 if( multi != - 1 )
2533 bsize = multi;
2534 break;
2536 case MAIN_MENU_BRUSH_SPEED:
2537 multi = menu_display( speed_menu, bspeed );
2538 if( multi != -1 )
2539 bspeed = multi;
2540 break;
2542 case MAIN_MENU_COLOR:
2543 rp_colors[drawcolor] = color_chooser( rp_colors[drawcolor] );
2544 break;
2546 case MAIN_MENU_GRID_SIZE:
2547 multi = menu_display( gridsize_menu, gridsize );
2548 if( multi != - 1 )
2549 gridsize = multi;
2550 break;
2552 case MAIN_MENU_EXIT:
2553 quit=true;
2554 return;
2556 case MAIN_MENU_RESUME:
2557 case MENU_ESC:
2558 return;
2559 }/* end switch */
2560 }/* end while */
2563 static void reset_tool( void )
2565 prev_x = -1;
2566 prev_y = -1;
2567 prev_x2 = -1;
2568 prev_y2 = -1;
2569 prev_x3 = -1;
2570 prev_y3 = -1;
2571 tool_mode = -1;
2572 preview = false;
2575 static bool rockpaint_loop( void )
2577 int button=0,i,j;
2578 int accelaration;
2580 while (!quit) {
2581 button = rb->button_get(true);
2583 if( tool == Brush && prev_x != -1 )
2585 accelaration = 1;
2587 else if( button & BUTTON_REPEAT )
2589 accelaration = 4;
2591 else
2593 accelaration = 1;
2596 switch(button)
2598 case ROCKPAINT_QUIT:
2599 rb->lcd_set_drawmode(DRMODE_SOLID);
2600 return PLUGIN_OK;
2602 case ROCKPAINT_MENU:
2603 inv_cursor(false);
2604 goto_menu();
2605 inv_cursor(true);
2606 break;
2608 case ROCKPAINT_DRAW:
2609 inv_cursor(false);
2610 switch( tool )
2612 case Brush:
2613 if( prev_x == -1 ) prev_x = 1;
2614 else prev_x = -1;
2615 break;
2617 case SelectRectangle:
2618 case Line:
2619 case Curve:
2620 case Rectangle:
2621 case RectangleFull:
2622 case Oval:
2623 case OvalFull:
2624 case LinearGradient:
2625 case RadialGradient:
2626 /* Curve uses 4 points, others use 2 */
2627 if( prev_x == -1 || prev_y == -1 )
2629 prev_x = x;
2630 prev_y = y;
2631 preview = true;
2633 else if( tool == Curve
2634 && ( prev_x2 == -1 || prev_y2 == -1 ) )
2636 prev_x2 = x;
2637 prev_y2 = y;
2639 else if( tool == SelectRectangle
2640 && ( prev_x2 == -1 || prev_y2 == -1 ) )
2642 tool_mode = menu_display( select_menu,
2643 SELECT_MENU_CUT );
2644 switch( tool_mode )
2646 case SELECT_MENU_CUT:
2647 case SELECT_MENU_COPY:
2648 prev_x2 = x;
2649 prev_y2 = y;
2650 copy_to_clipboard();
2651 if( prev_x < x ) x = prev_x;
2652 if( prev_y < y ) y = prev_y;
2653 break;
2655 case SELECT_MENU_INVERT:
2656 draw_invert( prev_x, prev_y, x, y );
2657 reset_tool();
2658 break;
2660 case SELECT_MENU_HFLIP:
2661 draw_hflip( prev_x, prev_y, x, y );
2662 reset_tool();
2663 break;
2665 case SELECT_MENU_VFLIP:
2666 draw_vflip( prev_x, prev_y, x, y );
2667 reset_tool();
2668 break;
2670 case SELECT_MENU_ROTATE90:
2671 break;
2672 case SELECT_MENU_ROTATE180:
2673 draw_hflip( prev_x, prev_y, x, y );
2674 draw_vflip( prev_x, prev_y, x, y );
2675 reset_tool();
2676 break;
2677 case SELECT_MENU_ROTATE270:
2678 break;
2680 case SELECT_MENU_CANCEL:
2681 reset_tool();
2682 break;
2684 case MENU_ESC:
2685 break;
2688 else if( tool == Curve
2689 && ( prev_x3 == -1 || prev_y3 == -1 ) )
2691 prev_x3 = x;
2692 prev_y3 = y;
2694 else
2696 preview = false;
2697 switch( tool )
2699 case SelectRectangle:
2700 draw_paste_rectangle( prev_x, prev_y,
2701 prev_x2, prev_y2,
2702 x, y, tool_mode );
2703 break;
2704 case Line:
2705 draw_line( prev_x, prev_y, x, y );
2706 break;
2707 case Curve:
2708 draw_curve( prev_x, prev_y,
2709 prev_x2, prev_y2,
2710 prev_x3, prev_y3,
2711 x, y );
2712 break;
2713 case Rectangle:
2714 draw_rect( prev_x, prev_y, x, y );
2715 break;
2716 case RectangleFull:
2717 draw_rect_full( prev_x, prev_y, x, y );
2718 break;
2719 case Oval:
2720 draw_oval_empty( prev_x, prev_y, x, y );
2721 break;
2722 case OvalFull:
2723 draw_oval_full( prev_x, prev_y, x, y );
2724 break;
2725 case LinearGradient:
2726 linear_gradient( prev_x, prev_y, x, y );
2727 break;
2728 case RadialGradient:
2729 radial_gradient( prev_x, prev_y, x, y );
2730 break;
2731 default:
2732 break;
2734 reset_tool();
2736 break;
2738 case Fill:
2739 draw_fill( x, y );
2740 break;
2742 case ColorPicker:
2743 color_picker( x, y );
2744 break;
2746 case Text:
2747 draw_text( x, y );
2748 break;
2750 default:
2751 break;
2753 inv_cursor(true);
2754 break;
2756 case ROCKPAINT_DRAW|BUTTON_REPEAT:
2757 if( tool == Curve )
2759 /* 3 point bezier curve */
2760 preview = false;
2761 draw_curve( prev_x, prev_y,
2762 prev_x2, prev_y2,
2763 -1, -1,
2764 x, y );
2765 reset_tool();
2766 restore_screen();
2767 inv_cursor( true );
2769 break;
2771 case ROCKPAINT_TOOLBAR:
2772 i = x; j = y;
2773 x = 10;
2774 toolbar();
2775 x = i; y = j;
2776 restore_screen();
2777 inv_cursor(true);
2778 break;
2780 case ROCKPAINT_TOOLBAR2:
2781 i = x; j = y;
2782 x = 110;
2783 toolbar();
2784 x = i; y = j;
2785 restore_screen();
2786 inv_cursor(true);
2787 break;
2789 case ROCKPAINT_LEFT:
2790 case ROCKPAINT_LEFT | BUTTON_REPEAT:
2791 inv_cursor(false);
2792 x-=bspeed * accelaration;
2793 if (x<0) x=COLS-1;
2794 inv_cursor(true);
2795 break;
2797 case ROCKPAINT_RIGHT:
2798 case ROCKPAINT_RIGHT | BUTTON_REPEAT:
2799 inv_cursor(false);
2800 x+=bspeed * accelaration;
2801 if (x>=COLS) x=0;
2802 inv_cursor(true);
2803 break;
2805 case ROCKPAINT_UP:
2806 case ROCKPAINT_UP | BUTTON_REPEAT:
2807 inv_cursor(false);
2808 y-=bspeed * accelaration;
2809 if (y<0) y=ROWS-1;
2810 inv_cursor(true);
2811 break;
2813 case ROCKPAINT_DOWN:
2814 case ROCKPAINT_DOWN | BUTTON_REPEAT:
2815 inv_cursor(false);
2816 y+=bspeed * accelaration;
2817 if (y>=ROWS)
2819 toolbar();
2820 restore_screen();
2822 inv_cursor(true);
2823 break;
2825 default:
2826 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
2827 return PLUGIN_USB_CONNECTED;
2828 break;
2830 if( tool == Brush && prev_x == 1 )
2832 inv_cursor(false);
2833 draw_brush( x, y );
2834 inv_cursor(true);
2836 if( preview || tool == ColorPicker )
2837 /* always preview color picker */
2839 restore_screen();
2840 switch( tool )
2842 case SelectRectangle:
2843 if( prev_x2 == -1 || prev_y2 == -1 )
2845 /* we are defining the selection */
2846 draw_select_rectangle( prev_x, prev_y, x, y );
2848 else
2850 /* we are pasting the selected data */
2851 draw_paste_rectangle( prev_x, prev_y, prev_x2,
2852 prev_y2, x, y, tool_mode );
2853 prev_x3 = prev_x2-prev_x;
2854 if( prev_x3 < 0 ) prev_x3 *= -1;
2855 prev_y3 = prev_y2-prev_y;
2856 if( prev_y3 < 0 ) prev_y3 *= -1;
2857 draw_select_rectangle( x, y, x+prev_x3, y+prev_y3 );
2858 prev_x3 = -1;
2859 prev_y3 = -1;
2861 break;
2863 case Brush:
2864 break;
2866 case Line:
2867 draw_line( prev_x, prev_y, x, y );
2868 break;
2870 case Curve:
2871 if( prev_x2 == -1 || prev_y2 == -1 )
2873 draw_line( prev_x, prev_y, x, y );
2875 else
2877 draw_curve( prev_x, prev_y,
2878 prev_x2, prev_y2,
2879 prev_x3, prev_y3,
2880 x, y );
2882 break;
2884 case Rectangle:
2885 draw_rect( prev_x, prev_y, x, y );
2886 break;
2888 case RectangleFull:
2889 draw_rect_full( prev_x, prev_y, x, y );
2890 break;
2892 case Oval:
2893 draw_oval_empty( prev_x, prev_y, x, y );
2894 break;
2896 case OvalFull:
2897 draw_oval_full( prev_x, prev_y, x, y );
2898 break;
2900 case Fill:
2901 break;
2903 case ColorPicker:
2904 preview = true;
2905 color_picker( x, y );
2906 preview = false;
2907 break;
2909 case LinearGradient:
2910 line_gradient( prev_x, prev_y, x, y );
2911 break;
2913 case RadialGradient:
2914 line_gradient( prev_x, prev_y, x, y );
2915 break;
2917 case Text:
2918 default:
2919 break;
2921 inv_cursor( true );
2923 if( gridsize > 0 )
2925 show_grid( true );
2926 show_grid( false );
2930 return PLUGIN_OK;
2933 static int load_bitmap( char *file )
2935 struct bitmap bm;
2936 bool ret;
2937 int l;
2939 bm.data = (char*)save_buffer;
2940 ret = rb->read_bmp_file( file, &bm, ROWS*COLS*sizeof( fb_data ),
2941 FORMAT_NATIVE );
2943 if((bm.width > COLS ) || ( bm.height > ROWS ))
2944 return -1;
2946 for( l = bm.height-1; l > 0; l-- )
2948 rb->memmove( save_buffer+l*COLS, save_buffer+l*bm.width,
2949 sizeof( fb_data )*bm.width );
2951 for( l = 0; l < bm.height; l++ )
2953 rb->memset( save_buffer+l*COLS+bm.width, rp_colors[ bgdrawcolor ],
2954 sizeof( fb_data )*(COLS-bm.width) );
2956 rb->memset( save_buffer+COLS*bm.height, rp_colors[ bgdrawcolor ],
2957 sizeof( fb_data )*COLS*(ROWS-bm.height) );
2959 return ret;
2962 static int save_bitmap( char *file )
2964 struct bitmap bm;
2965 bm.data = (char*)save_buffer;
2966 bm.height = ROWS;
2967 bm.width = COLS;
2968 bm.format = FORMAT_NATIVE;
2969 return save_bmp_file( file, &bm, rb );
2972 enum plugin_status plugin_start(struct plugin_api* api, void* parameter)
2974 /** must have stuff **/
2975 rb = api;
2977 rb->lcd_set_foreground(COLOR_WHITE);
2978 rb->lcd_set_backdrop(NULL);
2979 rb->lcd_fillrect(0,0,LCD_WIDTH,LCD_HEIGHT);
2980 rb->splash( HZ/2, "Rock Paint");
2982 rb->lcd_clear_display();
2984 filename[0] = '\0';
2986 if( parameter )
2988 if( load_bitmap( parameter ) <= 0 )
2990 rb->splash( 1*HZ, "File Open Error");
2991 clear_drawing();
2993 else
2995 rb->splash( 1*HZ, "Image loaded (%s)", (char *)parameter );
2996 restore_screen();
2997 rb->strcpy( filename, parameter );
3000 else
3002 clear_drawing();
3004 inv_cursor(true);
3006 return rockpaint_loop();