Source file: /~heha/Mikrocontroller/Displays/utft/Kalender.zip/ILI9341/kal.cpp

#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-80