/** * adg_gtk_area_get_extents: * @area: an #AdgGtkArea * * Gets the extents of the canvas bound to @area. The returned * struct is owned by @area and should not modified or freed. * * The extents of an #AdgGtkArea instance are the extents of * its canvas (as returned by adg_entity_get_extents()) with * the margins added to it and the #AdgGtkArea:render-map * transformation applied. * * If @area does not have any canvas associated to it or the * canvas is invalid or empty, an undefined #CpmlExtents * struct will be returned. * * The canvas will be updated, meaning adg_entity_arrange() * is called before the extents computation. * * Returns: the extents of the @area canvas or <constant>NULL</constant> on errors. * * Since: 1.0 **/ const CpmlExtents * adg_gtk_area_get_extents(AdgGtkArea *area) { g_return_val_if_fail(ADG_GTK_IS_AREA(area), NULL); return _adg_get_extents(area); }
/** * adg_gtk_area_reset: * @area: an #AdgGtkArea * * Forcibly resets the zoom ratio and position of the canvas bound * to @area. This means the canvas will be scaled and centered on * the current available space. **/ void adg_gtk_area_reset(AdgGtkArea *area) { AdgGtkAreaPrivate *data; GtkWidget *parent; const CpmlExtents *sheet; GtkAllocation allocation; CpmlPair size; gdouble zoom; g_return_if_fail(ADG_GTK_IS_AREA(area)); data = adg_gtk_area_get_instance_private(area); cairo_matrix_init_identity(&data->render_map); sheet = _adg_get_extents(area); if (!sheet->is_defined || sheet->size.x <= 0 || sheet->size.y <= 0) return; parent = gtk_widget_get_parent((GtkWidget *) area); gtk_widget_get_allocation(parent, &allocation); size.x = allocation.width; size.y = allocation.height; zoom = MIN(size.x / sheet->size.x, size.y / sheet->size.y); cairo_matrix_scale(&data->render_map, zoom, zoom); cairo_matrix_translate(&data->render_map, (size.x / zoom - sheet->size.x) / 2 - sheet->org.x, (size.y / zoom - sheet->size.y) / 2 - sheet->org.y); /* Trigger a resize trying to hide the scrollbars on the parent */ gtk_widget_queue_resize(parent); }
static void _adg_size_request(GtkWidget *widget, GtkRequisition *requisition) { AdgGtkArea *area = (AdgGtkArea *) widget; const CpmlExtents *extents = _adg_get_extents(area); if (extents->is_defined) { requisition->width = extents->size.x; requisition->height = extents->size.y; } }
static void _adg_get_preferred_width_for_height(GtkWidget *widget, gint height, gint *minimum_width, gint *natural_width) { AdgGtkArea *area; const CpmlExtents *extents; area = (AdgGtkArea *) widget; extents = _adg_get_extents(area); if (extents->is_defined && extents->size.y > 0) { *minimum_width = extents->size.x; *natural_width = *minimum_width * height / extents->size.y; } }
static void _adg_get_preferred_height_for_width(GtkWidget *widget, gint width, gint *minimum_height, gint *natural_height) { AdgGtkArea *area; const CpmlExtents *extents; area = (AdgGtkArea *) widget; extents = _adg_get_extents(area); if (extents->is_defined && extents->size.x > 0) { *minimum_height = extents->size.y; *natural_height = *minimum_height * width / extents->size.x; } }
/** * _adg_size_allocate: * @widget: an #AdgGtkArea widget * @allocation: the new allocation struct * * Scales the drawing according to the new allocation if * #AdgGtkArea:autozoom is <constant>TRUE</constant>. * * TODO: the current implementation initially centers the canvas * on the allocation space. Further allocations (due to a * window resizing, for example) use the top/left corner of the * canvas as reference point. Plan different policies for either * those situations. * * Since: 1.0 **/ static void _adg_size_allocate(GtkWidget *widget, GtkAllocation *allocation) { AdgGtkArea *area; AdgGtkAreaPrivate *data; const CpmlExtents *sheet; CpmlVector size; gdouble factor; if (_ADG_OLD_WIDGET_CLASS->size_allocate) _ADG_OLD_WIDGET_CLASS->size_allocate(widget, allocation); area = (AdgGtkArea *) widget; data = area->data; sheet = _adg_get_extents(area); if (!sheet->is_defined || sheet->size.x <= 0 || sheet->size.y <= 0) return; size.x = allocation->width; size.y = allocation->height; if (data->autozoom) { /* Adjust the zoom according to the allocation and sheet size */ factor = MIN(size.x / sheet->size.x, size.y / sheet->size.y); } else if (!data->initialized) { /* First allocation with autozoom off: keep the current zoom */ factor = 1; } else { /* Not the first allocation and autozoom off: keep the old map */ return; } if (!data->initialized) { /* TODO: plan different attachment policies other than centering */ cairo_matrix_init_translate(&data->render_map, (size.x - sheet->size.x) / 2 - sheet->org.x, (size.y - sheet->size.y) / 2 - sheet->org.y); data->initialized = TRUE; } /* TODO: plan other reference points other than left/top (x0, y0) */ data->render_map.x0 *= factor; data->render_map.y0 *= factor; data->render_map.xx *= factor; data->render_map.yy *= factor; }
static void _adg_set_map(GtkWidget *widget, gboolean local_space, const cairo_matrix_t *map) { AdgGtkAreaPrivate *data = adg_gtk_area_get_instance_private((AdgGtkArea *) widget); AdgEntity *entity = (AdgEntity *) data->canvas; if (entity == NULL) return; if (local_space) { /* TODO: this forcibly overwrites any local transformation */ adg_entity_set_local_map(entity, map); } else { adg_matrix_transform(&data->render_map, map, ADG_TRANSFORM_BEFORE); } /* This will emit the extents-changed signal when applicable */ _adg_get_extents((AdgGtkArea *) widget); }