//<copyright>
// 
// Copyright (c) 1994,95,96
// Institute for Information Processing and Computer Supported New Media (IICM),
// Graz University of Technology, Austria.
// 
//</copyright>

//<file>
//
// Name:        listbox.h
//
// Purpose:     Interface to option buttons (pop up list box)
//
// Created:      7 Mar 94   Michael Pichler
//
// $Id: listbox.h,v 1.3 1996/01/18 17:56:54 bmarsch Exp $
//
// $Log: listbox.h,v $
// Revision 1.3  1996/01/18 17:56:54  bmarsch
// Implemented disabling/enabling of items
//
//</file>



#ifndef harmony_widgets_listbox_h
#define harmony_widgets_listbox_h

#include "libwidgets.h"

#include <IV-look/button.h>
class BrowserList;
class Event;
class Handler;
class ListBoxAction;
class LayoutKit;
class Patch;
class PolyGlyph;
class WidgetKit;
class Window;


//<class>
//
// class ListBox (well, should be named OptionButton)
//
// a list box is a glyph for pop up selection out of a list
// on each new selection the confirm action is called
//
// initially the current selection is visible in the button; by
// dragging the mouse from the button another item can be selected;
// dragging out of the popup restores the original selection;
// alternatively one can click on the small bar graphic of the button
// to get the popup mapped for selection by mouse click (or key
// commands: arrows, return, cancel).
//
//</class>


class ListBox: public Button
{
  public:
    ListBox(                            // create a list box
      PolyGlyph* items,                 //   item list
      GlyphIndex selected,              //   index of selected item
      ListBoxAction* selchanged,        //   called when selection changes
      Style* style,                     //   style (for Button)
      TelltaleState* tstate = nil       //   telltale state (default: enabled)
    );

    ~ListBox();

    void reportEachSelection(int flag)  // when set, also re-selection of current
    { reporteachsel_ = flag; }          // item causes action call (off by default)

    const PolyGlyph* items() const      // returns item list
    { return items_; }

    GlyphIndex selected() const         // returns selected index
    { return selected_; }

    Glyph* selectedItem() const;        // returns selected item

    void selectItem(GlyphIndex);        // select an item; action is not called

    void removeItem(GlyphIndex);        // remove a list item (selection index will be
                                        // modified properly)

    void enabled(GlyphIndex, boolean);  // enable/disable an item
    void enableAll(GlyphIndex selected = 0);  // enable all items

    // Button
    void allocate (Canvas*, const Allocation&, Extension&);
    void move (const Event&);
    void press (const Event&);
    void release (const Event&);
    void undraw();

  private:
    void runpopup();                    // map and execute popup

    Glyph* createTopline(Glyph* selitem);
    void updateTopline(WidgetKit&, const LayoutKit&, Glyph* selitem);
    Glyph* createBox();
    int boxevent(Event&);
    boolean setCurItem(GlyphIndex);   // returns if set was ok (ie item enabled)
    void updateCurrent(const Event&);

    PolyGlyph* items_;
    GlyphIndex selected_;
    ListBoxAction* confirm_;  // selection changed
    GlyphIndex current_;
    BrowserList* telltales_;
    float maxx_, maxy_;  // max. item size

    int moved_;
    float margin_;
    PolyGlyph* toplinebox_;
    Window* win_;
    Patch* winpatch_;
    Handler* listinput_;
    float trfleft_, trfy_;
    int reporteachsel_;

    boolean disabled_;
};  // ListBox



//<class>
//
// class ListBoxAction
//
// get notified when selection of a list box changes
// argument of changed is pointer to the caller (ListBox)
// new index is accessible via listbox->selected ()
//
//</class>


class ListBoxAction: public Resource
{
  protected:
    virtual ~ListBoxAction()  { }

  public:
    virtual void changed(ListBox*) = 0;
};



// ListBoxCallback
//
// callback for ListBoxAction
// (compare "ActionCallback" and "FieldEditorCallback")
//
// declareListBoxCallback(T)
//   declares a ListBoxCallback(T), where T is the class name
//
// implementListBoxCallback(T)
//   implements a ListBoxCallback(T)
//
// class is acessed as ListBoxCallback(T)


#if defined(__STDC__) || defined(__ANSI_CPP__)
#define __ListBoxCallback(T) T##_ListBoxCallback
#define ListBoxCallback(T) __ListBoxCallback(T)
#define __ListBoxMemberFunction(T) T##_ListBoxMemberFunction
#define ListBoxMemberFunction(T) __ListBoxMemberFunction(T)
#else
#define __ListBoxCallback(T) T/**/_ListBoxCallback
#define ListBoxCallback(T) __ListBoxCallback(T)
#define __ListBoxMemberFunction(T) T/**/_ListBoxMemberFunction
#define ListBoxMemberFunction(T) __ListBoxMemberFunction(T)
#endif


#define declareListBoxCallback(T) \
typedef void (T::*ListBoxMemberFunction(T))(ListBox*); \
class ListBoxCallback(T) : public ListBoxAction { \
public: \
    ListBoxCallback(T)( \
	T*, ListBoxMemberFunction(T) changed \
    ); \
    virtual ~ListBoxCallback(T)(); \
\
    virtual void changed(ListBox*); \
private: \
    T* obj_; \
    ListBoxMemberFunction(T) changed_; \
};


#define implementListBoxCallback(T) \
ListBoxCallback(T)::ListBoxCallback(T)( \
    T* obj, ListBoxMemberFunction(T) changed \
) { \
    obj_ = obj; \
    changed_ = changed; \
} \
\
ListBoxCallback(T)::~ListBoxCallback(T)() { } \
\
void ListBoxCallback(T)::changed(ListBox* listbox) \
{ if (changed_ != nil) (obj_->*changed_)(listbox); } 


#endif
