// This may look like C code, but it's really -*- C++ -*-
/*
 * Copyright (C) 2008 Emweb bvba, Kessel-Lo, Belgium.
 *
 * See the LICENSE file for terms of use.
 */
#ifndef WPUSHBUTTON_H_
#define WPUSHBUTTON_H_

#include <Wt/WFormWidget>
#include <Wt/WJavaScript>

namespace Wt {

/*! \class WPushButton Wt/WPushButton Wt/WPushButton
 *  \brief A widget that represents a push button.
 *
 * To act on a button click, connect a slot to the clicked() signal.
 * 
 * \if cpp
 * Usage example:
 * \code
 * Wt::WPushButton *ok = new Wt::WPushButton("Okay");
 * ok->clicked().connect(ok, &Wt::WPushButton::disable);
 * ok->clicked().connect(this, &MyClass::processData);
 * \endcode
 * \endif
 *
 * %WPushButton is an \link WWidget::setInline(bool) inline \endlink widget.
 *
 * <h3>CSS</h3>
 *
 * The widget corresponds to the HTML <tt>&lt;button&gt;</tt> tag and
 * has the <tt>Wt-btn</tt> style. It may be styled through the current
 * theme, or you can override the style using internal or external CSS
 * as appropriate.
 */
class WT_API WPushButton : public WFormWidget
{
public:
  /*! \brief Creates a push button.
   */
  WPushButton(WContainerWidget *parent = 0);

  /*! \brief Creates a push button with given label text.
   */
  WPushButton(const WString& text, WContainerWidget *parent = 0);

  virtual ~WPushButton();

  /*! \brief Sets the button text.
   */
  void setText(const WString& text);

  /*! \brief Returns the button text.
   *
   * \sa setText()
   */
  const WString& text() const { return text_; }

  /*! \brief Sets an icon.
   *
   * The icon is placed to the left of the text.
   */
  void setIcon(const std::string& url);

  /*! \brief Returns the icon.
   *
   * \sa setIcon()
   */
  const std::string& icon() const { return icon_; }

  /*! \brief Sets a destination URL.
   *
   * This method can be used to make the button behave like a WAnchor
   * (or conversely, an anchor look like a button) and redirect to
   * another URL when clicked.
   *
   * By default, a button does not refer to an URL and you should
   * listen to the clicked() signal to react to a click event.
   *
   * \sa setResource(), setRefInternalPath()
   */
  void setRef(const std::string& url);

  /*! \brief Returns the destination URL.
   *
   * When the button refers to a resource, the current resource URL is
   * returned. Otherwise, the URL is returned that was set using
   * setRef().
   *
   * \sa setRef(), WResource::url()
   */
  const std::string& ref() const { return ref_; }

  void setRefInternalPath(const std::string& path);

  /*! \brief Sets a destination resource.
   *
   * This method can be used to make the button behave like a WAnchor
   * (or conversely, an anchor look like a button) and redirect to
   * another resource when clicked.
   *
   * A resource specifies application-dependent content, which may be
   * generated by your application on demand.
   *
   * This sets the \p resource as the destination of the button,
   * and is an alternative to setRef(). The resource may be cleared by
   * passing \p resource = \c 0.
   *
   * The button does not assume ownership of the resource.
   *
   * \sa setRef()
   */
  void setResource(WResource *resource);

  /*! \brief Returns the destination resource.
   *
   * Returns \c 0 if no resource has been set.
   *
   * \sa setResource()
   */
  WResource *resource() const { return resource_; }

  virtual void refresh();

private:
  static const int BIT_TEXT_CHANGED = 0;
  static const int BIT_ICON_CHANGED = 1;
  static const int BIT_ICON_RENDERED = 2;
  static const int BIT_REF_CHANGED = 3;
  static const int BIT_REF_INTERNAL_PATH = 4;

  WString        text_;
  std::string    icon_;
  std::string    ref_;
  WResource     *resource_;
  std::bitset<5> flags_;

  JSlot         *redirectJS_;

protected:
  virtual void           updateDom(DomElement& element, bool all);
  virtual DomElementType domElementType() const;
  virtual void           propagateRenderOk(bool deep);
  virtual void           getDomChanges(std::vector<DomElement *>& result,
				       WApplication *app);

private:
  void doRedirect();
  void resourceChanged();
};

}

#endif // WPUSHBUTTON_H_
