ba03cb4aea
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@31505 a1c6a512-1295-4272-9138-f99709370657
250 lines
9.4 KiB
C
250 lines
9.4 KiB
C
/***************************************************************************
|
|
* __________ __ ___.
|
|
* Open \______ \ ____ ____ | | _\_ |__ _______ ___
|
|
* Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
|
|
* Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
|
|
* Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
|
|
* \/ \/ \/ \/ \/
|
|
* $Id$
|
|
*
|
|
* Copyright (C) 2007 Copyright Kévin Ferrare based on Zakk Roberts's work
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
|
|
* KIND, either express or implied.
|
|
*
|
|
****************************************************************************/
|
|
|
|
#include "clock_draw_analog.h"
|
|
#include "lib/xlcd.h"
|
|
#include "lib/fixedpoint.h"
|
|
#include "clock_bitmaps.h"
|
|
#include "clock_bitmap_strings.h"
|
|
|
|
#define ANALOG_SECOND_RADIUS(screen, round) \
|
|
ANALOG_MINUTE_RADIUS(screen, round)
|
|
#define ANALOG_MINUTE_RADIUS(screen, round) \
|
|
(round?MIN(screen->getheight()/2 -10, screen->getwidth()/2 -10):screen->getheight()/2)
|
|
#define ANALOG_HOUR_RADIUS(screen, round) \
|
|
(2*ANALOG_MINUTE_RADIUS(screen, round)/3)
|
|
|
|
#define HOUR_ANGLE(hour, minute, second) (30*(hour) +(minute)/2)
|
|
#define MINUTE_ANGLE(minute, second) (6*(minute)+(second)/10)
|
|
#define SECOND_ANGLE(second) (6 * (second))
|
|
|
|
/* Note that the given angle's origin is midday and not 3 o'clock */
|
|
static void polar_to_cartesian(int a, int r, int* x, int* y)
|
|
{
|
|
#if CONFIG_LCD == LCD_SSD1815
|
|
/* Correct non-square pixel aspect of archos recorder LCD */
|
|
*x = (fp14_sin(a) * 5 / 4 * r) >> 14;
|
|
#else
|
|
*x = (fp14_sin(a) * r) >> 14;
|
|
#endif
|
|
*y = (fp14_sin(a-90) * r) >> 14;
|
|
}
|
|
|
|
static void polar_to_cartesian_screen_centered(struct screen * display,
|
|
int a, int r, int* x, int* y)
|
|
{
|
|
polar_to_cartesian(a, r, x, y);
|
|
*x+=display->getwidth()/2;
|
|
*y+=display->getheight()/2;
|
|
}
|
|
|
|
static void angle_to_square(int square_width, int square_height,
|
|
int a, int* x, int* y)
|
|
{
|
|
a = (a+360-90)%360;
|
|
if(a>45 && a<=135){/* top line */
|
|
a-=45;
|
|
*x=square_width-(square_width*2*a)/90;
|
|
*y=square_height;
|
|
}else if(a>135 && a<=225){/* left line */
|
|
a-=135;
|
|
*x=-square_width;
|
|
*y=square_height-(square_height*2*a)/90;
|
|
}else if(a>225 && a<=315){/* bottom line */
|
|
a-=225;
|
|
*x=(square_width*2*a)/90-square_width;
|
|
*y=-square_height;
|
|
}else if(a>315 || a<=45){/* right line */
|
|
if(a>315)
|
|
a-=315;
|
|
else
|
|
a+=45;
|
|
*x=square_width;
|
|
*y=(square_height*2*a)/90-square_height;
|
|
}
|
|
}
|
|
|
|
static void angle_to_square_screen_centered(struct screen * display,
|
|
int square_width, int square_height,
|
|
int a, int* x, int* y)
|
|
{
|
|
angle_to_square(square_width, square_height, a, x, y);
|
|
*x+=display->getwidth()/2;
|
|
*y+=display->getheight()/2;
|
|
}
|
|
|
|
static void draw_hand(struct screen* display, int angle,
|
|
int radius, int thickness, bool round)
|
|
{
|
|
int x1, y1; /* the longest */
|
|
int x2, y2, x3, y3; /* the base */
|
|
if(round){/* round clock */
|
|
polar_to_cartesian_screen_centered(display, angle, radius, &x1, &y1);
|
|
}else{/* fullscreen clock, hands describes square motions */
|
|
int square_width, square_height;
|
|
/* radius is defined smallest between getwidth() and getheight() */
|
|
square_height=radius;
|
|
square_width=(radius*display->getwidth())/display->getheight();
|
|
angle_to_square_screen_centered(
|
|
display, square_width, square_height, angle, &x1, &y1);
|
|
}
|
|
polar_to_cartesian_screen_centered(display, (angle+120)%360,
|
|
radius/40+thickness, &x2, &y2);
|
|
polar_to_cartesian_screen_centered(display, (angle+240)%360,
|
|
radius/40+thickness, &x3, &y3);
|
|
xlcd_filltriangle_screen(display, x1, y1, x2, y2, x3, y3);
|
|
rb->lcd_drawline(x1, y1, x2, y2);
|
|
rb->lcd_drawline(x1, y1, x3, y3);
|
|
}
|
|
|
|
static void draw_hands(struct screen* display, int hour, int minute, int second,
|
|
int thickness, bool round, bool draw_seconds)
|
|
{
|
|
if(draw_seconds){
|
|
draw_hand(display, SECOND_ANGLE(second),
|
|
ANALOG_SECOND_RADIUS(display, round), thickness, round);
|
|
}
|
|
draw_hand(display, MINUTE_ANGLE(minute, second),
|
|
ANALOG_MINUTE_RADIUS(display, round), thickness+2, round);
|
|
draw_hand(display, HOUR_ANGLE(hour, minute, second),
|
|
ANALOG_HOUR_RADIUS(display, round), thickness+2, round);
|
|
}
|
|
|
|
static void draw_counter(struct screen* display, struct counter* counter)
|
|
{
|
|
char buffer[10];
|
|
int second_str_w, hour_str_w, str_h;
|
|
const struct picture* smalldigits_bitmaps =
|
|
&(smalldigits[display->screen_type]);
|
|
struct time counter_time;
|
|
counter_get_elapsed_time(counter, &counter_time);
|
|
rb->snprintf(buffer, 10, "%02d:%02d",
|
|
counter_time.hour, counter_time.minute);
|
|
getstringsize(smalldigits_bitmaps, buffer, &hour_str_w, &str_h);
|
|
draw_string(display, smalldigits_bitmaps, buffer,
|
|
display->getwidth()-hour_str_w,
|
|
display->getheight()-2*str_h);
|
|
|
|
rb->snprintf(buffer, 10, "%02d", counter_time.second);
|
|
getstringsize(smalldigits_bitmaps, buffer, &second_str_w, &str_h);
|
|
draw_string(display, smalldigits_bitmaps, buffer,
|
|
display->getwidth()-(hour_str_w+second_str_w)/2,
|
|
display->getheight()-str_h);
|
|
}
|
|
|
|
static void draw_date(struct screen* display, struct time* time, int date_format)
|
|
{
|
|
char buffer[10];
|
|
int year_str_w, monthday_str_w, str_h;
|
|
int year_line=date_format==JAPANESE?1:2;
|
|
int monthday_line=date_format==JAPANESE?2:1;
|
|
const struct picture* smalldigits_bitmaps =
|
|
&(smalldigits[display->screen_type]);
|
|
if(date_format==ENGLISH || date_format==JAPANESE){
|
|
rb->snprintf(buffer, 10, "%02d/%02d", time->month, time->day);
|
|
}else{
|
|
rb->snprintf(buffer, 10, "%02d/%02d", time->day, time->month);
|
|
}
|
|
/* draws month and day */
|
|
getstringsize(smalldigits_bitmaps, buffer, &monthday_str_w, &str_h);
|
|
draw_string(display, smalldigits_bitmaps, buffer,
|
|
0, display->getheight()-year_line*str_h);
|
|
rb->snprintf(buffer, 10, "%04d", time->year);
|
|
|
|
/* draws year */
|
|
getstringsize(smalldigits_bitmaps, buffer, &year_str_w, &str_h);
|
|
draw_string(display, smalldigits_bitmaps, buffer,
|
|
(monthday_str_w-year_str_w)/2,
|
|
display->getheight()-monthday_line*str_h);
|
|
}
|
|
|
|
static void draw_border(struct screen* display, int skin)
|
|
{
|
|
/* Draws square dots every 5 minutes */
|
|
int i;
|
|
int x, y;
|
|
int size=display->getheight()/50;/* size of the square dots */
|
|
if(size%2)/* a pair number */
|
|
size++;
|
|
for(i=0; i < 60; i+=5){
|
|
if(skin){
|
|
polar_to_cartesian_screen_centered(display, MINUTE_ANGLE(i, 0),
|
|
ANALOG_MINUTE_RADIUS(display, skin), &x, &y);
|
|
}else{
|
|
angle_to_square_screen_centered(
|
|
display, display->getwidth()/2-size/2, display->getheight()/2-size/2,
|
|
MINUTE_ANGLE(i, 0), &x, &y);
|
|
}
|
|
display->fillrect(x-size/2, y-size/2, size, size);
|
|
}
|
|
}
|
|
|
|
static void draw_hour(struct screen* display, struct time* time,
|
|
bool show_seconds, int skin)
|
|
{
|
|
int hour=time->hour;
|
|
if(hour >= 12)
|
|
hour -= 12;
|
|
|
|
/* Crappy fake antialiasing (color LCDs only)!
|
|
* how this works is we draw a large mid-gray hr/min/sec hand,
|
|
* then the actual (slightly smaller) hand on top of those.
|
|
* End result: mid-gray edges to the black hands, smooths them out. */
|
|
#ifdef HAVE_LCD_COLOR
|
|
if(display->is_color){
|
|
display->set_foreground(LCD_RGBPACK(100,110,125));
|
|
draw_hands(display, hour, time->minute, time->second,
|
|
1, skin, show_seconds);
|
|
display->set_foreground(LCD_BLACK);
|
|
}
|
|
#endif
|
|
draw_hands(display, hour, time->minute, time->second,
|
|
0, skin, show_seconds);
|
|
}
|
|
|
|
static void draw_center_cover(struct screen* display)
|
|
{
|
|
display->hline((display->getwidth()/2)-1,
|
|
(display->getwidth()/2)+1, (display->getheight()/2)+3);
|
|
display->hline((display->getwidth()/2)-3,
|
|
(display->getwidth()/2)+3, (display->getheight()/2)+2);
|
|
display->fillrect((display->getwidth()/2)-4, (display->getheight()/2)-1, 9, 3);
|
|
display->hline((display->getwidth()/2)-3,
|
|
(display->getwidth()/2)+3, (display->getheight()/2)-2);
|
|
display->hline((display->getwidth()/2)-1,
|
|
(display->getwidth()/2)+1, (display->getheight()/2)-3);
|
|
}
|
|
|
|
void analog_clock_draw(struct screen* display, struct time* time,
|
|
struct clock_settings* settings,
|
|
struct counter* counter,
|
|
int skin)
|
|
{
|
|
|
|
draw_hour(display, time, settings->analog.show_seconds, skin);
|
|
if(settings->analog.show_border)
|
|
draw_border(display, skin);
|
|
if(counter)
|
|
draw_counter(display, counter);
|
|
if(settings->analog.show_date && settings->general.date_format!=NONE)
|
|
draw_date(display, time, settings->general.date_format);
|
|
draw_center_cover(display);
|
|
}
|