// This may look like C code, but it is really -*- C++ -*-

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

//<file>
//
// Name:        coldlg.h
//
// Purpose:     interface to colour dialog
//
// Created:     16 Apr 93   Michael Pichler
//
// Changed:     31 May 94   Michael Pichler
//
// Changed:     23 May 95   Bernhard Marschall
//
//
//</file>



#ifndef harmony_widgets_coldlg_h
#define harmony_widgets_coldlg_h


#include <hyperg/hyperg/language.h>

#include <InterViews/resource.h>
class Action;
class Color;
class Glyph;
class ManagedWindow;
class PolyGlyph;

class ColourDlgAction;  // defined below

class OColor;
class ColDlgInputHandler;

class ColorList;
class OrigColorViewer;
class WFileBrowser;


//<class>
//
// Name: ColourDialog
//
// Purpose: Dialog box for editing a colour
//
// Style name: ColourChooser (alias ColorChooser)
//
// attributes:
//
// - font            label font
// - foreground      label foreground colour
//
// Hint: the font and look of the fieldeditors is determined by
// style FieldEditor
//
//</class>


class ColourDialog
{
  public:
    ColourDialog (                      // create a colour dialog window - single colour
      HgLanguage::Language lang,        //   language (for buttons)
      float r, float g, float b,        //   colour (RGB, 0.0 to 1.0)
      const char* wintitle,             //   window title
      const char* titleline,            //   title line inside window
      ColourDlgAction* action           //   action on apply and close
    );
    ColourDialog (                      // create dialog - multiple colours
      HgLanguage::Language lang,        //   language (for buttons)
      const char* wintitle,             //   window title
      ColourDlgAction* action           //   action on apply and close
    );
    ~ColourDialog ();

    void setRGB (                       // set RGB values
      float r, float g, float b,        //   in range 0.0 to 1.0
      int index = 0                     //   number of colour to return
    );
    void setColor (                     // set (InterViews) colour
      const Color* c,
      int index = 0
    );

    void getRGB (                       // get RGB values
      float& r, float& g, float& b,     //   in range 0.0 to 1.0
      int index = 0                     //   number of colour to return
    ) const;
    const char* getHexRGB(              // get hex RGB string ("RRGGBB")
      int index = 0                     //   two hex digits per RGB, no leading #
    ) const;

    void map ();                        // map the dialog window
    void unmap ();                      // close the dialog window
    int ismapped ();                    // is dialog window currently mapped

    // actions of buttons and file browser
    void confirmAction ();
    void applyAction ();
    void cancelAction ();
    void acceptSelection ();

    // support for "Multichooser"
    void appendColourEntry(             // append new "choosable" entry
      const char* name,                 //   name of entry
      float r, float g, float b         //   initial colour for entry
    );
    int entries() const;                // return number of entries
    boolean modified(int i) const;      // return if the i-th entry has been modified

  private:
    void createWindow (HgLanguage::Language, const char*, const char*, boolean);
    void init (ColourDlgAction*);

    ColourDlgAction* action_;
    ColorList* origcol_;
    ColorList* currentcol_;
    int didapply_;
    OColor* ocolor_;
    ManagedWindow* win_;
    ColDlgInputHandler* coldlginput_;
    PolyGlyph* mainhbox_;
    PolyGlyph* mainvbox_;
    Glyph* colsel_;
    WFileBrowser* fbrowser_;
    OrigColorViewer* origColViewer_;

    int done_;

    int num_;
    int current_;

};  // ColourDialog

inline int ColourDialog::entries() const {
  return num_;
}


//<class>
//
// Name: ColourDlgAction
//
// Purpose: Action for a colour choosing dialog (abstract base class)
//
// apply (ColourDialog* cdlg)
//   is called any times a new colour has to be applied:
//   when APPLY or OK is pressed, or to apply the original colour on
//   CANCEL when another colour has been applied in the meantime.
//   Use cdlg->getRGB to access the RGB colour components.
//
// close (ColourDialog* cdlg)
//   is called to close the dialog. You should either call cdlg->unmap()
//   to close the dialog for later reuse with map() or destroy the whole
//   dialog with a call of delete cdlg.
//
//</class>


class ColourDlgAction: public Resource
{
  public:
    virtual void apply (                // apply selected colour
      ColourDialog* cdlg                //   invoking colour dialog
    ) = 0;

    virtual void close (                // close the dialog
      ColourDialog* cdlg                //   invoking colour dialog
    ) = 0;
};


//<class>
//
// Name: ColourDlgCallback
//
// Purpose: Action callback for colour choosing dialog
// based on preprocessor macros;
// member functions of any class may be used for a ColourDlgAction
//
// declareColourDlgCallback(T)
//   generates the declaration of ColourDlgCallback(T)
//
// implementColourDlgCallback(T)
//   generates the implementation of ColourDlgCallback(T)
//
// ColourDlgCallback(T) (T* obj, apply, close)
//   is the constructor of ColourDlgCallback(T), where
//   obj is a pointer to an object of type T,
//   apply is a member function of T:
//     T::(*apply) (ColourDialog* cdlg);
//     which is called to apply a colour
//   close is also a member function of T:
//     T::(*close) (ColourDialog* cdlg);
//     which is called to close the colour dialog
//   argument close is optional - when omitted, the dialog
//     is unmapped - but not deleted
//   
// ColourDlgCallback(T) is derived from ColourDlgAction
// and calls the functions given in the constructor;
// see remark of ColourDlgAction of intented behaviour
//
//</class>


#if defined(__STDC__) || defined(__ANSI_CPP__)
#define __ColourDlgCallback(T) T##_ColourDlgCallback
#define ColourDlgCallback(T) __ColourDlgCallback(T)
#define __MemberFunctionColourDlg(T) T##_MemberFunctionColourDlg
#define MemberFunctionColourDlg(T) __MemberFunctionColourDlg(T)
#else
#define __ColourDlgCallback(T) T/**/_ColourDlgCallback
#define ColourDlgCallback(T) __ColourDlgCallback(T)
#define __MemberFunctionColourDlg(T) T/**/_MemberFunctionColourDlg
#define MemberFunctionColourDlg(T) __MemberFunctionColourDlg(T)
#endif


#define declareColourDlgCallback(T) \
typedef void (T::*MemberFunctionColourDlg(T))(ColourDialog*); \
class ColourDlgCallback(T): public ColourDlgAction \
{ \
  public: \
    ColourDlgCallback(T)( \
        T*, MemberFunctionColourDlg(T) apply, \
        MemberFunctionColourDlg(T) close = nil \
    ); \
    virtual ~ColourDlgCallback(T)(); \
\
    virtual void apply(ColourDialog* cdlg); \
    virtual void close(ColourDialog* cdlg); \
  private: \
    T* obj_; \
    MemberFunctionColourDlg(T) apply_; \
    MemberFunctionColourDlg(T) close_; \
};

#define implementColourDlgCallback(T) \
ColourDlgCallback(T)::ColourDlgCallback(T)( \
    T* obj, MemberFunctionColourDlg(T) apply, \
    MemberFunctionColourDlg(T) close \
) { \
  obj_ = obj; \
  apply_ = apply; \
  close_ = close; \
} \
\
ColourDlgCallback(T)::~ColourDlgCallback(T)() { } \
\
void ColourDlgCallback(T)::apply(ColourDialog* cdlg) \
{ if (apply_ != nil) (obj_->*apply_)(cdlg); \
} \
void ColourDlgCallback(T)::close(ColourDialog* cdlg) \
{ if (close_ != nil) (obj_->*close_)(cdlg); \
  else cdlg->unmap (); \
}



#endif
