/*****************************************************************************
*           Change Log
*  Date     | Change
*-----------+-----------------------------------------------------------------
* 15-Nov-85 | [1.28] Created
* 16-Nov-85 | [1.84] Do not accept A,I,B button presses if running
* 12-Dec-85 | [1.178] Added set_reset_button
* 20-Dec-85 | [1.221] Made some local procedures static
* 24-Jan-86 | [1.306] Call 'bounded' for button test
* 25-Jan-86 | [1.331] Check bound height-1
* 27-Jan-86 | [1.351] Preserve cursor around button drawing
*  8-Feb-86 | [1.355] Added new parameters to structures for color display;
*           | modify draw_button to support color.
*  8-Feb-86 | [1.355] Change from <> to "" on #includes
* 22-Feb-86 | [1.360] Added a few more colors to the buttons
* 25-Feb-86 | [1.381] Added i_show, b_show, a_show to support 'slow' mode
* 29-Jul-86 | [1.385] Added lamp_button
* 29-Jul-86 | [1.385] Added void-decls
* 30-Jul-86 | [1.398] Removed lamp_button, now a lamp_switch
* 30-Jul-86 | [1.403] Added log_console_event calls
* 10-Nov-91 | [1.428] <jmn> converted to Microsoft C 6.0
* 06-Mar-92	<jrj> comment out (incorrect) re-decl of A_addr, B_addr, I_
*****************************************************************************/

#include "stdio.h"
/* #include "graph.h" */

#include "btypes.h"
#include "scdspmsg.h"

#include "panel.h"
#include "boolean.h"
#include "button.h"
#include "display.h"
#include "disp.h"
#include "mach.h"
#include "diag.h"
#include "color.h"
#include "1401.h"
#include "addr.h"
#include "hercules.h"
#include "kb.h"
#include "scan.h"

extern void a_push();
extern void b_push();
extern void i_push();
extern void off_push();
extern void load_push();
extern void start_push();
extern void stop_push();
extern void clear_off();
extern void reset_push();
/* extern short A_addr; */
/* extern short B_addr; */
/* extern short I_addr; */
extern boolean done;
	   /*    X       Y        legend   state  rtn    border   on   off*/
button 
A_button =   { A_X,    A_Y,     "A-reg", false, a_push,
	COLOR_YELLOW,COLOR_BROWN,COLOR_YELLOW};
button 
B_button =   { B_X,    B_Y,     "B-reg", false, b_push,
	COLOR_YELLOW,COLOR_BROWN,COLOR_YELLOW};
button
I_button =   { I_X,    I_Y,     "I-reg", false, i_push,
	COLOR_YELLOW,COLOR_BROWN,COLOR_YELLOW};
button
off_button = {power_X, power_Y, " off ", false, off_push,
	COLOR_RED,  COLOR_RED,   COLOR_RED};
button 
load_button ={load_X,  load_Y,  "Load ", false, load_push,
	COLOR_GREEN,COLOR_GREEN,COLOR_GREEN};
button
start_button={start_X, start_Y, "Start", false, start_push,
	COLOR_GREEN,COLOR_GREEN,COLOR_GREEN};
button 
stop_button ={stop_X,  stop_Y,  "Stop ", true,  stop_push,
	COLOR_RED,COLOR_RED,COLOR_RED};
button 
reset_button={reset_X, reset_Y, "Reset", false, reset_push,
	COLOR_YELLOW,COLOR_BROWN,COLOR_YELLOW};

/****************************************************************************
*                                 draw_button
* Inputs:
*	button * B: Button
* Effect: 
*       Draws the button at the indicated location on the screen, showing
*	the desired legend
*
* Monochrome display:
*	Draws the characters, no special attributes.
* Color:
*	Sets the color attribute for the border
****************************************************************************/

void draw_button(button * B)
    {
     coord x;
     coord y;
     attrib bfore;
     attrib bback;

     if(ismono())
        { /* mono */
	 bfore = H_NORMAL;
	 bback = COLOR_BLACK;
	} /* mono */
     else
	{ /* color */
	 bfore = B->border;
	 bback = COLOR_BLACK;
	} /* color */

     sccurpos(&y, &x);

     scdspmsg(B->Y,B->X,bfore,bback,  "ΙΝΝΝΝΝ»");
     scdspmsg((coord)(B->Y+1),B->X,bfore,bback,"Ί     Ί");
     hide_mouse_cursor();
     mark_screen_color((coord)(B->X+1),(coord)(B->Y+1),B->legend,
		(boolean)(lamp_test || B->active),
		COLOR_BLACK,B->on,B->off,COLOR_BLACK);
     show_mouse_cursor();
     scdspmsg((coord)(B->Y+2),B->X,bfore,bback,"ΘΝΝΝΝΝΌ");
     sccurset(y, x);
    }

/****************************************************************************
*                                draw_a_button
* Effect: 
*       Draws the A-display button on the screen
****************************************************************************/

void draw_a_button()
    {
     draw_button(&A_button);
    }


/****************************************************************************
*                                draw_b_button
* Effect: 
*       Draws the B-display button on the screen
****************************************************************************/

void draw_b_button()
    {
     draw_button(&B_button);
    }


/****************************************************************************
*                                draw_i_button
* Effect: 
*       Draws the i-display button on the screen
****************************************************************************/

void draw_i_button()
    {
     draw_button(&I_button);
    }


/****************************************************************************
*                               draw_off_button
* Effect: 
*       Draws the power-off button
****************************************************************************/

void draw_off_button()
    {
     draw_button(&off_button);
    }

/****************************************************************************
*                              draw_load_button
* Effect: 
*       Draws the load button
****************************************************************************/

void draw_load_button()
    {
     draw_button(&load_button);
    }

/****************************************************************************
*                              draw_start_button
* Effect: 
*       Draws the start button
****************************************************************************/

void draw_start_button()
    {
     draw_button(&start_button);
    }

/****************************************************************************
*                              draw_stop_button
* Effect: 
*       Draws the stop button
****************************************************************************/

void draw_stop_button()
    {
     draw_button(&stop_button);
    }

/****************************************************************************
*                              draw_reset_button
* Effect: 
*       Draws the reset button
****************************************************************************/

void draw_reset_button()
    {
     draw_button(&reset_button);
    }

/****************************************************************************
*                                  in_button
* Inputs:
*       coord X: X-screen coordinate of mouse hit
*	coord Y: Y-screen coordinate of mouse hit
*	button * B: Button descriptor
* Result: boolean
*       true if cursor is on button
*	false otherwise
****************************************************************************/

boolean in_button(coord X, coord Y, button * B)
    {
     return bounded(X,Y,
     			  B->X,
			  B->Y,
			  (coord)(B->X + button_width - 1), 
		          (coord)(B->Y + button_height - 1));
    }

/****************************************************************************
*                                clear_button
* Inputs:
*       button * B: Button to clear
* Effect: 
*       If button was active, turn it off
****************************************************************************/

void clear_button(button * B)
    {
     if(!B->active) return;
     B->active = false;
     draw_button(B);
    }

/****************************************************************************
*                                set_button
* Inputs:
*       button * B: Button to set
* Effect: 
*       If button was inactive, turn it on
****************************************************************************/

void set_button(button * B)
    {
     if(B->active) 
	return;
     B->active = true;
     draw_button(B);
    }

/****************************************************************************
*                                   a_show
* Effect: 
*       Unconditionally "pushes" the A-register display
****************************************************************************/

void a_show()
    {
     A_button.active = true;
     if(B_button.active) 
	clear_button(&B_button);
     if(I_button.active) 
	clear_button(&I_button);
     clear_off();
     draw_button(&A_button);
     display_address(A_addr);
    }

/****************************************************************************
*                                   a_push
* Effect: 
*       pushes the A button
****************************************************************************/

void a_push()
    {
     if(running()) 
	return;
     if(diagnostics_on) 
	log_console_event("A");
     a_show();
    }

/****************************************************************************
*                                   b_show
* Effect: 
*       Unconditionally "pushes" the B-display button
****************************************************************************/

void b_show()
    {
     B_button.active = true;
     if(A_button.active) 
	clear_button(&A_button);
     if(I_button.active) 
	clear_button(&I_button);
     clear_off();
     draw_button(&B_button);
     display_address(B_addr);
    }

/****************************************************************************
*                                   b_push
* Effect: 
*       pushes the B button
****************************************************************************/

void b_push()
    {
     if(running()) 
	return;
     if(diagnostics_on) 
	log_console_event("B");
     b_show();
    }

/****************************************************************************
*                                   i_show
* Effect: 
*       Unconditionally "pushes" the I-register light
****************************************************************************/

void i_show()
    {
     I_button.active = true;
     if(A_button.active) 
	clear_button(&A_button);
     if(B_button.active) 
	clear_button(&B_button);
     clear_off();
     draw_button(&I_button);
     display_address(I_addr);
    }

/****************************************************************************
*                                   i_push
* Effect: 
*       pushes the I button
****************************************************************************/

void i_push()
    {
     if(running()) 
	return;
     if(diagnostics_on) 
	log_console_event("I");
     i_show();
    }

/****************************************************************************
*                                  off_push
* Effect: 
*       Turns power off
****************************************************************************/

void off_push()
    {
     if(diagnostics_on) log_console_event("OFF");

     if(off_button.active)
        {
	 done = true;
	 return;
	}
     off_button.active = true;
     draw_button(&off_button);
    }

/****************************************************************************
*                                start_execute
* Result: void
*       
* Effect: 
*       Executes the start button event, internal or external call
****************************************************************************/

void start_execute()
    {
     if(!stop_button.active) return;
     clear_button(&stop_button);
     set_button(&start_button);

     start();
    }

/****************************************************************************
*                                 start_push
* Effect: 
*       The virtual machine starts running
****************************************************************************/

void start_push()
    {
     clear_off();
     if(running()) 
	return;
     if(diagnostics_on) 
	log_console_event("START");
     start_execute();
    }

/****************************************************************************
*                                stop_execute
* Result: void
*       
* Effect: 
*       Executes the stop button event (whether internal call or hit
*	by user)
****************************************************************************/

void stop_execute()
    {
     clear_button(&start_button);
     set_button(&stop_button);
     
     stop();
    }

/****************************************************************************
*                                 stop_push
* Effect: 
*       The virtual machine stops running
****************************************************************************/

void stop_push()
    {
     clear_off();
     if(!running()) 
	return;

     if(diagnostics_on) 
	log_console_event("STOP");
     stop_execute();
    }

/****************************************************************************
*                                 reset_push
* Effect: 
*       The virtual machine is reset
* Preconditions:
*	The virtual machine must be halted
****************************************************************************/

void reset_push()
    {

     clear_off();

     if(running()) 
	return;  /* can't reset running machine */

     if(diagnostics_on) 
	log_console_event("RESET");
     do_reset();		/* call reset routine */

     wait_for_mouse_up();
     hide_mouse_cursor();
     clear_button(&reset_button);
     show_mouse_cursor();

    }

/****************************************************************************
*                              set_reset_button
* Effect: 
*       Turns on the reset button
****************************************************************************/

void set_reset_button()
    {
     hide_mouse_cursor();
     set_button(&reset_button);
     show_mouse_cursor();
    }

/****************************************************************************
*                                 load_push
* Effect: 
*       The virtual machine enters its IPL state
* Preconditions:
*	The virtual machine must be halted
****************************************************************************/

void load_push()
    {
     clear_off();
     if(running()) 
	return;  /* can't load running machine */

     /* call load routine here */
     
     if(diagnostics_on) 
	log_console_event("LOAD");

     set_button(&load_button);
     wait_for_mouse_up();
     clear_button(&load_button);

     load_machine();
     
    }

/****************************************************************************
*                                  clear_off
* Effect: 
*       clears off-button state
****************************************************************************/

void clear_off()
    {
     if(off_button.active) 
	clear_button(&off_button);
    }

/****************************************************************************
*                              check_off_button
* Inputs:
*       coord X: X-screen coordinate of mouse hit
*	coord Y: Y-screen coordinate of mouse hit
* Effect: 
*       Checks for and processes hit on off button
****************************************************************************/

void check_off_button(coord X,coord Y)
    {
     if(in_button(X,Y,&off_button)) 
	(*off_button.push)();
    }

/****************************************************************************
*                              check_reset_button
* Inputs:
*       coord X: X-screen coordinate of mouse hit
*	coord Y: Y-screen coordinate of mouse hit
* Effect: 
*       Checks for and processes hit on reset button
****************************************************************************/

void check_reset_button(coord X,coord Y)
    {
     if(in_button(X,Y,&reset_button)) 
	(*reset_button.push)();
    }

/****************************************************************************
*                                check_buttons
* Inputs:
*       coord X: X-screen coordinate of mouse hit
*	coord Y: Y-screen coordinate of mouse hit
* Effect: 
*       Polls buttons; if one has been pushed, activates it
****************************************************************************/

void check_buttons(coord X,coord Y)
    {
     if(in_button(X,Y,&A_button)) 
	(*A_button.push)();
     if(in_button(X,Y,&B_button)) 
	(*B_button.push)();
     if(in_button(X,Y,&I_button)) 
	(*I_button.push)();

     check_off_button(X,Y);

     if(in_button(X,Y,&start_button)) 
	(*start_button.push)();
     if(in_button(X,Y,&stop_button)) 
	(*stop_button.push)();

     check_reset_button(X,Y);

     if(in_button(X,Y,&load_button)) 
	(*load_button.push)();
    }

/****************************************************************************
*			       check_run_buttons
* Inputs:
*       coord X: X-screen coordinate of mouse hit
*	coord Y: Y-screen coordinate of mouse hit
* Effect: 
*       Polls buttons which can be activated during run mode
****************************************************************************/

void check_run_buttons(coord X,coord Y)
    {
     if(in_button(X,Y,&off_button)) 
	(*off_button.push)();
     if(in_button(X,Y,&stop_button)) 
	(*stop_button.push)();
    }

/****************************************************************************
*                                   running
* Result: boolean
*       true if start key is activated
*	false if not
****************************************************************************/

boolean running()
    {
     return start_button.active;
    }
