/*=============================================================================
    Name    : UIcontrols.c
    Purpose : Functions for basic UI control types (buttons etc.)

    Created 7/7/1997 by lmoloney
    Copyright Relic Entertainment, Inc.  All rights reserved.
=============================================================================*/

#ifndef SW_Render
#include <windows.h>
#endif
#include "glinc.h"
#include "types.h"
#include "region.h"
#include "color.h"
#include "prim2d.h"
#include "mouse.h"
#include "font.h"
#include "fontreg.h"
#include "soundevent.h"
#include "uicontrols.h"
#include "scroller.h"
#include "scenpick.h"
#include "FeReg.h"
#include "mainswitches.h"
#include "mouse.h"
#include "universe.h"
#include "utility.h"
#include "task.h"
#include "strings.h"

#include "glcaps.h"

// Keyboard navigation callback functions
#define ATOM_FLAG   0
#define REGION_FLAG 1

/*=============================================================================
    Data:
=============================================================================*/

color FEC_ListItemTranslucent;
color FEC_ListItemTranslucentBorder;
color FEC_ListItemStandard;
color FEC_ListItemSelected;
color FEC_ListItemInactive;
color FEC_ListItemInvalid;
color FEC_Background;

color TB_SelectedColor = colRGB(255,255,255);
color TB_HyperspaceColor = colRGB(32,220,32);
color TB_CompleteColor = colRGB(0,160,200);
color TB_IncompleteColor = colRGB(25,90,90);

scriptEntry FrontEndColourTweaks[] =
{
    makeEntry(FEC_ListItemTranslucent, scriptSetRGBACB),
    makeEntry(FEC_ListItemTranslucentBorder, scriptSetRGBCB),
    makeEntry(FEC_ListItemStandard, scriptSetRGBCB),
    makeEntry(FEC_ListItemSelected, scriptSetRGBCB),
    makeEntry(FEC_ListItemInactive, scriptSetRGBCB),
    makeEntry(FEC_ListItemInvalid, scriptSetRGBCB),
    makeEntry(FEC_Background, scriptSetRGBCB),
    makeEntry(TB_SelectedColor, scriptSetRGBCB),
    makeEntry(TB_HyperspaceColor, scriptSetRGBCB),
    makeEntry(TB_CompleteColor, scriptSetRGBCB),
    makeEntry(TB_IncompleteColor, scriptSetRGBCB),
    endEntry
};

void uicButtonDraw(regionhandle reg);
udword uicButtonProcess(regionhandle region, sdword ID, udword event, udword data);
void uicToggleDraw(regionhandle reg);
udword uicToggleProcess(regionhandle region, sdword ID, udword event, udword data);
void uicCheckBoxDraw(regionhandle reg);
udword uicRadioButtonProcess(regionhandle region, sdword ID, udword event, udword data);
void uicRadioButtonDraw(regionhandle reg);
udword uicScrollBarProcess(regionhandle region, sdword ID, udword event, udword data);
void uicScrollBarDraw(regionhandle reg);
void uicScrollBarButtonDraw(regionhandle reg);
udword uicListWindowProcess(regionhandle region, sdword ID, udword event, udword data);
void uicListWindowDraw(regionhandle reg);
udword uicTextEntryProcess(regionhandle reg, sdword ID, udword event, udword data);
void uicTextEntryDraw(regionhandle reg);
//udword uicBitmapButtonProcess(regionhandle reg, sdword ID, udword event, udword data);
void uicBitmapButtonDraw(regionhandle reg);
udword uicHorizSliderProcess(regionhandle region, sdword ID, udword event, udword data);
udword uicVertSliderProcess(regionhandle region, sdword ID, udword event, udword data);
void uicHorizSliderDraw(regionhandle reg);
void uicVertSliderDraw(regionhandle reg);
udword uicDragButtonProcess(regionhandle region, sdword ID, udword event, udword data);

bool uicClearCurrent(regionhandle reg);
void uicSetCurrent(regionhandle reg, bool bUserInput);
void uicLimitTabstop(sdword num_buttons);

//global variables to pass drag information
sdword uicDragX = 0;
sdword uicDragY = 0;

//table of process/draw functions and region filters for a variety of control types
struct
{
    regionfunction function;
    regiondrawfunction drawFunction;
    udword regionFilter;
}
uicControlFunctions[] =
{
    {NULL,                      NULL,               0},             //Nothing
    {NULL,                      NULL,               0},             //FA_UserRegion = 1,
    {NULL,                      NULL,               0},             //FA_StaticText,
    {uicButtonProcess,          uicButtonDraw,      UIF_Button},    //FA_Button,
    {uicToggleProcess,          uicCheckBoxDraw,    UIF_Button},    //FA_CheckBox,
    {uicToggleProcess,          uicToggleDraw,      UIF_Button},    //FA_ToggleButton,
    {NULL,                      NULL,               0},             //FA_HorizScrollBar,
    {NULL,                      NULL,               0},             //FA_VerticalScrollBar,
    {NULL,                      NULL,               0},             //FA_TextEntry,
    {NULL,                      NULL,               0},             //FA_ListViewExpandButton,
    {NULL,                      NULL,               0},             //FA_TitleBar,
    {NULL,                      NULL,               0},             //FA_MenuItem,
    {uicRadioButtonProcess,     uicRadioButtonDraw, UIF_Button},    //FA_RadioButton,
    {NULL,                      NULL,               0},             //FA_CutoutRegion,
    {NULL,                      NULL,               0},             //FA_DecorativeRegion,
    {NULL,                      NULL,               0},             //FA_Divider,
    {NULL,                      NULL,               0},             //FA_ListWindow,
    {uicToggleProcess,          uicBitmapButtonDraw,UIF_Button},    //FA_BitmapButton,
    {uicHorizSliderProcess,     uicHorizSliderDraw, UIF_Button},    //FA_HorizSlider,
    {uicVertSliderProcess,      uicVertSliderDraw,  UIF_Button},     //FA_VertSlider,
    {uicDragButtonProcess,      uicButtonDraw,      UIF_DragButton} //FA_DragButton,
};
//space characters to delineate words for CTRL-cursor movement
char uicSpaceCharacters[] = " \\/()`'\".,";

typedef struct uicKeyTable
{
    char regularKey;
    char shiftKey;
} uicKeyTable;

uicKeyTable uicKeyEntryTable[KEY_TOTAL_KEYS] =
{
    /*            0 0  */  0,    0,
    /*              1  */  0,    0,
    /*              2  */  0,    0,
    /*              3  */  0,    0,
    /*              4  */  0,    0,
    /*              5  */  0,    0,
    /*              6  */  0,    0,
    /*              7  */  0,    0,
    /*              8  */  0,    0,
    /*              9  */  0,    0,
    /*              10 */  0,    0,
    /*              11 */  0,    0,
    /*              12 */  0,    0,
    /*              13 */  0,    0,
    /*              14 */  0,    0,
    /*              15 */  0,    0,
    /*           16 16 */  0,    0,
    /*              17 */  0,    0,
    /*              18 */  0,    0,
    /*              19 */  0,    0,
    /*              20 */  0,    0,
    /*              21 */  0,    0,
    /*              22 */  0,    0,
    /*              23 */  0,    0,
    /*              24 */  0,    0,
    /*              25 */  0,    0,
    /*              26 */  0,    0,
    /*              27 */  0,    0,
    /*              28 */  0,    0,
    /*              29 */  0,    0,
    /*              30 */  0,    0,
    /*              31 */  0,    0,
    /* space     32 32 */  ' ',  ' ',
    /*              33 */  0,    0,
    /*              34 */  0,    0,
    /*              35 */  0,    0,
    /*              36 */  0,    0,
    /*              37 */  0,    0,
    /*              38 */  0,    0,
    /* punctuation  39 */  0,    0,
    /*              40 */  0,    0,
    /*              41 */  0,    0,
    /*              42 */  0,    0,
    /*              43 */  0,    0,
    /*              44 */  0,    0,
    /*              45 */  '-',  '_',
    /*              46 */  0,    0,
    /*              47 */  0,    0,
    /* 0         48 48 */  '0',  ')',
    /* 1            49 */  '1',  '!',
    /* 2            50 */  '2',  '@',
    /* 3            51 */  '3',  '#',
    /* 4            52 */  '4',  '$',
    /* 5            53 */  '5',  '%',
    /* 6            54 */  '6',  '^',
    /* 7            55 */  '7',  '&',
    /* 8            56 */  '8',  '*',
    /* 9            57 */  '9',  '(',
    /* :            58 */  ':',  0,
    /* ;            59 */  ';',  0,
    /* <            60 */  '<',  0,
    /* =            61 */  '=',  '+',
    /* >            62 */  '>',  0,
    /* ?            63 */  '?',  0,
    /* @         64 64 */  '@',  0,
    /* A            65 */  'a',  'A',
    /* B            66 */  'b',  'B',
    /* C            67 */  'c',  'C',
    /* D            68 */  'd',  'D',
    /* E            69 */  'e',  'E',
    /* F            70 */  'f',  'F',
    /* G            71 */  'g',  'G',
    /* H            72 */  'h',  'H',
    /* I            73 */  'i',  'I',
    /* J            74 */  'j',  'J',
    /* K            75 */  'k',  'K',
    /* L            76 */  'l',  'L',
    /* M            77 */  'm',  'M',
    /* N            78 */  'n',  'N',
    /* O            79 */  'o',  'O',
    /* P         80 80 */  'p',  'P',
    /* Q            81 */  'q',  'Q',
    /* R            82 */  'r',  'R',
    /* S            83 */  's',  'S',
    /* T            84 */  't',  'T',
    /* U            85 */  'u',  'U',
    /* V            86 */  'v',  'V',
    /* W            87 */  'w',  'W',
    /* X            88 */  'x',  'X',
    /* Y            89 */  'y',  'Y',
    /* Z            90 */  'z',  'Z',
    /*              91 */  0,    0,
    /*              92 */  0,    0,
    /*              93 */  0,    0,
    /*              94 */  0,    0,
    /*              95 */  0,    0,
    /*           96 96 */  '0',  0,
    /*              97 */  '1',  0,
    /*              98 */  '2',  0,
    /*              99 */  '3',  0,
    /*              100*/  '4',  0,
    /*              101*/  '5',  0,
    /*              102*/  '6',  0,
    /*              103*/  '7',  0,
    /*              104*/  '8',  0,
    /*              105*/  '9',  0,
    /*              106*/  '*',  0,
    /*              107*/  '+',  0,
    /*              108*/  0,    0,
    /*              109*/  '-',  0,
    /*              110*/  '.',  0,
    /*              111*/  '/',  0,
    /*          112 112*/  0,    0,
    /*              113*/  0,    0,
    /*              114*/  0,    0,
    /*              115*/  0,    0,
    /*              116*/  0,    0,
    /*              117*/  0,    0,
    /*              118*/  0,    0,
    /*              119*/  0,    0,
    /*              120*/  0,    0,
    /*              121*/  0,    0,
    /*              122*/  0,    0,
    /*              123*/  0,    0,
    /*              124*/  0,    0,
    /*              125*/  0,    0,
    /*              126*/  0,    0,
    /*              127*/  0,    0,
    /*          128 128*/  0,    0,
    /*              129*/  0,    0,
    /*              130*/  0,    0,
    /*              131*/  0,    0,
    /*              132*/  0,    0,
    /*              133*/  0,    0,
    /*              134*/  0,    0,
    /*              135*/  0,    0,
    /*              136*/  0,    0,
    /*              137*/  0,    0,
    /*              138*/  0,    0,
    /*              139*/  0,    0,
    /*              140*/  0,    0,
    /*              141*/  0,    0,
    /*              142*/  0,    0,
    /*              143*/  0,    0,
    /*          144 144*/  0,    0,
    /*              145*/  0,    0,
    /*              146*/  0,    0,
    /*              147*/  0,    0,
    /*              148*/  0,    0,
    /*              149*/  0,    0,
    /*              150*/  0,    0,
    /*              151*/  0,    0,
    /*              152*/  0,    0,
    /*              153*/  0,    0,
    /*              154*/  0,    0,
    /*              155*/  0,    0,
    /*              156*/  0,    0,
    /*              157*/  0,    0,
    /*              158*/  0,    0,
    /*              159*/  0,    0,
    /*          160 160*/  0,    0,
    /*              161*/  0,    0,
    /*              162*/  0,    0,
    /*              163*/  0,    0,
    /*              164*/  0,    0,
    /*              165*/  0,    0,
    /*              166*/  0,    0,
    /*              167*/  0,    0,
    /*              168*/  0,    0,
    /*              169*/  0,    0,
    /*              170*/  0,    0,
    /*              171*/  0,    0,
    /*              172*/  0,    0,
    /*              173*/  0,    0,
    /*              174*/  0,    0,
    /*              175*/  0,    0,
    /*          176 176*/  0,    0,
    /*              177*/  0,    0,
    /*              178*/  0,    0,
    /*              179*/  0,    0,
    /*              180*/  0,    0,
    /*              181*/  0,    0,
    /*              182*/  0,    0,
    /*              183*/  0,    0,
    /*              184*/  0,    0,
    /*              185*/  0,    0,
    /*              186*/  ';',  ':',
    /*              187*/  '=',  '+',
    /*              188*/  ',',  '<',
    /*              189*/  '-',  '_',
    /*              190*/  '.',  '>',
    /*              191*/  '/',  '?',
    /*          192 192*/  '`',  '~',
    /*              193*/  0,    0,
    /*              194*/  0,    0,
    /*              195*/  0,    0,
    /*              196*/  0,    0,
    /*              197*/  0,    0,
    /*              198*/  0,    0,
    /*              199*/  0,    0,
    /*              200*/  0,    0,
    /*              201*/  0,    0,
    /*              202*/  0,    0,
    /*              203*/  0,    0,
    /*              204*/  0,    0,
    /*              205*/  0,    0,
    /*              206*/  0,    0,
    /*              207*/  0,    0,
    /*          208 208*/  0,    0,
    /*              209*/  0,    0,
    /*              210*/  0,    0,
    /*              211*/  0,    0,
    /*              212*/  0,    0,
    /*              213*/  0,    0,
    /*              214*/  0,    0,
    /*              215*/  0,    0,
    /*              216*/  0,    0,
    /*              217*/  0,    0,
    /*              218*/  0,    0,
    /*              219*/  '[',  '{',
    /*              220*/  '\\', '|',
    /*              221*/  ']',  '}',
    /*              222*/  '\'',  '"',
    /*              223*/  0,    0,
    /*          224 224*/  0,    0,
    /*              225*/  0,    0,
    /*              226*/  0,    0,
    /*              227*/  0,    0,
    /*              228*/  0,    0,
    /*              229*/  0,    0,
    /*              230*/  0,    0,
    /*              231*/  0,    0,
    /*              232*/  0,    0,
    /*              233*/  0,    0,
    /*              234*/  0,    0,
    /*              235*/  0,    0,
    /*              236*/  0,    0,
    /*              237*/  0,    0,
    /*              238*/  0,    0,
    /*              239*/  0,    0,
    /*          240 240*/  0,    0,
    /*              241*/  0,    0,
    /*              242*/  0,    0,
    /*              243*/  0,    0,
    /*              244*/  0,    0,
    /*              245*/  0,    0,
    /*              246*/  0,    0,
    /*              247*/  0,    0,
    /*              248*/  0,    0,
    /*              249*/  0,    0,
    /*              250*/  0,    0,
    /*              251*/  0,    0,
    /*              252*/  0,    0,
    /*              253*/  0,    0,
    /*              254*/  0,    0,
    /*              255*/  0,    0,
};

uicKeyTable uicFrenchKeyEntryTable[KEY_TOTAL_KEYS] =
{
    /*            0 0  */  0,    0,
    /*              1  */  0,    0,
    /*              2  */  0,    0,
    /*              3  */  0,    0,
    /*              4  */  0,    0,
    /*              5  */  0,    0,
    /*              6  */  0,    0,
    /*              7  */  0,    0,
    /*              8  */  0,    0,
    /*              9  */  0,    0,
    /*              10 */  0,    0,
    /*              11 */  0,    0,
    /*              12 */  0,    0,
    /*              13 */  0,    0,
    /*              14 */  0,    0,
    /*              15 */  0,    0,
    /*           16 16 */  0,    0,
    /*              17 */  0,    0,
    /*              18 */  0,    0,
    /*              19 */  0,    0,
    /*              20 */  0,    0,
    /*              21 */  0,    0,
    /*              22 */  0,    0,
    /*              23 */  0,    0,
    /*              24 */  0,    0,
    /*              25 */  0,    0,
    /*              26 */  0,    0,
    /*              27 */  0,    0,
    /*              28 */  0,    0,
    /*              29 */  0,    0,
    /*              30 */  0,    0,
    /*              31 */  0,    0,
    /* space     32 32 */  ' ',  ' ',
    /*              33 */  0,    0,
    /*              34 */  0,    0,
    /*              35 */  0,    0,
    /*              36 */  0,    0,
    /*              37 */  0,    0,
    /*              38 */  0,    0,
    /* punctuation  39 */  0,    0,
    /*              40 */  0,    0,
    /*              41 */  0,    0,
    /*              42 */  0,    0,
    /*              43 */  0,    0,
    /*              44 */  ',',  '?',
    /*              45 */  '-',  '_',
    /*              46 */  0,    0,
    /*              47 */  0,    0,
    /* 0         48 48 */  '',  '0',
    /* 1            49 */  '&',  '1',
    /* 2            50 */  '',  '2',
    /* 3            51 */  '"',  '3',
    /* 4            52 */  '\'', '4',
    /* 5            53 */  '(',  '5',
    /* 6            54 */  '-',  '6',
    /* 7            55 */  '',  '7',
    /* 8            56 */  '_',  '8',
    /* 9            57 */  '',  '9',
    /* :            58 */  ':',  0,
    /* ;            59 */  ';',  0,
    /* <            60 */  '<',  0,
    /* =            61 */  '=',  '+',
    /* >            62 */  '>',  0,
    /* ?            63 */  '?',  0,
    /* @         64 64 */  '@',  0,
    /* A            65 */  'a',  'A',
    /* B            66 */  'b',  'B',
    /* C            67 */  'c',  'C',
    /* D            68 */  'd',  'D',
    /* E            69 */  'e',  'E',
    /* F            70 */  'f',  'F',
    /* G            71 */  'g',  'G',
    /* H            72 */  'h',  'H',
    /* I            73 */  'i',  'I',
    /* J            74 */  'j',  'J',
    /* K            75 */  'k',  'K',
    /* L            76 */  'l',  'L',
    /* M            77 */  'm',  'M',
    /* N            78 */  'n',  'N',
    /* O            79 */  'o',  'O',
    /* P         80 80 */  'p',  'P',
    /* Q            81 */  'q',  'Q',
    /* R            82 */  'r',  'R',
    /* S            83 */  's',  'S',
    /* T            84 */  't',  'T',
    /* U            85 */  'u',  'U',
    /* V            86 */  'v',  'V',
    /* W            87 */  'w',  'W',
    /* X            88 */  'x',  'X',
    /* Y            89 */  'y',  'Y',
    /* Z            90 */  'z',  'Z',
    /*              91 */  0,    0,
    /*              92 */  0,    0,
    /*              93 */  0,    0,
    /*              94 */  0,    0,
    /*              95 */  0,    0,
    /*           96 96 */  '0',  0,
    /*              97 */  '1',  0,
    /*              98 */  '2',  0,
    /*              99 */  '3',  0,
    /*              100*/  '4',  0,
    /*              101*/  '5',  0,
    /*              102*/  '6',  0,
    /*              103*/  '7',  0,
    /*              104*/  '8',  0,
    /*              105*/  '9',  0,
    /*              106*/  '*',  0,
    /*              107*/  '+',  0,
    /*              108*/  0,    0,
    /*              109*/  '-',  0,
    /*              110*/  '.',  0,
    /*              111*/  '/',  0,
    /*          112 112*/  0,    0,
    /*              113*/  0,    0,
    /*              114*/  0,    0,
    /*              115*/  0,    0,
    /*              116*/  0,    0,
    /*              117*/  0,    0,
    /*              118*/  0,    0,
    /*              119*/  0,    0,
    /*              120*/  0,    0,
    /*              121*/  0,    0,
    /*              122*/  0,    0,
    /*              123*/  0,    0,
    /*              124*/  0,    0,
    /*              125*/  0,    0,
    /*              126*/  0,    0,
    /*              127*/  0,    0,
    /*          128 128*/  0,    0,
    /*              129*/  0,    0,
    /*              130*/  0,    0,
    /*              131*/  0,    0,
    /*              132*/  0,    0,
    /*              133*/  0,    0,
    /*              134*/  0,    0,
    /*              135*/  0,    0,
    /*              136*/  0,    0,
    /*              137*/  0,    0,
    /*              138*/  0,    0,
    /*              139*/  0,    0,
    /*              140*/  0,    0,
    /*              141*/  0,    0,
    /*              142*/  0,    0,
    /*              143*/  0,    0,
    /*          144 144*/  0,    0,
    /*              145*/  0,    0,
    /*              146*/  0,    0,
    /*              147*/  0,    0,
    /*              148*/  0,    0,
    /*              149*/  0,    0,
    /*              150*/  0,    0,
    /*              151*/  0,    0,
    /*              152*/  0,    0,
    /*              153*/  0,    0,
    /*              154*/  0,    0,
    /*              155*/  0,    0,
    /*              156*/  0,    0,
    /*              157*/  0,    0,
    /*              158*/  0,    0,
    /*              159*/  0,    0,
    /*          160 160*/  0,    0,
    /*              161*/  0,    0,
    /*              162*/  0,    0,
    /*              163*/  0,    0,
    /*              164*/  0,    0,
    /*              165*/  0,    0,
    /*              166*/  0,    0,
    /*              167*/  '!',  '',
    /*              168*/  0,    0,
    /*              169*/  0,    0,
    /*              170*/  0,    0,
    /*              171*/  0,    0,
    /*              172*/  0,    0,
    /*              173*/  0,    0,
    /*              174*/  0,    0,
    /*              175*/  0,    0,
    /*          176 176*/  0,    0,
    /*              177*/  0,    0,
    /*              178*/  0,    0,
    /*              179*/  0,    0,
    /*              180*/  0,    0,
    /*              181*/  0,    0,
    /*              182*/  0,    0,
    /*              183*/  0,    0,
    /*              184*/  0,    0,
    /*              185*/  0,    0,
    /*              186*/  ';',  ':',
    /*              187*/  '=',  '+',
    /*              188*/  ';',  '.',
    /*              189*/  ')',  '',
    /*              190*/  ':',  '/',
    /*              191*/  '/',  '?',
    /*          192 192*/  '',  0,
    /*              193*/  0,    0,
    /*              194*/  0,    0,
    /*              195*/  0,    0,
    /*              196*/  0,    0,
    /*              197*/  0,    0,
    /*              198*/  0,    0,
    /*              199*/  0,    0,
    /*              200*/  0,    0,
    /*              201*/  0,    0,
    /*              202*/  0,    0,
    /*              203*/  0,    0,
    /*              204*/  0,    0,
    /*              205*/  0,    0,
    /*              206*/  0,    0,
    /*              207*/  0,    0,
    /*          208 208*/  0,    0,
    /*              209*/  0,    0,
    /*              210*/  0,    0,
    /*              211*/  0,    0,
    /*              212*/  0,    0,
    /*              213*/  0,    0,
    /*              214*/  0,    0,
    /*              215*/  0,    0,
    /*              216*/  0,    0,
    /*              217*/  0,    0,
    /*              218*/  0,    0,
    /*              219*/  '',  '',
    /*              220*/  '*',  '',
    /*              221*/  '$',  '',
    /*              222*/  '\'',  '"',
    /*              223*/  0,    0,
    /*          224 224*/  0,    0,
    /*              225*/  0,    0,
    /*              226*/  0,    0,
    /*              227*/  0,    0,
    /*              228*/  0,    0,
    /*              229*/  0,    0,
    /*              230*/  0,    0,
    /*              231*/  0,    0,
    /*              232*/  0,    0,
    /*              233*/  0,    0,
    /*              234*/  0,    0,
    /*              235*/  0,    0,
    /*              236*/  0,    0,
    /*              237*/  0,    0,
    /*              238*/  0,    0,
    /*              239*/  0,    0,
    /*          240 240*/  0,    0,
    /*              241*/  0,    0,
    /*              242*/  0,    0,
    /*              243*/  0,    0,
    /*              244*/  0,    0,
    /*              245*/  0,    0,
    /*              246*/  0,    0,
    /*              247*/  0,    0,
    /*              248*/  0,    0,
    /*              249*/  '',  '%',
    /*              250*/  0,    0,
    /*              251*/  0,    0,
    /*              252*/  0,    0,
    /*              253*/  0,    0,
    /*              254*/  0,    0,
    /*              255*/  0,    0,
};

uicKeyTable uicGermanKeyEntryTable[KEY_TOTAL_KEYS] =
{
    /*            0 0  */  0,    0,
    /*              1  */  0,    0,
    /*              2  */  0,    0,
    /*              3  */  0,    0,
    /*              4  */  0,    0,
    /*              5  */  0,    0,
    /*              6  */  0,    0,
    /*              7  */  0,    0,
    /*              8  */  0,    0,
    /*              9  */  0,    0,
    /*              10 */  0,    0,
    /*              11 */  0,    0,
    /*              12 */  0,    0,
    /*              13 */  0,    0,
    /*              14 */  0,    0,
    /*              15 */  0,    0,
    /*           16 16 */  0,    0,
    /*              17 */  0,    0,
    /*              18 */  0,    0,
    /*              19 */  0,    0,
    /*              20 */  0,    0,
    /*              21 */  0,    0,
    /*              22 */  0,    0,
    /*              23 */  0,    0,
    /*              24 */  0,    0,
    /*              25 */  0,    0,
    /*              26 */  0,    0,
    /*              27 */  0,    0,
    /*              28 */  0,    0,
    /*              29 */  0,    0,
    /*              30 */  0,    0,
    /*              31 */  0,    0,
    /* space     32 32 */  ' ',  ' ',
    /*              33 */  0,    0,
    /*              34 */  0,    0,
    /*              35 */  0,    0,
    /*              36 */  0,    0,
    /*              37 */  0,    0,
    /*              38 */  0,    0,
    /* punctuation  39 */  0,    0,
    /*              40 */  0,    0,
    /*              41 */  0,    0,
    /*              42 */  0,    0,
    /*              43 */  0,    0,
    /*              44 */  ',',  '?',
    /*              45 */  0,    0,
    /*              46 */  0,    0,
    /*              47 */  0,    0,
    /* 0         48 48 */  '0',  '=',
    /* 1            49 */  '1',  '!',
    /* 2            50 */  '2',  '"',
    /* 3            51 */  '3',  '',
    /* 4            52 */  '4',  '$',
    /* 5            53 */  '5',  '%',
    /* 6            54 */  '6',  '&',
    /* 7            55 */  '7',  '/',
    /* 8            56 */  '8',  '(',
    /* 9            57 */  '9',  ')',
    /* :            58 */  ':',  0,
    /* ;            59 */  ';',  0,
    /* <            60 */  '<',  0,
    /* =            61 */  '=',  0,
    /* >            62 */  '>',  0,
    /* ?            63 */  '?',  0,
    /* @         64 64 */  '@',  0,
    /* A            65 */  'a',  'A',
    /* B            66 */  'b',  'B',
    /* C            67 */  'c',  'C',
    /* D            68 */  'd',  'D',
    /* E            69 */  'e',  'E',
    /* F            70 */  'f',  'F',
    /* G            71 */  'g',  'G',
    /* H            72 */  'h',  'H',
    /* I            73 */  'i',  'I',
    /* J            74 */  'j',  'J',
    /* K            75 */  'k',  'K',
    /* L            76 */  'l',  'L',
    /* M            77 */  'm',  'M',
    /* N            78 */  'n',  'N',
    /* O            79 */  'o',  'O',
    /* P         80 80 */  'p',  'P',
    /* Q            81 */  'q',  'Q',
    /* R            82 */  'r',  'R',
    /* S            83 */  's',  'S',
    /* T            84 */  't',  'T',
    /* U            85 */  'u',  'U',
    /* V            86 */  'v',  'V',
    /* W            87 */  'w',  'W',
    /* X            88 */  'x',  'X',
    /* Y            89 */  'y',  'Y',
    /* Z            90 */  'z',  'Z',
    /*              91 */  0,    0,
    /*              92 */  0,    0,
    /*              93 */  0,    0,
    /*              94 */  0,    0,
    /*              95 */  0,    0,
    /*           96 96 */  '0',  0,
    /*              97 */  '1',  0,
    /*              98 */  '2',  0,
    /*              99 */  '3',  0,
    /*              100*/  '4',  0,
    /*              101*/  '5',  0,
    /*              102*/  '6',  0,
    /*              103*/  '7',  0,
    /*              104*/  '8',  0,
    /*              105*/  '9',  0,
    /*              106*/  '*',  0,
    /*              107*/  '+',  0,
    /*              108*/  0,    0,
    /*              109*/  '-',  0,
    /*              110*/  '.',  0,
    /*              111*/  '/',  0,
    /*          112 112*/  0,    0,
    /*              113*/  0,    0,
    /*              114*/  0,    0,
    /*              115*/  0,    0,
    /*              116*/  0,    0,
    /*              117*/  0,    0,
    /*              118*/  0,    0,
    /*              119*/  0,    0,
    /*              120*/  0,    0,
    /*              121*/  0,    0,
    /*              122*/  0,    0,
    /*              123*/  0,    0,
    /*              124*/  0,    0,
    /*              125*/  0,    0,
    /*              126*/  0,    0,
    /*              127*/  0,    0,
    /*          128 128*/  0,    0,
    /*              129*/  0,    0,
    /*              130*/  0,    0,
    /*              131*/  0,    0,
    /*              132*/  0,    0,
    /*              133*/  0,    0,
    /*              134*/  0,    0,
    /*              135*/  0,    0,
    /*              136*/  0,    0,
    /*              137*/  0,    0,
    /*              138*/  0,    0,
    /*              139*/  0,    0,
    /*              140*/  0,    0,
    /*              141*/  0,    0,
    /*              142*/  0,    0,
    /*              143*/  0,    0,
    /*          144 144*/  0,    0,
    /*              145*/  0,    0,
    /*              146*/  0,    0,
    /*              147*/  0,    0,
    /*              148*/  0,    0,
    /*              149*/  0,    0,
    /*              150*/  0,    0,
    /*              151*/  0,    0,
    /*              152*/  0,    0,
    /*              153*/  0,    0,
    /*              154*/  0,    0,
    /*              155*/  0,    0,
    /*              156*/  0,    0,
    /*              157*/  0,    0,
    /*              158*/  0,    0,
    /*              159*/  0,    0,
    /*          160 160*/  0,    0,
    /*              161*/  0,    0,
    /*              162*/  0,    0,
    /*              163*/  0,    0,
    /*              164*/  0,    0,
    /*              165*/  0,    0,
    /*              166*/  0,    0,
    /*              167*/  0,    0,
    /*              168*/  0,    0,
    /*              169*/  0,    0,
    /*              170*/  0,    0,
    /*              171*/  0,    0,
    /*              172*/  0,    0,
    /*              173*/  0,    0,
    /*              174*/  0,    0,
    /*              175*/  0,    0,
    /*          176 176*/  0,    0,
    /*              177*/  0,    0,
    /*              178*/  0,    0,
    /*              179*/  0,    0,
    /*              180*/  0,    0,
    /*              181*/  0,    0,
    /*              182*/  0,    0,
    /*              183*/  0,    0,
    /*              184*/  0,    0,
    /*              185*/  0,    0,
    /*              186*/  ';',  ':',
    /*              187*/  '',  '`',
    /*              188*/  ',',  ';',
    /*              189*/  '',  '?',
    /*              190*/  '.',  ':',
    /*              191*/  '/',  '?',
    /*          192 192*/  '',  '',
    /*              193*/  0,    0,
    /*              194*/  0,    0,
    /*              195*/  0,    0,
    /*              196*/  0,    0,
    /*              197*/  0,    0,
    /*              198*/  0,    0,
    /*              199*/  0,    0,
    /*              200*/  '-',  '_',
    /*              201*/  0,    0,
    /*              202*/  0,    0,
    /*              203*/  0,    0,
    /*              204*/  0,    0,
    /*              205*/  0,    0,
    /*              206*/  0,    0,
    /*              207*/  0,    0,
    /*          208 208*/  0,    0,
    /*              209*/  0,    0,
    /*              210*/  0,    0,
    /*              211*/  0,    0,
    /*              212*/  0,    0,
    /*              213*/  0,    0,
    /*              214*/  0,    0,
    /*              215*/  0,    0,
    /*              216*/  0,    0,
    /*              217*/  0,    0,
    /*              218*/  0,    0,
    /*              219*/  '',  '',
    /*              220*/  '#',  '\'',
    /*              221*/  '+',  '*',
    /*              222*/  '\'', '"',
    /*              223*/  0,    0,
    /*          224 224*/  0,    0,
    /*              225*/  0,    0,
    /*              226*/  0,    0,
    /*              227*/  0,    0,
    /*              228*/  '',  '',
    /*              229*/  0,    0,
    /*              230*/  0,    0,
    /*              231*/  0,    0,
    /*              232*/  0,    0,
    /*              233*/  0,    0,
    /*              234*/  0,    0,
    /*              235*/  0,    0,
    /*              236*/  0,    0,
    /*              237*/  0,    0,
    /*              238*/  0,    0,
    /*              239*/  0,    0,
    /*          240 240*/  0,    0,
    /*              241*/  0,    0,
    /*              242*/  0,    0,
    /*              243*/  0,    0,
    /*              244*/  0,    0,
    /*              245*/  0,    0,
    /*              246*/  '',  '',
    /*              247*/  0,    0,
    /*              248*/  0,    0,
    /*              249*/  0,    0,
    /*              250*/  0,    0,
    /*              251*/  0,    0,
    /*              252*/  0,    0,
    /*              253*/  0,    0,
    /*              254*/  0,    0,
    /*              255*/  0,    0,
};

uicKeyTable uicSpanishKeyEntryTable[KEY_TOTAL_KEYS] =
{
    /*            0 0  */  0,    0,
    /*              1  */  0,    0,
    /*              2  */  0,    0,
    /*              3  */  0,    0,
    /*              4  */  0,    0,
    /*              5  */  0,    0,
    /*              6  */  0,    0,
    /*              7  */  0,    0,
    /*              8  */  0,    0,
    /*              9  */  0,    0,
    /*              10 */  0,    0,
    /*              11 */  0,    0,
    /*              12 */  0,    0,
    /*              13 */  0,    0,
    /*              14 */  0,    0,
    /*              15 */  0,    0,
    /*           16 16 */  0,    0,
    /*              17 */  0,    0,
    /*              18 */  0,    0,
    /*              19 */  0,    0,
    /*              20 */  0,    0,
    /*              21 */  0,    0,
    /*              22 */  0,    0,
    /*              23 */  0,    0,
    /*              24 */  0,    0,
    /*              25 */  0,    0,
    /*              26 */  0,    0,
    /*              27 */  0,    0,
    /*              28 */  0,    0,
    /*              29 */  0,    0,
    /*              30 */  0,    0,
    /*              31 */  0,    0,
    /* space     32 32 */  ' ',  ' ',
    /*              33 */  0,    0,
    /*              34 */  0,    0,
    /*              35 */  0,    0,
    /*              36 */  0,    0,
    /*              37 */  0,    0,
    /*              38 */  0,    0,
    /* punctuation  39 */  0,    0,
    /*              40 */  0,    0,
    /*              41 */  0,    0,
    /*              42 */  0,    0,
    /*              43 */  0,    0,
    /*              44 */  0,    0,
    /*              45 */  '-',  '_',
    /*              46 */  0,    0,
    /*              47 */  0,    0,
    /* 0         48 48 */  '0',  '=',
    /* 1            49 */  '1',  '!',
    /* 2            50 */  '2',  '"',
    /* 3            51 */  '3',  '',
    /* 4            52 */  '4',  '$',
    /* 5            53 */  '5',  '%',
    /* 6            54 */  '6',  '&',
    /* 7            55 */  '7',  '/',
    /* 8            56 */  '8',  '(',
    /* 9            57 */  '9',  ')',
    /* :            58 */  ':',  0,
    /* ;            59 */  ';',  0,
    /* <            60 */  '<',  0,
    /* =            61 */  '=',  '+',
    /* >            62 */  '>',  0,
    /* ?            63 */  '?',  0,
    /* @         64 64 */  '@',  0,
    /* A            65 */  'a',  'A',
    /* B            66 */  'b',  'B',
    /* C            67 */  'c',  'C',
    /* D            68 */  'd',  'D',
    /* E            69 */  'e',  'E',
    /* F            70 */  'f',  'F',
    /* G            71 */  'g',  'G',
    /* H            72 */  'h',  'H',
    /* I            73 */  'i',  'I',
    /* J            74 */  'j',  'J',
    /* K            75 */  'k',  'K',
    /* L            76 */  'l',  'L',
    /* M            77 */  'm',  'M',
    /* N            78 */  'n',  'N',
    /* O            79 */  'o',  'O',
    /* P         80 80 */  'p',  'P',
    /* Q            81 */  'q',  'Q',
    /* R            82 */  'r',  'R',
    /* S            83 */  's',  'S',
    /* T            84 */  't',  'T',
    /* U            85 */  'u',  'U',
    /* V            86 */  'v',  'V',
    /* W            87 */  'w',  'W',
    /* X            88 */  'x',  'X',
    /* Y            89 */  'y',  'Y',
    /* Z            90 */  'z',  'Z',
    /*              91 */  0,    0,
    /*              92 */  0,    0,
    /*              93 */  0,    0,
    /*              94 */  0,    0,
    /*              95 */  0,    0,
    /*           96 96 */  '0',  0,
    /*              97 */  '1',  0,
    /*              98 */  '2',  0,
    /*              99 */  '3',  0,
    /*              100*/  '4',  0,
    /*              101*/  '5',  0,
    /*              102*/  '6',  0,
    /*              103*/  '7',  0,
    /*              104*/  '8',  0,
    /*              105*/  '9',  0,
    /*              106*/  '*',  0,
    /*              107*/  '+',  0,
    /*              108*/  0,    0,
    /*              109*/  '-',  0,
    /*              110*/  '.',  0,
    /*              111*/  '/',  0,
    /*          112 112*/  0,    0,
    /*              113*/  0,    0,
    /*              114*/  0,    0,
    /*              115*/  0,    0,
    /*              116*/  0,    0,
    /*              117*/  0,    0,
    /*              118*/  0,    0,
    /*              119*/  0,    0,
    /*              120*/  0,    0,
    /*              121*/  0,    0,
    /*              122*/  0,    0,
    /*              123*/  0,    0,
    /*              124*/  0,    0,
    /*              125*/  0,    0,
    /*              126*/  0,    0,
    /*              127*/  0,    0,
    /*          128 128*/  0,    0,
    /*              129*/  0,    0,
    /*              130*/  0,    0,
    /*              131*/  0,    0,
    /*              132*/  0,    0,
    /*              133*/  0,    0,
    /*              134*/  0,    0,
    /*              135*/  0,    0,
    /*              136*/  0,    0,
    /*              137*/  0,    0,
    /*              138*/  0,    0,
    /*              139*/  0,    0,
    /*              140*/  0,    0,
    /*              141*/  0,    0,
    /*              142*/  0,    0,
    /*              143*/  0,    0,
    /*          144 144*/  0,    0,
    /*              145*/  0,    0,
    /*              146*/  0,    0,
    /*              147*/  0,    0,
    /*              148*/  0,    0,
    /*              149*/  0,    0,
    /*              150*/  0,    0,
    /*              151*/  0,    0,
    /*              152*/  0,    0,
    /*              153*/  0,    0,
    /*              154*/  0,    0,
    /*              155*/  0,    0,
    /*              156*/  0,    0,
    /*              157*/  0,    0,
    /*              158*/  0,    0,
    /*              159*/  0,    0,
    /*          160 160*/  0,    0,
    /*              161*/  0,    0,
    /*              162*/  0,    0,
    /*              163*/  0,    0,
    /*              164*/  0,    0,
    /*              165*/  0,    0,
    /*              166*/  0,    0,
    /*              167*/  0,    0,
    /*              168*/  0,    0,
    /*              169*/  0,    0,
    /*              170*/  0,    0,
    /*              171*/  0,    0,
    /*              172*/  0,    0,
    /*              173*/  0,    0,
    /*              174*/  0,    0,
    /*              175*/  0,    0,
    /*          176 176*/  0,    0,
    /*              177*/  0,    0,
    /*              178*/  0,    0,
    /*              179*/  0,    0,
    /*              180*/  '',  '',
    /*              181*/  0,    0,
    /*              182*/  0,    0,
    /*              183*/  0,    0,
    /*              184*/  0,    0,
    /*              185*/  0,    0,
    /*              186*/  ';',  ':',
    /*              187*/  '',  '',
    /*              188*/  ',',  ';',
    /*              189*/  '\'',  '?',
    /*              190*/  '.',  ':',
    /*              191*/  '/',  '?',
    /*          192 192*/  '',  '',
    /*              193*/  0,    0,
    /*              194*/  0,    0,
    /*              195*/  0,    0,
    /*              196*/  0,    0,
    /*              197*/  0,    0,
    /*              198*/  0,    0,
    /*              199*/  0,    0,
    /*              200*/  '-',  '_',
    /*              201*/  0,    0,
    /*              202*/  0,    0,
    /*              203*/  0,    0,
    /*              204*/  0,    0,
    /*              205*/  0,    0,
    /*              206*/  0,    0,
    /*              207*/  0,    0,
    /*          208 208*/  0,    0,
    /*              209*/  0,    0,
    /*              210*/  0,    0,
    /*              211*/  0,    0,
    /*              212*/  0,    0,
    /*              213*/  0,    0,
    /*              214*/  0,    0,
    /*              215*/  0,    0,
    /*              216*/  0,    0,
    /*              217*/  0,    0,
    /*              218*/  0,    0,
    /*              219*/  '`',  '^',
    /*              220*/  '',  '',
    /*              221*/  '+',  '*',
    /*              222*/  '\'',  '"',
    /*              223*/  0,    0,
    /*          224 224*/  0,    0,
    /*              225*/  0,    0,
    /*              226*/  0,    0,
    /*              227*/  0,    0,
    /*              228*/  0,    0,
    /*              229*/  0,    0,
    /*              230*/  0,    0,
    /*              231*/  '',  '',
    /*              232*/  0,    0,
    /*              233*/  0,    0,
    /*              234*/  0,    0,
    /*              235*/  0,    0,
    /*              236*/  0,    0,
    /*              237*/  0,    0,
    /*              238*/  0,    0,
    /*              239*/  0,    0,
    /*          240 240*/  0,    0,
    /*              241*/  '',  '',
    /*              242*/  0,    0,
    /*              243*/  0,    0,
    /*              244*/  0,    0,
    /*              245*/  0,    0,
    /*              246*/  0,    0,
    /*              247*/  0,    0,
    /*              248*/  0,    0,
    /*              249*/  0,    0,
    /*              250*/  0,    0,
    /*              251*/  0,    0,
    /*              252*/  0,    0,
    /*              253*/  0,    0,
    /*              254*/  0,    0,
    /*              255*/  0,    0,
};

uicKeyTable uicItalianKeyEntryTable[KEY_TOTAL_KEYS] =
{
    /*            0 0  */  0,    0,
    /*              1  */  0,    0,
    /*              2  */  0,    0,
    /*              3  */  0,    0,
    /*              4  */  0,    0,
    /*              5  */  0,    0,
    /*              6  */  0,    0,
    /*              7  */  0,    0,
    /*              8  */  0,    0,
    /*              9  */  0,    0,
    /*              10 */  0,    0,
    /*              11 */  0,    0,
    /*              12 */  0,    0,
    /*              13 */  0,    0,
    /*              14 */  0,    0,
    /*              15 */  0,    0,
    /*           16 16 */  0,    0,
    /*              17 */  0,    0,
    /*              18 */  0,    0,
    /*              19 */  0,    0,
    /*              20 */  0,    0,
    /*              21 */  0,    0,
    /*              22 */  0,    0,
    /*              23 */  0,    0,
    /*              24 */  0,    0,
    /*              25 */  0,    0,
    /*              26 */  0,    0,
    /*              27 */  0,    0,
    /*              28 */  0,    0,
    /*              29 */  0,    0,
    /*              30 */  0,    0,
    /*              31 */  0,    0,
    /* space     32 32 */  ' ',  ' ',
    /*              33 */  0,    0,
    /*              34 */  0,    0,
    /*              35 */  0,    0,
    /*              36 */  0,    0,
    /*              37 */  0,    0,
    /*              38 */  0,    0,
    /* punctuation  39 */  0,    0,
    /*              40 */  0,    0,
    /*              41 */  0,    0,
    /*              42 */  0,    0,
    /*              43 */  0,    0,
    /*              44 */  0,    0,
    /*              45 */  '-',  '_',
    /*              46 */  0,    0,
    /*              47 */  0,    0,
    /* 0         48 48 */  '0',  '=',
    /* 1            49 */  '1',  '!',
    /* 2            50 */  '2',  '"',
    /* 3            51 */  '3',  '',
    /* 4            52 */  '4',  '$',
    /* 5            53 */  '5',  '%',
    /* 6            54 */  '6',  '&',
    /* 7            55 */  '7',  '/',
    /* 8            56 */  '8',  '(',
    /* 9            57 */  '9',  ')',
    /* :            58 */  ':',  0,
    /* ;            59 */  ';',  0,
    /* <            60 */  '<',  0,
    /* =            61 */  '=',  '+',
    /* >            62 */  '>',  0,
    /* ?            63 */  '?',  0,
    /* @         64 64 */  '@',  0,
    /* A            65 */  'a',  'A',
    /* B            66 */  'b',  'B',
    /* C            67 */  'c',  'C',
    /* D            68 */  'd',  'D',
    /* E            69 */  'e',  'E',
    /* F            70 */  'f',  'F',
    /* G            71 */  'g',  'G',
    /* H            72 */  'h',  'H',
    /* I            73 */  'i',  'I',
    /* J            74 */  'j',  'J',
    /* K            75 */  'k',  'K',
    /* L            76 */  'l',  'L',
    /* M            77 */  'm',  'M',
    /* N            78 */  'n',  'N',
    /* O            79 */  'o',  'O',
    /* P         80 80 */  'p',  'P',
    /* Q            81 */  'q',  'Q',
    /* R            82 */  'r',  'R',
    /* S            83 */  's',  'S',
    /* T            84 */  't',  'T',
    /* U            85 */  'u',  'U',
    /* V            86 */  'v',  'V',
    /* W            87 */  'w',  'W',
    /* X            88 */  'x',  'X',
    /* Y            89 */  'y',  'Y',
    /* Z            90 */  'z',  'Z',
    /*              91 */  0,    0,
    /*              92 */  0,    0,
    /*              93 */  0,    0,
    /*              94 */  0,    0,
    /*              95 */  0,    0,
    /*           96 96 */  '0',  0,
    /*              97 */  '1',  0,
    /*              98 */  '2',  0,
    /*              99 */  '3',  0,
    /*              100*/  '4',  0,
    /*              101*/  '5',  0,
    /*              102*/  '6',  0,
    /*              103*/  '7',  0,
    /*              104*/  '8',  0,
    /*              105*/  '9',  0,
    /*              106*/  '*',  0,
    /*              107*/  '+',  0,
    /*              108*/  0,    0,
    /*              109*/  '-',  0,
    /*              110*/  '.',  0,
    /*              111*/  '/',  0,
    /*          112 112*/  0,    0,
    /*              113*/  0,    0,
    /*              114*/  0,    0,
    /*              115*/  0,    0,
    /*              116*/  0,    0,
    /*              117*/  0,    0,
    /*              118*/  0,    0,
    /*              119*/  0,    0,
    /*              120*/  0,    0,
    /*              121*/  0,    0,
    /*              122*/  0,    0,
    /*              123*/  0,    0,
    /*              124*/  0,    0,
    /*              125*/  0,    0,
    /*              126*/  0,    0,
    /*              127*/  0,    0,
    /*          128 128*/  0,    0,
    /*              129*/  0,    0,
    /*              130*/  0,    0,
    /*              131*/  0,    0,
    /*              132*/  0,    0,
    /*              133*/  0,    0,
    /*              134*/  0,    0,
    /*              135*/  0,    0,
    /*              136*/  0,    0,
    /*              137*/  0,    0,
    /*              138*/  0,    0,
    /*              139*/  0,    0,
    /*              140*/  0,    0,
    /*              141*/  0,    0,
    /*              142*/  0,    0,
    /*              143*/  0,    0,
    /*          144 144*/  0,    0,
    /*              145*/  0,    0,
    /*              146*/  0,    0,
    /*              147*/  0,    0,
    /*              148*/  0,    0,
    /*              149*/  0,    0,
    /*              150*/  0,    0,
    /*              151*/  0,    0,
    /*              152*/  0,    0,
    /*              153*/  0,    0,
    /*              154*/  0,    0,
    /*              155*/  0,    0,
    /*              156*/  0,    0,
    /*              157*/  0,    0,
    /*              158*/  0,    0,
    /*              159*/  0,    0,
    /*          160 160*/  0,    0,
    /*              161*/  0,    0,
    /*              162*/  0,    0,
    /*              163*/  0,    0,
    /*              164*/  0,    0,
    /*              165*/  0,    0,
    /*              166*/  0,    0,
    /*              167*/  0,    0,
    /*              168*/  0,    0,
    /*              169*/  0,    0,
    /*              170*/  0,    0,
    /*              171*/  0,    0,
    /*              172*/  0,    0,
    /*              173*/  0,    0,
    /*              174*/  0,    0,
    /*              175*/  0,    0,
    /*          176 176*/  0,    0,
    /*              177*/  0,    0,
    /*              178*/  0,    0,
    /*              179*/  0,    0,
    /*              180*/  0,    0,
    /*              181*/  0,    0,
    /*              182*/  0,    0,
    /*              183*/  0,    0,
    /*              184*/  0,    0,
    /*              185*/  0,    0,
    /*              186*/  ';',  ':',
    /*              187*/  '',  '^',
    /*              188*/  ',',  ';',
    /*              189*/  '\'', '?',
    /*              190*/  '.',  ':',
    /*              191*/  '/',  '?',
    /*          192 192*/  '\\', '|',
    /*              193*/  0,    0,
    /*              194*/  0,    0,
    /*              195*/  0,    0,
    /*              196*/  0,    0,
    /*              197*/  0,    0,
    /*              198*/  0,    0,
    /*              199*/  0,    0,
    /*              200*/  '-',  '_',
    /*              201*/  0,    0,
    /*              202*/  0,    0,
    /*              203*/  0,    0,
    /*              204*/  0,    0,
    /*              205*/  0,    0,
    /*              206*/  0,    0,
    /*              207*/  0,    0,
    /*          208 208*/  0,    0,
    /*              209*/  0,    0,
    /*              210*/  0,    0,
    /*              211*/  0,    0,
    /*              212*/  0,    0,
    /*              213*/  0,    0,
    /*              214*/  0,    0,
    /*              215*/  0,    0,
    /*              216*/  0,    0,
    /*              217*/  0,    0,
    /*              218*/  0,    0,
    /*              219*/  '',  '',
    /*              220*/  '',  '',
    /*              221*/  '+',  '*',
    /*              222*/  '',  '',
    /*              223*/  0,    0,
    /*          224 224*/  0,    0,
    /*              225*/  0,    0,
    /*              226*/  0,    0,
    /*              227*/  0,    0,
    /*              228*/  0,    0,
    /*              229*/  0,    0,
    /*              230*/  0,    0,
    /*              231*/  0,    0,
    /*              232*/  0,    0,
    /*              233*/  0,    0,
    /*              234*/  0,    0,
    /*              235*/  0,    0,
    /*              236*/  0,    0,
    /*              237*/  0,    0,
    /*              238*/  0,    0,
    /*              239*/  0,    0,
    /*          240 240*/  0,    0,
    /*              241*/  '',  '',
    /*              242*/  0,    0,
    /*              243*/  0,    0,
    /*              244*/  0,    0,
    /*              245*/  0,    0,
    /*              246*/  0,    0,
    /*              247*/  0,    0,
    /*              248*/  0,    0,
    /*              249*/  0,    0,
    /*              250*/  0,    0,
    /*              251*/  0,    0,
    /*              252*/  0,    0,
    /*              253*/  0,    0,
    /*              254*/  0,    0,
    /*              255*/  0,    0,
};


sdword uicListWindowMargin = 6;

/*=============================================================================
    Mouse/Keyboard focus:
=============================================================================*/
bool   uicMouseFocus = TRUE;
sdword uicMouseSavedX = 0, uicMouseSavedY = 0;

#define UIC_MOUSE_MOVED_X   (uicMouseSavedX != mouseCursorXPosition)
#define UIC_MOUSE_MOVED_Y   (uicMouseSavedY != mouseCursorYPosition)
#define UIC_MOUSE_MOVED     (UIC_MOUSE_MOVED_X || UIC_MOUSE_MOVED_Y)

void uicFocusToKeyboard(void)
{
    if (uicMouseFocus)
    {
        uicMouseFocus = FALSE;
        uicMouseSavedX = mouseCursorXPosition;
        uicMouseSavedY = mouseCursorYPosition;
    }
}

void uicFocusToMouse(regionhandle region)
{
    if (UIC_MOUSE_MOVED)
    {
        if (mouseInRectGeneral(region->rect.x0, region->rect.y0,
                               region->rect.x1, region->rect.y1))
        {
            uicMouseFocus = TRUE;
/*            uicClearCurrent(region);
            feTabStop = region->tabstop;
            uicSetCurrent(region, FALSE);*/
        }
    }
}



/*=============================================================================
    Private functions:
=============================================================================*/
#if UIC_TEST
extern regionhandle ghMainRegion;
sdword uicTestProcess(regionhandle region, sdword ID, udword event, udword data)
{
    dbgMessagef("\nUI test function region = 0x%x, ID = %d, event = 0x%x, data = %d", region, ID, event, data);
    return(0);
}
#endif //UIC_TEST

/*-----------------------------------------------------------------------------
    Name        : colAdjust
    Description : adjust a color's v component by amount (+ or -)
    Inputs      : c - the color the adjust, amount - adjustment
    Outputs     : c is modified
    Return      :
----------------------------------------------------------------------------*/
void colAdjust(color *c, sword amount)
{
    real32 r, g, b;
    real32 h, s, v;
    ubyte ir, ig, ib;

    r = colUbyteToReal(colRed(*c));
    g = colUbyteToReal(colGreen(*c));
    b = colUbyteToReal(colBlue(*c));

    colRGBToHSV(&h, &s, &v, r, g, b);
    if (amount > 0)
        v += colUbyteToReal(amount);
    else
        v += -colUbyteToReal(-amount);
    if (v > (real32)1.0)
        v = (real32)1.0;
    else if (v < (real32)0.0)
        v = (real32)0.0;

    colHSVToRGB(&r, &g, &b, h, s, v);
    ir = colRealToUbyte(r);
    ig = colRealToUbyte(g);
    ib = colRealToUbyte(b);
    *c = colRGB(ir, ig, ib);
}

//draw a button
void uicButtonDraw(regionhandle reg)
{
    featom* atom;

    if ((feStack[feStackIndex].screen!=NULL) &&
        (feStack[feStackIndex].screen != ((buttonhandle)reg)->screen) )
    {
        if ((reg->parent!=ghMainRegion) || (feStackIndex>0))
        {
            ferDrawButton(reg->rect, b_off);
            return;
        }
    }

    if (!uicMouseFocus)
        uicFocusToMouse(reg);

    atom = (featom*)reg->atom;
    if (atom != NULL && glCapFeatureExists(GL_SWAPFRIENDLY))
    {
        color c;
        rectangle r;

        r = reg->rect;
        r.y1++;

        if (bitTest(atom->flags, FAF_Background))
        {
            c = FEC_Background;
        }
        else
        {
            c = colBlack;
        }

        primRectSolid2(&r, c);
    }

    if (bitTest(reg->status, RSF_RegionDisabled))
    {
        ferDrawButton(reg->rect, b_off_disabled);
    }
    else if (bitTest(reg->status, RSF_LeftPressed))
    {
        if (bitTest(reg->status, RSF_MouseInside))
        {
            ferDrawButton(reg->rect, b_on_focus_mouse);
        }
        else
        {
            ferDrawButton(reg->rect, b_off_focus_mouse);
        }
    }
    else if (bitTest(reg->status, RSF_CurrentSelected))
    {
        if (bitTest(reg->status, RSF_MouseInside))
        {
            ferDrawButton(reg->rect, b_off_focus_mouse);
        }
        else
        {
            ferDrawButton(reg->rect, b_off_focus);
        }
    }
    else if (bitTest(reg->status, RSF_MouseInside))
    {
        ferDrawButton(reg->rect, b_off_mouse);
    }
    else
    {
        ferDrawButton(reg->rect, b_off);
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicButtonProcess
    Description : Region processor callback for buttons
    Inputs      : region - region to handle processing
                  ID - user-assigned ID of button
                  event - enumeration of event to be processed
                  data - additional event data (message specific)
    Outputs     : calls through to button handler function if button released
    Return      : flags indicating further operation:
    Note        : can call user function with any region message if filter set
                    up properly.
----------------------------------------------------------------------------*/
bool uicButtonReleased = FALSE;
udword uicButtonProcess(regionhandle region, sdword ID, udword event, udword data)
{
    udword mask = 0;
#ifndef HW_Release
    udword i;
    featom *atom = (featom *)region->atom;
#endif
    switch (event)
    {
        case RPE_PressLeft:
            uicClearCurrent(region);
            uicSetCurrent(region, FALSE);
            soundEvent(NULL, UI_Click);
            mask |= RPR_Redraw;
#ifndef HW_Release
            dbgMessagef("\nEn: %c Fr: %c De: %c Es: %c It: %c", atom->hotKey[0], atom->hotKey[1], atom->hotKey[2], atom->hotKey[3], atom->hotKey[4]);
#endif
        break;

        case RPE_KeyDown:
            soundEvent(NULL, UI_Click);
            //fall through
        case RPE_ReleaseLeft:
            uicButtonReleased = TRUE;
            ((buttonhandle)region)->processFunction(region, ID, CM_ButtonClick, 0);
            uicButtonReleased = FALSE;
            mask |= RPR_Redraw;
        break;

        case RPE_Enter:
        case RPE_Exit:
        case RPE_ExitHoldLeft:
            mask |= RPR_Redraw;
        break;
    }

    if (mask != 0)
    {
        regRecursiveSetDirty(region);
    }
    return(mask);
}

/*-----------------------------------------------------------------------------
    Name        : uicToggleDraw
    Description : Draw a toggle button
    Inputs      : reg - region representing toggle
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicToggleDraw(regionhandle reg)
{
    featom* atom;

    /*
    rectangle erase;

    erase = reg->rect;                                      //erase the background to get rid of text that might be there
    erase.y0 += 3;
    erase.x0 += 3;
    erase.x1 -= 3;
      */
    //primRectSolid2(&erase, colBlack);
    if (feStack[feStackIndex].screen != ((buttonhandle)reg)->screen)
    {                                                       //if a button on a different screen
        ferDrawButton(reg->rect, tb_off);                   //draw it normally
        return;
    }

    if (!uicMouseFocus)
        uicFocusToMouse(reg);

    atom = (featom*)reg->atom;
    if (atom != NULL && glCapFeatureExists(GL_SWAPFRIENDLY))
    {
        color c;
        rectangle r;

        r = reg->rect;
        r.y1++;

        if (bitTest(atom->flags, FAF_Background))
        {
            c = FEC_Background;
        }
        else
        {
            c = colBlack;
        }

        primRectSolid2(&r, c);
    }

    if (bitTest(reg->status, RSF_RegionDisabled))
    {
        if (FECHECKED(((featom *)reg->userID)))
            ferDrawButton(reg->rect, tb_on_disabled);
        else
            ferDrawButton(reg->rect, tb_off_disabled);
    }
    else
    {
        if (FECHECKED(((featom *)reg->userID)))
        {
            if (bitTest(reg->status, RSF_LeftPressed))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawButton(reg->rect, tb_on_focus_mouse);
                }
                else
                {
                    ferDrawButton(reg->rect, tb_on_focus);
                }
            }
            else if (bitTest(reg->status, RSF_CurrentSelected))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawButton(reg->rect, tb_on_focus_mouse);
                }
                else
                {
                    ferDrawButton(reg->rect, tb_on_focus);
                }
            }
            else if (bitTest(reg->status, RSF_MouseInside))
            {
                ferDrawButton(reg->rect, tb_on_mouse);
            }
            else
            {
                ferDrawButton(reg->rect, tb_on);
            }
        }
        else
        {
            if (bitTest(reg->status, RSF_LeftPressed))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawButton(reg->rect, tb_off_focus_mouse);
                }
                else
                {
                    ferDrawButton(reg->rect, tb_off_focus);
                }
            }
            else if (bitTest(reg->status, RSF_CurrentSelected))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawButton(reg->rect, tb_off_focus_mouse);
                }
                else
                {
                    ferDrawButton(reg->rect, tb_off_focus);
                }
            }
            else if (bitTest(reg->status, RSF_MouseInside))
            {
                ferDrawButton(reg->rect, tb_off_mouse);
            }
            else
            {
                ferDrawButton(reg->rect, tb_off);
            }
        }
    }
/*
    color c, ForeColor;
    bool8 checked;
    sdword width;
    uword cloops;

    if (!uicMouseFocus)
        uicFocusToMouse(reg);

    checked = (bool8)((bitTest(((featom *)reg->userID)->flags, FAF_Checked)) ? TRUE : FALSE);


    // a toggle button is a normal button that retains it's on state if it is toggled
    if (fetEnableTextures)
    {
        if (bitTest(reg->status, RSF_LeftPressed) && bitTest(reg->status, RSF_MouseInside))
        {
            ferDrawButton(reg->rect, on);
        }
        else if (checked)
        {
            ferDrawButton(reg->rect, mouse);
        }
        else
        {
            if ( ( (!uicMouseFocus) && (bitTest(reg->status, RSF_CurrentSelected)) ) ||
                ( (uicMouseFocus)  && (bitTest(reg->status, RSF_MouseInside    )) )  )
            {
                ferDrawButton(reg->rect, mouse);
            }
            else
            {
                ferDrawButton(reg->rect, off);
            }
        }
        return;
    }

    c = ((buttonhandle)reg)->contentColor;
    width = 2;
    if ((bitTest(reg->status, RSF_LeftPressed) && bitTest(reg->status, RSF_MouseInside)))
    {
        colAdjust(&c, 64);
    }
    else if (bitTest(reg->status, RSF_CurrentSelected))
    {
        colAdjust(&c, 32);
    }
    else if (checked)
    {
        colAdjust(&c, 16);
    }

    primBeveledRectSolid(&reg->rect, c, 3, 3);

    ForeColor = ((buttonhandle)reg)->borderColor;
    cloops = (bool8)(checked ? 7 : 3);
    colAdjust(&ForeColor, 64);
    primSeriesOfRoundRects(&reg->rect, 1, ForeColor, c, cloops, 2, 2);*/
}

/*-----------------------------------------------------------------------------
    Name        : uicToggleProcess
    Description : Region processor callback for toggle buttons
    Inputs      : region - region to handle processing
                  ID - user-assigned ID of button
                  event - enumeration of event to be processed
                  data - additional event data (message specific)
    Outputs     : calls through to button handler function if button released,
                    toggles state of reg->atom->flags.FAF_Checked
    Return      : flags indicating further operation:
    Note        : can call user function with any region message if filter set
                    up properly.
----------------------------------------------------------------------------*/
udword uicToggleProcess(regionhandle region, sdword ID, udword event, udword data)
{
    udword mask = 0;

    switch (event)
    {
        case RPE_PressLeft:
            uicClearCurrent(region);
            uicSetCurrent(region, FALSE);
            soundEvent(NULL, UI_Click);
            mask |= RPR_Redraw;
        break;

        case RPE_ReleaseLeft:
            bitToggle(((featom *)region->userID)->status, FAS_Checked);
            ((buttonhandle)region)->processFunction(region, ID, CM_ButtonClick, 0);
            mask |= RPR_Redraw;
        break;

        case RPE_KeyDown:
            soundEvent(NULL, UI_Click);
            bitToggle(((featom *)region->userID)->status, FAS_Checked);
            ((buttonhandle)region)->processFunction(region, ID, CM_ButtonClick, 0);
            mask |= RPR_Redraw;
        break;

        case RPE_Enter:
        case RPE_Exit:
        case RPE_ExitHoldLeft:
            mask |= RPR_Redraw;
        break;
    }

    if (mask != 0)
    {
        regRecursiveSetDirty(region);
    }
    return(mask);
}

/*-----------------------------------------------------------------------------
    Name        : uicRadioButtonProcess
    Description : Region processor callback for radio buttons
    Inputs      : region - region to handle processing
                  ID - user-assigned ID of button
                  event - enumeration of event to be processed
                  data - additional event data (message specific)
    Outputs     : calls through to button handler function if button released,
                    set reg->atom->flags.FAF_Checked, unset all other buttons in set
    Return      : flags indicating further operation:
    Note        : can call user function with any region message if filter set
                    up properly.
----------------------------------------------------------------------------*/
udword uicRadioButtonProcess(regionhandle region, sdword ID, udword event, udword data)
{
    udword mask = 0;
    featom *atom;

    switch (event)
    {
        case RPE_PressLeft:
            uicClearCurrent(region);
            uicSetCurrent(region, FALSE);
            soundEvent(NULL, UI_Click);
            mask |= RPR_Redraw;
        break;

        case RPE_KeyDown:
        case RPE_ReleaseLeft:
            ((buttonhandle)region)->processFunction(region, ID, CM_ButtonClick, 0);
            atom = (featom *)region->userID;                    //get this atom
            feRadioButtonSet(atom->name, (sdword)atom->pData);  //set a certain radio button
            if (event == RPE_KeyDown) soundEvent(NULL, UI_Click);
            mask |= RPR_Redraw;
        break;

        case RPE_Enter:
        case RPE_Exit:
        case RPE_ExitHoldLeft:
            mask |= RPR_Redraw;
        break;
    }

    if (mask != 0)
    {
        regRecursiveSetDirty(region);
    }
    return(mask);
}

//process scrollbar messages
udword uicScrollBarProcess(regionhandle region, sdword ID, udword event, udword data)
{
    scrollbarhandle shandle;
    udword mask = 0,x,y;

    switch (ID)
    {
        case UIC_ScrollbarTab:
            shandle = (scrollbarhandle)region;
            switch (event)
            {
                case RPE_ReleaseLeft:
                    shandle->processFunction(region, ID, CM_ButtonClick, shandle->clickType);
                    mask |= RPR_Redraw;
                    break;
                case RPE_WheelUp:
                    shandle->processFunction(region, ID, CM_ButtonClick, SC_Negative);
                    mask |= RPR_Redraw;
                    break;
                case RPE_WheelDown:
                    shandle->processFunction(region, ID, CM_ButtonClick, SC_Positive);
                    mask |= RPR_Redraw;
                    break;
                case RPE_PressLeft:
                    if (mouseInRect(&shandle->thumb))
                    {
                        shandle->clickType = SC_Thumb;
                        shandle->mouseX = scThumbRelativeX(shandle);
                        shandle->mouseY = scThumbRelativeY(shandle);
                    }
                    else
                    {
                        soundEvent(NULL, UI_Click);
                        shandle->clickType = SC_Other;
                        shandle->mouseX = scRelativeX(shandle);
                        shandle->mouseY = scRelativeY(shandle);
                    }
                    mask |= RPR_Redraw;
                    break;
                case RPE_EnterHoldLeft:
                    shandle->clickType = SC_Thumb;
                    mask |= RPR_Redraw;
                    break;
                case RPE_HoldLeft:
                    if (shandle->clickType == SC_Thumb)
                    {
                        x = (udword)scThumbRelativeX(shandle);
                        y = (udword)scThumbRelativeY(shandle);
                        shandle->processFunction(region, ID, CM_ThumbMoved, (x << 16) | y);
                    }
                    mask |= RPR_Redraw;
                    break;
                case RPE_Enter:
                case RPE_Exit:
                case RPE_ExitHoldLeft:
                    mask |= RPR_Redraw;
                    break;

            #if 0
                default:
                    shandle->clickType = SC_NoRegion;
            #endif
            }
            break;
        case UIC_ScrollbarUpButton:
        case UIC_ScrollbarDownButton:
            shandle = ((scrollbarbuttonhandle)region)->scrollbar;
            switch (event)
            {
                case RPE_ReleaseLeft:
                    if (ID==UIC_ScrollbarUpButton)
                        shandle->processFunction(region, ID, CM_ButtonClick, SC_Negative);
                    else
                        shandle->processFunction(region, ID, CM_ButtonClick, SC_Positive);
                    mask |= RPR_Redraw;
                    break;
                case RPE_WheelUp:
                    shandle->processFunction(region, ID, CM_ButtonClick, SC_Negative);
                    mask |= RPR_Redraw;
                    break;
                case RPE_WheelDown:
                    shandle->processFunction(region, ID, CM_ButtonClick, SC_Positive);
                    mask |= RPR_Redraw;
                    break;
                case RPE_PressLeft:
                    mask |= RPR_Redraw;
                    break;
                case RPE_EnterHoldLeft:
                case RPE_HoldLeft:
                case RPE_Enter:
                case RPE_Exit:
                case RPE_ExitHoldLeft:
                    mask |= RPR_Redraw;
                    break;
            }
            break;
//            soundEvent(NULL, Click);
            break;
    }

    if (mask != 0)
    {
        regRecursiveSetDirty(region);
    }
    return mask;
}

/*-----------------------------------------------------------------------------
    Name        : uicScrollBarDraw
    Description : Draw a scrollbar
    Inputs      : reg - region representing scrollbar
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicScrollBarDraw(regionhandle reg)
{
    scrollbarhandle shandle = (scrollbarhandle)reg;

    if (feStack[feStackIndex].screen != shandle->screen)
    {
        ferDrawScrollbar(shandle, s_off);
        return;
    }

    if (bitTest(reg->status,RSF_LeftPressed))
    {
        if (bitTest(reg->status, RSF_MouseInside))
        {
            ferDrawScrollbar(shandle, s_on_mouse);
            return;
        }
        else
        {
            ferDrawScrollbar(shandle, s_off_mouse);
            return;
        }
    }
    else
    {
        if (bitTest(reg->status, RSF_MouseInside))
        {
            ferDrawScrollbar(shandle, s_off_mouse);
            return;
        }
    }

    ferDrawScrollbar(shandle, s_off);
}

/*-----------------------------------------------------------------------------
    Name        : uicScrollBarButtonDraw
    Description : Draws the button for the scroll bar
    Inputs      : reg - region for the scrollbar button
    Outputs     :
    Return      : void
----------------------------------------------------------------------------*/
void uicScrollBarButtonDraw(regionhandle reg)
{
    if (feStack[feStackIndex].screen != ((scrollbarbuttonhandle)reg)->scrollbar->screen)
    {
        if (reg->userID==UIC_ScrollbarUpButton)
            ferDrawScrollbarButton(reg, sub_off);
        else if (reg->userID==UIC_ScrollbarDownButton)
            ferDrawScrollbarButton(reg, sdb_off);
        return;
    }

    if (bitTest(reg->status,RSF_LeftPressed))
    {
        if (bitTest(reg->status, RSF_MouseInside))
        {
            if (reg->userID==UIC_ScrollbarUpButton)
                ferDrawScrollbarButton(reg, sub_on_mouse);
            else if (reg->userID==UIC_ScrollbarDownButton)
                ferDrawScrollbarButton(reg, sdb_on_mouse);
            return;
        }
        else
        {
            if (reg->userID==UIC_ScrollbarUpButton)
                ferDrawScrollbarButton(reg, sub_off_mouse);
            else if (reg->userID==UIC_ScrollbarDownButton)
                ferDrawScrollbarButton(reg, sdb_off_mouse);
            return;
        }
    }
    else
    {
        if (bitTest(reg->status, RSF_MouseInside))
        {
            if (reg->userID==UIC_ScrollbarUpButton)
                ferDrawScrollbarButton(reg, sub_off_mouse);
            else if (reg->userID==UIC_ScrollbarDownButton)
                ferDrawScrollbarButton(reg, sdb_off_mouse);
            return;
        }
    }

    if (reg->userID==UIC_ScrollbarUpButton)
        ferDrawScrollbarButton(reg, sub_off);
    else if (reg->userID==UIC_ScrollbarDownButton)
        ferDrawScrollbarButton(reg, sdb_off);
}

void uicListItemSelectedDraw(rectangle* rect)
{
    rectangle r = *rect;

    r.x0 -= 2;
    r.x1++;
    r.y1--;
    primRectTranslucent2(&r, FEC_ListItemTranslucent);
    primRectOutline2(&r, 1, FEC_ListItemTranslucentBorder);
}

/*-----------------------------------------------------------------------------
    Name        : uicListWindowDraw
    Description : draws the list window by doing the callbacks for each line
    Inputs      : region
    Outputs     : none
    Return      : void
----------------------------------------------------------------------------*/
void uicListWindowDraw(regionhandle reg)
{
    listwindowhandle    listhandle;
    listitemhandle      item;
    rectangle           rect=reg->rect; //, erase;
    Node               *walk;
    sdword              count=0;

    listhandle = (listwindowhandle)reg;

/*    if (listhandle->windowflags&UICLW_JustRedrawTitle)
    {
        bitClear(listhandle->windowflags,UICLW_JustRedrawTitle);

        rect.y1 = rect.y0+listhandle->TitleHeight;
        erase = rect;
        erase.y0 += 3;
        erase.x0 += 3;
        erase.x1 -= 3;

        if (listhandle->windowflags&UICLW_HasTitleBar)
        {
            primRectSolid2(&erase, colBlack);
            dbgAssert(listhandle->titledraw!=NULL);
            listhandle->titledraw(&rect);
        }
    }
    else
    {*/

    rect.x0+=uicListWindowMargin;
    rect.y0+=uicListWindowMargin;
    rect.x1-=uicListWindowMargin;
    rect.y1-=uicListWindowMargin;

    primRectSolid2(&reg->rect, FEC_Background);

    if (bitTest(reg->status,RSF_CurrentSelected))
        ferDrawFocusWindow(reg, lw_focus);
    else
        ferDrawFocusWindow(reg, lw_normal);

    primRectSolid2(&rect, FEC_Background);

    rect.y1 = rect.y0+listhandle->TitleHeight;

    if (listhandle->windowflags&UICLW_HasTitleBar)
    {
        listhandle->titledraw(&rect);
    }

    rect.y0 = reg->rect.y0+listhandle->TitleHeight+uicListWindowMargin;
    rect.y1 = rect.y0+listhandle->itemheight;

    if (listhandle->topitem!=NULL)
        walk = &listhandle->topitem->link;
    else
        walk = NULL;
    while ( (walk!=NULL)                  &&
            (count<listhandle->MaxIndex)  )
    {
        item = (listitemhandle)listGetStructOfNode(walk);
        dbgAssert(listhandle->itemdraw!=NULL);
        listhandle->itemdraw((rectangle *)&rect, item);

        if (bitTest(item->flags, UICLI_Selected))
        {
            uicListItemSelectedDraw(&rect);
        }

        rect.y0 = rect.y0+listhandle->itemheight;
        rect.y1 = rect.y0+listhandle->itemheight;
        count++;
        walk = walk->next;
    }
//    }
}

/*-----------------------------------------------------------------------------
    Name        : uicListScrollBarAdjust
    Description : resizes the list window scrollbar if an item is added or removed
    Inputs      : list window handle
    Outputs     :
    Return      : void
----------------------------------------------------------------------------*/
void uicListScrollBarAdjust(listwindowhandle listwindow)
{
    if (listwindow->UpperIndex > listwindow->ListTotal)
    {
        listwindow->UpperIndex = listwindow->MaxIndex;
    }
    scAdjustThumbwheel(listwindow->scrollbar, (uword)listwindow->UpperIndex, (uword)listwindow->MaxIndex, (uword)listwindow->ListTotal);
}

/*-----------------------------------------------------------------------------
    Name        : uicListGetItemClicked
    Description : returns the item clicked on or NULL if no item clicked on.
    Inputs      : listwindow, mouse y position
    Outputs     : list item handle
    Return      : list item
----------------------------------------------------------------------------*/
listitemhandle uicListGetItemClicked(listwindowhandle listhandle, sdword yClicked)
{
    sdword              y=listhandle->reg.rect.y0;
    listitemhandle      item;
    Node               *walk;
    sdword              count=0;

    y += listhandle->TitleHeight+uicListWindowMargin;

    if (listhandle->topitem!=NULL)
        walk = &listhandle->topitem->link;
    else
        walk = NULL;

    while ( (walk!=NULL)                  &&
            (count<listhandle->MaxIndex)  )
    {
        if (yClicked < y + listhandle->itemheight)
        {
            break;
        }

        y += listhandle->itemheight;

        count++;
        walk = walk->next;
    }

    if (walk == NULL) return (NULL);

    item = (listitemhandle)listGetStructOfNode(walk);

    if (item->flags&UICLI_CanSelect)
        return (item);
    else
        return (NULL);
}

/*=============================================================================
    These next series of functions are for processing the list window
    cursor keys.  They are split up so that it is easier to understand
    and modify parts of them as needed.
=============================================================================*/
void uicListWindowViewSelection(listwindowhandle listhandle)
{
    sdword CurSelectedRelPos = uicListWindowRelativePos(listhandle);
    // bring the currently selected line into view, either by scrolling up or down.
    if (CurSelectedRelPos<0)
    {
        // must scroll up
        while (CurSelectedRelPos<0)
        {
            if (listhandle->topitem != NULL)
            {
                if (listhandle->topitem->link.prev!=NULL)
                {
                    listhandle->topitem = listGetStructOfNode(listhandle->topitem->link.prev);
                    listhandle->UpperIndex --;
                    uicListScrollBarAdjust(listhandle);
                    CurSelectedRelPos++;
                }
            }
        }
    }
    if (CurSelectedRelPos-listhandle->MaxIndex >= 0)
    {
        // must scroll down
        while (CurSelectedRelPos-listhandle->MaxIndex >= 0)
        {
            if (listhandle->topitem != NULL)
            {
                if (listhandle->topitem->link.next!=NULL)
                {
                    listhandle->topitem = listGetStructOfNode(listhandle->topitem->link.next);
                    listhandle->UpperIndex ++;
                    uicListScrollBarAdjust(listhandle);
                    CurSelectedRelPos--;
                }
            }
        }
    }
}

void uicListWindowCheckSel(listwindowhandle listhandle)
{
    // make sure that the currently selected line can be selected.
    if (!bitTest(listhandle->CurLineSelected->flags,UICLI_CanSelect))
    {
        while ( (!bitTest(listhandle->CurLineSelected->flags,UICLI_CanSelect)) &&
                (listhandle->CurLineSelected->link.prev!=NULL))
        {
            bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
            listhandle->CurLineSelected = listGetStructOfNode(listhandle->CurLineSelected->link.prev);
            bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);
        }
        if (!bitTest(listhandle->CurLineSelected->flags,UICLI_CanSelect))
        {
            listhandle->CurLineSelected = NULL;
        }
    }
}

void uicListWindowUpArrow(listwindowhandle listhandle)
{
    Node           *walk;
    listitemhandle  item;
//    sdword          relpos;

    if (bitTest(listhandle->windowflags,UICLW_CanSelect))
    {
        // we can select items in this window
        if (listhandle->CurLineSelected != NULL)
        {
            if (listhandle->CurLineSelected->link.prev != NULL)
            {
                // we are not at the top of the list
                walk = listhandle->CurLineSelected->link.prev;
                item = listGetStructOfNode(walk);
                // while we havn't reached the top of the list and we can't select the item
                while ((walk != NULL)&&(!bitTest(item->flags, UICLI_CanSelect)))
                {
                    item = listGetStructOfNode(walk);
                    walk = walk->prev;
//                    relpos--;
                }
                if (bitTest(item->flags, UICLI_CanSelect))
                {
                    // we have found an item we can actually select
                    bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                    listhandle->CurLineSelected = item;
                    bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);

                    uicListWindowViewSelection(listhandle);
                }
            }
        }
        else
        {
            // Nothing has been selected yet  select something if we can.
            walk = listhandle->listofitems.head;
            while (walk != NULL)
            {
                item = listGetStructOfNode(walk);
                if (bitTest(item->flags, UICLI_CanSelect))
                {
                    listhandle->CurLineSelected = item;
                    break;
                }

                walk = walk->next;
            }
        }
    }
    else
    {
        // this is easy just move the top display item up by one, no selections to worry about
        if (listhandle->topitem != NULL)
        {
            if (listhandle->topitem->link.prev!=NULL)
            {
                listhandle->topitem = listGetStructOfNode(listhandle->topitem->link.prev);
                listhandle->UpperIndex --;
                uicListScrollBarAdjust(listhandle);
            }
        }
    }
}

void uicListWindowDownArrow(listwindowhandle listhandle)
{
    Node           *walk;
    listitemhandle  item;
//    sdword          relpos;

    if (bitTest(listhandle->windowflags,UICLW_CanSelect))
    {
        // we can select items in this window
        if (listhandle->CurLineSelected != NULL)
        {
            if (listhandle->CurLineSelected->link.next!=NULL)
            {
                // we are not at the bottom of the list so ...
                walk = listhandle->CurLineSelected->link.next;
                item = listGetStructOfNode(walk);
                // while we havnt hit the bottom, and we can't select the current item
                while ( (walk != NULL)&&(!bitTest(item->flags, UICLI_CanSelect)) )
                {
                    item = listGetStructOfNode(walk);
                    walk = walk->next;
//                    relpos++;
                }
                if (bitTest(item->flags, UICLI_CanSelect))
                {
                    bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                    listhandle->CurLineSelected = item;
                    bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);

                    uicListWindowViewSelection(listhandle);
                }
            }
        }
        else
        {
            // Nothing has been selected yet  select something if we can.
            walk = listhandle->listofitems.head;
            while (walk != NULL)
            {
                item = listGetStructOfNode(walk);
                if (bitTest(item->flags, UICLI_CanSelect))
                {
                    listhandle->CurLineSelected = item;
                    break;
                }

                walk = walk->next;
            }
        }
    }
    else
    {
        // this is easy just move the top display item down by one, no selections to worry about
        if ( (listhandle->topitem != NULL) &&
             (listhandle->UpperIndex < listhandle->ListTotal - listhandle->MaxIndex) )
        {
            if (listhandle->topitem->link.next!=NULL)
            {
                listhandle->topitem = listGetStructOfNode(listhandle->topitem->link.next);
                listhandle->UpperIndex ++;
                uicListScrollBarAdjust(listhandle);
            }
        }
    }
}

void uicListWindowHome(listwindowhandle listhandle)
{
    // just move the selection and display item to the top of the list.
    if (listhandle->listofitems.head!=NULL)
    {
        listhandle->topitem     = listGetStructOfNode(listhandle->listofitems.head);
        listhandle->UpperIndex  = 0;
        if (bitTest(listhandle->windowflags,UICLW_CanSelect))
        {
            bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
            listhandle->CurLineSelected = listGetStructOfNode(listhandle->listofitems.head);
            bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);
        }

        uicListScrollBarAdjust(listhandle);
    }
}

void uicListWindowEnd(listwindowhandle listhandle)
{
    Node           *walk;
    listitemhandle  item;
    sdword          end, i;

    // just move the selection to the bottom of the list, and the display so that all of the
    // items are on the screen with the selected one at the bottom.

    if (listhandle->listofitems.tail!=NULL)
    {
        if (listhandle->ListTotal > listhandle->MaxIndex)
        {
            end = listhandle->MaxIndex-1;

            walk = listhandle->listofitems.tail;
            for (i=0;i<end;i++)
            {
                walk = walk->prev;
            }
            listhandle->topitem = listGetStructOfNode(walk);
            listhandle->UpperIndex = listhandle->ListTotal - listhandle->MaxIndex;

            uicListScrollBarAdjust(listhandle);

            // if can select items in the list window at all, if not don't waste the time searching
            if (bitTest(listhandle->windowflags,UICLW_CanSelect))
            {
                walk = listhandle->listofitems.tail;
                item = listGetStructOfNode(walk);

                while ((walk != NULL)&&(!bitTest(item->flags,UICLI_CanSelect)))
                {
                    item = listGetStructOfNode(walk);
                    walk = walk->prev;
                }
                if (bitTest(item->flags,UICLI_CanSelect))
                {
                    bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                    listhandle->CurLineSelected = item;
                    bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);
                }
                uicListWindowCheckSel(listhandle);
            }
        }
        else
        {
            // if can select items in the list window at all, if not don't waste the time searching
            if (bitTest(listhandle->windowflags,UICLW_CanSelect))
            {
                walk = listhandle->listofitems.tail;
                item = listGetStructOfNode(walk);

                while ((walk != NULL)&&(!bitTest(item->flags,UICLI_CanSelect)))
                {
                    item = listGetStructOfNode(walk);
                    walk = walk->prev;
                }
                if (bitTest(item->flags,UICLI_CanSelect))
                {
                    bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                    listhandle->CurLineSelected = item;
                    bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);
                }
                uicListWindowCheckSel(listhandle);
            }
        }
    }
}

void uicListWindowPageUp(listwindowhandle listhandle)
{
    listitemhandle  item;
    sdword          count,i;

    // this one is a pain in the ass.

    if (bitTest(listhandle->windowflags,UICLW_CanSelect))
    {
        count = 0;
        if ( (listhandle->topitem != NULL) &&
             (listhandle->UpperIndex > 0) )
        {
            while ( (count<listhandle->MaxIndex) && (listhandle->UpperIndex >= 0))
            {
                if (listhandle->topitem->link.prev!=NULL)
                {
                    listhandle->topitem = listGetStructOfNode(listhandle->topitem->link.prev);
                    listhandle->UpperIndex--;
                    uicListScrollBarAdjust(listhandle);
                }
                else
                    break;

                count++;
            }
        }
        if (listhandle->CurLineSelected!=NULL)
        {
            item = listGetStructOfNonPtrNode(listhandle->topitem->link);
            if (bitTest(item->flags,UICLI_CanSelect))
            {
                bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                listhandle->CurLineSelected = item;
                bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);

                if (count < listhandle->MaxIndex)
                {
                    if (count==0)
                    {
                        item = listGetStructOfNode(listhandle->listofitems.head);

                        bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                        listhandle->CurLineSelected = item;
                        bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);
                        return;
                    }
                }
                i=0;
                do
                {
                    if (listhandle->CurLineSelected->link.next!=NULL)
                    {
                        bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                        listhandle->CurLineSelected = listGetStructOfNode(listhandle->CurLineSelected->link.next);
                        bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);
                    }
                    i++;
                } while (i<uicListWindowRelativePos(listhandle));
            }
            else
            {

            }
        }
    }
    else
    {
        if ( (listhandle->topitem != NULL) &&
             (listhandle->UpperIndex > 0) )
        {
            count = 0;
            while ( (count<listhandle->MaxIndex) && (listhandle->UpperIndex >= 0))
            {
                if (listhandle->topitem->link.prev!=NULL)
                {
                    listhandle->topitem = listGetStructOfNode(listhandle->topitem->link.prev);
                    listhandle->UpperIndex--;
                    uicListScrollBarAdjust(listhandle);
                }
                else
                    break;

                count++;
            }
        }
    }
}

void uicListWindowPageDown(listwindowhandle listhandle)
{
    listitemhandle item;
    sdword  count,pos,i;
    Node   *walk;

    // so is this one real pain in the ass.
    if (bitTest(listhandle->windowflags,UICLW_CanSelect))
    {
        count = 0;
        pos = 0;
        if ( (listhandle->topitem != NULL) &&
             (listhandle->UpperIndex < listhandle->ListTotal - listhandle->MaxIndex) )
        {
            while ( (count<listhandle->MaxIndex) && (listhandle->UpperIndex < listhandle->ListTotal - listhandle->MaxIndex))
            {
                if (listhandle->topitem->link.next!=NULL)
                {
                    listhandle->topitem = listGetStructOfNode(listhandle->topitem->link.next);
                    listhandle->UpperIndex++;
                    uicListScrollBarAdjust(listhandle);
                }
                else
                    break;

                count++;
            }
            uicListWindowCheckSel(listhandle);
        }

        if (listhandle->CurLineSelected!=NULL)
        {
            item = listGetStructOfNonPtrNode(listhandle->topitem->link);
            if (bitTest(item->flags,UICLI_CanSelect))
            {
                bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                listhandle->CurLineSelected = item;
                bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);

                if (count < listhandle->MaxIndex)
                {
                    if (count==0)
                    {
                        walk = listhandle->listofitems.tail;
                        item = listGetStructOfNode(walk);

                        while ((walk != NULL)&&(!bitTest(item->flags,UICLI_CanSelect)))
                        {
                            item = listGetStructOfNode(walk);
                            walk = walk->prev;
                        }
                        if (bitTest(item->flags,UICLI_CanSelect))
                        {
                            bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                            listhandle->CurLineSelected = item;
                            bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);
                        }
                        uicListWindowCheckSel(listhandle);
                        return;
                    }
                    pos = uicListWindowRelativePos(listhandle) + count;
                    if (pos > listhandle->MaxIndex-1)
                    {
                        pos = listhandle->MaxIndex-1;
                    }
                }
                i=0;
                do
                {
                    if (listhandle->CurLineSelected->link.next!=NULL)
                    {
                        bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                        listhandle->CurLineSelected = listGetStructOfNode(listhandle->CurLineSelected->link.next);
                        bitSet(listhandle->CurLineSelected->flags,UICLI_Selected);
                    }
                    i++;
                } while (i<pos);
                uicListWindowCheckSel(listhandle);
            }
            else
            {

            }
        }
    }
    else
    {
        if ( (listhandle->topitem != NULL) &&
             (listhandle->UpperIndex < listhandle->ListTotal - listhandle->MaxIndex) )
        {
            count = 0;
            while ( (count<listhandle->MaxIndex) && (listhandle->UpperIndex < listhandle->ListTotal - listhandle->MaxIndex))
            {
                if (listhandle->topitem->link.next!=NULL)
                {
                    listhandle->topitem = listGetStructOfNode(listhandle->topitem->link.next);
                    listhandle->UpperIndex++;
                    uicListScrollBarAdjust(listhandle);
                }
                else
                    break;

                count++;
            }
        }
    }
}


/*-----------------------------------------------------------------------------
    Name        : uicListWindowProcess
    Description : processes list window events
    Inputs      : standard region callbacks
    Outputs     :
    Return      : void
----------------------------------------------------------------------------*/
udword uicListWindowProcess(regionhandle region, sdword ID, udword event, udword data)
{
    listwindowhandle listhandle;
    listitemhandle   item;
    udword mask = 0;
    regionhandle tabRegion;

    listhandle = (listwindowhandle)region;

    if ((bitTest(listhandle->windowflags, UICLW_GetKeyPressed)) &&
        (event == RPE_KeyDown) )
    {
        listhandle->message = CM_KeyCaptured;
        listhandle->keypressed = data;
        feFunctionExecute(((featom *)region->atom)->name, region->atom, FALSE);
        bitClear(listhandle->windowflags, UICLW_GetKeyPressed);
        return(0);
    }

    switch (event)
    {
        case RPE_KeyDown:
            mask |= RPR_Redraw;
/*#if ddunlop
            dbgMessagef("\nuicListWindowProcess:  key pressed: 0x%x, '%c'", data, data);
#endif*/
            switch (data)
            {
                case ESCKEY:
                    uicEscProcess(region,ID,event,data);
                    break;
                case BACKSPACEKEY:
                    break;
                case DELETEKEY:
                    break;
                case ARRLEFT:
                case ARRUP:
                    uicListWindowUpArrow(listhandle);
                    item = listhandle->CurLineSelected;
                    goto newSelection;
                    break;
                case ARRRIGHT:
                case ARRDOWN:
                    uicListWindowDownArrow(listhandle);
                    item = listhandle->CurLineSelected;
                    goto newSelection;
                    break;
                case HOMEKEY:
                    uicListWindowHome(listhandle);
                    item = listhandle->CurLineSelected;
                    goto newSelection;
                    break;
                case ENDKEY:
                    uicListWindowEnd(listhandle);
                    item = listhandle->CurLineSelected;
                    goto newSelection;
                    break;
                case PAGEUPKEY:
                    uicListWindowPageUp(listhandle);
                    item = listhandle->CurLineSelected;
                    goto newSelection;
                    break;
                case PAGEDOWNKEY:
                    uicListWindowPageDown(listhandle);
                    item = listhandle->CurLineSelected;
                    goto newSelection;
                    break;
                case TABKEY:
                    // process this tab key to go to the next tabstop
                    tabRegion = regSiblingFindByFunction(region, uicTabProcess);
                    if (tabRegion == NULL) break;
                    uicTabProcess(region, tabRegion->userID, 0, 0);
                    break;
                case SPACEKEY:
                case ENTERKEY:
                    // pass the enter key press onto the listwindow callback
                    listhandle->message = CM_AcceptText;
                    feFunctionExecute(((featom *)region->atom)->name, region->atom, FALSE);
                    break;

/*#if ddunlop
                default:
                    dbgMessagef(" (unprocessed)");
#endif*/
            }
            break;


        case RPE_DoubleLeft:
            dbgMessage("\nDouble click");
            if (listhandle->ListTotal==0) break;
            item = uicListGetItemClicked(listhandle, mouseCursorY());

            if (item != NULL)
            {
                if (listhandle->CurLineSelected != NULL)
                {
                    bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                }
                listhandle->CurLineSelected = item;
                bitSet(item->flags,UICLI_Selected);
                // pass this onto the listwindow callback
                listhandle->message = CM_DoubleClick;
                feFunctionExecute(((featom *)region->atom)->name, region->atom, FALSE);
            }
            mask |= RPR_Redraw;
        break;
        case RPE_ReleaseLeft:
            if (mouseCursorY() < region->rect.y0+listhandle->TitleHeight)
            {
                if (listhandle->windowflags & UICLW_CanClickOnTitle)
                {
                    dbgAssert(listhandle->titleprocess!=NULL);
                    listhandle->titleprocess(region, mouseCursorX());
                }
            }
            else
            {
                if (listhandle->ListTotal==0) break;
                item = uicListGetItemClicked(listhandle, mouseCursorY());
newSelection:
                if (item != NULL)
                {
                    if (listhandle->CurLineSelected != NULL)
                    {
                        bitClear(listhandle->CurLineSelected->flags,UICLI_Selected);
                    }
                    listhandle->CurLineSelected = item;
                    bitSet(item->flags,UICLI_Selected);
                    // pass this onto the listwindow callback
                    listhandle->message = CM_NewItemSelected;
                    soundEvent(NULL, UI_Click);
                    feFunctionExecute(((featom *)region->atom)->name, region->atom, FALSE);
                }
            }
            mask |= RPR_Redraw;
        break;
        case RPE_WheelUp:
            listhandle->processFunction(region,ID,event,data);
            mask |= RPR_Redraw;
        break;
        case RPE_WheelDown:
            listhandle->processFunction(region,ID,event,data);
            mask |= RPR_Redraw;
        break;
        case RPE_PressLeft:
            if  ( (!bitTest(listhandle->reg.status, RSF_CurrentSelected)) &&
                  (bitTest(listhandle->windowflags,UICLW_CanHaveFocus)))
            {
                uicClearCurrent(region);
                uicSetCurrent(region, FALSE);
//                soundEvent(NULL, UI_Click);
                mask |= RPR_Redraw;
            }
        break;
        case RPE_EnterHoldLeft:
//            mask |= RPR_Redraw;
        break;
        case RPE_HoldLeft:
//            mask |= RPR_Redraw;
        break;
    }

    if (mask != 0)
    {
        regRecursiveSetDirty(region);
    }
    return mask;
}

/*-----------------------------------------------------------------------------
    Name        : uicRadioButtonDraw
    Description : Draw a radioButton
    Inputs      : reg - region representing toggle
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicRadioButtonDraw(regionhandle reg)
{        /*
    rectangle erase;

    erase = reg->rect;                                      //erase the background to get rid of text that might be there
    erase.y0 += 3;
    erase.x0 += 3;
    erase.x1 -= 3;
           */
    //primRectSolid2(&erase, colBlack);
    if (feStack[feStackIndex].screen != ((buttonhandle)reg)->screen)
    {
        if (FECHECKED(((featom *)reg->userID)))
            ferDrawRadioButton(reg->rect, r_on);
        else
            ferDrawRadioButton(reg->rect, r_off);
        return;
    }

    if (!uicMouseFocus)
        uicFocusToMouse(reg);

    if (bitTest(reg->status, RSF_RegionDisabled))
    {
        if (FECHECKED(((featom *)reg->userID)))
            ferDrawRadioButton(reg->rect, r_on_disabled);
        else
            ferDrawRadioButton(reg->rect, r_off_disabled);
    }
    else
    {
        if (FECHECKED(((featom *)reg->userID)))
        {
            if (bitTest(reg->status, RSF_LeftPressed))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawRadioButton(reg->rect, r_on_focus_mouse);
                }
                else
                {
                    ferDrawRadioButton(reg->rect, r_on_focus);
                }
            }
            else if (bitTest(reg->status, RSF_CurrentSelected))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawRadioButton(reg->rect, r_on_focus_mouse);
                }
                else
                {
                    ferDrawRadioButton(reg->rect, r_on_focus);
                }
            }
            else if (bitTest(reg->status, RSF_MouseInside))
            {
                ferDrawRadioButton(reg->rect, r_on_mouse);
            }
            else
            {
                ferDrawRadioButton(reg->rect, r_on);
            }
        }
        else
        {
            if (bitTest(reg->status, RSF_LeftPressed))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawRadioButton(reg->rect, r_off_focus_mouse);
                }
                else
                {
                    ferDrawRadioButton(reg->rect, r_off_focus);
                }
            }
            else if (bitTest(reg->status, RSF_CurrentSelected))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawRadioButton(reg->rect, r_off_focus_mouse);
                }
                else
                {
                    ferDrawRadioButton(reg->rect, r_off_focus);
                }
            }
            else if (bitTest(reg->status, RSF_MouseInside))
            {
                ferDrawRadioButton(reg->rect, r_off_mouse);
            }
            else
            {
                ferDrawRadioButton(reg->rect, r_off);
            }
        }
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicBitmapButtonDraw
    Description : Draw a checkBox
    Inputs      : reg - region representing toggle
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicBitmapButtonDraw(regionhandle reg)
{
    if (feStack[feStackIndex].screen != ((buttonhandle)reg)->screen)
    {
        if (FECHECKED(((featom *)reg->userID)))
            ferDrawRadioButton(reg->rect, r_on);
        else
            ferDrawRadioButton(reg->rect, r_off);
        return;
    }

    if (!uicMouseFocus)
        uicFocusToMouse(reg);

    if (FECHECKED(((featom *)reg->userID)))
    {
        if (bitTest(reg->status, RSF_MouseInside))
        {
            ferDrawBitmapButton(reg, bb_on_mouse);
        }
        else
        {
            ferDrawBitmapButton(reg, bb_on);
        }
    }
    else
    {
        if (bitTest(reg->status, RSF_MouseInside))
        {
            ferDrawBitmapButton(reg, bb_off_mouse);
        }
        else
        {
            ferDrawBitmapButton(reg, bb_off);
        }
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicCheckBoxDraw
    Description : Draw a checkBox
    Inputs      : reg - region representing toggle
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicCheckBoxDraw(regionhandle reg)
{        /*
    rectangle erase;

    erase = reg->rect;                                      //erase the background to get rid of text that might be there
    erase.y0 += 3;
    erase.x0 += 3;
    erase.x1 -= 3;
           */
    //primRectSolid2(&erase, colBlack);
    if (feStack[feStackIndex].screen != ((buttonhandle)reg)->screen)
    {
        if (FECHECKED(((featom *)reg->userID)))
            ferDrawCheckbox(reg->rect, c_on_disabled);
        else
            ferDrawCheckbox(reg->rect, c_off_disabled);
        return;
    }

    if (!uicMouseFocus)
        uicFocusToMouse(reg);

    if (bitTest(reg->status, RSF_RegionDisabled))
    {
        if (FECHECKED(((featom *)reg->userID)))
            ferDrawCheckbox(reg->rect, c_on_disabled);
        else
            ferDrawCheckbox(reg->rect, c_off_disabled);
    }
    else
    {
        if (FECHECKED(((featom *)reg->userID)))
        {
            if (bitTest(reg->status, RSF_LeftPressed))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawCheckbox(reg->rect, c_on_focus_mouse);
                }
                else
                {
                    ferDrawCheckbox(reg->rect, c_on_focus);
                }
            }
            else if (bitTest(reg->status, RSF_CurrentSelected))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawCheckbox(reg->rect, c_on_focus_mouse);
                }
                else
                {
                    ferDrawCheckbox(reg->rect, c_on_focus);
                }
            }
            else if (bitTest(reg->status, RSF_MouseInside))
            {
                ferDrawCheckbox(reg->rect, c_on_mouse);
            }
            else
            {
                ferDrawCheckbox(reg->rect, c_on);
            }
        }
        else
        {
            if (bitTest(reg->status, RSF_LeftPressed))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawCheckbox(reg->rect, c_off_focus_mouse);
                }
                else
                {
                    ferDrawCheckbox(reg->rect, c_off_focus);
                }
            }
            else if (bitTest(reg->status, RSF_CurrentSelected))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawCheckbox(reg->rect, c_off_focus_mouse);
                }
                else
                {
                    ferDrawCheckbox(reg->rect, c_off_focus);
                }
            }
            else if (bitTest(reg->status, RSF_MouseInside))
            {
                ferDrawCheckbox(reg->rect, c_off_mouse);
            }
            else
            {
                ferDrawCheckbox(reg->rect, c_off);
            }
        }
    }
}

void Approach(approacher *app)
{
    real32 decelgoal,deceltime;

    app->currentvalue += app->vel;

    if (app->vel > 0.0f)
    {
        deceltime = app->vel / app->acc;
        decelgoal = app->currentvalue + 0.5f*app->acc*app->currentvalue*app->currentvalue;
        if (decelgoal > app->target)
        {
            app->vel = app->vel  - app->acc;
        }
        else
        {
            if (((app->currentvalue - app->target)/(decelgoal - app->target)) > app->threshold)
                app->vel = app->vel  + app->acc;
            else
                ; //don't change vel;
        }
    }
    else
    {
        deceltime = -app->vel / app->acc;
        decelgoal = app->currentvalue - 0.5f*app->acc*app->currentvalue*app->currentvalue;
        if (decelgoal > app->target)
        {
            if (((app->currentvalue - app->target)/(decelgoal - app->target)) > app->threshold)
                app->vel = app->vel  - app->acc;
            else
                ; //don't change vel;
        }
        else
        {
            app->vel = app->vel  + app->acc;
        }
    }
}

void SetHSliderValue(sliderhandle shandle)
{
    real32 val;

    val = (real32)(mouseCursorX() - shandle->reg.rect.x0);
    val = shandle->maxvalue * val / (real32)(shandle->reg.rect.x1-shandle->reg.rect.x0);
    shandle->value = (udword)val;
}

void SetVSliderValue(sliderhandle shandle)
{
    real32 val;

    val = (real32)(mouseCursorY() - shandle->reg.rect.y0);
    val = shandle->maxvalue * val / (real32)(shandle->reg.rect.y1-shandle->reg.rect.y0);
    shandle->value = (udword)val;
}


/*-----------------------------------------------------------------------------
    Name        : uicHorizSliderProcess
    Description : Draw a checkBox
    Inputs      : reg - region representing toggle
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
udword uicHorizSliderProcess(regionhandle region, sdword ID, udword event, udword data)
{
    sliderhandle shandle;
    udword mask = 0; //x,y;

    shandle = (sliderhandle)region;
    switch (event)
    {
        case RPE_ReleaseLeft:
            //shandle->processFunction(region, ID, CM_ButtonClick, shandle->clickType);
            mouseClipToRect(NULL);
            mask |= RPR_Redraw;
            break;
        case RPE_PressLeft:


            mouseClipToRect(&region->rect);


            SetHSliderValue(shandle);
            mask |= RPR_Redraw;

            if (shandle->processFunction)
                shandle->processFunction(region,ID,event,data);
            break;
        case RPE_EnterHoldLeft:
            //shandle->clickType = SC_Thumb;
            mask |= RPR_Redraw;
            break;
        case RPE_HoldLeft:

            SetHSliderValue(shandle);
            if (shandle->processFunction)
                shandle->processFunction(region,ID,event,data);
            mask |= RPR_Redraw;
            break;
        case RPE_Enter:
        case RPE_Exit:
        case RPE_ExitHoldLeft:
            mask |= RPR_Redraw;
            break;

    #if 0
        default:
            shandle->clickType = SC_NoRegion;
    #endif
    }

    if (mask != 0)
    {
        regRecursiveSetDirty(region);
    }
    return mask;
}


udword uicVertSliderProcess(regionhandle region, sdword ID, udword event, udword data)
{
    sliderhandle shandle;
    udword mask = 0; //x,y;

    shandle = (sliderhandle)region;
    switch (event)
    {
        case RPE_ReleaseLeft:
            //shandle->processFunction(region, ID, CM_ButtonClick, shandle->clickType);
            mouseClipToRect(NULL);
            mask |= RPR_Redraw;
            break;
        case RPE_WheelUp:
            //shandle->processFunction(region, ID, CM_ButtonClick, SC_Negative);
            mask |= RPR_Redraw;
            break;
        case RPE_WheelDown:
            //shandle->processFunction(region, ID, CM_ButtonClick, SC_Positive);
            mask |= RPR_Redraw;
            break;
        case RPE_PressLeft:


            mouseClipToRect(&region->rect);


            SetVSliderValue(shandle);
            mask |= RPR_Redraw;

            if (shandle->processFunction)
                shandle->processFunction(region,ID,event,data);
            break;
        case RPE_EnterHoldLeft:
            //shandle->clickType = SC_Thumb;
            mask |= RPR_Redraw;
            break;
    case RPE_HoldLeft:

            SetVSliderValue(shandle);
            if (shandle->processFunction)
                shandle->processFunction(region,ID,event,data);
            mask |= RPR_Redraw;
            break;
        case RPE_Enter:
        case RPE_Exit:
        case RPE_ExitHoldLeft:
            mask |= RPR_Redraw;
            break;

    #if 0
        default:
            shandle->clickType = SC_NoRegion;
    #endif
    }

    if (mask != 0)
    {
        regRecursiveSetDirty(region);
    }
    return mask;
}


/*-----------------------------------------------------------------------------
    Name        : uicHorizSliderDraw
    Description : Draw a checkBox
    Inputs      : reg - region representing slider
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicHorizSliderDraw(regionhandle reg)
{
    /*
    rectangle erase;

    erase = reg->rect;                                      //erase the background to get rid of text that might be there
    erase.y0 += 3;
    erase.x0 += 3;
    erase.x1 -= 3;
    */

    if (bitTest(reg->status, RSF_RegionDisabled))
    {
        ferDrawHorizSlider((sliderhandle)reg, s_disabled);
    }
    else if (bitTest(reg->status, RSF_MouseInside))
    {
        if (bitTest(reg->status, RSF_LeftPressed))
        {
            ferDrawHorizSlider((sliderhandle)reg, s_on_mouse);
        }
        else
        {
            ferDrawHorizSlider((sliderhandle)reg, s_off_mouse);
        }
    }
    else
    {
        ferDrawHorizSlider((sliderhandle)reg, s_off);
    }
}

void uicVertSliderDraw(regionhandle reg)
{
    if (bitTest(reg->status, RSF_MouseInside))
    {
        if (bitTest(reg->status, RSF_LeftPressed))
        {
            ferDrawVertSlider((sliderhandle)reg, s_on_mouse);
        }
        else
        {
            ferDrawVertSlider((sliderhandle)reg, s_off_mouse);
        }
    }
    else
    {
        ferDrawVertSlider((sliderhandle)reg, s_off);
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicRepositionText
    Description : Reposition the text of a text entry control such that the
                    cursor is still on-screen.
    Inputs      : entry - entry to reposition.
                  jump - if TRUE and the cursor is out of the window, the text
                    will be repositioned more than enough to get the cursor back
                    into the window.  It will be jumped so to speak.
    Outputs     :
    Return      : TRUE if cursor needed repositioning.
----------------------------------------------------------------------------*/
bool uicRepositionText(textentryhandle entry, bool jumpReposition)
{
    sdword length;
    fonthandle fhSave;

    fhSave = fontCurrentGet();                              //save the current font
    fontMakeCurrent(entry->currentFont);                    //select the appropriate font

    if (entry->iCharacter < entry->iVisible)
    {                                                       //if cursor off right of window
        entry->iVisible = entry->iCharacter;
        return(TRUE);
    }

    length = fontWidthN(entry->textBuffer + entry->iVisible, entry->iCharacter - entry->iVisible);
    if (length > entry->textRect.x1 - entry->textRect.x0)
    {                                                       //if cursor off right of window
        do
        {
            entry->iVisible++;
            length = fontWidthN(entry->textBuffer + entry->iVisible, entry->iCharacter - entry->iVisible);
            dbgAssert(entry->iVisible <= entry->iCharacter);
        }
        while (length > entry->textRect.x1 - entry->textRect.x0);
        return(TRUE);
    }
    fontMakeCurrent(fhSave);
    return(FALSE);
}

/*-----------------------------------------------------------------------------
    Name        : uicInsertCharacter
    Description : Insert a typed character into the text box.
    Inputs      : entry - text entry control to insert the character into.
                  character - character to insert
    Outputs     : inserts the character at the current point of typing.
    Return      : TRUE if the character was inserted correctly.
----------------------------------------------------------------------------*/
bool uicInsertCharacter(textentryhandle entry, udword character)
{
    sdword index;
    regVerify(&entry->reg);

    if (bitTest(entry->textflags, UICTE_FileName))
    {                                                       //if it's a filename we're typing
        if (strchr(UICTE_FileNameInvalids, character))
        {                                                   //and it's an invalid filename character
            return(FALSE);
        }
    }
    if (strlen(entry->textBuffer)+1 >= entry->bufferLength - 1)
    {
        return(FALSE);
    }
    //insert an empty space for the character
    for (index = strlen(entry->textBuffer); index >= entry->iCharacter; index--)
    {
        entry->textBuffer[index + 1] = entry->textBuffer[index];
    }
    entry->textBuffer[entry->iCharacter] = (ubyte)character;//put in the new character
    entry->iCharacter++;                                    //move the cursor over a bit
    dbgAssert(strlen(entry->textBuffer) < entry->bufferLength);//make sure we didn't run on too long
    uicRepositionText(entry, FALSE);                        //reposition the text
    return(TRUE);
}

/*-----------------------------------------------------------------------------
    Name        : uicBackspaceCharacter
    Description : Delete the character to the left of the cursor in a text
                    entry box.
    Inputs      : entry - control to delete a character from
    Outputs     :
    Return      : TRUE if the character was deleted properly
----------------------------------------------------------------------------*/
bool uicBackspaceCharacter(textentryhandle entry)
{
    sdword index;
    regVerify(&entry->reg);
    if (entry->iCharacter == 0)
    {                                                       //if there is nothing to the left of the cursor
        return(FALSE);                                      //nothing to do
    }
    for (index = entry->iCharacter; index <= strlen(entry->textBuffer); index++)
    {
        entry->textBuffer[index - 1] = entry->textBuffer[index];
    }
    entry->iCharacter--;
    uicRepositionText(entry, TRUE);                         //reposition the text
    return(TRUE);
}

/*-----------------------------------------------------------------------------
    Name        : uicDeleteCharacter
    Description : Delete the character to the right of the cursor.
    Inputs      : entry - control to delete character from
    Outputs     :
    Return      : TRUE if the character was deleted properly
----------------------------------------------------------------------------*/
bool uicDeleteCharacter(textentryhandle entry)
{
    sdword index;
    regVerify(&entry->reg);
    if (entry->iCharacter == strlen(entry->textBuffer))
    {                                                       //if nothing to right of cursor
        return(FALSE);
    }
    for (index = entry->iCharacter; index <= strlen(entry->textBuffer); index++)
    {
        entry->textBuffer[index] = entry->textBuffer[index + 1];
    }
    return(TRUE);
}

/*-----------------------------------------------------------------------------
    Name        : uicCursorMoveRelative
    Description : Move the cursor in a text entry box.
    Inputs      : entry - entry who's cursor we are to move
                  amount - amount to move the cursor by.  Can be negative.
    Outputs     :
    Return      : actual amount the cursor was moved
----------------------------------------------------------------------------*/
sdword uicCursorMoveRelative(textentryhandle entry, sdword amount)
{
    sdword oldICharacter;

    regVerify(&entry->reg);
    oldICharacter = entry->iCharacter;
    entry->iCharacter += amount;
    if (entry->iCharacter < 0)
    {
        entry->iCharacter = 0;
    }
    if (entry->iCharacter > strlen(entry->textBuffer))
    {
        entry->iCharacter = strlen(entry->textBuffer);
    }
    uicRepositionText(entry, TRUE);                         //reposition the text
    return(oldICharacter - entry->iCharacter);
}

/*-----------------------------------------------------------------------------
    Name        : uicCursorWordLeft
    Description : Move the cursor to the left one word.
    Inputs      :
    Outputs     :
    Return      : TRUE if the cursor was moved.
----------------------------------------------------------------------------*/
bool uicCursorWordLeft(textentryhandle entry)
{
    if (entry->iCharacter == 0)
    {                                                       //if can't move left
        return(FALSE);
    }
    //look left until we find a non-blank character
    while (entry->iCharacter > 0)
    {
        entry->iCharacter--;
        if (!strchr(uicSpaceCharacters, entry->textBuffer[entry->iCharacter]))
        {
            break;
        }
    }
    //try to find a blank character
    while (entry->iCharacter > 0)
    {
        if (strchr(uicSpaceCharacters, entry->textBuffer[entry->iCharacter - 1]))
        {
            break;
        }
        entry->iCharacter--;
    }
    uicRepositionText(entry, TRUE);                         //reposition the text
    return(TRUE);
}

/*-----------------------------------------------------------------------------
    Name        : uicCursorWordRight
    Description : Move the cursor to the left one word.
    Inputs      :
    Outputs     :
    Return      : TRUE if the cursor was moved.
----------------------------------------------------------------------------*/
bool uicCursorWordRight(textentryhandle entry)
{
    sdword length = strlen(entry->textBuffer);
    if (entry->iCharacter >= length - 1)
    {                                                       //if can't move right
        return(FALSE);
    }
    //look right until we find a non-blank character
    while (entry->iCharacter < length)
    {
        if (!strchr(uicSpaceCharacters, entry->textBuffer[entry->iCharacter]))
        {
            break;
        }
        entry->iCharacter++;
    }
    //try to find a blank character
    while (entry->iCharacter < length)
    {
        if (strchr(uicSpaceCharacters, entry->textBuffer[entry->iCharacter]))
        {
            break;
        }
        entry->iCharacter++;
    }
    uicRepositionText(entry, TRUE);                         //reposition the text
    return(TRUE);
}

udword keyLanguageTranslate(udword wParam);

/*-----------------------------------------------------------------------------
    Name        : uicTextEntryProcess
    Description : Process messages for a text entry box.
    Inputs      : data - keystroke scancode with shift status
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
udword uicTextEntryProcess(regionhandle reg, sdword ID, udword event, udword data)
{
    textentryhandle entry = (textentryhandle)reg;
    featom *atom = (featom *)reg->userID;
    regionhandle tabRegion;
    udword mask = 0;
    bool bShift = bitTest(data, RF_ShiftBit);

    bitClear(data, RF_ShiftBit);

    switch(event)
    {
        case RPE_KeyDown:
            mask |= RPR_Redraw;
#if UIC_VERBOSE_LEVEL >= 2
            dbgMessagef("\nuicTextEntryProcess:  key pressed: 0x%x, '%c'", data, data);
#endif
            //data = keyLanguageTranslate(data);

            switch (data)
            {
                case ESCKEY:
                    entry->message = CM_RejectText;
                    feFunctionExecute(atom->name, atom, FALSE);
                    uicEscProcess(reg,ID,event,data);
                    break;
                case ENTERKEY:
                    entry->message = CM_AcceptText;
                    feFunctionExecute(atom->name, atom, FALSE);
                    if (!(entry->textflags&UICTE_NoLossOfFocus))
                    {
                        bitClear(reg->status, RSF_KeyCapture);
                        regKeysFocussed = FALSE;
                    }
                    break;
                case BACKSPACEKEY:
                    uicBackspaceCharacter(entry);
                    break;
                case DELETEKEY:
                    uicDeleteCharacter(entry);
                    break;
                case ARRLEFT:
                    if (keyIsHit(CONTROLKEY))
                    {
                        uicCursorWordLeft(entry);
                    }
                    else
                    {
                        uicCursorMoveRelative(entry, -1);
                    }
                    break;
                case ARRRIGHT:
                    if (keyIsHit(CONTROLKEY))
                    {
                        uicCursorWordRight(entry);
                    }
                    else
                    {
                        uicCursorMoveRelative(entry, 1);
                    }
                    break;
                case HOMEKEY:
                    uicCursorMoveRelative(entry, SWORD_Min);
                    break;
                case ENDKEY:
                    uicCursorMoveRelative(entry, SWORD_Max);
                    break;
                case TABKEY:
                    tabRegion = regSiblingFindByFunction(reg, uicTabProcess);
                    if (tabRegion == NULL) break;
                    uicTabProcess(reg, tabRegion->userID, 0, 0);
                    break;
                case PAGEUPKEY:
                case PAGEDOWNKEY:
                    if (bitTest(entry->textflags,UICTE_SpecialChars))
                    {
                        entry->message = CM_SpecialKey;
                        entry->key     = data;
                        feFunctionExecute(atom->name, atom, FALSE);
                    }
                    break;
                default:
                    switch (strCurKeyboardLanguage)
                    {
                        case languageEnglish:
                            if (bitTest(entry->textflags,UICTE_NumberEntry))
                            {
                                if ( (data>= ZEROKEY) && (data<=NINEKEY) )
                                {
                                    uicInsertCharacter(entry, uicKeyEntryTable[data].regularKey);
                                }
                                if ( (data>=NUMPAD0) && (data<=NUMPAD9) )
                                {
                                    uicInsertCharacter(entry, uicKeyEntryTable[data].regularKey);
                                }
                            }
                            else
                            {
                                if (bShift)
                                {
                                    if (uicKeyEntryTable[data].shiftKey)
                                    {
                                        if ( (bitTest(entry->textflags, UICTE_UserNameEntry)) &&
                                             (data != SPACEKEY) )
                                        {
                                            uicInsertCharacter(entry, uicKeyEntryTable[data].shiftKey);
                                        }
                                        else
                                            uicInsertCharacter(entry, uicKeyEntryTable[data].shiftKey);
                                    }
                                }
                                else if (uicKeyEntryTable[data].regularKey)
                                {
                                    if (bitTest(entry->textflags, UICTE_UserNameEntry))
                                    {
                                        if (data != SPACEKEY) uicInsertCharacter(entry, uicKeyEntryTable[data].regularKey);
                                    }
                                    else
                                        uicInsertCharacter(entry, uicKeyEntryTable[data].regularKey);
                                }
                            }

                            if (bitTest(entry->textflags, UICTE_ChatTextEntry))
                            {
                                entry->message = CM_KeyPressed;
                                feFunctionExecute(atom->name, atom, FALSE);
                            }
        #if UIC_VERBOSE_LEVEL >= 2
                            dbgMessagef(" (unprocessed)");
        #endif
                        break;
                        case languageFrench:
                            if (bitTest(entry->textflags,UICTE_NumberEntry))
                            {
                                if ( (data>= ZEROKEY) && (data<=NINEKEY) )
                                {
                                    uicInsertCharacter(entry, uicFrenchKeyEntryTable[data].regularKey);
                                }
                                if ( (data>=NUMPAD0) && (data<=NUMPAD9) )
                                {
                                    uicInsertCharacter(entry, uicFrenchKeyEntryTable[data].regularKey);
                                }
                            }
                            else
                            {
                                if (bShift)
                                {
                                    if (uicFrenchKeyEntryTable[data].shiftKey)
                                    {
                                        if ( (bitTest(entry->textflags, UICTE_UserNameEntry)) &&
                                             (data != SPACEKEY) )
                                        {
                                            uicInsertCharacter(entry, uicFrenchKeyEntryTable[data].shiftKey);
                                        }
                                        else
                                            uicInsertCharacter(entry, uicFrenchKeyEntryTable[data].shiftKey);
                                    }
                                }
                                else if (uicFrenchKeyEntryTable[data].regularKey)
                                {
                                    if (bitTest(entry->textflags, UICTE_UserNameEntry))
                                    {
                                        if (data != SPACEKEY) uicInsertCharacter(entry, uicFrenchKeyEntryTable[data].regularKey);
                                    }
                                    else
                                        uicInsertCharacter(entry, uicFrenchKeyEntryTable[data].regularKey);
                                }
                            }

                            if (bitTest(entry->textflags, UICTE_ChatTextEntry))
                            {
                                entry->message = CM_KeyPressed;
                                feFunctionExecute(atom->name, atom, FALSE);
                            }
        #if UIC_VERBOSE_LEVEL >= 2
                            dbgMessagef(" (unprocessed)");
        #endif
                        break;
                        case languageGerman:
                            if (bitTest(entry->textflags,UICTE_NumberEntry))
                            {
                                if ( (data>= ZEROKEY) && (data<=NINEKEY) )
                                {
                                    uicInsertCharacter(entry, uicGermanKeyEntryTable[data].regularKey);
                                }
                                if ( (data>=NUMPAD0) && (data<=NUMPAD9) )
                                {
                                    uicInsertCharacter(entry, uicGermanKeyEntryTable[data].regularKey);
                                }
                            }
                            else
                            {
                                if (bShift)
                                {
                                    if (uicGermanKeyEntryTable[data].shiftKey)
                                    {
                                        if ( (bitTest(entry->textflags, UICTE_UserNameEntry)) &&
                                             (data != SPACEKEY) )
                                        {
                                            uicInsertCharacter(entry, uicGermanKeyEntryTable[data].shiftKey);
                                        }
                                        else
                                            uicInsertCharacter(entry, uicGermanKeyEntryTable[data].shiftKey);
                                    }
                                }
                                else if (uicGermanKeyEntryTable[data].regularKey)
                                {
                                    if (bitTest(entry->textflags, UICTE_UserNameEntry))
                                    {
                                        if (data != SPACEKEY) uicInsertCharacter(entry, uicGermanKeyEntryTable[data].regularKey);
                                    }
                                    else
                                        uicInsertCharacter(entry, uicGermanKeyEntryTable[data].regularKey);
                                }
                            }

                            if (bitTest(entry->textflags, UICTE_ChatTextEntry))
                            {
                                entry->message = CM_KeyPressed;
                                feFunctionExecute(atom->name, atom, FALSE);
                            }
        #if UIC_VERBOSE_LEVEL >= 2
                            dbgMessagef(" (unprocessed)");
        #endif
                        break;
                        case languageSpanish:
                            if (bitTest(entry->textflags,UICTE_NumberEntry))
                            {
                                if ( (data>= ZEROKEY) && (data<=NINEKEY) )
                                {
                                    uicInsertCharacter(entry, uicSpanishKeyEntryTable[data].regularKey);
                                }
                                if ( (data>=NUMPAD0) && (data<=NUMPAD9) )
                                {
                                    uicInsertCharacter(entry, uicSpanishKeyEntryTable[data].regularKey);
                                }
                            }
                            else
                            {
                                if (bShift)
                                {
                                    if (uicSpanishKeyEntryTable[data].shiftKey)
                                    {
                                        if ( (bitTest(entry->textflags, UICTE_UserNameEntry)) &&
                                             (data != SPACEKEY) )
                                        {
                                            uicInsertCharacter(entry, uicSpanishKeyEntryTable[data].shiftKey);
                                        }
                                        else
                                            uicInsertCharacter(entry, uicSpanishKeyEntryTable[data].shiftKey);
                                    }
                                }
                                else if (uicSpanishKeyEntryTable[data].regularKey)
                                {
                                    if (bitTest(entry->textflags, UICTE_UserNameEntry))
                                    {
                                        if (data != SPACEKEY) uicInsertCharacter(entry, uicSpanishKeyEntryTable[data].regularKey);
                                    }
                                    else
                                        uicInsertCharacter(entry, uicSpanishKeyEntryTable[data].regularKey);
                                }
                            }

                            if (bitTest(entry->textflags, UICTE_ChatTextEntry))
                            {
                                entry->message = CM_KeyPressed;
                                feFunctionExecute(atom->name, atom, FALSE);
                            }
        #if UIC_VERBOSE_LEVEL >= 2
                            dbgMessagef(" (unprocessed)");
        #endif
                        break;
                        case languageItalian:
                            if (bitTest(entry->textflags,UICTE_NumberEntry))
                            {
                                if ( (data>= ZEROKEY) && (data<=NINEKEY) )
                                {
                                    uicInsertCharacter(entry, uicItalianKeyEntryTable[data].regularKey);
                                }
                                if ( (data>=NUMPAD0) && (data<=NUMPAD9) )
                                {
                                    uicInsertCharacter(entry, uicItalianKeyEntryTable[data].regularKey);
                                }
                            }
                            else
                            {
                                if (bShift)
                                {
                                    if (uicItalianKeyEntryTable[data].shiftKey)
                                    {
                                        if ( (bitTest(entry->textflags, UICTE_UserNameEntry)) &&
                                             (data != SPACEKEY) )
                                        {
                                            uicInsertCharacter(entry, uicItalianKeyEntryTable[data].shiftKey);
                                        }
                                        else
                                            uicInsertCharacter(entry, uicItalianKeyEntryTable[data].shiftKey);
                                    }
                                }
                                else if (uicItalianKeyEntryTable[data].regularKey)
                                {
                                    if (bitTest(entry->textflags, UICTE_UserNameEntry))
                                    {
                                        if (data != SPACEKEY) uicInsertCharacter(entry, uicItalianKeyEntryTable[data].regularKey);
                                    }
                                    else
                                        uicInsertCharacter(entry, uicItalianKeyEntryTable[data].regularKey);
                                }
                            }

                            if (bitTest(entry->textflags, UICTE_ChatTextEntry))
                            {
                                entry->message = CM_KeyPressed;
                                feFunctionExecute(atom->name, atom, FALSE);
                            }
        #if UIC_VERBOSE_LEVEL >= 2
                            dbgMessagef(" (unprocessed)");
        #endif
                        break;
                    }
            }
            break;

        case RPE_PressLeft:
            uicClearCurrent(reg);
            uicSetCurrent(reg, FALSE);

            entry->message = CM_GainFocus;
            feFunctionExecute(atom->name, atom, FALSE);

            soundEvent(NULL, UI_Click);
            mask |= RPR_Redraw;
        break;

        case RPE_ExitHoldLeft:
        case RPE_Enter:
        case RPE_Exit:
            mask |= RPR_Redraw;
        break;

        case RPE_ReleaseLeft:
            mask |= RPR_Redraw;
        break;

        default:;
#if UIC_VERBOSE_LEVEL >= 1
            dbgMessagef("\nuicTextEntryProcess: unimplemented or unsupported message: 0x%x, userID 0x%x, data 0x%x (%d)", event, ID, data, data);
#endif
    }
    if (mask != 0)
    {
        regRecursiveSetDirty(reg);
    }
    return mask;
}

/*-----------------------------------------------------------------------------
    Name        : uicTextEntryDraw
    Description : Draw a text entry region.
    Inputs      : reg - region the text entry box corresponds to.
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicTextEntryDraw(regionhandle reg)
{
    featom *atom = (featom *)reg->userID;
    textentryhandle entry = (textentryhandle)reg;
    fonthandle fhSave;
    sdword caretLocation, nCharacters, length;
    sdword i, y;
//    udword timerInt, flashRateInt;
    char   temp[256];

    // text entry draw start ***

    if (!bitTest(entry->textflags,UICTE_NoTextures))
    {
        if (feStack[feStackIndex].screen != ((buttonhandle)reg)->screen)
        {
            ferDrawButton(reg->rect, te_off);
        }
        else
        {
            if (!uicMouseFocus)
                uicFocusToMouse(reg);

            if (bitTest(reg->status, RSF_RegionDisabled))
            {
                ferDrawButton(reg->rect, te_off_disabled);
            }
            else if (bitTest(reg->status, RSF_LeftPressed))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawButton(reg->rect, te_on_focus_mouse);
                }
                else
                {
                    ferDrawButton(reg->rect, te_off_focus_mouse);
                }
            }
            else if (bitTest(reg->status, RSF_CurrentSelected))
            {
                if (bitTest(reg->status, RSF_MouseInside))
                {
                    ferDrawButton(reg->rect, te_off_focus_mouse);
                }
                else
                {
                    ferDrawButton(reg->rect, te_off_focus);
                }
            }
            else if (bitTest(reg->status, RSF_MouseInside))
            {
                ferDrawButton(reg->rect, te_off_mouse);
            }
            else
            {
                ferDrawButton(reg->rect, te_off);
            }
        }
    }

    // text entry draw end ***

    dbgAssert(entry->textBuffer != NULL);                   //make sure there is a string
    fhSave = fontCurrentGet();                              //save the current font
    fontMakeCurrent(entry->currentFont);                    //select the appropriate font
    if (bitTest(entry->textflags, UICTE_DropShadow))
    {
        fontShadowSet(FS_SE, entry->shadowColor);
    }
    y = ((entry->textRect.y1 - entry->textRect.y0) - fontHeight(" ")) / 2 + entry->textRect.y0;
    if (strlen(entry->textBuffer) != 0)
    {                                                       //if there is a string to draw
        //figure how many characters to draw
        nCharacters = strlen(entry->textBuffer + entry->iVisible);
        length = fontWidth(entry->textBuffer + entry->iVisible);

        while (nCharacters > 0 && length > entry->textRect.x1 - entry->textRect.x0)
        {
            length = fontWidthN(entry->textBuffer + entry->iVisible, nCharacters);
            nCharacters--;
        }

        if (entry->textflags&UICTE_PasswordEntry)
        {
            memset(temp,0,256);
            for (i=0;i<nCharacters;i++)
            {
                temp[i] = 'x';
            }
            fontPrintN(entry->textRect.x0, y, entry->borderColor, temp, nCharacters);
        }
        else
        {
            fontPrintN(entry->textRect.x0, y, entry->borderColor, entry->textBuffer + entry->iVisible, nCharacters);
        }
    }
    //now draw a flashing caret, if there is input focus
    if (bitTest(reg->status, RSF_KeyCapture))
    {                                                       //if this region has input focus
        //timerInt = (udword)(taskTimeElapsed * 256);
        //flashRateInt = (udword)(entry->flashRate * 256);
//        if ((timerInt % flashRateInt) > (flashRateInt / 2))
//        {                                                   //if the flash action in is the 'on' state
        if (entry->textflags&UICTE_PasswordEntry)
        {
            caretLocation = entry->textRect.x0 +
                fontWidthN(temp, entry->iCharacter - entry->iVisible);
        }
        else
        {
            caretLocation = entry->textRect.x0 +
                fontWidthN(entry->textBuffer + entry->iVisible, entry->iCharacter - entry->iVisible);
        }
/*        if (frFontRegistry[entry->currentFont].fontdat->character['|'] != NULL)
        {                                               //draw a pipe of the current font if there is one
            fontPrint(caretLocation, y, entry->borderColor, "|");
        }
        else*/
        {                                               //draw a small rectangle instead of a pipe
            primLine2(caretLocation-1, y+2,
                      caretLocation-1, y + fontHeight(" "), entry->borderColor);
        }
//        }
    }
    fontShadowSet(FS_NONE, colBlack);

    fontMakeCurrent(fhSave);
}

/*-----------------------------------------------------------------------------
    Name        : uicDragButtonProcess
    Description : Process a drag button
    Inputs      :
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
udword uicDragButtonProcess(regionhandle region, sdword ID, udword event, udword data)
{
    udword mask = 0;

    switch (event)
    {
        case RPE_PressLeft:
            uicClearCurrent(region);
            uicSetCurrent(region, FALSE);
            soundEvent(NULL, UI_Click);
            mask |= RPR_Redraw;

            ((buttonhandle)region)->clickX = mouseCursorX();//record where the user clicked
            ((buttonhandle)region)->clickY = mouseCursorY();
            mouseCursorHide();
            ((buttonhandle)region)->bDragged = FALSE;
            break;
        case RPE_KeyDown:
            soundEvent(NULL, UI_Click);
            ((buttonhandle)region)->processFunction(region, ID, CM_ButtonClick, 0);
            ((buttonhandle)region)->bDragged = FALSE;
            break;
        case RPE_ReleaseLeft:
            mouseCursorShow();
            //...see if there was draggage
            if (!((buttonhandle)region)->bDragged)
            {                                               //if the mouse was never dragged
                uicDragX = uicDragY = 0;
                ((buttonhandle)region)->processFunction(region, ID, CM_ButtonClick, 0);
            }
            break;
        case RPE_ExitHoldLeft:
            bitSet(region->status, RSF_MouseInside);        //make mouse think it's still in this region
            bitSet(region->status, RSF_LeftPressed);
            //fall through
        case RPE_HoldLeft:
        case RPE_EnterHoldLeft:
            if (((buttonhandle)region)->bDragged)
            {                                               //if dragging has already happened
                if (((buttonhandle)region)->clickX != mouseCursorX() ||
                    ((buttonhandle)region)->clickY != mouseCursorY())
                {                                           //if the mouse has been dragged
                    //...register the motion
                    uicDragX = mouseCursorX() - ((buttonhandle)region)->clickX;
                    uicDragY = mouseCursorY() - ((buttonhandle)region)->clickY;
                    ((buttonhandle)region)->processFunction(region, ID, CM_ButtonDrag,
                            ((((buttonhandle)region)->clickY - mouseCursorY()) << 16) +
                            (((buttonhandle)region)->clickX - mouseCursorX()));
                    //...reset the mouse cursor
                    mousePositionSet(((buttonhandle)region)->clickX, ((buttonhandle)region)->clickY);
                }
            }
            else
            {                                               //no dragging yet
                if (abs(((buttonhandle)region)->clickX - mouseCursorX()) >= UIC_DragButtonThresholdX ||
                    abs(((buttonhandle)region)->clickY - mouseCursorY()) >= UIC_DragButtonThresholdY)
                {                                           //if the mouse has been dragged far enough to be considered a drag
                    //...register the motion
                    ((buttonhandle)region)->bDragged = TRUE;
                    //because the drag data has to go through several layers of
                    //calling and I don't want to retrofit any of these API's,
                    //let's just pass it in global variables.
                    uicDragX = mouseCursorX() - ((buttonhandle)region)->clickX;
                    uicDragY = mouseCursorY() - ((buttonhandle)region)->clickY;
                    ((buttonhandle)region)->processFunction(region, ID, CM_ButtonDrag, 0);
                    //...reset the mouse cursor/region status to make everybody think we're still inside the region
//                    regClickedLeft = region;                //no has mouse press focus
                    mousePositionSet(((buttonhandle)region)->clickX, ((buttonhandle)region)->clickY);
                }
            }
            break;
        case RPE_Enter:
        case RPE_Exit:
            if (!mouseLeftButton())
            {                                               //if mouse button was released outside of region
                mouseCursorShow();
            }
            mask |= RPR_Redraw;
        break;
    }
    if (mask != 0)
    {
        regRecursiveSetDirty(region);
    }
    return(mask);
}

/*=============================================================================
    Functions:
=============================================================================*/
//startup/shutdown
/*-----------------------------------------------------------------------------
    Name        : uicStartup/uicShudown
    Description : Startup/shutdown of module
    Inputs      : void
    Outputs     :
    Return      : void
----------------------------------------------------------------------------*/
void uicStartup(void)
{
    ;
#if UIC_TEST
    uicChildButtonAlloc((controlhandle)ghMainRegion, 10, 10, 10, 100, 20, uicTestProcess, 0);
#endif
}
void uicShutdown(void)
{
    ;
}

/*-----------------------------------------------------------------------------
    Name        : uicChildButtonAlloc
    Description : Create a button which is a child of either a region or another control
                  This is used for creating regular buttons, toggle buttons,
                    check boxes and radio buttons
    Inputs      : parent - handle to the parent region or control
                  ID - control ID of the button to be created
                  x, y, width, height - position and size of the control
                  function - function to recieve notification of button presses
                  flags - flags for control and the type of control (see above list)
    Outputs     : allocates and initializes the region
    Return      : handle to the newly created button
----------------------------------------------------------------------------*/
buttonhandle uicChildButtonAlloc(controlhandle parent, sdword ID, sdword x, sdword y,
                sdword width, sdword height, uicfunction function, udword flags)
{
    buttonhandle newHandle;
    featom      *atom=(featom *)ID;

    newHandle = (buttonhandle)regChildAlloc((regionhandle)parent, ID, //create region with some extra RAM
                    x, y, width, height, uicStructureExtra(uicbutton),
                    uicControlFunctions[flags & CFM_ControlType].regionFilter);

    if (bitTest(atom->flags,FAF_Disabled)) bitSet(newHandle->reg.status,RSF_RegionDisabled);

    dbgAssert(uicControlFunctions[flags & CFM_ControlType].function != NULL);
    dbgAssert(uicControlFunctions[flags & CFM_ControlType].drawFunction != NULL);
    regFunctionSet((regionhandle)newHandle,                 //set process/draw functions
                   uicControlFunctions[flags & CFM_ControlType].function);
    if (bitTest(atom->flags, FAF_Hidden))
    {
        regDrawFunctionSet((regionhandle)newHandle, NULL);
    }
    else
    {
        regDrawFunctionSet((regionhandle)newHandle,
                           uicControlFunctions[flags & CFM_ControlType].drawFunction);
    }
    newHandle->processFunction = function;                  //store function pointer
    newHandle->clickX = mouseCursorX();                     //record where the user clicked
    newHandle->clickY = mouseCursorY();

//    newHandle->regionFilter = 0;                            //default to no region messages passed through
    return(newHandle);
}

/*
 * convenient
 */
void setRect(rectangle *rect, rectangle* ofs,
             uword x0, uword x1, uword y0, uword y1)
{
    rect->x0 = ofs->x0 + x0;
    rect->y0 = ofs->y0 + y0;
    rect->x1 = ofs->x0 + x1;
    rect->y1 = ofs->y0 + y1;
}

/*-----------------------------------------------------------------------------
    Name        : uicChildScrollBarAlloc
    Description : Create a scrollbar which is a child of either a region or
                  another control
    Inputs      : parent - handle to the parent region or control
                  ID - control ID of the button to be created
                  x,y, width, height - position and size of the control
                  function - function to recieve notification of button presses
                  flags - flags for control and the type of control (see above list)
    Outputs     : allocates and initializes the region
    Return      : handle to the newly created scrollbar
----------------------------------------------------------------------------*/
scrollbarhandle uicChildScrollBarAlloc(controlhandle parent, sdword ID,
                                       sdword x, sdword y, sdword width, sdword height,
                                       uicfunction function, udword flags)
{
    featom *atom = (featom *)ID;
    scrollbarhandle newHandle;

    newHandle = (scrollbarhandle)regChildAlloc((regionhandle)parent, UIC_ScrollbarTab,
                    x, y+20, width, height-40, uicStructureExtra(uicscrollbar),
                    UIF_Button | RPE_WheelDown | RPE_WheelUp | RPE_HoldLeft | RPE_EnterHoldLeft);

    if (bitTest(atom->flags,FAF_Disabled)) bitSet(newHandle->reg.status,RSF_RegionDisabled);

    atom->pData = (ubyte *)newHandle;

    newHandle->isVertical = (bool8)(width < height);

    if (newHandle->isVertical)
    {
        newHandle->upbutton = (scrollbarbuttonhandle)regChildAlloc((regionhandle)parent, UIC_ScrollbarUpButton,
                                                  x, y, width, 20, uicStructureExtra(uicscrollbarbutton),
                                                  UIF_Button | RPE_WheelDown | RPE_WheelUp | RPE_HoldLeft | RPE_EnterHoldLeft);

        newHandle->upbutton->processFunction = NULL;
//        newHandle->upbutton->regionFilter = 0;
        newHandle->upbutton->contentColor = 0;
        newHandle->upbutton->borderColor = 0;
        newHandle->upbutton->screen = NULL;
        newHandle->upbutton->scrollbar = newHandle;
        regFunctionSet((regionhandle)newHandle->upbutton, uicScrollBarProcess);
        regDrawFunctionSet((regionhandle)newHandle->upbutton, uicScrollBarButtonDraw);

        newHandle->downbutton = (scrollbarbuttonhandle)regChildAlloc((regionhandle)parent, UIC_ScrollbarDownButton,
                                                   x, y+height-20, width, 20, uicStructureExtra(uicscrollbarbutton),
                                                   UIF_Button | RPE_WheelDown | RPE_WheelUp | RPE_HoldLeft | RPE_EnterHoldLeft);

        newHandle->downbutton->processFunction = NULL;
//        newHandle->downbutton->regionFilter = 0;
        newHandle->downbutton->contentColor = 0;
        newHandle->downbutton->borderColor = 0;
        newHandle->downbutton->screen = NULL;
        newHandle->downbutton->scrollbar = newHandle;

        regFunctionSet((regionhandle)newHandle->downbutton, uicScrollBarProcess);
        regDrawFunctionSet((regionhandle)newHandle->downbutton, uicScrollBarButtonDraw);

        newHandle->thumb.x0 = x+4;
        newHandle->thumb.y0 = y+20;
        newHandle->thumb.x1 = x+width-4;
        newHandle->thumb.y1 = y+height-40;

        newHandle->thumbreg = newHandle->reg.rect;
        newHandle->thumbreg.y0+=4;
        newHandle->thumbreg.y1-=4;
    }

    regFunctionSet((regionhandle)newHandle, uicScrollBarProcess);
    regDrawFunctionSet((regionhandle)newHandle, uicScrollBarDraw);
    newHandle->processFunction = function;
//    newHandle->regionFilter = 0;
    newHandle->mouseMoved = 0;

    return newHandle;
}

/*-----------------------------------------------------------------------------
    Name        : uicChildListWindowAlloc
    Description : this allocates and initializes the listwindow uic element.
    Inputs      : atom data
    Outputs     : uiclistwindow structure handle
    Return      : void
----------------------------------------------------------------------------*/
listwindowhandle uicChildListWindowAlloc(controlhandle parent, sdword ID,
                                         sdword x, sdword y, sdword width, sdword height,
                                         uicfunction function, udword flags)
{
    featom *atom = (featom *)ID;
    listwindowhandle newHandle;
    rectangle prect;

    newHandle = (listwindowhandle)regChildAlloc((regionhandle)parent, ID,
                 x, y, width, height, uicStructureExtra(uiclistwindow),
                 UIF_Button | RPE_WheelDown | RPE_WheelUp | RPE_HoldLeft | RPE_EnterHoldLeft);

    if (bitTest(atom->flags,FAF_Disabled)) bitSet(newHandle->reg.status,RSF_RegionDisabled);

    atom->pData = (ubyte *)newHandle;

    prect.x0 = x;
    prect.x1 = x + width;
    prect.y0 = y;
    prect.y1 = y + height;

    regFunctionSet((regionhandle)newHandle, uicListWindowProcess);
    if (bitTest(atom->flags, FAF_Hidden))
    {
        regDrawFunctionSet((regionhandle)newHandle, NULL);
    }
    else
    {
        regDrawFunctionSet((regionhandle)newHandle, uicListWindowDraw);
    }
    newHandle->processFunction  = function;

    newHandle->titleprocess     = NULL;
    newHandle->titledraw        = NULL;
    newHandle->itemdraw         = NULL;

    newHandle->windowflags      = 0;
    newHandle->ListTotal        = 0;
    newHandle->UpperIndex       = 0;
    newHandle->MaxIndex         = 0;
    newHandle->windowflags      = 0;
    newHandle->TitleHeight      = 0;
    newHandle->sorttype         = -1;
    newHandle->sortOrder        = TRUE;
    newHandle->topitem          = NULL;
    listInit(&newHandle->listofitems);
    newHandle->CurLineSelected=NULL;

    return newHandle;
}


/*-----------------------------------------------------------------------------
    Name        : uicListWindowInit
    Description : inititalizes the window with the information passed into.
    Inputs      : listwindow, all info for initilization
    Outputs     : none
    Return      : none
----------------------------------------------------------------------------*/
void uicListWindowInit(listwindowhandle     listwindow,
                       listtitlebardraw     titledraw,
                       listtitlebarclick    titleclick,
                       sdword               titleheight,
                       listitemdraw         itemdraw,
                       sdword               itemheight,
                       udword               flags)
{
    listwindow->windowflags     = flags;
    if (bitTest(flags,UICLW_CanHaveFocus))
        listwindow->reg.flags |= RPE_KeyDown;
    if (titledraw   != NULL) listwindow->windowflags |= UICLW_HasTitleBar;
    if (titleclick  != NULL) listwindow->windowflags |= UICLW_CanClickOnTitle;
    listwindow->reg.flags |= RPE_DoubleLeft;


    listwindow->titledraw       = titledraw;
    listwindow->titleprocess    = titleclick;
    listwindow->TitleHeight     = titleheight;
    listwindow->itemdraw        = itemdraw;
    listwindow->itemheight      = itemheight;
    listwindow->MaxIndex        = (listwindow->reg.rect.y1 - titleheight - listwindow->reg.rect.y0 - (uicListWindowMargin*2)) / itemheight;
    uicListScrollBarAdjust(listwindow);
}


/*-----------------------------------------------------------------------------
    Name        : uicListAddItem
    Description : adds an item to a the linked list of items and sets it up accordingly.
    Inputs      : listwindow, item
    Outputs     : none
    Return      : none
----------------------------------------------------------------------------*/
listitemhandle uicListAddItem(listwindowhandle listwindow, ubyte *data, udword flags, udword where)
{
    listitemhandle item;
    Node         *walk, *recalc=NULL;
    sdword        i = 1, pos;

    dbgAssert(listwindow!=NULL);

    item = (listitemhandle)memAlloc(sizeof(uiclistitem),"GameListElement",NonVolatile);
    item->data  = data;
    item->flags = flags;

    if (listwindow->listofitems.num == 0)
    {
        listwindow->topitem = item;
    }
    if (where==UICLW_AddToHead)
    {
        if (listwindow->listofitems.head!=NULL)
        {
            recalc = &item->link;
            pos = ((listitemhandle)listGetStructOfNode(listwindow->listofitems.head))->position;
            listAddNodeBefore(listwindow->listofitems.head,&item->link, item);
            listwindow->topitem = item;
        }
        else
        {
            listAddNode(&listwindow->listofitems, &item->link, item);
            item->position = 0;
        }
    }
    else if (where==UICLW_AddToTail)
    {
        if (listwindow->listofitems.tail!=NULL)
        {
            item->position = ((listitemhandle)listGetStructOfNode(listwindow->listofitems.tail))->position+1;
            listAddNodeAfter(listwindow->listofitems.tail, &item->link, item);
        }
        else
        {
            listAddNode(&listwindow->listofitems, &item->link, item);
            item->position = 0;
        }
    }
    else
    {
        if (listwindow->listofitems.head!=NULL)
        {
            item->position = ((listitemhandle)listGetStructOfNode(listwindow->listofitems.tail))->position+1;
            listAddNode(&listwindow->listofitems, &item->link, item);
        }
        else
        {
            listAddNode(&listwindow->listofitems, &item->link, item);
            item->position = 0;
        }
    }

    while (recalc != NULL)
    {
        pos++;
        ((listitemhandle)listGetStructOfNode(recalc))->position = pos;
        recalc = recalc->next;
    }

    listwindow->ListTotal++;
#ifdef DEBUG_STOMP
                regVerify(&listwindow->reg);
#endif
    regRecursiveSetDirty(&listwindow->reg);
    regDirtyScreensAboveRegion(&listwindow->reg);
//    listwindow->reg.status |= RSF_DrawThisFrame;

    if ( (listwindow->ListTotal > listwindow->MaxIndex) &&
         (listwindow->windowflags & UICLW_AutoScroll) &&
         (!(listwindow->windowflags & UICLW_AutoScrollOff)))
    {
        walk = listwindow->listofitems.tail;
        listwindow->UpperIndex = listwindow->ListTotal-1;

        while ( (walk->prev != NULL) && (i<listwindow->MaxIndex) )
        {
            i++;
            listwindow->UpperIndex--;
            walk = walk->prev;
        }

        listwindow->topitem = (listitemhandle)listGetStructOfNode(walk);
    }

    if (bitTest(flags,UICLI_Selected))
    {
        listwindow->CurLineSelected = item;
        uicListWindowViewSelection(listwindow);
    }
    uicListScrollBarAdjust(listwindow);

    return (item);
}

/*-----------------------------------------------------------------------------
    Name        : uicListFindItemByData
    Description : returns a listitemhandle which has data data in it, NULL if not found
    Inputs      :
    Outputs     :
    Return      : returns a listitemhandle which has data data in it, NULL if not found
----------------------------------------------------------------------------*/
listitemhandle uicListFindItemByData(listwindowhandle listwindow, ubyte *data)
{
    Node           *walk;
    listitemhandle item;

    walk = listwindow->listofitems.head;

    while (walk != NULL)
    {
        item = listGetStructOfNode(walk);
        if (item->data == data)
        {
            return item;
        }
        walk = walk->next;
    }

    return NULL;
}

/*-----------------------------------------------------------------------------
    Name        : uicListRemoveItemByData
    Description : remove a item from the list by its data
    Inputs      :
    Outputs     :
    Return      : remove a item from the list by its data
----------------------------------------------------------------------------*/
void uicListRemoveItemByData(listwindowhandle listwindow, ubyte *data)
{
    listitemhandle item = uicListFindItemByData(listwindow,data);
    if (item)
    {
        uicListRemoveItem(listwindow,item);
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicListFindFirstItem
    Description : returns the first item in a listwindow, or NULL
    Inputs      :
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
listitemhandle uicListFindFirstItem(listwindowhandle listwindow)
{
    if (listwindow->listofitems.head != NULL)
    {
        return listGetStructOfNode(listwindow->listofitems.head);
    }
    else
    {
        return NULL;
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicListRemoveAllItems
    Description : removes every item from a listwindow
    Inputs      :
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicListRemoveAllItems(listwindowhandle listwindow)
{
    listitemhandle item;

    for (;;)
    {
        item = uicListFindFirstItem(listwindow);
        if (item == NULL)
        {
            break;
        }
        uicListRemoveItem(listwindow, item);
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicListRemoveItem
    Description : removes an item from the list linked list of items and sets it up accordingly.
    Inputs      : listwindow, item
    Outputs     : none
    Return      : none
----------------------------------------------------------------------------*/
void uicListRemoveItem(listwindowhandle listwindow, listitemhandle item)
{
    Node           *walk,*count;
    bool            found=FALSE;
    listitemhandle  iteminfo, newpos;
    sdword          i, relativecount;

    walk = listwindow->listofitems.head;

    while (walk != NULL)
    {
        if (item == listGetStructOfNode(walk))
        {
            found = TRUE;
            break;
        }
        walk = walk->next;
    }

    if (found)
    {
        iteminfo = (listitemhandle)listGetStructOfNode(walk);
        count = walk->next;
        relativecount = iteminfo->position;

        if (iteminfo == listwindow->topitem)
        {
            listDeleteNode(walk);
            listwindow->ListTotal--;

            if (listwindow->listofitems.num != 0)
            {
                listwindow->topitem = (listitemhandle)listGetStructOfNode(listwindow->listofitems.head);
                listwindow->UpperIndex = 0;
            }
            else
                listwindow->topitem = NULL;
        }
        else
        {
            listwindow->ListTotal--;
            listDeleteNode(walk);

            i=0;
            walk = listwindow->listofitems.head;
            while (walk != NULL)
            {
                if (listGetStructOfNode(walk) == listwindow->topitem)
                {
                    break;
                }

                i++;
                walk = walk->next;
            }
            listwindow->UpperIndex = i;

        }

        if (count != NULL)
        {
            newpos = listGetStructOfNode(count);
            newpos->position = relativecount;

            relativecount++;
            count = count->next;
        }

        uicListScrollBarAdjust(listwindow);

#ifdef DEBUG_STOMP
        regVerify(&listwindow->reg);
#endif
        regRecursiveSetDirty(&listwindow->reg);
        regDirtyScreensAboveRegion(&listwindow->reg);
//        listwindow->reg.status |= RSF_DrawThisFrame;
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicListCleanUp
    Description : free's all memory allocated for the list of items.
    Inputs      : listwindow, item
    Outputs     : none
    Return      : none
----------------------------------------------------------------------------*/
void uicListCleanUp(listwindowhandle listwindow)
{
    listDeleteAll(&listwindow->listofitems);
    listwindow->topitem = NULL;
    listwindow->ListTotal = 0;
    listwindow->UpperIndex = 0;

}

/*-----------------------------------------------------------------------------
    Name        : uicListSort
    Description : free's all memory allocated for the list of items.
    Inputs      : listwindow, item
    Outputs     : none
    Return      : none
----------------------------------------------------------------------------*/
void uicListSort(listwindowhandle listwindow, MergeSortCompareCb compare)
{
    Node           *walk;
    sdword          index;
    listitemhandle  item;
    if (listwindow->ListTotal>0)
    {
        listMergeSortGeneral(&listwindow->listofitems, compare);

        walk = listwindow->listofitems.head;
        index = 0;
        while (walk != NULL)
        {
            item = listGetStructOfNode(walk);
            item->position = index;
            index++;
            walk = walk->next;
        }
        listwindow->topitem = listGetStructOfNode(listwindow->listofitems.head);
        listwindow->UpperIndex = 0;
        uicListScrollBarAdjust(listwindow);
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicListWindowSetCurItem
    Description : Sets the currently selected item to item.
    Inputs      : listwindow and item to set to currently selected.
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicListWindowSetCurItem(listwindowhandle listhandle, listitemhandle item)
{
    if (listhandle->CurLineSelected!=NULL)
    {
        bitClear(listhandle->CurLineSelected->flags, UICLI_Selected);
    }

    listhandle->CurLineSelected = item;
    if (listhandle->CurLineSelected!= NULL)
    {
        bitSet(listhandle->CurLineSelected->flags, UICLI_Selected);
        uicListWindowViewSelection(listhandle);
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicTextBufferResize
    Description : Resize the buffer in a text entry box
    Inputs      : entry - the text entry who's buffer we are resizing
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicTextBufferResize(textentryhandle entry, sdword size)
{
    sdword currentLength;

    regVerify(&entry->reg);
    if (entry->textBuffer != NULL)
    {                                                       //get the length of the string in the text box
        currentLength = strlen(entry->textBuffer);
    }
    else
    {
        currentLength = 0;
    }
    entry->textBuffer = memRealloc(entry->textBuffer, size, "TextEntryBuffer", 0);
    if (currentLength >= size)
    {                                                       //if string extends past the end of the buffer
        entry->textBuffer[0] = 0;
    }
    else if (currentLength == 0)
    {                                                       //or if there was no string
        memset(entry->textBuffer, 0, size);                 //clear the buffer to all zeros
    }
    entry->bufferLength = size;
}

/*-----------------------------------------------------------------------------
    Name        : uicTextEntryCleanUp
    Description : Cleans up the text entry boxes buffers.
    Inputs      : entry - the text entry who's buffer we are freeing buffers for.
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicTextEntryCleanUp(textentryhandle entry)
{
    if (entry->textBuffer != NULL)
    {
        memFree(entry->textBuffer);
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicTextEntrySet
    Description : Set the text to be edited in a text entry control.
    Inputs      : entry - what control to adjust
                  text - the text to be copied into it's edit buffer.  Will be
                    truncated and NULL-terminated if needed.
                  cursorPos - position of the cursor
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicTextEntrySet(textentryhandle entry, char *text, sdword cursorPos)
{
    sdword length = strlen(text);
    memset(entry->textBuffer,0,entry->bufferLength*sizeof(char));

    regVerify(&entry->reg);
    if (length >= entry->bufferLength - 1)
    {                                                       //if text too long
        memcpy(entry->textBuffer, text, entry->bufferLength);//truncated copy
        entry->textBuffer[entry->bufferLength - 1] = 0;     //null-terminate
    }
    else
    {
        strcpy(entry->textBuffer, text);                    //else straight copy
    }
    entry->iCharacter = min(cursorPos, min(entry->bufferLength - 1, length));
    if (entry->iCharacter < 0) entry->iCharacter=0;
    uicRepositionText(entry, TRUE);                         //reposition the text
}

/*-----------------------------------------------------------------------------
    Name        : uicTextEntryGet
    Description : Get a copy of the text in a text entry control.
    Inputs      : entry - text entry control to read
                  maxLength - length of the buffer we are to store the text into.
    Outputs     : dest - where to store the text
    Return      :
    Note        : If you just need a temporary reference to the text, you can
                    read entry->textBuffer directly.
----------------------------------------------------------------------------*/
void uicTextEntryGet(textentryhandle entry, char *dest, sdword maxLength)
{
    sdword length = min(maxLength, entry->bufferLength);
    memStrncpy(dest, entry->textBuffer, length);
    //entry->textBuffer[length - 1] = 0;
}

/*-----------------------------------------------------------------------------
    Name        : uicTextEntryInit
    Description : initilizes different flags for the text entry box.
    Inputs      : textentryhandle, flags to set.
    Outputs     : none
    Return      : void
----------------------------------------------------------------------------*/
void uicTextEntryInit(textentryhandle entry, udword flags)
{
    entry->textflags|=flags;
}


/*-----------------------------------------------------------------------------
    Name        : uicChildTextEntryAlloc
    Description : Allocate and initialize a text entry control.
    Inputs      : parent - parent of the new retion
                  atom - atom to use for this region
                  x, y - location of region
                  width, height - size of the text entry region
                  filter - currently not used.  But maybe one day!
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
textentryhandle uicChildTextEntryAlloc(controlhandle parent, featom *atom,
                                       sdword x, sdword y, sdword width, sdword height,
                                       udword filter)
{
    textentryhandle newHandle;

    newHandle = (textentryhandle)regChildAlloc((regionhandle)parent, (sdword)atom,
                    x, y, width, height, uicStructureExtra(uictextentry),
                    UIF_TextEntry);

    if (bitTest(atom->flags,FAF_Disabled)) bitSet(newHandle->reg.status,RSF_RegionDisabled);

    atom->pData = (ubyte *)newHandle;
    regFunctionSet((regionhandle)newHandle, uicTextEntryProcess);
    regDrawFunctionSet((regionhandle)newHandle, uicTextEntryDraw);
//    newHandle->regionFilter = 0xffffffff; //!!!!
    newHandle->contentColor = atom->contentColor;           //default colors
    newHandle->borderColor = atom->borderColor;
    newHandle->screen = NULL;                               //will be set later
    newHandle->textBuffer = NULL;
    uicTextBufferResize(newHandle, UTE_DefaultBufferSize);  //default text buffer size
    newHandle->bufferLength = UTE_DefaultBufferSize;
    newHandle->iCharacter = 0;                              //no text yet
    newHandle->iVisible = 0;                                //start with the first character visible
    newHandle->currentFont = frFontRegister("default.hff"); //give it a default font
    newHandle->flashRate = utyCaretBlinkRate();             //default blink rate
    newHandle->textRect = newHandle->reg.rect;
    newHandle->textflags = 0;
    if (bitTest(atom->flags, FAF_BorderVisible))
    {                                                       //if there is a border
        newHandle->textRect.x0 += FBA_TextEntry+5;             //adjust the text rectangle in a bit
        newHandle->textRect.x1 -= FBA_TextEntry+5;
        newHandle->textRect.y0 += FBA_TextEntry;
        newHandle->textRect.y1 -= FBA_TextEntry;
    }

    return(newHandle);
}

/*-----------------------------------------------------------------------------
    Name        : uicControlDelete
    Description : Delete a control, regardless of it's type
    Inputs      : handle - handle of the control to delete
    Outputs     : Memory freed up, links fixed up
    Return      : void
----------------------------------------------------------------------------*/
void uicControlDelete(controlhandle handle)
{
    featom *atom = (featom *)handle->userID;
    regRegionDelete((regionhandle)handle);
    if (atom->type == FA_TextEntry)
    {                                                       //free a text entry's buffer
        if (((textentryhandle)handle)->textBuffer != NULL)
        {
            memFree(((textentryhandle)handle)->textBuffer);
        }
    }
}

/*-----------------------------------------------------------------------------
    Name        : uicFindFlag
    Description : finds the flagged region in the list
    Inputs      : find - starting region for search.
                  flag - flag searched for
    Outputs     : None
    Return      : region containing flag
----------------------------------------------------------------------------*/
regionhandle uicFindFlag(regionhandle find, udword flag, uword type)
{
    // "find" represents the region created for the <enter> and <esc> key
    // callbacks.  We want to start our search at the beginning of the
    // list of regions - find->parent is the base region and
    // find->parent->child is the start of the list of regions that are
    // the children of the base region.  Following the linked list starting
    // with find->parent->child->next will eventually lead us back to the
    // starting point

    // we want to end our search when we reach the regions created
    // for the key callbacks because the addresses of temp->userID would
    // cause the computer to crash, therefore ending the search
    // when temp->userID < 256
    fescreen       *screen = feStack[feStackIndex].screen;
    sdword          i;

    if (screen == NULL)
    {
        return(NULL);
    }

    for (i=1;i<screen->nAtoms;i++)
    {
        if (type == ATOM_FLAG)
        {
            if (bitTest(screen->atoms[i].flags, flag))
            {
                return((regionhandle)screen->atoms[i].region);
            }
        }
        else if ( (type == REGION_FLAG) && (screen->atoms[i].region != NULL) )
        {
            if (bitTest( ((regionhandle)screen->atoms[i].region)->status, flag))
            {
                return((regionhandle)screen->atoms[i].region);
            }
        }
    }

    return NULL;
}

/*-----------------------------------------------------------------------------
    Name        : uicFindFlagGetAtom
    Description : finds the flagged region in the list
    Inputs      : find - starting region for search.
                  flag - flag searched for
    Outputs     : None
    Return      : region containing flag
----------------------------------------------------------------------------*/
featom *uicFindFlagGetAtom(regionhandle find, udword flag, uword type)
{
    // "find" represents the region created for the <enter> and <esc> key
    // callbacks.  We want to start our search at the beginning of the
    // list of regions - find->parent is the base region and
    // find->parent->child is the start of the list of regions that are
    // the children of the base region.  Following the linked list starting
    // with find->parent->child->next will eventually lead us back to the
    // starting point

    // we want to end our search when we reach the regions created
    // for the key callbacks because the addresses of temp->userID would
    // cause the computer to crash, therefore ending the search
    // when temp->userID < 256
    fescreen       *screen = feStack[feStackIndex].screen;
    sdword          i;

    if (screen == NULL)
    {
        return(NULL);
    }

    for (i=1;i<screen->nAtoms;i++)
    {
        if (type == ATOM_FLAG)
        {
            if (bitTest(screen->atoms[i].flags, flag))
            {
                return(&screen->atoms[i]);
            }
        }
        else if ( (type == REGION_FLAG) && (screen->atoms[i].region != NULL) )
        {
            if (bitTest( ((regionhandle)screen->atoms[i].region)->status, flag))
            {
                return(&screen->atoms[i]);
            }
        }
    }

    return NULL;
}



/*-----------------------------------------------------------------------------
    Name        : uicFindTabstop
    Description : finds the region in the list with a tabstop matching feTabStop
    Inputs      : find - starting region for search.  Function gets to the
                  beginning of the linked list which contains "find" and searches
                  the list
    Outputs     : None
    Return      : found region or NULL if not found
----------------------------------------------------------------------------*/
regionhandle uicFindTabstop(regionhandle find)
{
/*    regionhandle temp = find->parent->child;
    // "find" represents the region created for the <enter> and <esc> key
    // callbacks.  We want to start our search at the beginning of the
    // list of regions - find->parent is the base region and
    // find->parent->child is the start of the list of regions that are
    // the children of the base region.  Following the linked list starting
    // with find->parent->child->next will eventually lead us back to the
    // starting point

    while (temp != NULL)
    {
        if (temp->tabstop == feTabStop)
        {
            return (temp);
        }

        temp = temp->next;
    }*/
    fescreen       *screen = feStack[feStackIndex].screen;
    sdword          i;

    if (screen == NULL) return NULL;

    for (i=0;i<screen->nAtoms;i++)
    {
        if (screen->atoms[i].tabstop == feTabStop)
        {
            if (screen->atoms[i].type==FA_RadioButton)
            {
                return (feFindRadioButtonRegion(screen->atoms[i].region, TRUE));
            }
            else
                return ((regionhandle)screen->atoms[i].region);
        }
    }

    return NULL;
}



/*-----------------------------------------------------------------------------
    Name        : uicFindButtonType
    Description : Finds the buttontype of the callback region
    Inputs      : reg - callback region
    Outputs     :
    Return      : button type
----------------------------------------------------------------------------*/
enum tagFIBAtomFlagSff uicFindButtonType(struct tagRegion *reg)
{
    struct tagRegion *temp;

    temp = uicFindTabstop(reg);

    return ((enum tagFIBAtomFlagsff)((featom *)temp->userID)->type);
}

/*-----------------------------------------------------------------------------
    Name        : uicClearCurrent
    Description : Clears the current button flag on the currently selected button
    Inputs      : reg - callback region
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
bool uicClearCurrent(regionhandle reg)
{
    regionhandle        temp=NULL;
    textentryhandle     entry;
    listwindowhandle    listwindow;
    featom             *atom;

    // when not initialized properly, the CurrentSelected flag is set
    // on non-button regions, so we'll clear all regions with
    // RSF_CurrentSelected set.  Overkill usually, but fixes the problem

    atom = uicFindFlagGetAtom(reg, RSF_CurrentSelected, REGION_FLAG);
    if (atom != NULL)
    {
        temp = (regionhandle)atom->region;
    }

    if (temp!=NULL)
    {
        if (atom->type==FA_RadioButton)
        {
            atom = feAtomFindInScreen(feStack[feStackIndex].screen, atom->name);
            do
            {
#ifdef DEBUG_STOMP
                regVerify((regionhandle)atom->region);
#endif
                bitClear(((regionhandle)atom->region)->status,RSF_CurrentSelected);
//                bitSet(((regionhandle)atom->region)->status,RSF_DrawThisFrame);
                regRecursiveSetDirty((regionhandle)atom->region);

            }
            while ((atom = feAtomFindNextInScreen(feStack[feStackIndex].screen, atom, atom->name)) != NULL);
        }

        bitClear(temp->status, RSF_CurrentSelected);
#ifdef DEBUG_STOMP
        regVerify(temp);
#endif
        regRecursiveSetDirty(temp);
//        bitSet(temp->status, RSF_DrawThisFrame);
        if ( (((featom *)temp->userID) != NULL)             &&
             (((featom *)temp->userID)->type==FA_TextEntry) )
        {
            entry = (textentryhandle)temp;
            atom = (featom *)temp->userID;
            entry->message = CM_LoseFocus;
            feFunctionExecute(atom->name, atom, FALSE);
            bitClear(temp->status,RSF_KeyCapture);
            regKeysFocussed = FALSE;
        }
        if ( (((featom *)temp->userID) != NULL)             &&
             (((featom *)temp->userID)->type==FA_ListWindow) )
        {
            listwindow = (listwindowhandle)temp;
            atom = (featom *)temp->userID;
            if (bitTest(listwindow->windowflags,UICLW_CanHaveFocus))
            {
                listwindow->message = CM_LoseFocus;
                feFunctionExecute(atom->name, atom, FALSE);
                bitClear(listwindow->windowflags, UICLW_GetKeyPressed);
                bitClear(temp->status,RSF_KeyCapture);
                regKeysFocussed = FALSE;
            }
        }

        if (temp->tabstop != 0) return TRUE;
    }

    return FALSE;
}


/*-----------------------------------------------------------------------------
    Name        : uicSetCurrent
    Description : Set the current button flag on the button corresponding to the
                  tabstop key - only makes the change if the button is on the
                  topmost menu.
    Inputs      : reg - callback region
                  bUserInput - change of focus due to user input
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicSetCurrent(regionhandle reg, bool bUserInput)
{
    listwindowhandle listwindow;
    featom          *atom, *radio;
    if (reg != NULL)
    {
        if (bitTest(reg->status,RSF_CantFocusTo))
        {
            return;
        }

        if (!bitTest(reg->status, RSF_CurrentSelected))
        {
            bitSet(reg->status, RSF_CurrentSelected);
            if (reg->tabstop != 0) feTabStop = reg->tabstop;
#ifdef DEBUG_STOMP
        regVerify(reg);
#endif
        regRecursiveSetDirty(reg);
//            bitSet(reg->status, RSF_DrawThisFrame);
        }

        radio = reg->atom;

        //
        if (radio->type==FA_RadioButton)
        {
            atom = feAtomFindInScreen(feStack[feStackIndex].screen, radio->name);
            do
            {
                if (atom->tabstop != 0) feTabStop = reg->tabstop;
        #ifdef DEBUG_STOMP
                regVerify((regionhandle)atom->region);
        #endif
                bitSet(((regionhandle)atom->region)->status,RSF_CurrentSelected);
                regRecursiveSetDirty((regionhandle)atom->region);
//                bitSet(((regionhandle)atom->region)->status,RSF_DrawThisFrame);
            }
            while ((atom = feAtomFindNextInScreen(feStack[feStackIndex].screen, atom, radio->name)) != NULL);
        }

        //text entry special case: if tabbing into a text entry region, you can start typing
        if (reg->processFunction == uicTextEntryProcess)
        {
            bitSet(reg->status, RSF_KeyCapture);
            keyBufferClear();
            regKeysFocussed = TRUE;
        }
        if (reg->processFunction == uicListWindowProcess)
        {
           listwindow = (listwindowhandle)reg;
           if (bitTest(listwindow->windowflags,UICLW_CanHaveFocus))
           {
               bitSet(reg->status, RSF_KeyCapture);
               keyBufferClear();
               regKeysFocussed = TRUE;
           }
        }
    }
}



/*-----------------------------------------------------------------------------
    Name        : uicLimitTabstop
    Description : Ensures that the tabstop variable is not larger than the
                  number of buttons on the screen or smaller than 1
    Inputs      : num_buttons - number of buttons on the screen
    Outputs     :
    Return      :
----------------------------------------------------------------------------*/
void uicLimitTabstop(sdword num_buttons)
{
    if (feTabStop > (udword)num_buttons)
    {
        feTabStop = 1;
    }
    else if (feTabStop == 0)
    {
        feTabStop = num_buttons;
    }
}




/*-----------------------------------------------------------------------------
    Name        : uicTabProcess
    Description : Changes the glabal tabstop variable when the Tab (or Shift-Tab)
                  key is pressed
    Inputs      : num_buttons   (other variables are placeholders)
    Outputs     : tabstop incremented by 1 if the shift key is up or
                  decremented by 1 if shift key is down.
    Return      : 0 (placeholder)
----------------------------------------------------------------------------*/
udword uicTabProcess(struct tagRegion *reg, sdword num_buttons, udword event, udword data)
{
    regionhandle temp;

    uicFocusToKeyboard();

    if (uicClearCurrent(reg))
    {
        if (keyIsHit(SHIFTKEY))
        {
            --feTabStop;
        }
        else
        {
            ++feTabStop;
        }

        uicLimitTabstop(num_buttons);
    }

    temp = uicFindTabstop(reg);

    uicSetCurrent(temp, TRUE);

    return 0;
}


/*-----------------------------------------------------------------------------
    Name        : uicRightArrowProcess
    Description :
    Inputs      : reg - callback region  (other variables are placeholders)
    Outputs     :
    Return      : 0 (placeholder)
----------------------------------------------------------------------------*/
udword uicRightArrowProcess(struct tagRegion *reg, sdword num_buttons, udword event, udword data)
{
    struct tagRegion *temp;
    featom *radio, *atom;
    sdword       index;

    uicFocusToKeyboard();

    radio = uicFindFlagGetAtom(reg, RSF_CurrentSelected, REGION_FLAG);

    if (radio->type==FA_RadioButton)
    {
        temp = feFindRadioButtonRegion(radio->region, TRUE);
        if (temp != NULL)
        {
            radio = temp->atom;
            index = (sdword)radio->pData;
            index++;
            if (index < 0)
            {
                return 0;
            }
            atom = feAtomFindInScreen(feStack[feStackIndex].screen, radio->name);
            do
            {
                if ((sdword)atom->pData == index)
                {
                    uicFocusToKeyboard();

                    uicClearCurrent(radio->region);
                    uicSetCurrent(atom->region, TRUE);
                    uicRadioButtonProcess((regionhandle)atom->region,(sdword)atom, RPE_KeyDown, 0);

                    return 0;
                }
            }
            while ((atom = feAtomFindNextInScreen(feStack[feStackIndex].screen, atom, atom->name)) != NULL);
        }
    }
    else
    {
        uicFocusToKeyboard();

        uicClearCurrent(reg);
        feTabStop++;
        uicLimitTabstop(num_buttons);
        temp = uicFindTabstop(reg);
        uicSetCurrent(temp, TRUE);

        return 0;
    }
    return 0;
}


/*-----------------------------------------------------------------------------
    Name        : uicLeftArrowProcess
    Description :
    Inputs      : reg - callback region  (other variables are placeholders)
    Outputs     :
    Return      : 0 (placeholder)
----------------------------------------------------------------------------*/
udword uicLeftArrowProcess(struct tagRegion *reg, sdword num_buttons, udword event, udword data)
{
    struct tagRegion *temp;
    featom *radio, *atom;
    sdword       index;

    uicFocusToKeyboard();

    radio = uicFindFlagGetAtom(reg, RSF_CurrentSelected, REGION_FLAG);

    if (radio->type==FA_RadioButton)
    {
        temp = feFindRadioButtonRegion(radio->region, TRUE);
        if (temp != NULL)
        {
            radio = temp->atom;
            index = (sdword)radio->pData;
            index--;
            if (index < 0)
            {
                return 0;
            }
            atom = feAtomFindInScreen(feStack[feStackIndex].screen, radio->name);
            do
            {
                if ((sdword)atom->pData == index)
                {
                    uicFocusToKeyboard();

                    uicClearCurrent(radio->region);
                    uicSetCurrent(atom->region, TRUE);
                    uicRadioButtonProcess((regionhandle)atom->region, (sdword)atom, RPE_KeyDown, 0);

                    return 0;
                }
            }
            while ((atom = feAtomFindNextInScreen(feStack[feStackIndex].screen, atom, atom->name)) != NULL);
        }
    }
    else
    {
        uicFocusToKeyboard();

        uicClearCurrent(reg);
        feTabStop--;
        uicLimitTabstop(num_buttons);
        temp = uicFindTabstop(reg);
        uicSetCurrent(temp, TRUE);

        return 0;
    }
    return 0;
}


/*-----------------------------------------------------------------------------
    Name        : uicUpArrowProcess
    Description :
    Inputs      : reg - callback region  (other variables are placeholders)
    Outputs     :
    Return      : 0 (placeholder)
----------------------------------------------------------------------------*/
udword uicUpArrowProcess(struct tagRegion *reg, sdword num_buttons, udword event, udword data)
{
    struct tagRegion *temp;

    uicFocusToKeyboard();

    uicClearCurrent(reg);
    feTabStop--;
    uicLimitTabstop(num_buttons);
    temp = uicFindTabstop(reg);
    uicSetCurrent(temp, TRUE);

    return 0;
}


/*-----------------------------------------------------------------------------
    Name        : uicDownArrowProcess
    Description :
    Inputs      : reg - callback region  (other variables are placeholders)
    Outputs     :
    Return      : 0 (placeholder)
----------------------------------------------------------------------------*/
udword uicDownArrowProcess(struct tagRegion *reg, sdword num_buttons, udword event, udword data)
{
    struct tagRegion *temp;

    uicFocusToKeyboard();

    uicClearCurrent(reg);
    feTabStop++;
    uicLimitTabstop(num_buttons);
    temp = uicFindTabstop(reg);
    uicSetCurrent(temp, TRUE);

    return 0;
}



/*-----------------------------------------------------------------------------
    Name        : uicSpacebarProcess
    Description : Activates the current button
    Inputs      : reg - callback region  (other variables are placeholders)
    Outputs     : current button callback
    Return      : 0 (placeholder)
----------------------------------------------------------------------------*/
udword uicSpacebarProcess(struct tagRegion *reg, sdword num_buttons, udword event, udword data)
{
    regionhandle temp;
    enum tagFIBAtomFlagsff buttonType;
    featom *atom, *radio;
    sdword index, max;

    uicFocusToKeyboard();

    temp = uicFindFlag(reg, RSF_CurrentSelected, REGION_FLAG);

    // backup if (for some reason) the RSF_CurrentSelected flag is not set
    if (temp == NULL)
    {
        //temp = uicFindTabstop(reg);
        return 0;
    }

    buttonType = (enum tagFIBAtomFlagsff)((featom *)temp->userID)->type;

    switch (buttonType)
    {
        case FA_Button:
            if (uicButtonProcess(temp, temp->userID, RPE_KeyDown, 0)==RPR_Redraw)
            {
#ifdef DEBUG_STOMP
                regVerify(temp);
#endif
                regRecursiveSetDirty(temp);
//                temp->status |= RSF_DrawThisFrame;
            }
            break;
        case FA_CheckBox:
        case FA_ToggleButton:
            if (uicToggleProcess(temp, temp->userID, RPE_KeyDown, 0)==RPR_Redraw)
            {
#ifdef DEBUG_STOMP
                regVerify(temp);
#endif
                regRecursiveSetDirty(temp);
//                temp->status |= RSF_DrawThisFrame;
            }
            break;
        case FA_RadioButton:
            temp = feFindRadioButtonRegion(temp, TRUE);
            if (temp != NULL)
            {
                radio = temp->atom;
                index = (sdword)radio->pData;
                index++;
                max = 0;
                atom = feAtomFindInScreen(feStack[feStackIndex].screen, radio->name);
                do
                {
                    if ((sdword)atom->pData > max) max = (sdword)atom->pData;
                    if ((sdword)atom->pData == index)
                    {
                        uicFocusToKeyboard();

                        uicRadioButtonProcess((regionhandle)atom->region, (sdword)atom, RPE_KeyDown, 0);

                        return 0;
                    }
                }
                while ((atom = feAtomFindNextInScreen(feStack[feStackIndex].screen, atom, atom->name)) != NULL);

                atom = feAtomFindInScreen(feStack[feStackIndex].screen, radio->name);
                do
                {
                    if ((sdword)atom->pData == 0)
                    {
                        uicFocusToKeyboard();

                        uicRadioButtonProcess((regionhandle)atom->region, (sdword)atom, RPE_KeyDown, 0);

                        return 0;
                    }
                }
                while ((atom = feAtomFindNextInScreen(feStack[feStackIndex].screen, atom, atom->name)) != NULL);
            }
            break;
        default:
            break;
    }

    return 0;
}


/*-----------------------------------------------------------------------------
    Name        : uicReturnProcess
    Description : Activates the default OK button or the tabstop button
    Inputs      : reg - callback region  (other variables are placeholders)
    Outputs     : "OK" button callback
    Return      : 0 (placeholder)
----------------------------------------------------------------------------*/
udword uicReturnProcess(struct tagRegion *reg, sdword num_buttons, udword event, udword data)
{
    struct tagRegion *temp;
    featom *atom;

    uicFocusToKeyboard();

    temp = uicFindFlag(reg, FAF_DefaultOK, ATOM_FLAG);

    if (temp == NULL)
    {
        temp = uicFindTabstop(reg);
    }

    if (temp != NULL)
    {
        atom = (featom *)temp->userID;
        switch (atom->type)
        {
            case FA_Button:
            case FA_CheckBox:
            case FA_ToggleButton:
                if (((buttonhandle)temp)->processFunction(temp, temp->userID, CM_ButtonClick, 0)==RPR_Redraw)
                {
#ifdef DEBUG_STOMP
                    regVerify(temp);
#endif
//                    temp->status |= RSF_DrawThisFrame;
                    regRecursiveSetDirty(temp);
                }
                break;
            case FA_TextEntry:
                ((textentryhandle)((featom *)temp->userID)->pData)->message = CM_GainFocus;
                bitSet(temp->status, RSF_KeyCapture);
                keyBufferClear();
                regKeysFocussed = TRUE;
                feFunctionExecute(((featom *)temp->userID)->name, (featom *)temp->userID, FALSE);
                break;
            default:
                dbgMessagef("\nuicReturnProcess: don't know how to handle return for atom of type 0x%x", atom->type);
        }
    }

    return 0;
}


/*-----------------------------------------------------------------------------
    Name        : uicEscProcess
    Description : Activates the default back button
    Inputs      : reg - callback region   (other variables are placeholders)
    Outputs     : "back" button callback
    Return      : 0 (placeholder)
----------------------------------------------------------------------------*/
udword uicEscProcess(struct tagRegion *reg, sdword num_buttons, udword event, udword data)
{
    struct tagRegion *temp;

    uicFocusToKeyboard();

    temp = uicFindFlag(reg, FAF_DefaultBack, ATOM_FLAG);

    if (temp != NULL)
    {
        ((buttonhandle)temp)->processFunction(temp, temp->userID, CM_ButtonClick, 0);
        soundEvent(NULL, UI_Click);
    }

    return 0;
}


/*-----------------------------------------------------------------------------
    Name        : uicHomeProcess
    Description : Changes the glabal tabstop variable when the Home key
                  is pressed
    Inputs      : num_buttons   (other variables are placeholders)
    Outputs     : tabstop = 1
    Return      : 0 (placeholer)
----------------------------------------------------------------------------*/
udword uicHomeProcess(struct tagRegion *reg, sdword num_buttons, udword event, udword data)
{
    struct tagRegion *temp;

    uicFocusToKeyboard();

    uicClearCurrent(reg);
    feTabStop = 1;
    temp = uicFindTabstop(reg);
    uicSetCurrent(temp, TRUE);
    return 0;
}


/*-----------------------------------------------------------------------------
    Name        : uicEndProcess
    Description : Changes the glabal tabstop variable when the End key
                  is pressed
    Inputs      : num_buttons   (other variables are placeholders)
    Outputs     : tabstop = num_buttons
    Return      : 0 (placeholer)
----------------------------------------------------------------------------*/
udword uicEndProcess(struct tagRegion *reg, sdword num_buttons, udword event, udword data)
{
    struct tagRegion *temp;

    uicFocusToKeyboard();

    uicClearCurrent(reg);
    feTabStop = num_buttons;
    temp = uicFindTabstop(reg);
    uicSetCurrent(temp, TRUE);
    return 0;
}
