home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Simtel MSDOS 1992 June
/
SIMTEL_0692.cdr
/
msdos
/
desqview
/
dvglue10.arc
/
UIMBUILD.C
< prev
next >
Wrap
C/C++ Source or Header
|
1988-08-10
|
13KB
|
362 lines
/*======================================================*/
/* UIMBUILD.C */
/* */
/* (c) Copyright 1988 Ralf Brown. All Rights Reserved. */
/*======================================================*/
#include <mem.h>
#include <string.h>
#include "tvapi.h"
#include "tvstream.h"
#include "tvui.h"
/*======================================================*/
/*======================================================*/
#define physical_screen_height() ((*(BYTE far *)0x00400084L)+1)
#define physical_screen_width() (*(int far *)0x0040004AL)
#define PRIVATE(type) static type near pascal
#define HEADER_SIZE 4
/*======================================================*/
/*======================================================*/
static BYTE fixed_stream_header[] =
{
S_WINDOW(0), /* will fill in length later */
WS_HIDDEN, /* hide until we finish our setup */
WS_LSIZE(0,0), /* will fill in logical size later */
WS_WINPOS(0,0), /* will fill in window position later */
WS_WINSIZE(0,0), /* will fill in window size later */
WS_NOFRAME, /* we don't want a frame */
WS_LOGATTR, /* we want logical attributes */
WS_WRITEATTR, /* change attributes when writing */
WS_NOCTRLCHAR,
WS_SETCOLOR(1), /* use normal attribute */
WS_CLEAR, /* and clear screen to that color */
WS_SETCOLOR(3), /* change to border color */
WS_CURSPOS(0,1), /* home cursor */
WS_MANYCHAR(0,223), /* write top edge of border, fill in count later */
WS_SETCURSCOL(0), /* back to left edge */
WS_REPEAT(0), /* will fill in count later */
WS_CHARS(1),222, /* write left edge of border */
WS_SETCURSCOL(0), /* fill in later, moves to right edge */
WS_CHARS(1),221, /* write right edge of border */
WS_DOREPEAT,
WS_CURSPOS(0,1), /* fill in row later */
WS_MANYCHAR(0,220), /* write bottom edge of border, fill in count later */
WS_SETCOLOR(9), /* reverse video for title */
WS_SETCURSROW(1),
WS_SETCURSCOL(0), /* fill in column later */
WS_MANYCHARS(0), /* fill in count later */
/* rest of stream must be built at runtime */
} ;
static BYTE fixed_stream_trailer[] = {
WS_FLDCURS(1),
WS_UPDATE,
S_MANAGER(9), 0xBD, /* enable one of DESQview's extensions, don't know which */
MS_CURRFLDPOS, 0, 0,
MS_DISALLOW | TV_HMOVE,
MS_DISALLOW | TV_VMOVE,
MS_WINTOP, MS_FLDMARKER(0xAF) /* default field marker is » */
} ;
/*======================================================*/
/*======================================================*/
void * pascal UImenu_build(MENU_ITEM *menu_items,MENU_OPTIONS *menu_options)
{
register int tmp ;
int stream_size ;
BYTE *stream_start, *stream ;
int two_keys = FALSE ;
int phys_width = physical_screen_width() ;
int phys_height = physical_screen_height() ;
int num_fields = 0 ;
MENU_ITEM *menu_item ;
int width = 0 ;
int height = 4 ; /* top & bottom edges + title + key echo area */
int overhead ; /* how much space we need for menu's keystrokes */
int row, col ;
int line ;
/* find out whether we'll need one space or two for the menu's keystrokes */
for (menu_item = menu_items ; menu_item->type != M_END ; menu_item++)
if ((menu_item->type == M_ITEM || menu_item->type == M_SPECIAL) &&
menu_item->key2 != 0)
{
two_keys = TRUE ;
break ;
}
overhead = (two_keys ? 4 : 3) ;
/* determine how much memory to allocate for the stream, and simultaneously */
/* how big the menu window will be */
stream_size = sizeof( fixed_stream_header ) +
sizeof( fixed_stream_trailer ) +
strlen(menu_options->title) + sizeof(FT_HEADER) + 7 ;
for (menu_item = menu_items ; menu_item->type != M_END ; menu_item++)
{
switch (menu_item->type)
{
case M_ITEM:
if (menu_item->entry == NULL || *menu_item->entry == '\0')
return ME_BADITEM ;
tmp = strlen(menu_item->entry) ;
stream_size += tmp + ((two_keys && menu_item->key2 != 0) ? 11 : 10) ;
num_fields++ ;
if (tmp + overhead > width)
width = tmp + overhead ;
break ;
case M_HTEXT:
case M_TEXT:
stream_size += 4 ;
if (menu_item->entry && strlen(menu_item->entry) > 0)
{
tmp = strlen(menu_item->entry) ;
stream_size += tmp + ((menu_item->type == M_HTEXT) ? 6 : 2) ;
if (tmp > width)
width = tmp ;
}
break ;
case M_CENTER:
case M_HCENTER:
stream_size += 2 ;
if (menu_item->entry && strlen(menu_item->entry) > 0)
{
tmp = strlen(menu_item->entry) ;
stream_size += tmp + ((menu_item->type == M_HCENTER) ? 8 : 4) ;
if (tmp > width)
width = tmp ;
}
break ;
case M_SEP:
stream_size += 7 ;
break ;
case M_SPECIAL:
if (menu_item->entry == NULL || strchr(menu_item->entry,' ') == NULL)
return ME_BADITEM ;
tmp = strlen(menu_item->entry) ;
stream_size += tmp + 10 ;
num_fields++ ;
if (tmp > width)
width = tmp ;
break ;
case M_IGNORE:
/* do nothing */
break ;
default:
return ME_BADITEM ; /* indicate error */
}
if (menu_item->type != M_IGNORE)
height++ ;
}
stream_size += num_fields*sizeof(FT_ENTRY) ;
if (two_keys)
stream_size += sizeof(FT_ENTRY) ;
if (strlen(menu_options->title) > width)
width = strlen(menu_options->title) ;
width += 4 ; /* left & right edge, blanks just inside edges */
/* perform some simple error checks before proceeding */
if (height > phys_height || width > phys_width)
return ME_TOOBIG ;
if ((stream_start = (BYTE *)malloc(stream_size+HEADER_SIZE)) == NULL)
return ME_NOMEM ;
/* determine upper left corner of menu window */
if (menu_options->row < 0)
{
row = phys_height - height + menu_options->row + 1 ;
if (row < 0)
row = 0 ;
}
else
{
row = menu_options->row ;
if (row + height > phys_height)
row = phys_height - height ;
}
if (menu_options->col < 0)
{
col = phys_width - width + menu_options->col + 1 ;
if (col < 0)
col = 0 ;
}
else
{
col = menu_options->col ;
if (col + width > phys_width)
col = phys_width - width ;
}
/* start building the stream */
stream = stream_start ;
*((int *)stream)++ = stream_size ;
*((int *)stream)++ = num_fields ;
memcpy( stream, fixed_stream_header, sizeof( fixed_stream_header ) ) ;
*((int *)(stream+2)) = stream_size - sizeof( fixed_stream_trailer ) ;
stream[HEADER_SIZE+2] = height ;
stream[HEADER_SIZE+3] = width ;
stream[HEADER_SIZE+5] = row ;
stream[HEADER_SIZE+6] = col ;
stream[HEADER_SIZE+8] = height ;
stream[HEADER_SIZE+9] = width ;
stream[HEADER_SIZE+23] = width-2 ;
stream[HEADER_SIZE+28] = height ;
stream[HEADER_SIZE+32] = width-1 ;
stream[HEADER_SIZE+37] = height-1 ;
stream[HEADER_SIZE+40] = width-2 ;
stream += sizeof( fixed_stream_header ) ;
tmp = strlen(menu_options->title) ;
stream[-1] = tmp ;
stream[-3] = (width-tmp)/2 ;
memcpy( stream, menu_options->title, tmp ) ;
stream += tmp ;
*((int *)stream)++ = 0x01E2 ; /* set color back to normal */
*((int *)stream)++ = 0x02A0 ; /* skip next line */
for (menu_item = menu_items ; menu_item->type != M_END ; menu_item++)
if (menu_item->type != M_IGNORE)
{
*((int *)stream)++ = 0x01B0 ; /* move to start of next line */
switch (menu_item->type)
{
case M_ITEM:
*((int *)stream)++ = 0x02A1 ; /* leave a blank at start of line */
*stream++ = 0x98 ;
*stream++ = tmp = strlen(menu_item->entry) ;
memcpy((char *)stream,menu_item->entry,tmp) ;
stream += tmp ;
*stream++ = 0xB1 ;
*stream++ = width - tmp - (two_keys ? 6 : 5 ) ;
if (two_keys)
{
*stream++ = (menu_item->key2) ? 0x62 : 0x61 ;
*stream++ = (menu_item->key1) ? menu_item->key1 : ' ' ;
if (menu_item->key2)
*stream++ = menu_item->key2 ;
}
else
{
*stream++ = 0x61 ;
*stream++ = (menu_item->key1) ? menu_item->key1 : ' ' ;
}
break ;
case M_TEXT:
case M_HTEXT:
*((int *)stream)++ = 0x02A1 ; /* leave a blank at start of line */
if (menu_item->entry && (tmp = strlen(menu_item->entry)) > 0)
{
if (menu_item->type == M_HTEXT)
*((int *)stream)++ = 0x02E2 ; /* change to highlighted */
*stream++ = 0x98 ;
*stream++ = tmp ;
memcpy(stream,menu_item->entry,tmp) ;
stream += tmp ;
if (menu_item->type == M_HTEXT)
*((int *)stream)++ = 0x01E2 ; /* change back to normal */
}
break ;
case M_CENTER:
case M_HCENTER:
if (menu_item->entry && *menu_item->entry)
{
if (menu_item->type == M_HCENTER)
*((int *)stream)++ = 0x02E2 ; /* change to highlighted */
tmp = strlen(menu_item->entry) ;
*stream++ = 0xA1 ;
*stream++ = (width - tmp) / 2 ;
*stream++ = 0x98 ;
*stream++ = tmp ;
memcpy(stream,menu_item->entry,tmp) ;
stream += tmp ;
if (menu_item->type == M_HCENTER)
*((int *)stream)++ = 0x01E2 ; /* change back to normal */
}
break ;
case M_SEP:
*((int *)stream)++ = 0x01A1 ; /* don't leave a blank at start of line */
*stream++ = 0x88 ; /* replicate key across line */
*stream++ = width-2 ;
*stream++ = menu_item->key1 ;
break ;
case M_SPECIAL:
{
char *keyname = strrchr( menu_item->entry, ' ' ) + 1 ;
*((int *)stream)++ = 0x02A1 ; /* leave a blank at start of line */
*stream++ = 0x98 ;
*stream++ = tmp = keyname - menu_item->entry ;
memcpy( stream, menu_item->entry, tmp ) ;
stream += tmp ;
*stream++ = 0xB1 ; /* skip over to end of line */
*stream++ = width - 4 - tmp - strlen(keyname) ;
*stream++ = 0x98 ; /* show key to press */
*stream++ = tmp = strlen(keyname) ;
memcpy( stream, keyname, tmp ) ;
stream += tmp ;
}
break ;
}
}
*((int *)stream)++ = 0x18E5 ;
*stream++ = 0xFF ;
if (two_keys)
*stream++ = ((int *)stream_start)[1] + 1 ;
else
*stream++ = ((int *)stream_start)[1] ;
tmp = F_READARRAY ;
if (menu_options->allow_kbd)
tmp |= F_ALLOWKBD ;
if (menu_options->left_button)
tmp |= F_LEFTBUTTON ;
if (menu_options->right_button)
tmp |= F_RIGHTBUTTON ;
*stream++ = tmp ;
*((int *)stream)++ = 0 ;
*((int *)stream)++ = 0x0209 ;
menu_item = menu_items ;
line = 3 ;
while (menu_item->type != M_END)
{
if (menu_item->type == M_ITEM || menu_item->type == M_SPECIAL)
{
*stream++ = line ;
*stream++ = 1 ;
*stream++ = line ;
*stream++ = width-2 ;
*stream++ = (menu_item->selected) ? 0xC0 : 0xC0 | F_SELECTED ;
*stream++ = menu_item->key1 ;
*stream++ = 1 ;
*stream++ = two_keys ? menu_item->key2 : 0 ;
}
if (menu_item->type != M_IGNORE)
line++ ;
menu_item++ ;
}
if (two_keys)
{
*stream++ = 2 ;
*stream++ = (width+1)/2-1 ;
*stream++ = 2 ;
*stream++ = (width+1)/2-1 ;
*stream++ = 0x40 ;
*stream++ = 0 ;
*stream++ = 0 ;
*stream++ = 0 ;
}
memcpy( stream, fixed_stream_trailer, sizeof( fixed_stream_trailer )) ;
if (menu_options->marker)
stream[sizeof(fixed_stream_trailer)-1] = menu_options->marker ;
return (void *) stream_start ;
}
/* End of UIMBUILD.C */