mirror of https://github.com/GNOME/gimp.git
libgimp/gimpdrawablepreview.c added a navigation popup similar to the one
2004-09-09 Sven Neumann <sven@gimp.org> * libgimp/gimpdrawablepreview.c * libgimpwidgets/gimppreview.[ch]: added a navigation popup similar to the one in the image window. Needs some more work.
This commit is contained in:
parent
8a80b8e73e
commit
025e58a12d
|
@ -1,3 +1,9 @@
|
|||
2004-09-09 Sven Neumann <sven@gimp.org>
|
||||
|
||||
* libgimp/gimpdrawablepreview.c
|
||||
* libgimpwidgets/gimppreview.[ch]: added a navigation popup
|
||||
similar to the one in the image window. Needs some more work.
|
||||
|
||||
2004-09-09 DindinX <david@dindinx.org>
|
||||
|
||||
* libgimpwidgets/gimppreviewarea.c: added a utility function
|
||||
|
|
|
@ -36,11 +36,16 @@
|
|||
|
||||
|
||||
static void gimp_drawable_preview_class_init (GimpDrawablePreviewClass *klass);
|
||||
static void gimp_drawable_preview_init (GimpDrawablePreview *preview);
|
||||
static void gimp_drawable_preview_init (GimpDrawablePreview *preview);
|
||||
|
||||
static void gimp_drawable_preview_style_set (GtkWidget *widget,
|
||||
GtkStyle *prev_style);
|
||||
static void gimp_drawable_preview_draw_original (GimpPreview *preview);
|
||||
static void gimp_drawable_preview_style_set (GtkWidget *widget,
|
||||
GtkStyle *prev_style);
|
||||
|
||||
static void gimp_drawable_preview_draw_original (GimpPreview *preview);
|
||||
static void gimp_drawable_preview_draw_thumb (GimpPreview *preview,
|
||||
GimpPreviewArea *area,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
|
||||
static GimpPreviewClass *parent_class = NULL;
|
||||
|
@ -82,9 +87,10 @@ gimp_drawable_preview_class_init (GimpDrawablePreviewClass *klass)
|
|||
|
||||
parent_class = g_type_class_peek_parent (klass);
|
||||
|
||||
widget_class->style_set = gimp_drawable_preview_style_set;
|
||||
widget_class->style_set = gimp_drawable_preview_style_set;
|
||||
|
||||
preview_class->draw = gimp_drawable_preview_draw_original;
|
||||
preview_class->draw = gimp_drawable_preview_draw_original;
|
||||
preview_class->draw_thumb = gimp_drawable_preview_draw_thumb;
|
||||
}
|
||||
|
||||
static void
|
||||
|
@ -155,6 +161,48 @@ gimp_drawable_preview_draw_original (GimpPreview *preview)
|
|||
g_free (buffer);
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_preview_draw_thumb (GimpPreview *preview,
|
||||
GimpPreviewArea *area,
|
||||
gint width,
|
||||
gint height)
|
||||
{
|
||||
GimpDrawablePreview *drawable_preview = GIMP_DRAWABLE_PREVIEW (preview);
|
||||
GimpDrawable *drawable = drawable_preview->drawable;
|
||||
guchar *buffer;
|
||||
gint bpp;
|
||||
|
||||
if (! drawable)
|
||||
return;
|
||||
|
||||
buffer = gimp_drawable_get_thumbnail_data (drawable->drawable_id,
|
||||
&width, &height, &bpp);
|
||||
|
||||
if (buffer)
|
||||
{
|
||||
gtk_widget_set_size_request (GTK_WIDGET (area), width, height);
|
||||
gtk_widget_show (GTK_WIDGET (area));
|
||||
gtk_widget_realize (GTK_WIDGET (area));
|
||||
|
||||
switch (bpp)
|
||||
{
|
||||
case 3:
|
||||
gimp_preview_area_draw (area,
|
||||
0, 0, width, height,
|
||||
GIMP_RGB_IMAGE, buffer, 3 * width);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
gimp_preview_area_draw (area,
|
||||
0, 0, width, height,
|
||||
GIMP_RGBA_IMAGE, buffer, 4 * width);
|
||||
break;
|
||||
}
|
||||
|
||||
g_free (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_drawable_preview_set_drawable (GimpDrawablePreview *drawable_preview,
|
||||
GimpDrawable *drawable)
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
|
||||
#include <gtk/gtk.h>
|
||||
|
||||
#include "libgimpmath/gimpmath.h"
|
||||
|
||||
#include "gimpwidgets.h"
|
||||
|
||||
#include "gimppreview.h"
|
||||
|
@ -31,6 +33,8 @@
|
|||
|
||||
|
||||
#define DEFAULT_SIZE 150
|
||||
#define POPUP_SIZE 100
|
||||
#define PEN_WIDTH 3
|
||||
#define PREVIEW_TIMEOUT 200
|
||||
|
||||
|
||||
|
@ -47,40 +51,59 @@ enum
|
|||
};
|
||||
|
||||
|
||||
static void gimp_preview_class_init (GimpPreviewClass *klass);
|
||||
static void gimp_preview_init (GimpPreview *preview);
|
||||
static void gimp_preview_dispose (GObject *object);
|
||||
static void gimp_preview_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gimp_preview_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gimp_preview_direction_changed (GtkWidget *widget,
|
||||
GtkTextDirection prev_dir);
|
||||
static gboolean gimp_preview_popup_menu (GtkWidget *widget);
|
||||
static void gimp_preview_class_init (GimpPreviewClass *klass);
|
||||
static void gimp_preview_init (GimpPreview *preview);
|
||||
static void gimp_preview_dispose (GObject *object);
|
||||
static void gimp_preview_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec);
|
||||
static void gimp_preview_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec);
|
||||
|
||||
static void gimp_preview_area_realize (GtkWidget *widget,
|
||||
GimpPreview *preview);
|
||||
static void gimp_preview_area_unrealize (GtkWidget *widget,
|
||||
GimpPreview *preview);
|
||||
static void gimp_preview_area_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation,
|
||||
GimpPreview *preview);
|
||||
static gboolean gimp_preview_area_event (GtkWidget *area,
|
||||
GdkEvent *event,
|
||||
GimpPreview *preview);
|
||||
static void gimp_preview_direction_changed (GtkWidget *widget,
|
||||
GtkTextDirection prev_dir);
|
||||
static gboolean gimp_preview_popup_menu (GtkWidget *widget);
|
||||
|
||||
static void gimp_preview_h_scroll (GtkAdjustment *hadj,
|
||||
GimpPreview *preview);
|
||||
static void gimp_preview_v_scroll (GtkAdjustment *vadj,
|
||||
GimpPreview *preview);
|
||||
static void gimp_preview_toggle_callback (GtkWidget *toggle,
|
||||
GimpPreview *preview);
|
||||
static void gimp_preview_notify_checks (GimpPreview *preview);
|
||||
static gboolean gimp_preview_invalidate_now (GimpPreview *preview);
|
||||
static void gimp_preview_area_realize (GtkWidget *widget,
|
||||
GimpPreview *preview);
|
||||
static void gimp_preview_area_unrealize (GtkWidget *widget,
|
||||
GimpPreview *preview);
|
||||
static void gimp_preview_area_size_allocate (GtkWidget *widget,
|
||||
GtkAllocation *allocation,
|
||||
GimpPreview *preview);
|
||||
static gboolean gimp_preview_area_event (GtkWidget *area,
|
||||
GdkEvent *event,
|
||||
GimpPreview *preview);
|
||||
|
||||
static void gimp_preview_h_scroll (GtkAdjustment *hadj,
|
||||
GimpPreview *preview);
|
||||
static void gimp_preview_v_scroll (GtkAdjustment *vadj,
|
||||
GimpPreview *preview);
|
||||
|
||||
static gboolean gimp_preview_nav_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event,
|
||||
GimpPreview *preview);
|
||||
|
||||
static void gimp_preview_nav_popup_realize (GtkWidget *widget,
|
||||
GimpPreview *preview);
|
||||
static void gimp_preview_nav_popup_unrealize (GtkWidget *widget,
|
||||
GimpPreview *preview);
|
||||
static gboolean gimp_preview_nav_popup_event (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GimpPreview *preview);
|
||||
static gboolean gimp_preview_nav_popup_expose (GtkWidget *widget,
|
||||
GdkEventExpose *event,
|
||||
GimpPreview *preview);
|
||||
|
||||
static void gimp_preview_toggle_callback (GtkWidget *toggle,
|
||||
GimpPreview *preview);
|
||||
|
||||
static void gimp_preview_notify_checks (GimpPreview *preview);
|
||||
|
||||
static gboolean gimp_preview_invalidate_now (GimpPreview *preview);
|
||||
|
||||
|
||||
static guint preview_signals[LAST_SIGNAL] = { 0 };
|
||||
|
@ -142,6 +165,7 @@ gimp_preview_class_init (GimpPreviewClass *klass)
|
|||
widget_class->popup_menu = gimp_preview_popup_menu;
|
||||
|
||||
klass->draw = NULL;
|
||||
klass->draw_thumb = NULL;
|
||||
|
||||
g_object_class_install_property (object_class,
|
||||
PROP_UPDATE,
|
||||
|
@ -164,6 +188,7 @@ gimp_preview_init (GimpPreview *preview)
|
|||
{
|
||||
GtkWidget *table;
|
||||
GtkWidget *frame;
|
||||
GtkWidget *image;
|
||||
GtkObject *adj;
|
||||
gdouble xalign = 0.0;
|
||||
|
||||
|
@ -187,12 +212,14 @@ gimp_preview_init (GimpPreview *preview)
|
|||
preview->in_drag = FALSE;
|
||||
preview->timeout_id = 0;
|
||||
|
||||
preview->xmin = preview->ymin = 0;
|
||||
preview->xmax = preview->ymax = 1;
|
||||
preview->xmin = preview->ymin = 0;
|
||||
preview->xmax = preview->ymax = 1;
|
||||
preview->width = preview->xmax - preview->xmin;
|
||||
preview->height = preview->ymax - preview->ymin;
|
||||
|
||||
preview->width = preview->xmax - preview->xmin;
|
||||
preview->height = preview->ymax - preview->ymin;
|
||||
preview->nav_popup = NULL;
|
||||
|
||||
/* scrollbars */
|
||||
adj = gtk_adjustment_new (0, 0, preview->width - 1, 1.0,
|
||||
preview->width, preview->width);
|
||||
|
||||
|
@ -219,11 +246,11 @@ gimp_preview_init (GimpPreview *preview)
|
|||
gtk_table_attach (GTK_TABLE (table), preview->vscr, 1,2, 0,1,
|
||||
GTK_FILL, GTK_EXPAND | GTK_SHRINK | GTK_FILL, 0, 0);
|
||||
|
||||
/* the area itself */
|
||||
/* preview area */
|
||||
frame = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_IN);
|
||||
gtk_table_attach (GTK_TABLE (table), frame, 0,1, 0,1,
|
||||
GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0,0);
|
||||
GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 0, 0);
|
||||
gtk_widget_show (frame);
|
||||
|
||||
preview->area = gimp_preview_area_new ();
|
||||
|
@ -258,8 +285,20 @@ gimp_preview_init (GimpPreview *preview)
|
|||
G_CALLBACK (gimp_preview_area_size_allocate),
|
||||
preview);
|
||||
|
||||
/* a toggle button to (des)activate the instant preview */
|
||||
/* navigation icon */
|
||||
preview->nav_icon = gtk_event_box_new ();
|
||||
gtk_table_attach (GTK_TABLE (table), preview->nav_icon, 1,2, 1,2,
|
||||
GTK_SHRINK, GTK_SHRINK, 0, 0);
|
||||
|
||||
image = gtk_image_new_from_stock (GIMP_STOCK_NAVIGATION, GTK_ICON_SIZE_MENU);
|
||||
gtk_container_add (GTK_CONTAINER (preview->nav_icon), image);
|
||||
gtk_widget_show (image);
|
||||
|
||||
g_signal_connect (preview->nav_icon, "button_press_event",
|
||||
G_CALLBACK (gimp_preview_nav_button_press),
|
||||
preview);
|
||||
|
||||
/* toggle button to (des)activate the instant preview */
|
||||
preview->toggle = gtk_check_button_new_with_mnemonic (_("_Preview"));
|
||||
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (preview->toggle),
|
||||
preview->update_preview);
|
||||
|
@ -282,6 +321,12 @@ gimp_preview_dispose (GObject *object)
|
|||
preview->timeout_id = 0;
|
||||
}
|
||||
|
||||
if (preview->nav_popup)
|
||||
{
|
||||
gtk_widget_destroy (preview->nav_popup);
|
||||
preview->nav_popup = NULL;
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
@ -443,6 +488,17 @@ gimp_preview_area_size_allocate (GtkWidget *widget,
|
|||
gtk_widget_hide (preview->vscr);
|
||||
}
|
||||
|
||||
if (GTK_WIDGET_VISIBLE (preview->vscr) &&
|
||||
GTK_WIDGET_VISIBLE (preview->hscr) &&
|
||||
GIMP_PREVIEW_GET_CLASS (preview)->draw_thumb)
|
||||
{
|
||||
gtk_widget_show (preview->nav_icon);
|
||||
}
|
||||
else
|
||||
{
|
||||
gtk_widget_hide (preview->nav_icon);
|
||||
}
|
||||
|
||||
if (GTK_WIDGET_REALIZED (widget))
|
||||
gdk_window_set_cursor (widget->window, cursor);
|
||||
|
||||
|
@ -557,6 +613,197 @@ gimp_preview_v_scroll (GtkAdjustment *vadj,
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_preview_nav_button_press (GtkWidget *widget,
|
||||
GdkEventButton *event,
|
||||
GimpPreview *preview)
|
||||
{
|
||||
if (preview->nav_popup)
|
||||
return TRUE;
|
||||
|
||||
if (event->type == GDK_BUTTON_PRESS && event->button == 1)
|
||||
{
|
||||
GtkWidget *outer;
|
||||
GtkWidget *inner;
|
||||
GtkWidget *area;
|
||||
GdkCursor *cursor;
|
||||
gint x, y;
|
||||
gdouble h, v;
|
||||
|
||||
preview->nav_popup = gtk_window_new (GTK_WINDOW_POPUP);
|
||||
|
||||
gtk_window_set_screen (GTK_WINDOW (preview->nav_popup),
|
||||
gtk_widget_get_screen (widget));
|
||||
|
||||
outer = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (outer), GTK_SHADOW_OUT);
|
||||
gtk_container_add (GTK_CONTAINER (preview->nav_popup), outer);
|
||||
gtk_widget_show (outer);
|
||||
|
||||
inner = gtk_frame_new (NULL);
|
||||
gtk_frame_set_shadow_type (GTK_FRAME (inner), GTK_SHADOW_IN);
|
||||
gtk_container_add (GTK_CONTAINER (outer), inner);
|
||||
gtk_widget_show (inner);
|
||||
|
||||
area = gimp_preview_area_new ();
|
||||
gtk_container_add (GTK_CONTAINER (inner), area);
|
||||
|
||||
g_signal_connect (area, "realize",
|
||||
G_CALLBACK (gimp_preview_nav_popup_realize),
|
||||
preview);
|
||||
g_signal_connect (area, "unrealize",
|
||||
G_CALLBACK (gimp_preview_nav_popup_unrealize),
|
||||
preview);
|
||||
g_signal_connect (area, "event",
|
||||
G_CALLBACK (gimp_preview_nav_popup_event),
|
||||
preview);
|
||||
g_signal_connect_after (area, "expose_event",
|
||||
G_CALLBACK (gimp_preview_nav_popup_expose),
|
||||
preview);
|
||||
|
||||
GIMP_PREVIEW_GET_CLASS (preview)->draw_thumb (preview,
|
||||
GIMP_PREVIEW_AREA (area),
|
||||
POPUP_SIZE, POPUP_SIZE);
|
||||
gtk_widget_realize (area);
|
||||
gtk_widget_show (area);
|
||||
|
||||
gdk_window_get_origin (widget->window, &x, &y);
|
||||
|
||||
h = ((gdouble) (preview->xoff + preview->width / 2) /
|
||||
(gdouble) (preview->xmax - preview->xmin));
|
||||
v = ((gdouble) (preview->yoff + preview->height / 2) /
|
||||
(gdouble) (preview->ymax - preview->ymin));
|
||||
|
||||
x += event->x - h * (gdouble) GIMP_PREVIEW_AREA (area)->width;
|
||||
y += event->y - v * (gdouble) GIMP_PREVIEW_AREA (area)->height;
|
||||
|
||||
gtk_window_move (GTK_WINDOW (preview->nav_popup),
|
||||
x - 2 * widget->style->xthickness,
|
||||
y - 2 * widget->style->ythickness);
|
||||
|
||||
gtk_widget_show (preview->nav_popup);
|
||||
|
||||
gtk_grab_add (area);
|
||||
|
||||
cursor = gdk_cursor_new_for_display (gtk_widget_get_display (widget),
|
||||
GDK_FLEUR);
|
||||
|
||||
gdk_pointer_grab (area->window, TRUE,
|
||||
GDK_BUTTON_RELEASE_MASK | GDK_BUTTON_MOTION_MASK,
|
||||
area->window, cursor,
|
||||
event->time);
|
||||
|
||||
gdk_cursor_unref (cursor);
|
||||
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_preview_nav_popup_realize (GtkWidget *widget,
|
||||
GimpPreview *preview)
|
||||
{
|
||||
if (! preview->nav_gc)
|
||||
{
|
||||
preview->nav_gc = gdk_gc_new (widget->window);
|
||||
|
||||
gdk_gc_set_function (preview->nav_gc, GDK_INVERT);
|
||||
gdk_gc_set_line_attributes (preview->nav_gc,
|
||||
PEN_WIDTH,
|
||||
GDK_LINE_SOLID, GDK_CAP_BUTT, GDK_JOIN_ROUND);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_preview_nav_popup_unrealize (GtkWidget *widget,
|
||||
GimpPreview *preview)
|
||||
{
|
||||
if (preview->nav_gc)
|
||||
{
|
||||
g_object_unref (preview->nav_gc);
|
||||
preview->nav_gc = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_preview_nav_popup_event (GtkWidget *widget,
|
||||
GdkEvent *event,
|
||||
GimpPreview *preview)
|
||||
{
|
||||
switch (event->type)
|
||||
{
|
||||
case GDK_BUTTON_RELEASE:
|
||||
{
|
||||
GdkEventButton *button_event = (GdkEventButton *) event;
|
||||
|
||||
if (button_event->button == 1)
|
||||
{
|
||||
gtk_grab_remove (widget);
|
||||
gdk_display_pointer_ungrab (gtk_widget_get_display (widget),
|
||||
button_event->time);
|
||||
|
||||
gtk_widget_destroy (preview->nav_popup);
|
||||
preview->nav_popup = NULL;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case GDK_MOTION_NOTIFY:
|
||||
{
|
||||
GdkEventMotion *motion_event = (GdkEventMotion *) event;
|
||||
GtkAdjustment *hadj;
|
||||
GtkAdjustment *vadj;
|
||||
gdouble x, y;
|
||||
|
||||
hadj = gtk_range_get_adjustment (GTK_RANGE (preview->hscr));
|
||||
vadj = gtk_range_get_adjustment (GTK_RANGE (preview->vscr));
|
||||
|
||||
x = (motion_event->x *
|
||||
(hadj->upper - hadj->lower) / widget->allocation.width);
|
||||
y = (motion_event->y *
|
||||
(vadj->upper - vadj->lower) / widget->allocation.height);
|
||||
|
||||
gtk_adjustment_set_value (hadj, x + hadj->lower);
|
||||
gtk_adjustment_set_value (vadj, y + vadj->lower);
|
||||
|
||||
gtk_widget_queue_draw (widget);
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gimp_preview_nav_popup_expose (GtkWidget *widget,
|
||||
GdkEventExpose *event,
|
||||
GimpPreview *preview)
|
||||
{
|
||||
gdouble x, y;
|
||||
gdouble w, h;
|
||||
|
||||
x = (gdouble) preview->xoff / (gdouble) (preview->xmax - preview->xmin);
|
||||
y = (gdouble) preview->yoff / (gdouble) (preview->ymax - preview->ymin);
|
||||
|
||||
w = (gdouble) preview->width / (gdouble) (preview->xmax - preview->xmin);
|
||||
h = (gdouble) preview->height / (gdouble) (preview->ymax - preview->ymin);
|
||||
|
||||
gdk_gc_set_clip_rectangle (preview->nav_gc, &event->area);
|
||||
|
||||
gdk_draw_rectangle (widget->window, preview->nav_gc,
|
||||
FALSE,
|
||||
x * (gdouble) widget->allocation.width,
|
||||
y * (gdouble) widget->allocation.height,
|
||||
MAX (1, ceil (w * widget->allocation.width)),
|
||||
MAX (1, ceil (h * widget->allocation.height)));
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
gimp_preview_toggle_callback (GtkWidget *toggle,
|
||||
GimpPreview *preview)
|
||||
|
|
|
@ -51,9 +51,12 @@ struct _GimpPreview
|
|||
GtkWidget *frame;
|
||||
GtkWidget *hscr;
|
||||
GtkWidget *vscr;
|
||||
GtkWidget *nav_icon;
|
||||
GtkWidget *nav_popup;
|
||||
GtkWidget *toggle;
|
||||
GdkCursor *cursor_move;
|
||||
GdkCursor *cursor_busy;
|
||||
GdkGC *nav_gc;
|
||||
|
||||
/*< private >*/
|
||||
gint xoff, yoff;
|
||||
|
@ -70,10 +73,14 @@ struct _GimpPreviewClass
|
|||
GtkVBoxClass parent_class;
|
||||
|
||||
/* virtuals */
|
||||
void (* draw) (GimpPreview *preview);
|
||||
void (* draw) (GimpPreview *preview);
|
||||
void (* draw_thumb) (GimpPreview *preview,
|
||||
GimpPreviewArea *area,
|
||||
gint width,
|
||||
gint height);
|
||||
|
||||
/* signal */
|
||||
void (* invalidated) (GimpPreview *preview);
|
||||
void (* invalidated) (GimpPreview *preview);
|
||||
};
|
||||
|
||||
|
||||
|
@ -103,4 +110,3 @@ void gimp_preview_invalidate (GimpPreview *preview);
|
|||
G_END_DECLS
|
||||
|
||||
#endif /* __GIMP_PREVIEW_H__ */
|
||||
|
||||
|
|
Loading…
Reference in New Issue