/*
 * File: ginteractors.h
 * --------------------
 * This file exports a hierarchy of graphical interactors similar to those
 * provided in the Java Swing libraries.
 */

/*************************************************************************/
/* Stanford Portable Library                                             */
/* Copyright (c) 2014 by Eric Roberts <eroberts@cs.stanford.edu>         */
/*                                                                       */
/* This program is free software: you can redistribute it and/or modify  */
/* it under the terms of the GNU General Public License as published by  */
/* the Free Software Foundation, either version 3 of the License, or     */
/* (at your option) any later version.                                   */
/*                                                                       */
/* This program is distributed in the hope that it will be useful,       */
/* but WITHOUT ANY WARRANTY; without even the implied warranty of        */
/* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         */
/* GNU General Public License for more details.                          */
/*                                                                       */
/* You should have received a copy of the GNU General Public License     */
/* along with this program.  If not, see <http://www.gnu.org/licenses/>. */
/*************************************************************************/

#ifndef _ginteractors_h
#define _ginteractors_h

#include "gobjects.h"
#include "gtypes.h"
#include "gwindow.h"
#include "vector.h"

/*
 * Class: GInteractor
 * ------------------
 * This abstract class is the superclass for all graphical interactors.  In
 * most applications, interactors will be added to a control strip along
 * one of the sides of the GWindow, but they can also be placed in specific
 * positions just like any other GObject.
 */

class GInteractor : public GObject {

public:

/*
 * Method: setActionCommand
 * Usage: interactor.setActionCommand(cmd);
 * ----------------------------------------
 * Sets the action command to the indicated string.  If the string is not
 * empty, activating the interactor generates a GActionEvent.
 */

   void setActionCommand(std::string cmd);

/*
 * Method: getActionCommand
 * Usage: string cmd = interactor.getActionCommand();
 * --------------------------------------------------
 * Returns the action command associated with the interactor.
 */

   std::string getActionCommand();

/*
 * Method: setSize
 * Usage: interactor.setSize(size);
 *        interactor.setSize(width, height);
 * -----------------------------------------
 * Changes the size of the interactor to the specified width and height.
 */

   void setSize(const GDimension & size);
   void setSize(double width, double height);

/*
 * Method: setBounds
 * Usage: interactor.setBounds(rect);
 *        interactor.setBounds(x, y, width, height);
 * -------------------------------------------------
 * Changes the bounds of the interactor to the specified values.
 */

   void setBounds(const GRectangle & size);
   void setBounds(double x, double y, double width, double height);

/* Prototypes for the virtual methods */

   virtual GRectangle getBounds() const;

protected:

   GInteractor();

   std::string actionCommand;

};

/*
 * Class: GButton
 * --------------
 * This interactor subclass represents an onscreen button.  The following
 * program displays a button that, when pressed, generates the message
 * Please do not press this button again (with thanks to Douglas Adamss
 * Hitchhikers Guide to the Galaxy):
 *
 *    int main() {
 *       GWindow gw;
 *       GButton *button = new GButton("RED");
 *       gw.addToRegion(button, "SOUTH");
 *       while (true) {
 *          GEvent e = waitForEvent(ACTION_EVENT | CLICK_EVENT);
 *          if (e.getEventType() == MOUSE_CLICKED) break;
 *          cout << "Please do not press this button again." << endl;
 *       }
 *       return 0;
 *    }
 */

class GButton : public GInteractor {

public:

/*
 * Constructor: GButton
 * Usage: GButton *button = new GButton(label);
 * --------------------------------------------
 * Creates a GButton with the specified label.  This constructor also sets
 * the action command for the button to the label string.
 */

   GButton(std::string label);

/* Prototypes for the virtual methods */

   virtual std::string getType() const;
   virtual std::string toString() const;

private:
   std::string label;

};

/*
 * Class: GCheckBox
 * ----------------
 * This interactor subclass represents an onscreen check box.  Clicking
 * once on the check box selects it; clicking again removes the selection. 
 * If a GCheckBox has an action command, clicking on the box generates a
 * GActionEvent.
 */

class GCheckBox : public GInteractor {

public:

/*
 * Constructor: GCheckBox
 * Usage: GCheckBox *chkbox = new GCheckBox(label);
 * ------------------------------------------------
 * Creates a GCheckBox with the specified label.  In contrast to the
 * GButton constructor, this constructor does not set an action command.
 */

   GCheckBox(std::string label);

/*
 * Method: setSelected
 * Usage: chkbox->setSelected(state);
 * ----------------------------------
 * Sets the state of the check box.
 */

   void setSelected(bool state);

/*
 * Method: isSelected
 * Usage: if (chkbox->isSelected()) ...
 * ------------------------------------
 * Returns true if the check box is selected.
 */

   bool isSelected();

/* Prototypes for the virtual methods */

   virtual std::string getType() const;
   virtual std::string toString() const;

private:
   std::string label;

};

/*
 * Class: GSlider
 * --------------
 * This interactor subclass represents an onscreen slider.  Dragging the
 * slider control generates an ActionEvent if the slider has a nonempty
 * action command.
 */

class GSlider : public GInteractor {

public:

/*
 * Constructor: GSlider
 * Usage: GSlider *slider = new GSlider();
 *        GSlider *slider = new GSlider(min, max, value);
 * ------------------------------------------------------
 * Creates a horizontal GSlider.  The second form allows the client to
 * specify the minimum value, maximum value, and current value of the
 * slider.  The first form is equivalent to calling GSlider(0, 100, 50). 
 * Assigning an action command to the slider causes the slider to generate
 * an action event whenever the slider value changes.
 */

   GSlider();
   GSlider(int min, int max, int value);

/*
 * Method: setValue
 * Usage: slider->setValue(value);
 * -------------------------------
 * Sets the current value of the slider.
 */

   void setValue(int value);

/*
 * Method: getValue
 * Usage: int value = slider->getValue();
 * --------------------------------------
 * Returns the current value of the slider.
 */

   int getValue();

/* Prototypes for the virtual methods */

   virtual std::string getType() const;
   virtual std::string toString() const;

private:
   void create(int min, int max, int value);
   int min;
   int max;

};

/*
 * Class: GTextField
 * -----------------
 * This interactor subclass represents a text field for entering short text
 * strings.  Hitting enter in a text field generates a GActionEvent if the
 * text field has a nonempty action command.

 */

class GTextField : public GInteractor {

public:

/*
 * Constructor: GTextField
 * Usage: GTextField *field = new GTextField();
 *        GTextField *field = new GTextField(nChars);
 * --------------------------------------------------
 * Creates a text field capable of holding nChars characters, which
 * defaults to 10.  Assigning an action command to the text field causes it
 * to generate an action event whenever the user types the ENTER key.
 */

   GTextField();
   GTextField(int nChars);

/*
 * Method: setText
 * Usage: field->setText(str);
 * ---------------------------
 * Sets the text of the field to the specified string.
 */

   void setText(std::string str);

/*
 * Method: getText
 * Usage: string str = field->getText();
 * -------------------------------------
 * Returns the contents of the text field.
 */

   std::string getText();

/* Prototypes for the virtual methods */

   virtual std::string getType() const;
   virtual std::string toString() const;

};

/*
 * Class: GChooser
 * ---------------
 * This interactor subclass represents a selectable list.  The GChooser
 * constructor creates an empty chooser.  Once the chooser has been
 * created, clients can use addItem to add the options.  For example, the
 * following code creates a GChooser containing the four strings "Small",
 * "Medium", "Large", and "X-Large":
 *
 *    GChooser *sizeChooser = new GChooser();
 *    sizeChooser->addItem("Small");
 *    sizeChooser->addItem("Medium");
 *    sizeChooser->addItem("Large");
 *    sizeChooser->addItem("X-Large");
 */

class GChooser : public GInteractor {

public:

/*
 * Constructor: GChooser
 * Usage: GChooser *chooser = new GChooser();
 * ------------------------------------------
 * Creates a chooser that initially contains no items, which are added
 * using the addItem method.  Assigning an action command to the chooser
 * causes it to generate an action event whenever the user selects an item.
 */

   GChooser();

/*
 * Method: addItem
 * Usage: chooser->addItem(item);
 * ------------------------------
 * Adds a new item consisting of the specified string.
 */

   void addItem(std::string item);

/*
 * Method: setSelectedItem
 * Usage: chooser->setSelectedItem(item);
 * --------------------------------------
 * Sets the chooser so that it shows the specified item.  If the item does
 * not exist in the chooser, no change occurs.
 */

   void setSelectedItem(std::string item);

/*
 * Method: getSelectedItem
 * Usage: string item = chooser->getSelectedItem();
 * ------------------------------------------------
 * Returns the current item selected in the chooser.
 */

   std::string getSelectedItem();

/* Prototypes for the virtual methods */

   virtual std::string getType() const;
   virtual std::string toString() const;

};

#endif