Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  gtkaspectframe.c

  Sprache: C
 

/* GTK - The GIMP Toolkit
 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
 *
 * GtkAspectFrame: Ensure that the child window has a specified aspect ratio
 *    or, if obey_child, has the same aspect ratio as its requested size
 *
 *     Copyright Owen Taylor                          4/9/97
 *
 * 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 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 <http://www.gnu.org/licenses/>.
 */


/*
 * Modified by the GTK+ Team and others 1997-2001.  See the AUTHORS
 * file for a list of people on the GTK+ Team.  See the ChangeLog
 * files for a list of changes.  These files are distributed with
 * GTK+ at ftp://ftp.gtk.org/pub/gtk/.
 */


/**
 * GtkAspectFrame:
 *
 * Preserves the aspect ratio of its child.
 *
 * The frame can respect the aspect ratio of the child widget,
 * or use its own aspect ratio.
 *
 * # CSS nodes
 *
 * `GtkAspectFrame` uses a CSS node with name `aspectframe`.
 *
 * # Accessibility
 *
 * Until GTK 4.10, `GtkAspectFrame` used the [enum@Gtk.AccessibleRole.group] role.
 *
 * Starting from GTK 4.12, `GtkAspectFrame` uses the [enum@Gtk.AccessibleRole.generic] role.

 */


#include "config.h"

#include "gtkaspectframe.h"

#include "gtksizerequest.h"

#include "gtkbuildable.h"

#include "gtkwidgetprivate.h"
#include "gtkprivate.h"
#include "gtkbuilderprivate.h"


typedef struct _GtkAspectFrameClass GtkAspectFrameClass;

struct _GtkAspectFrame
{
  GtkWidget parent_instance;

  GtkWidget    *child;
  float         xalign;
  float         yalign;
  float         ratio;
  int           cached_min_size[2];
  int           cached_min_baseline;
  gboolean      obey_child;
};

struct _GtkAspectFrameClass
{
  GtkWidgetClass parent_class;
};

enum {
  PROP_0,
  PROP_XALIGN,
  PROP_YALIGN,
  PROP_RATIO,
  PROP_OBEY_CHILD,
  PROP_CHILD,
  N_PROPS
};

static GParamSpec *props[N_PROPS] = { NULL, };

static void gtk_aspect_frame_dispose      (GObject         *object);
static void gtk_aspect_frame_set_property (GObject         *object,
                                           guint            prop_id,
                                           const GValue    *value,
                                           GParamSpec      *pspec);
static void gtk_aspect_frame_get_property (GObject         *object,
                                           guint            prop_id,
                                           GValue          *value,
                                           GParamSpec      *pspec);
static void gtk_aspect_frame_size_allocate (GtkWidget      *widget,
                                            int             width,
                                            int             height,
                                            int             baseline);
static void gtk_aspect_frame_measure       (GtkWidget      *widget,
                                            GtkOrientation  orientation,
                                            int             for_size,
                                            int             *minimum,
                                            int             *natural,
                                            int             *minimum_baseline,
                                            int             *natural_baseline);

static void gtk_aspect_frame_compute_expand (GtkWidget     *widget,
                                             gboolean      *hexpand,
                                             gboolean      *vexpand);
static GtkSizeRequestMode
            gtk_aspect_frame_get_request_mode (GtkWidget *widget);

static void gtk_aspect_frame_buildable_init (GtkBuildableIface *iface);

#define MAX_RATIO 10000.0
#define MIN_RATIO 0.0001


G_DEFINE_TYPE_WITH_CODE (GtkAspectFrame, gtk_aspect_frame, GTK_TYPE_WIDGET,
                         G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
                                                gtk_aspect_frame_buildable_init))


static void
gtk_aspect_frame_class_init (GtkAspectFrameClass *class)
{
  GObjectClass *gobject_class = G_OBJECT_CLASS (class);
  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);

  gobject_class->dispose = gtk_aspect_frame_dispose;
  gobject_class->set_property = gtk_aspect_frame_set_property;
  gobject_class->get_property = gtk_aspect_frame_get_property;

  widget_class->measure = gtk_aspect_frame_measure;
  widget_class->size_allocate = gtk_aspect_frame_size_allocate;
  widget_class->compute_expand = gtk_aspect_frame_compute_expand;
  widget_class->get_request_mode = gtk_aspect_frame_get_request_mode;

  /**
   * GtkAspectFrame:xalign:
   *
   * The horizontal alignment of the child.
   */

  props[PROP_XALIGN] = g_param_spec_float ("xalign", NULL, NULL,
                                           0.01.00.5,
                                           G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);
  /**
   * GtkAspectFrame:yalign:
   *
   * The vertical alignment of the child.
   */

  props[PROP_YALIGN] = g_param_spec_float ("yalign", NULL, NULL,
                                           0.01.00.5,
                                           G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);
  /**
   * GtkAspectFrame:ratio:
   *
   * The aspect ratio to be used by the `GtkAspectFrame`.
   *
   * This property is only used if
   * [property@Gtk.AspectFrame:obey-child] is set to %FALSE.
   */

  props[PROP_RATIO] = g_param_spec_float ("ratio", NULL, NULL,
                                          MIN_RATIO, MAX_RATIO, 1.0,
                                          G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);
  /**
   * GtkAspectFrame:obey-child:
   *
   * Whether the `GtkAspectFrame` should use the aspect ratio of its child.
   */

  props[PROP_OBEY_CHILD] = g_param_spec_boolean ("obey-child", NULL, NULL,
                                                 TRUE,
                                                 G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);
  /**
   * GtkAspectFrame:child:
   *
   * The child widget.
   */

  props[PROP_CHILD] = g_param_spec_object ("child", NULL, NULL,
                                           GTK_TYPE_WIDGET,
                                           G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_EXPLICIT_NOTIFY);

  g_object_class_install_properties (gobject_class, N_PROPS, props);

  gtk_widget_class_set_css_name (GTK_WIDGET_CLASS (class), I_("aspectframe"));
  gtk_widget_class_set_accessible_role (GTK_WIDGET_CLASS (class), GTK_ACCESSIBLE_ROLE_GENERIC);
}

static void
gtk_aspect_frame_resize_func (GtkWidget *widget)
{
  GtkAspectFrame *self = GTK_ASPECT_FRAME (widget);

  self->cached_min_size[GTK_ORIENTATION_VERTICAL] = -1;
  self->cached_min_size[GTK_ORIENTATION_HORIZONTAL] = -1;
  self->cached_min_baseline = -1;
}

static void
gtk_aspect_frame_init (GtkAspectFrame *self)
{
  GtkWidget *widget = GTK_WIDGET (self);

  self->xalign = 0.5;
  self->yalign = 0.5;
  self->ratio = 1.0;
  self->obey_child = TRUE;

  widget->priv->resize_func = gtk_aspect_frame_resize_func;
}

static void
gtk_aspect_frame_dispose (GObject *object)
{
  GtkAspectFrame *self = GTK_ASPECT_FRAME (object);

  g_clear_pointer (&self->child, gtk_widget_unparent);

  G_OBJECT_CLASS (gtk_aspect_frame_parent_class)->dispose (object);
}

static void
gtk_aspect_frame_set_property (GObject         *object,
                               guint            prop_id,
                               const GValue    *value,
                               GParamSpec      *pspec)
{
  GtkAspectFrame *self = GTK_ASPECT_FRAME (object);

  switch (prop_id)
    {
      /* g_object_notify is handled by the _frame_set function */
    case PROP_XALIGN:
      gtk_aspect_frame_set_xalign (self, g_value_get_float (value));
      break;
    case PROP_YALIGN:
      gtk_aspect_frame_set_yalign (self, g_value_get_float (value));
      break;
    case PROP_RATIO:
      gtk_aspect_frame_set_ratio (self, g_value_get_float (value));
      break;
    case PROP_OBEY_CHILD:
      gtk_aspect_frame_set_obey_child (self, g_value_get_boolean (value));
      break;
    case PROP_CHILD:
      gtk_aspect_frame_set_child (self, g_value_get_object (value));
      break;
    default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static void
gtk_aspect_frame_get_property (GObject         *object,
                               guint            prop_id,
                               GValue          *value,
                               GParamSpec      *pspec)
{
  GtkAspectFrame *self = GTK_ASPECT_FRAME (object);

  switch (prop_id)
    {
    case PROP_XALIGN:
      g_value_set_float (value, self->xalign);
      break;
    case PROP_YALIGN:
      g_value_set_float (value, self->yalign);
      break;
    case PROP_RATIO:
      g_value_set_float (value, self->ratio);
      break;
    case PROP_OBEY_CHILD:
      g_value_set_boolean (value, self->obey_child);
      break;
    case PROP_CHILD:
      g_value_set_object (value, gtk_aspect_frame_get_child (self));
      break;
    default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
      break;
    }
}

static GtkBuildableIface *parent_buildable_iface;

static void
gtk_aspect_frame_buildable_add_child (GtkBuildable *buildable,
                                      GtkBuilder   *builder,
                                      GObject      *child,
                                      const char   *type)
{
  if (GTK_IS_WIDGET (child))
    {
      gtk_buildable_child_deprecation_warning (buildable, builder, NULL, "child");
      gtk_aspect_frame_set_child (GTK_ASPECT_FRAME (buildable), GTK_WIDGET (child));
    }
  else
    {
      parent_buildable_iface->add_child (buildable, builder, child, type);
    }
}

static void
gtk_aspect_frame_buildable_init (GtkBuildableIface *iface)
{
  parent_buildable_iface = g_type_interface_peek_parent (iface);

  iface->add_child = gtk_aspect_frame_buildable_add_child;
}

/**
 * gtk_aspect_frame_new:
 * @xalign: Horizontal alignment of the child within the parent.
 *   Ranges from 0.0 (left aligned) to 1.0 (right aligned)
 * @yalign: Vertical alignment of the child within the parent.
 *   Ranges from 0.0 (top aligned) to 1.0 (bottom aligned)
 * @ratio: The desired aspect ratio.
 * @obey_child: If %TRUE, @ratio is ignored, and the aspect
 *   ratio is taken from the requistion of the child.
 *
 * Create a new `GtkAspectFrame`.
 *
 * Returns: the new `GtkAspectFrame`.
 */

GtkWidget *
gtk_aspect_frame_new (float    xalign,
                      float    yalign,
                      float    ratio,
                      gboolean obey_child)
{
  GtkAspectFrame *self;

  self = g_object_new (GTK_TYPE_ASPECT_FRAME, NULL);

  self->xalign = CLAMP (xalign, 0.01.0);
  self->yalign = CLAMP (yalign, 0.01.0);
  self->ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO);
  self->obey_child = obey_child != FALSE;

  return GTK_WIDGET (self);
}

/**
 * gtk_aspect_frame_set_xalign:
 * @self: a `GtkAspectFrame`
 * @xalign: horizontal alignment, from 0.0 (left aligned) to 1.0 (right aligned)
 *
 * Sets the horizontal alignment of the child within the allocation
 * of the `GtkAspectFrame`.
 */

void
gtk_aspect_frame_set_xalign (GtkAspectFrame *self,
                             float           xalign)
{
  g_return_if_fail (GTK_IS_ASPECT_FRAME (self));

  xalign = CLAMP (xalign, 0.01.0);

  if (self->xalign == xalign)
    return;

  self->xalign = xalign;

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_XALIGN]);
  gtk_widget_queue_allocate (GTK_WIDGET (self));
}

/**
 * gtk_aspect_frame_get_xalign:
 * @self: a `GtkAspectFrame`
 *
 * Returns the horizontal alignment of the child within the
 * allocation of the `GtkAspectFrame`.
 *
 * Returns: the horizontal alignment
 */

float
gtk_aspect_frame_get_xalign (GtkAspectFrame *self)
{
  g_return_val_if_fail (GTK_IS_ASPECT_FRAME (self), 0.5);

  return self->xalign;
}

/**
 * gtk_aspect_frame_set_yalign:
 * @self: a `GtkAspectFrame`
 * @yalign: horizontal alignment, from 0.0 (top aligned) to 1.0 (bottom aligned)
 *
 * Sets the vertical alignment of the child within the allocation
 * of the `GtkAspectFrame`.
 */

void
gtk_aspect_frame_set_yalign (GtkAspectFrame *self,
                             float           yalign)
{
  g_return_if_fail (GTK_IS_ASPECT_FRAME (self));

  yalign = CLAMP (yalign, 0.01.0);

  if (self->yalign == yalign)
    return;

  self->yalign = yalign;

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_YALIGN]);
  if (self->cached_min_baseline != -1)
    gtk_widget_queue_resize (GTK_WIDGET (self));
  else
    gtk_widget_queue_allocate (GTK_WIDGET (self));
}

/**
 * gtk_aspect_frame_get_yalign:
 * @self: a `GtkAspectFrame`
 *
 * Returns the vertical alignment of the child within the
 * allocation of the `GtkAspectFrame`.
 *
 * Returns: the vertical alignment
 */

float
gtk_aspect_frame_get_yalign (GtkAspectFrame *self)
{
  g_return_val_if_fail (GTK_IS_ASPECT_FRAME (self), 0.5);

  return self->yalign;
}

/**
 * gtk_aspect_frame_set_ratio:
 * @self: a `GtkAspectFrame`
 * @ratio: aspect ratio of the child
 *
 * Sets the desired aspect ratio of the child.
 */

void
gtk_aspect_frame_set_ratio (GtkAspectFrame *self,
                            float           ratio)
{
  g_return_if_fail (GTK_IS_ASPECT_FRAME (self));

  ratio = CLAMP (ratio, MIN_RATIO, MAX_RATIO);

  if (self->ratio == ratio)
    return;

  self->ratio = ratio;

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_RATIO]);
  if (!self->obey_child)
    gtk_widget_queue_resize (GTK_WIDGET (self));
}

/**
 * gtk_aspect_frame_get_ratio:
 * @self: a `GtkAspectFrame`
 *
 * Returns the desired aspect ratio of the child.
 *
 * Returns: the desired aspect ratio
 */

float
gtk_aspect_frame_get_ratio (GtkAspectFrame *self)
{
  g_return_val_if_fail (GTK_IS_ASPECT_FRAME (self), 1.0);

  return self->ratio;
}

/**
 * gtk_aspect_frame_set_obey_child:
 * @self: a `GtkAspectFrame`
 * @obey_child: If %TRUE, @ratio is ignored, and the aspect
 *    ratio is taken from the requisition of the child.
 *
 * Sets whether the aspect ratio of the child's size
 * request should override the set aspect ratio of
 * the `GtkAspectFrame`.
 */

void
gtk_aspect_frame_set_obey_child (GtkAspectFrame *self,
                                 gboolean        obey_child)
{
  g_return_if_fail (GTK_IS_ASPECT_FRAME (self));

  if (self->obey_child == obey_child)
    return;

  self->obey_child = obey_child;

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_OBEY_CHILD]);
  gtk_widget_queue_resize (GTK_WIDGET (self));

}

/**
 * gtk_aspect_frame_get_obey_child:
 * @self: a `GtkAspectFrame`
 *
 * Returns whether the child's size request should override
 * the set aspect ratio of the `GtkAspectFrame`.
 *
 * Returns: whether to obey the child's size request
 */

gboolean
gtk_aspect_frame_get_obey_child (GtkAspectFrame *self)
{
  g_return_val_if_fail (GTK_IS_ASPECT_FRAME (self), TRUE);

  return self->obey_child;
}

static double
get_effective_ratio (GtkAspectFrame *self)
{
  double ratio;
  GtkRequisition child_requisition;

  if (!self->obey_child || !self->child)
    return self->ratio;

  gtk_widget_get_preferred_size (self->child, NULL, &child_requisition);

  if (child_requisition.height != 0)
    {
      ratio = ((double) child_requisition.width /
               child_requisition.height);
      if (ratio < MIN_RATIO)
        ratio = MIN_RATIO;
    }
  else if (child_requisition.width != 0)
    ratio = MAX_RATIO;
  else
    ratio = 1.0;

  return ratio;
}

static void
get_full_allocation (GtkAspectFrame *self,
                     GtkAllocation  *child_allocation)
{
  child_allocation->x = 0;
  child_allocation->y = 0;
  child_allocation->width = gtk_widget_get_width (GTK_WIDGET (self));
  child_allocation->height = gtk_widget_get_height (GTK_WIDGET (self));
}

static void
compute_child_allocation (GtkAspectFrame *self,
                          GtkAllocation  *child_allocation)
{
  double ratio;

  if (self->child && gtk_widget_get_visible (self->child))
    {
      GtkAllocation full_allocation;

      get_full_allocation (self, &full_allocation);
      ratio = get_effective_ratio (self);

      if (ratio * full_allocation.height > full_allocation.width)
        {
          child_allocation->width = full_allocation.width;
          child_allocation->height = full_allocation.width / ratio + 0.5;
        }
      else
        {
          child_allocation->width = ratio * full_allocation.height + 0.5;
          child_allocation->height = full_allocation.height;
        }

      child_allocation->x = full_allocation.x + self->xalign * (full_allocation.width - child_allocation->width);
      child_allocation->y = full_allocation.y + self->yalign * (full_allocation.height - child_allocation->height);
    }
  else
    get_full_allocation (self, child_allocation);
}

static inline double
apply_ratio (int            for_size,
             double         ratio,
             GtkOrientation orientation)
{
  if (orientation == GTK_ORIENTATION_HORIZONTAL)
    /* width = height * ratio */
    return for_size * ratio;
  else
    /* height = width / ratio */
    return for_size / ratio;
}

static void
gtk_aspect_frame_compute_minimum_size (GtkAspectFrame *self,
                                       double          ratio)
{
  GtkSizeRequestMode request_mode;
  GtkOrientation orientation, opposite_orientation;
  int start_size, end_size, opposite_size, baseline;

  /* From an allocation that GtkAspectFrame itself receives, it carves
   * out an allocation for its child that has the desired aspect ratio.
   * The possible sizes allocated to the child are ones that have that
   * aspect ratio; effectively the possible child size varies with a
   * single degree of freedom as opposed to the usual two.  Therefore,
   * there is a single minimum size for the child allocation: it is the
   * smallest among sizes having the desired aspect ratio that is still
   * acceptable to the child.
   *
   * While GtkAspectFrame is not constant-size because our natural size
   * proportionally depends on the size in the opposite orientation,
   * its minimum width and height don't depend on the available size in
   * the opposite orientation.  This is why we can compute this minimum
   * size once, and then use the cached values whenever we're measured.
   */


  request_mode = gtk_widget_get_request_mode (self->child);
  if (request_mode == GTK_SIZE_REQUEST_CONSTANT_SIZE)
    {
      int min_width, min_height, min_baseline;

      gtk_widget_measure (self->child, GTK_ORIENTATION_HORIZONTAL, -1,
                          &min_width, NULL, NULL, NULL);
      gtk_widget_measure (self->child, GTK_ORIENTATION_VERTICAL, -1,
                          &min_height, NULL, &min_baseline, NULL);
      self->cached_min_size[GTK_ORIENTATION_HORIZONTAL] = MAX (min_width, ceil (min_height * ratio));
      self->cached_min_size[GTK_ORIENTATION_VERTICAL] = MAX (min_height, ceil (min_width / ratio));

      if (min_baseline != -1)
        self->cached_min_baseline = min_baseline + round (self->yalign *
          (self->cached_min_size[GTK_ORIENTATION_VERTICAL] - min_height));
      else
        self->cached_min_baseline = -1;
      return;
    }
  else if (request_mode == GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH)
    {
      orientation = GTK_ORIENTATION_HORIZONTAL;
      opposite_orientation = GTK_ORIENTATION_VERTICAL;
    }
  else
    {
      orientation = GTK_ORIENTATION_VERTICAL;
      opposite_orientation = GTK_ORIENTATION_HORIZONTAL;
    }

  /* Search, among sizes that are acceptable to the child, for the one
   * that fits the desired ratio best.
   *
   * Start from the overall minimum size along this orientation.
   */

  gtk_widget_measure (self->child, orientation,
                      -1, &start_size, NULL, NULL, NULL);
  gtk_widget_measure (self->child, opposite_orientation,
                      start_size, &opposite_size, NULL, NULL, NULL);

  end_size = apply_ratio (opposite_size, ratio, orientation);
  /* See if the minimum size in fact already fits */
  if (start_size >= end_size)
    {
      end_size = start_size;
      goto found;
    }
  /* Otherwise, we know that end_size is certain to fit.
   *
   * Binary search for the minimum size that fits.
   *
   * Invariant: start_size doesn't fit, end_size does.
   */

  while (start_size + 1 < end_size)
    {
      int mid_size;

      mid_size = (start_size + 1 + end_size) / 2;
      g_assert (mid_size > start_size);
      gtk_widget_measure (self->child, opposite_orientation,
                          mid_size, &opposite_size, NULL, NULL, NULL);
      if (mid_size >= apply_ratio (opposite_size, ratio, orientation))
        end_size = mid_size;
      else
        start_size = mid_size;
    }

found:
  self->cached_min_size[orientation] = end_size;
  self->cached_min_size[opposite_orientation] =
    ceil (apply_ratio (end_size, ratio, opposite_orientation));

  /* Now compute the baseline */
  gtk_widget_measure (self->child, GTK_ORIENTATION_VERTICAL,
                      self->cached_min_size[GTK_ORIENTATION_HORIZONTAL],
                      &opposite_size, NULL, &baseline, NULL);
  g_assert (opposite_size <= self->cached_min_size[GTK_ORIENTATION_VERTICAL]);
  if (baseline != -1)
    self->cached_min_baseline = baseline + round (self->yalign *
      (self->cached_min_size[GTK_ORIENTATION_VERTICAL] - opposite_size));
  else
    self->cached_min_baseline = -1;
}

static void
gtk_aspect_frame_measure (GtkWidget      *widget,
                          GtkOrientation  orientation,
                          int             for_size,
                          int             *minimum,
                          int             *natural,
                          int             *minimum_baseline,
                          int             *natural_baseline)
{
  GtkAspectFrame *self = GTK_ASPECT_FRAME (widget);
  double ratio;
  int natural_constraint;

  if (!self->child || !gtk_widget_get_visible (self->child))
    {
      *minimum = *natural = 0;
      *minimum_baseline = *natural_baseline = -1;
      return;
    }

  ratio = get_effective_ratio (self);

  if (self->cached_min_size[orientation] == -1)
    gtk_aspect_frame_compute_minimum_size (self, ratio);

  *minimum = self->cached_min_size[orientation];
  if (orientation == GTK_ORIENTATION_VERTICAL)
    *minimum_baseline = self->cached_min_baseline;

  if (for_size != -1)
    {
      /* For any specific size, our natural size follows the ratio */
      if (orientation == GTK_ORIENTATION_HORIZONTAL)
        *natural = ceil (for_size * ratio);
      else
        *natural = floor (for_size / ratio);
      /* Note that (*natural) < (*minimum) could happen due to us
       * finding a close, but imprecise, ratio.
       */

      *natural = MAX (*natural, *minimum);

      if (orientation == GTK_ORIENTATION_VERTICAL && *minimum_baseline != -1)
        {
          int child_min, child_nat;
          int child_min_baseline;

          gtk_widget_measure (self->child, GTK_ORIENTATION_VERTICAL,
                              for_size, &child_min, &child_nat,
                              &child_min_baseline, natural_baseline);
          if (*natural >= child_nat)
            *natural_baseline += round ((*natural - child_nat) * self->yalign);
          else
            {
              /* Interpolate from child's min baseline to its nat baseline */
              double progress = ((double) (*natural - child_min)) / (child_nat - child_min);
              *natural_baseline = child_min_baseline + round ((*natural_baseline - child_min_baseline) * progress);
            }
        }
    }
  else
    {
      /* Our overall natural size is such that we can fit the child
       * at its natural size, in both orientations.
       */

      gtk_widget_measure (self->child, orientation, -1,
                          NULL, natural,
                          NULL, natural_baseline);
      if (!self->obey_child)
        {
          int natural_opposite;

          gtk_widget_measure (self->child,
                              OPPOSITE_ORIENTATION (orientation), -1,
                              NULL, &natural_opposite, NULL, NULL);
          natural_constraint = ceil (apply_ratio (natural_opposite, ratio, orientation));
          natural_constraint = MAX (natural_constraint, *minimum);

          if (*natural_baseline != -1 && natural_constraint > *natural)
            *natural_baseline += round ((natural_constraint - *natural) * self->yalign);
          *natural = MAX (*natural, natural_constraint);
        }
    }
}

static void
gtk_aspect_frame_size_allocate (GtkWidget *widget,
                                int        width,
                                int        height,
                                int        baseline)
{
  GtkAspectFrame *self = GTK_ASPECT_FRAME (widget);
  GtkAllocation new_allocation;

  compute_child_allocation (self, &new_allocation);

  if (self->child && gtk_widget_get_visible (self->child))
    gtk_widget_size_allocate (self->child, &new_allocation, -1);
}

static void
gtk_aspect_frame_compute_expand (GtkWidget *widget,
                                 gboolean  *hexpand,
                                 gboolean  *vexpand)
{
  GtkAspectFrame *self = GTK_ASPECT_FRAME (widget);

  if (self->child)
    {
      *hexpand = gtk_widget_compute_expand (self->child, GTK_ORIENTATION_HORIZONTAL);
      *vexpand = gtk_widget_compute_expand (self->child, GTK_ORIENTATION_VERTICAL);
    }
  else
    {
      *hexpand = FALSE;
      *vexpand = FALSE;
    }
}

static GtkSizeRequestMode
gtk_aspect_frame_get_request_mode (GtkWidget *widget)
{
  GtkAspectFrame *self = GTK_ASPECT_FRAME (widget);
  GtkSizeRequestMode request_mode;

  if (!self->child || !gtk_widget_get_visible (self->child))
    return GTK_SIZE_REQUEST_CONSTANT_SIZE;

  /* Our natural size always depends on for-size, so we're never
   * constant-size, even when our child is.
   */


  request_mode = gtk_widget_get_request_mode (self->child);
  if (request_mode != GTK_SIZE_REQUEST_CONSTANT_SIZE)
    return request_mode;
  return GTK_SIZE_REQUEST_HEIGHT_FOR_WIDTH;
}

/**
 * gtk_aspect_frame_set_child:
 * @self: a `GtkAspectFrame`
 * @child: (nullable): the child widget
 *
 * Sets the child widget of @self.
 */

void
gtk_aspect_frame_set_child (GtkAspectFrame  *self,
                            GtkWidget       *child)
{
  g_return_if_fail (GTK_IS_ASPECT_FRAME (self));
  g_return_if_fail (child == NULL || self->child == child || gtk_widget_get_parent (child) == NULL);

  if (self->child == child)
    return;

  g_clear_pointer (&self->child, gtk_widget_unparent);

  if (child)
    {
      self->child = child;
      gtk_widget_set_parent (child, GTK_WIDGET (self));
    }

  g_object_notify_by_pspec (G_OBJECT (self), props[PROP_CHILD]);
}

/**
 * gtk_aspect_frame_get_child:
 * @self: a `GtkAspectFrame`
 *
 * Gets the child widget of @self.
 *
 * Returns: (nullable) (transfer none): the child widget of @self
 */

GtkWidget *
gtk_aspect_frame_get_child (GtkAspectFrame *self)
{
  g_return_val_if_fail (GTK_IS_ASPECT_FRAME (self), NULL);

  return self->child;
}

Messung V0.5 in Prozent
C=98 H=94 G=95

¤ Dauer der Verarbeitung: 0.15 Sekunden  (vorverarbeitet am  2026-07-03) ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover

NIST Cobol Testsuite

Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik