/*
 * Copyright (C) 2008 Canonical Ltd
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 as
 * published by the Free Software Foundation.
 *
 * This program 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 * Authored by Neil Jagdish Patel <neil.patel@canonical.com>
 *
 */
/**
 * SECTION:ctk-button
 * @short_description: A widget that presents a button interface
 * @include ctk-button.h
 *
 * #CtkButton is used to present a classical "button" interface and to provide
 * appropriate signals when it is clicked on
 * Typically a CtkButton will/can hold a #CtkText and #CtkImage at the same time.
 */

#if HAVE_CONFIG_H
#include <config.h>
#endif

#include "ctk-button.h"

#include <glib.h>
#include <math.h>

#include <clutk/ctk-focusable.h>
#include <clutk/ctk-text.h>

#include "ctk-private.h"

G_DEFINE_TYPE (CtkButton, ctk_button, CTK_TYPE_BIN);

#define CTK_BUTTON_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj),\
  CTK_TYPE_BUTTON, \
  CtkButtonPrivate))

#define GFLOAT_FROM_PANGO_UNIT(x) (pango_units_to_double (x))
#define GFLOAT_TO_PANGO_UNIT(x) (pango_units_from_double (x))

struct _CtkButtonPrivate
{
  CtkOrientation orientation;
  ClutterActor *image;
  ClutterActor *text;

  gboolean entered;
  gboolean button_pressed;
  guint32  last_press_time;
};

enum
{
  PROP_0,
  PROP_LABEL,
  PROP_IMAGE,
  PROP_ORIENTATION
};

enum
{
  CLICKED,
  SHOW_CONTEXT_MENU,

  LAST_SIGNAL
};

/* Globals */
static guint _button_signals[LAST_SIGNAL] = { 0 };

/* Forwards */
static gboolean on_button_release (ClutterActor         *actor,
                                   ClutterButtonEvent   *event);
static gboolean on_button_press   (ClutterActor         *actor,
                                   ClutterButtonEvent   *event);
static gboolean on_enter          (ClutterActor         *actor,
                                   ClutterCrossingEvent *event);
static gboolean on_leave          (ClutterActor         *actor,
                                   ClutterCrossingEvent *event);

static void     ctk_button_focus_activate (CtkFocusable   *focusable);

/* GObject stuff */
static void
set_property (GObject      *object,
              guint         prop_id,
              const GValue *value,
              GParamSpec   *pspec)
{
  CtkButton *button = CTK_BUTTON (object);

  switch (prop_id)
    {
    case PROP_LABEL:
      ctk_button_set_label (button, g_value_get_string (value));
      break;

    case PROP_IMAGE:
      ctk_button_set_image (button, g_value_get_object (value));
      break;

    case PROP_ORIENTATION:
      ctk_button_set_orientation (button, g_value_get_int (value));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
get_property (GObject      *object,
              guint         prop_id,
              GValue       *value,
              GParamSpec   *pspec)
{
  CtkButton *button = CTK_BUTTON (object);

  switch (prop_id)
    {
    case PROP_LABEL:
      g_value_set_string (value, ctk_button_get_label (button));
      break;

    case PROP_IMAGE:
      g_value_set_object (value, ctk_button_get_image (button));
      break;

    case PROP_ORIENTATION:
      g_value_set_int (value, ctk_button_get_orientation (button));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
ctk_button_finalize (GObject *object)
{
  CtkButtonPrivate *priv = CTK_BUTTON (object)->priv;

  if (priv->image)
    {
      clutter_actor_unparent (priv->image);
      priv->image = NULL;
    }
  if (priv->text)
    {
      clutter_actor_unparent (priv->text);
      priv->text = NULL;
    }

  G_OBJECT_CLASS (ctk_button_parent_class)->finalize (object);
}

static void
get_preferred_width (ClutterActor *actor,
                     gfloat   for_height,
                     gfloat  *min_width,
                     gfloat  *nat_width)
{
  CtkButtonPrivate *priv = CTK_BUTTON (actor)->priv;
  ClutterActor     *child;
  CtkPadding        padding;

  ctk_actor_get_padding (CTK_ACTOR (actor), &padding);

  child = ctk_bin_get_child (CTK_BIN (actor));
  if (child)
    {
      clutter_actor_get_preferred_width (child, for_height, min_width, nat_width);

      if (min_width)
        *min_width += padding.left + padding.right;
      if (nat_width)
        *nat_width += padding.left + padding.right;
      return;
    }

  if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
    {
      gfloat          nwidth = 0;
      PangoLayout    *layout;
      PangoRectangle  log_rect = { 0 };

      clutter_actor_get_preferred_width (priv->image,
                                         for_height - padding.top - padding.bottom,
                                         NULL, &nwidth);

      nwidth += padding.left + padding.right;
      nwidth += 12.0;

      clutter_text_set_line_wrap (CLUTTER_TEXT (priv->text), FALSE);
      layout = clutter_text_get_layout (CLUTTER_TEXT (priv->text));
      pango_layout_get_extents (layout, NULL, &log_rect);

      nwidth += GFLOAT_FROM_PANGO_UNIT (log_rect.width);

      nwidth = MAX (nwidth, GFLOAT_FROM_PANGO_UNIT (log_rect.width));

      if (min_width)
        *min_width = nwidth;
      if (nat_width)
        *nat_width = nwidth;
    }
  else
    {
      gfloat nwidth = 0;

      clutter_actor_get_preferred_width (priv->image, -1, NULL, &nwidth);
      nwidth *= 2; /* This is so arbitrary */
      nwidth += padding.left + padding.right;

      if (min_width)
        *min_width = nwidth;
      if (nat_width)
        *nat_width = nwidth;
    }
}

static void
get_preferred_height (ClutterActor *actor,
                      gfloat   for_width,
                      gfloat  *min_height,
                      gfloat  *nat_height)
{
  CtkButtonPrivate *priv = CTK_BUTTON (actor)->priv;
  ClutterActor     *child;
  CtkPadding        padding;

  ctk_actor_get_padding (CTK_ACTOR (actor), &padding);

  child = ctk_bin_get_child (CTK_BIN (actor));
  if (child)
    {
      clutter_actor_get_preferred_height (child, for_width, min_height,
                                          nat_height);

      if (min_height)
        *min_height += padding.top + padding.bottom;
      if (nat_height)
        *nat_height += padding.top + padding.bottom;
      return;
    }

  if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
    {
      gfloat nheight = 0;

      clutter_actor_get_preferred_height (priv->image,
                                          for_width - padding.left - padding.right,
                                          NULL, &nheight);
      nheight += padding.top + padding.bottom;

      if (min_height)
        *min_height = nheight;
      if (nat_height)
        *nat_height = nheight;
    }
  else
    {
      gfloat     nheight = 0;
      PangoLayout    *layout;
      PangoRectangle  log_rect;

      clutter_actor_get_preferred_height (priv->image,
                                          for_width - padding.left - padding.right,
                                          NULL, &nheight);

      nheight += padding.top + padding.right;
      nheight += 12.0;

      layout = clutter_text_get_layout (CLUTTER_TEXT (priv->text));
      pango_layout_set_width (layout,
                              GFLOAT_TO_PANGO_UNIT (for_width - padding.right - padding.left));
      pango_layout_get_extents (layout, NULL, &log_rect);

      nheight += GFLOAT_FROM_PANGO_UNIT (log_rect.height);

      if (min_height)
        *min_height = nheight;
      if (nat_height)
        *nat_height = nheight;
    }
}

static void
allocate (ClutterActor          *actor,
          const ClutterActorBox *box,
          ClutterAllocationFlags flags)
{
  CtkButtonPrivate *priv = CTK_BUTTON (actor)->priv;
  CtkPadding  padding;
  ClutterActor    *child;
  gfloat      real_width;
  gfloat      real_height;
  gfloat      x;
  gfloat      y;
  GtkTextDirection direction;

  CLUTTER_ACTOR_CLASS (ctk_button_parent_class)->allocate (actor,box, flags);

  ctk_actor_get_padding (CTK_ACTOR (actor), &padding);
  direction = ctk_actor_get_default_direction ();
  real_width = box->x2 - box->x1 - padding.left - padding.right;
  real_height = box->y2 - box->y1 - padding.top - padding.bottom;

  /* If we contain a child, then just act like a normal bin */
  child = ctk_bin_get_child (CTK_BIN (actor));
  if (child)
    {
      ClutterActorBox child_box;

      child_box.x1 = floor (padding.left);
      child_box.x2 = floor (padding.left + real_width);
      child_box.y1 = floor (padding.top);
      child_box.y2 = floor (padding.top + real_height);

      clutter_actor_allocate (child, &child_box, flags);

      clutter_actor_hide (priv->image);
      clutter_actor_hide (priv->text);
      return;
    }

  x = padding.left;
  y = padding.top;

  if (priv->image)
    {
      ClutterActorBox child_box;

      if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
        {
          gfloat nat_width;

          clutter_actor_get_preferred_width (priv->image, real_height,
                                             NULL, &nat_width);
          child_box.x1 = floor (x);
          child_box.x2 = floor (x + nat_width);
          child_box.y1 = floor (y);
          child_box.y2 = floor (y + real_height);

          if (direction == GTK_TEXT_DIR_RTL)
            {
              child_box.x1 = floor (padding.left + real_width - nat_width);
              child_box.x2 = floor (child_box.x1 + nat_width);
            }
          x += nat_width + 12.0;
        }
      else
        {
          gfloat nat_height;

          clutter_actor_get_preferred_height (priv->image, real_width,
                                              NULL, &nat_height);
          child_box.x1 = floor (x);
          child_box.x2 = floor (x + real_width);
          child_box.y1 = floor (y);
          child_box.y2 = floor (y + nat_height);

          y += nat_height + 12.0;
        }
      clutter_actor_allocate (priv->image, &child_box, flags);
    }

  if (priv->text)
    {
      ClutterActorBox child_box;
      PangoLayout    *layout;
      PangoRectangle  log_rect;

      layout = clutter_text_get_layout (CLUTTER_TEXT (priv->text));
      pango_layout_get_extents (layout, NULL, &log_rect);

      if (priv->orientation == CTK_ORIENTATION_HORIZONTAL)
        {
          gfloat    text_height;

          text_height = GFLOAT_FROM_PANGO_UNIT (log_rect.height);

          child_box.x1 = floor (x);
          child_box.x2 = floor (x + (real_width - x));
          child_box.y1 = floor (y + ((real_height)/2-(text_height/2)));
          child_box.y2 = floor (y + (real_height - y));

          if (direction == GTK_TEXT_DIR_RTL)
            child_box.x1 = (box->x2-box->x1) - x -
                           (GFLOAT_FROM_PANGO_UNIT (log_rect.width));
        }
      else
        {
          gfloat text_width = GFLOAT_FROM_PANGO_UNIT (log_rect.width);
          gint lines = pango_layout_get_line_count (layout);

          child_box.x1 = floor (x);
          child_box.x2 = floor (x + (real_width ));
          child_box.y1 = floor (y);
          child_box.y2 = floor (y + (real_height - y));

          if (lines == 1)
            {
              child_box.x1 = floor (x + ((real_width)/2) - (text_width/2));
              child_box.x2 = floor (GFLOAT_FROM_PANGO_UNIT (text_width));
            }

        }
      clutter_actor_allocate (priv->text, &child_box, flags);
      clutter_actor_show (priv->text);
    }
}

static void
paint (ClutterActor *actor)
{
  CtkActor *ctk_actor = CTK_ACTOR (actor);
  GSList   *effects   = NULL;

  if (!ctk_actor_get_effects_painting (ctk_actor)
      && (effects = ctk_actor_get_effects (ctk_actor)))
    {
      GSList *e;

      ctk_actor_set_effects_painting (ctk_actor, TRUE);

      for (e = effects; e; e = e->next)
        {
          gboolean last_effect = e->next ? FALSE : TRUE;
          ctk_effect_paint (e->data, paint, last_effect);
        }

      ctk_actor_set_effects_painting (ctk_actor, FALSE);
    }
  else
    {
      CtkButtonPrivate *priv = CTK_BUTTON (actor)->priv;
      ClutterActor *child;

      CLUTTER_ACTOR_CLASS (ctk_button_parent_class)->paint (actor);

      child = ctk_bin_get_child (CTK_BIN (actor));
      if (child)
        {
          clutter_actor_paint (child);
          return;
        }
      else
        {
          clutter_actor_paint (priv->image);
          clutter_actor_paint (priv->text);
        }
    }
  ctk_actor_set_damaged (ctk_actor, FALSE);
}

static void
pick (ClutterActor *actor, const ClutterColor *color)
{
  CLUTTER_ACTOR_CLASS (ctk_button_parent_class)->pick (actor, color);
}

static void
map (ClutterActor *actor)
{
  CtkButtonPrivate *priv = CTK_BUTTON (actor)->priv;

  CLUTTER_ACTOR_CLASS (ctk_button_parent_class)->map (actor);

  clutter_actor_map (priv->image);
  clutter_actor_map (priv->text);
}

static void
unmap (ClutterActor *actor)
{
  CtkButtonPrivate *priv = CTK_BUTTON (actor)->priv;

  CLUTTER_ACTOR_CLASS (ctk_button_parent_class)->unmap (actor);

  clutter_actor_unmap (priv->image);
  clutter_actor_unmap (priv->text);
}

static void
ctk_button_class_init (CtkButtonClass *klass)
{
  GObjectClass      *obj_class = G_OBJECT_CLASS (klass);
  ClutterActorClass *act_class = CLUTTER_ACTOR_CLASS (klass);
  GParamSpec        *pspec;

  obj_class->finalize     = ctk_button_finalize;
  obj_class->set_property = set_property;
  obj_class->get_property = get_property;

  act_class->button_release_event = on_button_release;
  act_class->button_press_event   = on_button_press;
  act_class->enter_event          = on_enter;
  act_class->leave_event          = on_leave;
  act_class->get_preferred_width  = get_preferred_width;
  act_class->get_preferred_height = get_preferred_height;
  act_class->allocate             = allocate;
  act_class->paint                = paint;
  act_class->pick                 = pick;
  act_class->map                  = map;
  act_class->unmap                = unmap;

  /* Install class properties */
  pspec = g_param_spec_string ("label", "label",
                               "Text of the label inside the button",
                               NULL, CTK_PARAM_READWRITE);
  g_object_class_install_property (obj_class, PROP_LABEL, pspec);

  pspec = g_param_spec_object ("image", "image",
                               "LabelImage shown inside the ctk",
                               CTK_TYPE_IMAGE, CTK_PARAM_READWRITE);
  g_object_class_install_property (obj_class, PROP_IMAGE, pspec);

  pspec = g_param_spec_int ("orientation", "orientation",
                            "Orientation of the button and it's contents",
                            CTK_ORIENTATION_HORIZONTAL,
                            CTK_ORIENTATION_VERTICAL,
                            CTK_ORIENTATION_HORIZONTAL,
                            CTK_PARAM_READWRITE);
  g_object_class_install_property (obj_class, PROP_ORIENTATION, pspec);

  /* Install class signals */
  _button_signals[CLICKED] =
    g_signal_new ("clicked",
                  G_OBJECT_CLASS_TYPE (obj_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (CtkButtonClass, clicked),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__VOID,
                  G_TYPE_NONE, 0);

  _button_signals[SHOW_CONTEXT_MENU] =
    g_signal_new ("show-context-menu",
                  G_OBJECT_CLASS_TYPE (obj_class),
                  G_SIGNAL_RUN_LAST,
                  G_STRUCT_OFFSET (CtkButtonClass,show_context_menu),
                  NULL, NULL,
                  g_cclosure_marshal_VOID__UINT,
                  G_TYPE_NONE, 1, G_TYPE_UINT);

  g_type_class_add_private (obj_class, sizeof (CtkButtonPrivate));
}

static void
ctk_button_init (CtkButton *button)
{
  CtkButtonPrivate  *priv;
  CtkFocusableIface *iface;

  priv = button->priv = CTK_BUTTON_GET_PRIVATE (button);

  iface = CTK_FOCUSABLE_GET_IFACE (button);
  iface->activate = ctk_button_focus_activate;

  priv->orientation    = CTK_ORIENTATION_HORIZONTAL;
  priv->entered        = FALSE;
  priv->button_pressed = FALSE;

  priv->text = ctk_text_new (NULL);
  clutter_text_set_line_wrap (CLUTTER_TEXT (priv->text), TRUE);
  clutter_text_set_line_wrap_mode (CLUTTER_TEXT (priv->text),
                                   PANGO_WRAP_WORD_CHAR);
  clutter_actor_set_parent (priv->text, CLUTTER_ACTOR (button));
  clutter_actor_show (priv->text);

  priv->image = ctk_image_new (48);
  clutter_actor_set_parent (priv->image, CLUTTER_ACTOR (button));
  clutter_actor_show (priv->image);

  clutter_actor_set_reactive (CLUTTER_ACTOR (button), TRUE);
}

/**
 * ctk_button_new:
 * @orientation: a CtkOrientation defining horizontal or virtical orientation
 *
 * Creates a new CtkButton object
 *
 * returns: A new CtkButton object
 */
ClutterActor *
ctk_button_new (CtkOrientation orientation)
{
  return g_object_new (CTK_TYPE_BUTTON,
                       "orientation", orientation,
                       NULL);
}

/*
 * Private methods
 */
static gboolean
on_button_release (ClutterActor         *actor,
                   ClutterButtonEvent   *event)
{
#define CLICK_TIMEOUT 500
  CtkButtonPrivate *priv;

  g_return_val_if_fail (CTK_IS_BUTTON (actor), FALSE);
  priv = CTK_BUTTON (actor)->priv;

  priv->button_pressed = FALSE;
  ctk_actor_set_state (CTK_ACTOR (actor), CTK_STATE_PRELIGHT);

  if (event->button == 1
      && ((event->time - priv->last_press_time) < CLICK_TIMEOUT))
    {
      g_signal_emit (actor, _button_signals[CLICKED], 0);
      return TRUE;
    }

  return FALSE;
}

static gboolean
on_button_press (ClutterActor       *actor,
                 ClutterButtonEvent *event)
{
  CtkButtonPrivate *priv;

  g_return_val_if_fail (CTK_IS_BUTTON (actor), FALSE);
  priv = CTK_BUTTON (actor)->priv;

  priv->button_pressed = TRUE;

  ctk_focusable_set_focused (CTK_FOCUSABLE (actor), TRUE);
  ctk_actor_set_state (CTK_ACTOR (actor), CTK_STATE_ACTIVE);

  if (event->button == 1)
    {
      priv->last_press_time = event->time;
    }
  else if (event->button == 3)
    {
      g_signal_emit (actor, _button_signals[SHOW_CONTEXT_MENU], 0, event->time);
      return TRUE;
    }

  return FALSE;
}

static gboolean
on_enter (ClutterActor         *actor,
          ClutterCrossingEvent *event)
{
  CtkButtonPrivate *priv;

  g_return_val_if_fail (CTK_IS_BUTTON (actor), FALSE);
  priv = CTK_BUTTON (actor)->priv;

  CLUTTER_ACTOR_CLASS (ctk_button_parent_class)->enter_event (actor, event);

  priv->entered = TRUE;

  ctk_actor_set_state (CTK_ACTOR (actor), CTK_STATE_PRELIGHT);

  return FALSE;
}

static gboolean
on_leave (ClutterActor         *actor,
          ClutterCrossingEvent *event)
{
  CtkButtonPrivate *priv;

  g_return_val_if_fail (CTK_IS_BUTTON (actor), FALSE);
  priv = CTK_BUTTON (actor)->priv;

  CLUTTER_ACTOR_CLASS (ctk_button_parent_class)->leave_event (actor, event);

  priv->entered = FALSE;

  ctk_actor_set_state (CTK_ACTOR (actor), CTK_STATE_NORMAL);

  return FALSE;
}

static void
ctk_button_focus_activate (CtkFocusable   *focusable)
{
  g_return_if_fail (CTK_IS_BUTTON (focusable));

  g_signal_emit (focusable, _button_signals[CLICKED], 0);
}

/*
 * Public methods
 */
/**
 * ctk_button_set_label:
 * @button: a CtkButton
 * @label: A string containing the label text
 *
 * Sets the label of the button to @label
 * This will clear any previously set labels
 */
void
ctk_button_set_label (CtkButton  *button,
                      const gchar     *label)
{
  g_return_if_fail (CTK_IS_BUTTON (button));

  if (button->priv->text)
    {
      clutter_text_set_text (CLUTTER_TEXT (button->priv->text), label);
      clutter_actor_show (button->priv->text);
      clutter_actor_queue_relayout (CLUTTER_ACTOR (button));

      g_object_notify (G_OBJECT (button), "label");
    }
}


/**
 * ctk_button_get_label:
 * @button: a CtkButton
 *
 * This will fetch the text from the label of @button, if the label has not been
 * set with ctk_button_set_label() then this will return NULL
 *
 * returns: gchar string representing the text or NULL
 */
const gchar *
ctk_button_get_label (CtkButton  *button)
{
  g_return_val_if_fail (CTK_IS_BUTTON (button), NULL);

  if (button->priv->text)
    return clutter_text_get_text (CLUTTER_TEXT (button->priv->text));

  return NULL;
}

/**
 * ctk_button_set_image:
 * @button: A CtkButton
 * @image: A CtkImage to be attached to @button
 *
 * Attaches @image to @button with respect to the buttons Orientation
 */
void
ctk_button_set_image (CtkButton  *button,
                      CtkImage   *image)
{
  g_return_if_fail (CTK_IS_BUTTON (button));
  g_return_if_fail (CTK_IS_IMAGE (image));

  if (button->priv->image)
    {
      clutter_actor_unparent (button->priv->image);
    }
  button->priv->image = CLUTTER_ACTOR (image);
  clutter_actor_set_parent (CLUTTER_ACTOR (image), CLUTTER_ACTOR (button));

  g_object_notify (G_OBJECT (button), "image");

  if (CLUTTER_ACTOR_IS_VISIBLE (button))
    clutter_actor_queue_relayout (CLUTTER_ACTOR (button));
}

/**
 * ctk_button_get_image:
 * @button: A CtkButton
 *
 * returns the GtkImage that is attached to @button. see also: ctk_button_set_image()
 *
 * Returns: a CtkImage;
 */
CtkImage *
ctk_button_get_image (CtkButton  *button)
{
  g_return_val_if_fail (CTK_IS_BUTTON (button), NULL);

  return CTK_IMAGE (button->priv->image);
}

/**
 * ctk_button_set_text:
 * @button: A CtkButton
 * @text: a CtkText object to attach to @button
 *
 * Attaches @text to @button with respect to @button orientation
 */
void
ctk_button_set_text (CtkButton *button, CtkText *text)
{
  g_return_if_fail (CTK_IS_BUTTON (button));
  g_return_if_fail (CTK_IS_TEXT (text));

  if (button->priv->text)
    {
      clutter_actor_unparent (button->priv->text);
    }

  button->priv->text = CLUTTER_ACTOR (text);
  clutter_actor_set_parent (CLUTTER_ACTOR (text), CLUTTER_ACTOR (button));

  g_object_notify (G_OBJECT (button), "text");

  if (CLUTTER_ACTOR_IS_VISIBLE (button))
    clutter_actor_queue_relayout (CLUTTER_ACTOR (button));
}

/**
 * ctk_button_get_text:
 * @button: A CtkButton
 *
 * gets the CtkText object that is attached to @button. see also: ctk_button_set_text()
 *
 * Returns: a CtkText object;
 */
CtkText *
ctk_button_get_text (CtkButton *button)
{
  g_return_val_if_fail (CTK_IS_BUTTON (button), NULL);

  return CTK_TEXT (button->priv->text);
}

/**
 * ctk_button_set_orientation:
 * @button: A CtkButton
 * @orient: A CtkOrientation regarding @button orientation
 *
 * CtkButton can be orientated either horizontaly or vertically and can be set /
using this function, CTK_ORIENTATION_HORIZONTAL will prefer to line label/image /
in a row, whist CTK_ORIENTATION_VERTICAL will prefer to stack in a column.
 * see also: #CtkOrientation
 */
 void
ctk_button_set_orientation (CtkButton      *button,
                            CtkOrientation  orientation)
{
  g_return_if_fail (orientation == CTK_ORIENTATION_HORIZONTAL
                    || orientation == CTK_ORIENTATION_VERTICAL);

  if (button->priv->orientation != orientation)
    {
      button->priv->orientation = orientation;

      if (orientation == CTK_ORIENTATION_HORIZONTAL)
        {
          clutter_text_set_line_wrap (CLUTTER_TEXT (button->priv->text), FALSE);
        }
      else
        {
          clutter_text_set_line_wrap (CLUTTER_TEXT (button->priv->text), TRUE);
          clutter_text_set_line_alignment (CLUTTER_TEXT (button->priv->text),
                                           PANGO_ALIGN_CENTER);
        }

      clutter_actor_queue_relayout (CLUTTER_ACTOR (button));

      g_object_notify (G_OBJECT (button), "orientation");
    }
}

/**
 * ctk_button_get_orientation:
 * @button: A CtkButton
 *
 * Returns the orientation of @button. see also: ctk_button_set_orientation ()
 *
 * Returns: a CtkOrientation object
 */
CtkOrientation
ctk_button_get_orientation (CtkButton *button)
{
  g_return_val_if_fail (CTK_IS_BUTTON (button),
                        CTK_ORIENTATION_HORIZONTAL);

  return button->priv->orientation;
}
