#ifndef xmenu_h
#define xmenu_h

#include <InterViews/window.h>
#include <InterViews/box.h>
#include <InterViews/event.h>
#include <OS/list.h>
#include <OS/string.h>
#include <IV-look/kit.h>
#include <IV-look/stepper.h>
#include <IV-look/dialogs.h>
#if defined(MINGW) || defined(MAC)
#define UseFieldEditor 1
#else
#define UseFieldEditor 0  // Use the FieldSEditor
#endif
#if UseFieldEditor
#include <IV-look/field.h>
#define FieldSEditor FieldEditor
#else
#include "field.h"
#endif
#include "ocglyph.h"
#include "apwindow.h"
#include "ivocconf.h"

class HocPanel;      // panel is a vbox with menus, buttons, value editors, etc.
class HocMenu;       // popup menu panel item
class HocAction;     // button/menuItem action
class HocValEditor;  // field editor with button
class HocValAction;  // knows what to do when value editor or associated button pressed.
class HocItem;       // for printing
class HocDataPaths;
class HocCommand;
class HocVarLabel;
class HocUpdateItem;
class Patch;
class BoundedValue;
class HocRadioAction;
class StepperMenu;
class ValEdLabel;
class ScenePicker;
struct HocSymExtension;

declarePtrList(HocUpdateItemList, HocUpdateItem)
declarePtrList(HocItemList, HocItem)
declarePtrList(HocPanelList, HocPanel)

class HocPanel: public OcGlyph {
  public:
    HocPanel(const char* name, bool horizontal = false);
    virtual ~HocPanel();
    virtual void map_window(int scroll = -1);  // -1 leave up to panel_scroll attribute

    void pushButton(const char* name, const char* action, bool activate = false, Object* pyact = 0);
    void stateButton(double* pd,
                     const char* name,
                     const char* action,
                     int style,
                     Object* pyvar = NULL,
                     Object* pyact = NULL);
    HocMenu* menu(const char* name, bool add2menubar = false);
    MenuItem* menuItem(const char* name,
                       const char* action,
                       bool activate = false,
                       Object* pyact = 0);
    MenuItem* menuStateItem(double* pd,
                            const char* name,
                            const char* action,
                            Object* pyvar = NULL,
                            Object* pyact = NULL);
    void valueEd(const char* prompt,
                 const char* variable,
                 const char* action = 0,
                 bool canrun = false,
                 double* pd = NULL,
                 bool deflt = false,
                 bool keep_updated = false,
                 HocSymExtension* extra = NULL,
                 Object* pyvar = NULL,
                 Object* pyact = NULL);
    void valueEd(const char* prompt,
                 Object* pyvar,
                 Object* pyact = 0,
                 bool canrun = false,
                 bool deflt = false,
                 bool keep_updated = false);

    // ZFM added vert
    void slider(double*,
                float low = 0,
                float high = 100,
                float resolution = 1,
                int steps = 10,
                const char* send_cmd = NULL,
                bool vert = false,
                bool slow = false,
                Object* pyvar = NULL,
                Object* pysend = NULL);
    virtual void write(ostream&);
    virtual void save(ostream&);
    virtual HocItem* hoc_item();
    void label(const char*);
    void var_label(char**, Object* pyvar = NULL);
    PolyGlyph* box();
    const char* getName();
    void itemAppend(const char*);
    void notifyHocValue();
    void check_valid_pointers(void*, int);
    Coord left_, bottom_;  // write by makeTray read by dissolve
    static void save_all(ostream&);
    void data_path(HocDataPaths*, bool);
    void item_append(HocItem*);
#if MAC
    void mac_menubar();
    void mac_menubar(int&, int&, int);  // recurse per menu through list
#endif
    static void keep_updated();
    static void keep_updated(HocUpdateItem*, bool);
    static void paneltool(const char* name,
                          const char* procname,
                          const char* action,
                          ScenePicker*,
                          Object* pycallback = NULL,
                          Object* pyselact = NULL);
    static void update_ptrs();

  private:
    PolyGlyph* box_;
    HocUpdateItemList elist_;
    HocItemList ilist_;
    static HocUpdateItemList* update_list_;
    bool horizontal_;
    InputHandler* ih_;
};

class HocItem: public Resource {
  public:
    HocItem(const char*, HocItem* parent = NULL);
    virtual ~HocItem();
    virtual void write(ostream&);
    const char* getStr();
    virtual void help(const char* childpath = NULL);
    virtual void help_parent(HocItem*);
#if MAC
    virtual int mac_menubar(int&, int, int);
#endif
  private:
    CopyString str_;
    HocItem* help_parent_;
};

class HocPushButton: public HocItem {
  public:
    HocPushButton(const char*, HocAction*, HocItem* parent = NULL);
    virtual ~HocPushButton();
    virtual void write(ostream&);
#if MAC
    virtual int mac_menubar(int&, int, int);
#endif
  private:
    HocAction* a_;
};

class HocRadioButton: public HocItem {
  public:
    HocRadioButton(const char*, HocRadioAction*, HocItem* parent = NULL);
    virtual ~HocRadioButton();
    virtual void write(ostream&);
#if MAC
    virtual int mac_menubar(int&, int, int);
#endif
  private:
    HocRadioAction* a_;
};

class HocMenu: public HocItem {
  public:
    HocMenu(const char*, Menu*, MenuItem*, HocItem* parent = NULL, bool add2menubar = false);
    virtual ~HocMenu();
    virtual void write(ostream&);
    virtual Menu* menu() {
        return menu_;
    }
    virtual MenuItem* item() {
        return mi_;
    }
#if MAC
    virtual int mac_menubar(int&, int, int);
#endif
  private:
    MenuItem* mi_;
    Menu* menu_;
    bool add2menubar_;
};

class HocUpdateItem: public HocItem {
  public:
    HocUpdateItem(const char*, HocItem* parent = NULL);
    virtual ~HocUpdateItem();
    virtual void update_hoc_item();
    virtual void check_pointer(void*, int vector_size);
    virtual void data_path(HocDataPaths*, bool);
    virtual void update_ptrs() {}
    void update_ptrs_helper(double**);
};

class HocLabel: public HocItem {
  public:
    HocLabel(const char*);
    virtual ~HocLabel();
    virtual void write(ostream&);
};

class HocVarLabel: public HocUpdateItem {
  public:
    HocVarLabel(char**, PolyGlyph*, Object* pyvar = NULL);
    virtual ~HocVarLabel();
    virtual void write(ostream&);
    virtual void update_hoc_item();
    virtual void check_pointer(void*, int);
    virtual void data_path(HocDataPaths*, bool);

  private:
    Patch* p_;
    char** cpp_;
    char* cp_;
    CopyString* variable_;
    Object* pyvar_;
};

class HocAction: public Action {
  public:
    HocAction(const char* action, Object* pyact = NULL);
    virtual ~HocAction();
    virtual void execute();
    const char* name() const;
    virtual void help();
    void hoc_item(HocItem*);

  private:
    HocCommand* action_;
    HocItem* hi_;
};

class HocMenuAction: public HocAction {
  public:
    HocMenuAction(const char* action, Object* pyact, HocMenu*);
    virtual ~HocMenuAction();
    virtual void execute();

  private:
    HocMenu* hm_;
    HocPanel* hp_;  // a temporary. hm_ is not part of this panel
};

class HocEditorForItem: public FieldSEditor {
  public:
    HocEditorForItem(HocValEditor*, HocValAction*);
    virtual ~HocEditorForItem();

    virtual void keystroke(const Event&);
    virtual void press(const Event&);
    virtual void drag(const Event&);
    virtual void release(const Event&);
    virtual void val_inc(const Event&);

    virtual InputHandler* focus_in();
    virtual void focus_out();

  private:
    HocValEditor* hve_;
    Coord y_;
    int index_;
    EventButton b_;
};

class HocValStepper: public Stepper {
  public:
    static HocValStepper* instance(HocValEditor*);
    HocValStepper(HocValEditor*, Glyph*, Style*, TelltaleState*);
    virtual ~HocValStepper();

    virtual void press(const Event&);
    virtual void release(const Event&);
    virtual void menu_up(Event&);
    void default_inc(bool, double);
    double default_inc();
    static StepperMenu* menu() {
        return menu_;
    }

  protected:
    virtual void adjust();

  private:
    void left();
    void middle();
    void right();

  private:
    bool geometric_;
    int steps_;
    float default_inc_;
    float inc_;
    HocValEditor* hve_;
    static StepperMenu* menu_;
};

class HocValEditor: public HocUpdateItem {
  public:
    HocValEditor(const char* name,
                 const char* variable,
                 ValEdLabel*,
                 HocValAction*,
                 double* pd = 0,
                 bool canrun = false,
                 HocItem* parent = NULL,
                 Object* pvar = NULL);
    virtual ~HocValEditor();
    FieldSEditor* field_editor() {
        return fe_;
    }
    virtual Stepper* stepper() {
        return NULL;
    }
    virtual void update_hoc_item();
    void evalField();
    void audit();
    virtual void updateField();
    virtual void write(ostream&);
    virtual void data_path(HocDataPaths*, bool);
    virtual void check_pointer(void*, int);
    virtual void print(Printer*, const Allocation&) const;
    virtual int hoc_default_val_editor() {
        return 0;
    }
    void set_val(double);
    double get_val();
    virtual void exec_action();
    const char* variable() const;
    virtual void setlimits(float*);
    virtual double domain_limits(double);
    bool active() {
        return active_;
    }
    virtual void update_ptrs();

  private:
    friend class HocEditorForItem;
    friend class HocValStepper;
    HocEditorForItem* fe_;
    bool active_;
    bool canrun_;
    HocAction* action_;
    CopyString* variable_;
    double* pval_;
    ValEdLabel* prompt_;
    float* domain_limits_;
    Object* pyvar_;
};

class HocDefaultValEditor: public HocValEditor {
  public:
    HocDefaultValEditor(const char* name,
                        const char* variable,
                        ValEdLabel*,
                        HocValAction*,
                        double* pd = 0,
                        bool canrun = false,
                        HocItem* parent = NULL,
                        Object* pyvar = NULL);
    virtual ~HocDefaultValEditor();
    virtual Stepper* stepper() {
        return vs_;
    }
    virtual void updateField();
    virtual int hoc_default_val_editor() {
        return 1;
    }
    void deflt(double);
    void def_action();
    void def_change(float, float);
    Button* checkbox() {
        return checkbox_;
    }

  private:
    Button* checkbox_;  // not your normal checkbox. see xmenu.cpp
    double deflt_;
    double most_recent_;
    HocValStepper* vs_;
};

class HocValEditorKeepUpdated: public HocValEditor {
  public:
    HocValEditorKeepUpdated(const char* name,
                            const char* variable,
                            ValEdLabel*,
                            HocValAction*,
                            double*,
                            HocItem* parent = NULL,
                            Object* pyvar = NULL);
    virtual ~HocValEditorKeepUpdated();
    virtual void write(ostream&);
};

class HocValAction: public HocAction {
  public:
    HocValAction(const char* action, Object* pyact = 0);
    HocValAction(Object* pyaction);
    virtual ~HocValAction();
    void accept(FieldSEditor*);
    void execute();
    void setFieldSEditor(HocValEditor*);
#if UseFieldEditor
    FieldEditorAction* fea() {
        return fea_;
    }
#else
    FieldSEditorAction* fea() {
        return fea_;
    }
#endif
  private:
    HocValEditor* fe_;
#if UseFieldEditor
    FieldEditorAction* fea_;
#else
    FieldSEditorAction* fea_;
#endif
};


// ZFM added vert_
class OcSlider: public HocUpdateItem, public Observer {
  public:
    OcSlider(double*,
             float low,
             float high,
             float resolution,
             int nsteps,
             const char* send_cmd,
             bool vert,
             bool slow = false,
             Object* pyvar = NULL,
             Object* pysend = NULL);
    virtual ~OcSlider();
    virtual void write(ostream&);

    Adjustable* adjustable();

    virtual void update(Observable*);

    virtual void update_hoc_item();
    virtual void check_pointer(void*, int vector_size);
    virtual void data_path(HocDataPaths*, bool);
    virtual double slider_val();
    virtual void update_ptrs();

  private:
    void audit();

  private:
    float resolution_;
    BoundedValue* bv_;
    HocCommand* send_;
    double* pval_;
    Object* pyvar_;
    CopyString* variable_;
    bool scrolling_;
    bool vert_;
    bool slow_;
};


class HocStateButton: public HocUpdateItem, public Observer {
  public:
    HocStateButton(double*,
                   const char*,
                   Button*,
                   HocAction*,
                   int,
                   HocItem* parent = NULL,
                   Object* pyvar = NULL);
    virtual ~HocStateButton();
    virtual void write(ostream&);

    bool chosen();
    void button_action();

    virtual void update_hoc_item();
    virtual void check_pointer(void*, int);
    virtual void data_path(HocDataPaths*, bool);
    virtual void print(Printer*, const Allocation&) const;
    virtual void update_ptrs();
    enum { CHECKBOX, PALETTE };

  private:
    int style_;
    CopyString* variable_;
    CopyString* name_;
    double* pval_;
    Object* pyvar_;
    Button* b_;
    HocAction* action_;
};


class HocStateMenuItem: public HocUpdateItem, public Observer {
  public:
    HocStateMenuItem(double*,
                     const char*,
                     MenuItem*,
                     HocAction*,
                     HocItem* parent = NULL,
                     Object* pyvar = NULL);
    virtual ~HocStateMenuItem();
    virtual void write(ostream&);

    bool chosen();
    void button_action();

    virtual void update_hoc_item();
    virtual void check_pointer(void*, int);
    virtual void data_path(HocDataPaths*, bool);
    virtual void print(Printer*, const Allocation&) const;
    virtual void update_ptrs();

  private:
    CopyString* variable_;
    CopyString* name_;
    double* pval_;
    Object* pyvar_;
    MenuItem* b_;
    HocAction* action_;
};


#endif
