/*
 * ===========================
 * VDK Visual Development Kit
 * Version 0.4
 * October 1998
 * ===========================
 *
 * Copyright (C) 1998, Mario Motta
 * Developed by Mario Motta <mmotta@guest.net>
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Library General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library 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
 * Library General Public License for more details.
 *
 * You should have received a copy of the GNU Library General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
 * 02111-130
 */
/* This is a wrapper for GtkCombo.
   Author: Eric T. Wienke <eric@liquidsilver.com>
   =====================================================================
   Limitations: Listitems only setable via SetPopdownStrings which gets
   mapped to gtk_list_item_new_with_label. There is no high-level
   interface to GtkList and GtkListItem which would allow to insert
   any object to the List. Probably not really needed for a Combobox
   anyway.
   One problem is that the GetPopdownStrings won't work if Gtk functions
   are used to add anything else to the ListItems.
   Possible solution: Write wrappers for GtkList and GtkListItem and and
   provide a interface for them in the VDKCombo class. (too much work for
   this widget alone, would GtkList be of any other use?)
   ======================================================================
*/

#ifndef  COMBO_H
#define  COMBO_H

#include <vdk/vdkobj.h>
#include <vdk/value_sem_list.h>

typedef VDKValueList<VDKString> StringList;
typedef VDKValueListIterator<VDKString> StringListIterator;

/*!
  \class VDKCombo
  \brief Provides a simplified wrapper for gtkcombo
  \author Eric T. Wienke <eric@liquidsilver.com>
  \par Signals
  \arg \b activate_signal received when the Enter key is pressed in the Entry.
  \arg \b changed_signal received when text in Entry is changed.
  \arg \b selection_changed_signal, received when the selection in the List 
  is changed. This happens when an item has been selected or unselected. 
  This means that the signal is received more than once on a new selection.
  Always check the Selected property for a value of -1.
  \arg \b focus_in_signal received when Entry gets focus.
  \arg \b focus_out_signal received when Entry loses focus.
 */
class VDKCombo: public VDKObject
{
  static int FocusOutEvent(GtkWidget *w,
			    GdkEventFocus *event,
			    gpointer wid);
  static int FocusInEvent(GtkWidget *w,
			    GdkEventFocus *event,
			    gpointer wid);
 protected:
  int changeConnect;
  VDKObjectSignal s_activated, s_changed, s_selected;
  GList *popdownlist;
  StringList popdownstr;
  void SortList();
  VDKString buffer;
public:
  // properties
  /*!
    Set/Get the text in the Entry
   */
  VDKReadWriteValueProp<VDKCombo,char*> Text;
  /*!
    Same as Editable property in VDKEntry.
    Setting it to false allows you to provide a read-only list to select 
    from, without the user being able to enter text.
   */
  VDKReadWriteValueProp<VDKCombo,bool>  Editable;
  /*!
    Default: false. Setting Sorted to true will automatically sort 
    the listitems alphabetically and maintain the list sorted whenever
    a new item is added
   */
  VDKReadWriteValueProp<VDKCombo,bool>  Sorted;
  /*!
    Entry text visibility flag. (As in VDKEntry)
   */
  VDKReadWriteValueProp<VDKCombo,bool>  Hidden;
  /*!
    Default: false. Whether the Combo box should check for equality 
    in the list case-sensitive or not.
   */
  VDKReadWriteValueProp<VDKCombo,bool>  CaseSensitive;
  /*!
    A StringList corresponding to the Text of the Listitems. 
    Use this function to add items to the list, 
    \code
    StringList sl = mycombo->PopdownStrings;
    VDKString s("New line");
    sl.add(s);
    mycombo->PopdownStrings = sl;
    \endcode
    Since StringList is of type VDKValueList<VDKString> you can 
    use all functions of VDKValueList to manipulate the list. 
    It is very convenient to access the StringList by index:
    \code
    int sel = mycombo->Selected;
    char *seltext = (sel == -1) ? "None" : 
           (char*)(mycombo->GetPopdownStrings())[sel];
    printf("Selected item is %s\n",seltext);
    \endcode
    \par Tip 
    Note the use of the get function GetPopdownStrings() instead of 
    the property because it was used within an expression.
    \code
    mycombo->PopdownStrings[sel];
    \endcode
    would result in a compilation error. 
    You can however use a typecast:
    \code
    ((StringList)mycombo->PopdownStrings)[sel]
    \endcode
   */
  VDKReadWriteValueProp<VDKCombo,StringList> PopdownStrings;
  /*!
    Returns the index of the currently selected item in the dropdown 
    list or -1 if no item is selected. See PopdownStrings
    for example usage.
   */
  VDKReadOnlyValueProp<VDKCombo,int> Selected;
  /*!
    Constructor
    \param def is an optional initial value to be shown in the Entrybox.
    \param combo  internal use, leave it as NULL.
   */
  VDKCombo(VDKForm* owner, char* def = (char*) NULL, 
	   GtkWidget* combo = NULL);
  /*!
   */
  virtual ~VDKCombo();

  void SetText(char* text);
  char* GetText();
  void SetEditable(bool flag)
    { gtk_entry_set_editable(GTK_ENTRY(GTK_COMBO(widget)->entry),flag); }
  bool GetEditable()
    { return Editable; }
  void SetSorted(bool flag)
    { if(flag && !Sorted) SortList(); }
  bool GetSorted()
    { return Sorted; }
  void SetBackground(VDKRgb rgb,
		     GtkStateType state);
  void SetHidden(bool flag)
    { gtk_entry_set_visibility(GTK_ENTRY(GTK_COMBO(widget)->entry), ! flag) ; }
  bool GetHidden()
    { return ! Hidden; }
  void SetPopdownStrings(StringList);
  StringList GetPopdownStrings();
  void SetCaseSensitive(bool flag)
    { gtk_combo_set_case_sensitive(GTK_COMBO(widget),flag); }
  bool GetCaseSensitive()
    { return (bool)(GTK_COMBO(widget)->case_sensitive); }
  void UseArrows(bool flag)
    { gtk_combo_set_use_arrows(GTK_COMBO(widget),flag); }
  void UseArrowsAlways(bool flag)
    { gtk_combo_set_use_arrows_always(GTK_COMBO(widget),flag); }
  void SetValueInList(int val, bool ok_if_empty)
    { gtk_combo_set_value_in_list(GTK_COMBO(widget),val,ok_if_empty); }
  void ClearList();
  void SelectItem(int item)
    { gtk_list_select_item(GTK_LIST(GTK_COMBO(widget)->list), item); }
  void UnselectItem(int item)
    { gtk_list_unselect_item(GTK_LIST(GTK_COMBO(widget)->list), item); }
  int GetSelected();
#ifdef USE_SIGCPLUSPLUS
 public:
  /*!
      Extended LS signal system:
      Received when an item is selected
      \param int selected item
     */
  VDKSignal1<void,int>  OnItemSelect;
  /*!
      Extended LS signal system:
      Received when an item is unselected
      \param unselected item
     */
  VDKSignal1<void,int>  OnItemUnselect;
  /*!
      Extended LS signal system:
      Received when an item is changed
      \param int item
      \param char* changed text
     */
  VDKSignal2<void,int, const char*> OnItemTextChanged;
  /*!
      Extended LS signal system:
      Received when an item is activated
      \param int activated item
     */
  VDKSignal1<void, int> OnItemActivate;

 protected:
  static void make_gtksigc_connection(VDKCombo*);

 private:
  static void _handle_item_select(GtkWidget* list,
				  GtkWidget* item,
				  gpointer obj);
  static void _handle_item_unselect(GtkWidget* list,
				    GtkWidget* item,
				    gpointer obj);
  static void _handle_item_text_changed(GtkWidget*, gpointer obj);
  static void _handle_item_activate(GtkWidget*, gpointer obj);
#endif /* USE_SIGCPLUSPLUS */
};
#endif
/*
not implemented:
void gtk_combo_set_item_string (GtkCombo *combo, GtkItem *item, gchar *item_value)
Probably useless until GtkList and GtkListItem are implemented.
*/
