Commit e6be8f3f authored by Owen Taylor's avatar Owen Taylor Committed by Owen Taylor

Use new PangoAttrShape to reserve space for pixmaps, add GSList *pixmaps

Fri Jul 21 15:28:13 2000  Owen Taylor  <otaylor@redhat.com>

        * gtk/gtktextlayout.[ch], gtk/gtktextdisplay.c: Use new
	PangoAttrShape to reserve space for pixmaps, add
	GSList *pixmaps to GtkTextLineDisplay, draw the pixmaps
	in the display functions.

	* gtk/testgtk.c (create_layout): Set some more exotic
	scrolled window options

	* gtk/gtkscrolledwindow.[ch] (gtk_scrolled_window_set_shadow_type):
	Add function to set the shadow type of a window, to allow
	putting a shadow around widgets such as GtkLayout or GnomeCanvas
	which don't draw their own frame.
parent fa5d7c77
Fri Jul 21 15:28:13 2000 Owen Taylor <otaylor@redhat.com>
* gtk/gtktextlayout.[ch], gtk/gtktextdisplay.c: Use new
PangoAttrShape to reserve space for pixmaps, add
GSList *pixmaps to GtkTextLineDisplay, draw the pixmaps
in the display functions.
* gtk/testgtk.c (create_layout): Set some more exotic
scrolled window options
* gtk/gtkscrolledwindow.[ch] (gtk_scrolled_window_set_shadow_type):
Add function to set the shadow type of a window, to allow
putting a shadow around widgets such as GtkLayout or GnomeCanvas
which don't draw their own frame.
Fri Jul 21 16:34:42 BST 2000 Tony Gale <gale@gtk.org>
* docs/tutorial/package-db-tutorial.sh: New file for
......
Fri Jul 21 15:28:13 2000 Owen Taylor <otaylor@redhat.com>
* gtk/gtktextlayout.[ch], gtk/gtktextdisplay.c: Use new
PangoAttrShape to reserve space for pixmaps, add
GSList *pixmaps to GtkTextLineDisplay, draw the pixmaps
in the display functions.
* gtk/testgtk.c (create_layout): Set some more exotic
scrolled window options
* gtk/gtkscrolledwindow.[ch] (gtk_scrolled_window_set_shadow_type):
Add function to set the shadow type of a window, to allow
putting a shadow around widgets such as GtkLayout or GnomeCanvas
which don't draw their own frame.
Fri Jul 21 16:34:42 BST 2000 Tony Gale <gale@gtk.org>
* docs/tutorial/package-db-tutorial.sh: New file for
......
Fri Jul 21 15:28:13 2000 Owen Taylor <otaylor@redhat.com>
* gtk/gtktextlayout.[ch], gtk/gtktextdisplay.c: Use new
PangoAttrShape to reserve space for pixmaps, add
GSList *pixmaps to GtkTextLineDisplay, draw the pixmaps
in the display functions.
* gtk/testgtk.c (create_layout): Set some more exotic
scrolled window options
* gtk/gtkscrolledwindow.[ch] (gtk_scrolled_window_set_shadow_type):
Add function to set the shadow type of a window, to allow
putting a shadow around widgets such as GtkLayout or GnomeCanvas
which don't draw their own frame.
Fri Jul 21 16:34:42 BST 2000 Tony Gale <gale@gtk.org>
* docs/tutorial/package-db-tutorial.sh: New file for
......
Fri Jul 21 15:28:13 2000 Owen Taylor <otaylor@redhat.com>
* gtk/gtktextlayout.[ch], gtk/gtktextdisplay.c: Use new
PangoAttrShape to reserve space for pixmaps, add
GSList *pixmaps to GtkTextLineDisplay, draw the pixmaps
in the display functions.
* gtk/testgtk.c (create_layout): Set some more exotic
scrolled window options
* gtk/gtkscrolledwindow.[ch] (gtk_scrolled_window_set_shadow_type):
Add function to set the shadow type of a window, to allow
putting a shadow around widgets such as GtkLayout or GnomeCanvas
which don't draw their own frame.
Fri Jul 21 16:34:42 BST 2000 Tony Gale <gale@gtk.org>
* docs/tutorial/package-db-tutorial.sh: New file for
......
Fri Jul 21 15:28:13 2000 Owen Taylor <otaylor@redhat.com>
* gtk/gtktextlayout.[ch], gtk/gtktextdisplay.c: Use new
PangoAttrShape to reserve space for pixmaps, add
GSList *pixmaps to GtkTextLineDisplay, draw the pixmaps
in the display functions.
* gtk/testgtk.c (create_layout): Set some more exotic
scrolled window options
* gtk/gtkscrolledwindow.[ch] (gtk_scrolled_window_set_shadow_type):
Add function to set the shadow type of a window, to allow
putting a shadow around widgets such as GtkLayout or GnomeCanvas
which don't draw their own frame.
Fri Jul 21 16:34:42 BST 2000 Tony Gale <gale@gtk.org>
* docs/tutorial/package-db-tutorial.sh: New file for
......
Fri Jul 21 15:28:13 2000 Owen Taylor <otaylor@redhat.com>
* gtk/gtktextlayout.[ch], gtk/gtktextdisplay.c: Use new
PangoAttrShape to reserve space for pixmaps, add
GSList *pixmaps to GtkTextLineDisplay, draw the pixmaps
in the display functions.
* gtk/testgtk.c (create_layout): Set some more exotic
scrolled window options
* gtk/gtkscrolledwindow.[ch] (gtk_scrolled_window_set_shadow_type):
Add function to set the shadow type of a window, to allow
putting a shadow around widgets such as GtkLayout or GnomeCanvas
which don't draw their own frame.
Fri Jul 21 16:34:42 BST 2000 Tony Gale <gale@gtk.org>
* docs/tutorial/package-db-tutorial.sh: New file for
......
Fri Jul 21 15:28:13 2000 Owen Taylor <otaylor@redhat.com>
* gtk/gtktextlayout.[ch], gtk/gtktextdisplay.c: Use new
PangoAttrShape to reserve space for pixmaps, add
GSList *pixmaps to GtkTextLineDisplay, draw the pixmaps
in the display functions.
* gtk/testgtk.c (create_layout): Set some more exotic
scrolled window options
* gtk/gtkscrolledwindow.[ch] (gtk_scrolled_window_set_shadow_type):
Add function to set the shadow type of a window, to allow
putting a shadow around widgets such as GtkLayout or GnomeCanvas
which don't draw their own frame.
Fri Jul 21 16:34:42 BST 2000 Tony Gale <gale@gtk.org>
* docs/tutorial/package-db-tutorial.sh: New file for
......
......@@ -73,7 +73,8 @@ enum {
ARG_VADJUSTMENT,
ARG_HSCROLLBAR_POLICY,
ARG_VSCROLLBAR_POLICY,
ARG_WINDOW_PLACEMENT
ARG_WINDOW_PLACEMENT,
ARG_SHADOW
};
......@@ -91,6 +92,8 @@ static void gtk_scrolled_window_map (GtkWidget *widg
static void gtk_scrolled_window_unmap (GtkWidget *widget);
static void gtk_scrolled_window_draw (GtkWidget *widget,
GdkRectangle *area);
static gint gtk_scrolled_window_expose (GtkWidget *widget,
GdkEventExpose *event);
static void gtk_scrolled_window_size_request (GtkWidget *widget,
GtkRequisition *requisition);
static void gtk_scrolled_window_size_allocate (GtkWidget *widget,
......@@ -160,6 +163,7 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
widget_class->map = gtk_scrolled_window_map;
widget_class->unmap = gtk_scrolled_window_unmap;
widget_class->draw = gtk_scrolled_window_draw;
widget_class->expose_event = gtk_scrolled_window_expose;
widget_class->size_request = gtk_scrolled_window_size_request;
widget_class->size_allocate = gtk_scrolled_window_size_allocate;
widget_class->scroll_event = gtk_scrolled_window_scroll_event;
......@@ -190,6 +194,10 @@ gtk_scrolled_window_class_init (GtkScrolledWindowClass *class)
GTK_TYPE_CORNER_TYPE,
GTK_ARG_READWRITE,
ARG_WINDOW_PLACEMENT);
gtk_object_add_arg_type ("GtkScrolledWindow::shadow",
GTK_TYPE_SHADOW_TYPE,
GTK_ARG_READWRITE,
ARG_SHADOW);
}
static void
......@@ -223,6 +231,10 @@ gtk_scrolled_window_set_arg (GtkObject *object,
gtk_scrolled_window_set_placement (scrolled_window,
GTK_VALUE_ENUM (*arg));
break;
case ARG_SHADOW:
gtk_scrolled_window_set_shadow_type (scrolled_window,
GTK_VALUE_ENUM (*arg));
break;
default:
break;
}
......@@ -254,6 +266,9 @@ gtk_scrolled_window_get_arg (GtkObject *object,
case ARG_WINDOW_PLACEMENT:
GTK_VALUE_ENUM (*arg) = scrolled_window->window_placement;
break;
case ARG_SHADOW:
GTK_VALUE_ENUM (*arg) = scrolled_window->shadow_type;
break;
default:
arg->type = GTK_TYPE_INVALID;
break;
......@@ -458,6 +473,24 @@ gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
}
}
void
gtk_scrolled_window_set_shadow_type (GtkScrolledWindow *scrolled_window,
GtkShadowType type)
{
g_return_if_fail (GTK_IS_SCROLLED_WINDOW (scrolled_window));
g_return_if_fail (type >= GTK_SHADOW_NONE && type <= GTK_SHADOW_ETCHED_OUT);
if (scrolled_window->shadow_type != type)
{
scrolled_window->shadow_type = type;
if (GTK_WIDGET_DRAWABLE (scrolled_window))
gtk_widget_queue_clear (GTK_WIDGET (scrolled_window));
gtk_widget_queue_resize (GTK_WIDGET (scrolled_window));
}
}
static void
gtk_scrolled_window_destroy (GtkObject *object)
{
......@@ -529,6 +562,32 @@ gtk_scrolled_window_unmap (GtkWidget *widget)
gtk_widget_unmap (scrolled_window->vscrollbar);
}
static void
gtk_scrolled_window_paint (GtkWidget *widget,
GdkRectangle *area)
{
GtkAllocation relative_allocation;
GtkScrolledWindow *scrolled_window = GTK_SCROLLED_WINDOW (widget);
if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
{
gtk_scrolled_window_relative_allocation (widget, &relative_allocation);
relative_allocation.x -= widget->style->xthickness;
relative_allocation.y -= widget->style->ythickness;
relative_allocation.width += 2 * widget->style->xthickness;
relative_allocation.height += 2 * widget->style->ythickness;
gtk_paint_shadow (widget->style, widget->window,
GTK_STATE_NORMAL, scrolled_window->shadow_type,
area, widget, "scrolled_window",
widget->allocation.x + relative_allocation.x,
widget->allocation.y + relative_allocation.y,
relative_allocation.width,
relative_allocation.height);
}
}
static void
gtk_scrolled_window_draw (GtkWidget *widget,
GdkRectangle *area)
......@@ -544,17 +603,46 @@ gtk_scrolled_window_draw (GtkWidget *widget,
scrolled_window = GTK_SCROLLED_WINDOW (widget);
bin = GTK_BIN (widget);
if (bin->child && GTK_WIDGET_VISIBLE (bin->child) &&
gtk_widget_intersect (bin->child, area, &child_area))
gtk_widget_draw (bin->child, &child_area);
if (GTK_WIDGET_DRAWABLE (widget))
{
gtk_scrolled_window_paint (widget, area);
if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
gtk_widget_intersect (scrolled_window->hscrollbar, area, &child_area))
gtk_widget_draw (scrolled_window->hscrollbar, &child_area);
if (bin->child && GTK_WIDGET_VISIBLE (bin->child) &&
gtk_widget_intersect (bin->child, area, &child_area))
gtk_widget_draw (bin->child, &child_area);
if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar) &&
gtk_widget_intersect (scrolled_window->hscrollbar, area, &child_area))
gtk_widget_draw (scrolled_window->hscrollbar, &child_area);
if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
gtk_widget_intersect (scrolled_window->vscrollbar, area, &child_area))
gtk_widget_draw (scrolled_window->vscrollbar, &child_area);
}
}
if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar) &&
gtk_widget_intersect (scrolled_window->vscrollbar, area, &child_area))
gtk_widget_draw (scrolled_window->vscrollbar, &child_area);
static gint
gtk_scrolled_window_expose (GtkWidget *widget,
GdkEventExpose *event)
{
GtkBin *bin = GTK_BIN (widget);
GdkEventExpose child_event;
if (GTK_WIDGET_DRAWABLE (widget))
{
gtk_scrolled_window_paint (widget, &event->area);
if (bin->child && GTK_WIDGET_VISIBLE (bin->child) && GTK_WIDGET_NO_WINDOW (bin->child))
{
child_event = *event;
if (gtk_widget_intersect (bin->child, &event->area, &child_event.area))
gtk_widget_event (bin->child, (GdkEvent*) &child_event);
}
/* We rely on our knowledge that scrollbars are !NO_WINDOW widgets */
}
return FALSE;
}
static void
......@@ -673,6 +761,12 @@ gtk_scrolled_window_size_request (GtkWidget *widget,
requisition->width += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_width);
requisition->height += GTK_CONTAINER (widget)->border_width * 2 + MAX (0, extra_height);
if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
{
requisition->width += 2 * widget->style->xthickness;
requisition->height += 2 * widget->style->ythickness;
}
}
static void
......@@ -688,6 +782,13 @@ gtk_scrolled_window_relative_allocation (GtkWidget *widget,
allocation->x = GTK_CONTAINER (widget)->border_width;
allocation->y = GTK_CONTAINER (widget)->border_width;
if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
{
allocation->x += widget->style->xthickness;
allocation->y += widget->style->ythickness;
}
allocation->width = MAX (1, (gint)widget->allocation.width - allocation->x * 2);
allocation->height = MAX (1, (gint)widget->allocation.height - allocation->y * 2);
......@@ -808,7 +909,9 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
scrolled_window->window_placement == GTK_CORNER_TOP_RIGHT)
child_allocation.y = (relative_allocation.y +
relative_allocation.height +
SCROLLBAR_SPACING (scrolled_window));
SCROLLBAR_SPACING (scrolled_window) +
(scrolled_window->shadow_type == GTK_SHADOW_NONE ?
0 : widget->style->ythickness));
else
child_allocation.y = GTK_CONTAINER (scrolled_window)->border_width;
......@@ -817,6 +920,12 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
child_allocation.x += allocation->x;
child_allocation.y += allocation->y;
if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
{
child_allocation.x -= widget->style->xthickness;
child_allocation.width += 2 * widget->style->xthickness;
}
gtk_widget_size_allocate (scrolled_window->hscrollbar, &child_allocation);
}
else if (GTK_WIDGET_VISIBLE (scrolled_window->hscrollbar))
......@@ -835,7 +944,9 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
scrolled_window->window_placement == GTK_CORNER_BOTTOM_LEFT)
child_allocation.x = (relative_allocation.x +
relative_allocation.width +
SCROLLBAR_SPACING (scrolled_window));
SCROLLBAR_SPACING (scrolled_window) +
(scrolled_window->shadow_type == GTK_SHADOW_NONE ?
0 : widget->style->xthickness));
else
child_allocation.x = GTK_CONTAINER (scrolled_window)->border_width;
......@@ -845,6 +956,12 @@ gtk_scrolled_window_size_allocate (GtkWidget *widget,
child_allocation.x += allocation->x;
child_allocation.y += allocation->y;
if (scrolled_window->shadow_type != GTK_SHADOW_NONE)
{
child_allocation.y -= widget->style->ythickness;
child_allocation.height += 2 * widget->style->ythickness;
}
gtk_widget_size_allocate (scrolled_window->vscrollbar, &child_allocation);
}
else if (GTK_WIDGET_VISIBLE (scrolled_window->vscrollbar))
......
......@@ -63,6 +63,8 @@ struct _GtkScrolledWindow
guint hscrollbar_visible : 1;
guint vscrollbar_visible : 1;
guint window_placement : 2;
guint16 shadow_type;
};
struct _GtkScrolledWindowClass
......@@ -87,6 +89,8 @@ void gtk_scrolled_window_set_policy (GtkScrolledWindow *scrolle
GtkPolicyType vscrollbar_policy);
void gtk_scrolled_window_set_placement (GtkScrolledWindow *scrolled_window,
GtkCornerType window_placement);
void gtk_scrolled_window_set_shadow_type (GtkScrolledWindow *scrolled_window,
GtkShadowType type);
void gtk_scrolled_window_add_with_viewport (GtkScrolledWindow *scrolled_window,
GtkWidget *child);
......
......@@ -159,6 +159,7 @@ static void
render_layout_line (GdkDrawable *drawable,
GtkTextRenderState *render_state,
PangoLayoutLine *line,
GSList **pixmap_pointer,
int x,
int y,
gboolean selected)
......@@ -245,6 +246,39 @@ render_layout_line (GdkDrawable *drawable,
x_off += logical_rect.width;
}
else /* Pixmap segment */
{
GtkTextPixmap *pixmap = (*pixmap_pointer)->data;
gint width, height;
GdkRectangle pixmap_rect, draw_rect;
*pixmap_pointer = (*pixmap_pointer)->next;
gdk_drawable_get_size (pixmap->pixmap, &width, &height);
pixmap_rect.x = x + x_off / PANGO_SCALE;
pixmap_rect.y = y - height;
pixmap_rect.width = width;
pixmap_rect.height = height;
gdk_rectangle_intersect (&pixmap_rect, &render_state->clip_rect, &draw_rect);
if (pixmap->mask)
{
gdk_gc_set_clip_mask (render_state->fg_gc, pixmap->mask);
gdk_gc_set_clip_origin (render_state->fg_gc,
pixmap_rect.x, pixmap_rect.y);
}
gdk_draw_drawable (drawable, render_state->fg_gc, pixmap->pixmap,
draw_rect.x - pixmap_rect.x, draw_rect.y - pixmap_rect.y,
draw_rect.x, draw_rect.y, draw_rect.width, draw_rect.height);
if (pixmap->mask)
gdk_gc_set_clip_rectangle (render_state->fg_gc, &render_state->clip_rect);
x_off += width * PANGO_SCALE;
}
}
}
......@@ -258,6 +292,7 @@ render_para (GdkDrawable *drawable,
int selection_end_index)
{
PangoRectangle logical_rect;
GSList *pixmap_pointer = line_display->pixmaps;
GSList *tmp_list;
PangoAlignment align;
PangoLayout *layout = line_display->layout;
......@@ -340,14 +375,16 @@ render_para (GdkDrawable *drawable,
TRUE,
x + line_display->left_margin, selection_y,
total_width / PANGO_SCALE, selection_height);
render_layout_line (drawable, render_state,
line, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
render_layout_line (drawable, render_state, line, &pixmap_pointer,
x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
TRUE);
}
else
{
render_layout_line (drawable, render_state,
line, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
GSList *pixmap_pointer_tmp = pixmap_pointer;
render_layout_line (drawable, render_state, line, &pixmap_pointer,
x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
FALSE);
if (selection_start_index < byte_offset + line->length &&
......@@ -368,8 +405,8 @@ render_para (GdkDrawable *drawable,
logical_rect.width / PANGO_SCALE,
selection_height);
render_layout_line (drawable, render_state,
line, x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
render_layout_line (drawable, render_state, line, &pixmap_pointer_tmp,
x + x_offset / PANGO_SCALE, y + (y_offset - logical_rect.y) / PANGO_SCALE,
TRUE);
gdk_gc_set_clip_region (render_state->widget->style->fg_gc [GTK_STATE_SELECTED], NULL);
......@@ -467,8 +504,9 @@ get_item_properties (PangoItem *item,
if (attr->klass->type == gtk_text_attr_appearance_type)
{
*appearance = &((GtkTextAttrAppearance *)attr)->appearance;
return;
}
tmp_list = tmp_list->next;
}
}
......
......@@ -55,6 +55,7 @@
#include "gtktextiterprivate.h"
#include <stdlib.h>
#include <string.h>
static GtkTextLineData *gtk_text_line_data_new (GtkTextLayout *layout,
GtkTextLine *line);
......@@ -1090,17 +1091,35 @@ add_text_attrs (GtkTextLayout *layout,
attr->start_index = start;
attr->end_index = start + byte_count;
pango_attr_list_insert (attrs, attr);
pango_attr_list_insert (attrs, attr);
}
}
static void
add_pixmap_attrs (GtkTextLayout *layout,
GtkTextLineDisplay *display,
GtkTextStyleValues *style,
GtkTextLineSegment *seg,
PangoAttrList *attrs,
gint start)
{
PangoAttribute *attr;
PangoRectangle logical_rect;
GtkTextPixmap *pixmap = &seg->body.pixmap;
gint width, height;
gdk_drawable_get_size (pixmap->pixmap, &width, &height);
logical_rect.x = 0;
logical_rect.y = -height * PANGO_SCALE;
logical_rect.width = width * PANGO_SCALE;
logical_rect.height = height * PANGO_SCALE;
attr = pango_attr_shape_new (&logical_rect, &logical_rect);
attr->start_index = start;
attr->end_index = start + seg->byte_count;
pango_attr_list_insert (attrs, attr);
display->pixmaps = g_slist_append (display->pixmaps, pixmap);
}
static void
......@@ -1271,7 +1290,7 @@ gtk_text_layout_get_line_display (GtkTextLayout *layout,
}
else
{
add_pixmap_attrs (layout, style, seg, attrs, byte_offset);
add_pixmap_attrs (layout, display, style, seg, attrs, byte_offset);
memcpy (text + byte_offset, gtk_text_unknown_char_utf8, seg->byte_count);
byte_offset += seg->byte_count;
}
......@@ -1365,6 +1384,7 @@ gtk_text_layout_free_line_display (GtkTextLayout *layout,
{
g_slist_foreach (display->cursors, (GFunc)g_free, NULL);
g_slist_free (display->cursors);
g_slist_free (display->pixmaps);
}
g_free (display);
......
......@@ -115,6 +115,7 @@ struct _GtkTextLineDisplay
{
PangoLayout *layout;
GSList *cursors;
GSList *pixmaps;
GtkTextDirection direction;
......
......@@ -8418,6 +8418,10 @@ void create_layout (void)
gtk_widget_set_usize (window, 200, 200);
scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_SHADOW_IN);
gtk_scrolled_window_set_placement (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_CORNER_TOP_RIGHT);
gtk_container_add (GTK_CONTAINER (window), scrolledwindow);
......
......@@ -8418,6 +8418,10 @@ void create_layout (void)
gtk_widget_set_usize (window, 200, 200);
scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_SHADOW_IN);
gtk_scrolled_window_set_placement (GTK_SCROLLED_WINDOW (scrolledwindow),
GTK_CORNER_TOP_RIGHT);
gtk_container_add (GTK_CONTAINER (window), scrolledwindow);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment