list_dis.c
"QuickCall" is the main engine for QuickATM's airport information kiosks. It is written entirely in C, and runs under DOS. Most of the data files are flattened versions of our relational database, which were dumped into a pseudo-filesystem that we created. "QuickCall" ran in over one hundred kiosks nationwide.
In the code, the macro
PUB_EXE is used to denote public functions, and
PVT_EXE indicates a private (module level) function.
These macros allow for quick greps and extractions of public and
private function names.
This module handles the displaying of list files. A list file is a table in our flattened database, stored on disk as a plain text file, and in memory as a structure containing multiple lists and arrays.
/* -- list_dis.c: list displaying and history routines. -- */
/* -- Copyright (c) 1995 by QuickATM. All rights reserved. -- */
#include <ctype.h>
#include "proto.h"
#include "list.h"
extern List *list;
/* --------------------------------------------------------------------------*/
/* show_hermometer: displays the hermometer (scroll bar). */
/* --------------------------------------------------------------------------*/
PVT_EXE void show_hermometer( )
{
int idx1, idx2;
int y_base, y_offset, y1, y2;
long offset;
rect r;
/* erase the scrollbar area. */
start_graphics( );
BackColor( list->hermom_bg );
EraseRect( &( list->hermometer ) );
end_graphics( );
/* top and bottom of highlighted area -- list entries. */
idx1 = list_index_of( 1 );
idx2 = list_index_of( list->n_scroll );
/* top and bottom of highlighted area -- pixels. */
y_base = list->hermometer.Ymin;
y_offset = list->hermometer.Ymax - list->hermometer.Ymin;
offset = ((long)(y_offset) * (long)(idx1)) / (long)(list->ni);
y1 = y_base + (int)offset;
offset = ((long)(y_offset) * (long)(idx2)) / (long)(list->ni);
y2 = y_base + (int)offset;
/* adjust coordinates to make the rectangle slightly bigger. */
if ( y1 > y_base + 1 ) { y1--; };
if ( y2 < y_base + y_offset - 1 ) { y2++; };
/* X coordinates shrink if the scrollbar is wide enough. */
r.Xmin = list->hermometer.Xmin;
r.Xmax = list->hermometer.Xmax;
if ( ( r.Xmax - r.Xmin ) > 10 ) {
r.Xmin += 3;
r.Xmax -= 3;
}
BackColor( list->hermom_fg );
start_graphics( );
if ( y2 >= y1 ) {
/* normal case: one filled area. */
r.Ymin = y1;
r.Ymax = y2;
EraseRect( &r );
} else {
/* deviant case: two filled areas. */
r.Ymin = list->hermometer.Ymin;
r.Ymax = y2;
EraseRect( &r );
r.Ymin = y1;
r.Ymax = list->hermometer.Ymax;
EraseRect( &r );
}
end_graphics( );
BackColor( LTEAL );
}
/* ------------------------------------------------------------------------- */
/* refresh_list_az_rects: refreshes the scroll button labels for lists. */
/* ------------------------------------------------------------------------- */
PVT_EXE char atoz( char *c )
{
char d = *c;
if ( d == '\0' ) return ' ';
if ( d == ' ' ) return ' ';
if ( d < 'A' ) d = 'A';
if ( d >= 'a' ) d -= ( 'a' - 'A' );
if ( d > 'Z' ) d = 'Z';
return d;
}
PVT_EXE void refresh_list_az_rects( )
{
field f;
ints *tmp;
char buf[20], *font;
f.fg_color = BLACK;
f.bg_color = LGRAY;
f.h_align = f.v_align = 1;
f.font = LARGE_FONT;
if ( list == NULL ) return;
font = get_dictionary( STRING, "AZ RECT FONT" );
if ( set_def_font( font ) == 1 ) {
f.font = font;
}
tmp = get_dictionary( INTS, "UP AZ RECT" );
if ( tmp != NULL ) {
/* give the up-scroll button an appropriate name. */
char c, a;
c = atoz( list_item_of( -1 ) );
a = atoz( list_item_of( 1-list->curi ) );
sprintf( buf, "%c to %c", a, c );
if ( c <= a ) sprintf( buf, "%c", a );
if ( c == ' ' ) sprintf( buf, "(top)" );
Ints2Rect( &(f.disp), tmp );
clear_text_in_field( &f );
draw_text_in_field( buf, &f );
}
tmp = get_dictionary( INTS, "DOWN AZ RECT" );
if ( tmp != NULL ) {
/* give the down-scroll button an appropriate name. */
char c, z;
c = atoz( list_item_of( list->n_scroll ) );
z = atoz( list_item_of( -1-list->curi ) );
sprintf( buf, "%c to %c", c, z );
if ( c >= z ) sprintf( buf, "%c", z );
if ( c == ' ' ) sprintf( buf, "(bottom)" );
Ints2Rect( &(f.disp), tmp );
clear_text_in_field( &f );
draw_text_in_field( buf, &f );
}
/* display the alpha buffer. */
if ( list->control == ALPHA_CTRL ) {
f.bg_color = WHITE;
f.font = LARGE_FONT;
f.disp = list->alpha_rect;
clear_text_in_field( &f );
draw_text_in_field( list->alpha_buf, &f );
}
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
PVT_EXE int fg_color_of_label( int but, char *label )
{
int fg = BLACK;
/* simple cases. */
if ( list->display == QPHONE_DISP ) return BLACK;
if ( list->control == NO_CTRL ) return BLACK;
/* see if we should unhighlight this entry. */
switch ( list->control ) {
case ALPHA_CTRL:
if ( list->alpha_nbuf > 0 ) {
if ( strnicmp( label, list->alpha_buf, list->alpha_nbuf ) != 0 ) {
fg = DGRAY;
}
}
break;
case DATE_CTRL:
if ( strnicmp( list_item_of( but ), list->date_string,
strlen( list->date_string ) ) < 0 ) {
fg = DGRAY;
}
break;
case MAP_CTRL:
if ( list_index_of( but ) == list->map_best ) {
fg = DRED;
}
}
return fg;
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
PVT_EXE char *data_for_field( int ch, int but )
{
char *ret = "";
char *s;
int idx;
int min_i, max_i, i;
/* these are displayed separately; therefore return nothing! */
if ( ( ch == F_LABEL ) || ( ch == F_HASHMARK ) ) {
return NULL;
}
/* find the bounds of this list entry's data. */
idx = list_index_of( but );
min_i = list->ii[ idx ];
for ( i = min_i + 1; i < list->ns; i++ ) {
if ( *( list->ss[ i ] ) == L_ITEM ) break;
}
max_i = i;
switch( ch ) {
case 'P': /* phone number. */
{
char *my_air = get_dictionary( STRING, "Q_HOME_AIRPORT" );
for ( i = min_i; i < max_i; i++ ) {
s = list->ss[ i ];
if ( *s == 'p' ) {
if ( strnicmp( s + 1, "ANY", 3 ) == 0 ) {
if ( *ret == '\0' ) {
ret = s + 4;
}
}
if ( strnicmp( s + 1, my_air, 3 ) == 0 ) {
ret = s + 4;
}
} else if ( *s == 'P' ) {
ret = s + 1;
}
}
}
break;
default:
for ( i = min_i; i < max_i; i++ ) {
s = list->ss[ i ];
if ( *s == ch ) {
ret = s + 1;
}
}
}
return ret;
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
PVT_EXE void display_row_label( int but )
{
char *label;
field *fp, f;
/* get and copy a field for this label. */
/* if there is none, no need to display! */
fp = get_list_field( F_LABEL, but );
if ( fp == NULL ) return;
f = *fp;
/* find the label to be displayed. */
label = list_field_of( but, L_TEXT );
if ( *label == '\0' ) {
label = list_item_of( but );
}
/* change the color and the font as appropriate. */
if ( list->display == NO_DISP ) {
f.fg_color = fg_color_of_label( but, label );
f.font = get_dictionary( STRING, "LIST FONT" );
}
/* draw the label! */
draw_text_in_field( label, &f );
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
PVT_EXE void display_row_hashmark( int but )
{
int idx;
field *fp;
char *hash;
char hash2[ 80 ];
if ( list->enable_hashmarks == FALSE ) return;
/* get the field for the hashmark. */
fp = get_list_field( F_HASHMARK, but );
if ( fp == NULL ) return;
/* if it's a hash one, add a mark. */
idx = list_index_of( but );
if ( 1 || ( idx % list->hashmark_freq == 0 ) ) {
hash = get_dictionary( STRING, "Hash Mark" );
if ( ( hash == NULL ) || ( *hash == '\0' ) ) {
hash = "*";
}
sprintf( hash2, "%d", idx );
draw_text_in_field( hash2, fp );
}
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
PVT_EXE void clear_row( int but, char *chlist )
{
char *ch;
field *fp;
ch = chlist;
while ( *ch ) {
fp = get_list_field( *ch, but );
if ( ( fp != NULL ) && ( ! ( isnullrect( &(fp->disp) ) ) ) ) {
clear_text_in_field( fp );
}
ch++;
}
}
/* ------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------- */
PVT_EXE void display_row( int but, char *chlist )
{
char *ch, *data;
char dict[ 2 ] = " ";
field *fp;
/* fill in the [label] field. */
display_row_label( but );
/* fill in the [hashmark] field. */
display_row_hashmark( but );
/* now fill in all other fields. */
ch = chlist;
while ( *ch ) {
data = data_for_field( *ch, but );
if ( data != NULL ) {
fp = get_list_field( *ch, but );
if ( ( fp != NULL ) && ( ! ( isnullrect( &(fp->disp) ) ) ) ) {
draw_text_in_field( data, fp );
}
*dict = *ch;
add_dictionary( STRING, dict, data );
}
ch++;
}
}
/* ------------------------------------------------------------------------- */
/* display_list: redisplays the list. */
/* --------------------------------------------------------------------------*/
PUB_EXE void display_list( )
{
int row, idx;
char *fields;
list_resolve_curi( );
for ( row = 0; row < list->n_scroll; row++ ) {
if ( list->dirty[ row ] == TRUE ) {
fields = get_list_fields_of_row( row );
/* clear out this row. */
clear_row( row, fields );
/* if this row is in the list bounds, display it. */
idx = list_index_of( row );
if ( ( idx >= 0 ) && ( idx < list->ni ) ) {
display_row( row, fields );
}
}
list->dirty[ row ] = FALSE;
}
/* display the hermometer, if there is one. */
if ( list->enable_hermometer == TRUE ) {
show_hermometer( );
}
refresh_list_az_rects( );
}
Source code is:
© Copyright 1996, QuickATM. All rights reserved.