Пример #1
0
static void
mx_combo_box_update_menu (MxComboBox *box)
{
  MxComboBoxPrivate *priv = box->priv;
  GSList *l;
  gint index;
  MxMenu *menu;

  menu = mx_widget_get_menu (MX_WIDGET (box));
  if (!menu)
    return;

  mx_menu_remove_all (menu);

  for (index = 0, l = priv->actions; l; l = g_slist_next (l), index++)
    {
      MxAction *action;

      action = (MxAction *)l->data;
      g_object_set_data ((GObject*) action, "index", GINT_TO_POINTER (index));

      mx_menu_add_action (menu, action);
    }

  /* queue a relayout so the combobox size can match the new menu */
  clutter_actor_queue_relayout ((ClutterActor*) box);
}
Пример #2
0
static gboolean
mx_combo_box_open_menu (MxComboBox *actor)
{
  ClutterActor *menu;

  menu = (ClutterActor *) mx_widget_get_menu (MX_WIDGET (actor));
  if (!menu)
    return FALSE;

  clutter_actor_show (menu);

  return TRUE;
}
Пример #3
0
static void
mx_combo_box_style_changed (MxComboBox *combo, MxStyleChangedFlags flags)
{
  MxBorderImage *marker_filename;
  gint spacing;

  MxComboBoxPrivate *priv = combo->priv;

  mx_stylable_get (MX_STYLABLE (combo),
                   "x-mx-spacing", &spacing,
                   "x-mx-marker-image", &marker_filename,
                   NULL);

  if (spacing != priv->spacing)
    priv->spacing = spacing;

  if (priv->marker)
    {
      clutter_actor_destroy (priv->marker);
      priv->marker = NULL;
    }

  if (marker_filename)
    {
      MxTextureCache *cache = mx_texture_cache_get_default ();
      priv->marker = (ClutterActor *)
        mx_texture_cache_get_texture (cache, marker_filename->uri);
      if (priv->marker)
        clutter_actor_add_child (CLUTTER_ACTOR (combo), priv->marker);

      g_boxed_free (MX_TYPE_BORDER_IMAGE, marker_filename);
    }

  mx_stylable_apply_clutter_text_attributes (MX_STYLABLE (combo),
                                             CLUTTER_TEXT (combo->priv->label));

  /* make sure the popup is also up-to-date */
  mx_stylable_style_changed (MX_STYLABLE (mx_widget_get_menu (MX_WIDGET (combo))),
                             flags | MX_STYLE_CHANGED_FORCE);

  clutter_actor_queue_relayout (CLUTTER_ACTOR (combo));
}
Пример #4
0
static void
mx_combo_box_allocate (ClutterActor          *actor,
                       const ClutterActorBox *box,
                       ClutterAllocationFlags flags)
{
  MxComboBoxPrivate *priv = MX_COMBO_BOX (actor)->priv;
  MxPadding padding;
  gfloat x, y, width, height;
  gfloat min_menu_h, nat_menu_h;
  gfloat label_h;
  gfloat nat_icon_h, icon_h, icon_w;
  gfloat nat_marker_h, marker_h, marker_w;
  ClutterActorBox childbox;
  ClutterActor *menu, *stage;

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

  mx_widget_get_padding (MX_WIDGET (actor), &padding);

  x = padding.left;
  y = padding.top;
  width = box->x2 - box->x1 - padding.left - padding.right;
  height = box->y2 - box->y1 - padding.top - padding.bottom;

  icon_w = marker_w = 0;

  if (priv->icon)
    {
      /* Allocate the icon, if there is one, the space not used by the text */
      clutter_actor_get_preferred_height (priv->icon, -1, NULL, &nat_icon_h);

      if (height >= nat_icon_h)
        {
          icon_h = nat_icon_h;
          clutter_actor_get_preferred_width (priv->icon, -1, NULL, &icon_w);
        }
      else
        {
          icon_h = height;
          clutter_actor_get_preferred_width (priv->icon, icon_h, NULL, &icon_w);
        }

      childbox.x1 = (int)(x);
      childbox.y1 = (int)(y + (height - icon_h) / 2);
      childbox.x2 = (int)(x + icon_w);
      childbox.y2 = (int)(childbox.y1 + icon_h);

      clutter_actor_allocate (priv->icon, &childbox, flags);

      icon_w += priv->spacing;
    }

  if (priv->marker)
    {
      clutter_actor_get_preferred_height (priv->marker, -1,
                                          NULL, &nat_marker_h);

      if (height >= nat_marker_h)
        {
          marker_h = nat_marker_h;
          clutter_actor_get_preferred_width (priv->marker, -1, NULL, &marker_w);
        }
      else
        {
          marker_h = height;
          clutter_actor_get_preferred_width (priv->marker, marker_h,
                                             NULL, &marker_w);
        }

      childbox.x2 = (int)(x + width);
      childbox.x1 = (int)(childbox.x2 - marker_w);
      childbox.y1 = (int)(y + (height - marker_h) / 2);
      childbox.y2 = (int)(childbox.y1 + marker_h);

      clutter_actor_allocate (priv->marker, &childbox, flags);

      marker_w += priv->spacing;
    }

  clutter_actor_get_preferred_height (priv->label, -1, NULL, &label_h);

  childbox.x1 = (int)(x + icon_w);
  childbox.y1 = (int)(y + (height / 2 - label_h / 2));
  childbox.x2 = (int)(x + width - marker_w);
  childbox.y2 = (int)(childbox.y1 + label_h);
  clutter_actor_allocate (priv->label, &childbox, flags);

  menu = (ClutterActor*) mx_widget_get_menu (MX_WIDGET (actor));
  clutter_actor_get_preferred_height (menu, (box->x2 - box->x1), &min_menu_h,
                                      &nat_menu_h);

  childbox.x1 = 0;
  childbox.x2 = (box->x2 - box->x1);
  childbox.y1 = (box->y2 - box->y1);

  stage = clutter_actor_get_stage (actor);
  if (stage != NULL)
    {
      ClutterVertex point = { 0, };
      gfloat stage_w, stage_h, combo_h = box->y2 - box->y1;

      clutter_actor_get_size (stage, &stage_w, &stage_h);
      point.y = combo_h + nat_menu_h;
      clutter_actor_apply_transform_to_point (actor, &point, &point);

      /* If the menu would appear off the stage, flip it around. */
      if ((point.x < 0) || (point.x >= stage_w) ||
          (point.y < 0) || (point.y >= stage_h))
        {
          childbox.y1 = -nat_menu_h;
        }
    }

  childbox.y2 = childbox.y1 + nat_menu_h;
  clutter_actor_allocate (menu, &childbox, flags);
}
Пример #5
0
static void
mx_combo_box_get_preferred_width (ClutterActor *actor,
                                  gfloat        for_height,
                                  gfloat       *min_width_p,
                                  gfloat       *natural_height_p)
{
  gfloat height;
  gfloat min_w, nat_w;
  gfloat min_label_w, nat_label_w;

  gfloat min_icon_w = 0, nat_icon_w = 0;
  gfloat min_menu_w = 0, nat_menu_w = 0;
  gfloat min_marker_w = 0, nat_marker_w = 0;
  MxComboBoxPrivate *priv = MX_COMBO_BOX (actor)->priv;

  MxPadding padding;
  ClutterActor *menu;

  mx_widget_get_padding (MX_WIDGET (actor), &padding);

  height = for_height - padding.top - padding.bottom;

  menu = (ClutterActor *) mx_widget_get_menu (MX_WIDGET (actor));
  if (menu)
    {
      clutter_actor_get_preferred_width (menu, -1, &min_menu_w, &nat_menu_w);
    }

  clutter_actor_get_preferred_width (priv->label,
                                     height,
                                     &min_label_w,
                                     &nat_label_w);

  min_w = min_label_w;
  nat_w = nat_label_w;

  if (priv->icon)
    {
      clutter_actor_get_preferred_width (priv->icon,
                                         height,
                                         &min_icon_w,
                                         &nat_icon_w);

      min_w += min_icon_w + priv->spacing;
      nat_w += nat_icon_w + priv->spacing;
    }

  if (min_menu_w > min_w)
    min_w = min_menu_w;
  if (nat_menu_w > nat_w)
    nat_w = nat_menu_w;

  if (priv->marker)
    {
      clutter_actor_get_preferred_width (priv->marker,
                                         height,
                                         &min_marker_w,
                                         &nat_marker_w);

      min_w += min_marker_w + priv->spacing;
      nat_w += nat_marker_w + priv->spacing;
    }

  if (min_width_p)
    *min_width_p = padding.left + padding.right + min_w;

  if (natural_height_p)
    *natural_height_p = padding.left + padding.right + nat_w;
}
Пример #6
0
static void
mx_combo_box_allocate (ClutterActor          *actor,
                       const ClutterActorBox *box,
                       ClutterAllocationFlags flags)
{
  MxComboBoxPrivate *priv = MX_COMBO_BOX (actor)->priv;
  MxPadding padding;
  gfloat x, y, width, height;
  gfloat min_menu_h, nat_menu_h;
  gfloat label_h;
  gfloat nat_icon_h, icon_h, icon_w;
  gfloat nat_marker_h, marker_h, marker_w;
  ClutterActorBox childbox;
  ClutterActor *menu, *stage;

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

  mx_widget_get_padding (MX_WIDGET (actor), &padding);

  x = padding.left;
  y = padding.top;
  width = box->x2 - box->x1 - padding.left - padding.right;
  height = box->y2 - box->y1 - padding.top - padding.bottom;

  icon_w = marker_w = 0;

  if (priv->icon)
    {
      /* Allocate the icon, if there is one, the space not used by the text */
      clutter_actor_get_preferred_height (priv->icon, -1, NULL, &nat_icon_h);

      if (height >= nat_icon_h)
        {
          icon_h = nat_icon_h;
          clutter_actor_get_preferred_width (priv->icon, -1, NULL, &icon_w);
        }
      else
        {
          icon_h = height;
          clutter_actor_get_preferred_width (priv->icon, icon_h, NULL, &icon_w);
        }

      childbox.x1 = (int)(x);
      childbox.y1 = (int)(y + (height - icon_h) / 2);
      childbox.x2 = (int)(x + icon_w);
      childbox.y2 = (int)(childbox.y1 + icon_h);

      clutter_actor_allocate (priv->icon, &childbox, flags);

      icon_w += priv->spacing;
    }

  if (priv->marker)
    {
      clutter_actor_get_preferred_height (priv->marker, -1,
                                          NULL, &nat_marker_h);

      if (height >= nat_marker_h)
        {
          marker_h = nat_marker_h;
          clutter_actor_get_preferred_width (priv->marker, -1, NULL,
                                             &marker_w);
        }
      else
        {
          marker_h = height;
          clutter_actor_get_preferred_width (priv->marker, marker_h,
                                             NULL, &marker_w);
        }

      childbox.x2 = (int)(x + width);
      childbox.x1 = (int)(childbox.x2 - marker_w);
      childbox.y1 = (int)(y + (height - marker_h) / 2);
      childbox.y2 = (int)(childbox.y1 + marker_h);

      clutter_actor_allocate (priv->marker, &childbox, flags);

      marker_w += priv->spacing;
    }

  clutter_actor_get_preferred_height (priv->label, -1, NULL, &label_h);

  childbox.x1 = (int)(x + icon_w);
  childbox.y1 = (int)(y + (height / 2 - label_h / 2));
  childbox.x2 = (int)(x + width - marker_w);
  childbox.y2 = (int)(childbox.y1 + label_h);
  clutter_actor_allocate (priv->label, &childbox, flags);

  menu = (ClutterActor*) mx_widget_get_menu (MX_WIDGET (actor));
  clutter_actor_get_preferred_height (menu, (box->x2 - box->x1), &min_menu_h,
                                      &nat_menu_h);

  childbox.x1 = 0;
  childbox.x2 = (box->x2 - box->x1);
  childbox.y1 = (box->y2 - box->y1);

  childbox.y2 = childbox.y1 + nat_menu_h;

  stage = clutter_actor_get_stage (actor);
  if (stage != NULL)
    {
      ClutterVertex point = { 0, };
      gfloat stage_w, stage_h, combo_h = box->y2 - box->y1;

      clutter_actor_get_size (stage, &stage_w, &stage_h);
      point.y = combo_h + nat_menu_h;
      clutter_actor_apply_transform_to_point (actor, &point, &point);

      /* If the menu would appear off the stage, flip it around. */
      if ((point.y < 0) || (point.y >= stage_h))
        {
          childbox.y1 = -nat_menu_h;
          point.y = -nat_menu_h;
          clutter_actor_apply_transform_to_point (actor, &point, &point);
          /* if the menu would still appear out of the stage, force
           * it to appear on the top of the stage.
           */
          if (point.y < 0)
            {
              gfloat xactor, yactor;
              clutter_actor_get_transformed_position (actor, &xactor,
                                                      &yactor);
              childbox.y1 = -yactor;
            }
        }

      point.y = childbox.y1 + nat_menu_h;
      clutter_actor_apply_transform_to_point (actor, &point, &point);
      if (point.y >= stage_h)
        {
          gfloat xactor, yactor;
          clutter_actor_get_transformed_position (actor, &xactor, &yactor);
          /*
           * clamp so that the menu doesn't appear out of the screen
           */
          clutter_actor_transform_stage_point (actor, xactor, stage_h,
                                               NULL, &childbox.y2);
          /*
           * The previous transformation can lead to negative height
           * allocation if the top-left corner of the menu is already
           * flipped around. This happens when you put a combobox deep
           * enough in a scrollview taller that the stage.
           */
          childbox.y2 = MAX (childbox.y1, childbox.y2);
        }
      else
        {
          childbox.y2 = childbox.y1 + nat_menu_h;
        }

    }
  clutter_actor_allocate (menu, &childbox, flags);
}