ppmviewer/rockpaint: do not steal the audiobuffer (and stop playback) if the plugin...
[kugel-rb.git] / apps / plugins / rockpaint.c
blob264e4f6b1406ac2655f797492e20a95c3edc71f1
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 * This program is free software; you can redistribute it and/or
14 * modify it under the terms of the GNU General Public License
15 * as published by the Free Software Foundation; either version 2
16 * of the License, or (at your option) any later version.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ****************************************************************************/
23 /**
24 * TODO:
25 * - implement 2 layers with alpha colors
26 * - take brush width into account when drawing shapes
27 * - handle bigger than screen bitmaps
28 * - cache fonts when building the font preview (else it only works well on simulators because they have "fast" disk read)
31 #include "plugin.h"
32 #include "lib/pluginlib_bmp.h"
33 #include "lib/rgb_hsv.h"
34 #include "lib/playback_control.h"
36 PLUGIN_HEADER
38 /***********************************************************************
39 * Buttons
40 ***********************************************************************/
42 #if CONFIG_KEYPAD == IRIVER_H300_PAD
43 #define ROCKPAINT_QUIT BUTTON_OFF
44 #define ROCKPAINT_DRAW BUTTON_SELECT
45 #define ROCKPAINT_MENU BUTTON_ON
46 #define ROCKPAINT_TOOLBAR BUTTON_REC
47 #define ROCKPAINT_TOOLBAR2 BUTTON_MODE
48 #define ROCKPAINT_UP BUTTON_UP
49 #define ROCKPAINT_DOWN BUTTON_DOWN
50 #define ROCKPAINT_LEFT BUTTON_LEFT
51 #define ROCKPAINT_RIGHT BUTTON_RIGHT
53 #elif (CONFIG_KEYPAD == IPOD_4G_PAD) || (CONFIG_KEYPAD == IPOD_3G_PAD) || \
54 (CONFIG_KEYPAD == IPOD_1G2G_PAD)
55 #define ROCKPAINT_QUIT ( ~BUTTON_MAIN )
56 #define ROCKPAINT_DRAW BUTTON_SELECT
57 #define ROCKPAINT_MENU ( BUTTON_SELECT | BUTTON_MENU )
58 #define ROCKPAINT_TOOLBAR ( BUTTON_MENU | BUTTON_LEFT )
59 #define ROCKPAINT_TOOLBAR2 ( BUTTON_MENU | BUTTON_RIGHT )
60 #define ROCKPAINT_UP BUTTON_MENU
61 #define ROCKPAINT_DOWN BUTTON_PLAY
62 #define ROCKPAINT_LEFT BUTTON_LEFT
63 #define ROCKPAINT_RIGHT BUTTON_RIGHT
65 #elif ( CONFIG_KEYPAD == IAUDIO_X5M5_PAD )
66 #define ROCKPAINT_QUIT BUTTON_POWER
67 #define ROCKPAINT_DRAW BUTTON_SELECT
68 #define ROCKPAINT_MENU BUTTON_PLAY
69 #define ROCKPAINT_TOOLBAR BUTTON_REC
70 #define ROCKPAINT_TOOLBAR2 ( BUTTON_REC | BUTTON_LEFT )
71 #define ROCKPAINT_UP BUTTON_UP
72 #define ROCKPAINT_DOWN BUTTON_DOWN
73 #define ROCKPAINT_LEFT BUTTON_LEFT
74 #define ROCKPAINT_RIGHT BUTTON_RIGHT
76 #elif CONFIG_KEYPAD == GIGABEAT_PAD
77 #define ROCKPAINT_QUIT BUTTON_POWER
78 #define ROCKPAINT_DRAW BUTTON_SELECT
79 #define ROCKPAINT_MENU BUTTON_MENU
80 #define ROCKPAINT_TOOLBAR BUTTON_A
81 #define ROCKPAINT_TOOLBAR2 ( BUTTON_A | BUTTON_LEFT )
82 #define ROCKPAINT_UP BUTTON_UP
83 #define ROCKPAINT_DOWN BUTTON_DOWN
84 #define ROCKPAINT_LEFT BUTTON_LEFT
85 #define ROCKPAINT_RIGHT BUTTON_RIGHT
87 #elif (CONFIG_KEYPAD == SANSA_E200_PAD) || \
88 (CONFIG_KEYPAD == SANSA_C200_PAD)
89 #define ROCKPAINT_QUIT BUTTON_POWER
90 #define ROCKPAINT_DRAW BUTTON_SELECT
91 #define ROCKPAINT_MENU ( BUTTON_SELECT | BUTTON_POWER )
92 #define ROCKPAINT_TOOLBAR BUTTON_REC
93 #define ROCKPAINT_TOOLBAR2 ( BUTTON_REC | BUTTON_LEFT )
94 #define ROCKPAINT_UP BUTTON_UP
95 #define ROCKPAINT_DOWN BUTTON_DOWN
96 #define ROCKPAINT_LEFT BUTTON_LEFT
97 #define ROCKPAINT_RIGHT BUTTON_RIGHT
99 #elif (CONFIG_KEYPAD == SANSA_FUZE_PAD)
100 #define ROCKPAINT_QUIT (BUTTON_HOME|BUTTON_REPEAT)
101 #define ROCKPAINT_DRAW BUTTON_SELECT
102 #define ROCKPAINT_MENU ( BUTTON_SELECT | BUTTON_DOWN )
103 #define ROCKPAINT_TOOLBAR ( BUTTON_SELECT | BUTTON_LEFT )
104 #define ROCKPAINT_TOOLBAR2 ( BUTTON_SELECT | BUTTON_RIGHT )
105 #define ROCKPAINT_UP BUTTON_UP
106 #define ROCKPAINT_DOWN BUTTON_DOWN
107 #define ROCKPAINT_LEFT BUTTON_LEFT
108 #define ROCKPAINT_RIGHT BUTTON_RIGHT
110 #elif ( CONFIG_KEYPAD == IRIVER_H10_PAD )
111 #define ROCKPAINT_QUIT BUTTON_POWER
112 #define ROCKPAINT_DRAW BUTTON_FF
113 #define ROCKPAINT_MENU BUTTON_PLAY
114 #define ROCKPAINT_TOOLBAR BUTTON_REW
115 #define ROCKPAINT_TOOLBAR2 ( BUTTON_REW | BUTTON_LEFT )
116 #define ROCKPAINT_UP BUTTON_SCROLL_UP
117 #define ROCKPAINT_DOWN BUTTON_SCROLL_DOWN
118 #define ROCKPAINT_LEFT BUTTON_LEFT
119 #define ROCKPAINT_RIGHT BUTTON_RIGHT
121 #elif CONFIG_KEYPAD == GIGABEAT_S_PAD
122 #define ROCKPAINT_QUIT BUTTON_BACK
123 #define ROCKPAINT_DRAW BUTTON_SELECT
124 #define ROCKPAINT_MENU BUTTON_MENU
125 #define ROCKPAINT_TOOLBAR BUTTON_PLAY
126 #define ROCKPAINT_TOOLBAR2 ( BUTTON_PLAY | BUTTON_LEFT )
127 #define ROCKPAINT_UP BUTTON_UP
128 #define ROCKPAINT_DOWN BUTTON_DOWN
129 #define ROCKPAINT_LEFT BUTTON_LEFT
130 #define ROCKPAINT_RIGHT BUTTON_RIGHT
132 #elif ( CONFIG_KEYPAD == COWON_D2_PAD )
133 #define ROCKPAINT_QUIT BUTTON_POWER
134 #define ROCKPAINT_MENU BUTTON_MENU
136 #elif CONFIG_KEYPAD == CREATIVEZVM_PAD
137 #define ROCKPAINT_QUIT BUTTON_BACK
138 #define ROCKPAINT_DRAW BUTTON_SELECT
139 #define ROCKPAINT_MENU BUTTON_MENU
140 #define ROCKPAINT_TOOLBAR BUTTON_PLAY
141 #define ROCKPAINT_TOOLBAR2 ( BUTTON_PLAY | BUTTON_LEFT )
142 #define ROCKPAINT_UP BUTTON_UP
143 #define ROCKPAINT_DOWN BUTTON_DOWN
144 #define ROCKPAINT_LEFT BUTTON_LEFT
145 #define ROCKPAINT_RIGHT BUTTON_RIGHT
147 #elif CONFIG_KEYPAD == PHILIPS_HDD1630_PAD
148 #define ROCKPAINT_QUIT BUTTON_POWER
149 #define ROCKPAINT_DRAW BUTTON_SELECT
150 #define ROCKPAINT_MENU BUTTON_MENU
151 #define ROCKPAINT_TOOLBAR BUTTON_VIEW
152 #define ROCKPAINT_TOOLBAR2 BUTTON_PLAYLIST
153 #define ROCKPAINT_UP BUTTON_UP
154 #define ROCKPAINT_DOWN BUTTON_DOWN
155 #define ROCKPAINT_LEFT BUTTON_LEFT
156 #define ROCKPAINT_RIGHT BUTTON_RIGHT
158 #elif CONFIG_KEYPAD == PHILIPS_SA9200_PAD
159 #define ROCKPAINT_QUIT BUTTON_POWER
160 #define ROCKPAINT_DRAW BUTTON_PLAY
161 #define ROCKPAINT_MENU BUTTON_MENU
162 #define ROCKPAINT_TOOLBAR BUTTON_RIGHT
163 #define ROCKPAINT_TOOLBAR2 BUTTON_LEFT
164 #define ROCKPAINT_UP BUTTON_UP
165 #define ROCKPAINT_DOWN BUTTON_DOWN
166 #define ROCKPAINT_LEFT BUTTON_PREV
167 #define ROCKPAINT_RIGHT BUTTON_NEXT
169 #elif ( CONFIG_KEYPAD == ONDAVX747_PAD )
170 #define ROCKPAINT_QUIT BUTTON_POWER
171 #define ROCKPAINT_MENU BUTTON_MENU
173 #elif ( CONFIG_KEYPAD == ONDAVX777_PAD )
174 #define ROCKPAINT_QUIT BUTTON_POWER
176 #elif CONFIG_KEYPAD == MROBE500_PAD
177 #define ROCKPAINT_QUIT BUTTON_POWER
179 #elif ( CONFIG_KEYPAD == SAMSUNG_YH_PAD )
180 #define ROCKPAINT_QUIT BUTTON_REC
181 #define ROCKPAINT_DRAW BUTTON_PLAY
182 #define ROCKPAINT_MENU BUTTON_FFWD
183 #define ROCKPAINT_TOOLBAR BUTTON_REW
184 #define ROCKPAINT_TOOLBAR2 ( BUTTON_REW | BUTTON_LEFT )
185 #define ROCKPAINT_UP BUTTON_UP
186 #define ROCKPAINT_DOWN BUTTON_DOWN
187 #define ROCKPAINT_LEFT BUTTON_LEFT
188 #define ROCKPAINT_RIGHT BUTTON_RIGHT
190 #elif CONFIG_KEYPAD == PBELL_VIBE500_PAD
191 #define ROCKPAINT_QUIT BUTTON_REC
192 #define ROCKPAINT_DRAW BUTTON_PLAY
193 #define ROCKPAINT_MENU BUTTON_MENU
194 #define ROCKPAINT_TOOLBAR BUTTON_OK
195 #define ROCKPAINT_TOOLBAR2 BUTTON_CANCEL
196 #define ROCKPAINT_UP BUTTON_UP
197 #define ROCKPAINT_DOWN BUTTON_DOWN
198 #define ROCKPAINT_LEFT BUTTON_PREV
199 #define ROCKPAINT_RIGHT BUTTON_NEXT
201 #else
202 #error "Please define keys for this keypad"
203 #endif
205 #ifdef HAVE_TOUCHSCREEN
206 #ifndef ROCKPAINT_QUIT
207 #define ROCKPAINT_QUIT BUTTON_TOPLEFT
208 #endif
209 #ifndef ROCKPAINT_DRAW
210 #define ROCKPAINT_DRAW BUTTON_CENTER
211 #endif
212 #ifndef ROCKPAINT_MENU
213 #define ROCKPAINT_MENU BUTTON_TOPRIGHT
214 #endif
215 #ifndef ROCKPAINT_TOOLBAR
216 #define ROCKPAINT_TOOLBAR BUTTON_BOTTOMLEFT
217 #endif
218 #ifndef ROCKPAINT_TOOLBAR2
219 #define ROCKPAINT_TOOLBAR2 BUTTON_BOTTOMRIGHT
220 #endif
221 #ifndef ROCKPAINT_UP
222 #define ROCKPAINT_UP BUTTON_TOPMIDDLE
223 #endif
224 #ifndef ROCKPAINT_DOWN
225 #define ROCKPAINT_DOWN BUTTON_BOTTOMMIDDLE
226 #endif
227 #ifndef ROCKPAINT_LEFT
228 #define ROCKPAINT_LEFT BUTTON_MIDLEFT
229 #endif
230 #ifndef ROCKPAINT_RIGHT
231 #define ROCKPAINT_RIGHT BUTTON_MIDRIGHT
232 #endif
233 #endif
235 /***********************************************************************
236 * Palette Default Colors
237 ***********************************************************************/
238 #define COLOR_BLACK LCD_RGBPACK(0,0,0)
239 #define COLOR_WHITE LCD_RGBPACK(255,255,255)
240 #define COLOR_DARKGRAY LCD_RGBPACK(128,128,128)
241 #define COLOR_LIGHTGRAY LCD_RGBPACK(192,192,192)
242 #define COLOR_RED LCD_RGBPACK(128,0,0)
243 #define COLOR_LIGHTRED LCD_RGBPACK(255,0,0)
244 #define COLOR_DARKYELLOW LCD_RGBPACK(128,128,0)
245 #define COLOR_YELLOW LCD_RGBPACK(255,255,0)
246 #define COLOR_GREEN LCD_RGBPACK(0,128,0)
247 #define COLOR_LIGHTGREN LCD_RGBPACK(0,255,0)
248 #define COLOR_CYAN LCD_RGBPACK(0,128,128)
249 #define COLOR_LIGHTCYAN LCD_RGBPACK(0,255,255)
250 #define COLOR_BLUE LCD_RGBPACK(0,0,128)
251 #define COLOR_LIGHTBLUE LCD_RGBPACK(0,0,255)
252 #define COLOR_PURPLE LCD_RGBPACK(128,0,128)
253 #define COLOR_PINK LCD_RGBPACK(255,0,255)
254 #define COLOR_BROWN LCD_RGBPACK(128,64,0)
255 #define COLOR_LIGHTBROWN LCD_RGBPACK(255,128,64)
257 #define SPLASH_SCREEN PLUGIN_APPS_DIR "/rockpaint/splash.bmp"
258 #define ROCKPAINT_TITLE_FONT 2
260 /***********************************************************************
261 * Program Colors
262 ***********************************************************************/
263 #define ROCKPAINT_PALETTE LCD_RGBPACK(0,64,128)
264 #define ROCKPAINT_SELECTED LCD_RGBPACK(128,192,255)
266 #define ROWS LCD_HEIGHT
267 #define COLS LCD_WIDTH
270 * Toolbar positioning stuff ... don't read this unless you really need to
272 * TB Toolbar
273 * SP Separator
274 * SC Selected Color
275 * PL Palette
276 * TL Tools
279 /* Separator sizes */
280 #define TB_SP_MARGIN 3
281 #define TB_SP_WIDTH (2+2*TB_SP_MARGIN)
283 /* Selected color sizes */
284 #define TB_SC_SIZE 12
286 /* Palette sizes */
287 #define TB_PL_COLOR_SIZE 7
288 #define TB_PL_COLOR_SPACING 2
289 #define TB_PL_WIDTH ( 9 * TB_PL_COLOR_SIZE + 8 * TB_PL_COLOR_SPACING )
290 #define TB_PL_HEIGHT ( TB_PL_COLOR_SIZE * 2 + TB_PL_COLOR_SPACING )
292 /* Tools sizes */
293 #define TB_TL_SIZE 8
294 #define TB_TL_SPACING 2
295 #define TB_TL_WIDTH ( 7 * ( TB_TL_SIZE + TB_TL_SPACING ) - TB_TL_SPACING )
296 #define TB_TL_HEIGHT ( 2 * TB_TL_SIZE + TB_TL_SPACING )
298 /* Menu button size ... gruik */
299 #define TB_MENU_MIN_WIDTH 30
301 /* Selected colors position */
302 #define TB_SC_FG_TOP 2
303 #define TB_SC_FG_LEFT 2
304 #define TB_SC_BG_TOP (TB_SC_FG_TOP+TB_PL_COLOR_SIZE*2+TB_PL_COLOR_SPACING-TB_SC_SIZE)
305 #define TB_SC_BG_LEFT (TB_SC_FG_LEFT+TB_PL_COLOR_SIZE*2+TB_PL_COLOR_SPACING-TB_SC_SIZE)
307 /* Palette position */
308 #define TB_PL_TOP TB_SC_FG_TOP
309 #define TB_PL_LEFT (TB_SC_BG_LEFT + TB_SC_SIZE + TB_PL_COLOR_SPACING)
311 /* Tools position */
312 #define TB_TL_TOP TB_SC_FG_TOP
313 #define TB_TL_LEFT ( TB_PL_LEFT + TB_PL_WIDTH-1 + TB_SP_WIDTH )
315 #if TB_TL_LEFT + TB_TL_WIDTH + TB_MENU_MIN_WIDTH >= LCD_WIDTH
316 #undef TB_TL_TOP
317 #undef TB_TL_LEFT
318 #define TB_TL_TOP ( TB_PL_TOP + TB_PL_HEIGHT + 4 )
319 #define TB_TL_LEFT TB_SC_FG_LEFT
320 #endif
322 /* Menu button position */
323 #define TB_MENU_TOP ( TB_TL_TOP + (TB_TL_HEIGHT-8)/2 )
324 #define TB_MENU_LEFT ( TB_TL_LEFT + TB_TL_WIDTH-1 + TB_SP_WIDTH )
326 #define TB_HEIGHT ( TB_TL_TOP + TB_TL_HEIGHT + 1 )
329 static void draw_pixel(int x,int y);
330 static void draw_line( int x1, int y1, int x2, int y2 );
331 static void draw_rect( int x1, int y1, int x2, int y2 );
332 static void draw_toolbars(bool update);
333 static void inv_cursor(bool update);
334 static void restore_screen(void);
335 static void clear_drawing(void);
336 static void goto_menu(void);
337 static int load_bitmap( const char *filename );
338 static int save_bitmap( char *filename );
339 static void draw_rect_full( int x1, int y1, int x2, int y2 );
341 /***********************************************************************
342 * Global variables
343 ***********************************************************************/
345 static int drawcolor=0; /* Current color (in palette) */
346 static int bgdrawcolor=9; /* Current background color (in palette) */
347 static int img_height = ROWS;
348 static int img_width = COLS;
349 bool isbg = false; /* gruik ugly hack alert */
351 static int preview=false; /* Is preview mode on ? */
353 /* TODO: clean this up */
354 static int x=0, y=0; /* cursor position */
355 static int prev_x=-1, prev_y=-1; /* previous saved cursor position */
356 static int prev_x2=-1, prev_y2=-1;
357 static int prev_x3=-1, prev_y3=-1;
358 static int tool_mode=-1;
361 static int bsize=1; /* brush size */
362 static int bspeed=1; /* brush speed */
364 enum Tools { Brush = 0, /* Regular brush */
365 Fill = 1, /* Fill a shape with current color */
366 SelectRectangle = 2,
367 ColorPicker = 3, /* Pick a color */
368 Line = 4, /* Draw a line between two points */
369 Unused = 5, /* THIS IS UNUSED ... */
370 Curve = 6,
371 Text = 7,
372 Rectangle = 8, /* Draw a rectangle */
373 RectangleFull = 9,
374 Oval = 10, /* Draw an oval */
375 OvalFull = 11,
376 LinearGradient = 12,
377 RadialGradient = 13
380 enum Tools tool = Brush;
382 static bool quit=false;
383 static int gridsize=0;
385 static fb_data rp_colors[18] =
387 COLOR_BLACK, COLOR_DARKGRAY, COLOR_RED, COLOR_DARKYELLOW,
388 COLOR_GREEN, COLOR_CYAN, COLOR_BLUE, COLOR_PURPLE, COLOR_BROWN,
389 COLOR_WHITE, COLOR_LIGHTGRAY, COLOR_LIGHTRED, COLOR_YELLOW,
390 COLOR_LIGHTGREN, COLOR_LIGHTCYAN, COLOR_LIGHTBLUE, COLOR_PINK,
391 COLOR_LIGHTBROWN
394 static fb_data save_buffer[ ROWS*COLS ];
396 extern fb_data rockpaint[];
397 extern fb_data rockpaint_hsvrgb[];
399 /* Maximum string size allowed for the text tool */
400 #define MAX_TEXT 256
402 typedef union
404 /* Used by fill and gradient algorithms */
405 struct
407 short x;
408 short y;
409 } coord[ ROWS*COLS ];
411 /* Used by bezier curve algorithms */
412 struct
414 short x1, y1;
415 short x2, y2;
416 short x3, y3;
417 short x4, y4;
418 short depth;
419 } bezier[ (ROWS*COLS)/5 ]; /* We have 4.5 times more data per struct
420 * than coord ... so we divide to take
421 * less memory. */
423 /* Used to cut/copy/paste data */
424 fb_data clipboard[ ROWS*COLS ];
426 /* Used for text mode */
427 struct
429 char text[MAX_TEXT];
430 char font[MAX_PATH];
431 char old_font[MAX_PATH];
432 int fh_buf[30];
433 int fw_buf[30];
434 char fontname_buf[30][MAX_PATH];
435 } text;
436 } buf;
438 static buf *buffer;
440 /* Current filename */
441 static char filename[MAX_PATH];
443 /* Font preview buffer */
444 //#define FONT_PREVIEW_WIDTH ((LCD_WIDTH-30)/8)
445 //#define FONT_PREVIEW_HEIGHT 1000
446 //static unsigned char fontpreview[FONT_PREVIEW_WIDTH*FONT_PREVIEW_HEIGHT];
448 /***********************************************************************
449 * Offscreen buffer/Text/Fonts handling
451 * Parts of code taken from firmware/drivers/lcd-16bit.c
452 ***********************************************************************/
453 static void buffer_mono_bitmap_part(
454 fb_data *buf, int buf_width, int buf_height,
455 const unsigned char *src, int src_x, int src_y,
456 int stride, int x, int y, int width, int height )
457 /* this function only draws the foreground part of the bitmap */
459 const unsigned char *src_end;
460 fb_data *dst, *dst_end;
461 unsigned fgcolor = rb->lcd_get_foreground();
463 /* nothing to draw? */
464 if( ( width <= 0 ) || ( height <= 0 ) || ( x >= buf_width )
465 || ( y >= buf_height ) || ( x + width <= 0 ) || ( y + height <= 0 ) )
466 return;
468 /* clipping */
469 if( x < 0 )
471 width += x;
472 src_x -= x;
473 x = 0;
475 if( y < 0 )
477 height += y;
478 src_y -= y;
479 y = 0;
481 if( x + width > buf_width )
482 width = buf_width - x;
483 if( y + height > buf_height )
484 height = buf_height - y;
486 src += stride * (src_y >> 3) + src_x; /* move starting point */
487 src_y &= 7;
488 src_end = src + width;
490 dst = buf + y*buf_width + x;
494 const unsigned char *src_col = src++;
495 unsigned data = *src_col >> src_y;
496 fb_data *dst_col = dst++;
497 int numbits = 8 - src_y;
499 dst_end = dst_col + height * buf_width;
502 if( data & 0x01 )
503 *dst_col = fgcolor; /* FIXME ? */
505 dst_col += buf_width;
507 data >>= 1;
508 if( --numbits == 0 )
510 src_col += stride;
511 data = *src_col;
512 numbits = 8;
514 } while( dst_col < dst_end );
515 } while( src < src_end );
518 static void buffer_putsxyofs( fb_data *buf, int buf_width, int buf_height,
519 int x, int y, int ofs, const unsigned char *str )
521 unsigned short ch;
522 unsigned short *ucs;
524 struct font *pf = rb->font_get( FONT_UI );
525 if( !pf ) pf = rb->font_get( FONT_SYSFIXED );
527 ucs = rb->bidi_l2v( str, 1 );
529 while( (ch = *ucs++) != 0 && x < buf_width )
531 int width;
532 const unsigned char *bits;
534 /* get proportional width and glyph bits */
535 width = rb->font_get_width( pf, ch );
537 if( ofs > width )
539 ofs -= width;
540 continue;
543 bits = rb->font_get_bits( pf, ch );
545 buffer_mono_bitmap_part( buf, buf_width, buf_height, bits, ofs, 0,
546 width, x, y, width - ofs, pf->height);
548 x += width - ofs;
549 ofs = 0;
553 /***********************************************************************
554 * Menu handling
555 ***********************************************************************/
556 enum {
557 /* Main menu */
558 MAIN_MENU_RESUME,
559 MAIN_MENU_NEW, MAIN_MENU_LOAD, MAIN_MENU_SAVE,
560 MAIN_MENU_SET_WIDTH, MAIN_MENU_SET_HEIGHT,
561 MAIN_MENU_BRUSH_SIZE, MAIN_MENU_BRUSH_SPEED, MAIN_MENU_COLOR,
562 MAIN_MENU_GRID_SIZE,
563 MAIN_MENU_PLAYBACK_CONTROL,
564 MAIN_MENU_EXIT,
566 enum {
567 /* Select action menu */
568 SELECT_MENU_CUT, SELECT_MENU_COPY,
569 SELECT_MENU_INVERT, SELECT_MENU_HFLIP, SELECT_MENU_VFLIP,
570 SELECT_MENU_ROTATE90, SELECT_MENU_ROTATE180, SELECT_MENU_ROTATE270,
571 SELECT_MENU_CANCEL,
573 enum {
574 /* Text menu */
575 TEXT_MENU_TEXT, TEXT_MENU_FONT,
576 TEXT_MENU_PREVIEW, TEXT_MENU_APPLY, TEXT_MENU_CANCEL,
579 MENUITEM_STRINGLIST(main_menu, "RockPaint", NULL,
580 "Resume", "New", "Load", "Save",
581 "Set Width", "Set Height",
582 "Brush Size", "Brush Speed",
583 "Choose Color", "Grid Size",
584 "Playback Control", "Exit");
585 MENUITEM_STRINGLIST(select_menu, "Select...", NULL,
586 "Cut", "Copy",
587 "Invert", "Horizontal Flip", "Vertical Flip",
588 "Rotate 90°", "Rotate 180°", "Rotate 270°",
589 "Cancel");
590 MENUITEM_STRINGLIST(text_menu, "Text", NULL,
591 "Set Text", "Change Font",
592 "Preview", "Apply", "Cancel");
593 static const int times_list[] = { 1, 2, 4, 8 };
594 static const int gridsize_list[] = { 0, 5, 10, 20 };
595 static const struct opt_items times_options[] = {
596 { "1x", -1 }, { "2x", -1 }, { "4x", -1 }, { "8x", -1 }
598 static const struct opt_items gridsize_options[] = {
599 { "No grid", -1 }, { "5px", -1 }, { "10px", -1 }, { "20px", -1 }
602 static int draw_window( int height, int width,
603 int *top, int *left,
604 const char *title )
606 int fh;
607 rb->lcd_getstringsize( title, NULL, &fh );
608 fh++;
610 const int _top = ( LCD_HEIGHT - height ) / 2;
611 const int _left = ( LCD_WIDTH - width ) / 2;
612 if( top ) *top = _top;
613 if( left ) *left = _left;
614 rb->lcd_set_background(COLOR_BLUE);
615 rb->lcd_set_foreground(COLOR_LIGHTGRAY);
616 rb->lcd_fillrect( _left, _top, width, height );
617 rb->lcd_set_foreground(COLOR_BLUE);
618 rb->lcd_fillrect( _left, _top, width, fh+4 );
619 rb->lcd_set_foreground(COLOR_WHITE);
620 rb->lcd_putsxy( _left+2, _top+2, title );
621 rb->lcd_set_foreground(COLOR_BLACK);
622 rb->lcd_drawrect( _left, _top, width, height );
623 return _top+fh+4;
626 /***********************************************************************
627 * File browser
628 ***********************************************************************/
630 char bbuf[MAX_PATH]; /* used by file and font browsers */
631 char bbuf_s[MAX_PATH]; /* used by file and font browsers */
632 struct tree_context *tree = NULL;
634 static bool check_extention(const char *filename, const char *ext)
636 const char *p = rb->strrchr( filename, '.' );
637 return ( p != NULL && !rb->strcasecmp( p, ext ) );
640 static const char* browse_get_name_cb(int selected_item, void *data,
641 char *buffer, size_t buffer_len)
643 int *indexes = (int *) data;
644 struct entry* dc = tree->dircache;
645 struct entry* e = &dc[indexes[selected_item]];
646 (void) buffer;
647 (void) buffer_len;
649 return e->name;
652 static bool browse( char *dst, int dst_size, const char *start )
654 struct gui_synclist browse_list;
655 int item_count = 0, selected, button;
656 struct tree_context backup;
657 struct entry *dc;
658 bool reload = true;
659 int dirfilter = SHOW_ALL;
660 int *indexes = (int *) buffer->clipboard;
662 char *a;
664 rb->strcpy( bbuf, start );
665 a = bbuf+rb->strlen(bbuf)-1;
666 if( *a != '/' )
668 a[1] = '/';
669 a[2] = '\0';
671 bbuf_s[0] = '\0';
673 rb->gui_synclist_init(&browse_list, browse_get_name_cb,
674 (void*) indexes, false, 1, NULL);
676 tree = rb->tree_get_context();
677 backup = *tree;
678 dc = tree->dircache;
679 a = backup.currdir+rb->strlen(backup.currdir)-1;
680 if( *a != '/' )
682 *++a = '/';
683 *++a = '\0';
685 rb->strcpy( a, dc[tree->selected_item].name );
686 tree->dirfilter = &dirfilter;
687 while( 1 )
689 if( reload )
691 int i;
692 rb->set_current_file(bbuf);
693 item_count = 0;
694 selected = 0;
695 for( i = 0; i < tree->filesindir ; i++)
697 /* only displayes directories and .bmp files */
698 if( ((dc[i].attr & ATTR_DIRECTORY ) &&
699 rb->strcmp( dc[i].name, "." ) &&
700 rb->strcmp( dc[i].name, ".." )) ||
701 ( !(dc[i].attr & ATTR_DIRECTORY) &&
702 check_extention( dc[i].name, ".bmp" ) ) )
704 if( !rb->strcmp( dc[i].name, bbuf_s ) )
705 selected = item_count;
706 indexes[item_count++] = i;
710 rb->gui_synclist_set_nb_items(&browse_list,item_count);
711 rb->gui_synclist_select_item(&browse_list, selected);
712 rb->gui_synclist_set_title(&browse_list, bbuf, NOICON);
713 rb->gui_synclist_draw(&browse_list);
714 reload = false;
716 button = rb->get_action(CONTEXT_LIST,TIMEOUT_BLOCK);
717 if (rb->gui_synclist_do_button(&browse_list,&button,LIST_WRAP_UNLESS_HELD))
718 continue;
719 switch( button )
721 case ACTION_STD_CANCEL:
722 if( !rb->strcmp( bbuf, "/" ) )
724 *tree = backup;
725 rb->set_current_file( backup.currdir );
726 return false;
728 rb->strcpy( bbuf_s, ".." );
729 case ACTION_STD_OK:
730 if( button == ACTION_STD_OK )
732 selected = rb->gui_synclist_get_sel_pos( &browse_list );
733 if( selected < 0 || selected >= item_count )
734 break;
735 struct entry* e = &dc[indexes[selected]];
736 rb->strlcpy( bbuf_s, e->name, sizeof( bbuf_s ) );
737 if( !( e->attr & ATTR_DIRECTORY ) )
739 *tree = backup;
740 rb->set_current_file( backup.currdir );
741 rb->snprintf( dst, dst_size, "%s%s", bbuf, bbuf_s );
742 return true;
745 if( !rb->strcmp( bbuf_s, "." ) ) break;
746 a = bbuf+rb->strlen(bbuf);
747 if( !rb->strcmp( bbuf_s, ".." ) )
749 a--;
750 if( a == bbuf ) break;
751 if( *a == '/' ) a--;
752 while( *a != '/' ) a--;
753 rb->strcpy( bbuf_s, ++a );
754 /* select parent directory */
755 bbuf_s[rb->strlen(bbuf_s)-1] = '\0';
756 *a = '\0';
757 reload = true;
758 break;
760 rb->snprintf( a, bbuf+sizeof(bbuf)-a, "%s/", bbuf_s );
761 reload = true;
762 break;
764 case ACTION_STD_MENU:
765 *tree = backup;
766 rb->set_current_file( backup.currdir );
767 return false;
772 /***********************************************************************
773 * Font browser
775 * FIXME: This still needs some work ... it currently only works fine
776 * on the simulators, disk spins too much on real targets -> rendered
777 * font buffer needed.
778 ***********************************************************************/
779 static bool browse_fonts( char *dst, int dst_size )
781 #define WIDTH ( LCD_WIDTH - 20 )
782 #define HEIGHT ( LCD_HEIGHT - 20 )
783 #define LINE_SPACE 2
784 int top, top_inside = 0, left;
786 DIR *d;
787 struct dirent *de;
788 int fvi = 0; /* first visible item */
789 int lvi = 0; /* last visible item */
790 int si = 0; /* selected item */
791 int osi = 0; /* old selected item */
792 int li = 0; /* last item */
793 int nvih = 0; /* next visible item height */
794 int i;
795 int b_need_redraw = 1; /* Do we need to redraw ? */
797 int cp = 0; /* current position */
798 int fh; /* font height */
800 #define fh_buf buffer->text.fh_buf /* 30 might not be enough ... */
801 #define fw_buf buffer->text.fw_buf
802 int fw;
803 #define fontname_buf buffer->text.fontname_buf
805 rb->snprintf( buffer->text.old_font, MAX_PATH,
806 FONT_DIR "/%s.fnt",
807 rb->global_settings->font_file );
809 while( 1 )
811 if( !b_need_redraw )
813 /* we don't need to redraw ... but we need to unselect
814 * the previously selected item */
815 cp = top_inside + LINE_SPACE;
816 for( i = 0; i+fvi < osi; i++ )
818 cp += fh_buf[i] + LINE_SPACE;
820 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
821 rb->lcd_fillrect( left+10, cp, fw_buf[i], fh_buf[i] );
822 rb->lcd_set_drawmode(DRMODE_SOLID);
825 if( b_need_redraw )
827 b_need_redraw = 0;
829 d = rb->opendir( FONT_DIR "/" );
830 if( !d )
832 return false;
834 top_inside = draw_window( HEIGHT, WIDTH, &top, &left, "Fonts" );
835 i = 0;
836 li = -1;
837 while( i < fvi )
839 rb->readdir( d );
840 i++;
842 cp = top_inside+LINE_SPACE;
844 rb->lcd_set_foreground(COLOR_BLACK);
845 rb->lcd_set_background(COLOR_LIGHTGRAY);
847 while( cp < top+HEIGHT )
849 de = rb->readdir( d );
850 if( !de )
852 li = i-1;
853 break;
855 if( !check_extention( de->d_name, ".fnt" ) )
856 continue;
857 rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s",
858 de->d_name );
859 rb->font_load(NULL, bbuf );
860 rb->font_getstringsize( de->d_name, &fw, &fh, FONT_UI );
861 if( nvih > 0 )
863 nvih -= fh;
864 fvi++;
865 if( nvih < 0 ) nvih = 0;
866 i++;
867 continue;
869 if( cp + fh >= top+HEIGHT )
871 nvih = fh;
872 break;
874 rb->lcd_putsxy( left+10, cp, de->d_name );
875 fh_buf[i-fvi] = fh;
876 fw_buf[i-fvi] = fw;
877 cp += fh + LINE_SPACE;
878 rb->strcpy( fontname_buf[i-fvi], bbuf );
879 i++;
881 lvi = i-1;
882 if( li == -1 )
884 if( !(de = rb->readdir( d ) ) )
886 li = lvi;
888 else if( !nvih && check_extention( de->d_name, ".fnt" ) )
890 rb->snprintf( bbuf, MAX_PATH, FONT_DIR "/%s",
891 de->d_name );
892 rb->font_load(NULL, bbuf );
893 rb->font_getstringsize( de->d_name, NULL, &fh, FONT_UI );
894 nvih = fh;
897 rb->font_load(NULL, buffer->text.old_font );
898 rb->closedir( d );
901 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
902 cp = top_inside + LINE_SPACE;
903 for( i = 0; i+fvi < si; i++ )
905 cp += fh_buf[i] + LINE_SPACE;
907 rb->lcd_fillrect( left+10, cp, fw_buf[i], fh_buf[i] );
908 rb->lcd_set_drawmode(DRMODE_SOLID);
910 rb->lcd_update_rect( left, top, WIDTH, HEIGHT );
912 osi = si;
913 i = fvi;
914 switch( rb->button_get(true) )
916 case ROCKPAINT_UP:
917 case ROCKPAINT_UP|BUTTON_REPEAT:
918 if( si > 0 )
920 si--;
921 if( si<fvi )
923 fvi = si;
926 break;
928 case ROCKPAINT_DOWN:
929 case ROCKPAINT_DOWN|BUTTON_REPEAT:
930 if( li == -1 || si < li )
932 si++;
934 break;
936 case ROCKPAINT_LEFT:
937 return false;
939 case ROCKPAINT_RIGHT:
940 case ROCKPAINT_DRAW:
941 rb->snprintf( dst, dst_size, "%s", fontname_buf[si-fvi] );
942 return true;
945 if( i != fvi || si > lvi )
947 b_need_redraw = 1;
950 if( si<=lvi )
952 nvih = 0;
955 #undef fh_buf
956 #undef fw_buf
957 #undef fontname_buf
958 #undef WIDTH
959 #undef HEIGHT
960 #undef LINE_SPACE
963 /***********************************************************************
964 * HSVRGB Color chooser
965 ***********************************************************************/
966 static unsigned int color_chooser( unsigned int color )
968 int red = RGB_UNPACK_RED( color );
969 int green = RGB_UNPACK_GREEN( color );
970 int blue = RGB_UNPACK_BLUE( color );
971 int hue, saturation, value;
972 int r, g, b; /* temp variables */
973 int i, top, left;
975 enum BaseColor { Hue = 0, Saturation = 1, Value = 2,
976 Red = 3, Green = 4, Blue = 5 };
977 enum BaseColor current = Red;
978 bool has_changed;
980 char str[6] = "";
982 restore_screen();
984 rgb2hsv( red, green, blue, &hue, &saturation, &value );
986 while( 1 )
988 has_changed = false;
989 color = LCD_RGBPACK( red, green, blue );
991 #define HEIGHT ( 100 )
992 #define WIDTH ( 150 )
994 top = draw_window( HEIGHT, WIDTH, NULL, &left, "Color chooser" );
995 top -= 15;
997 for( i=0; i<100; i++ )
999 hsv2rgb( i*36, saturation, value, &r, &g, &b );
1000 rb->lcd_set_foreground( LCD_RGBPACK( r, g, b ) );
1001 rb->lcd_vline( left+15+i, top+20, top+27 );
1002 hsv2rgb( hue, i*255/100, value, &r, &g, &b );
1003 rb->lcd_set_foreground( LCD_RGBPACK( r, g, b ) );
1004 rb->lcd_vline( left+15+i, top+30, top+37 );
1005 hsv2rgb( hue, saturation, i*255/100, &r, &g, &b );
1006 rb->lcd_set_foreground( LCD_RGBPACK( r, g, b ) );
1007 rb->lcd_vline( left+15+i, top+40, top+47 );
1008 rb->lcd_set_foreground( LCD_RGBPACK( i*255/100, green, blue ) );
1009 rb->lcd_vline( left+15+i, top+50, top+57 );
1010 rb->lcd_set_foreground( LCD_RGBPACK( red, i*255/100, blue ) );
1011 rb->lcd_vline( left+15+i, top+60, top+67 );
1012 rb->lcd_set_foreground( LCD_RGBPACK( red, green, i*255/100 ) );
1013 rb->lcd_vline( left+15+i, top+70, top+77 );
1016 rb->lcd_set_foreground(COLOR_BLACK);
1017 #define POSITION( a, i ) \
1018 rb->lcd_drawpixel( left+14+i, top + 19 + a ); \
1019 rb->lcd_drawpixel( left+16+i, top + 19 + a ); \
1020 rb->lcd_drawpixel( left+14+i, top + 28 + a ); \
1021 rb->lcd_drawpixel( left+16+i, top + 28 + a );
1022 POSITION( 0, hue/36 );
1023 POSITION( 10, saturation*99/255 );
1024 POSITION( 20, value*99/255 );
1025 POSITION( 30, red*99/255 );
1026 POSITION( 40, green*99/255 );
1027 POSITION( 50, blue*99/255 );
1028 #undef POSITION
1029 rb->lcd_set_background(COLOR_LIGHTGRAY);
1030 rb->lcd_setfont( FONT_SYSFIXED );
1031 rb->snprintf( str, 6, "%d", hue/10 );
1032 rb->lcd_putsxy( left + 117, top + 20, str );
1033 rb->snprintf( str, 6, "%d.%d", saturation/255, ((saturation*100)/255)%100 );
1034 rb->lcd_putsxy( left + 117, top + 30, str );
1035 rb->snprintf( str, 6, "%d.%d", value/255, ((value*100)/255)%100 );
1036 rb->lcd_putsxy( left + 117, top + 40, str );
1037 rb->snprintf( str, 6, "%d", red );
1038 rb->lcd_putsxy( left + 117, top + 50, str );
1039 rb->snprintf( str, 6, "%d", green );
1040 rb->lcd_putsxy( left + 117, top + 60, str );
1041 rb->snprintf( str, 6, "%d", blue );
1042 rb->lcd_putsxy( left + 117, top + 70, str );
1043 rb->lcd_setfont( FONT_UI );
1045 #define CURSOR( l ) \
1046 rb->lcd_bitmap_transparent_part( rockpaint_hsvrgb, 1, 1, 16, left+l+1, top+20, 6, 58 ); \
1047 rb->lcd_bitmap_transparent_part( rockpaint_hsvrgb, 8, 10*current, 16, left+l, top+19+10*current, 8, 10 );
1048 CURSOR( 5 );
1049 #undef CURSOR
1051 rb->lcd_set_foreground( color );
1052 rb->lcd_fillrect( left+15, top+85, 100, 8 );
1054 rb->lcd_update();
1056 switch( rb->button_get(true) )
1058 case ROCKPAINT_UP:
1059 current = ( current + 5 )%6;
1060 break;
1062 case ROCKPAINT_DOWN:
1063 current = (current + 1 )%6;
1064 break;
1066 case ROCKPAINT_LEFT:
1067 has_changed = true;
1068 switch( current )
1070 case Hue:
1071 hue = ( hue + 3600 - 10 )%3600;
1072 break;
1073 case Saturation:
1074 if( saturation ) saturation--;
1075 break;
1076 case Value:
1077 if( value ) value--;
1078 break;
1079 case Red:
1080 if( red ) red--;
1081 break;
1082 case Green:
1083 if( green ) green--;
1084 break;
1085 case Blue:
1086 if( blue ) blue--;
1087 break;
1089 break;
1091 case ROCKPAINT_LEFT|BUTTON_REPEAT:
1092 has_changed = true;
1093 switch( current )
1095 case Hue:
1096 hue = ( hue + 3600 - 100 )%3600;
1097 break;
1098 case Saturation:
1099 if( saturation >= 8 ) saturation-=8;
1100 else saturation = 0;
1101 break;
1102 case Value:
1103 if( value >= 8 ) value-=8;
1104 else value = 0;
1105 break;
1106 case Red:
1107 if( red >= 8 ) red-=8;
1108 else red = 0;
1109 break;
1110 case Green:
1111 if( green >= 8 ) green-=8;
1112 else green = 0;
1113 break;
1114 case Blue:
1115 if( blue >= 8 ) blue-=8;
1116 else blue = 0;
1117 break;
1119 break;
1121 case ROCKPAINT_RIGHT:
1122 has_changed = true;
1123 switch( current )
1125 case Hue:
1126 hue = ( hue + 10 )%3600;
1127 break;
1128 case Saturation:
1129 if( saturation < 0xff ) saturation++;
1130 break;
1131 case Value:
1132 if( value < 0xff ) value++;
1133 break;
1134 case Red:
1135 if( red < 0xff ) red++;
1136 break;
1137 case Green:
1138 if( green < 0xff ) green++;
1139 break;
1140 case Blue:
1141 if( blue < 0xff ) blue++;
1142 break;
1144 break;
1146 case ROCKPAINT_RIGHT|BUTTON_REPEAT:
1147 has_changed = true;
1148 switch( current )
1150 case Hue:
1151 hue = ( hue + 100 )%3600;
1152 break;
1153 case Saturation:
1154 if( saturation < 0xff - 8 ) saturation+=8;
1155 else saturation = 0xff;
1156 break;
1157 case Value:
1158 if( value < 0xff - 8 ) value+=8;
1159 else value = 0xff;
1160 break;
1161 case Red:
1162 if( red < 0xff - 8 ) red+=8;
1163 else red = 0xff;
1164 break;
1165 case Green:
1166 if( green < 0xff - 8 ) green+=8;
1167 else green = 0xff;
1168 break;
1169 case Blue:
1170 if( blue < 0xff - 8 ) blue+=8;
1171 else blue = 0xff;
1172 break;
1174 break;
1176 case ROCKPAINT_DRAW:
1177 return color;
1179 if( has_changed )
1181 switch( current )
1183 case Hue:
1184 case Saturation:
1185 case Value:
1186 hsv2rgb( hue, saturation, value, &red, &green, &blue );
1187 break;
1189 case Red:
1190 case Green:
1191 case Blue:
1192 rgb2hsv( red, green, blue, &hue, &saturation, &value );
1193 break;
1196 #undef HEIGHT
1197 #undef WIDTH
1201 /***********************************************************************
1202 * Misc routines
1203 ***********************************************************************/
1204 static void init_buffer(void)
1206 int i;
1207 fb_data color = rp_colors[ bgdrawcolor ];
1208 for( i = 0; i < ROWS*COLS; i++ )
1210 save_buffer[i] = color;
1214 static void draw_pixel(int x,int y)
1216 if( !preview )
1218 if( x < 0 || x >= COLS || y < 0 || y >= ROWS ) return;
1219 if( isbg )
1221 save_buffer[ x+y*COLS ] = rp_colors[bgdrawcolor];
1223 else
1225 save_buffer[ x+y*COLS ] = rp_colors[drawcolor];
1228 rb->lcd_drawpixel(x,y);
1231 static void color_picker( int x, int y )
1233 if( preview )
1235 rb->lcd_set_foreground( save_buffer[ x+y*COLS ] );
1236 #define PSIZE 12
1237 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1238 if( x >= COLS - PSIZE ) x -= PSIZE + 2;
1239 if( y >= ROWS - PSIZE ) y -= PSIZE + 2;
1240 rb->lcd_drawrect( x + 2, y + 2, PSIZE - 2, PSIZE - 2 );
1241 rb->lcd_set_drawmode(DRMODE_SOLID);
1242 rb->lcd_drawrect( x + 3, y + 3, PSIZE - 4, PSIZE - 4 );
1243 #undef PSIZE
1244 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1246 else
1248 rp_colors[ drawcolor ] = save_buffer[ x+y*COLS ];
1252 static void draw_select_rectangle( int x1, int y1, int x2, int y2 )
1253 /* This is a preview mode only function */
1255 int i,a;
1256 if( x1 > x2 )
1258 i = x1;
1259 x1 = x2;
1260 x2 = i;
1262 if( y1 > y2 )
1264 i = y1;
1265 y1 = y2;
1266 y2 = i;
1268 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1269 i = 0;
1270 for( a = x1; a < x2; a++, i++ )
1271 if( i%2 )
1272 rb->lcd_drawpixel( a, y1 );
1273 for( a = y1; a < y2; a++, i++ )
1274 if( i%2 )
1275 rb->lcd_drawpixel( x2, a );
1276 if( y2 != y1 )
1277 for( a = x2; a > x1; a--, i++ )
1278 if( i%2 )
1279 rb->lcd_drawpixel( a, y2 );
1280 if( x2 != x1 )
1281 for( a = y2; a > y1; a--, i++ )
1282 if( i%2 )
1283 rb->lcd_drawpixel( x1, a );
1284 rb->lcd_set_drawmode(DRMODE_SOLID);
1287 static void copy_to_clipboard( void )
1289 /* This needs to be optimised ... but i'm lazy ATM */
1290 rb->memcpy( buffer->clipboard, save_buffer, COLS*ROWS*sizeof( fb_data ) );
1293 /* no preview mode handling atm ... do we need it ? (one if) */
1294 static void draw_invert( int x1, int y1, int x2, int y2 )
1296 int i;
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;
1310 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1311 rb->lcd_fillrect( x1, y1, x2-x1+1, y2-y1+1 );
1312 rb->lcd_set_drawmode(DRMODE_SOLID);
1314 for( ; y1<=y2; y1++ )
1316 for( i = x1; i<=x2; i++ )
1318 save_buffer[ y1*COLS + i ] = ~save_buffer[ y1*COLS + i ];
1321 /*if( update )*/ rb->lcd_update();
1324 static void draw_hflip( int x1, int y1, int x2, int y2 )
1326 int i;
1327 if( x1 > x2 )
1329 i = x1;
1330 x1 = x2;
1331 x2 = i;
1333 if( y1 > y2 )
1335 i = y1;
1336 y1 = y2;
1337 y2 = i;
1340 copy_to_clipboard();
1342 for( i = 0; i <= y2 - y1; i++ )
1344 rb->memcpy( save_buffer+(y1+i)*COLS+x1,
1345 buffer->clipboard+(y2-i)*COLS+x1,
1346 (x2-x1+1)*sizeof( fb_data ) );
1348 restore_screen();
1349 rb->lcd_update();
1352 static void draw_vflip( int x1, int y1, int x2, int y2 )
1354 int i;
1355 if( x1 > x2 )
1357 i = x1;
1358 x1 = x2;
1359 x2 = i;
1361 if( y1 > y2 )
1363 i = y1;
1364 y1 = y2;
1365 y2 = i;
1368 copy_to_clipboard();
1370 for( ; y1 <= y2; y1++ )
1372 for( i = 0; i <= x2 - x1; i++ )
1374 save_buffer[y1*COLS+x1+i] = buffer->clipboard[y1*COLS+x2-i];
1377 restore_screen();
1378 rb->lcd_update();
1381 /* direction: -1 = left, 1 = right */
1382 static void draw_rot_90_deg( int x1, int y1, int x2, int y2, int direction )
1384 int i, j;
1385 if( x1 > x2 )
1387 i = x1;
1388 x1 = x2;
1389 x2 = i;
1391 if( y1 > y2 )
1393 i = y1;
1394 y1 = y2;
1395 y2 = i;
1398 copy_to_clipboard();
1400 fb_data color = rp_colors[ bgdrawcolor ];
1401 const int width = x2 - x1, height = y2 - y1;
1402 const int sub_half = width/2-height/2, add_half = (width+height)/2;
1403 if( width > height )
1405 for( i = 0; i <= height; i++ )
1407 for( j = 0; j < sub_half; j++ )
1408 save_buffer[(y1+i)*COLS+x1+j] = color;
1409 for( j = add_half+1; j <= width; j++ )
1410 save_buffer[(y1+i)*COLS+x1+j] = color;
1413 else if( width < height )
1415 for( j = 0; j <= width; j++ )
1417 for( i = 0; i < -sub_half; i++ )
1418 save_buffer[(y1+i)*COLS+x1+j] = color;
1419 for( i = add_half+1; i <= height; i++ )
1420 save_buffer[(y1+i)*COLS+x1+j] = color;
1423 int x3 = x1 + sub_half, y3 = y1 - sub_half;
1424 int is = x3<0?-x3:0, ie = COLS-x3-1, js = y3<0?-y3:0, je = ROWS-y3-1;
1425 if( ie > height ) ie = height;
1426 if( je > width ) je = width;
1427 for( i = is; i <= ie; i++ )
1429 for( j = js; j <= je; j++ )
1431 int x, y;
1432 if(direction > 0)
1434 x = x1+j;
1435 y = y1+height-i;
1437 else
1439 x = x1+width-j;
1440 y = y1+i;
1442 save_buffer[(y3+j)*COLS+x3+i] = buffer->clipboard[y*COLS+x];
1445 restore_screen();
1446 rb->lcd_update();
1449 static void draw_paste_rectangle( int src_x1, int src_y1, int src_x2,
1450 int src_y2, int x1, int y1, int mode )
1452 int i, width, height;
1453 if( mode == SELECT_MENU_CUT )
1455 i = drawcolor;
1456 drawcolor = bgdrawcolor;
1457 draw_rect_full( src_x1, src_y1, src_x2, src_y2 );
1458 drawcolor = i;
1460 if( src_x1 > src_x2 )
1462 i = src_x1;
1463 src_x1 = src_x2;
1464 src_x2 = i;
1466 if( src_y1 > src_y2 )
1468 i = src_y1;
1469 src_y1 = src_y2;
1470 src_y2 = i;
1472 width = src_x2 - src_x1 + 1;
1473 height = src_y2 - src_y1 + 1;
1474 /* clipping */
1475 if( x1 + width > COLS )
1476 width = COLS - x1;
1477 if( y1 + height > ROWS )
1478 height = ROWS - y1;
1480 rb->lcd_bitmap_part( buffer->clipboard, src_x1, src_y1, COLS,
1481 x1, y1, width, height );
1482 if( !preview )
1484 for( i = 0; i < height; i++ )
1486 rb->memcpy( save_buffer+(y1+i)*COLS+x1,
1487 buffer->clipboard+(src_y1+i)*COLS+src_x1,
1488 width*sizeof( fb_data ) );
1493 static void show_grid( bool update )
1495 int i;
1496 if( gridsize > 0 )
1498 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1499 for( i = gridsize; i < img_width; i+= gridsize )
1501 rb->lcd_vline( i, 0, img_height-1 );
1503 for( i = gridsize; i < img_height; i+= gridsize )
1505 rb->lcd_hline( 0, img_width-1, i );
1507 rb->lcd_set_drawmode(DRMODE_SOLID);
1508 if( update ) rb->lcd_update();
1512 static void draw_text( int x, int y )
1514 int selected = 0;
1515 buffer->text.text[0] = '\0';
1516 rb->snprintf( buffer->text.old_font, MAX_PATH,
1517 FONT_DIR "/%s.fnt",
1518 rb->global_settings->font_file );
1519 while( 1 )
1521 switch( rb->do_menu( &text_menu, &selected, NULL, NULL ) )
1523 case TEXT_MENU_TEXT:
1524 rb->lcd_set_foreground(COLOR_BLACK);
1525 rb->kbd_input( buffer->text.text, MAX_TEXT );
1526 break;
1528 case TEXT_MENU_FONT:
1529 if( browse_fonts( buffer->text.font, MAX_PATH ) )
1531 rb->font_load(NULL, buffer->text.font );
1533 break;
1535 case TEXT_MENU_PREVIEW:
1536 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1537 while( 1 )
1539 int button;
1540 restore_screen();
1541 rb->lcd_putsxy( x, y, buffer->text.text );
1542 rb->lcd_update();
1543 switch( button = rb->button_get( true ) )
1545 case ROCKPAINT_LEFT:
1546 case ROCKPAINT_LEFT | BUTTON_REPEAT:
1547 x-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1548 if (x<0) x=COLS-1;
1549 break;
1551 case ROCKPAINT_RIGHT:
1552 case ROCKPAINT_RIGHT | BUTTON_REPEAT:
1553 x+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1554 if (x>=COLS) x=0;
1555 break;
1557 case ROCKPAINT_UP:
1558 case ROCKPAINT_UP | BUTTON_REPEAT:
1559 y-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1560 if (y<0) y=ROWS-1;
1561 break;
1563 case ROCKPAINT_DOWN:
1564 case ROCKPAINT_DOWN | BUTTON_REPEAT:
1565 y+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
1566 if (y>=ROWS-1) y=0;
1567 break;
1569 case ROCKPAINT_DRAW:
1570 break;
1571 default:
1572 if(rb->default_event_handler(button)
1573 == SYS_USB_CONNECTED)
1574 button = ROCKPAINT_DRAW;
1575 break;
1577 if( button == ROCKPAINT_DRAW ) break;
1579 break;
1581 case TEXT_MENU_APPLY:
1582 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1583 buffer_putsxyofs( save_buffer, COLS, ROWS, x, y, 0,
1584 buffer->text.text );
1585 case TEXT_MENU_CANCEL:
1586 default:
1587 restore_screen();
1588 rb->font_load(NULL, buffer->text.old_font );
1589 return;
1594 static void draw_brush( int x, int y )
1596 int i,j;
1597 for( i=-bsize/2+(bsize+1)%2; i<=bsize/2; i++ )
1599 for( j=-bsize/2+(bsize+1)%2; j<=bsize/2; j++ )
1601 draw_pixel( x+i, y+j );
1606 /* This is an implementation of Bresenham's line algorithm.
1607 * See http://en.wikipedia.org/wiki/Bresenham%27s_line_algorithm.
1609 static void draw_line( int x1, int y1, int x2, int y2 )
1611 int x = x1;
1612 int y = y1;
1613 int deltax = x2 - x1;
1614 int deltay = y2 - y1;
1615 int i;
1617 int xerr = abs(deltax);
1618 int yerr = abs(deltay);
1619 int xstep = deltax > 0 ? 1 : -1;
1620 int ystep = deltay > 0 ? 1 : -1;
1621 int err;
1623 if (yerr > xerr)
1625 /* more vertical */
1626 err = yerr;
1627 xerr <<= 1;
1628 yerr <<= 1;
1630 /* to leave off the last pixel of the line, leave off the "+ 1" */
1631 for (i = abs(deltay) + 1; i; --i)
1633 draw_pixel(x, y);
1634 y += ystep;
1635 err -= xerr;
1636 if (err < 0) {
1637 x += xstep;
1638 err += yerr;
1642 else
1644 /* more horizontal */
1645 err = xerr;
1646 xerr <<= 1;
1647 yerr <<= 1;
1649 for (i = abs(deltax) + 1; i; --i)
1651 draw_pixel(x, y);
1652 x += xstep;
1653 err -= yerr;
1654 if (err < 0) {
1655 y += ystep;
1656 err += xerr;
1662 static void draw_curve( int x1, int y1, int x2, int y2,
1663 int xa, int ya, int xb, int yb )
1665 int i = 0;
1666 short xl1, yl1;
1667 short xl2, yl2;
1668 short xl3, yl3;
1669 short xl4, yl4;
1670 short xr1, yr1;
1671 short xr2, yr2;
1672 short xr3, yr3;
1673 short xr4, yr4;
1674 short depth;
1675 short xh, yh;
1677 if( x1 == x2 && y1 == y2 )
1679 draw_pixel( x1, y1 );
1680 return;
1683 // if( preview )
1685 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
1686 if( xa == -1 || ya == -1 )
1688 rb->lcd_drawline( x1, y1, xb, yb );
1689 rb->lcd_drawline( x2, y2, xb, yb );
1691 else
1693 rb->lcd_drawline( x1, y1, xa, ya );
1694 rb->lcd_drawline( x2, y2, xb, yb );
1696 rb->lcd_set_drawmode(DRMODE_SOLID);
1699 if( xa == -1 || ya == -1 )
1700 /* We only have 3 of the points
1701 * This will currently only be used in preview mode */
1703 #define PUSH( a1, b1, a2, b2, a3, b3, d ) \
1704 buffer->bezier[i].x1 = a1; \
1705 buffer->bezier[i].y1 = b1; \
1706 buffer->bezier[i].x2 = a2; \
1707 buffer->bezier[i].y2 = b2; \
1708 buffer->bezier[i].x3 = a3; \
1709 buffer->bezier[i].y3 = b3; \
1710 buffer->bezier[i].depth = d; \
1711 i++;
1712 #define POP( a1, b1, a2, b2, a3, b3, d ) \
1713 i--; \
1714 a1 = buffer->bezier[i].x1; \
1715 b1 = buffer->bezier[i].y1; \
1716 a2 = buffer->bezier[i].x2; \
1717 b2 = buffer->bezier[i].y2; \
1718 a3 = buffer->bezier[i].x3; \
1719 b3 = buffer->bezier[i].y3; \
1720 d = buffer->bezier[i].depth;
1721 PUSH( x1<<4, y1<<4, xb<<4, yb<<4, x2<<4, y2<<4, 0 );
1722 while( i )
1724 /* de Casteljau's algorithm (see wikipedia) */
1725 POP( xl1, yl1, xb, yb, xr3, yr3, depth );
1726 if( depth < 10 ) /* check that the stack's 'i' doesn't overflow */
1728 xl2 = ( xl1 + xb )>>1;
1729 yl2 = ( yl1 + yb )>>1;
1730 xr2 = ( xb + xr3 )>>1;
1731 yr2 = ( yb + yr3 )>>1;
1732 xr1 = ( xl2 + xr2 )>>1;
1733 yr1 = ( yl2 + yr2 )>>1;
1734 xl3 = xr1;
1735 yl3 = yr1;
1736 PUSH( xl1, yl1, xl2, yl2, xl3, yl3, depth+1 );
1737 PUSH( xr1, yr1, xr2, yr2, xr3, yr3, depth+1 );
1739 else
1741 draw_line( ((xl1>>3)+1)>>1, ((yl1>>3)+1)>>1,
1742 ((xr3>>3)+1)>>1, ((yr3>>3)+1)>>1 );
1745 #undef PUSH
1746 #undef POP
1748 else /* We have the 4 points */
1750 #define PUSH( a1, b1, a2, b2, a3, b3, a4, b4, d ) \
1751 buffer->bezier[i].x1 = a1; \
1752 buffer->bezier[i].y1 = b1; \
1753 buffer->bezier[i].x2 = a2; \
1754 buffer->bezier[i].y2 = b2; \
1755 buffer->bezier[i].x3 = a3; \
1756 buffer->bezier[i].y3 = b3; \
1757 buffer->bezier[i].x4 = a4; \
1758 buffer->bezier[i].y4 = b4; \
1759 buffer->bezier[i].depth = d; \
1760 i++;
1761 #define POP( a1, b1, a2, b2, a3, b3, a4, b4, d ) \
1762 i--; \
1763 a1 = buffer->bezier[i].x1; \
1764 b1 = buffer->bezier[i].y1; \
1765 a2 = buffer->bezier[i].x2; \
1766 b2 = buffer->bezier[i].y2; \
1767 a3 = buffer->bezier[i].x3; \
1768 b3 = buffer->bezier[i].y3; \
1769 a4 = buffer->bezier[i].x4; \
1770 b4 = buffer->bezier[i].y4; \
1771 d = buffer->bezier[i].depth;
1773 PUSH( x1<<4, y1<<4, xa<<4, ya<<4, xb<<4, yb<<4, x2<<4, y2<<4, 0 );
1774 while( i )
1776 /* de Casteljau's algorithm (see wikipedia) */
1777 POP( xl1, yl1, xa, ya, xb, yb, xr4, yr4, depth );
1778 if( depth < 10 ) /* check that the stack's 'i' doesn't overflow */
1780 xl2 = ( xl1 + xa )>>1;
1781 yl2 = ( yl1 + ya )>>1;
1782 xh = ( xa + xb )>>1;
1783 yh = ( ya + yb )>>1;
1784 xr3 = ( xb + xr4 )>>1;
1785 yr3 = ( yb + yr4 )>>1;
1786 xl3 = ( xl2 + xh )>>1;
1787 yl3 = ( yl2 + yh )>>1;
1788 xr2 = ( xr3 + xh )>>1;
1789 yr2 = ( yr3 + yh )>>1;
1790 xl4 = ( xl3 + xr2 )>>1;
1791 yl4 = ( yl3 + yr2 )>>1;
1792 xr1 = xl4;
1793 yr1 = yl4;
1794 PUSH( xl1, yl1, xl2, yl2, xl3, yl3, xl4, yl4, depth+1 );
1795 PUSH( xr1, yr1, xr2, yr2, xr3, yr3, xr4, yr4, depth+1 );
1797 else
1799 draw_line( ((xl1>>3)+1)>>1, ((yl1>>3)+1)>>1,
1800 ((xr4>>3)+1)>>1, ((yr4>>3)+1)>>1 );
1803 #undef PUSH
1804 #undef POP
1808 static void draw_rect( int x1, int y1, int x2, int y2 )
1810 draw_line( x1, y1, x1, y2 );
1811 draw_line( x1, y1, x2, y1 );
1812 draw_line( x1, y2, x2, y2 );
1813 draw_line( x2, y1, x2, y2 );
1816 static void togglebg( void )
1818 if( isbg )
1820 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
1822 else
1824 rb->lcd_set_foreground( rp_colors[ bgdrawcolor ] );
1826 isbg = !isbg;
1829 static void draw_rect_full( int x1, int y1, int x2, int y2 )
1831 /* GRUIK */
1832 int x;
1833 togglebg();
1834 if( x1 > x2 )
1836 x = x1;
1837 x1 = x2;
1838 x2 = x;
1840 x = x1;
1841 do {
1842 draw_line( x, y1, x, y2 );
1843 } while( ++x <= x2 );
1844 togglebg();
1845 draw_rect( x1, y1, x2, y2 );
1848 static void draw_oval( int x1, int y1, int x2, int y2, bool full )
1850 /* TODO: simplify :) */
1851 int cx = (x1+x2)>>1;
1852 int cy = (y1+y2)>>1;
1854 int rx = (x1-x2)>>1;
1855 int ry = (y1-y2)>>1;
1856 if( rx < 0 ) rx *= -1;
1857 if( ry < 0 ) ry *= -1;
1859 if( rx == 0 || ry == 0 )
1861 draw_line( x1, y1, x2, y2 );
1862 return;
1865 int x,y;
1866 int dst, old_dst;
1868 for( x = 0; x < rx; x++ )
1870 y = 0;
1871 dst = -0xfff;
1872 do {
1873 old_dst = dst;
1874 dst = ry * ry * x * x + rx * rx * y * y - rx * rx * ry * ry;
1875 y++;
1876 } while( dst < 0 );
1877 if( -old_dst < dst ) y--;
1878 if( full )
1880 draw_line( cx+x, cy, cx+x, cy+y );
1881 draw_line( cx+x, cy, cx+x, cy-y );
1882 draw_line( cx-x, cy, cx-x, cy+y );
1883 draw_line( cx-x, cy, cx-x, cy-y );
1885 else
1887 draw_pixel( cx+x, cy+y );
1888 draw_pixel( cx+x, cy-y );
1889 draw_pixel( cx-x, cy+y );
1890 draw_pixel( cx-x, cy-y );
1893 for( y = 0; y < ry; y++ )
1895 x = 0;
1896 dst = -0xfff;
1897 do {
1898 old_dst = dst;
1899 dst = ry * ry * x * x + rx * rx * y * y - rx * rx * ry * ry;
1900 x++;
1901 } while( dst < 0 );
1902 if( -old_dst < dst ) x--;
1903 if( full )
1905 draw_line( cx+x, cy, cx+x, cy+y );
1906 draw_line( cx+x, cy, cx+x, cy-y );
1907 draw_line( cx-x, cy, cx-x, cy+y );
1908 draw_line( cx-x, cy, cx-x, cy-y );
1910 else
1912 draw_pixel( cx+x, cy+y );
1913 draw_pixel( cx+x, cy-y );
1914 draw_pixel( cx-x, cy+y );
1915 draw_pixel( cx-x, cy-y );
1920 static void draw_oval_empty( int x1, int y1, int x2, int y2 )
1922 draw_oval( x1, y1, x2, y2, false );
1925 static void draw_oval_full( int x1, int y1, int x2, int y2 )
1927 togglebg();
1928 draw_oval( x1, y1, x2, y2, true );
1929 togglebg();
1930 draw_oval( x1, y1, x2, y2, false );
1933 static void draw_fill( int x0, int y0 )
1935 #define PUSH( a, b ) \
1936 draw_pixel( (int)a, (int)b ); \
1937 buffer->coord[i].x = a; \
1938 buffer->coord[i].y = b; \
1939 i++;
1940 #define POP( a, b ) \
1941 i--; \
1942 a = buffer->coord[i].x; \
1943 b = buffer->coord[i].y;
1945 unsigned int i=0;
1946 short x = x0;
1947 short y = y0;
1948 unsigned int prev_color = save_buffer[ x0+y0*COLS ];
1950 if( prev_color == rp_colors[ drawcolor ] ) return;
1952 PUSH( x, y );
1954 while( i != 0 )
1956 POP( x, y );
1957 if( x > 0 && save_buffer[x-1+y*COLS] == prev_color )
1959 PUSH( x-1, y );
1961 if( x < COLS-1 && save_buffer[x+1+y*COLS] == prev_color )
1963 PUSH( x+1, y );
1965 if( y > 0 && save_buffer[x+(y-1)*COLS] == prev_color )
1967 PUSH( x, y-1 );
1969 if( y < ROWS - 1 && save_buffer[x+(y+1)*COLS] == prev_color )
1971 PUSH( x, y+1 );
1974 #undef PUSH
1975 #undef POP
1979 /* For preview purposes only */
1980 static void line_gradient( int x1, int y1, int x2, int y2 )
1982 int r1, g1, b1;
1983 int r2, g2, b2;
1984 int h1, s1, v1, h2, s2, v2, r, g, b;
1985 int w, h, x, y;
1987 bool a = false;
1989 x1 <<= 1;
1990 y1 <<= 1;
1991 x2 <<= 1;
1992 y2 <<= 1;
1994 w = x1 - x2;
1995 h = y1 - y2;
1997 if( w == 0 && h == 0 )
1999 draw_pixel( x1>>1, y1>>1 );
2000 return;
2003 r1 = RGB_UNPACK_RED( rp_colors[ bgdrawcolor ] );
2004 g1 = RGB_UNPACK_GREEN( rp_colors[ bgdrawcolor ] );
2005 b1 = RGB_UNPACK_BLUE( rp_colors[ bgdrawcolor ] );
2006 r2 = RGB_UNPACK_RED( rp_colors[ drawcolor ] );
2007 g2 = RGB_UNPACK_GREEN( rp_colors[ drawcolor ] );
2008 b2 = RGB_UNPACK_BLUE( rp_colors[ drawcolor ] );
2010 if( w < 0 )
2012 w *= -1;
2013 a = true;
2015 if( h < 0 )
2017 h *= -1;
2018 a = !a;
2020 if( a )
2022 r = r1;
2023 r1 = r2;
2024 r2 = r;
2025 g = g1;
2026 g1 = g2;
2027 g2 = g;
2028 b = b1;
2029 b1 = b2;
2030 b2 = b;
2033 rgb2hsv( r1, g1, b1, &h1, &s1, &v1 );
2034 rgb2hsv( r2, g2, b2, &h2, &s2, &v2 );
2036 if( w > h )
2038 if( x1 > x2 )
2040 x = x2;
2041 y = y2;
2042 x2 = x1;
2043 y2 = y1;
2044 x1 = x;
2045 y1 = y;
2047 w = x1 - x2;
2048 h = y1 - y2;
2049 while( x1 <= x2 )
2051 hsv2rgb( h1+((h2-h1)*(x1-x2))/w,
2052 s1+((s2-s1)*(x1-x2))/w,
2053 v1+((v2-v1)*(x1-x2))/w,
2054 &r, &g, &b );
2055 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2056 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2057 draw_pixel( (x1+1)>>1, (y1+1)>>1 );
2058 x1+=2;
2059 y1 = y2 - ( x2 - x1 ) * h / w;
2062 else /* h > w */
2064 if( y1 > y2 )
2066 x = x2;
2067 y = y2;
2068 x2 = x1;
2069 y2 = y1;
2070 x1 = x;
2071 y1 = y;
2073 w = x1 - x2;
2074 h = y1 - y2;
2075 while( y1 <= y2 )
2077 hsv2rgb( h1+((h2-h1)*(y1-y2))/h,
2078 s1+((s2-s1)*(y1-y2))/h,
2079 v1+((v2-v1)*(y1-y2))/h,
2080 &r, &g, &b );
2081 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2082 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2083 draw_pixel( (x1+1)>>1, (y1+1)>>1 );
2084 y1+=2;
2085 x1 = x2 - ( y2 - y1 ) * w / h;
2088 if( a )
2090 rp_colors[ drawcolor ] = LCD_RGBPACK( r1, g1, b1 );
2092 else
2094 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2098 static void linear_gradient( int x1, int y1, int x2, int y2 )
2100 int r1 = RGB_UNPACK_RED( rp_colors[ bgdrawcolor ] );
2101 int g1 = RGB_UNPACK_GREEN( rp_colors[ bgdrawcolor ] );
2102 int b1 = RGB_UNPACK_BLUE( rp_colors[ bgdrawcolor ] );
2103 int r2 = RGB_UNPACK_RED( rp_colors[ drawcolor ] );
2104 int g2 = RGB_UNPACK_GREEN( rp_colors[ drawcolor ] );
2105 int b2 = RGB_UNPACK_BLUE( rp_colors[ drawcolor ] );
2107 int h1, s1, v1, h2, s2, v2, r, g, b;
2109 /* radius^2 */
2110 int radius2 = ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 );
2111 int dist2, i=0;
2113 /* We only propagate the gradient to neighboring pixels with the same
2114 * color as ( x1, y1 ) */
2115 unsigned int prev_color = save_buffer[ x1+y1*COLS ];
2117 int x = x1;
2118 int y = y1;
2120 if( radius2 == 0 ) return;
2121 if( preview )
2123 line_gradient( x1, y1, x2, y2 );
2126 rgb2hsv( r1, g1, b1, &h1, &s1, &v1 );
2127 rgb2hsv( r2, g2, b2, &h2, &s2, &v2 );
2129 #define PUSH( x0, y0 ) \
2130 buffer->coord[i].x = (short)(x0); \
2131 buffer->coord[i].y = (short)(y0); \
2132 i++;
2133 #define POP( a, b ) \
2134 i--; \
2135 a = (int)buffer->coord[i].x; \
2136 b = (int)buffer->coord[i].y;
2138 PUSH( x, y );
2140 while( i != 0 )
2142 POP( x, y );
2144 dist2 = ( x2 - x1 ) * ( x - x1 ) + ( y2 - y1 ) * ( y - y1 );
2145 if( dist2 <= 0 )
2147 rp_colors[ drawcolor ] = rp_colors[ bgdrawcolor ];
2149 else if( dist2 < radius2 )
2151 hsv2rgb( h1+((h2-h1)*dist2)/radius2,
2152 s1+((s2-s1)*dist2)/radius2,
2153 v1+((v2-v1)*dist2)/radius2,
2154 &r, &g, &b );
2155 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2157 else
2159 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2161 if( rp_colors[ drawcolor ] == prev_color )
2163 if( rp_colors[ drawcolor ])
2164 rp_colors[ drawcolor ]--; /* GRUIK */
2165 else
2166 rp_colors[ drawcolor ]++; /* GRUIK */
2168 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2169 draw_pixel( x, y );
2171 if( x > 0 && save_buffer[x-1+y*COLS] == prev_color )
2173 PUSH( x-1, y );
2175 if( x < COLS-1 && save_buffer[x+1+y*COLS] == prev_color )
2177 PUSH( x+1, y );
2179 if( y > 0 && save_buffer[x+(y-1)*COLS] == prev_color )
2181 PUSH( x, y-1 );
2183 if( y < ROWS - 1 && save_buffer[x+(y+1)*COLS] == prev_color )
2185 PUSH( x, y+1 );
2188 #undef PUSH
2189 #undef POP
2191 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2194 static void radial_gradient( int x1, int y1, int x2, int y2 )
2196 int r1 = RGB_UNPACK_RED( rp_colors[ bgdrawcolor ] );
2197 int g1 = RGB_UNPACK_GREEN( rp_colors[ bgdrawcolor ] );
2198 int b1 = RGB_UNPACK_BLUE( rp_colors[ bgdrawcolor ] );
2199 int r2 = RGB_UNPACK_RED( rp_colors[ drawcolor ] );
2200 int g2 = RGB_UNPACK_GREEN( rp_colors[ drawcolor ] );
2201 int b2 = RGB_UNPACK_BLUE( rp_colors[ drawcolor ] );
2203 int h1, s1, v1, h2, s2, v2, r, g, b;
2205 /* radius^2 */
2206 int radius2 = ( x1 - x2 ) * ( x1 - x2 ) + ( y1 - y2 ) * ( y1 - y2 );
2207 int dist2, i=0;
2209 /* We only propagate the gradient to neighboring pixels with the same
2210 * color as ( x1, y1 ) */
2211 unsigned int prev_color = save_buffer[ x1+y1*COLS ];
2213 int x = x1;
2214 int y = y1;
2216 if( radius2 == 0 ) return;
2217 if( preview )
2219 line_gradient( x1, y1, x2, y2 );
2222 rgb2hsv( r1, g1, b1, &h1, &s1, &v1 );
2223 rgb2hsv( r2, g2, b2, &h2, &s2, &v2 );
2225 #define PUSH( x0, y0 ) \
2226 buffer->coord[i].x = (short)(x0); \
2227 buffer->coord[i].y = (short)(y0); \
2228 i++;
2229 #define POP( a, b ) \
2230 i--; \
2231 a = (int)buffer->coord[i].x; \
2232 b = (int)buffer->coord[i].y;
2234 PUSH( x, y );
2236 while( i != 0 )
2238 POP( x, y );
2240 if( ( dist2 = (x1-(x))*(x1-(x))+(y1-(y))*(y1-(y)) ) < radius2 )
2242 hsv2rgb( h1+((h2-h1)*dist2)/radius2,
2243 s1+((s2-s1)*dist2)/radius2,
2244 v1+((v2-v1)*dist2)/radius2,
2245 &r, &g, &b );
2246 rp_colors[ drawcolor ] = LCD_RGBPACK( r, g, b );
2248 else
2250 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2252 if( rp_colors[ drawcolor ] == prev_color )
2254 if( rp_colors[ drawcolor ])
2255 rp_colors[ drawcolor ]--; /* GRUIK */
2256 else
2257 rp_colors[ drawcolor ]++; /* GRUIK */
2259 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2260 draw_pixel( x, y );
2262 if( x > 0 && save_buffer[x-1+y*COLS] == prev_color )
2264 PUSH( x-1, y );
2266 if( x < COLS-1 && save_buffer[x+1+y*COLS] == prev_color )
2268 PUSH( x+1, y );
2270 if( y > 0 && save_buffer[x+(y-1)*COLS] == prev_color )
2272 PUSH( x, y-1 );
2274 if( y < ROWS - 1 && save_buffer[x+(y+1)*COLS] == prev_color )
2276 PUSH( x, y+1 );
2279 #undef PUSH
2280 #undef POP
2282 rp_colors[ drawcolor ] = LCD_RGBPACK( r2, g2, b2 );
2285 static void draw_toolbars(bool update)
2287 int i;
2288 #define TOP (LCD_HEIGHT-TB_HEIGHT)
2289 rb->lcd_set_background( COLOR_LIGHTGRAY );
2290 rb->lcd_set_foreground( COLOR_LIGHTGRAY );
2291 rb->lcd_fillrect( 0, TOP, LCD_WIDTH, TB_HEIGHT );
2292 rb->lcd_set_foreground( COLOR_BLACK );
2293 rb->lcd_drawrect( 0, TOP, LCD_WIDTH, TB_HEIGHT );
2295 rb->lcd_set_foreground( rp_colors[ bgdrawcolor ] );
2296 rb->lcd_fillrect( TB_SC_BG_LEFT, TOP+TB_SC_BG_TOP,
2297 TB_SC_SIZE, TB_SC_SIZE );
2298 rb->lcd_set_foreground(ROCKPAINT_PALETTE);
2299 rb->lcd_drawrect( TB_SC_BG_LEFT, TOP+TB_SC_BG_TOP,
2300 TB_SC_SIZE, TB_SC_SIZE );
2301 rb->lcd_set_foreground( rp_colors[ drawcolor ] );
2302 rb->lcd_fillrect( TB_SC_FG_LEFT, TOP+TB_SC_FG_TOP,
2303 TB_SC_SIZE, TB_SC_SIZE );
2304 rb->lcd_set_foreground(ROCKPAINT_PALETTE);
2305 rb->lcd_drawrect( TB_SC_FG_LEFT, TOP+TB_SC_FG_TOP,
2306 TB_SC_SIZE, TB_SC_SIZE );
2308 for( i=0; i<18; i++ )
2310 rb->lcd_set_foreground( rp_colors[i] );
2311 rb->lcd_fillrect(
2312 TB_PL_LEFT+(i%9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING ),
2313 TOP+TB_PL_TOP+(i/9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING),
2314 TB_PL_COLOR_SIZE, TB_PL_COLOR_SIZE );
2315 rb->lcd_set_foreground( ROCKPAINT_PALETTE );
2316 rb->lcd_drawrect(
2317 TB_PL_LEFT+(i%9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING ),
2318 TOP+TB_PL_TOP+(i/9)*( TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING),
2319 TB_PL_COLOR_SIZE, TB_PL_COLOR_SIZE );
2322 #define SEPARATOR( x, y ) \
2323 rb->lcd_set_foreground( COLOR_WHITE ); \
2324 rb->lcd_vline( x, TOP+y, TOP+y+TB_PL_HEIGHT-1 ); \
2325 rb->lcd_set_foreground( COLOR_DARKGRAY ); \
2326 rb->lcd_vline( x+1, TOP+y, TOP+y+TB_PL_HEIGHT-1 );
2327 SEPARATOR( TB_PL_LEFT + TB_PL_WIDTH - 1 + TB_SP_MARGIN, TB_PL_TOP );
2329 rb->lcd_bitmap_transparent( rockpaint, TB_TL_LEFT, TOP+TB_TL_TOP,
2330 TB_TL_WIDTH, TB_TL_HEIGHT );
2331 rb->lcd_set_foreground(ROCKPAINT_PALETTE);
2332 rb->lcd_drawrect( TB_TL_LEFT+(TB_TL_SIZE+TB_TL_SPACING)*(tool/2),
2333 TOP+TB_TL_TOP+(TB_TL_SIZE+TB_TL_SPACING)*(tool%2),
2334 TB_TL_SIZE, TB_TL_SIZE );
2336 SEPARATOR( TB_TL_LEFT + TB_TL_WIDTH - 1 + TB_SP_MARGIN, TB_TL_TOP );
2338 rb->lcd_setfont( FONT_SYSFIXED );
2339 rb->lcd_putsxy( TB_MENU_LEFT, TOP+TB_MENU_TOP, "Menu" );
2340 rb->lcd_setfont( FONT_UI );
2341 #undef TOP
2343 if( update ) rb->lcd_update();
2346 static void toolbar( void )
2348 int button, i, j;
2349 restore_screen();
2350 draw_toolbars( false );
2351 y = LCD_HEIGHT-TB_HEIGHT/2;
2352 inv_cursor( true );
2353 while( 1 )
2355 switch( button = rb->button_get( true ) )
2357 case ROCKPAINT_DRAW:
2358 #define TOP ( LCD_HEIGHT - TB_HEIGHT )
2359 if( y >= TOP + TB_SC_FG_TOP
2360 && y < TOP + TB_SC_FG_TOP + TB_SC_SIZE
2361 && x >= TB_SC_FG_LEFT
2362 && x < TB_SC_FG_LEFT + TB_SC_SIZE )
2364 /* click on the foreground color */
2365 rp_colors[drawcolor] = color_chooser( rp_colors[drawcolor] );
2367 else if( y >= TOP + TB_SC_BG_TOP
2368 && y < TOP + TB_SC_BG_TOP + TB_SC_SIZE
2369 && x >= TB_SC_BG_LEFT
2370 && x < TB_SC_BG_LEFT + TB_SC_SIZE )
2372 /* click on the background color */
2373 i = drawcolor;
2374 drawcolor = bgdrawcolor;
2375 bgdrawcolor = i;
2377 else if( y >= TOP + TB_PL_TOP
2378 && y < TOP + TB_PL_TOP + TB_PL_HEIGHT
2379 && x >= TB_PL_LEFT
2380 && x < TB_PL_LEFT + TB_PL_WIDTH )
2382 /* click on the palette */
2383 i = (x - TB_PL_LEFT)%(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2384 j = (y - (TOP+TB_PL_TOP) )%(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2385 if( i >= TB_PL_COLOR_SIZE || j >= TB_PL_COLOR_SIZE )
2386 break;
2387 i = ( x - TB_PL_LEFT )/(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2388 j = ( y - (TOP+TB_PL_TOP) )/(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING);
2389 drawcolor = j*(TB_PL_COLOR_SIZE+TB_PL_COLOR_SPACING)+i;
2391 else if( y >= TOP+TB_TL_TOP
2392 && y < TOP + TB_TL_TOP + TB_TL_HEIGHT
2393 && x >= TB_TL_LEFT
2394 && x <= TB_TL_LEFT + TB_TL_WIDTH )
2396 /* click on the tools */
2397 i = (x - TB_TL_LEFT ) % (TB_TL_SIZE+TB_TL_SPACING);
2398 j = (y - (TOP+TB_TL_TOP) ) %(TB_TL_SIZE+TB_TL_SPACING);
2399 if( i >= TB_TL_SIZE || j >= TB_TL_SIZE ) break;
2400 i = ( x - TB_TL_LEFT )/(TB_TL_SIZE+TB_TL_SPACING);
2401 j = ( y - (TOP+TB_TL_TOP) )/(TB_TL_SIZE+TB_TL_SPACING);
2402 tool = i*2+j;
2403 prev_x = -1;
2404 prev_y = -1;
2405 prev_x2 = -1;
2406 prev_y2 = -1;
2407 prev_x3 = -1;
2408 prev_y3 = -1;
2409 preview = false;
2411 else if( x >= TB_MENU_LEFT && y >= TOP+TB_MENU_TOP-2)
2413 /* menu button */
2414 goto_menu();
2416 #undef TOP
2417 restore_screen();
2418 draw_toolbars( false );
2419 inv_cursor( true );
2420 break;
2422 case ROCKPAINT_LEFT:
2423 case ROCKPAINT_LEFT | BUTTON_REPEAT:
2424 inv_cursor(false);
2425 x-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2426 if (x<0) x=COLS-1;
2427 inv_cursor(true);
2428 break;
2430 case ROCKPAINT_RIGHT:
2431 case ROCKPAINT_RIGHT | BUTTON_REPEAT:
2432 inv_cursor(false);
2433 x+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2434 if (x>=COLS) x=0;
2435 inv_cursor(true);
2436 break;
2438 case ROCKPAINT_UP:
2439 case ROCKPAINT_UP | BUTTON_REPEAT:
2440 inv_cursor(false);
2441 y-=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2442 if (y<LCD_HEIGHT-TB_HEIGHT)
2444 return;
2446 inv_cursor(true);
2447 break;
2449 case ROCKPAINT_DOWN:
2450 case ROCKPAINT_DOWN | BUTTON_REPEAT:
2451 inv_cursor(false);
2452 y+=bspeed * ( button & BUTTON_REPEAT ? 4 : 1 );
2453 if (y>=LCD_HEIGHT)
2455 y = 0;
2456 return;
2458 inv_cursor(true);
2459 break;
2461 case ROCKPAINT_TOOLBAR:
2462 case ROCKPAINT_TOOLBAR2:
2463 return;
2465 if( quit ) return;
2469 static void inv_cursor(bool update)
2471 rb->lcd_set_foreground(COLOR_BLACK);
2472 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
2473 /* cross painting */
2474 rb->lcd_hline(x-4,x+4,y);
2475 rb->lcd_vline(x,y-4,y+4);
2476 rb->lcd_set_foreground(rp_colors[drawcolor]);
2477 rb->lcd_set_drawmode(DRMODE_SOLID);
2479 if( update ) rb->lcd_update();
2482 static void restore_screen(void)
2484 rb->lcd_bitmap( save_buffer, 0, 0, COLS, ROWS );
2485 rb->lcd_set_drawmode(DRMODE_COMPLEMENT);
2486 rb->lcd_vline( img_width, 0, ROWS );
2487 rb->lcd_hline( 0, COLS, img_height );
2488 rb->lcd_drawpixel( img_width, img_height );
2489 rb->lcd_set_drawmode(DRMODE_SOLID);
2492 static void clear_drawing(void)
2494 init_buffer();
2495 img_height = ROWS;
2496 img_width = COLS;
2497 rb->lcd_set_foreground( rp_colors[ bgdrawcolor ] );
2498 rb->lcd_fillrect( 0, 0, COLS, ROWS );
2499 rb->lcd_update();
2502 static void goto_menu(void)
2504 int multi;
2505 int selected = 0;
2507 while( 1 )
2509 switch( rb->do_menu( &main_menu, &selected, NULL, false ) )
2511 case MAIN_MENU_NEW:
2512 clear_drawing();
2513 return;
2515 case MAIN_MENU_LOAD:
2516 if( browse( filename, MAX_PATH, "/" ) )
2518 if( load_bitmap( filename ) <= 0 )
2520 rb->splashf( 1*HZ, "Error while loading %s",
2521 filename );
2522 clear_drawing();
2524 else
2526 rb->splashf( 1*HZ, "Image loaded (%s)", filename );
2527 restore_screen();
2528 inv_cursor(true);
2529 return;
2532 break;
2534 case MAIN_MENU_SAVE:
2535 rb->lcd_set_foreground(COLOR_BLACK);
2536 if (!filename[0])
2537 rb->strcpy(filename,"/");
2538 if( !rb->kbd_input( filename, MAX_PATH ) )
2540 if( !check_extention( filename, ".bmp" ) )
2541 rb->strcat(filename, ".bmp");
2542 save_bitmap( filename );
2543 rb->splashf( 1*HZ, "File saved (%s)", filename );
2545 break;
2547 case MAIN_MENU_SET_WIDTH:
2548 rb->set_int( "Set Width", "px", UNIT_INT, &img_width,
2549 NULL, 1, 1, COLS, NULL );
2550 break;
2551 case MAIN_MENU_SET_HEIGHT:
2552 rb->set_int( "Set Height", "px", UNIT_INT, &img_height,
2553 NULL, 1, 1, ROWS, NULL );
2554 break;
2555 case MAIN_MENU_BRUSH_SIZE:
2556 for(multi = 0; multi<4; multi++)
2557 if(bsize == times_list[multi]) break;
2558 rb->set_option( "Brush Size", &multi, INT, times_options, 4, NULL );
2559 if( multi >= 0 )
2560 bsize = times_list[multi];
2561 break;
2563 case MAIN_MENU_BRUSH_SPEED:
2564 for(multi = 0; multi<3; multi++)
2565 if(bspeed == times_list[multi]) break;
2566 rb->set_option( "Brush Speed", &multi, INT, times_options, 3, NULL );
2567 if( multi >= 0 )
2568 bspeed = times_list[multi];
2569 break;
2571 case MAIN_MENU_COLOR:
2572 rp_colors[drawcolor] = color_chooser( rp_colors[drawcolor] );
2573 break;
2575 case MAIN_MENU_GRID_SIZE:
2576 for(multi = 0; multi<4; multi++)
2577 if(gridsize == gridsize_list[multi]) break;
2578 rb->set_option( "Grid Size", &multi, INT, gridsize_options, 4, NULL );
2579 if( multi >= 0 )
2580 gridsize = gridsize_list[multi];
2581 break;
2583 case MAIN_MENU_PLAYBACK_CONTROL:
2584 playback_control( NULL );
2585 break;
2587 case MAIN_MENU_EXIT:
2588 restore_screen();
2589 quit=true;
2590 return;
2592 case MAIN_MENU_RESUME:
2593 default:
2594 restore_screen();
2595 return;
2596 }/* end switch */
2597 }/* end while */
2600 static void reset_tool( void )
2602 prev_x = -1;
2603 prev_y = -1;
2604 prev_x2 = -1;
2605 prev_y2 = -1;
2606 prev_x3 = -1;
2607 prev_y3 = -1;
2608 tool_mode = -1;
2609 preview = false;
2612 static bool rockpaint_loop( void )
2614 int button=0,i,j;
2615 int accelaration;
2617 x = 10;
2618 toolbar();
2619 x = 0; y = 0;
2620 restore_screen();
2621 inv_cursor(true);
2623 while (!quit) {
2624 button = rb->button_get(true);
2626 if( tool == Brush && prev_x != -1 )
2628 accelaration = 1;
2630 else if( button & BUTTON_REPEAT )
2632 accelaration = 4;
2634 else
2636 accelaration = 1;
2639 switch(button)
2641 case ROCKPAINT_QUIT:
2642 rb->lcd_set_drawmode(DRMODE_SOLID);
2643 return PLUGIN_OK;
2645 case ROCKPAINT_MENU:
2646 inv_cursor(false);
2647 goto_menu();
2648 restore_screen();
2649 inv_cursor(true);
2650 break;
2652 case ROCKPAINT_DRAW:
2653 inv_cursor(false);
2654 switch( tool )
2656 case Brush:
2657 if( prev_x == -1 ) prev_x = 1;
2658 else prev_x = -1;
2659 break;
2661 case SelectRectangle:
2662 case Line:
2663 case Curve:
2664 case Rectangle:
2665 case RectangleFull:
2666 case Oval:
2667 case OvalFull:
2668 case LinearGradient:
2669 case RadialGradient:
2670 /* Curve uses 4 points, others use 2 */
2671 if( prev_x == -1 || prev_y == -1 )
2673 prev_x = x;
2674 prev_y = y;
2675 preview = true;
2677 else if( tool == Curve
2678 && ( prev_x2 == -1 || prev_y2 == -1 ) )
2680 prev_x2 = x;
2681 prev_y2 = y;
2683 else if( tool == SelectRectangle
2684 && ( prev_x2 == -1 || prev_y2 == -1 ) )
2686 tool_mode = rb->do_menu( &select_menu,
2687 NULL, NULL, false );
2688 switch( tool_mode )
2690 case SELECT_MENU_CUT:
2691 case SELECT_MENU_COPY:
2692 prev_x2 = x;
2693 prev_y2 = y;
2694 copy_to_clipboard();
2695 if( prev_x < x ) x = prev_x;
2696 if( prev_y < y ) y = prev_y;
2697 break;
2699 case SELECT_MENU_INVERT:
2700 draw_invert( prev_x, prev_y, x, y );
2701 reset_tool();
2702 break;
2704 case SELECT_MENU_HFLIP:
2705 draw_hflip( prev_x, prev_y, x, y );
2706 reset_tool();
2707 break;
2709 case SELECT_MENU_VFLIP:
2710 draw_vflip( prev_x, prev_y, x, y );
2711 reset_tool();
2712 break;
2714 case SELECT_MENU_ROTATE90:
2715 draw_rot_90_deg( prev_x, prev_y, x, y, 1 );
2716 reset_tool();
2717 break;
2719 case SELECT_MENU_ROTATE180:
2720 draw_hflip( prev_x, prev_y, x, y );
2721 draw_vflip( prev_x, prev_y, x, y );
2722 reset_tool();
2723 break;
2725 case SELECT_MENU_ROTATE270:
2726 draw_rot_90_deg( prev_x, prev_y, x, y, -1 );
2727 reset_tool();
2728 break;
2730 case SELECT_MENU_CANCEL:
2731 reset_tool();
2732 break;
2734 default:
2735 break;
2737 restore_screen();
2739 else if( tool == Curve
2740 && ( prev_x3 == -1 || prev_y3 == -1 ) )
2742 prev_x3 = x;
2743 prev_y3 = y;
2745 else
2747 preview = false;
2748 switch( tool )
2750 case SelectRectangle:
2751 draw_paste_rectangle( prev_x, prev_y,
2752 prev_x2, prev_y2,
2753 x, y, tool_mode );
2754 break;
2755 case Line:
2756 draw_line( prev_x, prev_y, x, y );
2757 break;
2758 case Curve:
2759 draw_curve( prev_x, prev_y,
2760 prev_x2, prev_y2,
2761 prev_x3, prev_y3,
2762 x, y );
2763 break;
2764 case Rectangle:
2765 draw_rect( prev_x, prev_y, x, y );
2766 break;
2767 case RectangleFull:
2768 draw_rect_full( prev_x, prev_y, x, y );
2769 break;
2770 case Oval:
2771 draw_oval_empty( prev_x, prev_y, x, y );
2772 break;
2773 case OvalFull:
2774 draw_oval_full( prev_x, prev_y, x, y );
2775 break;
2776 case LinearGradient:
2777 linear_gradient( prev_x, prev_y, x, y );
2778 break;
2779 case RadialGradient:
2780 radial_gradient( prev_x, prev_y, x, y );
2781 break;
2782 default:
2783 break;
2785 reset_tool();
2786 restore_screen();
2788 break;
2790 case Fill:
2791 draw_fill( x, y );
2792 restore_screen();
2793 break;
2795 case ColorPicker:
2796 color_picker( x, y );
2797 break;
2799 case Text:
2800 draw_text( x, y );
2801 break;
2803 default:
2804 break;
2806 inv_cursor(true);
2807 break;
2809 case ROCKPAINT_DRAW|BUTTON_REPEAT:
2810 if( tool == Curve )
2812 /* 3 point bezier curve */
2813 preview = false;
2814 draw_curve( prev_x, prev_y,
2815 prev_x2, prev_y2,
2816 -1, -1,
2817 x, y );
2818 reset_tool();
2819 restore_screen();
2820 inv_cursor( true );
2822 break;
2824 case ROCKPAINT_TOOLBAR:
2825 i = x; j = y;
2826 x = 10;
2827 toolbar();
2828 x = i; y = j;
2829 restore_screen();
2830 inv_cursor(true);
2831 break;
2833 case ROCKPAINT_TOOLBAR2:
2834 i = x; j = y;
2835 x = 110;
2836 toolbar();
2837 x = i; y = j;
2838 restore_screen();
2839 inv_cursor(true);
2840 break;
2842 case ROCKPAINT_LEFT:
2843 case ROCKPAINT_LEFT | BUTTON_REPEAT:
2844 inv_cursor(false);
2845 x-=bspeed * accelaration;
2846 if (x<0) x=COLS-1;
2847 inv_cursor(true);
2848 break;
2850 case ROCKPAINT_RIGHT:
2851 case ROCKPAINT_RIGHT | BUTTON_REPEAT:
2852 inv_cursor(false);
2853 x+=bspeed * accelaration;
2854 if (x>=COLS) x=0;
2855 inv_cursor(true);
2856 break;
2858 case ROCKPAINT_UP:
2859 case ROCKPAINT_UP | BUTTON_REPEAT:
2860 inv_cursor(false);
2861 y-=bspeed * accelaration;
2862 if (y<0) y=ROWS-1;
2863 inv_cursor(true);
2864 break;
2866 case ROCKPAINT_DOWN:
2867 case ROCKPAINT_DOWN | BUTTON_REPEAT:
2868 inv_cursor(false);
2869 y+=bspeed * accelaration;
2870 if (y>=ROWS)
2872 toolbar();
2873 restore_screen();
2875 inv_cursor(true);
2876 break;
2878 default:
2879 if (rb->default_event_handler(button) == SYS_USB_CONNECTED)
2880 return PLUGIN_USB_CONNECTED;
2881 break;
2883 if( tool == Brush && prev_x == 1 )
2885 inv_cursor(false);
2886 draw_brush( x, y );
2887 inv_cursor(true);
2889 if( preview || tool == ColorPicker )
2890 /* always preview color picker */
2892 restore_screen();
2893 switch( tool )
2895 case SelectRectangle:
2896 if( prev_x2 == -1 || prev_y2 == -1 )
2898 /* we are defining the selection */
2899 draw_select_rectangle( prev_x, prev_y, x, y );
2901 else
2903 /* we are pasting the selected data */
2904 draw_paste_rectangle( prev_x, prev_y, prev_x2,
2905 prev_y2, x, y, tool_mode );
2906 prev_x3 = prev_x2-prev_x;
2907 if( prev_x3 < 0 ) prev_x3 *= -1;
2908 prev_y3 = prev_y2-prev_y;
2909 if( prev_y3 < 0 ) prev_y3 *= -1;
2910 draw_select_rectangle( x, y, x+prev_x3, y+prev_y3 );
2911 prev_x3 = -1;
2912 prev_y3 = -1;
2914 break;
2916 case Brush:
2917 break;
2919 case Line:
2920 draw_line( prev_x, prev_y, x, y );
2921 break;
2923 case Curve:
2924 if( prev_x2 == -1 || prev_y2 == -1 )
2926 draw_line( prev_x, prev_y, x, y );
2928 else
2930 draw_curve( prev_x, prev_y,
2931 prev_x2, prev_y2,
2932 prev_x3, prev_y3,
2933 x, y );
2935 break;
2937 case Rectangle:
2938 draw_rect( prev_x, prev_y, x, y );
2939 break;
2941 case RectangleFull:
2942 draw_rect_full( prev_x, prev_y, x, y );
2943 break;
2945 case Oval:
2946 draw_oval_empty( prev_x, prev_y, x, y );
2947 break;
2949 case OvalFull:
2950 draw_oval_full( prev_x, prev_y, x, y );
2951 break;
2953 case Fill:
2954 break;
2956 case ColorPicker:
2957 preview = true;
2958 color_picker( x, y );
2959 preview = false;
2960 break;
2962 case LinearGradient:
2963 line_gradient( prev_x, prev_y, x, y );
2964 break;
2966 case RadialGradient:
2967 line_gradient( prev_x, prev_y, x, y );
2968 break;
2970 case Text:
2971 default:
2972 break;
2974 inv_cursor( true );
2976 if( gridsize > 0 )
2978 show_grid( true );
2979 show_grid( false );
2983 return PLUGIN_OK;
2986 static int load_bitmap( const char *file )
2988 struct bitmap bm;
2989 bool ret;
2990 int i, j;
2991 fb_data color = rp_colors[ bgdrawcolor ];
2993 bm.data = (char*)save_buffer;
2994 ret = rb->read_bmp_file( file, &bm, ROWS*COLS*sizeof( fb_data ),
2995 FORMAT_NATIVE, NULL );
2997 if((bm.width > COLS ) || ( bm.height > ROWS ))
2998 return -1;
3000 img_width = bm.width;
3001 img_height = bm.height;
3002 for( i = bm.height-1; i >= 0; i-- )
3004 rb->memmove( save_buffer+i*COLS, save_buffer+i*bm.width,
3005 sizeof( fb_data )*bm.width );
3006 for( j = bm.width; j < COLS; j++ )
3007 save_buffer[j+i*COLS] = color;
3009 for( i = bm.height*COLS; i < ROWS*COLS; i++ )
3010 save_buffer[i] = color;
3012 return ret;
3015 static int save_bitmap( char *file )
3017 struct bitmap bm;
3018 int i;
3019 for(i = 0; i < img_height; i++)
3021 rb->memcpy( buffer->clipboard+i*img_width, save_buffer+i*COLS,
3022 sizeof( fb_data )*img_width );
3024 bm.data = (char*)buffer->clipboard;
3025 bm.height = img_height;
3026 bm.width = img_width;
3027 bm.format = FORMAT_NATIVE;
3028 return save_bmp_file( file, &bm );
3031 enum plugin_status plugin_start(const void* parameter)
3033 size_t buffer_size;
3034 buffer = (buf*) (((uintptr_t)rb->plugin_get_buffer(&buffer_size) + 3) & ~3);
3035 if (buffer_size < sizeof(*buffer) + 3)
3037 /* steal from audiobuffer if plugin buffer is too small */
3038 buffer = (buf*)
3039 (((uintptr_t)rb->plugin_get_audio_buffer(&buffer_size) + 3) & ~3);
3041 if (buffer_size < sizeof(*buffer) + 3)
3043 rb->splash(HZ, "Not enough memory");
3044 return PLUGIN_ERROR;
3048 rb->lcd_set_foreground(COLOR_WHITE);
3049 rb->lcd_set_backdrop(NULL);
3050 rb->lcd_fillrect(0,0,LCD_WIDTH,LCD_HEIGHT);
3051 rb->splash( HZ/2, "Rock Paint");
3053 rb->lcd_clear_display();
3055 filename[0] = '\0';
3057 if( parameter )
3059 if( load_bitmap( parameter ) <= 0 )
3061 rb->splash( 1*HZ, "File Open Error");
3062 clear_drawing();
3064 else
3066 rb->splashf( 1*HZ, "Image loaded (%s)", (char *)parameter );
3067 restore_screen();
3068 rb->strcpy( filename, parameter );
3071 else
3073 clear_drawing();
3075 inv_cursor(true);
3077 return rockpaint_loop();