// event-driven GUI class definitions #include #include #include #include #include #include #include "event.h" // ********************************************************************** // base class for all windows and window-elements // ********************************************************************** // create a new window Window::Window ( byte xx1, byte yy1, byte xx2, byte yy2 ) { x1=xx1; y1=yy1; x2=xx2; y2=yy2; // save coordinates struct text_info ti; // save information about old window gettextinfo (&ti); oldx1=ti.winleft; oldy1=ti.wintop; oldx2=ti.winright; oldy2=ti.winbottom; oldx=ti.curx; oldy=ti.cury; oldattr=ti.attribute; Store=(byte *)malloc(4000); // get memory and store background image gettext (x1, y1, x2, y2, Store); window (1, 1, 80, 25); // set up window window (x1, y1, x2, y2); textattr (7); } // destroy a window Window::~Window () { window (1, 1, 80, 25); // restore window coordinates window (oldx1, oldy1, oldx2, oldy2); puttext (x1, y1, x2, y2, Store); // restore background image free (Store); // free image memory textattr (oldattr); // restore cursor/colours gotoxy (oldx, oldy); } // placeholder for key handling routines in descendants int Window::ProcessKey ( char ) { // return values : // 1 = key was not used - pass to next window // 0 = key was used up // 2 = application has terminated return 1; }; // placeholder for idle processing in descendants void Window::IdleAction () { }; // ********************************************************************** // main kernel class // ********************************************************************** Application *anApp; // global variable to access kernel // initialize kernel with no windows Application::Application () { Head=NULL; anApp=this; } // kill kernel by destroying all windows Application::~Application () { while (Head!=NULL) CloseWindow (); } // attach a new window to the kernel void Application::OpenWindow ( Window *p ) { p->Next=Head; Head=p; } // remove a window from the kernel's list void Application::CloseWindow () { if (Head!=NULL) { Window *p=Head; Head=Head->Next; delete p; } } // main message-processing loop void Application::Run () { char ch; int Status=0; do { if (kbhit ()) // check for key pressed { ch=getch (); // get keystoke if (ch!='Q') { // pass it to all windows until it is Window *p=Head; // .. processed while ((p!=NULL) && ((Status=(p->ProcessKey (ch)))==1)) p=p->Next; } } else // otherwise, do idle processing { Window *p=Head; // .. for all windows while (p!=NULL) { p->IdleAction (); p=p->Next; } } } while (Status!=2); // until a windows returns exit state } // ********************************************************************** // window with a border // ********************************************************************** BWindow::BWindow ( byte xx1, byte yy1, byte xx2, byte yy2, byte block ) : Window ( xx1, yy1, xx2, yy2 ) { if (block==1) Block (); } // output a character directly to the video memory void BWindow::directput ( int x, int y, byte cha, byte col ) { unsigned int xo=x; unsigned int yo=y; unsigned int offset=(yo-1)*160+(xo-1)*2; pokeb (0xB800, offset, cha); pokeb (0xB800, offset+1, col); } // make a block around the current window and shrink it void BWindow::Block () { int a; directput (x1, y1, 218, 7); directput (x2, y1, 191, 7); directput (x1, y2, 192, 7); directput (x2, y2, 217, 7); for ( a=1; aCloseWindow (); return 0; } // ********************************************************************** // menu item // ********************************************************************** // ********************************************************************** // linked list of menu items // ********************************************************************** // destroy menu item list MenuData::~MenuData () { while (Head!=NULL) { MenuItem *p=Head; Head=Head->Next; delete p; } } // ********************************************************************** // horizontal menu // ********************************************************************** HorzMenu::HorzMenu ( byte xx1, byte yy1, byte xx2, byte yy2, byte block ) : BWindow ( xx1, yy1, xx2, yy2, block ) { } // initialize menu and draw items on screen void HorzMenu::InitMenu ( MenuData *md ) { Position=0; Menu=md; MenuItem *p=Menu->Head; // find maximum length of item int MaxLength=0; while (p!=NULL) { if (strlen (p->Data)>MaxLength) MaxLength=strlen (p->Data); p=p->Next; } Separator=MaxLength+2; // set separator distance for ( int a=0; aCount; a++ ) // write items Draw (a, 0); Draw (Position, 1); // highlight first item } // write or highlight an item void HorzMenu::Draw ( int Pos, int State ) { MenuItem *m=Menu->Head; // search linked list for item int a=Pos; while (a>0) { a--; m=m->Next; } gotoxy (Pos*Separator+1, 1); // set cursor position & colour if (State==0) textattr (7); else textattr (112); for ( a=0; aData); a++ ) // output string putch (m->Data[a]); } // process left and right arrows int HorzMenu::ProcessKey ( char ch ) { switch (ch) { case 75 : if (Position>0) // left arrow { Draw (Position, 0); // move left Position--; Draw (Position, 1); }; return 0; case 77 : if (Position < (Menu->Count-1)) // right arrow { Draw (Position, 0); // move right Position++; Draw (Position, 1); } return 0; default : return 1; // pass keystroke to next window } } // ********************************************************************** // vertical menu // ********************************************************************** VertMenu::VertMenu ( byte xx1, byte yy1, byte xx2, byte yy2, byte block ) : BWindow ( xx1, yy1, xx2, yy2, block ) { } // initialise menu and draw items on screen void VertMenu::InitMenu ( MenuData *md ) { Position=0; Menu=md; for ( int a=0; aCount; a++ ) // write items Draw (a, 0); Draw (Position, 1); // highlight first item } // write or highlight an item void VertMenu::Draw ( int Pos, int State ) { MenuItem *m=Menu->Head; // search linked list for item int a=Pos; while (a>0) { a--; m=m->Next; } gotoxy (1, Pos+1); // move cursor and set colour if (State==0) textattr (7); else textattr (112); for ( a=0; aData); a++ ) // output string putch (m->Data[a]); } // process up and down arrows int VertMenu::ProcessKey ( char ch ) { switch (ch) { case 72 : if (Position>0) // up arrow { Draw (Position, 0); // move up Position--; Draw (Position, 1); }; return 0; case 80 : if (Position < (Menu->Count-1)) // down arrow { Draw (Position, 0); // move down Position++; Draw (Position, 1); } return 0; case 27 : anApp->CloseWindow (); // ESC = close window return 0; default : return 1; // pass keystroke to next window } } // ********************************************************************** // scrolling status line // ********************************************************************** StatusLine::StatusLine ( byte y, char *s ) : BWindow (1, y, 80, y, 0) { strcpy (Data, s); while (strlen (Data)<80) // pad line with spaces on left/right { strcat (Data, " "); if (strlen (Data)<80) { char t[100]=" "; strcat (t, Data); strcpy (Data, t); } } waitcount=0; IdleAction (); // display initial string } // display string and move it one space to the left void StatusLine::IdleAction () { waitcount++; // divide-by-N counter to slow down if (waitcount!=600) // .. iterations return; waitcount=0; for ( int a=0; a