#include <avr/io.h>
#include <avr/eeprom.h>
#include <util/delay.h>
#include "UTFT.h"
#include "TouchScreen.h"
#include "calib.h"
#include "stellen.h" // jetzt
#include "kal.h"
/********************************
* Monatskalender-Darstellung *
********************************/
extern TouchScreen ts;
extern void Rahmen(int top=19, int bot=2);
extern UTFT dc;
extern const byte ArialBP24[] PROGMEM;
extern PROGMEM const char mn[]; // Monatsnamen
PROGMEM const char wnk[]="So\0Mo\0Di\0Mi\0Do\0Fr\0Sa\0";
extern void Button(int x, int y, const char*s, int cx=-1,
word tlcolor=RGB(240,240,240), word brcolor=RGB(128,128,128));
extern int HitTest();
extern int nbuttons;
const char*stridx_P(const char*s, int idx);
extern PROGMEM const word bgcolors[9]; // Bit 0 = Index 1
#define COLOR_BACK RGB(200,200,200)
#define FIRST 1 // Montag als erster Tag (deutsch)
static char Easter2k(char year) { // Ostersonntag als Märzdatum (Wikipedia)
char a=(byte)(year+5)%19;
char d=(byte)(19*a+24)%30;
char r=(byte)(d+a/11)/29;
char og=21+d-r;
char sz=7-(byte)(year+(year>>2)+2)%7;
char oe=7-(byte)(og-sz)%7;
return og+oe;
}
static char MarchDay(const _date&d) { // Märzdatum für März, April, Mai, Juni
char mm=d.month-3; // Märzmonat, März=0
if ((byte)mm>4) return 0; // alle anderen Monate
char md=d.day+mm*31;
if (mm>=2) --md;
return md;
}
// Feiertage in Sachsen
bool Feiertag(const _date&d,char os) {
char dow=d.dow();
if (!dow) return true; // Sonntag
if (d.day==1 && d.month==1) return true; // Neujahr
if (d.day==1 && d.month==5) return true; // 1. Mai
if (d.day==3 && d.month==10) return true; // Tag der Vereinnahmnung
if (d.day==31 && d.month==10) return true; // Reformationstag
if (d.day==25 && d.month==12) return true; // Weihnachten
if (d.day==26 && d.month==12) return true;
// Bewegliche Feiertage
char md=MarchDay(d); // Märzdatum: 1.4. = 32.3.
if (md) {
if (md==os-2) return true; // Karfreitag
if (md==os+1) return true; // Ostermontag
if (md==os+39) return true; // Himmelfahrt
if (md==os+50) return true; // Pfingstmontag
}
if (dow==3 && d.month==11
&& (byte)(d.day-16)<7) return true; // Buß- und Bettag
// TODO: Halbe Tage (blau): Sonnabende, Heiligabend, Silvester
return false;
}
void Radio(int x, int y, const __FlashString*s, bool checked=false) {
dc.drawCircle(x+9,y+9,9);
if (checked) dc.fillCircle(x+9,y+9,5);
dc.print(s,x+22,y);
}
// Bits für das ganze Jahr
extern EEMEM long Tonne_E[4*12];
extern long Tonne[4*12];
static byte ByteIndex(const _date&d,byte i) {
// Index mmmmiidd; die Bitadresse ist (d.day-1)&7
byte b=d.month-1; b<<=2; b|=i; b<<=2; b|=(byte)(d.day-1)>>3;
return b;
}
static byte BitMask(const _date&d) {
return 1<<((byte)(d.day-1)&7);
}
byte Ereignis(const _date&d,byte i) {
byte b=((byte*)Tonne)[ByteIndex(d,i)];
return b&BitMask(d);
}
static void Toggle(const _date&d,byte i) {
((byte*)Tonne)[ByteIndex(d,i)]^=BitMask(d);
}
static byte Sorten(const _date&d) { // jedes Bit des Returnwertes repräsentiert eine Müllsorte
byte ret=0,mask=1;
for (byte i=0; i<4; i++,mask<<=1) if (Ereignis(d,i)) ret|=mask;
return ret;
}
/* bits 0..3: Müllarten, 7: heute; Randaufbau: Alle vier Bits verpackt
┌───────────────┐
│┌─┬────2──────┐│
││ ├─────────┬─┤│
││1│ │ ││
││ │ │3││
│├─┴─────────┤ ││
│└──────4────┴─┘│
└───────────────┘
*/
static void Rand(int x, int y, byte bits) {
x-=15; y-=1;
dc.setColor(bits&0x80?COLOR_RED:COLOR_BACK);
dc.drawRect(x-1,y-1,x+31,y+21);
if (bits==0x80) {
dc.drawRect(x,y,x+30,y+20);
dc.setColor(COLOR_BACK);
dc.drawRect(x+1,y+1,x+29,y+19);
}else{
static PROGMEM const byte cases[15]={
0b00000000, // 0001 einfarbiger Rahmen mit Index 0
0b01010101, // 0010
0b01010000, // 0011 zweifarbiger Rahmen
0b10101010, // 0100 einfarbig
0b10100000, // 0101 zweifarbig
0b10100101, // 0110
0b10010000, // 0111 dreifarbig
0b11111111, // 1000 einfarbig
0b11110000, // 1001 zweifarbig
0b11110101, // 1010
0b11010000, // 1011 dreifarbig
0b11111010, // 1100 zweifarbig
0b11100000, // 1101 dreifarbig
0b11100101, // 1110
0b11100100}; // 1111 vierfarbig
word c=COLOR_BACK;
byte mask=0;
// linke Seite (1 in der Skizze oben)
if (bits&=0x0F) {
mask=pgm_read_byte(cases-1+bits);
c=pgm_read_word(bgcolors+1+(mask&3));
}
dc.setColor(c);
dc.fillRect(x,y,x+2,y+18);
// oben
if (bits) {
mask>>=2;
c=pgm_read_word(bgcolors+1+(mask&3));
dc.setColor(c);
}
dc.fillRect(x+2,y,x+30,y+2);
// rechts
if (bits) {
mask>>=2;
c=pgm_read_word(bgcolors+1+(mask&3));
dc.setColor(c);
}
dc.fillRect(x+28,y,x+30,y+20);
// unten
if (bits) {
mask>>=2;
c=pgm_read_word(bgcolors+1+(mask&3));
dc.setColor(c);
}
dc.fillRect(x,y+18,x+28,y+20);
}
}
bool MonthCal() {
_date d=jetzt.d;
dc.clrClip();
Rahmen(); // Rahmen löschen
dc.gotoXY(120,0);
dc.print(F("Monatskalender"));
bool editmode=false;
bool dirty=false;
char editbit=0;
for(;;) {
dc.setColor(RGB(200,200,200));
dc.fillRectW(2,19,236,299);
nbuttons=0;
const char*p=stridx_P(mn,d.month-1); // Monatsname
static char s[16];
sprintf_P(s,PSTR("%S 20%02d"),p,d.year);
Button(120,30,s,120,COLOR_BLUE,COLOR_BLUE);
Button(20,30,"<");
Button(220,30,">");
if (editmode) {
Button(194,250,"zurück");
dc.align=0;
dc.setBackColor(COLOR_BACK);
Radio(10,245,F("gelb"), editbit==0);
Radio(10,275,F("grau"), editbit==1);
Radio(80,245,F("blau"), editbit==2);
Radio(80,275,F("braun"),editbit==3);
dc.align=2;
}else{
Button(50,250,"Ändern");
Button(180,250,dirty?"Speichern":"Zurück");
}
dc.setColor(COLOR_BLUE);
dc.setBackColor(COLOR_BACK);
char wt=FIRST;
for (int x=24; x<24+7*32; x+=32) {
p=stridx_P(wnk,wt); // Wochentag (kurz)
sprintf_P(s,PSTR("%S"),p);
dc.print(s,x,60);
if (++wt==7) wt=0;
}
dc.setColor(COLOR_BLACK);
dc.fillRect(8,80,232,81);
char os=Easter2k(d.year);
// Wo ist der Montag?
_date d1=d;
d1.day=1;
char dow=d1.dow();
if (dow<=FIRST) dow+=7; // mindestens einen gestrigen Tag
do d1.gestern(); while(--dow!=FIRST);
_date d2=d1;
for (int y=88; y<88+6*24; y+=24) {
for (int x=24; x<24+7*32; x+=32) {
dc.setColor(d1.month==d.month?COLOR_BLACK:COLOR_GRAY);
if (d1.month==d.month && Feiertag(d1,os)) dc.setColor(COLOR_RED);
sprintf_P(s,PSTR("%d"),d1.day);
dc.print(s,x,y);
if (d1.month==d.month) { // Nicht im Graubereich
byte bits=Sorten(d1);
if (editmode) bits&=1<<editbit; // nur eine Müllsorte anzeigen
if (d1.heute()) bits|=0x80;
if (bits) Rand(x,y,bits);
}
d1.morgen();
}
}
rept:
while (ts.isTouching()) _delay_ms(100); // warten bis Berührungsende
if (!waitTouch(600)) return false;
calib.getPoint(); // Position lesen und in Bildschirmpixel umrechnen
switch (HitTest()) {
case 0: d.prevmonth(); break;
case 1: d.nextmonth(); break;
case 2: editmode=!editmode; break;
case 3: return dirty; // speichern lassen (EEPROM-Update)
default: if (!editmode) goto rept;
if (240<=touch.y && touch.y<300) { // Radiobuttons umschalten
editbit=0;
if (touch.y>=270) editbit|=1; // 1 oder 3 (unten)
if (touch.x>=80) editbit|=2; // 2 oder 3 (rechts)
break;
}
d1=d2;
for (int y=88; y<88+6*24; y+=24) {
for (int x=24; x<24+7*32; x+=32) {
if (x-16<=touch.x && touch.x<x+16
&& y-3<=touch.y && touch.y<y+21) {
if (d1.month==d.month) {
Toggle(d1,editbit);
byte bits=Sorten(d1);
bits&=1<<editbit; // einfarbig halten
if (d1.heute()) bits|=0x80;
Rand(x,y,bits);
dirty=true;
_delay_ms(100);
goto rept;
}
}
d1.morgen();
}
}
editmode=false; // zurück
}
}
}
Detected encoding: UTF-8 | 0
|