Пример #1
0
static gboolean
mex_column_get_paint_volume (ClutterActor       *self,
                             ClutterPaintVolume *volume)
{
  MexColumnPrivate *priv = MEX_COLUMN (self)->priv;
  ClutterVertex v;

  if (!clutter_paint_volume_set_from_allocation (volume, self))
    return FALSE;

  if (priv->adjustment)
    {
      clutter_paint_volume_get_origin (volume, &v);
      v.y += priv->adjustment_value,
      clutter_paint_volume_set_origin (volume, &v);
    }

  return TRUE;
}
Пример #2
0
static void
mex_column_get_preferred_width (ClutterActor *actor,
                                gfloat        for_height,
                                gfloat       *min_width_p,
                                gfloat       *nat_width_p)
{
  GList *c;
  MxPadding padding;
  gfloat min_width = 0, nat_width = 0;

  MexColumn *self = MEX_COLUMN (actor);
  MexColumnPrivate *priv = self->priv;

  for_height = -1;

  if (priv->n_items > 0)
    {
      min_width = nat_width = 0;
      for_height /= (gfloat)priv->n_items;

      for (c = priv->children; c; c = c->next)
        {
          gfloat child_min_width, child_nat_width;
          ClutterActor *child = c->data;

          clutter_actor_get_preferred_width (child, for_height,
                                             &child_min_width,
                                             &child_nat_width);

          if (child_min_width > min_width)
            min_width = child_min_width;
          if (child_nat_width > nat_width)
            nat_width = child_nat_width;
        }
    }

  mx_widget_get_padding (MX_WIDGET (actor), &padding);

  if (min_width_p)
    *min_width_p = min_width + padding.left + padding.right;
  if (nat_width_p)
    *nat_width_p = nat_width + padding.left + padding.right;
}
Пример #3
0
static MxFocusable *
mex_column_accept_focus (MxFocusable *focusable,
                         MxFocusHint  hint)
{
  GList *link_;

  MexColumn *self = MEX_COLUMN (focusable);
  MexColumnPrivate *priv = self->priv;

  focusable = NULL;

  switch (hint)
    {
    case MX_FOCUS_HINT_FROM_LEFT:
    case MX_FOCUS_HINT_FROM_RIGHT:
    case MX_FOCUS_HINT_PRIOR:
      if (priv->current_focus &&
          (focusable = mx_focusable_accept_focus (
             MX_FOCUSABLE (priv->current_focus), hint)))
        break;
      /* If there's no prior focus, or the prior focus rejects focus,
       * try to just focus the first actor.
       */

    case MX_FOCUS_HINT_FIRST:
    case MX_FOCUS_HINT_FROM_ABOVE:
      if (priv->n_items)
        focusable = mx_focusable_accept_focus (
                       MX_FOCUSABLE (priv->children->data), hint);
      break;

    case MX_FOCUS_HINT_LAST:
    case MX_FOCUS_HINT_FROM_BELOW:
      link_ = g_list_last (priv->children);
      if (link_)
        focusable = mx_focusable_accept_focus (
                       MX_FOCUSABLE (link_->data), hint);
      break;
    }

  return focusable;
}
Пример #4
0
static void
mex_column_get_property (GObject    *object,
                         guint       prop_id,
                         GValue     *value,
                         GParamSpec *pspec)
{
  MxAdjustment *adjustment;
  MexColumn *self = MEX_COLUMN (object);

  switch (prop_id)
    {
    case PROP_LABEL:
      g_value_set_string (value, mex_column_get_label (self));
      break;

    case PROP_PLACEHOLDER_ACTOR:
      g_value_set_object (value, mex_column_get_placeholder_actor (self));
      break;

    case PROP_ICON_NAME:
      g_value_set_string (value, mex_column_get_icon_name (self));
      break;

    case PROP_HADJUST:
      mex_column_get_adjustments (MX_SCROLLABLE (self), &adjustment, NULL);
      g_value_set_object (value, adjustment);
      break;

    case PROP_VADJUST:
      mex_column_get_adjustments (MX_SCROLLABLE (self), NULL, &adjustment);
      g_value_set_object (value, adjustment);
      break;

    case PROP_COLLAPSE_ON_FOCUS:
      g_value_set_boolean (value, mex_column_get_collapse_on_focus (self));
      break;

    default:
      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}
Пример #5
0
static void
mex_column_view_pick (ClutterActor *actor, const ClutterColor *color)
{
  MexColumnView *self = MEX_COLUMN_VIEW (actor);
  MexColumnViewPrivate *priv = self->priv;

  CLUTTER_ACTOR_CLASS (mex_column_view_parent_class)->pick (actor, color);

  /* Don't pick children when we don't have focus */
  if (!priv->has_focus)
    return;

  if (mex_column_is_empty (MEX_COLUMN (priv->column)))
    {
      if (priv->placeholder_actor)
        clutter_actor_paint (priv->placeholder_actor);
    }
  else
    clutter_actor_paint (priv->scroll);

  clutter_actor_paint (priv->header);
}
Пример #6
0
static void
mex_column_get_adjustments (MxScrollable  *scrollable,
                            MxAdjustment **hadjust,
                            MxAdjustment **vadjust)
{
  MexColumnPrivate *priv = MEX_COLUMN (scrollable)->priv;

  if (hadjust)
    *hadjust = NULL;

  if (!vadjust)
    return;

  if (!priv->adjustment)
    {
      *vadjust = mx_adjustment_new ();
      mx_scrollable_set_adjustments (scrollable, NULL, *vadjust);
      g_object_unref (*vadjust);
    }
  else
    *vadjust = priv->adjustment;
}
Пример #7
0
static void
mex_column_dispose (GObject *object)
{
  MexColumn *self = MEX_COLUMN (object);
  MexColumnPrivate *priv = self->priv;

  if (priv->adjustment)
    {
      g_signal_handlers_disconnect_by_func (priv->adjustment,
                                            clutter_actor_queue_redraw,
                                            object);
      g_object_unref (priv->adjustment);
      priv->adjustment = NULL;
    }

  if (priv->header)
    {
      /* The header includes the label and icon */
      clutter_actor_destroy (priv->header);
      priv->header = NULL;
    }

  if (priv->expand_timeline)
    {
      g_object_unref (priv->expand_timeline);
      priv->expand_timeline = NULL;
    }

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

  while (priv->children)
    clutter_actor_destroy (CLUTTER_ACTOR (priv->children->data));

  G_OBJECT_CLASS (mex_column_parent_class)->dispose (object);
}
Пример #8
0
static void
mex_column_add (ClutterContainer *container,
                ClutterActor     *actor)
{
  MexColumn *self = MEX_COLUMN (container);
  MexColumnPrivate *priv = self->priv;

  if (priv->sort_func)
    priv->children =
      g_list_insert_sorted_with_data (priv->children, actor,
                                      (GCompareDataFunc)priv->sort_func,
                                      priv->sort_data);
  else
    priv->children = g_list_append (priv->children, actor);

  priv->n_items ++;

  /* Expand/collapse any drawer that gets added as appropriate */
  if (MEX_IS_EXPANDER_BOX (actor))
    {
      g_signal_connect (actor, "notify::open",
                        G_CALLBACK (expander_box_open_notify), container);

      mex_expander_box_set_important (MEX_EXPANDER_BOX (actor),
                                      priv->has_focus);

      if (MEX_IS_CONTENT_BOX (actor))
        {
          ClutterActor *tile =
            mex_content_box_get_tile (MEX_CONTENT_BOX (actor));
          mex_tile_set_important (MEX_TILE (tile), priv->has_focus);
        }
    }

  clutter_actor_set_parent (actor, CLUTTER_ACTOR (self));

  g_signal_emit_by_name (self, "actor-added", actor);
}
Пример #9
0
static void
mex_column_pick (ClutterActor *actor, const ClutterColor *color)
{
  GList *c;
  gdouble value;
  MxPadding padding;
  ClutterActorBox box;

  MexColumn *self = MEX_COLUMN (actor);
  MexColumnPrivate *priv = self->priv;

  CLUTTER_ACTOR_CLASS (mex_column_parent_class)->pick (actor, color);

  /* Don't pick children when we don't have focus */
  if (!priv->has_focus)
    return;

  mx_widget_get_padding (MX_WIDGET (actor), &padding);
  clutter_actor_get_allocation_box (actor, &box);
  if (priv->adjustment)
    value = mx_adjustment_get_value (priv->adjustment);
  else
    value = 0;

  cogl_clip_push_rectangle (padding.left,
                            clutter_actor_get_height (priv->header) +
                              padding.top + value,
                            box.x2 - box.x1 - padding.right,
                            box.y2 - box.y1 - padding.bottom + value);

  for (c = priv->children; c; c = c->next)
    clutter_actor_paint (c->data);

  cogl_clip_pop ();

  clutter_actor_paint (priv->header);
}
Пример #10
0
MexColumn *
mex_column_view_get_column (MexColumnView *column)
{
  g_return_val_if_fail (MEX_IS_COLUMN_VIEW (column), NULL);
  return MEX_COLUMN (column->priv->column);
}
Пример #11
0
static void
mex_column_allocate (ClutterActor          *actor,
                     const ClutterActorBox *box,
                     ClutterAllocationFlags flags)
{
  ClutterActorBox child_box;
  MxPadding padding;
  GList *c;

  MexColumn *column = MEX_COLUMN (actor);
  MexColumnPrivate *priv = column->priv;

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

  mx_widget_get_padding (MX_WIDGET (actor), &padding);

  child_box.x1 = padding.left;
  child_box.x2 = box->x2 - box->x1 - padding.right;
  child_box.y1 = padding.top;
  child_box.y2 = box->y2 - box->y1 - padding.bottom;

  if (priv->n_items)
    {
      /* Calculate child height multiplier */
      gfloat width, pref_height, avail_height, ratio, remainder;

      if (!priv->adjustment)
        {
          /* Find out the height available for each actor as a ratio of
           * their preferred height.
           */
          clutter_actor_get_preferred_height (actor, box->x2 - box->x1,
                                              NULL, &pref_height);
          pref_height -= padding.top + padding.bottom;

          avail_height = child_box.y2 - child_box.y1;

          ratio = avail_height / pref_height;
        }
      else
        ratio = 1;

      /* Allocate children */
      remainder = 0;
      width = child_box.x2 - child_box.x1;

      for (c = priv->children; c; c = c->next)
        {
          gfloat min_height, nat_height, height;
          ClutterActor *child = c->data;

          clutter_actor_get_preferred_height (child, width,
                                              &min_height, &nat_height);

          /* Calculate the allocatable height and keep an accumulator so
           * when we round to a pixel, we don't end up with a lot of
           * empty space at the end of the actor.
           */
          height = MAX (min_height, nat_height / ratio);
          remainder += (height - (gint)height);
          height = (gint)height;

          while (remainder >= 1.f)
            {
              height += 1.f;
              remainder -= 1.f;
            }

          /* Allocate the child */
          child_box.y2 = child_box.y1 + height;
          clutter_actor_allocate (child, &child_box, flags);

          /* Set the top position of the next child box */
          child_box.y1 = child_box.y2;
        }
    }

  /* Make sure the adjustment reflects the column's allocation */
  if (priv->adjustment)
    {
      gdouble page_size = box->y2 - box->y1 - padding.top - padding.bottom;
      mx_adjustment_set_values (priv->adjustment,
                                mx_adjustment_get_value (priv->adjustment),
                                0.0,
                                child_box.y2 - padding.top,
                                1.0,
                                page_size,
                                page_size);
    }
}
Пример #12
0
static void
mex_column_get_preferred_height (ClutterActor *actor,
                                 gfloat        for_width,
                                 gfloat       *min_height_p,
                                 gfloat       *nat_height_p)
{
  GList *c;
  gfloat min_height, nat_height;
  MxPadding padding;

  MexColumn *self = MEX_COLUMN (actor);
  MexColumnPrivate *priv = self->priv;

  mx_widget_get_padding (MX_WIDGET (actor), &padding);

  if (for_width >= 0)
    for_width = MAX (0, for_width - padding.left - padding.right);

  clutter_actor_get_preferred_height (priv->header,
                                      for_width,
                                      NULL,
                                      &min_height);
  nat_height = min_height;

  if (priv->n_items < 1)
    {
      gfloat min_placeholder, nat_placeholder;

      clutter_actor_get_preferred_height (priv->placeholder_actor,
                                          for_width,
                                          &min_placeholder,
                                          &nat_placeholder);

      min_height += min_placeholder;
      nat_height += nat_placeholder;
    }
  else
    {
      gfloat child_min_height, child_nat_height;

      for (c = priv->children; c; c = c->next)
        {
          ClutterActor *child = c->data;

          clutter_actor_get_preferred_height (child, for_width,
                                              &child_min_height,
                                              &child_nat_height);

          min_height += child_min_height;
          nat_height += child_nat_height;

          if (priv->adjustment)
            break;
        }
    }

  if (min_height_p)
    *min_height_p = min_height + padding.top + padding.bottom;
  if (nat_height_p)
    *nat_height_p += nat_height + padding.top + padding.bottom;
}
Пример #13
0
static void
mex_column_get_preferred_width (ClutterActor *actor,
                                gfloat        for_height,
                                gfloat       *min_width_p,
                                gfloat       *nat_width_p)
{
  GList *c;
  MxPadding padding;
  gfloat min_width, nat_width;
  gfloat min_header, nat_header;
  gfloat min_placeholder, nat_placeholder;

  MexColumn *self = MEX_COLUMN (actor);
  MexColumnPrivate *priv = self->priv;

  clutter_actor_get_preferred_width (priv->header,
                                     -1,
                                     &min_header,
                                     &nat_header);

  if (priv->adjustment)
    for_height = -1;
  else if (for_height >= 0)
    {
      gfloat height;
      clutter_actor_get_preferred_height (priv->header, -1, NULL, &height);
      for_height = MAX (0, for_height - height);
    }

  if (priv->n_items < 1)
    {
      if (priv->placeholder_actor)
        {
          clutter_actor_get_preferred_width (priv->placeholder_actor,
                                             for_height,
                                             &min_placeholder,
                                             &nat_placeholder);

          min_width = MAX (min_header, min_placeholder);
          nat_width = MAX (min_header, nat_placeholder);
        }
      else
        {
          min_width = min_header;
          nat_width = nat_header;
        }
    }
  else
    {
      min_width = nat_width = 0;
      for_height /= (gfloat)priv->n_items;

      for (c = priv->children; c; c = c->next)
        {
          gfloat child_min_width, child_nat_width;
          ClutterActor *child = c->data;

          clutter_actor_get_preferred_width (child, for_height,
                                             &child_min_width,
                                             &child_nat_width);

          if (child_min_width > min_width)
            min_width = child_min_width;
          if (child_nat_width > nat_width)
            nat_width = child_nat_width;
        }

      if (min_header > min_width)
        min_width = min_header;
      if (min_header > nat_width)
        nat_width = min_header;
    }

  mx_widget_get_padding (MX_WIDGET (actor), &padding);

  if (min_width_p)
    *min_width_p = min_width + padding.left + padding.right;
  if (nat_width_p)
    *nat_width_p = nat_width + padding.left + padding.right;
}
Пример #14
0
static MxFocusable *
mex_column_move_focus (MxFocusable      *focusable,
                       MxFocusDirection  direction,
                       MxFocusable      *from)
{
  MxFocusHint hint;

  GList *link_ = NULL;
  MexColumn *self = MEX_COLUMN (focusable);
  MexColumnPrivate *priv = self->priv;

  focusable = NULL;

  if ((ClutterActor *)from == priv->header)
    {
      if (((direction == MX_FOCUS_DIRECTION_NEXT) ||
           (direction == MX_FOCUS_DIRECTION_DOWN)) &&
          priv->n_items)
        {
          hint = (direction == MX_FOCUS_DIRECTION_NEXT) ?
            MX_FOCUS_HINT_FIRST : MX_FOCUS_HINT_FROM_ABOVE;
          if ((focusable = mx_focusable_accept_focus (
                 MX_FOCUSABLE (priv->children->data), hint)))
            {
              priv->current_focus = priv->children->data;
              return focusable;
            }
        }
      else
        return NULL;
    }

  link_ = g_list_find (priv->children, from);
  if (!link_)
    return NULL;

  switch (direction)
    {
    case MX_FOCUS_DIRECTION_PREVIOUS:
    case MX_FOCUS_DIRECTION_UP:
      hint = (direction == MX_FOCUS_DIRECTION_PREVIOUS) ?
        MX_FOCUS_HINT_LAST : MX_FOCUS_HINT_FROM_BELOW;
      link_ = g_list_previous (link_);

      if (!link_)
        {
          if ((focusable = mx_focusable_accept_focus (
                 MX_FOCUSABLE (priv->header), hint)))
            priv->current_focus = priv->header;
        }
      else if ((focusable = mx_focusable_accept_focus (
                  MX_FOCUSABLE (link_->data), hint)))
        priv->current_focus = link_->data;
      break;

    case MX_FOCUS_DIRECTION_NEXT:
    case MX_FOCUS_DIRECTION_DOWN:
      hint = (direction == MX_FOCUS_DIRECTION_NEXT) ?
        MX_FOCUS_HINT_FIRST : MX_FOCUS_HINT_FROM_ABOVE;
      link_ = g_list_next (link_);

      if (link_ && (focusable = mx_focusable_accept_focus (
                     MX_FOCUSABLE (link_->data), hint)))
        priv->current_focus = link_->data;
      break;

    case MX_FOCUS_DIRECTION_OUT:
      if (from &&
          (clutter_actor_get_parent (CLUTTER_ACTOR (from)) ==
           CLUTTER_ACTOR (self)))
        priv->current_focus = CLUTTER_ACTOR (from);
      break;

    default:
      break;
    }

  return focusable;
}