/* Copyright (C) 2003 The gtkmm Development Team
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 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
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
 */

_DEFS(gtkmm,gtk)
_CONFIGINCLUDE(gtkmmconfig.h)
_IS_DEPRECATED // The entire file is deprecated.

#include <gtkmm/widget.h>
#include <gtkmm/celllayout.h>
#include <gtkmm/celleditable.h>
#include <gtkmm/entry.h>
#include <gtkmm/treemodel.h>
#include <gtkmm/treeview.h>
#include <gtkmm/enums.h> //For SensitivityType.

_PINCLUDE(gtkmm/private/widget_p.h)

#m4 _PUSH(SECTION_CC_PRE_INCLUDES)
#undef GTK_DISABLE_DEPRECATED
#define GDK_DISABLE_DEPRECATION_WARNINGS 1
#m4 _POP()

namespace Gdk
{
class GTKMM_API Device;
}

namespace Gtk
{

/** A widget used to choose from a list of items.
 *
 * A ComboBox is a widget that allows the user to choose from a list of valid choices. The ComboBox displays the
 * selected choice. When activated, the ComboBox displays a popup which allows the user to make a new choice. The
 * style in which the selected value is displayed, and the style of the popup is determined by the current theme.
 * It may be similar to a Windows-style combo box.
 *
 * The ComboBox uses the model-view pattern; the list of valid choices is specified in the form of a tree model,
 * and the display of the choices can be adapted to the data in the model by using cell renderers, as you would in
 * a tree view. This is possible since ComboBox implements the CellLayout interface. The tree model holding the
 * valid choices is not restricted to a flat list, it can be a real tree, and the popup will reflect the tree
 * structure.
 *
 * To allow the user to enter values not in the model, the 'has-entry'
 * property allows the ComboBox to contain a Gtk::Entry. This entry
 * can be accessed by calling get_entry(), or you can just call get_entry_text()
 * to get the text from the Entry.
 *
 * For a simple list of textual choices, the model-view API of ComboBox
 * can be a bit overwhelming. In this case, ComboBoxText offers a
 * simple alternative. Both ComboBox and ComboBoxText can contain
 * an entry.
 *
 * @deprecated 4.10: Use Gtk::DropDown instead.
 *
 * The ComboBox widget looks like this:
 * @image html combobox1.png
 *
 * @ingroup Widgets
 */
class GTKMM_API ComboBox
: public Widget,
  public CellLayout,
  public CellEditable
{
  _CLASS_GTKOBJECT(ComboBox, GtkComboBox, GTK_COMBO_BOX, Gtk::Widget, GtkWidget, , , GTKMM_API)
  _IMPLEMENTS_INTERFACE(CellLayout)
  _IMPLEMENTS_INTERFACE(CellEditable)
public:

  /** Creates a new empty ComboBox, optionally with an entry.
   * @param has_entry If this is true then this will have an Entry widget.
   */
  explicit ComboBox(bool has_entry = false);
  _IGNORE(gtk_combo_box_new_with_entry)

  /** Creates a new ComboBox with the model initialized to @a model, optionally with an entry.
   * @param model The model containing data to display in the ComboBox.
   * @param has_entry If this is true then this will have an Entry widget.
   */
  explicit ComboBox(const Glib::RefPtr<TreeModel>& model, bool has_entry = false);
  _IGNORE(gtk_combo_box_new_with_model, gtk_combo_box_new_with_model_and_entry)
  _IGNORE(gtk_combo_box_new)

/* get/set active item */
  _WRAP_METHOD(int get_active_row_number() const, gtk_combo_box_get_active)

  /** Gets an iterator that points to the current active item, if it exists.
   * @result The iterator.
   */
  TreeModel::iterator get_active();

  /** Gets an iterator that points to the current active item, if it exists.
   * @result The iterator.
   */
  TreeModel::const_iterator get_active() const;
  _IGNORE(gtk_combo_box_get_active_iter)

  _WRAP_METHOD(void set_active(int index), gtk_combo_box_set_active)
  _WRAP_METHOD(void set_active(const TreeModel::const_iterator& iter), gtk_combo_box_set_active_iter)

  // See https://bugzilla.gnome.org/show_bug.cgi?id=612396#c30
  /** Get the text in the entry, if there is an entry.
   */
  Glib::ustring get_entry_text() const;

  /** Causes no item to be active. See also set_active().
   */
  void unset_active();

  _WRAP_METHOD(Glib::RefPtr<TreeModel> get_model(), gtk_combo_box_get_model, refreturn)
  _WRAP_METHOD(Glib::RefPtr<const TreeModel> get_model() const, gtk_combo_box_get_model, refreturn, constversion)

  /** Sets the model used by @a combo_box to be @a model.
   * Will unset a previously set model (if applicable).
   * Use unset_model() to unset the old model.
   *
   * Note that this function does not clear the cell renderers. You have to
   * call Gtk::CellLayout::clear() yourself if you need to set up different
   * cell renderers for the new model.
   *
   * Deprecated: 4.10: Use Gtk::DropDown
   *
   * @param model A `Gtk::TreeModel`.
   */
  _WRAP_METHOD(void set_model(const Glib::RefPtr<TreeModel>& model), gtk_combo_box_set_model)

  /** Remove the model from the ComboBox.
   *
   * @see set_model().
   */
  void unset_model();

  typedef TreeView::SlotRowSeparator SlotRowSeparator;

  /** Sets the row separator function, which is used to determine whether a row should be drawn as a separator.
   * See also unset_row_separator_func().
   *
   * @param slot The callback.
   */
  void set_row_separator_func(const SlotRowSeparator& slot);

  /** Causes no separators to be drawn.
   */
  void unset_row_separator_func();
  _IGNORE(gtk_combo_box_set_row_separator_func, gtk_combo_box_get_row_separator_func)

  _WRAP_METHOD(void set_button_sensitivity(SensitivityType sensitivity), gtk_combo_box_set_button_sensitivity)
  _WRAP_METHOD(SensitivityType get_button_sensitivity() const, gtk_combo_box_get_button_sensitivity)


  _WRAP_METHOD(bool get_has_entry() const, gtk_combo_box_get_has_entry)

  _WRAP_METHOD(void set_entry_text_column(const TreeModelColumnBase& text_column) const, gtk_combo_box_set_entry_text_column)
  _WRAP_METHOD(void set_entry_text_column(int text_column), gtk_combo_box_set_entry_text_column)

  _WRAP_METHOD(int get_entry_text_column() const, gtk_combo_box_get_entry_text_column)

  _WRAP_METHOD(void set_popup_fixed_width(bool fixed = true), gtk_combo_box_set_popup_fixed_width )
  _WRAP_METHOD(bool get_popup_fixed_width() const, gtk_combo_box_get_popup_fixed_width)

  _WRAP_METHOD(void popup(), gtk_combo_box_popup)
  _WRAP_METHOD(void popup(const Glib::RefPtr<Gdk::Device>& device), gtk_combo_box_popup_for_device)
  _WRAP_METHOD(void popdown(), gtk_combo_box_popdown)

  _WRAP_METHOD(int get_id_column() const, gtk_combo_box_get_id_column)
  _WRAP_METHOD(void set_id_column(int id_column), gtk_combo_box_set_id_column)
  _WRAP_METHOD(Glib::ustring get_active_id() const, gtk_combo_box_get_active_id)

  /** Changes the active row of the combo box to the one that has an ID equal to
   * @a active_id.
   *
   * If property_id_column() is unset or if no row has the given ID then the function
   * does nothing and returns false.
   *
   * @param active_id The ID of the row that should be set to active.
   * @returns true if a row with a matching ID was found.
   *
   * @newin{3,6}
   */
  _WRAP_METHOD(bool set_active_id(const Glib::ustring& active_id), gtk_combo_box_set_active_id)

  _WRAP_METHOD(void set_child(Widget& child), gtk_combo_box_set_child)
  void unset_child();
  _WRAP_METHOD(Widget* get_child(), gtk_combo_box_get_child)
  _WRAP_METHOD(const Widget* get_child() const, gtk_combo_box_get_child, constversion)

  /** @see get_child().
   */
  Entry* get_entry();

  /** @see get_child().
   */
  const Entry* get_entry() const;

  _WRAP_PROPERTY("model", Glib::RefPtr<TreeModel>)
  _WRAP_PROPERTY("active", int)
  _WRAP_PROPERTY("has-frame", bool)
  _WRAP_PROPERTY("popup-shown", bool)
  _WRAP_PROPERTY("button-sensitivity", SensitivityType)
  _WRAP_PROPERTY("popup-fixed-width", bool)
  _WRAP_PROPERTY("has-entry", bool)
  _WRAP_PROPERTY("entry-text-column", int)
  _WRAP_PROPERTY("id-column", int)
  _WRAP_PROPERTY("active-id", Glib::ustring)
  _WRAP_PROPERTY("child", Widget*)

  _WRAP_SIGNAL(void changed(), "changed")

#m4begin
dnl// The ::format_entry_text signal handler should return a newly allocated string.
dnl// (which is obviously not a const gchar*)
dnl// Also, ensure that format_entry_text never returns an empty char[],
dnl// because that could be caused by an intermediate empty ustring from an initial null char*.
dnl// See bug http://bugzilla.gnome.org/show_bug.cgi?id=168747.
  _CONVERSION(`Glib::ustring',`char*',`g_strdup(Glib::c_str_or_nullptr($3))')
  _CONVERSION(`char*',`Glib::ustring',`Glib::convert_return_gchar_ptr_to_ustring($3)')
  _CONVERSION(`const char*',`const TreeModel::Path&',`TreeModel::Path($3)')
  _CONVERSION(`const TreeModel::Path&',`const char*',`($3).to_string().c_str()')
#m4end
  _WRAP_SIGNAL(Glib::ustring format_entry_text(const TreeModel::Path& path), "format-entry-text")

  //Action signal:
  _IGNORE_SIGNAL("activate")
  //Key-binding signals:
  _IGNORE_SIGNAL("move-active")
  _IGNORE_SIGNAL("popup")
  _IGNORE_SIGNAL("popdown")
};

} // namespace Gtk
