diff options
Diffstat (limited to '')
-rw-r--r-- | drv_generic_bar.c | 471 |
1 files changed, 471 insertions, 0 deletions
diff --git a/drv_generic_bar.c b/drv_generic_bar.c new file mode 100644 index 0000000..0bf3f7e --- /dev/null +++ b/drv_generic_bar.c @@ -0,0 +1,471 @@ +/* $Id: drv_generic_bar.c,v 1.1 2004/01/20 04:51:39 reinelt Exp $ + * + * generic driver helper for bar creation + * + * Copyright 1999, 2000 Michael Reinelt <reinelt@eunet.at> + * Copyright 2004 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net> + * + * This file is part of LCD4Linux. + * + * LCD4Linux 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, or (at your option) + * any later version. + * + * LCD4Linux is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + * + * $Log: drv_generic_bar.c,v $ + * Revision 1.1 2004/01/20 04:51:39 reinelt + * moved generic stuff from drv_MatrixOrbital to drv_generic + * implemented new-stylish bars which are nearly finished + * + */ + +/* + * + * exported fuctions: + * + * Fixme: document me! + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +#include "debug.h" +#include "drv.h" +#include "widget.h" +#include "widget_bar.h" +#include "drv_generic.h" +#include "drv_generic_bar.h" + + +typedef struct { + int val1; + int val2; + DIRECTION dir; + int segment; +} BAR; + +typedef struct { + int val1; + int val2; + DIRECTION dir; + int used; + int ascii; +} SEGMENT; + + +static int RES; + +static int nSegment=0; +static int fSegment=0; +static SEGMENT Segment[128]; + +static BAR *Bar=NULL; + + +int drv_generic_text_bar_init (void) +{ + if (Bar) free (Bar); + + if ((Bar=malloc (LROWS*LCOLS*sizeof(BAR)))==NULL) { + error ("bar buffer allocation failed: out of memory"); + return -1; + } + + nSegment=0; + fSegment=0; + + drv_generic_text_bar_clear(); + + return 0; +} + + +void drv_generic_text_bar_clear(void) +{ + int i; + + for (i=0; i<LROWS*LCOLS; i++) { + Bar[i].val1 = -1; + Bar[i].val2 = -1; + Bar[i].dir = 0; + Bar[i].segment = -1; + } + + for (i=0; i<nSegment;i++) { + Segment[i].used = 0; + } +} + + +void drv_generic_text_bar_add_segment(int val1, int val2, DIRECTION dir, int ascii) +{ + Segment[fSegment].val1=val1; + Segment[fSegment].val2=val2; + Segment[fSegment].dir=dir; + Segment[fSegment].used=0; + Segment[fSegment].ascii=ascii; + + fSegment++; + nSegment=fSegment; +} + + +static void drv_generic_text_bar_create_bar (int row, int col, DIRECTION dir, int len, int val1, int val2) +{ + int rev=0; + + switch (dir) { + case DIR_WEST: + val1 = len-val1; + val2 = len-val2; + rev = 1; + + case DIR_EAST: + while (len > 0 && col < LCOLS) { + Bar[row*LCOLS+col].dir=dir; + Bar[row*LCOLS+col].segment=-1; + if (val1 >= XRES) { + Bar[row*LCOLS+col].val1 = rev?0:XRES; + val1 -= XRES; + } else { + Bar[row*LCOLS+col].val1 = rev?XRES-val1:val1; + val1 = 0; + } + if (val2 >= XRES) { + Bar[row*LCOLS+col].val2 = rev?0:XRES; + val2 -= XRES; + } else { + Bar[row*LCOLS+col].val2 = rev?XRES-val2:val2; + val2 = 0; + } + len--; + col++; + } + break; + + case DIR_SOUTH: + val1 = len-val1; + val2 = len-val2; + rev = 1; + + case DIR_NORTH: + while (len > 0 && row < LROWS) { + Bar[row*LCOLS+col].dir=dir; + Bar[row*LCOLS+col].segment=-1; + if (val1 >= YRES) { + Bar[row*LCOLS+col].val1 = rev?0:YRES; + val1 -= YRES; + } else { + Bar[row*LCOLS+col].val1 = rev?YRES-val1:val1; + val1 = 0; + } + if (val2 >= YRES) { + Bar[row*LCOLS+col].val2 = rev?0:YRES; + val2 -= YRES; + } else { + Bar[row*LCOLS+col].val2 = rev?YRES-val2:val2; + val2 = 0; + } + len--; + row++; + } + break; + + } +} + + +static void drv_generic_text_bar_create_segments (void) +{ + int i, j, n; + int res, l1, l2; + + /* find first unused segment */ + for (i=fSegment; i<nSegment && Segment[i].used; i++); + + /* pack unused segments */ + for (j=i+1; j<nSegment; j++) { + if (Segment[j].used) + Segment[i++]=Segment[j]; + } + nSegment=i; + + /* create needed segments */ + for (n=0; n<LROWS*LCOLS; n++) { + if (Bar[n].dir==0) continue; + res=Bar[n].dir & (DIR_EAST|DIR_WEST) ? XRES:YRES; + for (i=0; i<nSegment; i++) { + if (Segment[i].dir & Bar[n].dir) { + l1 = Segment[i].val1; if (l1>RES) l1=RES; + l2 = Segment[i].val2; if (l2>RES) l2=RES; + if (l1 == Bar[n].val1 && l2 == Bar[n].val2) break; + } + } + if (i==nSegment) { + nSegment++; + Segment[i].val1=Bar[n].val1; + Segment[i].val2=Bar[n].val2; + Segment[i].dir=Bar[n].dir; + Segment[i].used=0; + Segment[i].ascii=-1; + } + Bar[n].segment=i; + } +} + + +static int drv_generic_text_bar_segment_error (int i, int j) +{ + int res; + int i1, i2, j1, j2; + + if (i==j) return 65535; + if (!(Segment[i].dir & Segment[j].dir)) return 65535; + + res = Segment[i].dir&(DIR_EAST|DIR_WEST) ? XRES:YRES; + + i1=Segment[i].val1; if (i1>res) i1=res; + i2=Segment[i].val2; if (i2>res) i2=res; + j1=Segment[j].val1; if (j1>res) j1=res; + j2=Segment[j].val2; if (j2>res) j2=res; + + if (i1==0 && j1!=0) return 65535; + if (i2==0 && j2!=0) return 65535; + if (i1==res && j1<res) return 65535; + if (i2==res && j2<res) return 65535; + if (i1==1 && j1!=1 && i2 > 0) return 65535; + if (i2==1 && j2!=1 && j1 > 0) return 65535; + if (i1==i2 && j1!=j2) return 65535; + + return (i1-j1)*(i1-j1)+(i2-j2)*(i2-j2); +} + + +static void drv_generic_text_bar_pack_segments (void) +{ + int i, j, n, min; + int pack_i, pack_j; + int pass1=1; + int error[nSegment][nSegment]; + + if (nSegment<=fSegment+CHARS) { + return; + } + + for (i=0; i<nSegment; i++) { + for (j=0; j<nSegment; j++) { + error[i][j]=drv_generic_text_bar_segment_error(i,j); + } + } + + while (nSegment>fSegment+CHARS) { + + min=65535; + pack_i=-1; + pack_j=-1; + for (i=fSegment; i<nSegment; i++) { + if (pass1 && Segment[i].used) continue; + for (j=0; j<nSegment; j++) { + if (error[i][j]<min) { + min=error[i][j]; + pack_i=i; + pack_j=j; + } + } + } + if (pack_i==-1) { + if (pass1) { + pass1=0; + continue; + } else { + error ("unable to compact bar characters"); + nSegment=CHARS; + break; + } + } + +#if 1 + debug ("pack_segment: n=%d i=%d j=%d min=%d", nSegment, pack_i, pack_j, min); + debug ("Pack_segment: i1=%d i2=%d j1=%d j2=%d\n", + Segment[pack_i].val1, Segment[pack_i].val2, + Segment[pack_j].val1, Segment[pack_j].val2); +#endif + + nSegment--; + Segment[pack_i]=Segment[nSegment]; + + for (i=0; i<nSegment; i++) { + error[pack_i][i]=error[nSegment][i]; + error[i][pack_i]=error[i][nSegment]; + } + + for (n=0; n<LROWS*LCOLS; n++) { + if (Bar[n].segment==pack_i) Bar[n].segment=pack_j; + if (Bar[n].segment==nSegment) Bar[n].segment=pack_i; + } + } +} + + +static void drv_generic_text_bar_define_chars (void(*defchar)(int ascii, char *matrix)) +{ + int c, i, j; + char buffer[8]; + + for (i=fSegment; i<nSegment; i++) { + if (Segment[i].used) continue; + if (Segment[i].ascii!=-1) continue; + for (c=0; c<CHARS; c++) { + for (j=fSegment; j<nSegment; j++) { + if (Segment[j].ascii==c) break; + } + if (j==nSegment) break; + } + Segment[i].ascii=c; + switch (Segment[i].dir) { + case DIR_EAST: + for (j=0; j<4; j++) { + buffer[j ]=(1<<Segment[i].val1)-1; + buffer[j+4]=(1<<Segment[i].val2)-1; + } + break; + case DIR_WEST: + for (j=0; j<4; j++) { + buffer[j ]=255<<(XRES-Segment[i].val1); + buffer[j+4]=255<<(XRES-Segment[i].val2); + } + break; + case DIR_NORTH: + for (j=0; j<Segment[i].val1; j++) { + buffer[7-j]=(1<<XRES)-1; + } + for (; j<YRES; j++) { + buffer[7-j]=0; + } + break; + case DIR_SOUTH: + for (j=0; j<Segment[i].val1; j++) { + buffer[j]=(1<<XRES)-1; + } + for (; j<YRES; j++) { + buffer[j]=0; + } + break; + } + defchar(c, buffer); + } +} + + +int drv_generic_text_draw_bar (WIDGET *W, int goto_len, + void (*drv_defchar)(int ascii, char *buffer), + void (*drv_goto)(int row, int col), + void (*drv_write)(char *buffer, int len)) +{ + WIDGET_BAR *B = W->data; + int row, col, len, max, val1, val2; + int c, n, s; + DIRECTION dir; + + row = W->row; + col = W->col; + dir = B->direction; + len = B->length; + + // maybe grow layout framebuffer + // bars *always* grow heading North or East! + if (dir==DIR_EAST || dir==DIR_WEST) { + drv_generic_text_resizeFB (row, col+len-1); + RES = XRES; + } else { + drv_generic_text_resizeFB (row, col); + RES = YRES; + } + max = len * RES; + val1 = B->val1 * (double)(max); + val2 = B->val2 * (double)(max); + + if (val1<1) val1=1; + else if (val1>max) val1=max; + + if (val2<1) val2=1; + else if (val2>max) val2=max; + + // create this bar + drv_generic_text_bar_create_bar (row, col, dir, len, val1, val2); + + // process all bars + drv_generic_text_bar_create_segments (); + drv_generic_text_bar_pack_segments (); + drv_generic_text_bar_define_chars(drv_defchar); + + // reset usage flags + for (s=0; s<nSegment; s++) { + Segment[s].used=0; + } + + // set usage flags + for (n=0; n<LROWS*LCOLS; n++) { + if ((s=Bar[n].segment)!=-1) Segment[s].used=1; + } + + // transfer bars into layout buffer + for (n=0; n<LCOLS*LROWS; n++) { + s=Bar[n].segment; + if (s==-1) continue; + c=Segment[s].ascii; + if (c==-1) continue; + if(c==LayoutFB[n]) continue; + LayoutFB[n]=c; + } + + // transfer differences to the display + for (row=0; row<DROWS; row++) { + for (col=0; col<DCOLS; col++) { + int pos1, pos2, equal; + if (LayoutFB[row*LCOLS+col]==DisplayFB[row*DCOLS+col]) continue; + drv_goto (row, col); + for (pos1=col, pos2=pos1, col++, equal=0; col<DCOLS; col++) { + if (LayoutFB[row*LCOLS+col]==DisplayFB[row*DCOLS+col]) { + // If we find just one equal byte, we don't break, because this + // would require a goto, which takes several bytes, too. + if (++equal>goto_len) break; + } else { + pos2=col; + equal=0; + } + } + memcpy (DisplayFB+row*DCOLS+pos1, LayoutFB+row*LCOLS+pos1, pos2-pos1+1); + drv_write (DisplayFB+row*DCOLS+pos1, pos2-pos1+1); + debug ("Michi: bar(%d,%d) len=%d", row, pos1, pos2-pos1+1); + } + } + + return 0; + +} + +int drv_generic_text_bar_peek (int row, int col) +{ + int s; + + s=Bar[row*LCOLS+col].segment; + if (s==-1) { + return -1; + } else { + return Segment[s].ascii; + } +} + |