#include "Convac.h" // ListView class
#include <string.h> // memcpy
extern DISP d;
void ListView::onLenChange() {
byte H=B-T; // Höhe-1 des Fensters
if (pos+H>=len) { // Freiraum hinten? (<pos> verkleinern?)
if (H>=len) { // Weißraum verbleibt weil Liste zu kurz?
H=len-1;
pos=0;
d.flags=d.R2_ZERO; // Pixel löschen
d.fillRect(L,T+len,R-SBW,B); // Ungenutzten Bereich für immer weiß
}
else pos=len-H-1; // Kein Weißraum wenn Liste voll
}
paintScrollbar();
if (!len) return; // Nichts ausmalen
d.andClip(L,T,R-SBW,T+H); // Rest zum Ausmalen „markieren“
setRedraw();
}
// Symbolischen Rollbalken malen, SBW (10) Pixel breit
// (kann eh' nur mit Tasten „bedient“ werden)
void ListView::paintScrollbar() {
d.flags=d.R2_ZERO; // Pixel löschen
d.fillRect(R-SBW+1,T,R,B);
d.flags=d.COLOR|d.R2_COPYPEN; // Pixel setzen
d.drawRect(R-SBW+2,T,R,B);
byte t=T+2;
if (pos) {
d.drawPixel(R-SBM,t); t++; // Pfeil oben
d.drawLine(R-SBM-1,t,R-SBM+1,t); t++;
d.drawLine(R-SBM-2,t,R-SBM+2,t); t+=2;
}
word H=B-T+1; // Höhe des Fensters (Pixel)
byte b=B-2;
if (pos+H<len) {
d.drawPixel(R-SBM,b); b--; // Pfeil unten
d.drawLine(R-SBM-1,b,R-SBM+1,b); b--;
d.drawLine(R-SBM-2,b,R-SBM+2,b); b-=2;
}
if (len<=H) return; // Liste kürzer: Kein Thumb (Kein Scrollbar?)
byte hs=b-t+1; // Höhe Thumb-Bereich (Pixel)
byte tl=(byte)H*hs/len; // Länge des Thumbs (Pixel)
if (tl<3) tl=3; // Minimum zur Erkennbarkeit
byte ty=word(pos*(hs-tl))/word(len-H); // obere Thumb-Position
ty+=t;
d.fillRect(R-6,ty,R-2,ty+tl-1);
}
int ListView::posIntoView(word ip, byte ih) {
if (!ih) ip*=ih=dih;
byte h=B-T; // Höhe Fenster minus 1
--ih;
if (ip<pos || ih>h) return ip-pos; // herunterscrollen, hoch in Liste, dy<0
if (ip+ih>pos+h) return ip+ih-pos-h; // hochscrollen, hinunter in Liste, dy>0
return 0; // keine Aktion
}
void ListView::scrollIntoView(word ip, byte ih) {
int dy=posIntoView(ip,ih);
if (!dy) return; // keine Aktion
pos+=dy; // Ändern der ersten sichtbaren Pixelzeile
paintScrollbar();
byte ct=T, cb=B; // Clip-Top und Clip-Bottom
byte h=B-T; // Höhe Fenster minus 1
if (-h<=dy && dy<=h) {
d.L=L; d.T=T; d.R=R-SBW; d.B=B;
d.scroll(0,dy);
if (dy<0) cb=ct-dy-1; else ct=cb-dy+1;
}
d.andClip(L,ct,R-SBW,cb);
setRedraw(); // Scrollen: Teilweise oder alles neuzeichnen
}
void ListView::collapse(word ip, int dy) {
word h=len; // Größere der beiden Längen fangen
byte H=B-T; // Höhe der Listbox-1
len-=dy; // Neue Gesamtlänge
if (dy<0) h=len;
else if (pos && pos+H>=len) { // Freiraum hinten? (<pos> ist zu verkleinern?)
onLenChange();
return; // erst mal zu kompliziert zum Scrollen: Neuaufbau
}
h-=pos; // Anzahl Pixel-1 hinter <pos>
assert((int)len>=0,__LINE__);
paintScrollbar();
assert(len>=ip,__LINE__);
ip-=pos; // Stelle auf Bildschirm
if ((int)ip<0) ip=0; // Wenn oberhalb, tue so als wär's die obere Listen-Rand (kommt nie vor)
h-=ip; // Anzahl Pixel-1 hinter {Einfügestelle ODER oberer Listen-Rand}
assert(h>=0,__LINE__);
if (ip>H) return; // Wenn unterhalb, tue nichts
// Ab hier ist <ip> ein Byte
H-=ip; // Anzahl Pixel-1 hinter Einfügestelle
if (h>H) h=H; // Anzahl _sichtbarer_ Pixel-1 hinter {}
// Ab hier ist auch <h> ein Byte
d.L=L; d.R=R-SBW; d.B=(d.T=T+ip)+h; // Operations-Rechteck
if (dy<0) { // Einfüge-Operation
if (int(dy+h)>=0) {
d.scroll(0,dy);
d.B=d.T-dy-1;
}
}else{ // Lösch-Operation
if (h>=(word)dy) {
d.scroll(0,dy);
d.T=d.B-dy+1;
}
}
d.andClip(d.L,d.T,d.R,d.B);
setRedraw();
}
bool ListView::itemVisible(word ip, byte ih) {
if (!ih) ip*=ih=dih;
return ip+ih>pos && ip<=pos+(B-T);
}
bool ListView::itemInvalid(word ip, byte ih) {
if (!ih) ip*=ih=dih;
ip+=T;
return ip+ih>pos+d.clip.T && ip<=pos+d.clip.B;
}
void ListView::andItemClip(word ip, byte ih) {
if (!ih) ip*=ih=dih;
char dy=ip-pos; // muss in ein (vzb.) Byte passen da sichtbar
byte t=T; if (ip>pos) t+=dy;
byte b=B; if (ip+ih<=pos+b-T) b=T+dy+ih-1;
d.andClip(L,t,R-SBW,b);
}
void ListView::setFullClip() {
memcpy(&d.clip.L,&L,4);
}
void ListView::fillItem(int ip, int ih, byte l, byte r) {
if (!ih) ip*=ih=dih;
l+=L;
byte rr=r; // retten zur Überlauffeststellung (Carry)
byte rmax=R-SBW;
r+=L; if (r<rr || r>rmax) r=rmax; // begrenzen
if ((ip-=pos)<0) { // Anfang oberhalb?
if ((ih+=ip)<0) return; // verringern! Itemende außerhalb oben
ip=0;
}
byte h=B-T;
if (ip>h) return; // außerhalb unten
if (h>=ih) h=ih-1;
d.fillRect(l,T+ip,r,T+ip+h);
}
void ListView::xorFocusRect(word ip, byte ih, byte l, byte r) {
if (!ih) ip*=ih=dih;
l+=L;
byte rr=r;
byte rmax=R-SBW;
r+=L; if (r<rr || r>rmax) r=rmax;
byte t=ip-pos; // sollte nie <0 werden!
t+=T;
::xorFocusRect(l,t,r,t+ih-1);
}
Detected encoding: UTF-8 | 0
|