Discussion:
Zoom to center of UserControl in C# using GDI+
(too old to reply)
d***@gmail.com
2006-12-18 23:17:56 UTC
Permalink
Hi,

I'm currently trying to write a custom UserControl which (essentially)
is a drawing canvas and allows zooming and panning.

The functionality I'm trying to implement relates to zooming. I've
currently implemented something along the lines of Bob Powell's example
at http://www.bobpowell.net/zoompicbox.htm, however, what I'm trying to
achieve is zooming to the center point of the control, rather than to
the top left hand (i.e. the co-ordinate location).

I can't quite get my head around how to do this cleanly. Can anyone
offer an advice or pointers? The only way I can think of doing it at
the moment, is by manually setting the AutoScrollPosition by
calculating the new position before scaling, and then setting that
position after the scaling. However I'm not sure this is the best way
to achieve what I what?

Kind Regards
Doug
Michael C
2006-12-19 00:01:25 UTC
Permalink
Post by d***@gmail.com
Hi,
I'm currently trying to write a custom UserControl which (essentially)
is a drawing canvas and allows zooming and panning.
The functionality I'm trying to implement relates to zooming. I've
currently implemented something along the lines of Bob Powell's example
at http://www.bobpowell.net/zoompicbox.htm, however, what I'm trying to
achieve is zooming to the center point of the control, rather than to
the top left hand (i.e. the co-ordinate location).
I can't quite get my head around how to do this cleanly. Can anyone
offer an advice or pointers? The only way I can think of doing it at
the moment, is by manually setting the AutoScrollPosition by
calculating the new position before scaling, and then setting that
position after the scaling. However I'm not sure this is the best way
to achieve what I what?
You want to investigate graphics.Transform.
Post by d***@gmail.com
Kind Regards
Doug
TDwyer
2006-12-19 02:27:34 UTC
Permalink
This example is in vb.net but I think it does what you want.
Tom
Post by Michael C
Post by d***@gmail.com
Hi,
I'm currently trying to write a custom UserControl which (essentially)
is a drawing canvas and allows zooming and panning.
The functionality I'm trying to implement relates to zooming. I've
currently implemented something along the lines of Bob Powell's example
at http://www.bobpowell.net/zoompicbox.htm, however, what I'm trying to
achieve is zooming to the center point of the control, rather than to
the top left hand (i.e. the co-ordinate location).
I can't quite get my head around how to do this cleanly. Can anyone
offer an advice or pointers? The only way I can think of doing it at
the moment, is by manually setting the AutoScrollPosition by
calculating the new position before scaling, and then setting that
position after the scaling. However I'm not sure this is the best way
to achieve what I what?
You want to investigate graphics.Transform.
Post by d***@gmail.com
Kind Regards
Doug
TDwyer
2006-12-19 02:28:28 UTC
Permalink
Oops, here it is:

http://www.codeproject.com/useritems/PanZoomExample.asp?&forumid=345111&mpp=50
Post by Michael C
Post by d***@gmail.com
Hi,
I'm currently trying to write a custom UserControl which (essentially)
is a drawing canvas and allows zooming and panning.
The functionality I'm trying to implement relates to zooming. I've
currently implemented something along the lines of Bob Powell's example
at http://www.bobpowell.net/zoompicbox.htm, however, what I'm trying to
achieve is zooming to the center point of the control, rather than to
the top left hand (i.e. the co-ordinate location).
I can't quite get my head around how to do this cleanly. Can anyone
offer an advice or pointers? The only way I can think of doing it at
the moment, is by manually setting the AutoScrollPosition by
calculating the new position before scaling, and then setting that
position after the scaling. However I'm not sure this is the best way
to achieve what I what?
You want to investigate graphics.Transform.
Post by d***@gmail.com
Kind Regards
Doug
Michael C
2006-12-19 03:58:15 UTC
Permalink
Post by TDwyer
http://www.codeproject.com/useritems/PanZoomExample.asp?&forumid=345111&mpp=50
Although a good starting point this isn't the best example. It uses double
buffering when it doesn't need to and zooms from the top left corner when it
should zoom from the centre. It doesn't use the tranform features of GDI+
which while not essential are probably a better way to do it. It also
calculates the source rect which doesn't seem to improve performance. The
article states it does improve performance but when I tested it it didn't
make any difference.
TDwyer
2006-12-19 10:25:04 UTC
Permalink
Look at the comments at the bottom of the article for code to kep it
centered. The performance increase is more obvious if you are using
big files (5-10 meg).
Post by Michael C
Post by TDwyer
http://www.codeproject.com/useritems/PanZoomExample.asp?&forumid=345111&mpp=50
Although a good starting point this isn't the best example. It uses double
buffering when it doesn't need to and zooms from the top left corner when it
should zoom from the centre. It doesn't use the tranform features of GDI+
which while not essential are probably a better way to do it. It also
calculates the source rect which doesn't seem to improve performance. The
article states it does improve performance but when I tested it it didn't
make any difference.
Michael C
2006-12-19 10:57:54 UTC
Permalink
Post by TDwyer
Look at the comments at the bottom of the article for code to kep it
centered. The performance increase is more obvious if you are using
big files (5-10 meg).
I tested with big files because I'm working with 25MB xrays. There was no
difference. What did make the difference was using 32bit PARGB bitmaps.
Everything I tried was a small percentage difference but using 32bit PARGB
images was something like 100 times faster.

Michael
d***@gmail.com
2006-12-19 09:18:43 UTC
Permalink
Thank you all for your prompt replies.

Michael C: I have had a brief look at the Graphics.Transform
functionality. What I can't quite seem to understand is how performing
transformations on a Matrix and then transforming the Graphics object
with that Matrix is any different from just simply performing the
transformation directly onto the Graphics object? As both objects seem
to share the same methods?
Post by Michael C
Post by d***@gmail.com
Hi,
I'm currently trying to write a custom UserControl which (essentially)
is a drawing canvas and allows zooming and panning.
The functionality I'm trying to implement relates to zooming. I've
currently implemented something along the lines of Bob Powell's example
at http://www.bobpowell.net/zoompicbox.htm, however, what I'm trying to
achieve is zooming to the center point of the control, rather than to
the top left hand (i.e. the co-ordinate location).
I can't quite get my head around how to do this cleanly. Can anyone
offer an advice or pointers? The only way I can think of doing it at
the moment, is by manually setting the AutoScrollPosition by
calculating the new position before scaling, and then setting that
position after the scaling. However I'm not sure this is the best way
to achieve what I what?
You want to investigate graphics.Transform.
Post by d***@gmail.com
Kind Regards
Doug
Michael C
2006-12-19 11:02:54 UTC
Permalink
Post by d***@gmail.com
Thank you all for your prompt replies.
Michael C: I have had a brief look at the Graphics.Transform
functionality. What I can't quite seem to understand is how performing
transformations on a Matrix and then transforming the Graphics object
with that Matrix is any different from just simply performing the
transformation directly onto the Graphics object? As both objects seem
to share the same methods?
There is no difference, the functions are just there on the graphics object
for convenience. You can build up your matrix and assign it to the graphics
object or just apply the transforms directly to the graphics object. I
suspect if you call Graphics.Tranform it will just pass the call on to a
private instance of the matrix.

The great thing about using the graphics object is that you can apply other
transforms to what you're drawing also, such as rotations. You can also work
backwards much more easily if you need to find what point on the screen
applies to a point on the bitmap, usually for when a user clicks in a
certain location.

Michael
d***@gmail.com
2006-12-19 15:19:43 UTC
Permalink
But (unless I'm misunderstanding things?) the problem isn't to do with
the transformation of the image, it's related to the
AutoScrollPosition?

Surely if I start applying TranslateTransform's to the Graphic the
auto-scroll bars won't be in sync with the location I'm looking at?

As I said before, the only way I can think of doing it is by
calculating the new centered viewport co-ordinates and moving the
AutoScrollPosition to the scaled position once the ScaleTransform and
TranslateTransform have been performed?
Post by Michael C
Post by d***@gmail.com
Thank you all for your prompt replies.
Michael C: I have had a brief look at the Graphics.Transform
functionality. What I can't quite seem to understand is how performing
transformations on a Matrix and then transforming the Graphics object
with that Matrix is any different from just simply performing the
transformation directly onto the Graphics object? As both objects seem
to share the same methods?
There is no difference, the functions are just there on the graphics object
for convenience. You can build up your matrix and assign it to the graphics
object or just apply the transforms directly to the graphics object. I
suspect if you call Graphics.Tranform it will just pass the call on to a
private instance of the matrix.
The great thing about using the graphics object is that you can apply other
transforms to what you're drawing also, such as rotations. You can also work
backwards much more easily if you need to find what point on the screen
applies to a point on the bitmap, usually for when a user clicks in a
certain location.
Michael
d***@gmail.com
2006-12-19 18:30:40 UTC
Permalink
I've created the following control & form for people to see what
exactly I'm trying to do.

Here's the code:

--------------------------------LayoutMainControl.cs------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Collections;

namespace WindowsApplication1
{
public class LayoutMainControl : UserControl
{
private float _ScaleFactor = 1.0F;
private Rectangle DrawingCanvas = new Rectangle ( 0, 0, 1000, 500
);

public float ScaleFactor
{
get
{
return _ScaleFactor;
}

set
{
_ScaleFactor = value;

RescaleDrawingCanvas ( );

Invalidate ( );
}
}

private System.ComponentModel.IContainer components = null;

protected override void Dispose ( bool disposing )
{
if ( disposing && ( components != null ) )
{
components.Dispose ( );
}
base.Dispose ( disposing );
}

#region Component Designer generated code

private void InitializeComponent ( )
{
this.SuspendLayout ( );
this.AutoScaleDimensions = new System.Drawing.SizeF ( 6F, 13F );
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.AutoScroll = true;
this.BackColor = System.Drawing.Color.White;
this.BorderStyle = System.Windows.Forms.BorderStyle.FixedSingle;
this.DoubleBuffered = true;
this.Margin = new System.Windows.Forms.Padding ( 0 );
this.Name = "LayoutMainControl";
this.Size = new System.Drawing.Size ( 692, 409 );
this.Paint += new System.Windows.Forms.PaintEventHandler (
this.LayoutMainControl_Paint );
this.ResumeLayout ( false );

}

#endregion

public LayoutMainControl ( )
{
InitializeComponent ( );
}

private void RescaleDrawingCanvas ( )
{
AutoScrollMinSize = new Size ( ( int ) ( DrawingCanvas.Width *
_ScaleFactor ), ( int ) ( DrawingCanvas.Height * _ScaleFactor ) );
}

private void LayoutMainControl_Paint ( object sender,
PaintEventArgs e )
{
Graphics deviceContext = e.Graphics;

deviceContext.PageUnit = GraphicsUnit.Pixel;
deviceContext.InterpolationMode =
InterpolationMode.HighQualityBicubic;

deviceContext.ScaleTransform ( _ScaleFactor, _ScaleFactor );

deviceContext.TranslateTransform ( AutoScrollPosition.X /
_ScaleFactor, AutoScrollPosition.Y / _ScaleFactor );

Pen pen = new Pen ( Color.Red, 1 );
Rectangle rectangle = new Rectangle ( 500, 250, 10, 10 );
deviceContext.DrawRectangle ( pen, rectangle );
deviceContext.FillRectangle ( new SolidBrush ( pen.Color ),
rectangle );
}
}
}

--------------------------------Form1.cs------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

namespace WindowsApplication1
{
public partial class Form1 : Form
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;

/// <summary>
/// The main entry point for the application.
/// </summary>
[STAThread]
static void Main ( )
{
Application.EnableVisualStyles ( );
Application.SetCompatibleTextRenderingDefault ( false );
Application.Run ( new Form1 ( ) );
}

/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be
disposed; otherwise, false.</param>
protected override void Dispose ( bool disposing )
{
if ( disposing && ( components != null ) )
{
components.Dispose ( );
}
base.Dispose ( disposing );
}

#region Windows Form Designer generated code

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent ( )
{
this.trackBar1 = new System.Windows.Forms.TrackBar ( );
this.layoutMainControl1 = new LayoutMainControl ( );
( ( System.ComponentModel.ISupportInitialize ) ( this.trackBar1 )
).BeginInit ( );
this.SuspendLayout ( );
//
// trackBar1
//
this.trackBar1.Dock = System.Windows.Forms.DockStyle.Bottom;
this.trackBar1.Maximum = 100;
this.trackBar1.Minimum = 1;
this.trackBar1.Name = "trackBar1";
this.trackBar1.TabIndex = 0;
this.trackBar1.Value = 10;
this.trackBar1.ValueChanged += new System.EventHandler (
this.trackBar1_ValueChanged );
//
// layoutMainControl1
//
this.layoutMainControl1.AutoScroll = true;
this.layoutMainControl1.BackColor = System.Drawing.Color.White;
this.layoutMainControl1.BorderStyle =
System.Windows.Forms.BorderStyle.FixedSingle;
this.layoutMainControl1.Dock =
System.Windows.Forms.DockStyle.Fill;
this.layoutMainControl1.Margin = new System.Windows.Forms.Padding
( 0 );
this.layoutMainControl1.Name = "layoutMainControl1";
this.layoutMainControl1.ScaleFactor = 1F;
this.layoutMainControl1.TabIndex = 1;
//
// Form1
//
this.AutoScaleDimensions = new System.Drawing.SizeF ( 6F, 13F );
this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
this.ClientSize = new System.Drawing.Size ( 1020, 550 );
this.Controls.Add ( this.layoutMainControl1 );
this.Controls.Add ( this.trackBar1 );
this.Name = "Form1";
this.Text = "Form1";
( ( System.ComponentModel.ISupportInitialize ) ( this.trackBar1 )
).EndInit ( );
this.ResumeLayout ( false );
this.PerformLayout ( );

}

#endregion

private System.Windows.Forms.TrackBar trackBar1;
private LayoutMainControl layoutMainControl1;

public Form1 ( )
{
InitializeComponent ( );
}

private void trackBar1_ValueChanged ( object sender, EventArgs e )
{
this.layoutMainControl1.ScaleFactor = 0.1F *
this.trackBar1.Value;
}
}
}
Michael C
2006-12-19 22:56:02 UTC
Permalink
Post by d***@gmail.com
But (unless I'm misunderstanding things?) the problem isn't to do with
the transformation of the image, it's related to the
AutoScrollPosition?
Surely if I start applying TranslateTransform's to the Graphic the
auto-scroll bars won't be in sync with the location I'm looking at?
As I said before, the only way I can think of doing it is by
calculating the new centered viewport co-ordinates and moving the
AutoScrollPosition to the scaled position once the ScaleTransform and
TranslateTransform have been performed?
In that case I wouldn't use the AutoScroll feature of the control, just
create your own scrollbars.

Michael
Bob Powell [MVP]
2006-12-19 23:09:03 UTC
Permalink
Annoying because it has different behaviour depending on whether you zoom in
or out.

Once you have the two cases however, the result is pretty simple.....

Here's the user control (with some inelegant dummy drawing :-) )

public partial class zoom2centerControl : UserControl

{

public zoom2centerControl()

{

InitializeComponent();

_docCenter = new Point(this.ClientRectangle.Width / 2,
this.ClientRectangle.Height / 2);

}

Point _docCenter;

float _zoom = 1.0f;

public float Zoom

{

get { return _zoom; }

set {

_zoom = value;

Invalidate();

this.AutoScrollMinSize = new Size(

(int)(this.ClientRectangle.Width * _zoom),

(int)(this.ClientRectangle.Height * _zoom)

);

this.AutoScrollPosition = new Point(

this.AutoScrollMinSize.Width / 2 - this.ClientSize.Width / 2,

this.AutoScrollMinSize.Height / 2 - this.ClientSize.Height / 2

);

}

}

protected override void OnScroll(ScrollEventArgs se)

{

Invalidate();

base.OnScroll(se);

}

protected override void OnPaint(PaintEventArgs e)

{

Matrix mx=new Matrix();

if (_zoom >= 1)

mx = new Matrix(_zoom, 0, 0, _zoom, this.AutoScrollPosition.X,
this.AutoScrollPosition.Y);

else

mx = new Matrix(_zoom, 0, 0, _zoom, this.ClientRectangle.Width / 2 -
(this.ClientRectangle.Width / 2 * _zoom), this.ClientRectangle.Height / 2 -
(this.ClientRectangle.Height / 2 * _zoom));

e.Graphics.Transform = mx;

e.Graphics.DrawLine(Pens.Red, 0, this.ClientRectangle.Height / 2,
this.ClientRectangle.Width, this.ClientRectangle.Height / 2);

e.Graphics.DrawLine(Pens.Red, this.ClientRectangle.Width/2, 0,
this.ClientRectangle.Width/2, this.ClientRectangle.Height);

for (int x = 0; x < 5; x++)

e.Graphics.DrawEllipse(Pens.Blue, ((this.ClientRectangle.Width / 2) - (1 +
(3 * x))), ((this.ClientRectangle.Height / 2) - (1 + (3 * x))), x * 6, x *
6);

}

}

And here's the form the drives it all.....

partial class Form1 : Form

{

/// <summary>

/// Required designer variable.

/// </summary>

private System.ComponentModel.IContainer components = null;

/// <summary>

/// Clean up any resources being used.

/// </summary>

/// <param name="disposing">true if managed resources should be disposed;
otherwise, false.</param>

protected override void Dispose(bool disposing)

{

if (disposing && (components != null))

{

components.Dispose();

}

base.Dispose(disposing);

}

#region Windows Form Designer generated code

/// <summary>

/// Required method for Designer support - do not modify

/// the contents of this method with the code editor.

/// </summary>

private void InitializeComponent()

{

this.trackBar1 = new System.Windows.Forms.TrackBar();

this.zoom2centerControl1 = new zoom2centre.zoom2centerControl();

((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit();

this.SuspendLayout();

//

// trackBar1

//

this.trackBar1.Dock = System.Windows.Forms.DockStyle.Top;

this.trackBar1.Location = new System.Drawing.Point(0, 0);

this.trackBar1.Maximum = 20;

this.trackBar1.Minimum = 1;

this.trackBar1.Name = "trackBar1";

this.trackBar1.Size = new System.Drawing.Size(292, 45);

this.trackBar1.TabIndex = 1;

this.trackBar1.Value = 5;

this.trackBar1.ValueChanged += new
System.EventHandler(this.trackBar1_ValueChanged);

//

// zoom2centerControl1

//

this.zoom2centerControl1.AutoScroll = true;

this.zoom2centerControl1.AutoScrollMinSize = new System.Drawing.Size(584,
452);

this.zoom2centerControl1.Dock = System.Windows.Forms.DockStyle.Fill;

this.zoom2centerControl1.Location = new System.Drawing.Point(0, 45);

this.zoom2centerControl1.Name = "zoom2centerControl1";

this.zoom2centerControl1.Size = new System.Drawing.Size(292, 226);

this.zoom2centerControl1.TabIndex = 2;

this.zoom2centerControl1.Zoom = 2F;

//

// Form1

//

this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);

this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;

this.ClientSize = new System.Drawing.Size(292, 271);

this.Controls.Add(this.zoom2centerControl1);

this.Controls.Add(this.trackBar1);

this.Name = "Form1";

this.Text = "Form1";

((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit();

this.ResumeLayout(false);

this.PerformLayout();

}

#endregion

private System.Windows.Forms.TrackBar trackBar1;

private zoom2centerControl zoom2centerControl1;

public Form1()

{

InitializeComponent();

}





private void panel1_Paint(object sender, PaintEventArgs e)

{

}

private void trackBar1_ValueChanged(object sender, EventArgs e)

{

if (this.trackBar1.Value > 4)

this.zoom2centerControl1.Zoom = 1 + this.trackBar1.Value - 5;

else

this.zoom2centerControl1.Zoom = 1.0f / (5 - this.trackBar1.Value) * 0.5f;

}

}
--
Bob Powell [MVP]
Visual C#, System.Drawing

Ramuseco Limited .NET consulting
http://www.ramuseco.com

Find great Windows Forms articles in Windows Forms Tips and Tricks
http://www.bobpowell.net/tipstricks.htm

Answer those GDI+ questions with the GDI+ FAQ
http://www.bobpowell.net/faqmain.htm

All new articles provide code in C# and VB.NET.
Subscribe to the RSS feeds provided and never miss a new article.
Post by d***@gmail.com
Hi,
I'm currently trying to write a custom UserControl which (essentially)
is a drawing canvas and allows zooming and panning.
The functionality I'm trying to implement relates to zooming. I've
currently implemented something along the lines of Bob Powell's example
at http://www.bobpowell.net/zoompicbox.htm, however, what I'm trying to
achieve is zooming to the center point of the control, rather than to
the top left hand (i.e. the co-ordinate location).
I can't quite get my head around how to do this cleanly. Can anyone
offer an advice or pointers? The only way I can think of doing it at
the moment, is by manually setting the AutoScrollPosition by
calculating the new position before scaling, and then setting that
position after the scaling. However I'm not sure this is the best way
to achieve what I what?
Kind Regards
Doug
Michael C
2006-12-20 00:17:20 UTC
Permalink
Try that, this is my own ScrollView....
This doesn't compile. It's missing what I presume is an enum called
Alignment and it is missing a form called DraggingForm

Michael
Michael C
2006-12-20 01:04:42 UTC
Permalink
You could remove the dragging code.
But just if you want to keep it, I copy here the DraggingForm.
I also attached the Alignment file
The dragging form is missing some constants but removing all references to
it fixed the problem. What is this control meant to do? Is it a replacement
for the standard scrolling features of controls?

Michael
Lloyd Dupont
2006-12-20 03:10:27 UTC
Permalink
This is a ScrollView which also zoom.
It is ideally suited for subclassing, where you could ovewrite OnPaint() as
follow:
/// protected override void OnPaint(PaintEventArgs e)
/// {
/// // prepare the client space (standart in ScrollView)
/// Matrix m = e.Graphics.Transform;
/// m.Multiply(ClientTransform());
/// e.Graphics.Transform = m;
///
/// // ... normal drawing code ...
/// }
Post by Michael C
You could remove the dragging code.
But just if you want to keep it, I copy here the DraggingForm.
I also attached the Alignment file
The dragging form is missing some constants but removing all references to
it fixed the problem. What is this control meant to do? Is it a
replacement for the standard scrolling features of controls?
Michael
d***@gmail.com
2006-12-20 10:00:20 UTC
Permalink
Thank you all very much for your help. Everything is working now!

Cheers
Doug
Post by Lloyd Dupont
This is a ScrollView which also zoom.
It is ideally suited for subclassing, where you could ovewrite OnPaint() as
/// protected override void OnPaint(PaintEventArgs e)
/// {
/// // prepare the client space (standart in ScrollView)
/// Matrix m = e.Graphics.Transform;
/// m.Multiply(ClientTransform());
/// e.Graphics.Transform = m;
///
/// // ... normal drawing code ...
/// }
Post by Michael C
You could remove the dragging code.
But just if you want to keep it, I copy here the DraggingForm.
I also attached the Alignment file
The dragging form is missing some constants but removing all references to
it fixed the problem. What is this control meant to do? Is it a
replacement for the standard scrolling features of controls?
Michael
Michael C
2006-12-20 11:06:26 UTC
Permalink
Post by Lloyd Dupont
This is a ScrollView which also zoom.
It is ideally suited for subclassing, where you could ovewrite OnPaint()
/// protected override void OnPaint(PaintEventArgs e)
/// {
/// // prepare the client space (standart in ScrollView)
/// Matrix m = e.Graphics.Transform;
/// m.Multiply(ClientTransform());
/// e.Graphics.Transform = m;
///
/// // ... normal drawing code ...
/// }
I've have a similar control which I use for a few different things. Instead
of having the onpaint event in the control I inherit from so that there is
no need to copy the code each time it is used.

Michael

Loading...